Bug 1317416 - GetPrototypeFromConstructor needs to retrieve the fallback prototype from the constructor's realm. r=jandem
authorJason Orendorff <jorendorff@mozilla.com>
Mon, 14 Jan 2019 20:19:09 +0000
changeset 510909 1ce15a2a79e08b2b8803d42b06476d5b101111d0
parent 510908 54c6397bb3844b170f930425188003d2d35b126a
child 510910 1cf230625662499e8c2d0315cfa9d7cd161e1a48
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1317416
milestone66.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 1317416 - GetPrototypeFromConstructor needs to retrieve the fallback prototype from the constructor's realm. r=jandem Differential Revision: https://phabricator.services.mozilla.com/D14907
js/src/builtin/Array.cpp
js/src/builtin/Boolean.cpp
js/src/builtin/DataViewObject.cpp
js/src/builtin/MapObject.cpp
js/src/builtin/Promise.cpp
js/src/builtin/RegExp.cpp
js/src/builtin/Stream.cpp
js/src/builtin/String.cpp
js/src/builtin/WeakMapObject.cpp
js/src/builtin/WeakSetObject.cpp
js/src/builtin/intl/Collator.cpp
js/src/builtin/intl/DateTimeFormat.cpp
js/src/builtin/intl/NumberFormat.cpp
js/src/builtin/intl/PluralRules.cpp
js/src/builtin/intl/RelativeTimeFormat.cpp
js/src/jsdate.cpp
js/src/jsexn.cpp
js/src/jsnum.cpp
js/src/tests/jstests.list
js/src/vm/ArrayBufferObject.cpp
js/src/vm/JSFunction.cpp
js/src/vm/JSObject.cpp
js/src/vm/JSObject.h
js/src/vm/SharedArrayObject.cpp
js/src/vm/TypedArrayObject-inl.h
js/src/vm/TypedArrayObject.cpp
--- a/js/src/builtin/Array.cpp
+++ b/js/src/builtin/Array.cpp
@@ -3799,17 +3799,17 @@ static const JSFunctionSpec array_static
 
 const JSPropertySpec array_static_props[] = {
     JS_SELF_HOSTED_SYM_GET(species, "ArraySpecies", 0), JS_PS_END};
 
 static inline bool ArrayConstructorImpl(JSContext* cx, CallArgs& args,
                                         bool isConstructor) {
   RootedObject proto(cx);
   if (isConstructor) {
-    if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+    if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Array, &proto)) {
       return false;
     }
   } else {
     // We're emulating |new Array(n)| with |std_Array(n)| in self-hosted JS,
     // and the proto should be %ArrayPrototype% regardless of the callee.
     proto = GlobalObject::getOrCreateArrayPrototype(cx, cx->global());
     if (!proto) {
       return false;
--- a/js/src/builtin/Boolean.cpp
+++ b/js/src/builtin/Boolean.cpp
@@ -100,17 +100,18 @@ static const JSFunctionSpec boolean_meth
 
 static bool Boolean(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   bool b = args.length() != 0 ? JS::ToBoolean(args[0]) : false;
 
   if (args.isConstructing()) {
     RootedObject proto(cx);
-    if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+    if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Boolean,
+                                            &proto)) {
       return false;
     }
 
     JSObject* obj = BooleanObject::create(cx, b, proto);
     if (!obj) {
       return false;
     }
     args.rval().setObject(*obj);
--- a/js/src/builtin/DataViewObject.cpp
+++ b/js/src/builtin/DataViewObject.cpp
@@ -132,17 +132,17 @@ bool DataViewObject::constructSameCompar
   cx->check(bufobj);
 
   uint32_t byteOffset, byteLength;
   if (!getAndCheckConstructorArgs(cx, bufobj, args, &byteOffset, &byteLength)) {
     return false;
   }
 
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_DataView, &proto)) {
     return false;
   }
 
   Rooted<ArrayBufferObjectMaybeShared*> buffer(
       cx, &AsArrayBufferMaybeShared(bufobj));
   JSObject* obj =
       DataViewObject::create(cx, byteOffset, byteLength, buffer, proto);
   if (!obj) {
@@ -181,17 +181,17 @@ bool DataViewObject::constructWrapped(JS
   if (!getAndCheckConstructorArgs(cx, unwrapped, args, &byteOffset,
                                   &byteLength)) {
     return false;
   }
 
   // Make sure to get the [[Prototype]] for the created view from this
   // compartment.
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_DataView, &proto)) {
     return false;
   }
 
   Rooted<GlobalObject*> global(cx, cx->realm()->maybeGlobal());
   if (!proto) {
     proto = GlobalObject::getOrCreateDataViewPrototype(cx, global);
     if (!proto) {
       return false;
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -646,17 +646,17 @@ void MapObject::finalize(FreeOp* fop, JS
 bool MapObject::construct(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   if (!ThrowIfNotConstructing(cx, args, "Map")) {
     return false;
   }
 
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Map, &proto)) {
     return false;
   }
 
   Rooted<MapObject*> obj(cx, MapObject::create(cx, proto));
   if (!obj) {
     return false;
   }
 
@@ -1265,17 +1265,17 @@ bool SetObject::isBuiltinAdd(HandleValue
 bool SetObject::construct(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   if (!ThrowIfNotConstructing(cx, args, "Set")) {
     return false;
   }
 
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Set, &proto)) {
     return false;
   }
 
   Rooted<SetObject*> obj(cx, SetObject::create(cx, proto));
   if (!obj) {
     return false;
   }
 
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -2095,17 +2095,18 @@ static bool PromiseConstructor(JSContext
     }
   }
 
   if (needsWrapping) {
     if (!cx->compartment()->wrap(cx, &proto)) {
       return false;
     }
   } else {
-    if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+    if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Promise,
+                                            &proto)) {
       return false;
     }
   }
   PromiseObject* promise =
       PromiseObject::create(cx, executor, proto, needsWrapping);
   if (!promise) {
     return false;
   }
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -478,17 +478,17 @@ bool js::regexp_construct(JSContext* cx,
       // If the RegExpShared is in another Zone, don't reuse it.
       if (cx->zone() != shared->zone()) {
         shared = nullptr;
       }
     }
 
     // Step 7.
     RootedObject proto(cx);
