Bug 1364908 - IonMonkey: Add LoadElementFromSate to support argument[x] in inlined functions. r=jandem

This commit is contained in:
Nicolas B. Pierron 2017-07-18 12:08:22 +00:00
parent d6ec64d163
commit a1f0784e66
18 changed files with 606 additions and 27 deletions

View File

@ -42,7 +42,8 @@ namespace JS {
_(GetElem_TypedArray) \
_(GetElem_String) \
_(GetElem_Arguments) \
_(GetElem_ArgumentsInlined) \
_(GetElem_ArgumentsInlinedConstant) \
_(GetElem_ArgumentsInlinedSwitch) \
_(GetElem_InlineCache) \
\
_(SetElem_TypedObject) \

View File

@ -0,0 +1,59 @@
function cat() {
var res = "";
for (var i = 0; i < arguments.length; i++)
res += arguments[i];
return res;
}
function cat_m1(ion) {
var res = "";
for (var i = (ion ? -1 : 0); i < arguments.length; i++)
res += arguments[i];
return res;
}
function cat_p1(ion) {
var res = "";
for (var i = 0; i < arguments.length + (ion ? 1 : 0); i++)
res += arguments[i];
return res;
}
function sum() {
var res = 0;
for (var i = 0; i < arguments.length; i++)
res += arguments[i];
return res;
}
function wrapper() {
var res;
var i6 = { valueOf: () => 6 },
i8 = 8.5,
s2 = { toString: () => "2" },
s4 = {},
s6 = "6",
s7 = undefined,
s8 = null;
for (var b = true; b; b = !inIon()) {
res = sum(1,2,3,4,5,i6,7,i8,9,10);
assertEq(res, 55.5);
res = cat(true,s2,3,s4,5,s6,s7,s8);
assertEq(res, "true23[object Object]56undefinednull");
ion = inIon();
if (typeof ion !== "boolean") break;
res = cat_m1(ion,1,s2,3,s4,5,s6,s7,s8);
if (ion) assertEq(res, "undefinedtrue123[object Object]56undefinednull");
else assertEq(res, "false123[object Object]56undefinednull");
ion = inIon();
if (typeof ion !== "boolean") break;
res = cat_p1(ion,1,s2,3,s4,5,s6,s7,s8);
if (ion) assertEq(res, "true123[object Object]56undefinednullundefined");
else assertEq(res, "false123[object Object]56undefinednull");
}
}
wrapper();

View File

@ -42,6 +42,7 @@
#include "jit/MoveEmitter.h"
#include "jit/RangeAnalysis.h"
#include "jit/SharedICHelpers.h"
#include "jit/StackSlotAllocator.h"
#include "vm/AsyncFunction.h"
#include "vm/AsyncIteration.h"
#include "vm/MatchPairs.h"
@ -11023,6 +11024,238 @@ CodeGenerator::visitLoadTypedArrayElementHole(LLoadTypedArrayElementHole* lir)
masm.bind(&done);
}
template <SwitchTableType tableType>
class OutOfLineSwitch : public OutOfLineCodeBase<CodeGenerator>
{
using LabelsVector = Vector<Label, 0, JitAllocPolicy>;
using CodeLabelsVector = Vector<CodeLabel, 0, JitAllocPolicy>;
LabelsVector labels_;
CodeLabelsVector codeLabels_;
CodeLabel start_;
bool isOutOfLine_;
void accept(CodeGenerator* codegen) {
codegen->visitOutOfLineSwitch(this);
}
public:
explicit OutOfLineSwitch(TempAllocator& alloc)
: labels_(alloc),
codeLabels_(alloc),
isOutOfLine_(false)
{}
CodeLabel* start() {
return &start_;
}
CodeLabelsVector& codeLabels() {
return codeLabels_;
}
LabelsVector& labels() {
return labels_;
}
void jumpToCodeEntries(MacroAssembler& masm, Register index, Register temp) {
Register base;
if (tableType == SwitchTableType::Inline) {
#if defined(JS_CODEGEN_ARM)
base = ::js::jit::pc;
#else
MOZ_CRASH("NYI: SwitchTableType::Inline");
#endif
} else {
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
MOZ_CRASH("NYI: SwitchTableType::OutOfLine");
#else
masm.mov(start_.patchAt(), temp);
base = temp;
#endif
}
BaseIndex jumpTarget(base, index, ScalePointer);
masm.branchToComputedAddress(jumpTarget);
}
// Register an entry in the switch table.
void addTableEntry(MacroAssembler& masm) {
if ((!isOutOfLine_ && tableType == SwitchTableType::Inline) ||
(isOutOfLine_ && tableType == SwitchTableType::OutOfLine))
{
CodeLabel cl;
masm.writeCodePointer(cl.patchAt());
masm.propagateOOM(codeLabels_.append(mozilla::Move(cl)));
}
}
// Register the code, to which the table will jump to.
void addCodeEntry(MacroAssembler& masm) {
Label entry;
masm.bind(&entry);
masm.propagateOOM(labels_.append(mozilla::Move(entry)));
}
void setOutOfLine() {
isOutOfLine_ = true;
}
};
template <SwitchTableType tableType>
void
CodeGenerator::visitOutOfLineSwitch(OutOfLineSwitch<tableType>* jumpTable)
{
jumpTable->setOutOfLine();
if (tableType == SwitchTableType::OutOfLine) {
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
MOZ_CRASH("NYI: SwitchTableType::OutOfLine");
#else
masm.haltingAlign(sizeof(void*));
masm.use(jumpTable->start()->target());
masm.addCodeLabel(*jumpTable->start());
#endif
}
// Add table entries if the table is inlined.
auto& labels = jumpTable->labels();
for (size_t i = 0, e = labels.length(); i < e; i++)
jumpTable->addTableEntry(masm);
auto& codeLabels = jumpTable->codeLabels();
for (size_t i = 0, e = codeLabels.length(); i < e; i++) {
// The entries of the jump table need to be absolute addresses and thus
// must be patched after codegen is finished.
auto& cl = codeLabels[i];
cl.target()->bind(labels[i].offset());
masm.addCodeLabel(cl);
}
}
template void CodeGenerator::visitOutOfLineSwitch(OutOfLineSwitch<SwitchTableType::Inline>* jumpTable);
template void CodeGenerator::visitOutOfLineSwitch(OutOfLineSwitch<SwitchTableType::OutOfLine>* jumpTable);
void
CodeGenerator::visitLoadElementFromStateV(LLoadElementFromStateV* lir)
{
Register index = ToRegister(lir->index());
Register temp0 = ToRegister(lir->temp0());
#ifdef JS_NUNBOX32
Register temp1 = ToRegister(lir->temp1());
#endif
FloatRegister tempD = ToFloatRegister(lir->tempD());
ValueOperand out = ToOutValue(lir);
// For each element, load it and box it.
MArgumentState* array = lir->array()->toArgumentState();
Label join;
// Jump to the code which is loading the element, based on its index.
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
auto* jumpTable = new (alloc()) OutOfLineSwitch<SwitchTableType::Inline>(alloc());
#else
auto* jumpTable = new (alloc()) OutOfLineSwitch<SwitchTableType::OutOfLine>(alloc());
#endif
{
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
// Inhibit pools within the following sequence because we are indexing into
// a pc relative table. The region will have one instruction for ma_ldr, one
// for breakpoint, and each table case takes one word.
AutoForbidPools afp(&masm, 1 + 1 + array->numElements());
#endif
jumpTable->jumpToCodeEntries(masm, index, temp0);
// Add table entries if the table is inlined.
for (size_t i = 0, e = array->numElements(); i < e; i++)
jumpTable->addTableEntry(masm);
}
// Add inlined code for loading arguments from where they are allocated.
for (size_t i = 0, e = array->numElements(); i < e; i++) {
MDefinition* elem = array->getElement(i);
ConstantOrRegister input;
jumpTable->addCodeEntry(masm);
Register typeReg = Register::Invalid();
const LAllocation* a = lir->getOperand(1 + BOX_PIECES * i);
if (a->isBogus()) {
if (elem->type() == MIRType::Null) {
input = NullValue();
} else if (elem->type() == MIRType::Undefined) {
input = UndefinedValue();
} else if (elem->isConstant() && elem->isEmittedAtUses()) {
input = elem->toConstant()->toJSValue();
} else {
MOZ_CRASH("Unsupported element constant allocation.");
}
} else if (a->isMemory()) {
if (elem->type() == MIRType::Double) {
masm.loadDouble(ToAddress(a), tempD);
input = TypedOrValueRegister(elem->type(), AnyRegister(tempD));
} else if (elem->type() == MIRType::Value) {
typeReg = temp0;
masm.loadPtr(ToAddress(a), temp0);
#ifdef JS_PUNBOX64
input = TypedOrValueRegister(ValueOperand(temp0));
#endif
} else {
typeReg = temp0;
size_t width = StackSlotAllocator::width(LDefinition::TypeFrom(elem->type()));
if (width == 4)
masm.load32(ToAddress(a), temp0);
else if (width == 8)
masm.loadPtr(ToAddress(a), temp0);
else
MOZ_CRASH("Unsupported load size");
input = TypedOrValueRegister(elem->type(), AnyRegister(typeReg));
}
} else if (a->isGeneralReg()) {
typeReg = ToRegister(a);
input = TypedOrValueRegister(elem->type(), AnyRegister(typeReg));
#ifdef JS_PUNBOX64
if (elem->type() != MIRType::Value)
input = TypedOrValueRegister(elem->type(), AnyRegister(typeReg));
else
input = TypedOrValueRegister(ValueOperand(typeReg));
#else
if (elem->type() != MIRType::Value)
input = TypedOrValueRegister(elem->type(), AnyRegister(typeReg));
#endif
} else if (a->isFloatReg()) {
input = TypedOrValueRegister(elem->type(), AnyRegister(ToFloatRegister(a)));
} else if (a->isConstantValue()) {
input = a->toConstant()->toJSValue();
} else {
MOZ_CRASH("Unsupported element allocation.");
}
#ifdef JS_NUNBOX32
if (elem->type() == MIRType::Value) {
static_assert(TYPE_INDEX == 0, "Unexpected type allocation index");
static_assert(PAYLOAD_INDEX == 1, "Unexpected payload allocation index");
const LAllocation* a1 = lir->getOperand(1 + BOX_PIECES * i + 1);
MOZ_ASSERT(!a1->isBogus());
MOZ_ASSERT(typeReg != Register::Invalid());
if (a1->isMemory()) {
masm.loadPtr(ToAddress(a1), temp1);
input = TypedOrValueRegister(ValueOperand(typeReg, temp1));
} else if (a1->isGeneralReg()) {
input = TypedOrValueRegister(ValueOperand(typeReg, ToRegister(a1)));
} else {
MOZ_CRASH("Unsupported Value allocation.");
}
} else {
MOZ_ASSERT(lir->getOperand(1 + BOX_PIECES * i + 1)->isBogus());
}
#endif
masm.moveValue(input, out);
// For the last entry, fall-through.
if (i + 1 < e)
masm.jump(&join);
}
addOutOfLineCode(jumpTable, lir->mir());
masm.bind(&join);
}
template <typename T>
static inline void
StoreToTypedArray(MacroAssembler& masm, Scalar::Type writeType, const LAllocation* value,

View File

@ -33,6 +33,12 @@
namespace js {
namespace jit {
enum class SwitchTableType {
Inline,
OutOfLine
};
template <SwitchTableType tableType> class OutOfLineSwitch;
class OutOfLineTestObject;
class OutOfLineNewArray;
class OutOfLineNewObject;
@ -307,6 +313,9 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitLoadUnboxedPointerV(LLoadUnboxedPointerV* lir);
void visitLoadUnboxedPointerT(LLoadUnboxedPointerT* lir);
void visitUnboxObjectOrNull(LUnboxObjectOrNull* lir);
template <SwitchTableType tableType>
void visitOutOfLineSwitch(OutOfLineSwitch<tableType>* ool);
void visitLoadElementFromStateV(LLoadElementFromStateV* lir);
void visitStoreElementT(LStoreElementT* lir);
void visitStoreElementV(LStoreElementV* lir);
template <typename T> void emitStoreElementHoleT(T* lir);

View File

@ -7735,14 +7735,21 @@ IonBuilder::jsop_getelem()
if (emitted)
return Ok();
trackOptimizationAttempt(TrackedStrategy::GetElem_ArgumentsInlined);
MOZ_TRY(getElemTryArgumentsInlined(&emitted, obj, index));
trackOptimizationAttempt(TrackedStrategy::GetElem_ArgumentsInlinedConstant);
MOZ_TRY(getElemTryArgumentsInlinedConstant(&emitted, obj, index));
if (emitted)
return Ok();
if (script()->argumentsHasVarBinding())
trackOptimizationAttempt(TrackedStrategy::GetElem_ArgumentsInlinedSwitch);
MOZ_TRY(getElemTryArgumentsInlinedIndex(&emitted, obj, index));
if (emitted)
return Ok();
if (script()->argumentsHasVarBinding()) {
trackOptimizationOutcome(TrackedOutcome::NoTypeInfo);
return abort(AbortReason::Disable, "Type is not definitely lazy arguments.");
}
}
obj = maybeUnboxForPropertyAccess(obj);
if (obj->type() == MIRType::Object)
@ -8393,7 +8400,7 @@ IonBuilder::getElemTryArguments(bool* emitted, MDefinition* obj, MDefinition* in
}
AbortReasonOr<Ok>
IonBuilder::getElemTryArgumentsInlined(bool* emitted, MDefinition* obj, MDefinition* index)
IonBuilder::getElemTryArgumentsInlinedConstant(bool* emitted, MDefinition* obj, MDefinition* index)
{
MOZ_ASSERT(*emitted == false);
@ -8403,14 +8410,16 @@ IonBuilder::getElemTryArgumentsInlined(bool* emitted, MDefinition* obj, MDefinit
if (obj->type() != MIRType::MagicOptimizedArguments)
return Ok();
MConstant* indexConst = index->maybeConstantValue();
if (!indexConst || indexConst->type() != MIRType::Int32)
return Ok();
// Emit inlined arguments.
obj->setImplicitlyUsedUnchecked();
MOZ_ASSERT(!info().argsObjAliasesFormals());
// When the id is constant, we can just return the corresponding inlined argument
MConstant* indexConst = index->maybeConstantValue();
if (indexConst && indexConst->type() == MIRType::Int32) {
MOZ_ASSERT(inliningDepth_ > 0);
int32_t id = indexConst->toInt32();
@ -8426,8 +8435,58 @@ IonBuilder::getElemTryArgumentsInlined(bool* emitted, MDefinition* obj, MDefinit
return Ok();
}
// inlined not constant not supported, yet.
return abort(AbortReason::Disable, "NYI inlined not constant get argument element");
AbortReasonOr<Ok>
IonBuilder::getElemTryArgumentsInlinedIndex(bool* emitted, MDefinition* obj, MDefinition* index)
{
MOZ_ASSERT(*emitted == false);
if (inliningDepth_ == 0)
return Ok();
if (obj->type() != MIRType::MagicOptimizedArguments)
return Ok();
if (!IsNumberType(index->type()))
return Ok();
// Currently, we do not support any arguments vector larger than 10, as this
// is being translated into code at the call site, and it would be better to
// store the arguments contiguously on the stack.
if (inlineCallInfo_->argc() > 10) {
trackOptimizationOutcome(TrackedOutcome::CantInlineBound);
return abort(AbortReason::Disable, "NYI get argument element with too many arguments");
}
// Emit inlined arguments.
obj->setImplicitlyUsedUnchecked();
MOZ_ASSERT(!info().argsObjAliasesFormals());
// Ensure index is an integer.
MInstruction* idInt32 = MToInt32::New(alloc(), index);
current->add(idInt32);
index = idInt32;
// Bailout if we read more than the number of actual arguments. This bailout
// cannot re-enter because reading out of bounds arguments will disable the
// lazy arguments optimization for this script, when this code would be
// executed in Baseline. (see GetElemOptimizedArguments)
index = addBoundsCheck(index, constantInt(inlineCallInfo_->argc()));
// Get an instruction to represent the state of the argument vector.
MInstruction* args = MArgumentState::New(alloc().fallible(), inlineCallInfo_->argv());
if (!args)
return abort(AbortReason::Alloc);
current->add(args);
// Select a value to pick from a vector.
MInstruction* load = MLoadElementFromState::New(alloc(), args, index);
current->add(load);
current->push(load);
trackOptimizationSuccess();
*emitted = true;
return Ok();
}
AbortReasonOr<Ok>

View File

@ -427,7 +427,9 @@ class IonBuilder
AbortReasonOr<Ok> getElemTryTypedObject(bool* emitted, MDefinition* obj, MDefinition* index);
AbortReasonOr<Ok> getElemTryString(bool* emitted, MDefinition* obj, MDefinition* index);
AbortReasonOr<Ok> getElemTryArguments(bool* emitted, MDefinition* obj, MDefinition* index);
AbortReasonOr<Ok> getElemTryArgumentsInlined(bool* emitted, MDefinition* obj,
AbortReasonOr<Ok> getElemTryArgumentsInlinedConstant(bool* emitted, MDefinition* obj,
MDefinition* index);
AbortReasonOr<Ok> getElemTryArgumentsInlinedIndex(bool* emitted, MDefinition* obj,
MDefinition* index);
AbortReasonOr<Ok> getElemAddCache(MDefinition* obj, MDefinition* index);
AbortReasonOr<Ok> getElemTryScalarElemOfTypedObject(bool* emitted,

View File

@ -1177,6 +1177,14 @@ class LVariadicInstruction : public details::LInstructionFixedDefsTempsHelper<De
void setOperand(size_t index, const LAllocation& a) final override {
operands_[index] = a;
}
void setBoxOperand(size_t index, const LBoxAllocation& a) {
#ifdef JS_NUNBOX32
operands_[index + TYPE_INDEX] = a.type();
operands_[index + PAYLOAD_INDEX] = a.payload();
#else
operands_[index] = a.value();
#endif
}
};
template <size_t Defs, size_t Operands, size_t Temps>

View File

@ -3235,6 +3235,73 @@ LIRGenerator::visitLoadUnboxedString(MLoadUnboxedString* ins)
define(lir, ins);
}
void
LIRGenerator::visitLoadElementFromState(MLoadElementFromState* ins)
{
MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
LDefinition temp1 = LDefinition::BogusTemp();
#ifdef JS_NUNBOX32
temp1 = temp();
#endif
LLoadElementFromStateV* lir = new(alloc()) LLoadElementFromStateV(temp(), temp1, tempDouble());
MOZ_ASSERT(ins->array()->isArgumentState(),
"LIRGenerator::visitLoadElementFromState: Unsupported state object");
MArgumentState* array = ins->array()->toArgumentState();
// 1 -- for the index as a register
// BOX_PIECES * array->numElements() -- for using as operand all the
// elements of the inlined array.
size_t numOperands = 1 + BOX_PIECES * array->numElements();
if (!lir->init(alloc(), numOperands)) {
abort(AbortReason::Alloc, "OOM: LIRGenerator::visitLoadElementFromState");
return;
}
lir->setOperand(0, useRegister(ins->index())); // index
for (size_t i = 0, e = array->numElements(); i < e; i++) {
MDefinition* elem = array->getElement(i);
if (elem->isConstant() && elem->isEmittedAtUses()) {
lir->setOperand(1 + BOX_PIECES * i, LAllocation());
#ifdef JS_NUNBOX32
lir->setOperand(1 + BOX_PIECES * i + 1, LAllocation());
#endif
continue;
}
switch (array->getElement(i)->type()) {
case MIRType::Value:
lir->setBoxOperand(1 + BOX_PIECES * i, useBox(elem, LUse::ANY));
break;
// Anything which can be boxed:
case MIRType::Boolean:
case MIRType::Int32:
case MIRType::Double:
case MIRType::Object:
case MIRType::String:
case MIRType::Symbol:
lir->setOperand(1 + BOX_PIECES * i, use(elem));
#ifdef JS_NUNBOX32
// Bogus second operand.
lir->setOperand(1 + BOX_PIECES * i + 1, LAllocation());
#endif
break;
case MIRType::Null:
case MIRType::Undefined:
// Bogus operand, as these can be inlined.
lir->setOperand(1 + BOX_PIECES * i, LAllocation());
#ifdef JS_NUNBOX32
lir->setOperand(1 + BOX_PIECES * i + 1, LAllocation());
#endif
break;
default:
MOZ_CRASH("LIRGenerator::visitLoadElementFromState: Unsupported element type.");
return;
}
}
defineBox(lir, ins);
}
void
LIRGenerator::visitStoreElement(MStoreElement* ins)
{
@ -5130,6 +5197,12 @@ LIRGenerator::visitArrayState(MArrayState* objState)
MOZ_CRASH("Unexpected ArrayState node during Lowering.");
}
void
LIRGenerator::visitArgumentState(MArgumentState* objState)
{
// ArgumentState nodes are always inlined at their uses.
}
void
LIRGenerator::visitUnknownValue(MUnknownValue* ins)
{

View File

@ -232,6 +232,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitLoadElementHole(MLoadElementHole* ins);
void visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins);
void visitLoadUnboxedString(MLoadUnboxedString* ins);
void visitLoadElementFromState(MLoadElementFromState* ins);
void visitStoreElement(MStoreElement* ins);
void visitStoreElementHole(MStoreElementHole* ins);
void visitFallibleStoreElement(MFallibleStoreElement* ins);
@ -325,6 +326,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitBeta(MBeta* ins);
void visitObjectState(MObjectState* ins);
void visitArrayState(MArrayState* ins);
void visitArgumentState(MArgumentState* ins);
void visitUnknownValue(MUnknownValue* ins);
void visitLexicalCheck(MLexicalCheck* ins);
void visitThrowRuntimeLexicalError(MThrowRuntimeLexicalError* ins);

View File

@ -5098,6 +5098,28 @@ MArrayState::Copy(TempAllocator& alloc, MArrayState* state)
return res;
}
MArgumentState*
MArgumentState::New(TempAllocator::Fallible view, const MDefinitionVector& args)
{
MArgumentState* res = new(view.alloc) MArgumentState();
if (!res || !res->init(view.alloc, args.length()))
return nullptr;
for (size_t i = 0, e = args.length(); i < e; i++)
res->initOperand(i, args[i]);
return res;
}
MArgumentState*
MArgumentState::Copy(TempAllocator& alloc, MArgumentState* state)
{
MArgumentState* res = new(alloc) MArgumentState();
if (!res || !res->init(alloc, state->numElements()))
return nullptr;
for (size_t i = 0, e = res->numOperands(); i < e; i++)
res->initOperand(i, state->getOperand(i));
return res;
}
MNewArray::MNewArray(CompilerConstraintList* constraints, uint32_t length, MConstant* templateConst,
gc::InitialHeap initialHeap, jsbytecode* pc, bool vmCall)
: MUnaryInstruction(templateConst),

View File

@ -3957,6 +3957,41 @@ class MArrayState
}
};
// Hold the arguments of an inlined frame. At the moment this class is not
// recovered on bailout as it does not have an implementation and it should
// be inlined at all its uses.
class MArgumentState
: public MVariadicInstruction,
public NoFloatPolicyAfter<0>::Data
{
private:
explicit MArgumentState() {
setResultType(MIRType::Object);
setMovable();
}
public:
INSTRUCTION_HEADER(ArgumentState)
static MArgumentState* New(TempAllocator::Fallible view, const MDefinitionVector& args);
static MArgumentState* Copy(TempAllocator& alloc, MArgumentState* state);
size_t numElements() const {
return numOperands();
}
MDefinition* getElement(uint32_t index) const {
return getOperand(index);
}
bool congruentTo(const MDefinition* ins) const override {
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const override {
return AliasSet::None();
}
};
// Setting __proto__ in an object literal.
class MMutateProto
: public MAryInstruction<2>,
@ -9656,6 +9691,30 @@ class MStoreElementCommon
}
};
// This instruction is used to load an element of a non-escaped inlined array.
class MLoadElementFromState
: public MBinaryInstruction,
public SingleObjectPolicy::Data
{
MLoadElementFromState(MDefinition* array, MDefinition* index)
: MBinaryInstruction(array, index)
{
MOZ_ASSERT(array->isArgumentState());
MOZ_ASSERT(index->type() == MIRType::Int32);
setResultType(MIRType::Value);
setMovable();
}
public:
INSTRUCTION_HEADER(LoadElementFromState)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, array), (1, index));
AliasSet getAliasSet() const override {
return AliasSet::None();
}
};
// Store a value to a dense array slots vector.
class MStoreElement
: public MAryInstruction<3>,

