jscript: Use locals map for local variables.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
oldstable
Jacek Caban 2016-08-04 13:39:36 +02:00 committed by Alexandre Julliard
parent 2fc6720988
commit 2e06686ef9
3 changed files with 367 additions and 33 deletions

View File

@ -61,9 +61,6 @@ typedef struct {
statement_ctx_t *stat_ctx;
function_code_t *func;
variable_declaration_t *var_head;
variable_declaration_t *var_tail;
function_expression_t *func_head;
function_expression_t *func_tail;
} compiler_ctx_t;
@ -878,9 +875,7 @@ static HRESULT compile_object_literal(compiler_ctx_t *ctx, property_value_expres
static HRESULT compile_function_expression(compiler_ctx_t *ctx, function_expression_t *expr, BOOL emit_ret)
{
unsigned func_id = ctx->func->func_cnt++;
ctx->func_tail = ctx->func_tail ? (ctx->func_tail->next = expr) : (ctx->func_head = expr);
return emit_ret ? push_instr_uint(ctx, OP_func, func_id) : S_OK;
return emit_ret ? push_instr_uint(ctx, OP_func, expr->func_id) : S_OK;
}
static HRESULT compile_expression(compiler_ctx_t *ctx, expression_t *expr, BOOL emit_ret)
@ -1096,17 +1091,7 @@ static HRESULT compile_variable_list(compiler_ctx_t *ctx, variable_declaration_t
assert(list != NULL);
if(ctx->var_tail)
ctx->var_tail->global_next = list;
else
ctx->var_head = list;
for(iter = list; iter; iter = iter->next) {
ctx->func->var_cnt++;
iter->global_next = iter->next;
if(!iter->next)
ctx->var_tail = iter;
if(!iter->expr)
continue;
@ -1791,7 +1776,7 @@ 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)
static inline local_ref_t *find_local(compiler_ctx_t *ctx, const WCHAR *name)
{
return bsearch(name, ctx->locals_buf, ctx->locals_cnt, sizeof(*ctx->locals_buf), local_cmp);
}
@ -1826,6 +1811,351 @@ static BOOL alloc_local(compiler_ctx_t *ctx, BSTR name, int ref)
return TRUE;
}
static BOOL alloc_variable(compiler_ctx_t *ctx, const WCHAR *name)
{
BSTR ident;
if(find_local(ctx, name))
return TRUE;
ident = compiler_alloc_bstr(ctx, name);
if(!ident)
return FALSE;
return alloc_local(ctx, ident, ctx->func->var_cnt++);
}
static void 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);
}
static HRESULT visit_expression(compiler_ctx_t *ctx, expression_t *expr)
{
HRESULT hres = S_OK;
switch(expr->type) {
case EXPR_ADD:
case EXPR_AND:
case EXPR_ARRAY:
case EXPR_ASSIGN:
case EXPR_ASSIGNADD:
case EXPR_ASSIGNAND:
case EXPR_ASSIGNSUB:
case EXPR_ASSIGNMUL:
case EXPR_ASSIGNDIV:
case EXPR_ASSIGNMOD:
case EXPR_ASSIGNOR:
case EXPR_ASSIGNLSHIFT:
case EXPR_ASSIGNRSHIFT:
case EXPR_ASSIGNRRSHIFT:
case EXPR_ASSIGNXOR:
case EXPR_BAND:
case EXPR_BOR:
case EXPR_COMMA:
case EXPR_DIV:
case EXPR_EQ:
case EXPR_EQEQ:
case EXPR_GREATER:
case EXPR_GREATEREQ:
case EXPR_IN:
case EXPR_INSTANCEOF:
case EXPR_LESS:
case EXPR_LESSEQ:
case EXPR_LSHIFT:
case EXPR_MOD:
case EXPR_MUL:
case EXPR_NOTEQ:
case EXPR_NOTEQEQ:
case EXPR_OR:
case EXPR_RSHIFT:
case EXPR_RRSHIFT:
case EXPR_SUB:
case EXPR_BXOR: {
binary_expression_t *binary_expr = (binary_expression_t*)expr;
hres = visit_expression(ctx, binary_expr->expression1);
if(FAILED(hres))
return hres;
hres = visit_expression(ctx, binary_expr->expression2);
break;
}
case EXPR_BITNEG:
case EXPR_DELETE:
case EXPR_LOGNEG:
case EXPR_MINUS:
case EXPR_PLUS:
case EXPR_POSTDEC:
case EXPR_POSTINC:
case EXPR_PREDEC:
case EXPR_PREINC:
case EXPR_TYPEOF:
case EXPR_VOID:
hres = visit_expression(ctx, ((unary_expression_t*)expr)->expression);
break;
case EXPR_IDENT:
case EXPR_LITERAL:
case EXPR_THIS:
break;
case EXPR_ARRAYLIT: {
array_literal_expression_t *array_expr = (array_literal_expression_t*)expr;
array_element_t *iter;
for(iter = array_expr->element_list; iter; iter = iter->next) {
hres = visit_expression(ctx, iter->expr);
if(FAILED(hres))
return hres;
}
break;
}
case EXPR_CALL:
case EXPR_NEW: {
call_expression_t *call_expr = (call_expression_t*)expr;
argument_t *arg;
hres = visit_expression(ctx, call_expr->expression);
if(FAILED(hres))
return hres;
for(arg = call_expr->argument_list; arg; arg = arg->next) {
hres = visit_expression(ctx, arg->expr);
if(FAILED(hres))
return hres;
}
break;
}
case EXPR_COND: {
conditional_expression_t *cond_expr = (conditional_expression_t*)expr;
hres = visit_expression(ctx, cond_expr->expression);
if(FAILED(hres))
return hres;
hres = visit_expression(ctx, cond_expr->true_expression);
if(FAILED(hres))
return hres;
hres = visit_expression(ctx, cond_expr->false_expression);
break;
}
case EXPR_FUNC:
visit_function_expression(ctx, (function_expression_t*)expr);
break;
case EXPR_MEMBER:
hres = visit_expression(ctx, ((member_expression_t*)expr)->expression);
break;
case EXPR_PROPVAL: {
prop_val_t *iter;
for(iter = ((property_value_expression_t*)expr)->property_list; iter; iter = iter->next) {
hres = visit_expression(ctx, iter->value);
if(FAILED(hres))
return hres;
}
break;
}
DEFAULT_UNREACHABLE;
}
return hres;
}
static HRESULT visit_variable_list(compiler_ctx_t *ctx, variable_declaration_t *list)
{
variable_declaration_t *iter;
HRESULT hres;
for(iter = list; iter; iter = iter->next) {
if(!alloc_variable(ctx, iter->identifier))
return E_OUTOFMEMORY;
if(iter->expr) {
hres = visit_expression(ctx, iter->expr);
if(FAILED(hres))
return hres;
}
}
return S_OK;
}
static HRESULT visit_statement(compiler_ctx_t*,statement_t*);
static HRESULT visit_block_statement(compiler_ctx_t *ctx, statement_t *iter)
{
HRESULT hres;
while(iter) {
hres = visit_statement(ctx, iter);
if(FAILED(hres))
return hres;
iter = iter->next;
}
return S_OK;
}
static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat)
{
HRESULT hres = S_OK;
switch(stat->type) {
case STAT_BLOCK:
hres = visit_block_statement(ctx, ((block_statement_t*)stat)->stat_list);
break;
case STAT_BREAK:
case STAT_CONTINUE:
case STAT_EMPTY:
break;
case STAT_EXPR:
case STAT_RETURN:
case STAT_THROW: {
expression_statement_t *expr_stat = (expression_statement_t*)stat;
if(expr_stat->expr)
hres = visit_expression(ctx, expr_stat->expr);
break;
}
case STAT_FOR: {
for_statement_t *for_stat = (for_statement_t*)stat;
if(for_stat->variable_list)
hres = visit_variable_list(ctx, for_stat->variable_list);
else if(for_stat->begin_expr)
hres = visit_expression(ctx, for_stat->begin_expr);
if(FAILED(hres))
break;
if(for_stat->expr) {
hres = visit_expression(ctx, for_stat->expr);
if(FAILED(hres))
break;
}
hres = visit_statement(ctx, for_stat->statement);
if(FAILED(hres))
break;
if(for_stat->end_expr)
hres = visit_expression(ctx, for_stat->end_expr);
break;
}
case STAT_FORIN: {
forin_statement_t *forin_stat = (forin_statement_t*)stat;
if(forin_stat->variable) {
hres = visit_variable_list(ctx, forin_stat->variable);
if(FAILED(hres))
break;
}
hres = visit_expression(ctx, forin_stat->in_expr);
if(FAILED(hres))
return hres;
if(forin_stat->expr) {
hres = visit_expression(ctx, forin_stat->expr);
if(FAILED(hres))
return hres;
}
hres = visit_statement(ctx, forin_stat->statement);
break;
}
case STAT_IF: {
if_statement_t *if_stat = (if_statement_t*)stat;
hres = visit_expression(ctx, if_stat->expr);
if(FAILED(hres))
return hres;
hres = visit_statement(ctx, if_stat->if_stat);
if(FAILED(hres))
return hres;
if(if_stat->else_stat)
hres = visit_statement(ctx, if_stat->else_stat);
break;
}
case STAT_LABEL:
hres = visit_statement(ctx, ((labelled_statement_t*)stat)->statement);
break;
case STAT_SWITCH: {
switch_statement_t *switch_stat = (switch_statement_t*)stat;
statement_t *stat_iter;
case_clausule_t *iter;
hres = visit_expression(ctx, switch_stat->expr);
if(FAILED(hres))
return hres;
for(iter = switch_stat->case_list; iter; iter = iter->next) {
if(!iter->expr)
continue;
hres = visit_expression(ctx, iter->expr);
if(FAILED(hres))
return hres;
}
for(iter = switch_stat->case_list; iter; iter = iter->next) {
while(iter->next && iter->next->stat == iter->stat)
iter = iter->next;
for(stat_iter = iter->stat; stat_iter && (!iter->next || iter->next->stat != stat_iter);
stat_iter = stat_iter->next) {
hres = visit_statement(ctx, stat_iter);
if(FAILED(hres))
return hres;
}
}
break;
}
case STAT_TRY: {
try_statement_t *try_stat = (try_statement_t*)stat;
hres = visit_statement(ctx, try_stat->try_statement);
if(FAILED(hres))
return hres;
if(try_stat->catch_block) {
hres = visit_statement(ctx, try_stat->catch_block->statement);
if(FAILED(hres))
return hres;
}
if(try_stat->finally_statement)
hres = visit_statement(ctx, try_stat->finally_statement);
break;
}
case STAT_VAR:
hres = visit_variable_list(ctx, ((var_statement_t*)stat)->variable_list);
break;
case STAT_WHILE: {
while_statement_t *while_stat = (while_statement_t*)stat;
hres = visit_expression(ctx, while_stat->expr);
if(FAILED(hres))
return hres;
hres = visit_statement(ctx, while_stat->statement);
break;
}
case STAT_WITH: {
with_statement_t *with_stat = (with_statement_t*)stat;
hres = visit_expression(ctx, with_stat->expr);
if(FAILED(hres))
return hres;
hres = visit_statement(ctx, with_stat->statement);
break;
}
DEFAULT_UNREACHABLE;
}
return hres;
}
static void resolve_labels(compiler_ctx_t *ctx, unsigned off)
{
instr_t *instr;
@ -1890,14 +2220,12 @@ static HRESULT init_code(compiler_ctx_t *compiler, const WCHAR *source)
static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source, function_expression_t *func_expr,
BOOL from_eval, function_code_t *func)
{
variable_declaration_t *var_iter;
function_expression_t *iter;
unsigned off, i;
unsigned off, i, j;
HRESULT hres;
TRACE("\n");
ctx->var_head = ctx->var_tail = NULL;
ctx->func_head = ctx->func_tail = NULL;
ctx->from_eval = from_eval;
ctx->func = func;
@ -1928,6 +2256,10 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
return E_OUTOFMEMORY;
}
hres = visit_block_statement(ctx, source->statement);
if(FAILED(hres))
return hres;
off = ctx->code_off;
hres = compile_block_statement(ctx, source->statement);
if(FAILED(hres))
@ -1958,24 +2290,25 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
}
}
func->variables = compiler_alloc(ctx->code, func->var_cnt * sizeof(*func->variables));
if(!func->variables)
return E_OUTOFMEMORY;
for(var_iter = ctx->var_head, i=0; var_iter; var_iter = var_iter->global_next, i++) {
func->variables[i] = compiler_alloc_bstr(ctx, var_iter->identifier);
if(!func->variables[i])
return E_OUTOFMEMORY;
}
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->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;

View File

@ -617,7 +617,7 @@ static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *re
local_ref_t *ref = bsearch(identifier, func->locals, func->locals_cnt, sizeof(*func->locals), local_ref_cmp);
static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0};
if(ref) {
if(ref && ref->ref < 0) {
ret->type = EXPRVAL_STACK_REF;
ret->u.off = scope->frame->arguments_off - ref->ref - 1;
return S_OK;

View File

@ -294,6 +294,7 @@ typedef struct _function_expression_t {
source_elements_t *source_elements;
const WCHAR *src_str;
DWORD src_len;
unsigned func_id;
struct _function_expression_t *next; /* for compiler */
} function_expression_t;