From 713051d027cd554cdc3a3ead077245b1ac3ca514 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Thu, 4 Aug 2016 13:39:46 +0200 Subject: [PATCH] jscript: Store local functions in locals map. Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard --- dlls/jscript/compile.c | 88 ++++++++++++++++++++++------------------ dlls/jscript/engine.c | 15 +++++-- dlls/jscript/engine.h | 8 +++- dlls/jscript/function.c | 2 +- dlls/jscript/tests/run.c | 2 + 5 files changed, 71 insertions(+), 44 deletions(-) diff --git a/dlls/jscript/compile.c b/dlls/jscript/compile.c index 4dea4c79ef0..e911373f8d1 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,6 +2274,31 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source, if(FAILED(hres)) return hres; + func->locals = compiler_alloc(ctx->code, ctx->locals_cnt * sizeof(*func->locals)); + if(!func->locals) + return E_OUTOFMEMORY; + func->locals_cnt = ctx->locals_cnt; + memcpy(func->locals, ctx->locals_buf, func->locals_cnt * sizeof(*func->locals)); + + func->variables = compiler_alloc(ctx->code, func->var_cnt * sizeof(*func->variables)); + if(!func->variables) + return E_OUTOFMEMORY; + + 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].name = func->locals[i].name; + func->variables[func->locals[i].ref].func_id = -1; + j++; + } + + assert(j == func->var_cnt); + + func->funcs = compiler_alloc(ctx->code, func->func_cnt * sizeof(*func->funcs)); + if(!func->funcs) + 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)) @@ -2276,48 +2315,19 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source, 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; - func->locals_cnt = ctx->locals_cnt; - memcpy(func->locals, ctx->locals_buf, func->locals_cnt * sizeof(*func->locals)); - - func->variables = compiler_alloc(ctx->code, func->var_cnt * sizeof(*func->variables)); - if(!func->variables) - return E_OUTOFMEMORY; - - 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; - j++; - } - - assert(j == func->var_cnt); - - func->funcs = compiler_alloc(ctx->code, func->func_cnt * sizeof(*func->funcs)); - if(!func->funcs) - return E_OUTOFMEMORY; - memset(func->funcs, 0, func->func_cnt * sizeof(*func->funcs)); - 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 7861b77de4b..bc8eb5bb233 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 81be179f36b..0434ff14fae 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 247590846a5..704d2efe41b 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 0101f15f470..ff6edceace5 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);