aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
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
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')
-rw-r--r--src/qml/compiler/qv4bytecodegenerator_p.h24
-rw-r--r--src/qml/compiler/qv4codegen.cpp135
-rw-r--r--src/qml/compiler/qv4codegen_p.h3
-rw-r--r--src/qml/compiler/qv4compilercontrolflow_p.h74
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp9
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h17
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp13
7 files changed, 210 insertions, 65 deletions
diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h
index 81b64f96da..f53a720d2c 100644
--- a/src/qml/compiler/qv4bytecodegenerator_p.h
+++ b/src/qml/compiler/qv4bytecodegenerator_p.h
@@ -77,6 +77,14 @@ public:
index(generator->labels.size()) {
generator->labels.append(mode == LinkNow ? generator->instructions.size() : -1);
}
+ static Label returnLabel() {
+ Label l;
+ l.index = INT_MAX;
+ return l;
+ }
+ bool isReturn() const {
+ return index == INT_MAX;
+ }
void link() {
Q_ASSERT(index >= 0);
@@ -176,6 +184,22 @@ public:
return addJumpInstruction(data);
}
+ Q_REQUIRED_RESULT Jump jumpStrictEqualStackSlotInt(const StackSlot &lhs, int rhs)
+ {
+ Instruction::JumpStrictEqualStackSlotInt data;
+ data.lhs = lhs;
+ data.rhs = rhs;
+ return addJumpInstruction(data);
+ }
+
+ Q_REQUIRED_RESULT Jump jumpStrictNotEqualStackSlotInt(const StackSlot &lhs, int rhs)
+ {
+ Instruction::JumpStrictNotEqualStackSlotInt data;
+ data.lhs = lhs;
+ data.rhs = rhs;
+ return addJumpInstruction(data);
+ }
+
void setExceptionHandler(ExceptionHandler *handler)
{
currentExceptionHandler = handler;
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 4fb34a677f..c795841f00 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -214,7 +214,7 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
return Reference::fromAccumulator(this);
}
case PostIncrement:
- if (!_expr.accept(nx)) {
+ if (!_expr.accept(nx) || requiresReturnValue) {
Reference e = expr.asLValue();
e.loadInAccumulator();
Instruction::UPlus uplus;
@@ -239,7 +239,7 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
return e.storeRetainAccumulator();
}
case PostDecrement:
- if (!_expr.accept(nx)) {
+ if (!_expr.accept(nx) || requiresReturnValue) {
Reference e = expr.asLValue();
e.loadInAccumulator();
Instruction::UPlus uplus;
@@ -361,13 +361,33 @@ void Codegen::program(Program *ast)
void Codegen::sourceElements(SourceElements *ast)
{
+ bool _requiresReturnValue = false;
+ qSwap(_requiresReturnValue, requiresReturnValue);
for (SourceElements *it = ast; it; it = it->next) {
+ if (!it->next)
+ qSwap(_requiresReturnValue, requiresReturnValue);
sourceElement(it->element);
if (hasError)
return;
}
}
+void Codegen::statementList(StatementList *ast)
+{
+ bool _requiresReturnValue = requiresReturnValue;
+ requiresReturnValue = false;
+ for (StatementList *it = ast; it; it = it->next) {
+ if (!it->next ||
+ it->next->statement->kind == Statement::Kind_BreakStatement ||
+ it->next->statement->kind == Statement::Kind_ContinueStatement ||
+ it->next->statement->kind == Statement::Kind_ReturnStatement)
+ requiresReturnValue = _requiresReturnValue;
+ statement(it->statement);
+ requiresReturnValue = false;
+ }
+ requiresReturnValue = _requiresReturnValue;
+}
+
void Codegen::variableDeclaration(VariableDeclaration *ast)
{
RegisterScope scope(this);
@@ -1761,14 +1781,39 @@ bool Codegen::visit(FunctionDeclaration * ast)
RegisterScope scope(this);
- if (_context->compilationMode == QmlBinding) {
+ if (_context->compilationMode == QmlBinding)
Reference::fromName(this, ast->name.toString()).loadInAccumulator();
- Reference::fromStackSlot(this, _returnAddress).storeConsumeAccumulator();
- }
_expr.accept(nx);
return false;
}
+static bool endsWithReturn(Node *node)
+{
+ if (!node)
+ return false;
+ if (AST::cast<ReturnStatement *>(node))
+ return true;
+ if (Program *p = AST::cast<Program *>(node))
+ return endsWithReturn(p->elements);
+ if (SourceElements *se = AST::cast<SourceElements *>(node)) {
+ while (se->next)
+ se = se->next;
+ return endsWithReturn(se->element);
+ }
+ if (StatementSourceElement *sse = AST::cast<StatementSourceElement *>(node))
+ return endsWithReturn(sse->statement);
+ if (StatementList *sl = AST::cast<StatementList *>(node)) {
+ while (sl->next)
+ sl = sl->next;
+ return endsWithReturn(sl->statement);
+ }
+ if (Block *b = AST::cast<Block *>(node))
+ return endsWithReturn(b->statements);
+ if (IfStatement *is = AST::cast<IfStatement *>(node))
+ return is->ko && endsWithReturn(is->ok) && endsWithReturn(is->ko);
+ return false;
+}
+
int Codegen::defineFunction(const QString &name, AST::Node *ast,
AST::FormalParameterList *formals,
AST::SourceElements *body)
@@ -1797,8 +1842,11 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
// allocate the js stack frame (Context & js Function & accumulator)
bytecodeGenerator->newRegisterArray(sizeof(JSStackFrame)/sizeof(Value));
- int returnAddress = bytecodeGenerator->newRegister();
-
+ int returnAddress = -1;
+ bool _requiresReturnValue = (_context->compilationMode == QmlBinding || _context->compilationMode == EvalCode);
+ qSwap(requiresReturnValue, _requiresReturnValue);
+ if (requiresReturnValue)
+ returnAddress = bytecodeGenerator->newRegister();
if (!_context->parent || _context->usesArgumentsObject == Context::ArgumentsObjectUnknown)
_context->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
if (_context->usesArgumentsObject == Context::ArgumentsObjectUsed)
@@ -1830,11 +1878,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
}
}
- auto exitBlock = bytecodeGenerator->newLabel();
-
- qSwap(_exitBlock, exitBlock);
qSwap(_returnAddress, returnAddress);
-
for (const Context::Member &member : qAsConst(_context->members)) {
if (member.function) {
const int function = defineFunction(member.function->name.toString(), member.function, member.function->formals,
@@ -1870,13 +1914,17 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
sourceElements(body);
- _exitBlock.link();
- bytecodeGenerator->setLocation(ast->lastSourceLocation());
-
- {
- Instruction::Ret ret;
- ret.result = Reference::fromStackSlot(this, _returnAddress).theStackSlot;
- bytecodeGenerator->addInstruction(ret);
+ if (hasError || !endsWithReturn(body)) {
+ if (requiresReturnValue) {
+ if (_returnAddress >= 0) {
+ Instruction::LoadReg load;
+ load.reg = Moth::StackSlot::createRegister(_returnAddress);
+ bytecodeGenerator->addInstruction(load);
+ }
+ } else {
+ Reference::fromConst(this, Encode::undefined()).loadInAccumulator();
+ }
+ bytecodeGenerator->addInstruction(Instruction::Ret());
}
_context->code = bytecodeGenerator->finalize();
@@ -1889,9 +1937,8 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
qDebug();
}
- qSwap(_exitBlock, exitBlock);
qSwap(_returnAddress, returnAddress);
-
+ qSwap(requiresReturnValue, _requiresReturnValue);
bytecodeGenerator = savedBytecodeGenerator;
return leaveContext();
@@ -1922,9 +1969,7 @@ bool Codegen::visit(Block *ast)
RegisterScope scope(this);
- for (StatementList *it = ast->statements; it; it = it->next) {
- statement(it->statement);
- }
+ statementList(ast->statements);
return false;
}
@@ -2022,7 +2067,7 @@ bool Codegen::visit(ExpressionStatement *ast)
RegisterScope scope(this);
- if (_context->compilationMode == EvalCode || _context->compilationMode == QmlBinding) {
+ if (requiresReturnValue) {
Reference e = expression(ast->expression);
if (hasError)
return false;
@@ -2122,10 +2167,15 @@ bool Codegen::visit(IfStatement *ast)
trueLabel.link();
statement(ast->ok);
if (ast->ko) {
- BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
- falseLabel.link();
- statement(ast->ko);
- jump_endif.link();
+ if (endsWithReturn(ast)) {
+ falseLabel.link();
+ statement(ast->ko);
+ } else {
+ BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
+ falseLabel.link();
+ statement(ast->ko);
+ jump_endif.link();
+ }
} else {
falseLabel.link();
}
@@ -2253,19 +2303,25 @@ bool Codegen::visit(ReturnStatement *ast)
throwSyntaxError(ast->returnToken, QStringLiteral("Return statement outside of function"));
return false;
}
+ Reference expr;
if (ast->expression) {
- Reference expr = expression(ast->expression);
+ expr = expression(ast->expression);
if (hasError)
return false;
- expr.loadInAccumulator();
- Reference::fromStackSlot(this, _returnAddress).storeConsumeAccumulator();
+ } else {
+ expr = Reference::fromConst(this, Encode::undefined());
}
- if (_context->controlFlow) {
+ if (_context->controlFlow && _context->controlFlow->returnRequiresUnwind()) {
+ if (_returnAddress >= 0)
+ (void) expr.storeOnStack(_returnAddress);
+ else
+ expr.loadInAccumulator();
ControlFlow::Handler h = _context->controlFlow->getHandler(ControlFlow::Return);
_context->controlFlow->jumpToHandler(h);
} else {
- bytecodeGenerator->jump().link(_exitBlock);
+ expr.loadInAccumulator();
+ bytecodeGenerator->addInstruction(Instruction::Ret());
}
return false;
}
@@ -2324,24 +2380,21 @@ bool Codegen::visit(SwitchStatement *ast)
CaseClause *clause = it->clause;
blockMap[clause].link();
- for (StatementList *it2 = clause->statements; it2; it2 = it2->next)
- statement(it2->statement);
+ statementList(clause->statements);
}
if (ast->block->defaultClause) {
DefaultClause *clause = ast->block->defaultClause;
blockMap[clause].link();
- for (StatementList *it2 = clause->statements; it2; it2 = it2->next)
- statement(it2->statement);
+ statementList(clause->statements);
}
for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
CaseClause *clause = it->clause;
blockMap[clause].link();
- for (StatementList *it2 = clause->statements; it2; it2 = it2->next)
- statement(it2->statement);
+ statementList(clause->statements);
}
switchEnd.link();
@@ -2437,6 +2490,8 @@ bool Codegen::visit(WhileStatement *ast)
if (hasError)
return true;
+ RegisterScope scope(this);
+
BytecodeGenerator::Label start = bytecodeGenerator->newLabel();
BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
BytecodeGenerator::Label cond = bytecodeGenerator->label();
@@ -2449,7 +2504,6 @@ bool Codegen::visit(WhileStatement *ast)
bytecodeGenerator->jump().link(cond);
end.link();
-
return false;
}
@@ -3037,4 +3091,3 @@ void Codegen::Reference::loadInAccumulator() const
Q_ASSERT(false);
Q_UNREACHABLE();
}
-
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index f55ef026a8..0d63854ed1 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -484,6 +484,7 @@ protected:
void functionBody(AST::FunctionBody *ast);
void program(AST::Program *ast);
void sourceElements(AST::SourceElements *ast);
+ void statementList(AST::StatementList *ast);
void variableDeclaration(AST::VariableDeclaration *ast);
void variableDeclarationList(AST::VariableDeclarationList *ast);
@@ -623,7 +624,6 @@ protected:
friend struct ControlFlowFinally;
Result _expr;
Module *_module;
- BytecodeGenerator::Label _exitBlock;
int _returnAddress;
Context *_context;
AST::LabelledStatement *_labelledStatement;
@@ -631,6 +631,7 @@ protected:
BytecodeGenerator *bytecodeGenerator = 0;
bool _strictMode;
bool useFastLookups = true;
+ bool requiresReturnValue = false;
bool _fileNameIsUrl;
bool hasError;
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();
}
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index b3034e8b81..ed2f556e01 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -405,6 +405,14 @@ void dumpBytecode(const char *code, int len, int nFormals)
d << instr.lhs.dump(nFormals) << " " << absoluteInstructionOffset(start, instr);
MOTH_END_INSTR(JumpStrictNotEqual)
+ MOTH_BEGIN_INSTR(JumpStrictEqualStackSlotInt)
+ d << instr.lhs.dump(nFormals) << ", " << instr.rhs << " " << absoluteInstructionOffset(start, instr);
+ MOTH_END_INSTR(JumpStrictEqualStackSlotInt)
+
+ MOTH_BEGIN_INSTR(JumpStrictNotEqualStackSlotInt)
+ d << instr.lhs.dump(nFormals) << ", " << instr.rhs << " " << absoluteInstructionOffset(start, instr);
+ MOTH_END_INSTR(JumpStrictNotEqualStackSlotInt)
+
MOTH_BEGIN_INSTR(UNot)
MOTH_END_INSTR(UNot)
@@ -484,7 +492,6 @@ void dumpBytecode(const char *code, int len, int nFormals)
MOTH_END_INSTR(BinopContext)
MOTH_BEGIN_INSTR(Ret)
- d << instr.result.dump(nFormals);
MOTH_END_INSTR(Ret)
#ifndef QT_NO_QML_DEBUGGER
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 63b117dc0e..d07e44c41b 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -144,6 +144,8 @@ QT_BEGIN_NAMESPACE
F(CmpJmpLe, cmpJmpLe) \
F(JumpStrictEqual, jumpStrictEqual) \
F(JumpStrictNotEqual, jumpStrictNotEqual) \
+ F(JumpStrictEqualStackSlotInt, jumpStrictEqualStackSlotInt) \
+ F(JumpStrictNotEqualStackSlotInt, jumpStrictNotEqualStackSlotInt) \
F(UNot, unot) \
F(UPlus, uplus) \
F(UMinus, uminus) \
@@ -247,7 +249,6 @@ union Instr
};
struct instr_ret {
MOTH_INSTR_HEADER
- StackSlot result;
};
#ifndef QT_NO_QML_DEBUGGING
@@ -597,6 +598,18 @@ union Instr
ptrdiff_t offset;
StackSlot lhs;
};
+ struct instr_jumpStrictEqualStackSlotInt {
+ MOTH_INSTR_HEADER
+ ptrdiff_t offset;
+ StackSlot lhs;
+ int rhs;
+ };
+ struct instr_jumpStrictNotEqualStackSlotInt {
+ MOTH_INSTR_HEADER
+ ptrdiff_t offset;
+ StackSlot lhs;
+ int rhs;
+ };
struct instr_unot {
MOTH_INSTR_HEADER
};
@@ -770,6 +783,8 @@ union Instr
instr_cmpJmpLe cmpJmpLe;
instr_jumpStrictEqual jumpStrictEqual;
instr_jumpStrictNotEqual jumpStrictNotEqual;
+ instr_jumpStrictEqualStackSlotInt jumpStrictEqualStackSlotInt;
+ instr_jumpStrictNotEqualStackSlotInt jumpStrictNotEqualStackSlotInt;
instr_unot unot;
instr_uplus uplus;
instr_uminus uminus;
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index efab04b32d..b17341e5e5 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -640,7 +640,7 @@ QV4::ReturnedValue VME::exec(const FunctionObject *jsFunction, CallData *callDat
MOTH_BEGIN_INSTR(ThrowException)
Runtime::method_throwException(engine, accumulator);
- CHECK_EXCEPTION;
+ goto catchException;
MOTH_END_INSTR(ThrowException)
MOTH_BEGIN_INSTR(GetException)
@@ -905,6 +905,16 @@ QV4::ReturnedValue VME::exec(const FunctionObject *jsFunction, CallData *callDat
}
MOTH_END_INSTR(JumpStrictNotEqual)
+ MOTH_BEGIN_INSTR(JumpStrictNotEqualStackSlotInt)
+ if (STACK_VALUE(instr.lhs).int_32() != instr.rhs || STACK_VALUE(instr.lhs).isUndefined())
+ code = reinterpret_cast<const uchar *>(&instr.offset) + instr.offset;
+ MOTH_END_INSTR(JumpStrictNotEqualStackSlotInt)
+
+ MOTH_BEGIN_INSTR(JumpStrictEqualStackSlotInt)
+ if (STACK_VALUE(instr.lhs).int_32() == instr.rhs && !STACK_VALUE(instr.lhs).isUndefined())
+ code = reinterpret_cast<const uchar *>(&instr.offset) + instr.offset;
+ MOTH_END_INSTR(JumpStrictNotEqualStackSlotInt)
+
MOTH_BEGIN_INSTR(UNot)
if (accumulator.integerCompatible()) {
STORE_ACCUMULATOR(Encode(!static_cast<bool>(accumulator.int_32())))
@@ -1039,7 +1049,6 @@ QV4::ReturnedValue VME::exec(const FunctionObject *jsFunction, CallData *callDat
MOTH_END_INSTR(BinopContext)
MOTH_BEGIN_INSTR(Ret)
- accumulator = STACK_VALUE(instr.result).asReturnedValue();
goto functionExit;
MOTH_END_INSTR(Ret)