Bug 1527822 - Allow inlining some cross-realm native calls in IonBuilder. r=anba
authorJan de Mooij <jdemooij@mozilla.com>
Mon, 11 Mar 2019 10:35:32 +0000
changeset 521334 deb3594da5b1649fc3001d1dab5d4bac036de7bd
parent 521333 d45e5b4b57b98f6bf0fa85e951087a7359d5b1d7
child 521335 e108f9ad99a558afb7b4bcb5b0d8756c99a3f4f8
push id10866
push usernerli@mozilla.com
push dateTue, 12 Mar 2019 18:59:09 +0000
treeherdermozilla-beta@445c24a51727 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersanba
bugs1527822
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 1527822 - Allow inlining some cross-realm native calls in IonBuilder. r=anba This adds the basic infrastructure and uses it for some Math natives and the Array constructor. Differential Revision: https://phabricator.services.mozilla.com/D20340
js/public/TrackedOptimizationInfo.h
js/src/builtin/Array.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/MCallOptimize.cpp
js/src/vm/Interpreter.cpp
--- a/js/public/TrackedOptimizationInfo.h
+++ b/js/public/TrackedOptimizationInfo.h
@@ -198,16 +198,17 @@ namespace JS {
   _(CantInlineTooManyArgs)                        \
   _(CantInlineNeedsArgsObj)                       \
   _(CantInlineDebuggee)                           \
   _(CantInlineExceededDepth)                      \
   _(CantInlineExceededTotalBytecodeLength)        \
   _(CantInlineBigCaller)                          \
   _(CantInlineBigCallee)                          \
   _(CantInlineBigCalleeInlinedBytecodeLength)     \
+  _(CantInlineCrossRealm)                         \
   _(CantInlineNotHot)                             \
   _(CantInlineNotInDispatch)                      \
   _(CantInlineUnreachable)                        \
   _(CantInlineNativeBadForm)                      \
   _(CantInlineNativeBadType)                      \
   _(CantInlineNativeNoTemplateObj)                \
   _(CantInlineBound)                              \
   _(CantInlineNativeNoSpecialization)             \
--- a/js/src/builtin/Array.cpp
+++ b/js/src/builtin/Array.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "builtin/Array-inl.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/MathAlgorithms.h"
+#include "mozilla/Maybe.h"
 #include "mozilla/TextUtils.h"
 
 #include <algorithm>
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "jsnum.h"
 #include "jstypes.h"
@@ -52,16 +53,17 @@
 using namespace js;
 
 using mozilla::Abs;
 using mozilla::ArrayLength;
 using mozilla::CeilingLog2;
 using mozilla::CheckedInt;
 using mozilla::DebugOnly;
 using mozilla::IsAsciiDigit;
+using mozilla::Maybe;
 
 using JS::AutoCheckCannotGC;
 using JS::IsArrayAnswer;
 using JS::ToUint32;
 
 bool JS::IsArray(JSContext* cx, HandleObject obj, IsArrayAnswer* answer) {
   if (obj->is<ArrayObject>()) {
     *answer = IsArrayAnswer::Array;
@@ -3864,24 +3866,34 @@ bool js::array_construct(JSContext* cx, 
   MOZ_ASSERT(!args.isConstructing());
   MOZ_ASSERT(args.length() == 1);
   MOZ_ASSERT(args[0].isNumber());
   return ArrayConstructorImpl(cx, args, /* isConstructor = */ false);
 }
 
 ArrayObject* js::ArrayConstructorOneArg(JSContext* cx, HandleObjectGroup group,
                                         int32_t lengthInt) {
+  // Ion can call this with a group from a different realm when calling
+  // another realm's Array constructor.
+  Maybe<AutoRealm> ar;
+  if (cx->realm() != group->realm()) {
+    MOZ_ASSERT(cx->compartment() == group->compartment());
+    ar.emplace(cx, group);
+  }
+
   if (lengthInt < 0) {
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                               JSMSG_BAD_ARRAY_LENGTH);
     return nullptr;
   }
 
   uint32_t length = uint32_t(lengthInt);
-  return NewPartlyAllocatedArrayTryUseGroup(cx, group, length);
+  ArrayObject* res = NewPartlyAllocatedArrayTryUseGroup(cx, group, length);
+  MOZ_ASSERT_IF(res, res->realm() == group->realm());
+  return res;
 }
 
 static JSObject* CreateArrayPrototype(JSContext* cx, JSProtoKey key) {
   MOZ_ASSERT(key == JSProto_Array);
   RootedObject proto(
       cx, GlobalObject::getOrCreateObjectPrototype(cx, cx->global()));
   if (!proto) {
     return nullptr;
@@ -4323,23 +4335,33 @@ ArrayObject* js::NewCopiedArrayForCallin
     return nullptr;
   }
   return NewCopiedArrayTryUseGroup(cx, group, vp, length);
 }
 
 ArrayObject* js::NewArrayWithGroup(JSContext* cx, uint32_t length,
                                    HandleObjectGroup group,
                                    bool convertDoubleElements) {
+  // Ion can call this with a group from a different realm when calling
+  // another realm's Array constructor.
+  Maybe<AutoRealm> ar;
+  if (cx->realm() != group->realm()) {
+    MOZ_ASSERT(cx->compartment() == group->compartment());
+    ar.emplace(cx, group);
+  }
+
   ArrayObject* res = NewFullyAllocatedArrayTryUseGroup(cx, group, length);
   if (!res) {
     return nullptr;
   }
+
   if (convertDoubleElements) {
     res->setShouldConvertDoubleElements();
   }
+
   return res;
 }
 
 #ifdef DEBUG
 bool js::ArrayInfo(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   RootedObject obj(cx);
 
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -3663,18 +3663,19 @@ static bool TryAttachCallStub(JSContext*
       JitSpew(JitSpew_BaselineIC,
               "  Megamorphic Call_Native stubs. TODO: add Call_AnyNative!");
       return true;
     }
 
     bool isCrossRealm = cx->realm() != fun->realm();
 
     RootedObject templateObject(cx);
-    if (MOZ_LIKELY(!isSpread && !isSuper && !isCrossRealm)) {
+    if (MOZ_LIKELY(!isSpread && !isSuper)) {
       CallArgs args = CallArgsFromVp(argc, vp);
+      AutoRealm ar(cx, fun);
       if (!GetTemplateObjectForNative(cx, fun, args, &templateObject)) {
         return false;
       }
       MOZ_ASSERT_IF(templateObject,
                     !templateObject->group()
                          ->maybePreliminaryObjectsDontCheckGeneration());
     }
 
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -405,16 +405,22 @@ IonBuilder::InliningDecision IonBuilder:
                       "but Tracelogger cannot do that yet.");
   }
 
   if (!target->isInterpreted()) {
     trackOptimizationOutcome(TrackedOutcome::CantInlineNotInterpreted);
     return DontInline(nullptr, "Non-interpreted target");
   }
 
+  // Never inline scripted cross-realm calls.
+  if (target->realm() != script()->realm()) {
+    trackOptimizationOutcome(TrackedOutcome::CantInlineCrossRealm);
+    return DontInline(nullptr, "Cross-realm call");
+  }
+
   if (info().analysisMode() != Analysis_DefiniteProperties) {
     // If |this| or an argument has an empty resultTypeSet, don't bother
     // inlining, as the call is currently unreachable due to incomplete type
     // information. This does not apply to the definite properties analysis,
     // in that case we want to inline anyway.
 
     if (callInfo.thisArg()->emptyResultTypeSet()) {
       trackOptimizationOutcome(TrackedOutcome::CantInlineUnreachable);
@@ -4260,22 +4266,16 @@ MDefinition* IonBuilder::patchInlinedRet
 IonBuilder::InliningDecision IonBuilder::makeInliningDecision(
     JSObject* targetArg, CallInfo& callInfo) {
   // When there is no target, inlining is impossible.
   if (targetArg == nullptr) {
     trackOptimizationOutcome(TrackedOutcome::CantInlineNoTarget);
     return InliningDecision_DontInline;
   }
 
-  // Don't inline (native or scripted) cross-realm calls.
-  Realm* targetRealm = JS::GetObjectRealmOrNull(targetArg);
-  if (!targetRealm || targetRealm != script()->realm()) {
-    return InliningDecision_DontInline;
-  }
-
   // Inlining non-function targets is handled by inlineNonFunctionCall().
   if (!targetArg->is<JSFunction>()) {
     return InliningDecision_Inline;
   }
 
   JSFunction* target = &targetArg->as<JSFunction>();
 
   // Never inline during the arguments usage analysis.
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -707,17 +707,17 @@ class IonBuilder : public MIRGenerator,
   // Native inlining helpers.
   // The typeset for the return value of our function.  These are
   // the types it's been observed returning in the past.
   TemporaryTypeSet* getInlineReturnTypeSet();
   // The known MIR type of getInlineReturnTypeSet.
   MIRType getInlineReturnType();
 
   // Array natives.
-  InliningResult inlineArray(CallInfo& callInfo);
+  InliningResult inlineArray(CallInfo& callInfo, Realm* targetRealm);
   InliningResult inlineArrayIsArray(CallInfo& callInfo);
   InliningResult inlineArrayPopShift(CallInfo& callInfo,
                                      MArrayPopShift::Mode mode);
   InliningResult inlineArrayPush(CallInfo& callInfo);
   InliningResult inlineArraySlice(CallInfo& callInfo);
   InliningResult inlineArrayJoin(CallInfo& callInfo);
 
   // Boolean natives.
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -44,16 +44,182 @@ using mozilla::AssertedCast;
 using mozilla::Maybe;
 
 using JS::DoubleNaNValue;
 using JS::TrackedOutcome;
 
 namespace js {
 namespace jit {
 
+// Returns true if |native| can be inlined cross-realm. Especially inlined
+// natives that can allocate objects or throw exceptions shouldn't be inlined
+// cross-realm without a careful analysis because we might use the wrong realm!
+//
+// Note that self-hosting intrinsics are never called cross-realm. See the
+// MOZ_CRASH below.
+//
+// If you are adding a new inlinable native, the safe thing is to |return false|
+// here.
+static bool CanInlineCrossRealm(InlinableNative native) {
+  switch (native) {
+    case InlinableNative::MathAbs:
+    case InlinableNative::MathFloor:
+    case InlinableNative::MathCeil:
+    case InlinableNative::MathRound:
+    case InlinableNative::MathClz32:
+    case InlinableNative::MathSqrt:
+    case InlinableNative::MathATan2:
+    case InlinableNative::MathHypot:
+    case InlinableNative::MathMax:
+    case InlinableNative::MathMin:
+    case InlinableNative::MathPow:
+    case InlinableNative::MathImul:
+    case InlinableNative::MathFRound:
+    case InlinableNative::MathTrunc:
+    case InlinableNative::MathSign:
+    case InlinableNative::MathSin:
+    case InlinableNative::MathTan:
+    case InlinableNative::MathCos:
+    case InlinableNative::MathExp:
+    case InlinableNative::MathLog:
+    case InlinableNative::MathASin:
+    case InlinableNative::MathATan:
+    case InlinableNative::MathACos:
+    case InlinableNative::MathLog10:
+    case InlinableNative::MathLog2:
+    case InlinableNative::MathLog1P:
+    case InlinableNative::MathExpM1:
+    case InlinableNative::MathCosH:
+    case InlinableNative::MathSinH:
+    case InlinableNative::MathTanH:
+    case InlinableNative::MathACosH:
+    case InlinableNative::MathASinH:
+    case InlinableNative::MathATanH:
+    case InlinableNative::MathCbrt:
+    case InlinableNative::Boolean:
+      return true;
+
+    case InlinableNative::Array:
+      // Cross-realm case handled by inlineArray.
+      return true;
+
+    case InlinableNative::MathRandom:
+      // RNG state is per-realm.
+      return false;
+
+    case InlinableNative::IntlGuardToCollator:
+    case InlinableNative::IntlGuardToDateTimeFormat:
+    case InlinableNative::IntlGuardToNumberFormat:
+    case InlinableNative::IntlGuardToPluralRules:
+    case InlinableNative::IntlGuardToRelativeTimeFormat:
+    case InlinableNative::IsRegExpObject:
+    case InlinableNative::RegExpMatcher:
+    case InlinableNative::RegExpSearcher:
+    case InlinableNative::RegExpTester:
+    case InlinableNative::RegExpPrototypeOptimizable:
+    case InlinableNative::RegExpInstanceOptimizable:
+    case InlinableNative::GetFirstDollarIndex:
+    case InlinableNative::IntrinsicNewArrayIterator:
+    case InlinableNative::IntrinsicNewStringIterator:
+    case InlinableNative::IntrinsicNewRegExpStringIterator:
+    case InlinableNative::IntrinsicStringReplaceString:
+    case InlinableNative::IntrinsicStringSplitString:
+    case InlinableNative::IntrinsicUnsafeSetReservedSlot:
+    case InlinableNative::IntrinsicUnsafeGetReservedSlot:
+    case InlinableNative::IntrinsicUnsafeGetObjectFromReservedSlot:
+    case InlinableNative::IntrinsicUnsafeGetInt32FromReservedSlot:
+    case InlinableNative::IntrinsicUnsafeGetStringFromReservedSlot:
+    case InlinableNative::IntrinsicUnsafeGetBooleanFromReservedSlot:
+    case InlinableNative::IntrinsicIsCallable:
+    case InlinableNative::IntrinsicIsConstructor:
+    case InlinableNative::IntrinsicToObject:
+    case InlinableNative::IntrinsicIsObject:
+    case InlinableNative::IntrinsicIsCrossRealmArrayConstructor:
+    case InlinableNative::IntrinsicToInteger:
+    case InlinableNative::IntrinsicToString:
+    case InlinableNative::IntrinsicIsConstructing:
+    case InlinableNative::IntrinsicSubstringKernel:
+    case InlinableNative::IntrinsicGuardToArrayIterator:
+    case InlinableNative::IntrinsicGuardToMapIterator:
+    case InlinableNative::IntrinsicGuardToSetIterator:
+    case InlinableNative::IntrinsicGuardToStringIterator:
+    case InlinableNative::IntrinsicGuardToRegExpStringIterator:
+    case InlinableNative::IntrinsicObjectHasPrototype:
+    case InlinableNative::IntrinsicFinishBoundFunctionInit:
+    case InlinableNative::IntrinsicIsPackedArray:
+    case InlinableNative::IntrinsicGuardToMapObject:
+    case InlinableNative::IntrinsicGetNextMapEntryForIterator:
+    case InlinableNative::IntrinsicGuardToSetObject:
+    case InlinableNative::IntrinsicGetNextSetEntryForIterator:
+    case InlinableNative::IntrinsicGuardToArrayBuffer:
+    case InlinableNative::IntrinsicArrayBufferByteLength:
+    case InlinableNative::IntrinsicPossiblyWrappedArrayBufferByteLength:
+    case InlinableNative::IntrinsicGuardToSharedArrayBuffer:
+    case InlinableNative::IntrinsicIsTypedArrayConstructor:
+    case InlinableNative::IntrinsicIsTypedArray:
+    case InlinableNative::IntrinsicIsPossiblyWrappedTypedArray:
+    case InlinableNative::IntrinsicPossiblyWrappedTypedArrayLength:
+    case InlinableNative::IntrinsicTypedArrayLength:
+    case InlinableNative::IntrinsicTypedArrayByteOffset:
+    case InlinableNative::IntrinsicTypedArrayElementShift:
+    case InlinableNative::IntrinsicSetDisjointTypedElements:
+    case InlinableNative::IntrinsicObjectIsTypedObject:
+    case InlinableNative::IntrinsicObjectIsTransparentTypedObject:
+    case InlinableNative::IntrinsicObjectIsOpaqueTypedObject:
+    case InlinableNative::IntrinsicObjectIsTypeDescr:
+    case InlinableNative::IntrinsicTypeDescrIsSimpleType:
+    case InlinableNative::IntrinsicTypeDescrIsArrayType:
+    case InlinableNative::IntrinsicSetTypedObjectOffset:
+    case InlinableNative::IntrinsicArrayIteratorPrototypeOptimizable:
+      MOZ_CRASH("Unexpected cross-realm intrinsic call");
+
+    case InlinableNative::TestBailout:
+    case InlinableNative::TestAssertFloat32:
+    case InlinableNative::TestAssertRecoveredOnBailout:
+      // Testing functions, not worth inlining cross-realm.
+      return false;
+
+    case InlinableNative::ArrayIsArray:
+    case InlinableNative::ArrayJoin:
+    case InlinableNative::ArrayPop:
+    case InlinableNative::ArrayShift:
+    case InlinableNative::ArrayPush:
+    case InlinableNative::ArraySlice:
+    case InlinableNative::AtomicsCompareExchange:
+    case InlinableNative::AtomicsExchange:
+    case InlinableNative::AtomicsLoad:
+    case InlinableNative::AtomicsStore:
+    case InlinableNative::AtomicsAdd:
+    case InlinableNative::AtomicsSub:
+    case InlinableNative::AtomicsAnd:
+    case InlinableNative::AtomicsOr:
+    case InlinableNative::AtomicsXor:
+    case InlinableNative::AtomicsIsLockFree:
+    case InlinableNative::ReflectGetPrototypeOf:
+    case InlinableNative::String:
+    case InlinableNative::StringCharCodeAt:
+    case InlinableNative::StringFromCharCode:
+    case InlinableNative::StringFromCodePoint:
+    case InlinableNative::StringCharAt:
+    case InlinableNative::StringToLowerCase:
+    case InlinableNative::StringToUpperCase:
+    case InlinableNative::Object:
+    case InlinableNative::ObjectCreate:
+    case InlinableNative::ObjectIs:
+    case InlinableNative::ObjectToString:
+    case InlinableNative::TypedArrayConstructor:
+      // Default to false for most natives.
+      return false;
+
+    case InlinableNative::Limit:
+      break;
+  }
+  MOZ_CRASH("Unknown native");
+}
+
 IonBuilder::InliningResult IonBuilder::inlineNativeCall(CallInfo& callInfo,
                                                         JSFunction* target) {
   MOZ_ASSERT(target->isNative());
 
   if (!optimizationInfo().inlineNative()) {
     trackOptimizationOutcome(TrackedOutcome::CantInlineDisabledIon);
     return InliningStatus_NotInlined;
   }
@@ -86,20 +252,27 @@ IonBuilder::InliningResult IonBuilder::i
       return InliningStatus_NotInlined;
     }
   }
 
   if (isWasmCall) {
     return inlineWasmCall(callInfo, target);
   }
 
-  switch (InlinableNative inlNative = target->jitInfo()->inlinableNative) {
+  InlinableNative inlNative = target->jitInfo()->inlinableNative;
+
+  if (target->realm() != script()->realm() && !CanInlineCrossRealm(inlNative)) {
+    trackOptimizationOutcome(TrackedOutcome::CantInlineCrossRealm);
+    return InliningStatus_NotInlined;
+  }
+
+  switch (inlNative) {
     // Array natives.
     case InlinableNative::Array:
-      return inlineArray(callInfo);
+      return inlineArray(callInfo, target->realm());
     case InlinableNative::ArrayIsArray:
       return inlineArrayIsArray(callInfo);
     case InlinableNative::ArrayJoin:
       return inlineArrayJoin(callInfo);
     case InlinableNative::ArrayPop:
       return inlineArrayPopShift(callInfo, MArrayPopShift::Pop);
     case InlinableNative::ArrayShift:
       return inlineArrayPopShift(callInfo, MArrayPopShift::Shift);
@@ -420,16 +593,18 @@ IonBuilder::InliningResult IonBuilder::i
   MDefinition* thisArg = callInfo.thisArg();
   TemporaryTypeSet* thisTypes = thisArg->resultTypeSet();
   MOZ_ASSERT(callInfo.argc() == 0);
 
   if (!thisTypes) {
     return InliningStatus_NotInlined;
   }
 
+  // Note: target might be a cross-realm native!
+
   // Try to optimize typed array lengths.
   if (TypedArrayObject::isOriginalLengthGetter(native)) {
     if (thisTypes->forAllClasses(constraints(), IsTypedArrayClass) !=
         TemporaryTypeSet::ForAllResult::ALL_TRUE) {
       return InliningStatus_NotInlined;
     }
 
     MInstruction* length = addTypedArrayLength(thisArg);
@@ -475,25 +650,29 @@ IonBuilder::InliningResult IonBuilder::i
   return InliningStatus_NotInlined;
 }
 
 IonBuilder::InliningResult IonBuilder::inlineNonFunctionCall(CallInfo& callInfo,
                                                              JSObject* target) {
   // Inline a call to a non-function object, invoking the object's call or
   // construct hook.
 
-  MOZ_ASSERT(target->nonCCWRealm() == script()->realm());
-
   // Don't inline if we're constructing and new.target != callee. This can
   // happen with Reflect.construct or derived class constructors.
   if (callInfo.constructing() && callInfo.getNewTarget() != callInfo.fun()) {
     trackOptimizationOutcome(TrackedOutcome::CantInlineUnexpectedNewTarget);
     return InliningStatus_NotInlined;
   }
 
+  Realm* targetRealm = JS::GetObjectRealmOrNull(target);
+  if (!targetRealm || targetRealm != script()->realm()) {
+    trackOptimizationOutcome(TrackedOutcome::CantInlineCrossRealm);
+    return InliningStatus_NotInlined;
+  }
+
   if (callInfo.constructing() &&
       target->constructHook() == TypedObject::construct) {
     return inlineConstructTypedObject(callInfo, &target->as<TypeDescr>());
   }
 
   return InliningStatus_NotInlined;
 }
 
@@ -528,31 +707,37 @@ IonBuilder::InliningResult IonBuilder::i
 
   MMathFunction* ins =
       MMathFunction::New(alloc(), callInfo.getArg(0), function);
   current->add(ins);
   current->push(ins);
   return InliningStatus_Inlined;
 }
 
-IonBuilder::InliningResult IonBuilder::inlineArray(CallInfo& callInfo) {
+IonBuilder::InliningResult IonBuilder::inlineArray(CallInfo& callInfo,
+                                                   Realm* targetRealm) {
   uint32_t initLength = 0;
 
   JSObject* templateObject =
       inspector->getTemplateObjectForNative(pc, ArrayConstructor);
   // This is shared by ArrayConstructor and array_construct (std_Array).
   if (!templateObject) {
     templateObject = inspector->getTemplateObjectForNative(pc, array_construct);
   }
 
   if (!templateObject) {
     trackOptimizationOutcome(TrackedOutcome::CantInlineNativeNoTemplateObj);
     return InliningStatus_NotInlined;
   }
 
+  if (templateObject->nonCCWRealm() != targetRealm) {
+    trackOptimizationOutcome(TrackedOutcome::CantInlineCrossRealm);
+    return InliningStatus_NotInlined;
+  }
+
   // Multiple arguments imply array initialization, not just construction.
   if (callInfo.argc() >= 2) {
     initLength = callInfo.argc();
 
     TypeSet::ObjectKey* key = TypeSet::ObjectKey::get(templateObject);
     if (!key->unknownProperties()) {
       HeapTypeSetKey elemTypes = key->property(JSID_VOID);
 
@@ -4135,24 +4320,28 @@ IonBuilder::InliningResult IonBuilder::i
   current->push(ins);
 
   return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningResult IonBuilder::inlineWasmCall(CallInfo& callInfo,
                                                       JSFunction* target) {
   MOZ_ASSERT(target->isWasmOptimized());
-  MOZ_ASSERT(target->realm() == script()->realm());
 
   // Don't inline wasm constructors.
   if (callInfo.constructing()) {
     trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
     return InliningStatus_NotInlined;
   }
 
+  if (target->realm() != script()->realm()) {
+    trackOptimizationOutcome(TrackedOutcome::CantInlineCrossRealm);
+    return InliningStatus_NotInlined;
+  }
+
   wasm::Instance& inst = wasm::ExportedFunctionToInstance(target);
   uint32_t funcIndex = inst.code().getFuncIndex(target);
 
   auto bestTier = inst.code().bestTier();
   const wasm::FuncExport& funcExport =
       inst.metadata(bestTier).lookupFuncExport(funcIndex);
   const wasm::FuncType& sig = funcExport.funcType();
 
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -5232,16 +5232,17 @@ JSObject* js::CreateThisWithTemplate(JSC
   }
 
   return NewObjectOperationWithTemplate(cx, templateObject);
 }
 
 JSObject* js::NewArrayOperation(JSContext* cx, HandleScript script,
                                 jsbytecode* pc, uint32_t length,
                                 NewObjectKind newKind /* = GenericObject */) {
+  MOZ_ASSERT(*pc == JSOP_NEWARRAY);
   MOZ_ASSERT(newKind != SingletonObject);
 
   RootedObjectGroup group(cx);
   if (ObjectGroup::useSingletonForAllocationSite(script, pc, JSProto_Array)) {
     newKind = SingletonObject;
   } else {
     group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
     if (!group) {