[JSCRIPT] Sync with Wine Staging 2.9. CORE-13362

59c39fa jscript: Added new debug channel printing details and backtrace of unwinded exceptions.
60232cc jscript: Always jump to finally block from OP_pop_exept when available.
685cd43 jscript: Pass finally offset instead of catch ident to OP_push_except.
8bd99c3 jscript: Ensure that OP_pop_except is called with proper stack depth.
622eb72 jscript: Added new opcode to enter catch block and use it to setup the scope.
b7bb166 jscript: Simplify pop_to_stat implementation.
1731629 jscript: Add __WINE_ALLOC_SIZE attributes to heap_xxx() functions.

svn path=/trunk/; revision=74811
This commit is contained in:
Amine Khaldi 2017-06-03 22:28:19 +00:00
parent 7a8fa2cc0e
commit 96d090509e
5 changed files with 184 additions and 96 deletions

View file

@ -1376,24 +1376,30 @@ static HRESULT compile_forin_statement(compiler_ctx_t *ctx, forin_statement_t *s
return S_OK;
}
static HRESULT pop_to_stat(compiler_ctx_t *ctx, BOOL var_stack, BOOL scope_stack, statement_ctx_t *stat_ctx)
static HRESULT pop_to_stat(compiler_ctx_t *ctx, statement_ctx_t *stat_ctx)
{
unsigned stack_pop = 0;
statement_ctx_t *iter;
HRESULT hres;
for(iter = ctx->stat_ctx; iter != stat_ctx; iter = iter->next) {
if(scope_stack) {
if(iter->using_scope && !push_instr(ctx, OP_pop_scope))
return E_OUTOFMEMORY;
if(iter->using_except && !push_instr(ctx, OP_pop_except))
return E_OUTOFMEMORY;
if(iter->using_scope && !push_instr(ctx, OP_pop_scope))
return E_OUTOFMEMORY;
if(iter->using_except) {
if(stack_pop) {
hres = push_instr_uint(ctx, OP_pop, stack_pop);
if(FAILED(hres))
return hres;
stack_pop = 0;
}
hres = push_instr_uint(ctx, OP_pop_except, ctx->code_off+1);
if(FAILED(hres))
return hres;
}
stack_pop += iter->stack_use;
}
if(var_stack && stack_pop) {
HRESULT hres;
if(stack_pop) {
hres = push_instr_uint(ctx, OP_pop, stack_pop);
if(FAILED(hres))
return hres;
@ -1448,7 +1454,7 @@ static HRESULT compile_continue_statement(compiler_ctx_t *ctx, branch_statement_
}
}
hres = pop_to_stat(ctx, TRUE, TRUE, pop_ctx);
hres = pop_to_stat(ctx, pop_ctx);
if(FAILED(hres))
return hres;
@ -1485,7 +1491,7 @@ static HRESULT compile_break_statement(compiler_ctx_t *ctx, branch_statement_t *
}
}
hres = pop_to_stat(ctx, TRUE, TRUE, pop_ctx->next);
hres = pop_to_stat(ctx, pop_ctx->next);
if(FAILED(hres))
return hres;
@ -1502,10 +1508,6 @@ static HRESULT compile_return_statement(compiler_ctx_t *ctx, expression_statemen
return JS_E_MISPLACED_RETURN;
}
hres = pop_to_stat(ctx, TRUE, FALSE, NULL);
if(FAILED(hres))
return hres;
if(stat->expr) {
hres = compile_expression(ctx, stat->expr, TRUE);
if(FAILED(hres))
@ -1514,7 +1516,7 @@ static HRESULT compile_return_statement(compiler_ctx_t *ctx, expression_statemen
return E_OUTOFMEMORY;
}
hres = pop_to_stat(ctx, FALSE, TRUE, NULL);
hres = pop_to_stat(ctx, NULL);
if(FAILED(hres))
return hres;
@ -1680,9 +1682,8 @@ static HRESULT compile_throw_statement(compiler_ctx_t *ctx, expression_statement
/* ECMA-262 3rd Edition 12.14 */
static HRESULT compile_try_statement(compiler_ctx_t *ctx, try_statement_t *stat)
{
statement_ctx_t try_ctx = {0, FALSE, TRUE}, catch_ctx = {0, TRUE, FALSE};
statement_ctx_t finally_ctx = {2, FALSE, FALSE};
unsigned push_except;
statement_ctx_t try_ctx = {0, FALSE, TRUE}, finally_ctx = {2, FALSE, FALSE};
unsigned push_except, finally_off = 0, catch_off = 0, pop_except, catch_pop_except = 0;
BSTR ident;
HRESULT hres;
@ -1698,26 +1699,25 @@ static HRESULT compile_try_statement(compiler_ctx_t *ctx, try_statement_t *stat)
ident = NULL;
}
instr_ptr(ctx, push_except)->u.arg[1].bstr = ident;
if(!stat->catch_block)
try_ctx.stack_use = 2;
hres = compile_statement(ctx, &try_ctx, stat->try_statement);
if(FAILED(hres))
return hres;
if(!push_instr(ctx, OP_pop_except))
pop_except = push_instr(ctx, OP_pop_except);
if(!pop_except)
return E_OUTOFMEMORY;
if(stat->catch_block) {
unsigned jmp_finally;
statement_ctx_t catch_ctx = {0, TRUE, stat->finally_statement != NULL};
jmp_finally = push_instr(ctx, OP_jmp);
if(!jmp_finally)
return E_OUTOFMEMORY;
if(stat->finally_statement)
catch_ctx.using_except = TRUE;
instr_ptr(ctx, push_except)->u.arg[0].uint = ctx->code_off;
catch_off = ctx->code_off;
hres = push_instr_bstr(ctx, OP_enter_catch, ident);
if(FAILED(hres))
return hres;
hres = compile_statement(ctx, &catch_ctx, stat->catch_block->statement);
if(FAILED(hres))
@ -1726,20 +1726,33 @@ static HRESULT compile_try_statement(compiler_ctx_t *ctx, try_statement_t *stat)
if(!push_instr(ctx, OP_pop_scope))
return E_OUTOFMEMORY;
set_arg_uint(ctx, jmp_finally, ctx->code_off);
}else {
set_arg_uint(ctx, push_except, ctx->code_off);
if(stat->finally_statement) {
catch_pop_except = push_instr(ctx, OP_pop_except);
if(!catch_pop_except)
return E_OUTOFMEMORY;
}
}
if(stat->finally_statement) {
hres = compile_statement(ctx, stat->catch_block ? NULL : &finally_ctx, stat->finally_statement);
/*
* finally block expects two elements on the stack, which may be:
* - (true, return_addr) set by OP_pop_except, OP_end_finally jumps back to passed addres
* - (false, exception_value) set when unwinding an exception, which OP_end_finally rethrows
*/
finally_off = ctx->code_off;
hres = compile_statement(ctx, &finally_ctx, stat->finally_statement);
if(FAILED(hres))
return hres;
if(!stat->catch_block && !push_instr(ctx, OP_end_finally))
if(!push_instr(ctx, OP_end_finally))
return E_OUTOFMEMORY;
}
instr_ptr(ctx, pop_except)->u.arg[0].uint = ctx->code_off;
if(catch_pop_except)
instr_ptr(ctx, catch_pop_except)->u.arg[0].uint = ctx->code_off;
instr_ptr(ctx, push_except)->u.arg[0].uint = catch_off;
instr_ptr(ctx, push_except)->u.arg[1].uint = finally_off;
return S_OK;
}

View file

@ -18,6 +18,8 @@
#include "jscript.h"
WINE_DECLARE_DEBUG_CHANNEL(jscript_except);
static const WCHAR booleanW[] = {'b','o','o','l','e','a','n',0};
static const WCHAR functionW[] = {'f','u','n','c','t','i','o','n',0};
static const WCHAR numberW[] = {'n','u','m','b','e','r',0};
@ -30,7 +32,7 @@ struct _except_frame_t {
unsigned stack_top;
scope_chain_t *scope;
unsigned catch_off;
BSTR ident;
unsigned finally_off;
except_frame_t *next;
};
@ -891,35 +893,21 @@ static HRESULT interp_throw_type(script_ctx_t *ctx)
/* ECMA-262 3rd Edition 12.14 */
static HRESULT interp_push_except(script_ctx_t *ctx)
{
const unsigned arg1 = get_op_uint(ctx, 0);
const BSTR arg2 = get_op_bstr(ctx, 1);
const unsigned catch_off = get_op_uint(ctx, 0);
const unsigned finally_off = get_op_uint(ctx, 1);
call_frame_t *frame = ctx->call_ctx;
except_frame_t *except;
unsigned stack_top;
TRACE("\n");
stack_top = ctx->stack_top;
if(!arg2) {
HRESULT hres;
hres = stack_push(ctx, jsval_bool(TRUE));
if(FAILED(hres))
return hres;
hres = stack_push(ctx, jsval_bool(TRUE));
if(FAILED(hres))
return hres;
}
except = heap_alloc(sizeof(*except));
if(!except)
return E_OUTOFMEMORY;
except->stack_top = stack_top;
except->stack_top = ctx->stack_top;
except->scope = frame->scope;
except->catch_off = arg1;
except->ident = arg2;
except->catch_off = catch_off;
except->finally_off = finally_off;
except->next = frame->except_frame;
frame->except_frame = except;
return S_OK;
@ -928,22 +916,41 @@ static HRESULT interp_push_except(script_ctx_t *ctx)
/* ECMA-262 3rd Edition 12.14 */
static HRESULT interp_pop_except(script_ctx_t *ctx)
{
const unsigned ret_off = get_op_uint(ctx, 0);
call_frame_t *frame = ctx->call_ctx;
except_frame_t *except;
unsigned finally_off;
TRACE("\n");
TRACE("%u\n", ret_off);
except = frame->except_frame;
assert(except != NULL);
finally_off = except->finally_off;
frame->except_frame = except->next;
heap_free(except);
if(finally_off) {
HRESULT hres;
hres = stack_push(ctx, jsval_number(ret_off));
if(FAILED(hres))
return hres;
hres = stack_push(ctx, jsval_bool(TRUE));
if(FAILED(hres))
return hres;
frame->ip = finally_off;
}else {
frame->ip = ret_off;
}
return S_OK;
}
/* ECMA-262 3rd Edition 12.14 */
static HRESULT interp_end_finally(script_ctx_t *ctx)
{
call_frame_t *frame = ctx->call_ctx;
jsval_t v;
TRACE("\n");
@ -958,10 +965,32 @@ static HRESULT interp_end_finally(script_ctx_t *ctx)
return DISP_E_EXCEPTION;
}
stack_pop(ctx);
v = stack_pop(ctx);
assert(is_number(v));
frame->ip = get_number(v);
return S_OK;
}
static HRESULT interp_enter_catch(script_ctx_t *ctx)
{
const BSTR ident = get_op_bstr(ctx, 0);
jsdisp_t *scope_obj;
jsval_t v;
HRESULT hres;
hres = create_dispex(ctx, NULL, NULL, &scope_obj);
if(FAILED(hres))
return hres;
v = stack_pop(ctx);
hres = jsdisp_propput_name(scope_obj, ident, v);
jsval_release(v);
if(SUCCEEDED(hres))
hres = scope_push(ctx->call_ctx->scope, scope_obj, to_disp(scope_obj), &ctx->call_ctx->scope);
jsdisp_release(scope_obj);
return hres;
}
/* ECMA-262 3rd Edition 13 */
static HRESULT interp_func(script_ctx_t *ctx)
{
@ -2626,14 +2655,72 @@ static void pop_call_frame(script_ctx_t *ctx)
heap_free(frame);
}
static void print_backtrace(script_ctx_t *ctx)
{
unsigned depth = 0, i;
call_frame_t *frame;
for(frame = ctx->call_ctx; frame; frame = frame->prev_frame) {
TRACE_(jscript_except)("%u\t", depth);
depth++;
if(frame->this_obj && frame->this_obj != to_disp(ctx->global) && frame->this_obj != ctx->host_global)
TRACE_(jscript_except)("%p->", frame->this_obj);
TRACE_(jscript_except)("%s(", frame->function->name ? debugstr_w(frame->function->name) : "[unnamed]");
if(frame->base_scope && frame->base_scope->frame) {
for(i=0; i < frame->argc; i++) {
if(i < frame->function->param_cnt)
TRACE_(jscript_except)("%s%s=%s", i ? ", " : "",
debugstr_w(frame->function->params[i]),
debugstr_jsval(ctx->stack[local_off(frame, -i-1)]));
else
TRACE_(jscript_except)("%s%s", i ? ", " : "",
debugstr_jsval(ctx->stack[local_off(frame, -i-1)]));
}
}else {
TRACE_(jscript_except)("[detached frame]");
}
TRACE_(jscript_except)(")\n");
if(!(frame->flags & EXEC_RETURN_TO_INTERP)) {
TRACE_(jscript_except)("%u\t[native code]\n", depth);
depth++;
}
}
}
static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres)
{
except_frame_t *except_frame;
call_frame_t *frame;
jsval_t except_val;
BSTR ident;
unsigned catch_off;
HRESULT hres;
TRACE("%08x\n", exception_hres);
if(TRACE_ON(jscript_except)) {
jsdisp_t *error_obj;
jsval_t msg;
static const WCHAR messageW[] = {'m','e','s','s','a','g','e',0};
TRACE_(jscript_except)("Exception %08x %s", exception_hres, debugstr_jsval(ctx->ei.val));
if(jsval_type(ctx->ei.val) == JSV_OBJECT) {
error_obj = to_jsdisp(get_object(ctx->ei.val));
if(error_obj) {
hres = jsdisp_propget_name(error_obj, messageW, &msg);
if(SUCCEEDED(hres)) {
TRACE_(jscript_except)(" (message %s)", debugstr_jsval(msg));
jsval_release(msg);
}
}
}
TRACE_(jscript_except)(" in:\n");
print_backtrace(ctx);
}
for(frame = ctx->call_ctx; !frame->except_frame; frame = ctx->call_ctx) {
DWORD flags;
@ -2649,7 +2736,7 @@ static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres)
}
except_frame = frame->except_frame;
frame->except_frame = except_frame->next;
catch_off = except_frame->catch_off;
assert(except_frame->stack_top <= ctx->stack_top);
stack_popn(ctx, ctx->stack_top - except_frame->stack_top);
@ -2657,38 +2744,27 @@ static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres)
while(except_frame->scope != frame->scope)
scope_pop(&frame->scope);
frame->ip = except_frame->catch_off;
frame->ip = catch_off ? catch_off : except_frame->finally_off;
if(catch_off) assert(frame->bytecode->instrs[frame->ip].op == OP_enter_catch);
except_val = ctx->ei.val;
ctx->ei.val = jsval_undefined();
clear_ei(ctx);
ident = except_frame->ident;
heap_free(except_frame);
if(ident) {
jsdisp_t *scope_obj;
hres = create_dispex(ctx, NULL, NULL, &scope_obj);
if(SUCCEEDED(hres)) {
hres = jsdisp_propput_name(scope_obj, ident, except_val);
if(FAILED(hres))
jsdisp_release(scope_obj);
}
jsval_release(except_val);
if(FAILED(hres))
return hres;
hres = scope_push(frame->scope, scope_obj, to_disp(scope_obj), &frame->scope);
jsdisp_release(scope_obj);
/* keep current except_frame if we're entering catch block with finally block associated */
if(catch_off && except_frame->finally_off) {
except_frame->catch_off = 0;
}else {
hres = stack_push(ctx, except_val);
if(FAILED(hres))
return hres;
hres = stack_push(ctx, jsval_bool(FALSE));
frame->except_frame = except_frame->next;
heap_free(except_frame);
}
hres = stack_push(ctx, except_val);
if(FAILED(hres))
return hres;
if(!catch_off)
hres = stack_push(ctx, jsval_bool(FALSE));
return hres;
}
@ -2705,8 +2781,6 @@ static HRESULT enter_bytecode(script_ctx_t *ctx, jsval_t *r)
op = frame->bytecode->instrs[frame->ip].op;
hres = op_funcs[op](ctx);
if(FAILED(hres)) {
TRACE("EXCEPTION %08x\n", hres);
hres = unwind_exception(ctx, hres);
if(FAILED(hres))
return hres;

View file

@ -36,7 +36,8 @@
X(delete_ident,1,ARG_BSTR, 0) \
X(div, 1, 0,0) \
X(double, 1, ARG_DBL, 0) \
X(end_finally,1, 0,0) \
X(end_finally,0, 0,0) \
X(enter_catch,1, ARG_BSTR, 0) \
X(eq, 1, 0,0) \
X(eq2, 1, 0,0) \
X(forin, 0, ARG_ADDR, 0) \
@ -69,11 +70,11 @@
X(obj_prop, 1, ARG_BSTR, 0) \
X(or, 1, 0,0) \
X(pop, 1, ARG_UINT, 0) \
X(pop_except, 1, 0,0) \
X(pop_except, 0, ARG_ADDR, 0) \
X(pop_scope, 1, 0,0) \
X(postinc, 1, ARG_INT, 0) \
X(preinc, 1, ARG_INT, 0) \
X(push_except,1, ARG_ADDR, ARG_BSTR) \
X(push_except,1, ARG_ADDR, ARG_UINT) \
X(push_ret, 1, 0,0) \
X(push_scope, 1, 0,0) \
X(regexp, 1, ARG_STR, ARG_UINT) \
@ -89,7 +90,7 @@
X(typeofid, 1, 0,0) \
X(typeofident,1, 0,0) \
X(refval, 1, 0,0) \
X(ret, 0, 0,0) \
X(ret, 0, ARG_UINT, 0) \
X(setret, 1, 0,0) \
X(sub, 1, 0,0) \
X(undefined, 1, 0,0) \

View file

@ -68,19 +68,19 @@ void heap_pool_clear(heap_pool_t*) DECLSPEC_HIDDEN;
void heap_pool_free(heap_pool_t*) DECLSPEC_HIDDEN;
heap_pool_t *heap_pool_mark(heap_pool_t*) DECLSPEC_HIDDEN;
static inline void *heap_alloc(size_t len)
static inline void* __WINE_ALLOC_SIZE(1) heap_alloc(size_t size)
{
return HeapAlloc(GetProcessHeap(), 0, len);
return HeapAlloc(GetProcessHeap(), 0, size);
}
static inline void *heap_alloc_zero(size_t len)
static inline void* __WINE_ALLOC_SIZE(1) heap_alloc_zero(size_t size)
{
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
}
static inline void *heap_realloc(void *mem, size_t len)
static inline void* __WINE_ALLOC_SIZE(2) heap_realloc(void *mem, size_t size)
{
return HeapReAlloc(GetProcessHeap(), 0, mem, len);
return HeapReAlloc(GetProcessHeap(), 0, mem, size);
}
static inline BOOL heap_free(void *mem)

View file

@ -85,7 +85,7 @@ reactos/dll/win32/inseng # Synced to WineStaging-2.2
reactos/dll/win32/iphlpapi # Out of sync
reactos/dll/win32/itircl # Synced to WineStaging-1.9.11
reactos/dll/win32/itss # Synced to WineStaging-2.2
reactos/dll/win32/jscript # Synced to WineStaging-2.2
reactos/dll/win32/jscript # Synced to WineStaging-2.9
reactos/dll/win32/jsproxy # Synced to WineStaging-2.2
reactos/dll/win32/loadperf # Synced to WineStaging-2.2
reactos/dll/win32/lz32 # Synced to WineStaging-1.9.11