Module: wine Branch: master Commit: 765a52e86a65a1c0604b9ef985772195dbe5f67c URL: http://source.winehq.org/git/wine.git/?a=commit;h=765a52e86a65a1c0604b9ef985...
Author: Jacek Caban jacek@codeweavers.com Date: Thu Aug 4 13:40:11 2016 +0200
jscript: Store variables on the stack if possible.
Signed-off-by: Jacek Caban jacek@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/jscript/engine.c | 114 +++++++++++++++++++++++++++++++++++++------------- dlls/jscript/engine.h | 2 + 2 files changed, 86 insertions(+), 30 deletions(-)
diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index 2305998..642705a 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -217,11 +217,16 @@ static BOOL stack_topn_exprval(script_ctx_t *ctx, unsigned n, exprval_t *r)
if(!frame->base_scope->frame && off >= frame->arguments_off) { DISPID id; + BSTR name; HRESULT hres;
/* Got stack reference in deoptimized code. Need to convert it back to variable object reference. */
- hres = jsdisp_get_id(ctx->call_ctx->base_scope->jsobj, frame->function->params[off - frame->arguments_off], 0, &id); + assert(off < frame->variables_off + frame->function->var_cnt); + name = off >= frame->variables_off + ? frame->function->variables[off - frame->variables_off].name + : frame->function->params[off - frame->arguments_off]; + hres = jsdisp_get_id(ctx->call_ctx->base_scope->jsobj, name, 0, &id); if(FAILED(hres)) { r->type = EXPRVAL_INVALID; r->u.hres = hres; @@ -541,6 +546,13 @@ static HRESULT equal2_values(jsval_t lval, jsval_t rval, BOOL *ret) return S_OK; }
+static inline unsigned local_off(call_frame_t *frame, int ref) +{ + return ref < 0 + ? frame->arguments_off - ref-1 + : frame->variables_off + ref; +} + /* * Transfers local variables from stack to variable object. * It's slow, so we want to avoid it as much as possible. @@ -566,8 +578,9 @@ static HRESULT detach_variable_object(script_ctx_t *ctx, call_frame_t *frame)
frame->base_scope->frame = NULL;
- for(i = 0; i < frame->function->param_cnt; i++) { - hres = jsdisp_propput_name(frame->variable_obj, frame->function->params[i], ctx->stack[frame->arguments_off+i]); + for(i = 0; i < frame->function->locals_cnt; i++) { + hres = jsdisp_propput_name(frame->variable_obj, frame->function->locals[i].name, + ctx->stack[local_off(frame, frame->function->locals[i].ref)]); if(FAILED(hres)) return hres; } @@ -622,9 +635,10 @@ static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *re local_ref_t *ref = lookup_local(func, identifier); static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0};
- if(ref && ref->ref < 0) { + if(ref) { ret->type = EXPRVAL_STACK_REF; - ret->u.off = scope->frame->arguments_off - ref->ref - 1; + ret->u.off = local_off(scope->frame, ref->ref); + TRACE("returning ref %d for %d\n", ret->u.off, ref->ref); return S_OK; }
@@ -2532,20 +2546,24 @@ static void pop_call_frame(script_ctx_t *ctx) { call_frame_t *frame = ctx->call_ctx;
+ frame->stack_base -= frame->pop_locals + frame->pop_variables; + + assert(frame->scope == frame->base_scope); + + /* If current scope will be kept alive, we need to transfer local variables to its variable object. */ + if(frame->scope && frame->scope->ref > 1) { + HRESULT hres = detach_variable_object(ctx, frame); + if(FAILED(hres)) + ERR("Failed to detach variable object: %08x\n", hres); + } + if(frame->arguments_obj) detach_arguments_object(frame->arguments_obj); - - if(frame->scope) { - /* If current scope will be kept alive, we need to transfer local variables to its variable object. */ - if(frame->scope->ref > 1) { - HRESULT hres = detach_variable_object(ctx, frame); - if(FAILED(hres)) - ERR("Failed to detach variable object: %08x\n", hres); - } + if(frame->scope) scope_release(frame->scope); - }
- frame->stack_base -= frame->pop_locals; + if(frame->pop_variables) + stack_popn(ctx, frame->pop_variables); stack_popn(ctx, frame->pop_locals);
ctx->call_ctx = frame->prev_frame; @@ -2738,6 +2756,36 @@ static HRESULT setup_scope(script_ctx_t *ctx, call_frame_t *frame, unsigned argc }
frame->pop_locals = ctx->stack_top - orig_stack; + + frame->variables_off = ctx->stack_top; + + for(i = 0; i < frame->function->var_cnt; i++) { + hres = stack_push(ctx, jsval_undefined()); + if(FAILED(hres)) { + stack_popn(ctx, ctx->stack_top - orig_stack); + return hres; + } + } + + frame->pop_variables = i; + + for(i = 0; i < frame->function->func_cnt; i++) { + if(frame->function->funcs[i].name && !frame->function->funcs[i].event_target) { + jsdisp_t *func_obj; + unsigned off; + + hres = create_source_function(ctx, frame->bytecode, frame->function->funcs+i, frame->base_scope, &func_obj); + if(FAILED(hres)) { + stack_popn(ctx, ctx->stack_top - orig_stack); + return hres; + } + + off = local_off(frame, frame->function->funcs[i].local_ref); + jsval_release(ctx->stack[off]); + ctx->stack[off] = jsval_obj(func_obj); + } + } + frame->base_scope->frame = frame; return S_OK; } @@ -2752,33 +2800,38 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi for(i = 0; i < function->func_cnt; i++) { jsdisp_t *func_obj;
- if(!function->funcs[i].name) + if(!function->funcs[i].event_target) continue;
hres = create_source_function(ctx, bytecode, function->funcs+i, scope, &func_obj); if(FAILED(hres)) return hres;
- if(function->funcs[i].event_target) - hres = bind_event_target(ctx, function->funcs+i, func_obj); - else - hres = jsdisp_propput_name(variable_obj, function->funcs[i].name, jsval_obj(func_obj)); + hres = bind_event_target(ctx, function->funcs+i, func_obj); jsdisp_release(func_obj); if(FAILED(hres)) return hres; }
- for(i=0; i < function->var_cnt; i++) { - TRACE("[%d] %s %d\n", i, debugstr_w(function->variables[i].name), function->variables[i].func_id); - if(function->variables[i].func_id != -1) - continue; + if(flags & (EXEC_GLOBAL | EXEC_EVAL)) { + for(i=0; i < function->var_cnt; i++) { + TRACE("[%d] %s %d\n", i, debugstr_w(function->variables[i].name), function->variables[i].func_id); + if(function->variables[i].func_id != -1) { + jsdisp_t *func_obj;
- if(!(flags & EXEC_GLOBAL) || !lookup_global_members(ctx, function->variables[i].name, NULL)) { - DISPID id = 0; + hres = create_source_function(ctx, bytecode, function->funcs+function->variables[i].func_id, scope, &func_obj); + if(FAILED(hres)) + return hres;
- hres = jsdisp_get_id(variable_obj, function->variables[i].name, fdexNameEnsure, &id); - if(FAILED(hres)) - return hres; + hres = jsdisp_propput_name(variable_obj, function->variables[i].name, jsval_obj(func_obj)); + jsdisp_release(func_obj); + }else if(!(flags & EXEC_GLOBAL) || !lookup_global_members(ctx, function->variables[i].name, NULL)) { + DISPID id = 0; + + hres = jsdisp_get_id(variable_obj, function->variables[i].name, fdexNameEnsure, &id); + if(FAILED(hres)) + return hres; + } } }
@@ -2807,6 +2860,7 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi frame->function = function; frame->ret = jsval_undefined(); frame->argc = argc; + frame->bytecode = bytecode_addref(bytecode);
if(scope) { frame->base_scope = frame->scope = scope_addref(scope); @@ -2814,13 +2868,13 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi if(!(flags & (EXEC_GLOBAL|EXEC_EVAL))) { hres = setup_scope(ctx, frame, argc, argv); if(FAILED(hres)) { + release_bytecode(frame->bytecode); heap_free(frame); return hres; } } }
- frame->bytecode = bytecode_addref(bytecode); frame->ip = function->instr_off; frame->stack_base = ctx->stack_top; if(this_obj) diff --git a/dlls/jscript/engine.h b/dlls/jscript/engine.h index 2aaf831..b18b775 100644 --- a/dlls/jscript/engine.h +++ b/dlls/jscript/engine.h @@ -225,6 +225,8 @@ typedef struct _call_frame_t { unsigned argc; unsigned pop_locals; unsigned arguments_off; + unsigned variables_off; + unsigned pop_variables;
bytecode_t *bytecode; function_code_t *function;