Bug 1438727: [Part 1] Implement a subset of JSOP_ADD in CacheIR r=jandem

This patch adds both Ion and Baseline support for ADD when the arguments are
doubles or int32.

This is implmented as a strangler via the SharedIC, this falls back to the shared
IC if there's no attachment in CacheIR. This should allow preservation of performance
throughout.

To provide clobber safety to the float registers, this patch uses fixed temporaries on
LBinaryCache.

--HG--
extra : rebase_source : 35f32e5d0f99bb93845c41aadaf94693644192bd
This commit is contained in:
Matthew Gaudet 2018-03-29 09:09:58 -04:00
Родитель a7ecb4b922
Коммит 480171c17d
22 изменённых файлов: 517 добавлений и 5 удалений

Просмотреть файл

@ -2113,6 +2113,7 @@ BaselineCacheIRCompiler::init(CacheKind kind)
case CacheKind::In: case CacheKind::In:
case CacheKind::HasOwn: case CacheKind::HasOwn:
case CacheKind::InstanceOf: case CacheKind::InstanceOf:
case CacheKind::BinaryArith:
MOZ_ASSERT(numInputs == 2); MOZ_ASSERT(numInputs == 2);
allocator.initInputLocation(0, R0); allocator.initInputLocation(0, R0);
allocator.initInputLocation(1, R1); allocator.initInputLocation(1, R1);

Просмотреть файл

@ -4933,5 +4933,61 @@ ICUnaryArith_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
return tailCallVM(DoUnaryArithFallbackInfo, masm); return tailCallVM(DoUnaryArithFallbackInfo, masm);
} }
//
// BinaryArith_Fallback
//
// This currently is fused with the SharedIC DoBinaryArithFallback, however,
// as we deprecate the SharedIC, this will be able to eventually take over.
//
// At that point the stub argument will go away, and instead be generated here.
bool
DoCacheIRBinaryArithFallback(JSContext* cx, BaselineFrame* frame, ICBinaryArith_Fallback* stub_,
HandleValue lhs, HandleValue rhs, MutableHandleValue ret,
DebugModeOSRVolatileStub<ICBinaryArith_Fallback*>& stub)
{
RootedScript script(cx, frame->script());
jsbytecode* pc = stub->icEntry()->pc(script);
JSOp op = JSOp(*pc);
// Ensure we're only generating for an enabled opcode.
switch(op) {
case JSOP_ADD:
break;
default:
return false; // Fallback to shared IC.
}
FallbackICSpew(cx, stub, "CacheIRBinaryArith(%s,%d,%d)", CodeName[op],
int(lhs.isDouble() ? JSVAL_TYPE_DOUBLE : lhs.extractNonDoubleType()),
int(rhs.isDouble() ? JSVAL_TYPE_DOUBLE : rhs.extractNonDoubleType()));
// Check if debug mode toggling made the stub invalid.
if (stub.invalid())
return true;
if (ret.isDouble())
stub->setSawDoubleResult();
if (stub->state().maybeTransition())
stub->discardStubs(cx);
if (stub->state().canAttachStub()) {
BinaryArithIRGenerator gen(cx, script, pc, stub->state().mode(),
op, lhs, rhs, ret);
if (gen.tryAttachStub()) {
bool attached = false;
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
BaselineCacheIRStubKind::Regular,
ICStubEngine::Baseline, script, stub, &attached);
if (newStub)
JitSpew(JitSpew_BaselineIC, " Attached BinaryArith CacheIR stub for %s", CodeName[op]);
} else {
return false; // Fallback to shared IC.
}
}
return true;
}
} // namespace jit } // namespace jit
} // namespace js } // namespace js

Просмотреть файл

