Bug 1420910: Convert the Baseline InstanceOf IC to CacheIR r=jandem

This is the preliminary patch to convert the Baseline InstanceOf
IC to CacheIR, which will later allow us to add support to IonMonkey

--HG--
extra : rebase_source : a01db1640d7970dc90530fdf214248b1b076b0ab
This commit is contained in:
Matthew Gaudet 2017-12-12 16:21:45 -06:00
Родитель c8a5a694f9
Коммит 944d7681a3
13 изменённых файлов: 346 добавлений и 194 удалений

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

@ -0,0 +1,35 @@
// Testing InstanceOf IC.
Array.prototype.sum = function() {
return this.reduce(( acc, cur ) => acc + cur, 0);
}
Iters = 20;
function resultArray(fn, obj) {
res = new Array();
for (var x = 0; x < Iters; x++) {
res.push(fn(obj) ? 1 : 0);
}
return res;
}
// Ensure alteration of .prototype invalidates IC
function basic() {};
protoA = { prop1: "1"};
basic.prototype = protoA;
io1 = x => { return x instanceof basic; }
var x = new basic();
beforePrototypeModification = resultArray(io1,x).sum(); //Attach and test IC
assertEq(beforePrototypeModification,Iters);
basic.prototype = {}; // Invalidate IC
afterPrototypeModification = resultArray(io1,x).sum(); //Test
assertEq(afterPrototypeModification,0);
//Primitive LHS returns false.
assertEq(resultArray(io1,0).sum(),0);

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

