jscript: Enumerate with and block scopes.

Signed-off-by: Paul Gofman <pgofman@codeweavers.com>
Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Paul Gofman 2021-06-18 15:50:17 +03:00 committed by Alexandre Julliard
parent 2a368c45ae
commit a35901137e
3 changed files with 113 additions and 25 deletions

View File

@ -39,6 +39,8 @@ typedef struct _statement_ctx_t {
const labelled_statement_t *labelled_stat;
unsigned int scope_index;
BOOL block_scope;
struct _statement_ctx_t *next;
} statement_ctx_t;
@ -61,6 +63,14 @@ typedef struct _compiler_ctx_t {
unsigned labels_size;
unsigned labels_cnt;
struct
{
unsigned int locals_cnt;
unsigned int *ref_index;
}
*local_scopes;
unsigned local_scope_count;
unsigned local_scope_size;
struct wine_rb_tree locals;
unsigned locals_cnt;
@ -127,6 +137,42 @@ static void dump_code(compiler_ctx_t *ctx, unsigned off)
static HRESULT compile_expression(compiler_ctx_t*,expression_t*,BOOL);
static HRESULT compile_statement(compiler_ctx_t*,statement_ctx_t*,statement_t*);
static BOOL alloc_local_scope(compiler_ctx_t *ctx, unsigned int *scope_index)
{
unsigned int scope, new_size;
void *new_alloc;
scope = ctx->local_scope_count++;
if (scope == ctx->local_scope_size)
{
new_size = max(1, ctx->local_scope_size * 2);
if (!(new_alloc = heap_realloc(ctx->local_scopes, new_size * sizeof(*ctx->local_scopes))))
return FALSE;
ctx->local_scopes = new_alloc;
ctx->local_scope_size = new_size;
}
ctx->local_scopes[scope].locals_cnt = 0;
ctx->local_scopes[scope].ref_index = scope_index;
*scope_index = scope;
return TRUE;
}
static void remove_local_scope(compiler_ctx_t *ctx, unsigned int scope_index)
{
unsigned int i;
assert(scope_index < ctx->local_scope_count);
--ctx->local_scope_count;
assert(scope_index == *ctx->local_scopes[scope_index].ref_index);
*ctx->local_scopes[scope_index].ref_index = 0;
memmove(&ctx->local_scopes[scope_index], &ctx->local_scopes[scope_index + 1],
sizeof(*ctx->local_scopes) * (ctx->local_scope_count - scope_index));
for (i = scope_index; i < ctx->local_scope_count; ++i)
--*ctx->local_scopes[i].ref_index;
}
static inline void *compiler_alloc(bytecode_t *code, size_t size)
{
return heap_pool_alloc(&code->heap, size);
@ -1858,7 +1904,7 @@ static inline function_local_t *find_local(compiler_ctx_t *ctx, const WCHAR *nam
return entry ? WINE_RB_ENTRY_VALUE(entry, function_local_t, entry) : NULL;
}
static BOOL alloc_local(compiler_ctx_t *ctx, BSTR name, int ref)
static BOOL alloc_local(compiler_ctx_t *ctx, BSTR name, int ref, unsigned int scope)
{
function_local_t *local;
@ -1870,10 +1916,11 @@ static BOOL alloc_local(compiler_ctx_t *ctx, BSTR name, int ref)
local->ref = ref;
wine_rb_put(&ctx->locals, name, &local->entry);
ctx->locals_cnt++;
ctx->local_scopes[scope].locals_cnt++;
return TRUE;
}
static BOOL alloc_variable(compiler_ctx_t *ctx, const WCHAR *name)
static BOOL alloc_variable(compiler_ctx_t *ctx, const WCHAR *name, unsigned int scope)
{
BSTR ident;
@ -1884,7 +1931,7 @@ static BOOL alloc_variable(compiler_ctx_t *ctx, const WCHAR *name)
if(!ident)
return FALSE;
return alloc_local(ctx, ident, ctx->func->var_cnt++);
return alloc_local(ctx, ident, ctx->func->var_cnt++, scope);
}
static HRESULT visit_function_expression(compiler_ctx_t *ctx, function_expression_t *expr)
@ -1897,7 +1944,7 @@ static HRESULT visit_function_expression(compiler_ctx_t *ctx, function_expressio
if(!expr->is_statement && ctx->parser->script->version >= SCRIPTLANGUAGEVERSION_ES5)
return S_OK;
return alloc_variable(ctx, expr->identifier) ? S_OK : E_OUTOFMEMORY;
return alloc_variable(ctx, expr->identifier, 0) ? S_OK : E_OUTOFMEMORY;
}
static HRESULT visit_expression(compiler_ctx_t *ctx, expression_t *expr)
@ -2033,11 +2080,18 @@ static HRESULT visit_expression(compiler_ctx_t *ctx, expression_t *expr)
static HRESULT visit_variable_list(compiler_ctx_t *ctx, variable_declaration_t *list)
{
variable_declaration_t *iter;
statement_ctx_t *stat_ctx;
HRESULT hres;
for(iter = list; iter; iter = iter->next) {
if(!alloc_variable(ctx, iter->identifier))
return E_OUTOFMEMORY;
for (stat_ctx = ctx->stat_ctx; stat_ctx; stat_ctx = stat_ctx->next)
{
if (stat_ctx->block_scope)
break;
}
if(!alloc_variable(ctx, iter->identifier, iter->block_scope && stat_ctx ? stat_ctx->scope_index : 0))
return E_OUTOFMEMORY;
if(iter->expr) {
hres = visit_expression(ctx, iter->expr);
@ -2049,30 +2103,51 @@ static HRESULT visit_variable_list(compiler_ctx_t *ctx, variable_declaration_t *
return S_OK;
}
static HRESULT visit_statement(compiler_ctx_t*,statement_t*);
static HRESULT visit_statement(compiler_ctx_t*,statement_ctx_t *,statement_t*);
static HRESULT visit_block_statement(compiler_ctx_t *ctx, statement_t *iter)
static HRESULT visit_block_statement(compiler_ctx_t *ctx, block_statement_t *block, statement_t *iter)
{
statement_ctx_t stat_ctx = {0, TRUE};
BOOL needs_scope;
HRESULT hres;
needs_scope = block && ctx->parser->script->version >= SCRIPTLANGUAGEVERSION_ES5;
if (needs_scope)
{
if (!alloc_local_scope(ctx, &block->scope_index))
return E_OUTOFMEMORY;
stat_ctx.scope_index = block->scope_index;
stat_ctx.block_scope = TRUE;
}
while(iter) {
hres = visit_statement(ctx, iter);
hres = visit_statement(ctx, needs_scope ? &stat_ctx : NULL, iter);
if(FAILED(hres))
return hres;
iter = iter->next;
}
if (needs_scope && !ctx->local_scopes[stat_ctx.scope_index].locals_cnt)
remove_local_scope(ctx, block->scope_index);
return S_OK;
}
static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat)
static HRESULT visit_statement(compiler_ctx_t *ctx, statement_ctx_t *stat_ctx, statement_t *stat)
{
HRESULT hres = S_OK;
if(stat_ctx)
{
stat_ctx->next = ctx->stat_ctx;
ctx->stat_ctx = stat_ctx;
}
switch(stat->type) {
case STAT_BLOCK:
hres = visit_block_statement(ctx, ((block_statement_t*)stat)->stat_list);
hres = visit_block_statement(ctx, (block_statement_t*)stat, ((block_statement_t*)stat)->stat_list);
break;
case STAT_BREAK:
case STAT_CONTINUE:
@ -2110,7 +2185,7 @@ static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat)
break;
}
hres = visit_statement(ctx, for_stat->statement);
hres = visit_statement(ctx, NULL, for_stat->statement);
if(FAILED(hres))
break;
@ -2137,7 +2212,7 @@ static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat)
return hres;
}
hres = visit_statement(ctx, forin_stat->statement);
hres = visit_statement(ctx, NULL, forin_stat->statement);
break;
}
case STAT_IF: {
@ -2147,16 +2222,16 @@ static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat)
if(FAILED(hres))
return hres;
hres = visit_statement(ctx, if_stat->if_stat);
hres = visit_statement(ctx, NULL, if_stat->if_stat);
if(FAILED(hres))
return hres;
if(if_stat->else_stat)
hres = visit_statement(ctx, if_stat->else_stat);
hres = visit_statement(ctx, NULL, if_stat->else_stat);
break;
}
case STAT_LABEL:
hres = visit_statement(ctx, ((labelled_statement_t*)stat)->statement);
hres = visit_statement(ctx, NULL, ((labelled_statement_t*)stat)->statement);
break;
case STAT_SWITCH: {
switch_statement_t *switch_stat = (switch_statement_t*)stat;
@ -2180,7 +2255,7 @@ static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *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);
hres = visit_statement(ctx, NULL, stat_iter);
if(FAILED(hres))
return hres;
}
@ -2190,18 +2265,18 @@ static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat)
case STAT_TRY: {
try_statement_t *try_stat = (try_statement_t*)stat;
hres = visit_statement(ctx, try_stat->try_statement);
hres = visit_statement(ctx, NULL, try_stat->try_statement);
if(FAILED(hres))
return hres;
if(try_stat->catch_block) {
hres = visit_statement(ctx, try_stat->catch_block->statement);
hres = visit_statement(ctx, NULL, try_stat->catch_block->statement);
if(FAILED(hres))
return hres;
}
if(try_stat->finally_statement)
hres = visit_statement(ctx, try_stat->finally_statement);
hres = visit_statement(ctx, NULL, try_stat->finally_statement);
break;
}
case STAT_VAR:
@ -2214,7 +2289,7 @@ static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat)
if(FAILED(hres))
return hres;
hres = visit_statement(ctx, while_stat->statement);
hres = visit_statement(ctx, NULL, while_stat->statement);
break;
}
case STAT_WITH: {
@ -2224,12 +2299,18 @@ static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat)
if(FAILED(hres))
return hres;
hres = visit_statement(ctx, with_stat->statement);
hres = visit_statement(ctx, NULL, with_stat->statement);
break;
}
DEFAULT_UNREACHABLE;
}
if(stat_ctx)
{
assert(ctx->stat_ctx == stat_ctx);
ctx->stat_ctx = stat_ctx->next;
}
return hres;
}
@ -2325,7 +2406,7 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
{
function_expression_t *iter;
function_local_t *local;
unsigned off, i;
unsigned off, i, scope;
HRESULT hres;
TRACE("\n");
@ -2337,6 +2418,10 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
ctx->func = func;
ctx->locals_cnt = 0;
wine_rb_init(&ctx->locals, function_local_cmp);
ctx->local_scope_count = 0;
if (!alloc_local_scope(ctx, &scope))
return E_OUTOFMEMORY;
assert(!scope);
if(func_expr) {
parameter_t *param_iter;
@ -2371,11 +2456,11 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source,
}
for(i = 0; i < func->param_cnt; i++) {
if(!find_local(ctx, func->params[i]) && !alloc_local(ctx, func->params[i], -i-1))
if(!find_local(ctx, func->params[i]) && !alloc_local(ctx, func->params[i], -i-1, 0))
return E_OUTOFMEMORY;
}
hres = visit_block_statement(ctx, source->statement);
hres = visit_block_statement(ctx, NULL, source->statement);
if(FAILED(hres))
return hres;
@ -2549,6 +2634,7 @@ HRESULT compile_script(script_ctx_t *ctx, const WCHAR *code, UINT64 source_conte
heap_pool_init(&compiler.heap);
hres = compile_function(&compiler, compiler.parser->source, NULL, from_eval, &compiler.code->global_code);
heap_free(compiler.local_scopes);
heap_pool_free(&compiler.heap);
parser_release(compiler.parser);
if(FAILED(hres)) {

View File

@ -129,6 +129,7 @@ struct _statement_t {
typedef struct {
statement_t stat;
unsigned int scope_index;
statement_t *stat_list;
} block_statement_t;

View File

@ -1131,6 +1131,7 @@ static statement_t *new_block_statement(parser_ctx_t *ctx, unsigned loc, stateme
if(!ret)
return NULL;
ret->scope_index = 0;
ret->stat_list = list ? list->head : NULL;
return &ret->stat;