Bug 1595745 - Part 13: Change AsyncFunction to use ClassSpec. r=mgaudet
☠☠ backed out by ec8cad689121 ☠ ☠
authorAndré Bargull <andre.bargull@gmail.com>
Fri, 15 Nov 2019 15:05:58 +0000
changeset 502207 b11677f10f9d42f360852504ebedd4a3c03a1b32
parent 502206 2ce96c6187c2ad834605f4ea6cfb17688c0ebadd
child 502208 de5c2cca64c6114d1a681b7f6d42b0d6e80e3b47
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 13: Change AsyncFunction to use ClassSpec. r=mgaudet Update AsyncFunction similar to the changes performed in part 13. Differential Revision: https://phabricator.services.mozilla.com/D52679
js/public/ProtoKey.h
js/src/jsapi.cpp
js/src/vm/AsyncFunction.cpp
js/src/vm/AsyncFunction.h
--- a/js/public/ProtoKey.h
+++ b/js/public/ProtoKey.h
@@ -105,17 +105,17 @@
   REAL_IF_BDATA(TypedObject, InitViaClassSpec, OCLASP(TypedObjectModule))    \
   REAL(Reflect, InitViaClassSpec, CLASP(Reflect))                            \
   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, InitAsyncFunction, nullptr)                            \
