aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qv4codegen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/compiler/qv4codegen.cpp')
-rw-r--r--src/qml/compiler/qv4codegen.cpp403
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;
-}