View File

@ -144,6 +144,7 @@ namespace jit {
_(NewStringObject) \
_(ObjectState) \
_(ArrayState) \
_(ArgumentState) \
_(InitElem) \
_(InitElemGetterSetter) \
_(MutateProto) \
@ -217,6 +218,7 @@ namespace jit {
_(LoadUnboxedScalar) \
_(LoadUnboxedObjectOrNull) \
_(LoadUnboxedString) \
_(LoadElementFromState) \
_(StoreElement) \
_(StoreElementHole) \
_(FallibleStoreElement) \

View File

@ -587,6 +587,7 @@ NoFloatPolicyAfter<FirstOp>::adjustInputs(TempAllocator& alloc, MInstruction* de
return true;
}
template bool NoFloatPolicyAfter<0>::adjustInputs(TempAllocator& alloc, MInstruction* def);
template bool NoFloatPolicyAfter<1>::adjustInputs(TempAllocator& alloc, MInstruction* def);
template bool NoFloatPolicyAfter<2>::adjustInputs(TempAllocator& alloc, MInstruction* def);
@ -1268,6 +1269,7 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
_(MixPolicy<StringPolicy<0>, StringPolicy<1> >) \
_(MixPolicy<BoxPolicy<0>, BoxPolicy<1> >) \
_(NoFloatPolicy<0>) \
_(NoFloatPolicyAfter<0>) \
_(NoFloatPolicyAfter<1>) \
_(NoFloatPolicyAfter<2>) \
_(ObjectPolicy<0>) \

View File

@ -387,6 +387,12 @@ class Assembler : public vixl::Assembler
LabelBase* label = absoluteLabel;
label->bind(off.getOffset());
}
void writeCodePointer(CodeOffset* label) {
uintptr_t x = LabelBase::INVALID_OFFSET;
BufferOffset off = EmitData(&x, sizeof(uintptr_t));
label->bind(off.getOffset());
}
void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end,
const Disassembler::HeapAccess& heapAccess)

