Jacek Caban : jscript: Store local functions in locals map.

Alexandre Julliard julliard at winehq.org
Thu Aug 4 17:20:18 CDT 2016


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

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Thu Aug  4 13:39:46 2016 +0200

jscript: Store local functions in locals map.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/jscript/compile.c   | 74 +++++++++++++++++++++++++++---------------------
 dlls/jscript/engine.c    | 15 ++++++++--
 dlls/jscript/engine.h    |  8 +++++-
 dlls/jscript/function.c  |  2 +-
 dlls/jscript/tests/run.c |  2 ++
 5 files changed, 64 insertions(+), 37 deletions(-)

diff --git a/dlls/jscript/compile.c b/dlls/jscript/compile.c
index 4dea4c7..e911373 100644
--- a/dlls/jscript/compile.c
+++ b/dlls/jscript/compile.c
@@ -1825,10 +1825,12 @@ static BOOL alloc_variable(compiler_ctx_t *ctx, const WCHAR *name)
     return alloc_local(ctx, ident, ctx->func->var_cnt++);
 }
 
-static void visit_function_expression(compiler_ctx_t *ctx, function_expression_t *expr)
+static BOOL visit_function_expression(compiler_ctx_t *ctx, function_expression_t *expr)
 {
     expr->func_id = ctx->func->func_cnt++;
     ctx->func_tail = ctx->func_tail ? (ctx->func_tail->next = expr) : (ctx->func_head = expr);
+
+    return !expr->identifier || expr->event_target || alloc_variable(ctx, expr->identifier);
 }
 
 static HRESULT visit_expression(compiler_ctx_t *ctx, expression_t *expr)
@@ -2234,6 +2236,18 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
     if(func_expr) {
         parameter_t *param_iter;
 
+        if(func_expr->identifier) {
+            func->name = compiler_alloc_bstr(ctx, func_expr->identifier);
+            if(!func->name)
+                return E_OUTOFMEMORY;
+        }
+
+        if(func_expr->event_target) {
+            func->event_target = compiler_alloc_bstr(ctx, func_expr->event_target);
+            if(!func->event_target)
+                return E_OUTOFMEMORY;
+        }
+
         func->source = func_expr->src_str;
         func->source_len = func_expr->src_len;
 
@@ -2260,36 +2274,6 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
     if(FAILED(hres))
         return hres;
 
-    off = ctx->code_off;
-    hres = compile_block_statement(ctx, source->statement);
-    if(FAILED(hres))
-        return hres;
-
-    resolve_labels(ctx, off);
-
-    hres = push_instr_uint(ctx, OP_ret, !from_eval);
-    if(FAILED(hres))
-        return hres;
-
-    if(TRACE_ON(jscript_disas))
-        dump_code(ctx, off);
-
-    func->instr_off = off;
-
-    if(func_expr) {
-        if(func_expr->identifier) {
-            func->name = compiler_alloc_bstr(ctx, func_expr->identifier);
-            if(!func->name)
-                return E_OUTOFMEMORY;
-        }
-
-        if(func_expr->event_target) {
-            func->event_target = compiler_alloc_bstr(ctx, func_expr->event_target);
-            if(!func->event_target)
-                return E_OUTOFMEMORY;
-        }
-    }
-
     func->locals = compiler_alloc(ctx->code, ctx->locals_cnt * sizeof(*func->locals));
     if(!func->locals)
         return E_OUTOFMEMORY;
@@ -2303,7 +2287,8 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
     for(i = 0, j = 0; i < func->locals_cnt; i++) {
         if(func->locals[i].ref < 0)
             continue; /* skip arguments */
-        func->variables[func->locals[i].ref] = func->locals[i].name;
+        func->variables[func->locals[i].ref].name = func->locals[i].name;
+        func->variables[func->locals[i].ref].func_id = -1;
         j++;
     }
 
@@ -2314,10 +2299,35 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
         return E_OUTOFMEMORY;
     memset(func->funcs, 0, func->func_cnt * sizeof(*func->funcs));
 
+    off = ctx->code_off;
+    hres = compile_block_statement(ctx, source->statement);
+    if(FAILED(hres))
+        return hres;
+
+    resolve_labels(ctx, off);
+
+    hres = push_instr_uint(ctx, OP_ret, !from_eval);
+    if(FAILED(hres))
+        return hres;
+
+    if(TRACE_ON(jscript_disas))
+        dump_code(ctx, off);
+
+    func->instr_off = off;
+
     for(iter = ctx->func_head, i=0; iter; iter = iter->next, i++) {
         hres = compile_function(ctx, iter->source_elements, iter, FALSE, func->funcs+i);
         if(FAILED(hres))
             return hres;
+
+        TRACE("[%d] func %s\n", i, debugstr_w(func->funcs[i].name));
+        if(func->funcs[i].name && !func->funcs[i].event_target) {
+            local_ref_t *local_ref = lookup_local(func, func->funcs[i].name);
+            func->funcs[i].local_ref = local_ref->ref;
+            TRACE("found ref %s %d for %s\n", debugstr_w(local_ref->name), local_ref->ref, debugstr_w(func->funcs[i].name));
+            if(local_ref->ref >= 0)
+                func->variables[local_ref->ref].func_id = i;
+        }
     }
 
     assert(i == func->func_cnt);
diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c
index 7861b77..bc8eb5b 100644
--- a/dlls/jscript/engine.c
+++ b/dlls/jscript/engine.c
@@ -600,6 +600,11 @@ static int local_ref_cmp(const void *key, const void *ref)
     return strcmpW((const WCHAR*)key, ((const local_ref_t*)ref)->name);
 }
 
