3
3
*/
4
4
package scala .async .internal
5
5
6
+ import scala .collection .mutable
6
7
import scala .collection .mutable .ListBuffer
7
8
import language .existentials
8
9
@@ -117,16 +118,22 @@ trait ExprBuilder {
117
118
* <mkResumeApply>
118
119
* }
119
120
*/
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
+ }
130
137
131
138
override def mkOnCompleteHandler [T : WeakTypeTag ]: Option [CaseDef ] = {
132
139
Some (mkHandlerCase(onCompleteState, List (ifIsFailureTree[T ](Ident (symLookup.applyTrParam)))))
@@ -401,9 +408,10 @@ trait ExprBuilder {
401
408
val stateMemberSymbol = symLookup.stateMachineMember(name.state)
402
409
val stateMemberRef = symLookup.memberRef(name.state)
403
410
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)
404
412
405
- Try (
406
- body ,
413
+ maybeTry (
414
+ body1 ,
407
415
List (
408
416
CaseDef (
409
417
Bind (name.t, Typed (Ident (nme.WILDCARD ), Ident (defn.ThrowableClass ))),
@@ -417,8 +425,67 @@ trait ExprBuilder {
417
425
If (Apply (Ident (defn.NonFatalClass ), List (Ident (name.t))), then , Throw (Ident (name.t)))
418
426
then
419
427
})), EmptyTree )
428
+ }
420
429
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)
422
489
}
423
490
424
491
def forever (t : Tree ): Tree = {
0 commit comments