diff --git a/quickjs.c b/quickjs.c index 3c10351a..a3cd72a2 100644 --- a/quickjs.c +++ b/quickjs.c @@ -446,6 +446,7 @@ struct JSString { uint32_t hash : 30; uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */ uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */ + struct JSMapRecord *first_weak_ref; #ifdef DUMP_LEAKS struct list_head link; /* string list */ #endif @@ -43529,11 +43530,23 @@ static void map_hash_resize(JSContext *ctx, JSMapState *s) s->record_count_threshold = new_hash_size * 2; } +static JSMapRecord **get_first_weak_ref(JSValueConst key) { + JSAtomStruct *p; + switch (JS_VALUE_GET_TAG(key)) { + case JS_TAG_OBJECT: + return &JS_VALUE_GET_OBJ(key)->first_weak_ref; + case JS_TAG_SYMBOL: + p = JS_VALUE_GET_PTR(key); + return &p->first_weak_ref; + } + abort(); +} + static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s, JSValueConst key) { uint32_t h; - JSMapRecord *mr; + JSMapRecord *mr, **first_weak_ref; mr = js_malloc(ctx, sizeof(*mr)); if (!mr) @@ -43542,10 +43555,10 @@ static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s, mr->map = s; mr->empty = FALSE; if (s->is_weak) { - JSObject *p = JS_VALUE_GET_OBJ(key); /* Add the weak reference */ - mr->next_weak_ref = p->first_weak_ref; - p->first_weak_ref = mr; + first_weak_ref = get_first_weak_ref(key); + mr->next_weak_ref = *first_weak_ref; + *first_weak_ref = mr; } else { JS_DupValue(ctx, key); } @@ -43567,10 +43580,8 @@ static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s, static void delete_weak_ref(JSRuntime *rt, JSMapRecord *mr) { JSMapRecord **pmr, *mr1; - JSObject *p; - p = JS_VALUE_GET_OBJ(mr->key); - pmr = &p->first_weak_ref; + pmr = get_first_weak_ref(mr->key); for(;;) { mr1 = *pmr; assert(mr1 != NULL); @@ -43646,12 +43657,25 @@ static JSValue js_map_set(JSContext *ctx, JSValueConst this_val, JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic); JSMapRecord *mr; JSValueConst key, value; + JSAtomStruct *p; if (!s) return JS_EXCEPTION; key = map_normalize_key(ctx, argv[0]); - if (s->is_weak && !JS_IsObject(key)) - return JS_ThrowTypeErrorNotAnObject(ctx); + if (s->is_weak) { + switch (JS_VALUE_GET_TAG(key)) { + case JS_TAG_OBJECT: + break; + case JS_TAG_SYMBOL: + // Per spec: prohibit symbols registered with Symbol.for() + p = JS_VALUE_GET_PTR(key); + if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL) + break; + // fallthru + default: + return JS_ThrowTypeError(ctx, "invalid value used as weak map key"); + } + } if (magic & MAGIC_SET) value = JS_UNDEFINED; else diff --git a/test262_errors.txt b/test262_errors.txt index d67a2d88..0f3491ad 100644 --- a/test262_errors.txt +++ b/test262_errors.txt @@ -336,38 +336,6 @@ test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js:22: strict mode: Test262Error: Reflect.set(sample, "-1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.) test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: strict mode: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/built-ins/WeakMap/iterable-with-symbol-keys.js:32: TypeError: not an object -test262/test/built-ins/WeakMap/iterable-with-symbol-keys.js:32: strict mode: TypeError: not an object -test262/test/built-ins/WeakMap/prototype/delete/delete-entry-with-symbol-key-initial-iterable.js:26: TypeError: not an object -test262/test/built-ins/WeakMap/prototype/delete/delete-entry-with-symbol-key-initial-iterable.js:26: strict mode: TypeError: not an object -test262/test/built-ins/WeakMap/prototype/delete/delete-entry-with-symbol-key.js:24: TypeError: not an object -test262/test/built-ins/WeakMap/prototype/delete/delete-entry-with-symbol-key.js:24: strict mode: TypeError: not an object -test262/test/built-ins/WeakMap/prototype/delete/returns-false-when-symbol-key-not-present.js:18: TypeError: not an object -test262/test/built-ins/WeakMap/prototype/delete/returns-false-when-symbol-key-not-present.js:18: strict mode: TypeError: not an object -test262/test/built-ins/WeakMap/prototype/get/returns-undefined-with-symbol-key.js:28: TypeError: not an object -test262/test/built-ins/WeakMap/prototype/get/returns-undefined-with-symbol-key.js:28: strict mode: TypeError: not an object -test262/test/built-ins/WeakMap/prototype/get/returns-value-with-symbol-key.js:22: TypeError: not an object -test262/test/built-ins/WeakMap/prototype/get/returns-value-with-symbol-key.js:22: strict mode: TypeError: not an object -test262/test/built-ins/WeakMap/prototype/has/returns-false-when-symbol-key-not-present.js:20: TypeError: not an object -test262/test/built-ins/WeakMap/prototype/has/returns-false-when-symbol-key-not-present.js:20: strict mode: TypeError: not an object -test262/test/built-ins/WeakMap/prototype/has/returns-true-when-symbol-key-present.js:19: TypeError: not an object -test262/test/built-ins/WeakMap/prototype/has/returns-true-when-symbol-key-present.js:19: strict mode: TypeError: not an object -test262/test/built-ins/WeakMap/prototype/set/adds-symbol-element.js:17: TypeError: not an object -test262/test/built-ins/WeakMap/prototype/set/adds-symbol-element.js:17: strict mode: TypeError: not an object -test262/test/built-ins/WeakSet/iterable-with-symbol-values.js:24: TypeError: not an object -test262/test/built-ins/WeakSet/iterable-with-symbol-values.js:24: strict mode: TypeError: not an object -test262/test/built-ins/WeakSet/prototype/add/adds-symbol-element.js:17: TypeError: not an object -test262/test/built-ins/WeakSet/prototype/add/adds-symbol-element.js:17: strict mode: TypeError: not an object -test262/test/built-ins/WeakSet/prototype/add/returns-this-symbol.js:18: TypeError: not an object -test262/test/built-ins/WeakSet/prototype/add/returns-this-symbol.js:18: strict mode: TypeError: not an object -test262/test/built-ins/WeakSet/prototype/add/returns-this-when-ignoring-duplicate-symbol.js:20: TypeError: not an object -test262/test/built-ins/WeakSet/prototype/add/returns-this-when-ignoring-duplicate-symbol.js:20: strict mode: TypeError: not an object -test262/test/built-ins/WeakSet/prototype/delete/delete-symbol-entry.js:22: TypeError: not an object -test262/test/built-ins/WeakSet/prototype/delete/delete-symbol-entry.js:22: strict mode: TypeError: not an object -test262/test/built-ins/WeakSet/prototype/has/returns-false-when-symbol-value-not-present.js:20: TypeError: not an object -test262/test/built-ins/WeakSet/prototype/has/returns-false-when-symbol-value-not-present.js:20: strict mode: TypeError: not an object -test262/test/built-ins/WeakSet/prototype/has/returns-true-when-symbol-value-present.js:17: TypeError: not an object -test262/test/built-ins/WeakSet/prototype/has/returns-true-when-symbol-value-present.js:17: strict mode: TypeError: not an object test262/test/language/expressions/assignment/target-member-computed-reference-null.js:32: Test262Error: Expected a DummyError but got a TypeError test262/test/language/expressions/assignment/target-member-computed-reference-null.js:32: strict mode: Test262Error: Expected a DummyError but got a TypeError test262/test/language/expressions/assignment/target-member-computed-reference-undefined.js:32: Test262Error: Expected a DummyError but got a TypeError