Module: wine Branch: master Commit: 60232cc770c12349465c032deecdbb4f18c54660 URL: http://source.winehq.org/git/wine.git/?a=commit;h=60232cc770c12349465c032dee...
Author: Jacek Caban jacek@codeweavers.com Date: Mon May 1 18:31:02 2017 +0200
jscript: Always jump to finally block from OP_pop_exept when available.
Signed-off-by: Jacek Caban jacek@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/jscript/compile.c | 45 +++++++++++++++++++++++++-------------------- dlls/jscript/engine.c | 50 +++++++++++++++++++++++++++++++------------------- dlls/jscript/engine.h | 6 +++--- 3 files changed, 59 insertions(+), 42 deletions(-)
diff --git a/dlls/jscript/compile.c b/dlls/jscript/compile.c index f9f70f0..61c4077 100644 --- a/dlls/jscript/compile.c +++ b/dlls/jscript/compile.c @@ -1399,8 +1399,9 @@ static HRESULT pop_to_stat(compiler_ctx_t *ctx, statement_ctx_t *stat_ctx) return hres; stack_pop = 0; } - if(!push_instr(ctx, OP_pop_except)) - return E_OUTOFMEMORY; + hres = push_instr_uint(ctx, OP_pop_except, ctx->code_off+1); + if(FAILED(hres)) + return hres; } stack_pop += iter->stack_use; } @@ -1688,9 +1689,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, finally_off = 0, catch_off = 0; + 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;
@@ -1706,24 +1706,19 @@ 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;
catch_off = ctx->code_off;
@@ -1738,21 +1733,31 @@ 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) { + /* + * 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, stat->catch_block ? NULL : &finally_ctx, stat->finally_statement); + 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; diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index d012d7c..c9e856c 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -901,28 +901,14 @@ static HRESULT interp_push_except(script_ctx_t *ctx) 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(!catch_off) { - 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 = catch_off; except->finally_off = finally_off; @@ -934,22 +920,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"); @@ -964,7 +969,9 @@ 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; }
@@ -2676,7 +2683,6 @@ static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres)
except_frame = frame->except_frame; catch_off = except_frame->catch_off; - frame->except_frame = except_frame->next;
assert(except_frame->stack_top <= ctx->stack_top); stack_popn(ctx, ctx->stack_top - except_frame->stack_top); @@ -2691,7 +2697,13 @@ static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres) ctx->ei.val = jsval_undefined(); clear_ei(ctx);
- heap_free(except_frame); + /* 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 { + frame->except_frame = except_frame->next; + heap_free(except_frame); + }
hres = stack_push(ctx, except_val); if(FAILED(hres)) diff --git a/dlls/jscript/engine.h b/dlls/jscript/engine.h index 4992061..121a2c2 100644 --- a/dlls/jscript/engine.h +++ b/dlls/jscript/engine.h @@ -34,7 +34,7 @@ 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) \ @@ -68,7 +68,7 @@ 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) \ @@ -88,7 +88,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) \