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