aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@digia.com>2013-08-23 14:40:33 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-08-27 13:55:24 +0200
commit7313a37119f9d6e7389a61bf377f16473a44b0a7 (patch)
treedd8cdddf743e27f291106228664788f818188a74 /src
parentfc9199e4dbce55b011f66c36391e6c6aa08bd318 (diff)
The fast and the furious, register drift.
Enable the register allocator for X86_64 on Linux and MacOS. The implications are: - handle as much as possible with current code with as few changes as possible - temporarily force the register allocator to spill unop/binop arguments to the stack by doing a call in the implementation (as is the current case), so no change is needed here - only have loadThis and loadConst handle registers - have any method that might need to handle registrers actually cope with them - the inline versions of binops are not generated, as they cannot cope with registers. This will change when ISel for binops is added in the next patch. This means that we are still running with the handbrakes on, but allow for full-throttle in certain/limited cases. Note about the changed test: multiplication always returns a Number (double), so the operands are passed as doubles, so __qmljs_mul will return a double. For addition this is different: because it might return a Number or a String, the operands are passed as whatever fits best. So __qmljs_add will return an int when both operands are ints. Hence the change to the tests. Change-Id: If5bd7dffca8f7de5ba45af700b9c7bb568fc74b7 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp688
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h520
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp42
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h27
-rw-r--r--src/qml/compiler/qv4isel_p.cpp51
-rw-r--r--src/qml/compiler/qv4isel_p.h27
-rw-r--r--src/qml/compiler/qv4jsir.cpp4
-rw-r--r--src/qml/compiler/qv4regalloc.cpp68
-rw-r--r--src/qml/compiler/qv4ssa.cpp29
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp6
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h7
11 files changed, 1047 insertions, 422 deletions
diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp
index 1da78b5788..e6735b0ca5 100644
--- a/src/qml/compiler/qv4isel_masm.cpp
+++ b/src/qml/compiler/qv4isel_masm.cpp
@@ -208,8 +208,14 @@ const int Assembler::calleeSavedRegisterCount = sizeof(calleeSavedRegisters) / s
const Assembler::VoidType Assembler::Void;
-Assembler::Assembler(InstructionSelection *isel, V4IR::Function* function, QV4::ExecutableAllocator *executableAllocator)
- : _function(function), _isel(isel), _executableAllocator(executableAllocator), _nextBlock(0)
+Assembler::Assembler(InstructionSelection *isel, V4IR::Function* function, QV4::ExecutableAllocator *executableAllocator,
+ int maxArgCountForBuiltins)
+ : _stackLayout(function, maxArgCountForBuiltins)
+ , _constTable(this)
+ , _function(function)
+ , _nextBlock(0)
+ , _executableAllocator(executableAllocator)
+ , _isel(isel)
{
}
@@ -269,11 +275,7 @@ Assembler::Pointer Assembler::loadTempAddress(RegisterID reg, V4IR::Temp *t)
offset = t->index * sizeof(Value);
} break;
case V4IR::Temp::StackSlot: {
- assert(t->scope == 0);
- const int arg = _function->maxNumberOfArguments + t->index + 1;
- offset = - sizeof(Value) * (arg + 1);
- offset -= sizeof(void*) * calleeSavedRegisterCount;
- reg = LocalsRegister;
+ return stackSlotPointer(t);
} break;
default:
Q_UNIMPLEMENTED();
@@ -294,7 +296,7 @@ void Assembler::copyValue(Result result, Source source)
#ifdef VALUE_FITS_IN_REGISTER
// Use ReturnValueRegister as "scratch" register because loadArgument
// and storeArgument are functions that may need a scratch register themselves.
- loadArgumentInRegister(source, ReturnValueRegister);
+ loadArgumentInRegister(source, ReturnValueRegister, 0);
storeReturnValue(result);
#else
loadDouble(source, FPGpr0);
@@ -306,10 +308,14 @@ template <typename Result>
void Assembler::copyValue(Result result, V4IR::Expr* source)
{
#ifdef VALUE_FITS_IN_REGISTER
- // Use ReturnValueRegister as "scratch" register because loadArgument
- // and storeArgument are functions that may need a scratch register themselves.
- loadArgumentInRegister(source, ReturnValueRegister);
- storeReturnValue(result);
+ if (source->type == V4IR::DoubleType) {
+ storeDouble(toDoubleRegister(source), result);
+ } else {
+ // Use ReturnValueRegister as "scratch" register because loadArgument
+ // and storeArgument are functions that may need a scratch register themselves.
+ loadArgumentInRegister(source, ReturnValueRegister, 0);
+ storeReturnValue(result);
+ }
#else
if (V4IR::Temp *temp = source->asTemp()) {
loadDouble(temp, FPGpr0);
@@ -330,21 +336,7 @@ void Assembler::storeValue(QV4::Value value, V4IR::Temp* destination)
storeValue(value, addr);
}
-int Assembler::calculateStackFrameSize(int locals)
-{
- const int stackSpaceAllocatedOtherwise = StackSpaceAllocatedUponFunctionEntry
- + RegisterSize; // saved StackFrameRegister
-
- // space for the locals and the callee saved registers
- int frameSize = locals * sizeof(QV4::Value) + sizeof(void*) * calleeSavedRegisterCount;
-
- frameSize = WTF::roundUpToMultipleOf(StackAlignment, frameSize + stackSpaceAllocatedOtherwise);
- frameSize -= stackSpaceAllocatedOtherwise;
-
- return frameSize;
-}
-
-void Assembler::enterStandardStackFrame(int locals)
+void Assembler::enterStandardStackFrame(bool withLocals)
{
platformEnterStandardStackFrame();
@@ -353,7 +345,7 @@ void Assembler::enterStandardStackFrame(int locals)
push(StackFrameRegister);
move(StackPointerRegister, StackFrameRegister);
- int frameSize = calculateStackFrameSize(locals);
+ int frameSize = _stackLayout.calculateStackFrameSize(withLocals);
subPtr(TrustedImm32(frameSize), StackPointerRegister);
@@ -363,13 +355,13 @@ void Assembler::enterStandardStackFrame(int locals)
move(StackFrameRegister, LocalsRegister);
}
-void Assembler::leaveStandardStackFrame(int locals)
+void Assembler::leaveStandardStackFrame(bool withLocals)
{
// restore the callee saved registers
for (int i = calleeSavedRegisterCount - 1; i >= 0; --i)
loadPtr(Address(StackFrameRegister, -(i + 1) * sizeof(void*)), calleeSavedRegisters[i]);
- int frameSize = calculateStackFrameSize(locals);
+ int frameSize = _stackLayout.calculateStackFrameSize(withLocals);
// Work around bug in ARMv7Assembler.h where add32(imm, sp, sp) doesn't
// work well for large immediates.
#if CPU(ARM_THUMB2)
@@ -439,97 +431,6 @@ const Assembler::BinaryOperationInfo Assembler::binaryOperations[QQmlJS::V4IR::L
NULL_OP // OpOr
};
-void Assembler::generateBinOp(V4IR::AluOp operation, V4IR::Temp* target, V4IR::Temp *left, V4IR::Temp *right)
-{
- const BinaryOperationInfo& info = binaryOperations[operation];
- if (!info.fallbackImplementation && !info.contextImplementation) {
- assert(!"unreachable");
- return;
- }
-
- Value leftConst = Value::undefinedValue();
- Value rightConst = Value::undefinedValue();
-
- bool canDoInline = info.inlineMemRegOp && info.inlineImmRegOp;
-
- if (canDoInline) {
- if (left->asConst()) {
- leftConst = convertToValue(left->asConst());
- canDoInline = canDoInline && leftConst.tryIntegerConversion();
- }
- if (right->asConst()) {
- rightConst = convertToValue(right->asConst());
- canDoInline = canDoInline && rightConst.tryIntegerConversion();
- }
- }
-
- Jump binOpFinished;
-
- if (canDoInline) {
-
- Jump leftTypeCheck;
- if (left->asTemp()) {
- Address typeAddress = loadTempAddress(ScratchRegister, left->asTemp());
- typeAddress.offset += offsetof(QV4::Value, tag);
- leftTypeCheck = branch32(NotEqual, typeAddress, TrustedImm32(QV4::Value::_Integer_Type));
- }
-
- Jump rightTypeCheck;
- if (right->asTemp()) {
- Address typeAddress = loadTempAddress(ScratchRegister, right->asTemp());
- typeAddress.offset += offsetof(QV4::Value, tag);
- rightTypeCheck = branch32(NotEqual, typeAddress, TrustedImm32(QV4::Value::_Integer_Type));
- }
-
- if (left->asTemp()) {
- Address leftValue = loadTempAddress(ScratchRegister, left->asTemp());
- leftValue.offset += offsetof(QV4::Value, int_32);
- load32(leftValue, IntegerOpRegister);
- } else { // left->asConst()
- move(TrustedImm32(leftConst.integerValue()), IntegerOpRegister);
- }
-
- Jump overflowCheck;
-
- if (right->asTemp()) {
- Address rightValue = loadTempAddress(ScratchRegister, right->asTemp());
- rightValue.offset += offsetof(QV4::Value, int_32);
-
- overflowCheck = (this->*info.inlineMemRegOp)(rightValue, IntegerOpRegister);
- } else { // right->asConst()
- overflowCheck = (this->*info.inlineImmRegOp)(TrustedImm32(rightConst.integerValue()), IntegerOpRegister);
- }
-
- Address resultAddr = loadTempAddress(ScratchRegister, target);
- Address resultValueAddr = resultAddr;
- resultValueAddr.offset += offsetof(QV4::Value, int_32);
- store32(IntegerOpRegister, resultValueAddr);
-
- Address resultTypeAddr = resultAddr;
- resultTypeAddr.offset += offsetof(QV4::Value, tag);
- store32(TrustedImm32(QV4::Value::_Integer_Type), resultTypeAddr);
-
- binOpFinished = jump();
-
- if (leftTypeCheck.isSet())
- leftTypeCheck.link(this);
- if (rightTypeCheck.isSet())
- rightTypeCheck.link(this);
- if (overflowCheck.isSet())
- overflowCheck.link(this);
- }
-
- // Fallback
- if (info.contextImplementation)
- generateFunctionCallImp(Assembler::Void, info.name, info.contextImplementation, ContextRegister,
- Assembler::PointerToValue(target), Assembler::Reference(left), Assembler::Reference(right));
- else
- generateFunctionCallImp(Assembler::Void, info.name, info.fallbackImplementation,
- Assembler::PointerToValue(target), Assembler::Reference(left), Assembler::Reference(right));
-
- if (binOpFinished.isSet())
- binOpFinished.link(this);
-}
#if OS(LINUX) || OS(MAC_OS_X)
static void printDisassembledOutputWithCalls(const char* output, const QHash<void*, const char*>& functions)
{
@@ -605,6 +506,7 @@ JSC::MacroAssemblerCodeRef Assembler::link()
linkBuffer.patch(label, linkBuffer.locationOf(target));
}
}
+ _constTable.finalize(linkBuffer, _isel);
#if defined(Q_PROCESSOR_ARM) && !defined(Q_OS_IOS)
UnwindHelper::writeARMUnwindInfo(linkBuffer.debugAddress(), linkBuffer.offsetOf(endOfCode));
@@ -668,7 +570,6 @@ InstructionSelection::InstructionSelection(QV4::ExecutableAllocator *execAllocat
, _block(0)
, _function(0)
, _as(0)
- , _locals(0)
{
compilationUnit = new CompilationUnit;
}
@@ -684,13 +585,11 @@ void InstructionSelection::run(V4IR::Function *function)
QSet<V4IR::BasicBlock*> reentryBlocks;
qSwap(_function, function);
qSwap(_reentryBlocks, reentryBlocks);
- Assembler* oldAssembler = _as;
- _as = new Assembler(this, _function, executableAllocator);
V4IR::Optimizer opt(_function);
opt.run();
if (opt.isInSSA()) {
-#if CPU(X86_64) && (OS(MAC_OS_X) || OS(LINUX)) && 0 // TODO: masm cannot handle registers yet.
+#if CPU(X86_64) && (OS(MAC_OS_X) || OS(LINUX))
static const QVector<int> intRegisters = QVector<int>()
<< JSC::X86Registers::edi
<< JSC::X86Registers::esi
@@ -716,11 +615,12 @@ void InstructionSelection::run(V4IR::Function *function)
} else {
ConvertTemps().toStackSlots(_function);
}
+ V4IR::Optimizer::showMeTheCode(_function);
+
+ Assembler* oldAssembler = _as;
+ _as = new Assembler(this, _function, executableAllocator, 6); // 6 == max argc for calls to built-ins with an argument array
- int locals = (_function->tempCount + _function->maxNumberOfArguments) + 1;
- locals = (locals + 1) & ~1;
- qSwap(_locals, locals);
- _as->enterStandardStackFrame(_locals);
+ _as->enterStandardStackFrame(/*withLocals*/true);
int contextPointer = 0;
#if !defined(RETURN_VALUE_IN_REGISTER)
@@ -742,7 +642,7 @@ void InstructionSelection::run(V4IR::Function *function)
_as->registerBlock(_block, nextBlock);
if (_reentryBlocks.contains(_block)) {
- _as->enterStandardStackFrame(/*locals*/0);
+ _as->enterStandardStackFrame(/*locals*/false);
#ifdef ARGUMENTS_IN_REGISTERS
_as->move(Assembler::registerForArgument(0), Assembler::ContextRegister);
_as->move(Assembler::registerForArgument(1), Assembler::LocalsRegister);
@@ -764,11 +664,20 @@ void InstructionSelection::run(V4IR::Function *function)
qSwap(_function, function);
qSwap(_reentryBlocks, reentryBlocks);
- qSwap(_locals, locals);
delete _as;
_as = oldAssembler;
}
+void *InstructionSelection::addConstantTable(QVector<Value> *values)
+{
+ compilationUnit->constantValues.append(*values);
+ values->clear();
+
+ QVector<QV4::Value> &finalValues = compilationUnit->constantValues.last();
+ finalValues.squeeze();
+ return finalValues.data();
+}
+
QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep()
{
compilationUnit->data = generateUnit();
@@ -799,45 +708,53 @@ void InstructionSelection::callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *
}
}
-void InstructionSelection::callBuiltinTypeofMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
+void InstructionSelection::callBuiltinTypeofMember(V4IR::Expr *base, const QString &name,
+ V4IR::Temp *result)
{
generateFunctionCall(Assembler::Void, __qmljs_builtin_typeof_member, Assembler::ContextRegister,
- Assembler::PointerToValue(result), Assembler::Reference(base), Assembler::PointerToString(name));
+ Assembler::PointerToValue(result), Assembler::PointerToValue(base),
+ Assembler::PointerToString(name));
}
-void InstructionSelection::callBuiltinTypeofSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
+void InstructionSelection::callBuiltinTypeofSubscript(V4IR::Expr *base, V4IR::Expr *index,
+ V4IR::Temp *result)
{
generateFunctionCall(Assembler::Void, __qmljs_builtin_typeof_element,
- Assembler::ContextRegister, Assembler::PointerToValue(result),
- Assembler::Reference(base), Assembler::Reference(index));
+ Assembler::ContextRegister, Assembler::PointerToValue(result),
+ Assembler::PointerToValue(base), Assembler::PointerToValue(index));
}
void InstructionSelection::callBuiltinTypeofName(const QString &name, V4IR::Temp *result)
{
- generateFunctionCall(Assembler::Void, __qmljs_builtin_typeof_name, Assembler::ContextRegister, Assembler::PointerToValue(result), Assembler::PointerToString(name));
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_typeof_name, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), Assembler::PointerToString(name));
}
-void InstructionSelection::callBuiltinTypeofValue(V4IR::Temp *value, V4IR::Temp *result)
+void InstructionSelection::callBuiltinTypeofValue(V4IR::Expr *value, V4IR::Temp *result)
{
generateFunctionCall(Assembler::Void, __qmljs_builtin_typeof, Assembler::ContextRegister,
- Assembler::PointerToValue(result), Assembler::Reference(value));
+ Assembler::PointerToValue(result), Assembler::PointerToValue(value));
}
void InstructionSelection::callBuiltinDeleteMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
{
generateFunctionCall(Assembler::Void, __qmljs_delete_member, Assembler::ContextRegister,
- Assembler::PointerToValue(result), Assembler::Reference(base), Assembler::PointerToString(name));
+ Assembler::PointerToValue(result), Assembler::Reference(base),
+ Assembler::PointerToString(name));
}
-void InstructionSelection::callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
+void InstructionSelection::callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Expr *index,
+ V4IR::Temp *result)
{
generateFunctionCall(Assembler::Void, __qmljs_delete_subscript, Assembler::ContextRegister,
- Assembler::PointerToValue(result), Assembler::Reference(base), Assembler::Reference(index));
+ Assembler::PointerToValue(result), Assembler::Reference(base),
+ Assembler::PointerToValue(index));
}
void InstructionSelection::callBuiltinDeleteName(const QString &name, V4IR::Temp *result)
{
- generateFunctionCall(Assembler::Void, __qmljs_delete_name, Assembler::ContextRegister, Assembler::PointerToValue(result), Assembler::PointerToString(name));
+ generateFunctionCall(Assembler::Void, __qmljs_delete_name, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), Assembler::PointerToString(name));
}
void InstructionSelection::callBuiltinDeleteValue(V4IR::Temp *result)
@@ -847,14 +764,16 @@ void InstructionSelection::callBuiltinDeleteValue(V4IR::Temp *result)
void InstructionSelection::callBuiltinPostIncrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
{
- generateFunctionCall(Assembler::Void, __qmljs_builtin_post_increment_member, Assembler::ContextRegister,
- Assembler::PointerToValue(result), Assembler::PointerToValue(base), Assembler::PointerToString(name));
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_post_increment_member,
+ Assembler::ContextRegister, Assembler::PointerToValue(result),
+ Assembler::PointerToValue(base), Assembler::PointerToString(name));
}
void InstructionSelection::callBuiltinPostIncrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
{
- generateFunctionCall(Assembler::Void, __qmljs_builtin_post_increment_element, Assembler::ContextRegister,
- Assembler::PointerToValue(result), Assembler::Reference(base), Assembler::PointerToValue(index));
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_post_increment_element,
+ Assembler::ContextRegister, Assembler::PointerToValue(result),
+ Assembler::Reference(base), Assembler::PointerToValue(index));
}
void InstructionSelection::callBuiltinPostIncrementName(const QString &name, V4IR::Temp *result)
@@ -894,9 +813,10 @@ void InstructionSelection::callBuiltinPostDecrementValue(V4IR::Temp *value, V4IR
Assembler::PointerToValue(result), Assembler::PointerToValue(value));
}
-void InstructionSelection::callBuiltinThrow(V4IR::Temp *arg)
+void InstructionSelection::callBuiltinThrow(V4IR::Expr *arg)
{
- generateFunctionCall(Assembler::Void, __qmljs_throw, Assembler::ContextRegister, Assembler::Reference(arg));
+ generateFunctionCall(Assembler::Void, __qmljs_throw, Assembler::ContextRegister,
+ Assembler::PointerToValue(arg));
}
typedef void *(*MiddleOfFunctionEntryPoint(ExecutionContext *, void *localsPtr));
@@ -943,23 +863,31 @@ void InstructionSelection::callBuiltinFinishTry()
// This assumes that we're in code that was called by tryWrapper, so we return to try wrapper
// with the address that we'd like to continue at, which is right after the ret below.
Assembler::DataLabelPtr continuation = _as->moveWithPatch(Assembler::TrustedImmPtr(0), Assembler::ReturnValueRegister);
- _as->leaveStandardStackFrame(/*locals*/0);
+ _as->leaveStandardStackFrame(/*locals*/false);
_as->ret();
_as->addPatch(continuation, _as->label());
}
void InstructionSelection::callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result)
{
+ Q_ASSERT(arg);
+ Q_ASSERT(result);
+
generateFunctionCall(Assembler::Void, __qmljs_foreach_iterator_object, Assembler::ContextRegister, Assembler::PointerToValue(result), Assembler::Reference(arg));
}
void InstructionSelection::callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result)
{
+ Q_ASSERT(arg);
+ Q_ASSERT(result);
+
generateFunctionCall(Assembler::Void, __qmljs_foreach_next_property_name, Assembler::PointerToValue(result), Assembler::Reference(arg));
}
void InstructionSelection::callBuiltinPushWithScope(V4IR::Temp *arg)
{
+ Q_ASSERT(arg);
+
generateFunctionCall(Assembler::ContextRegister, __qmljs_builtin_push_with_scope, Assembler::Reference(arg), Assembler::ContextRegister);
}
@@ -976,26 +904,38 @@ void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &
void InstructionSelection::callBuiltinDefineGetterSetter(V4IR::Temp *object, const QString &name, V4IR::Temp *getter, V4IR::Temp *setter)
{
+ Q_ASSERT(object);
+ Q_ASSERT(getter);
+ Q_ASSERT(setter);
generateFunctionCall(Assembler::Void, __qmljs_builtin_define_getter_setter, Assembler::ContextRegister,
Assembler::Reference(object), Assembler::PointerToString(name), Assembler::PointerToValue(getter), Assembler::PointerToValue(setter));
}
-void InstructionSelection::callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value)
+void InstructionSelection::callBuiltinDefineProperty(V4IR::Temp *object, const QString &name,
+ V4IR::Expr *value)
{
- generateFunctionCall(Assembler::Void, __qmljs_builtin_define_property, Assembler::ContextRegister,
- Assembler::Reference(object), Assembler::PointerToString(name), Assembler::PointerToValue(value));
+ Q_ASSERT(object);
+ Q_ASSERT(value->asTemp() || value->asConst());
+
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_define_property,
+ Assembler::ContextRegister, Assembler::Reference(object), Assembler::PointerToString(name),
+ Assembler::PointerToValue(value));
}
void InstructionSelection::callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args)
{
+ Q_ASSERT(result);
+
int length = prepareVariableArguments(args);
generateFunctionCall(Assembler::Void, __qmljs_builtin_define_array, Assembler::ContextRegister,
- Assembler::PointerToValue(result),
- baseAddressForCallArguments(), Assembler::TrustedImm32(length));
+ Assembler::PointerToValue(result), baseAddressForCallArguments(),
+ Assembler::TrustedImm32(length));
}
void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args)
{
+ Q_ASSERT(result);
+
int argc = 0;
const int classId = registerJSClass(args);
@@ -1007,11 +947,11 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4
bool isData = it->expr->asConst()->value;
it = it->next;
- _as->copyValue(argumentAddressForCall(argc++), it->expr);
+ _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr);
if (!isData) {
it = it->next;
- _as->copyValue(argumentAddressForCall(argc++), it->expr);
+ _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr);
}
it = it->next;
@@ -1030,6 +970,8 @@ void InstructionSelection::callBuiltinSetupArgumentObject(V4IR::Temp *result)
void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result)
{
+ Q_ASSERT(value);
+
int argc = prepareVariableArguments(args);
V4IR::Temp* thisObject = 0;
generateFunctionCall(Assembler::Void, __qmljs_call_value, Assembler::ContextRegister,
@@ -1040,7 +982,8 @@ void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4
void InstructionSelection::loadThisObject(V4IR::Temp *temp)
{
#if defined(VALUE_FITS_IN_REGISTER)
- _as->load64(Pointer(Assembler::ContextRegister, offsetof(ExecutionContext, thisObject)), Assembler::ReturnValueRegister);
+ _as->load64(Pointer(Assembler::ContextRegister, offsetof(ExecutionContext, thisObject)),
+ Assembler::ReturnValueRegister);
_as->storeReturnValue(temp);
#else
_as->copyValue(temp, Pointer(Assembler::ContextRegister, offsetof(ExecutionContext, thisObject)));
@@ -1049,7 +992,26 @@ void InstructionSelection::loadThisObject(V4IR::Temp *temp)
void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp)
{
- _as->storeValue(convertToValue(sourceConst), targetTemp);
+ if (targetTemp->kind == V4IR::Temp::PhysicalRegister) {
+ if (targetTemp->type == V4IR::DoubleType) {
+ Q_ASSERT(sourceConst->type == V4IR::DoubleType);
+ _as->toDoubleRegister(sourceConst, (Assembler::FPRegisterID) targetTemp->index);
+ } else if (targetTemp->type == V4IR::SInt32Type) {
+ Q_ASSERT(sourceConst->type == V4IR::SInt32Type);
+ _as->toInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index);
+ } else if (targetTemp->type == V4IR::UInt32Type) {
+ Q_ASSERT(sourceConst->type == V4IR::UInt32Type);
+ _as->toUInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index);
+ } else if (targetTemp->type == V4IR::BoolType) {
+ Q_ASSERT(sourceConst->type == V4IR::BoolType);
+ _as->move(Assembler::TrustedImm32(convertToValue(sourceConst).int_32),
+ (Assembler::RegisterID) targetTemp->index);
+ } else {
+ Q_UNIMPLEMENTED();
+ }
+ } else {
+ _as->storeValue(convertToValue(sourceConst), targetTemp);
+ }
}
void InstructionSelection::loadString(const QString &str, V4IR::Temp *targetTemp)
@@ -1073,10 +1035,10 @@ void InstructionSelection::getActivationProperty(const V4IR::Name *name, V4IR::T
generateFunctionCall(Assembler::Void, __qmljs_get_activation_property, Assembler::ContextRegister, Assembler::PointerToValue(temp), Assembler::PointerToString(*name->id));
}
-void InstructionSelection::setActivationProperty(V4IR::Temp *source, const QString &targetName)
+void InstructionSelection::setActivationProperty(V4IR::Expr *source, const QString &targetName)
{
generateFunctionCall(Assembler::Void, __qmljs_set_activation_property,
- Assembler::ContextRegister, Assembler::PointerToString(targetName), Assembler::Reference(source));
+ Assembler::ContextRegister, Assembler::PointerToString(targetName), Assembler::PointerToValue(source));
}
void InstructionSelection::initClosure(V4IR::Closure *closure, V4IR::Temp *target)
@@ -1085,49 +1047,152 @@ void InstructionSelection::initClosure(V4IR::Closure *closure, V4IR::Temp *targe
generateFunctionCall(Assembler::Void, __qmljs_init_closure, Assembler::ContextRegister, Assembler::PointerToValue(target), Assembler::TrustedImm32(id));
}
-void InstructionSelection::getProperty(V4IR::Temp *base, const QString &name, V4IR::Temp *target)
+void InstructionSelection::getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target)
{
if (useFastLookups) {
uint index = registerGetterLookup(name);
generateLookupCall(index, offsetof(QV4::Lookup, getter), Assembler::PointerToValue(target),
- Assembler::Reference(base));
+ Assembler::PointerToValue(base));
} else {
- generateFunctionCall(Assembler::Void, __qmljs_get_property, Assembler::ContextRegister, Assembler::PointerToValue(target),
- Assembler::Reference(base), Assembler::PointerToString(name));
+ generateFunctionCall(Assembler::Void, __qmljs_get_property, Assembler::ContextRegister,
+ Assembler::PointerToValue(target), Assembler::PointerToValue(base),
+ Assembler::PointerToString(name));
}
}
-void InstructionSelection::setProperty(V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName)
+void InstructionSelection::setProperty(V4IR::Expr *source, V4IR::Expr *targetBase,
+ const QString &targetName)
{
if (useFastLookups) {
uint index = registerSetterLookup(targetName);
- generateLookupCall(index, offsetof(QV4::Lookup, setter), Assembler::Reference(targetBase), Assembler::Reference(source));
+ generateLookupCall(index, offsetof(QV4::Lookup, setter),
+ Assembler::PointerToValue(targetBase),
+ Assembler::PointerToValue(source));
} else {
generateFunctionCall(Assembler::Void, __qmljs_set_property, Assembler::ContextRegister,
- Assembler::Reference(targetBase),
- Assembler::PointerToString(targetName), Assembler::Reference(source));
+ Assembler::PointerToValue(targetBase), Assembler::PointerToString(targetName),
+ Assembler::PointerToValue(source));
}
}
-void InstructionSelection::getElement(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *target)
+void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target)
{
generateFunctionCall(Assembler::Void, __qmljs_get_element, Assembler::ContextRegister,
- Assembler::PointerToValue(target), Assembler::Reference(base),
- Assembler::Reference(index));
+ Assembler::PointerToValue(target), Assembler::PointerToValue(base),
+ Assembler::PointerToValue(index));
}
-void InstructionSelection::setElement(V4IR::Temp *source, V4IR::Temp *targetBase, V4IR::Temp *targetIndex)
+void InstructionSelection::setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex)
{
generateFunctionCall(Assembler::Void, __qmljs_set_element, Assembler::ContextRegister,
- Assembler::Reference(targetBase), Assembler::Reference(targetIndex),
- Assembler::Reference(source));
+ Assembler::PointerToValue(targetBase), Assembler::PointerToValue(targetIndex),
+ Assembler::PointerToValue(source));
}
void InstructionSelection::copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp)
{
+ if (*sourceTemp == *targetTemp)
+ return;
+
+ if (sourceTemp->kind == V4IR::Temp::PhysicalRegister) {
+ if (targetTemp->kind == V4IR::Temp::PhysicalRegister) {
+ if (sourceTemp->type == V4IR::DoubleType)
+ _as->moveDouble((Assembler::FPRegisterID) sourceTemp->index,
+ (Assembler::FPRegisterID) targetTemp->index);
+ else
+ _as->move((Assembler::RegisterID) sourceTemp->index,
+ (Assembler::RegisterID) targetTemp->index);
+ return;
+ } else {
+ Assembler::Pointer addr = _as->loadTempAddress(Assembler::ScratchRegister, targetTemp);
+ switch (sourceTemp->type) {
+ case V4IR::DoubleType:
+ _as->storeDouble((Assembler::FPRegisterID) sourceTemp->index, addr);
+ break;
+ case V4IR::SInt32Type:
+ _as->storeInt32((Assembler::RegisterID) sourceTemp->index, addr);
+ break;
+ case V4IR::UInt32Type:
+ _as->storeUInt32((Assembler::RegisterID) sourceTemp->index, addr);
+ break;
+ case V4IR::BoolType:
+ _as->storeBool((Assembler::RegisterID) sourceTemp->index, addr);
+ break;
+ default:
+ Q_ASSERT(!"Unreachable");
+ break;
+ }
+ return;
+ }
+ } else if (targetTemp->kind == V4IR::Temp::PhysicalRegister) {
+ switch (targetTemp->type) {
+ case V4IR::DoubleType:
+ Q_ASSERT(sourceTemp->type == V4IR::DoubleType);
+ _as->toDoubleRegister(sourceTemp, (Assembler::FPRegisterID) targetTemp->index);
+ return;
+ case V4IR::BoolType:
+ Q_ASSERT(sourceTemp->type == V4IR::BoolType);
+ _as->toInt32Register(sourceTemp, (Assembler::RegisterID) targetTemp->index);
+ return;
+ case V4IR::SInt32Type:
+ Q_ASSERT(sourceTemp->type == V4IR::SInt32Type);
+ _as->toInt32Register(sourceTemp, (Assembler::RegisterID) targetTemp->index);
+ return;
+ case V4IR::UInt32Type:
+ Q_ASSERT(sourceTemp->type == V4IR::UInt32Type);
+ _as->toUInt32Register(sourceTemp, (Assembler::RegisterID) targetTemp->index);
+ return;
+ default:
+ Q_ASSERT(!"Unreachable");
+ break;
+ }
+ }
+
_as->copyValue(targetTemp, sourceTemp);
}
+void InstructionSelection::swapValues(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp)
+{
+ Q_ASSERT(sourceTemp->type == targetTemp->type);
+
+ if (sourceTemp->kind == V4IR::Temp::PhysicalRegister) {
+ if (targetTemp->kind == V4IR::Temp::PhysicalRegister) {
+ if (sourceTemp->type == V4IR::DoubleType) {
+ _as->moveDouble((Assembler::FPRegisterID) targetTemp->index, Assembler::FPGpr0);
+ _as->moveDouble((Assembler::FPRegisterID) sourceTemp->index,
+ (Assembler::FPRegisterID) targetTemp->index);
+ _as->moveDouble(Assembler::FPGpr0, (Assembler::FPRegisterID) sourceTemp->index);
+ } else {
+ _as->swap((Assembler::RegisterID) sourceTemp->index,
+ (Assembler::RegisterID) targetTemp->index);
+ }
+ return;
+ }
+ } else if (sourceTemp->kind == V4IR::Temp::StackSlot) {
+ if (targetTemp->kind == V4IR::Temp::StackSlot) {
+ Assembler::FPRegisterID tReg = _as->toDoubleRegister(targetTemp);
+#if CPU(X86_64)
+ _as->load64(_as->stackSlotPointer(sourceTemp), Assembler::ScratchRegister);
+ _as->store64(Assembler::ScratchRegister, _as->stackSlotPointer(targetTemp));
+#else
+ Assembler::Pointer sAddr = _as->stackSlotPointer(sourceTemp);
+ Assembler::Pointer tAddr = _as->stackSlotPointer(targetTemp);
+ _as->load32(sAddr, Assembler::ScratchRegister);
+ _as->store32(Assembler::ScratchRegister, tAddr);
+ sAddr.offset += 4;
+ tAddr.offset += 4;
+ _as->load32(sAddr, Assembler::ScratchRegister);
+ _as->store32(Assembler::ScratchRegister, tAddr);
+#endif
+ _as->storeDouble(tReg, _as->stackSlotPointer(sourceTemp));
+ return;
+ }
+ }
+
+ // FIXME: TODO!
+ Q_UNIMPLEMENTED();
+}
+
#define setOp(op, opName, operation) \
do { op = operation; opName = isel_stringIfy(operation); } while (0)
#define setOpContext(op, opName, operation) \
@@ -1148,15 +1213,33 @@ void InstructionSelection::unop(V4IR::AluOp oper, V4IR::Temp *sourceTemp, V4IR::
default: assert(!"unreachable"); break;
} // switch
- if (op)
- _as->generateFunctionCallImp(Assembler::Void, opName, op, Assembler::PointerToValue(targetTemp),
- Assembler::Reference(sourceTemp));
+ if (op) {
+ _as->generateFunctionCallImp(Assembler::Void, opName, op,
+ Assembler::PointerToValue(targetTemp),
+ Assembler::PointerToValue(sourceTemp));
+ storeTarget(0, targetTemp);
+ }
}
void InstructionSelection::binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target)
{
- Q_ASSERT(leftSource->asTemp() && rightSource->asTemp());
- _as->generateBinOp(oper, target, leftSource->asTemp(), rightSource->asTemp());
+ const Assembler::BinaryOperationInfo& info = Assembler::binaryOperation(oper);
+ if (info.fallbackImplementation) {
+ _as->generateFunctionCallImp(Assembler::Void, info.name, info.fallbackImplementation,
+ Assembler::PointerToValue(target),
+ Assembler::PointerToValue(leftSource),
+ Assembler::PointerToValue(rightSource));
+ storeTarget(0, target);
+ } else if (info.contextImplementation) {
+ _as->generateFunctionCallImp(Assembler::Void, info.name, info.contextImplementation,
+ Assembler::ContextRegister,
+ Assembler::PointerToValue(target),
+ Assembler::PointerToValue(leftSource),
+ Assembler::PointerToValue(rightSource));
+ storeTarget(1, target);
+ } else {
+ assert(!"unreachable");
+ }
}
void InstructionSelection::inplaceNameOp(V4IR::AluOp oper, V4IR::Temp *rightSource, const QString &targetName)
@@ -1241,8 +1324,8 @@ void InstructionSelection::inplaceMemberOp(V4IR::AluOp oper, V4IR::Temp *source,
}
}
-void InstructionSelection::callProperty(V4IR::Temp *base, const QString &name,
- V4IR::ExprList *args, V4IR::Temp *result)
+void InstructionSelection::callProperty(V4IR::Expr *base, const QString &name, V4IR::ExprList *args,
+ V4IR::Temp *result)
{
assert(base != 0);
@@ -1252,36 +1335,38 @@ void InstructionSelection::callProperty(V4IR::Temp *base, const QString &name,
uint index = registerGetterLookup(name);
generateFunctionCall(Assembler::Void, __qmljs_call_property_lookup,
Assembler::ContextRegister, Assembler::PointerToValue(result),
- Assembler::Reference(base), Assembler::TrustedImm32(index),
+ Assembler::PointerToValue(base), Assembler::TrustedImm32(index),
baseAddressForCallArguments(),
Assembler::TrustedImm32(argc));
} else {
- generateFunctionCall(Assembler::Void, __qmljs_call_property,
- Assembler::ContextRegister, Assembler::PointerToValue(result),
- Assembler::Reference(base), Assembler::PointerToString(name),
- baseAddressForCallArguments(),
- Assembler::TrustedImm32(argc));
+ generateFunctionCall(Assembler::Void, __qmljs_call_property, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), Assembler::PointerToValue(base), Assembler::PointerToString(name),
+ baseAddressForCallArguments(), Assembler::TrustedImm32(argc));
}
}
-void InstructionSelection::callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result)
+void InstructionSelection::callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::ExprList *args,
+ V4IR::Temp *result)
{
assert(base != 0);
int argc = prepareVariableArguments(args);
- generateFunctionCall(Assembler::Void, __qmljs_call_element,
- Assembler::ContextRegister, Assembler::PointerToValue(result),
- Assembler::Reference(base), Assembler::Reference(index),
- baseAddressForCallArguments(),
+ generateFunctionCall(Assembler::Void, __qmljs_call_element, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), Assembler::PointerToValue(base),
+ Assembler::PointerToValue(index), baseAddressForCallArguments(),
Assembler::TrustedImm32(argc));
}
void InstructionSelection::convertType(V4IR::Temp *source, V4IR::Temp *target)
{
// FIXME: do something more useful with this info
- if (target->type & V4IR::NumberType && !(source->type & V4IR::NumberType))
+ if (target->type & V4IR::NumberType)
unop(V4IR::OpUPlus, source, target);
- else
+ else if (target->type == V4IR::BoolType) {
+ generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_to_boolean,
+ Assembler::PointerToValue(source));
+ _as->storeBool(Assembler::ReturnValueRegister, target);
+ } else
copyValue(source, target);
}
@@ -1327,64 +1412,83 @@ void InstructionSelection::visitJump(V4IR::Jump *s)
void InstructionSelection::visitCJump(V4IR::CJump *s)
{
if (V4IR::Temp *t = s->cond->asTemp()) {
- Address temp = _as->loadTempAddress(Assembler::ScratchRegister, t);
- Address tag = temp;
- tag.offset += offsetof(QV4::Value, tag);
- Assembler::Jump booleanConversion = _as->branch32(Assembler::NotEqual, tag, Assembler::TrustedImm32(QV4::Value::Boolean_Type));
-
- Address data = temp;
- data.offset += offsetof(QV4::Value, int_32);
- _as->load32(data, Assembler::ReturnValueRegister);
- Assembler::Jump testBoolean = _as->jump();
-
- booleanConversion.link(_as);
- {
- generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_to_boolean, Assembler::Reference(t));
+ Assembler::RegisterID reg;
+ if (t->kind == V4IR::Temp::PhysicalRegister) {
+ Q_ASSERT(t->type == V4IR::BoolType);
+ reg = (Assembler::RegisterID) t->index;
+ } else if (t->kind == V4IR::Temp::StackSlot && t->type == V4IR::BoolType) {
+ reg = Assembler::ReturnValueRegister;
+ _as->toInt32Register(t, reg);
+ } else {
+ Address temp = _as->loadTempAddress(Assembler::ScratchRegister, t);
+ Address tag = temp;
+ tag.offset += offsetof(QV4::Value, tag);
+ Assembler::Jump booleanConversion = _as->branch32(Assembler::NotEqual, tag, Assembler::TrustedImm32(QV4::Value::Boolean_Type));
+
+ Address data = temp;
+ data.offset += offsetof(QV4::Value, int_32);
+ _as->load32(data, Assembler::ReturnValueRegister);
+ Assembler::Jump testBoolean = _as->jump();
+
+ booleanConversion.link(_as);
+ reg = Assembler::ReturnValueRegister;
+ generateFunctionCall(reg, __qmljs_to_boolean, Assembler::Reference(t));
+
+ testBoolean.link(_as);
}
- testBoolean.link(_as);
- Assembler::Jump target = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister, Assembler::TrustedImm32(0));
+ Assembler::Jump target = _as->branch32(Assembler::NotEqual, reg, Assembler::TrustedImm32(0));
+ _as->addPatch(s->iftrue, target);
+ _as->jumpToBlock(_block, s->iffalse);
+ return;
+ } else if (V4IR::Const *c = s->cond->asConst()) {
+ // TODO: SSA optimization for constant condition evaluation should remove this.
+ // See also visitCJump() in RegAllocInfo.
+ generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_to_boolean,
+ Assembler::PointerToValue(c));
+ Assembler::Jump target = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister,
+ Assembler::TrustedImm32(0));
_as->addPatch(s->iftrue, target);
-
_as->jumpToBlock(_block, s->iffalse);
return;
} else if (V4IR::Binop *b = s->cond->asBinop()) {
- if (b->left->asTemp() && b->right->asTemp()) {
- CmpOp op = 0;
- CmpOpContext opContext = 0;
- const char *opName = 0;
- switch (b->op) {
- default: Q_UNREACHABLE(); assert(!"todo"); break;
- case V4IR::OpGt: setOp(op, opName, __qmljs_cmp_gt); break;
- case V4IR::OpLt: setOp(op, opName, __qmljs_cmp_lt); break;
- case V4IR::OpGe: setOp(op, opName, __qmljs_cmp_ge); break;
- case V4IR::OpLe: setOp(op, opName, __qmljs_cmp_le); break;
- case V4IR::OpEqual: setOp(op, opName, __qmljs_cmp_eq); break;
- case V4IR::OpNotEqual: setOp(op, opName, __qmljs_cmp_ne); break;
- case V4IR::OpStrictEqual: setOp(op, opName, __qmljs_cmp_se); break;
- case V4IR::OpStrictNotEqual: setOp(op, opName, __qmljs_cmp_sne); break;
- case V4IR::OpInstanceof: setOpContext(op, opName, __qmljs_cmp_instanceof); break;
- case V4IR::OpIn: setOpContext(op, opName, __qmljs_cmp_in); break;
- } // switch
-
- if (opContext)
- _as->generateFunctionCallImp(Assembler::ReturnValueRegister, opName, opContext, Assembler::ContextRegister,
- Assembler::Reference(b->left->asTemp()),
- Assembler::Reference(b->right->asTemp()));
- else
- _as->generateFunctionCallImp(Assembler::ReturnValueRegister, opName, op,
- Assembler::Reference(b->left->asTemp()),
- Assembler::Reference(b->right->asTemp()));
-
- Assembler::Jump target = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister, Assembler::TrustedImm32(0));
- _as->addPatch(s->iftrue, target);
-
- _as->jumpToBlock(_block, s->iffalse);
- return;
- } else {
- assert(!"wip");
- }
- Q_UNIMPLEMENTED();
+ CmpOp op = 0;
+ CmpOpContext opContext = 0;
+ const char *opName = 0;
+ switch (b->op) {
+ default: Q_UNREACHABLE(); assert(!"todo"); break;
+ case V4IR::OpGt: setOp(op, opName, __qmljs_cmp_gt); break;
+ case V4IR::OpLt: setOp(op, opName, __qmljs_cmp_lt); break;
+ case V4IR::OpGe: setOp(op, opName, __qmljs_cmp_ge); break;
+ case V4IR::OpLe: setOp(op, opName, __qmljs_cmp_le); break;
+ case V4IR::OpEqual: setOp(op, opName, __qmljs_cmp_eq); break;
+ case V4IR::OpNotEqual: setOp(op, opName, __qmljs_cmp_ne); break;
+ case V4IR::OpStrictEqual: setOp(op, opName, __qmljs_cmp_se); break;
+ case V4IR::OpStrictNotEqual: setOp(op, opName, __qmljs_cmp_sne); break;
+ case V4IR::OpInstanceof: setOpContext(op, opName, __qmljs_cmp_instanceof); break;
+ case V4IR::OpIn: setOpContext(op, opName, __qmljs_cmp_in); break;
+ } // switch
+
+ // TODO: in SSA optimization, do constant expression evaluation.
+ // The case here is, for example:
+ // if (true === true) .....
+ // Of course, after folding the CJUMP to a JUMP, dead-code (dead-basic-block)
+ // elimination (which isn't there either) would remove the whole else block.
+ if (opContext)
+ _as->generateFunctionCallImp(Assembler::ReturnValueRegister, opName, opContext,
+ Assembler::ContextRegister,
+ Assembler::PointerToValue(b->left),
+ Assembler::PointerToValue(b->right));
+ else
+ _as->generateFunctionCallImp(Assembler::ReturnValueRegister, opName, op,
+ Assembler::PointerToValue(b->left),
+ Assembler::PointerToValue(b->right));
+
+ Assembler::Jump target = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister,
+ Assembler::TrustedImm32(0));
+ _as->addPatch(s->iftrue, target);
+ _as->jumpToBlock(_block, s->iffalse);
+ return;
}
Q_UNIMPLEMENTED();
assert(!"TODO");
@@ -1400,21 +1504,57 @@ void InstructionSelection::visitRet(V4IR::Ret *s)
addr.offset += 4;
_as->load32(addr, JSC::X86Registers::edx);
#else
- _as->copyValue(Assembler::ReturnValueRegister, t);
+ if (t->kind == V4IR::Temp::PhysicalRegister) {
+ if (t->type == V4IR::DoubleType) {
+ _as->moveDoubleTo64((Assembler::FPRegisterID) t->index,
+ Assembler::ReturnValueRegister);
+ } else {
+ _as->zeroExtend32ToPtr((Assembler::RegisterID) t->index,
+ Assembler::ReturnValueRegister);
+ QV4::Value upper;
+ switch (t->type) {
+ case V4IR::SInt32Type:
+ case V4IR::UInt32Type:
+ upper = QV4::Value::fromInt32(0);
+ break;
+ case V4IR::BoolType:
+ upper = QV4::Value::fromBoolean(false);
+ break;
+ default:
+ upper = QV4::Value::undefinedValue();
+ Q_UNIMPLEMENTED();
+ }
+ _as->or64(Assembler::TrustedImm64(((int64_t) upper.tag) << 32),
+ Assembler::ReturnValueRegister);
+ }
+ } else {
+ _as->copyValue(Assembler::ReturnValueRegister, t);
+ }
#endif
#else
_as->loadPtr(addressForArgument(0), Assembler::ReturnValueRegister);
_as->copyValue(Address(Assembler::ReturnValueRegister, 0), t);
#endif
} else if (V4IR::Const *c = s->expr->asConst()) {
- _as->copyValue(Assembler::ReturnValueRegister, c);
+ QV4::Value retVal = convertToValue(c);
+#if defined(RETURN_VALUE_IN_REGISTER)
+#if CPU(X86)
+ _as->move(Assembler::TrustedImm32(retVal.int_32), JSC::X86Registers::eax);
+ _as->move(Assembler::TrustedImm32(retVal.tag), JSC::X86Registers::edx);
+#else
+ _as->move(Assembler::TrustedImm64(retVal.val), Assembler::ReturnValueRegister);
+#endif
+#else // !RETURN_VALUE_IN_REGISTER
+ _as->loadPtr(addressForArgument(0), Assembler::ReturnValueRegister);
+ _as->storeValue(retVal, Assembler::Address(Assembler::ReturnValueRegister));
+#endif
} else {
Q_UNIMPLEMENTED();
Q_UNREACHABLE();
Q_UNUSED(s);
}
- _as->leaveStandardStackFrame(_locals);
+ _as->leaveStandardStackFrame(/*withLocals*/true);
#if !defined(ARGUMENTS_IN_REGISTERS) && !defined(RETURN_VALUE_IN_REGISTER)
// Emulate ret(n) instruction
// Pop off return address into scratch register ...
@@ -1435,9 +1575,9 @@ int InstructionSelection::prepareVariableArguments(V4IR::ExprList* args)
int i = 0;
for (V4IR::ExprList *it = args; it; it = it->next, ++i) {
-// V4IR::Temp *arg = it->expr->asTemp();
-// assert(arg != 0);
- _as->copyValue(argumentAddressForCall(i), it->expr);
+ V4IR::Expr *arg = it->expr;
+ Q_ASSERT(arg != 0);
+ _as->copyValue(_as->stackLayout().argumentAddressForCall(i), arg);
}
return argc;
@@ -1454,3 +1594,45 @@ void InstructionSelection::callRuntimeMethodImp(V4IR::Temp *result, const char*
Assembler::TrustedImm32(argc));
}
+QT_BEGIN_NAMESPACE
+namespace QV4 {
+bool operator==(const Value &v1, const Value &v2)
+{
+ return v1.rawValue() == v2.rawValue();
+}
+} // QV4 namespace
+QT_END_NAMESPACE
+
+int Assembler::ConstantTable::add(const Value &v)
+{
+ int idx = _values.indexOf(v);
+ if (idx == -1) {
+ idx = _values.size();
+ _values.append(v);
+ }
+ return idx;
+}
+
+Assembler::ImplicitAddress Assembler::ConstantTable::loadValueAddress(V4IR::Const *c,
+ RegisterID baseReg)
+{
+ return loadValueAddress(convertToValue(c), baseReg);
+}
+
+Assembler::ImplicitAddress Assembler::ConstantTable::loadValueAddress(const Value &v,
+ RegisterID baseReg)
+{
+ _toPatch.append(_as->moveWithPatch(TrustedImmPtr(0), baseReg));
+ ImplicitAddress addr(baseReg);
+ addr.offset = add(v) * sizeof(QV4::Value);
+ Q_ASSERT(addr.offset >= 0);
+ return addr;
+}
+
+void Assembler::ConstantTable::finalize(JSC::LinkBuffer &linkBuffer, InstructionSelection *isel)
+{
+ void *tablePtr = isel->addConstantTable(&_values);
+
+ foreach (DataLabelPtr label, _toPatch)
+ linkBuffer.patch(label, tablePtr);
+}
diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h
index 84ceb2be4b..ef79e3524a 100644
--- a/src/qml/compiler/qv4isel_masm_p.h
+++ b/src/qml/compiler/qv4isel_masm_p.h
@@ -72,12 +72,15 @@ struct CompilationUnit : public QV4::CompiledData::CompilationUnit
// Coderef + execution engine
QVector<JSC::MacroAssemblerCodeRef> codeRefs;
+ QList<QVector<QV4::Value> > constantValues;
};
class Assembler : public JSC::MacroAssembler
{
public:
- Assembler(InstructionSelection *isel, V4IR::Function* function, QV4::ExecutableAllocator *executableAllocator);
+ Assembler(InstructionSelection *isel, V4IR::Function* function, QV4::ExecutableAllocator *executableAllocator,
+ int maxArgCountForBuiltins);
+
#if CPU(X86)
#undef VALUE_FITS_IN_REGISTER
@@ -246,10 +249,133 @@ public:
{}
};
+ // Stack layout:
+ // return address
+ // old FP <- FP, LocalsRegister
+ // callee saved reg n
+ // ...
+ // callee saved reg 0
+ // function call argument n
+ // ...
+ // function call argument 0
+ // local 0
+ // ...
+ // local n
+ // saved const arg 0
+ // ...
+ // saved const arg n <- SP
+ class StackLayout
+ {
+ public:
+ StackLayout(V4IR::Function *function, int maxArgCountForBuiltins)
+ : calleeSavedRegCount(Assembler::calleeSavedRegisterCount + 1)
+ , maxOutgoingArgumentCount(qMax(function->maxNumberOfArguments, maxArgCountForBuiltins))
+ , localCount(function->tempCount)
+ , savedConstCount(maxArgCountForBuiltins)
+ {
+#if 0 // debug code
+ qDebug("calleeSavedRegCount.....: %d",calleeSavedRegCount);
+ qDebug("maxOutgoingArgumentCount: %d",maxOutgoingArgumentCount);
+ qDebug("localCount..............: %d",localCount);
+ qDebug("savedConstCount.........: %d",savedConstCount);
+ qDebug("argumentAddressForCall(0) = 0x%x / -0x%x", argumentAddressForCall(0).offset, -argumentAddressForCall(0).offset);
+ if (localCount)qDebug("local(0) = 0x%x / -0x%x", stackSlotPointer(0).offset, -stackSlotPointer(0).offset);
+ qDebug("savedReg(0) = 0x%x", savedRegPointer(0).offset);
+ qDebug("savedReg(1) = 0x%x", savedRegPointer(1).offset);
+ qDebug("savedReg(2) = 0x%x", savedRegPointer(2).offset);
+ qDebug("savedReg(3) = 0x%x", savedRegPointer(3).offset);
+ qDebug("savedReg(4) = 0x%x", savedRegPointer(4).offset);
+ qDebug("savedReg(5) = 0x%x", savedRegPointer(5).offset);
+#endif
+ }
+
+ int calculateStackFrameSize(bool withLocals) const
+ {
+ const int stackSpaceAllocatedOtherwise = StackSpaceAllocatedUponFunctionEntry
+ + RegisterSize; // saved StackFrameRegister
+
+ const int locals = withLocals ? (maxOutgoingArgumentCount + localCount + savedConstCount) : 0;
+
+ // space for the locals and the callee saved registers
+ int frameSize = locals * sizeof(QV4::Value) + RegisterSize * calleeSavedRegisterCount;
+
+ frameSize = WTF::roundUpToMultipleOf(StackAlignment, frameSize + stackSpaceAllocatedOtherwise);
+ frameSize -= stackSpaceAllocatedOtherwise;
+
+ return frameSize;
+ }
+
+ Address stackSlotPointer(int idx) const
+ {
+ Q_ASSERT(idx >= 0);
+ Q_ASSERT(idx < localCount);
+
+ Pointer addr = argumentAddressForCall(0);
+ addr.offset -= sizeof(QV4::Value) * (idx + 1);
+ return addr;
+ }
+
+ // Some run-time functions take (Value* args, int argc). This function is for populating
+ // the args.
+ Pointer argumentAddressForCall(int argument) const
+ {
+ Q_ASSERT(argument >= 0);
+ Q_ASSERT(argument < maxOutgoingArgumentCount);
+
+ const int index = maxOutgoingArgumentCount - argument;
+ return Pointer(Assembler::LocalsRegister,
+ sizeof(QV4::Value) * (-index) - calleeSavedRegisterSpace());
+ }
+
+ Address savedRegPointer(int offset) const
+ {
+ Q_ASSERT(offset >= 0);
+ Q_ASSERT(offset < savedConstCount);
+
+ Address addr = argumentAddressForCall(0);
+ addr.offset -= sizeof(QV4::Value) * (offset + localCount + 1);
+ return addr;
+ }
+
+ int calleeSavedRegisterSpace() const
+ {
+ // plus 1 for the old FP
+ return RegisterSize * (calleeSavedRegCount + 1);
+ }
+
+ private:
+ int calleeSavedRegCount;
+
+ /// arg count for calls to JS functions
+ int maxOutgoingArgumentCount;
+
+ /// the number of spill slots needed by this function
+ int localCount;
+
+ /// used by built-ins to save arguments (e.g. constants) to the stack when they need to be
+ /// passed by reference.
+ int savedConstCount;
+ };
+
+ class ConstantTable
+ {
+ public:
+ ConstantTable(Assembler *as): _as(as) {}
+
+ int add(const QV4::Value &v);
+ ImplicitAddress loadValueAddress(V4IR::Const *c, RegisterID baseReg);
+ ImplicitAddress loadValueAddress(const QV4::Value &v, RegisterID baseReg);
+ void finalize(JSC::LinkBuffer &linkBuffer, InstructionSelection *isel);
+
+ private:
+ Assembler *_as;
+ QVector<QV4::Value> _values;
+ QVector<DataLabelPtr> _toPatch;
+ };
+
struct VoidType { VoidType() {} };
static const VoidType Void;
-
typedef JSC::FunctionPtr FunctionPtr;
struct CallToLink {
@@ -258,8 +384,10 @@ public:
const char* functionName;
};
struct PointerToValue {
- PointerToValue(V4IR::Temp *value) : value(value) {}
- V4IR::Temp *value;
+ PointerToValue(V4IR::Expr *value)
+ : value(value)
+ {}
+ V4IR::Expr *value;
};
struct PointerToString {
explicit PointerToString(const QString &string) : string(string) {}
@@ -295,54 +423,71 @@ public:
Pointer loadTempAddress(RegisterID reg, V4IR::Temp *t);
Pointer loadStringAddress(RegisterID reg, const QString &string);
+ Pointer stackSlotPointer(V4IR::Temp *t) const
+ {
+ Q_ASSERT(t->kind == V4IR::Temp::StackSlot);
+ Q_ASSERT(t->scope == 0);
+
+ return Pointer(_stackLayout.stackSlotPointer(t->index));
+ }
- void loadArgumentInRegister(RegisterID source, RegisterID dest)
+ void loadArgumentInRegister(RegisterID source, RegisterID dest, int argumentNumber)
{
+ Q_UNUSED(argumentNumber);
+
move(source, dest);
}
- void loadArgumentInRegister(TrustedImmPtr ptr, RegisterID dest)
+ void loadArgumentInRegister(TrustedImmPtr ptr, RegisterID dest, int argumentNumber)
{
+ Q_UNUSED(argumentNumber);
+
move(TrustedImmPtr(ptr), dest);
}
- void loadArgumentInRegister(const Pointer& ptr, RegisterID dest)
+ void loadArgumentInRegister(const Pointer& ptr, RegisterID dest, int argumentNumber)
{
+ Q_UNUSED(argumentNumber);
addPtr(TrustedImm32(ptr.offset), ptr.base, dest);
}
- void loadArgumentInRegister(PointerToValue temp, RegisterID dest)
+ void loadArgumentInRegister(PointerToValue temp, RegisterID dest, int argumentNumber)
{
if (!temp.value) {
- loadArgumentInRegister(TrustedImmPtr(0), dest);
+ loadArgumentInRegister(TrustedImmPtr(0), dest, argumentNumber);
} else {
- Pointer addr = loadTempAddress(dest, temp.value);
- loadArgumentInRegister(addr, dest);
+ Pointer addr = toAddress(dest, temp.value, argumentNumber);
+ loadArgumentInRegister(addr, dest, argumentNumber);
}
}
- void loadArgumentInRegister(PointerToString temp, RegisterID dest)
+ void loadArgumentInRegister(PointerToString temp, RegisterID dest, int argumentNumber)
{
+ Q_UNUSED(argumentNumber);
Pointer addr = loadStringAddress(dest, temp.string);
loadPtr(addr, dest);
}
- void loadArgumentInRegister(Reference temp, RegisterID dest)
+ void loadArgumentInRegister(Reference temp, RegisterID dest, int argumentNumber)
{
assert(temp.value);
Pointer addr = loadTempAddress(dest, temp.value);
- loadArgumentInRegister(addr, dest);
+ loadArgumentInRegister(addr, dest, argumentNumber);
}
- void loadArgumentInRegister(ReentryBlock block, RegisterID dest)
+ void loadArgumentInRegister(ReentryBlock block, RegisterID dest, int argumentNumber)
{
+ Q_UNUSED(argumentNumber);
+
assert(block.block);
DataLabelPtr patch = moveWithPatch(TrustedImmPtr(0), dest);
addPatch(patch, block.block);
}
#ifdef VALUE_FITS_IN_REGISTER
- void loadArgumentInRegister(V4IR::Temp* temp, RegisterID dest)
+ void loadArgumentInRegister(V4IR::Temp* temp, RegisterID dest, int argumentNumber)
{
+ Q_UNUSED(argumentNumber);
+
if (!temp) {
QV4::Value undefined = QV4::Value::undefinedValue();
move(TrustedImm64(undefined.val), dest);
@@ -352,21 +497,25 @@ public:
}
}
- void loadArgumentInRegister(V4IR::Const* c, RegisterID dest)
+ void loadArgumentInRegister(V4IR::Const* c, RegisterID dest, int argumentNumber)
{
+ Q_UNUSED(argumentNumber);
+
QV4::Value v = convertToValue(c);
move(TrustedImm64(v.val), dest);
}
- void loadArgumentInRegister(V4IR::Expr* expr, RegisterID dest)
+ void loadArgumentInRegister(V4IR::Expr* expr, RegisterID dest, int argumentNumber)
{
+ Q_UNUSED(argumentNumber);
+
if (!expr) {
QV4::Value undefined = QV4::Value::undefinedValue();
move(TrustedImm64(undefined.val), dest);
} else if (expr->asTemp()){
- loadArgumentInRegister(expr->asTemp(), dest);
+ loadArgumentInRegister(expr->asTemp(), dest, argumentNumber);
} else if (expr->asConst()) {
- loadArgumentInRegister(expr->asConst(), dest);
+ loadArgumentInRegister(expr->asConst(), dest, argumentNumber);
} else {
assert(!"unimplemented expression type in loadArgument");
}
@@ -378,13 +527,15 @@ public:
}
#endif
- void loadArgumentInRegister(QV4::String* string, RegisterID dest)
+ void loadArgumentInRegister(QV4::String* string, RegisterID dest, int argumentNumber)
{
- loadArgumentInRegister(TrustedImmPtr(string), dest);
+ loadArgumentInRegister(TrustedImmPtr(string), dest, argumentNumber);
}
- void loadArgumentInRegister(TrustedImm32 imm32, RegisterID dest)
+ void loadArgumentInRegister(TrustedImm32 imm32, RegisterID dest, int argumentNumber)
{
+ Q_UNUSED(argumentNumber);
+
xorPtr(dest, dest);
if (imm32.m_value)
move(imm32, dest);
@@ -415,55 +566,64 @@ public:
}
template <int StackSlot>
- void loadArgumentOnStack(RegisterID reg)
+ void loadArgumentOnStack(RegisterID reg, int argumentNumber)
{
+ Q_UNUSED(argumentNumber);
+
poke(reg, StackSlot);
}
template <int StackSlot>
- void loadArgumentOnStack(TrustedImm32 value)
+ void loadArgumentOnStack(TrustedImm32 value, int argumentNumber)
{
+ Q_UNUSED(argumentNumber);
+
poke(value, StackSlot);
}
template <int StackSlot>
- void loadArgumentOnStack(const Pointer& ptr)
+ void loadArgumentOnStack(const Pointer& ptr, int argumentNumber)
{
+ Q_UNUSED(argumentNumber);
+
addPtr(TrustedImm32(ptr.offset), ptr.base, ScratchRegister);
poke(ScratchRegister, StackSlot);
}
template <int StackSlot>
- void loadArgumentOnStack(PointerToValue temp)
+ void loadArgumentOnStack(PointerToValue temp, int argumentNumber)
{
if (temp.value) {
- Pointer ptr = loadTempAddress(ScratchRegister, temp.value);
- loadArgumentOnStack<StackSlot>(ptr);
+ Pointer ptr = toAddress(ScratchRegister, temp.value, argumentNumber);
+ loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
} else {
poke(TrustedImmPtr(0), StackSlot);
}
}
template <int StackSlot>
- void loadArgumentOnStack(PointerToString temp)
+ void loadArgumentOnStack(PointerToString temp, int argumentNumber)
{
+ Q_UNUSED(argumentNumber);
Pointer ptr = loadStringAddress(ScratchRegister, temp.string);
loadPtr(ptr, ScratchRegister);
poke(ScratchRegister, StackSlot);
}
template <int StackSlot>
- void loadArgumentOnStack(Reference temp)
+ void loadArgumentOnStack(Reference temp, int argumentNumber)
{
assert (temp.value);
Pointer ptr = loadTempAddress(ScratchRegister, temp.value);
- loadArgumentOnStack<StackSlot>(ptr);
+ loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
}
template <int StackSlot>
- void loadArgumentOnStack(ReentryBlock block)
+ void loadArgumentOnStack(ReentryBlock block, int argumentNumber)
{
+ Q_UNUSED(argumentNumber);
+
assert(block.block);
DataLabelPtr patch = moveWithPatch(TrustedImmPtr(0), ScratchRegister);
poke(ScratchRegister, StackSlot);
@@ -471,15 +631,19 @@ public:
}
template <int StackSlot>
- void loadArgumentOnStack(TrustedImmPtr ptr)
+ void loadArgumentOnStack(TrustedImmPtr ptr, int argumentNumber)
{
+ Q_UNUSED(argumentNumber);
+
move(TrustedImmPtr(ptr), ScratchRegister);
poke(ScratchRegister, StackSlot);
}
template <int StackSlot>
- void loadArgumentOnStack(QV4::String* name)
+ void loadArgumentOnStack(QV4::String* name, int argumentNumber)
{
+ Q_UNUSED(argumentNumber);
+
poke(TrustedImmPtr(name), StackSlot);
}
@@ -515,20 +679,19 @@ public:
void storeValue(QV4::Value value, V4IR::Temp* temp);
- static int calculateStackFrameSize(int locals);
- void enterStandardStackFrame(int locals);
- void leaveStandardStackFrame(int locals);
+ void enterStandardStackFrame(bool withLocals);
+ void leaveStandardStackFrame(bool withLocals);
template <int argumentNumber, typename T>
void loadArgumentOnStackOrRegister(const T &value)
{
if (argumentNumber < RegisterArgumentCount)
- loadArgumentInRegister(value, registerForArgument(argumentNumber));
+ loadArgumentInRegister(value, registerForArgument(argumentNumber), argumentNumber);
else
#if OS(WINDOWS) && CPU(X86_64)
- loadArgumentOnStack<argumentNumber>(value);
+ loadArgumentOnStack<argumentNumber>(value, argumentNumber);
#else // Sanity:
- loadArgumentOnStack<argumentNumber - RegisterArgumentCount>(value);
+ loadArgumentOnStack<argumentNumber - RegisterArgumentCount>(value, argumentNumber);
#endif
}
@@ -636,8 +799,9 @@ public:
};
static const BinaryOperationInfo binaryOperations[QQmlJS::V4IR::LastAluOp + 1];
+ static const BinaryOperationInfo &binaryOperation(V4IR::AluOp operation)
+ { return binaryOperations[operation]; }
- void generateBinOp(V4IR::AluOp operation, V4IR::Temp* target, V4IR::Temp* left, V4IR::Temp* right);
Jump inline_add32(Address addr, RegisterID reg)
{
@@ -780,11 +944,178 @@ public:
return Jump();
}
+ Pointer toAddress(RegisterID tmpReg, V4IR::Expr *e, int offset)
+ {
+ if (V4IR::Const *c = e->asConst()) {
+ Address addr = _stackLayout.savedRegPointer(offset);
+ Address tagAddr = addr;
+ tagAddr.offset += 4;
+
+ QV4::Value v = convertToValue(c);
+ store32(TrustedImm32(v.int_32), addr);
+ store32(TrustedImm32(v.tag), tagAddr);
+ return Pointer(addr);
+ }
+
+ V4IR::Temp *t = e->asTemp();
+ Q_ASSERT(t);
+ if (t->kind != V4IR::Temp::PhysicalRegister)
+ return loadTempAddress(tmpReg, t);
+
+ Pointer addr(_stackLayout.savedRegPointer(offset));
+ switch (t->type) {
+ case V4IR::BoolType:
+ storeBool((RegisterID) t->index, addr);
+ break;
+ case V4IR::SInt32Type:
+ storeInt32((RegisterID) t->index, addr);
+ break;
+ case V4IR::UInt32Type:
+ storeUInt32((RegisterID) t->index, addr);
+ break;
+ case V4IR::DoubleType:
+ storeDouble((FPRegisterID) t->index, addr);
+ break;
+ default:
+ Q_UNIMPLEMENTED();
+ }
+
+ return addr;
+ }
+
+ void storeBool(RegisterID reg, Pointer addr)
+ {
+ store32(reg, addr);
+ addr.offset += 4;
+ store32(TrustedImm32(QV4::Value::fromBoolean(0).tag), addr);
+ }
+
+ void storeBool(RegisterID reg, V4IR::Temp *target)
+ {
+ if (target->kind == V4IR::Temp::PhysicalRegister) {
+ move(reg, (RegisterID) target->index);
+ } else if (target->kind == V4IR::Temp::StackSlot) {
+ Pointer addr = stackSlotPointer(target);
+ storeBool(reg, addr);
+ } else {
+ Q_UNIMPLEMENTED();
+ }
+ }
+
+ void storeBool(bool value, V4IR::Temp *target) {
+ TrustedImm32 trustedValue(value ? 1 : 0);
+ if (target->kind == V4IR::Temp::PhysicalRegister) {
+ move(trustedValue, (RegisterID) target->index);
+ } else {
+ move(trustedValue, ScratchRegister);
+ storeBool(ScratchRegister, target);
+ }
+ }
+
+ void storeInt32(RegisterID reg, Pointer addr)
+ {
+ store32(reg, addr);
+ addr.offset += 4;
+ store32(TrustedImm32(QV4::Value::fromInt32(0).tag), addr);
+ }
+
+ void storeInt32(RegisterID reg, V4IR::Temp *target)
+ {
+ if (target->kind == V4IR::Temp::PhysicalRegister) {
+ move(reg, (RegisterID) target->index);
+ } else if (target->kind == V4IR::Temp::StackSlot) {
+ Pointer addr = stackSlotPointer(target);
+ storeInt32(reg, addr);
+ } else {
+ Q_UNIMPLEMENTED();
+ }
+ }
+
+ void storeUInt32(RegisterID reg, Pointer addr)
+ {
+#if CPU(X86_64)
+ Q_ASSERT(reg != ScratchRegister);
+ Jump intRange = branch32(GreaterThanOrEqual, reg, TrustedImm32(0));
+ convertUInt32ToDouble(reg, FPGpr0, ScratchRegister);
+ storeDouble(FPGpr0, addr);
+ Jump done = jump();
+ intRange.link(this);
+ storeInt32(reg, addr);
+ done.link(this);
+#else
+ Q_ASSERT(!"Not supported on this platform!");
+#endif
+ }
+
+ FPRegisterID toDoubleRegister(V4IR::Expr *e, FPRegisterID target = FPGpr0)
+ {
+ if (V4IR::Const *c = e->asConst()) {
+ loadDouble(constantTable().loadValueAddress(c, ScratchRegister), target);
+ return target;
+ }
+
+ V4IR::Temp *t = e->asTemp();
+ Q_ASSERT(t);
+ if (t->kind == V4IR::Temp::PhysicalRegister)
+ return (FPRegisterID) t->index;
+
+ Q_ASSERT(t->kind == V4IR::Temp::StackSlot);
+ loadDouble(loadTempAddress(ScratchRegister, t), target);
+ return target;
+ }
+
+ RegisterID toInt32Register(V4IR::Expr *e, RegisterID scratchReg)
+ {
+ if (V4IR::Const *c = e->asConst()) {
+ move(TrustedImm32(convertToValue(c).int_32), scratchReg);
+ return scratchReg;
+ }
+
+ V4IR::Temp *t = e->asTemp();
+ Q_ASSERT(t);
+ if (t->kind == V4IR::Temp::PhysicalRegister)
+ return (RegisterID) t->index;
+
+ return toInt32Register(loadTempAddress(scratchReg, t), scratchReg);
+ }
+
+ RegisterID toInt32Register(Pointer addr, RegisterID scratchReg)
+ {
+ load32(addr, scratchReg);
+ return scratchReg;
+ }
+
+ RegisterID toUInt32Register(V4IR::Expr *e, RegisterID scratchReg)
+ {
+ if (V4IR::Const *c = e->asConst()) {
+ move(TrustedImm32(unsigned(c->value)), scratchReg);
+ return scratchReg;
+ }
+
+ V4IR::Temp *t = e->asTemp();
+ Q_ASSERT(t);
+ if (t->kind == V4IR::Temp::PhysicalRegister)
+ return (RegisterID) t->index;
+
+ return toUInt32Register(loadTempAddress(scratchReg, t), scratchReg);
+ }
+
+ RegisterID toUInt32Register(Pointer addr, RegisterID scratchReg)
+ {
+ load32(addr, scratchReg);
+ return scratchReg;
+ }
+
JSC::MacroAssemblerCodeRef link();
void recordLineNumber(int lineNumber);
+ const StackLayout stackLayout() const { return _stackLayout; }
+ ConstantTable &constantTable() { return _constTable; }
+
private:
+ const StackLayout _stackLayout;
+ ConstantTable _constTable;
V4IR::Function *_function;
QHash<V4IR::BasicBlock *, Label> _addrs;
QHash<V4IR::BasicBlock *, QVector<Jump> > _patches;
@@ -820,16 +1151,17 @@ public:
virtual void run(V4IR::Function *function);
+ void *addConstantTable(QVector<QV4::Value> *values);
protected:
virtual QV4::CompiledData::CompilationUnit *backendCompileStep();
virtual void callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result);
- virtual void callBuiltinTypeofMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
- virtual void callBuiltinTypeofSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
+ virtual void callBuiltinTypeofMember(V4IR::Expr *base, const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinTypeofSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *result);
virtual void callBuiltinTypeofName(const QString &name, V4IR::Temp *result);
- virtual void callBuiltinTypeofValue(V4IR::Temp *value, V4IR::Temp *result);
+ virtual void callBuiltinTypeofValue(V4IR::Expr *value, V4IR::Temp *result);
virtual void callBuiltinDeleteMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
- virtual void callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
+ virtual void callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Expr *index, V4IR::Temp *result);
virtual void callBuiltinDeleteName(const QString &name, V4IR::Temp *result);
virtual void callBuiltinDeleteValue(V4IR::Temp *result);
virtual void callBuiltinPostDecrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
@@ -840,7 +1172,7 @@ protected:
virtual void callBuiltinPostIncrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
virtual void callBuiltinPostIncrementName(const QString &name, V4IR::Temp *result);
virtual void callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR::Temp *result);
- virtual void callBuiltinThrow(V4IR::Temp *arg);
+ virtual void callBuiltinThrow(V4IR::Expr *arg);
virtual void callBuiltinFinishTry();
virtual void callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result);
virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result);
@@ -848,26 +1180,27 @@ protected:
virtual void callBuiltinPopScope();
virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
virtual void callBuiltinDefineGetterSetter(V4IR::Temp *object, const QString &name, V4IR::Temp *getter, V4IR::Temp *setter);
- virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value);
+ virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Expr *value);
virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args);
virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args);
virtual void callBuiltinSetupArgumentObject(V4IR::Temp *result);
virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
- virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
- virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void callProperty(V4IR::Expr *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::ExprList *args, V4IR::Temp *result);
virtual void convertType(V4IR::Temp *source, V4IR::Temp *target);
virtual void loadThisObject(V4IR::Temp *temp);
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp);
virtual void loadString(const QString &str, V4IR::Temp *targetTemp);
virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp);
virtual void getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp);
- virtual void setActivationProperty(V4IR::Temp *source, const QString &targetName);
+ virtual void setActivationProperty(V4IR::Expr *source, const QString &targetName);
virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target);
- virtual void getProperty(V4IR::Temp *base, const QString &name, V4IR::Temp *target);
- virtual void setProperty(V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName);
- virtual void getElement(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *target);
- virtual void setElement(V4IR::Temp *source, V4IR::Temp *targetBase, V4IR::Temp *targetIndex);
+ virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target);
+ virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName);
+ virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target);
+ virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex);
virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
+ virtual void swapValues(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
virtual void unop(V4IR::AluOp oper, V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
virtual void binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target);
virtual void inplaceNameOp(V4IR::AluOp oper, V4IR::Temp *rightSource, const QString &targetName);
@@ -885,19 +1218,9 @@ protected:
return Address(Assembler::StackFrameRegister, (index + 2) * sizeof(void*));
}
- // Some run-time functions take (Value* args, int argc). This function is for populating
- // the args.
- Pointer argumentAddressForCall(int argument)
- {
- const int index = _function->maxNumberOfArguments - argument;
- return Pointer(Assembler::LocalsRegister, sizeof(QV4::Value) * (-index)
- - sizeof(void*) // size of ebp
- - sizeof(void*) * Assembler::calleeSavedRegisterCount
- );
- }
Pointer baseAddressForCallArguments()
{
- return argumentAddressForCall(0);
+ return _as->stackLayout().argumentAddressForCall(0);
}
virtual void constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result);
@@ -910,6 +1233,48 @@ protected:
virtual void visitTry(V4IR::Try *);
private:
+ void convertIntToDouble(V4IR::Temp *source, V4IR::Temp *target)
+ {
+ if (target->kind == V4IR::Temp::PhysicalRegister) {
+ _as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister),
+ (Assembler::FPRegisterID) target->index);
+ } else if (target->kind == V4IR::Temp::StackSlot) {
+ _as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister),
+ Assembler::FPGpr0);
+ _as->storeDouble(Assembler::FPGpr0, _as->stackSlotPointer(target));
+ } else {
+ Q_UNIMPLEMENTED();
+ }
+ }
+
+ void convertUIntToDouble(V4IR::Temp *source, V4IR::Temp *target)
+ {
+ if (target->kind == V4IR::Temp::PhysicalRegister) {
+#if CPU(X86_64)
+ _as->convertUInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister),
+ (Assembler::FPRegisterID) target->index,
+ Assembler::ScratchRegister);
+#else
+ Q_ASSERT(!"Not supported on this platform!");
+#endif
+ } else {
+ Q_UNIMPLEMENTED();
+ }
+ }
+
+ void convertIntToBool(V4IR::Temp *source, V4IR::Temp *target)
+ {
+ if (target->kind == V4IR::Temp::PhysicalRegister) {
+ _as->storeBool(_as->toInt32Register(source, Assembler::ScratchRegister), target);
+ } else if (target->kind == V4IR::Temp::StackSlot) {
+ _as->move(_as->toInt32Register(source, Assembler::ScratchRegister),
+ Assembler::ScratchRegister);
+ _as->storeBool(Assembler::ScratchRegister, target);
+ } else {
+ Q_UNIMPLEMENTED();
+ }
+ }
+
#define isel_stringIfyx(s) #s
#define isel_stringIfy(s) isel_stringIfyx(s)
@@ -943,11 +1308,32 @@ private:
generateLookupCall(index, getterSetterOffset, arg1, Assembler::VoidType());
}
+ /// This is a temporary method, and will be removed when registers are fully supported.
+ void storeTarget(int argumentNumber, V4IR::Temp *target)
+ {
+ if (target->kind == V4IR::Temp::PhysicalRegister) {
+ Address addr = _as->stackLayout().savedRegPointer(argumentNumber);
+ if (target->type == V4IR::DoubleType)
+ _as->loadDouble(addr, (Assembler::FPRegisterID) target->index);
+ else if (target->type == V4IR::SInt32Type)
+ generateFunctionCall((Assembler::RegisterID) target->index,
+ QV4::__qmljs_value_to_int32,
+ Assembler::Pointer(addr));
+ else if (target->type == V4IR::UInt32Type)
+ generateFunctionCall((Assembler::RegisterID) target->index,
+ QV4::__qmljs_value_to_uint32,
+ Assembler::Pointer(addr));
+ else if (target->type == V4IR::BoolType)
+ _as->load32(addr, (Assembler::RegisterID) target->index);
+ else
+ Q_ASSERT(!"WIP!");
+ }
+ }
+
V4IR::BasicBlock *_block;
V4IR::Function* _function;
Assembler* _as;
QSet<V4IR::BasicBlock*> _reentryBlocks;
- int _locals;
CompilationUnit *compilationUnit;
QHash<V4IR::Function*, JSC::MacroAssemblerCodeRef> codeRefs;
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index affe8514b9..37772ca90f 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -317,7 +317,8 @@ void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4
addInstruction(call);
}
-void InstructionSelection::callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result)
+void InstructionSelection::callProperty(V4IR::Expr *base, const QString &name, V4IR::ExprList *args,
+ V4IR::Temp *result)
{
// call the property on the loaded base
Instruction::CallProperty call;
@@ -328,7 +329,8 @@ void InstructionSelection::callProperty(V4IR::Temp *base, const QString &name, V
addInstruction(call);
}
-void InstructionSelection::callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result)
+void InstructionSelection::callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::ExprList *args,
+ V4IR::Temp *result)
{
// call the property on the loaded base
Instruction::CallElement call;
@@ -422,7 +424,7 @@ void InstructionSelection::getActivationProperty(const V4IR::Name *name, V4IR::T
addInstruction(load);
}
-void InstructionSelection::setActivationProperty(V4IR::Temp *source, const QString &targetName)
+void InstructionSelection::setActivationProperty(V4IR::Expr *source, const QString &targetName)
{
Instruction::StoreName store;
store.source = getParam(source);
@@ -439,7 +441,7 @@ void InstructionSelection::initClosure(V4IR::Closure *closure, V4IR::Temp *targe
addInstruction(load);
}
-void InstructionSelection::getProperty(V4IR::Temp *base, const QString &name, V4IR::Temp *target)
+void InstructionSelection::getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target)
{
Instruction::LoadProperty load;
load.base = getParam(base);
@@ -448,7 +450,8 @@ void InstructionSelection::getProperty(V4IR::Temp *base, const QString &name, V4
addInstruction(load);
}
-void InstructionSelection::setProperty(V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName)
+void InstructionSelection::setProperty(V4IR::Expr *source, V4IR::Expr *targetBase,
+ const QString &targetName)
{
Instruction::StoreProperty store;
store.base = getParam(targetBase);
@@ -457,7 +460,7 @@ void InstructionSelection::setProperty(V4IR::Temp *source, V4IR::Temp *targetBas
addInstruction(store);
}
-void InstructionSelection::getElement(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *target)
+void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target)
{
Instruction::LoadElement load;
load.base = getParam(base);
@@ -466,7 +469,8 @@ void InstructionSelection::getElement(V4IR::Temp *base, V4IR::Temp *index, V4IR:
addInstruction(load);
}
-void InstructionSelection::setElement(V4IR::Temp *source, V4IR::Temp *targetBase, V4IR::Temp *targetIndex)
+void InstructionSelection::setElement(V4IR::Expr *source, V4IR::Expr *targetBase,
+ V4IR::Expr *targetIndex)
{
Instruction::StoreElement store;
store.base = getParam(targetBase);
@@ -487,6 +491,12 @@ void InstructionSelection::copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetT
addInstruction(move);
}
+void InstructionSelection::swapValues(V4IR::Temp *, V4IR::Temp *)
+{
+ // This is generated by the register allocator for the JIT, so it cannot end up here.
+ Q_UNREACHABLE();
+}
+
void InstructionSelection::unop(V4IR::AluOp oper, V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp)
{
QV4::UnaryOpName op = 0;
@@ -549,7 +559,7 @@ Param InstructionSelection::binopHelper(V4IR::AluOp oper, V4IR::Expr *leftSource
}
}
#else // !USE_TYPE_INFO
- Q_ASSERT(leftSource->asTemp() && rightSource->asTemp());
+ //Q_ASSERT(leftSource->asTemp() && rightSource->asTemp());
#endif // USE_TYPE_INFO
if (oper == V4IR::OpInstanceof || oper == V4IR::OpIn || oper == V4IR::OpAdd) {
@@ -758,7 +768,8 @@ void InstructionSelection::callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *
addInstruction(call);
}
-void InstructionSelection::callBuiltinTypeofMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
+void InstructionSelection::callBuiltinTypeofMember(V4IR::Expr *base, const QString &name,
+ V4IR::Temp *result)
{
Instruction::CallBuiltinTypeofMember call;
call.base = getParam(base);
@@ -767,7 +778,8 @@ void InstructionSelection::callBuiltinTypeofMember(V4IR::Temp *base, const QStri
addInstruction(call);
}
-void InstructionSelection::callBuiltinTypeofSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
+void InstructionSelection::callBuiltinTypeofSubscript(V4IR::Expr *base, V4IR::Expr *index,
+ V4IR::Temp *result)
{
Instruction::CallBuiltinTypeofSubscript call;
call.base = getParam(base);
@@ -784,7 +796,7 @@ void InstructionSelection::callBuiltinTypeofName(const QString &name, V4IR::Temp
addInstruction(call);
}
-void InstructionSelection::callBuiltinTypeofValue(V4IR::Temp *value, V4IR::Temp *result)
+void InstructionSelection::callBuiltinTypeofValue(V4IR::Expr *value, V4IR::Temp *result)
{
Instruction::CallBuiltinTypeofValue call;
call.value = getParam(value);
@@ -801,7 +813,8 @@ void InstructionSelection::callBuiltinDeleteMember(V4IR::Temp *base, const QStri
addInstruction(call);
}
-void InstructionSelection::callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
+void InstructionSelection::callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Expr *index,
+ V4IR::Temp *result)
{
Instruction::CallBuiltinDeleteSubscript call;
call.base = getParam(base);
@@ -894,7 +907,7 @@ void InstructionSelection::callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR
addInstruction(call);
}
-void InstructionSelection::callBuiltinThrow(V4IR::Temp *arg)
+void InstructionSelection::callBuiltinThrow(V4IR::Expr *arg)
{
Instruction::CallBuiltinThrow call;
call.arg = getParam(arg);
@@ -954,7 +967,8 @@ void InstructionSelection::callBuiltinDefineGetterSetter(V4IR::Temp *object, con
addInstruction(call);
}
-void InstructionSelection::callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value)
+void InstructionSelection::callBuiltinDefineProperty(V4IR::Temp *object, const QString &name,
+ V4IR::Expr *value)
{
Instruction::CallBuiltinDefineProperty call;
call.object = getParam(object);
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index c88db6f759..1b4d8b6d77 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -84,12 +84,12 @@ protected:
virtual void visitTry(V4IR::Try *);
virtual void callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result);
- virtual void callBuiltinTypeofMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
- virtual void callBuiltinTypeofSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
+ virtual void callBuiltinTypeofMember(V4IR::Expr *base, const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinTypeofSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *result);
virtual void callBuiltinTypeofName(const QString &name, V4IR::Temp *result);
- virtual void callBuiltinTypeofValue(V4IR::Temp *value, V4IR::Temp *result);
+ virtual void callBuiltinTypeofValue(V4IR::Expr *value, V4IR::Temp *result);
virtual void callBuiltinDeleteMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
- virtual void callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
+ virtual void callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Expr *index, V4IR::Temp *result);
virtual void callBuiltinDeleteName(const QString &name, V4IR::Temp *result);
virtual void callBuiltinDeleteValue(V4IR::Temp *result);
virtual void callBuiltinPostDecrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
@@ -100,7 +100,7 @@ protected:
virtual void callBuiltinPostIncrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
virtual void callBuiltinPostIncrementName(const QString &name, V4IR::Temp *result);
virtual void callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR::Temp *result);
- virtual void callBuiltinThrow(V4IR::Temp *arg);
+ virtual void callBuiltinThrow(V4IR::Expr *arg);
virtual void callBuiltinFinishTry();
virtual void callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result);
virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result);
@@ -108,13 +108,13 @@ protected:
virtual void callBuiltinPopScope();
virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
virtual void callBuiltinDefineGetterSetter(V4IR::Temp *object, const QString &name, V4IR::Temp *getter, V4IR::Temp *setter);
- virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value);
+ virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Expr *value);
virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args);
virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args);
virtual void callBuiltinSetupArgumentObject(V4IR::Temp *result);
virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
- virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
- virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void callProperty(V4IR::Expr *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::ExprList *args, V4IR::Temp *result);
virtual void convertType(V4IR::Temp *source, V4IR::Temp *target);
virtual void constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result);
virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
@@ -124,13 +124,14 @@ protected:
virtual void loadString(const QString &str, V4IR::Temp *targetTemp);
virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp);
virtual void getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp);
- virtual void setActivationProperty(V4IR::Temp *source, const QString &targetName);
+ virtual void setActivationProperty(V4IR::Expr *source, const QString &targetName);
virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target);
- virtual void getProperty(V4IR::Temp *base, const QString &name, V4IR::Temp *target);
- virtual void setProperty(V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName);
- virtual void getElement(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *target);
- virtual void setElement(V4IR::Temp *source, V4IR::Temp *targetBase, V4IR::Temp *targetIndex);
+ virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target);
+ virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName);
+ virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target);
+ virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex);
virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
+ virtual void swapValues(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
virtual void unop(V4IR::AluOp oper, V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
virtual void binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target);
virtual void inplaceNameOp(V4IR::AluOp oper, V4IR::Temp *rightSource, const QString &targetName);
diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp
index 96199b59d2..66f8ca5327 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -88,8 +88,8 @@ void IRDecoder::visitMove(V4IR::Move *s)
{
if (s->op == V4IR::OpInvalid) {
if (V4IR::Name *n = s->target->asName()) {
- if (s->source->asTemp()) {
- setActivationProperty(s->source->asTemp(), *n->id);
+ if (s->source->asTemp() || s->source->asConst()) {
+ setActivationProperty(s->source, *n->id);
return;
}
} else if (V4IR::Temp *t = s->target->asTemp()) {
@@ -103,7 +103,10 @@ void IRDecoder::visitMove(V4IR::Move *s)
loadConst(c, t);
return;
} else if (V4IR::Temp *t2 = s->source->asTemp()) {
- copyValue(t2, t);
+ if (s->swap)
+ swapValues(t2, t);
+ else
+ copyValue(t2, t);
return;
} else if (V4IR::String *str = s->source->asString()) {
loadString(*str->value, t);
@@ -126,12 +129,12 @@ void IRDecoder::visitMove(V4IR::Move *s)
return;
}
} else if (V4IR::Member *m = s->source->asMember()) {
- if (V4IR::Temp *base = m->base->asTemp()) {
- getProperty(base, *m->name, t);
+ if (m->base->asTemp() || m->base->asConst()) {
+ getProperty(m->base, *m->name, t);
return;
}
} else if (V4IR::Subscript *ss = s->source->asSubscript()) {
- getElement(ss->base->asTemp(), ss->index->asTemp(), t);
+ getElement(ss->base->asTemp(), ss->index, t);
return;
} else if (V4IR::Unop *u = s->source->asUnop()) {
if (V4IR::Temp *e = u->expr->asTemp()) {
@@ -146,13 +149,10 @@ void IRDecoder::visitMove(V4IR::Move *s)
callBuiltin(c, t);
return;
} else if (Member *member = c->base->asMember()) {
- Q_ASSERT(member->base->asTemp());
- callProperty(member->base->asTemp(), *member->name, c->args, t);
+ callProperty(member->base, *member->name, c->args, t);
return;
- } else if (Subscript *s = c->base->asSubscript()) {
- Q_ASSERT(s->base->asTemp());
- Q_ASSERT(s->index->asTemp());
- callSubscript(s->base->asTemp(), s->index->asTemp(), c->args, t);
+ } else if (Subscript *ss = c->base->asSubscript()) {
+ callSubscript(ss->base, ss->index, c->args, t);
return;
} else if (V4IR::Temp *value = c->base->asTemp()) {
callValue(value, c->args, t);
@@ -164,15 +164,15 @@ void IRDecoder::visitMove(V4IR::Move *s)
return;
}
} else if (V4IR::Member *m = s->target->asMember()) {
- if (V4IR::Temp *base = m->base->asTemp()) {
- if (s->source->asTemp()) {
- setProperty(s->source->asTemp(), base, *m->name);
+ if (m->base->asTemp() || m->base->asConst()) {
+ if (s->source->asTemp() || s->source->asConst()) {
+ setProperty(s->source, m->base, *m->name);
return;
}
}
} else if (V4IR::Subscript *ss = s->target->asSubscript()) {
- if (s->source->asTemp()) {
- setElement(s->source->asTemp(), ss->base->asTemp(), ss->index->asTemp());
+ if (s->source->asTemp() || s->source->asConst()) {
+ setElement(s->source, ss->base, ss->index);
return;
}
}
@@ -248,17 +248,16 @@ void IRDecoder::callBuiltin(V4IR::Call *call, V4IR::Temp *result)
case V4IR::Name::builtin_typeof: {
if (V4IR::Member *m = call->args->expr->asMember()) {
- callBuiltinTypeofMember(m->base->asTemp(), *m->name, result);
+ callBuiltinTypeofMember(m->base, *m->name, result);
return;
} else if (V4IR::Subscript *ss = call->args->expr->asSubscript()) {
- callBuiltinTypeofSubscript(ss->base->asTemp(), ss->index->asTemp(), result);
+ callBuiltinTypeofSubscript(ss->base, ss->index, result);
return;
} else if (V4IR::Name *n = call->args->expr->asName()) {
callBuiltinTypeofName(*n->id, result);
return;
- } else if (V4IR::Temp *arg = call->args->expr->asTemp()){
- assert(arg != 0);
- callBuiltinTypeofValue(arg, result);
+ } else if (call->args->expr->asTemp() || call->args->expr->asConst()){
+ callBuiltinTypeofValue(call->args->expr, result);
return;
}
} break;
@@ -268,7 +267,7 @@ void IRDecoder::callBuiltin(V4IR::Call *call, V4IR::Temp *result)
callBuiltinDeleteMember(m->base->asTemp(), *m->name, result);
return;
} else if (V4IR::Subscript *ss = call->args->expr->asSubscript()) {
- callBuiltinDeleteSubscript(ss->base->asTemp(), ss->index->asTemp(), result);
+ callBuiltinDeleteSubscript(ss->base->asTemp(), ss->index, result);
return;
} else if (V4IR::Name *n = call->args->expr->asName()) {
callBuiltinDeleteName(*n->id, result);
@@ -315,8 +314,8 @@ void IRDecoder::callBuiltin(V4IR::Call *call, V4IR::Temp *result)
} break;
case V4IR::Name::builtin_throw: {
- V4IR::Temp *arg = call->args->expr->asTemp();
- assert(arg != 0);
+ V4IR::Expr *arg = call->args->expr;
+ assert(arg->asTemp() || arg->asConst());
callBuiltinThrow(arg);
} return;
@@ -387,7 +386,7 @@ void IRDecoder::callBuiltin(V4IR::Call *call, V4IR::Temp *result)
V4IR::Name *name = args->expr->asName();
args = args->next;
assert(args);
- V4IR::Temp *value = args->expr->asTemp();
+ V4IR::Expr *value = args->expr;
callBuiltinDefineProperty(object, *name->id, value);
} return;
diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h
index 6f4b042a09..ef601cd152 100644
--- a/src/qml/compiler/qv4isel_p.h
+++ b/src/qml/compiler/qv4isel_p.h
@@ -100,12 +100,12 @@ public: // visitor methods for StmtVisitor:
public: // to implement by subclasses:
virtual void callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result) = 0;
- virtual void callBuiltinTypeofMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result) = 0;
- virtual void callBuiltinTypeofSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result) = 0;
+ virtual void callBuiltinTypeofMember(V4IR::Expr *base, const QString &name, V4IR::Temp *result) = 0;
+ virtual void callBuiltinTypeofSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *result) = 0;
virtual void callBuiltinTypeofName(const QString &name, V4IR::Temp *result) = 0;
- virtual void callBuiltinTypeofValue(V4IR::Temp *value, V4IR::Temp *result) = 0;
+ virtual void callBuiltinTypeofValue(V4IR::Expr *value, V4IR::Temp *result) = 0;
virtual void callBuiltinDeleteMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result) = 0;
- virtual void callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result) = 0;
+ virtual void callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Expr *index, V4IR::Temp *result) = 0;
virtual void callBuiltinDeleteName(const QString &name, V4IR::Temp *result) = 0;
virtual void callBuiltinDeleteValue(V4IR::Temp *result) = 0;
virtual void callBuiltinPostDecrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result) = 0;
@@ -116,7 +116,7 @@ public: // to implement by subclasses:
virtual void callBuiltinPostIncrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result) = 0;
virtual void callBuiltinPostIncrementName(const QString &name, V4IR::Temp *result) = 0;
virtual void callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR::Temp *result) = 0;
- virtual void callBuiltinThrow(V4IR::Temp *arg) = 0;
+ virtual void callBuiltinThrow(V4IR::Expr *arg) = 0;
virtual void callBuiltinFinishTry() = 0;
virtual void callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result) = 0;
virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result) = 0;
@@ -124,13 +124,13 @@ public: // to implement by subclasses:
virtual void callBuiltinPopScope() = 0;
virtual void callBuiltinDeclareVar(bool deletable, const QString &name) = 0;
virtual void callBuiltinDefineGetterSetter(V4IR::Temp *object, const QString &name, V4IR::Temp *getter, V4IR::Temp *setter) = 0;
- virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value) = 0;
+ virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Expr *value) = 0;
virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args) = 0;
virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args) = 0;
virtual void callBuiltinSetupArgumentObject(V4IR::Temp *result) = 0;
virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) = 0;
- virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result) = 0;
- virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result) = 0;
+ virtual void callProperty(V4IR::Expr *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result) = 0;
+ virtual void callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::ExprList *args, V4IR::Temp *result) = 0;
virtual void convertType(V4IR::Temp *source, V4IR::Temp *target) = 0;
virtual void constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result) = 0;
virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result) = 0;
@@ -140,13 +140,14 @@ public: // to implement by subclasses:
virtual void loadString(const QString &str, V4IR::Temp *targetTemp) = 0;
virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp) = 0;
virtual void getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp) = 0;
- virtual void setActivationProperty(V4IR::Temp *source, const QString &targetName) = 0;
+ virtual void setActivationProperty(V4IR::Expr *source, const QString &targetName) = 0;
virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target) = 0;
- virtual void getProperty(V4IR::Temp *base, const QString &name, V4IR::Temp *target) = 0;
- virtual void setProperty(V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName) = 0;
- virtual void getElement(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *target) = 0;
- virtual void setElement(V4IR::Temp *source, V4IR::Temp *targetBase, V4IR::Temp *targetIndex) = 0;
+ virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target) = 0;
+ virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName) = 0;
+ virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target) = 0;
+ virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex) = 0;
virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp) = 0;
+ virtual void swapValues(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp) = 0;
virtual void unop(V4IR::AluOp oper, V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp) = 0;
virtual void binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target) = 0;
virtual void inplaceNameOp(V4IR::AluOp oper, V4IR::Temp *rightSource, const QString &targetName) = 0;
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index 74445cc2c8..5ad5cf0131 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -947,10 +947,8 @@ void BasicBlock::dump(QTextStream &out, Stmt::Mode mode)
void BasicBlock::appendStatement(Stmt *statement)
{
- if (nextLocation.isValid()) {
+ if (nextLocation.isValid())
statement->location = nextLocation;
- nextLocation = AST::SourceLocation();
- }
statements.append(statement);
}
diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp
index a43baaea27..9b3a427c95 100644
--- a/src/qml/compiler/qv4regalloc.cpp
+++ b/src/qml/compiler/qv4regalloc.cpp
@@ -175,12 +175,12 @@ public:
protected: // IRDecoder
virtual void callBuiltinInvalid(V4IR::Name *, V4IR::ExprList *, V4IR::Temp *) {}
- virtual void callBuiltinTypeofMember(V4IR::Temp *, const QString &, V4IR::Temp *) {}
- virtual void callBuiltinTypeofSubscript(V4IR::Temp *, V4IR::Temp *, V4IR::Temp *) {}
+ virtual void callBuiltinTypeofMember(V4IR::Expr *, const QString &, V4IR::Temp *) {}
+ virtual void callBuiltinTypeofSubscript(V4IR::Expr *, V4IR::Expr *, V4IR::Temp *) {}
virtual void callBuiltinTypeofName(const QString &, V4IR::Temp *) {}
- virtual void callBuiltinTypeofValue(V4IR::Temp *, V4IR::Temp *) {}
+ virtual void callBuiltinTypeofValue(V4IR::Expr *, V4IR::Temp *) {}
virtual void callBuiltinDeleteMember(V4IR::Temp *, const QString &, V4IR::Temp *) {}
- virtual void callBuiltinDeleteSubscript(V4IR::Temp *, V4IR::Temp *, V4IR::Temp *) {}
+ virtual void callBuiltinDeleteSubscript(V4IR::Temp *, V4IR::Expr *, V4IR::Temp *) {}
virtual void callBuiltinDeleteName(const QString &, V4IR::Temp *) {}
virtual void callBuiltinDeleteValue(V4IR::Temp *) {}
virtual void callBuiltinPostDecrementMember(V4IR::Temp *, const QString &, V4IR::Temp *) {}
@@ -191,7 +191,7 @@ protected: // IRDecoder
virtual void callBuiltinPostIncrementSubscript(V4IR::Temp *, V4IR::Temp *, V4IR::Temp *) {}
virtual void callBuiltinPostIncrementName(const QString &, V4IR::Temp *) {}
virtual void callBuiltinPostIncrementValue(V4IR::Temp *, V4IR::Temp *) {}
- virtual void callBuiltinThrow(V4IR::Temp *) {}
+ virtual void callBuiltinThrow(V4IR::Expr *) {}
virtual void callBuiltinFinishTry() {}
virtual void callBuiltinForeachIteratorObject(V4IR::Temp *, V4IR::Temp *) {}
virtual void callBuiltinForeachNextProperty(V4IR::Temp *, V4IR::Temp *) {}
@@ -200,7 +200,7 @@ protected: // IRDecoder
virtual void callBuiltinPopScope() {}
virtual void callBuiltinDeclareVar(bool , const QString &) {}
virtual void callBuiltinDefineGetterSetter(V4IR::Temp *, const QString &, V4IR::Temp *, V4IR::Temp *) {}
- virtual void callBuiltinDefineProperty(V4IR::Temp *, const QString &, V4IR::Temp *) {}
+ virtual void callBuiltinDefineProperty(V4IR::Temp *, const QString &, V4IR::Expr *) {}
virtual void callBuiltinDefineArray(V4IR::Temp *, V4IR::ExprList *) {}
virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *, V4IR::ExprList *) {}
virtual void callBuiltinSetupArgumentObject(V4IR::Temp *) {}
@@ -213,19 +213,21 @@ protected: // IRDecoder
addCall();
}
- virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result)
+ virtual void callProperty(V4IR::Expr *base, const QString &name, V4IR::ExprList *args,
+ V4IR::Temp *result)
{
addDef(result);
- addUses(base, Use::CouldHaveRegister);
+ addUses(base->asTemp(), Use::CouldHaveRegister);
addUses(args, Use::CouldHaveRegister);
addCall();
}
- virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result)
+ virtual void callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::ExprList *args,
+ V4IR::Temp *result)
{
addDef(result);
- addUses(base, Use::CouldHaveRegister);
- addUses(index, Use::CouldHaveRegister);
+ addUses(base->asTemp(), Use::CouldHaveRegister);
+ addUses(index->asTemp(), Use::CouldHaveRegister);
addUses(args, Use::CouldHaveRegister);
addCall();
}
@@ -238,6 +240,7 @@ protected: // IRDecoder
bool needsCall = true;
Use::RegisterFlag sourceReg = Use::CouldHaveRegister;
+#if 0 // TODO: change masm to generate code
// TODO: verify this method
switch (target->type) {
case DoubleType:
@@ -265,6 +268,7 @@ protected: // IRDecoder
default:
break;
}
+#endif
addUses(source, sourceReg);
@@ -325,9 +329,9 @@ protected: // IRDecoder
addCall();
}
- virtual void setActivationProperty(V4IR::Temp *source, const QString &)
+ virtual void setActivationProperty(V4IR::Expr *source, const QString &)
{
- addUses(source, Use::CouldHaveRegister);
+ addUses(source->asTemp(), Use::CouldHaveRegister);
addCall();
}
@@ -337,33 +341,33 @@ protected: // IRDecoder
addCall();
}
- virtual void getProperty(V4IR::Temp *base, const QString &, V4IR::Temp *target)
+ virtual void getProperty(V4IR::Expr *base, const QString &, V4IR::Temp *target)
{
addDef(target);
- addUses(base, Use::CouldHaveRegister);
+ addUses(base->asTemp(), Use::CouldHaveRegister);
addCall();
}
- virtual void setProperty(V4IR::Temp *source, V4IR::Temp *targetBase, const QString &)
+ virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &)
{
- addUses(source, Use::CouldHaveRegister);
- addUses(targetBase, Use::CouldHaveRegister);
+ addUses(source->asTemp(), Use::CouldHaveRegister);
+ addUses(targetBase->asTemp(), Use::CouldHaveRegister);
addCall();
}
- virtual void getElement(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *target)
+ virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target)
{
addDef(target);
- addUses(base, Use::CouldHaveRegister);
- addUses(index, Use::CouldHaveRegister);
+ addUses(base->asTemp(), Use::CouldHaveRegister);
+ addUses(index->asTemp(), Use::CouldHaveRegister);
addCall();
}
- virtual void setElement(V4IR::Temp *source, V4IR::Temp *targetBase, V4IR::Temp *targetIndex)
+ virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex)
{
- addUses(source, Use::CouldHaveRegister);
- addUses(targetBase, Use::CouldHaveRegister);
- addUses(targetIndex, Use::CouldHaveRegister);
+ addUses(source->asTemp(), Use::CouldHaveRegister);
+ addUses(targetBase->asTemp(), Use::CouldHaveRegister);
+ addUses(targetIndex->asTemp(), Use::CouldHaveRegister);
addCall();
}
@@ -385,6 +389,7 @@ protected: // IRDecoder
addDef(targetTemp);
bool needsCall = true;
+#if 0 // TODO: change masm to generate code
switch (oper) {
case OpIfTrue:
case OpNot:
@@ -399,8 +404,10 @@ protected: // IRDecoder
default:
Q_UNREACHABLE();
}
+#endif
if (needsCall) {
+ addUses(sourceTemp, Use::CouldHaveRegister);
addCall();
} else {
addUses(sourceTemp, Use::MustHaveRegister);
@@ -411,6 +418,7 @@ protected: // IRDecoder
{
bool needsCall = true;
+#if 0 // TODO: change masm to generate code
switch (leftSource->type) {
case DoubleType:
case SInt32Type:
@@ -427,6 +435,7 @@ protected: // IRDecoder
default:
break;
}
+#endif
addDef(target);
@@ -472,9 +481,18 @@ protected: // IRDecoder
virtual void visitCJump(V4IR::CJump *s)
{
if (Temp *t = s->cond->asTemp()) {
+#if 0 // TODO: change masm to generate code
addUses(t, Use::MustHaveRegister);
+#else
+ addUses(t, Use::CouldHaveRegister);
+ addCall();
+#endif
} else if (Binop *b = s->cond->asBinop()) {
binop(b->op, b->left, b->right, 0);
+ } else if (Const *c = s->cond->asConst()) {
+ // TODO: SSA optimization for constant condition evaluation should remove this.
+ // See also visitCJump() in masm.
+ addCall();
} else {
Q_UNREACHABLE();
}
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 21161f9881..0b663288ab 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -142,10 +142,14 @@ void showMeTheCode(Function *function)
if (s->id > 0)
out << s->id << ": ";
s->dump(out, Stmt::MIR);
- out.flush();
+ if (s->location.isValid()) {
+ out.flush();
+ for (int i = 58 - str.length(); i > 0; --i)
+ out << ' ';
+ out << " // line: " << s->location.startLine << " column: " << s->location.startColumn;
+ }
- if (s->location.isValid())
- qout << " // line: " << s->location.startLine << " column: " << s->location.startColumn << endl;
+ out.flush();
#ifndef QV4_NO_LIVENESS
for (int i = 60 - str.size(); i >= 0; --i)
@@ -2602,7 +2606,7 @@ void Optimizer::run()
// showMeTheCode(function);
// qout << "Running SSA optimization..." << endl;
-// optimizeSSA(function, defUses);
+ optimizeSSA(function, defUses);
// showMeTheCode(function);
// qout << "Running type inference..." << endl;
@@ -2630,8 +2634,23 @@ void Optimizer::run()
namespace {
void insertMove(Function *function, BasicBlock *basicBlock, Temp *target, Expr *source) {
- if (target->type != source->type)
+ if (target->type != source->type) {
+ if (source->asConst()) {
+ const int idx = function->tempCount++;
+
+ Temp *tmp = function->New<Temp>();
+ tmp->init(Temp::VirtualRegister, idx, 0);
+
+ Move *s = function->New<Move>();
+ s->init(tmp, source, OpInvalid);
+ basicBlock->statements.insert(basicBlock->statements.size() - 1, s);
+
+ tmp = function->New<Temp>();
+ tmp->init(Temp::VirtualRegister, idx, 0);
+ source = tmp;
+ }
source = basicBlock->CONVERT(source, target->type);
+ }
Move *s = function->New<Move>();
s->init(target, source, OpInvalid);
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 64345559e5..5f043347dd 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -932,7 +932,8 @@ void __qmljs_builtin_typeof_name(ExecutionContext *context, Value *result, Strin
*result = res;
}
-void __qmljs_builtin_typeof_member(ExecutionContext *context, Value *result, const Value &base, String *name)
+void __qmljs_builtin_typeof_member(ExecutionContext *context, Value *result, const Value &base,
+ String *name)
{
Object *obj = base.toObject(context);
Value res;
@@ -941,7 +942,8 @@ void __qmljs_builtin_typeof_member(ExecutionContext *context, Value *result, con
*result = res;
}
-void __qmljs_builtin_typeof_element(ExecutionContext *context, Value *result, const Value &base, const Value &index)
+void __qmljs_builtin_typeof_element(ExecutionContext *context, Value *result, const Value &base,
+ const Value &index)
{
String *name = index.toString(context);
Object *obj = base.toObject(context);
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index 5f3f45263c..4ae28ab094 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -158,7 +158,7 @@ void __qmljs_foreach_next_property_name(QV4::Value *result, const QV4::Value &fo
// type conversion and testing
QV4::Value __qmljs_to_primitive(const QV4::Value &value, int typeHint);
-QV4::Bool __qmljs_to_boolean(const QV4::Value &value);
+Q_QML_EXPORT QV4::Bool __qmljs_to_boolean(const QV4::Value &value);
double __qmljs_to_number(const QV4::Value &value);
QV4::Value __qmljs_to_string(const QV4::Value &value, QV4::ExecutionContext *ctx);
Q_QML_EXPORT QV4::String *__qmljs_convert_to_string(QV4::ExecutionContext *ctx, const QV4::Value &value);
@@ -178,6 +178,11 @@ void __qmljs_not(QV4::Value *result, const QV4::Value &value);
void __qmljs_increment(QV4::Value *result, const QV4::Value &value);
void __qmljs_decrement(QV4::Value *result, const QV4::Value &value);
+Q_QML_EXPORT int __qmljs_value_to_int32(const Value &value);
+Q_QML_EXPORT int __qmljs_double_to_int32(double d);
+Q_QML_EXPORT unsigned __qmljs_value_to_uint32(const Value &value);
+Q_QML_EXPORT unsigned __qmljs_double_to_uint32(double d);
+
void __qmljs_delete_subscript(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &base, const QV4::Value &index);
void __qmljs_delete_member(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &base, QV4::String *name);
void __qmljs_delete_name(QV4::ExecutionContext *ctx, QV4::Value *result, QV4::String *name);