diff options
Diffstat (limited to 'src/qml/compiler/qv4isel_moth.cpp')
-rw-r--r-- | src/qml/compiler/qv4isel_moth.cpp | 226 |
1 files changed, 179 insertions, 47 deletions
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index e84b9c6ec9..ca6319ef3c 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -46,6 +46,7 @@ #include <private/qv4regexpobject_p.h> #include <private/qv4compileddata_p.h> #include <private/qqmlengine_p.h> +#include <wtf/MathExtras.h> #undef USE_TYPE_INFO @@ -54,7 +55,7 @@ using namespace QV4::Moth; namespace { -inline QV4::Runtime::BinaryOperation aluOpFunction(IR::AluOp op) +inline uint aluOpFunction(IR::AluOp op) { switch (op) { case IR::OpInvalid: @@ -70,43 +71,43 @@ inline QV4::Runtime::BinaryOperation aluOpFunction(IR::AluOp op) case IR::OpCompl: return 0; case IR::OpBitAnd: - return QV4::Runtime::bitAnd; + return offsetof(QV4::Runtime, bitAnd); case IR::OpBitOr: - return QV4::Runtime::bitOr; + return offsetof(QV4::Runtime, bitOr); case IR::OpBitXor: - return QV4::Runtime::bitXor; + return offsetof(QV4::Runtime, bitXor); case IR::OpAdd: return 0; case IR::OpSub: - return QV4::Runtime::sub; + return offsetof(QV4::Runtime, sub); case IR::OpMul: - return QV4::Runtime::mul; + return offsetof(QV4::Runtime, mul); case IR::OpDiv: - return QV4::Runtime::div; + return offsetof(QV4::Runtime, div); case IR::OpMod: - return QV4::Runtime::mod; + return offsetof(QV4::Runtime, mod); case IR::OpLShift: - return QV4::Runtime::shl; + return offsetof(QV4::Runtime, shl); case IR::OpRShift: - return QV4::Runtime::shr; + return offsetof(QV4::Runtime, shr); case IR::OpURShift: - return QV4::Runtime::ushr; + return offsetof(QV4::Runtime, ushr); case IR::OpGt: - return QV4::Runtime::greaterThan; + return offsetof(QV4::Runtime, greaterThan); case IR::OpLt: - return QV4::Runtime::lessThan; + return offsetof(QV4::Runtime, lessThan); case IR::OpGe: - return QV4::Runtime::greaterEqual; + return offsetof(QV4::Runtime, greaterEqual); case IR::OpLe: - return QV4::Runtime::lessEqual; + return offsetof(QV4::Runtime, lessEqual); case IR::OpEqual: - return QV4::Runtime::equal; + return offsetof(QV4::Runtime, equal); case IR::OpNotEqual: - return QV4::Runtime::notEqual; + return offsetof(QV4::Runtime, notEqual); case IR::OpStrictEqual: - return QV4::Runtime::strictEqual; + return offsetof(QV4::Runtime, strictEqual); case IR::OpStrictNotEqual: - return QV4::Runtime::strictNotEqual; + return offsetof(QV4::Runtime, strictNotEqual); case IR::OpInstanceof: return 0; case IR::OpIn: @@ -151,8 +152,8 @@ inline bool isBoolType(IR::Expr *e) } // anonymous namespace -InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) - : EvalInstructionSelection(execAllocator, module, jsGenerator) +InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory) + : EvalInstructionSelection(execAllocator, module, jsGenerator, iselFactory) , qmlEngine(qmlEngine) , _block(0) , _codeStart(0) @@ -250,6 +251,7 @@ void InstructionSelection::run(int functionIndex) if (s->location.startLine != currentLine) { blockNeedsDebugInstruction = false; currentLine = s->location.startLine; +#ifndef QT_NO_QML_DEBUGGER if (irModule->debugMode) { Instruction::Debug debug; debug.lineNumber = currentLine; @@ -259,10 +261,11 @@ void InstructionSelection::run(int functionIndex) line.lineNumber = currentLine; addInstruction(line); } +#endif } } - s->accept(this); + visit(s); } } @@ -576,18 +579,20 @@ void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *target addInstruction(store); } -void InstructionSelection::getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target) +void InstructionSelection::getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, bool captureRequired, IR::Expr *target) { if (kind == IR::Member::MemberOfQmlScopeObject) { Instruction::LoadScopeObjectProperty load; load.base = getParam(source); load.propertyIndex = index; + load.captureRequired = captureRequired; load.result = getResultParam(target); addInstruction(load); } else if (kind == IR::Member::MemberOfQmlContextObject) { Instruction::LoadContextObjectProperty load; load.base = getParam(source); load.propertyIndex = index; + load.captureRequired = captureRequired; load.result = getResultParam(target); addInstruction(load); } else if (kind == IR::Member::MemberOfIdObjectsArray) { @@ -879,11 +884,11 @@ Param InstructionSelection::binopHelper(IR::AluOp oper, IR::Expr *leftSource, IR if (oper == IR::OpInstanceof || oper == IR::OpIn || oper == IR::OpAdd) { Instruction::BinopContext binop; if (oper == IR::OpInstanceof) - binop.alu = QV4::Runtime::instanceof; + binop.alu = offsetof(QV4::Runtime, instanceof); else if (oper == IR::OpIn) - binop.alu = QV4::Runtime::in; + binop.alu = offsetof(QV4::Runtime, in); else - binop.alu = QV4::Runtime::add; + binop.alu = offsetof(QV4::Runtime, add); binop.lhs = getParam(leftSource); binop.rhs = getParam(rightSource); binop.result = getResultParam(target); @@ -930,6 +935,17 @@ void InstructionSelection::prepareCallArgs(IR::ExprList *e, quint32 &argc, quint } } +void InstructionSelection::addDebugInstruction() +{ +#ifndef QT_NO_QML_DEBUGGER + if (blockNeedsDebugInstruction) { + Instruction::Debug debug; + debug.lineNumber = -int(currentLine); + addInstruction(debug); + } +#endif +} + void InstructionSelection::visitJump(IR::Jump *s) { if (s->target == _nextBlock) @@ -937,11 +953,7 @@ void InstructionSelection::visitJump(IR::Jump *s) if (_removableJumps.contains(s)) return; - if (blockNeedsDebugInstruction) { - Instruction::Debug debug; - debug.lineNumber = -int(currentLine); - addInstruction(debug); - } + addDebugInstruction(); Instruction::Jump jump; jump.offset = 0; @@ -952,11 +964,7 @@ void InstructionSelection::visitJump(IR::Jump *s) void InstructionSelection::visitCJump(IR::CJump *s) { - if (blockNeedsDebugInstruction) { - Instruction::Debug debug; - debug.lineNumber = -int(currentLine); - addInstruction(debug); - } + addDebugInstruction(); Param condition; if (IR::Temp *t = s->cond->asTemp()) { @@ -991,12 +999,8 @@ void InstructionSelection::visitCJump(IR::CJump *s) void InstructionSelection::visitRet(IR::Ret *s) { - if (blockNeedsDebugInstruction) { - // this is required so stepOut will always be guaranteed to stop in every stack frame - Instruction::Debug debug; - debug.lineNumber = -int(currentLine); - addInstruction(debug); - } + // this is required so stepOut will always be guaranteed to stop in every stack frame + addDebugInstruction(); Instruction::Ret ret; ret.result = getParam(s->expr); @@ -1332,12 +1336,7 @@ void QV4::Moth::InstructionSelection::callBuiltinConvertThisToObject() ptrdiff_t InstructionSelection::addInstructionHelper(Instr::Type type, Instr &instr) { - -#ifdef MOTH_THREADED_INTERPRETER - instr.common.code = VME::instructionJumpTable()[static_cast<int>(type)]; -#else instr.common.instructionType = type; -#endif int instructionSize = Instr::size(type); if (_codeEnd - _codeNext < instructionSize) { @@ -1423,6 +1422,29 @@ CompilationUnit::~CompilationUnit() void CompilationUnit::linkBackendToEngine(QV4::ExecutionEngine *engine) { +#ifdef MOTH_THREADED_INTERPRETER + // link byte code against addresses of instructions + for (int i = 0; i < codeRefs.count(); ++i) { + QByteArray &codeRef = codeRefs[i]; + char *code = codeRef.data(); + int index = 0; + while (index < codeRef.size()) { + Instr *genericInstr = reinterpret_cast<Instr *>(code + index); + + switch (genericInstr->common.instructionType) { +#define LINK_INSTRUCTION(InstructionType, Member) \ + case Instr::InstructionType: \ + genericInstr->common.code = VME::instructionJumpTable()[static_cast<int>(genericInstr->common.instructionType)]; \ + index += InstrMeta<(int)Instr::InstructionType>::Size; \ + break; + + FOR_EACH_MOTH_INSTR(LINK_INSTRUCTION) + + } + } + } +#endif + runtimeFunctions.resize(data->functionTableSize); runtimeFunctions.fill(0); for (int i = 0 ;i < runtimeFunctions.size(); ++i) { @@ -1433,3 +1455,113 @@ void CompilationUnit::linkBackendToEngine(QV4::ExecutionEngine *engine) runtimeFunctions[i] = runtimeFunction; } } + +void CompilationUnit::prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit) +{ + const int codeAlignment = 16; + quint64 offset = WTF::roundUpToMultipleOf(codeAlignment, unit->unitSize); + Q_ASSERT(int(unit->functionTableSize) == codeRefs.size()); + for (int i = 0; i < codeRefs.size(); ++i) { + CompiledData::Function *compiledFunction = const_cast<CompiledData::Function *>(unit->functionAt(i)); + compiledFunction->codeOffset = offset; + compiledFunction->codeSize = codeRefs.at(i).size(); + offset = WTF::roundUpToMultipleOf(codeAlignment, offset + compiledFunction->codeSize); + } +} + +bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString) +{ + Q_ASSERT(device->pos() == unit->unitSize); + Q_ASSERT(device->atEnd()); + Q_ASSERT(int(unit->functionTableSize) == codeRefs.size()); + + QByteArray padding; + +#ifdef MOTH_THREADED_INTERPRETER + // Map from instruction label back to instruction type. Only needed when persisting + // already linked compilation units; + QHash<void*, int> reverseInstructionMapping; + if (engine) { + void **instructions = VME::instructionJumpTable(); + for (int i = 0; i < Instr::LastInstruction; ++i) + reverseInstructionMapping.insert(instructions[i], i); + } +#endif + + for (int i = 0; i < codeRefs.size(); ++i) { + const CompiledData::Function *compiledFunction = unit->functionAt(i); + + if (device->pos() > qint64(compiledFunction->codeOffset)) { + *errorString = QStringLiteral("Invalid state of cache file to write."); + return false; + } + + const quint64 paddingSize = compiledFunction->codeOffset - device->pos(); + padding.fill(0, paddingSize); + qint64 written = device->write(padding); + if (written != padding.size()) { + *errorString = device->errorString(); + return false; + } + + QByteArray code = codeRefs.at(i); + +#ifdef MOTH_THREADED_INTERPRETER + if (!reverseInstructionMapping.isEmpty()) { + char *codePtr = code.data(); // detaches + int index = 0; + while (index < code.size()) { + Instr *genericInstr = reinterpret_cast<Instr *>(codePtr + index); + + genericInstr->common.instructionType = reverseInstructionMapping.value(genericInstr->common.code); + + switch (genericInstr->common.instructionType) { + #define REVERSE_INSTRUCTION(InstructionType, Member) \ + case Instr::InstructionType: \ + index += InstrMeta<(int)Instr::InstructionType>::Size; \ + break; + + FOR_EACH_MOTH_INSTR(REVERSE_INSTRUCTION) + } + } + } +#endif + + written = device->write(code.constData(), compiledFunction->codeSize); + if (written != qint64(compiledFunction->codeSize)) { + *errorString = device->errorString(); + return false; + } + } + return true; +} + +bool CompilationUnit::memoryMapCode(QString *errorString) +{ + Q_UNUSED(errorString); + codeRefs.resize(data->functionTableSize); + + const char *basePtr = reinterpret_cast<const char *>(data); + + for (uint i = 0; i < data->functionTableSize; ++i) { + const CompiledData::Function *compiledFunction = data->functionAt(i); + const char *codePtr = const_cast<const char *>(reinterpret_cast<const char *>(basePtr + compiledFunction->codeOffset)); +#ifdef MOTH_THREADED_INTERPRETER + // for the threaded interpreter we need to make a copy of the data because it needs to be + // modified for the instruction handler addresses. + QByteArray code(codePtr, compiledFunction->codeSize); +#else + QByteArray code = QByteArray::fromRawData(codePtr, compiledFunction->codeSize); +#endif + codeRefs[i] = code; + } + + return true; +} + +QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory::createUnitForLoading() +{ + QQmlRefPointer<CompiledData::CompilationUnit> result; + result.adopt(new Moth::CompilationUnit); + return result; +} |