Bug 1595745 - Part 14: Change AsyncGeneratorFunction to use ClassSpec. r=mgaudet
☠☠ backed out by ec8cad689121 ☠ ☠
authorAndré Bargull <andre.bargull@gmail.com>
Fri, 15 Nov 2019 15:06:18 +0000
changeset 502208 de5c2cca64c6114d1a681b7f6d42b0d6e80e3b47
parent 502207 b11677f10f9d42f360852504ebedd4a3c03a1b32
child 502209 8e8c4124f21990d54d48215611651e6dd0cb3a98
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmgaudet
bugs1595745
milestone72.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1595745 - Part 14: Change AsyncGeneratorFunction to use ClassSpec. r=mgaudet Differential Revision: https://phabricator.services.mozilla.com/D52680
js/public/ProtoKey.h
js/src/jsapi.cpp
js/src/vm/AsyncIteration.cpp
js/src/vm/AsyncIteration.h
--- a/js/public/ProtoKey.h
+++ b/js/public/ProtoKey.h
@@ -107,17 +107,18 @@
   REAL(WeakSet, InitViaClassSpec, OCLASP(WeakSet))                           \
   REAL(TypedArray, InitViaClassSpec,                                         \
        &js::TypedArrayObject::sharedTypedArrayPrototypeClass)                \
   REAL(Atomics, InitViaClassSpec, OCLASP(Atomics))                           \
   REAL(SavedFrame, InitViaClassSpec, &js::SavedFrame::class_)                \
   REAL(Promise, InitViaClassSpec, OCLASP(Promise))                           \
   REAL(AsyncFunction, InitViaClassSpec, CLASP(AsyncFunction))                \
   REAL(GeneratorFunction, InitViaClassSpec, CLASP(GeneratorFunction))        \
-  REAL(AsyncGeneratorFunction, InitAsyncGeneratorFunction, nullptr)          \
+  REAL(AsyncGeneratorFunction, InitViaClassSpec,                             \
+       CLASP(AsyncGeneratorFunction))                                        \
   REAL(ReadableStream, InitViaClassSpec, &js::ReadableStream::class_)        \
   REAL(ReadableStreamDefaultReader, InitViaClassSpec,                        \
        &js::ReadableStreamDefaultReader::class_)                             \
   REAL(ReadableStreamDefaultController, InitViaClassSpec,                    \
        &js::ReadableStreamDefaultController::class_)                         \
   REAL(ReadableByteStreamController, InitViaClassSpec,                       \
        &js::ReadableByteStreamController::class_)                            \
   REAL(WritableStream, InitViaClassSpec, &js::WritableStream::class_)        \
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -890,17 +890,17 @@ JS_PUBLIC_API bool JS_ResolveStandardCla
 
   if (stdnm && GlobalObject::skipDeselectedConstructor(cx, stdnm->key)) {
     stdnm = nullptr;
   }
 
   // If this class is anonymous, then it doesn't exist as a global
   // property, so we won't resolve anything.
   JSProtoKey key = stdnm ? stdnm->key : JSProto_Null;
