jscript: Use locals map for local variables.
Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
2fc6720988
commit
2e06686ef9
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue