diff options
author | Philipp Haller <hallerp@gmail.com> | 2013-10-13 23:44:18 +0200 |
---|---|---|
committer | Philipp Haller <hallerp@gmail.com> | 2013-10-22 14:40:01 +0200 |
commit | d6c5aeb6f6effcac4a054f0290711aa64ae3c191 (patch) | |
tree | c661375d5d9299466936c9f3df6949b4346e1a85 /src/main/scala/scala/async/internal/ExprBuilder.scala | |
parent | 9ecbb7a54ed0e9927a0efba23fa4e61d06be761e (diff) | |
download | scala-async-d6c5aeb6f6effcac4a054f0290711aa64ae3c191.tar.gz scala-async-d6c5aeb6f6effcac4a054f0290711aa64ae3c191.tar.bz2 scala-async-d6c5aeb6f6effcac4a054f0290711aa64ae3c191.zip |
Liveness analysis to avoid memory retention issues
- Iterative, backwards data-flow analysis
- Make sure fields captured by nested defs are never zeroed out.
This is done elegantly by declaring such fields a being live
at the exit of the final state; thus, they will never be
zeroed out.
Diffstat (limited to 'src/main/scala/scala/async/internal/ExprBuilder.scala')
-rw-r--r-- | src/main/scala/scala/async/internal/ExprBuilder.scala | 24 |
1 files changed, 16 insertions, 8 deletions
diff --git a/src/main/scala/scala/async/internal/ExprBuilder.scala b/src/main/scala/scala/async/internal/ExprBuilder.scala index 438e59e..16e95dd 100644 --- a/src/main/scala/scala/async/internal/ExprBuilder.scala +++ b/src/main/scala/scala/async/internal/ExprBuilder.scala @@ -25,11 +25,13 @@ trait ExprBuilder { trait AsyncState { def state: Int + def nextStates: List[Int] + def mkHandlerCaseForState: CaseDef def mkOnCompleteHandler[T: WeakTypeTag]: Option[CaseDef] = None - def stats: List[Tree] + var stats: List[Tree] final def allStats: List[Tree] = this match { case a: AsyncStateWithAwait => stats :+ a.awaitable.resultValDef @@ -43,9 +45,12 @@ trait ExprBuilder { } /** A sequence of statements that concludes with a unconditional transition to `nextState` */ - final class SimpleAsyncState(val stats: List[Tree], val state: Int, nextState: Int, symLookup: SymLookup) + final class SimpleAsyncState(var stats: List[Tree], val state: Int, nextState: Int, symLookup: SymLookup) extends AsyncState { + def nextStates: List[Int] = + List(nextState) + def mkHandlerCaseForState: CaseDef = mkHandlerCase(state, stats :+ mkStateTree(nextState, symLookup) :+ mkResumeApply(symLookup)) @@ -56,21 +61,24 @@ trait ExprBuilder { /** A sequence of statements with a conditional transition to the next state, which will represent * a branch of an `if` or a `match`. */ - final class AsyncStateWithoutAwait(val stats: List[Tree], val state: Int) extends AsyncState { + final class AsyncStateWithoutAwait(var stats: List[Tree], val state: Int, val nextStates: List[Int]) extends AsyncState { override def mkHandlerCaseForState: CaseDef = mkHandlerCase(state, stats) override val toString: String = - s"AsyncStateWithoutAwait #$state" + s"AsyncStateWithoutAwait #$state, nextStates = $nextStates" } /** A sequence of statements that concludes with an `await` call. The `onComplete` * handler will unconditionally transition to `nextState`. */ - final class AsyncStateWithAwait(val stats: List[Tree], val state: Int, nextState: Int, + final class AsyncStateWithAwait(var stats: List[Tree], val state: Int, nextState: Int, val awaitable: Awaitable, symLookup: SymLookup) extends AsyncState { + def nextStates: List[Int] = + List(nextState) + override def mkHandlerCaseForState: CaseDef = { val callOnComplete = futureSystemOps.onComplete(Expr(awaitable.expr), Expr(This(tpnme.EMPTY)), Expr(Ident(name.execContext))).tree @@ -147,7 +155,7 @@ trait ExprBuilder { def resultWithIf(condTree: Tree, thenState: Int, elseState: Int): AsyncState = { def mkBranch(state: Int) = Block(mkStateTree(state, symLookup) :: Nil, mkResumeApply(symLookup)) this += If(condTree, mkBranch(thenState), mkBranch(elseState)) - new AsyncStateWithoutAwait(stats.toList, state) + new AsyncStateWithoutAwait(stats.toList, state, List(thenState, elseState)) } /** @@ -169,12 +177,12 @@ trait ExprBuilder { } // 2. insert changed match tree at the end of the current state this += Match(scrutTree, newCases) - new AsyncStateWithoutAwait(stats.toList, state) + new AsyncStateWithoutAwait(stats.toList, state, caseStates) } def resultWithLabel(startLabelState: Int, symLookup: SymLookup): AsyncState = { this += Block(mkStateTree(startLabelState, symLookup) :: Nil, mkResumeApply(symLookup)) - new AsyncStateWithoutAwait(stats.toList, state) + new AsyncStateWithoutAwait(stats.toList, state, List(startLabelState)) } override def toString: String = { |