summaryrefslogtreecommitdiffstats
path: root/js/src/vm/Iteration.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm/Iteration.cpp')
-rw-r--r--js/src/vm/Iteration.cpp118
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),