Bug 844882 - Part 4: Ion inlining for self-hosted classes. (r=jandem)

This commit is contained in:
Shu-yu Guo 2013-06-19 17:33:14 -07:00
parent 6e6c2d3aed
commit 6072f225c5
16 changed files with 196 additions and 8 deletions

View File

@ -2741,6 +2741,10 @@ class OutOfLineNewObject : public OutOfLineCodeBase<CodeGenerator>
typedef JSObject *(*NewInitObjectFn)(JSContext *, HandleObject);
static const VMFunction NewInitObjectInfo = FunctionInfo<NewInitObjectFn>(NewInitObject);
typedef JSObject *(*NewInitObjectWithClassPrototypeFn)(JSContext *, HandleObject);
static const VMFunction NewInitObjectWithClassPrototypeInfo =
FunctionInfo<NewInitObjectWithClassPrototypeFn>(NewInitObjectWithClassPrototype);
bool
CodeGenerator::visitNewObjectVMCall(LNewObject *lir)
{
@ -2752,8 +2756,17 @@ CodeGenerator::visitNewObjectVMCall(LNewObject *lir)
saveLive(lir);
pushArg(ImmGCPtr(lir->mir()->templateObject()));
if (!callVM(NewInitObjectInfo, lir))
// If we're making a new object with a class prototype (that is, an object
// that derives its class from its prototype instead of being
// ObjectClass'd) from self-hosted code, we need a different init
// function.
if (lir->mir()->templateObjectIsClassPrototype()) {
if (!callVM(NewInitObjectWithClassPrototypeInfo, lir))
return false;
} else if (!callVM(NewInitObjectInfo, lir)) {
return false;
}
if (ReturnReg != objReg)
masm.movePtr(ReturnReg, objReg);
@ -6828,6 +6841,22 @@ CodeGenerator::visitOutOfLinePropagateParallelAbort(OutOfLinePropagateParallelAb
return true;
}
bool
CodeGenerator::visitHaveSameClass(LHaveSameClass *ins)
{
Register lhs = ToRegister(ins->lhs());
Register rhs = ToRegister(ins->rhs());
Register temp = ToRegister(ins->getTemp(0));
Register output = ToRegister(ins->output());
masm.loadObjClass(lhs, temp);
masm.loadObjClass(rhs, output);
masm.cmpPtr(temp, output);
masm.emitSet(Assembler::Equal, output);
return true;
}
bool
CodeGenerator::visitAsmJSCall(LAsmJSCall *ins)
{

View File

@ -238,6 +238,7 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitCallDOMNative(LCallDOMNative *lir);
bool visitCallGetIntrinsicValue(LCallGetIntrinsicValue *lir);
bool visitIsCallable(LIsCallable *lir);
bool visitHaveSameClass(LHaveSameClass *lir);
bool visitAsmJSCall(LAsmJSCall *lir);
bool visitAsmJSParameter(LAsmJSParameter *lir);
bool visitAsmJSReturn(LAsmJSReturn *ret);

View File

@ -5228,7 +5228,8 @@ IonBuilder::jsop_newobject(HandleObject baseObj)
templateObject->setType(type);
}
MNewObject *ins = MNewObject::New(templateObject);
MNewObject *ins = MNewObject::New(templateObject,
/* templateObjectIsClassPrototype = */ false);
current->add(ins);
current->push(ins);

View File

@ -509,6 +509,8 @@ class IonBuilder : public MIRGenerator
// Utility intrinsics.
InliningStatus inlineThrowError(CallInfo &callInfo);
InliningStatus inlineIsCallable(CallInfo &callInfo);
InliningStatus inlineNewObjectWithClassPrototype(CallInfo &callInfo);
InliningStatus inlineHaveSameClass(CallInfo &callInfo);
InliningStatus inlineToObject(CallInfo &callInfo);
InliningStatus inlineDump(CallInfo &callInfo);

View File

@ -4567,6 +4567,28 @@ class LIsCallable : public LInstructionHelper<1, 1, 0>
}
};
class LHaveSameClass : public LInstructionHelper<1, 2, 1>
{
public:
LIR_HEADER(HaveSameClass);
LHaveSameClass(const LAllocation &left, const LAllocation &right,
const LDefinition &temp) {
setOperand(0, left);
setOperand(1, right);
setTemp(0, temp);
}
const LAllocation *lhs() {
return getOperand(0);
}
const LAllocation *rhs() {
return getOperand(1);
}
MHaveSameClass *mir() const {
return mir_->toHaveSameClass();
}
};
class LAsmJSLoadHeap : public LInstructionHelper<1, 1, 0>
{
public:

View File

@ -226,6 +226,7 @@
_(SetDOMProperty) \
_(CallDOMNative) \
_(IsCallable) \
_(HaveSameClass) \
_(AsmJSLoadHeap) \
_(AsmJSStoreHeap) \
_(AsmJSLoadGlobalVar) \

View File

@ -2636,6 +2636,18 @@ LIRGenerator::visitIsCallable(MIsCallable *ins)
return define(new LIsCallable(useRegister(ins->object())), ins);
}
bool
LIRGenerator::visitHaveSameClass(MHaveSameClass *ins)
{
MDefinition *lhs = ins->lhs();
MDefinition *rhs = ins->rhs();
JS_ASSERT(lhs->type() == MIRType_Object);
JS_ASSERT(rhs->type() == MIRType_Object);
return define(new LHaveSameClass(useRegister(lhs), useRegister(rhs), temp()), ins);
}
bool
LIRGenerator::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins)
{

View File

@ -231,6 +231,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitCallInstanceOf(MCallInstanceOf *ins);
bool visitFunctionBoundary(MFunctionBoundary *ins);
bool visitIsCallable(MIsCallable *ins);
bool visitHaveSameClass(MHaveSameClass *ins);
bool visitAsmJSLoadHeap(MAsmJSLoadHeap *ins);
bool visitAsmJSLoadGlobalVar(MAsmJSLoadGlobalVar *ins);
bool visitAsmJSStoreGlobalVar(MAsmJSStoreGlobalVar *ins);

View File

@ -114,6 +114,10 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native)
return inlineThrowError(callInfo);
if (native == intrinsic_IsCallable)
return inlineIsCallable(callInfo);
if (native == intrinsic_NewObjectWithClassPrototype)
return inlineNewObjectWithClassPrototype(callInfo);
if (native == intrinsic_HaveSameClass)
return inlineHaveSameClass(callInfo);
if (native == intrinsic_ToObject)
return inlineToObject(callInfo);
#ifdef DEBUG
@ -1351,6 +1355,64 @@ IonBuilder::inlineUnsafeGetReservedSlot(CallInfo &callInfo)
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineNewObjectWithClassPrototype(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
return InliningStatus_NotInlined;
if (callInfo.getArg(0)->type() != MIRType_Object)
return InliningStatus_NotInlined;
MDefinition *arg = callInfo.getArg(0)->toPassArg()->getArgument();
if (!arg->isConstant())
return InliningStatus_NotInlined;
JSObject *proto = &arg->toConstant()->value().toObject();
JSObject *templateObject = NewObjectWithGivenProto(cx, proto->getClass(), proto, cx->global());
if (!templateObject)
return InliningStatus_Error;
MNewObject *newObj = MNewObject::New(templateObject,
/* templateObjectIsClassPrototype = */ true);
current->add(newObj);
current->push(newObj);
if (!resumeAfter(newObj))
return InliningStatus_Error;
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineHaveSameClass(CallInfo &callInfo)
{
if (callInfo.argc() != 2 || callInfo.constructing())
return InliningStatus_NotInlined;
if (callInfo.getArg(0)->type() != MIRType_Object)
return InliningStatus_NotInlined;
if (callInfo.getArg(1)->type() != MIRType_Object)
return InliningStatus_NotInlined;
types::StackTypeSet *arg1Types = callInfo.getArg(0)->resultTypeSet();
types::StackTypeSet *arg2Types = callInfo.getArg(1)->resultTypeSet();
Class *arg1Clasp = arg1Types ? arg1Types->getKnownClass() : NULL;
Class *arg2Clasp = arg2Types ? arg1Types->getKnownClass() : NULL;
if (arg1Clasp && arg2Clasp) {
MConstant *constant = MConstant::New(BooleanValue(arg1Clasp == arg2Clasp));
current->add(constant);
current->push(constant);
return InliningStatus_Inlined;
}
callInfo.unwrapArgs();
MHaveSameClass *sameClass = MHaveSameClass::New(callInfo.getArg(0), callInfo.getArg(1));
current->add(sameClass);
current->push(sameClass);
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineThrowError(CallInfo &callInfo)
{

View File

@ -1184,10 +1184,13 @@ class MNewArray : public MNullaryInstruction
class MNewObject : public MNullaryInstruction
{
CompilerRootObject templateObject_;
bool templateObjectIsClassPrototype_;
MNewObject(JSObject *templateObject)
: templateObject_(templateObject)
MNewObject(JSObject *templateObject, bool templateObjectIsClassPrototype)
: templateObject_(templateObject),
templateObjectIsClassPrototype_(templateObjectIsClassPrototype)
{
JS_ASSERT_IF(templateObjectIsClassPrototype, !shouldUseVM());
setResultType(MIRType_Object);
setResultTypeSet(MakeSingletonTypeSet(templateObject));
}
@ -1195,14 +1198,18 @@ class MNewObject : public MNullaryInstruction
public:
INSTRUCTION_HEADER(NewObject)
static MNewObject *New(JSObject *templateObject) {
return new MNewObject(templateObject);
static MNewObject *New(JSObject *templateObject, bool templateObjectIsClassPrototype) {
return new MNewObject(templateObject, templateObjectIsClassPrototype);
}
// Returns true if the code generator should call through to the
// VM rather than the fast path.
bool shouldUseVM() const;
bool templateObjectIsClassPrototype() const {
return templateObjectIsClassPrototype_;
}
JSObject *templateObject() const {
return templateObject_;
}
@ -7847,6 +7854,35 @@ class MIsCallable
MDefinition *object() const {
return getOperand(0);
}
AliasSet getAliasSet() const {
return AliasSet::None();
}
};
class MHaveSameClass
: public MBinaryInstruction,
public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >
{
MHaveSameClass(MDefinition *left, MDefinition *right)
: MBinaryInstruction(left, right)
{
setResultType(MIRType_Boolean);
setMovable();
}
public:
INSTRUCTION_HEADER(HaveSameClass);
static MHaveSameClass *New(MDefinition *left, MDefinition *right) {
return new MHaveSameClass(left, right);
}
TypePolicy *typePolicy() {
return this;
}
AliasSet getAliasSet() const {
return AliasSet::None();
}
};
class MAsmJSNeg : public MUnaryInstruction

View File

@ -168,6 +168,7 @@ namespace ion {
_(GetDOMProperty) \
_(SetDOMProperty) \
_(IsCallable) \
_(HaveSameClass) \
_(AsmJSNeg) \
_(AsmJSUDiv) \
_(AsmJSUMod) \

View File

@ -276,6 +276,7 @@ class ParallelArrayVisitor : public MInstructionVisitor
SAFE_OP(FunctionDispatch)
SAFE_OP(TypeObjectDispatch)
SAFE_OP(IsCallable)
SAFE_OP(HaveSameClass)
UNSAFE_OP(EffectiveAddress)
UNSAFE_OP(AsmJSUnsignedToDouble)
UNSAFE_OP(AsmJSNeg)

View File

@ -289,6 +289,23 @@ NewInitObject(JSContext *cx, HandleObject templateObject)
return obj;
}
JSObject *
NewInitObjectWithClassPrototype(JSContext *cx, HandleObject templateObject)
{
JS_ASSERT(!templateObject->hasSingletonType());
JSObject *obj = NewObjectWithGivenProto(cx,
templateObject->getClass(),
templateObject->getProto(),
cx->global());
if (!obj)
return NULL;
obj->setType(templateObject->type());
return obj;
}
bool
ArrayPopDense(JSContext *cx, HandleObject obj, MutableHandleValue rval)
{

View File

@ -557,6 +557,7 @@ bool IteratorMore(JSContext *cx, HandleObject obj, JSBool *res);
JSObject *NewInitParallelArray(JSContext *cx, HandleObject templateObj);
JSObject *NewInitArray(JSContext *cx, uint32_t count, types::TypeObject *type);
JSObject *NewInitObject(JSContext *cx, HandleObject templateObject);
JSObject *NewInitObjectWithClassPrototype(JSContext *cx, HandleObject templateObject);
bool ArrayPopDense(JSContext *cx, HandleObject obj, MutableHandleValue rval);
bool ArrayPushDense(JSContext *cx, HandleObject obj, HandleValue v, uint32_t *length);

View File

@ -2363,6 +2363,7 @@ JSBool intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp);
JSBool intrinsic_UnsafeSetElement(JSContext *cx, unsigned argc, Value *vp);
JSBool intrinsic_UnsafeSetReservedSlot(JSContext *cx, unsigned argc, Value *vp);
JSBool intrinsic_UnsafeGetReservedSlot(JSContext *cx, unsigned argc, Value *vp);
JSBool intrinsic_NewObjectWithClassPrototype(JSContext *cx, unsigned argc, Value *vp);
JSBool intrinsic_HaveSameClass(JSContext *cx, unsigned argc, Value *vp);
JSBool intrinsic_ShouldForceSequential(JSContext *cx, unsigned argc, Value *vp);

View File

@ -505,8 +505,8 @@ intrinsic_NewClassPrototype(JSContext *cx, unsigned argc, Value *vp)
return true;
}
static JSBool
intrinsic_NewObjectWithClassPrototype(JSContext *cx, unsigned argc, Value *vp)
JSBool
js::intrinsic_NewObjectWithClassPrototype(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JS_ASSERT(args.length() == 1);