diff options
Diffstat (limited to 'js/src/vm/Iteration.cpp')
-rw-r--r-- | js/src/vm/Iteration.cpp | 118 |
1 files changed, 114 insertions, 4 deletions
diff --git a/js/src/vm/Iteration.cpp b/js/src/vm/Iteration.cpp index d02f9de8cf..e36ea8b555 100644 --- a/js/src/vm/Iteration.cpp +++ b/js/src/vm/Iteration.cpp @@ -1940,10 +1940,113 @@ static const JSFunctionSpec iterator_methods_with_helpers[] = { JS_FS_END, }; +// https://tc39.es/proposal-iterator-helpers/#sec-SetterThatIgnoresPrototypeProperties +static bool SetterThatIgnoresPrototypeProperties(JSContext* cx, + Handle<Value> thisv, + Handle<PropertyKey> prop, + Handle<Value> value) { + // Step 1. + Rooted<JSObject*> thisObj(cx, + RequireObject(cx, JSMSG_OBJECT_REQUIRED, thisv)); + if (!thisObj) { + return false; + } + + // Step 2. + Rooted<JSObject*> home( + cx, GlobalObject::getOrCreateIteratorPrototype(cx, cx->global())); + if (!home) { + return false; + } + if (thisObj == home) { + UniqueChars propName = + IdToPrintableUTF8(cx, prop, IdToPrintableBehavior::IdIsPropertyKey); + if (!propName) { + return false; + } + + // Step 2.b. + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_READ_ONLY, + propName.get()); + return false; + } + + // Step 3. + Rooted<Maybe<PropertyDescriptor>> desc(cx); + if (!GetOwnPropertyDescriptor(cx, thisObj, prop, &desc)) { + return false; + } + + // Step 4. + if (desc.isNothing()) { + // Step 4.a. + return DefineDataProperty(cx, thisObj, prop, value, JSPROP_ENUMERATE); + } + + // Step 5. + return SetProperty(cx, thisObj, prop, value); +} + +// https://tc39.es/proposal-iterator-helpers/#sec-get-iteratorprototype-@@tostringtag +static bool toStringTagGetter(JSContext* cx, unsigned argc, Value* vp) { + CallArgs args = CallArgsFromVp(argc, vp); + + // Step 1. + args.rval().setString(cx->names().Iterator); + return true; +} + +// https://tc39.es/proposal-iterator-helpers/#sec-set-iteratorprototype-@@tostringtag +static bool toStringTagSetter(JSContext* cx, unsigned argc, Value* vp) { + CallArgs args = CallArgsFromVp(argc, vp); + + // Step 1. + Rooted<PropertyKey> prop( + cx, PropertyKey::Symbol(cx->wellKnownSymbols().toStringTag)); + if (!SetterThatIgnoresPrototypeProperties(cx, args.thisv(), prop, + args.get(0))) { + return false; + } + + // Step 2. + args.rval().setUndefined(); + return true; +} + +// https://tc39.es/proposal-iterator-helpers/#sec-get-iteratorprototype-constructor +static bool constructorGetter(JSContext* cx, unsigned argc, Value* vp) { + CallArgs args = CallArgsFromVp(argc, vp); + + // Step 1. + Rooted<JSObject*> constructor( + cx, GlobalObject::getOrCreateConstructor(cx, JSProto_Iterator)); + if (!constructor) { + return false; + } + args.rval().setObject(*constructor); + return true; +} + +// https://tc39.es/proposal-iterator-helpers/#sec-set-iteratorprototype-constructor +static bool constructorSetter(JSContext* cx, unsigned argc, Value* vp) { + CallArgs args = CallArgsFromVp(argc, vp); + + // Step 1. + Rooted<PropertyKey> prop(cx, NameToId(cx->names().constructor)); + if (!SetterThatIgnoresPrototypeProperties(cx, args.thisv(), prop, + args.get(0))) { + return false; + } + + // Step 2. + args.rval().setUndefined(); + return true; +} + static const JSPropertySpec iterator_properties[] = { - // NOTE: Contrary to most other @@toStringTag properties, this property is - // writable. - JS_STRING_SYM_PS(toStringTag, "Iterator", 0), + // NOTE: Contrary to most other @@toStringTag properties, this property + // has a special setter (and a getter). + JS_SYM_GETSET(toStringTag, toStringTagGetter, toStringTagSetter, 0), JS_PS_END, }; @@ -2081,7 +2184,7 @@ static const ClassSpec IteratorObjectClassSpec = { nullptr, iterator_methods_with_helpers, iterator_properties, - nullptr, + IteratorObject::finishInit, }; const JSClass IteratorObject::class_ = { @@ -2098,6 +2201,13 @@ const JSClass IteratorObject::protoClass_ = { &IteratorObjectClassSpec, }; +/* static */ bool IteratorObject::finishInit(JSContext* cx, HandleObject ctor, + HandleObject proto) { + Rooted<PropertyKey> id(cx, NameToId(cx->names().constructor)); + return JS_DefinePropertyById(cx, proto, id, constructorGetter, + constructorSetter, 0); +} + // Set up WrapForValidIteratorObject class and its prototype. static const JSFunctionSpec wrap_for_valid_iterator_methods[] = { JS_SELF_HOSTED_FN("next", "WrapForValidIteratorNext", 0, 0), |