diff options
Diffstat (limited to 'Build/source/utils/asymptote/stm.cc')
-rw-r--r-- | Build/source/utils/asymptote/stm.cc | 90 |
1 files changed, 57 insertions, 33 deletions
diff --git a/Build/source/utils/asymptote/stm.cc b/Build/source/utils/asymptote/stm.cc index 43f56aea042..d4ffdaa4e81 100644 --- a/Build/source/utils/asymptote/stm.cc +++ b/Build/source/utils/asymptote/stm.cc @@ -181,8 +181,8 @@ void ifStm::prettyprint(ostream &out, Int indent) void ifStm::trans(coenv &e) { - Int elseLabel = e.c.fwdLabel(); - Int end = e.c.fwdLabel(); + label elseLabel = e.c.fwdLabel(); + label end = e.c.fwdLabel(); #ifdef TRANSJUMP test->transConditionalJump(e, false, elseLabel); @@ -209,9 +209,47 @@ void ifStm::trans(coenv &e) void transLoopBody(coenv &e, stm *body) { - e.c.encodePushFrame(); + // The semantics of the language are defined so that any variable declared + // inside a loop are new variables for each iteration of the loop. For + // instance, the code + // + // int f(); + // for (int i = 0; i < 10; ++i) { + // int j=10*i; + // if (i == 5) + // f = new int() { return j; } + // } + // write(f()); + // + // will write 50. This is implemented by allocating a new frame for each + // iteration. However, this can have a big performance hit, so we first + // translate the code without the frame, check if it needed the closure, and + // rewrite the code if necessary. + + label start = e.c.defNewLabel(); + + // Encode a no-op, in case we need to jump over the default implementation + // to a special case. + e.c.encode(inst::nop); + body->markTrans(e); - e.c.encodePopFrame(); + + // Don't re-translate if there were errors. + if (em.errors()) + return; + + if (e.c.usesClosureSinceLabel(start)){ + // Jump over the old section. + label end = e.c.defNewLabel(); + e.c.encodePatch(start, end); + + // Let coder know that break and continue need to pop the frame. + e.c.loopPushesFrame(); + + e.c.encodePushFrame(); + body->markTrans(e); + e.c.encodePopFrame(); + } } void whileStm::prettyprint(ostream &out, Int indent) @@ -224,11 +262,9 @@ void whileStm::prettyprint(ostream &out, Int indent) void whileStm::trans(coenv &e) { - Int end = e.c.fwdLabel(); - e.c.pushBreak(end); - - Int start = e.c.defLabel(); - e.c.pushContinue(start); + label end = e.c.fwdLabel(); + label start = e.c.defNewLabel(); + e.c.pushLoop(start, end); #ifdef TRANSJUMP test->transConditionalJump(e, false, end); @@ -242,8 +278,7 @@ void whileStm::trans(coenv &e) e.c.useLabel(inst::jmp,start); e.c.defLabel(end); - e.c.popBreak(); - e.c.popContinue(); + e.c.popLoop(); } @@ -257,12 +292,11 @@ void doStm::prettyprint(ostream &out, Int indent) void doStm::trans(coenv &e) { - Int testLabel = e.c.fwdLabel(); - e.c.pushContinue(testLabel); - Int end = e.c.fwdLabel(); - e.c.pushBreak(end); + label testLabel = e.c.fwdLabel(); + label end = e.c.fwdLabel(); + e.c.pushLoop(testLabel, end); - Int start = e.c.defLabel(); + label start = e.c.defNewLabel(); transLoopBody(e,body); @@ -277,8 +311,7 @@ void doStm::trans(coenv &e) e.c.defLabel(end); - e.c.popBreak(); - e.c.popContinue(); + e.c.popLoop(); } @@ -299,12 +332,11 @@ void forStm::trans(coenv &e) if (init) init->markTrans(e); - Int ctarget = e.c.fwdLabel(); - e.c.pushContinue(ctarget); - Int end = e.c.fwdLabel(); - e.c.pushBreak(end); + label ctarget = e.c.fwdLabel(); + label end = e.c.fwdLabel(); + e.c.pushLoop(ctarget, end); - Int start = e.c.defLabel(); + label start = e.c.defNewLabel(); if(test) { #ifdef TRANSJUMP test->transConditionalJump(e, false, end); @@ -324,9 +356,9 @@ void forStm::trans(coenv &e) e.c.defLabel(end); + e.c.popLoop(); + e.e.endScope(); - e.c.popBreak(); - e.c.popContinue(); } void extendedForStm::prettyprint(ostream &out, Int indent) @@ -415,10 +447,6 @@ void breakStm::prettyprint(ostream &out, Int indent) void breakStm::trans(coenv &e) { - // Loop bodies have their own frame to declare variables for each iteration. - // Pop out of this frame when jumping out of the loop body. - e.c.encode(inst::popframe); - if (!e.c.encodeBreak()) { em.error(getPos()); em << "break statement outside of a loop"; @@ -433,10 +461,6 @@ void continueStm::prettyprint(ostream &out, Int indent) void continueStm::trans(coenv &e) { - // Loop bodies have their own frame to declare variables for each iteration. - // Pop out of this frame when jumping out of the loop body. - e.c.encode(inst::popframe); - if (!e.c.encodeContinue()) { em.error(getPos()); em << "continue statement outside of a loop"; |