-- v4: jscript: Properly set JS_E_WRONG_THIS as a TypeError. mshtml/tests: Add tests for WeakMap. jscript: Implement WeakMap.has(). jscript: Implement WeakMap.clear(). jscript: Implement WeakMap.delete(). jscript: Implement WeakMap.get(). jscript: Implement WeakMap.set(). jscript: Implement WeakMap instance stub and constructor. jscript: Convert unlink_props to a helper that unlinks the entire object.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
It will be useful for other cases, and we don't need the gc_ctx for unlinking. Also set the PROP_PROTREFs to PROP_DELETED since we're unliking the prototype.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index b5fc3699212..9e87c38004f 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -665,14 +665,13 @@ static HRESULT fill_protrefs(jsdisp_t *This) return S_OK; }
-static void unlink_props(jsdisp_t *jsdisp) +static void unlink_jsdisp(jsdisp_t *jsdisp) { dispex_prop_t *prop = jsdisp->props, *end;
for(end = prop + jsdisp->prop_cnt; prop < end; prop++) { switch(prop->type) { case PROP_DELETED: - case PROP_PROTREF: continue; case PROP_JSVAL: jsval_release(prop->u.val); @@ -688,6 +687,14 @@ static void unlink_props(jsdisp_t *jsdisp) } prop->type = PROP_DELETED; } + + if(jsdisp->prototype) { + jsdisp_release(jsdisp->prototype); + jsdisp->prototype = NULL; + } + + if(jsdisp->builtin_info->gc_traverse) + jsdisp->builtin_info->gc_traverse(NULL, GC_TRAVERSE_UNLINK, jsdisp); }
@@ -927,15 +934,7 @@ HRESULT gc_run(script_ctx_t *ctx)
/* Grab it since it gets removed when unlinked */ jsdisp_addref(obj); - unlink_props(obj); - - if(obj->prototype) { - jsdisp_release(obj->prototype); - obj->prototype = NULL; - } - - if(obj->builtin_info->gc_traverse) - obj->builtin_info->gc_traverse(&gc_ctx, GC_TRAVERSE_UNLINK, obj); + unlink_jsdisp(obj);
/* Releasing unlinked object should not delete any other object, so we can safely obtain the next pointer now */
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/jscript.h | 6 +- dlls/jscript/object.c | 1 + dlls/jscript/set.c | 134 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 46644b8247b..d907da3a36c 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -117,6 +117,7 @@ typedef enum { JSCLASS_JSON, JSCLASS_MAP, JSCLASS_SET, + JSCLASS_WEAKMAP, } jsclass_t;
jsdisp_t *iface_to_jsdisp(IDispatch*); @@ -418,11 +419,12 @@ struct _script_ctx_t { jsdisp_t *vbarray_constr; jsdisp_t *map_prototype; jsdisp_t *set_prototype; + jsdisp_t *weakmap_prototype; }; - jsdisp_t *global_objects[22]; + jsdisp_t *global_objects[23]; }; }; -C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, set_prototype) == RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, global_objects)); +C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, weakmap_prototype) == RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, global_objects));
void script_release(script_ctx_t*);
diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index 4f6acacbc95..65b25cab239 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -51,6 +51,7 @@ static HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns L"[object Object]", L"[object Object]", L"[object Object]", + L"[object Object]", L"[object Object]" };
diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index eca26a890f7..2afb763f4d7 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -614,6 +614,125 @@ static HRESULT Set_constructor(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns } }
+typedef struct { + jsdisp_t dispex; +} WeakMapInstance; + +static HRESULT WeakMap_clear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WeakMap_delete(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WeakMap_get(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WeakMap_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WeakMap_has(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WeakMap_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static void WeakMap_destructor(jsdisp_t *dispex) +{ + WeakMapInstance *weakmap = (WeakMapInstance*)dispex; + + free(weakmap); +} + +static HRESULT WeakMap_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex) +{ + return S_OK; +} + +static const builtin_prop_t WeakMap_prototype_props[] = { + {L"clear", WeakMap_clear, PROPF_METHOD}, + {L"delete", WeakMap_delete, PROPF_METHOD|1}, + {L"get", WeakMap_get, PROPF_METHOD|1}, + {L"has", WeakMap_has, PROPF_METHOD|1}, + {L"set", WeakMap_set, PROPF_METHOD|2}, +}; + +static const builtin_info_t WeakMap_prototype_info = { + JSCLASS_OBJECT, + WeakMap_value, + ARRAY_SIZE(WeakMap_prototype_props), + WeakMap_prototype_props, + NULL, + NULL +}; + +static const builtin_info_t WeakMap_info = { + JSCLASS_WEAKMAP, + WeakMap_value, + 0, + NULL, + WeakMap_destructor, + NULL, + NULL, + NULL, + NULL, + WeakMap_gc_traverse +}; + +static HRESULT WeakMap_constructor(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + WeakMapInstance *weakmap; + HRESULT hres; + + switch(flags) { + case DISPATCH_CONSTRUCT: + TRACE("\n"); + + if(!r) + return S_OK; + if(!(weakmap = calloc(1, sizeof(*weakmap)))) + return E_OUTOFMEMORY; + + hres = init_dispex(&weakmap->dispex, ctx, &WeakMap_info, ctx->weakmap_prototype); + if(FAILED(hres)) + return hres; + + *r = jsval_obj(&weakmap->dispex); + return S_OK; + + case DISPATCH_METHOD: + return throw_error(ctx, JS_E_WRONG_THIS, L"WeakMap"); + + default: + FIXME("unimplemented flags %x\n", flags); + return E_NOTIMPL; + } +} + HRESULT init_set_constructor(script_ctx_t *ctx) { jsdisp_t *constructor; @@ -649,5 +768,20 @@ HRESULT init_set_constructor(script_ctx_t *ctx) hres = jsdisp_define_data_property(ctx->global, L"Map", PROPF_WRITABLE, jsval_obj(constructor)); jsdisp_release(constructor); + if(FAILED(hres)) + return hres; + + hres = create_dispex(ctx, &WeakMap_prototype_info, ctx->object_prototype, &ctx->weakmap_prototype); + if(FAILED(hres)) + return hres; + + hres = create_builtin_constructor(ctx, WeakMap_constructor, L"WeakMap", NULL, + PROPF_CONSTR, ctx->weakmap_prototype, &constructor); + if(FAILED(hres)) + return hres; + + hres = jsdisp_define_data_property(ctx->global, L"WeakMap", PROPF_WRITABLE, + jsval_obj(constructor)); + jsdisp_release(constructor); return hres; }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 25 ++++++++ dlls/jscript/error.c | 1 + dlls/jscript/jscript.c | 8 +++ dlls/jscript/jscript.h | 18 ++++++ dlls/jscript/jscript.rc | 1 + dlls/jscript/resource.h | 1 + dlls/jscript/set.c | 135 +++++++++++++++++++++++++++++++++++++++- 7 files changed, 187 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 9e87c38004f..2da2270fb0f 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -896,6 +896,24 @@ HRESULT gc_run(script_ctx_t *ctx) break; }
+ /* For weak refs, traverse paths accessible from it via the WeakMaps, if the WeakMaps are alive at this point. + We need both the key and the WeakMap for the entry to actually be accessible (and thus traversed). */ + if(obj2->has_weak_refs) { + struct list *list = &RB_ENTRY_VALUE(rb_get(&ctx->weak_refs, obj2), struct weak_refs_entry, entry)->list; + struct weakmap_entry *entry; + + LIST_FOR_EACH_ENTRY(entry, list, struct weakmap_entry, weak_refs_entry) { + if(!entry->weakmap->gc_marked && is_object_instance(entry->value) && (link = to_jsdisp(get_object(entry->value)))) { + hres = gc_stack_push(&gc_ctx, link); + if(FAILED(hres)) + break; + } + } + + if(FAILED(hres)) + break; + } + do obj2 = gc_stack_pop(&gc_ctx); while(obj2 && !obj2->gc_marked); } while(obj2);
@@ -2222,6 +2240,13 @@ void jsdisp_free(jsdisp_t *obj)
TRACE("(%p)\n", obj);
+ if(obj->has_weak_refs) { + struct list *list = &RB_ENTRY_VALUE(rb_get(&obj->ctx->weak_refs, obj), struct weak_refs_entry, entry)->list; + do { + remove_weakmap_entry(LIST_ENTRY(list->next, struct weakmap_entry, weak_refs_entry)); + } while(obj->has_weak_refs); + } + for(prop = obj->props; prop < obj->props+obj->prop_cnt; prop++) { switch(prop->type) { case PROP_JSVAL: diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index c3768668178..cf0ece42f15 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -483,6 +483,7 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_OBJECT_NONEXTENSIBLE: case JS_E_NONCONFIGURABLE_REDEFINED: case JS_E_NONWRITABLE_MODIFIED: + case JS_E_KEY_NOT_OBJECT: case JS_E_PROP_DESC_MISMATCH: case JS_E_INVALID_WRITABLE_PROP_DESC: constr = ctx->type_error_constr; diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index 401f6ca85b0..b1940b770d3 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -715,6 +715,13 @@ static ULONG WINAPI JScript_Release(IActiveScript *iface) return ref; }
+static int weak_refs_compare(const void *key, const struct rb_entry *entry) +{ + const struct weak_refs_entry *weak_refs_entry = RB_ENTRY_VALUE(entry, const struct weak_refs_entry, entry); + ULONG_PTR a = (ULONG_PTR)key, b = (ULONG_PTR)LIST_ENTRY(weak_refs_entry->list.next, struct weakmap_entry, weak_refs_entry)->key; + return (a > b) - (a < b); +} + static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass) { @@ -748,6 +755,7 @@ static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface, ctx->acc = jsval_undefined(); list_init(&ctx->named_items); list_init(&ctx->objects); + rb_init(&ctx->weak_refs, weak_refs_compare); heap_pool_init(&ctx->tmp_heap);
hres = create_jscaller(ctx); diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index d907da3a36c..650c9278793 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -32,6 +32,7 @@ #include "resource.h"
#include "wine/list.h" +#include "wine/rbtree.h"
/* * This is Wine jscript extension for ES5 compatible mode. Native IE9+ implements @@ -179,6 +180,7 @@ struct jsdisp_t {
LONG ref;
+ BOOLEAN has_weak_refs; BOOLEAN extensible; BOOLEAN gc_marked;
@@ -362,6 +364,11 @@ typedef struct { unsigned length; } match_result_t;
+struct weak_refs_entry { + struct rb_entry entry; + struct list list; +}; + struct _script_ctx_t { LONG ref;
@@ -371,6 +378,7 @@ struct _script_ctx_t { struct _call_frame_t *call_ctx; struct list named_items; struct list objects; + struct rb_tree weak_refs; IActiveScriptSite *site; IInternetHostSecurityManager *secmgr; DWORD safeopt; @@ -426,6 +434,15 @@ struct _script_ctx_t { }; C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, weakmap_prototype) == RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, global_objects));
+struct weakmap_entry { + struct rb_entry entry; + jsdisp_t *key; + jsval_t value; + jsdisp_t *weakmap; + struct list weak_refs_entry; +}; +void remove_weakmap_entry(struct weakmap_entry*); + void script_release(script_ctx_t*);
static inline void script_addref(script_ctx_t *ctx) @@ -550,6 +567,7 @@ static inline HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, jsval_ #define JS_E_NONCONFIGURABLE_REDEFINED MAKE_JSERROR(IDS_NONCONFIGURABLE_REDEFINED) #define JS_E_NONWRITABLE_MODIFIED MAKE_JSERROR(IDS_NONWRITABLE_MODIFIED) #define JS_E_WRONG_THIS MAKE_JSERROR(IDS_WRONG_THIS) +#define JS_E_KEY_NOT_OBJECT MAKE_JSERROR(IDS_KEY_NOT_OBJECT) #define JS_E_PROP_DESC_MISMATCH MAKE_JSERROR(IDS_PROP_DESC_MISMATCH) #define JS_E_INVALID_WRITABLE_PROP_DESC MAKE_JSERROR(IDS_INVALID_WRITABLE_PROP_DESC)
diff --git a/dlls/jscript/jscript.rc b/dlls/jscript/jscript.rc index fbf965fb7e8..e5289a550a3 100644 --- a/dlls/jscript/jscript.rc +++ b/dlls/jscript/jscript.rc @@ -77,6 +77,7 @@ STRINGTABLE IDS_NONCONFIGURABLE_REDEFINED "Cannot redefine non-configurable property '|'" IDS_NONWRITABLE_MODIFIED "Cannot modify non-writable property '|'" IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value"
IDS_COMPILATION_ERROR "Microsoft JScript compilation error" diff --git a/dlls/jscript/resource.h b/dlls/jscript/resource.h index 0ac457d740d..ad771b67475 100644 --- a/dlls/jscript/resource.h +++ b/dlls/jscript/resource.h @@ -75,6 +75,7 @@ #define IDS_NONCONFIGURABLE_REDEFINED 0x13D6 #define IDS_NONWRITABLE_MODIFIED 0x13D7 #define IDS_WRONG_THIS 0x13FC +#define IDS_KEY_NOT_OBJECT 0x13FD /* FIXME: This is not compatible with native, but we would * conflict with IDS_UNSUPPORTED_ACTION otherwise */ #define IDS_PROP_DESC_MISMATCH 0x1F00 diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index 2afb763f4d7..8be959a027d 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -616,8 +616,55 @@ static HRESULT Set_constructor(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns
typedef struct { jsdisp_t dispex; + struct rb_tree map; } WeakMapInstance;
+static int weakmap_compare(const void *k, const struct rb_entry *e) +{ + ULONG_PTR a = (ULONG_PTR)k, b = (ULONG_PTR)RB_ENTRY_VALUE(e, const struct weakmap_entry, entry)->key; + return (a > b) - (a < b); +} + +static HRESULT get_weakmap_this(script_ctx_t *ctx, jsval_t vthis, WeakMapInstance **ret) +{ + jsdisp_t *jsdisp; + + if(!is_object_instance(vthis)) + return JS_E_OBJECT_EXPECTED; + if(!(jsdisp = to_jsdisp(get_object(vthis))) || !is_class(jsdisp, JSCLASS_WEAKMAP)) { + WARN("not a WeakMap object passed as 'this'\n"); + return throw_error(ctx, JS_E_WRONG_THIS, L"WeakMap"); + } + + *ret = CONTAINING_RECORD(jsdisp, WeakMapInstance, dispex); + return S_OK; +} + +static struct weakmap_entry *get_weakmap_entry(WeakMapInstance *weakmap, jsdisp_t *key) +{ + struct rb_entry *entry; + if(!(entry = rb_get(&weakmap->map, key))) return NULL; + return CONTAINING_RECORD(entry, struct weakmap_entry, entry); +} + +void remove_weakmap_entry(struct weakmap_entry *entry) +{ + WeakMapInstance *weakmap = (WeakMapInstance*)entry->weakmap; + struct list *next = entry->weak_refs_entry.next; + + if(next->next != &entry->weak_refs_entry) + list_remove(&entry->weak_refs_entry); + else { + struct weak_refs_entry *weak_refs_entry = LIST_ENTRY(next, struct weak_refs_entry, list); + entry->key->has_weak_refs = FALSE; + rb_remove(&entry->key->ctx->weak_refs, &weak_refs_entry->entry); + free(weak_refs_entry); + } + rb_remove(&weakmap->map, &entry->entry); + jsval_release(entry->value); + free(entry); +} + static HRESULT WeakMap_clear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { @@ -642,8 +689,67 @@ static HRESULT WeakMap_get(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigne static HRESULT WeakMap_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - FIXME("\n"); - return E_NOTIMPL; + jsdisp_t *key = (argc >= 1 && is_object_instance(argv[0])) ? to_jsdisp(get_object(argv[0])) : NULL; + jsval_t value = argc >= 2 ? argv[1] : jsval_undefined(); + struct weakmap_entry *entry; + WeakMapInstance *weakmap; + HRESULT hres; + + hres = get_weakmap_this(ctx, vthis, &weakmap); + if(FAILED(hres)) + return hres; + + TRACE("%p (%p %s)\n", weakmap, key, debugstr_jsval(value)); + + if(!key) + return JS_E_KEY_NOT_OBJECT; + + if(key->ctx != ctx) { + FIXME("different ctx not supported\n"); + return JS_E_KEY_NOT_OBJECT; + } + + if((entry = get_weakmap_entry(weakmap, key))) { + jsval_t val; + hres = jsval_copy(value, &val); + if(FAILED(hres)) + return hres; + + jsval_release(entry->value); + entry->value = val; + }else { + struct weak_refs_entry *weak_refs_entry; + + if(!(entry = malloc(sizeof(*entry)))) + return E_OUTOFMEMORY; + + hres = jsval_copy(value, &entry->value); + if(FAILED(hres)) { + free(entry); + return hres; + } + + if(key->has_weak_refs) + weak_refs_entry = RB_ENTRY_VALUE(rb_get(&ctx->weak_refs, key), struct weak_refs_entry, entry); + else { + if(!(weak_refs_entry = malloc(sizeof(*weak_refs_entry)))) { + jsval_release(entry->value); + free(entry); + return E_OUTOFMEMORY; + } + rb_put(&ctx->weak_refs, key, &weak_refs_entry->entry); + list_init(&weak_refs_entry->list); + key->has_weak_refs = TRUE; + } + list_add_tail(&weak_refs_entry->list, &entry->weak_refs_entry); + + entry->key = key; + entry->weakmap = &weakmap->dispex; + rb_put(&weakmap->map, key, &entry->entry); + } + + if(r) *r = jsval_undefined(); + return S_OK; }
static HRESULT WeakMap_has(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, @@ -664,11 +770,35 @@ static void WeakMap_destructor(jsdisp_t *dispex) { WeakMapInstance *weakmap = (WeakMapInstance*)dispex;
+ while(weakmap->map.root) + remove_weakmap_entry(RB_ENTRY_VALUE(weakmap->map.root, struct weakmap_entry, entry)); + free(weakmap); }
static HRESULT WeakMap_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex) { + WeakMapInstance *weakmap = (WeakMapInstance*)dispex; + struct weakmap_entry *entry; + HRESULT hres; + + if(op == GC_TRAVERSE_UNLINK) { + while(weakmap->map.root) + remove_weakmap_entry(RB_ENTRY_VALUE(weakmap->map.root, struct weakmap_entry, entry)); + return S_OK; + } + + RB_FOR_EACH_ENTRY(entry, &weakmap->map, struct weakmap_entry, entry) { + /* Only traverse the values if the key turned out to be alive, which means it might not have traversed + the associated values with it from this WeakMap yet (because it wasn't considered alive back then). + We need both the key and the WeakMap for the entry to actually be accessible (and thus traversed). */ + if(op == GC_TRAVERSE && entry->key->gc_marked) + continue; + + hres = gc_process_linked_val(gc_ctx, op, dispex, &entry->value); + if(FAILED(hres)) + return hres; + } return S_OK; }
@@ -721,6 +851,7 @@ static HRESULT WeakMap_constructor(script_ctx_t *ctx, jsval_t vthis, WORD flags, if(FAILED(hres)) return hres;
+ rb_init(&weakmap->map, weakmap_compare); *r = jsval_obj(&weakmap->dispex); return S_OK;
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/set.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index 8be959a027d..c4d8cf0cd14 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -682,8 +682,23 @@ static HRESULT WeakMap_delete(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi static HRESULT WeakMap_get(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - FIXME("\n"); - return E_NOTIMPL; + jsdisp_t *key = (argc >= 1 && is_object_instance(argv[0])) ? to_jsdisp(get_object(argv[0])) : NULL; + struct weakmap_entry *entry; + WeakMapInstance *weakmap; + HRESULT hres; + + hres = get_weakmap_this(ctx, vthis, &weakmap); + if(FAILED(hres)) + return hres; + + TRACE("%p (%p)\n", weakmap, key); + + if(!(entry = get_weakmap_entry(weakmap, key))) { + if(r) *r = jsval_undefined(); + return S_OK; + } + + return r ? jsval_copy(entry->value, r) : S_OK; }
static HRESULT WeakMap_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/set.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index c4d8cf0cd14..c12c93a90b9 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -675,8 +675,21 @@ static HRESULT WeakMap_clear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsig static HRESULT WeakMap_delete(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - FIXME("\n"); - return E_NOTIMPL; + jsdisp_t *key = (argc >= 1 && is_object_instance(argv[0])) ? to_jsdisp(get_object(argv[0])) : NULL; + struct weakmap_entry *entry; + WeakMapInstance *weakmap; + HRESULT hres; + + hres = get_weakmap_this(ctx, vthis, &weakmap); + if(FAILED(hres)) + return hres; + + TRACE("%p (%p)\n", weakmap, key); + + if((entry = get_weakmap_entry(weakmap, key))) + remove_weakmap_entry(entry); + if(r) *r = jsval_bool(!!entry); + return S_OK; }
static HRESULT WeakMap_get(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/set.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index c12c93a90b9..46b73bd42b5 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -668,8 +668,20 @@ void remove_weakmap_entry(struct weakmap_entry *entry) static HRESULT WeakMap_clear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - FIXME("\n"); - return E_NOTIMPL; + WeakMapInstance *weakmap; + HRESULT hres; + + hres = get_weakmap_this(ctx, vthis, &weakmap); + if(FAILED(hres)) + return hres; + + TRACE("%p\n", weakmap); + + while(weakmap->map.root) + remove_weakmap_entry(RB_ENTRY_VALUE(weakmap->map.root, struct weakmap_entry, entry)); + + if(r) *r = jsval_undefined(); + return S_OK; }
static HRESULT WeakMap_delete(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/set.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index 46b73bd42b5..a5d3eeb7e4a 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -795,8 +795,18 @@ static HRESULT WeakMap_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigne static HRESULT WeakMap_has(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - FIXME("\n"); - return E_NOTIMPL; + jsdisp_t *key = (argc >= 1 && is_object_instance(argv[0])) ? to_jsdisp(get_object(argv[0])) : NULL; + WeakMapInstance *weakmap; + HRESULT hres; + + hres = get_weakmap_this(ctx, vthis, &weakmap); + if(FAILED(hres)) + return hres; + + TRACE("%p (%p)\n", weakmap, key); + + if(r) *r = jsval_bool(!!get_weakmap_entry(weakmap, key)); + return S_OK; }
static HRESULT WeakMap_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/tests/documentmode.js | 130 ++++++++++++++++++ dlls/mshtml/tests/script.c | 210 ++++++++++++++++++++++++++++++ 2 files changed, 340 insertions(+)
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 3533d721960..00a6eded3fe 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -470,6 +470,8 @@ sync_test("window_props", function() { test_exposed("requestAnimationFrame", v >= 10); test_exposed("Map", v >= 11); test_exposed("Set", v >= 11); + test_exposed("WeakMap", v >= 11); + test_exposed("WeakSet", false); test_exposed("performance", true); test_exposed("console", v >= 10); test_exposed("matchMedia", v >= 10); @@ -1608,6 +1610,134 @@ sync_test("map_obj", function() { ok(r === 1, "r = " + r); });
+async_test("weakmap_obj", function() { + if(!("WeakMap" in window)) { next_test(); return; } + + try { + var s = WeakMap(); + ok(false, "expected exception calling constructor as method"); + }catch(e) { + ok(e.number === 0xa13fc - 0x80000000, "calling constructor as method threw " + e.number); + } + + var s = new WeakMap, r, o, o2; + ok(Object.getPrototypeOf(s) === WeakMap.prototype, "unexpected WeakMap prototype"); + + function test_length(name, len) { + ok(WeakMap.prototype[name].length === len, "WeakMap.prototype." + name + " = " + WeakMap.prototype[name].length); + } + test_length("clear", 0); + test_length("delete", 1); + test_length("get", 1); + test_length("has", 1); + test_length("set", 2); + ok(!("entries" in s), "entries is in WeakMap"); + ok(!("forEach" in s), "forEach is in WeakMap"); + ok(!("keys" in s), "keys is in WeakMap"); + ok(!("size" in s), "size is in WeakMap"); + ok(!("values" in s), "values is in WeakMap"); + + r = Object.prototype.toString.call(s); + ok(r === "[object Object]", "toString returned " + r); + + r = s.get("test"); + ok(r === undefined, "get('test') returned " + r); + r = s.has("test"); + ok(r === false, "has('test') returned " + r); + + try { + r = s.set("test", 1); + ok(false, "set('test') did not throw"); + }catch(e) { + ok(e.number === 0xa13fd - 0x80000000, "set('test') threw " + e.number); + } + try { + r = s.set(external.testHostContext(true), 1); + ok(false, "set(host_obj) did not throw"); + }catch(e) { + ok(e.number === 0xa13fd - 0x80000000, "set(host_obj) threw " + e.number); + } + + r = s.set({}, 1); + ok(r === undefined, "set({}, 1) returned " + r); + + o = {}, o2 = {}; + r = s.get({}); + ok(r === undefined, "get({}) returned " + r); + r = s.has({}); + ok(r === false, "has({}) returned " + r); + + r = s.set(o, 2); + ok(r === undefined, "set(o, 2) returned " + r); + r = s.get(o); + ok(r === 2, "get(o) returned " + r); + r = s.has(o); + ok(r === true, "has(o) returned " + r); + r = s.get(o2); + ok(r === undefined, "get(o2) before set returned " + r); + r = s.has(o2); + ok(r === false, "has(o2) before set returned " + r); + r = s.set(o2, "test"); + ok(r === undefined, "set(o2, 'test') returned " + r); + r = s.get(o2); + ok(r === "test", "get(o2) returned " + r); + r = s.has(o2); + ok(r === true, "has(o2) returned " + r); + + r = s["delete"]("test"); /* using s.delete() would break parsing in quirks mode */ + ok(r === false, "delete('test') returned " + r); + r = s["delete"]({}); + ok(r === false, "delete({}) returned " + r); + r = s["delete"](o); + ok(r === true, "delete(o) returned " + r); + + r = s.get(o); + ok(r === undefined, "get(o) after delete returned " + r); + r = s.has(o); + ok(r === false, "has(o) after delete returned " + r); + r = s.get(o2); + ok(r === "test", "get(o2) after delete returned " + r); + r = s.has(o2); + ok(r === true, "has(o2) after delete returned " + r); + + r = s.set(o, undefined); + ok(r === undefined, "set(o, undefined) returned " + r); + r = s.get(o); + ok(r === undefined, "get(o) after re-set returned " + r); + r = s.has(o); + ok(r === true, "has(o) after re-set returned " + r); + + r = s.clear(); + ok(r === undefined, "clear() returned " + r); + r = s.get(o); + ok(r === undefined, "get(o) after clear returned " + r); + r = s.has(o); + ok(r === false, "has(o) after clear returned " + r); + r = s.get(o2); + ok(r === undefined, "get(o2) after clear returned " + r); + r = s.has(o2); + ok(r === false, "has(o2) after clear returned " + r); + + r = external.newRefTest(); + ok(r.ref === 1, "wrong ref after newRefTest: " + r.ref); + o = { val: r.get(), map: s }; + s.set(o, o); + ok(r.ref > 1, "map entry released"); + + o = Date.now(); + CollectGarbage(); + function retry() { + if(r.ref > 1 && Date.now() - o < 5000) { + CollectGarbage(); + window.setTimeout(retry); + return; + } + ok(r.ref === 1, "map entry not released"); + next_test(); + } + window.setTimeout(retry); +}); + sync_test("storage", function() { var v = document.documentMode, i, r, list;
diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index 2dc68f1456e..60f8b07e88a 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -155,6 +155,8 @@ DEFINE_EXPECT(GetTypeInfo);
#define DISPID_SCRIPT_TESTPROP 0x100000 #define DISPID_SCRIPT_TESTPROP2 0x100001 +#define DISPID_REFTEST_GET 0x100000 +#define DISPID_REFTEST_REF 0x100001
#define DISPID_EXTERNAL_OK 0x300000 #define DISPID_EXTERNAL_TRACE 0x300001 @@ -171,6 +173,7 @@ DEFINE_EXPECT(GetTypeInfo); #define DISPID_EXTERNAL_TESTHOSTCTX 0x30000C #define DISPID_EXTERNAL_GETMIMETYPE 0x30000D #define DISPID_EXTERNAL_SETVIEWSIZE 0x30000E +#define DISPID_EXTERNAL_NEWREFTEST 0x30000F
static const GUID CLSID_TestScript[] = { {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}}, @@ -641,6 +644,13 @@ static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DW return E_NOTIMPL; }
+static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + static HRESULT WINAPI funcDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { @@ -840,6 +850,181 @@ static IDispatchExVtbl testHostContextDisp_no_this_vtbl = {
static IDispatchEx testHostContextDisp_no_this = { &testHostContextDisp_no_this_vtbl };
+struct refTestObj +{ + IDispatchEx IDispatchEx_iface; + LONG ref; +}; + +struct refTest +{ + IDispatchEx IDispatchEx_iface; + LONG ref; + struct refTestObj *obj; +}; + +static inline struct refTestObj *refTestObj_from_IDispatchEx(IDispatchEx *iface) +{ + return CONTAINING_RECORD(iface, struct refTestObj, IDispatchEx_iface); +} + +static inline struct refTest *refTest_from_IDispatchEx(IDispatchEx *iface) +{ + return CONTAINING_RECORD(iface, struct refTest, IDispatchEx_iface); +} + +static HRESULT WINAPI refTestObj_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) +{ + struct refTestObj *This = refTestObj_from_IDispatchEx(iface); + + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, &IID_IDispatchEx)) + *ppv = &This->IDispatchEx_iface; + else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IDispatchEx_AddRef(&This->IDispatchEx_iface); + return S_OK; +} + +static ULONG WINAPI refTestObj_AddRef(IDispatchEx *iface) +{ + struct refTestObj *This = refTestObj_from_IDispatchEx(iface); + + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI refTestObj_Release(IDispatchEx *iface) +{ + struct refTestObj *This = refTestObj_from_IDispatchEx(iface); + LONG ref = InterlockedDecrement(&This->ref); + + if(!ref) + free(This); + + return ref; +} + +static IDispatchExVtbl refTestObj_vtbl = { + refTestObj_QueryInterface, + refTestObj_AddRef, + refTestObj_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + DispatchEx_InvokeEx, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static HRESULT WINAPI refTest_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) +{ + struct refTest *This = refTest_from_IDispatchEx(iface); + + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, &IID_IDispatchEx)) + *ppv = &This->IDispatchEx_iface; + else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IDispatchEx_AddRef(&This->IDispatchEx_iface); + return S_OK; +} + +static ULONG WINAPI refTest_AddRef(IDispatchEx *iface) +{ + struct refTest *This = refTest_from_IDispatchEx(iface); + + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI refTest_Release(IDispatchEx *iface) +{ + struct refTest *This = refTest_from_IDispatchEx(iface); + LONG ref = InterlockedDecrement(&This->ref); + + if(!ref) { + IDispatchEx_Release(&This->obj->IDispatchEx_iface); + free(This); + } + + return ref; +} + +static HRESULT WINAPI refTest_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) +{ + if(!wcscmp(bstrName, L"get")) { + *pid = DISPID_REFTEST_GET; + return S_OK; + } + if(!wcscmp(bstrName, L"ref")) { + *pid = DISPID_REFTEST_REF; + return S_OK; + } + ok(0, "unexpected call %s\n", wine_dbgstr_w(bstrName)); + return E_NOTIMPL; +} + +static HRESULT WINAPI refTest_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + struct refTest *This = refTest_from_IDispatchEx(iface); + + ok(pdp != NULL, "pdp == NULL\n"); + ok(!pdp->cArgs, "pdp->cArgs = %d\n", pdp->cArgs); + ok(pvarRes != NULL, "pvarRes == NULL\n"); + ok(pei != NULL, "pei == NULL\n"); + ok(pspCaller != NULL, "pspCaller == NULL\n"); + + switch(id) { + case DISPID_REFTEST_GET: { + ok(wFlags == DISPATCH_METHOD, "DISPID_REFTEST_GET wFlags = %x\n", wFlags); + V_VT(pvarRes) = VT_DISPATCH; + V_DISPATCH(pvarRes) = (IDispatch*)&This->obj->IDispatchEx_iface; + IDispatchEx_AddRef(&This->obj->IDispatchEx_iface); + break; + } + case DISPID_REFTEST_REF: + ok(wFlags == DISPATCH_PROPERTYGET, "DISPID_REFTEST_REF wFlags = %x\n", wFlags); + V_VT(pvarRes) = VT_I4; + V_I4(pvarRes) = This->obj->ref; + break; + + default: + ok(0, "id = %ld", id); + V_VT(pvarRes) = VT_EMPTY; + break; + } + + return S_OK; +} + +static IDispatchExVtbl refTest_vtbl = { + refTest_QueryInterface, + refTest_AddRef, + refTest_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + refTest_GetDispID, + refTest_InvokeEx, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + static HRESULT WINAPI externalDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) { if(!lstrcmpW(bstrName, L"ok")) { @@ -902,6 +1087,10 @@ static HRESULT WINAPI externalDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, *pid = DISPID_EXTERNAL_SETVIEWSIZE; return S_OK; } + if(!lstrcmpW(bstrName, L"newRefTest")) { + *pid = DISPID_EXTERNAL_NEWREFTEST; + return S_OK; + }
ok(0, "unexpected name %s\n", wine_dbgstr_w(bstrName)); return DISP_E_UNKNOWNNAME; @@ -1180,6 +1369,27 @@ static HRESULT WINAPI externalDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID return IOleDocumentView_SetRect(view, &rect); }
+ case DISPID_EXTERNAL_NEWREFTEST: { + struct refTest *obj = malloc(sizeof(*obj)); + + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->rgvarg != NULL, "rgvarg == NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(!pdp->cArgs, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pei != NULL, "pei == NULL\n"); + + obj->IDispatchEx_iface.lpVtbl = &refTest_vtbl; + obj->ref = 1; + obj->obj = malloc(sizeof(*obj->obj)); + obj->obj->IDispatchEx_iface.lpVtbl = &refTestObj_vtbl; + obj->obj->ref = 1; + + V_VT(pvarRes) = VT_DISPATCH; + V_DISPATCH(pvarRes) = (IDispatch*)&obj->IDispatchEx_iface; + return S_OK; + } + default: ok(0, "unexpected call\n"); return E_NOTIMPL;
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/error.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index cf0ece42f15..f6eda62b88d 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -483,6 +483,7 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_OBJECT_NONEXTENSIBLE: case JS_E_NONCONFIGURABLE_REDEFINED: case JS_E_NONWRITABLE_MODIFIED: + case JS_E_WRONG_THIS: case JS_E_KEY_NOT_OBJECT: case JS_E_PROP_DESC_MISMATCH: case JS_E_INVALID_WRITABLE_PROP_DESC:
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=134973
Your paranoid android.
=== w10pro64 (64 bit report) ===
mshtml: htmldoc.c:351: Test failed: expected Exec_SETTITLE
Jacek Caban (@jacek) commented about dlls/jscript/dispex.c:
break; }
/* For weak refs, traverse paths accessible from it via the WeakMaps, if the WeakMaps are alive at this point.
We need both the key and the WeakMap for the entry to actually be accessible (and thus traversed). */
if(obj2->has_weak_refs) {
struct list *list = &RB_ENTRY_VALUE(rb_get(&ctx->weak_refs, obj2), struct weak_refs_entry, entry)->list;
struct weakmap_entry *entry;
LIST_FOR_EACH_ENTRY(entry, list, struct weakmap_entry, weak_refs_entry) {
if(!entry->weakmap->gc_marked && is_object_instance(entry->value) && (link = to_jsdisp(get_object(entry->value)))) {
Shouldn't we check for true gc_marked here?
gc_marked means it's marked for garbage collection (i.e. dead). We want to pursue this path only if the WeakMap is unmarked (i.e. alive).
On Wed Jul 19 15:11:23 2023 +0000, Gabriel Ivăncescu wrote:
gc_marked means it's marked for garbage collection (i.e. dead). We want to pursue this path only if the WeakMap is unmarked (i.e. alive).
Ah, right.
This merge request was approved by Jacek Caban.
CI build error seems to be false positive, but real.
On Thu Jul 20 11:06:29 2023 +0000, Jacek Caban wrote:
CI build error seems to be false positive, but real.
It looks like a compiler bug to me, if I add some other patches on top (that don't touch this part at all, and without LTO of course), it magically goes away, even if I rebuild `set.c`.
I can initialize it to NULL of course but, should we work around such bugs?
On Thu Jul 20 11:06:29 2023 +0000, Gabriel Ivăncescu wrote:
It looks like a compiler bug to me, if I add some other patches on top (that don't touch this part at all, and without LTO of course), it magically goes away, even if I rebuild `set.c`. I can initialize it to NULL of course but, should we work around such bugs?
Yeah, it is a compiler bug, but changing the code to look like this does not seem like a bad idea: ``` if (!(weakmap = get_weakmap_this(ctx, vthis)) return DISP_E_EXCEPTION; ```
On Thu Jul 20 13:16:32 2023 +0000, Jacek Caban wrote:
Yeah, it is a compiler bug, but changing the code to look like this does not seem like a bad idea:
if (!(weakmap = get_weakmap_this(ctx, vthis)) return DISP_E_EXCEPTION;
That would complicate the case with JS_E_OBJECT_EXPECTED and also it would be different than for Map or Set. :/
Probably better if I just return DISP_E_EXCEPTION from it instead of throw_error's return value, since it's the same anyway.