зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1420910: Add InstanceOf inline cache to IonMonkey r=jandem
Install an inline cache for some of the instanceof calls in IonMonkey that would otherwise hit the interpreter. --HG-- extra : rebase_source : 5f87ab799d22f44c84c74ec5d53524133900ec79
This commit is contained in:
Родитель
944d7681a3
Коммит
d644f669bc
|
@ -4292,7 +4292,7 @@ ICIteratorClose_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
|
||||
static bool
|
||||
TryAttachInstanceOfStub(JSContext* cx, BaselineFrame* frame, ICInstanceOf_Fallback* stub,
|
||||
HandleValue lhs, HandleValue rhs, bool* attached)
|
||||
HandleValue lhs, HandleObject rhs, bool* attached)
|
||||
{
|
||||
MOZ_ASSERT(!*attached);
|
||||
FallbackICSpew(cx, stub, "InstanceOf");
|
||||
|
@ -4351,7 +4351,7 @@ DoInstanceOfFallback(JSContext* cx, BaselineFrame* frame, ICInstanceOf_Fallback*
|
|||
EnsureTrackPropertyTypes(cx, obj, NameToId(cx->names().prototype));
|
||||
|
||||
bool attached = false;
|
||||
if (!TryAttachInstanceOfStub(cx, frame, stub, lhs, rhs, &attached))
|
||||
if (!TryAttachInstanceOfStub(cx, frame, stub, lhs, obj, &attached))
|
||||
return false;
|
||||
if (!attached)
|
||||
stub->noteUnoptimizableAccess();
|
||||
|
|
|
@ -4002,10 +4002,10 @@ SetPropIRGenerator::tryAttachAddSlotStub(HandleObjectGroup oldGroup, HandleShape
|
|||
}
|
||||
|
||||
InstanceOfIRGenerator::InstanceOfIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
|
||||
ICState::Mode mode, HandleValue lhs, HandleValue rhs)
|
||||
ICState::Mode mode, HandleValue lhs, HandleObject rhs)
|
||||
: IRGenerator(cx, script, pc, CacheKind::InstanceOf, mode),
|
||||
lhsVal_(lhs),
|
||||
rhsVal_(rhs)
|
||||
rhsObj_(rhs)
|
||||
{ }
|
||||
|
||||
bool
|
||||
|
@ -4013,7 +4013,14 @@ InstanceOfIRGenerator::tryAttachStub()
|
|||
{
|
||||
MOZ_ASSERT(cacheKind_ == CacheKind::InstanceOf);
|
||||
AutoAssertNoPendingException aanpe(cx_);
|
||||
RootedFunction fun(cx_, &rhsVal_.toObject().as<JSFunction>());
|
||||
|
||||
// Ensure RHS is a function -- could be a Proxy, which the IC isn't prepared to handle.
|
||||
if (!rhsObj_->is<JSFunction>()) {
|
||||
trackNotAttached();
|
||||
return false;
|
||||
}
|
||||
|
||||
HandleFunction fun = rhsObj_.as<JSFunction>();
|
||||
|
||||
if (fun->isBoundFunction()) {
|
||||
trackNotAttached();
|
||||
|
@ -4086,7 +4093,7 @@ InstanceOfIRGenerator::trackAttached(const char* name)
|
|||
LockGuard<Mutex> guard(sp.lock());
|
||||
sp.beginCache(guard, *this);
|
||||
sp.valueProperty(guard, "lhs", lhsVal_);
|
||||
sp.valueProperty(guard, "rhs", rhsVal_);
|
||||
sp.valueProperty(guard, "rhs", ObjectValue(*rhsObj_));
|
||||
sp.attached(guard, name);
|
||||
sp.endCache(guard);
|
||||
}
|
||||
|
@ -4102,7 +4109,7 @@ InstanceOfIRGenerator::trackNotAttached()
|
|||
LockGuard<Mutex> guard(sp.lock());
|
||||
sp.beginCache(guard, *this);
|
||||
sp.valueProperty(guard, "lhs", lhsVal_);
|
||||
sp.valueProperty(guard, "rhs", rhsVal_);
|
||||
sp.valueProperty(guard, "rhs", ObjectValue(*rhsObj_));
|
||||
sp.endCache(guard);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1504,13 +1504,13 @@ class MOZ_RAII HasPropIRGenerator : public IRGenerator
|
|||
class MOZ_RAII InstanceOfIRGenerator : public IRGenerator
|
||||
{
|
||||
HandleValue lhsVal_;
|
||||
HandleValue rhsVal_;
|
||||
HandleObject rhsObj_;
|
||||
|
||||
void trackAttached(const char* name);
|
||||
void trackNotAttached();
|
||||
public:
|
||||
InstanceOfIRGenerator(JSContext*, HandleScript, jsbytecode*, ICState::Mode,
|
||||
HandleValue, HandleValue);
|
||||
HandleValue, HandleObject);
|
||||
|
||||
bool tryAttachStub();
|
||||
};
|
||||
|
|
|
@ -173,6 +173,12 @@ typedef bool (*IonInICFn)(JSContext*, HandleScript, IonInIC*, HandleValue, Handl
|
|||
static const VMFunction IonInICInfo =
|
||||
FunctionInfo<IonInICFn>(IonInIC::update, "IonInIC::update");
|
||||
|
||||
|
||||
typedef bool (*IonInstanceOfICFn)(JSContext*, HandleScript, IonInstanceOfIC*,
|
||||
HandleValue lhs, HandleObject rhs, bool* res);
|
||||
static const VMFunction IonInstanceOfInfo =
|
||||
FunctionInfo<IonInstanceOfICFn>(IonInstanceOfIC::update, "IonInstanceOfIC::update");
|
||||
|
||||
void
|
||||
CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool)
|
||||
{
|
||||
|
@ -331,10 +337,27 @@ CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool)
|
|||
masm.jump(ool->rejoin());
|
||||
return;
|
||||
}
|
||||
case CacheKind::InstanceOf: {
|
||||
IonInstanceOfIC* hasInstanceOfIC = ic->asInstanceOfIC();
|
||||
|
||||
saveLive(lir);
|
||||
|
||||
pushArg(hasInstanceOfIC->rhs());
|
||||
pushArg(hasInstanceOfIC->lhs());
|
||||
icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
|
||||
pushArg(ImmGCPtr(gen->info().script()));
|
||||
|
||||
callVM(IonInstanceOfInfo, lir);
|
||||
|
||||
StoreRegisterTo(hasInstanceOfIC->output()).generate(this);
|
||||
restoreLiveIgnore(lir, StoreRegisterTo(hasInstanceOfIC->output()).clobbered());
|
||||
|
||||
masm.jump(ool->rejoin());
|
||||
return;
|
||||
}
|
||||
case CacheKind::Call:
|
||||
case CacheKind::Compare:
|
||||
case CacheKind::TypeOf:
|
||||
case CacheKind::InstanceOf:
|
||||
MOZ_CRASH("Unsupported IC");
|
||||
}
|
||||
MOZ_CRASH();
|
||||
|
@ -11612,15 +11635,16 @@ typedef bool (*HasInstanceFn)(JSContext*, HandleObject, HandleValue, bool*);
|
|||
static const VMFunction HasInstanceInfo = FunctionInfo<HasInstanceFn>(js::HasInstance, "HasInstance");
|
||||
|
||||
void
|
||||
CodeGenerator::visitCallInstanceOf(LCallInstanceOf* ins)
|
||||
CodeGenerator::visitInstanceOfCache(LInstanceOfCache* ins)
|
||||
{
|
||||
ValueOperand lhs = ToValue(ins, LCallInstanceOf::LHS);
|
||||
// The Lowering ensures that RHS is an object, and that LHS is a value.
|
||||
LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
|
||||
TypedOrValueRegister lhs = TypedOrValueRegister(ToValue(ins, LInstanceOfCache::LHS));
|
||||
Register rhs = ToRegister(ins->rhs());
|
||||
MOZ_ASSERT(ToRegister(ins->output()) == ReturnReg);
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
pushArg(lhs);
|
||||
pushArg(rhs);
|
||||
callVM(HasInstanceInfo, ins);
|
||||
IonInstanceOfIC ic(liveRegs, lhs, rhs, output);
|
||||
addIC(ins, allocateIC(ic));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -371,7 +371,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
|||
void visitInArray(LInArray* ins) override;
|
||||
void visitInstanceOfO(LInstanceOfO* ins) override;
|
||||
void visitInstanceOfV(LInstanceOfV* ins) override;
|
||||
void visitCallInstanceOf(LCallInstanceOf* ins) override;
|
||||
void visitInstanceOfCache(LInstanceOfCache* ins) override;
|
||||
void visitGetDOMProperty(LGetDOMProperty* lir) override;
|
||||
void visitGetDOMMemberV(LGetDOMMemberV* lir) override;
|
||||
void visitGetDOMMemberT(LGetDOMMemberT* lir) override;
|
||||
|
|
|
@ -13214,7 +13214,7 @@ IonBuilder::jsop_instanceof()
|
|||
return resumeAfter(ins);
|
||||
} while (false);
|
||||
|
||||
MCallInstanceOf* ins = MCallInstanceOf::New(alloc(), obj, rhs);
|
||||
MInstanceOfCache* ins = MInstanceOfCache::New(alloc(), obj, rhs);
|
||||
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
|
|
@ -530,10 +530,22 @@ IonCacheIRCompiler::init()
|
|||
allocator.initInputLocation(1, ic->value());
|
||||
break;
|
||||
}
|
||||
case CacheKind::InstanceOf: {
|
||||
IonInstanceOfIC* ic = ic_->asInstanceOfIC();
|
||||
Register output = ic->output();
|
||||
available.add(output);
|
||||
liveRegs_.emplace(ic->liveRegs());
|
||||
outputUnchecked_.emplace(TypedOrValueRegister(MIRType::Boolean, AnyRegister(output)));
|
||||
|
||||
MOZ_ASSERT(numInputs == 2);
|
||||
allocator.initInputLocation(0, ic->lhs());
|
||||
allocator.initInputLocation(1, TypedOrValueRegister(MIRType::Object,
|
||||
AnyRegister(ic->rhs())));
|
||||
break;
|
||||
}
|
||||
case CacheKind::Call:
|
||||
case CacheKind::Compare:
|
||||
case CacheKind::TypeOf:
|
||||
case CacheKind::InstanceOf:
|
||||
MOZ_CRASH("Unsupported IC");
|
||||
}
|
||||
|
||||
|
|
|
@ -58,10 +58,11 @@ IonIC::scratchRegisterForEntryJump()
|
|||
return asHasOwnIC()->output();
|
||||
case CacheKind::GetIterator:
|
||||
return asGetIteratorIC()->temp1();
|
||||
case CacheKind::InstanceOf:
|
||||
return asInstanceOfIC()->output();
|
||||
case CacheKind::Call:
|
||||
case CacheKind::Compare:
|
||||
case CacheKind::TypeOf:
|
||||
case CacheKind::InstanceOf:
|
||||
MOZ_CRASH("Unsupported IC");
|
||||
}
|
||||
|
||||
|
@ -475,6 +476,32 @@ IonInIC::update(JSContext* cx, HandleScript outerScript, IonInIC* ic,
|
|||
|
||||
return OperatorIn(cx, key, obj, res);
|
||||
}
|
||||
/* static */ bool
|
||||
IonInstanceOfIC::update(JSContext* cx, HandleScript outerScript, IonInstanceOfIC* ic,
|
||||
HandleValue lhs, HandleObject rhs, bool* res)
|
||||
{
|
||||
IonScript* ionScript = outerScript->ionScript();
|
||||
|
||||
if (ic->state().maybeTransition())
|
||||
ic->discardStubs(cx->zone());
|
||||
|
||||
if (ic->state().canAttachStub()) {
|
||||
bool attached = false;
|
||||
RootedScript script(cx, ic->script());
|
||||
jsbytecode* pc = ic->pc();
|
||||
|
||||
InstanceOfIRGenerator gen(cx, script, pc, ic->state().mode(),
|
||||
lhs, rhs);
|
||||
|
||||
if (gen.tryAttachStub())
|
||||
ic->attachCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), ionScript, &attached);
|
||||
|
||||
if (!attached)
|
||||
ic->state().trackNotAttached();
|
||||
}
|
||||
|
||||
return HasInstance(cx, rhs, lhs, res);
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
IonICStub::stubDataStart()
|
||||
|
|
|
@ -64,6 +64,7 @@ class IonBindNameIC;
|
|||
class IonGetIteratorIC;
|
||||
class IonHasOwnIC;
|
||||
class IonInIC;
|
||||
class IonInstanceOfIC;
|
||||
|
||||
class IonIC
|
||||
{
|
||||
|
@ -167,6 +168,10 @@ class IonIC
|
|||
MOZ_ASSERT(kind_ == CacheKind::In);
|
||||
return (IonInIC*)this;
|
||||
}
|
||||
IonInstanceOfIC* asInstanceOfIC() {
|
||||
MOZ_ASSERT(kind_ == CacheKind::InstanceOf);
|
||||
return (IonInstanceOfIC*)this;
|
||||
}
|
||||
|
||||
void updateBaseAddress(JitCode* code, MacroAssembler& masm);
|
||||
|
||||
|
@ -441,6 +446,35 @@ class IonInIC : public IonIC
|
|||
HandleValue key, HandleObject obj, bool* res);
|
||||
};
|
||||
|
||||
class IonInstanceOfIC : public IonIC
|
||||
{
|
||||
LiveRegisterSet liveRegs_;
|
||||
|
||||
TypedOrValueRegister lhs_;
|
||||
Register rhs_;
|
||||
Register output_;
|
||||
|
||||
public:
|
||||
|
||||
IonInstanceOfIC(LiveRegisterSet liveRegs, TypedOrValueRegister lhs, Register rhs,
|
||||
Register output)
|
||||
: IonIC(CacheKind::InstanceOf),
|
||||
liveRegs_(liveRegs),
|
||||
lhs_(lhs),
|
||||
rhs_(rhs),
|
||||
output_(output)
|
||||
{ }
|
||||
|
||||
LiveRegisterSet liveRegs() const { return liveRegs_; }
|
||||
TypedOrValueRegister lhs() const { return lhs_; }
|
||||
Register rhs() const { return rhs_; }
|
||||
Register output() const { return output_; }
|
||||
|
||||
// This signature mimics that of TryAttachInstanceOfStub in baseline
|
||||
static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, IonInstanceOfIC* ic,
|
||||
HandleValue lhs, HandleObject rhs, bool* attached);
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -4335,7 +4335,7 @@ LIRGenerator::visitInstanceOf(MInstanceOf* ins)
|
|||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitCallInstanceOf(MCallInstanceOf* ins)
|
||||
LIRGenerator::visitInstanceOfCache(MInstanceOfCache* ins)
|
||||
{
|
||||
MDefinition* lhs = ins->lhs();
|
||||
MDefinition* rhs = ins->rhs();
|
||||
|
@ -4343,9 +4343,9 @@ LIRGenerator::visitCallInstanceOf(MCallInstanceOf* ins)
|
|||
MOZ_ASSERT(lhs->type() == MIRType::Value);
|
||||
MOZ_ASSERT(rhs->type() == MIRType::Object);
|
||||
|
||||
LCallInstanceOf* lir = new(alloc()) LCallInstanceOf(useBoxAtStart(lhs),
|
||||
useRegisterAtStart(rhs));
|
||||
defineReturn(lir, ins);
|
||||
LInstanceOfCache* lir = new(alloc()) LInstanceOfCache(useBox(lhs),
|
||||
useRegister(rhs));
|
||||
define(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
|
|
|
@ -294,7 +294,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
void visitInArray(MInArray* ins) override;
|
||||
void visitHasOwnCache(MHasOwnCache* ins) override;
|
||||
void visitInstanceOf(MInstanceOf* ins) override;
|
||||
void visitCallInstanceOf(MCallInstanceOf* ins) override;
|
||||
void visitInstanceOfCache(MInstanceOfCache* ins) override;
|
||||
void visitIsCallable(MIsCallable* ins) override;
|
||||
void visitIsConstructor(MIsConstructor* ins) override;
|
||||
void visitIsArray(MIsArray* ins) override;
|
||||
|
|
|
@ -12923,18 +12923,18 @@ class MInstanceOf
|
|||
};
|
||||
|
||||
// Implementation for instanceof operator with unknown rhs.
|
||||
class MCallInstanceOf
|
||||
class MInstanceOfCache
|
||||
: public MBinaryInstruction,
|
||||
public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
|
||||
{
|
||||
MCallInstanceOf(MDefinition* obj, MDefinition* proto)
|
||||
MInstanceOfCache(MDefinition* obj, MDefinition* proto)
|
||||
: MBinaryInstruction(classOpcode, obj, proto)
|
||||
{
|
||||
setResultType(MIRType::Boolean);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(CallInstanceOf)
|
||||
INSTRUCTION_HEADER(InstanceOfCache)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
};
|
||||
|
||||
|
|
|
@ -275,7 +275,7 @@ namespace jit {
|
|||
_(InCache) \
|
||||
_(HasOwnCache) \
|
||||
_(InstanceOf) \
|
||||
_(CallInstanceOf) \
|
||||
_(InstanceOfCache) \
|
||||
_(InterruptCheck) \
|
||||
_(GetDOMProperty) \
|
||||
_(GetDOMMember) \
|
||||
|
|
|
@ -8016,11 +8016,11 @@ class LInstanceOfV : public LInstructionHelper<1, BOX_PIECES, 0>
|
|||
static const size_t LHS = 0;
|
||||
};
|
||||
|
||||
class LCallInstanceOf : public LCallInstructionHelper<1, BOX_PIECES+1, 0>
|
||||
class LInstanceOfCache : public LInstructionHelper<1, BOX_PIECES+1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(CallInstanceOf)
|
||||
LCallInstanceOf(const LBoxAllocation& lhs, const LAllocation& rhs) {
|
||||
LIR_HEADER(InstanceOfCache)
|
||||
LInstanceOfCache(const LBoxAllocation& lhs, const LAllocation& rhs) {
|
||||
setBoxOperand(LHS, lhs);
|
||||
setOperand(RHS, rhs);
|
||||
}
|
||||
|
|
|
@ -383,7 +383,7 @@
|
|||
_(HasOwnCache) \
|
||||
_(InstanceOfO) \
|
||||
_(InstanceOfV) \
|
||||
_(CallInstanceOf) \
|
||||
_(InstanceOfCache) \
|
||||
_(InterruptCheck) \
|
||||
_(Rotate) \
|
||||
_(RotateI64) \
|
||||
|
|
Загрузка…
Ссылка в новой задаче