diff options
Diffstat (limited to 'src/qml/compiler/qv4codegen.cpp')
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 403 |
1 files changed, 7 insertions, 396 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 8cfdb6919d..d2ec9be105 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -51,6 +51,8 @@ #include <private/qqmljsast_p.h> #include <private/qv4string_p.h> #include <private/qv4value_p.h> +#include <private/qv4compilercontext_p.h> +#include <private/qv4compilercontrolflow_p.h> #include <private/qv4bytecodegenerator_p.h> #include <private/qv4compilationunit_moth_p.h> @@ -67,368 +69,8 @@ QT_USE_NAMESPACE using namespace QV4; -using namespace QQmlJS; -using namespace AST; - -QT_BEGIN_NAMESPACE -namespace QV4 { - -struct ControlFlow { - using Reference = Codegen::Reference; - using BytecodeGenerator = Moth::BytecodeGenerator; - using Instruction = Moth::Instruction; - - enum Type { - Loop, - With, - Finally, - Catch - }; - - enum HandlerType { - Invalid, - Break, - Continue, - Return, - Throw - }; - - struct Handler { - HandlerType type; - QString label; - BytecodeGenerator::Label linkLabel; - int tempIndex; - int value; - }; - - Codegen *cg; - ControlFlow *parent; - Type type; - bool needsLookupByName = false; - - ControlFlow(Codegen *cg, Type type) - : cg(cg), parent(cg->_context->controlFlow), type(type) - { - cg->_context->controlFlow = this; - } - - virtual ~ControlFlow() { - cg->_context->controlFlow = parent; - } - - void jumpToHandler(const Handler &h) { - if (h.tempIndex >= 0) { - Reference val = Reference::fromConst(cg, QV4::Encode(h.value)); - Reference temp = Reference::fromTemp(cg, h.tempIndex); - temp.store(val); - } - cg->bytecodeGenerator->jump().link(h.linkLabel); - } - - virtual QString label() const { return QString(); } - - bool isSimple() const { - return type == Loop; - } - - Handler getParentHandler(HandlerType type, const QString &label = QString()) { - if (parent) - return parent->getHandler(type, label); - switch (type) { - case Break: - case Continue: - return { Invalid, QString(), {}, -1, 0 }; - case Return: - case Throw: - return { type, QString(), cg->_exitBlock, -1, 0 }; - case Invalid: - break; - } - Q_ASSERT(false); - Q_UNREACHABLE(); - } - - virtual Handler getHandler(HandlerType type, const QString &label = QString()) { - return getParentHandler(type, label); - } - - virtual BytecodeGenerator::ExceptionHandler *exceptionHandler() { - return parent ? parent->exceptionHandler() : 0; - } - BytecodeGenerator::ExceptionHandler *parentExceptionHandler() { - return parent ? parent->exceptionHandler() : 0; - } - - virtual void handleThrow(const Reference &expr) { - Handler h = getHandler(ControlFlow::Throw); - if (h.tempIndex >= 0) { - Reference val = Reference::fromConst(cg, QV4::Encode(h.value)); - Reference temp = Reference::fromTemp(cg, h.tempIndex); - temp.store(val); - } - Instruction::CallBuiltinThrow instr; - instr.arg = expr.asRValue(); - generator()->addInstruction(instr); - } - -protected: - QString loopLabel() const { - QString label; - if (cg->_labelledStatement) { - label = cg->_labelledStatement->label.toString(); - cg->_labelledStatement = 0; - } - return label; - } - BytecodeGenerator *generator() const { - return cg->bytecodeGenerator; - } -}; - -struct ControlFlowLoop : public ControlFlow -{ - QString loopLabel; - BytecodeGenerator::Label *breakLabel = 0; - BytecodeGenerator::Label *continueLabel = 0; - - ControlFlowLoop(Codegen *cg, BytecodeGenerator::Label *breakLabel, BytecodeGenerator::Label *continueLabel = 0) - : ControlFlow(cg, Loop), loopLabel(ControlFlow::loopLabel()), breakLabel(breakLabel), continueLabel(continueLabel) - { - } - - virtual QString label() const { return loopLabel; } - - virtual Handler getHandler(HandlerType type, const QString &label = QString()) { - switch (type) { - case Break: - if (breakLabel && (label.isEmpty() || label == loopLabel)) - return { type, loopLabel, *breakLabel, -1, 0 }; - break; - case Continue: - if (continueLabel && (label.isEmpty() || label == loopLabel)) - return { type, loopLabel, *continueLabel, -1, 0 }; - break; - case Return: - case Throw: - break; - case Invalid: - Q_ASSERT(false); - Q_UNREACHABLE(); - } - return ControlFlow::getHandler(type, label); - } - -}; - -struct ControlFlowUnwind : public ControlFlow -{ - BytecodeGenerator::ExceptionHandler unwindLabel; - int controlFlowTemp; - QVector<Handler> handlers; - - ControlFlowUnwind(Codegen *cg, Type type) - : ControlFlow(cg, type), unwindLabel(generator()->newExceptionHandler()) - { - Q_ASSERT(type != Loop); - controlFlowTemp = static_cast<int>(generator()->newTemp()); - Reference::fromTemp(cg, controlFlowTemp).store(Reference::fromConst(cg, QV4::Encode::undefined())); - // we'll need at least a handler for throw - getHandler(Throw); - } - - void emitUnwindHandler() - { - Q_ASSERT(!isSimple()); - - Reference temp = Reference::fromTemp(cg, controlFlowTemp); - for (const auto &h : qAsConst(handlers)) { - Codegen::TempScope tempScope(cg); - Handler parentHandler = getParentHandler(h.type, h.label); - - - if (h.type == Throw || parentHandler.tempIndex >= 0) { - BytecodeGenerator::Label skip = generator()->newLabel(); - generator()->jumpStrictNotEqual(temp.asRValue(), Reference::fromConst(cg, QV4::Encode(h.value)).asRValue()) - .link(skip); - if (h.type == Throw) - emitForThrowHandling(); - Reference parentTemp = Reference::fromTemp(cg, parentHandler.tempIndex); - parentTemp.store(Reference::fromConst(cg, QV4::Encode(parentHandler.value))); - generator()->jump().link(parentHandler.linkLabel); - skip.link(); - } else { - generator()->jumpStrictEqual(temp.asRValue(), Reference::fromConst(cg, QV4::Encode(h.value)).asRValue()) - .link(parentHandler.linkLabel); - } - } - } - - virtual Handler getHandler(HandlerType type, const QString &label = QString()) { - for (const auto &h : qAsConst(handlers)) { - if (h.type == type && h.label == label) - return h; - } - Handler h = { - type, - label, - unwindLabel, - controlFlowTemp, - handlers.size() - }; - handlers.append(h); - return h; - } - - virtual BytecodeGenerator::ExceptionHandler *exceptionHandler() { - return &unwindLabel; - } - - virtual void emitForThrowHandling() { } -}; - -struct ControlFlowWith : public ControlFlowUnwind -{ - ControlFlowWith(Codegen *cg) - : ControlFlowUnwind(cg, With) - { - needsLookupByName = true; - generator()->setExceptionHandler(&unwindLabel); - } - - virtual ~ControlFlowWith() { - // emit code for unwinding - unwindLabel.link(); - - generator()->setExceptionHandler(parentExceptionHandler()); - Instruction::CallBuiltinPopScope pop; - generator()->addInstruction(pop); - - emitUnwindHandler(); - } -}; - -struct ControlFlowCatch : public ControlFlowUnwind -{ - AST::Catch *catchExpression; - bool insideCatch = false; - BytecodeGenerator::ExceptionHandler exceptionLabel; - BytecodeGenerator::ExceptionHandler catchUnwindLabel; - - ControlFlowCatch(Codegen *cg, AST::Catch *catchExpression) - : ControlFlowUnwind(cg, Catch), catchExpression(catchExpression), - exceptionLabel(generator()->newExceptionHandler()), - catchUnwindLabel(generator()->newExceptionHandler()) - { - generator()->setExceptionHandler(&exceptionLabel); - } - - virtual Handler getHandler(HandlerType type, const QString &label = QString()) { - Handler h = ControlFlowUnwind::getHandler(type, label); - if (insideCatch) - // if we're inside the catch block, we need to jump to the pop scope - // instruction at the end of the catch block, not the unwind handler - h.linkLabel = catchUnwindLabel; - else if (type == Throw) - // if we're inside the try block, we need to jump to the catch block, - // not the unwind handler - h.linkLabel = exceptionLabel; - return h; - } - - virtual BytecodeGenerator::ExceptionHandler *exceptionHandler() { - return insideCatch ? &catchUnwindLabel : &exceptionLabel; - } - - ~ControlFlowCatch() { - // emit code for unwinding - - needsLookupByName = true; - insideCatch = true; - - // exceptions inside the try block go here - exceptionLabel.link(); - Reference name = Reference::fromName(cg, catchExpression->name.toString()); - Instruction::CallBuiltinPushCatchScope pushCatchScope; - pushCatchScope.name = name.nameIndex; - generator()->addInstruction(pushCatchScope); - // clear the unwind temp for exceptions, we want to resume normal code flow afterwards - Reference::fromTemp(cg, controlFlowTemp).store(Reference::fromConst(cg, QV4::Encode::undefined())); - generator()->setExceptionHandler(&catchUnwindLabel); - - cg->statement(catchExpression->statement); - - insideCatch = false; - needsLookupByName = false; - - // exceptions inside catch and break/return statements go here - catchUnwindLabel.link(); - Instruction::CallBuiltinPopScope pop; - generator()->addInstruction(pop); - - // break/continue/return statements in try go here - unwindLabel.link(); - generator()->setExceptionHandler(parentExceptionHandler()); - - emitUnwindHandler(); - } -}; - -struct ControlFlowFinally : public ControlFlowUnwind -{ - AST::Finally *finally; - bool insideFinally = false; - int exceptionTemp = -1; - - ControlFlowFinally(Codegen *cg, AST::Finally *finally) - : ControlFlowUnwind(cg, Finally), finally(finally) - { - Q_ASSERT(finally != 0); - generator()->setExceptionHandler(&unwindLabel); - } - - virtual Handler getHandler(HandlerType type, const QString &label = QString()) { - // if we're inside the finally block, any exceptions etc. should - // go directly to the parent handler - if (insideFinally) - return ControlFlow::getHandler(type, label); - return ControlFlowUnwind::getHandler(type, label); - } - - virtual BytecodeGenerator::ExceptionHandler *exceptionHandler() { - return insideFinally ? parentExceptionHandler() : ControlFlowUnwind::exceptionHandler(); - } - - ~ControlFlowFinally() { - // emit code for unwinding - unwindLabel.link(); - - Codegen::TempScope scope(cg); - - insideFinally = true; - exceptionTemp = generator()->newTemp(); - Reference exception = Reference::fromTemp(cg, exceptionTemp); - Instruction::GetException instr; - instr.result = exception.asLValue(); - generator()->addInstruction(instr); - - generator()->setExceptionHandler(parentExceptionHandler()); - cg->statement(finally->statement); - insideFinally = false; - - emitUnwindHandler(); - } - - virtual void emitForThrowHandling() { - // reset the exception flag, that got cleared before executing the statements in finally - Instruction::SetException setException; - Q_ASSERT(exceptionTemp != -1); - setException.exception = Reference::fromTemp(cg, exceptionTemp).asRValue(); - generator()->addInstruction(setException); - } -}; - -} // QV4 namespace -QT_END_NAMESPACE +using namespace QV4::Compiler; +using namespace QQmlJS::AST; static inline QV4::Runtime::RuntimeMethods aluOpFunction(QSOperator::Op op) { @@ -851,7 +493,7 @@ Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict) void Codegen::generateFromProgram(const QString &fileName, const QString &sourceCode, Program *node, - QQmlJS::Module *module, + Module *module, CompilationMode mode) { Q_ASSERT(node); @@ -870,7 +512,7 @@ void Codegen::generateFromProgram(const QString &fileName, void Codegen::generateFromFunctionExpression(const QString &fileName, const QString &sourceCode, AST::FunctionExpression *ast, - QQmlJS::Module *module) + Module *module) { _module = module; _module->fileName = fileName; @@ -3156,7 +2798,7 @@ QQmlRefPointer<CompiledData::CompilationUnit> Codegen::generateCompilationUnit(b Moth::CompilationUnit *compilationUnit = new Moth::CompilationUnit; compilationUnit->codeRefs.resize(_module->functions.size()); int i = 0; - for (QQmlJS::Context *irFunction : qAsConst(_module->functions)) + for (Context *irFunction : qAsConst(_module->functions)) compilationUnit->codeRefs[i++] = irFunction->code; if (generateUnitData) @@ -3514,34 +3156,3 @@ void Codegen::Reference::load(uint tmp) const } } -Context *Module::newContext(Node *node, Context *parent, CompilationMode compilationMode) -{ - Context *c = new Context(parent, compilationMode); - if (node) { - SourceLocation loc = node->firstSourceLocation(); - c->line = loc.startLine; - c->column = loc.startColumn; - } - - contextMap.insert(node, c); - - if (!parent) - rootContext = c; - else { - parent->nestedContexts.append(c); - c->isStrict = parent->isStrict; - } - - return c; -} - -bool Context::forceLookupByName() -{ - QV4::ControlFlow *flow = controlFlow; - while (flow) { - if (flow->needsLookupByName) - return true; - flow = flow->parent; - } - return false; -} |