@ -5078,3 +5078,95 @@ UnaryArithIRGenerator::tryAttachNumber()
writer.returnFromIC(); writer.returnFromIC();
return true; return true;
} }
BinaryArithIRGenerator::BinaryArithIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, ICState::Mode mode,
JSOp op, HandleValue lhs, HandleValue rhs, HandleValue res)
: IRGenerator(cx, script, pc, CacheKind::BinaryArith, mode),
op_(op),
lhs_(lhs),
rhs_(rhs),
res_(res)
{ }
void
BinaryArithIRGenerator::trackAttached(const char* name)
{
#ifdef JS_CACHEIR_SPEW
if (const CacheIRSpewer::Guard& sp = CacheIRSpewer::Guard(*this, name)) {
sp.opcodeProperty("op", op_);
sp.valueProperty("rhs", rhs_);
sp.valueProperty("lhs", lhs_);
}
#endif
}
bool
BinaryArithIRGenerator::tryAttachStub()
{
if (tryAttachInt32())
return true;
if (tryAttachDouble())
return true;
trackAttached(IRGenerator::NotAttached);
return false;
}
bool
BinaryArithIRGenerator::tryAttachDouble()
{
if (op_ != JSOP_ADD)
return false;
if (!lhs_.isDouble() || !rhs_.isDouble() || !res_.isDouble())
return false;
if (!cx_->runtime()->jitSupportsFloatingPoint)
return false;
ValOperandId lhsId(writer.setInputOperandId(0));
ValOperandId rhsId(writer.setInputOperandId(1));
writer.guardIsNumber(lhsId);
writer.guardIsNumber(rhsId);
switch (op_) {
case JSOP_ADD:
writer.doubleAddResult(lhsId, rhsId);
trackAttached("BinaryArith.Double.Add");
break;
default:
MOZ_CRASH("Unhandled Op");
}
writer.returnFromIC();
return true;
}
bool
BinaryArithIRGenerator::tryAttachInt32()
{
if (op_ != JSOP_ADD)
return false;
if (!lhs_.isInt32() || !rhs_.isInt32())
return false;
ValOperandId lhsId(writer.setInputOperandId(0));
ValOperandId rhsId(writer.setInputOperandId(1));
Int32OperandId lhsIntId = writer.guardIsInt32(lhsId);
Int32OperandId rhsIntId = writer.guardIsInt32(rhsId);
switch (op_) {
case JSOP_ADD:
writer.int32AddResult(lhsIntId, rhsIntId);
trackAttached("BinaryArith.Int32.Add");
break;
default:
MOZ_CRASH("Unhandled op in tryAttachInt32");
}
writer.returnFromIC();
return true;
}

Просмотреть файл

@ -166,7 +166,8 @@ class TypedOperandId : public OperandId
_(Compare) \ _(Compare) \
_(ToBool) \ _(ToBool) \
_(Call) \ _(Call) \
_(UnaryArith) _(UnaryArith) \
_(BinaryArith)
enum class CacheKind : uint8_t enum class CacheKind : uint8_t
{ {
@ -290,6 +291,8 @@ extern const char* CacheKindNames[];
_(LoadStringResult) \ _(LoadStringResult) \
_(LoadInstanceOfObjectResult) \ _(LoadInstanceOfObjectResult) \
_(LoadTypeOfObjectResult) \ _(LoadTypeOfObjectResult) \
_(DoubleAddResult) \
_(Int32AddResult) \
_(Int32NotResult) \ _(Int32NotResult) \
_(Int32NegationResult) \ _(Int32NegationResult) \
_(DoubleNegationResult) \ _(DoubleNegationResult) \
@ -989,6 +992,14 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
buffer_.writeByte(uint32_t(hasOwn)); buffer_.writeByte(uint32_t(hasOwn));
} }
void doubleAddResult(ValOperandId lhsId, ValOperandId rhsId) {
writeOpWithOperandId(CacheOp::DoubleAddResult, lhsId);
writeOperandId(rhsId);
}
void int32AddResult(Int32OperandId lhs, Int32OperandId rhs) {
writeOpWithOperandId(CacheOp::Int32AddResult, lhs);
writeOperandId(rhs);
}
void int32NotResult(Int32OperandId id) { void int32NotResult(Int32OperandId id) {
writeOpWithOperandId(CacheOp::Int32NotResult, id); writeOpWithOperandId(CacheOp::Int32NotResult, id);
} }
@ -1777,6 +1788,26 @@ class MOZ_RAII UnaryArithIRGenerator : public IRGenerator
bool tryAttachStub(); bool tryAttachStub();
}; };
class MOZ_RAII BinaryArithIRGenerator : public IRGenerator
{
JSOp op_;
HandleValue lhs_;
HandleValue rhs_;
HandleValue res_;
void trackAttached(const char* name);
bool tryAttachInt32();
bool tryAttachDouble();
public:
BinaryArithIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc, ICState::Mode,
JSOp op, HandleValue lhs, HandleValue rhs, HandleValue res);
bool tryAttachStub();
};
} // namespace jit } // namespace jit
} // namespace js } // namespace js

