aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qv4compilercontrolflow_p.h
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@qt.io>2017-08-04 13:38:33 +0200
committerErik Verbruggen <erik.verbruggen@qt.io>2017-08-18 09:56:28 +0000
commit4f9875a10ff67aafebe227e9f5ea1b7b97abb52e (patch)
tree75504c1c17304c5118ac8ffc84bb626dbdd6d1c2 /src/qml/compiler/qv4compilercontrolflow_p.h
parentebc6979801d86ae79dbbbb64c8793d90e0508d18 (diff)
Don't use a return value register for regular functions
don't use the return value register for normal functions anymore. It's still needed for eval code and qml bindings that have an implicit return value, as the accumulator gets clobbered too easily in those cases. Also get rid of the exit block we used to generate. Adjust the control flow handlers to correctly unwind. This required adding some jump instructions that left the accumulator untouched (as it now holds the return value) and using those in handlers. Change-Id: I2ca1afaf7234cb632e5d26ba5b10ec3f11f50c93 Reviewed-by: Lars Knoll <lars.knoll@qt.io> Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
Diffstat (limited to 'src/qml/compiler/qv4compilercontrolflow_p.h')
-rw-r--r--src/qml/compiler/qv4compilercontrolflow_p.h74
1 files changed, 55 insertions, 19 deletions
diff --git a/src/qml/compiler/qv4compilercontrolflow_p.h b/src/qml/compiler/qv4compilercontrolflow_p.h
index f8efd010a3..354015a542 100644
--- a/src/qml/compiler/qv4compilercontrolflow_p.h
+++ b/src/qml/compiler/qv4compilercontrolflow_p.h
@@ -103,10 +103,34 @@ struct ControlFlow {
cg->_context->controlFlow = parent;
}
+ void emitReturnStatement() const {
+ if (cg->_returnAddress >= 0) {
+ Instruction::LoadReg load;
+ load.reg = Moth::StackSlot::createRegister(cg->_returnAddress);
+ generator()->addInstruction(load);
+ }
+ Instruction::Ret ret;
+ cg->bytecodeGenerator->addInstruction(ret);
+ }
+
void jumpToHandler(const Handler &h) {
- if (h.tempIndex >= 0)
- Reference::storeConstOnStack(cg, QV4::Encode(h.value), h.tempIndex);
- cg->bytecodeGenerator->jump().link(h.linkLabel);
+ if (h.linkLabel.isReturn()) {
+ emitReturnStatement();
+ } else {
+ if (h.tempIndex >= 0)
+ Reference::storeConstOnStack(cg, QV4::Encode(h.value), h.tempIndex);
+ cg->bytecodeGenerator->jump().link(h.linkLabel);
+ }
+ }
+
+ bool returnRequiresUnwind() const {
+ const ControlFlow *f = this;
+ while (f) {
+ if (f->type == Finally)
+ return true;
+ f = f->parent;
+ }
+ return false;
}
virtual QString label() const { return QString(); }
@@ -124,7 +148,7 @@ struct ControlFlow {
return { Invalid, QString(), {}, -1, 0 };
case Return:
case Throw:
- return { type, QString(), cg->_exitBlock, -1, 0 };
+ return { type, QString(), BytecodeGenerator::Label::returnLabel(), -1, 0 };
case Invalid:
break;
}
@@ -132,17 +156,17 @@ struct ControlFlow {
Q_UNREACHABLE();
}
- virtual Handler getHandler(HandlerType type, const QString &label = QString()) {
- return getParentHandler(type, label);
- }
+ virtual Handler getHandler(HandlerType type, const QString &label = QString()) = 0;
- virtual BytecodeGenerator::ExceptionHandler *exceptionHandler() {
- return parent ? parent->exceptionHandler() : 0;
- }
BytecodeGenerator::ExceptionHandler *parentExceptionHandler() {
return parent ? parent->exceptionHandler() : 0;
}
+ virtual BytecodeGenerator::ExceptionHandler *exceptionHandler() {
+ return parentExceptionHandler();
+ }
+
+
virtual void handleThrow(const Reference &expr) {
Reference e = expr;
Handler h = getHandler(ControlFlow::Throw);
@@ -199,7 +223,7 @@ struct ControlFlowLoop : public ControlFlow
Q_ASSERT(false);
Q_UNREACHABLE();
}
- return ControlFlow::getHandler(type, label);
+ return getParentHandler(type, label);
}
};
@@ -226,21 +250,24 @@ struct ControlFlowUnwind : public ControlFlow
Reference temp = Reference::fromStackSlot(cg, controlFlowTemp);
for (const auto &h : qAsConst(handlers)) {
- Codegen::RegisterScope tempScope(cg);
Handler parentHandler = getParentHandler(h.type, h.label);
if (h.type == Throw || parentHandler.tempIndex >= 0) {
BytecodeGenerator::Label skip = generator()->newLabel();
- Reference::fromConst(cg, QV4::Encode(h.value)).loadInAccumulator();
- generator()->jumpStrictNotEqual(temp.stackSlot()).link(skip);
+ generator()->jumpStrictNotEqualStackSlotInt(temp.stackSlot(), h.value).link(skip);
if (h.type == Throw)
emitForThrowHandling();
- Reference::storeConstOnStack(cg, QV4::Encode(parentHandler.value), parentHandler.tempIndex);
- generator()->jump().link(parentHandler.linkLabel);
+ jumpToHandler(parentHandler);
skip.link();
} else {
- Reference::fromConst(cg, QV4::Encode(h.value)).loadInAccumulator();
- generator()->jumpStrictEqual(temp.stackSlot()).link(parentHandler.linkLabel);
+ if (parentHandler.linkLabel.isReturn()) {
+ BytecodeGenerator::Label skip = generator()->newLabel();
+ generator()->jumpStrictNotEqualStackSlotInt(temp.stackSlot(), h.value).link(skip);
+ emitReturnStatement();
+ skip.link();
+ } else {
+ generator()->jumpStrictEqualStackSlotInt(temp.stackSlot(), h.value).link(parentHandler.linkLabel);
+ }
}
}
}
@@ -389,7 +416,7 @@ struct ControlFlowFinally : public ControlFlowUnwind
// 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 getParentHandler(type, label);
return ControlFlowUnwind::getHandler(type, label);
}
@@ -403,6 +430,11 @@ struct ControlFlowFinally : public ControlFlowUnwind
Codegen::RegisterScope scope(cg);
+ Moth::StackSlot retVal = Moth::StackSlot::createRegister(generator()->newRegister());
+ Instruction::StoreReg storeRetVal;
+ storeRetVal.reg = retVal;
+ generator()->addInstruction(storeRetVal);
+
insideFinally = true;
exceptionTemp = generator()->newRegister();
Instruction::GetException instr;
@@ -413,6 +445,10 @@ struct ControlFlowFinally : public ControlFlowUnwind
cg->statement(finally->statement);
insideFinally = false;
+ Instruction::LoadReg loadRetVal;
+ loadRetVal.reg = retVal;
+ generator()->addInstruction(loadRetVal);
+
emitUnwindHandler();
}