33 */
44package scala .async .internal
55
6+ import scala .collection .mutable
67import scala .collection .mutable .ListBuffer
78import language .existentials
89
@@ -117,16 +118,22 @@ trait ExprBuilder {
117118 * <mkResumeApply>
118119 * }
119120 */
120- def ifIsFailureTree [T : WeakTypeTag ](tryReference : => Tree ) =
121- If (futureSystemOps.tryyIsFailure(c.Expr [futureSystem.Tryy [T ]](tryReference)).tree,
122- Block (toList(futureSystemOps.completeProm[T ](
123- c.Expr [futureSystem.Prom [T ]](symLookup.memberRef(name.result)),
124- c.Expr [futureSystem.Tryy [T ]](
125- TypeApply (Select (tryReference, newTermName(" asInstanceOf" )),
126- List (TypeTree (futureSystemOps.tryType[T ]))))).tree),
127- Return (literalUnit)),
128- Block (List (tryGetTree(tryReference)), mkStateTree(nextState, symLookup))
129- )
121+ def ifIsFailureTree [T : WeakTypeTag ](tryReference : => Tree ) = {
122+ val getAndUpdateState = Block (List (tryGetTree(tryReference)), mkStateTree(nextState, symLookup))
123+ if (asyncBase.futureSystem.emitTryCatch) {
124+ If (futureSystemOps.tryyIsFailure(c.Expr [futureSystem.Tryy [T ]](tryReference)).tree,
125+ Block (toList(futureSystemOps.completeProm[T ](
126+ c.Expr [futureSystem.Prom [T ]](symLookup.memberRef(name.result)),
127+ c.Expr [futureSystem.Tryy [T ]](
128+ TypeApply (Select (tryReference, newTermName(" asInstanceOf" )),
129+ List (TypeTree (futureSystemOps.tryType[T ]))))).tree),
130+ Return (literalUnit)),
131+ getAndUpdateState
132+ )
133+ } else {
134+ getAndUpdateState
135+ }
136+ }
130137
131138 override def mkOnCompleteHandler [T : WeakTypeTag ]: Option [CaseDef ] = {
132139 Some (mkHandlerCase(onCompleteState, List (ifIsFailureTree[T ](Ident (symLookup.applyTrParam)))))
@@ -401,9 +408,10 @@ trait ExprBuilder {
401408 val stateMemberSymbol = symLookup.stateMachineMember(name.state)
402409 val stateMemberRef = symLookup.memberRef(name.state)
403410 val body = Match (stateMemberRef, mkCombinedHandlerCases[T ] ++ initStates.flatMap(_.mkOnCompleteHandler[T ]) ++ List (CaseDef (Ident (nme.WILDCARD ), EmptyTree , Throw (Apply (Select (New (Ident (defn.IllegalStateExceptionClass )), termNames.CONSTRUCTOR ), List ())))))
411+ val body1 = eliminateDeadStates(body)
404412
405- Try (
406- body ,
413+ maybeTry (
414+ body1 ,
407415 List (
408416 CaseDef (
409417 Bind (name.t, Typed (Ident (nme.WILDCARD ), Ident (defn.ThrowableClass ))),
@@ -417,8 +425,67 @@ trait ExprBuilder {
417425 If (Apply (Ident (defn.NonFatalClass ), List (Ident (name.t))), then , Throw (Ident (name.t)))
418426 then
419427 })), EmptyTree )
428+ }
420429
421- // body
430+ // Identify dead states: `case <id> => { state = nextId; (); (); ... }, eliminated, and compact state ids to
431+ // enable emission of a tableswitch.
432+ private def eliminateDeadStates (m : Match ): Tree = {
433+ object DeadState {
434+ private val liveStates = mutable.AnyRefMap [Integer , Integer ]()
435+ private val deadStates = mutable.AnyRefMap [Integer , Integer ]()
436+ private var compactedStateId = 1
437+ for (CaseDef (Literal (Constant (stateId : Integer )), EmptyTree , body) <- m.cases) {
438+ body match {
439+ case _ if (stateId == 0 ) => liveStates(stateId) = stateId
440+ case Block (Assign (_, Literal (Constant (nextState : Integer ))) :: rest, expr) if (expr :: rest).forall(t => isLiteralUnit(t)) =>
441+ deadStates(stateId) = nextState
442+ case _ =>
443+ liveStates(stateId) = compactedStateId
444+ compactedStateId += 1
445+ }
446+ }
447+ if (deadStates.nonEmpty)
448+ AsyncUtils .vprintln(s " ${deadStates.size} dead states eliminated " )
449+ def isDead (i : Integer ) = deadStates.contains(i)
450+ def translatedStateId (i : Integer , tree : Tree ): Integer = {
451+ def chaseDead (i : Integer ): Integer = {
452+ val replacement = deadStates.getOrNull(i)
453+ if (replacement == null ) i
454+ else chaseDead(replacement)
455+ }
456+
457+ val live = chaseDead(i)
458+ liveStates.get(live) match {
459+ case Some (x) => x
460+ case None => sys.error(s " $live, $liveStates \n $deadStates\n $m\n\n ==== \n $tree" )
461+ }
462+ }
463+ }
464+ val stateMemberSymbol = symLookup.stateMachineMember(name.state)
465+ // - remove CaseDef-s for dead states
466+ // - rewrite state transitions to dead states to instead transition to the
467+ // non-dead successor.
468+ val elimDeadStateTransform = new Transformer {
469+ override def transform (tree : Tree ): Tree = tree match {
470+ case as @ Assign (lhs, Literal (Constant (i : Integer ))) if lhs.symbol == stateMemberSymbol =>
471+ val replacement = DeadState .translatedStateId(i, as)
472+ treeCopy.Assign (tree, lhs, Literal (Constant (replacement)))
473+ case _ : Match | _ : CaseDef | _ : Block | _ : If =>
474+ super .transform(tree)
475+ case _ => tree
476+ }
477+ }
478+ val cases1 = m.cases.flatMap {
479+ case cd @ CaseDef (Literal (Constant (i : Integer )), EmptyTree , rhs) =>
480+ if (DeadState .isDead(i)) Nil
481+ else {
482+ val replacement = DeadState .translatedStateId(i, cd)
483+ val rhs1 = elimDeadStateTransform.transform(rhs)
484+ treeCopy.CaseDef (cd, Literal (Constant (replacement)), EmptyTree , rhs1) :: Nil
485+ }
486+ case x => x :: Nil
487+ }
488+ treeCopy.Match (m, m.selector, cases1)
422489 }
423490
424491 def forever (t : Tree ): Tree = {
0 commit comments