@ -449,6 +449,34 @@ BaselineCacheIRCompiler::emitGuardXrayExpandoShapeAndDefaultProto()
return true;
}
bool
BaselineCacheIRCompiler::emitGuardFunctionPrototype()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
Register prototypeObject = allocator.useRegister(masm, reader.objOperandId());
// Allocate registers before the failure path to make sure they're registered
// by addFailurePath.
AutoScratchRegister scratch1(allocator, masm);
AutoScratchRegister scratch2(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
// Guard on the .prototype object.
masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch1);
masm.load32(Address(stubAddress(reader.stubOffset())), scratch2);
BaseValueIndex prototypeSlot(scratch1, scratch2);
masm.branchTestObject(Assembler::NotEqual, prototypeSlot, failure->label());
masm.unboxObject(prototypeSlot, scratch1);
masm.branchPtr(Assembler::NotEqual,
prototypeObject,
scratch1, failure->label());
return true;
}
bool
BaselineCacheIRCompiler::emitLoadFixedSlotResult()
{
@ -2076,6 +2104,7 @@ BaselineCacheIRCompiler::init(CacheKind kind)
case CacheKind::SetProp:
case CacheKind::In:
case CacheKind::HasOwn:
case CacheKind::InstanceOf:
MOZ_ASSERT(numInputs == 2);
allocator.initInputLocation(0, R0);
allocator.initInputLocation(1, R1);

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

@ -4292,46 +4292,34 @@ ICIteratorClose_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
static bool
TryAttachInstanceOfStub(JSContext* cx, BaselineFrame* frame, ICInstanceOf_Fallback* stub,
HandleFunction fun, bool* attached)
HandleValue lhs, HandleValue rhs, bool* attached)
{
MOZ_ASSERT(!*attached);
if (fun->isBoundFunction())
return true;
FallbackICSpew(cx, stub, "InstanceOf");
// If the user has supplied their own @@hasInstance method we shouldn't
// clobber it.
if (!js::FunctionHasDefaultHasInstance(fun, cx->wellKnownSymbols()))
return true;
if (stub->state().maybeTransition())
stub->discardStubs(cx);
// Refuse to optimize any function whose [[Prototype]] isn't
// Function.prototype.
if (!fun->hasStaticPrototype() || fun->hasUncacheableProto())
return true;
if (stub->state().canAttachStub()) {
RootedScript script(cx, frame->script());
jsbytecode* pc = stub->icEntry()->pc(script);
Value funProto = cx->global()->getPrototype(JSProto_Function);
if (funProto.isObject() && fun->staticPrototype() != &funProto.toObject())
return true;
ICStubEngine engine = ICStubEngine::Baseline;
InstanceOfIRGenerator gen(cx, script, pc, stub->state().mode(),
lhs,
rhs);
Shape* shape = fun->lookupPure(cx->names().prototype);
if (!shape || !shape->isDataProperty())
return true;
if (gen.tryAttachStub()) {
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
BaselineCacheIRStubKind::Regular,
engine, script, stub, attached);
if (newStub)
JitSpew(JitSpew_BaselineIC, " Attached InstanceOf CacheIR stub, attached is now %d", *attached);
}
if (!attached)
stub->state().trackNotAttached();
}
uint32_t slot = shape->slot();
MOZ_ASSERT(fun->numFixedSlots() == 0, "Stub code relies on this");
if (!fun->getSlot(slot).isObject())
return true;
JSObject* protoObject = &fun->getSlot(slot).toObject();
JitSpew(JitSpew_BaselineIC, " Generating InstanceOf(Function) stub");
ICInstanceOf_Function::Compiler compiler(cx, fun->lastProperty(), protoObject, slot);
ICStub* newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
if (!newStub)
return false;
stub->addNewStub(newStub);
*attached = true;
return true;
}
@ -4362,12 +4350,8 @@ DoInstanceOfFallback(JSContext* cx, BaselineFrame* frame, ICInstanceOf_Fallback*
// for use during Ion compilation.
EnsureTrackPropertyTypes(cx, obj, NameToId(cx->names().prototype));
if (stub->numOptimizedStubs() >= ICInstanceOf_Fallback::MAX_OPTIMIZED_STUBS)
return true;
RootedFunction fun(cx, &obj->as<JSFunction>());
bool attached = false;
if (!TryAttachInstanceOfStub(cx, frame, stub, fun, &attached))
if (!TryAttachInstanceOfStub(cx, frame, stub, lhs, rhs, &attached))
return false;
if (!attached)
stub->noteUnoptimizableAccess();
@ -4399,82 +4383,6 @@ ICInstanceOf_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
return tailCallVM(DoInstanceOfFallbackInfo, masm);
}
bool
ICInstanceOf_Function::Compiler::generateStubCode(MacroAssembler& masm)
{
MOZ_ASSERT(engine_ == Engine::Baseline);
Label failure;
// Ensure RHS is an object.
masm.branchTestObject(Assembler::NotEqual, R1, &failure);
Register rhsObj = masm.extractObject(R1, ExtractTemp0);
// Allow using R1's type register as scratch. We have to restore it when
// we want to jump to the next stub.
Label failureRestoreR1;
AllocatableGeneralRegisterSet regs(availableGeneralRegs(1));
regs.takeUnchecked(rhsObj);
Register scratch1 = regs.takeAny();
Register scratch2 = regs.takeAny();
// Shape guard.
masm.loadPtr(Address(ICStubReg, ICInstanceOf_Function::offsetOfShape()), scratch1);
masm.branchTestObjShape(Assembler::NotEqual, rhsObj, scratch1, &failureRestoreR1);
// Guard on the .prototype object.
masm.loadPtr(Address(rhsObj, NativeObject::offsetOfSlots()), scratch1);
masm.load32(Address(ICStubReg, ICInstanceOf_Function::offsetOfSlot()), scratch2);
BaseValueIndex prototypeSlot(scratch1, scratch2);
masm.branchTestObject(Assembler::NotEqual, prototypeSlot, &failureRestoreR1);
masm.unboxObject(prototypeSlot, scratch1);
masm.branchPtr(Assembler::NotEqual,
Address(ICStubReg, ICInstanceOf_Function::offsetOfPrototypeObject()),
scratch1, &failureRestoreR1);
// If LHS is a primitive, return false.
Label returnFalse, returnTrue;
masm.branchTestObject(Assembler::NotEqual, R0, &returnFalse);
// LHS is an object. Load its proto.
masm.unboxObject(R0, scratch2);
masm.loadObjProto(scratch2, scratch2);
{
// Walk the proto chain until we either reach the target object,
// nullptr or LazyProto.
Label loop;
masm.bind(&loop);
masm.branchPtr(Assembler::Equal, scratch2, scratch1, &returnTrue);
masm.branchTestPtr(Assembler::Zero, scratch2, scratch2, &returnFalse);
MOZ_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1);
masm.branchPtr(Assembler::Equal, scratch2, ImmWord(1), &failureRestoreR1);
masm.loadObjProto(scratch2, scratch2);
masm.jump(&loop);
}
EmitReturnFromIC(masm);
masm.bind(&returnFalse);
masm.moveValue(BooleanValue(false), R0);
EmitReturnFromIC(masm);
masm.bind(&returnTrue);
masm.moveValue(BooleanValue(true), R0);
EmitReturnFromIC(masm);
masm.bind(&failureRestoreR1);
masm.tagValue(JSVAL_TYPE_OBJECT, rhsObj, R1);
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
//
// TypeOf_Fallback
//
@ -4667,14 +4575,6 @@ ICGetIntrinsic_Constant::ICGetIntrinsic_Constant(JitCode* stubCode, const Value&
ICGetIntrinsic_Constant::~ICGetIntrinsic_Constant()
{ }
ICInstanceOf_Function::ICInstanceOf_Function(JitCode* stubCode, Shape* shape,
JSObject* prototypeObj, uint32_t slot)
: ICStub(InstanceOf_Function, stubCode),
shape_(shape),
prototypeObj_(prototypeObj),
slot_(slot)
{ }
ICCall_Scripted::ICCall_Scripted(JitCode* stubCode, ICStub* firstMonitorStub,
JSFunction* callee, JSObject* templateObject,
uint32_t pcOffset)

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

@ -1454,7 +1454,6 @@ class ICInstanceOf_Fallback : public ICFallbackStub
static const uint16_t UNOPTIMIZABLE_ACCESS_BIT = 0x1;
public:
static const uint32_t MAX_OPTIMIZED_STUBS = 4;
void noteUnoptimizableAccess() {
extra_ |= UNOPTIMIZABLE_ACCESS_BIT;
@ -1478,59 +1477,6 @@ class ICInstanceOf_Fallback : public ICFallbackStub
};
};
class ICInstanceOf_Function : public ICStub
{
friend class ICStubSpace;
GCPtrShape shape_;
GCPtrObject prototypeObj_;
uint32_t slot_;
ICInstanceOf_Function(JitCode* stubCode, Shape* shape, JSObject* prototypeObj, uint32_t slot);
public:
GCPtrShape& shape() {
return shape_;
}
GCPtrObject& prototypeObject() {
return prototypeObj_;
}
uint32_t slot() const {
return slot_;
}
static size_t offsetOfShape() {
return offsetof(ICInstanceOf_Function, shape_);
}
static size_t offsetOfPrototypeObject() {
return offsetof(ICInstanceOf_Function, prototypeObj_);
}
static size_t offsetOfSlot() {
return offsetof(ICInstanceOf_Function, slot_);
}
class Compiler : public ICStubCompiler {
RootedShape shape_;
RootedObject prototypeObj_;
uint32_t slot_;
protected:
MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
public:
Compiler(JSContext* cx, Shape* shape, JSObject* prototypeObj, uint32_t slot)
: ICStubCompiler(cx, ICStub::InstanceOf_Function, Engine::Baseline),
shape_(cx, shape),
prototypeObj_(cx, prototypeObj),
slot_(slot)
{}
ICStub* getStub(ICStubSpace* space) override {
return newStub<ICInstanceOf_Function>(space, getStubCode(), shape_, prototypeObj_,
slot_);
}
};
};
// TypeOf
// JSOP_TYPEOF
// JSOP_TYPEOFEXPR

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