+local_ref_t *lookup_local(const function_code_t *function, const WCHAR *identifier)
+{
+    return bsearch(identifier, function->locals, function->locals_cnt, sizeof(*function->locals), local_ref_cmp);
+}
+
 /* ECMA-262 3rd Edition    10.1.4 */
 static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
 {
@@ -614,7 +619,7 @@ static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *re
         for(scope = ctx->call_ctx->scope; scope; scope = scope->next) {
             if(scope->frame) {
                 function_code_t *func = scope->frame->function;
-                local_ref_t *ref = bsearch(identifier, func->locals, func->locals_cnt, sizeof(*func->locals), local_ref_cmp);
+                local_ref_t *ref = lookup_local(func, identifier);
                 static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0};
 
                 if(ref && ref->ref < 0) {
@@ -2779,10 +2784,14 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi
     }
 
     for(i=0; i < function->var_cnt; i++) {
-        if(!(flags & EXEC_GLOBAL) || !lookup_global_members(ctx, function->variables[i], NULL)) {
+        TRACE("[%d] %s %d\n", i, debugstr_w(function->variables[i].name), function->variables[i].func_id);
+        if(function->variables[i].func_id != -1)
+            continue;
+
+        if(!(flags & EXEC_GLOBAL) || !lookup_global_members(ctx, function->variables[i].name, NULL)) {
             DISPID id = 0;
 
-            hres = jsdisp_get_id(variable_obj, function->variables[i], fdexNameEnsure, &id);
+            hres = jsdisp_get_id(variable_obj, function->variables[i].name, fdexNameEnsure, &id);
             if(FAILED(hres))
                 return hres;
         }
diff --git a/dlls/jscript/engine.h b/dlls/jscript/engine.h
index 81be179..0434ff1 100644
--- a/dlls/jscript/engine.h
+++ b/dlls/jscript/engine.h
@@ -133,6 +133,7 @@ typedef struct {
 
 typedef struct _function_code_t {
     BSTR name;
+    int local_ref;
     BSTR event_target;
     unsigned instr_off;
 
@@ -143,7 +144,10 @@ typedef struct _function_code_t {
     struct _function_code_t *funcs;
 
     unsigned var_cnt;
-    BSTR *variables;
+    struct {
+        BSTR name;
+        int func_id; /* -1 if not a function */
+    } *variables;
 
     unsigned param_cnt;
     BSTR *params;
@@ -152,6 +156,8 @@ typedef struct _function_code_t {
     local_ref_t *locals;
 } function_code_t;
 
+local_ref_t *lookup_local(const function_code_t*,const WCHAR*) DECLSPEC_HIDDEN;
+
 typedef struct _bytecode_t {
     LONG ref;
 
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c
index 2475908..704d2ef 100644
--- a/dlls/jscript/function.c
+++ b/dlls/jscript/function.c
@@ -813,7 +813,7 @@ static HRESULT construct_function(script_ctx_t *ctx, unsigned argc, jsval_t *arg
     if(FAILED(hres))
         return hres;
 
-    if(code->global_code.func_cnt != 1 || code->global_code.var_cnt) {
+    if(code->global_code.func_cnt != 1 || code->global_code.var_cnt != 1) {
         ERR("Invalid parser result!\n");
         release_bytecode(code);
         return E_UNEXPECTED;
diff --git a/dlls/jscript/tests/run.c b/dlls/jscript/tests/run.c
index 0101f15..ff6edce 100644
--- a/dlls/jscript/tests/run.c
+++ b/dlls/jscript/tests/run.c
@@ -2530,6 +2530,8 @@ static BOOL run_tests(void)
     parse_script_a("eval('var testPropGet;');");
     CHECK_CALLED(global_propget_d);
 
+    parse_script_a("var testPropGet; function testPropGet() {}");
+
     SET_EXPECT(global_notexists_d);
     parse_script_a("var notExists; notExists = 1;");
     CHECK_CALLED(global_notexists_d);




More information about the wine-cvs mailing list