View File

@ -5744,6 +5744,47 @@ class LUnboxObjectOrNull : public LInstructionHelper<1, 1, 0>
}
};
// Load an element from a non-allocated entity represented by its state object
// such as ArgumentState. The elements of the state object are set as operands
// of this variadic LIR instruction and inlined in the code generated for this
// instruction.
//
// Each element is represented with BOX_PIECES allocations, even if 1 (typed
// register) or 0 (constants) is enough. In such case, the unused allocations
// would be bogus.
class LLoadElementFromStateV : public LVariadicInstruction<BOX_PIECES, 3>
{
public:
LIR_HEADER(LoadElementFromStateV)
LLoadElementFromStateV(const LDefinition& temp0, const LDefinition& temp1,
const LDefinition& tempD)
{
setTemp(0, temp0);
setTemp(1, temp1);
setTemp(2, tempD);
}
const MLoadElementFromState* mir() const {
return mir_->toLoadElementFromState();
}
const LAllocation* index() {
return getOperand(0);
}
const LDefinition* temp0() {
return getTemp(0);
}
const LDefinition* temp1() {
return getTemp(1);
}
const LDefinition* tempD() {
return getTemp(2);
}
MDefinition* array() {
return mir()->array();
}
};
// Store a boxed value to a dense array's element vector.
class LStoreElementV : public LInstructionHelper<0, 2 + BOX_PIECES, 0>
{

View File

@ -283,6 +283,7 @@
_(LoadUnboxedScalar) \
_(LoadUnboxedPointerV) \
_(LoadUnboxedPointerT) \
_(LoadElementFromStateV) \
_(UnboxObjectOrNull) \
_(StoreElementV) \
_(StoreElementT) \

View File

@ -159,9 +159,9 @@ LIRGeneratorShared::defineInt64ReuseInput(LInstructionHelper<INT64_PIECES, Ops,
}
template <size_t Ops, size_t Temps> void
LIRGeneratorShared::defineBox(LInstructionHelper<BOX_PIECES, Ops, Temps>* lir, MDefinition* mir,
LDefinition::Policy policy)
template <size_t Temps> void
LIRGeneratorShared::defineBox(details::LInstructionFixedDefsTempsHelper<BOX_PIECES, Temps>* lir,
MDefinition* mir, LDefinition::Policy policy)
{
// Call instructions should use defineReturn.
MOZ_ASSERT(!lir->isCall());

View File

@ -157,9 +157,9 @@ class LIRGeneratorShared : public MDefinitionVisitor
inline void defineFixed(LInstructionHelper<1, Ops, Temps>* lir, MDefinition* mir,
const LAllocation& output);
template <size_t Ops, size_t Temps>
inline void defineBox(LInstructionHelper<BOX_PIECES, Ops, Temps>* lir, MDefinition* mir,
LDefinition::Policy policy = LDefinition::REGISTER);
template <size_t Temps>
inline void defineBox(details::LInstructionFixedDefsTempsHelper<BOX_PIECES, Temps>* lir,
MDefinition* mir, LDefinition::Policy policy = LDefinition::REGISTER);
template <size_t Ops, size_t Temps>
inline void defineInt64(LInstructionHelper<INT64_PIECES, Ops, Temps>* lir, MDefinition* mir,