jscript: Setup arguments object by interpreter and store all arguments inside the object on call exit.
Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
9daafa87bc
commit
5a7327d21d
|
@ -2529,13 +2529,8 @@ static void pop_call_frame(script_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
call_frame_t *frame = ctx->call_ctx;
|
call_frame_t *frame = ctx->call_ctx;
|
||||||
|
|
||||||
if(frame->arguments_obj) {
|
if(frame->arguments_obj)
|
||||||
/* Reset arguments value to cut the reference cycle. Note that since all activation contexts have
|
detach_arguments_object(frame->arguments_obj);
|
||||||
* their own arguments property, it's impossible to use prototype's one during name lookup */
|
|
||||||
static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0};
|
|
||||||
jsdisp_propput_name(frame->variable_obj, argumentsW, jsval_undefined());
|
|
||||||
jsdisp_release(frame->arguments_obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(frame->scope) {
|
if(frame->scope) {
|
||||||
/* If current scope will be kept alive, we need to transfer local variables to its variable object. */
|
/* If current scope will be kept alive, we need to transfer local variables to its variable object. */
|
||||||
|
@ -2706,7 +2701,7 @@ static HRESULT bind_event_target(script_ctx_t *ctx, function_code_t *func, jsdis
|
||||||
return hres;
|
return hres;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT setup_scope(script_ctx_t *ctx, call_frame_t *frame, unsigned argc, jsval_t *argv)
|
static HRESULT setup_scope(script_ctx_t *ctx, call_frame_t *frame, unsigned argc, jsval_t *argv, jsdisp_t *function_instance)
|
||||||
{
|
{
|
||||||
const unsigned orig_stack = ctx->stack_top;
|
const unsigned orig_stack = ctx->stack_top;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
@ -2741,12 +2736,11 @@ static HRESULT setup_scope(script_ctx_t *ctx, call_frame_t *frame, unsigned argc
|
||||||
|
|
||||||
frame->pop_locals = ctx->stack_top - orig_stack;
|
frame->pop_locals = ctx->stack_top - orig_stack;
|
||||||
frame->base_scope->frame = frame;
|
frame->base_scope->frame = frame;
|
||||||
return S_OK;
|
return setup_arguments_object(ctx, frame, argc, function_instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, function_code_t *function, scope_chain_t *scope,
|
HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, function_code_t *function, scope_chain_t *scope,
|
||||||
IDispatch *this_obj, jsdisp_t *function_instance, jsdisp_t *variable_obj, unsigned argc, jsval_t *argv,
|
IDispatch *this_obj, jsdisp_t *function_instance, jsdisp_t *variable_obj, unsigned argc, jsval_t *argv, jsval_t *r)
|
||||||
jsdisp_t *arguments_obj, jsval_t *r)
|
|
||||||
{
|
{
|
||||||
call_frame_t *frame;
|
call_frame_t *frame;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
@ -2810,7 +2804,7 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi
|
||||||
frame->base_scope = frame->scope = scope_addref(scope);
|
frame->base_scope = frame->scope = scope_addref(scope);
|
||||||
|
|
||||||
if(!(flags & (EXEC_GLOBAL|EXEC_EVAL))) {
|
if(!(flags & (EXEC_GLOBAL|EXEC_EVAL))) {
|
||||||
hres = setup_scope(ctx, frame, argc, argv);
|
hres = setup_scope(ctx, frame, argc, argv, function_instance);
|
||||||
if(FAILED(hres)) {
|
if(FAILED(hres)) {
|
||||||
heap_free(frame);
|
heap_free(frame);
|
||||||
return hres;
|
return hres;
|
||||||
|
@ -2831,8 +2825,6 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi
|
||||||
|
|
||||||
if(function_instance)
|
if(function_instance)
|
||||||
frame->function_instance = jsdisp_addref(function_instance);
|
frame->function_instance = jsdisp_addref(function_instance);
|
||||||
if(arguments_obj)
|
|
||||||
frame->arguments_obj = jsdisp_addref(arguments_obj);
|
|
||||||
|
|
||||||
frame->flags = flags;
|
frame->flags = flags;
|
||||||
frame->variable_obj = jsdisp_addref(variable_obj);
|
frame->variable_obj = jsdisp_addref(variable_obj);
|
||||||
|
|
|
@ -232,6 +232,8 @@ typedef struct _call_frame_t {
|
||||||
#define EXEC_EVAL 0x0008
|
#define EXEC_EVAL 0x0008
|
||||||
|
|
||||||
HRESULT exec_source(script_ctx_t*,DWORD,bytecode_t*,function_code_t*,scope_chain_t*,IDispatch*,
|
HRESULT exec_source(script_ctx_t*,DWORD,bytecode_t*,function_code_t*,scope_chain_t*,IDispatch*,
|
||||||
jsdisp_t*,jsdisp_t*,unsigned,jsval_t*,jsdisp_t*,jsval_t*) DECLSPEC_HIDDEN;
|
jsdisp_t*,jsdisp_t*,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
HRESULT create_source_function(script_ctx_t*,bytecode_t*,function_code_t*,scope_chain_t*,jsdisp_t**) DECLSPEC_HIDDEN;
|
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*,unsigned,jsdisp_t*) DECLSPEC_HIDDEN;
|
||||||
|
void detach_arguments_object(jsdisp_t*) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -39,7 +39,9 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
jsdisp_t jsdisp;
|
jsdisp_t jsdisp;
|
||||||
FunctionInstance *function;
|
FunctionInstance *function;
|
||||||
scope_chain_t *scope;
|
jsval_t *buf;
|
||||||
|
call_frame_t *frame;
|
||||||
|
unsigned argc;
|
||||||
} ArgumentsInstance;
|
} ArgumentsInstance;
|
||||||
|
|
||||||
static inline FunctionInstance *function_from_jsdisp(jsdisp_t *jsdisp)
|
static inline FunctionInstance *function_from_jsdisp(jsdisp_t *jsdisp)
|
||||||
|
@ -57,6 +59,11 @@ static inline FunctionInstance *function_this(vdisp_t *jsthis)
|
||||||
return is_vclass(jsthis, JSCLASS_FUNCTION) ? function_from_vdisp(jsthis) : NULL;
|
return is_vclass(jsthis, JSCLASS_FUNCTION) ? function_from_vdisp(jsthis) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline ArgumentsInstance *arguments_from_jsdisp(jsdisp_t *jsdisp)
|
||||||
|
{
|
||||||
|
return CONTAINING_RECORD(jsdisp, ArgumentsInstance, jsdisp);
|
||||||
|
}
|
||||||
|
|
||||||
static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0};
|
static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0};
|
||||||
|
|
||||||
static const WCHAR lengthW[] = {'l','e','n','g','t','h',0};
|
static const WCHAR lengthW[] = {'l','e','n','g','t','h',0};
|
||||||
|
@ -78,23 +85,30 @@ static void Arguments_destructor(jsdisp_t *jsdisp)
|
||||||
|
|
||||||
TRACE("(%p)\n", arguments);
|
TRACE("(%p)\n", arguments);
|
||||||
|
|
||||||
|
if(arguments->buf) {
|
||||||
|
unsigned i;
|
||||||
|
for(i = 0; i < arguments->argc; i++)
|
||||||
|
jsval_release(arguments->buf[i]);
|
||||||
|
heap_free(arguments->buf);
|
||||||
|
}
|
||||||
|
|
||||||
jsdisp_release(&arguments->function->dispex);
|
jsdisp_release(&arguments->function->dispex);
|
||||||
scope_release(arguments->scope);
|
|
||||||
heap_free(arguments);
|
heap_free(arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned Arguments_idx_length(jsdisp_t *jsdisp)
|
static unsigned Arguments_idx_length(jsdisp_t *jsdisp)
|
||||||
{
|
{
|
||||||
ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
|
ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
|
||||||
return arguments->function->length;
|
return arguments->argc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static jsval_t *get_argument_ref(ArgumentsInstance *arguments, unsigned idx)
|
static jsval_t *get_argument_ref(ArgumentsInstance *arguments, unsigned idx)
|
||||||
{
|
{
|
||||||
call_frame_t *frame = arguments->scope->frame;
|
if(arguments->buf)
|
||||||
return frame
|
return arguments->buf + idx;
|
||||||
? arguments->jsdisp.ctx->stack + frame->arguments_off + idx
|
if(arguments->frame->base_scope->frame || idx >= arguments->frame->function->param_cnt)
|
||||||
: NULL;
|
return arguments->jsdisp.ctx->stack + arguments->frame->arguments_off + idx;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT Arguments_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r)
|
static HRESULT Arguments_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r)
|
||||||
|
@ -108,7 +122,7 @@ static HRESULT Arguments_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r)
|
||||||
return jsval_copy(*ref, r);
|
return jsval_copy(*ref, r);
|
||||||
|
|
||||||
/* FIXME: Accessing by name won't work for duplicated argument names */
|
/* FIXME: Accessing by name won't work for duplicated argument names */
|
||||||
return jsdisp_propget_name(arguments->scope->jsobj, arguments->function->func_code->params[idx], r);
|
return jsdisp_propget_name(arguments->frame->base_scope->jsobj, arguments->function->func_code->params[idx], r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val)
|
static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val)
|
||||||
|
@ -131,7 +145,7 @@ static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: Accessing by name won't work for duplicated argument names */
|
/* FIXME: Accessing by name won't work for duplicated argument names */
|
||||||
return jsdisp_propput_name(arguments->scope->jsobj, arguments->function->func_code->params[idx], val);
|
return jsdisp_propput_name(arguments->frame->base_scope->jsobj, arguments->function->func_code->params[idx], val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const builtin_info_t Arguments_info = {
|
static const builtin_info_t Arguments_info = {
|
||||||
|
@ -145,11 +159,9 @@ static const builtin_info_t Arguments_info = {
|
||||||
Arguments_idx_put
|
Arguments_idx_put
|
||||||
};
|
};
|
||||||
|
|
||||||
static HRESULT create_arguments(script_ctx_t *ctx, FunctionInstance *calee, scope_chain_t *scope,
|
HRESULT setup_arguments_object(script_ctx_t *ctx, call_frame_t *frame, unsigned argc, jsdisp_t *function_instance)
|
||||||
unsigned argc, jsval_t *argv, jsdisp_t **ret)
|
|
||||||
{
|
{
|
||||||
ArgumentsInstance *args;
|
ArgumentsInstance *args;
|
||||||
unsigned i;
|
|
||||||
HRESULT hres;
|
HRESULT hres;
|
||||||
|
|
||||||
static const WCHAR caleeW[] = {'c','a','l','l','e','e',0};
|
static const WCHAR caleeW[] = {'c','a','l','l','e','e',0};
|
||||||
|
@ -164,41 +176,65 @@ static HRESULT create_arguments(script_ctx_t *ctx, FunctionInstance *calee, scop
|
||||||
return hres;
|
return hres;
|
||||||
}
|
}
|
||||||
|
|
||||||
jsdisp_addref(&calee->dispex);
|
args->function = function_from_jsdisp(jsdisp_addref(function_instance));
|
||||||
args->function = calee;
|
args->argc = argc;
|
||||||
args->scope = scope_addref(scope);
|
args->frame = frame;
|
||||||
|
|
||||||
/* Store unnamed arguments directly in arguments object */
|
hres = jsdisp_propput_dontenum(&args->jsdisp, lengthW, jsval_number(argc));
|
||||||
for(i = calee->length; i < argc; i++) {
|
if(SUCCEEDED(hres))
|
||||||
WCHAR buf[12];
|
hres = jsdisp_propput_dontenum(&args->jsdisp, caleeW, jsval_disp(to_disp(&args->function->dispex)));
|
||||||
|
if(SUCCEEDED(hres))
|
||||||
static const WCHAR formatW[] = {'%','d',0};
|
hres = jsdisp_propput(frame->base_scope->jsobj, argumentsW, PROPF_DONTDELETE, jsval_obj(&args->jsdisp));
|
||||||
|
|
||||||
sprintfW(buf, formatW, i);
|
|
||||||
hres = jsdisp_propput_dontenum(&args->jsdisp, buf, argv[i]);
|
|
||||||
if(FAILED(hres))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(SUCCEEDED(hres)) {
|
|
||||||
hres = jsdisp_propput_dontenum(&args->jsdisp, lengthW, jsval_number(argc));
|
|
||||||
if(SUCCEEDED(hres))
|
|
||||||
hres = jsdisp_propput_dontenum(&args->jsdisp, caleeW, jsval_disp(to_disp(&calee->dispex)));
|
|
||||||
}
|
|
||||||
if(FAILED(hres)) {
|
if(FAILED(hres)) {
|
||||||
jsdisp_release(&args->jsdisp);
|
jsdisp_release(&args->jsdisp);
|
||||||
return hres;
|
return hres;
|
||||||
}
|
}
|
||||||
|
|
||||||
*ret = &args->jsdisp;
|
frame->arguments_obj = &args->jsdisp;
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void detach_arguments_object(jsdisp_t *args_disp)
|
||||||
|
{
|
||||||
|
ArgumentsInstance *arguments = arguments_from_jsdisp(args_disp);
|
||||||
|
call_frame_t *frame = arguments->frame;
|
||||||
|
const BOOL on_stack = frame->base_scope->frame == frame;
|
||||||
|
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 */
|
||||||
|
jsdisp_propput_name(frame->base_scope->jsobj, argumentsW, jsval_undefined());
|
||||||
|
arguments->frame = NULL;
|
||||||
|
|
||||||
|
/* Don't bother coppying arguments if call frame holds the last reference. */
|
||||||
|
if(arguments->jsdisp.ref > 1) {
|
||||||
|
arguments->buf = heap_alloc(arguments->argc * sizeof(*arguments->buf));
|
||||||
|
if(arguments->buf) {
|
||||||
|
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(frame->base_scope->jsobj, frame->function->params[i], arguments->buf+i);
|
||||||
|
if(FAILED(hres))
|
||||||
|
arguments->buf[i] = jsval_undefined();
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
ERR("out of memory\n");
|
||||||
|
arguments->argc = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jsdisp_release(frame->arguments_obj);
|
||||||
|
}
|
||||||
|
|
||||||
static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, unsigned argc, jsval_t *argv,
|
static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, unsigned argc, jsval_t *argv,
|
||||||
BOOL is_constructor, BOOL caller_execs_source, jsval_t *r)
|
BOOL is_constructor, BOOL caller_execs_source, jsval_t *r)
|
||||||
{
|
{
|
||||||
jsdisp_t *var_disp, *arg_disp;
|
jsdisp_t *var_disp;
|
||||||
scope_chain_t *scope;
|
scope_chain_t *scope;
|
||||||
|
DWORD exec_flags = 0;
|
||||||
HRESULT hres;
|
HRESULT hres;
|
||||||
|
|
||||||
if(ctx->state == SCRIPTSTATE_UNINITIALIZED || ctx->state == SCRIPTSTATE_CLOSED) {
|
if(ctx->state == SCRIPTSTATE_UNINITIALIZED || ctx->state == SCRIPTSTATE_CLOSED) {
|
||||||
|
@ -220,26 +256,13 @@ static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDis
|
||||||
if(FAILED(hres))
|
if(FAILED(hres))
|
||||||
return hres;
|
return hres;
|
||||||
|
|
||||||
hres = create_arguments(ctx, function, scope, argc, argv, &arg_disp);
|
if(caller_execs_source)
|
||||||
if(FAILED(hres)) {
|
exec_flags |= EXEC_RETURN_TO_INTERP;
|
||||||
scope_release(scope);
|
if(is_constructor)
|
||||||
return hres;
|
exec_flags |= EXEC_CONSTRUCTOR;
|
||||||
}
|
hres = exec_source(ctx, exec_flags, function->code, function->func_code, scope, this_obj,
|
||||||
|
&function->dispex, scope->jsobj, argc, argv, r);
|
||||||
|
|
||||||
hres = jsdisp_propput(scope->jsobj, argumentsW, PROPF_DONTDELETE, jsval_obj(arg_disp));
|
|
||||||
if(SUCCEEDED(hres)) {
|
|
||||||
DWORD exec_flags = 0;
|
|
||||||
|
|
||||||
if(caller_execs_source)
|
|
||||||
exec_flags |= EXEC_RETURN_TO_INTERP;
|
|
||||||
if(is_constructor)
|
|
||||||
exec_flags |= EXEC_CONSTRUCTOR;
|
|
||||||
hres = exec_source(ctx, exec_flags, function->code, function->func_code, scope, this_obj,
|
|
||||||
&function->dispex, scope->jsobj, argc, argv, arg_disp, r);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
jsdisp_release(arg_disp);
|
|
||||||
scope_release(scope);
|
scope_release(scope);
|
||||||
return hres;
|
return hres;
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,7 +229,7 @@ HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned a
|
||||||
if(flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE)
|
if(flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE)
|
||||||
exec_flags |= EXEC_RETURN_TO_INTERP;
|
exec_flags |= EXEC_RETURN_TO_INTERP;
|
||||||
hres = exec_source(ctx, exec_flags, code, &code->global_code, frame->scope,
|
hres = exec_source(ctx, exec_flags, code, &code->global_code, frame->scope,
|
||||||
frame->this_obj, NULL, frame->variable_obj, 0, NULL, NULL, r);
|
frame->this_obj, NULL, frame->variable_obj, 0, NULL, r);
|
||||||
release_bytecode(code);
|
release_bytecode(code);
|
||||||
return hres;
|
return hres;
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ static HRESULT exec_global_code(JScript *This, bytecode_t *code)
|
||||||
IActiveScriptSite_OnEnterScript(This->site);
|
IActiveScriptSite_OnEnterScript(This->site);
|
||||||
|
|
||||||
clear_ei(This->ctx);
|
clear_ei(This->ctx);
|
||||||
hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, 0, NULL, NULL, NULL);
|
hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, 0, NULL, NULL);
|
||||||
|
|
||||||
IActiveScriptSite_OnLeaveScript(This->site);
|
IActiveScriptSite_OnLeaveScript(This->site);
|
||||||
return hres;
|
return hres;
|
||||||
|
@ -773,7 +773,7 @@ static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface,
|
||||||
IActiveScriptSite_OnEnterScript(This->site);
|
IActiveScriptSite_OnEnterScript(This->site);
|
||||||
|
|
||||||
clear_ei(This->ctx);
|
clear_ei(This->ctx);
|
||||||
hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, 0, NULL, NULL, &r);
|
hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, 0, NULL, &r);
|
||||||
if(SUCCEEDED(hres)) {
|
if(SUCCEEDED(hres)) {
|
||||||
if(pvarResult)
|
if(pvarResult)
|
||||||
hres = jsval_to_variant(r, pvarResult);
|
hres = jsval_to_variant(r, pvarResult);
|
||||||
|
|
Loading…
Reference in New Issue