@ -1383,27 +1383,49 @@ BaselineInspector::instanceOfData(jsbytecode* pc, Shape** shape, uint32_t* slot,
JSObject** prototypeObject)
{
MOZ_ASSERT(*pc == JSOP_INSTANCEOF);
if (!hasBaselineScript())
return false;
const ICEntry& entry = icEntryFromPC(pc);
ICStub* firstStub = entry.firstStub();
ICStub* stub = entry.firstStub();
if (!stub->isInstanceOf_Function() ||
!stub->next()->isInstanceOf_Fallback() ||
stub->next()->toInstanceOf_Fallback()->hadUnoptimizableAccess())
{
// Ensure singleton instanceof stub
if (!firstStub->next() ||
!firstStub->isCacheIR_Regular() ||
!firstStub->next()->isInstanceOf_Fallback() ||
firstStub->next()->toInstanceOf_Fallback()->hadUnoptimizableAccess())
{
return false;
}
ICCacheIR_Regular* stub = entry.firstStub()->toCacheIR_Regular();
CacheIRReader reader(stub->stubInfo());
ObjOperandId rhsId = ObjOperandId(1);
ObjOperandId resId = ObjOperandId(2);
if (!reader.matchOp(CacheOp::GuardIsObject, rhsId))
return false;
}
ICInstanceOf_Function* optStub = stub->toInstanceOf_Function();
*shape = optStub->shape();
*prototypeObject = optStub->prototypeObject();
*slot = optStub->slot();
if (!reader.matchOp(CacheOp::GuardShape, rhsId))
return false;
*shape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());
if (!reader.matchOp(CacheOp::LoadObject, resId))
return false;
*prototypeObject = stub->stubInfo()->getStubField<JSObject*>(stub, reader.stubOffset()).get();
if (IsInsideNursery(*prototypeObject))
return false;
if (!reader.matchOp(CacheOp::GuardFunctionPrototype, rhsId))
return false;
reader.skip(); // Skip over the protoID;
*slot = stub->stubInfo()->getStubRawWord(stub, reader.stubOffset());
return true;
}

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

