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