Bug 1272269: IonMonkey - Reintroduce template object on the VM variant of MNewArray And MNewObject, r=efaust a=ritu
--- 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();