зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1139152 - IonMonkey: Add dynamic output type checks for LIRs that use redefine, r=jandem
This commit is contained in:
Родитель
9bde438ed5
Коммит
1e5553841b
|
@ -0,0 +1,25 @@
|
|||
function toLiteralSource(value) {
|
||||
if (value === null) {
|
||||
return 'null';
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
return escapeString(value);
|
||||
}
|
||||
if (typeof value === 'number') {
|
||||
return generateNumber(value);
|
||||
}
|
||||
if (typeof value === 'boolean') {
|
||||
return value ? 'true' : 'false';
|
||||
}
|
||||
value.test();
|
||||
}
|
||||
|
||||
function test(x) {
|
||||
var b = x ? true : {};
|
||||
return toLiteralSource(b);
|
||||
}
|
||||
|
||||
var output = true
|
||||
for (var i=0; i<1000; i++) {
|
||||
output = test(output) == 'true';
|
||||
}
|
|
@ -3740,7 +3740,6 @@ struct ScriptCountBlockState
|
|||
}
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
CodeGenerator::branchIfInvalidated(Register temp, Label *invalidated)
|
||||
{
|
||||
|
@ -3755,16 +3754,13 @@ CodeGenerator::branchIfInvalidated(Register temp, Label *invalidated)
|
|||
}
|
||||
|
||||
void
|
||||
CodeGenerator::emitObjectOrStringResultChecks(LInstruction *lir, MDefinition *mir)
|
||||
CodeGenerator::emitAssertObjectOrStringResult(Register input, MIRType type, TemporaryTypeSet *typeset)
|
||||
{
|
||||
if (lir->numDefs() == 0)
|
||||
return;
|
||||
|
||||
MOZ_ASSERT(lir->numDefs() == 1);
|
||||
Register output = ToRegister(lir->getDef(0));
|
||||
MOZ_ASSERT(type == MIRType_Object || type == MIRType_ObjectOrNull ||
|
||||
type == MIRType_String || type == MIRType_Symbol);
|
||||
|
||||
GeneralRegisterSet regs(GeneralRegisterSet::All());
|
||||
regs.take(output);
|
||||
regs.take(input);
|
||||
|
||||
Register temp = regs.takeAny();
|
||||
masm.push(temp);
|
||||
|
@ -3774,22 +3770,21 @@ CodeGenerator::emitObjectOrStringResultChecks(LInstruction *lir, MDefinition *mi
|
|||
Label done;
|
||||
branchIfInvalidated(temp, &done);
|
||||
|
||||
if ((mir->type() == MIRType_Object || mir->type() == MIRType_ObjectOrNull) &&
|
||||
mir->resultTypeSet() &&
|
||||
!mir->resultTypeSet()->unknownObject())
|
||||
if ((type == MIRType_Object || type == MIRType_ObjectOrNull) &&
|
||||
typeset && !typeset->unknownObject())
|
||||
{
|
||||
// We have a result TypeSet, assert this object is in it.
|
||||
Label miss, ok;
|
||||
if (mir->type() == MIRType_ObjectOrNull)
|
||||
masm.branchPtr(Assembler::Equal, output, ImmWord(0), &ok);
|
||||
if (mir->resultTypeSet()->getObjectCount() > 0)
|
||||
masm.guardObjectType(output, mir->resultTypeSet(), temp, &miss);
|
||||
if (type == MIRType_ObjectOrNull)
|
||||
masm.branchPtr(Assembler::Equal, input, ImmWord(0), &ok);
|
||||
if (typeset->getObjectCount() > 0)
|
||||
masm.guardObjectType(input, typeset, temp, &miss);
|
||||
else
|
||||
masm.jump(&miss);
|
||||
masm.jump(&ok);
|
||||
|
||||
masm.bind(&miss);
|
||||
masm.guardTypeSetMightBeIncomplete(output, temp, &ok);
|
||||
masm.guardTypeSetMightBeIncomplete(input, temp, &ok);
|
||||
|
||||
masm.assumeUnreachable("MIR instruction returned object with unexpected type");
|
||||
|
||||
|
@ -3801,10 +3796,10 @@ CodeGenerator::emitObjectOrStringResultChecks(LInstruction *lir, MDefinition *mi
|
|||
masm.setupUnalignedABICall(2, temp);
|
||||
masm.loadJSContext(temp);
|
||||
masm.passABIArg(temp);
|
||||
masm.passABIArg(output);
|
||||
masm.passABIArg(input);
|
||||
|
||||
void *callee;
|
||||
switch (mir->type()) {
|
||||
switch (type) {
|
||||
case MIRType_Object:
|
||||
callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidObjectPtr);
|
||||
break;
|
||||
|
@ -3829,19 +3824,10 @@ CodeGenerator::emitObjectOrStringResultChecks(LInstruction *lir, MDefinition *mi
|
|||
}
|
||||
|
||||
void
|
||||
CodeGenerator::emitValueResultChecks(LInstruction *lir, MDefinition *mir)
|
||||
CodeGenerator::emitAssertResultV(const ValueOperand input, TemporaryTypeSet *typeset)
|
||||
{
|
||||
if (lir->numDefs() == 0)
|
||||
return;
|
||||
|
||||
MOZ_ASSERT(lir->numDefs() == BOX_PIECES);
|
||||
if (!lir->getDef(0)->output()->isRegister())
|
||||
return;
|
||||
|
||||
ValueOperand output = ToOutValue(lir);
|
||||
|
||||
GeneralRegisterSet regs(GeneralRegisterSet::All());
|
||||
regs.take(output);
|
||||
regs.take(input);
|
||||
|
||||
Register temp1 = regs.takeAny();
|
||||
Register temp2 = regs.takeAny();
|
||||
|
@ -3853,10 +3839,10 @@ CodeGenerator::emitValueResultChecks(LInstruction *lir, MDefinition *mir)
|
|||
Label done;
|
||||
branchIfInvalidated(temp1, &done);
|
||||
|
||||
if (mir->resultTypeSet() && !mir->resultTypeSet()->unknown()) {
|
||||
if (typeset && !typeset->unknown()) {
|
||||
// We have a result TypeSet, assert this value is in it.
|
||||
Label miss, ok;
|
||||
masm.guardTypeSet(output, mir->resultTypeSet(), BarrierKind::TypeSet, temp1, &miss);
|
||||
masm.guardTypeSet(input, typeset, BarrierKind::TypeSet, temp1, &miss);
|
||||
masm.jump(&ok);
|
||||
|
||||
masm.bind(&miss);
|
||||
|
@ -3864,8 +3850,8 @@ CodeGenerator::emitValueResultChecks(LInstruction *lir, MDefinition *mir)
|
|||
// Check for cases where the type set guard might have missed due to
|
||||
// changing object groups.
|
||||
Label realMiss;
|
||||
masm.branchTestObject(Assembler::NotEqual, output, &realMiss);
|
||||
Register payload = masm.extractObject(output, temp1);
|
||||
masm.branchTestObject(Assembler::NotEqual, input, &realMiss);
|
||||
Register payload = masm.extractObject(input, temp1);
|
||||
masm.guardTypeSetMightBeIncomplete(payload, temp1, &ok);
|
||||
masm.bind(&realMiss);
|
||||
|
||||
|
@ -3877,7 +3863,7 @@ CodeGenerator::emitValueResultChecks(LInstruction *lir, MDefinition *mir)
|
|||
// Check that we have a valid GC pointer.
|
||||
saveVolatile();
|
||||
|
||||
masm.pushValue(output);
|
||||
masm.pushValue(input);
|
||||
masm.movePtr(StackPointer, temp1);
|
||||
|
||||
masm.setupUnalignedABICall(2, temp2);
|
||||
|
@ -3885,7 +3871,7 @@ CodeGenerator::emitValueResultChecks(LInstruction *lir, MDefinition *mir)
|
|||
masm.passABIArg(temp2);
|
||||
masm.passABIArg(temp1);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, AssertValidValue));
|
||||
masm.popValue(output);
|
||||
masm.popValue(input);
|
||||
restoreVolatile();
|
||||
|
||||
masm.bind(&done);
|
||||
|
@ -3893,6 +3879,34 @@ CodeGenerator::emitValueResultChecks(LInstruction *lir, MDefinition *mir)
|
|||
masm.pop(temp1);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
CodeGenerator::emitObjectOrStringResultChecks(LInstruction *lir, MDefinition *mir)
|
||||
{
|
||||
if (lir->numDefs() == 0)
|
||||
return;
|
||||
|
||||
MOZ_ASSERT(lir->numDefs() == 1);
|
||||
Register output = ToRegister(lir->getDef(0));
|
||||
|
||||
emitAssertObjectOrStringResult(output, mir->type(), mir->resultTypeSet());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::emitValueResultChecks(LInstruction *lir, MDefinition *mir)
|
||||
{
|
||||
if (lir->numDefs() == 0)
|
||||
return;
|
||||
|
||||
MOZ_ASSERT(lir->numDefs() == BOX_PIECES);
|
||||
if (!lir->getDef(0)->output()->isRegister())
|
||||
return;
|
||||
|
||||
ValueOperand output = ToOutValue(lir);
|
||||
|
||||
emitAssertResultV(output, mir->resultTypeSet());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::emitDebugResultChecks(LInstruction *ins)
|
||||
{
|
||||
|
@ -9549,6 +9563,22 @@ CodeGenerator::emitAssertRangeD(const Range *r, FloatRegister input, FloatRegist
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitAssertResultV(LAssertResultV *ins)
|
||||
{
|
||||
const ValueOperand value = ToValue(ins, LAssertResultV::Input);
|
||||
emitAssertResultV(value, ins->mirRaw()->resultTypeSet());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitAssertResultT(LAssertResultT *ins)
|
||||
{
|
||||
Register input = ToRegister(ins->input());
|
||||
MDefinition *mir = ins->mirRaw();
|
||||
|
||||
emitAssertObjectOrStringResult(input, mir->type(), mir->resultTypeSet());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitAssertRangeI(LAssertRangeI *ins)
|
||||
{
|
||||
|
|
|
@ -356,6 +356,11 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||
void visitAssertRangeF(LAssertRangeF *ins);
|
||||
void visitAssertRangeV(LAssertRangeV *ins);
|
||||
|
||||
void visitAssertResultV(LAssertResultV *ins);
|
||||
void visitAssertResultT(LAssertResultT *ins);
|
||||
void emitAssertResultV(const ValueOperand output, TemporaryTypeSet *typeset);
|
||||
void emitAssertObjectOrStringResult(Register input, MIRType type, TemporaryTypeSet *typeset);
|
||||
|
||||
void visitInterruptCheck(LInterruptCheck *lir);
|
||||
void visitAsmJSInterruptCheck(LAsmJSInterruptCheck *lir);
|
||||
void visitRecompileCheck(LRecompileCheck *ins);
|
||||
|
@ -459,9 +464,10 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||
void emitAssertRangeD(const Range *r, FloatRegister input, FloatRegister temp);
|
||||
|
||||
Vector<CodeOffsetLabel, 0, JitAllocPolicy> ionScriptLabels_;
|
||||
#ifdef DEBUG
|
||||
|
||||
void branchIfInvalidated(Register temp, Label *invalidated);
|
||||
|
||||
#ifdef DEBUG
|
||||
void emitDebugResultChecks(LInstruction *ins);
|
||||
void emitObjectOrStringResultChecks(LInstruction *lir, MDefinition *mir);
|
||||
void emitValueResultChecks(LInstruction *lir, MDefinition *mir);
|
||||
|
|
|
@ -74,6 +74,9 @@ JitOptions::JitOptions()
|
|||
// RangeAnalysis results.
|
||||
SET_DEFAULT(checkRangeAnalysis, false);
|
||||
|
||||
// Whether to enable extra code to perform dynamic validations.
|
||||
SET_DEFAULT(runExtraChecks, false);
|
||||
|
||||
// Toggle whether eager scalar replacement is globally disabled.
|
||||
SET_DEFAULT(disableScalarReplacement, false);
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ struct JitOptions
|
|||
bool checkOsiPointRegisters;
|
||||
#endif
|
||||
bool checkRangeAnalysis;
|
||||
bool runExtraChecks;
|
||||
bool disableScalarReplacement;
|
||||
bool disableEagerSimdUnbox;
|
||||
bool disableGvn;
|
||||
|
|
|
@ -6799,6 +6799,28 @@ class LAssertRangeV : public LInstructionHelper<0, BOX_PIECES, 3>
|
|||
}
|
||||
};
|
||||
|
||||
class LAssertResultT : public LInstructionHelper<0, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(AssertResultT)
|
||||
|
||||
explicit LAssertResultT(const LAllocation &input) {
|
||||
setOperand(0, input);
|
||||
}
|
||||
|
||||
const LAllocation *input() {
|
||||
return getOperand(0);
|
||||
}
|
||||
};
|
||||
|
||||
class LAssertResultV : public LInstructionHelper<0, BOX_PIECES, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(AssertResultV)
|
||||
|
||||
static const size_t Input = 0;
|
||||
};
|
||||
|
||||
class LRecompileCheck : public LInstructionHelper<0, 0, 1>
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -339,6 +339,8 @@
|
|||
_(AssertRangeD) \
|
||||
_(AssertRangeF) \
|
||||
_(AssertRangeV) \
|
||||
_(AssertResultV) \
|
||||
_(AssertResultT) \
|
||||
_(LexicalCheck) \
|
||||
_(ThrowUninitializedLexical) \
|
||||
_(NurseryObject) \
|
||||
|
|
|
@ -24,6 +24,12 @@ using namespace jit;
|
|||
using mozilla::DebugOnly;
|
||||
using JS::GenericNaN;
|
||||
|
||||
void
|
||||
LIRGenerator::useBoxAtStart(LInstruction *lir, size_t n, MDefinition *mir, LUse::Policy policy)
|
||||
{
|
||||
return useBox(lir, n, mir, policy, true);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitCloneLiteral(MCloneLiteral *ins)
|
||||
{
|
||||
|
@ -2317,8 +2323,8 @@ LIRGenerator::visitTypeBarrier(MTypeBarrier *ins)
|
|||
if (ins->alwaysBails()) {
|
||||
LBail *bail = new(alloc()) LBail();
|
||||
assignSnapshot(bail, Bailout_Inevitable);
|
||||
redefine(ins, ins->input());
|
||||
add(bail, ins);
|
||||
redefine(ins, ins->input());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2328,8 +2334,8 @@ LIRGenerator::visitTypeBarrier(MTypeBarrier *ins)
|
|||
LTypeBarrierV *barrier = new(alloc()) LTypeBarrierV(tmp);
|
||||
useBox(barrier, LTypeBarrierV::Input, ins->input());
|
||||
assignSnapshot(barrier, Bailout_TypeBarrierV);
|
||||
redefine(ins, ins->input());
|
||||
add(barrier, ins);
|
||||
redefine(ins, ins->input());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2348,8 +2354,8 @@ LIRGenerator::visitTypeBarrier(MTypeBarrier *ins)
|
|||
LDefinition tmp = needTemp ? temp() : LDefinition::BogusTemp();
|
||||
LTypeBarrierO *barrier = new(alloc()) LTypeBarrierO(useRegister(ins->getOperand(0)), tmp);
|
||||
assignSnapshot(barrier, Bailout_TypeBarrierO);
|
||||
redefine(ins, ins->getOperand(0));
|
||||
add(barrier, ins);
|
||||
redefine(ins, ins->getOperand(0));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4072,10 +4078,10 @@ LIRGenerator::visitLexicalCheck(MLexicalCheck *ins)
|
|||
MDefinition *input = ins->input();
|
||||
MOZ_ASSERT(input->type() == MIRType_Value);
|
||||
LLexicalCheck *lir = new(alloc()) LLexicalCheck();
|
||||
redefine(ins, input);
|
||||
useBox(lir, LLexicalCheck::Input, input);
|
||||
add(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
redefine(ins, input);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -47,9 +47,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
private:
|
||||
|
||||
void useBoxAtStart(LInstruction *lir, size_t n, MDefinition *mir,
|
||||
LUse::Policy policy = LUse::REGISTER) {
|
||||
return useBox(lir, n, mir, policy, true);
|
||||
}
|
||||
LUse::Policy policy = LUse::REGISTER);
|
||||
|
||||
void lowerBitOp(JSOp op, MInstruction *ins);
|
||||
void lowerShiftOp(JSOp op, MShiftInstruction *ins);
|
||||
|
|
|
@ -1135,7 +1135,6 @@ AutoDetectInvalidation::setReturnOverride()
|
|||
cx_->runtime()->jitRuntime()->setIonReturnOverride(rval_.get());
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
AssertValidObjectPtr(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
|
@ -1149,7 +1148,7 @@ AssertValidObjectPtr(JSContext *cx, JSObject *obj)
|
|||
|
||||
if (obj->isTenured()) {
|
||||
MOZ_ASSERT(obj->isAligned());
|
||||
gc::AllocKind kind = obj->asTenured().getAllocKind();
|
||||
mozilla::DebugOnly<gc::AllocKind> kind = obj->asTenured().getAllocKind();
|
||||
MOZ_ASSERT(kind <= js::gc::AllocKind::OBJECT_LAST);
|
||||
MOZ_ASSERT(obj->asTenured().zone() == cx->zone());
|
||||
}
|
||||
|
@ -1180,7 +1179,7 @@ AssertValidStringPtr(JSContext *cx, JSString *str)
|
|||
MOZ_ASSERT(str->isAligned());
|
||||
MOZ_ASSERT(str->length() <= JSString::MAX_LENGTH);
|
||||
|
||||
gc::AllocKind kind = str->getAllocKind();
|
||||
mozilla::DebugOnly<gc::AllocKind> kind = str->getAllocKind();
|
||||
if (str->isFatInline())
|
||||
MOZ_ASSERT(kind == gc::AllocKind::FAT_INLINE_STRING);
|
||||
else if (str->isExternal())
|
||||
|
@ -1220,7 +1219,6 @@ AssertValidValue(JSContext *cx, Value *v)
|
|||
else if (v->isSymbol())
|
||||
AssertValidSymbolPtr(cx, v->toSymbol());
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
ObjectIsCallable(JSObject *obj)
|
||||
|
|
|
@ -748,13 +748,11 @@ JSString *StringReplace(JSContext *cx, HandleString string, HandleString pattern
|
|||
bool SetDenseElement(JSContext *cx, HandleNativeObject obj, int32_t index, HandleValue value,
|
||||
bool strict);
|
||||
|
||||
#ifdef DEBUG
|
||||
void AssertValidObjectPtr(JSContext *cx, JSObject *obj);
|
||||
void AssertValidObjectOrNullPtr(JSContext *cx, JSObject *obj);
|
||||
void AssertValidStringPtr(JSContext *cx, JSString *str);
|
||||
void AssertValidSymbolPtr(JSContext *cx, JS::Symbol *sym);
|
||||
void AssertValidValue(JSContext *cx, Value *v);
|
||||
#endif
|
||||
|
||||
void MarkValueFromIon(JSRuntime *rt, Value *vp);
|
||||
void MarkStringFromIon(JSRuntime *rt, JSString **stringp);
|
||||
|
|
|
@ -17,16 +17,6 @@ using namespace js::jit;
|
|||
|
||||
using mozilla::FloorLog2;
|
||||
|
||||
void
|
||||
LIRGeneratorARM::useBox(LInstruction *lir, size_t n, MDefinition *mir,
|
||||
LUse::Policy policy, bool useAtStart)
|
||||
{
|
||||
MOZ_ASSERT(mir->type() == MIRType_Value);
|
||||
ensureDefined(mir);
|
||||
lir->setOperand(n, LUse(mir->virtualRegister(), policy, useAtStart));
|
||||
lir->setOperand(n + 1, LUse(VirtualRegisterOfPayload(mir), policy, useAtStart));
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorARM::useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1,
|
||||
Register reg2)
|
||||
|
|
|
@ -22,8 +22,6 @@ class LIRGeneratorARM : public LIRGeneratorShared
|
|||
protected:
|
||||
// Adds a box input to an instruction, setting operand |n| to the type and
|
||||
// |n+1| to the payload.
|
||||
void useBox(LInstruction *lir, size_t n, MDefinition *mir,
|
||||
LUse::Policy policy = LUse::REGISTER, bool useAtStart = false);
|
||||
void useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1, Register reg2);
|
||||
|
||||
// x86 has constraints on what registers can be formatted for 1-byte
|
||||
|
|
|
@ -18,17 +18,6 @@ using namespace js::jit;
|
|||
|
||||
using mozilla::FloorLog2;
|
||||
|
||||
void
|
||||
LIRGeneratorMIPS::useBox(LInstruction *lir, size_t n, MDefinition *mir,
|
||||
LUse::Policy policy, bool useAtStart)
|
||||
{
|
||||
MOZ_ASSERT(mir->type() == MIRType_Value);
|
||||
|
||||
ensureDefined(mir);
|
||||
lir->setOperand(n, LUse(mir->virtualRegister(), policy, useAtStart));
|
||||
lir->setOperand(n + 1, LUse(VirtualRegisterOfPayload(mir), policy, useAtStart));
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorMIPS::useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1,
|
||||
Register reg2)
|
||||
|
|
|
@ -22,8 +22,6 @@ class LIRGeneratorMIPS : public LIRGeneratorShared
|
|||
protected:
|
||||
// Adds a box input to an instruction, setting operand |n| to the type and
|
||||
// |n+1| to the payload.
|
||||
void useBox(LInstruction *lir, size_t n, MDefinition *mir,
|
||||
LUse::Policy policy = LUse::REGISTER, bool useAtStart = false);
|
||||
void useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1, Register reg2);
|
||||
|
||||
// x86 has constraints on what registers can be formatted for 1-byte
|
||||
|
|
|
@ -21,10 +21,6 @@ class LIRGeneratorNone : public LIRGeneratorShared
|
|||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
void useBox(LInstruction *, size_t, MDefinition *,
|
||||
LUse::Policy a = LUse::REGISTER, bool b = false) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
void useBoxFixed(LInstruction *, size_t, MDefinition *, Register, Register) { MOZ_CRASH(); }
|
||||
|
||||
LAllocation useByteOpRegister(MDefinition *) { MOZ_CRASH(); }
|
||||
|
|
|
@ -207,6 +207,32 @@ LIRGeneratorShared::redefine(MDefinition *def, MDefinition *as)
|
|||
} else {
|
||||
ensureDefined(as);
|
||||
def->setVirtualRegister(as->virtualRegister());
|
||||
|
||||
#ifdef DEBUG
|
||||
if (js_JitOptions.runExtraChecks &&
|
||||
def->resultTypeSet() && as->resultTypeSet() &&
|
||||
!def->resultTypeSet()->equals(as->resultTypeSet()))
|
||||
{
|
||||
switch (def->type()) {
|
||||
case MIRType_Object:
|
||||
case MIRType_ObjectOrNull:
|
||||
case MIRType_String:
|
||||
case MIRType_Symbol: {
|
||||
LAssertResultT *check = new(alloc()) LAssertResultT(useRegister(def));
|
||||
add(check, def->toInstruction());
|
||||
break;
|
||||
}
|
||||
case MIRType_Value: {
|
||||
LAssertResultV *check = new(alloc()) LAssertResultV();
|
||||
useBox(check, LAssertRangeV::Input, def);
|
||||
add(check, def->toInstruction());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -499,6 +525,19 @@ LIRGeneratorShared::useRegisterForTypedLoad(MDefinition *mir, MIRType type)
|
|||
return useRegisterAtStart(mir);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorShared::useBox(LInstruction *lir, size_t n, MDefinition *mir,
|
||||
LUse::Policy policy, bool useAtStart)
|
||||
{
|
||||
MOZ_ASSERT(mir->type() == MIRType_Value);
|
||||
|
||||
ensureDefined(mir);
|
||||
lir->setOperand(n, LUse(mir->virtualRegister(), policy, useAtStart));
|
||||
#if defined(JS_NUNBOX32)
|
||||
lir->setOperand(n + 1, LUse(VirtualRegisterOfPayload(mir), policy, useAtStart));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -156,6 +156,10 @@ class LIRGeneratorShared : public MDefinitionVisitor
|
|||
template <size_t Ops, size_t Temps>
|
||||
inline void defineReuseInput(LInstructionHelper<1, Ops, Temps> *lir, MDefinition *mir, uint32_t operand);
|
||||
|
||||
// Adds a use at operand |n| of a value-typed insturction.
|
||||
inline void useBox(LInstruction *lir, size_t n, MDefinition *mir,
|
||||
LUse::Policy policy = LUse::REGISTER, bool useAtStart = false);
|
||||
|
||||
// Rather than defining a new virtual register, sets |ins| to have the same
|
||||
// virtual register as |as|.
|
||||
inline void redefine(MDefinition *ins, MDefinition *as);
|
||||
|
|
|
@ -14,16 +14,6 @@
|
|||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
void
|
||||
LIRGeneratorX64::useBox(LInstruction *lir, size_t n, MDefinition *mir,
|
||||
LUse::Policy policy, bool useAtStart)
|
||||
{
|
||||
MOZ_ASSERT(mir->type() == MIRType_Value);
|
||||
|
||||
ensureDefined(mir);
|
||||
lir->setOperand(n, LUse(mir->virtualRegister(), policy, useAtStart));
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorX64::useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1, Register)
|
||||
{
|
||||
|
|
|
@ -24,8 +24,6 @@ class LIRGeneratorX64 : public LIRGeneratorX86Shared
|
|||
void defineUntypedPhi(MPhi *phi, size_t lirIndex);
|
||||
|
||||
// Adds a use at operand |n| of a value-typed insturction.
|
||||
void useBox(LInstruction *lir, size_t n, MDefinition *mir,
|
||||
LUse::Policy policy = LUse::REGISTER, bool useAtStart = false);
|
||||
void useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1, Register);
|
||||
|
||||
// x86 has constraints on what registers can be formatted for 1-byte
|
||||
|
|
|
@ -14,17 +14,6 @@
|
|||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
void
|
||||
LIRGeneratorX86::useBox(LInstruction *lir, size_t n, MDefinition *mir,
|
||||
LUse::Policy policy, bool useAtStart)
|
||||
{
|
||||
MOZ_ASSERT(mir->type() == MIRType_Value);
|
||||
|
||||
ensureDefined(mir);
|
||||
lir->setOperand(n, LUse(mir->virtualRegister(), policy, useAtStart));
|
||||
lir->setOperand(n + 1, LUse(VirtualRegisterOfPayload(mir), policy, useAtStart));
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorX86::useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1,
|
||||
Register reg2)
|
||||
|
|
|
@ -22,8 +22,6 @@ class LIRGeneratorX86 : public LIRGeneratorX86Shared
|
|||
protected:
|
||||
// Adds a box input to an instruction, setting operand |n| to the type and
|
||||
// |n+1| to the payload.
|
||||
void useBox(LInstruction *lir, size_t n, MDefinition *mir,
|
||||
LUse::Policy policy = LUse::REGISTER, bool useAtStart = false);
|
||||
void useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1, Register reg2);
|
||||
|
||||
// It's a trap! On x86, the 1-byte store can only use one of
|
||||
|
|
|
@ -5836,6 +5836,9 @@ SetRuntimeOptions(JSRuntime *rt, const OptionParser &op)
|
|||
if (op.getBoolOption("ion-check-range-analysis"))
|
||||
jit::js_JitOptions.checkRangeAnalysis = true;
|
||||
|
||||
if (op.getBoolOption("ion-extra-checks"))
|
||||
jit::js_JitOptions.runExtraChecks = true;
|
||||
|
||||
if (const char *str = op.getStringOption("ion-inlining")) {
|
||||
if (strcmp(str, "on") == 0)
|
||||
jit::js_JitOptions.disableInlining = false;
|
||||
|
@ -6147,6 +6150,8 @@ main(int argc, char **argv, char **envp)
|
|||
"Loop unrolling (default: off, on to enable)")
|
||||
|| !op.addBoolOption('\0', "ion-check-range-analysis",
|
||||
"Range analysis checking")
|
||||
|| !op.addBoolOption('\0', "ion-extra-checks",
|
||||
"Perform extra dynamic validation checks")
|
||||
|| !op.addStringOption('\0', "ion-inlining", "on/off",
|
||||
"Inline methods where possible (default: on, off to disable)")
|
||||
|| !op.addStringOption('\0', "ion-osr", "on/off",
|
||||
|
|
|
@ -15,7 +15,7 @@ TBPL_FLAGS = [
|
|||
[], # no flags, normal baseline and ion
|
||||
['--ion-eager', '--ion-offthread-compile=off'], # implies --baseline-eager
|
||||
['--ion-eager', '--ion-offthread-compile=off',
|
||||
'--ion-check-range-analysis', '--no-sse3', '--no-threads'],
|
||||
'--ion-check-range-analysis', '--ion-extra-checks', '--no-sse3', '--no-threads'],
|
||||
['--baseline-eager'],
|
||||
['--baseline-eager', '--no-fpu'],
|
||||
['--no-baseline', '--no-ion'],
|
||||
|
|
Загрузка…
Ссылка в новой задаче