Bug 1232022 - Part 2: Implement JSOP_DEBUGCHECKSELFHOSTED, and use it to check self-hosted callFunction()s. (r=till, r=h4writer)
authorEric Faust <efaustbmo@gmail.com>
Wed, 16 Dec 2015 08:14:41 -0800
changeset 315833 cdc3315bff369dfdd6b71bc638cd3e1ed5e6e388
parent 315832 a91d3c32c0ef17f45e27fd88e0115ce9be40920f
child 315834 e2d7e9400d746483a0ee3dabf665e899f244bc1b
push id8468
push userhurley@todesschaf.org
push dateWed, 16 Dec 2015 19:25:06 +0000
reviewerstill, h4writer
bugs1232022
milestone46.0a1
Bug 1232022 - Part 2: Implement JSOP_DEBUGCHECKSELFHOSTED, and use it to check self-hosted callFunction()s. (r=till, r=h4writer)
js/src/builtin/Array.js
js/src/builtin/Iterator.js
js/src/builtin/Map.js
js/src/builtin/Object.js
js/src/builtin/Set.js
js/src/builtin/TypedArray.js
js/src/builtin/Utilities.js
js/src/frontend/BytecodeEmitter.cpp
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineCompiler.h
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/IonBuilder.cpp
js/src/jit/Lowering.cpp
js/src/jit/Lowering.h
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/shared/LIR-shared.h
js/src/jit/shared/LOpcodes-shared.h
js/src/js.msg
js/src/vm/CommonPropertyNames.h
js/src/vm/Interpreter.cpp
js/src/vm/Interpreter.h
js/src/vm/Opcodes.h
js/src/vm/Xdr.h
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -131,17 +131,17 @@ function ArrayEvery(callbackfn/*, thisAr
     var T = arguments.length > 1 ? arguments[1] : void 0;
 
     /* Steps 6-7. */
     /* Steps a (implicit), and d. */
     for (var k = 0; k < len; k++) {
         /* Step b */
         if (k in O) {
             /* Step c. */
-            if (!callFunction(callbackfn, T, O[k], k, O))
+            if (!callContentFunction(callbackfn, T, O[k], k, O))
                 return false;
         }
     }
 
     /* Step 8. */
     return true;
 }
 
@@ -172,17 +172,17 @@ function ArraySome(callbackfn/*, thisArg
     var T = arguments.length > 1 ? arguments[1] : void 0;
 
     /* Steps 6-7. */
     /* Steps a (implicit), and d. */
     for (var k = 0; k < len; k++) {
         /* Step b */
         if (k in O) {
             /* Step c. */
-            if (callFunction(callbackfn, T, O[k], k, O))
+            if (callContentFunction(callbackfn, T, O[k], k, O))
                 return true;
         }
     }
 
     /* Step 8. */
     return false;
 }
 
