# HG changeset patch # User Christian Kamm # Date 1237925898 -3600 # Node ID f99a3b393c035e4d51532d97daecf03658c8afc8 # Parent 45d73f0a9b43de845c88ca9e9ced28a2e20bf94a Reorganize EnclosingHandlers to require less changes to the frontend and allow us to implement the synchronized storage class for functions. diff -r 45d73f0a9b43 -r f99a3b393c03 dmd/func.c --- a/dmd/func.c Tue Mar 24 14:34:16 2009 +0100 +++ b/dmd/func.c Tue Mar 24 21:18:18 2009 +0100 @@ -682,8 +682,8 @@ sc2->explicitProtection = 0; sc2->structalign = 8; sc2->incontract = 0; - sc2->tf = NULL; - sc2->tfOfTry = NULL; + sc2->enclosingFinally = NULL; + sc2->enclosingScopeExit = NULL; sc2->noctor = 0; // Declare 'this' @@ -1243,6 +1243,38 @@ } fbody = new CompoundStatement(0, a); + + // wrap body of synchronized functions in a synchronized statement + if (isSynchronized()) + { + ClassDeclaration *cd = parent->isClassDeclaration(); + if (!cd) + error("synchronized function %s must be a member of a class", toChars()); + + Expression *sync; + if (isStatic()) + { + // static member functions synchronize on classinfo + // (the expression passed doesn't matter) + sync = cd->type->dotExp(sc2, new DollarExp(loc), Id::classinfo); + } + else + { + // non-static member functions synchronize on this + sync = new VarExp(loc, vthis); + } + + // is is ok to not rerun semantic on the whole fbody here; only the enclosingScopeExit + // value will differ and as it is impossible to goto out of this synchronized statement, + // that should not lead to errors + SynchronizedStatement* s = new SynchronizedStatement(loc, sync, NULL); + s->semantic(sc2); + s->body = fbody; + + a = new Statements; + a->push(s); + fbody = new CompoundStatement(0, a); + } } sc2->callSuper = 0; diff -r 45d73f0a9b43 -r f99a3b393c03 dmd/scope.c --- a/dmd/scope.c Tue Mar 24 14:34:16 2009 +0100 +++ b/dmd/scope.c Tue Mar 24 21:18:18 2009 +0100 @@ -52,8 +52,8 @@ this->enclosing = NULL; this->parent = NULL; this->sw = NULL; - this->tf = NULL; - this->tfOfTry = NULL; + this->enclosingFinally = NULL; + this->enclosingScopeExit = NULL; this->tinst = NULL; this->sbreak = NULL; this->scontinue = NULL; @@ -91,8 +91,8 @@ this->scopesym = NULL; this->sd = NULL; this->sw = enclosing->sw; - this->tf = enclosing->tf; - this->tfOfTry = enclosing->tfOfTry; + this->enclosingFinally = enclosing->enclosingFinally; + this->enclosingScopeExit = enclosing->enclosingScopeExit; this->tinst = enclosing->tinst; this->sbreak = enclosing->sbreak; this->scontinue = enclosing->scontinue; diff -r 45d73f0a9b43 -r f99a3b393c03 dmd/scope.h --- a/dmd/scope.h Tue Mar 24 14:34:16 2009 +0100 +++ b/dmd/scope.h Tue Mar 24 21:18:18 2009 +0100 @@ -46,8 +46,8 @@ Dsymbol *parent; // parent to use LabelStatement *slabel; // enclosing labelled statement SwitchStatement *sw; // enclosing switch statement - TryFinallyStatement *tf; // enclosing try finally statement; set inside its finally block - EnclosingHandler *tfOfTry; // enclosing try-finally, volatile or synchronized statement; set inside its try or body block + TryFinallyStatement *enclosingFinally; // enclosing try finally statement; set inside its finally block + Statement *enclosingScopeExit; // enclosing statement that wants to do something on scope exit TemplateInstance *tinst; // enclosing template instance Statement *sbreak; // enclosing statement that supports "break" Statement *scontinue; // enclosing statement that supports "continue" diff -r 45d73f0a9b43 -r f99a3b393c03 dmd/statement.c --- a/dmd/statement.c Tue Mar 24 14:34:16 2009 +0100 +++ b/dmd/statement.c Tue Mar 24 21:18:18 2009 +0100 @@ -582,7 +582,6 @@ : Statement(loc) { statements = s; - enclosinghandler = NULL; } Statement *UnrolledLoopStatement::syntaxCopy() @@ -604,8 +603,6 @@ { //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc); - enclosinghandler = sc->tfOfTry; - sc->noctor++; Scope *scd = sc->push(); scd->sbreak = this; @@ -795,7 +792,6 @@ { condition = c; body = b; - enclosinghandler = NULL; } Statement *WhileStatement::syntaxCopy() @@ -830,8 +826,6 @@ } #endif - enclosinghandler = sc->tfOfTry; - condition = condition->semantic(sc); condition = resolveProperties(sc, condition); condition = condition->optimize(WANTvalue); @@ -919,7 +913,6 @@ { body = b; condition = c; - enclosinghandler = NULL; } Statement *DoStatement::syntaxCopy() @@ -931,8 +924,6 @@ Statement *DoStatement::semantic(Scope *sc) { - enclosinghandler = sc->tfOfTry; - sc->noctor++; if (body) body = body->semanticScope(sc, this, this); @@ -1010,7 +1001,6 @@ this->condition = condition; this->increment = increment; this->body = body; - this->enclosinghandler = NULL; } Statement *ForStatement::syntaxCopy() @@ -1030,8 +1020,6 @@ Statement *ForStatement::semantic(Scope *sc) { - enclosinghandler = sc->tfOfTry; - ScopeDsymbol *sym = new ScopeDsymbol(); sym->parent = sc->scopesym; sc = sc->push(sym); @@ -1169,7 +1157,6 @@ this->arguments = arguments; this->aggr = aggr; this->body = body; - this->enclosinghandler = NULL; this->key = NULL; this->value = NULL; @@ -1197,8 +1184,6 @@ Type *tn = NULL; Type *tnv = NULL; - enclosinghandler = sc->tfOfTry; - func = sc->func; if (func->fes) func = func->fes->func; @@ -2253,8 +2238,6 @@ sdefault = NULL; cases = NULL; hasNoDefault = 0; - // LDC - enclosinghandler = NULL; } Statement *SwitchStatement::syntaxCopy() @@ -2269,8 +2252,6 @@ //printf("SwitchStatement::semantic(%p)\n", this); assert(!cases); // ensure semantic() is only run once - enclosinghandler = sc->tfOfTry; - condition = condition->semantic(sc); condition = resolveProperties(sc, condition); if (condition->type->isString()) @@ -2571,7 +2552,6 @@ : Statement(loc) { sw = NULL; - enclosinghandler = NULL; } Statement *GotoDefaultStatement::syntaxCopy() @@ -2582,7 +2562,6 @@ Statement *GotoDefaultStatement::semantic(Scope *sc) { - enclosinghandler = sc->tfOfTry; sw = sc->sw; if (!sw) error("goto default not in switch statement"); @@ -2606,7 +2585,6 @@ { cs = NULL; this->exp = exp; - enclosinghandler = NULL; sw = NULL; } @@ -2619,7 +2597,6 @@ Statement *GotoCaseStatement::semantic(Scope *sc) { - enclosinghandler = sc->tfOfTry; if (exp) exp = exp->semantic(sc); @@ -2678,7 +2655,6 @@ : Statement(loc) { this->exp = exp; - this->enclosinghandler = NULL; } Statement *ReturnStatement::syntaxCopy() @@ -2693,7 +2669,6 @@ Statement *ReturnStatement::semantic(Scope *sc) { //printf("ReturnStatement::semantic() %s\n", toChars()); - this->enclosinghandler = sc->tfOfTry; FuncDeclaration *fd = sc->parent->isFuncDeclaration(); Scope *scx = sc; @@ -2730,7 +2705,7 @@ if (sc->incontract || scx->incontract) error("return statements cannot be in contracts"); - if (sc->tf || scx->tf) + if (sc->enclosingFinally || scx->enclosingFinally) error("return statements cannot be in finally, scope(exit) or scope(success) bodies"); if (fd->isCtorDeclaration()) @@ -2955,7 +2930,6 @@ : Statement(loc) { this->ident = ident; - this->enclosinghandler = NULL; } Statement *BreakStatement::syntaxCopy() @@ -2967,7 +2941,6 @@ Statement *BreakStatement::semantic(Scope *sc) { //printf("BreakStatement::semantic()\n"); - enclosinghandler = sc->tfOfTry; // If: // break Identifier; if (ident) @@ -3005,7 +2978,7 @@ if (!s->hasBreak()) error("label '%s' has no break", ident->toChars()); - if (ls->tf != sc->tf) + if (ls->enclosingFinally != sc->enclosingFinally) error("cannot break out of finally block"); this->target = ls; @@ -3051,7 +3024,6 @@ : Statement(loc) { this->ident = ident; - this->enclosinghandler = NULL; } Statement *ContinueStatement::syntaxCopy() @@ -3062,7 +3034,6 @@ Statement *ContinueStatement::semantic(Scope *sc) { - enclosinghandler = sc->tfOfTry; //printf("ContinueStatement::semantic() %p\n", this); if (ident) { @@ -3109,7 +3080,7 @@ if (!s->hasContinue()) error("label '%s' has no continue", ident->toChars()); - if (ls->tf != sc->tf) + if (ls->enclosingFinally != sc->enclosingFinally) error("cannot continue out of finally block"); this->target = ls; @@ -3156,7 +3127,6 @@ this->exp = exp; this->body = body; this->esync = NULL; - this->enclosinghandler = NULL; // LDC this->llsync = NULL; } @@ -3167,7 +3137,6 @@ this->exp = NULL; this->body = body; this->esync = esync; - this->enclosinghandler = NULL; // LDC this->llsync = NULL; } @@ -3199,10 +3168,10 @@ } if (body) { - enclosinghandler = sc->tfOfTry; - sc->tfOfTry = new EnclosingSynchro(this); - body = body->semantic(sc); - sc->tfOfTry = enclosinghandler; + Statement* oldScopeExit = sc->enclosingScopeExit; + sc->enclosingScopeExit = this; + body = body->semantic(sc); + sc->enclosingScopeExit = oldScopeExit; } return this; } @@ -3455,7 +3424,7 @@ //printf("Catch::semantic(%s)\n", ident->toChars()); #ifndef IN_GCC - if (sc->tf) + if (sc->enclosingFinally) { /* This is because the _d_local_unwind() gets the stack munged * up on this. The workaround is to place any try-catches into @@ -3516,7 +3485,6 @@ { this->body = body; this->finalbody = finalbody; - this->enclosinghandler = NULL; } Statement *TryFinallyStatement::syntaxCopy() @@ -3530,13 +3498,13 @@ { //printf("TryFinallyStatement::semantic()\n"); - enclosinghandler = sc->tfOfTry; - sc->tfOfTry = new EnclosingTryFinally(this); + Statement* oldScopeExit = sc->enclosingScopeExit; + sc->enclosingScopeExit = this; body = body->semantic(sc); - sc->tfOfTry = enclosinghandler; + sc->enclosingScopeExit = oldScopeExit; sc = sc->push(); - sc->tf = this; + sc->enclosingFinally = this; sc->sbreak = NULL; sc->scontinue = NULL; // no break or continue out of finally block finalbody = finalbody->semantic(sc); @@ -3711,7 +3679,6 @@ : Statement(loc) { this->statement = statement; - this->enclosinghandler = NULL; } Statement *VolatileStatement::syntaxCopy() @@ -3725,10 +3692,10 @@ { if (statement) { - enclosinghandler = sc->tfOfTry; - sc->tfOfTry = new EnclosingVolatile(this); - statement = statement->semantic(sc); - sc->tfOfTry = enclosinghandler; + Statement* oldScopeExit = sc->enclosingScopeExit; + sc->enclosingScopeExit = this; + statement = statement->semantic(sc); + sc->enclosingScopeExit = oldScopeExit; } return this; } @@ -3775,8 +3742,8 @@ { this->ident = ident; this->label = NULL; - this->tf = NULL; - this->enclosinghandler = NULL; + this->enclosingFinally = NULL; + this->enclosingScopeExit = NULL; } Statement *GotoStatement::syntaxCopy() @@ -3789,8 +3756,9 @@ { FuncDeclaration *fd = sc->parent->isFuncDeclaration(); //printf("GotoStatement::semantic()\n"); - tf = sc->tf; - enclosinghandler = sc->tfOfTry; + enclosingFinally = sc->enclosingFinally; + enclosingScopeExit = sc->enclosingScopeExit; + label = fd->searchLabel(ident); if (!label->statement && sc->fes) { @@ -3808,7 +3776,7 @@ sc->fes->gotos.push(s); // 'look at this later' list return s; } - if (label->statement && label->statement->tf != sc->tf) + if (label->statement && label->statement->enclosingFinally != sc->enclosingFinally) error("cannot goto in or out of finally block"); return this; } @@ -3834,8 +3802,8 @@ { this->ident = ident; this->statement = statement; - this->tf = NULL; - this->enclosinghandler = NULL; + this->enclosingFinally = NULL; + this->enclosingScopeExit = NULL; this->lblock = NULL; this->isReturnLabel = 0; this->asmLabel = false; @@ -3857,8 +3825,10 @@ error("Label '%s' already defined", ls->toChars()); else ls->statement = this; - tf = sc->tf; - enclosinghandler = sc->tfOfTry; + + enclosingFinally = sc->enclosingFinally; + enclosingScopeExit = sc->enclosingScopeExit; + sc = sc->push(); sc->scopesym = sc->enclosing->scopesym; sc->callSuper |= CSXlabel; diff -r 45d73f0a9b43 -r f99a3b393c03 dmd/statement.h --- a/dmd/statement.h Tue Mar 24 14:34:16 2009 +0100 +++ b/dmd/statement.h Tue Mar 24 21:18:18 2009 +0100 @@ -94,35 +94,6 @@ BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt), }; -// LDC this is used for tracking try-finally, synchronized and volatile scopes -// definitions in gen/llvmhelpers.cpp -struct EnclosingHandler : Object -{ - virtual void emitCode(IRState* p) = 0; - virtual EnclosingHandler* getEnclosing() = 0; -}; -struct EnclosingTryFinally : EnclosingHandler -{ - TryFinallyStatement* tf; - void emitCode(IRState* p); - EnclosingHandler* getEnclosing(); - EnclosingTryFinally(TryFinallyStatement* _tf) : tf(_tf) {} -}; -struct EnclosingVolatile : EnclosingHandler -{ - VolatileStatement* v; - void emitCode(IRState* p); - EnclosingHandler* getEnclosing(); - EnclosingVolatile(VolatileStatement* _tf) : v(_tf) {} -}; -struct EnclosingSynchro : EnclosingHandler -{ - SynchronizedStatement* s; - void emitCode(IRState* p); - EnclosingHandler* getEnclosing(); - EnclosingSynchro(SynchronizedStatement* _tf) : s(_tf) {} -}; - struct Statement : Object { Loc loc; @@ -255,7 +226,6 @@ struct UnrolledLoopStatement : Statement { Statements *statements; - EnclosingHandler* enclosinghandler; UnrolledLoopStatement(Loc loc, Statements *statements); Statement *syntaxCopy(); @@ -300,7 +270,6 @@ { Expression *condition; Statement *body; - EnclosingHandler* enclosinghandler; WhileStatement(Loc loc, Expression *c, Statement *b); Statement *syntaxCopy(); @@ -322,7 +291,6 @@ { Statement *body; Expression *condition; - EnclosingHandler* enclosinghandler; DoStatement(Loc loc, Statement *b, Expression *c); Statement *syntaxCopy(); @@ -346,7 +314,6 @@ Expression *condition; Expression *increment; Statement *body; - EnclosingHandler* enclosinghandler; ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body); Statement *syntaxCopy(); @@ -371,7 +338,6 @@ Arguments *arguments; // array of Argument*'s Expression *aggr; Statement *body; - EnclosingHandler* enclosinghandler; VarDeclaration *key; VarDeclaration *value; @@ -499,7 +465,6 @@ Statement *body; DefaultStatement *sdefault; - EnclosingHandler* enclosinghandler; Array gotoCases; // array of unresolved GotoCaseStatement's Array *cases; // array of CaseStatement's @@ -574,7 +539,6 @@ struct GotoDefaultStatement : Statement { SwitchStatement *sw; - EnclosingHandler* enclosinghandler; GotoDefaultStatement(Loc loc); Statement *syntaxCopy(); @@ -590,7 +554,6 @@ { Expression *exp; // NULL, or which case to goto CaseStatement *cs; // case statement it resolves to - EnclosingHandler* enclosinghandler; SwitchStatement *sw; GotoCaseStatement(Loc loc, Expression *exp); @@ -615,7 +578,6 @@ struct ReturnStatement : Statement { Expression *exp; - EnclosingHandler* enclosinghandler; ReturnStatement(Loc loc, Expression *exp); Statement *syntaxCopy(); @@ -636,7 +598,6 @@ struct BreakStatement : Statement { Identifier *ident; - EnclosingHandler* enclosinghandler; BreakStatement(Loc loc, Identifier *ident); Statement *syntaxCopy(); @@ -654,7 +615,6 @@ struct ContinueStatement : Statement { Identifier *ident; - EnclosingHandler* enclosinghandler; ContinueStatement(Loc loc, Identifier *ident); Statement *syntaxCopy(); @@ -673,7 +633,6 @@ { Expression *exp; Statement *body; - EnclosingHandler* enclosinghandler; SynchronizedStatement(Loc loc, Expression *exp, Statement *body); Statement *syntaxCopy(); @@ -749,7 +708,6 @@ { Statement *body; Statement *finalbody; - EnclosingHandler* enclosinghandler; TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody); Statement *syntaxCopy(); @@ -799,7 +757,6 @@ struct VolatileStatement : Statement { Statement *statement; - EnclosingHandler* enclosinghandler; VolatileStatement(Loc loc, Statement *statement); Statement *syntaxCopy(); @@ -817,8 +774,8 @@ { Identifier *ident; LabelDsymbol *label; - TryFinallyStatement *tf; - EnclosingHandler* enclosinghandler; + TryFinallyStatement *enclosingFinally; + Statement* enclosingScopeExit; GotoStatement(Loc loc, Identifier *ident); Statement *syntaxCopy(); @@ -835,8 +792,8 @@ { Identifier *ident; Statement *statement; - TryFinallyStatement *tf; - EnclosingHandler* enclosinghandler; + TryFinallyStatement *enclosingFinally; + Statement* enclosingScopeExit; block *lblock; // back end int isReturnLabel; @@ -895,8 +852,8 @@ struct AsmBlockStatement : CompoundStatement { - EnclosingHandler* enclosinghandler; - TryFinallyStatement* tf; + TryFinallyStatement* enclosingFinally; + Statement* enclosingScopeExit; AsmBlockStatement(Loc loc, Statements *s); Statements *flatten(Scope *sc); diff -r 45d73f0a9b43 -r f99a3b393c03 gen/asmstmt.cpp --- a/gen/asmstmt.cpp Tue Mar 24 14:34:16 2009 +0100 +++ b/gen/asmstmt.cpp Tue Mar 24 21:18:18 2009 +0100 @@ -444,8 +444,8 @@ AsmBlockStatement::AsmBlockStatement(Loc loc, Statements* s) : CompoundStatement(loc, s) { - enclosinghandler = NULL; - tf = NULL; + enclosingFinally = NULL; + enclosingScopeExit = NULL; abiret = NULL; } @@ -772,7 +772,7 @@ sw->addCase(llvm::ConstantInt::get(llvm::IntegerType::get(32), it->second), casebb); p->scope() = IRScope(casebb,bb); - DtoGoto(&loc, it->first, enclosinghandler, tf); + DtoGoto(loc, it->first); } p->scope() = IRScope(bb,oldend); @@ -803,8 +803,8 @@ // necessary for in-asm branches Statement *AsmBlockStatement::semantic(Scope *sc) { - enclosinghandler = sc->tfOfTry; - tf = sc->tf; + enclosingFinally = sc->enclosingFinally; + enclosingScopeExit = sc->enclosingScopeExit; return CompoundStatement::semantic(sc); } diff -r 45d73f0a9b43 -r f99a3b393c03 gen/irstate.cpp --- a/gen/irstate.cpp Tue Mar 24 14:34:16 2009 +0100 +++ b/gen/irstate.cpp Tue Mar 24 21:18:18 2009 +0100 @@ -34,18 +34,16 @@ } ////////////////////////////////////////////////////////////////////////////////////////// -IRLoopScope::IRLoopScope() +IRTargetScope::IRTargetScope() { } -IRLoopScope::IRLoopScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* b, llvm::BasicBlock* e, bool isSwitch) +IRTargetScope::IRTargetScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* continueTarget, llvm::BasicBlock* breakTarget) { - begin = b; - end = e; - //builder.SetInsertPoint(b); this->s = s; this->enclosinghandler = enclosinghandler; - this->isSwitch = isSwitch; + this->breakTarget = breakTarget; + this->continueTarget = continueTarget; } ////////////////////////////////////////////////////////////////////////////////////////// diff -r 45d73f0a9b43 -r f99a3b393c03 gen/irstate.h --- a/gen/irstate.h Tue Mar 24 14:34:16 2009 +0100 +++ b/gen/irstate.h Tue Mar 24 21:18:18 2009 +0100 @@ -51,19 +51,21 @@ IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e); }; -// scope for loops -struct IRLoopScope : IRScope +// scope statements that can be target of jumps +// includes loops, switch, case, labels +struct IRTargetScope { // generating statement Statement* s; + // the try of a TryFinally that encloses the loop EnclosingHandler* enclosinghandler; - // if it is a switch, we are a possible target for break - // but not for continue - bool isSwitch; + + llvm::BasicBlock* breakTarget; + llvm::BasicBlock* continueTarget; - IRLoopScope(); - IRLoopScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* b, llvm::BasicBlock* e, bool isSwitch = false); + IRTargetScope(); + IRTargetScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* continueTarget, llvm::BasicBlock* breakTarget); }; struct IRBuilderHelper @@ -158,8 +160,8 @@ llvm::CallSite CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name=""); // loop blocks - typedef std::vector LoopScopeVec; - LoopScopeVec loopbbs; + typedef std::vector TargetScopeVec; + TargetScopeVec targetScopes; // this holds the array being indexed or sliced so $ will work // might be a better way but it works. problem is I only get a diff -r 45d73f0a9b43 -r f99a3b393c03 gen/llvmhelpers.cpp --- a/gen/llvmhelpers.cpp Tue Mar 24 14:34:16 2009 +0100 +++ b/gen/llvmhelpers.cpp Tue Mar 24 21:18:18 2009 +0100 @@ -110,7 +110,7 @@ // ASSERT HELPER ////////////////////////////////////////////////////////////////////////////////////////*/ -void DtoAssert(Module* M, Loc* loc, DValue* msg) +void DtoAssert(Module* M, Loc loc, DValue* msg) { std::vector args; @@ -133,7 +133,7 @@ args.push_back(DtoLoad(M->ir.irModule->fileName)); // line param - LLConstant* c = DtoConstUint(loc->linnum); + LLConstant* c = DtoConstUint(loc.linnum); args.push_back(c); // call @@ -172,19 +172,19 @@ /*//////////////////////////////////////////////////////////////////////////////////////// // GOTO HELPER ////////////////////////////////////////////////////////////////////////////////////////*/ -void DtoGoto(Loc* loc, Identifier* target, EnclosingHandler* enclosinghandler, TryFinallyStatement* sourcetf) +void DtoGoto(Loc loc, Identifier* target) { assert(!gIR->scopereturned()); LabelStatement* lblstmt = DtoLabelStatement(target); if(!lblstmt) { - error(*loc, "the label %s does not exist", target->toChars()); + error(loc, "the label %s does not exist", target->toChars()); fatal(); } // if the target label is inside inline asm, error if(lblstmt->asmLabel) { - error(*loc, "cannot goto to label %s inside an inline asm block", target->toChars()); + error(loc, "cannot goto to label %s inside an inline asm block", target->toChars()); fatal(); } @@ -194,25 +194,16 @@ if (targetBB == NULL) targetBB = llvm::BasicBlock::Create("label_" + labelname, gIR->topfunc()); - // find finallys between goto and label - EnclosingHandler* endfinally = enclosinghandler; - while(endfinally != NULL && endfinally != lblstmt->enclosinghandler) { - endfinally = endfinally->getEnclosing(); - } - - // error if didn't find tf statement of label - if(endfinally != lblstmt->enclosinghandler) - error(*loc, "cannot goto into try block"); + // emit code for finallys between goto and label + DtoEnclosingHandlers(loc, lblstmt); // goto into finally blocks is forbidden by the spec - // though it should not be problematic to implement + // but should work fine + /* if(lblstmt->tf != sourcetf) { - error(*loc, "spec disallows goto into finally block"); + error(loc, "spec disallows goto into finally block"); fatal(); - } - - // emit code for finallys between goto and label - DtoEnclosingHandlers(enclosinghandler, endfinally); + }*/ llvm::BranchInst::Create(targetBB, gIR->scopebb()); } @@ -225,16 +216,11 @@ void EnclosingSynchro::emitCode(IRState * p) { if (s->exp) - DtoLeaveMonitor(s->llsync); + DtoLeaveMonitor(s->exp->toElem(p)->getRVal()); else DtoLeaveCritical(s->llsync); } -EnclosingHandler* EnclosingSynchro::getEnclosing() -{ - return s->enclosinghandler; -} - //////////////////////////////////////////////////////////////////////////////////////// void EnclosingVolatile::emitCode(IRState * p) @@ -243,11 +229,6 @@ DtoMemoryBarrier(false, false, true, false); } -EnclosingHandler* EnclosingVolatile::getEnclosing() -{ - return v->enclosinghandler; -} - //////////////////////////////////////////////////////////////////////////////////////// void EnclosingTryFinally::emitCode(IRState * p) @@ -256,34 +237,43 @@ tf->finalbody->toIR(p); } -EnclosingHandler* EnclosingTryFinally::getEnclosing() -{ - return tf->enclosinghandler; -} - //////////////////////////////////////////////////////////////////////////////////////// -void DtoEnclosingHandlers(EnclosingHandler* start, EnclosingHandler* end) +void DtoEnclosingHandlers(Loc loc, Statement* target) { - // verify that end encloses start - EnclosingHandler* endfinally = start; - while(endfinally != NULL && endfinally != end) { - endfinally = endfinally->getEnclosing(); + // labels are a special case: they are not required to enclose the current scope + // for them we use the enclosing scope handler as a reference point + LabelStatement* lblstmt = dynamic_cast(target); + if (lblstmt) + target = lblstmt->enclosingScopeExit; + + // figure out up until what handler we need to emit + IRState::TargetScopeVec::reverse_iterator targetit; + for (targetit = gIR->targetScopes.rbegin(); targetit != gIR->targetScopes.rend(); ++targetit) { + if (targetit->s == target) { + break; + } } - assert(endfinally == end); + if (target && targetit == gIR->targetScopes.rend()) { + if (lblstmt) + error(loc, "cannot goto into try, volatile or synchronized statement at %s", target->loc.toChars()); + else + error(loc, "internal error, cannot find jump path to statement at %s", target->loc.toChars()); + return; + } // - // emit code for finallys between start and end + // emit code for enclosing handlers // // since the labelstatements possibly inside are private // and might already exist push a label scope gIR->func()->pushUniqueLabelScope("enclosing"); - EnclosingHandler* tf = start; - while(tf != end) { - tf->emitCode(gIR); - tf = tf->getEnclosing(); + IRState::TargetScopeVec::reverse_iterator it; + for (it = gIR->targetScopes.rbegin(); it != targetit; ++it) { + if (it->enclosinghandler) + it->enclosinghandler->emitCode(gIR); } gIR->func()->popLabelScope(); } diff -r 45d73f0a9b43 -r f99a3b393c03 gen/llvmhelpers.h --- a/gen/llvmhelpers.h Tue Mar 24 14:34:16 2009 +0100 +++ b/gen/llvmhelpers.h Tue Mar 24 21:18:18 2009 +0100 @@ -4,6 +4,31 @@ #include "gen/llvm.h" #include "statement.h" +// this is used for tracking try-finally, synchronized and volatile scopes +struct EnclosingHandler +{ + virtual void emitCode(IRState* p) = 0; +}; +struct EnclosingTryFinally : EnclosingHandler +{ + TryFinallyStatement* tf; + void emitCode(IRState* p); + EnclosingTryFinally(TryFinallyStatement* _tf) : tf(_tf) {} +}; +struct EnclosingVolatile : EnclosingHandler +{ + VolatileStatement* v; + void emitCode(IRState* p); + EnclosingVolatile(VolatileStatement* _tf) : v(_tf) {} +}; +struct EnclosingSynchro : EnclosingHandler +{ + SynchronizedStatement* s; + void emitCode(IRState* p); + EnclosingSynchro(SynchronizedStatement* _tf) : s(_tf) {} +}; + + // dynamic memory helpers LLValue* DtoNew(Type* newtype); void DtoDeleteMemory(LLValue* ptr); @@ -16,17 +41,16 @@ llvm::AllocaInst* DtoAlloca(const LLType* lltype, LLValue* arraysize, const std::string& name = ""); // assertion generator -void DtoAssert(Module* M, Loc* loc, DValue* msg); +void DtoAssert(Module* M, Loc loc, DValue* msg); // return the LabelStatement from the current function with the given identifier or NULL if not found LabelStatement* DtoLabelStatement(Identifier* ident); // emit goto -void DtoGoto(Loc* loc, Identifier* target, EnclosingHandler* enclosingtryfinally, TryFinallyStatement* sourcetf); +void DtoGoto(Loc loc, Identifier* target); -// generates IR for finally blocks between the 'start' and 'end' statements -// will begin with the finally block belonging to 'start' and does not include -// the finally block of 'end' -void DtoEnclosingHandlers(EnclosingHandler* start, EnclosingHandler* end); +// Generates IR for enclosing handlers between the current state and +// the scope created by the 'target' statement. +void DtoEnclosingHandlers(Loc loc, Statement* target); // enters a critical section void DtoEnterCritical(LLValue* g); diff -r 45d73f0a9b43 -r f99a3b393c03 gen/statements.cpp --- a/gen/statements.cpp Tue Mar 24 14:34:16 2009 +0100 +++ b/gen/statements.cpp Tue Mar 24 21:18:18 2009 +0100 @@ -76,7 +76,7 @@ DtoAssign(loc, rvar, e); // emit scopes - DtoEnclosingHandlers(enclosinghandler, NULL); + DtoEnclosingHandlers(loc, NULL); // emit dbg end function if (global.params.symdebug) DtoDwarfFuncEnd(f->decl); @@ -122,7 +122,7 @@ Logger::cout() << "return value after cast: " << *v << '\n'; } - DtoEnclosingHandlers(enclosinghandler, NULL); + DtoEnclosingHandlers(loc, NULL); if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl); llvm::ReturnInst::Create(v, p->scopebb()); @@ -132,7 +132,7 @@ else { assert(p->topfunc()->getReturnType() == LLType::VoidTy); - DtoEnclosingHandlers(enclosinghandler, NULL); + DtoEnclosingHandlers(loc, NULL); if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl); llvm::ReturnInst::Create(p->scopebb()); @@ -296,9 +296,9 @@ gIR->scope() = IRScope(whilebodybb,endbb); // while body code - p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,whilebb,endbb)); + p->targetScopes.push_back(IRTargetScope(this,NULL,whilebb,endbb)); body->toIR(p); - p->loopbbs.pop_back(); + p->targetScopes.pop_back(); // loop if (!gIR->scopereturned()) @@ -332,9 +332,9 @@ gIR->scope() = IRScope(dowhilebb,condbb); // do-while body code - p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,condbb,endbb)); + p->targetScopes.push_back(IRTargetScope(this,NULL,condbb,endbb)); body->toIR(p); - p->loopbbs.pop_back(); + p->targetScopes.pop_back(); // branch to condition block llvm::BranchInst::Create(condbb, gIR->scopebb()); @@ -377,7 +377,7 @@ assert(!gIR->scopereturned()); llvm::BranchInst::Create(forbb, gIR->scopebb()); - p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,forincbb,endbb)); + p->targetScopes.push_back(IRTargetScope(this,NULL,forincbb,endbb)); // replace current scope gIR->scope() = IRScope(forbb,forbodybb); @@ -420,7 +420,7 @@ if (!gIR->scopereturned()) llvm::BranchInst::Create(forbb, gIR->scopebb()); - p->loopbbs.pop_back(); + p->targetScopes.pop_back(); // rewrite the scope gIR->scope() = IRScope(endbb,oldend); @@ -444,7 +444,7 @@ if (ident != 0) { Logger::println("ident = %s", ident->toChars()); - DtoEnclosingHandlers(enclosinghandler, target->enclosinghandler); + DtoEnclosingHandlers(loc, target); // get the loop statement the label refers to Statement* targetLoopStatement = target->statement; @@ -454,10 +454,10 @@ // find the right break block and jump there bool found = false; - IRState::LoopScopeVec::reverse_iterator it; - for(it = p->loopbbs.rbegin(); it != p->loopbbs.rend(); ++it) { + IRState::TargetScopeVec::reverse_iterator it; + for(it = p->targetScopes.rbegin(); it != p->targetScopes.rend(); ++it) { if(it->s == targetLoopStatement) { - llvm::BranchInst::Create(it->end, p->scopebb()); + llvm::BranchInst::Create(it->breakTarget, p->scopebb()); found = true; break; } @@ -465,8 +465,15 @@ assert(found); } else { - DtoEnclosingHandlers(enclosinghandler, p->loopbbs.back().enclosinghandler); - llvm::BranchInst::Create(p->loopbbs.back().end, p->scopebb()); + // find closest scope with a break target + IRState::TargetScopeVec::reverse_iterator it; + for(it = gIR->targetScopes.rbegin(); it != gIR->targetScopes.rend(); ++it) { + if(it->breakTarget) { + break; + } + } + DtoEnclosingHandlers(loc, it->s); + llvm::BranchInst::Create(it->breakTarget, gIR->scopebb()); } // the break terminated this basicblock, start a new one @@ -488,7 +495,7 @@ if (ident != 0) { Logger::println("ident = %s", ident->toChars()); - DtoEnclosingHandlers(enclosinghandler, target->enclosinghandler); + DtoEnclosingHandlers(loc, target); // get the loop statement the label refers to Statement* targetLoopStatement = target->statement; @@ -498,10 +505,10 @@ // find the right continue block and jump there bool found = false; - IRState::LoopScopeVec::reverse_iterator it; - for(it = gIR->loopbbs.rbegin(); it != gIR->loopbbs.rend(); ++it) { + IRState::TargetScopeVec::reverse_iterator it; + for(it = gIR->targetScopes.rbegin(); it != gIR->targetScopes.rend(); ++it) { if(it->s == targetLoopStatement) { - llvm::BranchInst::Create(it->begin, gIR->scopebb()); + llvm::BranchInst::Create(it->continueTarget, gIR->scopebb()); found = true; break; } @@ -509,15 +516,15 @@ assert(found); } else { - // can't 'continue' within switch, so omit them - IRState::LoopScopeVec::reverse_iterator it; - for(it = gIR->loopbbs.rbegin(); it != gIR->loopbbs.rend(); ++it) { - if(!it->isSwitch) { + // find closest scope with a continue target + IRState::TargetScopeVec::reverse_iterator it; + for(it = gIR->targetScopes.rbegin(); it != gIR->targetScopes.rend(); ++it) { + if(it->continueTarget) { break; } } - DtoEnclosingHandlers(enclosinghandler, it->enclosinghandler); - llvm::BranchInst::Create(it->begin, gIR->scopebb()); + DtoEnclosingHandlers(loc, it->s); + llvm::BranchInst::Create(it->continueTarget, gIR->scopebb()); } // the continue terminated this basicblock, start a new one @@ -586,7 +593,9 @@ p->scope() = IRScope(trybb,finallybb); assert(body); + p->targetScopes.push_back(IRTargetScope(this,new EnclosingTryFinally(this),NULL,NULL)); body->toIR(p); + p->targetScopes.pop_back(); // terminate try BB if (!p->scopereturned()) @@ -842,9 +851,9 @@ assert(body); p->scope() = IRScope(bodybb, endbb); - p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,p->scopebb(),endbb,true)); + p->targetScopes.push_back(IRTargetScope(this,NULL,NULL,endbb)); body->toIR(p); - p->loopbbs.pop_back(); + p->targetScopes.pop_back(); if (!p->scopereturned()) llvm::BranchInst::Create(endbb, p->scopebb()); @@ -963,13 +972,13 @@ // push loop scope // continue goes to next statement, break goes to end - p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,nextbb,endbb)); + p->targetScopes.push_back(IRTargetScope(this,NULL,nextbb,endbb)); // do statement s->toIR(p); // pop loop scope - p->loopbbs.pop_back(); + p->targetScopes.pop_back(); // next stmt if (!p->scopereturned()) @@ -1086,10 +1095,10 @@ } // emit body - p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,nextbb,endbb)); + p->targetScopes.push_back(IRTargetScope(this,NULL,nextbb,endbb)); if(body) body->toIR(p); - p->loopbbs.pop_back(); + p->targetScopes.pop_back(); if (!p->scopereturned()) llvm::BranchInst::Create(nextbb, p->scopebb()); @@ -1182,10 +1191,10 @@ } // emit body - p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,nextbb,endbb)); + p->targetScopes.push_back(IRTargetScope(this,NULL,nextbb,endbb)); if (body) body->toIR(p); - p->loopbbs.pop_back(); + p->targetScopes.pop_back(); // jump to next iteration if (!p->scopereturned()) @@ -1251,8 +1260,11 @@ p->scope() = IRScope(labelBB,oldend); } - if (statement) + if (statement) { + p->targetScopes.push_back(IRTargetScope(this,NULL,NULL,NULL)); statement->toIR(p); + p->targetScopes.pop_back(); + } } ////////////////////////////////////////////////////////////////////////////// @@ -1268,7 +1280,7 @@ llvm::BasicBlock* oldend = gIR->scopeend(); llvm::BasicBlock* bb = llvm::BasicBlock::Create("aftergoto", p->topfunc(), oldend); - DtoGoto(&loc, label->ident, enclosinghandler, tf); + DtoGoto(loc, label->ident); p->scope() = IRScope(bb,oldend); } @@ -1289,7 +1301,7 @@ assert(!p->scopereturned()); assert(sw->sdefault->bodyBB); - DtoEnclosingHandlers(enclosinghandler, sw->enclosinghandler); + DtoEnclosingHandlers(loc, sw); llvm::BranchInst::Create(sw->sdefault->bodyBB, p->scopebb()); p->scope() = IRScope(bb,oldend); @@ -1314,7 +1326,7 @@ cs->bodyBB = llvm::BasicBlock::Create("goto_case", p->topfunc(), p->scopeend()); } - DtoEnclosingHandlers(enclosinghandler, sw->enclosinghandler); + DtoEnclosingHandlers(loc, sw); llvm::BranchInst::Create(cs->bodyBB, p->scopebb()); p->scope() = IRScope(bb,oldend); @@ -1373,7 +1385,9 @@ } // emit body + p->targetScopes.push_back(IRTargetScope(this,new EnclosingSynchro(this),NULL,NULL)); body->toIR(p); + p->targetScopes.pop_back(); // exit lock // no point in a unreachable unlock, terminating statements must insert this themselves. @@ -1405,7 +1419,9 @@ DtoMemoryBarrier(false, true, false, false); // do statement + p->targetScopes.push_back(IRTargetScope(this,new EnclosingVolatile(this),NULL,NULL)); statement->toIR(p); + p->targetScopes.pop_back(); // no point in a unreachable barrier, terminating statements must insert this themselves. if (statement->blockExit() & BEfallthru) diff -r 45d73f0a9b43 -r f99a3b393c03 gen/toir.cpp --- a/gen/toir.cpp Tue Mar 24 14:34:16 2009 +0100 +++ b/gen/toir.cpp Tue Mar 24 21:18:18 2009 +0100 @@ -1783,7 +1783,7 @@ // call assert runtime functions p->scope() = IRScope(assertbb,endbb); - DtoAssert(p->func()->decl->getModule(), &loc, msg ? msg->toElem(p) : NULL); + DtoAssert(p->func()->decl->getModule(), loc, msg ? msg->toElem(p) : NULL); // rewrite the scope p->scope() = IRScope(endbb,oldend); @@ -1958,7 +1958,7 @@ // FIXME: DMD inserts a trap here... we probably should as well !?! #if 1 - DtoAssert(p->func()->decl->getModule(), &loc, NULL); + DtoAssert(p->func()->decl->getModule(), loc, NULL); #else // call the new (?) trap intrinsic p->ir->CreateCall(GET_INTRINSIC_DECL(trap),"");