From: Gabriel Ivăncescu gabrielopcode@gmail.com
We will need it when looking up arguments by name.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/engine.c | 32 ++++++++++++++++++++------------ dlls/jscript/engine.h | 4 ++-- dlls/jscript/function.c | 14 +++++++++----- 3 files changed, 31 insertions(+), 19 deletions(-)
diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index a4b416ba8ed..393e5429d3a 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -428,7 +428,8 @@ static void scope_destructor(jsdisp_t *dispex)
if(scope->next) scope_release(scope->next); - + if(scope->arguments_obj) + jsdisp_release(scope->arguments_obj); if(scope->obj) IDispatch_Release(scope->obj); free(scope); @@ -445,6 +446,12 @@ static HRESULT scope_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, return hres; }
+ if(scope->arguments_obj) { + hres = gc_process_linked_obj(gc_ctx, op, dispex, scope->arguments_obj, (void**)&scope->arguments_obj); + if(FAILED(hres)) + return hres; + } + if(op == GC_TRAVERSE_UNLINK) { IDispatch *obj = scope->obj; if(obj) { @@ -689,7 +696,7 @@ static HRESULT detach_variable_object(script_ctx_t *ctx, call_frame_t *frame, BO assert(frame == frame->base_scope->frame); assert(frame->variable_obj == frame->base_scope->jsobj);
- if(!from_release && !frame->arguments_obj) { + if(!from_release && !frame->base_scope->arguments_obj) { hres = setup_arguments_object(ctx, frame); if(FAILED(hres)) return hres; @@ -2987,23 +2994,24 @@ OP_LIST static void pop_call_frame(script_ctx_t *ctx) { call_frame_t *frame = ctx->call_ctx; + scope_chain_t *scope = frame->scope;
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->dispex.ref > 1) { - HRESULT hres = detach_variable_object(ctx, frame, TRUE); - if(FAILED(hres)) - ERR("Failed to detach variable object: %08lx\n", hres); + if(scope) { + /* If current scope will be kept alive, we need to transfer local variables to its variable object. */ + if(scope->dispex.ref > 1) { + HRESULT hres = detach_variable_object(ctx, frame, TRUE); + if(FAILED(hres)) + ERR("Failed to detach variable object: %08lx\n", hres); + } + if(scope->arguments_obj) + detach_arguments_object(scope->arguments_obj, frame); + scope_release(scope); }
- if(frame->arguments_obj) - detach_arguments_object(frame->arguments_obj); - if(frame->scope) - scope_release(frame->scope); - if(frame->pop_variables) stack_popn(ctx, frame->pop_variables); stack_popn(ctx, frame->pop_locals); diff --git a/dlls/jscript/engine.h b/dlls/jscript/engine.h index 987e1cfa52d..6a7a16d2923 100644 --- a/dlls/jscript/engine.h +++ b/dlls/jscript/engine.h @@ -226,6 +226,7 @@ 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 *jsobj; IDispatch *obj; + jsdisp_t *arguments_obj; unsigned int scope_index; struct _call_frame_t *frame; struct _scope_chain_t *next; @@ -279,7 +280,6 @@ typedef struct _call_frame_t { IDispatch *this_obj; jsdisp_t *function_instance; jsdisp_t *variable_obj; - jsdisp_t *arguments_obj; DWORD flags;
unsigned argc; @@ -304,4 +304,4 @@ HRESULT exec_source(script_ctx_t*,DWORD,bytecode_t*,function_code_t*,scope_chain
HRESULT create_source_function(script_ctx_t*,bytecode_t*,function_code_t*,scope_chain_t*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT setup_arguments_object(script_ctx_t*,call_frame_t*) DECLSPEC_HIDDEN; -void detach_arguments_object(jsdisp_t*) DECLSPEC_HIDDEN; +void detach_arguments_object(jsdisp_t*,call_frame_t*) DECLSPEC_HIDDEN; diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 018fd3955db..f0677948093 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -233,20 +233,24 @@ HRESULT setup_arguments_object(script_ctx_t *ctx, call_frame_t *frame) return hres; }
- frame->arguments_obj = &args->jsdisp; + frame->base_scope->arguments_obj = &args->jsdisp; return S_OK; }
-void detach_arguments_object(jsdisp_t *args_disp) +void detach_arguments_object(jsdisp_t *args_disp, call_frame_t *popped_frame) { ArgumentsInstance *arguments = arguments_from_jsdisp(args_disp); call_frame_t *frame = arguments->frame; const BOOL on_stack = frame->base_scope->frame == frame; HRESULT hres;
+ if(frame != popped_frame) + return; + /* 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 */ jsdisp_propput_name(frame->base_scope->jsobj, L"arguments", jsval_undefined()); + frame->base_scope->arguments_obj = NULL; arguments->frame = NULL;
/* Don't bother coppying arguments if call frame holds the last reference. */ @@ -269,7 +273,7 @@ void detach_arguments_object(jsdisp_t *args_disp) } }
- jsdisp_release(frame->arguments_obj); + jsdisp_release(&arguments->jsdisp); }
HRESULT Function_invoke(jsdisp_t *func_this, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) @@ -542,12 +546,12 @@ static HRESULT Function_get_arguments(script_ctx_t *ctx, jsdisp_t *jsthis, jsval
for(frame = ctx->call_ctx; frame; frame = frame->prev_frame) { if(frame->function_instance == &function->dispex) { - if(!frame->arguments_obj) { + if(!frame->base_scope->arguments_obj) { hres = setup_arguments_object(ctx, frame); if(FAILED(hres)) return hres; } - *r = jsval_obj(jsdisp_addref(frame->arguments_obj)); + *r = jsval_obj(jsdisp_addref(frame->base_scope->arguments_obj)); return S_OK; } }