Bug 814177 - Use a callVM for generic InstanceOf cases. r=dvander

This commit is contained in:
Nicolas B. Pierron 2012-11-26 19:08:37 -08:00
Родитель 4bec908ccc
Коммит 047f75f8d3
12 изменённых файлов: 59 добавлений и 266 удалений

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

@ -3418,8 +3418,6 @@ class OutOfLineCache : public OutOfLineCodeBase<CodeGenerator>
bool accept(CodeGenerator *codegen) {
switch (ins->op()) {
case LInstruction::LOp_InstanceOfO:
case LInstruction::LOp_InstanceOfV:
case LInstruction::LOp_GetPropertyCacheT:
case LInstruction::LOp_GetPropertyCacheV:
return codegen->visitOutOfLineCacheGetProperty(this);
@ -3531,12 +3529,6 @@ CodeGenerator::visitOutOfLineCacheGetProperty(OutOfLineCache *ool)
PropertyName *name = NULL;
bool allowGetters = false;
switch (ins->op()) {
case LInstruction::LOp_InstanceOfO:
case LInstruction::LOp_InstanceOfV:
name = gen->compartment->rt->atomState.classPrototype;
objReg = ToRegister(ins->getTemp(1));
output = TypedOrValueRegister(MIRType_Object, ToAnyRegister(ins->getDef(0)));
break;
case LInstruction::LOp_GetPropertyCacheT:
name = ((LGetPropertyCacheT *) ins)->mir()->name();
objReg = ToRegister(ins->getOperand(0));
@ -4214,15 +4206,15 @@ CodeGenerator::visitInArray(LInArray *lir)
}
bool
CodeGenerator::visitInstanceOfTypedO(LInstanceOfTypedO *ins)
CodeGenerator::visitInstanceOfO(LInstanceOfO *ins)
{
return emitInstanceOfTyped(ins, ins->mir()->prototypeObject());
return emitInstanceOf(ins, ins->mir()->prototypeObject());
}
bool
CodeGenerator::visitInstanceOfTypedV(LInstanceOfTypedV *ins)
CodeGenerator::visitInstanceOfV(LInstanceOfV *ins)
{
return emitInstanceOfTyped(ins, ins->mir()->prototypeObject());
return emitInstanceOf(ins, ins->mir()->prototypeObject());
}
// Wrap IsDelegate, which takes a Value for the lhs of an instanceof.
@ -4240,7 +4232,7 @@ typedef bool (*IsDelegateObjectFn)(JSContext *, HandleObject, HandleObject, JSBo
static const VMFunction IsDelegateObjectInfo = FunctionInfo<IsDelegateObjectFn>(IsDelegateObject);
bool
CodeGenerator::emitInstanceOfTyped(LInstruction *ins, RawObject prototypeObject)
CodeGenerator::emitInstanceOf(LInstruction *ins, RawObject prototypeObject)
{
// This path implements fun_hasInstance when the function's prototype is
// known to be prototypeObject.
@ -4250,16 +4242,16 @@ CodeGenerator::emitInstanceOfTyped(LInstruction *ins, RawObject prototypeObject)
// If the lhs is a primitive, the result is false.
Register objReg;
if (ins->isInstanceOfTypedV()) {
if (ins->isInstanceOfV()) {
Label isObject;
ValueOperand lhsValue = ToValue(ins, LInstanceOfTypedV::LHS);
ValueOperand lhsValue = ToValue(ins, LInstanceOfV::LHS);
masm.branchTestObject(Assembler::Equal, lhsValue, &isObject);
masm.mov(Imm32(0), output);
masm.jump(&done);
masm.bind(&isObject);
objReg = masm.extractObject(lhsValue, output);
} else {
objReg = ToRegister(ins->toInstanceOfTypedO()->lhs());
objReg = ToRegister(ins->toInstanceOfO()->lhs());
}
// Crawl the lhs's prototype chain in a loop to search for prototypeObject.
@ -4311,11 +4303,11 @@ CodeGenerator::emitInstanceOfTyped(LInstruction *ins, RawObject prototypeObject)
} else {
masm.bind(&regenerate);
lazyEntry = &regenerate;
if (ins->isInstanceOfTypedV()) {
ValueOperand lhsValue = ToValue(ins, LInstanceOfTypedV::LHS);
if (ins->isInstanceOfV()) {
ValueOperand lhsValue = ToValue(ins, LInstanceOfV::LHS);
objReg = masm.extractObject(lhsValue, output);
} else {
objReg = ToRegister(ins->toInstanceOfTypedO()->lhs());
objReg = ToRegister(ins->toInstanceOfO()->lhs());
}
JS_ASSERT(objReg == output);
masm.jump(ool->entry());
@ -4329,182 +4321,19 @@ CodeGenerator::emitInstanceOfTyped(LInstruction *ins, RawObject prototypeObject)
return true;
}
bool
CodeGenerator::visitInstanceOfO(LInstanceOfO *ins)
{
Register rhs = ToRegister(ins->getOperand(1));
return emitInstanceOf(ins, rhs);
}
bool
CodeGenerator::visitInstanceOfV(LInstanceOfV *ins)
{
Register rhs = ToRegister(ins->getOperand(LInstanceOfV::RHS));
return emitInstanceOf(ins, rhs);
}
typedef bool (*HasInstanceFn)(JSContext *, HandleObject, HandleValue, JSBool *);
static const VMFunction HasInstanceInfo = FunctionInfo<HasInstanceFn>(js::HasInstance);
bool
CodeGenerator::emitInstanceOf(LInstruction *ins, Register rhs)
CodeGenerator::visitCallInstanceOf(LCallInstanceOf *ins)
{
Register rhsTmp = ToRegister(ins->getTemp(1));
Register output = ToRegister(ins->getDef(0));
ValueOperand lhs = ToValue(ins, LCallInstanceOf::LHS);
Register rhs = ToRegister(ins->rhs());
JS_ASSERT(ToRegister(ins->output()) == ReturnReg);
// This temporary is used in other parts of the code.
// Different names are used so the purpose is clear.
Register rhsFlags = ToRegister(ins->getTemp(0));
Register lhsTmp = ToRegister(ins->getTemp(0));
Label boundFunctionCheck;
Label boundFunctionDone;
Label done;
Label loopPrototypeChain;
JS_ASSERT(ins->isInstanceOfO() || ins->isInstanceOfV());
bool lhsIsValue = ins->isInstanceOfV();
// If the lhs is an object, then the ValueOperand that gets sent to
// HasInstance must be boxed first. If the lhs is a value, it can
// be sent directly. Hence the choice between ToValue and ToTempValue
// below. Note that the same check is done below in the generated code
// and explicit boxing instructions emitted before calling the OOL code
// if we're handling a LInstanceOfO.
OutOfLineCode *call = oolCallVM(HasInstanceInfo, ins,
(ArgList(), rhs, lhsIsValue ? ToValue(ins, 0) : ToTempValue(ins, 0)),
StoreRegisterTo(output));
if (!call)
return false;
// 1. CODE FOR HASINSTANCE_BOUND_FUNCTION
// ASM-equivalent of following code
// boundFunctionCheck:
// if (!rhs->isFunction())
// goto callHasInstance
// if (!rhs->isBoundFunction())
// goto HasInstanceCunction
// rhs = rhs->getBoundFunction();
// goto boundFunctionCheck
masm.mov(rhs, rhsTmp);
// Check Function
masm.bind(&boundFunctionCheck);
masm.loadBaseShape(rhsTmp, output);
masm.cmpPtr(Address(output, BaseShape::offsetOfClass()), ImmWord(&js::FunctionClass));
if (lhsIsValue) {
// If the input LHS is a value, no boxing necessary.
masm.j(Assembler::NotEqual, call->entry());
} else {
// If the input LHS is raw object pointer, it must be boxed before
// calling into js::HasInstance.
Label dontCallHasInstance;
masm.j(Assembler::Equal, &dontCallHasInstance);
masm.boxNonDouble(JSVAL_TYPE_OBJECT, ToRegister(ins->getOperand(0)), ToTempValue(ins, 0));
masm.jump(call->entry());
masm.bind(&dontCallHasInstance);
}
// Check Bound Function
masm.loadPtr(Address(output, BaseShape::offsetOfFlags()), rhsFlags);
masm.and32(Imm32(BaseShape::BOUND_FUNCTION), rhsFlags);
masm.j(Assembler::Zero, &boundFunctionDone);
// Get Bound Function
masm.loadPtr(Address(output, BaseShape::offsetOfParent()), rhsTmp);
masm.jump(&boundFunctionCheck);
// 2. CODE FOR HASINSTANCE_FUNCTION
masm.bind(&boundFunctionDone);
// ASM-equivalent of following code
// if (!lhs->isObject()) {
// output = false;
// goto done;
// }
// rhs = rhs->getPrototypeClass();
// output = false;
// while (1) {
// lhs = lhs->getType().proto;
// if (lhs == NULL)
// goto done;
// if (lhs != rhs) {
// output = true;
// goto done;
// }
// }
// When lhs is a value: The HasInstance for function objects always
// return false when lhs isn't an object. So check if
// lhs is an object and otherwise return false
if (lhsIsValue) {
Label isObject;
ValueOperand lhsValue = ToValue(ins, LInstanceOfV::LHS);
masm.branchTestObject(Assembler::Equal, lhsValue, &isObject);
masm.mov(Imm32(0), output);
masm.jump(&done);
masm.bind(&isObject);
Register tmp = masm.extractObject(lhsValue, lhsTmp);
masm.mov(tmp, lhsTmp);
} else {
masm.mov(ToRegister(ins->getOperand(0)), lhsTmp);
}
// Get prototype-class by using a OutOfLine GetProperty Cache
// It will use register 'rhsTmp' as input and register 'output' as output, see r1889
OutOfLineCache *ool = new OutOfLineCache(ins);
if (!addOutOfLineCode(ool))
return false;
// If the IC code wants to patch, make sure there is enough space to that
// the patching does not overwrite an invalidation marker.
ensureOsiSpace();
CodeOffsetJump jump = masm.jumpWithPatch(ool->repatchEntry());
CodeOffsetLabel label = masm.labelForPatch();
masm.bind(ool->rejoin());
ool->setInlineJump(jump, label);
// Move the OutOfLineCache return value and set the output on false
masm.mov(output, rhsTmp);
masm.mov(Imm32(0), output);
// Walk the prototype chain
masm.bind(&loopPrototypeChain);
masm.loadPtr(Address(lhsTmp, JSObject::offsetOfType()), lhsTmp);
masm.loadPtr(Address(lhsTmp, offsetof(types::TypeObject, proto)), lhsTmp);
// Bail out if we hit a lazy proto
if (lhsIsValue) {
masm.branch32(Assembler::Equal, lhsTmp, Imm32(1), call->entry());
} else {
// If the input LHS is raw object pointer, it must be boxed before
// calling into js::HasInstance.
Label dontCallHasInstance;
masm.branch32(Assembler::NotEqual, lhsTmp, Imm32(1), &dontCallHasInstance);
masm.boxNonDouble(JSVAL_TYPE_OBJECT, ToRegister(ins->getOperand(0)), ToTempValue(ins, 0));
masm.jump(call->entry());
masm.bind(&dontCallHasInstance);
}
masm.testPtr(lhsTmp, lhsTmp);
masm.j(Assembler::Zero, &done);
// Check lhs is equal to rhsShape
masm.cmpPtr(lhsTmp, rhsTmp);
masm.j(Assembler::NotEqual, &loopPrototypeChain);
// return true
masm.mov(Imm32(1), output);
masm.bind(call->rejoin());
masm.bind(&done);
return true;
pushArg(lhs);
pushArg(rhs);
return callVM(HasInstanceInfo, ins);
}
bool

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

@ -168,14 +168,12 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitCallDeleteProperty(LCallDeleteProperty *lir);
bool visitBitNotV(LBitNotV *lir);
bool visitBitOpV(LBitOpV *lir);
bool emitInstanceOfTyped(LInstruction *ins, RawObject prototypeObject);
bool emitInstanceOf(LInstruction *ins, Register rhs);
bool emitInstanceOf(LInstruction *ins, RawObject prototypeObject);
bool visitIn(LIn *ins);
bool visitInArray(LInArray *ins);
bool visitInstanceOfTypedO(LInstanceOfTypedO *ins);
bool visitInstanceOfTypedV(LInstanceOfTypedV *ins);
bool visitInstanceOfO(LInstanceOfO *ins);
bool visitInstanceOfV(LInstanceOfV *ins);
bool visitCallInstanceOf(LCallInstanceOf *ins);
bool visitFunctionBoundary(LFunctionBoundary *lir);
bool visitGetDOMProperty(LGetDOMProperty *lir);
bool visitSetDOMProperty(LSetDOMProperty *lir);

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

@ -6527,7 +6527,7 @@ IonBuilder::jsop_instanceof()
if (!protoObject)
break;
MInstanceOfTyped *ins = new MInstanceOfTyped(obj, protoObject);
MInstanceOf *ins = new MInstanceOf(obj, protoObject);
current->add(ins);
current->push(ins);
@ -6535,7 +6535,7 @@ IonBuilder::jsop_instanceof()
return resumeAfter(ins);
} while (false);
MInstanceOf *ins = new MInstanceOf(obj, rhs);
MCallInstanceOf *ins = new MCallInstanceOf(obj, rhs);
current->add(ins);
current->push(ins);

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

@ -1927,4 +1927,3 @@ js::ion::GetNameCache(JSContext *cx, size_t cacheIndex, HandleObject scopeChain,
return true;
}

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

@ -3146,16 +3146,16 @@ class LIn : public LCallInstructionHelper<1, BOX_PIECES+1, 0>
static const size_t RHS = BOX_PIECES;
};
class LInstanceOfTypedO : public LInstructionHelper<1, 1, 0>
class LInstanceOfO : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(InstanceOfTypedO);
LInstanceOfTypedO(const LAllocation &lhs) {
LIR_HEADER(InstanceOfO);
LInstanceOfO(const LAllocation &lhs) {
setOperand(0, lhs);
}
MInstanceOfTyped *mir() const {
return mir_->toInstanceOfTyped();
MInstanceOf *mir() const {
return mir_->toInstanceOf();
}
const LAllocation *lhs() {
@ -3163,15 +3163,15 @@ class LInstanceOfTypedO : public LInstructionHelper<1, 1, 0>
}
};
class LInstanceOfTypedV : public LInstructionHelper<1, BOX_PIECES, 0>
class LInstanceOfV : public LInstructionHelper<1, BOX_PIECES, 0>
{
public:
LIR_HEADER(InstanceOfTypedV);
LInstanceOfTypedV() {
LIR_HEADER(InstanceOfV);
LInstanceOfV() {
}
MInstanceOfTyped *mir() const {
return mir_->toInstanceOfTyped();
MInstanceOf *mir() const {
return mir_->toInstanceOf();
}
const LAllocation *lhs() {
@ -3181,37 +3181,17 @@ class LInstanceOfTypedV : public LInstructionHelper<1, BOX_PIECES, 0>
static const size_t LHS = 0;
};
class LInstanceOfO : public LInstructionHelper<1, 2, 2>
class LCallInstanceOf : public LCallInstructionHelper<1, BOX_PIECES+1, 0>
{
public:
LIR_HEADER(InstanceOfO);
LInstanceOfO(const LAllocation &lhs, const LAllocation &rhs,
const LDefinition &temp, const LDefinition &temp2)
{
setOperand(0, lhs);
setOperand(1, rhs);
setTemp(0, temp);
setTemp(1, temp2);
}
const LAllocation *lhs() {
return getOperand(0);
}
const LAllocation *rhs() {
return getOperand(1);
}
};
class LInstanceOfV : public LInstructionHelper<1, BOX_PIECES+1, 2>
{
public:
LIR_HEADER(InstanceOfV);
LInstanceOfV(const LAllocation &rhs, const LDefinition &temp, const LDefinition &temp2) {
LIR_HEADER(CallInstanceOf);
LCallInstanceOf(const LAllocation &rhs) {
setOperand(RHS, rhs);
setTemp(0, temp);
setTemp(1, temp2);
}
const LDefinition *output() {
return this->getDef(0);
}
const LAllocation *lhs() {
return getOperand(LHS);
}

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

@ -169,10 +169,9 @@
_(Round) \
_(In) \
_(InArray) \
_(InstanceOfTypedO) \
_(InstanceOfTypedV) \
_(InstanceOfO) \
_(InstanceOfV) \
_(CallInstanceOf) \
_(InterruptCheck) \
_(FunctionBoundary) \
_(GetDOMProperty) \

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

@ -1925,37 +1925,34 @@ LIRGenerator::visitIn(MIn *ins)
}
bool
LIRGenerator::visitInstanceOfTyped(MInstanceOfTyped *ins)
LIRGenerator::visitInstanceOf(MInstanceOf *ins)
{
MDefinition *lhs = ins->getOperand(0);
JS_ASSERT(lhs->type() == MIRType_Value || lhs->type() == MIRType_Object);
if (lhs->type() == MIRType_Object) {
LInstanceOfTypedO *lir = new LInstanceOfTypedO(useRegister(lhs));
LInstanceOfO *lir = new LInstanceOfO(useRegister(lhs));
return define(lir, ins) && assignSafepoint(lir, ins);
}
LInstanceOfTypedV *lir = new LInstanceOfTypedV();
return useBox(lir, LInstanceOfTypedV::LHS, lhs) && define(lir, ins) && assignSafepoint(lir, ins);
LInstanceOfV *lir = new LInstanceOfV();
return useBox(lir, LInstanceOfV::LHS, lhs) && define(lir, ins) && assignSafepoint(lir, ins);
}
bool
LIRGenerator::visitInstanceOf(MInstanceOf *ins)
LIRGenerator::visitCallInstanceOf(MCallInstanceOf *ins)
{
MDefinition *lhs = ins->lhs();
MDefinition *rhs = ins->rhs();
JS_ASSERT(lhs->type() == MIRType_Value || lhs->type() == MIRType_Object);
JS_ASSERT(lhs->type() == MIRType_Value);
JS_ASSERT(rhs->type() == MIRType_Object);
if (lhs->type() == MIRType_Object) {
LInstanceOfO *lir = new LInstanceOfO(useRegister(lhs), useRegister(rhs), temp(), temp());
return define(lir, ins) && assignSafepoint(lir, ins);
}
LInstanceOfV *lir = new LInstanceOfV(useRegister(rhs), temp(), temp());
return useBox(lir, LInstanceOfV::LHS, lhs) && define(lir, ins) && assignSafepoint(lir, ins);
LCallInstanceOf *lir = new LCallInstanceOf(useRegisterAtStart(rhs));
if (!useBoxAtStart(lir, LCallInstanceOf::LHS, lhs))
return false;
return defineVMReturn(lir, ins) && assignSafepoint(lir, ins);
}
bool

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

@ -184,8 +184,8 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitThrow(MThrow *ins);
bool visitIn(MIn *ins);
bool visitInArray(MInArray *ins);
bool visitInstanceOfTyped(MInstanceOfTyped *ins);
bool visitInstanceOf(MInstanceOf *ins);
bool visitCallInstanceOf(MCallInstanceOf *ins);
bool visitFunctionBoundary(MFunctionBoundary *ins);
bool visitSetDOMProperty(MSetDOMProperty *ins);
bool visitGetDOMProperty(MGetDOMProperty *ins);

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

@ -5246,21 +5246,21 @@ class MInArray
};
// Implementation for instanceof operator with specific rhs.
class MInstanceOfTyped
class MInstanceOf
: public MUnaryInstruction,
public InstanceOfPolicy
{
CompilerRootObject protoObj_;
public:
MInstanceOfTyped(MDefinition *obj, RawObject proto)
MInstanceOf(MDefinition *obj, RawObject proto)
: MUnaryInstruction(obj)
{
protoObj_ = proto;
setResultType(MIRType_Boolean);
}
INSTRUCTION_HEADER(InstanceOfTyped);
INSTRUCTION_HEADER(InstanceOf);
TypePolicy *typePolicy() {
return this;
@ -5272,18 +5272,18 @@ class MInstanceOfTyped
};
// Implementation for instanceof operator with unknown rhs.
class MInstanceOf
class MCallInstanceOf
: public MBinaryInstruction,
public InstanceOfPolicy
public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >
{
public:
MInstanceOf(MDefinition *obj, MDefinition *proto)
MCallInstanceOf(MDefinition *obj, MDefinition *proto)
: MBinaryInstruction(obj, proto)
{
setResultType(MIRType_Boolean);
}
INSTRUCTION_HEADER(InstanceOf);
INSTRUCTION_HEADER(CallInstanceOf);
TypePolicy *typePolicy() {
return this;

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

@ -133,8 +133,8 @@ namespace ion {
_(Floor) \
_(Round) \
_(In) \
_(InstanceOfTyped) \
_(InstanceOf) \
_(CallInstanceOf) \
_(InterruptCheck) \
_(FunctionBoundary) \
_(GetDOMProperty) \

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

@ -386,12 +386,6 @@ InstanceOfPolicy::adjustInputs(MInstruction *def)
BoxPolicy<0>::staticAdjustInputs(def);
}
if (def->numOperands() == 2) {
// Unbox second operand forcefully to an object,
// so it bailouts with other types
ObjectPolicy<1>::staticAdjustInputs(def);
}
return true;
}

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

@ -480,11 +480,8 @@ fun_hasInstance(JSContext *cx, HandleObject objArg, MutableHandleValue v, JSBool
{
RootedObject obj(cx, objArg);
while (obj->isFunction()) {
if (!obj->isBoundFunction())
break;
while (obj->isFunction() && obj->isBoundFunction())
obj = obj->toFunction()->getBoundFunctionTarget();
}
RootedValue pval(cx);
if (!JSObject::getProperty(cx, obj, obj, cx->names().classPrototype, &pval))