@ -4001,6 +4001,113 @@ SetPropIRGenerator::tryAttachAddSlotStub(HandleObjectGroup oldGroup, HandleShape
return true;
}
InstanceOfIRGenerator::InstanceOfIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
ICState::Mode mode, HandleValue lhs, HandleValue rhs)
: IRGenerator(cx, script, pc, CacheKind::InstanceOf, mode),
lhsVal_(lhs),
rhsVal_(rhs)
{ }
bool
InstanceOfIRGenerator::tryAttachStub()
{
MOZ_ASSERT(cacheKind_ == CacheKind::InstanceOf);
AutoAssertNoPendingException aanpe(cx_);
RootedFunction fun(cx_, &rhsVal_.toObject().as<JSFunction>());
if (fun->isBoundFunction()) {
trackNotAttached();
return false;
}
// If the user has supplied their own @@hasInstance method we shouldn't
// clobber it.
if (!js::FunctionHasDefaultHasInstance(fun, cx_->wellKnownSymbols())) {
trackNotAttached();
return false;
}
// Refuse to optimize any function whose [[Prototype]] isn't
// Function.prototype.
if (!fun->hasStaticPrototype() || fun->hasUncacheableProto()) {
trackNotAttached();
return false;
}
Value funProto = cx_->global()->getPrototype(JSProto_Function);
if (!funProto.isObject() || fun->staticPrototype() != &funProto.toObject()) {
trackNotAttached();
return false;
}
// Ensure that the function's prototype slot is the same.
Shape* shape = fun->lookupPure(cx_->names().prototype);
if (!shape || !shape->isDataProperty()) {
trackNotAttached();
return false;
}
uint32_t slot = shape->slot();
MOZ_ASSERT(fun->numFixedSlots() == 0, "Stub code relies on this");
if (!fun->getSlot(slot).isObject()) {
trackNotAttached();
return false;
}
JSObject* prototypeObject = &fun->getSlot(slot).toObject();
// Abstract Objects
ValOperandId lhs(writer.setInputOperandId(0));
ValOperandId rhs(writer.setInputOperandId(1));
ObjOperandId rhsId = writer.guardIsObject(rhs);
writer.guardShape(rhsId, fun->lastProperty());
// Load prototypeObject into the cache -- consumed twice in the IC
ObjOperandId protoId = writer.loadObject(prototypeObject);
// Ensure that rhs[slot] == prototypeObject.
writer.guardFunctionPrototype(rhsId, slot, protoId);
// Needn't guard LHS is object, because the actual stub can handle that
// and correctly return false.
writer.loadInstanceOfObjectResult(lhs, protoId, slot);
writer.returnFromIC();
trackAttached("InstanceOf");
return true;
}
void
InstanceOfIRGenerator::trackAttached(const char* name)
{
#ifdef JS_CACHEIR_SPEW
CacheIRSpewer& sp = CacheIRSpewer::singleton();
if (sp.enabled()) {
LockGuard<Mutex> guard(sp.lock());
sp.beginCache(guard, *this);
sp.valueProperty(guard, "lhs", lhsVal_);
sp.valueProperty(guard, "rhs", rhsVal_);
sp.attached(guard, name);
sp.endCache(guard);
}
#endif
}
void
InstanceOfIRGenerator::trackNotAttached()
{
#ifdef JS_CACHEIR_SPEW
CacheIRSpewer& sp = CacheIRSpewer::singleton();
if (sp.enabled()) {
LockGuard<Mutex> guard(sp.lock());
sp.beginCache(guard, *this);
sp.valueProperty(guard, "lhs", lhsVal_);
sp.valueProperty(guard, "rhs", rhsVal_);
sp.endCache(guard);
}
#endif
}
TypeOfIRGenerator::TypeOfIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
ICState::Mode mode, HandleValue value)
: IRGenerator(cx, script, pc, CacheKind::TypeOf, mode),

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

