-- v9: jscript: Remove PROP_IDX dispex props by handling them in object prop methods. jscript: Move filling the PROTREF into a helper. jscript: Simplify get_flags to only check whether it's enumerable. jscript: Get rid of on_put in the object vtbl. jscript: Inline prop_put. jscript: Inline prop_get. jscript: Inline invoke_prop_func and invoke PROTREFs using their vtbl method. jscript: Inline delete_prop. jscript: Use mandatory methods in the object vtbl to operate on props found jscript: Use mandatory methods in the object vtbl to operate on props mshtml/tests: Test redefining a writable indexed prop.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/tests/es5.js | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 353d0b0b5c0..57fde4d7c9d 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -829,6 +829,16 @@ sync_test("defineProperty", function() { test_accessor_prop_desc(child.prototype, "funcprop_prot", desc); ok(obj.funcprop_prot(100) === 10, "obj.funcprop_prot() = " + obj.funcprop_prot(100));
+ (function() { + ok(arguments.length === 3, "arguments.length = " + arguments.length); + ok(arguments[0] === 1, "arguments[0] = " + arguments[0]); + ok(arguments[1] === 2, "arguments[1] = " + arguments[1]); + ok(arguments[2] === 3, "arguments[2] = " + arguments[2]); + Object.defineProperty(arguments, "1", {value: "foobar", writable: false, enumerable: true, configurable: false}); + test_own_data_prop_desc(arguments, "1", false, true, false); + ok(arguments[1] === "foobar", "arguments[1] after defineProperty = " + arguments[1]); + })(1, 2, 3); + expect_exception(function() { Object.defineProperty(null, "funcprop", desc); }, JS_E_OBJECT_EXPECTED);
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/array.c | 3 + dlls/jscript/arraybuf.c | 6 ++ dlls/jscript/bool.c | 2 + dlls/jscript/date.c | 3 + dlls/jscript/dispex.c | 160 +++++++++++++++++++++----------------- dlls/jscript/engine.c | 3 +- dlls/jscript/enumerator.c | 3 + dlls/jscript/error.c | 2 + dlls/jscript/function.c | 5 ++ dlls/jscript/global.c | 1 + dlls/jscript/jscript.c | 2 +- dlls/jscript/jscript.h | 17 ++++ dlls/jscript/json.c | 1 + dlls/jscript/jsregexp.c | 3 + dlls/jscript/math.c | 1 + dlls/jscript/number.c | 2 + dlls/jscript/object.c | 3 + dlls/jscript/set.c | 6 ++ dlls/jscript/string.c | 3 + dlls/jscript/vbarray.c | 1 + 20 files changed, 153 insertions(+), 74 deletions(-)
diff --git a/dlls/jscript/array.c b/dlls/jscript/array.c index dfd9eda75cc..64a945f9d84 100644 --- a/dlls/jscript/array.c +++ b/dlls/jscript/array.c @@ -1635,6 +1635,7 @@ static const builtin_prop_t Array_props[] = { };
static const builtin_info_t Array_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_ARRAY, .props_cnt = ARRAY_SIZE(Array_props), .props = Array_props, @@ -1646,6 +1647,7 @@ static const builtin_prop_t ArrayInst_props[] = { };
static const builtin_info_t ArrayInst_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_ARRAY, .props_cnt = ARRAY_SIZE(ArrayInst_props), .props = ArrayInst_props, @@ -1752,6 +1754,7 @@ static const builtin_prop_t ArrayConstr_props[] = { };
static const builtin_info_t ArrayConstr_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_FUNCTION, .call = Function_value, .props_cnt = ARRAY_SIZE(ArrayConstr_props), diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index fc01773338f..c252dd27169 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -121,6 +121,7 @@ static const builtin_prop_t ArrayBuffer_props[] = { };
static const builtin_info_t ArrayBuffer_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_ARRAYBUFFER, .props_cnt = ARRAY_SIZE(ArrayBuffer_props), .props = ArrayBuffer_props, @@ -131,6 +132,7 @@ static const builtin_prop_t ArrayBufferInst_props[] = { };
static const builtin_info_t ArrayBufferInst_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_ARRAYBUFFER, .props_cnt = ARRAY_SIZE(ArrayBufferInst_props), .props = ArrayBufferInst_props, @@ -208,6 +210,7 @@ static const builtin_prop_t ArrayBufferConstr_props[] = { };
static const builtin_info_t ArrayBufferConstr_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_FUNCTION, .call = Function_value, .props_cnt = ARRAY_SIZE(ArrayBufferConstr_props), @@ -601,6 +604,7 @@ static HRESULT DataView_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op o }
static const builtin_info_t DataView_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_DATAVIEW, .props_cnt = ARRAY_SIZE(DataView_props), .props = DataView_props, @@ -609,6 +613,7 @@ static const builtin_info_t DataView_info = { };
static const builtin_info_t DataViewInst_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_DATAVIEW, .destructor = DataView_destructor, .gc_traverse = DataView_gc_traverse @@ -680,6 +685,7 @@ static HRESULT DataViewConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags }
static const builtin_info_t DataViewConstr_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_FUNCTION, .call = Function_value, }; diff --git a/dlls/jscript/bool.c b/dlls/jscript/bool.c index a4bbdec3a80..e8ddf653e82 100644 --- a/dlls/jscript/bool.c +++ b/dlls/jscript/bool.c @@ -119,6 +119,7 @@ static const builtin_prop_t Bool_props[] = { };
static const builtin_info_t Bool_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_BOOLEAN, .call = Bool_value, .props_cnt = ARRAY_SIZE(Bool_props), @@ -126,6 +127,7 @@ static const builtin_info_t Bool_info = { };
static const builtin_info_t BoolInst_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_BOOLEAN, .call = Bool_value, }; diff --git a/dlls/jscript/date.c b/dlls/jscript/date.c index d39b52177f6..87bb7b312ad 100644 --- a/dlls/jscript/date.c +++ b/dlls/jscript/date.c @@ -1900,12 +1900,14 @@ static const builtin_prop_t Date_props[] = { };
static const builtin_info_t Date_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_DATE, .props_cnt = ARRAY_SIZE(Date_props), .props = Date_props, };
static const builtin_info_t DateInst_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_DATE, };
@@ -2429,6 +2431,7 @@ static const builtin_prop_t DateConstr_props[] = { };
static const builtin_info_t DateConstr_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_FUNCTION, .call = Function_value, .props_cnt = ARRAY_SIZE(DateConstr_props), diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index a678421f0a3..47d4ec2f8bd 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -60,6 +60,11 @@ struct _dispex_prop_t { int bucket_next; };
+static inline DWORD prop_id_to_idx(DISPID id) +{ + return id - 1; +} + static void fix_protref_prop(jsdisp_t *jsdisp, dispex_prop_t *prop) { DWORD ref; @@ -84,15 +89,17 @@ static inline DISPID prop_to_id(jsdisp_t *This, dispex_prop_t *prop) return prop - This->props + 1; }
-static inline dispex_prop_t *get_prop(jsdisp_t *This, DISPID id) +static inline BOOL is_dispid_prop(jsdisp_t *This, DISPID id) { - DWORD idx = id - 1; + DWORD idx = prop_id_to_idx(id);
if(idx >= This->prop_cnt) - return NULL; + return FALSE; fix_protref_prop(This, &This->props[idx]);
- return This->props[idx].type == PROP_DELETED ? NULL : &This->props[idx]; + if(This->props[idx].type == PROP_DELETED) + return FALSE; + return TRUE; }
static inline BOOL is_function_prop(dispex_prop_t *prop) @@ -603,12 +610,67 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t return E_FAIL; }
+static HRESULT delete_prop(dispex_prop_t *prop, BOOL *ret) +{ + if(prop->type == PROP_PROTREF || prop->type == PROP_DELETED) { + *ret = TRUE; + return S_OK; + } + + if(!(prop->flags & PROPF_CONFIGURABLE)) { + *ret = FALSE; + return S_OK; + } + + *ret = TRUE; + + if(prop->type == PROP_JSVAL) + jsval_release(prop->u.val); + if(prop->type == PROP_ACCESSOR) { + if(prop->u.accessor.getter) + jsdisp_release(prop->u.accessor.getter); + if(prop->u.accessor.setter) + jsdisp_release(prop->u.accessor.setter); + } + prop->type = PROP_DELETED; + return S_OK; +} + HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value) { TRACE("%p %s\n", jsthis, debugstr_jsval(value)); return S_OK; }
+HRESULT dispex_prop_get(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, jsval_t *r) +{ + return prop_get(jsdisp, jsthis, &jsdisp->props[prop_id_to_idx(id)], r); +} + +HRESULT dispex_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t val) +{ + return prop_put(jsdisp, &jsdisp->props[prop_id_to_idx(id)], val); +} + +HRESULT dispex_prop_invoke(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, WORD flags, + unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) +{ + return invoke_prop_func(jsdisp, jsthis, &jsdisp->props[prop_id_to_idx(id)], flags, argc, argv, r, caller); +} + +HRESULT dispex_prop_delete(jsdisp_t *jsdisp, DISPID id, BOOL *ret) +{ + return delete_prop(&jsdisp->props[prop_id_to_idx(id)], ret); +} + +void *dispex_prop_get_name(jsdisp_t *jsdisp, DISPID id, BOOL bstr) +{ + const WCHAR *name = jsdisp->props[prop_id_to_idx(id)].name; + if(bstr) + return SysAllocString(name); + return jsstr_alloc(name); +} + static HRESULT fill_props(jsdisp_t *obj) { dispex_prop_t *prop; @@ -1916,7 +1978,6 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc { jsdisp_t *This = impl_from_IDispatchEx(iface); IServiceProvider *prev_caller; - dispex_prop_t *prop; jsexcept_t ei; HRESULT hres;
@@ -1925,8 +1986,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc if(pvarRes) V_VT(pvarRes) = VT_EMPTY;
- prop = get_prop(This, id); - if(!prop && id != DISPID_VALUE) { + if(!is_dispid_prop(This, id) && id != DISPID_VALUE) { TRACE("invalid id\n"); return DISP_E_MEMBERNOTFOUND; } @@ -1953,8 +2013,8 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc break;
passed_this = get_this(pdp); - if(prop) - hres = invoke_prop_func(This, passed_this, prop, wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller); + if(id != DISPID_VALUE) + hres = This->builtin_info->prop_invoke(This, passed_this, id, wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller); else hres = jsdisp_call_value(This, passed_this ? jsval_disp(passed_this) : jsval_undefined(), wFlags, argc, argv, pvarRes ? &r : NULL);
@@ -1971,8 +2031,8 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc case DISPATCH_PROPERTYGET: { jsval_t r;
- if(prop) - hres = prop_get(This, to_disp(This), prop, &r); + if(id != DISPID_VALUE) + hres = This->builtin_info->prop_get(This, to_disp(This), id, &r); else { hres = to_primitive(This->ctx, jsval_obj(This), &r, NO_HINT); if(hres == JS_E_TO_PRIMITIVE) @@ -1991,7 +2051,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc jsval_t val; DWORD i;
- if(!prop) { + if(id == DISPID_VALUE) { hres = DISP_E_MEMBERNOTFOUND; break; } @@ -2011,7 +2071,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc if(FAILED(hres)) break;
- hres = prop_put(This, prop, val); + This->builtin_info->prop_put(This, id, val); jsval_release(val); break; } @@ -2027,32 +2087,6 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc return leave_script(This->ctx, hres); }
-static HRESULT delete_prop(dispex_prop_t *prop, BOOL *ret) -{ - if(prop->type == PROP_PROTREF || prop->type == PROP_DELETED) { - *ret = TRUE; - return S_OK; - } - - if(!(prop->flags & PROPF_CONFIGURABLE)) { - *ret = FALSE; - return S_OK; - } - - *ret = TRUE; - - if(prop->type == PROP_JSVAL) - jsval_release(prop->u.val); - if(prop->type == PROP_ACCESSOR) { - if(prop->u.accessor.getter) - jsdisp_release(prop->u.accessor.getter); - if(prop->u.accessor.setter) - jsdisp_release(prop->u.accessor.setter); - } - prop->type = PROP_DELETED; - return S_OK; -} - static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) { jsdisp_t *This = impl_from_IDispatchEx(iface); @@ -2079,18 +2113,16 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bst static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) { jsdisp_t *This = impl_from_IDispatchEx(iface); - dispex_prop_t *prop; BOOL b;
TRACE("(%p)->(%lx)\n", This, id);
- prop = get_prop(This, id); - if(!prop) { + if(!is_dispid_prop(This, id)) { WARN("invalid id\n"); return DISP_E_MEMBERNOTFOUND; }
- return delete_prop(prop, &b); + return This->builtin_info->prop_delete(This, id, &b); }
static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) @@ -2103,15 +2135,13 @@ static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName) { jsdisp_t *This = impl_from_IDispatchEx(iface); - dispex_prop_t *prop;
TRACE("(%p)->(%lx %p)\n", This, id, pbstrName);
- prop = get_prop(This, id); - if(!prop) + if(!is_dispid_prop(This, id)) return DISP_E_MEMBERNOTFOUND;
- *pbstrName = SysAllocString(prop->name); + *pbstrName = This->builtin_info->prop_get_name(This, id, TRUE); if(!*pbstrName) return E_OUTOFMEMORY;
@@ -2204,7 +2234,7 @@ HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *b return S_OK; }
-static const builtin_info_t dispex_info = { .class = JSCLASS_NONE }; +static const builtin_info_t dispex_info = { DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_NONE };
HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype, jsdisp_t **dispex) { @@ -2381,13 +2411,10 @@ HRESULT jsdisp_call_value(jsdisp_t *jsfunc, jsval_t vthis, WORD flags, unsigned
HRESULT jsdisp_call(jsdisp_t *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - dispex_prop_t *prop; - - prop = get_prop(disp, id); - if(!prop) + if(!is_dispid_prop(disp, id)) return DISP_E_MEMBERNOTFOUND;
- return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, &disp->ctx->jscaller->IServiceProvider_iface); + return disp->builtin_info->prop_invoke(disp, to_disp(disp), id, flags, argc, argv, r, &disp->ctx->jscaller->IServiceProvider_iface); }
HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) @@ -2665,11 +2692,8 @@ HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val)
jsdisp = iface_to_jsdisp(disp); if(jsdisp && jsdisp->ctx == ctx) { - dispex_prop_t *prop; - - prop = get_prop(jsdisp, id); - if(prop) - hres = prop_put(jsdisp, prop, val); + if(is_dispid_prop(jsdisp, id)) + hres = jsdisp->builtin_info->prop_put(jsdisp, id, val); else hres = DISP_E_MEMBERNOTFOUND;
@@ -2771,13 +2795,10 @@ HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r)
HRESULT jsdisp_propget(jsdisp_t *jsdisp, DISPID id, jsval_t *val) { - dispex_prop_t *prop; - - prop = get_prop(jsdisp, id); - if(!prop) + if(!is_dispid_prop(jsdisp, id)) return DISP_E_MEMBERNOTFOUND;
- return prop_get(jsdisp, to_disp(jsdisp), prop, val); + return jsdisp->builtin_info->prop_get(jsdisp, to_disp(jsdisp), id, val); }
HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val) @@ -2832,11 +2853,8 @@ HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret)
jsdisp = iface_to_jsdisp(disp); if(jsdisp) { - dispex_prop_t *prop; - - prop = get_prop(jsdisp, id); - if(prop) - hres = delete_prop(prop, ret); + if(is_dispid_prop(jsdisp, id)) + hres = jsdisp->builtin_info->prop_delete(jsdisp, id, ret); else hres = DISP_E_MEMBERNOTFOUND;
@@ -3192,11 +3210,9 @@ BOOL jsdisp_is_frozen(jsdisp_t *obj, BOOL sealed)
HRESULT jsdisp_get_prop_name(jsdisp_t *obj, DISPID id, jsstr_t **r) { - dispex_prop_t *prop = get_prop(obj, id); - - if(!prop) + if(!is_dispid_prop(obj, id)) return DISP_E_MEMBERNOTFOUND;
- *r = jsstr_alloc(prop->name); + *r = obj->builtin_info->prop_get_name(obj, id, FALSE); return *r ? S_OK : E_OUTOFMEMORY; } diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index 60b479fb83b..2142b70e677 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -544,7 +544,8 @@ static HRESULT scope_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, }
static const builtin_info_t scope_info = { - JSCLASS_NONE, + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, + .class = JSCLASS_NONE, .destructor = scope_destructor, .idx_length = scope_idx_length, .idx_get = scope_idx_get, diff --git a/dlls/jscript/enumerator.c b/dlls/jscript/enumerator.c index 203bfa8b8e0..90bd98f19af 100644 --- a/dlls/jscript/enumerator.c +++ b/dlls/jscript/enumerator.c @@ -181,12 +181,14 @@ static const builtin_prop_t Enumerator_props[] = { };
static const builtin_info_t Enumerator_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_ENUMERATOR, .props_cnt = ARRAY_SIZE(Enumerator_props), .props = Enumerator_props, };
static const builtin_info_t EnumeratorInst_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_ENUMERATOR, .destructor = Enumerator_destructor, .gc_traverse = Enumerator_gc_traverse @@ -313,6 +315,7 @@ static HRESULT EnumeratorConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD fla }
static const builtin_info_t EnumeratorConstr_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_FUNCTION, .call = Function_value, }; diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index e1f04aef38c..5031ce935c1 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -139,6 +139,7 @@ static const builtin_prop_t Error_props[] = { };
static const builtin_info_t Error_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_ERROR, .call = Error_value, .props_cnt = ARRAY_SIZE(Error_props), @@ -146,6 +147,7 @@ static const builtin_info_t Error_info = { };
static const builtin_info_t ErrorInst_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_ERROR, .call = Error_value, }; diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 9c339b807f7..55ec36788c3 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -183,6 +183,7 @@ static HRESULT Arguments_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op }
static const builtin_info_t Arguments_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_ARGUMENTS, .call = Arguments_value, .destructor = Arguments_destructor, @@ -597,6 +598,7 @@ static const builtin_prop_t Function_props[] = { };
static const builtin_info_t Function_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_FUNCTION, .call = Function_value, .props_cnt = ARRAY_SIZE(Function_props), @@ -612,6 +614,7 @@ static const builtin_prop_t FunctionInst_props[] = { };
static const builtin_info_t FunctionInst_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_FUNCTION, .call = Function_value, .props_cnt = ARRAY_SIZE(FunctionInst_props), @@ -795,6 +798,7 @@ static const builtin_prop_t InterpretedFunction_props[] = { };
static const builtin_info_t InterpretedFunction_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_FUNCTION, .call = Function_value, .props_cnt = ARRAY_SIZE(InterpretedFunction_props), @@ -923,6 +927,7 @@ static const builtin_prop_t BindFunction_props[] = { };
static const builtin_info_t BindFunction_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_FUNCTION, .call = Function_value, .props_cnt = ARRAY_SIZE(BindFunction_props), diff --git a/dlls/jscript/global.c b/dlls/jscript/global.c index 2653d72cd2b..284c3aa9025 100644 --- a/dlls/jscript/global.c +++ b/dlls/jscript/global.c @@ -905,6 +905,7 @@ static const builtin_prop_t JSGlobal_props[] = { };
static const builtin_info_t JSGlobal_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_GLOBAL, .props_cnt = ARRAY_SIZE(JSGlobal_props), .props = JSGlobal_props, diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index fc07c818edf..8a983b13ce6 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -122,7 +122,7 @@ static inline BOOL is_started(script_ctx_t *ctx)
HRESULT create_named_item_script_obj(script_ctx_t *ctx, named_item_t *item) { - static const builtin_info_t disp_info = { .class = JSCLASS_GLOBAL }; + static const builtin_info_t disp_info = { DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_GLOBAL }; return create_dispex(ctx, &disp_info, NULL, &item->script_obj); }
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 80641731006..b51c1fa482c 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -130,6 +130,11 @@ typedef HRESULT (*builtin_getter_t)(script_ctx_t*,jsdisp_t*,jsval_t*); typedef HRESULT (*builtin_setter_t)(script_ctx_t*,jsdisp_t*,jsval_t);
HRESULT builtin_set_const(script_ctx_t*,jsdisp_t*,jsval_t); +HRESULT dispex_prop_get(jsdisp_t*,IDispatch*,DISPID,jsval_t*); +HRESULT dispex_prop_put(jsdisp_t*,DISPID,jsval_t); +HRESULT dispex_prop_invoke(jsdisp_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*); +HRESULT dispex_prop_delete(jsdisp_t*,DISPID,BOOL*); +void *dispex_prop_get_name(jsdisp_t*,DISPID,BOOL);
struct thread_data { LONG ref; @@ -185,6 +190,11 @@ typedef struct { const builtin_prop_t *props; void (*destructor)(jsdisp_t*); void (*on_put)(jsdisp_t*,const WCHAR*); + HRESULT (*prop_get)(jsdisp_t*,IDispatch*,DISPID,jsval_t*); + HRESULT (*prop_put)(jsdisp_t*,DISPID,jsval_t); + HRESULT (*prop_invoke)(jsdisp_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*); + HRESULT (*prop_delete)(jsdisp_t*,DISPID,BOOL*); + void *(*prop_get_name)(jsdisp_t*,DISPID,BOOL); unsigned (*idx_length)(jsdisp_t*); HRESULT (*idx_get)(jsdisp_t*,unsigned,jsval_t*); HRESULT (*idx_put)(jsdisp_t*,unsigned,jsval_t); @@ -211,6 +221,13 @@ struct jsdisp_t { struct list entry; };
+#define DEFAULT_DISPEX_PROP_VTBL_ENTRIES \ + .prop_get = dispex_prop_get, \ + .prop_put = dispex_prop_put, \ + .prop_invoke = dispex_prop_invoke, \ + .prop_delete = dispex_prop_delete, \ + .prop_get_name = dispex_prop_get_name + static inline IDispatch *to_disp(jsdisp_t *jsdisp) { return (IDispatch*)&jsdisp->IDispatchEx_iface; diff --git a/dlls/jscript/json.c b/dlls/jscript/json.c index b56d75d3570..e69caf090a2 100644 --- a/dlls/jscript/json.c +++ b/dlls/jscript/json.c @@ -948,6 +948,7 @@ static const builtin_prop_t JSON_props[] = { };
static const builtin_info_t JSON_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_JSON, .props_cnt = ARRAY_SIZE(JSON_props), .props = JSON_props, diff --git a/dlls/jscript/jsregexp.c b/dlls/jscript/jsregexp.c index e3a707b1f6b..ccddebcd6c6 100644 --- a/dlls/jscript/jsregexp.c +++ b/dlls/jscript/jsregexp.c @@ -569,6 +569,7 @@ static const builtin_prop_t RegExp_props[] = { };
static const builtin_info_t RegExp_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_REGEXP, .call = RegExp_value, .props_cnt = ARRAY_SIZE(RegExp_props), @@ -586,6 +587,7 @@ static const builtin_prop_t RegExpInst_props[] = { };
static const builtin_info_t RegExpInst_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_REGEXP, .call = RegExp_value, .props_cnt = ARRAY_SIZE(RegExpInst_props), @@ -952,6 +954,7 @@ static const builtin_prop_t RegExpConstr_props[] = { };
static const builtin_info_t RegExpConstr_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_FUNCTION, .call = Function_value, .props_cnt = ARRAY_SIZE(RegExpConstr_props), diff --git a/dlls/jscript/math.c b/dlls/jscript/math.c index 7739f27ab0f..28b3d5264a5 100644 --- a/dlls/jscript/math.c +++ b/dlls/jscript/math.c @@ -491,6 +491,7 @@ static const builtin_prop_t Math_props[] = { };
static const builtin_info_t Math_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_MATH, .props_cnt = ARRAY_SIZE(Math_props), .props = Math_props, }; diff --git a/dlls/jscript/number.c b/dlls/jscript/number.c index 711d9bee89f..842e8e00636 100644 --- a/dlls/jscript/number.c +++ b/dlls/jscript/number.c @@ -586,12 +586,14 @@ static const builtin_prop_t Number_props[] = { };
static const builtin_info_t Number_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_NUMBER, .props_cnt = ARRAY_SIZE(Number_props), .props = Number_props, };
static const builtin_info_t NumberInst_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_NUMBER, };
diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index 382f4107c45..da363cd92c9 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -460,12 +460,14 @@ static const builtin_prop_t Object_props[] = { };
static const builtin_info_t Object_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_OBJECT, .props_cnt = ARRAY_SIZE(Object_props), .props = Object_props, };
static const builtin_info_t ObjectInst_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_OBJECT, };
@@ -1057,6 +1059,7 @@ static const builtin_prop_t ObjectConstr_props[] = { };
static const builtin_info_t ObjectConstr_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_FUNCTION, .call = Function_value, .props_cnt = ARRAY_SIZE(ObjectConstr_props), diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index 5a568607a43..af37302b67c 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -399,6 +399,7 @@ static const builtin_prop_t Map_props[] = { };
static const builtin_info_t Map_prototype_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_OBJECT, .call = Map_value, .props_cnt = ARRAY_SIZE(Map_prototype_props), @@ -406,6 +407,7 @@ static const builtin_info_t Map_prototype_info = { };
static const builtin_info_t Map_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_MAP, .call = Map_value, .props_cnt = ARRAY_SIZE(Map_props), @@ -552,6 +554,7 @@ static const builtin_prop_t Set_prototype_props[] = { };
static const builtin_info_t Set_prototype_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_OBJECT, .call = Set_value, .props_cnt = ARRAY_SIZE(Set_prototype_props), @@ -559,6 +562,7 @@ static const builtin_info_t Set_prototype_info = { };
static const builtin_info_t Set_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_SET, .call = Set_value, .props_cnt = ARRAY_SIZE(Map_props), @@ -841,6 +845,7 @@ static const builtin_prop_t WeakMap_prototype_props[] = { };
static const builtin_info_t WeakMap_prototype_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_OBJECT, .call = WeakMap_value, .props_cnt = ARRAY_SIZE(WeakMap_prototype_props), @@ -848,6 +853,7 @@ static const builtin_info_t WeakMap_prototype_info = { };
static const builtin_info_t WeakMap_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_WEAKMAP, .call = WeakMap_value, .destructor = WeakMap_destructor, diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c index ab7497912f2..63cd24db05a 100644 --- a/dlls/jscript/string.c +++ b/dlls/jscript/string.c @@ -1568,6 +1568,7 @@ static const builtin_prop_t String_props[] = { };
static const builtin_info_t String_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_STRING, .props_cnt = ARRAY_SIZE(String_props), .props = String_props, @@ -1579,6 +1580,7 @@ static const builtin_prop_t StringInst_props[] = { };
static const builtin_info_t StringInst_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_STRING, .props_cnt = ARRAY_SIZE(StringInst_props), .props = StringInst_props, @@ -1698,6 +1700,7 @@ static const builtin_prop_t StringConstr_props[] = { };
static const builtin_info_t StringConstr_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_FUNCTION, .call = Function_value, .props_cnt = ARRAY_SIZE(StringConstr_props), diff --git a/dlls/jscript/vbarray.c b/dlls/jscript/vbarray.c index 55500c86769..c29ae83b8de 100644 --- a/dlls/jscript/vbarray.c +++ b/dlls/jscript/vbarray.c @@ -246,6 +246,7 @@ static const builtin_prop_t VBArray_props[] = { };
static const builtin_info_t VBArray_info = { + DEFAULT_DISPEX_PROP_VTBL_ENTRIES, .class = JSCLASS_VBARRAY, .call = VBArray_value, .props_cnt = ARRAY_SIZE(VBArray_props),
From: Gabriel Ivăncescu gabrielopcode@gmail.com
is_dispex_prop_id will be more useful later when we'll also have indexed props with their own vtbl, for now it avoids DISPID_VALUE.
dispex_prop_defineSigned-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 527 +++++++++++++++++++++-------------------- dlls/jscript/jscript.h | 13 +- 2 files changed, 287 insertions(+), 253 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 47d4ec2f8bd..7533c97cb25 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -251,7 +251,7 @@ static dispex_prop_t *alloc_protref(jsdisp_t *This, const WCHAR *name, DWORD ref return ret; }
-static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, dispex_prop_t **ret) +static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, DISPID *ret) { const builtin_prop_t *builtin; unsigned bucket, pos, prev = ~0; @@ -268,8 +268,8 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, This->props[bucket].bucket_head = pos; }
- *ret = &This->props[pos]; - return S_OK; + prop = &This->props[pos]; + goto ret; }
prev = pos; @@ -294,8 +294,7 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name,
prop->type = PROP_JSVAL; prop->u.val = jsval_obj(obj); - *ret = prop; - return S_OK; + goto ret; }else if(builtin->setter) flags |= PROPF_WRITABLE; flags &= PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE; @@ -304,8 +303,7 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, return E_OUTOFMEMORY;
prop->u.p = builtin; - *ret = prop; - return S_OK; + goto ret; }
if(This->builtin_info->idx_length) { @@ -323,79 +321,92 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, return E_OUTOFMEMORY;
prop->u.idx = idx; - *ret = prop; - return S_OK; + goto ret; } }
- *ret = NULL; - return S_OK; + *ret = 0; + return S_FALSE; + +ret: + *ret = prop_to_id(This, prop); + return prop->type != PROP_DELETED ? S_OK : S_FALSE; }
-static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, dispex_prop_t **ret) +static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, DISPID *ret) { - dispex_prop_t *prop, *del=NULL; + dispex_prop_t *prop, *del = NULL; HRESULT hres;
- hres = find_prop_name(This, hash, name, case_insens, &prop); + hres = find_prop_name(This, hash, name, case_insens, ret); if(FAILED(hres)) return hres; - if(prop && prop->type==PROP_DELETED) { - del = prop; - } else if(prop) { + + if(hres == S_OK) { + prop = &This->props[prop_id_to_idx(*ret)]; fix_protref_prop(This, prop); - *ret = prop; - return S_OK; + return prop->type != PROP_DELETED ? S_OK : S_FALSE; }
+ if(is_dispex_prop_id(*ret)) + del = &This->props[prop_id_to_idx(*ret)]; + if(This->prototype) { - hres = find_prop_name_prot(This->prototype, hash, name, case_insens, &prop); + hres = find_prop_name_prot(This->prototype, hash, name, case_insens, ret); if(FAILED(hres)) return hres; - if(prop && prop->type != PROP_DELETED) { + if(hres == S_OK) { + DWORD ref = prop_id_to_idx(*ret); + if(del) { del->type = PROP_PROTREF; - del->u.ref = prop - This->prototype->props; + del->u.ref = ref; prop = del; }else { - prop = alloc_protref(This, prop->name, prop - This->prototype->props); + /* Case insensitive name lookups can differ from the prototype prop's actual name */ + prop = alloc_protref(This, This->prototype->props[ref].name, ref); if(!prop) return E_OUTOFMEMORY; } - - *ret = prop; - return S_OK; + goto ret; } }
- *ret = del; - return S_OK; + if(!del) { + *ret = 0; + return S_FALSE; + } + prop = del; + +ret: + *ret = prop_to_id(This, prop); + return prop->type != PROP_DELETED ? S_OK : S_FALSE; }
-static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_flags, BOOL case_insens, dispex_prop_t **ret) +static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_flags, BOOL case_insens, DISPID *ret) { dispex_prop_t *prop; HRESULT hres;
- hres = find_prop_name_prot(This, string_hash(name), name, case_insens, &prop); - if(SUCCEEDED(hres) && (!prop || prop->type == PROP_DELETED)) { - TRACE("creating prop %s flags %lx\n", debugstr_w(name), create_flags); - - if(prop) { - prop->type = PROP_JSVAL; - prop->flags = create_flags; - prop->u.val = jsval_undefined(); - }else { - prop = alloc_prop(This, name, PROP_JSVAL, create_flags); - if(!prop) - return E_OUTOFMEMORY; - } + hres = find_prop_name_prot(This, string_hash(name), name, case_insens, ret); + if(hres != S_FALSE) + return hres;
- prop->u.val = jsval_undefined(); + if(is_dispex_prop_id(*ret)) { + prop = &This->props[prop_id_to_idx(*ret)]; + prop->type = PROP_JSVAL; + prop->flags = create_flags; + }else { + prop = alloc_prop(This, name, PROP_JSVAL, create_flags); + if(!prop) + return E_OUTOFMEMORY; }
- *ret = prop; - return hres; + TRACE("creating prop %s flags %lx\n", debugstr_w(name), create_flags); + + prop->u.val = jsval_undefined(); + *ret = prop_to_id(This, prop); + return S_OK; }
static IDispatch *get_this(DISPPARAMS *dp) @@ -663,6 +674,38 @@ HRESULT dispex_prop_delete(jsdisp_t *jsdisp, DISPID id, BOOL *ret) return delete_prop(&jsdisp->props[prop_id_to_idx(id)], ret); }
+HRESULT dispex_prop_get_desc(jsdisp_t *jsdisp, DISPID id, BOOL flags_only, property_desc_t *desc) +{ + dispex_prop_t *prop = &jsdisp->props[prop_id_to_idx(id)]; + HRESULT hres; + + switch(prop->type) { + case PROP_BUILTIN: + case PROP_JSVAL: + case PROP_IDX: + desc->explicit_value = TRUE; + if(!flags_only) { + hres = dispex_prop_get(jsdisp, to_disp(jsdisp), id, &desc->value); + if(FAILED(hres)) + return hres; + } + break; + case PROP_ACCESSOR: + desc->mask = PROPF_ENUMERABLE | PROPF_CONFIGURABLE; + desc->explicit_getter = desc->explicit_setter = TRUE; + if(!flags_only) { + desc->getter = prop->u.accessor.getter ? jsdisp_addref(prop->u.accessor.getter) : NULL; + desc->setter = prop->u.accessor.setter ? jsdisp_addref(prop->u.accessor.setter) : NULL; + } + break; + default: + return DISP_E_UNKNOWNNAME; + } + + desc->flags = prop->flags & (PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE); + return S_OK; +} + void *dispex_prop_get_name(jsdisp_t *jsdisp, DISPID id, BOOL bstr) { const WCHAR *name = jsdisp->props[prop_id_to_idx(id)].name; @@ -671,10 +714,131 @@ void *dispex_prop_get_name(jsdisp_t *jsdisp, DISPID id, BOOL bstr) return jsstr_alloc(name); }
+HRESULT dispex_prop_define(jsdisp_t *jsdisp, DISPID id, const property_desc_t *desc) +{ + dispex_prop_t *prop = &jsdisp->props[prop_id_to_idx(id)]; + script_ctx_t *ctx = jsdisp->ctx; + HRESULT hres; + + if(prop->type == PROP_DELETED || prop->type == PROP_PROTREF) { + if(prop->type == PROP_PROTREF && !jsdisp->extensible) + return throw_error(ctx, JS_E_OBJECT_NONEXTENSIBLE, prop->name); + + prop->flags = desc->flags; + if(desc->explicit_getter || desc->explicit_setter) { + prop->type = PROP_ACCESSOR; + prop->u.accessor.getter = desc->getter ? jsdisp_addref(desc->getter) : NULL; + prop->u.accessor.setter = desc->setter ? jsdisp_addref(desc->setter) : NULL; + TRACE("%s = accessor { get: %p set: %p }\n", debugstr_w(prop->name), + prop->u.accessor.getter, prop->u.accessor.setter); + }else { + prop->type = PROP_JSVAL; + if(desc->explicit_value) { + hres = jsval_copy(desc->value, &prop->u.val); + if(FAILED(hres)) + return hres; + }else { + prop->u.val = jsval_undefined(); + } + TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_jsval(prop->u.val)); + } + return S_OK; + } + + TRACE("existing prop %s prop flags %lx desc flags %x desc mask %x\n", debugstr_w(prop->name), + prop->flags, desc->flags, desc->mask); + + if(!(prop->flags & PROPF_CONFIGURABLE)) { + if(((desc->mask & PROPF_CONFIGURABLE) && (desc->flags & PROPF_CONFIGURABLE)) + || ((desc->mask & PROPF_ENUMERABLE) + && ((desc->flags & PROPF_ENUMERABLE) != (prop->flags & PROPF_ENUMERABLE)))) + return throw_error(ctx, JS_E_NONCONFIGURABLE_REDEFINED, prop->name); + } + + if(desc->explicit_value || (desc->mask & PROPF_WRITABLE)) { + if(prop->type == PROP_ACCESSOR) { + if(!(prop->flags & PROPF_CONFIGURABLE)) + return throw_error(ctx, JS_E_NONCONFIGURABLE_REDEFINED, prop->name); + if(prop->u.accessor.getter) + jsdisp_release(prop->u.accessor.getter); + if(prop->u.accessor.setter) + jsdisp_release(prop->u.accessor.setter); + + prop->type = PROP_JSVAL; + hres = jsval_copy(desc->value, &prop->u.val); + if(FAILED(hres)) { + prop->u.val = jsval_undefined(); + return hres; + } + }else { + if(!(prop->flags & PROPF_CONFIGURABLE) && !(prop->flags & PROPF_WRITABLE)) { + if((desc->mask & PROPF_WRITABLE) && (desc->flags & PROPF_WRITABLE)) + return throw_error(ctx, JS_E_NONWRITABLE_MODIFIED, prop->name); + if(desc->explicit_value) { + if(prop->type == PROP_JSVAL) { + BOOL eq; + hres = jsval_strict_equal(desc->value, prop->u.val, &eq); + if(FAILED(hres)) + return hres; + if(!eq) + return throw_error(ctx, JS_E_NONWRITABLE_MODIFIED, prop->name); + }else { + FIXME("redefinition of property type %d\n", prop->type); + } + } + } + if(desc->explicit_value) { + if(prop->type == PROP_JSVAL) + jsval_release(prop->u.val); + else + prop->type = PROP_JSVAL; + hres = jsval_copy(desc->value, &prop->u.val); + if(FAILED(hres)) { + prop->u.val = jsval_undefined(); + return hres; + } + } + } + }else if(desc->explicit_getter || desc->explicit_setter) { + if(prop->type != PROP_ACCESSOR) { + if(!(prop->flags & PROPF_CONFIGURABLE)) + return throw_error(ctx, JS_E_NONCONFIGURABLE_REDEFINED, prop->name); + if(prop->type == PROP_JSVAL) + jsval_release(prop->u.val); + prop->type = PROP_ACCESSOR; + prop->u.accessor.getter = prop->u.accessor.setter = NULL; + }else if(!(prop->flags & PROPF_CONFIGURABLE)) { + if((desc->explicit_getter && desc->getter != prop->u.accessor.getter) + || (desc->explicit_setter && desc->setter != prop->u.accessor.setter)) + return throw_error(ctx, JS_E_NONCONFIGURABLE_REDEFINED, prop->name); + } + + if(desc->explicit_getter) { + if(prop->u.accessor.getter) { + jsdisp_release(prop->u.accessor.getter); + prop->u.accessor.getter = NULL; + } + if(desc->getter) + prop->u.accessor.getter = jsdisp_addref(desc->getter); + } + if(desc->explicit_setter) { + if(prop->u.accessor.setter) { + jsdisp_release(prop->u.accessor.setter); + prop->u.accessor.setter = NULL; + } + if(desc->setter) + prop->u.accessor.setter = jsdisp_addref(desc->setter); + } + } + + prop->flags = (prop->flags & ~desc->mask) | (desc->flags & desc->mask); + return S_OK; +} + static HRESULT fill_props(jsdisp_t *obj) { - dispex_prop_t *prop; HRESULT hres; + DISPID id;
if(obj->builtin_info->idx_length) { unsigned i = 0, len = obj->builtin_info->idx_length(obj); @@ -682,7 +846,7 @@ static HRESULT fill_props(jsdisp_t *obj)
for(i = 0; i < len; i++) { swprintf(name, ARRAY_SIZE(name), L"%u", i); - hres = find_prop_name(obj, string_hash(name), name, FALSE, &prop); + hres = find_prop_name(obj, string_hash(name), name, FALSE, &id); if(FAILED(hres)) return hres; } @@ -693,8 +857,9 @@ static HRESULT fill_props(jsdisp_t *obj)
static HRESULT fill_protrefs(jsdisp_t *This) { - dispex_prop_t *iter, *prop; + dispex_prop_t *iter; HRESULT hres; + DISPID id;
hres = fill_props(This); if(FAILED(hres)) @@ -708,18 +873,17 @@ static HRESULT fill_protrefs(jsdisp_t *This) return hres;
for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) { - hres = find_prop_name(This, iter->hash, iter->name, FALSE, &prop); + hres = find_prop_name(This, iter->hash, iter->name, FALSE, &id); if(FAILED(hres)) return hres; - if(!prop || prop->type==PROP_DELETED) { - if(prop) { - prop->type = PROP_PROTREF; - prop->flags = 0; - prop->u.ref = iter - This->prototype->props; - }else { - prop = alloc_protref(This, iter->name, iter - This->prototype->props); - if(!prop) - return E_OUTOFMEMORY; + if(hres != S_OK) { + if(is_dispex_prop_id(id)) { + dispex_prop_t *p = &This->props[prop_id_to_idx(id)]; + p->type = PROP_PROTREF; + p->flags = 0; + p->u.ref = iter - This->prototype->props; + }else if(!alloc_protref(This, iter->name, iter - This->prototype->props)) { + return E_OUTOFMEMORY; } } } @@ -2090,7 +2254,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) { jsdisp_t *This = impl_from_IDispatchEx(iface); - dispex_prop_t *prop; + DISPID id; BOOL b; HRESULT hres;
@@ -2099,15 +2263,15 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bst if(grfdex & ~(fdexNameCaseSensitive|fdexNameCaseInsensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) FIXME("Unsupported grfdex %lx\n", grfdex);
- hres = find_prop_name(This, string_hash(bstrName), bstrName, grfdex & fdexNameCaseInsensitive, &prop); + hres = find_prop_name(This, string_hash(bstrName), bstrName, grfdex & fdexNameCaseInsensitive, &id); if(FAILED(hres)) return hres; - if(!prop) { + if(hres != S_OK) { TRACE("not found\n"); return S_OK; }
- return delete_prop(prop, &b); + return This->builtin_info->prop_delete(This, id, &b); }
static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) @@ -2320,14 +2484,14 @@ void jsdisp_release(jsdisp_t *jsdisp) HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *constr) { jsdisp_t *prot = NULL; - dispex_prop_t *prop; HRESULT hres; + DISPID id;
- hres = find_prop_name_prot(constr, string_hash(L"prototype"), L"prototype", FALSE, &prop); - if(SUCCEEDED(hres) && prop && prop->type!=PROP_DELETED) { + hres = find_prop_name_prot(constr, string_hash(L"prototype"), L"prototype", FALSE, &id); + if(hres == S_OK) { jsval_t val;
- hres = prop_get(constr, to_disp(constr), prop, &val); + hres = constr->builtin_info->prop_get(constr, to_disp(constr), id, &val); if(FAILED(hres)) { ERR("Could not get prototype\n"); return hres; @@ -2357,21 +2521,18 @@ jsdisp_t *iface_to_jsdisp(IDispatch *iface)
HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID *id) { - dispex_prop_t *prop; HRESULT hres;
if(jsdisp->extensible && (flags & fdexNameEnsure)) hres = ensure_prop_name(jsdisp, name, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE, - flags & fdexNameCaseInsensitive, &prop); + flags & fdexNameCaseInsensitive, id); else - hres = find_prop_name_prot(jsdisp, string_hash(name), name, flags & fdexNameCaseInsensitive, &prop); + hres = find_prop_name_prot(jsdisp, string_hash(name), name, flags & fdexNameCaseInsensitive, id); if(FAILED(hres)) return hres;
- if(prop && prop->type!=PROP_DELETED) { - *id = prop_to_id(jsdisp, prop); + if(hres == S_OK) return S_OK; - }
TRACE("not found %s\n", debugstr_w(name)); *id = DISPID_UNKNOWN; @@ -2419,17 +2580,14 @@ HRESULT jsdisp_call(jsdisp_t *disp, DISPID id, WORD flags, unsigned argc, jsval_
HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - dispex_prop_t *prop; HRESULT hres; + DISPID id;
- hres = find_prop_name_prot(disp, string_hash(name), name, FALSE, &prop); - if(FAILED(hres)) - return hres; - - if(!prop || prop->type == PROP_DELETED) - return JS_E_INVALID_PROPERTY; + hres = find_prop_name_prot(disp, string_hash(name), name, FALSE, &id); + if(hres != S_OK) + return FAILED(hres) ? hres : JS_E_INVALID_PROPERTY;
- return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, &disp->ctx->jscaller->IServiceProvider_iface); + return disp->builtin_info->prop_invoke(disp, to_disp(disp), id, flags, argc, argv, r, &disp->ctx->jscaller->IServiceProvider_iface); }
static HRESULT disp_invoke(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, DISPPARAMS *params, VARIANT *r, @@ -2657,19 +2815,19 @@ HRESULT disp_call_value_with_caller(script_ctx_t *ctx, IDispatch *disp, jsval_t
HRESULT jsdisp_propput(jsdisp_t *obj, const WCHAR *name, DWORD flags, BOOL throw, jsval_t val) { - dispex_prop_t *prop; HRESULT hres; + DISPID id;
if(obj->extensible) - hres = ensure_prop_name(obj, name, flags, FALSE, &prop); + hres = ensure_prop_name(obj, name, flags, FALSE, &id); else - hres = find_prop_name(obj, string_hash(name), name, FALSE, &prop); + hres = find_prop_name(obj, string_hash(name), name, FALSE, &id); if(FAILED(hres)) return hres; - if(!prop || (prop->type == PROP_DELETED && !obj->extensible)) + if(hres != S_OK && (!id || !obj->extensible)) return throw ? JS_E_INVALID_ACTION : S_OK;
- return prop_put(obj, prop, val); + return obj->builtin_info->prop_put(obj, id, val); }
HRESULT jsdisp_propput_name(jsdisp_t *obj, const WCHAR *name, jsval_t val) @@ -2758,39 +2916,39 @@ HRESULT disp_propput_name(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name,
HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val) { - dispex_prop_t *prop; HRESULT hres; + DISPID id;
- hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, &prop); + hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, &id); if(FAILED(hres)) return hres;
- if(!prop || prop->type==PROP_DELETED) { + if(hres != S_OK) { *val = jsval_undefined(); return S_OK; }
- return prop_get(obj, to_disp(obj), prop, val); + return obj->builtin_info->prop_get(obj, to_disp(obj), id, val); }
HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r) { WCHAR name[12]; - dispex_prop_t *prop; HRESULT hres; + DISPID id;
swprintf(name, ARRAY_SIZE(name), L"%d", idx);
- hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, &prop); + hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, &id); if(FAILED(hres)) return hres;
- if(!prop || prop->type==PROP_DELETED) { + if(hres != S_OK) { *r = jsval_undefined(); return DISP_E_UNKNOWNNAME; }
- return prop_get(obj, to_disp(obj), prop, r); + return obj->builtin_info->prop_get(obj, to_disp(obj), id, r); }
HRESULT jsdisp_propget(jsdisp_t *jsdisp, DISPID id, jsval_t *val) @@ -2829,17 +2987,17 @@ HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val HRESULT jsdisp_delete_idx(jsdisp_t *obj, DWORD idx) { WCHAR buf[12]; - dispex_prop_t *prop; + DISPID id; BOOL b; HRESULT hres;
swprintf(buf, ARRAY_SIZE(buf), L"%d", idx);
- hres = find_prop_name(obj, string_hash(buf), buf, FALSE, &prop); - if(FAILED(hres) || !prop) - return hres; + hres = find_prop_name(obj, string_hash(buf), buf, FALSE, &id); + if(hres != S_OK) + return FAILED(hres) ? hres : S_OK;
- hres = delete_prop(prop, &b); + hres = obj->builtin_info->prop_delete(obj, id, &b); if(FAILED(hres)) return hres; return b ? S_OK : JS_E_INVALID_ACTION; @@ -2919,8 +3077,8 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL
jsdisp = iface_to_jsdisp(disp); if(jsdisp) { - dispex_prop_t *prop; const WCHAR *ptr; + DISPID id;
ptr = jsstr_flatten(name); if(!ptr) { @@ -2928,9 +3086,9 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL return E_OUTOFMEMORY; }
- hres = find_prop_name(jsdisp, string_hash(ptr), ptr, FALSE, &prop); - if(prop) { - hres = delete_prop(prop, ret); + hres = find_prop_name(jsdisp, string_hash(ptr), ptr, FALSE, &id); + if(hres == S_OK) { + hres = jsdisp->builtin_info->prop_delete(jsdisp, id, ret); }else { *ret = TRUE; hres = S_OK; @@ -2972,173 +3130,38 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_only, property_desc_t *desc) { - dispex_prop_t *prop; HRESULT hres; + DISPID id;
- hres = find_prop_name(obj, string_hash(name), name, FALSE, &prop); - if(FAILED(hres)) - return hres; - - if(!prop) - return DISP_E_UNKNOWNNAME; + hres = find_prop_name(obj, string_hash(name), name, FALSE, &id); + if(hres != S_OK) + return FAILED(hres) ? hres : DISP_E_UNKNOWNNAME;
memset(desc, 0, sizeof(*desc)); - - switch(prop->type) { - case PROP_BUILTIN: - case PROP_JSVAL: - case PROP_IDX: - desc->mask |= PROPF_WRITABLE; - desc->explicit_value = TRUE; - if(!flags_only) { - hres = prop_get(obj, to_disp(obj), prop, &desc->value); - if(FAILED(hres)) - return hres; - } - break; - case PROP_ACCESSOR: - desc->explicit_getter = desc->explicit_setter = TRUE; - if(!flags_only) { - desc->getter = prop->u.accessor.getter - ? jsdisp_addref(prop->u.accessor.getter) : NULL; - desc->setter = prop->u.accessor.setter - ? jsdisp_addref(prop->u.accessor.setter) : NULL; - } - break; - default: - return DISP_E_UNKNOWNNAME; - } - - desc->flags = prop->flags & (PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE); - desc->mask |= PROPF_ENUMERABLE | PROPF_CONFIGURABLE; - return S_OK; + desc->mask = PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE; + return obj->builtin_info->prop_get_desc(obj, id, flags_only, desc); }
HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t *desc) { - dispex_prop_t *prop; HRESULT hres; + DISPID id;
- hres = find_prop_name(obj, string_hash(name), name, FALSE, &prop); + hres = find_prop_name(obj, string_hash(name), name, FALSE, &id); if(FAILED(hres)) return hres;
- if((!prop || prop->type == PROP_DELETED || prop->type == PROP_PROTREF) && !obj->extensible) + if(hres != S_OK && !obj->extensible) return throw_error(obj->ctx, JS_E_OBJECT_NONEXTENSIBLE, name);
- if(!prop && !(prop = alloc_prop(obj, name, PROP_DELETED, 0))) - return E_OUTOFMEMORY; - - if(prop->type == PROP_DELETED || prop->type == PROP_PROTREF) { - prop->flags = desc->flags; - if(desc->explicit_getter || desc->explicit_setter) { - prop->type = PROP_ACCESSOR; - prop->u.accessor.getter = desc->getter ? jsdisp_addref(desc->getter) : NULL; - prop->u.accessor.setter = desc->setter ? jsdisp_addref(desc->setter) : NULL; - TRACE("%s = accessor { get: %p set: %p }\n", debugstr_w(name), - prop->u.accessor.getter, prop->u.accessor.setter); - }else { - prop->type = PROP_JSVAL; - if(desc->explicit_value) { - hres = jsval_copy(desc->value, &prop->u.val); - if(FAILED(hres)) - return hres; - }else { - prop->u.val = jsval_undefined(); - } - TRACE("%s = %s\n", debugstr_w(name), debugstr_jsval(prop->u.val)); - } - return S_OK; - } - - TRACE("existing prop %s prop flags %lx desc flags %x desc mask %x\n", debugstr_w(name), - prop->flags, desc->flags, desc->mask); - - if(!(prop->flags & PROPF_CONFIGURABLE)) { - if(((desc->mask & PROPF_CONFIGURABLE) && (desc->flags & PROPF_CONFIGURABLE)) - || ((desc->mask & PROPF_ENUMERABLE) - && ((desc->flags & PROPF_ENUMERABLE) != (prop->flags & PROPF_ENUMERABLE)))) - return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name); - } - - if(desc->explicit_value || (desc->mask & PROPF_WRITABLE)) { - if(prop->type == PROP_ACCESSOR) { - if(!(prop->flags & PROPF_CONFIGURABLE)) - return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name); - if(prop->u.accessor.getter) - jsdisp_release(prop->u.accessor.getter); - if(prop->u.accessor.setter) - jsdisp_release(prop->u.accessor.setter); - - prop->type = PROP_JSVAL; - hres = jsval_copy(desc->value, &prop->u.val); - if(FAILED(hres)) { - prop->u.val = jsval_undefined(); - return hres; - } - }else { - if(!(prop->flags & PROPF_CONFIGURABLE) && !(prop->flags & PROPF_WRITABLE)) { - if((desc->mask & PROPF_WRITABLE) && (desc->flags & PROPF_WRITABLE)) - return throw_error(obj->ctx, JS_E_NONWRITABLE_MODIFIED, name); - if(desc->explicit_value) { - if(prop->type == PROP_JSVAL) { - BOOL eq; - hres = jsval_strict_equal(desc->value, prop->u.val, &eq); - if(FAILED(hres)) - return hres; - if(!eq) - return throw_error(obj->ctx, JS_E_NONWRITABLE_MODIFIED, name); - }else { - FIXME("redefinition of property type %d\n", prop->type); - } - } - } - if(desc->explicit_value) { - if(prop->type == PROP_JSVAL) - jsval_release(prop->u.val); - else - prop->type = PROP_JSVAL; - hres = jsval_copy(desc->value, &prop->u.val); - if(FAILED(hres)) { - prop->u.val = jsval_undefined(); - return hres; - } - } - } - }else if(desc->explicit_getter || desc->explicit_setter) { - if(prop->type != PROP_ACCESSOR) { - if(!(prop->flags & PROPF_CONFIGURABLE)) - return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name); - if(prop->type == PROP_JSVAL) - jsval_release(prop->u.val); - prop->type = PROP_ACCESSOR; - prop->u.accessor.getter = prop->u.accessor.setter = NULL; - }else if(!(prop->flags & PROPF_CONFIGURABLE)) { - if((desc->explicit_getter && desc->getter != prop->u.accessor.getter) - || (desc->explicit_setter && desc->setter != prop->u.accessor.setter)) - return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name); - } - - if(desc->explicit_getter) { - if(prop->u.accessor.getter) { - jsdisp_release(prop->u.accessor.getter); - prop->u.accessor.getter = NULL; - } - if(desc->getter) - prop->u.accessor.getter = jsdisp_addref(desc->getter); - } - if(desc->explicit_setter) { - if(prop->u.accessor.setter) { - jsdisp_release(prop->u.accessor.setter); - prop->u.accessor.setter = NULL; - } - if(desc->setter) - prop->u.accessor.setter = jsdisp_addref(desc->setter); - } + if(!id) { + dispex_prop_t *prop = alloc_prop(obj, name, PROP_DELETED, 0); + if(!prop) + return E_OUTOFMEMORY; + id = prop_to_id(obj, prop); }
- prop->flags = (prop->flags & ~desc->mask) | (desc->flags & desc->mask); - return S_OK; + return obj->builtin_info->prop_define(obj, id, desc); }
HRESULT jsdisp_define_data_property(jsdisp_t *obj, const WCHAR *name, unsigned flags, jsval_t value) diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index b51c1fa482c..93c7eb5aadd 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -134,7 +134,9 @@ HRESULT dispex_prop_get(jsdisp_t*,IDispatch*,DISPID,jsval_t*); HRESULT dispex_prop_put(jsdisp_t*,DISPID,jsval_t); HRESULT dispex_prop_invoke(jsdisp_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*); HRESULT dispex_prop_delete(jsdisp_t*,DISPID,BOOL*); +HRESULT dispex_prop_get_desc(jsdisp_t*,DISPID,BOOL,property_desc_t*); void *dispex_prop_get_name(jsdisp_t*,DISPID,BOOL); +HRESULT dispex_prop_define(jsdisp_t*,DISPID,const property_desc_t*);
struct thread_data { LONG ref; @@ -194,7 +196,9 @@ typedef struct { HRESULT (*prop_put)(jsdisp_t*,DISPID,jsval_t); HRESULT (*prop_invoke)(jsdisp_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*); HRESULT (*prop_delete)(jsdisp_t*,DISPID,BOOL*); + HRESULT (*prop_get_desc)(jsdisp_t*,DISPID,BOOL,property_desc_t*); void *(*prop_get_name)(jsdisp_t*,DISPID,BOOL); + HRESULT (*prop_define)(jsdisp_t*,DISPID,const property_desc_t*); unsigned (*idx_length)(jsdisp_t*); HRESULT (*idx_get)(jsdisp_t*,unsigned,jsval_t*); HRESULT (*idx_put)(jsdisp_t*,unsigned,jsval_t); @@ -226,7 +230,9 @@ struct jsdisp_t { .prop_put = dispex_prop_put, \ .prop_invoke = dispex_prop_invoke, \ .prop_delete = dispex_prop_delete, \ - .prop_get_name = dispex_prop_get_name + .prop_get_desc = dispex_prop_get_desc, \ + .prop_get_name = dispex_prop_get_name, \ + .prop_define = dispex_prop_define
static inline IDispatch *to_disp(jsdisp_t *jsdisp) { @@ -269,6 +275,11 @@ void jsdisp_release(jsdisp_t*);
#endif
+static inline BOOL is_dispex_prop_id(DISPID id) +{ + return id > 0; +} + enum jsdisp_enum_type { JSDISP_ENUM_ALL, JSDISP_ENUM_OWN,
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 51 ++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 27 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 7533c97cb25..2bd4e8c6285 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -621,32 +621,6 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t return E_FAIL; }
-static HRESULT delete_prop(dispex_prop_t *prop, BOOL *ret) -{ - if(prop->type == PROP_PROTREF || prop->type == PROP_DELETED) { - *ret = TRUE; - return S_OK; - } - - if(!(prop->flags & PROPF_CONFIGURABLE)) { - *ret = FALSE; - return S_OK; - } - - *ret = TRUE; - - if(prop->type == PROP_JSVAL) - jsval_release(prop->u.val); - if(prop->type == PROP_ACCESSOR) { - if(prop->u.accessor.getter) - jsdisp_release(prop->u.accessor.getter); - if(prop->u.accessor.setter) - jsdisp_release(prop->u.accessor.setter); - } - prop->type = PROP_DELETED; - return S_OK; -} - HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value) { TRACE("%p %s\n", jsthis, debugstr_jsval(value)); @@ -671,7 +645,30 @@ HRESULT dispex_prop_invoke(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, WORD
HRESULT dispex_prop_delete(jsdisp_t *jsdisp, DISPID id, BOOL *ret) { - return delete_prop(&jsdisp->props[prop_id_to_idx(id)], ret); + dispex_prop_t *prop = &jsdisp->props[prop_id_to_idx(id)]; + + if(prop->type == PROP_PROTREF || prop->type == PROP_DELETED) { + *ret = TRUE; + return S_OK; + } + + if(!(prop->flags & PROPF_CONFIGURABLE)) { + *ret = FALSE; + return S_OK; + } + + *ret = TRUE; + + if(prop->type == PROP_JSVAL) + jsval_release(prop->u.val); + if(prop->type == PROP_ACCESSOR) { + if(prop->u.accessor.getter) + jsdisp_release(prop->u.accessor.getter); + if(prop->u.accessor.setter) + jsdisp_release(prop->u.accessor.setter); + } + prop->type = PROP_DELETED; + return S_OK; }
HRESULT dispex_prop_get_desc(jsdisp_t *jsdisp, DISPID id, BOOL flags_only, property_desc_t *desc)
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 57 ++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 31 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 2bd4e8c6285..c0ad8f59320 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -570,17 +570,34 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val) return S_OK; }
-static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, WORD flags, - unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) +HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value) +{ + TRACE("%p %s\n", jsthis, debugstr_jsval(value)); + return S_OK; +} + +HRESULT dispex_prop_get(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, jsval_t *r) +{ + return prop_get(jsdisp, jsthis, &jsdisp->props[prop_id_to_idx(id)], r); +} + +HRESULT dispex_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t val) +{ + return prop_put(jsdisp, &jsdisp->props[prop_id_to_idx(id)], val); +} + +HRESULT dispex_prop_invoke(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, WORD flags, + unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) { + dispex_prop_t *prop = &jsdisp->props[prop_id_to_idx(id)]; HRESULT hres;
switch(prop->type) { case PROP_BUILTIN: return JS_E_FUNCTION_EXPECTED; case PROP_PROTREF: - return invoke_prop_func(This->prototype, jsthis ? jsthis : (IDispatch *)&This->IDispatchEx_iface, - This->prototype->props+prop->u.ref, flags, argc, argv, r, caller); + return jsdisp->prototype->builtin_info->prop_invoke(jsdisp->prototype, jsthis ? jsthis : (IDispatch*)&jsdisp->IDispatchEx_iface, + prop->u.ref + 1, flags, argc, argv, r, caller); case PROP_JSVAL: { if(!is_object_instance(prop->u.val)) { FIXME("invoke %s\n", debugstr_jsval(prop->u.val)); @@ -589,21 +606,21 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t
TRACE("call %s %p\n", debugstr_w(prop->name), get_object(prop->u.val));
- return disp_call_value_with_caller(This->ctx, get_object(prop->u.val), - jsval_disp(jsthis ? jsthis : (IDispatch*)&This->IDispatchEx_iface), + return disp_call_value_with_caller(jsdisp->ctx, get_object(prop->u.val), + jsval_disp(jsthis ? jsthis : (IDispatch*)&jsdisp->IDispatchEx_iface), flags, argc, argv, r, caller); } case PROP_ACCESSOR: case PROP_IDX: { jsval_t val;
- hres = prop_get(This, jsthis ? jsthis : (IDispatch *)&This->IDispatchEx_iface, prop, &val); + hres = dispex_prop_get(jsdisp, jsthis ? jsthis : (IDispatch*)&jsdisp->IDispatchEx_iface, id, &val); if(FAILED(hres)) return hres;
if(is_object_instance(val)) { - hres = disp_call_value_with_caller(This->ctx, get_object(val), - jsval_disp(jsthis ? jsthis : (IDispatch*)&This->IDispatchEx_iface), + hres = disp_call_value_with_caller(jsdisp->ctx, get_object(val), + jsval_disp(jsthis ? jsthis : (IDispatch*)&jsdisp->IDispatchEx_iface), flags, argc, argv, r, caller); }else { FIXME("invoke %s\n", debugstr_jsval(val)); @@ -621,28 +638,6 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t return E_FAIL; }
-HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value) -{ - TRACE("%p %s\n", jsthis, debugstr_jsval(value)); - return S_OK; -} - -HRESULT dispex_prop_get(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, jsval_t *r) -{ - return prop_get(jsdisp, jsthis, &jsdisp->props[prop_id_to_idx(id)], r); -} - -HRESULT dispex_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t val) -{ - return prop_put(jsdisp, &jsdisp->props[prop_id_to_idx(id)], val); -} - -HRESULT dispex_prop_invoke(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, WORD flags, - unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) -{ - return invoke_prop_func(jsdisp, jsthis, &jsdisp->props[prop_id_to_idx(id)], flags, argc, argv, r, caller); -} - HRESULT dispex_prop_delete(jsdisp_t *jsdisp, DISPID id, BOOL *ret) { dispex_prop_t *prop = &jsdisp->props[prop_id_to_idx(id)];
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 84 +++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 44 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index c0ad8f59320..e6d780cf584 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -460,49 +460,6 @@ static HRESULT convert_params(script_ctx_t *ctx, const DISPPARAMS *dp, jsval_t * return S_OK; }
-static HRESULT prop_get(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, jsval_t *r) -{ - jsdisp_t *prop_obj = This; - HRESULT hres; - - while(prop->type == PROP_PROTREF) { - prop_obj = prop_obj->prototype; - prop = prop_obj->props + prop->u.ref; - } - - switch(prop->type) { - case PROP_BUILTIN: - hres = prop->u.p->getter(This->ctx, prop_obj, r); - break; - case PROP_JSVAL: - hres = jsval_copy(prop->u.val, r); - break; - case PROP_ACCESSOR: - if(prop->u.accessor.getter) { - hres = jsdisp_call_value(prop->u.accessor.getter, jsval_disp(jsthis), - DISPATCH_METHOD, 0, NULL, r); - }else { - *r = jsval_undefined(); - hres = S_OK; - } - break; - case PROP_IDX: - hres = prop_obj->builtin_info->idx_get(prop_obj, prop->u.idx, r); - break; - default: - ERR("type %d\n", prop->type); - return E_FAIL; - } - - if(FAILED(hres)) { - TRACE("fail %08lx\n", hres); - return hres; - } - - TRACE("%p.%s ret %s\n", This, debugstr_w(prop->name), debugstr_jsval(*r)); - return hres; -} - static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val) { HRESULT hres; @@ -578,7 +535,46 @@ HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
HRESULT dispex_prop_get(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, jsval_t *r) { - return prop_get(jsdisp, jsthis, &jsdisp->props[prop_id_to_idx(id)], r); + dispex_prop_t *prop = &jsdisp->props[prop_id_to_idx(id)]; + jsdisp_t *prop_obj = jsdisp; + HRESULT hres; + + while(prop->type == PROP_PROTREF) { + prop_obj = prop_obj->prototype; + prop = prop_obj->props + prop->u.ref; + } + + switch(prop->type) { + case PROP_BUILTIN: + hres = prop->u.p->getter(jsdisp->ctx, prop_obj, r); + break; + case PROP_JSVAL: + hres = jsval_copy(prop->u.val, r); + break; + case PROP_ACCESSOR: + if(prop->u.accessor.getter) { + hres = jsdisp_call_value(prop->u.accessor.getter, jsval_disp(jsthis), + DISPATCH_METHOD, 0, NULL, r); + }else { + *r = jsval_undefined(); + hres = S_OK; + } + break; + case PROP_IDX: + hres = prop_obj->builtin_info->idx_get(prop_obj, prop->u.idx, r); + break; + default: + ERR("type %d\n", prop->type); + return E_FAIL; + } + + if(FAILED(hres)) { + TRACE("fail %08lx\n", hres); + return hres; + } + + TRACE("%p.%s ret %s\n", jsdisp, debugstr_w(prop->name), debugstr_jsval(*r)); + return hres; }
HRESULT dispex_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t val)
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 126 ++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 65 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index e6d780cf584..900407d9d23 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -460,13 +460,64 @@ static HRESULT convert_params(script_ctx_t *ctx, const DISPPARAMS *dp, jsval_t * return S_OK; }
-static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val) +HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value) +{ + TRACE("%p %s\n", jsthis, debugstr_jsval(value)); + return S_OK; +} + +HRESULT dispex_prop_get(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, jsval_t *r) { + dispex_prop_t *prop = &jsdisp->props[prop_id_to_idx(id)]; + jsdisp_t *prop_obj = jsdisp; + HRESULT hres; + + while(prop->type == PROP_PROTREF) { + prop_obj = prop_obj->prototype; + prop = prop_obj->props + prop->u.ref; + } + + switch(prop->type) { + case PROP_BUILTIN: + hres = prop->u.p->getter(jsdisp->ctx, prop_obj, r); + break; + case PROP_JSVAL: + hres = jsval_copy(prop->u.val, r); + break; + case PROP_ACCESSOR: + if(prop->u.accessor.getter) { + hres = jsdisp_call_value(prop->u.accessor.getter, jsval_disp(jsthis), + DISPATCH_METHOD, 0, NULL, r); + }else { + *r = jsval_undefined(); + hres = S_OK; + } + break; + case PROP_IDX: + hres = prop_obj->builtin_info->idx_get(prop_obj, prop->u.idx, r); + break; + default: + ERR("type %d\n", prop->type); + return E_FAIL; + } + + if(FAILED(hres)) { + TRACE("fail %08lx\n", hres); + return hres; + } + + TRACE("%p.%s ret %s\n", jsdisp, debugstr_w(prop->name), debugstr_jsval(*r)); + return hres; +} + +HRESULT dispex_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t val) +{ + dispex_prop_t *prop = &jsdisp->props[prop_id_to_idx(id)]; HRESULT hres;
if(prop->type == PROP_PROTREF) { dispex_prop_t *prop_iter = prop; - jsdisp_t *prototype_iter = This; + jsdisp_t *prototype_iter = jsdisp;
do { prototype_iter = prototype_iter->prototype; @@ -483,10 +534,10 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val) TRACE("getter with no setter\n"); return S_OK; } - return prop->u.p->setter(This->ctx, This, val); + return prop->u.p->setter(jsdisp->ctx, jsdisp, val); case PROP_PROTREF: case PROP_DELETED: - if(!This->extensible) + if(!jsdisp->extensible) return S_OK; prop->type = PROP_JSVAL; prop->flags = PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE; @@ -503,85 +554,30 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val) TRACE("no setter\n"); return S_OK; } - return jsdisp_call_value(prop->u.accessor.setter, jsval_obj(This), DISPATCH_METHOD, 1, &val, NULL); + return jsdisp_call_value(prop->u.accessor.setter, jsval_obj(jsdisp), DISPATCH_METHOD, 1, &val, NULL); case PROP_IDX: - if(!This->builtin_info->idx_put) { + if(!jsdisp->builtin_info->idx_put) { TRACE("no put_idx\n"); return S_OK; } - return This->builtin_info->idx_put(This, prop->u.idx, val); + return jsdisp->builtin_info->idx_put(jsdisp, prop->u.idx, val); default: ERR("type %d\n", prop->type); return E_FAIL; }
- TRACE("%p.%s = %s\n", This, debugstr_w(prop->name), debugstr_jsval(val)); + TRACE("%p.%s = %s\n", jsdisp, debugstr_w(prop->name), debugstr_jsval(val));
hres = jsval_copy(val, &prop->u.val); if(FAILED(hres)) return hres;
- if(This->builtin_info->on_put) - This->builtin_info->on_put(This, prop->name); - - return S_OK; -} + if(jsdisp->builtin_info->on_put) + jsdisp->builtin_info->on_put(jsdisp, prop->name);
-HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value) -{ - TRACE("%p %s\n", jsthis, debugstr_jsval(value)); return S_OK; }
-HRESULT dispex_prop_get(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, jsval_t *r) -{ - dispex_prop_t *prop = &jsdisp->props[prop_id_to_idx(id)]; - jsdisp_t *prop_obj = jsdisp; - HRESULT hres; - - while(prop->type == PROP_PROTREF) { - prop_obj = prop_obj->prototype; - prop = prop_obj->props + prop->u.ref; - } - - switch(prop->type) { - case PROP_BUILTIN: - hres = prop->u.p->getter(jsdisp->ctx, prop_obj, r); - break; - case PROP_JSVAL: - hres = jsval_copy(prop->u.val, r); - break; - case PROP_ACCESSOR: - if(prop->u.accessor.getter) { - hres = jsdisp_call_value(prop->u.accessor.getter, jsval_disp(jsthis), - DISPATCH_METHOD, 0, NULL, r); - }else { - *r = jsval_undefined(); - hres = S_OK; - } - break; - case PROP_IDX: - hres = prop_obj->builtin_info->idx_get(prop_obj, prop->u.idx, r); - break; - default: - ERR("type %d\n", prop->type); - return E_FAIL; - } - - if(FAILED(hres)) { - TRACE("fail %08lx\n", hres); - return hres; - } - - TRACE("%p.%s ret %s\n", jsdisp, debugstr_w(prop->name), debugstr_jsval(*r)); - return hres; -} - -HRESULT dispex_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t val) -{ - return prop_put(jsdisp, &jsdisp->props[prop_id_to_idx(id)], val); -} - HRESULT dispex_prop_invoke(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) {
From: Gabriel Ivăncescu gabrielopcode@gmail.com
We can just use the object's prop_put now.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/array.c | 54 ++++++++++++++++++++++++++++-------------- dlls/jscript/dispex.c | 8 ++++--- dlls/jscript/jscript.h | 2 +- 3 files changed, 42 insertions(+), 22 deletions(-)
diff --git a/dlls/jscript/array.c b/dlls/jscript/array.c index 64a945f9d84..6befe44b304 100644 --- a/dlls/jscript/array.c +++ b/dlls/jscript/array.c @@ -1589,25 +1589,33 @@ done: return hres; }
-static void Array_on_put(jsdisp_t *dispex, const WCHAR *name) +static HRESULT Array_prop_put(jsdisp_t *dispex, DISPID id, jsval_t val) { ArrayInstance *array = array_from_jsdisp(dispex); - const WCHAR *ptr = name; - DWORD id = 0; + const WCHAR *ptr; + DWORD idx = 0; + HRESULT hres; + + hres = dispex_prop_put(&array->dispex, id, val); + if(hres != S_OK) + return hres;
+ ptr = dispex_prop_get_static_name(&array->dispex, id); if(!is_digit(*ptr)) - return; + return hres;
while(*ptr && is_digit(*ptr)) { - id = id*10 + (*ptr-'0'); + idx = idx*10 + (*ptr-'0'); ptr++; }
if(*ptr) - return; + return hres;
- if(id >= array->length) - array->length = id+1; + if(idx >= array->length) + array->length = idx + 1; + + return hres; }
static const builtin_prop_t Array_props[] = { @@ -1635,11 +1643,16 @@ static const builtin_prop_t Array_props[] = { };
static const builtin_info_t Array_info = { - DEFAULT_DISPEX_PROP_VTBL_ENTRIES, - .class = JSCLASS_ARRAY, - .props_cnt = ARRAY_SIZE(Array_props), - .props = Array_props, - .on_put = Array_on_put, + .class = JSCLASS_ARRAY, + .props_cnt = ARRAY_SIZE(Array_props), + .props = Array_props, + .prop_get = dispex_prop_get, + .prop_put = Array_prop_put, + .prop_invoke = dispex_prop_invoke, + .prop_delete = dispex_prop_delete, + .prop_get_desc = dispex_prop_get_desc, + .prop_get_name = dispex_prop_get_name, + .prop_define = dispex_prop_define };
static const builtin_prop_t ArrayInst_props[] = { @@ -1647,11 +1660,16 @@ static const builtin_prop_t ArrayInst_props[] = { };
static const builtin_info_t ArrayInst_info = { - DEFAULT_DISPEX_PROP_VTBL_ENTRIES, - .class = JSCLASS_ARRAY, - .props_cnt = ARRAY_SIZE(ArrayInst_props), - .props = ArrayInst_props, - .on_put = Array_on_put, + .class = JSCLASS_ARRAY, + .props_cnt = ARRAY_SIZE(ArrayInst_props), + .props = ArrayInst_props, + .prop_get = dispex_prop_get, + .prop_put = Array_prop_put, + .prop_invoke = dispex_prop_invoke, + .prop_delete = dispex_prop_delete, + .prop_get_desc = dispex_prop_get_desc, + .prop_get_name = dispex_prop_get_name, + .prop_define = dispex_prop_define };
/* ECMA-262 5.1 Edition 15.4.3.2 */ diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 900407d9d23..7fa5bab0eea 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -572,9 +572,6 @@ HRESULT dispex_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t val) if(FAILED(hres)) return hres;
- if(jsdisp->builtin_info->on_put) - jsdisp->builtin_info->on_put(jsdisp, prop->name); - return S_OK; }
@@ -819,6 +816,11 @@ HRESULT dispex_prop_define(jsdisp_t *jsdisp, DISPID id, const property_desc_t *d return S_OK; }
+const WCHAR *dispex_prop_get_static_name(jsdisp_t *jsdisp, DISPID id) +{ + return jsdisp->props[prop_id_to_idx(id)].name; +} + static HRESULT fill_props(jsdisp_t *obj) { HRESULT hres; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 93c7eb5aadd..70d71b34337 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -137,6 +137,7 @@ HRESULT dispex_prop_delete(jsdisp_t*,DISPID,BOOL*); HRESULT dispex_prop_get_desc(jsdisp_t*,DISPID,BOOL,property_desc_t*); void *dispex_prop_get_name(jsdisp_t*,DISPID,BOOL); HRESULT dispex_prop_define(jsdisp_t*,DISPID,const property_desc_t*); +const WCHAR *dispex_prop_get_static_name(jsdisp_t*,DISPID);
struct thread_data { LONG ref; @@ -191,7 +192,6 @@ typedef struct { DWORD props_cnt; const builtin_prop_t *props; void (*destructor)(jsdisp_t*); - void (*on_put)(jsdisp_t*,const WCHAR*); HRESULT (*prop_get)(jsdisp_t*,IDispatch*,DISPID,jsval_t*); HRESULT (*prop_put)(jsdisp_t*,DISPID,jsval_t); HRESULT (*prop_invoke)(jsdisp_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*);
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
It's the only thing it was used for anyway, this will simplify next patches. --- dlls/jscript/dispex.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 7fa5bab0eea..92ecf145c0c 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -115,7 +115,7 @@ static inline BOOL is_function_prop(dispex_prop_t *prop) return ret; }
-static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop) +static BOOL is_enumerable(jsdisp_t *This, dispex_prop_t *prop) { if(prop->type == PROP_PROTREF) { dispex_prop_t *parent = NULL; @@ -125,13 +125,13 @@ static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop)
if(!parent || parent->type == PROP_DELETED) { prop->type = PROP_DELETED; - return 0; + return FALSE; }
- return get_flags(This->prototype, parent); + return is_enumerable(This->prototype, parent); }
- return prop->flags; + return !!(prop->flags & PROPF_ENUMERABLE); }
static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name, BOOL case_insens) @@ -3042,7 +3042,7 @@ HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, enum jsdisp_enum_type enum_ty continue; if(enum_type != JSDISP_ENUM_ALL && iter->type == PROP_PROTREF) continue; - if(enum_type != JSDISP_ENUM_OWN && !(get_flags(obj, iter) & PROPF_ENUMERABLE)) + if(enum_type != JSDISP_ENUM_OWN && !is_enumerable(obj, iter)) continue; *ret = prop_to_id(obj, iter); return S_OK;
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 92ecf145c0c..38cac3a28e1 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -841,11 +841,29 @@ static HRESULT fill_props(jsdisp_t *obj) return S_OK; }
+static HRESULT fill_protref(jsdisp_t *This, unsigned hash, const WCHAR *name, DWORD ref) +{ + HRESULT hres; + DISPID id; + + hres = find_prop_name(This, hash, name, FALSE, &id); + if(hres != S_FALSE) + return hres; + if(is_dispex_prop_id(id)) { + dispex_prop_t *p = &This->props[prop_id_to_idx(id)]; + p->type = PROP_PROTREF; + p->flags = 0; + p->u.ref = ref; + }else if(!alloc_protref(This, name, ref)) { + return E_OUTOFMEMORY; + } + return S_OK; +} + static HRESULT fill_protrefs(jsdisp_t *This) { dispex_prop_t *iter; HRESULT hres; - DISPID id;
hres = fill_props(This); if(FAILED(hres)) @@ -859,19 +877,9 @@ static HRESULT fill_protrefs(jsdisp_t *This) return hres;
for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) { - hres = find_prop_name(This, iter->hash, iter->name, FALSE, &id); - if(FAILED(hres)) + hres = fill_protref(This, iter->hash, iter->name, iter - This->prototype->props); + if(hres != S_OK) return hres; - if(hres != S_OK) { - if(is_dispex_prop_id(id)) { - dispex_prop_t *p = &This->props[prop_id_to_idx(id)]; - p->type = PROP_PROTREF; - p->flags = 0; - p->u.ref = iter - This->prototype->props; - }else if(!alloc_protref(This, iter->name, iter - This->prototype->props)) { - return E_OUTOFMEMORY; - } - } }
return S_OK;
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 194 +++++++++++++++++++++++++++++----------- dlls/jscript/engine.c | 62 +++++++++---- dlls/jscript/function.c | 93 +++++++++++++++---- dlls/jscript/jscript.h | 21 ++++- dlls/jscript/string.c | 76 +++++++++++----- 5 files changed, 334 insertions(+), 112 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 38cac3a28e1..7952d5bbc0d 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -36,7 +36,6 @@ typedef enum { PROP_PROTREF, PROP_ACCESSOR, PROP_DELETED, - PROP_IDX } prop_type_t;
struct _dispex_prop_t { @@ -49,7 +48,6 @@ struct _dispex_prop_t { jsval_t val; const builtin_prop_t *p; DWORD ref; - unsigned idx; struct { jsdisp_t *getter; jsdisp_t *setter; @@ -74,7 +72,12 @@ static void fix_protref_prop(jsdisp_t *jsdisp, dispex_prop_t *prop) ref = prop->u.ref;
while((jsdisp = jsdisp->prototype)) { - if(ref >= jsdisp->prop_cnt || jsdisp->props[ref].type == PROP_DELETED) + if(ref >= jsdisp->prop_cnt) { + if(jsdisp->builtin_info->idx_length && indexed_prop_id_to_idx(ref + 1) < jsdisp->builtin_info->idx_length(jsdisp)) + return; + break; + } + if(jsdisp->props[ref].type == PROP_DELETED) break; if(jsdisp->props[ref].type != PROP_PROTREF) return; @@ -94,7 +97,7 @@ static inline BOOL is_dispid_prop(jsdisp_t *This, DISPID id) DWORD idx = prop_id_to_idx(id);
if(idx >= This->prop_cnt) - return FALSE; + return This->builtin_info->idx_length && indexed_prop_id_to_idx(id) < This->builtin_info->idx_length(This); fix_protref_prop(This, &This->props[idx]);
if(This->props[idx].type == PROP_DELETED) @@ -122,6 +125,8 @@ static BOOL is_enumerable(jsdisp_t *This, dispex_prop_t *prop)
if(prop->u.ref < This->prototype->prop_cnt) parent = &This->prototype->props[prop->u.ref]; + else if(This->prototype->builtin_info->idx_length && indexed_prop_id_to_idx(prop->u.ref + 1) < This->prototype->builtin_info->idx_length(This->prototype)) + return TRUE;
if(!parent || parent->type == PROP_DELETED) { prop->type = PROP_DELETED; @@ -313,15 +318,8 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, for(ptr = name; is_digit(*ptr) && idx < 0x10000; ptr++) idx = idx*10 + (*ptr-'0'); if(!*ptr && idx < This->builtin_info->idx_length(This)) { - unsigned flags = PROPF_ENUMERABLE; - if(This->builtin_info->idx_put) - flags |= PROPF_WRITABLE; - prop = alloc_prop(This, name, PROP_IDX, flags); - if(!prop) - return E_OUTOFMEMORY; - - prop->u.idx = idx; - goto ret; + *ret = indexed_prop_idx_to_id(idx); + return S_OK; } }
@@ -339,7 +337,7 @@ static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *n HRESULT hres;
hres = find_prop_name(This, hash, name, case_insens, ret); - if(FAILED(hres)) + if(FAILED(hres) || is_indexed_prop_id(*ret)) return hres;
if(hres == S_OK) { @@ -363,8 +361,8 @@ static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *n del->u.ref = ref; prop = del; }else { - /* Case insensitive name lookups can differ from the prototype prop's actual name */ - prop = alloc_protref(This, This->prototype->props[ref].name, ref); + /* Case insensitive name lookups can differ from the prototype prop's actual name, but not with indexed props */ + prop = alloc_protref(This, is_indexed_prop_id(*ret) ? name : This->prototype->props[ref].name, ref); if(!prop) return E_OUTOFMEMORY; } @@ -389,7 +387,7 @@ static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_ HRESULT hres;
hres = find_prop_name_prot(This, string_hash(name), name, case_insens, ret); - if(hres != S_FALSE) + if(hres != S_FALSE || is_indexed_prop_id(*ret)) return hres;
if(is_dispex_prop_id(*ret)) { @@ -469,17 +467,14 @@ HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value) HRESULT dispex_prop_get(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, jsval_t *r) { dispex_prop_t *prop = &jsdisp->props[prop_id_to_idx(id)]; - jsdisp_t *prop_obj = jsdisp; HRESULT hres;
- while(prop->type == PROP_PROTREF) { - prop_obj = prop_obj->prototype; - prop = prop_obj->props + prop->u.ref; - } + if(prop->type == PROP_PROTREF) + return jsdisp->prototype->builtin_info->prop_get(jsdisp->prototype, jsthis, prop->u.ref + 1, r);
switch(prop->type) { case PROP_BUILTIN: - hres = prop->u.p->getter(jsdisp->ctx, prop_obj, r); + hres = prop->u.p->getter(jsdisp->ctx, jsdisp, r); break; case PROP_JSVAL: hres = jsval_copy(prop->u.val, r); @@ -493,9 +488,6 @@ HRESULT dispex_prop_get(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, jsval_t hres = S_OK; } break; - case PROP_IDX: - hres = prop_obj->builtin_info->idx_get(prop_obj, prop->u.idx, r); - break; default: ERR("type %d\n", prop->type); return E_FAIL; @@ -521,6 +513,9 @@ HRESULT dispex_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t val)
do { prototype_iter = prototype_iter->prototype; + if(!is_dispex_prop_id(prop_iter->u.ref + 1)) + break; + prop_iter = prototype_iter->props + prop_iter->u.ref; } while(prop_iter->type == PROP_PROTREF);
@@ -555,12 +550,6 @@ HRESULT dispex_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t val) return S_OK; } return jsdisp_call_value(prop->u.accessor.setter, jsval_obj(jsdisp), DISPATCH_METHOD, 1, &val, NULL); - case PROP_IDX: - if(!jsdisp->builtin_info->idx_put) { - TRACE("no put_idx\n"); - return S_OK; - } - return jsdisp->builtin_info->idx_put(jsdisp, prop->u.idx, val); default: ERR("type %d\n", prop->type); return E_FAIL; @@ -599,8 +588,7 @@ HRESULT dispex_prop_invoke(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, WORD jsval_disp(jsthis ? jsthis : (IDispatch*)&jsdisp->IDispatchEx_iface), flags, argc, argv, r, caller); } - case PROP_ACCESSOR: - case PROP_IDX: { + case PROP_ACCESSOR: { jsval_t val;
hres = dispex_prop_get(jsdisp, jsthis ? jsthis : (IDispatch*)&jsdisp->IDispatchEx_iface, id, &val); @@ -663,7 +651,6 @@ HRESULT dispex_prop_get_desc(jsdisp_t *jsdisp, DISPID id, BOOL flags_only, prope switch(prop->type) { case PROP_BUILTIN: case PROP_JSVAL: - case PROP_IDX: desc->explicit_value = TRUE; if(!flags_only) { hres = dispex_prop_get(jsdisp, to_disp(jsdisp), id, &desc->value); @@ -821,24 +808,107 @@ const WCHAR *dispex_prop_get_static_name(jsdisp_t *jsdisp, DISPID id) return jsdisp->props[prop_id_to_idx(id)].name; }
-static HRESULT fill_props(jsdisp_t *obj) +HRESULT indexed_prop_invoke(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, WORD flags, + unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) { HRESULT hres; - DISPID id; + jsval_t val;
- if(obj->builtin_info->idx_length) { - unsigned i = 0, len = obj->builtin_info->idx_length(obj); - WCHAR name[12]; + if(is_dispex_prop_id(id)) + return dispex_prop_invoke(jsdisp, jsthis, id, flags, argc, argv, r, caller);
- for(i = 0; i < len; i++) { - swprintf(name, ARRAY_SIZE(name), L"%u", i); - hres = find_prop_name(obj, string_hash(name), name, FALSE, &id); + hres = jsdisp->builtin_info->prop_get(jsdisp, jsthis ? jsthis : to_disp(jsdisp), id, &val); + if(FAILED(hres)) + return hres; + + if(is_object_instance(val)) + hres = disp_call_value_with_caller(jsdisp->ctx, get_object(val), jsval_disp(jsthis ? jsthis : to_disp(jsdisp)), + flags, argc, argv, r, caller); + else { + FIXME("invoke %s\n", debugstr_jsval(val)); + hres = E_NOTIMPL; + } + + jsval_release(val); + return hres; +} + +HRESULT indexed_prop_delete(jsdisp_t *jsdisp, DISPID id, BOOL *ret) +{ + if(is_dispex_prop_id(id)) + return dispex_prop_delete(jsdisp, id, ret); + + /* indexed props are not configurable */ + *ret = FALSE; + return S_OK; +} + +void *indexed_prop_get_name(jsdisp_t *jsdisp, DISPID id, BOOL bstr) +{ + WCHAR buf[11]; + unsigned len; + + if(is_dispex_prop_id(id)) + return dispex_prop_get_name(jsdisp, id, bstr); + + len = swprintf(buf, ARRAY_SIZE(buf), L"%u", indexed_prop_id_to_idx(id)); + if(bstr) + return SysAllocStringLen(buf, len); + return jsstr_alloc_len(buf, len); +} + +HRESULT indexed_prop_define(jsdisp_t *jsdisp, DISPID id, const property_desc_t *desc) +{ + property_desc_t prop_desc; + WCHAR buf[11]; + HRESULT hres; + jsval_t val; + BOOL eq; + + if(is_dispex_prop_id(id)) + return dispex_prop_define(jsdisp, id, desc); + + TRACE("existing prop L"%lu" desc flags %x desc mask %x\n", indexed_prop_id_to_idx(id), desc->flags, desc->mask); + + if((desc->mask & desc->flags & (PROPF_CONFIGURABLE | PROPF_ENUMERABLE)) != (desc->mask & PROPF_ENUMERABLE)) { + hres = JS_E_NONCONFIGURABLE_REDEFINED; + goto throw; + } + + if(desc->explicit_value || (desc->mask & PROPF_WRITABLE)) { + if(jsdisp->builtin_info->prop_get_desc(jsdisp, id, TRUE, &prop_desc) == S_OK && !(prop_desc.flags & PROPF_WRITABLE)) { + if(desc->mask & desc->flags & PROPF_WRITABLE) { + hres = JS_E_NONWRITABLE_MODIFIED; + goto throw; + } + if(desc->explicit_value) { + hres = jsdisp->builtin_info->prop_get(jsdisp, to_disp(jsdisp), id, &val); + if(FAILED(hres)) + return hres; + hres = jsval_strict_equal(desc->value, val, &eq); + jsval_release(val); + if(FAILED(hres)) + return hres; + if(!eq) { + hres = JS_E_NONWRITABLE_MODIFIED; + goto throw; + } + } + }else if(desc->explicit_value) { + HRESULT hres = jsdisp->builtin_info->prop_put(jsdisp, id, desc->value); if(FAILED(hres)) return hres; } + }else if(desc->explicit_getter || desc->explicit_setter) { + hres = JS_E_NONCONFIGURABLE_REDEFINED; + goto throw; }
return S_OK; + +throw: + swprintf(buf, ARRAY_SIZE(buf), L"%u", indexed_prop_id_to_idx(id)); + return throw_error(jsdisp->ctx, hres, buf); }
static HRESULT fill_protref(jsdisp_t *This, unsigned hash, const WCHAR *name, DWORD ref) @@ -849,6 +919,8 @@ static HRESULT fill_protref(jsdisp_t *This, unsigned hash, const WCHAR *name, DW hres = find_prop_name(This, hash, name, FALSE, &id); if(hres != S_FALSE) return hres; + if(is_indexed_prop_id(id)) + return S_OK; if(is_dispex_prop_id(id)) { dispex_prop_t *p = &This->props[prop_id_to_idx(id)]; p->type = PROP_PROTREF; @@ -865,10 +937,6 @@ static HRESULT fill_protrefs(jsdisp_t *This) dispex_prop_t *iter; HRESULT hres;
- hres = fill_props(This); - if(FAILED(hres)) - return hres; - if(!This->prototype) return S_OK;
@@ -876,6 +944,18 @@ static HRESULT fill_protrefs(jsdisp_t *This) if(FAILED(hres)) return hres;
+ if(This->prototype->builtin_info->idx_length) { + DWORD i, len = This->prototype->builtin_info->idx_length(This->prototype); + WCHAR buf[11]; + + for(i = 0; i < len; i++) { + swprintf(buf, ARRAY_SIZE(buf), L"%u", i); + hres = fill_protref(This, string_hash(buf), buf, prop_id_to_idx(indexed_prop_idx_to_id(i))); + if(hres != S_OK) + return hres; + } + } + for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) { hres = fill_protref(This, iter->hash, iter->name, iter - This->prototype->props); if(hres != S_OK) @@ -3032,15 +3112,25 @@ HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret) HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, enum jsdisp_enum_type enum_type, DISPID *ret) { dispex_prop_t *iter; - DWORD idx = id; + BOOL fill = FALSE; HRESULT hres; + DWORD idx; + + id = (id == DISPID_STARTENUM) ? indexed_prop_idx_to_id(0) : id + 1; + if(is_indexed_prop_id(id)) { + if(obj->builtin_info->idx_length && indexed_prop_id_to_idx(id) < obj->builtin_info->idx_length(obj)) { + *ret = id; + return S_OK; + } + fill = TRUE; + id = 1; + } + idx = prop_id_to_idx(id);
- if(id == DISPID_STARTENUM || idx >= obj->prop_cnt) { - hres = (enum_type == JSDISP_ENUM_ALL) ? fill_protrefs(obj) : fill_props(obj); + if(fill || idx >= obj->prop_cnt) { + hres = (enum_type == JSDISP_ENUM_ALL) ? fill_protrefs(obj) : S_OK; if(FAILED(hres)) return hres; - if(id == DISPID_STARTENUM) - idx = 0; if(idx >= obj->prop_cnt) return S_FALSE; } diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index 2142b70e677..d84bdaa7bcf 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -478,36 +478,60 @@ static void scope_destructor(jsdisp_t *dispex) IDispatch_Release(scope->obj); }
-static unsigned scope_idx_length(jsdisp_t *dispex) +static HRESULT scope_prop_get(jsdisp_t *dispex, IDispatch *jsthis, DISPID id, jsval_t *r) { scope_chain_t *scope = scope_from_dispex(dispex);
- return scope->detached_vars->argc; -} + if(is_dispex_prop_id(id)) + return dispex_prop_get(&scope->dispex, jsthis, id, r);
-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); + return jsval_copy(scope->detached_vars->var[indexed_prop_id_to_idx(id)], r); }
-static HRESULT scope_idx_put(jsdisp_t *dispex, unsigned idx, jsval_t val) +static HRESULT scope_prop_put(jsdisp_t *dispex, DISPID id, jsval_t val) { scope_chain_t *scope = scope_from_dispex(dispex); jsval_t copy, *ref; HRESULT hres;
+ if(is_dispex_prop_id(id)) + return dispex_prop_put(&scope->dispex, id, val); + hres = jsval_copy(val, ©); if(FAILED(hres)) return hres;
- ref = &scope->detached_vars->var[idx]; + ref = &scope->detached_vars->var[indexed_prop_id_to_idx(id)]; jsval_release(*ref); *ref = copy; return S_OK; }
+static HRESULT scope_prop_get_desc(jsdisp_t *dispex, DISPID id, BOOL flags_only, property_desc_t *desc) +{ + scope_chain_t *scope = scope_from_dispex(dispex); + + if(is_dispex_prop_id(id)) + return dispex_prop_get_desc(&scope->dispex, id, flags_only, desc); + + if(!flags_only) { + HRESULT hres = scope_prop_get(&scope->dispex, to_disp(&scope->dispex), id, &desc->value); + if(FAILED(hres)) + return hres; + } + + desc->explicit_value = TRUE; + desc->flags = PROPF_ENUMERABLE | PROPF_WRITABLE; + return S_OK; +} + +static unsigned scope_idx_length(jsdisp_t *dispex) +{ + scope_chain_t *scope = scope_from_dispex(dispex); + + return scope->detached_vars->argc; +} + static HRESULT scope_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex) { scope_chain_t *scope = scope_from_dispex(dispex); @@ -544,13 +568,17 @@ static HRESULT scope_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, }
static const builtin_info_t scope_info = { - DEFAULT_DISPEX_PROP_VTBL_ENTRIES, - .class = JSCLASS_NONE, - .destructor = scope_destructor, - .idx_length = scope_idx_length, - .idx_get = scope_idx_get, - .idx_put = scope_idx_put, - .gc_traverse = scope_gc_traverse + .class = JSCLASS_NONE, + .destructor = scope_destructor, + .prop_get = scope_prop_get, + .prop_put = scope_prop_put, + .prop_invoke = indexed_prop_invoke, + .prop_delete = indexed_prop_delete, + .prop_get_desc = scope_prop_get_desc, + .prop_get_name = indexed_prop_get_name, + .prop_define = indexed_prop_define, + .idx_length = scope_idx_length, + .gc_traverse = scope_gc_traverse };
static HRESULT scope_push(script_ctx_t *ctx, scope_chain_t *scope, IDispatch *obj, scope_chain_t **ret) diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 55ec36788c3..45e26e8c294 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -68,6 +68,7 @@ typedef struct { jsval_t *buf; scope_chain_t *scope; unsigned argc; + BYTE readonly_flags[]; } ArgumentsInstance;
static HRESULT create_bind_function(script_ctx_t*,FunctionInstance*,jsval_t,unsigned,jsval_t*,jsdisp_t**r); @@ -117,12 +118,6 @@ static void Arguments_destructor(jsdisp_t *jsdisp) scope_release(arguments->scope); }
-static unsigned Arguments_idx_length(jsdisp_t *jsdisp) -{ - ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); - return arguments->argc; -} - static jsval_t *get_argument_ref(ArgumentsInstance *arguments, unsigned idx) { if(arguments->buf) @@ -132,22 +127,33 @@ static jsval_t *get_argument_ref(ArgumentsInstance *arguments, unsigned idx) return arguments->scope->detached_vars->var + idx; }
-static HRESULT Arguments_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r) +static HRESULT Arguments_prop_get(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, jsval_t *r) { ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + DWORD idx = indexed_prop_id_to_idx(id); + + if(is_dispex_prop_id(id)) + return dispex_prop_get(&arguments->jsdisp, jsthis, id, r);
- TRACE("%p[%u]\n", arguments, idx); + TRACE("%p[%lu]\n", arguments, idx);
return jsval_copy(*get_argument_ref(arguments, idx), r); }
-static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val) +static HRESULT Arguments_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t val) { ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + DWORD idx = indexed_prop_id_to_idx(id); jsval_t copy, *ref; HRESULT hres;
- TRACE("%p[%u] = %s\n", arguments, idx, debugstr_jsval(val)); + if(is_dispex_prop_id(id)) + return dispex_prop_put(&arguments->jsdisp, id, val); + + TRACE("%p[%lu] = %s\n", arguments, idx, debugstr_jsval(val)); + + if(arguments->readonly_flags[idx / 8] & (1u << idx % 8)) + return S_OK;
hres = jsval_copy(val, ©); if(FAILED(hres)) @@ -159,6 +165,51 @@ static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val) return S_OK; }
+static HRESULT Arguments_prop_get_desc(jsdisp_t *jsdisp, DISPID id, BOOL flags_only, property_desc_t *desc) +{ + ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + DWORD idx = indexed_prop_id_to_idx(id); + + if(is_dispex_prop_id(id)) + return dispex_prop_get_desc(&arguments->jsdisp, id, flags_only, desc); + + if(!flags_only) { + HRESULT hres = Arguments_prop_get(&arguments->jsdisp, to_disp(&arguments->jsdisp), id, &desc->value); + if(FAILED(hres)) + return hres; + } + + desc->explicit_value = TRUE; + desc->flags = PROPF_ENUMERABLE; + if(!(arguments->readonly_flags[idx / 8] & (1u << idx % 8))) + desc->flags |= PROPF_WRITABLE; + + return S_OK; +} + +static HRESULT Arguments_prop_define(jsdisp_t *jsdisp, DISPID id, const property_desc_t *desc) +{ + ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + DWORD idx = indexed_prop_id_to_idx(id); + HRESULT hres; + + hres = indexed_prop_define(&arguments->jsdisp, id, desc); + if(FAILED(hres)) + return hres; + + /* Need to keep track of props made read-only */ + if((desc->mask & PROPF_WRITABLE) && !(desc->flags & PROPF_WRITABLE)) + arguments->readonly_flags[idx / 8] |= 1u << idx % 8; + + return hres; +} + +static unsigned Arguments_idx_length(jsdisp_t *jsdisp) +{ + ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + return arguments->argc; +} + static HRESULT Arguments_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *jsdisp) { ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); @@ -183,14 +234,18 @@ static HRESULT Arguments_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op }
static const builtin_info_t Arguments_info = { - DEFAULT_DISPEX_PROP_VTBL_ENTRIES, - .class = JSCLASS_ARGUMENTS, - .call = Arguments_value, - .destructor = Arguments_destructor, - .idx_length = Arguments_idx_length, - .idx_get = Arguments_idx_get, - .idx_put = Arguments_idx_put, - .gc_traverse = Arguments_gc_traverse + .class = JSCLASS_ARGUMENTS, + .call = Arguments_value, + .destructor = Arguments_destructor, + .prop_get = Arguments_prop_get, + .prop_put = Arguments_prop_put, + .prop_invoke = indexed_prop_invoke, + .prop_delete = indexed_prop_delete, + .prop_get_desc = Arguments_prop_get_desc, + .prop_get_name = indexed_prop_get_name, + .prop_define = Arguments_prop_define, + .idx_length = Arguments_idx_length, + .gc_traverse = Arguments_gc_traverse };
HRESULT setup_arguments_object(script_ctx_t *ctx, call_frame_t *frame) @@ -198,7 +253,7 @@ HRESULT setup_arguments_object(script_ctx_t *ctx, call_frame_t *frame) ArgumentsInstance *args; HRESULT hres;
- args = calloc(1, sizeof(*args)); + args = calloc(1, FIELD_OFFSET(ArgumentsInstance, readonly_flags[(frame->argc + 7) / 8])); if(!args) return E_OUTOFMEMORY;
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 70d71b34337..75a24eddd89 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -138,6 +138,10 @@ HRESULT dispex_prop_get_desc(jsdisp_t*,DISPID,BOOL,property_desc_t*); void *dispex_prop_get_name(jsdisp_t*,DISPID,BOOL); HRESULT dispex_prop_define(jsdisp_t*,DISPID,const property_desc_t*); const WCHAR *dispex_prop_get_static_name(jsdisp_t*,DISPID); +HRESULT indexed_prop_invoke(jsdisp_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*); +HRESULT indexed_prop_delete(jsdisp_t*,DISPID,BOOL*); +void *indexed_prop_get_name(jsdisp_t*,DISPID,BOOL); +HRESULT indexed_prop_define(jsdisp_t*,DISPID,const property_desc_t*);
struct thread_data { LONG ref; @@ -200,8 +204,6 @@ typedef struct { void *(*prop_get_name)(jsdisp_t*,DISPID,BOOL); HRESULT (*prop_define)(jsdisp_t*,DISPID,const property_desc_t*); unsigned (*idx_length)(jsdisp_t*); - HRESULT (*idx_get)(jsdisp_t*,unsigned,jsval_t*); - HRESULT (*idx_put)(jsdisp_t*,unsigned,jsval_t); HRESULT (*gc_traverse)(struct gc_ctx*,enum gc_traverse_op,jsdisp_t*); } builtin_info_t;
@@ -280,6 +282,21 @@ static inline BOOL is_dispex_prop_id(DISPID id) return id > 0; }
+static inline BOOL is_indexed_prop_id(DISPID id) +{ + return id < 0; +} + +static inline DWORD indexed_prop_id_to_idx(DISPID id) +{ + return (DWORD)id - 0x80000000u; +} + +static inline DISPID indexed_prop_idx_to_id(DWORD idx) +{ + return idx + 0x80000000u; +} + enum jsdisp_enum_type { JSDISP_ENUM_ALL, JSDISP_ENUM_OWN, diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c index 63cd24db05a..e62e6313e4a 100644 --- a/dlls/jscript/string.c +++ b/dlls/jscript/string.c @@ -1501,6 +1501,48 @@ static void String_destructor(jsdisp_t *dispex) jsstr_release(This->str); }
+static HRESULT String_prop_get(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, jsval_t *r) +{ + StringInstance *string = string_from_jsdisp(jsdisp); + DWORD idx = indexed_prop_id_to_idx(id); + jsstr_t *ret; + + if(is_dispex_prop_id(id)) + return dispex_prop_get(&string->dispex, jsthis, id, r); + + ret = jsstr_substr(string->str, idx, 1); + if(!ret) + return E_OUTOFMEMORY; + + TRACE("%p[%lu] = %s\n", string, idx, debugstr_jsstr(ret)); + + *r = jsval_string(ret); + return S_OK; +} + +static HRESULT String_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t val) +{ + if(is_dispex_prop_id(id)) + return dispex_prop_put(jsdisp, id, val); + return S_OK; +} + +static HRESULT String_prop_get_desc(jsdisp_t *jsdisp, DISPID id, BOOL flags_only, property_desc_t *desc) +{ + if(is_dispex_prop_id(id)) + return dispex_prop_get_desc(jsdisp, id, flags_only, desc); + + if(!flags_only) { + HRESULT hres = String_prop_get(jsdisp, to_disp(jsdisp), id, &desc->value); + if(FAILED(hres)) + return hres; + } + + desc->explicit_value = TRUE; + desc->flags = PROPF_ENUMERABLE; + return S_OK; +} + static unsigned String_idx_length(jsdisp_t *jsdisp) { StringInstance *string = string_from_jsdisp(jsdisp); @@ -1515,21 +1557,6 @@ static unsigned String_idx_length(jsdisp_t *jsdisp) return string->dispex.ctx->version < 2 ? 0 : jsstr_length(string->str); }
-static HRESULT String_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r) -{ - StringInstance *string = string_from_jsdisp(jsdisp); - jsstr_t *ret; - - ret = jsstr_substr(string->str, idx, 1); - if(!ret) - return E_OUTOFMEMORY; - - TRACE("%p[%u] = %s\n", string, idx, debugstr_jsstr(ret)); - - *r = jsval_string(ret); - return S_OK; -} - static const builtin_prop_t String_props[] = { {L"anchor", String_anchor, PROPF_METHOD|1}, {L"big", String_big, PROPF_METHOD}, @@ -1580,13 +1607,18 @@ static const builtin_prop_t StringInst_props[] = { };
static const builtin_info_t StringInst_info = { - DEFAULT_DISPEX_PROP_VTBL_ENTRIES, - .class = JSCLASS_STRING, - .props_cnt = ARRAY_SIZE(StringInst_props), - .props = StringInst_props, - .destructor = String_destructor, - .idx_length = String_idx_length, - .idx_get = String_idx_get, + .class = JSCLASS_STRING, + .props_cnt = ARRAY_SIZE(StringInst_props), + .props = StringInst_props, + .destructor = String_destructor, + .prop_get = String_prop_get, + .prop_put = String_prop_put, + .prop_invoke = indexed_prop_invoke, + .prop_delete = indexed_prop_delete, + .prop_get_desc = String_prop_get_desc, + .prop_get_name = indexed_prop_get_name, + .prop_define = indexed_prop_define, + .idx_length = String_idx_length, };
/* ECMA-262 3rd Edition 15.5.3.2 */
Rebased with new upstream changes, such as designated initializers like in mshtml, simplifying some of the patches.
This merge request was closed by Jacek Caban.
We have a new mechanism for MSHTML bindings that could potentially be extended to support typed arrays as well.
While looking at MSHTML bindings, I experimented with a different approach to avoid props entry allocations. Although convenient for cases requiring DISPIDs, we could skip those allocations when operating on properties by name. Since we perform the lookup anyway, we could directly use its result. Currently, jscript relies on DISPIDs internally, but the vast majority of cases could be refactored to not use them. I'm not sure, it would need more work.
That said, this is more of an optimization than a blocker at the moment and would require a different solution. Closing for now.