Bug 784568 - Refactor calls for clarity. r=dvander

This commit is contained in:
Sean Stangl 2012-08-22 16:57:06 -07:00
parent 188c88907e
commit a0de22ce01
5 changed files with 261 additions and 281 deletions

View File

@ -471,7 +471,7 @@ CodeGenerator::visitMonitorTypes(LMonitorTypes *lir)
bool
CodeGenerator::visitCallNative(LCallNative *call)
{
JSFunction *target = call->function();
JSFunction *target = call->getSingleTarget();
JS_ASSERT(target);
JS_ASSERT(target->isNative());
@ -554,7 +554,7 @@ CodeGenerator::visitCallNative(LCallNative *call)
bool
CodeGenerator::visitCallDOMNative(LCallDOMNative *call)
{
JSFunction *target = call->func();
JSFunction *target = call->getSingleTarget();
JS_ASSERT(target);
JS_ASSERT(target->isNative());
JS_ASSERT(target->jitInfo());
@ -654,7 +654,8 @@ CodeGenerator::visitCallDOMNative(LCallDOMNative *call)
bool
CodeGenerator::emitCallInvokeFunction(LCallGeneric *call, uint32 unusedStack)
CodeGenerator::emitCallInvokeFunction(LInstruction *call, Register calleereg,
uint32 argc, uint32 unusedStack)
{
typedef bool (*pf)(JSContext *, JSFunction *, uint32, Value *, Value *);
static const VMFunction InvokeFunctionInfo = FunctionInfo<pf>(InvokeFunction);
@ -663,52 +664,129 @@ CodeGenerator::emitCallInvokeFunction(LCallGeneric *call, uint32 unusedStack)
// Each path must account for framePushed_ separately, for callVM to be valid.
masm.freeStack(unusedStack);
pushArg(StackPointer); // argv.
pushArg(Imm32(call->numActualArgs())); // argc.
pushArg(ToRegister(call->getFunction())); // JSFunction *.
pushArg(StackPointer); // argv.
pushArg(Imm32(argc)); // argc.
pushArg(calleereg); // JSFunction *.
if (!callVM(InvokeFunctionInfo, call))
return false;
// Un-nestle %esp from the argument vector. No prefix was pushed.
masm.reserveStack(unusedStack);
return true;
}
bool
CodeGenerator::visitCallGeneric(LCallGeneric *call)
{
// Holds the function object.
const LAllocation *callee = call->getFunction();
Register calleereg = ToRegister(callee);
Register calleereg = ToRegister(call->getFunction());
Register objreg = ToRegister(call->getTempObject());
Register nargsreg = ToRegister(call->getNargsReg());
uint32 unusedStack = StackOffsetOfPassedArg(call->argslot());
Label invoke, thunk, makeCall, end;
// Temporary register for modifying the function object.
const LAllocation *obj = call->getTempObject();
Register objreg = ToRegister(obj);
// Known-target case is handled by LCallKnown.
JS_ASSERT(!call->hasSingleTarget());
// Unknown constructor case is handled by LCallConstructor.
JS_ASSERT(!call->mir()->isConstructing());
// Holds the function nargs. Initially undefined.
const LAllocation *nargs = call->getNargsReg();
Register nargsreg = ToRegister(nargs);
uint32 callargslot = call->argslot();
uint32 unusedStack = StackOffsetOfPassedArg(callargslot);
// Generate an ArgumentsRectifier.
IonCompartment *ion = gen->ionCompartment();
IonCode *argumentsRectifier = ion->getArgumentsRectifier(GetIonContext()->cx);
if (!argumentsRectifier)
return false;
masm.checkStackAlignment();
// Unless already known, guard that calleereg is actually a function object.
if (!call->hasSingleTarget()) {
masm.loadObjClass(calleereg, nargsreg);
masm.cmpPtr(nargsreg, ImmWord(&js::FunctionClass));
if (!bailoutIf(Assembler::NotEqual, call->snapshot()))
return false;
// Guard that calleereg is actually a function object.
masm.loadObjClass(calleereg, nargsreg);
masm.cmpPtr(nargsreg, ImmWord(&js::FunctionClass));
if (!bailoutIf(Assembler::NotEqual, call->snapshot()))
return false;
// Guard that calleereg is a non-native function:
// Non-native iff (callee->flags & JSFUN_KINDMASK >= JSFUN_INTERPRETED).
// This is equivalent to testing if any of the bits in JSFUN_KINDMASK are set.
Address flags(calleereg, offsetof(JSFunction, flags));
masm.load16ZeroExtend_mask(flags, Imm32(JSFUN_INTERPRETED), nargsreg);
masm.branch32(Assembler::NotEqual, nargsreg, Imm32(JSFUN_INTERPRETED), &invoke);
// Knowing that calleereg is a non-native function, load the JSScript.
masm.movePtr(Address(calleereg, offsetof(JSFunction, u.i.script_)), objreg);
masm.movePtr(Address(objreg, offsetof(JSScript, ion)), objreg);
// Guard that the IonScript has been compiled.
masm.branchPtr(Assembler::BelowOrEqual, objreg, ImmWord(ION_COMPILING_SCRIPT), &invoke);
// Nestle the StackPointer up to the argument vector.
masm.freeStack(unusedStack);
// Construct the IonFramePrefix.
uint32 descriptor = MakeFrameDescriptor(masm.framePushed(), IonFrame_JS);
masm.Push(Imm32(call->numActualArgs()));
masm.Push(calleereg);
masm.Push(Imm32(descriptor));
// Check whether the provided arguments satisfy target argc.
masm.load16ZeroExtend(Address(calleereg, offsetof(JSFunction, nargs)), nargsreg);
masm.cmp32(nargsreg, Imm32(call->numStackArgs()));
masm.j(Assembler::Above, &thunk);
// No argument fixup needed. Load the start of the target IonCode.
masm.movePtr(Address(objreg, offsetof(IonScript, method_)), objreg);
masm.movePtr(Address(objreg, IonCode::OffsetOfCode()), objreg);
masm.jump(&makeCall);
// Argument fixed needed. Load the ArgumentsRectifier.
masm.bind(&thunk);
{
JS_ASSERT(ArgumentsRectifierReg != objreg);
masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking.
masm.movePtr(Address(objreg, IonCode::OffsetOfCode()), objreg);
masm.move32(Imm32(call->numStackArgs()), ArgumentsRectifierReg);
}
// Finally call the function in objreg.
masm.bind(&makeCall);
masm.callIon(objreg);
if (!markSafepoint(call))
return false;
// Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
// The return address has already been removed from the Ion frame.
int prefixGarbage = sizeof(IonJSFrameLayout) - sizeof(void *);
masm.adjustStack(prefixGarbage - unusedStack);
masm.jump(&end);
// Handle uncompiled or native functions.
masm.bind(&invoke);
if (!emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack))
return false;
masm.bind(&end);
dropArguments(call->numStackArgs() + 1);
return true;
}
bool
CodeGenerator::visitCallKnown(LCallKnown *call)
{
Register calleereg = ToRegister(call->getFunction());
Register objreg = ToRegister(call->getTempObject());
uint32 unusedStack = StackOffsetOfPassedArg(call->argslot());
JSFunction *target = call->getSingleTarget();
Label end, invoke;
// Native single targets are handled by LCallNative.
JS_ASSERT(!target->isNative());
// Missing arguments must have been explicitly appended by the IonBuilder.
JS_ASSERT(target->nargs <= call->numStackArgs());
masm.checkStackAlignment();
// If the function is known to be uncompilable, only emit the call to InvokeFunction.
if (call->hasSingleTarget() &&
call->getSingleTarget()->script()->ion == ION_DISABLED_SCRIPT)
{
if (!emitCallInvokeFunction(call, unusedStack))
if (target->script()->ion == ION_DISABLED_SCRIPT) {
if (!emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack))
return false;
if (call->mir()->isConstructing()) {
@ -722,21 +800,6 @@ CodeGenerator::visitCallGeneric(LCallGeneric *call)
return true;
}
Label end, invoke;
// Guard that calleereg is a non-native function:
// Non-native iff (callee->flags & JSFUN_KINDMASK >= JSFUN_INTERPRETED).
// This is equivalent to testing if any of the bits in JSFUN_KINDMASK are set.
if (!call->hasSingleTarget()) {
Address flags(calleereg, offsetof(JSFunction, flags));
masm.load16ZeroExtend_mask(flags, Imm32(JSFUN_INTERPRETED), nargsreg);
masm.branch32(Assembler::NotEqual, nargsreg, Imm32(JSFUN_INTERPRETED), &invoke);
} else {
// Native single targets are handled by LCallNative.
JS_ASSERT(!call->getSingleTarget()->isNative());
}
// Knowing that calleereg is a non-native function, load the JSScript.
masm.movePtr(Address(calleereg, offsetof(JSFunction, u.i.script_)), objreg);
masm.movePtr(Address(objreg, offsetof(JSScript, ion)), objreg);
@ -744,7 +807,11 @@ CodeGenerator::visitCallGeneric(LCallGeneric *call)
// Guard that the IonScript has been compiled.
masm.branchPtr(Assembler::BelowOrEqual, objreg, ImmWord(ION_COMPILING_SCRIPT), &invoke);
// Nestle %esp up to the argument vector.
// Load the start of the target IonCode.
masm.movePtr(Address(objreg, offsetof(IonScript, method_)), objreg);
masm.movePtr(Address(objreg, IonCode::OffsetOfCode()), objreg);
// Nestle the StackPointer up to the argument vector.
masm.freeStack(unusedStack);
// Construct the IonFramePrefix.
@ -753,65 +820,20 @@ CodeGenerator::visitCallGeneric(LCallGeneric *call)
masm.Push(calleereg);
masm.Push(Imm32(descriptor));
Label thunk, rejoin;
if (call->hasSingleTarget()) {
// Missing arguments must have been explicitly appended by the IonBuilder.
JS_ASSERT(call->getSingleTarget()->nargs <= call->numStackArgs());
} else {
// Check whether the provided arguments satisfy target argc.
masm.load16ZeroExtend(Address(calleereg, offsetof(JSFunction, nargs)), nargsreg);
masm.cmp32(nargsreg, Imm32(call->numStackArgs()));
masm.j(Assembler::Above, &thunk);
}
// No argument fixup needed. Load the start of the target IonCode.
{
masm.movePtr(Address(objreg, offsetof(IonScript, method_)), objreg);
masm.movePtr(Address(objreg, IonCode::OffsetOfCode()), objreg);
}
Label afterCall;
// Argument fixup needed. Get ready to call the argumentsRectifier.
if (!call->hasSingleTarget()) {
// Skip this thunk unless an explicit jump target.
masm.jump(&rejoin);
masm.bind(&thunk);
// Hardcode the address of the argumentsRectifier code.
IonCompartment *ion = gen->ionCompartment();
IonCode *argumentsRectifier = ion->getArgumentsRectifier(GetIonContext()->cx);
if (!argumentsRectifier)
return false;
JS_ASSERT(ArgumentsRectifierReg != objreg);
masm.move32(Imm32(call->numStackArgs()), ArgumentsRectifierReg);
masm.call(argumentsRectifier);
if (!markSafepoint(call))
return false;
masm.jump(&afterCall);
}
masm.bind(&rejoin);
// Finally call the function in objreg.
masm.callIon(objreg);
if (!markSafepoint(call))
return false;
masm.bind(&afterCall);
// Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
// The return address has already been removed from the Ion frame.
int prefixGarbage = sizeof(IonJSFrameLayout) - sizeof(void *);
masm.adjustStack(prefixGarbage - unusedStack);
masm.jump(&end);
// Handle uncompiled or native functions.
// Handle uncompiled functions.
masm.bind(&invoke);
if (!emitCallInvokeFunction(call, unusedStack))
if (!emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack))
return false;
masm.bind(&end);

View File

@ -70,8 +70,10 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitTypeBarrier(LTypeBarrier *lir);
bool visitMonitorTypes(LMonitorTypes *lir);
bool visitCallNative(LCallNative *call);
bool emitCallInvokeFunction(LCallGeneric *call, uint32 unusedStack);
bool emitCallInvokeFunction(LInstruction *call, Register callereg,
uint32 argc, uint32 unusedStack);
bool visitCallGeneric(LCallGeneric *call);
bool visitCallKnown(LCallKnown *call);
bool visitCallConstructor(LCallConstructor *call);
bool emitCallInvokeFunction(LApplyArgsGeneric *apply, Register extraStackSize);
void emitPushArguments(LApplyArgsGeneric *apply, Register extraStackSpace);

View File

@ -439,33 +439,31 @@ class LStackArg : public LInstructionHelper<0, BOX_PIECES, 0>
}
};
// Generates a polymorphic callsite, wherein the function being called is
// unknown and anticipated to vary.
class LCallGeneric : public LCallInstructionHelper<BOX_PIECES, 1, 2>
// Common code for LIR descended from MCall.
template <size_t Defs, size_t Operands, size_t Temps>
class LJSCallInstructionHelper : public LCallInstructionHelper<Defs, Operands, Temps>
{
// Slot below which %esp should be adjusted to make the call.
// Zero for a function without arguments.
uint32 argslot_;
public:
LIR_HEADER(CallGeneric);
LCallGeneric(const LAllocation &func,
uint32 argslot,
const LDefinition &nargsreg,
const LDefinition &tmpobjreg)
LJSCallInstructionHelper(uint32 argslot)
: argslot_(argslot)
{
setOperand(0, func);
setTemp(0, nargsreg);
setTemp(1, tmpobjreg);
}
{ }
uint32 argslot() const {
return argslot_;
}
MCall *mir() const {
return mir_->toCall();
return this->mir_->toCall();
}
bool hasSingleTarget() const {
return getSingleTarget() != NULL;
}
JSFunction *getSingleTarget() const {
return mir()->getSingleTarget();
}
// The number of stack arguments is the max between the number of formal
@ -480,12 +478,22 @@ class LCallGeneric : public LCallInstructionHelper<BOX_PIECES, 1, 2>
uint32 numActualArgs() const {
return mir()->numActualArgs();
}
};
bool hasSingleTarget() const {
return getSingleTarget() != NULL;
}
JSFunction *getSingleTarget() const {
return mir()->getSingleTarget();
// Generates a polymorphic callsite, wherein the function being called is
// unknown and anticipated to vary.
class LCallGeneric : public LJSCallInstructionHelper<BOX_PIECES, 1, 2>
{
public:
LIR_HEADER(CallGeneric);
LCallGeneric(const LAllocation &func, uint32 argslot,
const LDefinition &nargsreg, const LDefinition &tmpobjreg)
: LJSCallInstructionHelper(argslot)
{
setOperand(0, func);
setTemp(0, nargsreg);
setTemp(1, tmpobjreg);
}
const LAllocation *getFunction() {
@ -499,89 +507,37 @@ class LCallGeneric : public LCallInstructionHelper<BOX_PIECES, 1, 2>
}
};
template <size_t defs, size_t ops>
class LDOMPropertyInstructionHelper : public LCallInstructionHelper<defs, 1 + ops, 3>
// Generates a hardcoded callsite for a known, non-native target.
class LCallKnown : public LJSCallInstructionHelper<BOX_PIECES, 1, 1>
{
protected:
LDOMPropertyInstructionHelper(const LDefinition &JSContextReg,
const LAllocation &ObjectReg,
const LDefinition &PrivReg,
const LDefinition &ValueReg)
public:
LIR_HEADER(CallKnown);
LCallKnown(const LAllocation &func, uint32 argslot, const LDefinition &tmpobjreg)
: LJSCallInstructionHelper(argslot)
{
this->setTemp(0, JSContextReg);
this->setTemp(1, PrivReg);
this->setTemp(2, ValueReg);
this->setOperand(0, ObjectReg);
setOperand(0, func);
setTemp(0, tmpobjreg);
}
public:
const LAllocation *getJSContextReg() {
return this->getTemp(0)->output();
const LAllocation *getFunction() {
return getOperand(0);
}
const LAllocation *getObjectReg() {
return this->getOperand(0);
}
const LAllocation *getPrivReg() {
return this->getTemp(1)->output();
}
const LAllocation *getValueReg() {
return this->getTemp(2)->output();
const LAllocation *getTempObject() {
return getTemp(0)->output();
}
};
class LGetDOMProperty : public LDOMPropertyInstructionHelper<BOX_PIECES, 0>
// Generates a hardcoded callsite for a known, native target.
class LCallNative : public LJSCallInstructionHelper<BOX_PIECES, 0, 4>
{
public:
LIR_HEADER(GetDOMProperty);
LGetDOMProperty(const LDefinition &JSContextReg,
const LAllocation &ObjectReg,
const LDefinition &PrivReg,
const LDefinition &ValueReg)
: LDOMPropertyInstructionHelper<BOX_PIECES, 0>(JSContextReg, ObjectReg,
PrivReg, ValueReg)
{ }
MGetDOMProperty *mir() const {
return mir_->toGetDOMProperty();
}
};
class LSetDOMProperty : public LDOMPropertyInstructionHelper<0, BOX_PIECES>
{
public:
LIR_HEADER(SetDOMProperty);
LSetDOMProperty(const LDefinition &JSContextReg,
const LAllocation &ObjectReg,
const LDefinition &PrivReg,
const LDefinition &ValueReg)
: LDOMPropertyInstructionHelper<0, BOX_PIECES>(JSContextReg, ObjectReg,
PrivReg, ValueReg)
{ }
static const size_t Value = 1;
MSetDOMProperty *mir() const {
return mir_->toSetDOMProperty();
}
};
// Generates a monomorphic callsite for a known, native target.
class LCallNative : public LCallInstructionHelper<BOX_PIECES, 0, 4>
{
uint32 argslot_;
public:
LIR_HEADER(CallNative);
LCallNative(uint32 argslot,
const LDefinition &argJSContext, const LDefinition &argUintN,
const LDefinition &argVp, const LDefinition &tmpreg)
: argslot_(argslot)
: LJSCallInstructionHelper(argslot)
{
// Registers used for callWithABI().
setTemp(0, argJSContext);
@ -592,25 +548,6 @@ class LCallNative : public LCallInstructionHelper<BOX_PIECES, 0, 4>
setTemp(3, tmpreg);
}
JSFunction *function() const {
return mir()->getSingleTarget();
}
uint32 argslot() const {
return argslot_;
}
MCall *mir() const {
return mir_->toCall();
}
// :TODO: Common this out with LCallGeneric.
uint32 numStackArgs() const {
JS_ASSERT(mir()->numStackArgs() >= 1);
return mir()->numStackArgs() - 1; // |this| is not a formal argument.
}
uint32 numActualArgs() const {
return mir()->numActualArgs();
}
const LAllocation *getArgJSContextReg() {
return getTemp(0)->output();
}
@ -620,16 +557,14 @@ class LCallNative : public LCallInstructionHelper<BOX_PIECES, 0, 4>
const LAllocation *getArgVpReg() {
return getTemp(2)->output();
}
const LAllocation *getTempReg() {
return getTemp(3)->output();
}
};
class LCallDOMNative : public LCallInstructionHelper<BOX_PIECES, 0, 5>
// Generates a hardcoded callsite for a known, DOM-native target.
class LCallDOMNative : public LJSCallInstructionHelper<BOX_PIECES, 0, 5>
{
uint32 argslot_;
public:
LIR_HEADER(CallDOMNative);
@ -637,7 +572,7 @@ class LCallDOMNative : public LCallInstructionHelper<BOX_PIECES, 0, 5>
const LDefinition &argJSContext, const LDefinition &argObj,
const LDefinition &argPrivate, const LDefinition &argArgc,
const LDefinition &argVp)
: argslot_(argslot)
: LJSCallInstructionHelper(argslot)
{
setTemp(0, argJSContext);
setTemp(1, argObj);
@ -646,22 +581,6 @@ class LCallDOMNative : public LCallInstructionHelper<BOX_PIECES, 0, 5>
setTemp(4, argVp);
}
JSFunction *func() const {
return mir()->getSingleTarget();
}
uint32 argslot() const {
return argslot_;
}
MCall *mir() const {
return mir_->toCall();
}
// Named for consistency with LCallNative. Actually should be argc().
uint32 numStackArgs() const {
JS_ASSERT(mir()->numStackArgs() >= 1);
return mir()->numStackArgs() - 1;
}
const LAllocation *getArgJSContext() {
return getTemp(0)->output();
}
@ -681,39 +600,85 @@ class LCallDOMNative : public LCallInstructionHelper<BOX_PIECES, 0, 5>
// Generates a polymorphic callsite for |new|, where |this| has not been
// pre-allocated by the caller.
class LCallConstructor : public LCallInstructionHelper<BOX_PIECES, 1, 0>
class LCallConstructor : public LJSCallInstructionHelper<BOX_PIECES, 1, 0>
{
uint32 argslot_;
public:
LIR_HEADER(CallConstructor);
LCallConstructor(const LAllocation &func, uint32 argslot)
: argslot_(argslot)
: LJSCallInstructionHelper(argslot)
{
setOperand(0, func);
}
uint32 argslot() const {
return argslot_;
}
MCall *mir() const {
return mir_->toCall();
}
uint32 numStackArgs() const {
JS_ASSERT(mir()->numStackArgs() >= 1);
return mir()->numStackArgs() - 1; // |this| is not a formal argument.
}
uint32 numActualArgs() const {
return mir()->numActualArgs();
}
const LAllocation *getFunction() {
return getOperand(0);
}
};
template <size_t defs, size_t ops>
class LDOMPropertyInstructionHelper : public LCallInstructionHelper<defs, 1 + ops, 3>
{
protected:
LDOMPropertyInstructionHelper(const LDefinition &JSContextReg, const LAllocation &ObjectReg,
const LDefinition &PrivReg, const LDefinition &ValueReg)
{
this->setOperand(0, ObjectReg);
this->setTemp(0, JSContextReg);
this->setTemp(1, PrivReg);
this->setTemp(2, ValueReg);
}
public:
const LAllocation *getJSContextReg() {
return this->getTemp(0)->output();
}
const LAllocation *getObjectReg() {
return this->getOperand(0);
}
const LAllocation *getPrivReg() {
return this->getTemp(1)->output();
}
const LAllocation *getValueReg() {
return this->getTemp(2)->output();
}
};
class LGetDOMProperty : public LDOMPropertyInstructionHelper<BOX_PIECES, 0>
{
public:
LIR_HEADER(GetDOMProperty);
LGetDOMProperty(const LDefinition &JSContextReg, const LAllocation &ObjectReg,
const LDefinition &PrivReg, const LDefinition &ValueReg)
: LDOMPropertyInstructionHelper<BOX_PIECES, 0>(JSContextReg, ObjectReg,
PrivReg, ValueReg)
{ }
MGetDOMProperty *mir() const {
return mir_->toGetDOMProperty();
}
};
class LSetDOMProperty : public LDOMPropertyInstructionHelper<0, BOX_PIECES>
{
public:
LIR_HEADER(SetDOMProperty);
LSetDOMProperty(const LDefinition &JSContextReg, const LAllocation &ObjectReg,
const LDefinition &PrivReg, const LDefinition &ValueReg)
: LDOMPropertyInstructionHelper<0, BOX_PIECES>(JSContextReg, ObjectReg,
PrivReg, ValueReg)
{ }
static const size_t Value = 1;
MSetDOMProperty *mir() const {
return mir_->toSetDOMProperty();
}
};
// Generates a polymorphic callsite, wherein the function being called is
// unknown and anticipated to vary.
class LApplyArgsGeneric : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 2, 2>
@ -721,10 +686,8 @@ class LApplyArgsGeneric : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES +
public:
LIR_HEADER(ApplyArgsGeneric);
LApplyArgsGeneric(const LAllocation &func,
const LAllocation &argc,
const LDefinition &tmpobjreg,
const LDefinition &tmpcopy)
LApplyArgsGeneric(const LAllocation &func, const LAllocation &argc,
const LDefinition &tmpobjreg, const LDefinition &tmpcopy)
{
setOperand(0, func);
setOperand(1, argc);

View File

@ -29,6 +29,7 @@
_(CheckOverRecursed) \
_(RecompileCheck) \
_(DefVar) \
_(CallKnown) \
_(CallGeneric) \
_(CallNative) \
_(CallConstructor) \

View File

@ -212,52 +212,44 @@ LIRGenerator::visitCall(MCall *call)
// Height of the current argument vector.
uint32 argslot = getArgumentSlotForCall();
freeArguments(call->numStackArgs());
JSFunction *target = call->getSingleTarget();
if (target && target->isNative()) {
if (call->isDOMFunction()) {
LCallDOMNative *lir = new LCallDOMNative(argslot,
tempFixed(CallTempReg0),
tempFixed(CallTempReg1),
tempFixed(CallTempReg2),
tempFixed(CallTempReg3),
tempFixed(CallTempReg4));
if (!defineReturn(lir, call))
return false;
if (!assignSafepoint(lir, call))
return false;
} else {
// Call DOM functions.
if (call->isDOMFunction()) {
JS_ASSERT(target && target->isNative());
LCallDOMNative *lir = new LCallDOMNative(argslot, tempFixed(CallTempReg0),
tempFixed(CallTempReg1), tempFixed(CallTempReg2),
tempFixed(CallTempReg3), tempFixed(CallTempReg4));
return (defineReturn(lir, call) && assignSafepoint(lir, call));
}
// Call known functions.
if (target) {
if (target->isNative()) {
LCallNative *lir = new LCallNative(argslot, tempFixed(CallTempReg0),
tempFixed(CallTempReg1), tempFixed(CallTempReg2),
tempFixed(CallTempReg3));
if (!defineReturn(lir, call))
return false;
if (!assignSafepoint(lir, call))
return false;
return (defineReturn(lir, call) && assignSafepoint(lir, call));
}
} else if (!target && call->isConstructing()) {
LCallConstructor *lir = new LCallConstructor(useFixed(call->getFunction(), CallTempReg0),
argslot);
if (!defineVMReturn(lir, call))
return false;
if (!assignSafepoint(lir, call))
return false;
} else {
LCallGeneric *lir = new LCallGeneric(useFixed(call->getFunction(), CallTempReg0),
argslot, tempFixed(ArgumentsRectifierReg), tempFixed(CallTempReg2));
// Bailout is only needed in the case of possible non-JSFunction callee.
if (!target && !assignSnapshot(lir))
return false;
if (!defineReturn(lir, call))
return false;
if (!assignSafepoint(lir, call))
return false;
LCallKnown *lir = new LCallKnown(useFixed(call->getFunction(), CallTempReg0),
argslot, tempFixed(CallTempReg2));
return (defineReturn(lir, call) && assignSafepoint(lir, call));
}
freeArguments(call->numStackArgs());
return true;
// Call unknown constructors.
if (call->isConstructing()) {
LCallConstructor *lir = new LCallConstructor(useFixed(call->getFunction(),
CallTempReg0), argslot);
return (defineVMReturn(lir, call) && assignSafepoint(lir, call));
}
// Call anything, using the most generic code.
LCallGeneric *lir = new LCallGeneric(useFixed(call->getFunction(), CallTempReg0),
argslot, tempFixed(ArgumentsRectifierReg), tempFixed(CallTempReg2));
return (assignSnapshot(lir) && defineReturn(lir, call) && assignSafepoint(lir, call));
}
bool