Просмотреть файл

@ -88,6 +88,51 @@ CacheRegisterAllocator::useValueRegister(MacroAssembler& masm, ValOperandId op)
MOZ_CRASH(); MOZ_CRASH();
} }
// Load a value operand directly into a float register. Caller must have
// guarded isNumber on the provided val.
void
CacheRegisterAllocator::loadDouble(MacroAssembler& masm, ValOperandId op, FloatRegister dest)
{
OperandLocation& loc = operandLocations_[op.id()];
Label failure, done;
switch (loc.kind()) {
case OperandLocation::ValueReg: {
masm.ensureDouble(loc.valueReg(), dest, &failure);
break;
}
case OperandLocation::ValueStack: {
masm.ensureDouble(valueAddress(masm, &loc), dest, &failure);
break;
}
case OperandLocation::BaselineFrame: {
Address addr = addressOf(masm, loc.baselineFrameSlot());
masm.ensureDouble(addr, dest, &failure);
break;
}
case OperandLocation::DoubleReg: {
masm.moveDouble(loc.doubleReg(), dest);
loc.setDoubleReg(dest);
return;
}
case OperandLocation::Constant:
case OperandLocation::PayloadStack:
case OperandLocation::PayloadReg:
case OperandLocation::Uninitialized:
MOZ_CRASH("Unhandled operand type in loadDouble");
return;
}
masm.jump(&done);
masm.bind(&failure);
masm.assumeUnreachable("Missing guard allowed non-number to hit loadDouble");
masm.bind(&done);
}
ValueOperand ValueOperand
CacheRegisterAllocator::useFixedValueRegister(MacroAssembler& masm, ValOperandId valId, CacheRegisterAllocator::useFixedValueRegister(MacroAssembler& masm, ValOperandId valId,
ValueOperand reg) ValueOperand reg)
@ -668,6 +713,13 @@ CacheRegisterAllocator::popPayload(MacroAssembler& masm, OperandLocation* loc, R
loc->setPayloadReg(dest, loc->payloadType()); loc->setPayloadReg(dest, loc->payloadType());
} }
Address
CacheRegisterAllocator::valueAddress(MacroAssembler& masm, OperandLocation* loc)
{
MOZ_ASSERT(loc >= operandLocations_.begin() && loc < operandLocations_.end());
return Address(masm.getStackPointer(), stackPushed_ - loc->valueStack());
}
void void
CacheRegisterAllocator::popValue(MacroAssembler& masm, OperandLocation* loc, ValueOperand dest) CacheRegisterAllocator::popValue(MacroAssembler& masm, OperandLocation* loc, ValueOperand dest)
{ {
@ -777,9 +829,11 @@ CacheRegisterAllocator::restoreInputState(MacroAssembler& masm, bool shouldDisca
case OperandLocation::ValueStack: case OperandLocation::ValueStack:
popValue(masm, &cur, dest.valueReg()); popValue(masm, &cur, dest.valueReg());
continue; continue;
case OperandLocation::DoubleReg:
masm.boxDouble(cur.doubleReg(), dest.valueReg(), cur.doubleReg());
continue;
case OperandLocation::Constant: case OperandLocation::Constant:
case OperandLocation::BaselineFrame: case OperandLocation::BaselineFrame:
case OperandLocation::DoubleReg:
case OperandLocation::Uninitialized: case OperandLocation::Uninitialized:
break; break;
} }
@ -1867,6 +1921,39 @@ CacheIRCompiler::emitLoadInt32ArrayLengthResult()
EmitStoreResult(masm, scratch, JSVAL_TYPE_INT32, output); EmitStoreResult(masm, scratch, JSVAL_TYPE_INT32, output);
return true; return true;
} }
bool
CacheIRCompiler::emitDoubleAddResult()
{
AutoOutputRegister output(*this);
// Float register must be preserved. The BinaryArith ICs use
// the fact that baseline has them available, as well as fixed temps on
// LBinaryCache.
allocator.loadDouble(masm, reader.valOperandId(), FloatReg0);
allocator.loadDouble(masm, reader.valOperandId(), FloatReg1);
masm.addDouble(FloatReg1, FloatReg0);
masm.boxDouble(FloatReg0, output.valueReg(), FloatReg0);
return true;
}
bool
CacheIRCompiler::emitInt32AddResult()
{
AutoOutputRegister output(*this);
Register lhs = allocator.useRegister(masm, reader.int32OperandId());
Register rhs = allocator.useRegister(masm, reader.int32OperandId());
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
masm.branchAdd32(Assembler::Overflow, lhs, rhs, failure->label());
EmitStoreResult(masm, rhs, JSVAL_TYPE_INT32, output);
return true;
}
bool bool
CacheIRCompiler::emitInt32NegationResult() CacheIRCompiler::emitInt32NegationResult()