-  if (key != JSProto_Null && key != JSProto_AsyncGeneratorFunction) {
+  if (key != JSProto_Null) {
     const JSClass* clasp = ProtoKeyToClass(key);
     if (!clasp || clasp->specShouldDefineConstructor()) {
       if (!GlobalObject::ensureConstructor(cx, global, key)) {
         return false;
       }
 
       *resolved = true;
       return true;
@@ -966,21 +966,16 @@ static bool EnumerateStandardClassesInTa
     if (!includeResolved && global->isStandardClassResolved(key)) {
       continue;
     }
 
     if (GlobalObject::skipDeselectedConstructor(cx, key)) {
       continue;
     }
 
-    // AsyncGenerator doesn't yet use ClassSpec.
-    if (key == JSProto_AsyncGeneratorFunction) {
-      continue;
-    }
-
     if (const JSClass* clasp = ProtoKeyToClass(key)) {
       if (!clasp->specShouldDefineConstructor()) {
         continue;
       }
     }
 
     jsid id = NameToId(AtomStateOffsetToName(cx->names(), table[i].atomOffset));
     if (!properties.append(id)) {
--- a/js/src/vm/AsyncIteration.cpp
+++ b/js/src/vm/AsyncIteration.cpp
@@ -453,69 +453,92 @@ bool GlobalObject::initAsyncFromSyncIter
     return false;
   }
 
   global->setReservedSlot(ASYNC_FROM_SYNC_ITERATOR_PROTO,
                           ObjectValue(*asyncFromSyncIterProto));
   return true;
 }
 
-JSObject* js::InitAsyncGeneratorFunction(JSContext* cx,
-                                         Handle<GlobalObject*> global) {
-  RootedObject asyncIterProto(
-      cx, GlobalObject::getOrCreateAsyncIteratorPrototype(cx, global));
-  if (!asyncIterProto) {
-    return nullptr;
-  }
-
-  // 25.5 AsyncGenerator Objects
-  RootedObject asyncGenProto(cx, GlobalObject::createBlankPrototypeInheriting(
-                                     cx, &PlainObject::class_, asyncIterProto));
-  if (!asyncGenProto) {
-    return nullptr;
-  }
-  if (!DefinePropertiesAndFunctions(cx, asyncGenProto, nullptr,
-                                    async_generator_methods) ||
-      !DefineToStringTag(cx, asyncGenProto, cx->names().AsyncGenerator)) {
-    return nullptr;
-  }
-
-  // 25.3.3 Properties of the AsyncGeneratorFunction Prototype Object
-  RootedObject asyncGenerator(
-      cx, NewSingletonObjectWithFunctionPrototype(cx, global));
-  if (!asyncGenerator) {
-    return nullptr;
-  }
-  if (!LinkConstructorAndPrototype(cx, asyncGenerator, asyncGenProto,
-                                   JSPROP_READONLY, JSPROP_READONLY) ||
-      !DefineToStringTag(cx, asyncGenerator,
-                         cx->names().AsyncGeneratorFunction)) {
-    return nullptr;
-  }
-
+static JSObject* CreateAsyncGeneratorFunction(JSContext* cx, JSProtoKey key) {
   RootedObject proto(
       cx, GlobalObject::getOrCreateFunctionConstructor(cx, cx->global()));
   if (!proto) {
     return nullptr;
   }
   HandlePropertyName name = cx->names().AsyncGeneratorFunction;
 
   // 25.3.1 The AsyncGeneratorFunction Constructor
-  RootedObject asyncGenFunction(
-      cx, NewFunctionWithProto(cx, AsyncGeneratorConstructor, 1,
-                               FunctionFlags::NATIVE_CTOR, nullptr, name, proto,
-                               gc::AllocKind::FUNCTION, SingletonObject));
-  if (!asyncGenFunction) {
-    return nullptr;
+  return NewFunctionWithProto(cx, AsyncGeneratorConstructor, 1,
+                              FunctionFlags::NATIVE_CTOR, nullptr, name, proto,
+                              gc::AllocKind::FUNCTION, SingletonObject);
+}
+
+static JSObject* CreateAsyncGeneratorFunctionPrototype(JSContext* cx,
+                                                       JSProtoKey key) {
+  return NewSingletonObjectWithFunctionPrototype(cx, cx->global());
+}
+
+static bool AsyncGeneratorFunctionClassFinish(JSContext* cx,
+                                              HandleObject asyncGenFunction,
+                                              HandleObject asyncGenerator) {
+  Handle<GlobalObject*> global = cx->global();
+
+  // Change the "constructor" property to non-writable before adding any other
+  // properties, so it's still the last property and can be modified without a
+  // dictionary-mode transition.
+  MOZ_ASSERT(StringEqualsAscii(
+      JSID_TO_LINEAR_STRING(
+          asyncGenerator->as<NativeObject>().lastProperty()->propid()),
+      "constructor"));
+  MOZ_ASSERT(!asyncGenerator->as<NativeObject>().inDictionaryMode());
+
+  RootedValue asyncGenFunctionVal(cx, ObjectValue(*asyncGenFunction));
+  if (!DefineDataProperty(cx, asyncGenerator, cx->names().constructor,
+                          asyncGenFunctionVal, JSPROP_READONLY)) {
+    return false;
   }
-  if (!LinkConstructorAndPrototype(cx, asyncGenFunction, asyncGenerator,
-                                   JSPROP_PERMANENT | JSPROP_READONLY,
-                                   JSPROP_READONLY)) {
-    return nullptr;
+  MOZ_ASSERT(!asyncGenerator->as<NativeObject>().inDictionaryMode());
+
+  RootedObject asyncIterProto(
+      cx, GlobalObject::getOrCreateAsyncIteratorPrototype(cx, global));
+  if (!asyncIterProto) {
+    return false;
+  }
+
+  // 25.5 AsyncGenerator Objects
+  RootedObject asyncGenProto(cx, GlobalObject::createBlankPrototypeInheriting(
+                                     cx, &PlainObject::class_, asyncIterProto));
+  if (!asyncGenProto) {
+    return false;
+  }
+  if (!DefinePropertiesAndFunctions(cx, asyncGenProto, nullptr,
+                                    async_generator_methods) ||
+      !DefineToStringTag(cx, asyncGenProto, cx->names().AsyncGenerator)) {
+    return false;
+  }
+
+  // 25.3.3 Properties of the AsyncGeneratorFunction Prototype Object
+  if (!LinkConstructorAndPrototype(cx, asyncGenerator, asyncGenProto,
+                                   JSPROP_READONLY, JSPROP_READONLY) ||
+      !DefineToStringTag(cx, asyncGenerator,
+                         cx->names().AsyncGeneratorFunction)) {
+    return false;
   }
 
   global->setAsyncGeneratorPrototype(asyncGenProto);
-  global->setConstructor(JSProto_AsyncGeneratorFunction,
-                         ObjectValue(*asyncGenFunction));
-  global->setPrototype(JSProto_AsyncGeneratorFunction,
-                       ObjectValue(*asyncGenerator));
-  return asyncGenFunction;
+
+  return true;
 }
+
+static const ClassSpec AsyncGeneratorFunctionClassSpec = {
+    CreateAsyncGeneratorFunction,
+    CreateAsyncGeneratorFunctionPrototype,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    AsyncGeneratorFunctionClassFinish,
+    ClassSpec::DontDefineConstructor};
+
+const JSClass js::AsyncGeneratorFunctionClass = {
+    "AsyncGeneratorFunction", 0, JS_NULL_CLASS_OPS,
+    &AsyncGeneratorFunctionClassSpec};
--- a/js/src/vm/AsyncIteration.h
+++ b/js/src/vm/AsyncIteration.h
@@ -12,17 +12,18 @@
 #include "vm/GeneratorObject.h"
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 #include "vm/List.h"
 
 namespace js {
 
 class AsyncGeneratorObject;
-class GlobalObject;
+
+extern const JSClass AsyncGeneratorFunctionClass;
 
 // Resume the async generator when the `await` operand fulfills to `value`.
 MOZ_MUST_USE bool AsyncGeneratorAwaitedFulfilled(
     JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
     HandleValue value);
 
 // Resume the async generator when the `await` operand rejects with `reason`.
 MOZ_MUST_USE bool AsyncGeneratorAwaitedRejected(
@@ -290,14 +291,11 @@ class AsyncFromSyncIteratorObject : publ
 
   const Value& nextMethod() const { return getFixedSlot(Slot_NextMethod); }
 };
 
 MOZ_MUST_USE bool AsyncGeneratorResume(
     JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
     CompletionKind completionKind, HandleValue argument);
 
-extern JSObject* InitAsyncGeneratorFunction(JSContext* cx,
-                                            js::Handle<GlobalObject*> global);
-
 }  // namespace js
 
 #endif /* vm_AsyncIteration_h */