diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 4eda70470e5..640e954d97b 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -39,7 +39,8 @@ typedef enum { PROP_JSVAL, PROP_BUILTIN, PROP_PROTREF, - PROP_DELETED + PROP_DELETED, + PROP_IDX } prop_type_t; struct _dispex_prop_t { @@ -52,6 +53,7 @@ struct _dispex_prop_t { jsval_t val; const builtin_prop_t *p; DWORD ref; + unsigned idx; } u; int bucket_head; @@ -219,6 +221,23 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, return S_OK; } + if(This->builtin_info->idx_length) { + const WCHAR *ptr; + unsigned idx = 0; + + for(ptr = name; isdigitW(*ptr) && idx < 0x10000; ptr++) + idx = idx*10 + (*ptr-'0'); + if(!*ptr && idx < This->builtin_info->idx_length(This)) { + prop = alloc_prop(This, name, PROP_IDX, This->builtin_info->idx_put ? 0 : PROPF_CONST); + if(!prop) + return E_OUTOFMEMORY; + + prop->u.idx = idx; + *ret = prop; + return S_OK; + } + } + *ret = NULL; return S_OK; } @@ -383,10 +402,14 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t return disp_call_value(This->ctx, get_object(prop->u.val), jsthis, flags, argc, argv, r); } - default: - ERR("type %d\n", prop->type); + case PROP_IDX: + FIXME("Invoking PROP_IDX not yet supported\n"); + return E_NOTIMPL; + case PROP_DELETED: + assert(0); } + assert(0); return E_FAIL; } @@ -423,6 +446,9 @@ static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, DISPPARAMS *dp, case PROP_JSVAL: hres = jsval_copy(prop->u.val, r); break; + case PROP_IDX: + hres = This->builtin_info->idx_get(This, prop->u.idx, r); + break; default: ERR("type %d\n", prop->type); return E_FAIL; @@ -463,6 +489,8 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val, IServi case PROP_JSVAL: jsval_release(prop->u.val); break; + case PROP_IDX: + return This->builtin_info->idx_put(This, prop->u.idx, val); default: ERR("type %d\n", prop->type); return E_FAIL; @@ -479,7 +507,6 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val, IServi if(This->builtin_info->on_put) This->builtin_info->on_put(This, prop->name); - TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_jsval(val)); return S_OK; } diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 299fafba515..329bec2aef0 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -37,6 +37,12 @@ typedef struct { jsdisp_t *arguments; } FunctionInstance; +typedef struct { + jsdisp_t jsdisp; + FunctionInstance *function; + jsdisp_t *var_obj; +} ArgumentsInstance; + static inline FunctionInstance *function_from_vdisp(vdisp_t *vdisp) { return (FunctionInstance*)vdisp->u.jsdisp; @@ -77,61 +83,102 @@ static HRESULT Arguments_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, u return E_NOTIMPL; } +static void Arguments_destructor(jsdisp_t *jsdisp) +{ + ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp; + + jsdisp_release(&arguments->function->dispex); + jsdisp_release(arguments->var_obj); + heap_free(arguments); +} + +static unsigned Arguments_idx_length(jsdisp_t *jsdisp) +{ + ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp; + return arguments->function->length; +} + +static HRESULT Arguments_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *res) +{ + ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp; + + TRACE("%p[%u]\n", arguments, idx); + + /* FIXME: Accessing by name won't work for duplicated argument names */ + return jsdisp_propget_name(arguments->var_obj, arguments->function->func_code->params[idx], res); +} + +static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val) +{ + ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp; + + TRACE("%p[%u] = %s\n", arguments, idx, debugstr_jsval(val)); + + /* FIXME: Accessing by name won't work for duplicated argument names */ + return jsdisp_propput_name(arguments->var_obj, arguments->function->func_code->params[idx], val); +} + static const builtin_info_t Arguments_info = { JSCLASS_ARGUMENTS, {NULL, Arguments_value, 0}, 0, NULL, + Arguments_destructor, NULL, - NULL + Arguments_idx_length, + Arguments_idx_get, + Arguments_idx_put }; -static HRESULT create_arguments(script_ctx_t *ctx, IDispatch *calee, unsigned argc, jsval_t *argv, jsdisp_t **ret) +static HRESULT create_arguments(script_ctx_t *ctx, FunctionInstance *calee, jsdisp_t *var_obj, + unsigned argc, jsval_t *argv, jsdisp_t **ret) { - jsdisp_t *args; - DWORD i; + ArgumentsInstance *args; + unsigned i; HRESULT hres; static const WCHAR caleeW[] = {'c','a','l','l','e','e',0}; - args = heap_alloc_zero(sizeof(jsdisp_t)); + args = heap_alloc_zero(sizeof(*args)); if(!args) return E_OUTOFMEMORY; - hres = init_dispex_from_constr(args, ctx, &Arguments_info, ctx->object_constr); + hres = init_dispex_from_constr(&args->jsdisp, ctx, &Arguments_info, ctx->object_constr); if(FAILED(hres)) { heap_free(args); return hres; } - for(i=0; i < argc; i++) { + jsdisp_addref(&calee->dispex); + args->function = calee; + args->var_obj = jsdisp_addref(var_obj); + + /* Store unnamed arguments directly in arguments object */ + for(i = calee->length; i < argc; i++) { WCHAR buf[12]; static const WCHAR formatW[] = {'%','d',0}; sprintfW(buf, formatW, i); - hres = jsdisp_propput_dontenum(args, buf, argv[i]); + hres = jsdisp_propput_dontenum(&args->jsdisp, buf, argv[i]); if(FAILED(hres)) break; } if(SUCCEEDED(hres)) { - hres = jsdisp_propput_dontenum(args, lengthW, jsval_number(argc)); - + hres = jsdisp_propput_dontenum(&args->jsdisp, lengthW, jsval_number(argc)); if(SUCCEEDED(hres)) - hres = jsdisp_propput_dontenum(args, caleeW, jsval_disp(calee)); + hres = jsdisp_propput_dontenum(&args->jsdisp, caleeW, jsval_disp(to_disp(&calee->dispex))); } - if(FAILED(hres)) { - jsdisp_release(args); + jsdisp_release(&args->jsdisp); return hres; } - *ret = args; + *ret = &args->jsdisp; return S_OK; } -static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, jsdisp_t *arg_disp, - unsigned argc, jsval_t *argv, jsdisp_t **ret) +static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, unsigned argc, jsval_t *argv, jsdisp_t **ret) { jsdisp_t *var_disp; HRESULT hres; @@ -140,9 +187,7 @@ static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, js if(FAILED(hres)) return hres; - hres = jsdisp_propput_name(var_disp, argumentsW, jsval_obj(arg_disp)); - if(SUCCEEDED(hres)) - hres = init_parameters(var_disp, function, argc, argv); + hres = init_parameters(var_disp, function, argc, argv); if(FAILED(hres)) { jsdisp_release(var_disp); return hres; @@ -165,20 +210,23 @@ static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDis return E_FAIL; } - hres = create_arguments(ctx, to_disp(&function->dispex), argc, argv, &arg_disp); + hres = create_var_disp(ctx, function, argc, argv, &var_disp); if(FAILED(hres)) return hres; - hres = create_var_disp(ctx, function, arg_disp, argc, argv, &var_disp); + hres = create_arguments(ctx, function, var_disp, argc, argv, &arg_disp); if(FAILED(hres)) { - jsdisp_release(arg_disp); + jsdisp_release(var_disp); return hres; } - hres = scope_push(function->scope_chain, var_disp, to_disp(var_disp), &scope); + hres = jsdisp_propput_name(var_disp, argumentsW, jsval_obj(arg_disp)); if(SUCCEEDED(hres)) { - hres = create_exec_ctx(ctx, this_obj, var_disp, scope, FALSE, &exec_ctx); - scope_release(scope); + hres = scope_push(function->scope_chain, var_disp, to_disp(var_disp), &scope); + if(SUCCEEDED(hres)) { + hres = create_exec_ctx(ctx, this_obj, var_disp, scope, FALSE, &exec_ctx); + scope_release(scope); + } } jsdisp_release(var_disp); if(SUCCEEDED(hres)) { diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 0ab2e065038..1c848236ed7 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -200,6 +200,9 @@ typedef struct { const builtin_prop_t *props; void (*destructor)(jsdisp_t*); void (*on_put)(jsdisp_t*,const WCHAR*); + unsigned (*idx_length)(jsdisp_t*); + HRESULT (*idx_get)(jsdisp_t*,unsigned,jsval_t*); + HRESULT (*idx_put)(jsdisp_t*,unsigned,jsval_t); } builtin_info_t; struct jsdisp_t { diff --git a/dlls/jscript/tests/lang.js b/dlls/jscript/tests/lang.js index 4f5f29c7455..fa3d6d2aca7 100644 --- a/dlls/jscript/tests/lang.js +++ b/dlls/jscript/tests/lang.js @@ -74,6 +74,15 @@ function testFunc1(x, y) { ok(arguments.callee === testFunc1, "arguments.calee !== testFunc1"); ok(testFunc1.arguments === arguments, "testFunc1.arguments = " + testFunc1.arguments); + x = false; + ok(arguments[0] === false, "arguments[0] is not false"); + arguments[1] = "x"; + ok(y === "x", "y = " + y); + ok(arguments[1] === "x", "arguments[1] = " + arguments[1]); + + ok(arguments["0x0"] === undefined, "arguments['0x0'] = " + arguments["0x0"]); + ok(arguments["x"] === undefined, "arguments['x'] = " + arguments["x"]); + ok(this === test, "this !== test"); eval('ok(this === test, "this !== test");');