+  REAL(AsyncFunction, InitViaClassSpec, CLASP(AsyncFunction))                \
   REAL(GeneratorFunction, InitViaClassSpec, CLASP(GeneratorFunction))        \
   REAL(AsyncGeneratorFunction, InitAsyncGeneratorFunction, nullptr)          \
   REAL(ReadableStream, InitViaClassSpec, &js::ReadableStream::class_)        \
   REAL(ReadableStreamDefaultReader, InitViaClassSpec,                        \
        &js::ReadableStreamDefaultReader::class_)                             \
   REAL(ReadableStreamDefaultController, InitViaClassSpec,                    \
        &js::ReadableStreamDefaultController::class_)                         \
   REAL(ReadableByteStreamController, InitViaClassSpec,                       \
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -890,18 +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_AsyncFunction &&
-      key != JSProto_AsyncGeneratorFunction) {
+  if (key != JSProto_Null && key != JSProto_AsyncGeneratorFunction) {
     const JSClass* clasp = ProtoKeyToClass(key);
     if (!clasp || clasp->specShouldDefineConstructor()) {
       if (!GlobalObject::ensureConstructor(cx, global, key)) {
         return false;
       }
 
       *resolved = true;
       return true;
@@ -967,18 +966,18 @@ static bool EnumerateStandardClassesInTa
     if (!includeResolved && global->isStandardClassResolved(key)) {
       continue;
     }
 
     if (GlobalObject::skipDeselectedConstructor(cx, key)) {
       continue;
     }
 
-    // Async(Function|Generator) don't yet use ClassSpec.
-    if (key == JSProto_AsyncFunction || key == JSProto_AsyncGeneratorFunction) {
+    // AsyncGenerator doesn't yet use ClassSpec.
+    if (key == JSProto_AsyncGeneratorFunction) {
       continue;
     }
 
     if (const JSClass* clasp = ProtoKeyToClass(key)) {
       if (!clasp->specShouldDefineConstructor()) {
         continue;
       }
     }
--- a/js/src/vm/AsyncFunction.cpp
+++ b/js/src/vm/AsyncFunction.cpp
@@ -7,59 +7,75 @@
 #include "vm/AsyncFunction.h"
 
 #include "mozilla/Maybe.h"
 
 #include "builtin/Promise.h"
 #include "vm/GeneratorObject.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
+#include "vm/NativeObject.h"
 #include "vm/Realm.h"
 #include "vm/SelfHosting.h"
 
 #include "vm/JSObject-inl.h"
 
 using namespace js;
 
 using mozilla::Maybe;
 
-JSObject* js::InitAsyncFunction(JSContext* cx, Handle<GlobalObject*> global) {
-  RootedObject asyncFunctionProto(
-      cx, NewSingletonObjectWithFunctionPrototype(cx, global));
-  if (!asyncFunctionProto) {
-    return nullptr;
-  }
-
-  if (!DefineToStringTag(cx, asyncFunctionProto, cx->names().AsyncFunction)) {
-    return nullptr;
-  }
-
+static JSObject* CreateAsyncFunction(JSContext* cx, JSProtoKey key) {
   RootedObject proto(
       cx, GlobalObject::getOrCreateFunctionConstructor(cx, cx->global()));
   if (!proto) {
     return nullptr;
   }
+
   HandlePropertyName name = cx->names().AsyncFunction;
-  RootedObject asyncFunction(
-      cx,
-      NewFunctionWithProto(cx, AsyncFunctionConstructor, 1,
-                           FunctionFlags::NATIVE_CTOR, nullptr, name, proto));
-  if (!asyncFunction) {
-    return nullptr;
+  return NewFunctionWithProto(cx, AsyncFunctionConstructor, 1,
+                              FunctionFlags::NATIVE_CTOR, nullptr, name, proto);
+}
+
+static JSObject* CreateAsyncFunctionPrototype(JSContext* cx, JSProtoKey key) {
+  return NewSingletonObjectWithFunctionPrototype(cx, cx->global());
+}
+
+static bool AsyncFunctionClassFinish(JSContext* cx, HandleObject asyncFunction,
+                                     HandleObject asyncFunctionProto) {
+  // 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(
+          asyncFunctionProto->as<NativeObject>().lastProperty()->propid()),
+      "constructor"));
+  MOZ_ASSERT(!asyncFunctionProto->as<NativeObject>().inDictionaryMode());
+
+  RootedValue asyncFunctionVal(cx, ObjectValue(*asyncFunction));
+  if (!DefineDataProperty(cx, asyncFunctionProto, cx->names().constructor,
+                          asyncFunctionVal, JSPROP_READONLY)) {
+    return false;
   }
-  if (!LinkConstructorAndPrototype(cx, asyncFunction, asyncFunctionProto,
-                                   JSPROP_PERMANENT | JSPROP_READONLY,
-                                   JSPROP_READONLY)) {
-    return nullptr;
-  }
+  MOZ_ASSERT(!asyncFunctionProto->as<NativeObject>().inDictionaryMode());
+
+  return DefineToStringTag(cx, asyncFunctionProto, cx->names().AsyncFunction);
+}
 
-  global->setConstructor(JSProto_AsyncFunction, ObjectValue(*asyncFunction));
-  global->setPrototype(JSProto_AsyncFunction, ObjectValue(*asyncFunctionProto));
-  return asyncFunction;
-}
+static const ClassSpec AsyncFunctionClassSpec = {
+    CreateAsyncFunction,
+    CreateAsyncFunctionPrototype,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    AsyncFunctionClassFinish,
+    ClassSpec::DontDefineConstructor};
+
+const JSClass js::AsyncFunctionClass = {"AsyncFunction", 0, JS_NULL_CLASS_OPS,
+                                        &AsyncFunctionClassSpec};
 
 enum class ResumeKind { Normal, Throw };
 
 // ES2020 draft rev a09fc232c137800dbf51b6204f37fdede4ba1646
 // 6.2.3.1.1 Await Fulfilled Functions
 // 6.2.3.1.2 Await Rejected Functions
 static bool AsyncFunctionResume(JSContext* cx,
                                 Handle<AsyncFunctionGeneratorObject*> generator,
--- a/js/src/vm/AsyncFunction.h
+++ b/js/src/vm/AsyncFunction.h
@@ -11,17 +11,18 @@
 #include "js/Class.h"
 #include "vm/GeneratorObject.h"
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 
 namespace js {
 
 class AsyncFunctionGeneratorObject;
-class GlobalObject;
+
+extern const JSClass AsyncFunctionClass;
 
 // Resume the async function when the `await` operand resolves.
 // Split into two functions depending on whether the awaited value was
 // fulfilled or rejected.
 MOZ_MUST_USE bool AsyncFunctionAwaitedFulfilled(
     JSContext* cx, Handle<AsyncFunctionGeneratorObject*> generator,
     HandleValue value);
 
@@ -51,14 +52,11 @@ class AsyncFunctionGeneratorObject : pub
   static AsyncFunctionGeneratorObject* create(JSContext* cx,
                                               HandleFunction asyncGen);
 
   PromiseObject* promise() {
     return &getFixedSlot(PROMISE_SLOT).toObject().as<PromiseObject>();
   }
 };
 
-extern JSObject* InitAsyncFunction(JSContext* cx,
-                                   js::Handle<GlobalObject*> global);
-
 }  // namespace js
 
 #endif /* vm_AsyncFunction_h */