mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 784568 - Refactor calls for clarity. r=dvander
This commit is contained in:
parent
188c88907e
commit
a0de22ce01
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -29,6 +29,7 @@
|
||||
_(CheckOverRecursed) \
|
||||
_(RecompileCheck) \
|
||||
_(DefVar) \
|
||||
_(CallKnown) \
|
||||
_(CallGeneric) \
|
||||
_(CallNative) \
|
||||
_(CallConstructor) \
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user