зеркало из https://github.com/mozilla/gecko-dev.git
Bug 814177 - Use a callVM for generic InstanceOf cases. r=dvander
This commit is contained in:
Родитель
4bec908ccc
Коммит
047f75f8d3
|
@ -3418,8 +3418,6 @@ class OutOfLineCache : public OutOfLineCodeBase<CodeGenerator>
|
||||||
|
|
||||||
bool accept(CodeGenerator *codegen) {
|
bool accept(CodeGenerator *codegen) {
|
||||||
switch (ins->op()) {
|
switch (ins->op()) {
|
||||||
case LInstruction::LOp_InstanceOfO:
|
|
||||||
case LInstruction::LOp_InstanceOfV:
|
|
||||||
case LInstruction::LOp_GetPropertyCacheT:
|
case LInstruction::LOp_GetPropertyCacheT:
|
||||||
case LInstruction::LOp_GetPropertyCacheV:
|
case LInstruction::LOp_GetPropertyCacheV:
|
||||||
return codegen->visitOutOfLineCacheGetProperty(this);
|
return codegen->visitOutOfLineCacheGetProperty(this);
|
||||||
|
@ -3531,12 +3529,6 @@ CodeGenerator::visitOutOfLineCacheGetProperty(OutOfLineCache *ool)
|
||||||
PropertyName *name = NULL;
|
PropertyName *name = NULL;
|
||||||
bool allowGetters = false;
|
bool allowGetters = false;
|
||||||
switch (ins->op()) {
|
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:
|
case LInstruction::LOp_GetPropertyCacheT:
|
||||||
name = ((LGetPropertyCacheT *) ins)->mir()->name();
|
name = ((LGetPropertyCacheT *) ins)->mir()->name();
|
||||||
objReg = ToRegister(ins->getOperand(0));
|
objReg = ToRegister(ins->getOperand(0));
|
||||||
|
@ -4214,15 +4206,15 @@ CodeGenerator::visitInArray(LInArray *lir)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CodeGenerator::visitInstanceOfTypedO(LInstanceOfTypedO *ins)
|
CodeGenerator::visitInstanceOfO(LInstanceOfO *ins)
|
||||||
{
|
{
|
||||||
return emitInstanceOfTyped(ins, ins->mir()->prototypeObject());
|
return emitInstanceOf(ins, ins->mir()->prototypeObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
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.
|
// 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);
|
static const VMFunction IsDelegateObjectInfo = FunctionInfo<IsDelegateObjectFn>(IsDelegateObject);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CodeGenerator::emitInstanceOfTyped(LInstruction *ins, RawObject prototypeObject)
|
CodeGenerator::emitInstanceOf(LInstruction *ins, RawObject prototypeObject)
|
||||||
{
|
{
|
||||||
// This path implements fun_hasInstance when the function's prototype is
|
// This path implements fun_hasInstance when the function's prototype is
|
||||||
// known to be prototypeObject.
|
// known to be prototypeObject.
|
||||||
|
@ -4250,16 +4242,16 @@ CodeGenerator::emitInstanceOfTyped(LInstruction *ins, RawObject prototypeObject)
|
||||||
|
|
||||||
// If the lhs is a primitive, the result is false.
|
// If the lhs is a primitive, the result is false.
|
||||||
Register objReg;
|
Register objReg;
|
||||||
if (ins->isInstanceOfTypedV()) {
|
if (ins->isInstanceOfV()) {
|
||||||
Label isObject;
|
Label isObject;
|
||||||
ValueOperand lhsValue = ToValue(ins, LInstanceOfTypedV::LHS);
|
ValueOperand lhsValue = ToValue(ins, LInstanceOfV::LHS);
|
||||||
masm.branchTestObject(Assembler::Equal, lhsValue, &isObject);
|
masm.branchTestObject(Assembler::Equal, lhsValue, &isObject);
|
||||||
masm.mov(Imm32(0), output);
|
masm.mov(Imm32(0), output);
|
||||||
masm.jump(&done);
|
masm.jump(&done);
|
||||||
masm.bind(&isObject);
|
masm.bind(&isObject);
|
||||||
objReg = masm.extractObject(lhsValue, output);
|
objReg = masm.extractObject(lhsValue, output);
|
||||||
} else {
|
} else {
|
||||||
objReg = ToRegister(ins->toInstanceOfTypedO()->lhs());
|
objReg = ToRegister(ins->toInstanceOfO()->lhs());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crawl the lhs's prototype chain in a loop to search for prototypeObject.
|
// Crawl the lhs's prototype chain in a loop to search for prototypeObject.
|
||||||
|
@ -4311,11 +4303,11 @@ CodeGenerator::emitInstanceOfTyped(LInstruction *ins, RawObject prototypeObject)
|
||||||
} else {
|
} else {
|
||||||
masm.bind(®enerate);
|
masm.bind(®enerate);
|
||||||
lazyEntry = ®enerate;
|
lazyEntry = ®enerate;
|
||||||
if (ins->isInstanceOfTypedV()) {
|
if (ins->isInstanceOfV()) {
|
||||||
ValueOperand lhsValue = ToValue(ins, LInstanceOfTypedV::LHS);
|
ValueOperand lhsValue = ToValue(ins, LInstanceOfV::LHS);
|
||||||
objReg = masm.extractObject(lhsValue, output);
|
objReg = masm.extractObject(lhsValue, output);
|
||||||
} else {
|
} else {
|
||||||
objReg = ToRegister(ins->toInstanceOfTypedO()->lhs());
|
objReg = ToRegister(ins->toInstanceOfO()->lhs());
|
||||||
}
|
}
|
||||||
JS_ASSERT(objReg == output);
|
JS_ASSERT(objReg == output);
|
||||||
masm.jump(ool->entry());
|
masm.jump(ool->entry());
|
||||||
|
@ -4329,182 +4321,19 @@ CodeGenerator::emitInstanceOfTyped(LInstruction *ins, RawObject prototypeObject)
|
||||||
return true;
|
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 *);
|
typedef bool (*HasInstanceFn)(JSContext *, HandleObject, HandleValue, JSBool *);
|
||||||
static const VMFunction HasInstanceInfo = FunctionInfo<HasInstanceFn>(js::HasInstance);
|
static const VMFunction HasInstanceInfo = FunctionInfo<HasInstanceFn>(js::HasInstance);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CodeGenerator::emitInstanceOf(LInstruction *ins, Register rhs)
|
CodeGenerator::visitCallInstanceOf(LCallInstanceOf *ins)
|
||||||
{
|
{
|
||||||
Register rhsTmp = ToRegister(ins->getTemp(1));
|
ValueOperand lhs = ToValue(ins, LCallInstanceOf::LHS);
|
||||||
Register output = ToRegister(ins->getDef(0));
|
Register rhs = ToRegister(ins->rhs());
|
||||||
|
JS_ASSERT(ToRegister(ins->output()) == ReturnReg);
|
||||||
|
|
||||||
// This temporary is used in other parts of the code.
|
pushArg(lhs);
|
||||||
// Different names are used so the purpose is clear.
|
pushArg(rhs);
|
||||||
Register rhsFlags = ToRegister(ins->getTemp(0));
|
return callVM(HasInstanceInfo, ins);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -168,14 +168,12 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||||
bool visitCallDeleteProperty(LCallDeleteProperty *lir);
|
bool visitCallDeleteProperty(LCallDeleteProperty *lir);
|
||||||
bool visitBitNotV(LBitNotV *lir);
|
bool visitBitNotV(LBitNotV *lir);
|
||||||
bool visitBitOpV(LBitOpV *lir);
|
bool visitBitOpV(LBitOpV *lir);
|
||||||
bool emitInstanceOfTyped(LInstruction *ins, RawObject prototypeObject);
|
bool emitInstanceOf(LInstruction *ins, RawObject prototypeObject);
|
||||||
bool emitInstanceOf(LInstruction *ins, Register rhs);
|
|
||||||
bool visitIn(LIn *ins);
|
bool visitIn(LIn *ins);
|
||||||
bool visitInArray(LInArray *ins);
|
bool visitInArray(LInArray *ins);
|
||||||
bool visitInstanceOfTypedO(LInstanceOfTypedO *ins);
|
|
||||||
bool visitInstanceOfTypedV(LInstanceOfTypedV *ins);
|
|
||||||
bool visitInstanceOfO(LInstanceOfO *ins);
|
bool visitInstanceOfO(LInstanceOfO *ins);
|
||||||
bool visitInstanceOfV(LInstanceOfV *ins);
|
bool visitInstanceOfV(LInstanceOfV *ins);
|
||||||
|
bool visitCallInstanceOf(LCallInstanceOf *ins);
|
||||||
bool visitFunctionBoundary(LFunctionBoundary *lir);
|
bool visitFunctionBoundary(LFunctionBoundary *lir);
|
||||||
bool visitGetDOMProperty(LGetDOMProperty *lir);
|
bool visitGetDOMProperty(LGetDOMProperty *lir);
|
||||||
bool visitSetDOMProperty(LSetDOMProperty *lir);
|
bool visitSetDOMProperty(LSetDOMProperty *lir);
|
||||||
|
|
|
@ -6527,7 +6527,7 @@ IonBuilder::jsop_instanceof()
|
||||||
if (!protoObject)
|
if (!protoObject)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
MInstanceOfTyped *ins = new MInstanceOfTyped(obj, protoObject);
|
MInstanceOf *ins = new MInstanceOf(obj, protoObject);
|
||||||
|
|
||||||
current->add(ins);
|
current->add(ins);
|
||||||
current->push(ins);
|
current->push(ins);
|
||||||
|
@ -6535,7 +6535,7 @@ IonBuilder::jsop_instanceof()
|
||||||
return resumeAfter(ins);
|
return resumeAfter(ins);
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
MInstanceOf *ins = new MInstanceOf(obj, rhs);
|
MCallInstanceOf *ins = new MCallInstanceOf(obj, rhs);
|
||||||
|
|
||||||
current->add(ins);
|
current->add(ins);
|
||||||
current->push(ins);
|
current->push(ins);
|
||||||
|
|
|
@ -1927,4 +1927,3 @@ js::ion::GetNameCache(JSContext *cx, size_t cacheIndex, HandleObject scopeChain,
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3146,16 +3146,16 @@ class LIn : public LCallInstructionHelper<1, BOX_PIECES+1, 0>
|
||||||
static const size_t RHS = BOX_PIECES;
|
static const size_t RHS = BOX_PIECES;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LInstanceOfTypedO : public LInstructionHelper<1, 1, 0>
|
class LInstanceOfO : public LInstructionHelper<1, 1, 0>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LIR_HEADER(InstanceOfTypedO);
|
LIR_HEADER(InstanceOfO);
|
||||||
LInstanceOfTypedO(const LAllocation &lhs) {
|
LInstanceOfO(const LAllocation &lhs) {
|
||||||
setOperand(0, lhs);
|
setOperand(0, lhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
MInstanceOfTyped *mir() const {
|
MInstanceOf *mir() const {
|
||||||
return mir_->toInstanceOfTyped();
|
return mir_->toInstanceOf();
|
||||||
}
|
}
|
||||||
|
|
||||||
const LAllocation *lhs() {
|
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:
|
public:
|
||||||
LIR_HEADER(InstanceOfTypedV);
|
LIR_HEADER(InstanceOfV);
|
||||||
LInstanceOfTypedV() {
|
LInstanceOfV() {
|
||||||
}
|
}
|
||||||
|
|
||||||
MInstanceOfTyped *mir() const {
|
MInstanceOf *mir() const {
|
||||||
return mir_->toInstanceOfTyped();
|
return mir_->toInstanceOf();
|
||||||
}
|
}
|
||||||
|
|
||||||
const LAllocation *lhs() {
|
const LAllocation *lhs() {
|
||||||
|
@ -3181,37 +3181,17 @@ class LInstanceOfTypedV : public LInstructionHelper<1, BOX_PIECES, 0>
|
||||||
static const size_t LHS = 0;
|
static const size_t LHS = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LInstanceOfO : public LInstructionHelper<1, 2, 2>
|
class LCallInstanceOf : public LCallInstructionHelper<1, BOX_PIECES+1, 0>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LIR_HEADER(InstanceOfO);
|
LIR_HEADER(CallInstanceOf);
|
||||||
LInstanceOfO(const LAllocation &lhs, const LAllocation &rhs,
|
LCallInstanceOf(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) {
|
|
||||||
setOperand(RHS, rhs);
|
setOperand(RHS, rhs);
|
||||||
setTemp(0, temp);
|
|
||||||
setTemp(1, temp2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const LDefinition *output() {
|
||||||
|
return this->getDef(0);
|
||||||
|
}
|
||||||
const LAllocation *lhs() {
|
const LAllocation *lhs() {
|
||||||
return getOperand(LHS);
|
return getOperand(LHS);
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,10 +169,9 @@
|
||||||
_(Round) \
|
_(Round) \
|
||||||
_(In) \
|
_(In) \
|
||||||
_(InArray) \
|
_(InArray) \
|
||||||
_(InstanceOfTypedO) \
|
|
||||||
_(InstanceOfTypedV) \
|
|
||||||
_(InstanceOfO) \
|
_(InstanceOfO) \
|
||||||
_(InstanceOfV) \
|
_(InstanceOfV) \
|
||||||
|
_(CallInstanceOf) \
|
||||||
_(InterruptCheck) \
|
_(InterruptCheck) \
|
||||||
_(FunctionBoundary) \
|
_(FunctionBoundary) \
|
||||||
_(GetDOMProperty) \
|
_(GetDOMProperty) \
|
||||||
|
|
|
@ -1925,37 +1925,34 @@ LIRGenerator::visitIn(MIn *ins)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LIRGenerator::visitInstanceOfTyped(MInstanceOfTyped *ins)
|
LIRGenerator::visitInstanceOf(MInstanceOf *ins)
|
||||||
{
|
{
|
||||||
MDefinition *lhs = ins->getOperand(0);
|
MDefinition *lhs = ins->getOperand(0);
|
||||||
|
|
||||||
JS_ASSERT(lhs->type() == MIRType_Value || lhs->type() == MIRType_Object);
|
JS_ASSERT(lhs->type() == MIRType_Value || lhs->type() == MIRType_Object);
|
||||||
|
|
||||||
if (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);
|
return define(lir, ins) && assignSafepoint(lir, ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
LInstanceOfTypedV *lir = new LInstanceOfTypedV();
|
LInstanceOfV *lir = new LInstanceOfV();
|
||||||
return useBox(lir, LInstanceOfTypedV::LHS, lhs) && define(lir, ins) && assignSafepoint(lir, ins);
|
return useBox(lir, LInstanceOfV::LHS, lhs) && define(lir, ins) && assignSafepoint(lir, ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LIRGenerator::visitInstanceOf(MInstanceOf *ins)
|
LIRGenerator::visitCallInstanceOf(MCallInstanceOf *ins)
|
||||||
{
|
{
|
||||||
MDefinition *lhs = ins->lhs();
|
MDefinition *lhs = ins->lhs();
|
||||||
MDefinition *rhs = ins->rhs();
|
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);
|
JS_ASSERT(rhs->type() == MIRType_Object);
|
||||||
|
|
||||||
if (lhs->type() == MIRType_Object) {
|
LCallInstanceOf *lir = new LCallInstanceOf(useRegisterAtStart(rhs));
|
||||||
LInstanceOfO *lir = new LInstanceOfO(useRegister(lhs), useRegister(rhs), temp(), temp());
|
if (!useBoxAtStart(lir, LCallInstanceOf::LHS, lhs))
|
||||||
return define(lir, ins) && assignSafepoint(lir, ins);
|
return false;
|
||||||
}
|
return defineVMReturn(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -184,8 +184,8 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||||
bool visitThrow(MThrow *ins);
|
bool visitThrow(MThrow *ins);
|
||||||
bool visitIn(MIn *ins);
|
bool visitIn(MIn *ins);
|
||||||
bool visitInArray(MInArray *ins);
|
bool visitInArray(MInArray *ins);
|
||||||
bool visitInstanceOfTyped(MInstanceOfTyped *ins);
|
|
||||||
bool visitInstanceOf(MInstanceOf *ins);
|
bool visitInstanceOf(MInstanceOf *ins);
|
||||||
|
bool visitCallInstanceOf(MCallInstanceOf *ins);
|
||||||
bool visitFunctionBoundary(MFunctionBoundary *ins);
|
bool visitFunctionBoundary(MFunctionBoundary *ins);
|
||||||
bool visitSetDOMProperty(MSetDOMProperty *ins);
|
bool visitSetDOMProperty(MSetDOMProperty *ins);
|
||||||
bool visitGetDOMProperty(MGetDOMProperty *ins);
|
bool visitGetDOMProperty(MGetDOMProperty *ins);
|
||||||
|
|
|
@ -5246,21 +5246,21 @@ class MInArray
|
||||||
};
|
};
|
||||||
|
|
||||||
// Implementation for instanceof operator with specific rhs.
|
// Implementation for instanceof operator with specific rhs.
|
||||||
class MInstanceOfTyped
|
class MInstanceOf
|
||||||
: public MUnaryInstruction,
|
: public MUnaryInstruction,
|
||||||
public InstanceOfPolicy
|
public InstanceOfPolicy
|
||||||
{
|
{
|
||||||
CompilerRootObject protoObj_;
|
CompilerRootObject protoObj_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MInstanceOfTyped(MDefinition *obj, RawObject proto)
|
MInstanceOf(MDefinition *obj, RawObject proto)
|
||||||
: MUnaryInstruction(obj)
|
: MUnaryInstruction(obj)
|
||||||
{
|
{
|
||||||
protoObj_ = proto;
|
protoObj_ = proto;
|
||||||
setResultType(MIRType_Boolean);
|
setResultType(MIRType_Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTRUCTION_HEADER(InstanceOfTyped);
|
INSTRUCTION_HEADER(InstanceOf);
|
||||||
|
|
||||||
TypePolicy *typePolicy() {
|
TypePolicy *typePolicy() {
|
||||||
return this;
|
return this;
|
||||||
|
@ -5272,18 +5272,18 @@ class MInstanceOfTyped
|
||||||
};
|
};
|
||||||
|
|
||||||
// Implementation for instanceof operator with unknown rhs.
|
// Implementation for instanceof operator with unknown rhs.
|
||||||
class MInstanceOf
|
class MCallInstanceOf
|
||||||
: public MBinaryInstruction,
|
: public MBinaryInstruction,
|
||||||
public InstanceOfPolicy
|
public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MInstanceOf(MDefinition *obj, MDefinition *proto)
|
MCallInstanceOf(MDefinition *obj, MDefinition *proto)
|
||||||
: MBinaryInstruction(obj, proto)
|
: MBinaryInstruction(obj, proto)
|
||||||
{
|
{
|
||||||
setResultType(MIRType_Boolean);
|
setResultType(MIRType_Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTRUCTION_HEADER(InstanceOf);
|
INSTRUCTION_HEADER(CallInstanceOf);
|
||||||
|
|
||||||
TypePolicy *typePolicy() {
|
TypePolicy *typePolicy() {
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -133,8 +133,8 @@ namespace ion {
|
||||||
_(Floor) \
|
_(Floor) \
|
||||||
_(Round) \
|
_(Round) \
|
||||||
_(In) \
|
_(In) \
|
||||||
_(InstanceOfTyped) \
|
|
||||||
_(InstanceOf) \
|
_(InstanceOf) \
|
||||||
|
_(CallInstanceOf) \
|
||||||
_(InterruptCheck) \
|
_(InterruptCheck) \
|
||||||
_(FunctionBoundary) \
|
_(FunctionBoundary) \
|
||||||
_(GetDOMProperty) \
|
_(GetDOMProperty) \
|
||||||
|
|
|
@ -386,12 +386,6 @@ InstanceOfPolicy::adjustInputs(MInstruction *def)
|
||||||
BoxPolicy<0>::staticAdjustInputs(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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -480,11 +480,8 @@ fun_hasInstance(JSContext *cx, HandleObject objArg, MutableHandleValue v, JSBool
|
||||||
{
|
{
|
||||||
RootedObject obj(cx, objArg);
|
RootedObject obj(cx, objArg);
|
||||||
|
|
||||||
while (obj->isFunction()) {
|
while (obj->isFunction() && obj->isBoundFunction())
|
||||||
if (!obj->isBoundFunction())
|
|
||||||
break;
|
|
||||||
obj = obj->toFunction()->getBoundFunctionTarget();
|
obj = obj->toFunction()->getBoundFunctionTarget();
|
||||||
}
|
|
||||||
|
|
||||||
RootedValue pval(cx);
|
RootedValue pval(cx);
|
||||||
if (!JSObject::getProperty(cx, obj, obj, cx->names().classPrototype, &pval))
|
if (!JSObject::getProperty(cx, obj, obj, cx->names().classPrototype, &pval))
|
||||||
|
|
Загрузка…
Ссылка в новой задаче