F(CallBuiltinFinishTry, callBuiltinFinishTry) \
F(CallBuiltinGetException, callBuiltinGetException) \
F(CallBuiltinPushScope, callBuiltinPushScope) \
- F(CallBuiltinPushCatchScope, callBuiltinPushCatchScope) \
F(CallBuiltinPopScope, callBuiltinPopScope) \
F(CallBuiltinForeachIteratorObject, callBuiltinForeachIteratorObject) \
F(CallBuiltinForeachNextPropertyName, callBuiltinForeachNextPropertyName) \
MOTH_INSTR_HEADER
ptrdiff_t tryOffset;
ptrdiff_t catchOffset;
+ VM::String *exceptionVarName;
};
struct instr_callValue {
MOTH_INSTR_HEADER
MOTH_INSTR_HEADER
Param arg;
};
- struct instr_callBuiltinPushCatchScope {
- MOTH_INSTR_HEADER
- VM::String *varName;
- };
struct instr_callBuiltinPopScope {
MOTH_INSTR_HEADER
};
instr_callBuiltinFinishTry callBuiltinFinishTry;
instr_callBuiltinGetException callBuiltinGetException;
instr_callBuiltinPushScope callBuiltinPushScope;
- instr_callBuiltinPushCatchScope callBuiltinPushCatchScope;
instr_callBuiltinPopScope callBuiltinPopScope;
instr_callBuiltinForeachIteratorObject callBuiltinForeachIteratorObject;
instr_callBuiltinForeachNextPropertyName callBuiltinForeachNextPropertyName;
Instruction::EnterTry enterTry;
enterTry.tryOffset = 0;
enterTry.catchOffset = 0;
+ enterTry.exceptionVarName = identifier(t->exceptionVarName);
ptrdiff_t enterTryLoc = addInstruction(enterTry);
ptrdiff_t tryLoc = enterTryLoc + (((const char *)&enterTry.tryOffset) - ((const char *)&enterTry));
addInstruction(call);
}
-void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionVarName)
-{
- Instruction::CallBuiltinPushCatchScope call;
- call.varName = identifier(exceptionVarName);
- addInstruction(call);
-}
-
void InstructionSelection::callBuiltinPopScope()
{
Instruction::CallBuiltinPopScope call;
virtual void callBuiltinForeachIteratorObject(IR::Temp *arg, IR::Temp *result);
virtual void callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result);
virtual void callBuiltinPushWithScope(IR::Temp *arg);
- virtual void callBuiltinPushCatchScope(const QString &exceptionVarName);
virtual void callBuiltinPopScope();
virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
virtual void callBuiltinDefineGetterSetter(IR::Temp *object, const QString &name, IR::Temp *getter, IR::Temp *setter);
} catch (VM::Exception &ex) {
ex.accept(context);
try {
+ VM::ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(instr.exceptionVarName, context);
const uchar *catchCode = ((uchar *)&instr.catchOffset) + instr.catchOffset;
- run(context, catchCode, stack, stackSize);
+ run(catchContext, catchCode, stack, stackSize);
code = catchCode;
+ context = __qmljs_builtin_pop_scope(catchContext);
} catch (VM::Exception &ex) {
ex.accept(context);
const uchar *catchCode = ((uchar *)&instr.catchOffset) + instr.catchOffset;
context = __qmljs_builtin_push_with_scope(VALUE(instr.arg), context);
MOTH_END_INSTR(CallBuiltinPushScope)
- MOTH_BEGIN_INSTR(CallBuiltinPushCatchScope)
- context = __qmljs_builtin_push_catch_scope(instr.varName, context);
- MOTH_END_INSTR(CallBuiltinPushCatchScope)
-
MOTH_BEGIN_INSTR(CallBuiltinPopScope)
context = __qmljs_builtin_pop_scope(context);
MOTH_END_INSTR(CallBuiltinPopScope)
ScopeAndFinally tcf(_scopeAndFinally, ast->finallyExpression, finishTryArgs);
_scopeAndFinally = &tcf;
- _block->TRY(tryBody, catchBody);
+ _block->TRY(tryBody, catchBody, ast->catchExpression ? ast->catchExpression->name.toString() : QString());
_block = tryBody;
statement(ast->statement);
move(_block->TEMP(hasException), _block->CONST(IR::BoolType, true));
if (ast->catchExpression) {
- IR::ExprList *catchScopeArgs = _function->New<IR::ExprList>();
- catchScopeArgs->init(_block->NAME(ast->catchExpression->name.toString(), ast->catchExpression->identifierToken.startLine, ast->catchExpression->identifierToken.startColumn));
- _block->EXP(_block->CALL(_block->NAME(IR::Name::builtin_push_catch_scope, 0, 0), catchScopeArgs));
-
++_function->insideWithOrCatch;
{
- ScopeAndFinally scope(_scopeAndFinally);
+ ScopeAndFinally scope(_scopeAndFinally, ScopeAndFinally::CatchScope);
_scopeAndFinally = &scope;
statement(ast->catchExpression->statement);
_scopeAndFinally = scope.parent;
}
--_function->insideWithOrCatch;
-
move(_block->TEMP(hasException), _block->CONST(IR::BoolType, false));
- _block->EXP(_block->CALL(_block->NAME(IR::Name::builtin_pop_scope, 0, 0)));
}
_block->JUMP(finallyBody);
ScopeAndFinally *scopeAndFinally = _scopeAndFinally;
qSwap(_scopeAndFinally, scopeAndFinally);
while (_scopeAndFinally != outest) {
- if (_scopeAndFinally->popScope) {
+ switch (_scopeAndFinally->type) {
+ case ScopeAndFinally::WithScope:
_block->EXP(_block->CALL(_block->NAME(IR::Name::builtin_pop_scope, 0, 0)));
+ // fall through
+ case ScopeAndFinally::CatchScope:
_scopeAndFinally = _scopeAndFinally->parent;
--_function->insideWithOrCatch;
- } else {
+ break;
+ case ScopeAndFinally::TryScope: {
_block->EXP(_block->CALL(_block->NAME(IR::Name::builtin_finish_try, 0, 0), _scopeAndFinally->finishTryArgs));
ScopeAndFinally *tc = _scopeAndFinally;
_scopeAndFinally = tc->parent;
if (tc->finally && tc->finally->statement)
statement(tc->finally->statement);
+ break;
+ }
}
}
qSwap(_scopeAndFinally, scopeAndFinally);
};
struct ScopeAndFinally {
+ enum ScopeType {
+ WithScope,
+ TryScope,
+ CatchScope
+ };
+
ScopeAndFinally *parent;
AST::Finally *finally;
IR::ExprList *finishTryArgs;
- bool popScope;
+ ScopeType type;
- ScopeAndFinally(ScopeAndFinally *parent) : parent(parent), finally(0), finishTryArgs(0), popScope(true) {}
+ ScopeAndFinally(ScopeAndFinally *parent, ScopeType t = WithScope) : parent(parent), finally(0), finishTryArgs(0), type(t) {}
ScopeAndFinally(ScopeAndFinally *parent, AST::Finally *finally, IR::ExprList *finishTryArgs)
- : parent(parent), finally(finally), finishTryArgs(finishTryArgs), popScope(false)
+ : parent(parent), finally(finally), finishTryArgs(finishTryArgs), type(TryScope)
{}
};
virtual void callBuiltinForeachIteratorObject(IR::Temp *arg, IR::Temp *result);
virtual void callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result);
virtual void callBuiltinPushWithScope(IR::Temp *arg);
- virtual void callBuiltinPushCatchScope(const QString &exceptionVarName){}
virtual void callBuiltinPopScope();
virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
virtual void callBuiltinDefineGetterSetter(IR::Temp *object, const QString &name, IR::Temp *getter, IR::Temp *setter);
}
typedef void *(*MiddleOfFunctionEntryPoint(ExecutionContext *, void *localsPtr));
-static void *tryWrapper(ExecutionContext *context, void *localsPtr, MiddleOfFunctionEntryPoint tryBody, MiddleOfFunctionEntryPoint catchBody)
+static void *tryWrapper(ExecutionContext *context, void *localsPtr, MiddleOfFunctionEntryPoint tryBody, MiddleOfFunctionEntryPoint catchBody,
+ VM::String *exceptionVarName)
{
void *addressToContinueAt = 0;
try {
} catch (Exception& ex) {
ex.accept(context);
try {
- addressToContinueAt = catchBody(context, localsPtr);
+ ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(exceptionVarName, context);
+ addressToContinueAt = catchBody(catchContext, localsPtr);
+ context = __qmljs_builtin_pop_scope(catchContext);
} catch (Exception& ex) {
ex.accept(context);
addressToContinueAt = catchBody(context, localsPtr);
_reentryBlocks.insert(t->catchBlock);
generateFunctionCall(Assembler::ReturnValueRegister, tryWrapper, Assembler::ContextRegister, Assembler::LocalsRegister,
- Assembler::ReentryBlock(t->tryBlock), Assembler::ReentryBlock(t->catchBlock));
+ Assembler::ReentryBlock(t->tryBlock), Assembler::ReentryBlock(t->catchBlock),
+ identifier(t->exceptionVarName));
_as->jump(Assembler::ReturnValueRegister);
}
generateFunctionCall(Assembler::ContextRegister, __qmljs_builtin_push_with_scope, Assembler::Reference(arg), Assembler::ContextRegister);
}
-void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionVarName)
-{
- generateFunctionCall(Assembler::ContextRegister, __qmljs_builtin_push_catch_scope, identifier(exceptionVarName), Assembler::ContextRegister);
-}
-
void InstructionSelection::callBuiltinPopScope()
{
generateFunctionCall(Assembler::ContextRegister, __qmljs_builtin_pop_scope, Assembler::ContextRegister);
virtual void callBuiltinForeachIteratorObject(IR::Temp *arg, IR::Temp *result);
virtual void callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result);
virtual void callBuiltinPushWithScope(IR::Temp *arg);
- virtual void callBuiltinPushCatchScope(const QString &exceptionVarName);
virtual void callBuiltinPopScope();
virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
virtual void callBuiltinDefineGetterSetter(IR::Temp *object, const QString &name, IR::Temp *getter, IR::Temp *setter);
callBuiltinPushWithScope(arg);
} return;
- case IR::Name::builtin_push_catch_scope: {
- IR::Name *arg = call->args->expr->asName();
- assert(arg != 0);
- callBuiltinPushCatchScope(*arg->id);
- } return;
-
case IR::Name::builtin_pop_scope:
callBuiltinPopScope();
return;
virtual void callBuiltinForeachIteratorObject(IR::Temp *arg, IR::Temp *result) = 0;
virtual void callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result) = 0;
virtual void callBuiltinPushWithScope(IR::Temp *arg) = 0;
- virtual void callBuiltinPushCatchScope(const QString &exceptionVarName) = 0;
virtual void callBuiltinPopScope() = 0;
virtual void callBuiltinDeclareVar(bool deletable, const QString &name) = 0;
virtual void callBuiltinDefineGetterSetter(IR::Temp *object, const QString &name, IR::Temp *getter, IR::Temp *setter) = 0;
return "builtin_foreach_next_property_name";
case IR::Name::builtin_push_with_scope:
return "builtin_push_with_scope";
- case IR::Name::builtin_push_catch_scope:
- return "builtin_push_catch_scope";
case IR::Name::builtin_pop_scope:
return "builtin_pop_scope";
case IR::Name::builtin_declare_vars:
void Try::dump(QTextStream &out, Stmt::Mode mode)
{
- out << "try L" << tryBlock->index << "; catch L" << catchBlock->index << ';';
+ out << "try L" << tryBlock->index << "; catch exception as " << exceptionVarName << " and go to L" << catchBlock->index << ';';
}
Function *Module::newFunction(const QString &name, Function *outer)
return s;
}
-Stmt *BasicBlock::TRY(BasicBlock *tryBlock, BasicBlock *catchBlock)
+Stmt *BasicBlock::TRY(BasicBlock *tryBlock, BasicBlock *catchBlock, const QString &exceptionVarName)
{
if (isTerminated())
return 0;
Try *t = function->New<Try>();
- t->init(tryBlock, catchBlock);
+ t->init(tryBlock, catchBlock, exceptionVarName);
statements.append(t);
assert(! out.contains(tryBlock));
builtin_foreach_iterator_object,
builtin_foreach_next_property_name,
builtin_push_with_scope,
- builtin_push_catch_scope,
builtin_pop_scope,
builtin_declare_vars,
builtin_define_property,
struct Try: Stmt {
BasicBlock *tryBlock;
BasicBlock *catchBlock;
+ QString exceptionVarName;
- void init(BasicBlock *tryBlock, BasicBlock *catchBlock)
+ void init(BasicBlock *tryBlock, BasicBlock *catchBlock, const QString &exceptionVarName)
{
this->tryBlock = tryBlock;
this->catchBlock = catchBlock;
+ this->exceptionVarName = exceptionVarName;
}
virtual Stmt *asTerminator() { return this; }
Stmt *JUMP(BasicBlock *target);
Stmt *CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse);
Stmt *RET(Temp *expr);
- Stmt *TRY(BasicBlock *tryBlock, BasicBlock *catchBlock);
+ Stmt *TRY(BasicBlock *tryBlock, BasicBlock *catchBlock, const QString &exceptionVarName);
void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
};