-- v2: jscript: Do existing prop lookups for external props only on objects with
From: Gabriel Ivăncescu gabrielopcode@gmail.com
And for non-volatile objects, don't even use them to store new props; instead just create normal jscript props.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 6 ++-- dlls/jscript/jscript.h | 1 + dlls/jscript/jsdisp.idl | 1 + dlls/mshtml/htmlcurstyle.c | 1 + dlls/mshtml/htmldoc.c | 8 ++--- dlls/mshtml/htmlelem.c | 3 ++ dlls/mshtml/htmlelemcol.c | 1 + dlls/mshtml/htmlform.c | 1 + dlls/mshtml/htmlframe.c | 2 ++ dlls/mshtml/htmlnode.c | 1 + dlls/mshtml/htmlselect.c | 1 + dlls/mshtml/htmlstorage.c | 2 +- dlls/mshtml/htmlstyle.c | 2 ++ dlls/mshtml/htmlstylesheet.c | 2 ++ dlls/mshtml/htmlwindow.c | 2 +- dlls/mshtml/tests/documentmode.js | 59 +++++++++++++++++++++++++++++++ 16 files changed, 85 insertions(+), 8 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 64e00277b21..f39a8cd4b12 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -322,7 +322,7 @@ static HRESULT update_external_prop(jsdisp_t *obj, const WCHAR *name, dispex_pro
static HRESULT find_external_prop(jsdisp_t *This, const WCHAR *name, BOOL case_insens, dispex_prop_t *prop, dispex_prop_t **ret) { - if(This->builtin_info->lookup_prop) { + if(This->has_volatile_props || (!prop && This->builtin_info->lookup_prop)) { struct property_info desc; HRESULT hres;
@@ -461,7 +461,7 @@ static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_ return E_OUTOFMEMORY; }
- if(This->builtin_info->lookup_prop) { + if(This->has_volatile_props) { struct property_info desc; hres = This->builtin_info->lookup_prop(This, name, fdexNameEnsure, &desc); if(hres == S_OK) @@ -3658,6 +3658,8 @@ HRESULT init_host_object(script_ctx_t *ctx, IWineJSDispatchHost *host_iface, IWi host_obj->host_iface = host_iface; if(flags & HOSTOBJ_CONSTRUCTOR) host_obj->jsdisp.is_constructor = TRUE; + if(flags & HOSTOBJ_VOLATILE_PROPS) + host_obj->jsdisp.has_volatile_props = TRUE; *ret = &host_obj->jsdisp.IWineJSDispatch_iface; return S_OK; } diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index b0b65c37c72..f484b059bff 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -199,6 +199,7 @@ struct jsdisp_t {
LONG ref;
+ BOOLEAN has_volatile_props : 1; BOOLEAN is_constructor : 1; BOOLEAN has_weak_refs : 1; BOOLEAN props_filled : 1; diff --git a/dlls/jscript/jsdisp.idl b/dlls/jscript/jsdisp.idl index b0d881509c4..4783edbfef5 100644 --- a/dlls/jscript/jsdisp.idl +++ b/dlls/jscript/jsdisp.idl @@ -41,6 +41,7 @@ const unsigned int PROPF_PUBLIC_MASK = PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF
const unsigned int HOSTOBJ_CONSTRUCTOR = 0x0001; const unsigned int HOSTOBJ_VOLATILE_FILL = 0x0002; +const unsigned int HOSTOBJ_VOLATILE_PROPS = 0x0004;
interface IWineJSDispatchHost;
diff --git a/dlls/mshtml/htmlcurstyle.c b/dlls/mshtml/htmlcurstyle.c index e2f3f2ff9e8..41e02c2bfdd 100644 --- a/dlls/mshtml/htmlcurstyle.c +++ b/dlls/mshtml/htmlcurstyle.c @@ -1201,6 +1201,7 @@ dispex_static_data_t MSCurrentStyleCSSProperties_dispex = { .disp_tid = DispHTMLCurrentStyle_tid, .iface_tids = MSCurrentStyleCSSProperties_iface_tids, .init_info = MSCurrentStyleCSSProperties_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS };
HRESULT HTMLCurrentStyle_Create(HTMLElement *elem, IHTMLCurrentStyle **p) diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 7a9301796ba..13a383fded2 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -5866,7 +5866,7 @@ dispex_static_data_t Document_dispex = { .disp_tid = DispHTMLDocument_tid, .iface_tids = HTMLDocumentNode_iface_tids, .init_info = HTMLDocumentNode_init_dispex_info, - .js_flags = HOSTOBJ_VOLATILE_FILL, + .js_flags = HOSTOBJ_VOLATILE_FILL | HOSTOBJ_VOLATILE_PROPS, };
dispex_static_data_t HTMLDocument_dispex = { @@ -5876,7 +5876,7 @@ dispex_static_data_t HTMLDocument_dispex = { .disp_tid = DispHTMLDocument_tid, .iface_tids = HTMLDocumentNode_iface_tids, .init_info = HTMLDocumentNode_init_dispex_info, - .js_flags = HOSTOBJ_VOLATILE_FILL, + .js_flags = HOSTOBJ_VOLATILE_FILL | HOSTOBJ_VOLATILE_PROPS, .min_compat_mode = COMPAT_MODE_IE11, };
@@ -5887,7 +5887,7 @@ dispex_static_data_t XMLDocument_dispex = { .disp_tid = DispHTMLDocument_tid, .iface_tids = HTMLDocumentNode_iface_tids, .init_info = HTMLDocumentNode_init_dispex_info, - .js_flags = HOSTOBJ_VOLATILE_FILL, + .js_flags = HOSTOBJ_VOLATILE_FILL | HOSTOBJ_VOLATILE_PROPS, .min_compat_mode = COMPAT_MODE_IE11, };
@@ -6027,7 +6027,7 @@ dispex_static_data_t DocumentFragment_dispex = { .disp_tid = DispHTMLDocument_tid, .iface_tids = DocumentFragment_iface_tids, .init_info = DocumentFragment_init_dispex_info, - .js_flags = HOSTOBJ_VOLATILE_FILL, + .js_flags = HOSTOBJ_VOLATILE_FILL | HOSTOBJ_VOLATILE_PROPS, };
static HRESULT create_document_fragment(nsIDOMNode *nsnode, HTMLDocumentNode *doc_node, HTMLDocumentNode **ret) diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 44d4816b9ee..b90fc24d284 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -1000,6 +1000,7 @@ dispex_static_data_t ClientRectList_dispex = { .vtbl = &HTMLRectCollection_dispex_vtbl, .disp_tid = IHTMLRectCollection_tid, .iface_tids = ClientRectList_iface_tids, + .js_flags = HOSTOBJ_VOLATILE_PROPS };
DISPEX_IDISPATCH_IMPL(HTMLElement, IHTMLElement, @@ -7193,6 +7194,7 @@ dispex_static_data_t DOMTokenList_dispex = { .vtbl = &token_list_dispex_vtbl, .disp_tid = IWineDOMTokenList_tid, .iface_tids = DOMTokenList_tids, + .js_flags = HOSTOBJ_VOLATILE_PROPS, .min_compat_mode = COMPAT_MODE_IE10, };
@@ -8322,6 +8324,7 @@ dispex_static_data_t NamedNodeMap_dispex = { .vtbl = &HTMLAttributeCollection_dispex_vtbl, .disp_tid = DispHTMLAttributeCollection_tid, .init_info = NamedNodeMap_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS };
HRESULT HTMLElement_get_attr_col(HTMLDOMNode *iface, HTMLAttributeCollection **ac) diff --git a/dlls/mshtml/htmlelemcol.c b/dlls/mshtml/htmlelemcol.c index 6707970cfe4..7aa27aebd8b 100644 --- a/dlls/mshtml/htmlelemcol.c +++ b/dlls/mshtml/htmlelemcol.c @@ -463,6 +463,7 @@ dispex_static_data_t HTMLCollection_dispex = { .vtbl = &HTMLElementColection_dispex_vtbl, .disp_tid = DispHTMLElementCollection_tid, .iface_tids = HTMLCollection_iface_tids, + .js_flags = HOSTOBJ_VOLATILE_PROPS };
static void create_all_list(HTMLDOMNode *elem, elem_vector_t *buf) diff --git a/dlls/mshtml/htmlform.c b/dlls/mshtml/htmlform.c index b7b06c17794..6ffbd495a97 100644 --- a/dlls/mshtml/htmlform.c +++ b/dlls/mshtml/htmlform.c @@ -866,6 +866,7 @@ dispex_static_data_t HTMLFormElement_dispex = { .vtbl = &HTMLFormElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLFormElement_tid, .init_info = HTMLFormElement_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS };
HRESULT HTMLFormElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) diff --git a/dlls/mshtml/htmlframe.c b/dlls/mshtml/htmlframe.c index d5aab3c7fcf..e2a8b1f96a5 100644 --- a/dlls/mshtml/htmlframe.c +++ b/dlls/mshtml/htmlframe.c @@ -946,6 +946,7 @@ dispex_static_data_t HTMLFrameElement_dispex = { .vtbl = &HTMLFrameElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLFrameElement_tid, .init_info = HTMLFrameElement_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS };
HRESULT HTMLFrameElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) @@ -1399,6 +1400,7 @@ dispex_static_data_t HTMLIFrameElement_dispex = { .disp_tid = DispHTMLIFrame_tid, .iface_tids = HTMLIFrameElement_iface_tids, .init_info = HTMLIFrameElement_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS };
HRESULT HTMLIFrame_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) diff --git a/dlls/mshtml/htmlnode.c b/dlls/mshtml/htmlnode.c index c5a4c8d9b32..022acccf915 100644 --- a/dlls/mshtml/htmlnode.c +++ b/dlls/mshtml/htmlnode.c @@ -244,6 +244,7 @@ dispex_static_data_t NodeList_dispex = { .vtbl = &HTMLDOMChildrenCollection_dispex_vtbl, .disp_tid = DispDOMChildrenCollection_tid, .iface_tids = NodeList_iface_tids, + .js_flags = HOSTOBJ_VOLATILE_PROPS };
HRESULT create_child_collection(nsIDOMNodeList *nslist, DispatchEx *owner, IHTMLDOMChildrenCollection **ret) diff --git a/dlls/mshtml/htmlselect.c b/dlls/mshtml/htmlselect.c index c2a47cecae7..af04cda37c9 100644 --- a/dlls/mshtml/htmlselect.c +++ b/dlls/mshtml/htmlselect.c @@ -1233,6 +1233,7 @@ dispex_static_data_t HTMLSelectElement_dispex = { .vtbl = &HTMLSelectElement_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLSelectElement_tid, .init_info = HTMLSelectElement_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS };
HRESULT HTMLSelectElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) diff --git a/dlls/mshtml/htmlstorage.c b/dlls/mshtml/htmlstorage.c index 4b4e9341d3a..1df7528c747 100644 --- a/dlls/mshtml/htmlstorage.c +++ b/dlls/mshtml/htmlstorage.c @@ -1298,7 +1298,7 @@ dispex_static_data_t Storage_dispex = { .vtbl = &Storage_dispex_vtbl, .disp_tid = IHTMLStorage_tid, .iface_tids = HTMLStorage_iface_tids, - .js_flags = HOSTOBJ_VOLATILE_FILL, + .js_flags = HOSTOBJ_VOLATILE_FILL | HOSTOBJ_VOLATILE_PROPS, };
static HRESULT build_session_origin(IUri *uri, BSTR hostname, BSTR *ret) diff --git a/dlls/mshtml/htmlstyle.c b/dlls/mshtml/htmlstyle.c index 3fa8954dbb6..b54f0926e0c 100644 --- a/dlls/mshtml/htmlstyle.c +++ b/dlls/mshtml/htmlstyle.c @@ -9783,6 +9783,7 @@ dispex_static_data_t MSStyleCSSProperties_dispex = { .disp_tid = DispHTMLStyle_tid, .iface_tids = MSStyleCSSProperties_iface_tids, .init_info = MSStyleCSSProperties_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS };
static HRESULT get_style_from_elem(HTMLElement *elem, nsIDOMCSSStyleDeclaration **ret) @@ -9927,6 +9928,7 @@ dispex_static_data_t CSSStyleDeclaration_dispex = { .vtbl = &CSSStyleDeclaration_dispex_vtbl, .disp_tid = DispHTMLW3CComputedStyle_tid, .init_info = CSSStyleDeclaration_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS };
HRESULT create_computed_style(nsIDOMCSSStyleDeclaration *nsstyle, DispatchEx *owner, IHTMLCSSStyleDeclaration **p) diff --git a/dlls/mshtml/htmlstylesheet.c b/dlls/mshtml/htmlstylesheet.c index e4be2be7e25..b5ce4a3f4e7 100644 --- a/dlls/mshtml/htmlstylesheet.c +++ b/dlls/mshtml/htmlstylesheet.c @@ -368,6 +368,7 @@ dispex_static_data_t MSCSSRuleList_dispex = { .vtbl = &MSCSSRuleList_dispex_vtbl, .disp_tid = DispHTMLStyleSheetRulesCollection_tid, .iface_tids = MSCSSRuleList_iface_tids, + .js_flags = HOSTOBJ_VOLATILE_PROPS };
static HRESULT create_style_sheet_rules_collection(nsIDOMCSSRuleList *nslist, DispatchEx *owner, @@ -603,6 +604,7 @@ dispex_static_data_t StyleSheetList_dispex = { .vtbl = &StyleSheetList_dispex_vtbl, .disp_tid = DispHTMLStyleSheetsCollection_tid, .iface_tids = StyleSheetList_iface_tids, + .js_flags = HOSTOBJ_VOLATILE_PROPS };
HRESULT create_style_sheet_collection(nsIDOMStyleSheetList *nslist, HTMLDocumentNode *doc, diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 716b60b56c0..1977c6137ba 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -4318,7 +4318,7 @@ dispex_static_data_t Window_dispex = { .vtbl = &HTMLWindow_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLWindow2_tid, .init_info = HTMLWindow_init_dispex_info, - .js_flags = HOSTOBJ_VOLATILE_FILL, + .js_flags = HOSTOBJ_VOLATILE_FILL | HOSTOBJ_VOLATILE_PROPS, };
static nsresult NSAPI outer_window_traverse(void *ccp, void *p, nsCycleCollectionTraversalCallback *cb) diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 5ae6624abdf..1c5f5dd4d25 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -3953,6 +3953,65 @@ sync_test("form", function() { ok(form[0] === "test", "form[0] = " + form[0]); });
+sync_test("indexed hostobj props", function() { + var v = document.documentMode; + if(v < 9) + return; + function getter() { return 42; } + + function check(obj, value) { + var name = Object.prototype.toString.call(obj).slice(8, -1); + if(value === undefined) + ok(typeof(obj[0]) === "object", name + "[0] = " + obj[0]); + else + ok(obj[0] === value, name + "[0] post-del = " + obj[0]); + + Object.defineProperty(obj, "0", { get: getter, set: undefined, configurable: true, enumerable: false }); + var desc = Object.getOwnPropertyDescriptor(obj, "0"); + ok(desc.value === undefined, name + "[0] value = " + desc.value); + ok(desc.get === getter, name + "[0] get = " + desc.get); + ok(desc.set === undefined, name + "[0] set = " + desc.set); + ok(desc.writable === undefined, name + "[0] writable = " + desc.writable); + ok(desc.enumerable === false, name + "[0] enumerable = " + desc.enumerable); + ok(desc.configurable === true, name + "[0] configurable = " + desc.configurable); + + ok(obj[0] === 42, name + "[0] = " + obj[0]); + delete obj["0"]; + + desc = Object.getOwnPropertyDescriptor(obj, "0"); + if(value === undefined) + ok(typeof(desc.value) === "object", name + "[0] value post-del = " + desc.value); + else + ok(desc.value === value, name + "[0] value post-del = " + desc.value); + ok(desc.get === undefined, name + "[0] get post-del = " + desc.get); + ok(desc.set === undefined, name + "[0] set post-del = " + desc.set); + ok(desc.writable === true, name + "[0] writable post-del = " + desc.writable); + todo_wine. + ok(desc.enumerable === true, name + "[0] enumerable post-del = " + desc.enumerable); + ok(desc.configurable === true, name + "[0] configurable post-del = " + desc.configurable); + if(value === undefined) + ok(typeof(obj[0]) === "object", name + "[0] post-del = " + obj[0]); + else + ok(obj[0] === value, name + "[0] post-del = " + obj[0]); + ok(obj.hasOwnProperty("0"), "0 not a prop of " + name); + } + + document.body.innerHTML = "<style>div { margin-left: 1px; }</style>"; + var e = document.createElement("select"); + e.innerHTML = '<option value="wine"/>' + e.setAttribute("class", "wine"); + + check(document.all); + check(document.childNodes); + check(document.styleSheets); + check(document.styleSheets[0].rules); + check(document.body.getClientRects()); + check(e); + check(e.attributes); + if(v > 9) + check(e.classList, "wine"); +}); + function test_own_props(obj, name, props, todos, flaky) { var v = document.documentMode, prop, expected = {}, enumerated = Object.getOwnPropertyNames(obj).sort();
Jacek Caban (@jacek) commented about dlls/mshtml/htmlcurstyle.c:
.disp_tid = DispHTMLCurrentStyle_tid, .iface_tids = MSCurrentStyleCSSProperties_iface_tids, .init_info = MSCurrentStyleCSSProperties_init_dispex_info,
- .js_flags = HOSTOBJ_VOLATILE_PROPS
Could we just set the flag based on the presence of `get_dispid`/`find_dispid` in `init_host_object` instead of specifying it separately? That’s fine if we have use cases that need a different condition, but for this patch it doesn’t seem necessary.
On Wed Nov 19 18:48:57 2025 +0000, Jacek Caban wrote:
Could we just set the flag based on the presence of `get_dispid`/`find_dispid` in `init_host_object` instead of specifying it separately? That’s fine if we have use cases that need a different condition, but for this patch it doesn’t seem necessary.
I had a deeper look, there's a couple issues if we go that route:
1. `find_dispid` would be overzealous and also apply it to prototypes and stub constructors (in dispex.c), while they don't have volatile props. Relying only on `get_dispid` isn't perfect either, since then Window won't be marked as having volatile props. I guess we could use a flag on top of just checking for `get_dispid` but...
2. Object elements (and plugin containers) aren't volatile since they cache the props now, but would be marked as such.
So what should I do?
On Thu Nov 20 16:34:22 2025 +0000, Gabriel Ivăncescu wrote:
I had a deeper look, there's a couple issues if we go that route:
- `find_dispid` would be overzealous and also apply it to prototypes
and stub constructors (in dispex.c), while they don't have volatile props. Relying only on `get_dispid` isn't perfect either, since then Window won't be marked as having volatile props. I guess we could use a flag on top of just checking for `get_dispid` but... 2. Object elements (and plugin containers) aren't volatile since they cache the props now, but would be marked as such. So what should I do?
That's fine then, thanks.
This merge request was approved by Jacek Caban.