Jacek Caban : jscript: Added bytecode version of switch statement.

Alexandre Julliard julliard at winehq.org
Tue Dec 27 11:27:56 CST 2011


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

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Tue Dec 27 11:16:40 2011 +0100

jscript: Added bytecode version of switch statement.

---

 dlls/jscript/compile.c |  104 ++++++++++++++++++++++++++++++++++++++++++++++++
 dlls/jscript/engine.c  |   25 +++++++++++
 dlls/jscript/engine.h  |    1 +
 dlls/jscript/parser.y  |    2 +-
 4 files changed, 131 insertions(+), 1 deletions(-)

diff --git a/dlls/jscript/compile.c b/dlls/jscript/compile.c
index c2179d3..e54c16a 100644
--- a/dlls/jscript/compile.c
+++ b/dlls/jscript/compile.c
@@ -1131,6 +1131,108 @@ static HRESULT compile_with_statement(compiler_ctx_t *ctx, with_statement_t *sta
     return S_OK;
 }
 
+/* ECMA-262 3rd Edition    12.13 */
+static HRESULT compile_switch_statement(compiler_ctx_t *ctx, switch_statement_t *stat)
+{
+    unsigned case_cnt = 0, *case_jmps, i, default_jmp;
+    BOOL have_default = FALSE;
+    statement_t *stat_iter;
+    case_clausule_t *iter;
+    unsigned off_backup;
+    BOOL prev_no_fallback;
+    HRESULT hres;
+
+    off_backup = ctx->code_off;
+
+    hres = compile_expression(ctx, stat->expr);
+    if(FAILED(hres))
+        return hres;
+
+    for(iter = stat->case_list; iter; iter = iter->next) {
+        if(iter->expr)
+            case_cnt++;
+    }
+
+    case_jmps = heap_alloc(case_cnt * sizeof(*case_jmps));
+    if(!case_jmps)
+        return E_OUTOFMEMORY;
+
+    i = 0;
+    for(iter = stat->case_list; iter; iter = iter->next) {
+        if(!iter->expr) {
+            have_default = TRUE;
+            continue;
+        }
+
+        hres = compile_expression(ctx, iter->expr);
+        if(FAILED(hres))
+            break;
+
+        case_jmps[i] = push_instr(ctx, OP_case);
+        if(case_jmps[i] == -1) {
+            hres = E_OUTOFMEMORY;
+            break;
+        }
+        i++;
+    }
+
+    if(SUCCEEDED(hres)) {
+        if(push_instr(ctx, OP_pop) != -1) {
+            default_jmp = push_instr(ctx, OP_jmp);
+            if(default_jmp == -1)
+                hres = E_OUTOFMEMORY;
+        }else {
+            hres = E_OUTOFMEMORY;
+        }
+    }
+
+    if(FAILED(hres)) {
+        heap_free(case_jmps);
+        return hres;
+    }
+
+    i = 0;
+    for(iter = stat->case_list; iter; iter = iter->next) {
+        while(iter->next && iter->next->stat == iter->stat) {
+            instr_ptr(ctx, iter->expr ? case_jmps[i++] : default_jmp)->arg1.uint = ctx->code_off;
+            iter = iter->next;
+        }
+
+        instr_ptr(ctx, iter->expr ? case_jmps[i++] : default_jmp)->arg1.uint = ctx->code_off;
+
+        for(stat_iter = iter->stat; stat_iter && (!iter->next || iter->next->stat != stat_iter); stat_iter = stat_iter->next) {
+            prev_no_fallback = ctx->no_fallback;
+            ctx->no_fallback = TRUE;
+            hres = compile_statement(ctx, stat_iter);
+            ctx->no_fallback = prev_no_fallback;
+            if(hres == E_NOTIMPL) {
+                ctx->code_off = off_backup;
+                stat->stat.eval = switch_statement_eval;
+                return compile_interp_fallback(ctx, &stat->stat);
+            }
+            if(FAILED(hres))
+                break;
+
+            if(stat_iter->next && push_instr(ctx, OP_pop) == -1) {
+                hres = E_OUTOFMEMORY;
+                break;
+            }
+        }
+        if(FAILED(hres))
+            break;
+    }
+
+    heap_free(case_jmps);
+    if(FAILED(hres))
+        return hres;
+    assert(i == case_cnt);
+
+    if(!have_default)
+        instr_ptr(ctx, default_jmp)->arg1.uint = ctx->code_off;
+
+    return S_OK;
+}
+
 static HRESULT compile_statement(compiler_ctx_t *ctx, statement_t *stat)
 {
     switch(stat->type) {
@@ -1144,6 +1246,8 @@ static HRESULT compile_statement(compiler_ctx_t *ctx, statement_t *stat)
         return compile_for_statement(ctx, (for_statement_t*)stat);
     case STAT_IF:
         return compile_if_statement(ctx, (if_statement_t*)stat);
+    case STAT_SWITCH:
+        return compile_switch_statement(ctx, (switch_statement_t*)stat);
     case STAT_VAR:
         return compile_var_statement(ctx, (var_statement_t*)stat);
     case STAT_WHILE:
diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c
index af15a94..99c492f 100644
--- a/dlls/jscript/engine.c
+++ b/dlls/jscript/engine.c
@@ -1074,6 +1074,31 @@ HRESULT labelled_statement_eval(script_ctx_t *ctx, statement_t *stat, return_typ
 }
 
 /* ECMA-262 3rd Edition    12.13 */
+static HRESULT interp_case(exec_ctx_t *ctx)
+{
+    const unsigned arg = ctx->parser->code->instrs[ctx->ip].arg1.uint;
+    VARIANT *v;
+    BOOL b;
+    HRESULT hres;
+
+    TRACE("\n");
+
+    v = stack_pop(ctx);
+    hres = equal2_values(stack_top(ctx), v, &b);
+    VariantClear(v);
+    if(FAILED(hres))
+        return hres;
+
+    if(b) {
+        stack_popn(ctx, 1);
+        ctx->ip = arg;
+    }else {
+        ctx->ip++;
+    }
+    return S_OK;
+}
+
+/* ECMA-262 3rd Edition    12.13 */
 HRESULT switch_statement_eval(script_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
 {
     switch_statement_t *stat = (switch_statement_t*)_stat;
diff --git a/dlls/jscript/engine.h b/dlls/jscript/engine.h
index 1ca6630..263548e 100644
--- a/dlls/jscript/engine.h
+++ b/dlls/jscript/engine.h
@@ -52,6 +52,7 @@ typedef struct _func_stack {
     X(call,       1, ARG_UINT,   ARG_UINT) \
     X(call_member,1, ARG_UINT,   ARG_UINT) \
     X(carray,     1, ARG_UINT,   0)        \
+    X(case,       0, ARG_ADDR,   0)        \
     X(cnd_nz,     0, ARG_ADDR,   0)        \
     X(cnd_z,      0, ARG_ADDR,   0)        \
     X(delete,     1, 0,0)                  \
diff --git a/dlls/jscript/parser.y b/dlls/jscript/parser.y
index 578ae23..aaec649 100644
--- a/dlls/jscript/parser.y
+++ b/dlls/jscript/parser.y
@@ -846,7 +846,7 @@ static const statement_eval_t stat_eval_table[] = {
     compiled_statement_eval,
     labelled_statement_eval,
     return_statement_eval,
-    switch_statement_eval,
+    compiled_statement_eval,
     throw_statement_eval,
     try_statement_eval,
     compiled_statement_eval,




More information about the wine-cvs mailing list