Просмотреть файл

@ -51,6 +51,8 @@ namespace jit {
_(LoadUndefinedResult) \ _(LoadUndefinedResult) \
_(LoadBooleanResult) \ _(LoadBooleanResult) \
_(LoadInt32ArrayLengthResult) \ _(LoadInt32ArrayLengthResult) \
_(Int32AddResult) \
_(DoubleAddResult) \
_(Int32NegationResult) \ _(Int32NegationResult) \
_(Int32NotResult) \ _(Int32NotResult) \
_(DoubleNegationResult) \ _(DoubleNegationResult) \
@ -329,6 +331,7 @@ class MOZ_RAII CacheRegisterAllocator
void popPayload(MacroAssembler& masm, OperandLocation* loc, Register dest); void popPayload(MacroAssembler& masm, OperandLocation* loc, Register dest);
void popValue(MacroAssembler& masm, OperandLocation* loc, ValueOperand dest); void popValue(MacroAssembler& masm, OperandLocation* loc, ValueOperand dest);
Address valueAddress(MacroAssembler& masm, OperandLocation* loc);
#ifdef DEBUG #ifdef DEBUG
void assertValidState() const; void assertValidState() const;
@ -469,6 +472,9 @@ class MOZ_RAII CacheRegisterAllocator
Register defineRegister(MacroAssembler& masm, TypedOperandId typedId); Register defineRegister(MacroAssembler& masm, TypedOperandId typedId);
ValueOperand defineValueRegister(MacroAssembler& masm, ValOperandId val); ValueOperand defineValueRegister(MacroAssembler& masm, ValOperandId val);
// Loads (and unboxes) a value into a float register (caller guarded)
void loadDouble(MacroAssembler&, ValOperandId, FloatRegister);
// Returns |val|'s JSValueType or JSVAL_TYPE_UNKNOWN. // Returns |val|'s JSValueType or JSVAL_TYPE_UNKNOWN.
JSValueType knownType(ValOperandId val) const; JSValueType knownType(ValOperandId val) const;

Просмотреть файл

@ -156,6 +156,17 @@ CacheIRSpewer::valueProperty(const char* name, const Value& v)
j.endObject(); j.endObject();
} }
void
CacheIRSpewer::opcodeProperty(const char* name, const JSOp op)
{
MOZ_ASSERT(enabled());
JSONPrinter& j = json.ref();
j.beginStringProperty(name);
output.put(CodeName[op]);
j.endStringProperty();
}
void void
CacheIRSpewer::attached(const char* name) CacheIRSpewer::attached(const char* name)
{ {

Просмотреть файл

@ -37,6 +37,7 @@ class CacheIRSpewer
void beginCache(const IRGenerator& generator); void beginCache(const IRGenerator& generator);
void valueProperty(const char* name, const Value& v); void valueProperty(const char* name, const Value& v);
void opcodeProperty(const char* name, const JSOp op);
void attached(const char* name); void attached(const char* name);
void endCache(); void endCache();
@ -74,6 +75,10 @@ class CacheIRSpewer
sp_.valueProperty(name, v); sp_.valueProperty(name, v);
} }
void opcodeProperty(const char* name, const JSOp op) const {
sp_.opcodeProperty(name, op);
}
explicit operator bool() const { explicit operator bool() const {
return sp_.enabled(); return sp_.enabled();
} }

Просмотреть файл

