-- v3: 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 | 21 ++++- dlls/jscript/arraybuf.c | 38 ++++++++- dlls/jscript/bool.c | 14 +++- dlls/jscript/date.c | 21 ++++- dlls/jscript/dispex.c | 165 +++++++++++++++++++++----------------- dlls/jscript/engine.c | 5 ++ dlls/jscript/enumerator.c | 19 ++++- dlls/jscript/error.c | 14 +++- dlls/jscript/function.c | 25 ++++++ dlls/jscript/global.c | 7 +- dlls/jscript/jscript.c | 7 +- dlls/jscript/jscript.h | 10 +++ dlls/jscript/json.c | 7 +- dlls/jscript/jsregexp.c | 17 +++- dlls/jscript/math.c | 7 +- dlls/jscript/number.c | 14 +++- dlls/jscript/object.c | 21 ++++- dlls/jscript/set.c | 36 ++++++++- dlls/jscript/string.c | 19 ++++- dlls/jscript/vbarray.c | 7 +- 20 files changed, 370 insertions(+), 104 deletions(-)
diff --git a/dlls/jscript/array.c b/dlls/jscript/array.c index 078e2ce7d4c..9b1ca03cfa5 100644 --- a/dlls/jscript/array.c +++ b/dlls/jscript/array.c @@ -1645,7 +1645,12 @@ static const builtin_info_t Array_info = { ARRAY_SIZE(Array_props), Array_props, Array_destructor, - Array_on_put + Array_on_put, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static const builtin_prop_t ArrayInst_props[] = { @@ -1658,7 +1663,12 @@ static const builtin_info_t ArrayInst_info = { ARRAY_SIZE(ArrayInst_props), ArrayInst_props, Array_destructor, - Array_on_put + Array_on_put, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
/* ECMA-262 5.1 Edition 15.4.3.2 */ @@ -1766,7 +1776,12 @@ static const builtin_info_t ArrayConstr_info = { ARRAY_SIZE(ArrayConstr_props), ArrayConstr_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
HRESULT create_array_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 62dfe614d65..014f2373fc6 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -126,7 +126,12 @@ static const builtin_info_t ArrayBuffer_info = { ARRAY_SIZE(ArrayBuffer_props), ArrayBuffer_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static const builtin_prop_t ArrayBufferInst_props[] = { @@ -139,7 +144,12 @@ static const builtin_info_t ArrayBufferInst_info = { ARRAY_SIZE(ArrayBufferInst_props), ArrayBufferInst_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static HRESULT create_arraybuf(script_ctx_t *ctx, DWORD size, ArrayBufferInstance **ret) @@ -219,7 +229,12 @@ static const builtin_info_t ArrayBufferConstr_info = { ARRAY_SIZE(ArrayBufferConstr_props), ArrayBufferConstr_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static inline DataViewInstance *dataview_this(jsval_t vthis) @@ -616,6 +631,11 @@ static const builtin_info_t DataView_info = { DataView_props, DataView_destructor, NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, NULL, NULL, NULL, @@ -629,6 +649,11 @@ static const builtin_info_t DataViewInst_info = { NULL, DataView_destructor, NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, NULL, NULL, NULL, @@ -706,7 +731,12 @@ static const builtin_info_t DataViewConstr_info = { 0, NULL, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
HRESULT init_arraybuf_constructors(script_ctx_t *ctx) diff --git a/dlls/jscript/bool.c b/dlls/jscript/bool.c index 57c5cf5b4c6..574450ca898 100644 --- a/dlls/jscript/bool.c +++ b/dlls/jscript/bool.c @@ -124,7 +124,12 @@ static const builtin_info_t Bool_info = { ARRAY_SIZE(Bool_props), Bool_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static const builtin_info_t BoolInst_info = { @@ -132,7 +137,12 @@ static const builtin_info_t BoolInst_info = { Bool_value, 0, NULL, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static HRESULT BoolConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, diff --git a/dlls/jscript/date.c b/dlls/jscript/date.c index b1846fb3245..1006a82fab5 100644 --- a/dlls/jscript/date.c +++ b/dlls/jscript/date.c @@ -1905,7 +1905,12 @@ static const builtin_info_t Date_info = { ARRAY_SIZE(Date_props), Date_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static const builtin_info_t DateInst_info = { @@ -1913,7 +1918,12 @@ static const builtin_info_t DateInst_info = { NULL, 0, NULL, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static HRESULT create_date(script_ctx_t *ctx, jsdisp_t *object_prototype, DOUBLE time, DateInstance **ret) @@ -2441,7 +2451,12 @@ static const builtin_info_t DateConstr_info = { ARRAY_SIZE(DateConstr_props), DateConstr_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
HRESULT create_date_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 57882bf499e..baf6c6d9de8 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) { + *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) { - *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;
@@ -2209,7 +2239,12 @@ static const builtin_info_t dispex_info = { NULL, 0, NULL, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype, jsdisp_t **dispex) @@ -2388,13 +2423,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) @@ -2672,11 +2704,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;
@@ -2778,13 +2807,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) @@ -2839,11 +2865,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;
@@ -3199,11 +3222,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 76e6a271bdf..091d7f2c072 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -551,6 +551,11 @@ static const builtin_info_t scope_info = { NULL, scope_destructor, NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, scope_idx_length, scope_idx_get, scope_idx_put, diff --git a/dlls/jscript/enumerator.c b/dlls/jscript/enumerator.c index d962c65d229..dcceafa01b5 100644 --- a/dlls/jscript/enumerator.c +++ b/dlls/jscript/enumerator.c @@ -187,7 +187,12 @@ static const builtin_info_t Enumerator_info = { ARRAY_SIZE(Enumerator_props), Enumerator_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static const builtin_info_t EnumeratorInst_info = { @@ -197,6 +202,11 @@ static const builtin_info_t EnumeratorInst_info = { NULL, Enumerator_destructor, NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, NULL, NULL, NULL, @@ -329,7 +339,12 @@ static const builtin_info_t EnumeratorConstr_info = { 0, NULL, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
HRESULT create_enumerator_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index 81e3a3a9739..a3473a8cd86 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -144,7 +144,12 @@ static const builtin_info_t Error_info = { ARRAY_SIZE(Error_props), Error_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static const builtin_info_t ErrorInst_info = { @@ -153,7 +158,12 @@ static const builtin_info_t ErrorInst_info = { 0, NULL, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static HRESULT alloc_error(script_ctx_t *ctx, jsdisp_t *prototype, diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 68f841b38a1..7384dce26aa 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -190,6 +190,11 @@ static const builtin_info_t Arguments_info = { 0, NULL, Arguments_destructor, NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, Arguments_idx_length, Arguments_idx_get, Arguments_idx_put, @@ -608,6 +613,11 @@ static const builtin_info_t Function_info = { Function_props, Function_destructor, NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, NULL, NULL, NULL, @@ -627,6 +637,11 @@ static const builtin_info_t FunctionInst_info = { FunctionInst_props, Function_destructor, NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, NULL, NULL, NULL, @@ -814,6 +829,11 @@ static const builtin_info_t InterpretedFunction_info = { InterpretedFunction_props, Function_destructor, NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, NULL, NULL, NULL, @@ -946,6 +966,11 @@ static const builtin_info_t BindFunction_info = { BindFunction_props, Function_destructor, NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, NULL, NULL, NULL, diff --git a/dlls/jscript/global.c b/dlls/jscript/global.c index cc108b84e4b..9ca65c88224 100644 --- a/dlls/jscript/global.c +++ b/dlls/jscript/global.c @@ -910,7 +910,12 @@ static const builtin_info_t JSGlobal_info = { ARRAY_SIZE(JSGlobal_props), JSGlobal_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static HRESULT init_object_prototype_accessors(script_ctx_t *ctx, jsdisp_t *object_prototype) diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index 6829f80f299..6eda89a3246 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -127,7 +127,12 @@ HRESULT create_named_item_script_obj(script_ctx_t *ctx, named_item_t *item) NULL, 0, NULL, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
return create_dispex(ctx, &disp_info, NULL, &item->script_obj); diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 1a9446893a1..a9819449c00 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); diff --git a/dlls/jscript/json.c b/dlls/jscript/json.c index 277a5e01144..9087a48a827 100644 --- a/dlls/jscript/json.c +++ b/dlls/jscript/json.c @@ -953,7 +953,12 @@ static const builtin_info_t JSON_info = { ARRAY_SIZE(JSON_props), JSON_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
HRESULT create_json(script_ctx_t *ctx, jsdisp_t **ret) diff --git a/dlls/jscript/jsregexp.c b/dlls/jscript/jsregexp.c index 70673ec190e..48257f03ee5 100644 --- a/dlls/jscript/jsregexp.c +++ b/dlls/jscript/jsregexp.c @@ -576,6 +576,11 @@ static const builtin_info_t RegExp_info = { RegExp_props, RegExp_destructor, NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, NULL, NULL, NULL, @@ -597,6 +602,11 @@ static const builtin_info_t RegExpInst_info = { RegExpInst_props, RegExp_destructor, NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, NULL, NULL, NULL, @@ -966,7 +976,12 @@ static const builtin_info_t RegExpConstr_info = { ARRAY_SIZE(RegExpConstr_props), RegExpConstr_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
HRESULT create_regexp_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) diff --git a/dlls/jscript/math.c b/dlls/jscript/math.c index 362b877cb5e..2401acaf62d 100644 --- a/dlls/jscript/math.c +++ b/dlls/jscript/math.c @@ -496,7 +496,12 @@ static const builtin_info_t Math_info = { ARRAY_SIZE(Math_props), Math_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
HRESULT create_math(script_ctx_t *ctx, jsdisp_t **ret) diff --git a/dlls/jscript/number.c b/dlls/jscript/number.c index 27c3d5ecfee..ff2d73f5722 100644 --- a/dlls/jscript/number.c +++ b/dlls/jscript/number.c @@ -591,7 +591,12 @@ static const builtin_info_t Number_info = { ARRAY_SIZE(Number_props), Number_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static const builtin_info_t NumberInst_info = { @@ -599,7 +604,12 @@ static const builtin_info_t NumberInst_info = { NULL, 0, NULL, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static HRESULT NumberConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index 16ecc3dea3c..1053f5d27c8 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -470,7 +470,12 @@ static const builtin_info_t Object_info = { ARRAY_SIZE(Object_props), Object_props, Object_destructor, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static const builtin_info_t ObjectInst_info = { @@ -478,7 +483,12 @@ static const builtin_info_t ObjectInst_info = { NULL, 0, NULL, Object_destructor, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static void release_property_descriptor(property_desc_t *desc) @@ -1074,7 +1084,12 @@ static const builtin_info_t ObjectConstr_info = { ARRAY_SIZE(ObjectConstr_props), ObjectConstr_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static HRESULT ObjectConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index 7e49e31a5d5..1f7f8f2be20 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -406,7 +406,12 @@ static const builtin_info_t Map_prototype_info = { ARRAY_SIZE(Map_prototype_props), Map_prototype_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static const builtin_info_t Map_info = { @@ -416,6 +421,11 @@ static const builtin_info_t Map_info = { Map_props, Map_destructor, NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, NULL, NULL, NULL, @@ -565,7 +575,12 @@ static const builtin_info_t Set_prototype_info = { ARRAY_SIZE(Set_prototype_props), Set_prototype_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static const builtin_info_t Set_info = { @@ -575,6 +590,11 @@ static const builtin_info_t Set_info = { Map_props, Map_destructor, NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, NULL, NULL, NULL, @@ -862,7 +882,12 @@ static const builtin_info_t WeakMap_prototype_info = { ARRAY_SIZE(WeakMap_prototype_props), WeakMap_prototype_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static const builtin_info_t WeakMap_info = { @@ -872,6 +897,11 @@ static const builtin_info_t WeakMap_info = { NULL, WeakMap_destructor, NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, NULL, NULL, NULL, diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c index 4033f0a2b56..0ab9df0a588 100644 --- a/dlls/jscript/string.c +++ b/dlls/jscript/string.c @@ -1574,7 +1574,12 @@ static const builtin_info_t String_info = { ARRAY_SIZE(String_props), String_props, String_destructor, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static const builtin_prop_t StringInst_props[] = { @@ -1588,6 +1593,11 @@ static const builtin_info_t StringInst_info = { StringInst_props, String_destructor, NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, String_idx_length, String_idx_get }; @@ -1708,7 +1718,12 @@ static const builtin_info_t StringConstr_info = { ARRAY_SIZE(StringConstr_props), StringConstr_props, NULL, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
HRESULT create_string_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) diff --git a/dlls/jscript/vbarray.c b/dlls/jscript/vbarray.c index 998dc230818..3cfa84d8de7 100644 --- a/dlls/jscript/vbarray.c +++ b/dlls/jscript/vbarray.c @@ -252,7 +252,12 @@ static const builtin_info_t VBArray_info = { ARRAY_SIZE(VBArray_props), VBArray_props, VBArray_destructor, - NULL + NULL, + dispex_prop_get, + dispex_prop_put, + dispex_prop_invoke, + dispex_prop_delete, + dispex_prop_get_name, };
static HRESULT alloc_vbarray(script_ctx_t *ctx, jsdisp_t *object_prototype, VBArrayInstance **ret)
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.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/array.c | 6 + dlls/jscript/arraybuf.c | 12 + dlls/jscript/bool.c | 4 + dlls/jscript/date.c | 6 + dlls/jscript/dispex.c | 526 ++++++++++++++++++++------------------ dlls/jscript/engine.c | 2 + dlls/jscript/enumerator.c | 6 + dlls/jscript/error.c | 4 + dlls/jscript/function.c | 10 + dlls/jscript/global.c | 2 + dlls/jscript/jscript.c | 2 + dlls/jscript/jscript.h | 9 + dlls/jscript/json.c | 2 + dlls/jscript/jsregexp.c | 6 + dlls/jscript/math.c | 2 + dlls/jscript/number.c | 4 + dlls/jscript/object.c | 6 + dlls/jscript/set.c | 12 + dlls/jscript/string.c | 6 + dlls/jscript/vbarray.c | 2 + 20 files changed, 377 insertions(+), 252 deletions(-)
diff --git a/dlls/jscript/array.c b/dlls/jscript/array.c index 9b1ca03cfa5..6d2bbd7e32e 100644 --- a/dlls/jscript/array.c +++ b/dlls/jscript/array.c @@ -1650,7 +1650,9 @@ static const builtin_info_t Array_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static const builtin_prop_t ArrayInst_props[] = { @@ -1668,7 +1670,9 @@ static const builtin_info_t ArrayInst_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
/* ECMA-262 5.1 Edition 15.4.3.2 */ @@ -1781,7 +1785,9 @@ static const builtin_info_t ArrayConstr_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
HRESULT create_array_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 014f2373fc6..cd92fb47924 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -131,7 +131,9 @@ static const builtin_info_t ArrayBuffer_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static const builtin_prop_t ArrayBufferInst_props[] = { @@ -149,7 +151,9 @@ static const builtin_info_t ArrayBufferInst_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static HRESULT create_arraybuf(script_ctx_t *ctx, DWORD size, ArrayBufferInstance **ret) @@ -234,7 +238,9 @@ static const builtin_info_t ArrayBufferConstr_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static inline DataViewInstance *dataview_this(jsval_t vthis) @@ -635,7 +641,9 @@ static const builtin_info_t DataView_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, NULL, NULL, NULL, @@ -653,7 +661,9 @@ static const builtin_info_t DataViewInst_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, NULL, NULL, NULL, @@ -736,7 +746,9 @@ static const builtin_info_t DataViewConstr_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
HRESULT init_arraybuf_constructors(script_ctx_t *ctx) diff --git a/dlls/jscript/bool.c b/dlls/jscript/bool.c index 574450ca898..51a51cd48de 100644 --- a/dlls/jscript/bool.c +++ b/dlls/jscript/bool.c @@ -129,7 +129,9 @@ static const builtin_info_t Bool_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static const builtin_info_t BoolInst_info = { @@ -142,7 +144,9 @@ static const builtin_info_t BoolInst_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static HRESULT BoolConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, diff --git a/dlls/jscript/date.c b/dlls/jscript/date.c index 1006a82fab5..f712a7f5805 100644 --- a/dlls/jscript/date.c +++ b/dlls/jscript/date.c @@ -1910,7 +1910,9 @@ static const builtin_info_t Date_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static const builtin_info_t DateInst_info = { @@ -1923,7 +1925,9 @@ static const builtin_info_t DateInst_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static HRESULT create_date(script_ctx_t *ctx, jsdisp_t *object_prototype, DOUBLE time, DateInstance **ret) @@ -2456,7 +2460,9 @@ static const builtin_info_t DateConstr_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
HRESULT create_date_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index baf6c6d9de8..ecba9522f39 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,89 @@ 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) { if(del) { del->type = PROP_PROTREF; - del->u.ref = prop - This->prototype->props; + del->u.ref = prop_id_to_idx(*ret); prop = del; }else { - prop = alloc_protref(This, prop->name, prop - This->prototype->props); + prop = alloc_protref(This, name, prop_id_to_idx(*ret)); 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 +671,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 +711,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 +843,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 +854,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 +870,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 +2251,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 +2260,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) @@ -2244,7 +2405,9 @@ static const builtin_info_t dispex_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype, jsdisp_t **dispex) @@ -2332,14 +2495,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; @@ -2369,21 +2532,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; @@ -2431,17 +2591,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, @@ -2669,19 +2826,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) @@ -2770,39 +2927,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) @@ -2841,17 +2998,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; @@ -2931,8 +3088,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) { @@ -2940,9 +3097,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; @@ -2984,173 +3141,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/engine.c b/dlls/jscript/engine.c index 091d7f2c072..777a3462c3a 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -555,7 +555,9 @@ static const builtin_info_t scope_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, scope_idx_length, scope_idx_get, scope_idx_put, diff --git a/dlls/jscript/enumerator.c b/dlls/jscript/enumerator.c index dcceafa01b5..7c14955759b 100644 --- a/dlls/jscript/enumerator.c +++ b/dlls/jscript/enumerator.c @@ -192,7 +192,9 @@ static const builtin_info_t Enumerator_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static const builtin_info_t EnumeratorInst_info = { @@ -206,7 +208,9 @@ static const builtin_info_t EnumeratorInst_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, NULL, NULL, NULL, @@ -344,7 +348,9 @@ static const builtin_info_t EnumeratorConstr_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
HRESULT create_enumerator_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index a3473a8cd86..00e748b1f60 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -149,7 +149,9 @@ static const builtin_info_t Error_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static const builtin_info_t ErrorInst_info = { @@ -163,7 +165,9 @@ static const builtin_info_t ErrorInst_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static HRESULT alloc_error(script_ctx_t *ctx, jsdisp_t *prototype, diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 7384dce26aa..1335aad4a40 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -194,7 +194,9 @@ static const builtin_info_t Arguments_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, Arguments_idx_length, Arguments_idx_get, Arguments_idx_put, @@ -617,7 +619,9 @@ static const builtin_info_t Function_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, NULL, NULL, NULL, @@ -641,7 +645,9 @@ static const builtin_info_t FunctionInst_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, NULL, NULL, NULL, @@ -833,7 +839,9 @@ static const builtin_info_t InterpretedFunction_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, NULL, NULL, NULL, @@ -970,7 +978,9 @@ static const builtin_info_t BindFunction_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, NULL, NULL, NULL, diff --git a/dlls/jscript/global.c b/dlls/jscript/global.c index 9ca65c88224..ab00017cda2 100644 --- a/dlls/jscript/global.c +++ b/dlls/jscript/global.c @@ -915,7 +915,9 @@ static const builtin_info_t JSGlobal_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static HRESULT init_object_prototype_accessors(script_ctx_t *ctx, jsdisp_t *object_prototype) diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index 6eda89a3246..721a2edf826 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -132,7 +132,9 @@ HRESULT create_named_item_script_obj(script_ctx_t *ctx, named_item_t *item) dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
return create_dispex(ctx, &disp_info, NULL, &item->script_obj); diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index a9819449c00..67f5c3a90da 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); @@ -257,6 +261,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, diff --git a/dlls/jscript/json.c b/dlls/jscript/json.c index 9087a48a827..66c220e1c18 100644 --- a/dlls/jscript/json.c +++ b/dlls/jscript/json.c @@ -958,7 +958,9 @@ static const builtin_info_t JSON_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
HRESULT create_json(script_ctx_t *ctx, jsdisp_t **ret) diff --git a/dlls/jscript/jsregexp.c b/dlls/jscript/jsregexp.c index 48257f03ee5..93e5b1351f9 100644 --- a/dlls/jscript/jsregexp.c +++ b/dlls/jscript/jsregexp.c @@ -580,7 +580,9 @@ static const builtin_info_t RegExp_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, NULL, NULL, NULL, @@ -606,7 +608,9 @@ static const builtin_info_t RegExpInst_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, NULL, NULL, NULL, @@ -981,7 +985,9 @@ static const builtin_info_t RegExpConstr_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
HRESULT create_regexp_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) diff --git a/dlls/jscript/math.c b/dlls/jscript/math.c index 2401acaf62d..11e9670a71a 100644 --- a/dlls/jscript/math.c +++ b/dlls/jscript/math.c @@ -501,7 +501,9 @@ static const builtin_info_t Math_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
HRESULT create_math(script_ctx_t *ctx, jsdisp_t **ret) diff --git a/dlls/jscript/number.c b/dlls/jscript/number.c index ff2d73f5722..186fcc6ee2f 100644 --- a/dlls/jscript/number.c +++ b/dlls/jscript/number.c @@ -596,7 +596,9 @@ static const builtin_info_t Number_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static const builtin_info_t NumberInst_info = { @@ -609,7 +611,9 @@ static const builtin_info_t NumberInst_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static HRESULT NumberConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index 1053f5d27c8..a2097cb2d3c 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -475,7 +475,9 @@ static const builtin_info_t Object_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static const builtin_info_t ObjectInst_info = { @@ -488,7 +490,9 @@ static const builtin_info_t ObjectInst_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static void release_property_descriptor(property_desc_t *desc) @@ -1089,7 +1093,9 @@ static const builtin_info_t ObjectConstr_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static HRESULT ObjectConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index 1f7f8f2be20..24bdc059b27 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -411,7 +411,9 @@ static const builtin_info_t Map_prototype_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static const builtin_info_t Map_info = { @@ -425,7 +427,9 @@ static const builtin_info_t Map_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, NULL, NULL, NULL, @@ -580,7 +584,9 @@ static const builtin_info_t Set_prototype_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static const builtin_info_t Set_info = { @@ -594,7 +600,9 @@ static const builtin_info_t Set_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, NULL, NULL, NULL, @@ -887,7 +895,9 @@ static const builtin_info_t WeakMap_prototype_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static const builtin_info_t WeakMap_info = { @@ -901,7 +911,9 @@ static const builtin_info_t WeakMap_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, NULL, NULL, NULL, diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c index 0ab9df0a588..3dac3bd41e1 100644 --- a/dlls/jscript/string.c +++ b/dlls/jscript/string.c @@ -1579,7 +1579,9 @@ static const builtin_info_t String_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static const builtin_prop_t StringInst_props[] = { @@ -1597,7 +1599,9 @@ static const builtin_info_t StringInst_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, String_idx_length, String_idx_get }; @@ -1723,7 +1727,9 @@ static const builtin_info_t StringConstr_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
HRESULT create_string_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) diff --git a/dlls/jscript/vbarray.c b/dlls/jscript/vbarray.c index 3cfa84d8de7..55b9e0df109 100644 --- a/dlls/jscript/vbarray.c +++ b/dlls/jscript/vbarray.c @@ -257,7 +257,9 @@ static const builtin_info_t VBArray_info = { dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, + dispex_prop_get_desc, dispex_prop_get_name, + dispex_prop_define, };
static HRESULT alloc_vbarray(script_ctx_t *ctx, jsdisp_t *object_prototype, VBArrayInstance **ret)
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 ecba9522f39..bc4463d8023 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -618,32 +618,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) { - *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)); @@ -668,7 +642,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) { + *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 bc4463d8023..297f2f14789 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -567,17 +567,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)); @@ -586,21 +603,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)); @@ -618,28 +635,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 | 126 ++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 65 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index bc17d6c4ad0..227e33becee 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -457,13 +457,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; @@ -480,10 +531,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; @@ -500,85 +551,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
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 297f2f14789..bc17d6c4ad0 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -457,49 +457,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; @@ -575,7 +532,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
We can just use the object's prop_put now.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/array.c | 31 ++++++++++++++++++------------- dlls/jscript/arraybuf.c | 6 ------ dlls/jscript/bool.c | 2 -- dlls/jscript/date.c | 3 --- dlls/jscript/dispex.c | 9 +++++---- dlls/jscript/engine.c | 1 - dlls/jscript/enumerator.c | 3 --- dlls/jscript/error.c | 2 -- dlls/jscript/function.c | 5 ----- dlls/jscript/global.c | 1 - dlls/jscript/jscript.c | 1 - dlls/jscript/jscript.h | 2 +- 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, 24 insertions(+), 62 deletions(-)
diff --git a/dlls/jscript/array.c b/dlls/jscript/array.c index 6d2bbd7e32e..f6449ec0ad1 100644 --- a/dlls/jscript/array.c +++ b/dlls/jscript/array.c @@ -1594,25 +1594,33 @@ static void Array_destructor(jsdisp_t *dispex) free(dispex); }
-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[] = { @@ -1645,9 +1653,8 @@ static const builtin_info_t Array_info = { ARRAY_SIZE(Array_props), Array_props, Array_destructor, - Array_on_put, dispex_prop_get, - dispex_prop_put, + Array_prop_put, dispex_prop_invoke, dispex_prop_delete, dispex_prop_get_desc, @@ -1665,9 +1672,8 @@ static const builtin_info_t ArrayInst_info = { ARRAY_SIZE(ArrayInst_props), ArrayInst_props, Array_destructor, - Array_on_put, dispex_prop_get, - dispex_prop_put, + Array_prop_put, dispex_prop_invoke, dispex_prop_delete, dispex_prop_get_desc, @@ -1780,7 +1786,6 @@ static const builtin_info_t ArrayConstr_info = { ARRAY_SIZE(ArrayConstr_props), ArrayConstr_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index cd92fb47924..ce0c482e914 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -126,7 +126,6 @@ static const builtin_info_t ArrayBuffer_info = { ARRAY_SIZE(ArrayBuffer_props), ArrayBuffer_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -146,7 +145,6 @@ static const builtin_info_t ArrayBufferInst_info = { ARRAY_SIZE(ArrayBufferInst_props), ArrayBufferInst_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -233,7 +231,6 @@ static const builtin_info_t ArrayBufferConstr_info = { ARRAY_SIZE(ArrayBufferConstr_props), ArrayBufferConstr_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -636,7 +633,6 @@ static const builtin_info_t DataView_info = { ARRAY_SIZE(DataView_props), DataView_props, DataView_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -656,7 +652,6 @@ static const builtin_info_t DataViewInst_info = { 0, NULL, DataView_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -741,7 +736,6 @@ static const builtin_info_t DataViewConstr_info = { 0, NULL, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/bool.c b/dlls/jscript/bool.c index 51a51cd48de..0b5f9a2c34f 100644 --- a/dlls/jscript/bool.c +++ b/dlls/jscript/bool.c @@ -124,7 +124,6 @@ static const builtin_info_t Bool_info = { ARRAY_SIZE(Bool_props), Bool_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -139,7 +138,6 @@ static const builtin_info_t BoolInst_info = { Bool_value, 0, NULL, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/date.c b/dlls/jscript/date.c index f712a7f5805..25a99a45b54 100644 --- a/dlls/jscript/date.c +++ b/dlls/jscript/date.c @@ -1905,7 +1905,6 @@ static const builtin_info_t Date_info = { ARRAY_SIZE(Date_props), Date_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -1920,7 +1919,6 @@ static const builtin_info_t DateInst_info = { NULL, 0, NULL, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -2455,7 +2453,6 @@ static const builtin_info_t DateConstr_info = { ARRAY_SIZE(DateConstr_props), DateConstr_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 227e33becee..587ae1c87cb 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -569,9 +569,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; }
@@ -816,6 +813,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; @@ -2384,7 +2386,6 @@ static const builtin_info_t dispex_info = { NULL, 0, NULL, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index 777a3462c3a..e8437780d1b 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -550,7 +550,6 @@ static const builtin_info_t scope_info = { 0, NULL, scope_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/enumerator.c b/dlls/jscript/enumerator.c index 7c14955759b..1282882ae8f 100644 --- a/dlls/jscript/enumerator.c +++ b/dlls/jscript/enumerator.c @@ -187,7 +187,6 @@ static const builtin_info_t Enumerator_info = { ARRAY_SIZE(Enumerator_props), Enumerator_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -203,7 +202,6 @@ static const builtin_info_t EnumeratorInst_info = { 0, NULL, Enumerator_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -343,7 +341,6 @@ static const builtin_info_t EnumeratorConstr_info = { 0, NULL, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index 00e748b1f60..88e9e14fede 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -144,7 +144,6 @@ static const builtin_info_t Error_info = { ARRAY_SIZE(Error_props), Error_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -160,7 +159,6 @@ static const builtin_info_t ErrorInst_info = { 0, NULL, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 1335aad4a40..3b43b763512 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -189,7 +189,6 @@ static const builtin_info_t Arguments_info = { Arguments_value, 0, NULL, Arguments_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -614,7 +613,6 @@ static const builtin_info_t Function_info = { ARRAY_SIZE(Function_props), Function_props, Function_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -640,7 +638,6 @@ static const builtin_info_t FunctionInst_info = { ARRAY_SIZE(FunctionInst_props), FunctionInst_props, Function_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -834,7 +831,6 @@ static const builtin_info_t InterpretedFunction_info = { ARRAY_SIZE(InterpretedFunction_props), InterpretedFunction_props, Function_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -973,7 +969,6 @@ static const builtin_info_t BindFunction_info = { ARRAY_SIZE(BindFunction_props), BindFunction_props, Function_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/global.c b/dlls/jscript/global.c index ab00017cda2..a97ec29c7e8 100644 --- a/dlls/jscript/global.c +++ b/dlls/jscript/global.c @@ -910,7 +910,6 @@ static const builtin_info_t JSGlobal_info = { ARRAY_SIZE(JSGlobal_props), JSGlobal_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index 721a2edf826..38a65471bb5 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -127,7 +127,6 @@ HRESULT create_named_item_script_obj(script_ctx_t *ctx, named_item_t *item) NULL, 0, NULL, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 67f5c3a90da..70edb27447d 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*); diff --git a/dlls/jscript/json.c b/dlls/jscript/json.c index 66c220e1c18..6ae5bf961cb 100644 --- a/dlls/jscript/json.c +++ b/dlls/jscript/json.c @@ -953,7 +953,6 @@ static const builtin_info_t JSON_info = { ARRAY_SIZE(JSON_props), JSON_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/jsregexp.c b/dlls/jscript/jsregexp.c index 93e5b1351f9..02a35c09f71 100644 --- a/dlls/jscript/jsregexp.c +++ b/dlls/jscript/jsregexp.c @@ -575,7 +575,6 @@ static const builtin_info_t RegExp_info = { ARRAY_SIZE(RegExp_props), RegExp_props, RegExp_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -603,7 +602,6 @@ static const builtin_info_t RegExpInst_info = { ARRAY_SIZE(RegExpInst_props), RegExpInst_props, RegExp_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -980,7 +978,6 @@ static const builtin_info_t RegExpConstr_info = { ARRAY_SIZE(RegExpConstr_props), RegExpConstr_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/math.c b/dlls/jscript/math.c index 11e9670a71a..6d820ec71e1 100644 --- a/dlls/jscript/math.c +++ b/dlls/jscript/math.c @@ -496,7 +496,6 @@ static const builtin_info_t Math_info = { ARRAY_SIZE(Math_props), Math_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/number.c b/dlls/jscript/number.c index 186fcc6ee2f..9be6f6a2f90 100644 --- a/dlls/jscript/number.c +++ b/dlls/jscript/number.c @@ -591,7 +591,6 @@ static const builtin_info_t Number_info = { ARRAY_SIZE(Number_props), Number_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -606,7 +605,6 @@ static const builtin_info_t NumberInst_info = { NULL, 0, NULL, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index a2097cb2d3c..8739c0089e7 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -470,7 +470,6 @@ static const builtin_info_t Object_info = { ARRAY_SIZE(Object_props), Object_props, Object_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -485,7 +484,6 @@ static const builtin_info_t ObjectInst_info = { NULL, 0, NULL, Object_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -1088,7 +1086,6 @@ static const builtin_info_t ObjectConstr_info = { ARRAY_SIZE(ObjectConstr_props), ObjectConstr_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index 24bdc059b27..4310cd6f86c 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -406,7 +406,6 @@ static const builtin_info_t Map_prototype_info = { ARRAY_SIZE(Map_prototype_props), Map_prototype_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -422,7 +421,6 @@ static const builtin_info_t Map_info = { ARRAY_SIZE(Map_props), Map_props, Map_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -579,7 +577,6 @@ static const builtin_info_t Set_prototype_info = { ARRAY_SIZE(Set_prototype_props), Set_prototype_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -595,7 +592,6 @@ static const builtin_info_t Set_info = { ARRAY_SIZE(Map_props), Map_props, Map_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -890,7 +886,6 @@ static const builtin_info_t WeakMap_prototype_info = { ARRAY_SIZE(WeakMap_prototype_props), WeakMap_prototype_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -906,7 +901,6 @@ static const builtin_info_t WeakMap_info = { 0, NULL, WeakMap_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c index 3dac3bd41e1..e3aa61483d1 100644 --- a/dlls/jscript/string.c +++ b/dlls/jscript/string.c @@ -1574,7 +1574,6 @@ static const builtin_info_t String_info = { ARRAY_SIZE(String_props), String_props, String_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -1594,7 +1593,6 @@ static const builtin_info_t StringInst_info = { ARRAY_SIZE(StringInst_props), StringInst_props, String_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, @@ -1722,7 +1720,6 @@ static const builtin_info_t StringConstr_info = { ARRAY_SIZE(StringConstr_props), StringConstr_props, NULL, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke, diff --git a/dlls/jscript/vbarray.c b/dlls/jscript/vbarray.c index 55b9e0df109..81eaf83f908 100644 --- a/dlls/jscript/vbarray.c +++ b/dlls/jscript/vbarray.c @@ -252,7 +252,6 @@ static const builtin_info_t VBArray_info = { ARRAY_SIZE(VBArray_props), VBArray_props, VBArray_destructor, - NULL, dispex_prop_get, dispex_prop_put, dispex_prop_invoke,
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 587ae1c87cb..7f81b136d56 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) @@ -3052,7 +3052,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 7f81b136d56..46e4d878417 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -838,11 +838,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)) @@ -856,19 +874,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/arraybuf.c | 4 - dlls/jscript/dispex.c | 187 +++++++++++++++++++++++++++++--------- dlls/jscript/engine.c | 60 ++++++++---- dlls/jscript/enumerator.c | 2 - dlls/jscript/function.c | 97 ++++++++++++++------ dlls/jscript/jscript.h | 21 ++++- dlls/jscript/jsregexp.c | 4 - dlls/jscript/set.c | 6 -- dlls/jscript/string.c | 72 ++++++++++----- 9 files changed, 321 insertions(+), 132 deletions(-)
diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index ce0c482e914..697a9cbe7ad 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -641,8 +641,6 @@ static const builtin_info_t DataView_info = { dispex_prop_get_name, dispex_prop_define, NULL, - NULL, - NULL, DataView_gc_traverse };
@@ -660,8 +658,6 @@ static const builtin_info_t DataViewInst_info = { dispex_prop_get_name, dispex_prop_define, NULL, - NULL, - NULL, DataView_gc_traverse };
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 46e4d878417..ff4d4810d57 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) { @@ -386,7 +384,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)) { @@ -471,6 +469,10 @@ HRESULT dispex_prop_get(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, jsval_t
while(prop->type == PROP_PROTREF) { prop_obj = prop_obj->prototype; + if(!is_dispex_prop_id(prop->u.ref + 1)) { + hres = prop_obj->builtin_info->prop_get(prop_obj, jsthis, prop->u.ref + 1, r); + goto ret; + } prop = prop_obj->props + prop->u.ref; }
@@ -490,9 +492,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; @@ -503,6 +502,7 @@ HRESULT dispex_prop_get(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, jsval_t return hres; }
+ret: TRACE("%p.%s ret %s\n", jsdisp, debugstr_w(prop->name), debugstr_jsval(*r)); return hres; } @@ -518,6 +518,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)) + return prototype_iter->builtin_info->prop_put(prototype_iter, prop_iter->u.ref + 1, val); + prop_iter = prototype_iter->props + prop_iter->u.ref; } while(prop_iter->type == PROP_PROTREF);
@@ -552,12 +555,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; @@ -596,8 +593,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); @@ -660,7 +656,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); @@ -818,24 +813,108 @@ 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 : (IDispatch*)&jsdisp->IDispatchEx_iface, 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 : (IDispatch*)&jsdisp->IDispatchEx_iface), + 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) @@ -846,6 +925,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; @@ -862,10 +943,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;
@@ -873,6 +950,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) @@ -3042,15 +3131,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 e8437780d1b..0062b9889f2 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -479,36 +479,60 @@ static void scope_destructor(jsdisp_t *dispex) free(scope); }
-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); @@ -550,16 +574,14 @@ static const builtin_info_t scope_info = { 0, NULL, scope_destructor, - dispex_prop_get, - dispex_prop_put, - dispex_prop_invoke, - dispex_prop_delete, - dispex_prop_get_desc, - dispex_prop_get_name, - dispex_prop_define, + scope_prop_get, + scope_prop_put, + indexed_prop_invoke, + indexed_prop_delete, + scope_prop_get_desc, + indexed_prop_get_name, + indexed_prop_define, scope_idx_length, - scope_idx_get, - scope_idx_put, scope_gc_traverse };
diff --git a/dlls/jscript/enumerator.c b/dlls/jscript/enumerator.c index 1282882ae8f..b394beb15ec 100644 --- a/dlls/jscript/enumerator.c +++ b/dlls/jscript/enumerator.c @@ -210,8 +210,6 @@ static const builtin_info_t EnumeratorInst_info = { dispex_prop_get_name, dispex_prop_define, NULL, - NULL, - NULL, Enumerator_gc_traverse };
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 3b43b763512..3091a08f033 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); @@ -119,12 +120,6 @@ static void Arguments_destructor(jsdisp_t *jsdisp) free(arguments); }
-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) @@ -134,22 +129,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)) @@ -161,6 +167,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); @@ -189,16 +240,14 @@ static const builtin_info_t Arguments_info = { Arguments_value, 0, NULL, Arguments_destructor, - dispex_prop_get, - dispex_prop_put, - dispex_prop_invoke, - dispex_prop_delete, - dispex_prop_get_desc, - dispex_prop_get_name, - dispex_prop_define, + Arguments_prop_get, + Arguments_prop_put, + indexed_prop_invoke, + indexed_prop_delete, + Arguments_prop_get_desc, + indexed_prop_get_name, + Arguments_prop_define, Arguments_idx_length, - Arguments_idx_get, - Arguments_idx_put, Arguments_gc_traverse };
@@ -207,7 +256,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;
@@ -621,8 +670,6 @@ static const builtin_info_t Function_info = { dispex_prop_get_name, dispex_prop_define, NULL, - NULL, - NULL, Function_gc_traverse };
@@ -646,8 +693,6 @@ static const builtin_info_t FunctionInst_info = { dispex_prop_get_name, dispex_prop_define, NULL, - NULL, - NULL, Function_gc_traverse };
@@ -839,8 +884,6 @@ static const builtin_info_t InterpretedFunction_info = { dispex_prop_get_name, dispex_prop_define, NULL, - NULL, - NULL, Function_gc_traverse };
@@ -977,8 +1020,6 @@ static const builtin_info_t BindFunction_info = { dispex_prop_get_name, dispex_prop_define, NULL, - NULL, - NULL, Function_gc_traverse };
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 70edb27447d..2c2868291c7 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;
@@ -266,6 +268,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/jsregexp.c b/dlls/jscript/jsregexp.c index 02a35c09f71..c80dcd4ffd5 100644 --- a/dlls/jscript/jsregexp.c +++ b/dlls/jscript/jsregexp.c @@ -583,8 +583,6 @@ static const builtin_info_t RegExp_info = { dispex_prop_get_name, dispex_prop_define, NULL, - NULL, - NULL, RegExp_gc_traverse };
@@ -610,8 +608,6 @@ static const builtin_info_t RegExpInst_info = { dispex_prop_get_name, dispex_prop_define, NULL, - NULL, - NULL, RegExp_gc_traverse };
diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index 4310cd6f86c..78a38ef7cf0 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -429,8 +429,6 @@ static const builtin_info_t Map_info = { dispex_prop_get_name, dispex_prop_define, NULL, - NULL, - NULL, Map_gc_traverse };
@@ -600,8 +598,6 @@ static const builtin_info_t Set_info = { dispex_prop_get_name, dispex_prop_define, NULL, - NULL, - NULL, Map_gc_traverse };
@@ -909,8 +905,6 @@ static const builtin_info_t WeakMap_info = { dispex_prop_get_name, dispex_prop_define, NULL, - NULL, - NULL, WeakMap_gc_traverse };
diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c index e3aa61483d1..40e416fc9aa 100644 --- a/dlls/jscript/string.c +++ b/dlls/jscript/string.c @@ -1502,6 +1502,48 @@ static void String_destructor(jsdisp_t *dispex) free(This); }
+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); @@ -1516,21 +1558,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}, @@ -1593,15 +1620,14 @@ static const builtin_info_t StringInst_info = { ARRAY_SIZE(StringInst_props), StringInst_props, String_destructor, - dispex_prop_get, - dispex_prop_put, - dispex_prop_invoke, - dispex_prop_delete, - dispex_prop_get_desc, - dispex_prop_get_name, - dispex_prop_define, + String_prop_get, + String_prop_put, + indexed_prop_invoke, + indexed_prop_delete, + String_prop_get_desc, + indexed_prop_get_name, + indexed_prop_define, String_idx_length, - String_idx_get };
/* ECMA-262 3rd Edition 15.5.3.2 */
On Tue Apr 16 15:10:32 2024 +0000, Jacek Caban wrote:
Well this MR technically isn't about that, is it?
I think it should, see my earlier comments.
And having something like this is clearly the most "extensible" since
it allows overriding every prop's behavior. There are many solutions, we're looking for the one that fits our needs best. I can't review that aspect in its current form and I don't share your confidence about it.
I pushed new version with a small fix for arguments.
I also rewrote the Typed Arrays and jscript proxy patches to make use of this. It's on my wine's branch `jscript-proxies`.
The patches of note are cb615b32c4cd8cd9afed43bf1882df9139e6d365 and be63c5738979878a154b65e142983c9802feef4f. Note that they aren't split yet, since I keep rewriting them for now, it would make it too much wasted effort. But I don't think a full review of them is necessary, just the parts handling the props, right?
Some things to note:
* I got rid of PropDefineOverride and the "this" pointer for PropInvoke. * With respect to props, there are no special cases anymore for proxies, it's all handled in the props methods in the vtbl (from this MR). * Only one new method had to be added, `prop_fixup`.
I hope this shows that the current MR's approach is solid enough for proxies later.
A couple of things to note while reviewing, if you're wondering why it looks "hackish":
* async props in localStorage etc are weird as hell. Defining an accessor bypasses the override, and stores a normal js prop, and getOwnPropertyDescriptor also retrieves the normal js prop "underneath" the one set by setItem, if available. But, that only applies to getOwnPropertyDescriptor. Retrieving the prop via normal getter looks at getItem first. Look at the "storage" tests starting in dom.js after line 577 (on my branch).
* Other things making use of the "fixup" are the doc/window with props being from element lookups (or global props for window). But note that these are different from localStorage because they cannot *add* a new one, while localStorage can (e.g. localStorage.foobar = "1234" defining a new prop, but that can't happen on doc or window with the element lookup, it defines an actual jscript prop in those cases). They also don't override an existing js prop at all, so they only make use of the "fixup" but not the "override".
On Wed Apr 17 19:23:20 2024 +0000, Gabriel Ivăncescu wrote:
I pushed new version with a small fix for arguments. I also rewrote the Typed Arrays and jscript proxy patches to make use of this. It's on my wine's branch `jscript-proxies`. The patches of note are cb615b32c4cd8cd9afed43bf1882df9139e6d365 and be63c5738979878a154b65e142983c9802feef4f. Note that they aren't split yet, since I keep rewriting them for now, it would make it too much wasted effort. But I don't think a full review of them is necessary, just the parts handling the props, right? Some things to note:
- I got rid of PropDefineOverride and the "this" pointer for PropInvoke.
- With respect to props, there are no special cases anymore for proxies,
it's all handled in the props methods in the vtbl (from this MR).
- Only one new method had to be added, `prop_fixup`.
I hope this shows that the current MR's approach is solid enough for proxies later. A couple of things to note while reviewing, if you're wondering why it looks "hackish":
- async props in localStorage etc are weird as hell. Defining an
accessor bypasses the override, and stores a normal js prop, and getOwnPropertyDescriptor also retrieves the normal js prop "underneath" the one set by setItem, if available. But, that only applies to getOwnPropertyDescriptor. Retrieving the prop via normal getter looks at getItem first. Look at the "storage" tests starting in dom.js after line 577 (on my branch).
- Other things making use of the "fixup" are the doc/window with props
being from element lookups (or global props for window). But note that these are different from localStorage because they cannot *add* a new one, while localStorage can (e.g. localStorage.foobar = "1234" defining a new prop, but that can't happen on doc or window with the element lookup, it defines an actual jscript prop in those cases). They also don't override an existing js prop at all, so they only make use of the "fixup" but not the "override".
The interface for functions looks suspicious and I think that's a result of special-casing them in a wrong place. If they are indeed JS functions, `dispex.c` should be able to just call it like any other function (and `proxy_disp_call` should not be needed). Then something like `ProxyFunction_call` could just call a `IJSDispatchHost` method of the proper object if it implements the required interface.
This `prop_fixup` sounds solvable by just using different override strategy in relevant code paths. In one case we may interpret such case differently than in the other, I'm sure there is a cleaner way for that.
Did you consider allowing enums without callbacks to jscript? Ie. `IJSDispatchHost` enum could have an ID parameter and return the next one like `IDispatchEx` does? jscript could still additionally skip over properties if needed.
The interface for functions looks suspicious and I think that's a result of special-casing them in a wrong place. If they are indeed JS functions, `dispex.c` should be able to just call it like any other function (and `proxy_disp_call` should not be needed). Then something like `ProxyFunction_call` could just call a `IJSDispatchHost` method of the proper object if it implements the required interface.
But `proxy_disp_call` is not used for the functions, it's basically the analog for the builtin_info->call except for proxies. In fact, that's exactly where it is called from, the "call" method of JSCLASS_PROXY objects. It's for calling DISPID_VALUE mainly on objects (and constructors that aren't actual functions for instance, which is the majority of them).
It is additionally used for calling PROP_PROXY props—these are not the functions, but rather calling a prop like for instance sessionStorage's props and so on. You know, like our builtins on jscript that aren't functions nor accessors. Those can be invoked too, although it will likely error out.
In such case, the error is given by mshtml, which I found more extensible and cleaner so jscript doesn't have to worry about it (I don't know yet if some objects return something else, either). Plus, it's just one line of code re-using the same helper that's needed anyway… I could hardcode the error in jscript if you prefer it, but I'm not sure that buys us anything? `proxy_disp_call` is already used by the builtin_info->call anyway.
If you want an example of an object that's **not** a function that still needs to be invoked: anchor element's DISPID_VALUE.
This `prop_fixup` sounds solvable by just using different override strategy in relevant code paths. In one case we may interpret such case differently than in the other, I'm sure there is a cleaner way for that.
Sorry, I don't quite understand what you mean here. I use different cases because of how native works, to pass existing and new tests. `prop_fixup` is basically similar to the PROP_PROTREF fixup (in fact, the PROTREF fixup is implemented with it too), except it's for props that may pop into existence or pop out of existence at any point.
Can you be more specific about the other strategy please? And are you sure it's going to work in all cases?
EDIT: Regardless, I do believe that since it's a new method added only for proxies, this MR should be fine as it is, right? I mean the remaining methods in this MR do seem fine unless I'm missing something...?
Did you consider allowing enums without callbacks to jscript? Ie. `IJSDispatchHost` enum could have an ID parameter and return the next one like `IDispatchEx` does? jscript could still additionally skip over properties if needed.
Yeah, I guess that can work too, the only thing jscript is doing right now is to just populate the props (with find_prop_name), similar to fill_props. It's probably unrelated to this MR though, I don't see how it affects it.
On Mon Apr 22 16:02:21 2024 +0000, Gabriel Ivăncescu wrote:
The interface for functions looks suspicious and I think that's a
result of special-casing them in a wrong place. If they are indeed JS functions, `dispex.c` should be able to just call it like any other function (and `proxy_disp_call` should not be needed). Then something like `ProxyFunction_call` could just call a `IJSDispatchHost` method of the proper object if it implements the required interface. But `proxy_disp_call` is not used for the functions, it's basically the analog for the builtin_info->call except for proxies. In fact, that's exactly where it is called from, the "call" method of JSCLASS_PROXY objects. It's for calling DISPID_VALUE mainly on objects (and constructors that aren't actual functions for instance, which is the majority of them). It is additionally used for calling PROP_PROXY props—these are not the functions, but rather calling a prop like for instance sessionStorage's props and so on. You know, like our builtins on jscript that aren't functions nor accessors. Those can be invoked too, although it will likely error out. In such case, the error is given by mshtml, which I found more extensible and cleaner so jscript doesn't have to worry about it (I don't know yet if some objects return something else, either). Plus, it's just one line of code re-using the same helper that's needed anyway… I could hardcode the error in jscript if you prefer it, but I'm not sure that buys us anything? `proxy_disp_call` is already used by the builtin_info->call anyway. If you want an example of an object that's **not** a function that still needs to be invoked: anchor element's DISPID_VALUE.
This `prop_fixup` sounds solvable by just using different override
strategy in relevant code paths. In one case we may interpret such case differently than in the other, I'm sure there is a cleaner way for that. Sorry, I don't quite understand what you mean here. I use different cases because of how native works, to pass existing and new tests. `prop_fixup` is basically similar to the PROP_PROTREF fixup (in fact, the PROTREF fixup is implemented with it too), except it's for props that may pop into existence or pop out of existence at any point. Can you be more specific about the other strategy please? And are you sure it's going to work in all cases? EDIT: Regardless, I do believe that since it's a new method added only for proxies, this MR should be fine as it is, right? I mean the remaining methods in this MR do seem fine unless I'm missing something...?
Did you consider allowing enums without callbacks to jscript? Ie.
`IJSDispatchHost` enum could have an ID parameter and return the next one like `IDispatchEx` does? jscript could still additionally skip over properties if needed. Yeah, I guess that can work too, the only thing jscript is doing right now is to just populate the props (with find_prop_name), similar to fill_props. It's probably unrelated to this MR though, I don't see how it affects it.
Scratch the reference to the implementation, let me put it differently: why do you need a separate interface for functions? They are always called on "this" object, so why not use `IJSDisatchHost` of "this" object? Its implementation may get a function descriptor from the ID. The only additional thing from function descriptor that you need earlier is IID, to make sure that the object implements required interface. You could just make that a part of function description. I think we already discussed this part years ago. Things like `get_dispex_for_hook` should not be needed in the first place.
`prop_fixup` is an implementation detail (not a pretty one) that shouldn't be a part of the interface in its current form. When you need to check if the prototype is still valid, you may just query that value's description, for example.
On Wed Apr 24 22:01:05 2024 +0000, Jacek Caban wrote:
Scratch the reference to the implementation, let me put it differently: why do you need a separate interface for functions? They are always called on "this" object, so why not use `IJSDisatchHost` of "this" object? Its implementation may get a function descriptor from the ID. The only additional thing from function descriptor that you need earlier is IID, to make sure that the object implements required interface. You could just make that a part of function description. I think we already discussed this part years ago. Things like `get_dispex_for_hook` should not be needed in the first place. `prop_fixup` is an implementation detail (not a pretty one) that shouldn't be a part of the interface in its current form. When you need to check if the prototype is still valid, you may just query that value's description, for example.
The "this" object can be anything. It doesn't have to be a mshtml object. So what happens then? That's why I store the entire function context along with the this object in the function interface. For the props, we do have a mshtml object (the one holding the prop), so we don't need that, hence why it's a different interface.
You did mention the IID. The only way I can see how this can work out is by duplicating the interface checks from mshtml into jscript. Is that actually a good idea? I'd rather not duplicate code if mshtml can already handle it. BTW, how do I even store the IID without the function context (in the function interface, not the proxy)?
For `prop_fixup`, do you mean to use PropGetInfo? Or did I misunderstand? Honestly, I believe I tried that at first and something didn't work out, but that was awhile ago, maybe I was wrong or something changed since then. Not sure.
On Thu Apr 25 17:41:29 2024 +0000, Gabriel Ivăncescu wrote:
The "this" object can be anything. It doesn't have to be a mshtml object. So what happens then? That's why I store the entire function context along with the this object in the function interface. For the props, we do have a mshtml object (the one holding the prop), so we don't need that, hence why it's a different interface. You did mention the IID. The only way I can see how this can work out is by duplicating the interface checks from mshtml into jscript. Is that actually a good idea? I'd rather not duplicate code if mshtml can already handle it. BTW, how do I even store the IID without the function context (in the function interface, not the proxy)? For `prop_fixup`, do you mean to use PropGetInfo? Or did I misunderstand? Honestly, I believe I tried that at first and something didn't work out, but that was awhile ago, maybe I was wrong or something changed since then. Not sure.
Actually wait nevermind, we can't use the IJSDispatchHost for functions, because functions can be completely detached from the object: ```jscript var a = document.createEvent; a(...) ``` I remember I did try that at first and it was a dead end.
On Thu Apr 25 17:44:33 2024 +0000, Gabriel Ivăncescu wrote:
Actually wait nevermind, we can't use the IJSDispatchHost for functions, because functions can be completely detached from the object:
var a = document.createEvent; a(...)
I remember I did try that at first and it was a dead end.
If "this" object is not MSHTML object, then we know that it doesn't implement the required interface and we throw an appropriate error. The code from your example should fail, unless I'm missing something. It's really the same: it would get the default "this" handling, which means that "this" object doesn't implement the required interface. (That code could work in older compat modes, where functions were tied to object instances, but it's a very different semantics and not interesting for the interface).
For `IID`, it seems to me that the first step would be to replace `proxy_func_invoker` with just `IID`, you already have `DISPID` anyway.
And yes, for `prop_fixup` I meant something like that. It may be more convenient to have an ID-based variant (instead of name lookup), possibly not, I'm not sure.
On Fri Apr 26 12:13:08 2024 +0000, Jacek Caban wrote:
If "this" object is not MSHTML object, then we know that it doesn't implement the required interface and we throw an appropriate error. The code from your example should fail, unless I'm missing something. It's really the same: it would get the default "this" handling, which means that "this" object doesn't implement the required interface. (That code could work in older compat modes, where functions were tied to object instances, but it's a very different semantics and not interesting for the interface). For `IID`, it seems to me that the first step would be to replace `proxy_func_invoker` with just `IID`, you already have `DISPID` anyway. And yes, for `prop_fixup` I meant something like that. It may be more convenient to have an ID-based variant (instead of name lookup), possibly not, I'm not sure.
OK, I see what you mean with the IID. I didn't think of it, because I thought of delegating everything to mshtml (which already queries the IID and returns appropriate error) and making a generic interface for jscript so that it won't care of also checking it, but if you're ok with that I can try to squash the interfaces.
For the lookup, we need name-based lookup unfortunately because that's the whole point of the fixup (and override): such props may not have existed before, so what would the ID even be?
That said, I'm not sure either of these have to do with this MR, I mean "prop_fixup" itself is not tied to the fixup on the mshtml side (which can have a different interface later), but it's for jscript code itself. Anything in particular wrong with the interfaces in this MR? Or something you'd rather have done differently?
Even if we change PropFixup to PropGetInfo, I don't think it will change the jscript side for this MR.
On Fri Apr 26 15:52:42 2024 +0000, Gabriel Ivăncescu wrote:
OK, I see what you mean with the IID. I didn't think of it, because I thought of delegating everything to mshtml (which already queries the IID and returns appropriate error) and making a generic interface for jscript so that it won't care of also checking it, but if you're ok with that I can try to squash the interfaces. For the lookup, we need name-based lookup unfortunately because that's the whole point of the fixup (and override): such props may not have existed before, so what would the ID even be? That said, I'm not sure either of these have to do with this MR, I mean "prop_fixup" itself is not tied to the fixup on the mshtml side (which can have a different interface later), but it's for jscript code itself. Anything in particular wrong with the interfaces in this MR? Or something you'd rather have done differently? Even if we change PropFixup to PropGetInfo, I don't think it will change the jscript side for this MR.
I pushed new version to `jscript-proxies` that should address the suggestions. But it didn't change anything in the jscript object vtbl (for props I mean, not those interacting with mshtml). So for this MR, nothing changed at all.
On Tue Apr 30 19:10:03 2024 +0000, Gabriel Ivăncescu wrote:
I pushed new version to `jscript-proxies` that should address the suggestions. But it didn't change anything in the jscript object vtbl (for props I mean, not those interacting with mshtml). So for this MR, nothing changed at all.
That part looks better, thanks. FWIW, if QI itself would fit better in MSHTML, it could also be just passed back together with ID.
`PropOverride` still looks weird to have in the interface. Can't we use other functions for that? It's essentially a `GetPropInfo` combined with a getter call.
For calling the other way around, forwarding MSHTML `IDispatchEx` to jscript looks reasonable, but do you have some tests confirming it? Another approach would be to have them keep doing 'IE8' thing and use something entirely separate for JS. An example of a test distinguishing those approaches would be div element's `IDispatchEx` being able to query properties of `Element` and `Object` methods, respond to defining new ones (on prototypes) and deleting ones, something like that.
For enums, I didn't really mean a glue code, but to consider if we'd want to change it at the core. It would be great if you'd include the code required for proper external prototype support, that should answer a number of my questions.
Generally, jscript guarantees that if a property was exposed from given object once, a property of that name will always have the same dispid, even if it's removed and redefined. This is partially to make sure that callers `IDispatch` dispid caching works, but it's probably more than we really need to guarantee there.
Current jsdisp implementation depends on this strict behavior for correctness. That's what allows prototype reference to work like they do right now, but maintaining an invariant like this is not really convenient for MSHTML. It's not clear to me what's your plan here; you tweaked that for enum, but I'm afraid that for allowing MSHTML objects to be prototypes we may need to change it at the core.
Anyway, it's probably better to talk with a prototype, since you already have it implemented. I'd be mostly interested with minimal testable case, like a single MSHTML object with required interface and implementation changes. Could you please port something like that into the branch?
But it didn't change anything in the jscript object vtbl (for props I mean, not those interacting with mshtml). So for this MR, nothing changed at all.
Well, you put some glue code instead of changing jscript, so nothing changed. I really don't review this MR can be reviewed of the context. Most of comments about the interface apply to this internal interface as well. For example, I hope there is a better way than 'fixup' callbacks (even if it's not technically in this MR, that's what this MR leads to).
I think that the best way forward is to get the prototype into a better shape first. It would be great if you could get unneeded parts out of it. That includes typed arrays and a few other commits, I really hope that we can take care of MSHTML bindings first. Since we already started discussing it here, maybe it makes sense to push such stripped branch to this MR, rename it and mark as a draft? Or have a new draft, if you prefer?
`PropOverride` still looks weird to have in the interface. Can't we use other functions for that? It's essentially a `GetPropInfo` combined with a getter call.
Well the thing is it only applies to specific objects, and must return S_FALSE otherwise so we know it doesn't. Not sure how to fit that in existing functions without over-engineering them? I could make a function that returns a BOOL like `OverridesProps` but that's just replacing it with another…
For calling the other way around, forwarding MSHTML `IDispatchEx` to jscript looks reasonable, but do you have some tests confirming it? Another approach would be to have them keep doing 'IE8' thing and use something entirely separate for JS. An example of a test distinguishing those approaches would be div element's `IDispatchEx` being able to query properties of `Element` and `Object` methods, respond to defining new ones (on prototypes) and deleting ones, something like that.
For enums, I didn't really mean a glue code, but to consider if we'd want to change it at the core. It would be great if you'd include the code required for proper external prototype support, that should answer a number of my questions.
Generally, jscript guarantees that if a property was exposed from given object once, a property of that name will always have the same dispid, even if it's removed and redefined. This is partially to make sure that callers `IDispatch` dispid caching works, but it's probably more than we really need to guarantee there.
Current jsdisp implementation depends on this strict behavior for correctness. That's what allows prototype reference to work like they do right now, but maintaining an invariant like this is not really convenient for MSHTML. It's not clear to me what's your plan here; you tweaked that for enum, but I'm afraid that for allowing MSHTML objects to be prototypes we may need to change it at the core.
Not sure if we have a test (or how to test it?), but native **does not** use the fixed DISPIDs in IE9+ like in IE8 and below, which suggests that it does something similar to my approach. See `test_elem_GetIDsOfNames` in `tests/dom.c` comment; feel free to remove that check and watch it fail. Obviously I can't test for fixed DISPID that's why I skipped it…
There is also `test_doc_obj` in `tests/events.c` with the comment and following test at `Navigate to a different document mode page`, where we test `importNode`'s DISPID, and it's not fixed.
In my case we guarantee the DISPIDs are the same for the given name, just not across different objects, but on the same object. Isn't that enough? It is the same as jscript. Two jscript objects, even if they're the same object "type", will likely have different DISPIDs for the same name. The only thing we don't guarantee is their "fixed" DISPIDs but that's already the case on native in IE9+.
I don't really understand what you mean by enums. Right now it's basically just doing what jscript does, filling the props, except instead of jscript builtins it's mshtml builtins (which end up as proxies, either functions, accessors or PROP_PROXY). It works the same way, there's zero changes needed for prototypes. We have a new method to deal with it because we have to bypass the normal `GetNextDispID` since that would call back into us, just like e.g. PropInvoke vs InvokeEx.
Anyway, it's probably better to talk with a prototype, since you already have it implemented. I'd be mostly interested with minimal testable case, like a single MSHTML object with required interface and implementation changes. Could you please port something like that into the branch?
Sorry, I don't understand what you mean here. Wouldn't special casing one object be worse, because it would include extra checks/code (generic is easier, it applies to all DispatchEx on mshtml side), **and** there's no guarantee that it would cover all cases, which is the main point isn't it? If we didn't have objects like `localStorage` then all this override/fixup wouldn't have been needed. Tbh I'm not even sure how to begin special casing just one object.
Well, you put some glue code instead of changing jscript, so nothing changed. I really don't review this MR can be reviewed of the context. Most of comments about the interface apply to this internal interface as well. For example, I hope there is a better way than 'fixup' callbacks (even if it's not technically in this MR, that's what this MR leads to).
Unfortunately I can't see a better way, since there's no way even for mshtml code to know when some underlying storage changed for those objects (no callbacks or anything). We already fixup the PROP_PROTREFs so I thought reusing that would make it more acceptable.
The other concerns, like forwarding calls to jscript, DISPIDs, and so on, I don't see how they're relevant to this MR? I prefer doing it a bit at a time instead of all at once.
I think that the best way forward is to get the prototype into a better shape first. It would be great if you could get unneeded parts out of it. That includes typed arrays and a few other commits, I really hope that we can take care of MSHTML bindings first. Since we already started discussing it here, maybe it makes sense to push such stripped branch to this MR, rename it and mark as a draft? Or have a new draft, if you prefer?
I can, but this is a lot more work than Typed Arrays, so I wanted to get those in first so it doesn't keep piling up. Note that I haven't split it up yet, and I want to get it in acceptable shape somewhat first because re-writing it constantly if it's split up becomes a nightmare.
Though Typed Arrays don't really affect this much, they do show that they are enough for the current jscript prop methods in the vtbl, isn't that enough for this MR?
Are you sure you don't want to review this MR as-is so I can get those in first? "fixup" may not be good, but it's not part of this MR as noted, and so if we find a better way later it wouldn't affect this MR.
The other methods are totally justified for non-mshtml cases so we need them regardless of what happens with mshtml bindings.
Not sure if we have a test (or how to test it?)
I didn't talk about testing it, but your observations confirm my suspicious. Now imagine that we have `pobj` like that, with async properties not guarantying dispid stability, which initially has `async1` prop. Now consider this: ``` function f() {} f.prototype = pobj; var o = new f(); x = o.async1; // some other code; meantime async1 disappears, async2 appears and then a new async1 appears with a different dispid x = o.async1; // problem: now prototype ref points to wrong property and simple name dispid or name validation will not be enough ```
I expect the above to be a problem if you base prototypes on something like this MR, so I'm curious what you did about it.
The test I asked was about something different, to show how `IDispatchEx should behave. That requires prototypes to test: ``` div = document.getElementById("divid"); Object.prototype.x = 1; // verify that div IDispatchEx can query x Element.prototype.y = 2; // verify that div IDispatchEx can query y detele Object.prototype.x; // ... ```
Do you have a test like that?
The other concerns, like forwarding calls to jscript, DISPIDs, and so on, I don't see how they're relevant to this MR? I prefer doing it a bit at a time instead of all at once.
The test above may be a bit of corner case, but more generally forwarding calls to jscript is by no means a corner case, it affects a pretty core part of the design and this MR is a part of its implementation. I'm not very interested in corner cases at this point, but I'm interested in making sure we don't end up with ad-hoc design mess (like the code in Proton).
On Fri May 10 00:16:53 2024 +0000, Jacek Caban wrote:
Not sure if we have a test (or how to test it?)
I didn't talk about testing it, but your observations confirm my suspicious. Now imagine that we have `pobj` like that, with async properties not guarantying dispid stability, which initially has `async1` prop. Now consider this:
function f() {} f.prototype = pobj; var o = new f(); x = o.async1; // some other code; meantime async1 disappears, async2 appears and then a new async1 appears with a different dispid x = o.async1; // problem: now prototype ref points to wrong property and simple name dispid or name validation will not be enough
I expect the above to be a problem if you base prototypes on something like this MR, so I'm curious what you did about it. The test I asked was about something different, to show how `IDispatchEx should behave. That requires prototypes to test:
div = document.getElementById("divid"); Object.prototype.x = 1; // verify that div IDispatchEx can query x Element.prototype.y = 2; // verify that div IDispatchEx can query y detele Object.prototype.x; // ...
Do you have a test like that?
The other concerns, like forwarding calls to jscript, DISPIDs, and so
on, I don't see how they're relevant to this MR? I prefer doing it a bit at a time instead of all at once. The test above may be a bit of corner case, but more generally forwarding calls to jscript is by no means a corner case, it affects a pretty core part of the design and this MR is a part of its implementation. I'm not very interested in corner cases at this point, but I'm interested in making sure we don't end up with ad-hoc design mess (like the code in Proton).
I tried hard to reproduce what you meant but it doesn't seem to be possible? I mean, if o.async1 disappears, it doesn't mean the DISPID disappears. It just becomes PROP_DELETED on jscript or equivalent. Obviously it disappears from the jscript code's perspective, but not when querying the DISPID, the name is still "stored" in the object's props. Am I missing something?
I'm just using jscript's facility here. If you mean the "override" rather than the "fixup", then it's done on *existing props* so still have the same DISPID, although it's looked up via name on mshtml side but that's purely implementation detail, since mshtml doesn't know about jscript's DISPID (I guess it could be possible to obtain the name from DISPID via GetMemberName or the like but why complicate it when we can pass the name?).
In short: the prop "fixup" doesn't fixup the name, but rather the prop's value/contents (or deletes the prop). But deleted props don't delete the name—and DISPIDs are associated with the name, not the contents of the prop.
So: ```jscript x = o.async1 // ... x = o.async1 ``` First one let's say creates the async1 prop. Then it gets deleted on the file. jscript doesn't know this of course. Next time we obtain it, it's actually deleted, so it returns "undefined". But note that this is done in the getter, which already has the DISPID—the same DISPID as previously.
Unless I'm missing something? Maybe I'm testing it wrong.
On Fri May 10 17:20:07 2024 +0000, Gabriel Ivăncescu wrote:
I tried hard to reproduce what you meant but it doesn't seem to be possible? I mean, if o.async1 disappears, it doesn't mean the DISPID disappears. It just becomes PROP_DELETED on jscript or equivalent. Obviously it disappears from the jscript code's perspective, but not when querying the DISPID, the name is still "stored" in the object's props. Am I missing something? I'm just using jscript's facility here. If you mean the "override" rather than the "fixup", then it's done on *existing props* so still have the same DISPID, although it's looked up via name on mshtml side but that's purely implementation detail, since mshtml doesn't know about jscript's DISPID (I guess it could be possible to obtain the name from DISPID via GetMemberName or the like but why complicate it when we can pass the name?). In short: the prop "fixup" doesn't fixup the name, but rather the prop's value/contents (or deletes the prop). But deleted props don't delete the name—and DISPIDs are associated with the name, not the contents of the prop. So:
x = o.async1 // ... x = o.async1
First one let's say creates the async1 prop. Then it gets deleted on the file. jscript doesn't know this of course. Next time we obtain it, it's actually deleted, so it returns "undefined". But note that this is done in the getter, which already has the DISPID—the same DISPID as previously. Unless I'm missing something? Maybe I'm testing it wrong.
`o`'s dispid points to a protocol reference, which references the prototype's property by dispid. The prototype reference is never removed in my example (only the property in the prototype, but `o` wouldn't know about it even if it wasn't an "async" property), it would still forward to the prototype, but potentially using a wrong dispid now.
`o`'s dispid points to a protocol reference
I meant prototype reference.
On Fri May 10 19:38:37 2024 +0000, Jacek Caban wrote:
`o`'s dispid points to a protocol reference
I meant prototype reference.
Wait so let's break it down a bit. Are you talking about the DISPID on mshtml side (the "internal" prop on mshtml, e.g. dynamic prop or whatever), or the DISPID on jscript side?
The DISPID on mshtml side is opaque to jscript, it's part of the proxy function/accessor/PROP_PROXY, but jscript doesn't really need to know about it. You can think of it as an opaque `void *context` so it shouldn't interfere with prototype lookup at all.
Now if you mean the DISPID on jscript side, I can't reproduce what you describe. Let's say `o` has PROP_PROTREF that points to the async prop, let's say it's 42. The backing file then removes the prop on the prototype, so next time we "fixup" the prop we turn it (on the prototype) into PROP_DELETED.
The PROP_PROTREF should then be fixed up whenever accessed just like normally via our fix_protref_prop, as we lookup where `42` points to and it's a PROP_DELETED now, so the PROP_PROTREF gets turned into a PROP_DELETED itself (except I've now moved it into a vtbl function so that proxy objects can override it).
Note that prop_fixup on proxy objects should forward to the standard `dispex_prop_fixup` where necessary (to fixup PROTREF as mentioned), so this should be handled already. That PROTREF fixup was already a thing before this patch, actually it's a thing before this entire MR… It's not exclusive to async props.
If I'm still misunderstanding, can you please provide a simple case that actually fails, no matter how hacky it is, I don't mind. It doesn't have to even use a mshtml object, just hack something so it "acts" like one? (actually that's how I've been trying to reproduce this, to no avail)
On Sat May 11 17:42:25 2024 +0000, Gabriel Ivăncescu wrote:
Wait so let's break it down a bit. Are you talking about the DISPID on mshtml side (the "internal" prop on mshtml, e.g. dynamic prop or whatever), or the DISPID on jscript side? The DISPID on mshtml side is opaque to jscript, it's part of the proxy function/accessor/PROP_PROXY, but jscript doesn't really need to know about it. You can think of it as an opaque `void *context` so it shouldn't interfere with prototype lookup at all. Now if you mean the DISPID on jscript side, I can't reproduce what you describe. Let's say `o` has PROP_PROTREF that points to the async prop, let's say it's 42. The backing file then removes the prop on the prototype, so next time we "fixup" the prop we turn it (on the prototype) into PROP_DELETED. The PROP_PROTREF should then be fixed up whenever accessed just like normally via our fix_protref_prop, as we lookup where `42` points to and it's a PROP_DELETED now, so the PROP_PROTREF gets turned into a PROP_DELETED itself (except I've now moved it into a vtbl function so that proxy objects can override it). Note that prop_fixup on proxy objects should forward to the standard `dispex_prop_fixup` where necessary (to fixup PROTREF as mentioned), so this should be handled already. That PROTREF fixup was already a thing before this patch, actually it's a thing before this entire MR… It's not exclusive to async props. If I'm still misunderstanding, can you please provide a simple case that actually fails, no matter how hacky it is, I don't mind. It doesn't have to even use a mshtml object, just hack something so it "acts" like one? (actually that's how I've been trying to reproduce this, to no avail)
Ah, right, shadow dispids would take care of it. The `PROP_PROXY` thing is confusing to me, I'm not yet sure what to think about it. I thought that the point of this MR is to allow external properties to not need `dispex_prop_t` (just like jscript internal indexed props). I can see how some things are easier this way (through I feel like the same would be true for other parts if we didn't allocate those). It may be useful to allow "shadowing" properties for some cases, but for that a flag in `dispex_prop_t` could be enough, I'm not sure it needs a new property type. Did you consider something like that? Is it not feasible?
On Mon May 13 09:57:45 2024 +0000, Jacek Caban wrote:
Ah, right, shadow dispids would take care of it. The `PROP_PROXY` thing is confusing to me, I'm not yet sure what to think about it. I thought that the point of this MR is to allow external properties to not need `dispex_prop_t` (just like jscript internal indexed props). I can see how some things are easier this way (through I feel like the same would be true for other parts if we didn't allocate those). It may be useful to allow "shadowing" properties for some cases, but for that a flag in `dispex_prop_t` could be enough, I'm not sure it needs a new property type. Did you consider something like that? Is it not feasible?
We have to use `dispex_prop_t` because we need the name and DISPID for them in this case, they're not just indices.
PROP_PROXY is simply a prop that delegates to mshtml side, it's very similar to PROP_BUILTIN except the "builtin" here is on mshtml, so we just store the necessary info to access it (mshtml DISPID, basically). Note that it is *not* for functions or accessors, it's for the other props (custom props for instance), just like PROP_BUILTIN.
There's other ways of implementing it but this is the most straightforward, I think, since it simply forwards.
I'm not sure how to implement these custom props *without* dispex_prop_t because, again, we need a name and that's what dispex_prop_t facility is for.
I could make an exception for indexed mshtml props (custom props that are just indices), but that needs special-casing and I don't think it's good to complicate this initial design with it. It can come later, since it doesn't affect functionality, just an optimization.
BTW for "shadowing props". PROP_PROXY props aren't special in the sense of shadowing other props, they're props just like PROP_BUILTIN for example. The "overriding" props (in localStorage for instance) are special, though, but that's not related to PROP_PROXY directly; they override any prop, not just PROP_PROXY.
I think it helps if you think of PROP_PROXY just like PROP_BUILTIN except the builtin code is in mshtml, but that's it.
We have to use `dispex_prop_t` because we need the name and DISPID for them in this case, they're not just indices.
They could potentially be just indices, the association between name and ID may be easily done on MSHTML side (it's already doing that now).
Note that it is _not_ for functions or accessors, it's for the other props (custom props for instance), just like PROP_BUILTIN.
I think I can live with it, but note that the requirement to create a function object instance for all MSHTML builtin functions that are used is not exactly optimal. It would be possible to optimize that in the future, hopefully without full rewrite of the interface. Just like we do for jscript builtin functions.
I think it helps if you think of PROP_PROXY just like PROP_BUILTIN except the builtin code is in mshtml, but that's it.
Sure, although... it's by no means something for now, but I could imagine getting rid of `PROP_BUILTIN` and use the same 'external' properties for them instead, just like other external props (MSHTML and indexed props in the current proposal).
They could potentially be just indices, the association between name and ID may be easily done on MSHTML side (it's already doing that now).
I don't think I follow. The name is used for jscript prop lookup, not mshtml. We absolutely need it for hash and standard name lookup. It's not an internal thing. PROP_PROXY doesn't care what name it has, it only stores the DISPID (index basically) to access it from mshtml. But looking it up **does** require name, because the prop has a name, so we do need dispex_prop_t, just like builtins. To be fair I'm talking about **being accessed by name via jscript**, nothing to do with mshtml internals.
Think of window props, for example. I'm not talking about simple dynamic props on the window, which can be stored in jscript as simple values (and will be, later though, not in my branch yet, as I said I don't want to overcomplicate it). Instead, think of the other "global_props" (from mshtml's meaning of it) on the window, such as other scripts, elements, etc. Those need PROP_PROXY to get accessed…
I think I can live with it, but note that the requirement to create a function object instance for all MSHTML builtin functions that are used is not exactly optimal. It would be possible to optimize that in the future, hopefully without full rewrite of the interface. Just like we do for jscript builtin functions.
We can save that for later, but I believe it's as optimal as builtins right now. That is, they get allocated on demand (when needed), but otherwise we need them as functions, because even builtins had to be converted from builtins into actual functions at some point. Only the "value prop" builtins still remain as such (it's same with PROP_PROXY).
Sure, although... it's by no means something for now, but I could imagine getting rid of `PROP_BUILTIN` and use the same 'external' properties for them instead, just like other external props (MSHTML and indexed props in the current proposal).
How would that work? Builtins have a name, so we can't just use the same as indexed props because such name needs to have a DISPID mapping to it and be looked up by hash. We could use an extra layer of mapping for builtins of course, but I think that's overkill and likely slower (instead of just one hash lookup, now it's two lookups).
It also complicates it because, for instance, builtins can be deleted, and then we have to actually implement every prop behavior on them instead of relying on dispex_prop_t facilities. Right now if they get deleted, the prop remains as PROP_DELETED and so can be easily replaced by something else. But yeah, maybe it's worth it way later though, we'll need measurements I guess.