@ -148,6 +148,7 @@ class TypedOperandId : public OperandId
_(In) \
_(HasOwn) \
_(TypeOf) \
_(InstanceOf) \
_(GetIterator) \
_(Compare) \
_(Call)
@ -195,6 +196,7 @@ extern const char* CacheKindNames[];
_(GuardGroupHasUnanalyzedNewScript) \
_(GuardIndexIsNonNegative) \
_(GuardXrayExpandoShapeAndDefaultProto) \
_(GuardFunctionPrototype) \
_(LoadStackValue) \
_(LoadObject) \
_(LoadProto) \
@ -264,6 +266,7 @@ extern const char* CacheKindNames[];
_(LoadUndefinedResult) \
_(LoadBooleanResult) \
_(LoadStringResult) \
_(LoadInstanceOfObjectResult) \
_(LoadTypeOfObjectResult) \
\
_(CallStringSplitResult) \
@ -533,6 +536,12 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
writeOpWithOperandId(CacheOp::GuardXrayExpandoShapeAndDefaultProto, obj);
buffer_.writeByte(uint32_t(!!shapeWrapper)); addStubField(uintptr_t(shapeWrapper), StubField::Type::JSObject);
}
// Guard rhs[slot] == prototypeObject
void guardFunctionPrototype(ObjOperandId rhs, uint32_t slot, ObjOperandId protoId) {
writeOpWithOperandId(CacheOp::GuardFunctionPrototype, rhs);
writeOperandId(protoId);
addStubField(slot, StubField::Type::RawWord);
}
void guardGroup(ObjOperandId obj, ObjectGroup* group) {
writeOpWithOperandId(CacheOp::GuardGroup, obj);
addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
@ -992,10 +1001,14 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
void loadObjectResult(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::LoadObjectResult, obj);
}
void loadInstanceOfObjectResult(ValOperandId lhs, ObjOperandId protoId, uint32_t slot) {
writeOp(CacheOp::LoadInstanceOfObjectResult);
writeOperandId(lhs);
writeOperandId(protoId);
}
void loadTypeOfObjectResult(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::LoadTypeOfObjectResult, obj);
}
void callStringSplitResult(StringOperandId str, StringOperandId sep, ObjectGroup* group) {
writeOp(CacheOp::CallStringSplitResult);
writeOperandId(str);
@ -1063,6 +1076,9 @@ class MOZ_RAII CacheIRReader
return CacheOp(buffer_.readByte());
}
// Skip data not currently used.
void skip() { buffer_.readByte(); }
ValOperandId valOperandId() { return ValOperandId(buffer_.readByte()); }
ObjOperandId objOperandId() { return ObjOperandId(buffer_.readByte()); }
StringOperandId stringOperandId() { return StringOperandId(buffer_.readByte()); }
@ -1485,6 +1501,20 @@ class MOZ_RAII HasPropIRGenerator : public IRGenerator
bool tryAttachStub();
};
class MOZ_RAII InstanceOfIRGenerator : public IRGenerator
{
HandleValue lhsVal_;
HandleValue rhsVal_;
void trackAttached(const char* name);
void trackNotAttached();
public:
InstanceOfIRGenerator(JSContext*, HandleScript, jsbytecode*, ICState::Mode,
HandleValue, HandleValue);
bool tryAttachStub();
};
class MOZ_RAII TypeOfIRGenerator : public IRGenerator
{
HandleValue val_;

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

@ -863,6 +863,13 @@ AsGCPtr(uintptr_t* ptr)
return reinterpret_cast<GCPtr<T>*>(ptr);
}
uintptr_t
CacheIRStubInfo::getStubRawWord(ICStub* stub, uint32_t offset) const {
uint8_t* stubData = (uint8_t*)stub + stubDataOffset_;
MOZ_ASSERT(uintptr_t(stubData) % sizeof(uintptr_t) == 0);
return *(uintptr_t*)(stubData + offset);
}
template<class Stub, class T>
GCPtr<T>&
CacheIRStubInfo::getStubField(Stub* stub, uint32_t offset) const
@ -2631,3 +2638,50 @@ CacheIRCompiler::emitCallObjectHasSparseElementResult()
masm.adjustStack(sizeof(Value));
return true;
}
bool
CacheIRCompiler::emitLoadInstanceOfObjectResult()
{
AutoOutputRegister output(*this);
ValueOperand lhs = allocator.useValueRegister(masm, reader.valOperandId());
Register proto = allocator.useRegister(masm, reader.objOperandId());
AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
Label returnFalse, returnTrue, done;
masm.branchTestObject(Assembler::NotEqual, lhs, &returnFalse);
// LHS is an object. Load its proto.
masm.unboxObject(lhs, scratch);
masm.loadObjProto(scratch, scratch);
{
// Walk the proto chain until we either reach the target object,
// nullptr or LazyProto.
Label loop;
masm.bind(&loop);
masm.branchPtr(Assembler::Equal, scratch, proto, &returnTrue);
masm.branchTestPtr(Assembler::Zero, scratch, scratch, &returnFalse);
MOZ_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1);
masm.branchPtr(Assembler::Equal, scratch, ImmWord(1), failure->label());
masm.loadObjProto(scratch, scratch);
masm.jump(&loop);
}
masm.bind(&returnFalse);
EmitStoreBoolean(masm, false, output);
masm.jump(&done);
masm.bind(&returnTrue);
EmitStoreBoolean(masm, true, output);
//fallthrough
masm.bind(&done);
return true;
}

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

