const Assembler::VoidType Assembler::Void;
-Assembler::Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator,
- int maxArgCountForBuiltins)
- : _stackLayout(function, maxArgCountForBuiltins)
- , _constTable(this)
+Assembler::Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator)
+ : _constTable(this)
, _function(function)
, _nextBlock(0)
, _executableAllocator(executableAllocator)
storeValue(value, addr);
}
-void Assembler::enterStandardStackFrame()
+void Assembler::enterStandardStackFrame(const RegisterInformation ®ularRegistersToSave)
{
platformEnterStandardStackFrame(this);
push(StackFrameRegister);
move(StackPointerRegister, StackFrameRegister);
- int frameSize = _stackLayout.calculateStackFrameSize();
+ int frameSize = _stackLayout->calculateStackFrameSize();
subPtr(TrustedImm32(frameSize), StackPointerRegister);
- const RegisterInformation &calleeSavedRegisters = getCalleeSavedRegisters();
- for (int i = 0; i < calleeSavedRegisterCount(); ++i)
- storePtr(calleeSavedRegisters[i].reg<RegisterID>(), Address(StackFrameRegister, -(i + 1) * sizeof(void*)));
-
+ Address slotAddr(StackFrameRegister, -RegisterSize);
+ for (int i = 0, ei = regularRegistersToSave.size(); i < ei; ++i) {
+ storePtr(regularRegistersToSave.at(i).reg<RegisterID>(), slotAddr);
+ slotAddr.offset -= RegisterSize;
+ }
}
-void Assembler::leaveStandardStackFrame()
+void Assembler::leaveStandardStackFrame(const RegisterInformation ®ularRegistersToSave)
{
+ Address slotAddr(StackFrameRegister, -regularRegistersToSave.size() * RegisterSize);
+
// restore the callee saved registers
- const RegisterInformation &calleeSavedRegisters = getCalleeSavedRegisters();
- for (int i = calleeSavedRegisterCount() - 1; i >= 0; --i)
- loadPtr(Address(StackFrameRegister, -(i + 1) * sizeof(void*)), calleeSavedRegisters[i].reg<RegisterID>());
+ for (int i = regularRegistersToSave.size() - 1; i >= 0; --i) {
+ loadPtr(slotAddr, regularRegistersToSave.at(i).reg<RegisterID>());
+ slotAddr.offset += RegisterSize;
+ }
- int frameSize = _stackLayout.calculateStackFrameSize();
+ int frameSize = _stackLayout->calculateStackFrameSize();
// Work around bug in ARMv7Assembler.h where add32(imm, sp, sp) doesn't
// work well for large immediates.
#if CPU(ARM_THUMB2)
toInt32Register(right, Assembler::ReturnValueRegister));
}
+void Assembler::setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave)
+{
+ _stackLayout.reset(new StackLayout(_function, maxArgCountForBuiltins, regularRegistersToSave));
+}
+
#endif
class Assembler : public JSC::MacroAssembler, public TargetPlatform
{
+ Q_DISABLE_COPY(Assembler)
+
public:
- Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator,
- int maxArgCountForBuiltins);
+ Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator);
// Explicit type to allow distinguishing between
// pushing an address itself or the value it points
class StackLayout
{
public:
- StackLayout(IR::Function *function, int maxArgCountForBuiltins)
- : calleeSavedRegCount(Assembler::calleeSavedRegisterCount() + 1)
+ StackLayout(IR::Function *function, int maxArgCountForBuiltins, int normalRegistersToSave)
+ : normalRegistersToSave(normalRegistersToSave)
, maxOutgoingArgumentCount(function->maxNumberOfArguments)
, localCount(function->tempCount)
, savedRegCount(maxArgCountForBuiltins)
+ RegisterSize; // saved StackFrameRegister
// space for the callee saved registers
- int frameSize = RegisterSize * calleeSavedRegisterCount();
+ int frameSize = RegisterSize * normalRegistersToSave;
frameSize += savedRegCount * sizeof(QV4::Value); // these get written out as Values, not as native registers
Q_ASSERT(frameSize + stackSpaceAllocatedOtherwise < INT_MAX);
int calleeSavedRegisterSpace() const
{
// plus 1 for the old FP
- return RegisterSize * (calleeSavedRegCount + 1);
+ return RegisterSize * (normalRegistersToSave + 1);
}
private:
- int calleeSavedRegCount;
+ int normalRegistersToSave;
/// arg count for calls to JS functions
int maxOutgoingArgumentCount;
{
Q_ASSERT(t->kind == IR::Temp::StackSlot);
- return Pointer(_stackLayout.stackSlotPointer(t->index));
+ return Pointer(_stackLayout->stackSlotPointer(t->index));
}
template <int argumentNumber>
return;
if (IR::Temp *t = arg.value->asTemp()) {
if (t->kind == IR::Temp::PhysicalRegister) {
- Pointer addr(_stackLayout.savedRegPointer(argumentNumber));
+ Pointer addr(_stackLayout->savedRegPointer(argumentNumber));
switch (t->type) {
case IR::BoolType:
storeBool((RegisterID) t->index, addr);
void storeValue(QV4::Primitive value, IR::Expr* temp);
- void enterStandardStackFrame();
- void leaveStandardStackFrame();
+ void enterStandardStackFrame(const RegisterInformation ®ularRegistersToSave);
+ void leaveStandardStackFrame(const RegisterInformation ®ularRegistersToSave);
void checkException() {
loadPtr(Address(ContextRegister, qOffsetOf(QV4::ExecutionContext::Data, engine)), ScratchRegister);
Pointer toAddress(RegisterID tmpReg, IR::Expr *e, int offset)
{
if (IR::Const *c = e->asConst()) {
- Address addr = _stackLayout.savedRegPointer(offset);
+ Address addr = _stackLayout->savedRegPointer(offset);
Address tagAddr = addr;
tagAddr.offset += 4;
if (IR::Temp *t = e->asTemp())
if (t->kind == IR::Temp::PhysicalRegister)
- return Pointer(_stackLayout.savedRegPointer(offset));
+ return Pointer(_stackLayout->savedRegPointer(offset));
return loadAddress(tmpReg, e);
}
JSC::MacroAssemblerCodeRef link(int *codeSize);
- const StackLayout stackLayout() const { return _stackLayout; }
+ void setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave);
+ const StackLayout &stackLayout() const { return *_stackLayout.data(); }
ConstantTable &constantTable() { return _constTable; }
Label exceptionReturnLabel;
IR::BasicBlock * catchBlock;
QVector<Jump> exceptionPropagationJumps;
private:
- const StackLayout _stackLayout;
+ QScopedPointer<const StackLayout> _stackLayout;
ConstantTable _constTable;
IR::Function *_function;
QHash<IR::BasicBlock *, Label> _addrs;
static const bool withRegisterAllocator = qgetenv("QV4_NO_REGALLOC").isEmpty();
if (Assembler::RegAllocIsSupported && opt.isInSSA() && withRegisterAllocator) {
RegisterAllocator(Assembler::getRegisterInfo()).run(_function, opt);
+ calculateRegistersToSave(Assembler::getRegisterInfo());
} else {
if (opt.isInSSA())
// No register allocator available for this platform, or env. var was set, so:
opt.convertOutOfSSA();
ConvertTemps().toStackSlots(_function);
IR::Optimizer::showMeTheCode(_function);
+ calculateRegistersToSave(Assembler::getRegisterInfo()); // FIXME: this saves all registers. We can probably do with a subset: those that are not used by the register allocator.
}
QSet<IR::Jump *> removableJumps = opt.calculateOptionalJumps();
qSwap(_removableJumps, removableJumps);
Assembler* oldAssembler = _as;
- _as = new Assembler(this, _function, executableAllocator, 6); // 6 == max argc for calls to built-ins with an argument array
-
- _as->enterStandardStackFrame();
+ _as = new Assembler(this, _function, executableAllocator);
+ _as->setStackLayout(6, // 6 == max argc for calls to built-ins with an argument array
+ regularRegistersToSave.size());
+ _as->enterStandardStackFrame(regularRegistersToSave);
#ifdef ARGUMENTS_IN_REGISTERS
_as->move(_as->registerForArgument(0), Assembler::ContextRegister);
_as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext::Data, engine)), Assembler::ScratchRegister);
_as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
- _as->leaveStandardStackFrame();
+ _as->leaveStandardStackFrame(regularRegistersToSave);
_as->ret();
}
return argc;
}
+void InstructionSelection::calculateRegistersToSave(const RegisterInformation &used)
+{
+ regularRegistersToSave.clear();
+
+ foreach (const RegisterInfo &ri, Assembler::getRegisterInfo()) {
+ if (ri.isCallerSaved())
+ continue;
+
+ if (ri.isRegularRegister()) {
+#if defined(RESTORE_EBX_ON_CALL)
+ if (ri.isRegularRegister() && ri.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) {
+ regularRegistersToSave.append(ri);
+ continue;
+ }
+#endif // RESTORE_EBX_ON_CALL
+ if (ri.isPredefined() || used.contains(ri))
+ regularRegistersToSave.append(ri);
+ }
+ }
+}
QT_BEGIN_NAMESPACE
namespace QV4 {
int prepareVariableArguments(IR::ExprList* args);
int prepareCallData(IR::ExprList* args, IR::Expr *thisObject);
+ void calculateRegistersToSave(const RegisterInformation &used);
+
template <typename Retval, typename Arg1, typename Arg2, typename Arg3>
void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3)
{
QScopedPointer<CompilationUnit> compilationUnit;
QQmlEnginePrivate *qmlEngine;
+ RegisterInformation regularRegistersToSave;
};
class Q_QML_EXPORT ISelFactory: public EvalISelFactory
class RegisterInfo
{
public:
- enum { InvalidRegister = -1 };
+ enum { InvalidRegister = (1 << 29) - 1 };
enum SavedBy { CallerSaved, CalleeSaved };
enum RegisterType { RegularRegister, FloatingPointRegister };
enum Usage { Predefined, RegAlloc };
public:
RegisterInfo()
- : _reg(InvalidRegister)
- , _type(RegularRegister)
- , _savedBy(CallerSaved)
+ : _savedBy(CallerSaved)
, _usage(Predefined)
+ , _type(RegularRegister)
+ , _reg(InvalidRegister)
{}
RegisterInfo(int reg, const QString &prettyName, RegisterType type, SavedBy savedBy, Usage usage)
- : _reg(reg)
- , _prettyName(prettyName)
- , _type(type)
+ : _prettyName(prettyName)
, _savedBy(savedBy)
, _usage(usage)
+ , _type(type)
+ , _reg(reg)
{}
+ bool operator==(const RegisterInfo &other) const
+ { return _type == other._type && _reg == other._reg; }
+
bool isValid() const { return _reg != InvalidRegister; }
template <typename T> T reg() const { return static_cast<T>(_reg); }
QString prettyName() const { return _prettyName; }
bool isFloatingPoint() const { return _type == FloatingPointRegister; }
bool isRegularRegister() const { return _type == RegularRegister; }
bool useForRegAlloc() const { return _usage == RegAlloc; }
+ bool isPredefined() const { return _usage == Predefined; }
private:
- int _reg;
QString _prettyName;
- RegisterType _type;
- SavedBy _savedBy;
- Usage _usage;
+ unsigned _savedBy : 1;
+ unsigned _usage : 1;
+ unsigned _type : 1;
+ unsigned _reg : 29;
};
typedef QVector<RegisterInfo> RegisterInformation;
return info;
}
-
- static RegisterInformation &getCalleeSavedRegisters()
- {
- static RegisterInformation regs;
- if (regs.isEmpty()) {
- foreach (const RegisterInfo &info, getRegisterInfo()) {
-#if defined(RESTORE_EBX_ON_CALL)
- if (info.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) {
- regs.append(info);
- continue;
- }
-#endif // RESTORE_EBX_ON_CALL
- if (info.isCalleeSaved())
- regs.append(info);
- }
- }
-
- return regs;
- }
-
- static int calleeSavedRegisterCount()
- {
- return getCalleeSavedRegisters().size();
- }
};
} // JIT namespace