Bug 1643486 - Transpile GuardNoDenseElements. r=jandem
authorTom Schuster <evilpies@gmail.com>
Fri, 05 Jun 2020 11:02:54 +0000
changeset 534119 17218fef8f25a4f1d69a019fb1c37428676cce88
parent 534118 8604456ea61eafc35ae28670d95e8595ee850f6e
child 534120 fb1e3f30a194b8260bac3125172813c22e1b70f4
push id37483
push userapavel@mozilla.com
push dateFri, 05 Jun 2020 21:40:11 +0000
treeherdermozilla-central@dadc7312128e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1643486
milestone79.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 1643486 - Transpile GuardNoDenseElements. r=jandem Differential Revision: https://phabricator.services.mozilla.com/D78376
js/src/jit/AliasAnalysis.cpp
js/src/jit/BaselineBailouts.cpp
js/src/jit/CacheIROps.yaml
js/src/jit/CodeGenerator.cpp
js/src/jit/IonTypes.h
js/src/jit/Lowering.cpp
js/src/jit/MIR.h
js/src/jit/WarpCacheIRTranspiler.cpp
js/src/jit/shared/LIR-shared.h
--- a/js/src/jit/AliasAnalysis.cpp
+++ b/js/src/jit/AliasAnalysis.cpp
@@ -141,16 +141,17 @@ static inline const MDefinition* GetObje
     case MDefinition::Opcode::LoadElementHole:
     case MDefinition::Opcode::ArrayBufferViewElements:
     case MDefinition::Opcode::CopyLexicalEnvironmentObject:
     case MDefinition::Opcode::IsPackedArray:
     case MDefinition::Opcode::SuperFunction:
     case MDefinition::Opcode::InitHomeObject:
     case MDefinition::Opcode::HomeObjectSuperBase:
     case MDefinition::Opcode::ObjectStaticProto:
