Bug 1530745 - Part 3: Add a helper to retrieve the prototype for a specific function type. r=arai
authorAndré Bargull <andre.bargull@gmail.com>
Fri, 08 Mar 2019 12:36:14 +0000
changeset 521218 588b9eec2edb
parent 521217 4e633d85d45d
child 521219 d6cab6cee202
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarai
bugs1530745
milestone67.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 1530745 - Part 3: Add a helper to retrieve the prototype for a specific function type. r=arai Depends on D22667 Differential Revision: https://phabricator.services.mozilla.com/D22668
js/src/frontend/Parser.cpp
js/src/vm/JSFunction.cpp
js/src/vm/JSFunction.h
js/src/vm/JSScript.cpp
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2552,33 +2552,18 @@ GeneralParser<ParseHandler, Unit>::funct
     if (!skipLazyInnerFunction(funNode, toStringStart, kind, tryAnnexB)) {
       return null();
     }
 
     return funNode;
   }
 
   RootedObject proto(cx_);
-  if (asyncKind == FunctionAsyncKind::AsyncFunction &&
-      generatorKind == GeneratorKind::Generator) {
-    proto = GlobalObject::getOrCreateAsyncGenerator(cx_, cx_->global());
-    if (!proto) {
-      return null();
-    }
-  } else if (asyncKind == FunctionAsyncKind::AsyncFunction) {
-    proto = GlobalObject::getOrCreateAsyncFunctionPrototype(cx_, cx_->global());
-    if (!proto) {
-      return null();
-    }
-  } else if (generatorKind == GeneratorKind::Generator) {
-    proto =
-        GlobalObject::getOrCreateGeneratorFunctionPrototype(cx_, cx_->global());
-    if (!proto) {
-      return null();
-    }
+  if (!GetFunctionPrototype(cx_, generatorKind, asyncKind, &proto)) {
+    return null();
   }
   RootedFunction fun(
       cx_, newFunction(funName, kind, generatorKind, asyncKind, proto));
   if (!fun) {
     return null();
   }
 
   // Speculatively parse using the directives of the parent parsing context.
--- a/js/src/vm/JSFunction.cpp
+++ b/js/src/vm/JSFunction.cpp
@@ -600,33 +600,27 @@ XDRResult js::XDRInterpretedFunction(XDR
   MOZ_TRY(xdr->codeUint32(&firstword));
 
   if (firstword & HasAtom) {
     MOZ_TRY(XDRAtom(xdr, &atom));
   }
   MOZ_TRY(xdr->codeUint32(&flagsword));
 
   if (mode == XDR_DECODE) {
+    GeneratorKind generatorKind = (firstword & IsGenerator)
+                                      ? GeneratorKind::Generator
+                                      : GeneratorKind::NotGenerator;
+
+    FunctionAsyncKind asyncKind = (firstword & IsAsync)
+                                      ? FunctionAsyncKind::AsyncFunction
+                                      : FunctionAsyncKind::SyncFunction;
+
     RootedObject proto(cx);
-    if ((firstword & IsAsync) && (firstword & IsGenerator)) {
-      proto = GlobalObject::getOrCreateAsyncGenerator(cx, cx->global());
-      if (!proto) {
-        return xdr->fail(JS::TranscodeResult_Throw);
-      }
-    } else if (firstword & IsAsync) {
-      proto = GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global());
-      if (!proto) {
-        return xdr->fail(JS::TranscodeResult_Throw);
-      }
-    } else if (firstword & IsGenerator) {
-      proto =
-          GlobalObject::getOrCreateGeneratorFunctionPrototype(cx, cx->global());
-      if (!proto) {
-        return xdr->fail(JS::TranscodeResult_Throw);
-      }
+    if (!GetFunctionPrototype(cx, generatorKind, asyncKind, &proto)) {
+      return xdr->fail(JS::TranscodeResult_Throw);
     }
 
     gc::AllocKind allocKind = gc::AllocKind::FUNCTION;
     if (uint16_t(flagsword) & JSFunction::EXTENDED) {
       allocKind = gc::AllocKind::FUNCTION_EXTENDED;
     }
     fun = NewFunctionWithProto(cx, nullptr, 0, JSFunction::INTERPRETED,
                                /* enclosingDynamicScope = */ nullptr, nullptr,
@@ -1905,32 +1899,18 @@ static bool CreateDynamicFunction(JSCont
    * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
    * and so would a call to f from another top-level's script or function.
    */
   RootedAtom anonymousAtom(cx, cx->names().anonymous);
 
   // Initialize the function with the default prototype:
   // Leave as nullptr to get the default from clasp for normal functions.
   RootedObject defaultProto(cx);
-  if (isAsync && isGenerator) {
-    defaultProto = GlobalObject::getOrCreateAsyncGenerator(cx, cx->global());
-    if (!defaultProto) {
-      return false;
-    }
-  } else if (isAsync) {
-    defaultProto = GlobalObject::getOrCreateAsyncFunctionPrototype(cx, global);
-    if (!defaultProto) {
-      return false;
-    }
-  } else if (isGenerator) {
-    defaultProto =
-        GlobalObject::getOrCreateGeneratorFunctionPrototype(cx, global);
-    if (!defaultProto) {
-      return false;
-    }
+  if (!GetFunctionPrototype(cx, generatorKind, asyncKind, &defaultProto)) {
+    return false;
   }
 
   // Step 30-37 (reordered).
   RootedObject globalLexical(cx, &global->lexicalEnvironment());
   JSFunction::Flags flags =
       (isGenerator || isAsync)
           ? JSFunction::INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC
           : JSFunction::INTERPRETED_LAMBDA;
@@ -2144,16 +2124,38 @@ JSFunction* js::NewFunctionWithProto(
   if (allocKind == gc::AllocKind::FUNCTION_EXTENDED) {
     fun->initializeExtended();
   }
   fun->initAtom(atom);
 
   return fun;
 }
 
+bool js::GetFunctionPrototype(JSContext* cx, js::GeneratorKind generatorKind,
+                              js::FunctionAsyncKind asyncKind,
+                              js::MutableHandleObject proto) {
+  if (generatorKind == js::GeneratorKind::NotGenerator) {
+    if (asyncKind == js::FunctionAsyncKind::SyncFunction) {
+      proto.set(nullptr);
+      return true;
+    }
+
+    proto.set(
+        GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global()));
+  } else {
+    if (asyncKind == js::FunctionAsyncKind::SyncFunction) {
+      proto.set(GlobalObject::getOrCreateGeneratorFunctionPrototype(
+          cx, cx->global()));
+    } else {
+      proto.set(GlobalObject::getOrCreateAsyncGenerator(cx, cx->global()));
+    }
+  }
+  return !!proto;
+}
+
 bool js::CanReuseScriptForClone(JS::Realm* realm, HandleFunction fun,
                                 HandleObject newParent) {
   MOZ_ASSERT(fun->isInterpreted());
 
   if (realm != fun->realm() || fun->isSingleton() ||
       ObjectGroup::useSingletonForClone(fun)) {
     return false;
   }
@@ -2178,33 +2180,19 @@ bool js::CanReuseScriptForClone(JS::Real
 }
 
 static inline JSFunction* NewFunctionClone(JSContext* cx, HandleFunction fun,
                                            NewObjectKind newKind,
                                            gc::AllocKind allocKind,
                                            HandleObject proto) {
   RootedObject cloneProto(cx, proto);
   if (!proto) {
-    if (fun->isAsync() && fun->isGenerator()) {
-      cloneProto = GlobalObject::getOrCreateAsyncGenerator(cx, cx->global());
-      if (!cloneProto) {
-        return nullptr;
-      }
-    } else if (fun->isAsync()) {
-      cloneProto =
-          GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global());
-      if (!cloneProto) {
-        return nullptr;
-      }
-    } else if (fun->isGenerator()) {
-      cloneProto =
-          GlobalObject::getOrCreateGeneratorFunctionPrototype(cx, cx->global());
-      if (!cloneProto) {
-        return nullptr;
-      }
+    if (!GetFunctionPrototype(cx, fun->generatorKind(), fun->asyncKind(),
+                              &cloneProto)) {
+      return nullptr;
     }
   }
 
   RootedFunction clone(cx);
   clone =
       NewObjectWithClassProto<JSFunction>(cx, cloneProto, allocKind, newKind);
   if (!clone) {
     return nullptr;
--- a/js/src/vm/JSFunction.h
+++ b/js/src/vm/JSFunction.h
@@ -889,16 +889,29 @@ inline JSFunction* NewNativeConstructor(
 // Allocate a new scripted function.  If enclosingEnv is null, the
 // global will be used.  In all cases the parent of the resulting object will be
 // the global.
 extern JSFunction* NewScriptedFunction(
     JSContext* cx, unsigned nargs, JSFunction::Flags flags, HandleAtom atom,
     HandleObject proto = nullptr,
     gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
     NewObjectKind newKind = GenericObject, HandleObject enclosingEnv = nullptr);
+
+// Determine which [[Prototype]] to use when creating a new function using the
+// requested generator and async kind.
+//
+// This sets `proto` to `nullptr` for non-generator, synchronous functions to
+// mean "the builtin %FunctionPrototype% in the current realm", the common case.
+//
+// We could set it to `cx->global()->getOrCreateFunctionPrototype()`, but
+// nullptr gets a fast path in e.g. js::NewObjectWithClassProtoCommon.
+extern bool GetFunctionPrototype(JSContext* cx, js::GeneratorKind generatorKind,
+                                 js::FunctionAsyncKind asyncKind,
+                                 js::MutableHandleObject proto);
+
 extern JSAtom* IdToFunctionName(
     JSContext* cx, HandleId id,
     FunctionPrefixKind prefixKind = FunctionPrefixKind::None);
 
 extern bool SetFunctionName(JSContext* cx, HandleFunction fun, HandleValue name,
                             FunctionPrefixKind prefixKind);
 
 extern JSFunction* DefineFunction(
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -3983,33 +3983,19 @@ void js::DescribeScriptedCallerForCompil
   }
 }
 
 static JSObject* CloneInnerInterpretedFunction(
     JSContext* cx, HandleScope enclosingScope, HandleFunction srcFun,
     Handle<ScriptSourceObject*> sourceObject) {
   /* NB: Keep this in sync with XDRInterpretedFunction. */
   RootedObject cloneProto(cx);
-  if (srcFun->isAsync() && srcFun->isGenerator()) {
-    cloneProto = GlobalObject::getOrCreateAsyncGenerator(cx, cx->global());
-    if (!cloneProto) {
-      return nullptr;
-    }
-  } else if (srcFun->isAsync()) {
-    cloneProto =
-        GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global());
-    if (!cloneProto) {
-      return nullptr;
-    }
-  } else if (srcFun->isGenerator()) {
-    cloneProto =
-        GlobalObject::getOrCreateGeneratorFunctionPrototype(cx, cx->global());
-    if (!cloneProto) {
-      return nullptr;
-    }
+  if (!GetFunctionPrototype(cx, srcFun->generatorKind(), srcFun->asyncKind(),
+                            &cloneProto)) {
+    return nullptr;
   }
 
   gc::AllocKind allocKind = srcFun->getAllocKind();
   uint16_t flags = srcFun->flags();
   if (srcFun->isSelfHostedBuiltin()) {
     // Functions in the self-hosting compartment are only extended in
     // debug mode. For top-level functions, FUNCTION_EXTENDED gets used by
     // the cloning algorithm. Do the same for inner functions here.