@ -188,6 +188,11 @@ typedef bool (*IonUnaryArithICFn)(JSContext* cx, HandleScript outerScript, IonUn
static const VMFunction IonUnaryArithICInfo = static const VMFunction IonUnaryArithICInfo =
FunctionInfo<IonUnaryArithICFn>(IonUnaryArithIC::update, "IonUnaryArithIC::update"); FunctionInfo<IonUnaryArithICFn>(IonUnaryArithIC::update, "IonUnaryArithIC::update");
typedef bool (*IonBinaryArithICFn)(JSContext* cx, HandleScript outerScript, IonBinaryArithIC* stub,
HandleValue lhs, HandleValue rhs, MutableHandleValue res);
static const VMFunction IonBinaryArithICInfo =
FunctionInfo<IonBinaryArithICFn>(IonBinaryArithIC::update, "IonBinaryArithIC::update");
void void
CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool) CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool)
{ {
@ -380,6 +385,23 @@ CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool)
masm.jump(ool->rejoin()); masm.jump(ool->rejoin());
return; return;
} }
case CacheKind::BinaryArith: {
IonBinaryArithIC* binaryArithIC = ic->asBinaryArithIC();
saveLive(lir);
pushArg(binaryArithIC->rhs());
pushArg(binaryArithIC->lhs());
icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
pushArg(ImmGCPtr(gen->info().script()));
callVM(IonBinaryArithICInfo, lir);
StoreValueTo(binaryArithIC->output()).generate(this);
restoreLiveIgnore(lir, StoreValueTo(binaryArithIC->output()).clobbered());
masm.jump(ool->rejoin());
return;
}
case CacheKind::Call: case CacheKind::Call:
case CacheKind::Compare: case CacheKind::Compare:
case CacheKind::TypeOf: case CacheKind::TypeOf:
@ -2760,6 +2782,18 @@ CodeGenerator::emitSharedStub(ICStub::Kind kind, LInstruction* lir)
markSafepointAt(callOffset, lir); markSafepointAt(callOffset, lir);
} }
void
CodeGenerator::visitBinaryCache(LBinaryCache* lir)
{
LiveRegisterSet liveRegs = lir->safepoint()->liveRegs();
TypedOrValueRegister lhs = TypedOrValueRegister(ToValue(lir, LBinaryCache::LhsInput));
TypedOrValueRegister rhs = TypedOrValueRegister(ToValue(lir, LBinaryCache::RhsInput));
ValueOperand output = ToOutValue(lir);
IonBinaryArithIC ic(liveRegs, lhs, rhs, output);
addIC(lir, allocateIC(ic));
}
void void
CodeGenerator::visitBinarySharedStub(LBinarySharedStub* lir) CodeGenerator::visitBinarySharedStub(LBinarySharedStub* lir)
{ {

Просмотреть файл

@ -3570,6 +3570,12 @@ IonBuilder::arithTrySharedStub(bool* emitted, JSOp op,
stub = MUnaryCache::New(alloc(), right); stub = MUnaryCache::New(alloc(), right);
break; break;
case JSOP_ADD: case JSOP_ADD:
// If not disabled, prefer the cache IR stub.
if (!JitOptions.disableCacheIRBinaryArith) {
stub = MBinaryCache::New(alloc(), left, right);
break;
}
MOZ_FALLTHROUGH;
case JSOP_SUB: case JSOP_SUB:
case JSOP_MUL: case JSOP_MUL:
case JSOP_DIV: case JSOP_DIV:

Просмотреть файл

@ -523,6 +523,20 @@ IonCacheIRCompiler::init()
allocator.initInputLocation(0, ic->input()); allocator.initInputLocation(0, ic->input());
break; break;
} }
case CacheKind::BinaryArith: {
IonBinaryArithIC* ic = ic_->asBinaryArithIC();
ValueOperand output = ic->output();
available.add(output);
liveRegs_.emplace(ic->liveRegs());
outputUnchecked_.emplace(TypedOrValueRegister(output));
MOZ_ASSERT(numInputs == 2);
allocator.initInputLocation(0, ic->lhs());
allocator.initInputLocation(1, ic->rhs());
break;
}
case CacheKind::Call: case CacheKind::Call:
case CacheKind::Compare: case CacheKind::Compare:
case CacheKind::TypeOf: case CacheKind::TypeOf:

Просмотреть файл

@ -58,6 +58,8 @@ IonIC::scratchRegisterForEntryJump()
return asInstanceOfIC()->output(); return asInstanceOfIC()->output();
case CacheKind::UnaryArith: case CacheKind::UnaryArith:
return asUnaryArithIC()->output().scratchReg(); return asUnaryArithIC()->output().scratchReg();
case CacheKind::BinaryArith:
return asBinaryArithIC()->output().scratchReg();
case CacheKind::Call: case CacheKind::Call:
case CacheKind::Compare: case CacheKind::Compare:
case CacheKind::TypeOf: case CacheKind::TypeOf:
@ -548,6 +550,48 @@ IonUnaryArithIC::update(JSContext* cx, HandleScript outerScript, IonUnaryArithIC
return true; return true;
} }
/* static */ bool
IonBinaryArithIC::update(JSContext* cx, HandleScript outerScript, IonBinaryArithIC* ic,
HandleValue lhs, HandleValue rhs, MutableHandleValue ret)
{
IonScript* ionScript = outerScript->ionScript();
RootedScript script(cx, ic->script());
jsbytecode* pc = ic->pc();
JSOp op = JSOp(*pc);
// Don't pass lhs/rhs directly, we need the original values when
// generating stubs.
RootedValue lhsCopy(cx, lhs);
RootedValue rhsCopy(cx, rhs);
// Perform the compare operation.
switch(op) {
case JSOP_ADD:
// Do an add.
if (!AddValues(cx, &lhsCopy, &rhsCopy, ret))
return false;
break;
default:
MOZ_CRASH("Unhandled binary arith op");
}
if (ic->state().maybeTransition())
ic->discardStubs(cx->zone());
if (ic->state().canAttachStub()) {
bool attached = false;
BinaryArithIRGenerator gen(cx, script, pc, ic->state().mode(),
op, lhs, rhs, ret);
if (gen.tryAttachStub()) {
ic->attachCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), ionScript, &attached);
if (!attached)
ic->state().trackNotAttached();
}
}
return true;
}
uint8_t* uint8_t*
IonICStub::stubDataStart() IonICStub::stubDataStart()
{ {

Просмотреть файл

@ -66,6 +66,7 @@ class IonHasOwnIC;
class IonInIC; class IonInIC;
class IonInstanceOfIC; class IonInstanceOfIC;
class IonUnaryArithIC; class IonUnaryArithIC;
class IonBinaryArithIC;
class IonIC class IonIC
{ {
@ -177,6 +178,10 @@ class IonIC
MOZ_ASSERT(kind_ == CacheKind::UnaryArith); MOZ_ASSERT(kind_ == CacheKind::UnaryArith);
return (IonUnaryArithIC*)this; return (IonUnaryArithIC*)this;
} }
IonBinaryArithIC* asBinaryArithIC() {
MOZ_ASSERT(kind_ == CacheKind::BinaryArith);
return (IonBinaryArithIC*)this;
}
void updateBaseAddress(JitCode* code); void updateBaseAddress(JitCode* code);
@ -504,6 +509,34 @@ class IonUnaryArithIC : public IonIC
HandleValue val, MutableHandleValue res); HandleValue val, MutableHandleValue res);
}; };
class IonBinaryArithIC : public IonIC
{
LiveRegisterSet liveRegs_;
TypedOrValueRegister lhs_;
TypedOrValueRegister rhs_;
ValueOperand output_;
public:
IonBinaryArithIC(LiveRegisterSet liveRegs, TypedOrValueRegister lhs, TypedOrValueRegister rhs, ValueOperand output)
: IonIC(CacheKind::BinaryArith),
liveRegs_(liveRegs),
lhs_(lhs),
rhs_(rhs),
output_(output)
{ }
LiveRegisterSet liveRegs() const { return liveRegs_; }
TypedOrValueRegister lhs() const { return lhs_; }
TypedOrValueRegister rhs() const { return rhs_; }
ValueOperand output() const { return output_; }
static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, IonBinaryArithIC* stub,
HandleValue lhs, HandleValue rhs, MutableHandleValue res);
};
} // namespace jit } // namespace jit
} // namespace js } // namespace js