+    case MDefinition::Opcode::GuardNoDenseElements:
       object = ins->getOperand(0);
       break;
     case MDefinition::Opcode::GetPropertyCache:
     case MDefinition::Opcode::CallGetProperty:
     case MDefinition::Opcode::GetDOMProperty:
     case MDefinition::Opcode::GetDOMMember:
     case MDefinition::Opcode::Call:
     case MDefinition::Opcode::Throw:
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -1984,16 +1984,17 @@ bool jit::FinishBailoutToBaseline(Baseli
     case Bailout_NonPrimitiveInput:
     case Bailout_PrecisionLoss:
     case Bailout_TypeBarrierO:
     case Bailout_TypeBarrierV:
     case Bailout_ValueGuard:
     case Bailout_NullOrUndefinedGuard:
     case Bailout_MonitorTypes:
     case Bailout_Hole:
+    case Bailout_NoDenseElementsGuard:
     case Bailout_NegativeIndex:
     case Bailout_NonInt32Input:
     case Bailout_NonNumericInput:
     case Bailout_NonBooleanInput:
     case Bailout_NonObjectInput:
     case Bailout_NonStringInput:
     case Bailout_NonSymbolInput:
     case Bailout_NonBigIntInput:
--- a/js/src/jit/CacheIROps.yaml
+++ b/js/src/jit/CacheIROps.yaml
@@ -282,17 +282,17 @@
 
 - name: GuardFrameHasNoArgumentsObject
   shared: false
   transpile: false
   args:
 
 - name: GuardNoDenseElements
   shared: true
-  transpile: false
+  transpile: true
   args:
     obj: ObjId
 
 - name: GuardAndGetIndexFromString
   shared: true
   transpile: false
   args:
     str: StringId
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4438,16 +4438,28 @@ void CodeGenerator::visitGuardSpecificAt
 
 void CodeGenerator::visitGuardSpecificSymbol(LGuardSpecificSymbol* guard) {
   Register symbol = ToRegister(guard->symbol());
 
   bailoutCmpPtr(Assembler::NotEqual, symbol, ImmGCPtr(guard->mir()->expected()),
                 guard->snapshot());
 }
 
+void CodeGenerator::visitGuardNoDenseElements(LGuardNoDenseElements* guard) {
+  Register obj = ToRegister(guard->input());
+  Register temp = ToRegister(guard->temp());
+
+  // Load obj->elements.
+  masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), temp);
+
+  // Make sure there are no dense elements.
+  Address initLength(temp, ObjectElements::offsetOfInitializedLength());
+  bailoutCmp32(Assembler::NotEqual, initLength, Imm32(0), guard->snapshot());
+}
+
 void CodeGenerator::visitGuardReceiverPolymorphic(
     LGuardReceiverPolymorphic* lir) {
   const MGuardReceiverPolymorphic* mir = lir->mir();
   Register obj = ToRegister(lir->object());
   Register temp = ToRegister(lir->temp());
 
   Label done;
 
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -101,16 +101,19 @@ enum BailoutKind {
   // We tripped a type barrier (value was not in the expected TypeSet)
   Bailout_TypeBarrierV,
   // We tripped a type monitor (wrote an unexpected type in a property)
   Bailout_MonitorTypes,
 
   // We hit a hole in an array.
   Bailout_Hole,
 
+  // The object has dense array elements
+  Bailout_NoDenseElementsGuard,
+
   // Array access with negative index
   Bailout_NegativeIndex,
 
   // Array access with non integer index
   Bailout_NonIntegerIndex,
 
   // Pretty specific case:
   //  - need a type barrier on a property write
@@ -212,16 +215,18 @@ inline const char* BailoutKindString(Bai
     case Bailout_TypeBarrierO:
       return "Bailout_TypeBarrierO";
     case Bailout_TypeBarrierV:
       return "Bailout_TypeBarrierV";
     case Bailout_MonitorTypes:
       return "Bailout_MonitorTypes";
     case Bailout_Hole:
       return "Bailout_Hole";
+    case Bailout_NoDenseElementsGuard:
+      return "Bailout_NoDenseElementsGuard";
     case Bailout_NegativeIndex:
       return "Bailout_NegativeIndex";
     case Bailout_NonIntegerIndex:
       return "Bailout_NonIntegerIndex";
     case Bailout_ObjectIdentityOrTypeGuard:
       return "Bailout_ObjectIdentityOrTypeGuard";
     case Bailout_SpecificAtomGuard:
       return "Bailout_SpecifcAtomGuard";
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4023,16 +4023,24 @@ void LIRGenerator::visitGuardSpecificAto
 
 void LIRGenerator::visitGuardSpecificSymbol(MGuardSpecificSymbol* ins) {
   auto* guard = new (alloc()) LGuardSpecificSymbol(useRegister(ins->symbol()));
   assignSnapshot(guard, Bailout_SpecificSymbolGuard);
   add(guard, ins);
   redefine(ins, ins->symbol());
 }
 
+void LIRGenerator::visitGuardNoDenseElements(MGuardNoDenseElements* ins) {
+  auto* guard =
+      new (alloc()) LGuardNoDenseElements(useRegister(ins->object()), temp());
+  assignSnapshot(guard, Bailout_NoDenseElementsGuard);
+  add(guard, ins);
+  redefine(ins, ins->object());
+}
+
 void LIRGenerator::visitGuardShape(MGuardShape* ins) {
   MOZ_ASSERT(ins->object()->type() == MIRType::Object);
 
   if (JitOptions.spectreObjectMitigationsMisc) {
     auto* lir =
         new (alloc()) LGuardShape(useRegisterAtStart(ins->object()), temp());
     assignSnapshot(lir, Bailout_ShapeGuard);
     defineReuseInput(lir, ins, 0);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -9289,16 +9289,35 @@ class MGuardSpecificSymbol : public MUna
   MDefinition* foldsTo(TempAllocator& alloc) override;
   AliasSet getAliasSet() const override { return AliasSet::None(); }
 
   bool appendRoots(MRootList& roots) const override {
     return roots.append(expected_);
   }
 };
 
+class MGuardNoDenseElements : public MUnaryInstruction,
+                              public ObjectPolicy<0>::Data {
+  explicit MGuardNoDenseElements(MDefinition* obj)
+      : MUnaryInstruction(classOpcode, obj) {
+    setGuard();
+    setMovable();
+    setResultType(MIRType::Object);
+  }
+
+ public:
+  INSTRUCTION_HEADER(GuardNoDenseElements)
+  TRIVIAL_NEW_WRAPPERS
+  NAMED_OPERANDS((0, object))
+
+  AliasSet getAliasSet() const override {
+    return AliasSet::Load(AliasSet::ObjectFields);
+  }
+};
+
 // Load from vp[slot] (slots that are not inline in an object).
 class MLoadDynamicSlot : public MUnaryInstruction, public NoTypePolicy::Data {
   uint32_t slot_;
 
   MLoadDynamicSlot(MDefinition* slots, uint32_t slot)
       : MUnaryInstruction(classOpcode, slots), slot_(slot) {
     setResultType(MIRType::Value);
     setMovable();
--- a/js/src/jit/WarpCacheIRTranspiler.cpp
+++ b/js/src/jit/WarpCacheIRTranspiler.cpp
@@ -277,16 +277,26 @@ bool WarpCacheIRTranspiler::emitGuardSpe
 
   auto* ins = MGuardSpecificFunction::New(alloc(), obj, constObj, nargs, flags);
   add(ins);
 
   setOperand(objId, ins);
   return true;
 }
 
+bool WarpCacheIRTranspiler::emitGuardNoDenseElements(ObjOperandId objId) {
+  MDefinition* obj = getOperand(objId);
+
+  auto* ins = MGuardNoDenseElements::New(alloc(), obj);
+  add(ins);
+
+  setOperand(objId, ins);
+  return true;
+}
+
 bool WarpCacheIRTranspiler::emitGuardNonDoubleType(ValOperandId inputId,
                                                    ValueType type) {
   switch (type) {
     case ValueType::String:
     case ValueType::Symbol:
     case ValueType::BigInt:
     case ValueType::Int32:
     case ValueType::Boolean:
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -6085,16 +6085,29 @@ class LGuardObjectGroup : public LInstru
       : LInstructionHelper(classOpcode) {
     setOperand(0, in);
     setTemp(0, temp);
   }
   const LDefinition* temp() { return getTemp(0); }
   const MGuardObjectGroup* mir() const { return mir_->toGuardObjectGroup(); }
 };
 
+class LGuardNoDenseElements : public LInstructionHelper<0, 1, 1> {
+ public:
+  LIR_HEADER(GuardNoDenseElements)
+
+  LGuardNoDenseElements(const LAllocation& in, const LDefinition& temp)
+      : LInstructionHelper(classOpcode) {
+    setOperand(0, in);
+    setTemp(0, temp);
+  }
+
+  const LDefinition* temp() { return getTemp(0); }
+};
+
 // Guard against the sharedness of a TypedArray's memory.
 class LGuardSharedTypedArray : public LInstructionHelper<0, 1, 1> {
  public:
   LIR_HEADER(GuardSharedTypedArray)
 
   LGuardSharedTypedArray(const LAllocation& in, const LDefinition& temp)
       : LInstructionHelper(classOpcode) {
     setOperand(0, in);