-    if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+    if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_RegExp, &proto)) {
       return false;
     }
 
     Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx, GenericObject, proto));
     if (!regexp) {
       return false;
     }
 
@@ -554,17 +554,17 @@ bool js::regexp_construct(JSContext* cx,
   } else {
     // Steps 6.a-b.
     P = patternValue;
     F = args.get(1);
   }
 
   // Step 7.
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_RegExp, &proto)) {
     return false;
   }
 
   Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx, GenericObject, proto));
   if (!regexp) {
     return false;
   }
 
--- a/js/src/builtin/Stream.cpp
+++ b/js/src/builtin/Stream.cpp
@@ -546,17 +546,18 @@ bool ReadableStream::constructor(JSConte
     }
     strategy = ObjectValue(*emptyObj);
   }
 
   // Implicit in the spec: Set this to
   //     OrdinaryCreateFromConstructor(NewTarget, ...).
   // Step 1: Perform ! InitializeReadableStream(this).
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_ReadableStream,
+                                          &proto)) {
     return false;
   }
   Rooted<ReadableStream*> stream(cx, ReadableStream::create(cx, proto));
   if (!stream) {
     return false;
   }
 
   // Step 2: Let size be ? GetV(strategy, "size").
@@ -1787,17 +1788,17 @@ bool ReadableStreamDefaultReader::constr
   CallArgs args = CallArgsFromVp(argc, vp);
 
   if (!ThrowIfNotConstructing(cx, args, "ReadableStreamDefaultReader")) {
     return false;
   }
 
   // Implicit in the spec: Find the prototype object to use.
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
     return false;
   }
 
   // Step 1: If ! IsReadableStream(stream) is false, throw a TypeError
   // exception.
   Rooted<ReadableStream*> unwrappedStream(
       cx, UnwrapAndTypeCheckArgument<ReadableStream>(
               cx, args, "ReadableStreamDefaultReader constructor", 0));
@@ -3930,17 +3931,18 @@ bool js::ByteLengthQueuingStrategy::cons
   CallArgs args = CallArgsFromVp(argc, vp);
 
   if (!ThrowIfNotConstructing(cx, args, "ByteLengthQueuingStrategy")) {
     return false;
   }
 
   // Implicit in the spec: Create the new strategy object.
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(
+          cx, args, JSProto_ByteLengthQueuingStrategy, &proto)) {
     return false;
   }
   RootedObject strategy(
       cx, NewObjectWithClassProto<ByteLengthQueuingStrategy>(cx, proto));
   if (!strategy) {
     return false;
   }
 
@@ -3989,17 +3991,18 @@ bool js::CountQueuingStrategy::construct
   CallArgs args = CallArgsFromVp(argc, vp);
 
   if (!ThrowIfNotConstructing(cx, args, "CountQueuingStrategy")) {
     return false;
   }
 
   // Implicit in the spec: Create the new strategy object.
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(
+          cx, args, JSProto_CountQueuingStrategy, &proto)) {
     return false;
   }
   Rooted<CountQueuingStrategy*> strategy(
       cx, NewObjectWithClassProto<CountQueuingStrategy>(cx, proto));
   if (!strategy) {
     return false;
   }
 
--- a/js/src/builtin/String.cpp
+++ b/js/src/builtin/String.cpp
@@ -3421,17 +3421,17 @@ bool js::StringConstructor(JSContext* cx
       return false;
     }
   } else {
     str = cx->runtime()->emptyString;
   }
 
   if (args.isConstructing()) {
     RootedObject proto(cx);
-    if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+    if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_String, &proto)) {
       return false;
     }
 
     StringObject* strobj = StringObject::create(cx, str, proto);
     if (!strobj) {
       return false;
     }
     args.rval().setObject(*strobj);
--- a/js/src/builtin/WeakMapObject.cpp
+++ b/js/src/builtin/WeakMapObject.cpp
@@ -222,17 +222,17 @@ JS_PUBLIC_API bool JS::SetWeakMapEntry(J
   CallArgs args = CallArgsFromVp(argc, vp);
 
   // ES6 draft rev 31 (15 Jan 2015) 23.3.1.1 step 1.
   if (!ThrowIfNotConstructing(cx, args, "WeakMap")) {
     return false;
   }
 
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_WeakMap, &proto)) {
     return false;
   }
 
   RootedObject obj(cx, NewObjectWithClassProto<WeakMapObject>(cx, proto));
   if (!obj) {
     return false;
   }
 