Просмотреть файл

@ -125,6 +125,9 @@ DefaultJitOptions::DefaultJitOptions()
// Toggles whether CacheIR stubs are used. // Toggles whether CacheIR stubs are used.
SET_DEFAULT(disableCacheIR, false); SET_DEFAULT(disableCacheIR, false);
// Toggles whether CacheIR stubs for binary arith operations are used
SET_DEFAULT(disableCacheIRBinaryArith, false);
// Toggles whether shared stubs are used in Ionmonkey. // Toggles whether shared stubs are used in Ionmonkey.
SET_DEFAULT(disableSharedStubs, false); SET_DEFAULT(disableSharedStubs, false);

Просмотреть файл

@ -63,6 +63,7 @@ struct DefaultJitOptions
bool disableRecoverIns; bool disableRecoverIns;
bool disableScalarReplacement; bool disableScalarReplacement;
bool disableCacheIR; bool disableCacheIR;
bool disableCacheIRBinaryArith;
bool disableSharedStubs; bool disableSharedStubs;
bool disableSincos; bool disableSincos;
bool disableSink; bool disableSink;

Просмотреть файл

@ -2512,6 +2512,24 @@ LIRGenerator::visitStringReplace(MStringReplace* ins)
assignSafepoint(lir, ins); assignSafepoint(lir, ins);
} }
void
LIRGenerator::visitBinaryCache(MBinaryCache* ins)
{
MDefinition* lhs = ins->getOperand(0);
MDefinition* rhs = ins->getOperand(1);
MOZ_ASSERT(ins->type() == MIRType::Value);
MOZ_ASSERT(ins->type() == MIRType::Value);
LBinaryCache* lir = new(alloc()) LBinaryCache(useBox(lhs),
useBox(rhs),
tempFixed(FloatReg0),
tempFixed(FloatReg1));
defineBox(lir, ins);
assignSafepoint(lir, ins);
}
void void
LIRGenerator::visitBinarySharedStub(MBinarySharedStub* ins) LIRGenerator::visitBinarySharedStub(MBinarySharedStub* ins)
{ {

Просмотреть файл

@ -8338,6 +8338,22 @@ class MBinarySharedStub
TRIVIAL_NEW_WRAPPERS TRIVIAL_NEW_WRAPPERS
}; };
class MBinaryCache
: public MBinaryInstruction,
public MixPolicy<BoxPolicy<0>, BoxPolicy<1> >::Data
{
protected:
explicit MBinaryCache(MDefinition* left, MDefinition* right)
: MBinaryInstruction(classOpcode, left, right)
{
setResultType(MIRType::Value);
}
public:
INSTRUCTION_HEADER(BinaryCache)
TRIVIAL_NEW_WRAPPERS
};
class MUnaryCache class MUnaryCache
: public MUnaryInstruction, : public MUnaryInstruction,
public BoxPolicy<0>::Data public BoxPolicy<0>::Data

