Jacek Caban : jscript: Always jump to finally block from OP_pop_exept when available.

Alexandre Julliard julliard at winehq.org
Mon May 1 16:38:05 CDT 2017


Module: wine
Branch: master
Commit: 60232cc770c12349465c032deecdbb4f18c54660
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=60232cc770c12349465c032deecdbb4f18c54660

Author: Jacek Caban <jacek at 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 at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at 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)                  \




More information about the wine-cvs mailing list