--- a/js/src/builtin/WeakSetObject.cpp
+++ b/js/src/builtin/WeakSetObject.cpp
@@ -167,17 +167,17 @@ bool WeakSetObject::construct(JSContext*
   // Based on our "Set" implementation instead of the more general ES6 steps.
   CallArgs args = CallArgsFromVp(argc, vp);
 
   if (!ThrowIfNotConstructing(cx, args, "WeakSet")) {
     return false;
   }
 
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_WeakSet, &proto)) {
     return false;
   }
 
   Rooted<WeakSetObject*> obj(cx, WeakSetObject::create(cx, proto));
   if (!obj) {
     return false;
   }
 
--- a/js/src/builtin/intl/Collator.cpp
+++ b/js/src/builtin/intl/Collator.cpp
@@ -76,17 +76,17 @@ static const JSPropertySpec collator_pro
  *
  * ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
  */
 static bool Collator(JSContext* cx, const CallArgs& args) {
   // Step 1 (Handled by OrdinaryCreateFromConstructor fallback code).
 
   // Steps 2-5 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
     return false;
   }
 
   if (!proto) {
     proto = GlobalObject::getOrCreateCollatorPrototype(cx, cx->global());
     if (!proto) {
       return false;
     }
--- a/js/src/builtin/intl/DateTimeFormat.cpp
+++ b/js/src/builtin/intl/DateTimeFormat.cpp
@@ -87,17 +87,17 @@ static const JSPropertySpec dateTimeForm
  * ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
  */
 static bool DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct,
                            DateTimeFormatOptions dtfOptions) {
   // Step 1 (Handled by OrdinaryCreateFromConstructor fallback code).
 
   // Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
     return false;
   }
 
   if (!proto) {
     proto = GlobalObject::getOrCreateDateTimeFormatPrototype(cx, cx->global());
     if (!proto) {
       return false;
     }
--- a/js/src/builtin/intl/NumberFormat.cpp
+++ b/js/src/builtin/intl/NumberFormat.cpp
@@ -86,17 +86,17 @@ static const JSPropertySpec numberFormat
  *
  * ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
  */
 static bool NumberFormat(JSContext* cx, const CallArgs& args, bool construct) {
   // Step 1 (Handled by OrdinaryCreateFromConstructor fallback code).
 
   // Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
     return false;
   }
 
   if (!proto) {
     proto = GlobalObject::getOrCreateNumberFormatPrototype(cx, cx->global());
     if (!proto) {
       return false;
     }
--- a/js/src/builtin/intl/PluralRules.cpp
+++ b/js/src/builtin/intl/PluralRules.cpp
@@ -72,17 +72,17 @@ static bool PluralRules(JSContext* cx, u
 
   // Step 1.
   if (!ThrowIfNotConstructing(cx, args, "Intl.PluralRules")) {
     return false;
   }
 
   // Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
     return false;
   }
 
   if (!proto) {
     proto = GlobalObject::getOrCreatePluralRulesPrototype(cx, cx->global());
     if (!proto) {
       return false;
     }
--- a/js/src/builtin/intl/RelativeTimeFormat.cpp
+++ b/js/src/builtin/intl/RelativeTimeFormat.cpp
@@ -78,17 +78,17 @@ static bool RelativeTimeFormat(JSContext
 
   // Step 1.
   if (!ThrowIfNotConstructing(cx, args, "Intl.RelativeTimeFormat")) {
     return false;
   }
 
   // Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
     return false;
   }
 
   if (!proto) {
     proto =
         GlobalObject::getOrCreateRelativeTimeFormatPrototype(cx, cx->global());
     if (!proto) {
       return false;
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -3131,17 +3131,17 @@ static const JSFunctionSpec date_methods
     JS_FN(js_valueOf_str, date_valueOf, 0, 0),
     JS_SYM_FN(toPrimitive, date_toPrimitive, 1, JSPROP_READONLY),
     JS_FS_END};
 
 static bool NewDateObject(JSContext* cx, const CallArgs& args, ClippedTime t) {
   MOZ_ASSERT(args.isConstructing());
 
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Date, &proto)) {
     return false;
   }
 
   JSObject* obj = NewDateObjectMsec(cx, t, proto);
   if (!obj) {
     return false;
   }
 
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -383,75 +383,74 @@ JS_PUBLIC_API uint64_t JS::ExceptionTime
   }
 
   return obj->as<ErrorObject>().timeWarpTarget();
 }
 
 bool Error(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
+  // ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
+  // called as functions, without operator new.  But as we do not give
+  // each constructor a distinct JSClass, we must get the exception type
+  // ourselves.
+  JSExnType exnType =
+      JSExnType(args.callee().as<JSFunction>().getExtendedSlot(0).toInt32());
+
+  JSProtoKey protoKey =
+      JSCLASS_CACHED_PROTO_KEY(&ErrorObject::classes[exnType]);
+
   // ES6 19.5.1.1 mandates the .prototype lookup happens before the toString
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, protoKey, &proto)) {
     return false;
   }
 
