From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- js/src/builtin/WeakSetObject.cpp | 236 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 js/src/builtin/WeakSetObject.cpp (limited to 'js/src/builtin/WeakSetObject.cpp') diff --git a/js/src/builtin/WeakSetObject.cpp b/js/src/builtin/WeakSetObject.cpp new file mode 100644 index 0000000000..06e190f51e --- /dev/null +++ b/js/src/builtin/WeakSetObject.cpp @@ -0,0 +1,236 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "builtin/WeakSetObject.h" + +#include "builtin/MapObject.h" +#include "js/friend/ErrorMessages.h" // JSMSG_* +#include "js/PropertySpec.h" +#include "vm/GlobalObject.h" +#include "vm/JSContext.h" +#include "vm/SelfHosting.h" + +#include "builtin/WeakMapObject-inl.h" +#include "vm/JSObject-inl.h" +#include "vm/NativeObject-inl.h" + +using namespace js; + +/* static */ MOZ_ALWAYS_INLINE bool WeakSetObject::is(HandleValue v) { + return v.isObject() && v.toObject().is(); +} + +// ES2018 draft rev 7a2d3f053ecc2336fc19f377c55d52d78b11b296 +// 23.4.3.1 WeakSet.prototype.add ( value ) +/* static */ MOZ_ALWAYS_INLINE bool WeakSetObject::add_impl( + JSContext* cx, const CallArgs& args) { + MOZ_ASSERT(is(args.thisv())); + + // Step 4. + if (!CanBeHeldWeakly(cx, args.get(0))) { + ReportValueError(cx, JSMSG_WEAKSET_VAL_CANT_BE_HELD_WEAKLY, + JSDVG_IGNORE_STACK, args.get(0), nullptr); + return false; + } + + // Steps 5-7. + RootedValue value(cx, args[0]); + Rooted map(cx, &args.thisv().toObject().as()); + if (!WeakCollectionPutEntryInternal(cx, map, value, TrueHandleValue)) { + return false; + } + + // Steps 6.a.i, 8. + args.rval().set(args.thisv()); + return true; +} + +/* static */ +bool WeakSetObject::add(JSContext* cx, unsigned argc, Value* vp) { + // Steps 1-3. + CallArgs args = CallArgsFromVp(argc, vp); + return CallNonGenericMethod(cx, + args); +} + +// ES2018 draft rev 7a2d3f053ecc2336fc19f377c55d52d78b11b296 +// 23.4.3.3 WeakSet.prototype.delete ( value ) +/* static */ MOZ_ALWAYS_INLINE bool WeakSetObject::delete_impl( + JSContext* cx, const CallArgs& args) { + MOZ_ASSERT(is(args.thisv())); + + // Step 4. + if (!CanBeHeldWeakly(cx, args.get(0))) { + args.rval().setBoolean(false); + return true; + } + + // Steps 5-6. + if (ValueValueWeakMap* map = + args.thisv().toObject().as().getMap()) { + Value value = args[0]; + if (ValueValueWeakMap::Ptr ptr = map->lookup(value)) { + map->remove(ptr); + args.rval().setBoolean(true); + return true; + } + } + + // Step 7. + args.rval().setBoolean(false); + return true; +} + +/* static */ +bool WeakSetObject::delete_(JSContext* cx, unsigned argc, Value* vp) { + // Steps 1-3. + CallArgs args = CallArgsFromVp(argc, vp); + return CallNonGenericMethod( + cx, args); +} + +// ES2018 draft rev 7a2d3f053ecc2336fc19f377c55d52d78b11b296 +// 23.4.3.4 WeakSet.prototype.has ( value ) +/* static */ MOZ_ALWAYS_INLINE bool WeakSetObject::has_impl( + JSContext* cx, const CallArgs& args) { + MOZ_ASSERT(is(args.thisv())); + + // Step 5. + if (!CanBeHeldWeakly(cx, args.get(0))) { + args.rval().setBoolean(false); + return true; + } + + // Steps 4, 6. + if (ValueValueWeakMap* map = + args.thisv().toObject().as().getMap()) { + Value value = args[0]; + if (map->has(value)) { + args.rval().setBoolean(true); + return true; + } + } + + // Step 7. + args.rval().setBoolean(false); + return true; +} + +/* static */ +bool WeakSetObject::has(JSContext* cx, unsigned argc, Value* vp) { + // Steps 1-3. + CallArgs args = CallArgsFromVp(argc, vp); + return CallNonGenericMethod(cx, + args); +} + +const ClassSpec WeakSetObject::classSpec_ = { + GenericCreateConstructor, + GenericCreatePrototype, + nullptr, + nullptr, + WeakSetObject::methods, + WeakSetObject::properties, +}; + +const JSClass WeakSetObject::class_ = { + "WeakSet", + JSCLASS_HAS_RESERVED_SLOTS(SlotCount) | + JSCLASS_HAS_CACHED_PROTO(JSProto_WeakSet) | JSCLASS_BACKGROUND_FINALIZE, + &WeakCollectionObject::classOps_, &WeakSetObject::classSpec_}; + +const JSClass WeakSetObject::protoClass_ = { + "WeakSet.prototype", JSCLASS_HAS_CACHED_PROTO(JSProto_WeakSet), + JS_NULL_CLASS_OPS, &WeakSetObject::classSpec_}; + +const JSPropertySpec WeakSetObject::properties[] = { + JS_STRING_SYM_PS(toStringTag, "WeakSet", JSPROP_READONLY), JS_PS_END}; + +const JSFunctionSpec WeakSetObject::methods[] = { + JS_FN("add", add, 1, 0), JS_FN("delete", delete_, 1, 0), + JS_FN("has", has, 1, 0), JS_FS_END}; + +WeakSetObject* WeakSetObject::create(JSContext* cx, + HandleObject proto /* = nullptr */) { + return NewObjectWithClassProto(cx, proto); +} + +bool WeakSetObject::isBuiltinAdd(HandleValue add) { + return IsNativeFunction(add, WeakSetObject::add); +} + +bool WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp) { + // Based on our "Set" implementation instead of the more general ES6 steps. + CallArgs args = CallArgsFromVp(argc, vp); + + if (!ThrowIfNotConstructing(cx, args, "WeakSet")) { + return false; + } + + RootedObject proto(cx); + if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_WeakSet, &proto)) { + return false; + } + + Rooted obj(cx, WeakSetObject::create(cx, proto)); + if (!obj) { + return false; + } + + if (!args.get(0).isNullOrUndefined()) { + RootedValue iterable(cx, args[0]); + bool optimized = false; + if (!IsOptimizableInitForSet(cx, obj, iterable, &optimized)) { + return false; + } + + if (optimized) { + RootedValue keyVal(cx); + Rooted array(cx, &iterable.toObject().as()); + for (uint32_t index = 0; index < array->getDenseInitializedLength(); + ++index) { + keyVal.set(array->getDenseElement(index)); + MOZ_ASSERT(!keyVal.isMagic(JS_ELEMENTS_HOLE)); + + if (!CanBeHeldWeakly(cx, keyVal)) { + ReportValueError(cx, JSMSG_WEAKSET_VAL_CANT_BE_HELD_WEAKLY, + JSDVG_IGNORE_STACK, keyVal, nullptr); + return false; + } + + if (!WeakCollectionPutEntryInternal(cx, obj, keyVal, TrueHandleValue)) { + return false; + } + } + } else { + FixedInvokeArgs<1> args2(cx); + args2[0].set(args[0]); + + RootedValue thisv(cx, ObjectValue(*obj)); + if (!CallSelfHostedFunction(cx, cx->names().WeakSetConstructorInit, thisv, + args2, args2.rval())) { + return false; + } + } + } + + args.rval().setObject(*obj); + return true; +} + +JS_PUBLIC_API bool JS_NondeterministicGetWeakSetKeys(JSContext* cx, + HandleObject objArg, + MutableHandleObject ret) { + RootedObject obj(cx, UncheckedUnwrap(objArg)); + if (!obj || !obj->is()) { + ret.set(nullptr); + return true; + } + return WeakCollectionObject::nondeterministicGetKeys( + cx, obj.as(), ret); +} -- cgit v1.2.3