[PATCH v5 2/6] jscript: Enumerate with and block scopes.
Paul Gofman
pgofman at codeweavers.com
Fri Jun 18 07:50:17 CDT 2021
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
v5:
- do not assign scope indexes to 'with' scopes.
dlls/jscript/compile.c | 136 +++++++++++++++++++++++++++++++++--------
dlls/jscript/parser.h | 1 +
dlls/jscript/parser.y | 1 +
3 files changed, 113 insertions(+), 25 deletions(-)
diff --git a/dlls/jscript/compile.c b/dlls/jscript/compile.c
index 46efd53cdb5..801ef53249c 100644
--- a/dlls/jscript/compile.c
+++ b/dlls/jscript/compile.c
@@ -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)) {
diff --git a/dlls/jscript/parser.h b/dlls/jscript/parser.h
index c4dd0752ee9..f110b40a247 100644
--- a/dlls/jscript/parser.h
+++ b/dlls/jscript/parser.h
@@ -129,6 +129,7 @@ struct _statement_t {
typedef struct {
statement_t stat;
+ unsigned int scope_index;
statement_t *stat_list;
} block_statement_t;
diff --git a/dlls/jscript/parser.y b/dlls/jscript/parser.y
index 6de39e43fac..e09de81c2bb 100644
--- a/dlls/jscript/parser.y
+++ b/dlls/jscript/parser.y
@@ -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;
--
2.31.1
More information about the wine-devel
mailing list