-  /* Compute the error message, if any. */
+  // Compute the error message, if any.
   RootedString message(cx, nullptr);
   if (args.hasDefined(0)) {
     message = ToString<CanGC>(cx, args[0]);
     if (!message) {
       return false;
     }
   }
 
-  /* Find the scripted caller, but only ones we're allowed to know about. */
+  // Find the scripted caller, but only ones we're allowed to know about.
   NonBuiltinFrameIter iter(cx, cx->realm()->principals());
 
-  /* Set the 'fileName' property. */
   RootedString fileName(cx);
   if (args.length() > 1) {
     fileName = ToString<CanGC>(cx, args[1]);
   } else {
     fileName = cx->runtime()->emptyString;
     if (!iter.done()) {
       if (const char* cfilename = iter.filename()) {
         fileName = JS_NewStringCopyZ(cx, cfilename);
       }
     }
   }
   if (!fileName) {
     return false;
   }
 
-  /* Set the 'lineNumber' property. */
   uint32_t lineNumber, columnNumber = 0;
   if (args.length() > 2) {
     if (!ToUint32(cx, args[2], &lineNumber)) {
       return false;
     }
   } else {
     lineNumber = iter.done() ? 0 : iter.computeLine(&columnNumber);
     columnNumber = FixupColumnForDisplay(columnNumber);
   }
 
   RootedObject stack(cx);
   if (!CaptureStack(cx, &stack)) {
     return false;
   }
 
-  /*
-   * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
-   * called as functions, without operator new.  But as we do not give
-   * each constructor a distinct JSClass, we must get the exception type
-   * ourselves.
-   */
-  JSExnType exnType =
-      JSExnType(args.callee().as<JSFunction>().getExtendedSlot(0).toInt32());
-
   RootedObject obj(cx,
                    ErrorObject::create(cx, exnType, stack, fileName, lineNumber,
                                        columnNumber, nullptr, message, proto));
   if (!obj) {
     return false;
   }
 
   args.rval().setObject(*obj);
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -558,17 +558,17 @@ static bool Number(JSContext* cx, unsign
       args.rval().set(args[0]);
     } else {
       args.rval().setInt32(0);
     }
     return true;
   }
 
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Number, &proto)) {
     return false;
   }
 
   double d = args.length() > 0 ? args[0].toNumber() : 0;
   JSObject* obj = NumberObject::create(cx, d, proto);
   if (!obj) {
     return false;
   }
--- a/js/src/tests/jstests.list
+++ b/js/src/tests/jstests.list
@@ -261,22 +261,22 @@ skip script test262/built-ins/Proxy/revo
 skip script test262/built-ins/Promise/all/resolve-element-function-name.js
 skip script test262/built-ins/Promise/executor-function-name.js
 skip script test262/built-ins/Promise/reject-function-name.js
 skip script test262/built-ins/Promise/resolve-function-name.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=944846
 skip script test262/built-ins/Number/prototype/toExponential/return-values.js
 
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1225839
+skip script test262/built-ins/Function/internals/Call/class-ctor-realm.js
+
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1288457
 skip script test262/built-ins/Function/internals/Construct/base-ctor-revoked-proxy-realm.js
 
-# https://bugzilla.mozilla.org/show_bug.cgi?id=1225839
-skip script test262/built-ins/Function/internals/Call/class-ctor-realm.js
-
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1297179
 skip script test262/built-ins/Proxy/apply/arguments-realm.js
 skip script test262/built-ins/Proxy/apply/trap-is-not-callable-realm.js
 skip script test262/built-ins/Proxy/construct/arguments-realm.js
 skip script test262/built-ins/Proxy/construct/trap-is-not-callable-realm.js
 skip script test262/built-ins/Proxy/defineProperty/desc-realm.js
 skip script test262/built-ins/Proxy/defineProperty/null-handler-realm.js
 skip script test262/built-ins/Proxy/defineProperty/targetdesc-configurable-desc-not-configurable-realm.js
@@ -293,61 +293,25 @@ skip script test262/built-ins/Proxy/getP
 skip script test262/built-ins/Proxy/has/trap-is-not-callable-realm.js
 skip script test262/built-ins/Proxy/isExtensible/trap-is-not-callable-realm.js
 skip script test262/built-ins/Proxy/ownKeys/return-not-list-object-throws-realm.js
 skip script test262/built-ins/Proxy/ownKeys/trap-is-not-callable-realm.js
 skip script test262/built-ins/Proxy/preventExtensions/trap-is-not-callable-realm.js
 skip script test262/built-ins/Proxy/set/trap-is-not-callable-realm.js
 skip script test262/built-ins/Proxy/setPrototypeOf/trap-is-not-callable-realm.js
 
-# Erros thrown from wrong realm, similar to 1225839, 1288457, and 1297179.
+# Errors thrown from wrong realm, similar to 1225839, 1288457, and 1297179.
 skip script test262/built-ins/Array/length/define-own-prop-length-overflow-realm.js
 skip script test262/built-ins/Function/internals/Construct/derived-return-val-realm.js
 skip script test262/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1317416
 skip script test262/language/expressions/super/realm.js
