jscript: Store local functions in locals map.
Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
2e06686ef9
commit
713051d027
|
@ -1825,10 +1825,12 @@ static BOOL alloc_variable(compiler_ctx_t *ctx, const WCHAR *name)
|
||||||
return alloc_local(ctx, ident, ctx->func->var_cnt++);
|
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++;
|
expr->func_id = ctx->func->func_cnt++;
|
||||||
ctx->func_tail = ctx->func_tail ? (ctx->func_tail->next = expr) : (ctx->func_head = expr);
|
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)
|
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) {
|
if(func_expr) {
|
||||||
parameter_t *param_iter;
|
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 = func_expr->src_str;
|
||||||
func->source_len = func_expr->src_len;
|
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))
|
if(FAILED(hres))
|
||||||
return 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;
|
off = ctx->code_off;
|
||||||
hres = compile_block_statement(ctx, source->statement);
|
hres = compile_block_statement(ctx, source->statement);
|
||||||
if(FAILED(hres))
|
if(FAILED(hres))
|
||||||
|
@ -2276,48 +2315,19 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
|
||||||
|
|
||||||
func->instr_off = 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;
|
|
||||||
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++) {
|
for(iter = ctx->func_head, i=0; iter; iter = iter->next, i++) {
|
||||||
hres = compile_function(ctx, iter->source_elements, iter, FALSE, func->funcs+i);
|
hres = compile_function(ctx, iter->source_elements, iter, FALSE, func->funcs+i);
|
||||||
if(FAILED(hres))
|
if(FAILED(hres))
|
||||||
return 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);
|
assert(i == func->func_cnt);
|
||||||
|
|
|
@ -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);
|
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 */
|
/* ECMA-262 3rd Edition 10.1.4 */
|
||||||
static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
|
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) {
|
for(scope = ctx->call_ctx->scope; scope; scope = scope->next) {
|
||||||
if(scope->frame) {
|
if(scope->frame) {
|
||||||
function_code_t *func = scope->frame->function;
|
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};
|
static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0};
|
||||||
|
|
||||||
if(ref && ref->ref < 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++) {
|
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;
|
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))
|
if(FAILED(hres))
|
||||||
return hres;
|
return hres;
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,6 +133,7 @@ typedef struct {
|
||||||
|
|
||||||
typedef struct _function_code_t {
|
typedef struct _function_code_t {
|
||||||
BSTR name;
|
BSTR name;
|
||||||
|
int local_ref;
|
||||||
BSTR event_target;
|
BSTR event_target;
|
||||||
unsigned instr_off;
|
unsigned instr_off;
|
||||||
|
|
||||||
|
@ -143,7 +144,10 @@ typedef struct _function_code_t {
|
||||||
struct _function_code_t *funcs;
|
struct _function_code_t *funcs;
|
||||||
|
|
||||||
unsigned var_cnt;
|
unsigned var_cnt;
|
||||||
BSTR *variables;
|
struct {
|
||||||
|
BSTR name;
|
||||||
|
int func_id; /* -1 if not a function */
|
||||||
|
} *variables;
|
||||||
|
|
||||||
unsigned param_cnt;
|
unsigned param_cnt;
|
||||||
BSTR *params;
|
BSTR *params;
|
||||||
|
@ -152,6 +156,8 @@ typedef struct _function_code_t {
|
||||||
local_ref_t *locals;
|
local_ref_t *locals;
|
||||||
} function_code_t;
|
} function_code_t;
|
||||||
|
|
||||||
|
local_ref_t *lookup_local(const function_code_t*,const WCHAR*) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
typedef struct _bytecode_t {
|
typedef struct _bytecode_t {
|
||||||
LONG ref;
|
LONG ref;
|
||||||
|
|
||||||
|
|
|
@ -813,7 +813,7 @@ static HRESULT construct_function(script_ctx_t *ctx, unsigned argc, jsval_t *arg
|
||||||
if(FAILED(hres))
|
if(FAILED(hres))
|
||||||
return 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");
|
ERR("Invalid parser result!\n");
|
||||||
release_bytecode(code);
|
release_bytecode(code);
|
||||||
return E_UNEXPECTED;
|
return E_UNEXPECTED;
|
||||||
|
|
|
@ -2530,6 +2530,8 @@ static BOOL run_tests(void)
|
||||||
parse_script_a("eval('var testPropGet;');");
|
parse_script_a("eval('var testPropGet;');");
|
||||||
CHECK_CALLED(global_propget_d);
|
CHECK_CALLED(global_propget_d);
|
||||||
|
|
||||||
|
parse_script_a("var testPropGet; function testPropGet() {}");
|
||||||
|
|
||||||
SET_EXPECT(global_notexists_d);
|
SET_EXPECT(global_notexists_d);
|
||||||
parse_script_a("var notExists; notExists = 1;");
|
parse_script_a("var notExists; notExists = 1;");
|
||||||
CHECK_CALLED(global_notexists_d);
|
CHECK_CALLED(global_notexists_d);
|
||||||
|
|
Loading…
Reference in New Issue