Bug 1639159 - Transpile LoadProto. r=jandem
authorTom Schuster <evilpies@gmail.com>
Wed, 20 May 2020 18:18:01 +0000
changeset 531299 1704b3d9cf33e89fc6c9783596ccfbe8ca134d8f
parent 531298 6c10970490f3cc19e644964f583be1a047c08b2c
child 531300 6e5ab322dc4d0a68833dbd73e55a4657d0c219c2
push id37437
push usernerli@mozilla.com
push dateThu, 21 May 2020 02:34:41 +0000
treeherdermozilla-central@3d91ba9e1d25 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1639159
milestone78.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 1639159 - Transpile LoadProto. r=jandem Due to the previous guards emitted by CacheIR we know that this is always going to load a static prototype. For example using MGetPrototypeOf would also try to handle dynamic prototypes. I added a JIT assertion to make sure this assumption holds. Differential Revision: https://phabricator.services.mozilla.com/D75925
js/src/jit/AliasAnalysis.cpp
js/src/jit/CacheIROps.yaml
js/src/jit/CodeGenerator.cpp
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
@@ -140,16 +140,17 @@ static inline const MDefinition* GetObje
     case MDefinition::Opcode::InArray:
     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:
       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/CacheIROps.yaml
+++ b/js/src/jit/CacheIROps.yaml
@@ -428,17 +428,17 @@
   shared: true
   transpile: true
   args:
     result: ObjId
     obj: ObjectField
 
 - name: LoadProto
   shared: true
-  transpile: false
+  transpile: true
   args:
     obj: ObjId
     result: ObjId
 
 - name: LoadEnclosingEnvironment
   shared: true
   transpile: true
   args:
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -14491,16 +14491,33 @@ void CodeGenerator::visitGetPrototypeOf(
 
 void CodeGenerator::visitObjectWithProto(LObjectWithProto* lir) {
   pushArg(ToValue(lir, LObjectWithProto::PrototypeValue));
 
   using Fn = PlainObject* (*)(JSContext*, HandleValue);
   callVM<Fn, js::ObjectWithProtoOperation>(lir);
 }
 
+void CodeGenerator::visitObjectStaticProto(LObjectStaticProto* lir) {
+  Register obj = ToRegister(lir->input());
+  Register output = ToRegister(lir->output());
+
+  masm.loadObjProto(obj, output);
+
+#ifdef DEBUG
+  // We shouldn't encounter a null or lazy proto.
+  MOZ_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1);
+
+  Label done;
+  masm.branchPtr(Assembler::Above, output, ImmWord(1), &done);
+  masm.assumeUnreachable("Unexpected null or lazy proto in MObjectStaticProto");
+  masm.bind(&done);
+#endif
+}
+
 void CodeGenerator::visitFunctionProto(LFunctionProto* lir) {
   using Fn = JSObject* (*)(JSContext*);
   callVM<Fn, js::FunctionProtoOperation>(lir);
 }
 
 void CodeGenerator::visitSuperFunction(LSuperFunction* lir) {
   Register callee = ToRegister(lir->callee());
   ValueOperand out = ToOutValue(lir);
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -5007,16 +5007,25 @@ void LIRGenerator::visitObjectWithProto(
   MOZ_ASSERT(ins->prototype()->type() == MIRType::Value);
   MOZ_ASSERT(ins->type() == MIRType::Object);
 
   auto* lir = new (alloc()) LObjectWithProto(useBoxAtStart(ins->prototype()));
   defineReturn(lir, ins);
   assignSafepoint(lir, ins);
 }
 
+void LIRGenerator::visitObjectStaticProto(MObjectStaticProto* ins) {
+  MOZ_ASSERT(ins->object()->type() == MIRType::Object);
+  MOZ_ASSERT(ins->type() == MIRType::Object);
+
+  auto* lir =
+      new (alloc()) LObjectStaticProto(useRegisterAtStart(ins->object()));
+  define(lir, ins);
+};
+
 void LIRGenerator::visitFunctionProto(MFunctionProto* ins) {
   MOZ_ASSERT(ins->type() == MIRType::Object);
 
   auto* lir = new (alloc()) LFunctionProto();
   defineReturn(lir, ins);
   assignSafepoint(lir, ins);
 }
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -11230,16 +11230,36 @@ class MObjectWithProto : public MUnaryIn
  public:
   INSTRUCTION_HEADER(ObjectWithProto)
   TRIVIAL_NEW_WRAPPERS
   NAMED_OPERANDS((0, prototype))
 
   bool possiblyCalls() const override { return true; }
 };
 