@ -47,6 +47,7 @@ namespace jit {
_(LoadStringLengthResult) \
_(LoadStringCharResult) \
_(LoadArgumentsObjectArgResult) \
_(LoadInstanceOfObjectResult) \
_(LoadDenseElementResult) \
_(LoadDenseElementHoleResult) \
_(LoadDenseElementExistsResult) \
@ -712,6 +713,8 @@ class CacheIRStubInfo
return getStubField<ICStub, T>(stub, field);
}
uintptr_t getStubRawWord(ICStub* stub, uint32_t field) const;
void copyStubData(ICStub* src, ICStub* dest) const;
};

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

@ -334,6 +334,7 @@ CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool)
case CacheKind::Call:
case CacheKind::Compare:
case CacheKind::TypeOf:
case CacheKind::InstanceOf:
MOZ_CRASH("Unsupported IC");
}
MOZ_CRASH();

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

@ -533,6 +533,7 @@ IonCacheIRCompiler::init()
case CacheKind::Call:
case CacheKind::Compare:
case CacheKind::TypeOf:
case CacheKind::InstanceOf:
MOZ_CRASH("Unsupported IC");
}
@ -844,6 +845,35 @@ IonCacheIRCompiler::emitGuardXrayExpandoShapeAndDefaultProto()
return true;
}
bool
IonCacheIRCompiler::emitGuardFunctionPrototype()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
Register prototypeObject = allocator.useRegister(masm, reader.objOperandId());
// Allocate registers before the failure path to make sure they're registered
// by addFailurePath.
AutoScratchRegister scratch1(allocator, masm);
AutoScratchRegister scratch2(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
// Guard on the .prototype object.
masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch1);
uintptr_t slot = readStubWord(reader.stubOffset(), StubField::Type::RawWord);
masm.move32(Imm32(slot), scratch2);
BaseValueIndex prototypeSlot(scratch1, scratch2);
masm.branchTestObject(Assembler::NotEqual, prototypeSlot, failure->label());
masm.unboxObject(prototypeSlot, scratch1);
masm.branchPtr(Assembler::NotEqual,
prototypeObject,
scratch1, failure->label());
return true;
}
bool
IonCacheIRCompiler::emitLoadFixedSlotResult()
{

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

@ -61,6 +61,7 @@ IonIC::scratchRegisterForEntryJump()
case CacheKind::Call:
case CacheKind::Compare:
case CacheKind::TypeOf:
case CacheKind::InstanceOf:
MOZ_CRASH("Unsupported IC");
}

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

@ -297,12 +297,6 @@ ICStub::trace(JSTracer* trc)
TraceEdge(trc, &constantStub->value(), "baseline-getintrinsic-constant-value");
break;
}
case ICStub::InstanceOf_Function: {
ICInstanceOf_Function* instanceofStub = toInstanceOf_Function();
TraceEdge(trc, &instanceofStub->shape(), "baseline-instanceof-fun-shape");
TraceEdge(trc, &instanceofStub->prototypeObject(), "baseline-instanceof-fun-prototype");
break;
}
case ICStub::NewArray_Fallback: {
ICNewArray_Fallback* stub = toNewArray_Fallback();
TraceNullableEdge(trc, &stub->templateObject(), "baseline-newarray-template");