Просмотреть файл

@ -673,6 +673,12 @@ SharedStubInfo::outerScript(JSContext* cx)
// //
// BinaryArith_Fallback // BinaryArith_Fallback
// //
// This will be phased out in favour of the CacheIR system.
extern bool
DoCacheIRBinaryArithFallback(JSContext* cx, BaselineFrame* frame, ICBinaryArith_Fallback* stub_,
HandleValue lhs, HandleValue rhs, MutableHandleValue ret,
DebugModeOSRVolatileStub<ICBinaryArith_Fallback*>& stub);
static bool static bool
DoBinaryArithFallback(JSContext* cx, void* payload, ICBinaryArith_Fallback* stub_, DoBinaryArithFallback(JSContext* cx, void* payload, ICBinaryArith_Fallback* stub_,
@ -690,6 +696,7 @@ DoBinaryArithFallback(JSContext* cx, void* payload, ICBinaryArith_Fallback* stub
int(lhs.isDouble() ? JSVAL_TYPE_DOUBLE : lhs.extractNonDoubleType()), int(lhs.isDouble() ? JSVAL_TYPE_DOUBLE : lhs.extractNonDoubleType()),
int(rhs.isDouble() ? JSVAL_TYPE_DOUBLE : rhs.extractNonDoubleType())); int(rhs.isDouble() ? JSVAL_TYPE_DOUBLE : rhs.extractNonDoubleType()));
// Don't pass lhs/rhs directly, we need the original values when // Don't pass lhs/rhs directly, we need the original values when
// generating stubs. // generating stubs.
RootedValue lhsCopy(cx, lhs); RootedValue lhsCopy(cx, lhs);
@ -770,6 +777,13 @@ DoBinaryArithFallback(JSContext* cx, void* payload, ICBinaryArith_Fallback* stub
if (stub.invalid()) if (stub.invalid())
return true; return true;
// Try to use a CacheIR stub first. If that succeeds, then we're done. Otherwise, we
// need to try to attach a shared stub.
if (engine == ICStubCompiler::Engine::Baseline && !JitOptions.disableCacheIRBinaryArith) {
if (DoCacheIRBinaryArithFallback(cx, (BaselineFrame*)payload, stub_, lhs, rhs, ret, stub))
return true;
}
if (ret.isDouble()) if (ret.isDouble())
stub->setSawDoubleResult(); stub->setSawDoubleResult();

Просмотреть файл

@ -5556,6 +5556,32 @@ class LBinarySharedStub : public LCallInstructionHelper<BOX_PIECES, 2 * BOX_PIEC
static const size_t RhsInput = BOX_PIECES; static const size_t RhsInput = BOX_PIECES;
}; };
class LBinaryCache : public LInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 2>
{
public:
LIR_HEADER(BinaryCache)
// Takes two temps: these are intendend to be FloatReg0 and FloatReg1
// To allow the actual cache code to safely clobber those values without
// save and restore.
LBinaryCache(const LBoxAllocation& lhs, const LBoxAllocation& rhs,
const LDefinition& temp0, const LDefinition& temp1)
: LInstructionHelper(classOpcode)
{
setBoxOperand(LhsInput, lhs);
setBoxOperand(RhsInput, rhs);
setTemp(0, temp0);
setTemp(1, temp1);
}
const MBinaryCache* mir() const {
return mir_->toBinaryCache();
}
static const size_t LhsInput = 0;
static const size_t RhsInput = BOX_PIECES;
};
class LUnaryCache : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 0> class LUnaryCache : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
{ {
public: public:

Просмотреть файл

@ -687,6 +687,14 @@ LIRGeneratorShared::tempFixed(Register reg)
return t; return t;
} }
LDefinition
LIRGeneratorShared::tempFixed(FloatRegister reg)
{
LDefinition t = temp(LDefinition::DOUBLE);
t.setOutput(LFloatReg(reg));
return t;
}
LDefinition LDefinition
LIRGeneratorShared::tempFloat32() LIRGeneratorShared::tempFloat32()
{ {

Просмотреть файл

@ -150,8 +150,11 @@ class LIRGeneratorShared
inline LDefinition tempDouble(); inline LDefinition tempDouble();
inline LDefinition tempCopy(MDefinition* input, uint32_t reusedInput); inline LDefinition tempCopy(MDefinition* input, uint32_t reusedInput);
// Note that the fixed register has a GENERAL type. // Note that the fixed register has a GENERAL type,
// unless the arg is of FloatRegister type
inline LDefinition tempFixed(Register reg); inline LDefinition tempFixed(Register reg);
inline LDefinition tempFixed(FloatRegister reg);
template <size_t Ops, size_t Temps> template <size_t Ops, size_t Temps>
inline void defineFixed(LInstructionHelper<1, Ops, Temps>* lir, MDefinition* mir, inline void defineFixed(LInstructionHelper<1, Ops, Temps>* lir, MDefinition* mir,

Просмотреть файл

@ -8645,6 +8645,8 @@ SetContextOptions(JSContext* cx, const OptionParser& op)
jit::JitOptions.disableCacheIR = false; jit::JitOptions.disableCacheIR = false;
else if (strcmp(str, "off") == 0) else if (strcmp(str, "off") == 0)
jit::JitOptions.disableCacheIR = true; jit::JitOptions.disableCacheIR = true;
else if (strcmp(str, "nobinary") == 0)
jit::JitOptions.disableCacheIRBinaryArith = true;
else else
return OptionFailure("cache-ir-stubs", str); return OptionFailure("cache-ir-stubs", str);
} }
@ -9199,8 +9201,9 @@ main(int argc, char** argv, char** envp)
#endif #endif
|| !op.addStringOption('\0', "spectre-mitigations", "on/off", || !op.addStringOption('\0', "spectre-mitigations", "on/off",
"Whether Spectre mitigations are enabled (default: off, on to enable)") "Whether Spectre mitigations are enabled (default: off, on to enable)")
|| !op.addStringOption('\0', "cache-ir-stubs", "on/off", || !op.addStringOption('\0', "cache-ir-stubs", "on/off/nobinary",
"Use CacheIR stubs (default: on, off to disable)") "Use CacheIR stubs (default: on, off to disable, nobinary to"
"just disable binary arith)")
|| !op.addStringOption('\0', "ion-shared-stubs", "on/off", || !op.addStringOption('\0', "ion-shared-stubs", "on/off",
"Use shared stubs (default: on, off to disable)") "Use shared stubs (default: on, off to disable)")
|| !op.addStringOption('\0', "ion-scalar-replacement", "on/off", || !op.addStringOption('\0', "ion-scalar-replacement", "on/off",