@@ -213,17 +213,17 @@ function ArrayForEach(callbackfn/*, this
     var T = arguments.length > 1 ? arguments[1] : void 0;
 
     /* Steps 6-7. */
     /* Steps a (implicit), and d. */
     for (var k = 0; k < len; k++) {
         /* Step b */
         if (k in O) {
             /* Step c. */
-            callFunction(callbackfn, T, O[k], k, O);
+            callContentFunction(callbackfn, T, O[k], k, O);
         }
     }
 
     /* Step 8. */
     return void 0;
 }
 
 function ArrayStaticForEach(list, callbackfn/*, thisArg*/) {
@@ -256,17 +256,17 @@ function ArrayMap(callbackfn/*, thisArg*
     var A = std_Array(len);
 
     /* Step 7-8. */
     /* Step a (implicit), and d. */
     for (var k = 0; k < len; k++) {
         /* Step b */
         if (k in O) {
             /* Step c.i-iii. */
-            var mappedValue = callFunction(callbackfn, T, O[k], k, O);
+            var mappedValue = callContentFunction(callbackfn, T, O[k], k, O);
             _DefineDataProperty(A, k, mappedValue);
         }
     }
 
     /* Step 9. */
     return A;
 }
 
@@ -302,17 +302,17 @@ function ArrayFilter(callbackfn/*, thisA
     /* Steps 8-11. */
     /* Steps 11.a (implicit), and 11.e. */
     for (var k = 0, to = 0; k < len; k++) {
         /* Steps 11.b-c. */
         if (k in O) {
             /* Steps 11.c.i-ii. */
             var kValue = O[k];
             /* Steps 11.c.iii-iv. */
-            var selected = callFunction(callbackfn, T, kValue, k, O);
+            var selected = callContentFunction(callbackfn, T, kValue, k, O);
             /* Step 11.c.v. */
             if (selected)
                 _DefineDataProperty(A, to++, kValue);
         }
     }
 
     /* Step 12. */
     return A;
@@ -484,17 +484,17 @@ function ArrayFind(predicate/*, thisArg*
      * imprecision for large values. Example:
      * var obj = { 18014398509481984: true, length: 18014398509481988 };
      * Array.prototype.find.call(obj, () => true);
      */
     for (var k = 0; k < len; k++) {
         /* Steps a-c. */
         var kValue = O[k];
         /* Steps d-f. */
-        if (callFunction(predicate, T, kValue, k, O))
+        if (callContentFunction(predicate, T, kValue, k, O))
             return kValue;
     }
 
     /* Step 10. */
     return undefined;
 }
 
 /* ES6 draft 2013-05-14 15.4.3.23. */
@@ -518,17 +518,17 @@ function ArrayFindIndex(predicate/*, thi
     /* Steps a (implicit), and g. */
     /* Note: this will hang in some corner-case situations, because of IEEE-754 numbers'
      * imprecision for large values. Example:
      * var obj = { 18014398509481984: true, length: 18014398509481988 };
      * Array.prototype.find.call(obj, () => true);
      */
     for (var k = 0; k < len; k++) {
         /* Steps a-f. */
-        if (callFunction(predicate, T, O[k], k, O))
+        if (callContentFunction(predicate, T, O[k], k, O))
             return k;
     }
 
     /* Step 10. */
     return -1;
 }
 
 /* ES6 draft 2013-09-27 22.1.3.3. */
@@ -766,31 +766,31 @@ function ArrayFrom(items, mapfn=undefine
         // Step 6.f.
         var k = 0;
 
         // Step 6.g.
         // These steps cannot be implemented using a for-of loop.
         // See <https://bugs.ecmascript.org/show_bug.cgi?id=2883>.
         while (true) {
             // Steps 6.g.i-iii.
-            var next = callFunction(iterator.next, iterator);
+            var next = callContentFunction(iterator.next, iterator);
             if (!IsObject(next))
                 ThrowTypeError(JSMSG_NEXT_RETURNED_PRIMITIVE);
 
             // Step 6.g.iv.
             if (next.done) {
                 A.length = k;
                 return A;
             }
 
             // Steps 6.g.v-vi.
             var nextValue = next.value;
 
             // Steps 6.g.vii-viii.
-            var mappedValue = mapping ? callFunction(mapfn, thisArg, nextValue, k) : nextValue;
+            var mappedValue = mapping ? callContentFunction(mapfn, thisArg, nextValue, k) : nextValue;
 
             // Steps 6.g.ix-xi.
             _DefineDataProperty(A, k++, mappedValue);
         }
     }
 
     // Step 7.
     assert(usingIterator === undefined, "`items` can't be an Iterable after step 6.g.iv");
@@ -805,17 +805,17 @@ function ArrayFrom(items, mapfn=undefine
     var A = IsConstructor(C) ? new C(len) : std_Array(len);
 
     // Steps 15-16.
     for (var k = 0; k < len; k++) {
         // Steps 16.a-c.
         var kValue = items[k];
 
         // Steps 16.d-e.
-        var mappedValue = mapping ? callFunction(mapfn, thisArg, kValue, k) : kValue;
+        var mappedValue = mapping ? callContentFunction(mapfn, thisArg, kValue, k) : kValue;
 
         // Steps 16.f-g.
         _DefineDataProperty(A, k, mappedValue);
     }
 
     // Steps 17-18.
     A.length = len;
 
@@ -829,10 +829,10 @@ function ArrayToString() {
     var array = ToObject(this);
 
     // Steps 3-4.
     var func = array.join;
 
     // Steps 5-6.
     if (!IsCallable(func))
         return callFunction(std_Object_toString, array);
-    return callFunction(func, array);
+    return callContentFunction(func, array);
 }
--- a/js/src/builtin/Iterator.js
+++ b/js/src/builtin/Iterator.js
@@ -6,28 +6,28 @@ function IteratorIdentity() {
     return this;
 }
 
 var LegacyIteratorWrapperMap = new std_WeakMap();
 
 function LegacyIteratorNext(arg) {
     var iter = callFunction(std_WeakMap_get, LegacyIteratorWrapperMap, this);
     try {
-        return { value: callFunction(iter.next, iter, arg), done: false };
+        return { value: callContentFunction(iter.next, iter, arg), done: false };
     } catch (e) {
         if (e instanceof std_StopIteration)
             return { value: undefined, done: true };
         throw e;
     }
 }
 
 function LegacyIteratorThrow(exn) {
     var iter = callFunction(std_WeakMap_get, LegacyIteratorWrapperMap, this);
     try {
-        return { value: callFunction(iter.throw, iter, exn), done: false };
+        return { value: callContentFunction(iter.throw, iter, exn), done: false };
     } catch (e) {
         if (e instanceof std_StopIteration)
             return { value: undefined, done: true };
         throw e;
     }
 }
 
 function LegacyIterator(iter) {
--- a/js/src/builtin/Map.js
+++ b/js/src/builtin/Map.js
@@ -24,17 +24,17 @@ function MapForEach(callbackfn, thisArg 
 
     /* Step 6-8. */
     var entries = callFunction(std_Map_iterator, M);
     while (true) {
         var result = callFunction(std_Map_iterator_next, entries);
         if (result.done)
             break;
         var entry = result.value;
-        callFunction(callbackfn, thisArg, entry[1], entry[0], M);
+        callContentFunction(callbackfn, thisArg, entry[1], entry[0], M);
     }
 }
 
 var iteratorTemp = { mapIterationResultPair : null };
 
 function MapIteratorNext() {
     // Step 1.
     var O = this;
--- a/js/src/builtin/Object.js
+++ b/js/src/builtin/Object.js
@@ -52,17 +52,17 @@ function ObjectIsExtensible(obj) {
 }
 
 /* ES2015 19.1.3.5 Object.prototype.toLocaleString */
 function Object_toLocaleString() {
     // Step 1.
     var O = this;
 
     // Step 2.
-    return callFunction(O.toString, O);
+    return callContentFunction(O.toString, O);
 }
 
 function ObjectDefineSetter(name, setter) {
     var object;
     if (this === null || this === undefined)
         object = global;
     else
         object = ToObject(this);
--- a/js/src/builtin/Set.js
+++ b/js/src/builtin/Set.js
@@ -24,17 +24,17 @@ function SetForEach(callbackfn, thisArg 
 
     /* Step 7-8. */
     var values = callFunction(std_Set_iterator, S);
     while (true) {
         var result = callFunction(std_Set_iterator_next, values);
         if (result.done)
             break;
         var value = result.value;
-        callFunction(callbackfn, thisArg, value, value, S);
+        callContentFunction(callbackfn, thisArg, value, value, S);
     }
 }
 
 // ES6 final draft 23.2.2.2.
 function SetSpecies() {
     // Step 1.
     return this;
 }
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -116,17 +116,17 @@ function TypedArrayEvery(callbackfn, thi
 
     // Steps 8-9.
     // Omit steps 9.a-9.c and the 'if' clause in step 9.d, since there are no holes in typed arrays.
     for (var k = 0; k < len; k++) {
         // Steps 9.d.i-9.d.ii.
         var kValue = O[k];
 
         // Steps 9.d.iii-9.d.iv.
-        var testResult = callFunction(callbackfn, T, kValue, k, O);
+        var testResult = callContentFunction(callbackfn, T, kValue, k, O);
 
         // Step 9.d.v.
         if (!testResult)
             return false;
     }
 
     // Step 10.
     return true;
@@ -207,17 +207,17 @@ function TypedArrayFilter(callbackfn, th
     // Step 12.
     var captured = 0;
 
     // Steps 11, 13 and 13.g.
     for (var k = 0; k < len; k++) {
         // Steps 13.b-c.
         var kValue = O[k];
         // Steps 13.d-e.
-        var selected = ToBoolean(callFunction(callbackfn, T, kValue, k, O));
+        var selected = ToBoolean(callContentFunction(callbackfn, T, kValue, k, O));
         // Step 13.f.
         if (selected) {
             // Step 13.f.i.
             callFunction(std_Array_push, kept, kValue);
             // Step 13.f.ii.
             captured++;
         }
     }
@@ -259,17 +259,17 @@ function TypedArrayFind(predicate, thisA
     var T = thisArg;
 
     // Steps 8-9.
     // Steps a (implicit), and g.
     for (var k = 0; k < len; k++) {
         // Steps a-c.
         var kValue = O[k];
         // Steps d-f.
-        if (callFunction(predicate, T, kValue, k, O))
+        if (callContentFunction(predicate, T, kValue, k, O))
             return kValue;
     }
 
     // Step 10.
     return undefined;
 }
 
 // ES6 draft rev28 (2014/10/14) 22.2.3.11 %TypedArray%.prototype.findIndex(predicate[, thisArg]).
@@ -294,53 +294,53 @@ function TypedArrayFindIndex(predicate, 
 
     // Step 7.
     var T = thisArg;
 
     // Steps 8-9.
     // Steps a (implicit), and g.
     for (var k = 0; k < len; k++) {
         // Steps a-f.
-        if (callFunction(predicate, T, O[k], k, O))
+        if (callContentFunction(predicate, T, O[k], k, O))
             return k;
     }
 
     // Step 10.
     return -1;
 }
 
 // ES6 draft rev31 (2015-01-15) 22.1.3.10 %TypedArray%.prototype.forEach(callbackfn[,thisArg])
 function TypedArrayForEach(callbackfn, thisArg = undefined) {
     // This function is not generic.
     if (!IsObject(this) || !IsTypedArray(this)) {
-	return callFunction(CallTypedArrayMethodIfWrapped, this, callbackfn, thisArg,
-			    "TypedArrayForEach");
+        return callFunction(CallTypedArrayMethodIfWrapped, this, callbackfn, thisArg,
+                            "TypedArrayForEach");
     }
 
     // Step 1-2.
     var O = this;
 
     // Step 3-4.
     var len = TypedArrayLength(O);
 
     // Step 5.
     if (arguments.length === 0)
-	ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'TypedArray.prototype.forEach');
+        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'TypedArray.prototype.forEach');
     if (!IsCallable(callbackfn))
-	ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
+        ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
 
     // Step 6.
     var T = thisArg;
 
     // Step 7-8.
     // Step 7, 8a (implicit) and 8e.
     for (var k = 0; k < len; k++) {
-	// Step 8b-8c are unnecessary since the condition always holds true for TypedArray.
-	// Step 8d.
-	callFunction(callbackfn, T, O[k], k, O);
+        // Step 8b-8c are unnecessary since the condition always holds true for TypedArray.
+        // Step 8d.
+        callContentFunction(callbackfn, T, O[k], k, O);
     }
 
     // Step 9.
     return undefined;
 }
 
 // ES6 draft rev29 (2014/12/06) 22.2.3.13 %TypedArray%.prototype.indexOf(searchElement[, fromIndex]).
 function TypedArrayIndexOf(searchElement, fromIndex = 0) {
@@ -521,17 +521,17 @@ function TypedArrayMap(callbackfn, thisA
     var C = SpeciesConstructor(O, defaultConstructor);
 
     // Steps 10-11.
     var A = new C(len);
 
     // Steps 12, 13.a (implicit) and 13.h.
     for (var k = 0; k < len; k++) {
         // Steps 13.d-e.
-        var mappedValue = callFunction(callbackfn, T, O[k], k, O);
+        var mappedValue = callContentFunction(callbackfn, T, O[k], k, O);
         // Steps 13.f-g.
         A[k] = mappedValue;
     }
 
     // Step 14.
     return A;
 }
 
@@ -562,17 +562,17 @@ function TypedArrayReduce(callbackfn/*, 
 
     // Steps 9-10.
     // Omit some steps, since 'accumulator' should always be O[0] in step 10 for typed arrays.
     var accumulator = arguments.length > 1 ? arguments[1] : O[k++];
 
     // Step 11.
     // Omit steps 11.b-11.c and the 'if' clause in step 11.d, since there are no holes in typed arrays.
     for (; k < len; k++) {
-        accumulator = callFunction(callbackfn, undefined, accumulator, O[k], k, O);
+        accumulator = callContentFunction(callbackfn, undefined, accumulator, O[k], k, O);
     }
 
     // Step 12.
     return accumulator;
 }
 
 // ES6 draft rev30 (2014/12/24) 22.2.3.20 %TypedArray%.prototype.reduceRight(callbackfn[, initialValue]).
 function TypedArrayReduceRight(callbackfn/*, initialValue*/) {
@@ -601,17 +601,17 @@ function TypedArrayReduceRight(callbackf
 
     // Steps 9-10.
     // Omit some steps, since 'accumulator' should always be O[len-1] in step 10 for typed arrays.
     var accumulator = arguments.length > 1 ? arguments[1] : O[k--];
 
     // Step 11.
     // Omit steps 11.b-11.c and the 'if' clause in step 11.d, since there are no holes in typed arrays.
     for (; k >= 0; k--) {
-        accumulator = callFunction(callbackfn, undefined, accumulator, O[k], k, O);
+        accumulator = callContentFunction(callbackfn, undefined, accumulator, O[k], k, O);
     }
 
     // Step 12.
     return accumulator;
 }
 
 // ES6 draft rev29 (2014/12/06) 22.2.3.21 %TypedArray%.prototype.reverse().
 function TypedArrayReverse() {
@@ -710,25 +710,25 @@ function SetFromNonTypedArray(target, ar
 
     // Steps 12-15, 21, 23-24.
     while (targetOffset < limitOffset) {
         // Steps 24a-c.
         var kNumber = ToNumber(src[k]);
 
         // Step 24d.  This explicit check will be unnecessary when we implement
         // throw-on-getting/setting-element-in-detached-buffer semantics.
-	if (!isShared) {
+        if (!isShared) {
             if (targetBuffer === null) {
-		// A typed array previously using inline storage may acquire a
-		// buffer, so we must check with the source.
-		targetBuffer = ViewedArrayBufferIfReified(target);
+                // A typed array previously using inline storage may acquire a
+                // buffer, so we must check with the source.
+                targetBuffer = ViewedArrayBufferIfReified(target);
             }
             if (IsDetachedBuffer(targetBuffer))
-		ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
-	}
+                ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
+        }
 
         // Step 24e.
         target[targetOffset] = kNumber;
 
         // Steps 24f-g.
         k++;
         targetOffset++;
     }
@@ -887,17 +887,17 @@ function TypedArraySome(callbackfn, this
 
     // Steps 8-9.
     // Omit steps 9.a-9.c and the 'if' clause in step 9.d, since there are no holes in typed arrays.
     for (var k = 0; k < len; k++) {
         // Steps 9.d.i-9.d.ii.
         var kValue = O[k];
 
         // Steps 9.d.iii-9.d.iv.
-        var testResult = callFunction(callbackfn, T, kValue, k, O);
+        var testResult = callContentFunction(callbackfn, T, kValue, k, O);
 
         // Step 9.d.v.
         if (testResult)
             return true;
     }
 
     // Step 10.
     return false;
@@ -1069,17 +1069,17 @@ function TypedArrayFrom(constructor, tar
         var iterator = GetIterator(items, usingIterator);
 
         // Step 10.c.
         var values = new List();
 
         // Steps 10.d-e.
         while (true) {
             // Steps 10.e.i-ii.
-            var next = callFunction(iterator.next, iterator);
+            var next = callContentFunction(iterator.next, iterator);
             if (!IsObject(next))
                 ThrowTypeError(JSMSG_NEXT_RETURNED_PRIMITIVE);
 
             // Steps 10.e.iii-vi.
             if (next.done)
                 break;
             callFunction(std_Array_push, values, next.value);
         }
@@ -1093,17 +1093,17 @@ function TypedArrayFrom(constructor, tar
         var targetObj = new C(len);
 
         // Steps 10.i-j.
         for (var k = 0; k < len; k++) {
             // Steps 10.j.i-ii.
             var kValue = values[k];
 
             // Steps 10.j.iii-iv.
-            var mappedValue = mapping ? callFunction(mapfn, T, kValue, k) : kValue;
+            var mappedValue = mapping ? callContentFunction(mapfn, T, kValue, k) : kValue;
 
             // Steps 10.j.v-vi.
             targetObj[k] = mappedValue;
         }
 
         // Step 10.k.
         // asserting that `values` is empty here would require removing them one by one from
         // the list's start in the loop above. That would introduce unacceptable overhead.
@@ -1127,17 +1127,17 @@ function TypedArrayFrom(constructor, tar
     var targetObj = new C(len);
 
     // Steps 19-20.
     for (var k = 0; k < len; k++) {
         // Steps 20.a-c.
         var kValue = arrayLike[k];
 
         // Steps 20.d-e.
-        var mappedValue = mapping ? callFunction(mapfn, T, kValue, k) : kValue;
+        var mappedValue = mapping ? callContentFunction(mapfn, T, kValue, k) : kValue;
 
         // Steps 20.f-g.
         targetObj[k] = mappedValue;
     }
 
     // Step 21.
     return targetObj;
 }
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -137,17 +137,17 @@ function IsPropertyKey(argument) {
 
 /* Spec: ECMAScript Draft, 6th edition Dec 24, 2014, 7.4.1 */
 function GetIterator(obj, method) {
     // Steps 1-2.
     if (arguments.length === 1)
         method = GetMethod(obj, std_iterator);
 
     // Steps 3-4.
-    var iterator = callFunction(method, obj);
+    var iterator = callContentFunction(method, obj);
 
     // Step 5.
     if (!IsObject(iterator))
         ThrowTypeError(JSMSG_NOT_ITERABLE, ToString(iterator));
 
     // Step 6.
     return iterator;
 }
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -7070,16 +7070,23 @@ BytecodeEmitter::emitSelfHostedCallFunct
         return false;
     }
 
     ParseNode* pn2 = pn->pn_head;
     ParseNode* funNode = pn2->pn_next;
     if (!emitTree(funNode))
         return false;
 
+#ifdef DEBUG
+    if (pn2->name() != cx->names().callContentFunction) {
+        if (!emit1(JSOP_DEBUGCHECKSELFHOSTED))
+            return false;
+    }
+#endif
+
     ParseNode* thisArg = funNode->pn_next;
     if (!emitTree(thisArg))
         return false;
 
     bool oldEmittingForInit = emittingForInit;
     emittingForInit = false;
 
     for (ParseNode* argpn = thisArg->pn_next; argpn; argpn = argpn->pn_next) {
@@ -7170,18 +7177,21 @@ BytecodeEmitter::emitCallOrNew(ParseNode
     switch (pn2->getKind()) {
       case PNK_NAME:
         if (emitterMode == BytecodeEmitter::SelfHosting && !spread) {
             // We shouldn't see foo(bar) = x in self-hosted code.
             MOZ_ASSERT(!(pn->pn_xflags & PNX_SETCALL));
 
             // Calls to "forceInterpreter", "callFunction" or "resumeGenerator"
             // in self-hosted code generate inline bytecode.
-            if (pn2->name() == cx->names().callFunction)
+            if (pn2->name() == cx->names().callFunction ||
+                pn2->name() == cx->names().callContentFunction)
+            {
                 return emitSelfHostedCallFunction(pn);
+            }
             if (pn2->name() == cx->names().resumeGenerator)
                 return emitSelfHostedResumeGenerator(pn);
             if (pn2->name() == cx->names().forceInterpreter)
                 return emitSelfHostedForceInterpreter(pn);
             // Fall through.
         }
         if (!emitNameOp(pn2, callop))
             return false;
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -4236,8 +4236,27 @@ BaselineCompiler::emit_JSOP_RESUME()
     // return value and we're done.
     masm.bind(&returnTarget);
     masm.computeEffectiveAddress(frame.addressOfStackValue(frame.peek(-1)), masm.getStackPointer());
     frame.popn(2);
     frame.push(R0);
     return true;
 }
 
+typedef bool (*CheckSelfHostedFn)(JSContext*, HandleValue);
+static const VMFunction CheckSelfHostedInfo = FunctionInfo<CheckSelfHostedFn>(js::Debug_CheckSelfHosted);
+
+bool
+BaselineCompiler::emit_JSOP_DEBUGCHECKSELFHOSTED()
+{
+#ifdef DEBUG
+    frame.syncStack(0);
+
+    masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+
+    prepareVMCall();
+    pushArg(R0);
+    if (!callVM(CheckSelfHostedInfo))
+        return false;
+#endif
+    return true;
+
+}
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -214,17 +214,18 @@ namespace jit {
     _(JSOP_SPREADSUPERCALL)    \
     _(JSOP_THROWSETCONST)      \
     _(JSOP_THROWSETALIASEDCONST) \
     _(JSOP_INITHIDDENPROP_GETTER) \
     _(JSOP_INITHIDDENPROP_SETTER) \
     _(JSOP_INITHIDDENELEM)     \
     _(JSOP_INITHIDDENELEM_GETTER) \
     _(JSOP_INITHIDDENELEM_SETTER) \
-    _(JSOP_CHECKOBJCOERCIBLE)
+    _(JSOP_CHECKOBJCOERCIBLE)  \
+    _(JSOP_DEBUGCHECKSELFHOSTED)
 
 class BaselineCompiler : public BaselineCompilerSpecific
 {
     FixedList<Label>            labels_;
     NonAssertingLabel           return_;
     NonAssertingLabel           postBarrierSlot_;
 
     // Native code offset right before the scope chain is initialized.
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -10369,16 +10369,27 @@ CodeGenerator::visitCheckObjCoercible(LC
     masm.branchTestNull(Assembler::Equal, checkValue, &fail);
     masm.branchTestUndefined(Assembler::NotEqual, checkValue, &done);
     masm.bind(&fail);
     pushArg(checkValue);
     callVM(ThrowObjectCoercibleInfo, ins);
     masm.bind(&done);
 }
 
+typedef bool (*CheckSelfHostedFn)(JSContext*, HandleValue);
+static const VMFunction CheckSelfHostedInfo = FunctionInfo<CheckSelfHostedFn>(js::Debug_CheckSelfHosted);
+
+void
+CodeGenerator::visitDebugCheckSelfHosted(LDebugCheckSelfHosted* ins)
+{
+    ValueOperand checkValue = ToValue(ins, LDebugCheckSelfHosted::CheckValue);
+    pushArg(checkValue);
+    callVM(CheckSelfHostedInfo, ins);
+}
+
 void
 CodeGenerator::visitRandom(LRandom* ins)
 {
     using mozilla::non_crypto::XorShift128PlusRNG;
 
     FloatRegister output = ToFloatRegister(ins->output());
     Register tempReg = ToRegister(ins->temp0());
 
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -340,16 +340,17 @@ class CodeGenerator : public CodeGenerat
     void visitLexicalCheck(LLexicalCheck* ins);
     void visitThrowRuntimeLexicalError(LThrowRuntimeLexicalError* ins);
     void visitGlobalNameConflictsCheck(LGlobalNameConflictsCheck* ins);
     void visitDebugger(LDebugger* ins);
     void visitNewTarget(LNewTarget* ins);
     void visitArrowNewTarget(LArrowNewTarget* ins);
     void visitCheckReturn(LCheckReturn* ins);
     void visitCheckObjCoercible(LCheckObjCoercible* ins);
+    void visitDebugCheckSelfHosted(LDebugCheckSelfHosted* ins);
 
     void visitCheckOverRecursed(LCheckOverRecursed* lir);
     void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool);
 
     void visitInterruptCheckImplicit(LInterruptCheckImplicit* ins);
     void visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit* ins);
 
     void visitUnboxFloatingPoint(LUnboxFloatingPoint* lir);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -2094,16 +2094,29 @@ IonBuilder::inspectOpcode(JSOp op)
         break;
 
       case JSOP_NEWTARGET:
         return jsop_newtarget();
 
       case JSOP_CHECKOBJCOERCIBLE:
         return jsop_checkobjcoercible();
 
+      case JSOP_DEBUGCHECKSELFHOSTED:
+      {
+#ifdef DEBUG
+        MDebugCheckSelfHosted* check = MDebugCheckSelfHosted::New(alloc(), current->pop());
+        current->add(check);
+        current->push(check);
+        if (!resumeAfter(check))
+            return false;
+#endif
+        return true;
+      }
+
+
 #ifdef DEBUG
       case JSOP_PUSHBLOCKSCOPE:
       case JSOP_FRESHENBLOCKSCOPE:
       case JSOP_POPBLOCKSCOPE:
         // These opcodes are currently unhandled by Ion, but in principle
         // there's no reason they couldn't be.  Whenever this happens, OSR will
         // have to consider that JSOP_FRESHENBLOCK mutates the scope chain --
         // right now it caches the scope chain in MBasicBlock::scopeChain().
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4328,16 +4328,29 @@ LIRGenerator::visitCheckObjCoercible(MCh
 
     LCheckObjCoercible* lir = new(alloc()) LCheckObjCoercible();
     useBoxAtStart(lir, LCheckObjCoercible::CheckValue, checkVal);
     redefine(ins, checkVal);
     add(lir, ins);
     assignSafepoint(lir, ins);
 }
 
+void
+LIRGenerator::visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins)
+{
+    MDefinition* checkVal = ins->checkValue();
+    MOZ_ASSERT(checkVal->type() == MIRType_Value);
+
+    LDebugCheckSelfHosted* lir = new (alloc()) LDebugCheckSelfHosted();
+    useBoxAtStart(lir, LDebugCheckSelfHosted::CheckValue, checkVal);
+    redefine(ins, checkVal);
+    add(lir, ins);
+    assignSafepoint(lir, ins);
+}
+
 static void
 SpewResumePoint(MBasicBlock* block, MInstruction* ins, MResumePoint* resumePoint)
 {
     Fprinter& out = JitSpewPrinter();
     out.printf("Current resume point %p details:\n", (void*)resumePoint);
     out.printf("    frame count: %u\n", resumePoint->frameCount());
 
     if (ins) {
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -305,14 +305,15 @@ class LIRGenerator : public LIRGenerator
     void visitGlobalNameConflictsCheck(MGlobalNameConflictsCheck* ins);
     void visitDebugger(MDebugger* ins);
     void visitNewTarget(MNewTarget* ins);
     void visitArrowNewTarget(MArrowNewTarget* ins);
     void visitAtomicIsLockFree(MAtomicIsLockFree* ins);
     void visitGuardSharedTypedArray(MGuardSharedTypedArray* ins);
     void visitCheckReturn(MCheckReturn* ins);
     void visitCheckObjCoercible(MCheckObjCoercible* ins);
+    void visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins);
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_Lowering_h */
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -13351,16 +13351,39 @@ class MCheckObjCoercible
         return new(alloc) MCheckObjCoercible(toCheck);
     }
 
     MDefinition* checkValue() {
         return getOperand(0);
     }
 };
 
+class MDebugCheckSelfHosted
+  : public MUnaryInstruction,
+    public BoxInputsPolicy::Data
+{
+    explicit MDebugCheckSelfHosted(MDefinition* toCheck)
+      : MUnaryInstruction(toCheck)
+    {
+        setGuard();
+        setResultType(MIRType_Value);
+        setResultTypeSet(toCheck->resultTypeSet());
+    }
+
+  public:
+    INSTRUCTION_HEADER(DebugCheckSelfHosted)
+    static MDebugCheckSelfHosted* New(TempAllocator& alloc, MDefinition* toCheck) {
+        return new(alloc) MDebugCheckSelfHosted(toCheck);
+    }
+
+    MDefinition* checkValue() {
+        return getOperand(0);
+    }
+};
+
 class MAsmJSNeg
   : public MUnaryInstruction,
     public NoTypePolicy::Data
 {
     MAsmJSNeg(MDefinition* op, MIRType type)
       : MUnaryInstruction(op)
     {
         setResultType(type);
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -274,17 +274,18 @@ namespace jit {
     _(UnknownValue)                                                         \
     _(LexicalCheck)                                                         \
     _(ThrowRuntimeLexicalError)                                             \
     _(GlobalNameConflictsCheck)                                             \
     _(Debugger)                                                             \
     _(NewTarget)                                                            \
     _(ArrowNewTarget)                                                       \
     _(CheckReturn)                                                          \
-    _(CheckObjCoercible)
+    _(CheckObjCoercible)                                                    \
+    _(DebugCheckSelfHosted)
 
 // Forward declarations of MIR types.
 #define FORWARD_DECLARE(op) class M##op;
  MIR_OPCODE_LIST(FORWARD_DECLARE)
 #undef FORWARD_DECLARE
 
 class MDefinitionVisitor // interface i.e. pure abstract class
 {
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -7383,12 +7383,20 @@ class LCheckReturn : public LCallInstruc
 class LCheckObjCoercible : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
 {
   public:
     static const size_t CheckValue = 0;
 
     LIR_HEADER(CheckObjCoercible)
 };
 
+class LDebugCheckSelfHosted : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
+{
+  public:
+    static const size_t CheckValue = 0;
+
+    LIR_HEADER(DebugCheckSelfHosted)
+};
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_shared_LIR_shared_h */
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -362,11 +362,12 @@
     _(AssertResultT)                \
     _(LexicalCheck)                 \
     _(ThrowRuntimeLexicalError)     \
     _(GlobalNameConflictsCheck)     \
     _(Debugger)                     \
     _(NewTarget)                    \
     _(ArrowNewTarget)               \
     _(CheckReturn)                  \
-    _(CheckObjCoercible)
+    _(CheckObjCoercible)            \
+    _(DebugCheckSelfHosted)
 
 #endif /* jit_shared_LOpcodes_shared_h */
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -102,16 +102,17 @@ MSG_DEF(JSMSG_CANT_SET_PROTO,          0
 MSG_DEF(JSMSG_CANT_SET_PROTO_OF,       1, JSEXN_TYPEERR, "can't set prototype of {0}")
 MSG_DEF(JSMSG_CANT_SET_PROTO_CYCLE,    0, JSEXN_TYPEERR, "can't set prototype: it would cause a prototype chain cycle")
 MSG_DEF(JSMSG_INVALID_ARG_TYPE,        3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}")
 MSG_DEF(JSMSG_TERMINATED,              1, JSEXN_ERR, "Script terminated by timeout at:\n{0}")
 MSG_DEF(JSMSG_PROTO_NOT_OBJORNULL,     1, JSEXN_TYPEERR, "{0}.prototype is not an object or null")
 MSG_DEF(JSMSG_CANT_CALL_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class constructors must be invoked with |new|")
 MSG_DEF(JSMSG_UNINITIALIZED_THIS,      1, JSEXN_REFERENCEERR, "|this| used uninitialized in {0} class constructor")
 MSG_DEF(JSMSG_BAD_DERIVED_RETURN,      1, JSEXN_TYPEERR, "derived class constructor returned invalid value {0}")
+MSG_DEF(JSMSG_NOT_SELFHOSTED,          1, JSEXN_TYPEERR, "callFunction() used on non self-hosted builtin {0}")
 
 // JSON
 MSG_DEF(JSMSG_JSON_BAD_PARSE,          3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data")
 MSG_DEF(JSMSG_JSON_CYCLIC_VALUE,       1, JSEXN_TYPEERR, "cyclic {0} value")
 
 // Runtime errors
 MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS,      1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}")
 MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS,     0, JSEXN_REFERENCEERR, "invalid assignment left-hand side")
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -28,16 +28,17 @@
     macro(builder, builder, "builder") \
     macro(by, by, "by") \
     macro(byteLength, byteLength, "byteLength") \
     macro(byteAlignment, byteAlignment, "byteAlignment") \
     macro(byteOffset, byteOffset, "byteOffset") \
     macro(bytes, bytes, "bytes") \
     macro(BYTES_PER_ELEMENT, BYTES_PER_ELEMENT, "BYTES_PER_ELEMENT") \
     macro(call, call, "call") \
+    macro(callContentFunction, callContentFunction, "callContentFunction") \
     macro(callee, callee, "callee") \
     macro(caller, caller, "caller") \
     macro(callFunction, callFunction, "callFunction") \
     macro(caseFirst, caseFirst, "caseFirst") \
     macro(class_, class_, "class") \
     macro(close, close, "close") \
     macro(Collator, Collator, "Collator") \
     macro(CollatorCompareGet, CollatorCompareGet, "Intl_Collator_compare_get") \
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -170,16 +170,32 @@ js::GetNonSyntacticGlobalThis(JSContext*
             return true;
         }
         scope = scope->enclosingScope();
     }
 
     return true;
 }
 
+bool
+js::Debug_CheckSelfHosted(JSContext* cx, HandleValue fun)
+{
+#ifndef DEBUG
+    MOZ_CRASH("Self hosted checks should only be done in Debug builds");
+#endif
+
+    MOZ_ASSERT(fun.isObject());
+
+    MOZ_ASSERT(fun.toObject().is<JSFunction>());
+    MOZ_ASSERT(fun.toObject().as<JSFunction>().isSelfHostedOrIntrinsic());
+
+    // This is purely to police self-hosted code. There is no actual operation.
+    return true;
+}
+
 static inline bool
 GetPropertyOperation(JSContext* cx, InterpreterFrame* fp, HandleScript script, jsbytecode* pc,
                      MutableHandleValue lval, MutableHandleValue vp)
 {
     JSOp op = JSOp(*pc);
 
     if (op == JSOP_LENGTH) {
         if (IsOptimizedArguments(fp, lval)) {
@@ -1735,17 +1751,16 @@ CASE(EnableInterruptsPseudoOpcode)
     DISPATCH_TO(op);
 }
 
 /* Various 1-byte no-ops. */
 CASE(JSOP_NOP)
 CASE(JSOP_UNUSED14)
 CASE(JSOP_UNUSED65)
 CASE(JSOP_BACKPATCH)
-CASE(JSOP_UNUSED177)
 CASE(JSOP_UNUSED178)
 CASE(JSOP_UNUSED179)
 CASE(JSOP_UNUSED180)
 CASE(JSOP_UNUSED181)
 CASE(JSOP_UNUSED182)
 CASE(JSOP_UNUSED183)
 CASE(JSOP_UNUSED187)
 CASE(JSOP_UNUSED192)
@@ -3886,16 +3901,26 @@ END_CASE(JSOP_CLASSCONSTRUCTOR)
 CASE(JSOP_CHECKOBJCOERCIBLE)
 {
     ReservedRooted<Value> checkVal(&rootValue0, REGS.sp[-1]);
     if (checkVal.isNullOrUndefined() && !ToObjectFromStack(cx, checkVal))
         goto error;
 }
 END_CASE(JSOP_CHECKOBJCOERCIBLE)
 
+CASE(JSOP_DEBUGCHECKSELFHOSTED)
+{
+#ifdef DEBUG
+    ReservedRooted<Value> checkVal(&rootValue0, REGS.sp[-1]);
+    if (!Debug_CheckSelfHosted(cx, checkVal))
+        goto error;
+#endif
+}
+END_CASE(JSOP_DEBUGCHECKSELFHOSTED)
+
 DEFAULT()
 {
     char numBuf[12];
     JS_snprintf(numBuf, sizeof numBuf, "%d", *REGS.pc);
     JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                          JSMSG_BAD_BYTECODE, numBuf);
     goto error;
 }
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -479,11 +479,14 @@ bool
 ThrowUninitializedThis(JSContext* cx, AbstractFramePtr frame);
 
 bool
 DefaultClassConstructor(JSContext* cx, unsigned argc, Value* vp);
 
 bool
 DefaultDerivedClassConstructor(JSContext* cx, unsigned argc, Value* vp);
 
+bool
+Debug_CheckSelfHosted(JSContext* cx, HandleValue v);
+
 }  /* namespace js */
 
 #endif /* vm_Interpreter_h */
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -1804,17 +1804,17 @@ 1234567890123456789012345678901234567890
     /*
      * Gets the value of a module import by name and pushes it onto the stack.
      *   Category: Variables and Scopes
      *   Type: Variables
      *   Operands: uint32_t nameIndex
      *   Stack: => val
      */ \
     macro(JSOP_GETIMPORT,     176,"getimport",  NULL,     5,  0,  1,  JOF_ATOM|JOF_NAME|JOF_TYPESET) \
-    macro(JSOP_UNUSED177,     177,"unused177",  NULL,     1,  0,  0,  JOF_BYTE) \
+    macro(JSOP_DEBUGCHECKSELFHOSTED, 177,"debug-checkselfhosted",  NULL, 1,  1,  1,  JOF_BYTE) \
     macro(JSOP_UNUSED178,     178,"unused178",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED179,     179,"unused179",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED180,     180,"unused180",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED181,     181,"unused181",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED182,     182,"unused182",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED183,     183,"unused183",  NULL,     1,  0,  0,  JOF_BYTE) \
     \
     /*
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -24,21 +24,21 @@ namespace js {
  * versions.  If deserialization fails, the data should be invalidated if
  * possible.
  *
  * When you change this, run make_opcode_doc.py and copy the new output into
  * this wiki page:
  *
  *  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
  */
-static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 331;
+static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 332;
 static const uint32_t XDR_BYTECODE_VERSION =
     uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
 
-static_assert(JSErr_Limit == 420,
+static_assert(JSErr_Limit == 421,
               "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
               "removed MSG_DEFs from js.msg, you should increment "
               "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
               "expected JSErr_Limit value.");
 
 class XDRBuffer {
   public:
     explicit XDRBuffer(JSContext* cx)