Bug 1272269: IonMonkey - Reintroduce template object on the VM variant of MNewArray And MNewObject, r=efaust a=ritu
authorHannes Verschore <hv1989@gmail.com>
Mon, 23 May 2016 16:59:31 -0700
changeset 332986 dfe3d2e9bdbe8568c92f17789c6bebec119bdd3e
parent 332985 a0f48f447f41503a403053dc6f6b88a045a9d3a8
child 332987 a2baee5a734efd4bb9646e5ad06d7552d6618bcb
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust, ritu
bugs1272269
milestone48.0a2
Bug 1272269: IonMonkey - Reintroduce template object on the VM variant of MNewArray And MNewObject, r=efaust a=ritu
js/src/jit/CodeGenerator.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/shared/LIR-shared.h
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4902,17 +4902,17 @@ CodeGenerator::visitNewArray(LNewArray* 
 {
     Register objReg = ToRegister(lir->output());
     Register tempReg = ToRegister(lir->temp());
     JSObject* templateObject = lir->mir()->templateObject();
     DebugOnly<uint32_t> length = lir->mir()->length();
 
     MOZ_ASSERT(length <= NativeObject::MAX_DENSE_ELEMENTS_COUNT);
 
-    if (!templateObject) {
+    if (lir->mir()->isVMCall()) {
         visitNewArrayCallVM(lir);
         return;
     }
 
     OutOfLineNewArray* ool = new(alloc()) OutOfLineNewArray(lir);
     addOutOfLineCode(ool, lir->mir());
 
     masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(),
@@ -5159,17 +5159,17 @@ ShouldInitFixedSlots(LInstruction* lir, 
 
 void
 CodeGenerator::visitNewObject(LNewObject* lir)
 {
     Register objReg = ToRegister(lir->output());
     Register tempReg = ToRegister(lir->temp());
     JSObject* templateObject = lir->mir()->templateObject();
 
-    if (!templateObject) {
+    if (lir->mir()->isVMCall()) {
         visitNewObjectVMCall(lir);
         return;
     }
 
     OutOfLineNewObject* ool = new(alloc()) OutOfLineNewObject(lir);
     addOutOfLineCode(ool, lir->mir());
 
     bool initContents = ShouldInitFixedSlots(lir, templateObject);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -7245,27 +7245,33 @@ IonBuilder::newArrayTrySharedStub(bool* 
     if (!resumeAfter(stub))
         return false;
 
     *emitted = true;
     return true;
 }
 
 bool
-IonBuilder::newArrayTryVM(bool* emitted, uint32_t length)
+IonBuilder::newArrayTryVM(bool* emitted, JSObject* templateObject, uint32_t length)
 {
     MOZ_ASSERT(*emitted == false);
 
     // Emit a VM call.
 
     gc::InitialHeap heap = gc::DefaultHeap;
     MConstant* templateConst = MConstant::New(alloc(), NullValue());
+
+    if (templateObject) {
+        heap = templateObject->group()->initialHeap(constraints());
+        templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
+    }
+
     current->add(templateConst);
 
-    MNewArray* ins = MNewArray::New(alloc(), constraints(), length, templateConst, heap, pc);
+    MNewArray* ins = MNewArray::NewVM(alloc(), constraints(), length, templateConst, heap, pc);
     current->add(ins);
     current->push(ins);
 
     *emitted = true;
     return true;
 }
 
 bool
@@ -7293,17 +7299,17 @@ IonBuilder::jsop_newarray(JSObject* temp
     if (!forceInlineCaches()) {
         if (!newArrayTryTemplateObject(&emitted, templateObject, length) || emitted)
             return emitted;
     }
 
     if (!newArrayTrySharedStub(&emitted) || emitted)
         return emitted;
 
-    if (!newArrayTryVM(&emitted, length) || emitted)
+    if (!newArrayTryVM(&emitted, templateObject, length) || emitted)
         return emitted;
 
     MOZ_CRASH("newarray should have been emited");
 }
 
 bool
 IonBuilder::jsop_newarray_copyonwrite()
 {
@@ -7377,50 +7383,58 @@ IonBuilder::newObjectTrySharedStub(bool*
     if (!resumeAfter(stub))
         return false;
 
     *emitted = true;
     return true;
 }
 
 bool
-IonBuilder::newObjectTryVM(bool* emitted)
+IonBuilder::newObjectTryVM(bool* emitted, JSObject* templateObject)
 {
     // Emit a VM call.
+    MOZ_ASSERT(JSOp(*pc) == JSOP_NEWOBJECT || JSOp(*pc) == JSOP_NEWINIT);
 
     gc::InitialHeap heap = gc::DefaultHeap;
     MConstant* templateConst = MConstant::New(alloc(), NullValue());
+
+    if (templateObject) {
+        heap = templateObject->group()->initialHeap(constraints());
+        templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
+    }
+
     current->add(templateConst);
 
-    MNewObject* ins = MNewObject::New(alloc(), constraints(), templateConst, heap,
-                                     MNewObject::ObjectLiteral);
+    MNewObject* ins = MNewObject::NewVM(alloc(), constraints(), templateConst, heap,
+                                        MNewObject::ObjectLiteral);
     current->add(ins);
     current->push(ins);
 
     if (!resumeAfter(ins))
         return false;
 
     *emitted = true;
     return true;
 }
 
 bool
 IonBuilder::jsop_newobject()
 {
     bool emitted = false;
 
+    JSObject* templateObject = inspector->getTemplateObject(pc);
+
     if (!forceInlineCaches()) {
-        JSObject* templateObject = inspector->getTemplateObject(pc);
         if (!newObjectTryTemplateObject(&emitted, templateObject) || emitted)
             return emitted;
     }
     if (!newObjectTrySharedStub(&emitted) || emitted)
         return emitted;
 
-    if (!newObjectTryVM(&emitted) || emitted)
+    if (!newObjectTryVM(&emitted, templateObject) || emitted)
         return emitted;
 
     MOZ_CRASH("newobject should have been emited");
 }
 
 bool
 IonBuilder::jsop_initelem()
 {
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -511,22 +511,22 @@ class IonBuilder
     bool compareTryBitwise(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
     bool compareTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, MDefinition* left,
                                                   MDefinition* right);
     bool compareTrySharedStub(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
 
     // jsop_newarray helpers.
     bool newArrayTrySharedStub(bool* emitted);
     bool newArrayTryTemplateObject(bool* emitted, JSObject* templateObject, uint32_t length);
-    bool newArrayTryVM(bool* emitted, uint32_t length);
+    bool newArrayTryVM(bool* emitted, JSObject* templateObject, uint32_t length);
 
     // jsop_newobject helpers.
     bool newObjectTrySharedStub(bool* emitted);
     bool newObjectTryTemplateObject(bool* emitted, JSObject* templateObject);
-    bool newObjectTryVM(bool* emitted);
+    bool newObjectTryVM(bool* emitted, JSObject* templateObject);
 
     // jsop_in helpers.
     bool inTryDense(bool* emitted, MDefinition* obj, MDefinition* id);
     bool inTryFold(bool* emitted, MDefinition* obj, MDefinition* id);
 
     // binary data lookup helpers.
     TypedObjectPrediction typedObjectPrediction(MDefinition* typedObj);
     TypedObjectPrediction typedObjectPrediction(TemporaryTypeSet* types);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -4525,22 +4525,23 @@ MArrayState::Copy(TempAllocator& alloc, 
     if (!res || !res->init(alloc, arr, len))
         return nullptr;
     for (size_t i = 0; i < res->numElements(); i++)
         res->initElement(i, state->getElement(i));
     return res;
 }
 
 MNewArray::MNewArray(CompilerConstraintList* constraints, uint32_t length, MConstant* templateConst,
-                     gc::InitialHeap initialHeap, jsbytecode* pc)
+                     gc::InitialHeap initialHeap, jsbytecode* pc, bool vmCall)
   : MUnaryInstruction(templateConst),
     length_(length),
     initialHeap_(initialHeap),
     convertDoubleElements_(false),
-    pc_(pc)
+    pc_(pc),
+    vmCall_(vmCall)
 {
     setResultType(MIRType_Object);
     if (templateObject()) {
         if (TemporaryTypeSet* types = MakeSingletonTypeSet(constraints, templateObject())) {
             setResultTypeSet(types);
             if (types->convertDoubleElements(constraints) == TemporaryTypeSet::AlwaysConvertToDoubles)
                 convertDoubleElements_ = true;
         }
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -3053,27 +3053,36 @@ class MNewArray
     // Heap where the array should be allocated.
     gc::InitialHeap initialHeap_;
 
     // Whether values written to this array should be converted to double first.
     bool convertDoubleElements_;
 
     jsbytecode* pc_;
 
+    bool vmCall_;
+
     MNewArray(CompilerConstraintList* constraints, uint32_t length, MConstant* templateConst,
-              gc::InitialHeap initialHeap, jsbytecode* pc);
+              gc::InitialHeap initialHeap, jsbytecode* pc, bool vmCall);
 
   public:
     INSTRUCTION_HEADER(NewArray)
 
     static MNewArray* New(TempAllocator& alloc, CompilerConstraintList* constraints,
                           uint32_t length, MConstant* templateConst,
                           gc::InitialHeap initialHeap, jsbytecode* pc)
     {
-        return new(alloc) MNewArray(constraints, length, templateConst, initialHeap, pc);
+        return new(alloc) MNewArray(constraints, length, templateConst, initialHeap, pc, false);
+    }
+
+    static MNewArray* NewVM(TempAllocator& alloc, CompilerConstraintList* constraints,
+                            uint32_t length, MConstant* templateConst,
+                            gc::InitialHeap initialHeap, jsbytecode* pc)
+    {
+        return new(alloc) MNewArray(constraints, length, templateConst, initialHeap, pc, true);
     }
 
     uint32_t length() const {
         return length_;
     }
 
     JSObject* templateObject() const {
         return getOperand(0)->toConstant()->toObjectOrNull();
@@ -3082,16 +3091,20 @@ class MNewArray
     gc::InitialHeap initialHeap() const {
         return initialHeap_;
     }
 
     jsbytecode* pc() const {
         return pc_;
     }
 
+    bool isVMCall() const {
+        return vmCall_;
+    }
+
     bool convertDoubleElements() const {
         return convertDoubleElements_;
     }
 
     // NewArray is marked as non-effectful because all our allocations are
     // either lazy when we are using "new Array(length)" or bounded by the
     // script or the stack size when we are using "new Array(...)" or "[...]"
     // notations.  So we might have to allocate the array twice if we bail
@@ -3197,22 +3210,24 @@ class MNewObject
     public NoTypePolicy::Data
 {
   public:
     enum Mode { ObjectLiteral, ObjectCreate };
 
   private:
     gc::InitialHeap initialHeap_;
     Mode mode_;
+    bool vmCall_;
 
     MNewObject(CompilerConstraintList* constraints, MConstant* templateConst,
-               gc::InitialHeap initialHeap, Mode mode)
+               gc::InitialHeap initialHeap, Mode mode, bool vmCall)
       : MUnaryInstruction(templateConst),
         initialHeap_(initialHeap),
-        mode_(mode)
+        mode_(mode),
+        vmCall_(vmCall)
     {
         MOZ_ASSERT_IF(mode != ObjectLiteral, templateObject());
         setResultType(MIRType_Object);
 
         if (JSObject* obj = templateObject())
             setResultTypeSet(MakeSingletonTypeSet(constraints, obj));
 
         // The constant is kept separated in a MConstant, this way we can safely
@@ -3226,31 +3241,42 @@ class MNewObject
 
   public:
     INSTRUCTION_HEADER(NewObject)
 
     static MNewObject* New(TempAllocator& alloc, CompilerConstraintList* constraints,
                            MConstant* templateConst, gc::InitialHeap initialHeap,
                            Mode mode)
     {
-        return new(alloc) MNewObject(constraints, templateConst, initialHeap, mode);
+        return new(alloc) MNewObject(constraints, templateConst, initialHeap, mode, false);
+    }
+
+    static MNewObject* NewVM(TempAllocator& alloc, CompilerConstraintList* constraints,
+                             MConstant* templateConst, gc::InitialHeap initialHeap,
+                             Mode mode)
+    {
+        return new(alloc) MNewObject(constraints, templateConst, initialHeap, mode, true);
     }
 
     Mode mode() const {
         return mode_;
     }
 
     JSObject* templateObject() const {
         return getOperand(0)->toConstant()->toObjectOrNull();
     }
 
     gc::InitialHeap initialHeap() const {
         return initialHeap_;
     }
 
+    bool isVMCall() const {
+        return vmCall_;
+    }
+
     bool writeRecoverData(CompactBufferWriter& writer) const override;
     bool canRecoverOnBailout() const override {
         // The template object can safely be used in the recover instruction
         // because it can never be mutated by any other function execution.
         return templateObject() != nullptr;
     }
 };
 
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -886,17 +886,17 @@ class LNewArray : public LInstructionHel
   public:
     LIR_HEADER(NewArray)
 
     explicit LNewArray(const LDefinition& temp) {
         setTemp(0, temp);
     }
 
     const char* extraName() const {
-        return mir()->templateObject() ? "VMCall" : nullptr;
+        return mir()->isVMCall() ? "VMCall" : nullptr;
     }
 
     const LDefinition* temp() {
         return getTemp(0);
     }
 
     MNewArray* mir() const {
         return mir_->toNewArray();
@@ -948,17 +948,17 @@ class LNewObject : public LInstructionHe
   public:
     LIR_HEADER(NewObject)
 
     explicit LNewObject(const LDefinition& temp) {
         setTemp(0, temp);
     }
 
     const char* extraName() const {
-        return mir()->templateObject() ? "VMCall" : nullptr;
+        return mir()->isVMCall() ? "VMCall" : nullptr;
     }
 
     const LDefinition* temp() {
         return getTemp(0);
     }
 
     MNewObject* mir() const {
         return mir_->toNewObject();