jscript: Alias arguments properties to real values.
This commit is contained in:
parent
4821b06ed1
commit
6b56c65f8d
|
@ -39,7 +39,8 @@ typedef enum {
|
||||||
PROP_JSVAL,
|
PROP_JSVAL,
|
||||||
PROP_BUILTIN,
|
PROP_BUILTIN,
|
||||||
PROP_PROTREF,
|
PROP_PROTREF,
|
||||||
PROP_DELETED
|
PROP_DELETED,
|
||||||
|
PROP_IDX
|
||||||
} prop_type_t;
|
} prop_type_t;
|
||||||
|
|
||||||
struct _dispex_prop_t {
|
struct _dispex_prop_t {
|
||||||
|
@ -52,6 +53,7 @@ struct _dispex_prop_t {
|
||||||
jsval_t val;
|
jsval_t val;
|
||||||
const builtin_prop_t *p;
|
const builtin_prop_t *p;
|
||||||
DWORD ref;
|
DWORD ref;
|
||||||
|
unsigned idx;
|
||||||
} u;
|
} u;
|
||||||
|
|
||||||
int bucket_head;
|
int bucket_head;
|
||||||
|
@ -219,6 +221,23 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name,
|
||||||
return S_OK;
|
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;
|
*ret = NULL;
|
||||||
return S_OK;
|
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);
|
return disp_call_value(This->ctx, get_object(prop->u.val), jsthis, flags, argc, argv, r);
|
||||||
}
|
}
|
||||||
default:
|
case PROP_IDX:
|
||||||
ERR("type %d\n", prop->type);
|
FIXME("Invoking PROP_IDX not yet supported\n");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
case PROP_DELETED:
|
||||||
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(0);
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,6 +446,9 @@ static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, DISPPARAMS *dp,
|
||||||
case PROP_JSVAL:
|
case PROP_JSVAL:
|
||||||
hres = jsval_copy(prop->u.val, r);
|
hres = jsval_copy(prop->u.val, r);
|
||||||
break;
|
break;
|
||||||
|
case PROP_IDX:
|
||||||
|
hres = This->builtin_info->idx_get(This, prop->u.idx, r);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ERR("type %d\n", prop->type);
|
ERR("type %d\n", prop->type);
|
||||||
return E_FAIL;
|
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:
|
case PROP_JSVAL:
|
||||||
jsval_release(prop->u.val);
|
jsval_release(prop->u.val);
|
||||||
break;
|
break;
|
||||||
|
case PROP_IDX:
|
||||||
|
return This->builtin_info->idx_put(This, prop->u.idx, val);
|
||||||
default:
|
default:
|
||||||
ERR("type %d\n", prop->type);
|
ERR("type %d\n", prop->type);
|
||||||
return E_FAIL;
|
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)
|
if(This->builtin_info->on_put)
|
||||||
This->builtin_info->on_put(This, prop->name);
|
This->builtin_info->on_put(This, prop->name);
|
||||||
|
|
||||||
TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_jsval(val));
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,12 @@ typedef struct {
|
||||||
jsdisp_t *arguments;
|
jsdisp_t *arguments;
|
||||||
} FunctionInstance;
|
} FunctionInstance;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
jsdisp_t jsdisp;
|
||||||
|
FunctionInstance *function;
|
||||||
|
jsdisp_t *var_obj;
|
||||||
|
} ArgumentsInstance;
|
||||||
|
|
||||||
static inline FunctionInstance *function_from_vdisp(vdisp_t *vdisp)
|
static inline FunctionInstance *function_from_vdisp(vdisp_t *vdisp)
|
||||||
{
|
{
|
||||||
return (FunctionInstance*)vdisp->u.jsdisp;
|
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;
|
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 = {
|
static const builtin_info_t Arguments_info = {
|
||||||
JSCLASS_ARGUMENTS,
|
JSCLASS_ARGUMENTS,
|
||||||
{NULL, Arguments_value, 0},
|
{NULL, Arguments_value, 0},
|
||||||
0, NULL,
|
0, NULL,
|
||||||
|
Arguments_destructor,
|
||||||
NULL,
|
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;
|
ArgumentsInstance *args;
|
||||||
DWORD i;
|
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};
|
||||||
|
|
||||||
args = heap_alloc_zero(sizeof(jsdisp_t));
|
args = heap_alloc_zero(sizeof(*args));
|
||||||
if(!args)
|
if(!args)
|
||||||
return E_OUTOFMEMORY;
|
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)) {
|
if(FAILED(hres)) {
|
||||||
heap_free(args);
|
heap_free(args);
|
||||||
return hres;
|
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];
|
WCHAR buf[12];
|
||||||
|
|
||||||
static const WCHAR formatW[] = {'%','d',0};
|
static const WCHAR formatW[] = {'%','d',0};
|
||||||
|
|
||||||
sprintfW(buf, formatW, i);
|
sprintfW(buf, formatW, i);
|
||||||
hres = jsdisp_propput_dontenum(args, buf, argv[i]);
|
hres = jsdisp_propput_dontenum(&args->jsdisp, buf, argv[i]);
|
||||||
if(FAILED(hres))
|
if(FAILED(hres))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(SUCCEEDED(hres)) {
|
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))
|
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)) {
|
if(FAILED(hres)) {
|
||||||
jsdisp_release(args);
|
jsdisp_release(&args->jsdisp);
|
||||||
return hres;
|
return hres;
|
||||||
}
|
}
|
||||||
|
|
||||||
*ret = args;
|
*ret = &args->jsdisp;
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, jsdisp_t *arg_disp,
|
static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, unsigned argc, jsval_t *argv, jsdisp_t **ret)
|
||||||
unsigned argc, jsval_t *argv, jsdisp_t **ret)
|
|
||||||
{
|
{
|
||||||
jsdisp_t *var_disp;
|
jsdisp_t *var_disp;
|
||||||
HRESULT hres;
|
HRESULT hres;
|
||||||
|
@ -140,9 +187,7 @@ static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, js
|
||||||
if(FAILED(hres))
|
if(FAILED(hres))
|
||||||
return hres;
|
return hres;
|
||||||
|
|
||||||
hres = jsdisp_propput_name(var_disp, argumentsW, jsval_obj(arg_disp));
|
hres = init_parameters(var_disp, function, argc, argv);
|
||||||
if(SUCCEEDED(hres))
|
|
||||||
hres = init_parameters(var_disp, function, argc, argv);
|
|
||||||
if(FAILED(hres)) {
|
if(FAILED(hres)) {
|
||||||
jsdisp_release(var_disp);
|
jsdisp_release(var_disp);
|
||||||
return hres;
|
return hres;
|
||||||
|
@ -165,20 +210,23 @@ static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDis
|
||||||
return E_FAIL;
|
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))
|
if(FAILED(hres))
|
||||||
return 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)) {
|
if(FAILED(hres)) {
|
||||||
jsdisp_release(arg_disp);
|
jsdisp_release(var_disp);
|
||||||
return hres;
|
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)) {
|
if(SUCCEEDED(hres)) {
|
||||||
hres = create_exec_ctx(ctx, this_obj, var_disp, scope, FALSE, &exec_ctx);
|
hres = scope_push(function->scope_chain, var_disp, to_disp(var_disp), &scope);
|
||||||
scope_release(scope);
|
if(SUCCEEDED(hres)) {
|
||||||
|
hres = create_exec_ctx(ctx, this_obj, var_disp, scope, FALSE, &exec_ctx);
|
||||||
|
scope_release(scope);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
jsdisp_release(var_disp);
|
jsdisp_release(var_disp);
|
||||||
if(SUCCEEDED(hres)) {
|
if(SUCCEEDED(hres)) {
|
||||||
|
|
|
@ -200,6 +200,9 @@ typedef struct {
|
||||||
const builtin_prop_t *props;
|
const builtin_prop_t *props;
|
||||||
void (*destructor)(jsdisp_t*);
|
void (*destructor)(jsdisp_t*);
|
||||||
void (*on_put)(jsdisp_t*,const WCHAR*);
|
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;
|
} builtin_info_t;
|
||||||
|
|
||||||
struct jsdisp_t {
|
struct jsdisp_t {
|
||||||
|
|
|
@ -74,6 +74,15 @@ function testFunc1(x, y) {
|
||||||
ok(arguments.callee === testFunc1, "arguments.calee !== testFunc1");
|
ok(arguments.callee === testFunc1, "arguments.calee !== testFunc1");
|
||||||
ok(testFunc1.arguments === arguments, "testFunc1.arguments = " + testFunc1.arguments);
|
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");
|
ok(this === test, "this !== test");
|
||||||
eval('ok(this === test, "this !== test");');
|
eval('ok(this === test, "this !== test");');
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue