Author: akhaldi
Date: Sat Jun 3 22:28:19 2017
New Revision: 74811
URL:
http://svn.reactos.org/svn/reactos?rev=74811&view=rev
Log:
[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.
Modified:
trunk/reactos/dll/win32/jscript/compile.c
trunk/reactos/dll/win32/jscript/engine.c
trunk/reactos/dll/win32/jscript/engine.h
trunk/reactos/dll/win32/jscript/jscript.h
trunk/reactos/media/doc/README.WINE
Modified: trunk/reactos/dll/win32/jscript/compile.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/compile.…
==============================================================================
--- trunk/reactos/dll/win32/jscript/compile.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/jscript/compile.c [iso-8859-1] Sat Jun 3 22:28:19 2017
@@ -1376,24 +1376,30 @@
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 @@
}
}
- 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 @@
}
}
- 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 @@
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 @@
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 @@
/* 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 @@
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;
-
- jmp_finally = push_instr(ctx, OP_jmp);
- if(!jmp_finally)
- return E_OUTOFMEMORY;
-
- instr_ptr(ctx, push_except)->u.arg[0].uint = ctx->code_off;
+ statement_ctx_t catch_ctx = {0, TRUE, stat->finally_statement != NULL};
+
+ if(stat->finally_statement)
+ catch_ctx.using_except = TRUE;
+
+ 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 @@
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);
- if(FAILED(hres))
- return hres;
-
- if(!stat->catch_block && !push_instr(ctx, OP_end_finally))
+ /*
+ * 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(!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;
}
Modified: trunk/reactos/dll/win32/jscript/engine.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/engine.c…
==============================================================================
--- trunk/reactos/dll/win32/jscript/engine.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/jscript/engine.c [iso-8859-1] Sat Jun 3 22:28:19 2017
@@ -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 @@
unsigned stack_top;
scope_chain_t *scope;
unsigned catch_off;
- BSTR ident;
+ unsigned finally_off;
except_frame_t *next;
};
@@ -891,59 +893,64 @@
/* 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) {
+
+ TRACE("\n");
+
+ except = heap_alloc(sizeof(*except));
+ if(!except)
+ return E_OUTOFMEMORY;
+
+ except->stack_top = ctx->stack_top;
+ except->scope = frame->scope;
+ except->catch_off = catch_off;
+ except->finally_off = finally_off;
+ except->next = frame->except_frame;
+ frame->except_frame = except;
+ return S_OK;
+}
+
+/* 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("%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_bool(TRUE));
+ 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;
- }
-
- except = heap_alloc(sizeof(*except));
- if(!except)
- return E_OUTOFMEMORY;
-
- except->stack_top = stack_top;
- except->scope = frame->scope;
- except->catch_off = arg1;
- except->ident = arg2;
- except->next = frame->except_frame;
- frame->except_frame = except;
- return S_OK;
-}
-
-/* ECMA-262 3rd Edition 12.14 */
-static HRESULT interp_pop_except(script_ctx_t *ctx)
-{
- call_frame_t *frame = ctx->call_ctx;
- except_frame_t *except;
-
- TRACE("\n");
-
- except = frame->except_frame;
- assert(except != NULL);
-
- frame->except_frame = except->next;
- heap_free(except);
+ 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,8 +965,30 @@
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 */
@@ -2626,13 +2655,71 @@
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;
- HRESULT hres;
+ 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 @@
}
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 @@
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;
-
+ 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 @@
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;
Modified: trunk/reactos/dll/win32/jscript/engine.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/engine.h…
==============================================================================
--- trunk/reactos/dll/win32/jscript/engine.h [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/jscript/engine.h [iso-8859-1] Sat Jun 3 22:28:19 2017
@@ -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) \
Modified: trunk/reactos/dll/win32/jscript/jscript.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/jscript/jscript.…
==============================================================================
--- trunk/reactos/dll/win32/jscript/jscript.h [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/jscript/jscript.h [iso-8859-1] Sat Jun 3 22:28:19 2017
@@ -68,19 +68,19 @@
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)
-{
- return HeapAlloc(GetProcessHeap(), 0, len);
-}
-
-static inline void *heap_alloc_zero(size_t len)
-{
- return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
-}
-
-static inline void *heap_realloc(void *mem, size_t len)
-{
- return HeapReAlloc(GetProcessHeap(), 0, mem, len);
+static inline void* __WINE_ALLOC_SIZE(1) heap_alloc(size_t size)
+{
+ return HeapAlloc(GetProcessHeap(), 0, size);
+}
+
+static inline void* __WINE_ALLOC_SIZE(1) heap_alloc_zero(size_t size)
+{
+ return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
+}
+
+static inline void* __WINE_ALLOC_SIZE(2) heap_realloc(void *mem, size_t size)
+{
+ return HeapReAlloc(GetProcessHeap(), 0, mem, size);
}
static inline BOOL heap_free(void *mem)
Modified: trunk/reactos/media/doc/README.WINE
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/media/doc/README.WINE?rev=…
==============================================================================
--- trunk/reactos/media/doc/README.WINE [iso-8859-1] (original)
+++ trunk/reactos/media/doc/README.WINE [iso-8859-1] Sat Jun 3 22:28:19 2017
@@ -85,7 +85,7 @@
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