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:
Matthew Gaudet 2018-01-12 14:07:07 -05:00
Родитель 944d7681a3
Коммит d644f669bc
15 изменённых файлов: 137 добавлений и 33 удалений

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

@ -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) \