jscript: Build local references map in compiler and use it to search the scope.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2016-08-03 16:27:35 +02:00 committed by Alexandre Julliard
parent 668fe2030d
commit b652a9787c
3 changed files with 96 additions and 28 deletions

View file

@ -54,6 +54,10 @@ typedef struct {
unsigned labels_size;
unsigned labels_cnt;
local_ref_t *locals_buf;
unsigned locals_buf_size;
unsigned locals_cnt;
statement_ctx_t *stat_ctx;
function_code_t *func;
@ -1782,6 +1786,46 @@ static HRESULT compile_statement(compiler_ctx_t *ctx, statement_ctx_t *stat_ctx,
return hres;
}
static int local_cmp(const void *key, const void *ref)
{
return strcmpW((const WCHAR*)key, ((const local_ref_t*)ref)->name);
}
static inline local_ref_t *find_local(compiler_ctx_t *ctx, BSTR name)
{
return bsearch(name, ctx->locals_buf, ctx->locals_cnt, sizeof(*ctx->locals_buf), local_cmp);
}
static BOOL alloc_local(compiler_ctx_t *ctx, BSTR name, int ref)
{
unsigned i;
if(!ctx->locals_buf_size) {
ctx->locals_buf = heap_alloc(4 * sizeof(*ctx->locals_buf));
if(!ctx->locals_buf)
return FALSE;
ctx->locals_buf_size = 4;
}else if(ctx->locals_buf_size == ctx->locals_cnt) {
local_ref_t *new_buf = heap_realloc(ctx->locals_buf, ctx->locals_buf_size * 2 * sizeof(*ctx->locals_buf));
if(!new_buf)
return FALSE;
ctx->locals_buf = new_buf;
ctx->locals_buf_size *= 2;
}
for(i = 0; i < ctx->locals_cnt; i++) {
if(strcmpW(ctx->locals_buf[i].name, name) > 0) {
memmove(ctx->locals_buf + i+1, ctx->locals_buf + i, (ctx->locals_cnt - i) * sizeof(*ctx->locals_buf));
break;
}
}
ctx->locals_buf[i].name = name;
ctx->locals_buf[i].ref = ref;
ctx->locals_cnt++;
return TRUE;
}
static void resolve_labels(compiler_ctx_t *ctx, unsigned off)
{
instr_t *instr;
@ -1856,9 +1900,35 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
ctx->var_head = ctx->var_tail = NULL;
ctx->func_head = ctx->func_tail = NULL;
ctx->from_eval = from_eval;
ctx->func = func;
ctx->locals_cnt = 0;
if(func_expr) {
parameter_t *param_iter;
func->source = func_expr->src_str;
func->source_len = func_expr->src_len;
for(param_iter = func_expr->parameter_list; param_iter; param_iter = param_iter->next)
func->param_cnt++;
func->params = compiler_alloc(ctx->code, func->param_cnt * sizeof(*func->params));
if(!func->params)
return E_OUTOFMEMORY;
for(param_iter = func_expr->parameter_list, i=0; param_iter; param_iter = param_iter->next, i++) {
func->params[i] = compiler_alloc_bstr(ctx, param_iter->identifier);
if(!func->params[i])
return E_OUTOFMEMORY;
}
}
for(i = 0; i < func->param_cnt; i++) {
if(!find_local(ctx, func->params[i]) && !alloc_local(ctx, func->params[i], -i-1))
return E_OUTOFMEMORY;
}
off = ctx->code_off;
ctx->func = func;
hres = compile_block_statement(ctx, source->statement);
if(FAILED(hres))
return hres;
@ -1888,26 +1958,6 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
}
}
if(func_expr) {
parameter_t *param_iter;
func->source = func_expr->src_str;
func->source_len = func_expr->src_len;
for(param_iter = func_expr->parameter_list; param_iter; param_iter = param_iter->next)
func->param_cnt++;
func->params = compiler_alloc(ctx->code, func->param_cnt * sizeof(*func->params));
if(!func->params)
return E_OUTOFMEMORY;
for(param_iter = func_expr->parameter_list, i=0; param_iter; param_iter = param_iter->next, i++) {
func->params[i] = compiler_alloc_bstr(ctx, param_iter->identifier);
if(!func->params[i])
return E_OUTOFMEMORY;
}
}
func->variables = compiler_alloc(ctx->code, func->var_cnt * sizeof(*func->variables));
if(!func->variables)
return E_OUTOFMEMORY;
@ -1920,6 +1970,12 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
assert(i == func->var_cnt);
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->funcs = compiler_alloc(ctx->code, func->func_cnt * sizeof(*func->funcs));
if(!func->funcs)
return E_OUTOFMEMORY;
@ -2038,6 +2094,7 @@ HRESULT compile_script(script_ctx_t *ctx, const WCHAR *code, const WCHAR *args,
hres = compile_function(&compiler, compiler.parser->source, NULL, from_eval, &compiler.code->global_code);
parser_release(compiler.parser);
heap_free(compiler.locals_buf);
if(FAILED(hres)) {
release_bytecode(compiler.code);
return hres;

View file

@ -589,6 +589,11 @@ static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t
return FALSE;
}
static int local_ref_cmp(const void *key, const void *ref)
{
return strcmpW((const WCHAR*)key, ((const local_ref_t*)ref)->name);
}
/* ECMA-262 3rd Edition 10.1.4 */
static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
{
@ -603,14 +608,12 @@ 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;
int i;
local_ref_t *ref = bsearch(identifier, func->locals, func->locals_cnt, sizeof(*func->locals), local_ref_cmp);
for(i = 0; i < func->param_cnt; i++) {
if(!strcmpW(identifier, func->params[i])) {
ret->type = EXPRVAL_STACK_REF;
ret->u.off = scope->frame->arguments_off+i;
return S_OK;
}
if(ref) {
ret->type = EXPRVAL_STACK_REF;
ret->u.off = scope->frame->arguments_off - ref->ref - 1;
return S_OK;
}
}
if(scope->jsobj)

View file

@ -126,6 +126,11 @@ typedef struct {
} u;
} instr_t;
typedef struct {
BSTR name;
int ref;
} local_ref_t;
typedef struct _function_code_t {
BSTR name;
BSTR event_target;
@ -142,6 +147,9 @@ typedef struct _function_code_t {
unsigned param_cnt;
BSTR *params;
unsigned locals_cnt;
local_ref_t *locals;
} function_code_t;
typedef struct _bytecode_t {