зеркало из https://github.com/mozilla/gecko-dev.git
Bug 844887 - Inline IsCallable and ToObject intrinsics in Ion. (r=sstangl)
This commit is contained in:
Родитель
bad51eb853
Коммит
fbb393d573
|
@ -6102,6 +6102,28 @@ CodeGenerator::visitOutOfLineParallelAbort(OutOfLineParallelAbort *ool)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitIsCallable(LIsCallable *ins)
|
||||
{
|
||||
Register object = ToRegister(ins->object());
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
masm.loadObjClass(object, output);
|
||||
|
||||
// An object is callable iff (isFunction() || getClass()->call).
|
||||
Label notFunction, done;
|
||||
masm.branchPtr(Assembler::NotEqual, output, ImmWord(&js::FunctionClass), ¬Function);
|
||||
masm.move32(Imm32(1), output);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(¬Function);
|
||||
masm.cmpPtr(Address(output, offsetof(js::Class, call)), ImmWord((void *)NULL));
|
||||
masm.emitSet(Assembler::NonZero, output);
|
||||
masm.bind(&done);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitAsmJSCall(LAsmJSCall *ins)
|
||||
{
|
||||
|
|
|
@ -217,6 +217,7 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||
bool visitSetDOMProperty(LSetDOMProperty *lir);
|
||||
bool visitCallDOMNative(LCallDOMNative *lir);
|
||||
bool visitCallGetIntrinsicValue(LCallGetIntrinsicValue *lir);
|
||||
bool visitIsCallable(LIsCallable *lir);
|
||||
bool visitAsmJSCall(LAsmJSCall *lir);
|
||||
bool visitAsmJSParameter(LAsmJSParameter *lir);
|
||||
bool visitAsmJSReturn(LAsmJSReturn *ret);
|
||||
|
|
|
@ -460,6 +460,8 @@ class IonBuilder : public MIRGenerator
|
|||
uint32_t discards);
|
||||
|
||||
InliningStatus inlineThrowError(CallInfo &callInfo);
|
||||
InliningStatus inlineIsCallable(CallInfo &callInfo);
|
||||
InliningStatus inlineToObject(CallInfo &callInfo);
|
||||
InliningStatus inlineDump(CallInfo &callInfo);
|
||||
|
||||
// Main inlining functions
|
||||
|
|
|
@ -4162,6 +4162,22 @@ class LFunctionBoundary : public LInstructionHelper<0, 0, 1>
|
|||
}
|
||||
};
|
||||
|
||||
class LIsCallable : public LInstructionHelper<1, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(IsCallable);
|
||||
LIsCallable(const LAllocation &object) {
|
||||
setOperand(0, object);
|
||||
}
|
||||
|
||||
const LAllocation *object() {
|
||||
return getOperand(0);
|
||||
}
|
||||
MIsCallable *mir() const {
|
||||
return mir_->toIsCallable();
|
||||
}
|
||||
};
|
||||
|
||||
class LAsmJSLoadHeap : public LInstructionHelper<1, 1, 0>
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -210,6 +210,7 @@
|
|||
_(GetDOMProperty) \
|
||||
_(SetDOMProperty) \
|
||||
_(CallDOMNative) \
|
||||
_(IsCallable) \
|
||||
_(AsmJSLoadHeap) \
|
||||
_(AsmJSStoreHeap) \
|
||||
_(AsmJSLoadGlobalVar) \
|
||||
|
|
|
@ -2461,6 +2461,14 @@ LIRGenerator::visitFunctionBoundary(MFunctionBoundary *ins)
|
|||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitIsCallable(MIsCallable *ins)
|
||||
{
|
||||
JS_ASSERT(ins->object()->type() == MIRType_Object);
|
||||
JS_ASSERT(ins->type() == MIRType_Boolean);
|
||||
return define(new LIsCallable(useRegister(ins->object())), ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins)
|
||||
{
|
||||
|
|
|
@ -220,6 +220,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
bool visitInstanceOf(MInstanceOf *ins);
|
||||
bool visitCallInstanceOf(MCallInstanceOf *ins);
|
||||
bool visitFunctionBoundary(MFunctionBoundary *ins);
|
||||
bool visitIsCallable(MIsCallable *ins);
|
||||
bool visitAsmJSLoadHeap(MAsmJSLoadHeap *ins);
|
||||
bool visitAsmJSLoadGlobalVar(MAsmJSLoadGlobalVar *ins);
|
||||
bool visitAsmJSStoreGlobalVar(MAsmJSStoreGlobalVar *ins);
|
||||
|
|
|
@ -85,25 +85,25 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native)
|
|||
if (native == regexp_test)
|
||||
return inlineRegExpTest(callInfo);
|
||||
|
||||
// Parallel Array
|
||||
// Array intrinsics.
|
||||
if (native == intrinsic_UnsafeSetElement)
|
||||
return inlineUnsafeSetElement(callInfo);
|
||||
if (native == testingFunc_inParallelSection)
|
||||
return inlineShouldForceSequentialOrInParallelSection(callInfo);
|
||||
if (native == intrinsic_NewDenseArray)
|
||||
return inlineNewDenseArray(callInfo);
|
||||
|
||||
// Self-hosting
|
||||
// Utility intrinsics.
|
||||
if (native == intrinsic_ThrowError)
|
||||
return inlineThrowError(callInfo);
|
||||
if (native == intrinsic_IsCallable)
|
||||
return inlineIsCallable(callInfo);
|
||||
if (native == intrinsic_ToObject)
|
||||
return inlineToObject(callInfo);
|
||||
#ifdef DEBUG
|
||||
if (native == intrinsic_Dump)
|
||||
return inlineDump(callInfo);
|
||||
#endif
|
||||
|
||||
// Parallel Array
|
||||
if (native == intrinsic_UnsafeSetElement)
|
||||
return inlineUnsafeSetElement(callInfo);
|
||||
// Parallel intrinsics.
|
||||
if (native == intrinsic_ShouldForceSequential)
|
||||
return inlineShouldForceSequentialOrInParallelSection(callInfo);
|
||||
if (native == testingFunc_inParallelSection)
|
||||
|
@ -112,16 +112,6 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native)
|
|||
return inlineNewParallelArray(callInfo);
|
||||
if (native == ParallelArrayObject::construct)
|
||||
return inlineParallelArray(callInfo);
|
||||
if (native == intrinsic_NewDenseArray)
|
||||
return inlineNewDenseArray(callInfo);
|
||||
|
||||
// Self-hosting
|
||||
if (native == intrinsic_ThrowError)
|
||||
return inlineThrowError(callInfo);
|
||||
#ifdef DEBUG
|
||||
if (native == intrinsic_Dump)
|
||||
return inlineDump(callInfo);
|
||||
#endif
|
||||
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
@ -1317,6 +1307,51 @@ IonBuilder::inlineThrowError(CallInfo &callInfo)
|
|||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineIsCallable(CallInfo &callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 1 || callInfo.constructing())
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
if (getInlineReturnType() != MIRType_Boolean)
|
||||
return InliningStatus_NotInlined;
|
||||
if (getInlineArgType(callInfo, 0) != MIRType_Object)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
callInfo.unwrapArgs();
|
||||
|
||||
MIsCallable *isCallable = MIsCallable::New(callInfo.getArg(0));
|
||||
current->add(isCallable);
|
||||
current->push(isCallable);
|
||||
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineToObject(CallInfo &callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 1 || callInfo.constructing())
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
// If we know the input type is an object, nop ToObject.
|
||||
if (getInlineReturnType() != MIRType_Object)
|
||||
return InliningStatus_NotInlined;
|
||||
if (getInlineArgType(callInfo, 0) != MIRType_Object)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
callInfo.unwrapArgs();
|
||||
MDefinition *object = callInfo.getArg(0);
|
||||
|
||||
// TI still expects the barrier to be checked, since this was a native
|
||||
// call. We manually make a MTypeBarrier here to avoid pointless
|
||||
// boxing-unbox sequences.
|
||||
MTypeBarrier *barrier = MTypeBarrier::New(object, cloneTypeSet(callInfo.barrier()));
|
||||
current->add(barrier);
|
||||
|
||||
current->push(object);
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineDump(CallInfo &callInfo)
|
||||
{
|
||||
|
|
|
@ -7172,6 +7172,29 @@ class FlattenedMResumePointIter
|
|||
}
|
||||
};
|
||||
|
||||
class MIsCallable
|
||||
: public MUnaryInstruction,
|
||||
public SingleObjectPolicy
|
||||
{
|
||||
MIsCallable(MDefinition *object)
|
||||
: MUnaryInstruction(object)
|
||||
{
|
||||
setResultType(MIRType_Boolean);
|
||||
setMovable();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(IsCallable);
|
||||
|
||||
static MIsCallable *New(MDefinition *obj) {
|
||||
return new MIsCallable(obj);
|
||||
}
|
||||
|
||||
MDefinition *object() const {
|
||||
return getOperand(0);
|
||||
}
|
||||
};
|
||||
|
||||
class MAsmJSNeg : public MUnaryInstruction
|
||||
{
|
||||
MAsmJSNeg(MDefinition *op, MIRType type)
|
||||
|
|
|
@ -156,6 +156,7 @@ namespace ion {
|
|||
_(FunctionBoundary) \
|
||||
_(GetDOMProperty) \
|
||||
_(SetDOMProperty) \
|
||||
_(IsCallable) \
|
||||
_(AsmJSNeg) \
|
||||
_(AsmJSUDiv) \
|
||||
_(AsmJSUMod) \
|
||||
|
|
|
@ -264,6 +264,7 @@ class ParallelArrayVisitor : public MInstructionVisitor
|
|||
SAFE_OP(PolyInlineDispatch)
|
||||
SAFE_OP(FunctionDispatch)
|
||||
SAFE_OP(TypeObjectDispatch)
|
||||
SAFE_OP(IsCallable)
|
||||
UNSAFE_OP(EffectiveAddress)
|
||||
UNSAFE_OP(AsmJSUnsignedToDouble)
|
||||
UNSAFE_OP(AsmJSNeg)
|
||||
|
|
|
@ -2393,6 +2393,8 @@ class ContextAllocPolicy
|
|||
void reportAllocOverflow() const { js_ReportAllocationOverflow(cx_); }
|
||||
};
|
||||
|
||||
JSBool intrinsic_ToObject(JSContext *cx, unsigned argc, Value *vp);
|
||||
JSBool intrinsic_IsCallable(JSContext *cx, unsigned argc, Value *vp);
|
||||
JSBool intrinsic_ThrowError(JSContext *cx, unsigned argc, Value *vp);
|
||||
JSBool intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp);
|
||||
JSBool intrinsic_UnsafeSetElement(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
|
|
@ -43,8 +43,8 @@ static JSClass self_hosting_global_class = {
|
|||
JS_ConvertStub, NULL
|
||||
};
|
||||
|
||||
static JSBool
|
||||
intrinsic_ToObject(JSContext *cx, unsigned argc, Value *vp)
|
||||
JSBool
|
||||
js::intrinsic_ToObject(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
RootedValue val(cx, args[0]);
|
||||
|
@ -66,8 +66,8 @@ intrinsic_ToInteger(JSContext *cx, unsigned argc, Value *vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
intrinsic_IsCallable(JSContext *cx, unsigned argc, Value *vp)
|
||||
JSBool
|
||||
js::intrinsic_IsCallable(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
Value val = args[0];
|
||||
|
|
Загрузка…
Ссылка в новой задаче