The fast and the furious, register drift.
authorErik Verbruggen <erik.verbruggen@digia.com>
Fri, 23 Aug 2013 12:40:33 +0000 (14:40 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Tue, 27 Aug 2013 11:55:24 +0000 (13:55 +0200)
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>
12 files changed:
src/qml/compiler/qv4isel_masm.cpp
src/qml/compiler/qv4isel_masm_p.h
src/qml/compiler/qv4isel_moth.cpp
src/qml/compiler/qv4isel_moth_p.h
src/qml/compiler/qv4isel_p.cpp
src/qml/compiler/qv4isel_p.h
src/qml/compiler/qv4jsir.cpp
src/qml/compiler/qv4regalloc.cpp
src/qml/compiler/qv4ssa.cpp
src/qml/jsruntime/qv4runtime.cpp
src/qml/jsruntime/qv4runtime_p.h
tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp

index 1da78b5..e6735b0 100644 (file)
@@ -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);
+}
index 84ceb2b..ef79e35 100644 (file)
@@ -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;
index affe851..37772ca 100644 (file)
@@ -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);
index c88db6f..1b4d8b6 100644 (file)
@@ -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);
index 96199b5..66f8ca5 100644 (file)
@@ -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;
index 6f4b042..ef601cd 100644 (file)
@@ -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;
index 74445cc..5ad5cf0 100644 (file)
@@ -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);
 }
 
index a43baae..9b3a427 100644 (file)
@@ -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();
         }
index 21161f9..0b66328 100644 (file)
@@ -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);
index 6434555..5f04334 100644 (file)
@@ -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);
index 5f3f452..4ae28ab 100644 (file)
@@ -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);
index 852034c..ec5eaf2 100644 (file)
@@ -843,7 +843,7 @@ void tst_qqmllanguage::bindJSValueToVar()
     QCOMPARE(object->property("test15").userType(), (int)QVariant::SizeF);
     QCOMPARE(object->property("test16").userType(), (int)QVariant::Vector3D);
     QCOMPARE(object->property("test1Bound").userType(), (int)QVariant::Int);
-    QCOMPARE(object->property("test20Bound").userType(), (int)QVariant::Int);
+    QCOMPARE(object->property("test20Bound").userType(), (int)QVariant::Double);
 
     QCOMPARE(object->property("test1"), QVariant(5));
     QCOMPARE(object->property("test2"), QVariant((double)1.7));
@@ -892,7 +892,7 @@ void tst_qqmllanguage::bindJSValueToVariant()
     QCOMPARE(object->property("test15").userType(), (int)QVariant::SizeF);
     QCOMPARE(object->property("test16").userType(), (int)QVariant::Vector3D);
     QCOMPARE(object->property("test1Bound").userType(), (int)QVariant::Int);
-    QCOMPARE(object->property("test20Bound").userType(), (int)QVariant::Int);
+    QCOMPARE(object->property("test20Bound").userType(), (int)QVariant::Double);
 
     QCOMPARE(object->property("test1"), QVariant(5));
     QCOMPARE(object->property("test2"), QVariant((double)1.7));