+// Used to load the prototype of an object known to have
+// a static prototype.
+class MObjectStaticProto : public MUnaryInstruction,
+                           public SingleObjectPolicy::Data {
+  explicit MObjectStaticProto(MDefinition* object)
+      : MUnaryInstruction(classOpcode, object) {
+    setResultType(MIRType::Object);
+    setMovable();
+  }
+
+ public:
+  INSTRUCTION_HEADER(ObjectStaticProto)
+  TRIVIAL_NEW_WRAPPERS
+  NAMED_OPERANDS((0, object))
+
+  AliasSet getAliasSet() const override {
+    return AliasSet::Load(AliasSet::ObjectFields);
+  }
+};
+
 class MFunctionProto : public MNullaryInstruction {
   explicit MFunctionProto() : MNullaryInstruction(classOpcode) {
     setResultType(MIRType::Object);
   }
 
  public:
   INSTRUCTION_HEADER(FunctionProto)
   TRIVIAL_NEW_WRAPPERS
--- a/js/src/jit/WarpCacheIRTranspiler.cpp
+++ b/js/src/jit/WarpCacheIRTranspiler.cpp
@@ -409,16 +409,26 @@ bool WarpCacheIRTranspiler::emitLoadObje
   JSObject* obj = objectStubField(objOffset);
 
   auto* ins = MConstant::NewConstraintlessObject(alloc(), obj);
   add(ins);
 
   return defineOperand(resultId, ins);
 }
 
+bool WarpCacheIRTranspiler::emitLoadProto(ObjOperandId objId,
+                                          ObjOperandId resultId) {
+  MDefinition* obj = getOperand(objId);
+
+  auto* ins = MObjectStaticProto::New(alloc(), obj);
+  add(ins);
+
+  return defineOperand(resultId, ins);
+}
+
 bool WarpCacheIRTranspiler::emitLoadDynamicSlotResult(ObjOperandId objId,
                                                       uint32_t offsetOffset) {
   int32_t offset = int32StubField(offsetOffset);
 
   MDefinition* obj = getOperand(objId);
   size_t slotIndex = NativeObject::getDynamicSlotIndexFromOffset(offset);
 
   auto* slots = MSlots::New(alloc(), obj);
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -7509,16 +7509,26 @@ class LObjectWithProto : public LCallIns
   static const size_t PrototypeValue = 0;
 
   explicit LObjectWithProto(const LBoxAllocation& prototype)
       : LCallInstructionHelper(classOpcode) {
     setBoxOperand(PrototypeValue, prototype);
   }
 };
 
+class LObjectStaticProto : public LInstructionHelper<1, 1, 0> {
+ public:
+  LIR_HEADER(ObjectStaticProto)
+
+  explicit LObjectStaticProto(const LAllocation& object)
+      : LInstructionHelper(classOpcode) {
+    setOperand(0, object);
+  }
+};
+
 class LFunctionProto : public LCallInstructionHelper<1, 0, 0> {
  public:
   LIR_HEADER(FunctionProto)
 
   LFunctionProto() : LCallInstructionHelper(classOpcode) {}
 
   MFunctionProto* mir() const { return mir_->toFunctionProto(); }
 };