Jacek Caban : jscript: Use bytecode for assignment to identifier.

Alexandre Julliard julliard at winehq.org
Mon Dec 5 14:55:01 CST 2011


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

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Mon Dec  5 11:11:29 2011 +0100

jscript: Use bytecode for assignment to identifier.

---

 dlls/jscript/compile.c     |   35 ++++++++++++++++++++-
 dlls/jscript/engine.c      |   72 ++++++++++++++++++++++++++++++++++++++++++++
 dlls/jscript/engine.h      |    4 ++-
 dlls/jscript/parser.y      |    2 +-
 dlls/jscript/tests/api.js  |    4 ++
 dlls/jscript/tests/lang.js |    3 ++
 6 files changed, 116 insertions(+), 4 deletions(-)

diff --git a/dlls/jscript/compile.c b/dlls/jscript/compile.c
index ed42b4d..3679dfe 100644
--- a/dlls/jscript/compile.c
+++ b/dlls/jscript/compile.c
@@ -345,6 +345,35 @@ static HRESULT compile_delete_expression(compiler_ctx_t *ctx, unary_expression_t
     return S_OK;
 }
 
+static HRESULT compile_assign_expression(compiler_ctx_t *ctx, binary_expression_t *expr)
+{
+    HRESULT hres;
+
+    switch(expr->expression1->type) {
+    case EXPR_IDENT: {
+        identifier_expression_t *ident_expr = (identifier_expression_t*)expr->expression1;
+
+        hres = push_instr_bstr(ctx, OP_identid, ident_expr->identifier);
+        if(FAILED(hres))
+            return hres;
+        break;
+    }
+    default:
+        expr->expr.eval = assign_expression_eval;
+        return compile_interp_fallback(ctx, &expr->expr);
+    }
+
+
+    hres = compile_expression(ctx, expr->expression2);
+    if(FAILED(hres))
+        return hres;
+
+    if(push_instr(ctx, OP_assign) == -1)
+        return E_OUTOFMEMORY;
+
+    return S_OK;
+}
+
 static HRESULT compile_literal(compiler_ctx_t *ctx, literal_t *literal)
 {
     switch(literal->type) {
@@ -384,10 +413,12 @@ static HRESULT compile_literal(compiler_ctx_t *ctx, literal_t *literal)
 static HRESULT compile_expression(compiler_ctx_t *ctx, expression_t *expr)
 {
     switch(expr->type) {
-    case EXPR_AND:
-        return compile_logical_expression(ctx, (binary_expression_t*)expr, OP_jmp_z);
     case EXPR_ADD:
         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_add);
+    case EXPR_AND:
+        return compile_logical_expression(ctx, (binary_expression_t*)expr, OP_jmp_z);
+    case EXPR_ASSIGN:
+        return compile_assign_expression(ctx, (binary_expression_t*)expr);
     case EXPR_BITNEG:
         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_bneg);
     case EXPR_BOR:
diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c
index d24392c..c445eab 100644
--- a/dlls/jscript/engine.c
+++ b/dlls/jscript/engine.c
@@ -102,6 +102,22 @@ static inline HRESULT stack_push_int(exec_ctx_t *ctx, INT n)
     return stack_push(ctx, &v);
 }
 
+static HRESULT stack_push_objid(exec_ctx_t *ctx, IDispatch *disp, DISPID id)
+{
+    VARIANT v;
+    HRESULT hres;
+
+    V_VT(&v) = VT_DISPATCH;
+    V_DISPATCH(&v) = disp;
+    hres = stack_push(ctx, &v);
+    if(FAILED(hres))
+        return hres;
+
+    V_VT(&v) = VT_INT;
+    V_INT(&v) = id;
+    return stack_push(ctx, &v);
+}
+
 static inline VARIANT *stack_top(exec_ctx_t *ctx)
 {
     assert(ctx->top);
@@ -142,6 +158,14 @@ static inline HRESULT stack_pop_int(exec_ctx_t *ctx, INT *r)
     return to_int32(ctx->parser->script, stack_pop(ctx), &ctx->ei, r);
 }
 
+static inline IDispatch *stack_pop_objid(exec_ctx_t *ctx, DISPID *id)
+{
+    assert(V_VT(stack_top(ctx)) == VT_INT && V_VT(stack_topn(ctx, 1)) == VT_DISPATCH);
+
+    *id = V_INT(stack_pop(ctx));
+    return V_DISPATCH(stack_pop(ctx));
+}
+
 static void exprval_release(exprval_t *val)
 {
     switch(val->type) {
@@ -1757,6 +1781,28 @@ static HRESULT interp_ident(exec_ctx_t *ctx)
     return stack_push(ctx, &v);
 }
 
+/* ECMA-262 3rd Edition    10.1.4 */
+static HRESULT interp_identid(exec_ctx_t *ctx)
+{
+    const BSTR arg = ctx->parser->code->instrs[ctx->ip].arg1.bstr;
+    exprval_t exprval;
+    HRESULT hres;
+
+    TRACE("%s\n", debugstr_w(arg));
+
+    hres = identifier_eval(ctx->parser->script, arg, EXPR_NEWREF, &ctx->ei, &exprval);
+    if(FAILED(hres))
+        return hres;
+
+    if(exprval.type != EXPRVAL_IDREF) {
+        WARN("invalid ref\n");
+        exprval_release(&exprval);
+        return stack_push_objid(ctx, NULL, -1);
+    }
+
+    return stack_push_objid(ctx, exprval.u.idref.disp, exprval.u.idref.id);
+}
+
 /* ECMA-262 3rd Edition    7.8.1 */
 static HRESULT interp_null(exec_ctx_t *ctx)
 {
@@ -3261,6 +3307,32 @@ HRESULT assign_expression_eval(script_ctx_t *ctx, expression_t *_expr, DWORD fla
     return S_OK;
 }
 
+/* ECMA-262 3rd Edition    11.13.1 */
+static HRESULT interp_assign(exec_ctx_t *ctx)
+{
+    IDispatch *disp;
+    DISPID id;
+    VARIANT *v;
+    HRESULT hres;
+
+    TRACE("\n");
+
+    v = stack_pop(ctx);
+    disp = stack_pop_objid(ctx, &id);
+
+    if(!disp)
+        return throw_reference_error(ctx->parser->script, &ctx->ei, JS_E_ILLEGAL_ASSIGN, NULL);
+
+    hres = disp_propput(ctx->parser->script, disp, id, v, &ctx->ei, NULL/*FIXME*/);
+    IDispatch_Release(disp);
+    if(FAILED(hres)) {
+        VariantClear(v);
+        return hres;
+    }
+
+    return stack_push(ctx, v);
+}
+
 /* ECMA-262 3rd Edition    11.13.2 */
 HRESULT assign_lshift_expression_eval(script_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
 {
diff --git a/dlls/jscript/engine.h b/dlls/jscript/engine.h
index e86db0f..12329e8 100644
--- a/dlls/jscript/engine.h
+++ b/dlls/jscript/engine.h
@@ -43,6 +43,7 @@ typedef struct _func_stack {
 
 #define OP_LIST                            \
     X(add,        1, 0,0)                  \
+    X(assign,     1, 0,0)                  \
     X(bool,       1, ARG_INT,    0)        \
     X(bneg,       1, 0,0)                  \
     X(delete,     1, 0,0)                  \
@@ -51,8 +52,9 @@ typedef struct _func_stack {
     X(eq,         1, 0,0)                  \
     X(eq2,        1, 0,0)                  \
     X(gt,         1, 0,0)                  \
-    X(gteq,         1, 0,0)                \
+    X(gteq,       1, 0,0)                  \
     X(ident,      1, ARG_BSTR,   0)        \
+    X(identid,    1, ARG_BSTR,   0)        \
     X(in,         1, 0,0)                  \
     X(int,        1, ARG_INT,    0)        \
     X(jmp,        0, ARG_ADDR,   0)        \
diff --git a/dlls/jscript/parser.y b/dlls/jscript/parser.y
index c1c5df6..55f8aac 100644
--- a/dlls/jscript/parser.y
+++ b/dlls/jscript/parser.y
@@ -1340,7 +1340,7 @@ static const expression_eval_t expression_eval_table[] = {
    left_shift_expression_eval,
    right_shift_expression_eval,
    right2_shift_expression_eval,
-   assign_expression_eval,
+   compiled_expression_eval,
    assign_lshift_expression_eval,
    assign_rshift_expression_eval,
    assign_rrshift_expression_eval,
diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js
index d99364f..b5ac66a 100644
--- a/dlls/jscript/tests/api.js
+++ b/dlls/jscript/tests/api.js
@@ -2072,6 +2072,10 @@ testSyntaxError("/* @cc_on @*/ @_jscript_version", "E_DISABLED_CC");
 // ReferenceError tests
 testException(function() {test = function() {}}, "E_ILLEGAL_ASSIGN");
 
+tmp = false;
+testException(function() {test = (tmp = true);}, "E_ILLEGAL_ASSIGN");
+ok(tmp, "expr value on invalid assign not evaluated");
+
 // RegExpError tests
 testException(function() {RegExp(/a/, "g");}, "E_REGEXP_SYNTAX_ERROR");
 
diff --git a/dlls/jscript/tests/lang.js b/dlls/jscript/tests/lang.js
index 4f3d509..1dd0c02 100644
--- a/dlls/jscript/tests/lang.js
+++ b/dlls/jscript/tests/lang.js
@@ -118,6 +118,9 @@ ok(testFunc1(true, "test") === true, "testFunc1 not returned true");
 
 ok(testFunc1.arguments === null, "testFunc1.arguments = " + testFunc1.arguments);
 
+(tmp) = 3;
+ok(tmp === 3, "tmp = " + tmp);
+
 function testRecFunc(x) {
     ok(testRecFunc.arguments === arguments, "testRecFunc.arguments = " + testRecFunc.arguments);
     if(x) {




More information about the wine-cvs mailing list