-skip script test262/built-ins/Array/proto-from-ctor-realm.js
-skip script test262/built-ins/ArrayBuffer/proto-from-ctor-realm.js
-skip script test262/built-ins/Boolean/proto-from-ctor-realm.js
-skip script test262/built-ins/DataView/proto-from-ctor-realm.js
-skip script test262/built-ins/DataView/proto-from-ctor-realm-sab.js
-skip script test262/built-ins/Date/proto-from-ctor-realm-one.js
-skip script test262/built-ins/Date/proto-from-ctor-realm-two.js
-skip script test262/built-ins/Date/proto-from-ctor-realm-zero.js
-skip script test262/built-ins/Error/proto-from-ctor-realm.js
+skip script test262/built-ins/GeneratorFunction/proto-from-ctor-realm.js
 skip script test262/built-ins/Function/prototype/bind/proto-from-ctor-realm.js
-skip script test262/built-ins/Function/proto-from-ctor-realm.js
-skip script test262/built-ins/GeneratorFunction/proto-from-ctor-realm.js
-skip script test262/built-ins/Map/proto-from-ctor-realm.js
-skip script test262/built-ins/Number/proto-from-ctor-realm.js
-skip script test262/built-ins/Object/proto-from-ctor.js
-skip script test262/built-ins/Promise/proto-from-ctor-realm.js
-skip script test262/built-ins/RegExp/proto-from-ctor-realm.js
-skip script test262/built-ins/Set/proto-from-ctor-realm.js
-skip script test262/built-ins/SharedArrayBuffer/proto-from-ctor-realm.js
-skip script test262/built-ins/String/proto-from-ctor-realm.js
-skip script test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/proto-from-ctor-realm.js
-skip script test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/proto-from-ctor-realm-sab.js
-skip script test262/built-ins/TypedArrayConstructors/ctors-bigint/length-arg/proto-from-ctor-realm.js
-skip script test262/built-ins/TypedArrayConstructors/ctors-bigint/no-args/proto-from-ctor-realm.js
-skip script test262/built-ins/TypedArrayConstructors/ctors-bigint/object-arg/proto-from-ctor-realm.js
-skip script test262/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-custom-species-proto-from-ctor-realm.js
-skip script test262/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/proto-from-ctor-realm.js
-skip script test262/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-custom-proto-from-ctor-realm.js
-skip script test262/built-ins/TypedArrayConstructors/ctors/buffer-arg/proto-from-ctor-realm.js
-skip script test262/built-ins/TypedArrayConstructors/ctors/buffer-arg/proto-from-ctor-realm-sab.js
-skip script test262/built-ins/TypedArrayConstructors/ctors/length-arg/proto-from-ctor-realm.js
-skip script test262/built-ins/TypedArrayConstructors/ctors/no-args/proto-from-ctor-realm.js
-skip script test262/built-ins/TypedArrayConstructors/ctors/object-arg/proto-from-ctor-realm.js
-skip script test262/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-custom-species-proto-from-ctor-realm.js
-skip script test262/built-ins/TypedArrayConstructors/ctors/typedarray-arg/proto-from-ctor-realm.js
-skip script test262/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-custom-proto-from-ctor-realm.js
-skip script test262/built-ins/WeakMap/proto-from-ctor-realm.js
-skip script test262/built-ins/WeakSet/proto-from-ctor-realm.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1317395
 skip script test262/built-ins/ArrayBuffer/prototype/byteLength/detached-buffer.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1317378
 skip script test262/language/statements/do-while/cptn-abrupt-empty.js
 skip script test262/language/statements/do-while/cptn-normal.js
 skip script test262/language/statements/for-in/cptn-decl-abrupt-empty.js
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -414,17 +414,18 @@ bool ArrayBufferObject::class_constructo
   uint64_t byteLength;
   if (!ToIndex(cx, args.get(0), &byteLength)) {
     return false;
   }
 
   // Step 3 (Inlined 24.1.1.1 AllocateArrayBuffer).
   // 24.1.1.1, step 1 (Inlined 9.1.14 OrdinaryCreateFromConstructor).
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_ArrayBuffer,
+                                          &proto)) {
     return false;
   }
 
   // 24.1.1.1, step 3 (Inlined 6.2.6.1 CreateByteDataBlock, step 2).
   // Refuse to allocate too large buffers, currently limited to ~2 GiB.
   if (byteLength > INT32_MAX) {
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                               JSMSG_BAD_ARRAY_LENGTH);
--- a/js/src/vm/JSFunction.cpp
+++ b/js/src/vm/JSFunction.cpp
@@ -1994,16 +1994,17 @@ static bool CreateDynamicFunction(JSCont
   SourceOwnership ownership = stableChars.maybeGiveOwnershipToCaller()
                                   ? SourceOwnership::TakeOwnership
                                   : SourceOwnership::Borrowed;
   SourceText<char16_t> srcBuf;
   if (!srcBuf.init(cx, chars.begin().get(), chars.length(), ownership)) {
     return false;
   }
 
+  JSProtoKey protoKey = JSProto_Null;
   if (isAsync) {
     if (isGenerator) {
       if (!CompileStandaloneAsyncGenerator(cx, &fun, options, srcBuf,
                                            parameterListEnd)) {
         return false;
       }
     } else {
       if (!CompileStandaloneAsyncFunction(cx, &fun, options, srcBuf,
@@ -2017,22 +2018,23 @@ static bool CreateDynamicFunction(JSCont
                                       parameterListEnd)) {
         return false;
       }
     } else {
       if (!CompileStandaloneFunction(cx, &fun, options, srcBuf,
                                      parameterListEnd)) {
         return false;
       }
+      protoKey = JSProto_Function;
     }
   }
 
   // Steps 6, 29.
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, protoKey, &proto)) {
     return false;
   }
 
   if (isAsync) {
     // Create the async function wrapper.
     JSObject* wrapped;
     if (isGenerator) {
       wrapped = proto ? WrapAsyncGeneratorWithProto(cx, fun, proto)
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -1021,17 +1021,18 @@ bool js::NewObjectScriptedCall(JSContext
 
   pobj.set(obj);
   return true;
 }
 
 JSObject* js::CreateThis(JSContext* cx, const Class* newclasp,
                          HandleObject callee) {
   RootedObject proto(cx);
-  if (!GetPrototypeFromConstructor(cx, callee, &proto)) {
+  if (!GetPrototypeFromConstructor(
+          cx, callee, JSCLASS_CACHED_PROTO_KEY(newclasp), &proto)) {
     return nullptr;
   }
   gc::AllocKind kind = NewObjectGCKind(newclasp);
   return NewObjectWithClassProto(cx, newclasp, proto, kind);
 }
 
 static inline JSObject* CreateThisForFunctionWithGroup(JSContext* cx,
                                                        HandleObjectGroup group,
@@ -1153,30 +1154,63 @@ JSObject* js::CreateThisForFunctionWithP
     }
     TypeScript::SetThis(cx, script, TypeSet::ObjectType(res));
   }
 
   return res;
 }
 
 bool js::GetPrototypeFromConstructor(JSContext* cx, HandleObject newTarget,
+                                     JSProtoKey intrinsicDefaultProto,
                                      MutableHandleObject proto) {
   RootedValue protov(cx);
   if (!GetProperty(cx, newTarget, newTarget, cx->names().prototype, &protov)) {
     return false;
   }
-  proto.set(protov.isObject() ? &protov.toObject() : nullptr);
+  if (protov.isObject()) {
+    proto.set(&protov.toObject());
+  } else if (newTarget->is<JSFunction>() &&
+             newTarget->as<JSFunction>().realm() == cx->realm()) {
+    // Steps 4.a-b fetch the builtin prototype of the current realm, which we
+    // represent as nullptr.
+    proto.set(nullptr);
+  } else if (intrinsicDefaultProto == JSProto_Null) {
+    // Bug 1317416. The caller did not pass a reasonable JSProtoKey, so let the
+    // caller select a prototype object. Most likely they will choose one from
+    // the wrong realm.
+    proto.set(nullptr);
+  } else {
+    // Step 4.a: Let realm be ? GetFunctionRealm(constructor);
+    JSObject* unwrappedConstructor = CheckedUnwrap(newTarget);
+    if (!unwrappedConstructor) {
+      ReportAccessDenied(cx);
+      return false;
+    }
+
+    // Step 4.b: Set proto to realm's intrinsic object named
+    //           intrinsicDefaultProto.
+    {
+      AutoRealm ar(cx, unwrappedConstructor);
+      proto.set(GlobalObject::getOrCreatePrototype(cx, intrinsicDefaultProto));
+    }
+    if (!proto) {
+      return false;
+    }
+    if (!cx->compartment()->wrap(cx, proto)) {
+      return false;
+    }
+  }
   return true;
 }
 
 JSObject* js::CreateThisForFunction(JSContext* cx, HandleObject callee,
                                     HandleObject newTarget,
                                     NewObjectKind newKind) {
   RootedObject proto(cx);
-  if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) {
+  if (!GetPrototypeFromConstructor(cx, newTarget, JSProto_Null, &proto)) {
     return nullptr;
   }
 
   JSObject* obj =
       CreateThisForFunctionWithProto(cx, callee, newTarget, proto, newKind);
 
   if (obj && newKind == SingletonObject) {
     RootedPlainObject nobj(cx, &obj->as<PlainObject>());
@@ -3674,16 +3708,20 @@ static void DumpProperty(const NativeObj
 
   if (shape.isDataProperty()) {
     out.printf(" slot %d", shape.maybeSlot());
   }
 
   out.printf(")\n");
 }
 
+bool JSObject::hasSameRealmAs(JSContext* cx) const {
+  return nonCCWRealm() == cx->realm();
+}
+
 bool JSObject::uninlinedIsProxy() const { return is<ProxyObject>(); }
 
 bool JSObject::uninlinedNonProxyIsExtensible() const {
   return nonProxyIsExtensible();
 }
 
 void JSObject::dump(js::GenericPrinter& out) const {
   const JSObject* obj = this;
--- a/js/src/vm/JSObject.h
+++ b/js/src/vm/JSObject.h
@@ -430,16 +430,17 @@ class JSObject : public js::gc::Cell {
   // Cross-compartment wrappers are not associated with a single realm/global,
   // so these methods assert the object is not a CCW.
   inline js::GlobalObject& nonCCWGlobal() const;
 
   JS::Realm* nonCCWRealm() const {
     MOZ_ASSERT(!js::UninlinedIsCrossCompartmentWrapper(this));
     return group_->realm();
   }
+  bool hasSameRealmAs(JSContext* cx) const;
 
   // Returns the object's realm even if the object is a CCW (be careful, in
   // this case the realm is not very meaningful because wrappers are shared by
   // all realms in the compartment).
   JS::Realm* maybeCCWRealm() const { return group_->realm(); }
 
   /*
    * ES5 meta-object properties and operations.
@@ -788,32 +789,54 @@ inline gc::InitialHeap GetInitialHeap(Ne
 bool NewObjectWithTaggedProtoIsCachable(JSContext* cx,
                                         Handle<TaggedProto> proto,
                                         NewObjectKind newKind,
                                         const Class* clasp);
 
 // ES6 9.1.15 GetPrototypeFromConstructor.
 extern bool GetPrototypeFromConstructor(JSContext* cx,
                                         js::HandleObject newTarget,
+                                        JSProtoKey intrinsicDefaultProto,
                                         js::MutableHandleObject proto);
 
+// https://tc39.github.io/ecma262/#sec-getprototypefromconstructor
+//
+// Determine which [[Prototype]] to use when creating a new object using a
+// builtin constructor.
+//
+// This sets `proto` to `nullptr` to mean "the builtin prototype object for
+// this type in the current realm", the common case.
+//
+// We could set it to `cx->global()->getOrCreatePrototype(protoKey)`, but
+// nullptr gets a fast path in e.g. js::NewObjectWithClassProtoCommon.
+//
+// intrinsicDefaultProto can be JSProto_Null if there's no appropriate
+// JSProtoKey enum; but we then select the wrong prototype object in a
+// multi-realm corner case (see bug 1515167).
 MOZ_ALWAYS_INLINE bool GetPrototypeFromBuiltinConstructor(
-    JSContext* cx, const CallArgs& args, js::MutableHandleObject proto) {
-  // When proto is set to nullptr, the caller is expected to select the
-  // correct default built-in prototype for this constructor.
+    JSContext* cx, const CallArgs& args, JSProtoKey intrinsicDefaultProto,
+    js::MutableHandleObject proto) {
+  // We can skip the "prototype" lookup in the two common cases:
+  // 1.  Builtin constructor called without `new`, as in `obj = Object();`.
+  // 2.  Builtin constructor called with `new`, as in `obj = new Object();`.
+  //
+  // Cases that can't take the fast path include `new MySubclassOfObject()`,
+  // `new otherGlobal.Object()`, and `Reflect.construct(Object, [], Date)`.
   if (!args.isConstructing() ||
       &args.newTarget().toObject() == &args.callee()) {
+    MOZ_ASSERT(args.callee().hasSameRealmAs(cx));
     proto.set(nullptr);
     return true;
   }
 
   // We're calling this constructor from a derived class, retrieve the
   // actual prototype from newTarget.
   RootedObject newTarget(cx, &args.newTarget().toObject());
-  return GetPrototypeFromConstructor(cx, newTarget, proto);
+  return GetPrototypeFromConstructor(cx, newTarget, intrinsicDefaultProto,
+                                     proto);
 }
 
 // Specialized call for constructing |this| with a known function callee,
 // and a known prototype.
 extern JSObject* CreateThisForFunctionWithProto(
     JSContext* cx, js::HandleObject callee, HandleObject newTarget,
     HandleObject proto, NewObjectKind newKind = GenericObject);
 
--- a/js/src/vm/SharedArrayObject.cpp
+++ b/js/src/vm/SharedArrayObject.cpp
@@ -193,17 +193,18 @@ bool SharedArrayBufferObject::class_cons
   uint64_t byteLength;
   if (!ToIndex(cx, args.get(0), &byteLength)) {
     return false;
   }
 
   // Step 3 (Inlined 24.2.1.1 AllocateSharedArrayBuffer).
   // 24.2.1.1, step 1 (Inlined 9.1.14 OrdinaryCreateFromConstructor).
   RootedObject proto(cx);
-  if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_SharedArrayBuffer,
+                                          &proto)) {
     return false;
   }
 
   // 24.2.1.1, step 3 (Inlined 6.2.7.2 CreateSharedByteDataBlock, step 2).
   // Refuse to allocate too large buffers, currently limited to ~2 GiB.
   if (byteLength > INT32_MAX) {
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                               JSMSG_SHARED_ARRAY_BAD_LENGTH);
--- a/js/src/vm/TypedArrayObject-inl.h
+++ b/js/src/vm/TypedArrayObject-inl.h
@@ -116,48 +116,57 @@ inline To ConvertNumber(From src) {
   return To(src);
 }
 
 template <typename NativeType>
 struct TypeIDOfType;
 template <>
 struct TypeIDOfType<int8_t> {
   static const Scalar::Type id = Scalar::Int8;
+  static const JSProtoKey protoKey = JSProto_Int8Array;
 };
 template <>
 struct TypeIDOfType<uint8_t> {
   static const Scalar::Type id = Scalar::Uint8;
+  static const JSProtoKey protoKey = JSProto_Uint8Array;
 };
 template <>
 struct TypeIDOfType<int16_t> {
   static const Scalar::Type id = Scalar::Int16;
+  static const JSProtoKey protoKey = JSProto_Int16Array;
 };
 template <>
 struct TypeIDOfType<uint16_t> {
   static const Scalar::Type id = Scalar::Uint16;
+  static const JSProtoKey protoKey = JSProto_Uint16Array;
 };
 template <>
 struct TypeIDOfType<int32_t> {
   static const Scalar::Type id = Scalar::Int32;
+  static const JSProtoKey protoKey = JSProto_Int32Array;
 };
 template <>
 struct TypeIDOfType<uint32_t> {
   static const Scalar::Type id = Scalar::Uint32;
+  static const JSProtoKey protoKey = JSProto_Uint32Array;
 };
 template <>
 struct TypeIDOfType<float> {
   static const Scalar::Type id = Scalar::Float32;
+  static const JSProtoKey protoKey = JSProto_Float32Array;
 };
 template <>
 struct TypeIDOfType<double> {
   static const Scalar::Type id = Scalar::Float64;
+  static const JSProtoKey protoKey = JSProto_Float64Array;
 };
 template <>
 struct TypeIDOfType<uint8_clamped> {
   static const Scalar::Type id = Scalar::Uint8Clamped;
+  static const JSProtoKey protoKey = JSProto_Uint8ClampedArray;
 };
 
 class SharedOps {
  public:
   template <typename T>
   static T load(SharedMem<T*> addr) {
     return js::jit::AtomicOperations::loadSafeWhenRacy(addr);
   }
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -280,16 +280,20 @@ enum class CreateSingleton { No, Yes };
 template <typename NativeType>
 class TypedArrayObjectTemplate : public TypedArrayObject {
   friend class TypedArrayObject;
 
  public:
   static constexpr Scalar::Type ArrayTypeID() {
     return TypeIDOfType<NativeType>::id;
   }
+  static constexpr JSProtoKey protoKey() {
+    return TypeIDOfType<NativeType>::protoKey;
+  }
+
   static constexpr bool ArrayTypeIsUnsigned() {
     return TypeIsUnsigned<NativeType>();
   }
   static constexpr bool ArrayTypeIsFloatingPoint() {
     return TypeIsFloatingPoint<NativeType>();
   }
 
   static constexpr size_t BYTES_PER_ELEMENT = sizeof(NativeType);
@@ -591,29 +595,29 @@ class TypedArrayObjectTemplate : public 
       uint64_t len;
       if (!ToIndex(cx, args.get(0), JSMSG_BAD_ARRAY_LENGTH, &len)) {
         return nullptr;
       }
 
       // 22.2.4.1, step 3 and 22.2.4.2, step 5.
       // 22.2.4.2.1 AllocateTypedArray, step 1.
       RootedObject proto(cx);
-      if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+      if (!GetPrototypeFromBuiltinConstructor(cx, args, protoKey(), &proto)) {
         return nullptr;
       }
 
       return fromLength(cx, len, proto);
     }
 
     RootedObject dataObj(cx, &args[0].toObject());
 
     // 22.2.4.{3,4,5}, step 4.
     // 22.2.4.2.1 AllocateTypedArray, step 1.
     RootedObject proto(cx);
-    if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
+    if (!GetPrototypeFromBuiltinConstructor(cx, args, protoKey(), &proto)) {
       return nullptr;
     }
 
     // 22.2.4.3 TypedArray ( typedArray )
     // 22.2.4.4 TypedArray ( object )
     if (!UncheckedUnwrap(dataObj)->is<ArrayBufferObjectMaybeShared>()) {
       return fromArray(cx, dataObj, proto);
     }
@@ -952,30 +956,19 @@ template <typename T>
       GlobalObject::getOrCreateArrayBufferConstructor(cx, cx->global());
   if (!arrayBufferCtor) {
     return false;
   }
 
   // As an optimization, skip the "prototype" lookup for %ArrayBuffer%.
   if (ctor != arrayBufferCtor) {
     // 9.1.13 OrdinaryCreateFromConstructor, steps 1-2.
-    if (!GetPrototypeFromConstructor(cx, ctor, &proto)) {
+    if (!GetPrototypeFromConstructor(cx, ctor, JSProto_ArrayBuffer, &proto)) {
       return false;
     }
-
-    JSObject* arrayBufferProto =
-        GlobalObject::getOrCreateArrayBufferPrototype(cx, cx->global());
-    if (!arrayBufferProto) {
-      return false;
-    }
-
-    // Reset |proto| if it's the default %ArrayBufferPrototype%.
-    if (proto == arrayBufferProto) {
-      proto = nullptr;
-    }
   }
 
   // 24.1.1.1 steps 1 (remaining part), 2-6.
   if (!maybeCreateArrayBuffer(cx, count, proto, buffer)) {
     return false;
   }
 
   return true;