From: Gabriel Ivăncescu gabrielopcode@gmail.com
Rather than using the variable obj for it. Since it's an implementation detail, the scope's dispex object accesses them using index props (using same indices as the buffer's).
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 8 +++ dlls/jscript/engine.c | 134 ++++++++++++++++++++++++++++++++++++++-- dlls/jscript/engine.h | 9 ++- dlls/jscript/function.c | 42 ++++--------- dlls/jscript/jscript.h | 1 + 5 files changed, 159 insertions(+), 35 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index e8f7d599463..b5fc3699212 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2332,6 +2332,14 @@ HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID * return DISP_E_UNKNOWNNAME; }
+HRESULT jsdisp_get_idx_id(jsdisp_t *jsdisp, DWORD idx, DISPID *id) +{ + WCHAR name[11]; + + swprintf(name, ARRAY_SIZE(name), L"%u", idx); + return jsdisp_get_id(jsdisp, name, 0, id); +} + HRESULT jsdisp_call_value(jsdisp_t *jsfunc, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { HRESULT hres; diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index ceaa01b0648..2ca9cc56725 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -162,6 +162,23 @@ static inline BSTR local_name(call_frame_t *frame, int ref) return ref < 0 ? frame->function->params[-ref-1] : frame->function->variables[ref].name; }
+static jsval_t *get_detached_var_ref(scope_chain_t *scope, const WCHAR *name) +{ + struct vars_buffer *detached_vars = scope->detached_vars; + local_ref_t *ref; + + if(!detached_vars) + return NULL; + ref = lookup_local(detached_vars->func_code, name, scope->scope_index); + return ref && ref->ref < 0 ? &detached_vars->var[-ref->ref - 1] : NULL; +} + +static HRESULT get_detached_var_dispid(scope_chain_t *scope, const WCHAR *name, DISPID *id) +{ + jsval_t *var_ref = get_detached_var_ref(scope, name); + return var_ref ? jsdisp_get_idx_id(&scope->dispex, var_ref - scope->detached_vars->var, id) : DISP_E_UNKNOWNNAME; +} + /* Steals input reference even on failure. */ static HRESULT stack_push_exprval(script_ctx_t *ctx, exprval_t *val) { @@ -228,6 +245,18 @@ static BOOL stack_topn_exprval(script_ctx_t *ctx, unsigned n, exprval_t *r)
while (1) { + hres = get_detached_var_dispid(scope, name, &id); + if (hres != DISP_E_UNKNOWNNAME) + { + if (FAILED(hres)) + { + r->type = EXPRVAL_INVALID; + r->u.hres = hres; + return FALSE; + } + jsobj = &scope->dispex; + break; + } if ((jsobj = to_jsdisp(scope->obj)) && SUCCEEDED(hres = jsdisp_get_id(jsobj, name, 0, &id))) break; if (scope == frame->base_scope) @@ -423,9 +452,24 @@ static inline void clear_acc(script_ctx_t *ctx) ctx->acc = jsval_undefined(); }
+static inline scope_chain_t *scope_from_dispex(jsdisp_t *dispex) +{ + return CONTAINING_RECORD(dispex, scope_chain_t, dispex); +} + static void scope_destructor(jsdisp_t *dispex) { - scope_chain_t *scope = CONTAINING_RECORD(dispex, scope_chain_t, dispex); + scope_chain_t *scope = scope_from_dispex(dispex); + + if(scope->detached_vars) { + struct vars_buffer *vars = scope->detached_vars; + unsigned i, cnt = vars->argc; + + release_bytecode(vars->func_code->bytecode); + for(i = 0; i < cnt; i++) + jsval_release(vars->var[i]); + free(vars); + }
if(scope->next) scope_release(scope->next); @@ -435,12 +479,53 @@ static void scope_destructor(jsdisp_t *dispex) free(scope); }
+static unsigned scope_idx_length(jsdisp_t *dispex) +{ + scope_chain_t *scope = scope_from_dispex(dispex); + + return scope->detached_vars->argc; +} + +static HRESULT scope_idx_get(jsdisp_t *dispex, unsigned idx, jsval_t *r) +{ + scope_chain_t *scope = scope_from_dispex(dispex); + + return jsval_copy(scope->detached_vars->var[idx], r); +} + +static HRESULT scope_idx_put(jsdisp_t *dispex, unsigned idx, jsval_t val) +{ + scope_chain_t *scope = scope_from_dispex(dispex); + jsval_t copy, *ref; + HRESULT hres; + + hres = jsval_copy(val, ©); + if(FAILED(hres)) + return hres; + + ref = &scope->detached_vars->var[idx]; + jsval_release(*ref); + *ref = copy; + return S_OK; +} + static HRESULT scope_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex) { - scope_chain_t *scope = CONTAINING_RECORD(dispex, scope_chain_t, dispex); + scope_chain_t *scope = scope_from_dispex(dispex); jsdisp_t *jsobj; HRESULT hres;
+ if(scope->detached_vars) { + struct vars_buffer *vars = scope->detached_vars; + unsigned i, cnt = vars->argc; + + for(i = 0; i < cnt; i++) { + hres = gc_process_linked_val(gc_ctx, op, dispex, &vars->var[i]); + if(FAILED(hres)) + return hres; + } + } + if(scope->next) { hres = gc_process_linked_obj(gc_ctx, op, dispex, &scope->next->dispex, (void**)&scope->next); if(FAILED(hres)) @@ -466,9 +551,9 @@ static const builtin_info_t scope_info = { NULL, scope_destructor, NULL, - NULL, - NULL, - NULL, + scope_idx_length, + scope_idx_get, + scope_idx_put, scope_gc_traverse };
@@ -622,6 +707,35 @@ HRESULT jsval_strict_equal(jsval_t lval, jsval_t rval, BOOL *ret) return S_OK; }
+static HRESULT alloc_detached_vars(script_ctx_t *ctx, call_frame_t *frame, scope_chain_t *scope) +{ + function_code_t *func = frame->function; + jsval_t *detached_var; + unsigned i, argc; + HRESULT hres; + + argc = (scope == frame->base_scope) ? max(frame->argc, func->param_cnt) : 0; + if(!argc) + return S_OK; + + if(!(scope->detached_vars = malloc(FIELD_OFFSET(struct vars_buffer, var[argc])))) + return E_OUTOFMEMORY; + detached_var = scope->detached_vars->var; + scope->detached_vars->argc = argc; + scope->detached_vars->func_code = func; + bytecode_addref(func->bytecode); + + for(i = 0; i < argc; i++) { + hres = jsval_copy(ctx->stack[frame->arguments_off + i], &detached_var[i]); + if(FAILED(hres)) { + do detached_var[i++] = jsval_undefined(); while(i < argc); + return hres; + } + } + + return S_OK; +} + static HRESULT detach_scope(script_ctx_t *ctx, call_frame_t *frame, scope_chain_t *scope) { function_code_t *func = frame->function; @@ -635,6 +749,10 @@ static HRESULT detach_scope(script_ctx_t *ctx, call_frame_t *frame, scope_chain_ assert(scope->frame == frame); scope->frame = NULL;
+ hres = alloc_detached_vars(ctx, frame, scope); + if (FAILED(hres)) + return hres; + if (!scope->obj) { if (FAILED(hres = create_object(ctx, NULL, &jsobj))) @@ -654,6 +772,8 @@ static HRESULT detach_scope(script_ctx_t *ctx, call_frame_t *frame, scope_chain_ WCHAR *name = frame->function->local_scopes[index].locals[i].name; int ref = frame->function->local_scopes[index].locals[i].ref;
+ if (ref < 0) + continue; if (FAILED(hres = jsdisp_propput_name(jsobj, name, ctx->stack[local_off(frame, ref)]))) return hres; if (scope != frame->base_scope && frame->function->variables[ref].func_id != -1 @@ -781,6 +901,10 @@ static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *re ret->u.val = jsval_obj(jsdisp_addref(scope->frame->function_instance)); return S_OK; } + }else if((hres = get_detached_var_dispid(scope, identifier, &id)) != DISP_E_UNKNOWNNAME) { + if(SUCCEEDED(hres)) + exprval_set_disp_ref(ret, to_disp(&scope->dispex), id); + return hres; }
if (!scope->obj) diff --git a/dlls/jscript/engine.h b/dlls/jscript/engine.h index 9b29373a0da..917f67c17d8 100644 --- a/dlls/jscript/engine.h +++ b/dlls/jscript/engine.h @@ -222,10 +222,17 @@ static inline bytecode_t *bytecode_addref(bytecode_t *code) return code; }
+struct vars_buffer { + function_code_t *func_code; + unsigned argc; + jsval_t var[]; +}; + typedef struct _scope_chain_t { - jsdisp_t dispex; /* FIXME: don't wrap it in a jsdisp (it holds ref and traverse for the garbage collector) */ + jsdisp_t dispex; IDispatch *obj; unsigned int scope_index; + struct vars_buffer *detached_vars; struct _call_frame_t *frame; struct _scope_chain_t *next; } scope_chain_t; diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 7f53122001c..f049e08be94 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -129,48 +129,36 @@ static jsval_t *get_argument_ref(ArgumentsInstance *arguments, unsigned idx) { if(arguments->buf) return arguments->buf + idx; - if(arguments->frame->base_scope->frame || idx >= arguments->frame->function->param_cnt) + if(!arguments->frame->base_scope->detached_vars) return arguments->jsdisp.ctx->stack + arguments->frame->arguments_off + idx; - return NULL; + return arguments->frame->base_scope->detached_vars->var + idx; }
static HRESULT Arguments_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r) { ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); - jsval_t *ref;
TRACE("%p[%u]\n", arguments, idx);
- if((ref = get_argument_ref(arguments, idx))) - return jsval_copy(*ref, r); - - /* FIXME: Accessing by name won't work for duplicated argument names */ - return jsdisp_propget_name(as_jsdisp(arguments->frame->base_scope->obj), - arguments->function->func_code->params[idx], r); + return jsval_copy(*get_argument_ref(arguments, idx), r); }
static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val) { ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); - jsval_t *ref; + jsval_t copy, *ref; HRESULT hres;
TRACE("%p[%u] = %s\n", arguments, idx, debugstr_jsval(val));
- if((ref = get_argument_ref(arguments, idx))) { - jsval_t copy; - hres = jsval_copy(val, ©); - if(FAILED(hres)) - return hres; - - jsval_release(*ref); - *ref = copy; - return S_OK; - } + hres = jsval_copy(val, ©); + if(FAILED(hres)) + return hres;
- /* FIXME: Accessing by name won't work for duplicated argument names */ - return jsdisp_propput_name(as_jsdisp(arguments->frame->base_scope->obj), - arguments->function->func_code->params[idx], val); + ref = get_argument_ref(arguments, idx); + jsval_release(*ref); + *ref = copy; + return S_OK; }
static HRESULT Arguments_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *jsdisp) @@ -243,7 +231,6 @@ void detach_arguments_object(jsdisp_t *args_disp) call_frame_t *frame = arguments->frame; const BOOL on_stack = frame->base_scope->frame == frame; jsdisp_t *jsobj = as_jsdisp(frame->base_scope->obj); - HRESULT hres;
/* Reset arguments value to cut the reference cycle. Note that since all activation contexts have * their own arguments property, it's impossible to use prototype's one during name lookup */ @@ -254,14 +241,11 @@ void detach_arguments_object(jsdisp_t *args_disp) if(arguments->jsdisp.ref > 1) { arguments->buf = malloc(arguments->argc * sizeof(*arguments->buf)); if(arguments->buf) { + const jsval_t *args = on_stack ? arguments->jsdisp.ctx->stack + frame->arguments_off : frame->base_scope->detached_vars->var; int i;
for(i = 0; i < arguments->argc ; i++) { - if(on_stack || i >= frame->function->param_cnt) - hres = jsval_copy(arguments->jsdisp.ctx->stack[frame->arguments_off + i], arguments->buf+i); - else - hres = jsdisp_propget_name(jsobj, frame->function->params[i], arguments->buf+i); - if(FAILED(hres)) + if(FAILED(jsval_copy(args[i], &arguments->buf[i]))) arguments->buf[i] = jsval_undefined(); } }else { diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index e91aa6dfabd..bd80528c020 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -254,6 +254,7 @@ HRESULT jsdisp_propput_idx(jsdisp_t*,DWORD,jsval_t) DECLSPEC_HIDDEN; HRESULT jsdisp_propget_name(jsdisp_t*,LPCWSTR,jsval_t*) DECLSPEC_HIDDEN; HRESULT jsdisp_get_idx(jsdisp_t*,DWORD,jsval_t*) DECLSPEC_HIDDEN; HRESULT jsdisp_get_id(jsdisp_t*,const WCHAR*,DWORD,DISPID*) DECLSPEC_HIDDEN; +HRESULT jsdisp_get_idx_id(jsdisp_t*,DWORD,DISPID*) DECLSPEC_HIDDEN; HRESULT disp_delete(IDispatch*,DISPID,BOOL*) DECLSPEC_HIDDEN; HRESULT disp_delete_name(script_ctx_t*,IDispatch*,jsstr_t*,BOOL*) DECLSPEC_HIDDEN; HRESULT jsdisp_delete_idx(jsdisp_t*,DWORD) DECLSPEC_HIDDEN;