@@ -113,16 +113,6 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
113113 }
114114 }
115115
116- def genThrow (expr : Tree ): Unit = {
117- val thrownKind = tpeTK(expr)
118- // `throw null` is valid although scala.Null (as defined in src/libray-aux) isn't a subtype of Throwable.
119- // Similarly for scala.Nothing (again, as defined in src/libray-aux).
120- assert(thrownKind.isNullType || thrownKind.isNothingType || thrownKind.asClassBType.isSubtypeOf(ThrowableReference ))
121- genLoad(expr, thrownKind)
122- lineNumber(expr)
123- emit(asm.Opcodes .ATHROW ) // ICode enters here into enterIgnoreMode, we'll rely instead on DCE at ClassNode level.
124- }
125-
126116 /* Generate code for primitive arithmetic operations. */
127117 def genArithmeticOp (tree : Tree , code : Int ): BType = tree match {
128118 case Apply (fun @ DesugaredSelect (larg, _), args) =>
@@ -211,7 +201,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
211201 generatedType
212202 }
213203
214- def genLoadIf (tree : If , expectedType : BType ): BType = tree match {
204+ def genLoadIfTo (tree : If , expectedType : BType , dest : LoadDestination ): BType = tree match {
215205 case If (condp, thenp, elsep) =>
216206
217207 val success = new asm.Label
@@ -221,25 +211,37 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
221211 case Literal (value) if value.tag == UnitTag => false
222212 case _ => true
223213 })
224- val postIf = if (hasElse) new asm.Label else failure
225214
226215 genCond(condp, success, failure, targetIfNoJump = success)
227216 markProgramPoint(success)
228217
229- val thenKind = tpeTK(thenp)
230- val elseKind = if (! hasElse) UNIT else tpeTK(elsep)
231- def hasUnitBranch = (thenKind == UNIT || elseKind == UNIT ) && expectedType == UNIT
232- val resKind = if (hasUnitBranch) UNIT else tpeTK(tree)
233-
234- genLoad(thenp, resKind)
235- if (hasElse) { bc goTo postIf }
236- markProgramPoint(failure)
237- if (hasElse) {
238- genLoad(elsep, resKind)
239- markProgramPoint(postIf)
240- }
241-
242- resKind
218+ if dest == LoadDestination .FallThrough then
219+ if hasElse then
220+ val thenKind = tpeTK(thenp)
221+ val elseKind = tpeTK(elsep)
222+ def hasUnitBranch = (thenKind == UNIT || elseKind == UNIT ) && expectedType == UNIT
223+ val resKind = if (hasUnitBranch) UNIT else tpeTK(tree)
224+
225+ val postIf = new asm.Label
226+ genLoadTo(thenp, resKind, LoadDestination .Jump (postIf))
227+ markProgramPoint(failure)
228+ genLoadTo(elsep, resKind, LoadDestination .FallThrough )
229+ markProgramPoint(postIf)
230+ resKind
231+ else
232+ genLoad(thenp, UNIT )
233+ markProgramPoint(failure)
234+ UNIT
235+ end if
236+ else
237+ genLoadTo(thenp, expectedType, dest)
238+ markProgramPoint(failure)
239+ if hasElse then
240+ genLoadTo(elsep, expectedType, dest)
241+ else
242+ genAdaptAndSendToDest(UNIT , expectedType, dest)
243+ expectedType
244+ end if
243245 }
244246
245247 def genPrimitiveOp (tree : Apply , expectedType : BType ): BType = (tree : @ unchecked) match {
@@ -285,8 +287,13 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
285287 }
286288
287289 /* Generate code for trees that produce values on the stack */
288- def genLoad (tree : Tree , expectedType : BType ): Unit = {
290+ def genLoad (tree : Tree , expectedType : BType ): Unit =
291+ genLoadTo(tree, expectedType, LoadDestination .FallThrough )
292+
293+ /* Generate code for trees that produce values, sent to a given `LoadDestination`. */
294+ def genLoadTo (tree : Tree , expectedType : BType , dest : LoadDestination ): Unit =
289295 var generatedType = expectedType
296+ var generatedDest = LoadDestination .FallThrough
290297
291298 lineNumber(tree)
292299
@@ -307,24 +314,29 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
307314 generatedType = UNIT
308315
309316 case t @ If (_, _, _) =>
310- generatedType = genLoadIf(t, expectedType)
317+ generatedType = genLoadIfTo(t, expectedType, dest)
318+ generatedDest = dest
311319
312320 case t @ Labeled (_, _) =>
313- generatedType = genLabeled(t)
321+ generatedType = genLabeledTo(t, expectedType, dest)
322+ generatedDest = dest
314323
315324 case r : Return =>
316325 genReturn(r)
317- generatedType = expectedType
326+ generatedDest = LoadDestination . Return
318327
319328 case t @ WhileDo (_, _) =>
320- generatedType = genWhileDo(t, expectedType)
329+ generatedDest = genWhileDo(t)
330+ generatedType = UNIT
321331
322332 case t @ Try (_, _, _) =>
323333 generatedType = genLoadTry(t)
324334
325335 case t : Apply if t.fun.symbol eq defn.throwMethod =>
326- genThrow(t.args.head)
327- generatedType = expectedType
336+ val thrownExpr = t.args.head
337+ val thrownKind = tpeTK(thrownExpr)
338+ genLoadTo(thrownExpr, thrownKind, LoadDestination .Throw )
339+ generatedDest = LoadDestination .Throw
328340
329341 case New (tpt) =>
330342 abort(s " Unexpected New( ${tpt.tpe.showSummary()}/ $tpt) reached GenBCode. \n " +
@@ -425,12 +437,18 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
425437
426438 case blck @ Block (stats, expr) =>
427439 if (stats.isEmpty)
428- genLoad(expr, expectedType)
429- else genBlock(blck, expectedType)
440+ genLoadTo(expr, expectedType, dest)
441+ else
442+ genBlockTo(blck, expectedType, dest)
443+ generatedDest = dest
430444
431- case Typed (Super (_, _), _) => genLoad(tpd.This (claszSymbol.asClass), expectedType)
445+ case Typed (Super (_, _), _) =>
446+ genLoadTo(tpd.This (claszSymbol.asClass), expectedType, dest)
447+ generatedDest = dest
432448
433- case Typed (expr, _) => genLoad(expr, expectedType)
449+ case Typed (expr, _) =>
450+ genLoadTo(expr, expectedType, dest)
451+ generatedDest = dest
434452
435453 case Assign (_, _) =>
436454 generatedType = UNIT
@@ -440,7 +458,8 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
440458 generatedType = genArrayValue(av)
441459
442460 case mtch @ Match (_, _) =>
443- generatedType = genMatch(mtch)
461+ generatedType = genMatchTo(mtch, expectedType, dest)
462+ generatedDest = dest
444463
445464 case tpd.EmptyTree => if (expectedType != UNIT ) { emitZeroOf(expectedType) }
446465
@@ -451,12 +470,29 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
451470 case _ => abort(s " Unexpected tree in genLoad: $tree/ ${tree.getClass} at: ${tree.span}" )
452471 }
453472
454- // emit conversion
455- if (generatedType != expectedType) {
473+ // emit conversion and send to the right destination
474+ if generatedDest == LoadDestination .FallThrough then
475+ genAdaptAndSendToDest(generatedType, expectedType, dest)
476+ end genLoadTo
477+
478+ def genAdaptAndSendToDest (generatedType : BType , expectedType : BType , dest : LoadDestination ): Unit =
479+ if generatedType != expectedType then
456480 adapt(generatedType, expectedType)
457- }
458481
459- } // end of GenBCode.genLoad()
482+ dest match
483+ case LoadDestination .FallThrough =>
484+ ()
485+ case LoadDestination .Jump (label) =>
486+ bc goTo label
487+ case LoadDestination .Return =>
488+ bc emitRETURN returnType
489+ case LoadDestination .Throw =>
490+ val thrownType = expectedType
491+ // `throw null` is valid although scala.Null (as defined in src/libray-aux) isn't a subtype of Throwable.
492+ // Similarly for scala.Nothing (again, as defined in src/libray-aux).
493+ assert(thrownType.isNullType || thrownType.isNothingType || thrownType.asClassBType.isSubtypeOf(ThrowableReference ))
494+ emit(asm.Opcodes .ATHROW )
495+ end genAdaptAndSendToDest
460496
461497 // ---------------- field load and store ----------------
462498
@@ -533,13 +569,23 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
533569 }
534570 }
535571
536- private def genLabeled (tree : Labeled ): BType = tree match {
572+ private def genLabeledTo (tree : Labeled , expectedType : BType , dest : LoadDestination ): BType = tree match {
537573 case Labeled (bind, expr) =>
538574
539- val resKind = tpeTK(tree)
540- genLoad(expr, resKind)
541- markProgramPoint(programPoint(bind.symbol))
542- resKind
575+ val labelSym = bind.symbol
576+
577+ if dest == LoadDestination .FallThrough then
578+ val resKind = tpeTK(tree)
579+ val jumpTarget = new asm.Label
580+ registerJumpDest(labelSym, resKind, LoadDestination .Jump (jumpTarget))
581+ genLoad(expr, resKind)
582+ markProgramPoint(jumpTarget)
583+ resKind
584+ else
585+ registerJumpDest(labelSym, expectedType, dest)
586+ genLoadTo(expr, expectedType, dest)
587+ expectedType
588+ end if
543589 }
544590
545591 private def genReturn (r : Return ): Unit = {
@@ -548,17 +594,14 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
548594
549595 if (NoSymbol == fromSym) {
550596 // return from enclosing method
551- val returnedKind = tpeTK(expr)
552- genLoad(expr, returnedKind)
553- adapt(returnedKind, returnType)
554- val saveReturnValue = (returnType != UNIT )
555- lineNumber(r)
556-
557597 cleanups match {
558598 case Nil =>
559599 // not an assertion: !shouldEmitCleanup (at least not yet, pendingCleanups() may still have to run, and reset `shouldEmitCleanup`.
560- bc emitRETURN returnType
600+ genLoadTo(expr, returnType, LoadDestination . Return )
561601 case nextCleanup :: rest =>
602+ genLoad(expr, returnType)
603+ lineNumber(r)
604+ val saveReturnValue = (returnType != UNIT )
562605 if (saveReturnValue) {
563606 // regarding return value, the protocol is: in place of a `return-stmt`, a sequence of `adapt, store, jump` are inserted.
564607 if (earlyReturnVar == null ) {
@@ -578,54 +621,39 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
578621 * that cross cleanup boundaries. However, in theory such crossings are valid, so we should take care
579622 * of them.
580623 */
581- val resultKind = toTypeKind(fromSym.info)
582- genLoad(expr, resultKind)
583- lineNumber(r)
584- bc goTo programPoint(fromSym)
624+ val (exprExpectedType, exprDest) = findJumpDest(fromSym)
625+ genLoadTo(expr, exprExpectedType, exprDest)
585626 }
586627 } // end of genReturn()
587628
588- def genWhileDo (tree : WhileDo , expectedType : BType ): BType = tree match {
629+ def genWhileDo (tree : WhileDo ): LoadDestination = tree match {
589630 case WhileDo (cond, body) =>
590631
591632 val isInfinite = cond == tpd.EmptyTree
592633
634+ val loop = new asm.Label
635+ markProgramPoint(loop)
636+
593637 if isInfinite then
594- body match
595- case Labeled (bind, expr) if tpeTK(body) == UNIT =>
596- // this is the shape of tailrec methods
597- val loop = programPoint(bind.symbol)
598- markProgramPoint(loop)
599- genLoad(expr, UNIT )
600- bc goTo loop
601- case _ =>
602- val loop = new asm.Label
603- markProgramPoint(loop)
604- genLoad(body, UNIT )
605- bc goTo loop
606- end match
607- expectedType
638+ val dest = LoadDestination .Jump (loop)
639+ genLoadTo(body, UNIT , dest)
640+ dest
608641 else
609642 body match
610643 case Literal (value) if value.tag == UnitTag =>
611644 // this is the shape of do..while loops
612- val loop = new asm.Label
613- markProgramPoint(loop)
614645 val exitLoop = new asm.Label
615646 genCond(cond, loop, exitLoop, targetIfNoJump = exitLoop)
616647 markProgramPoint(exitLoop)
617648 case _ =>
618- val loop = new asm.Label
619649 val success = new asm.Label
620650 val failure = new asm.Label
621- markProgramPoint(loop)
622651 genCond(cond, success, failure, targetIfNoJump = success)
623652 markProgramPoint(success)
624- genLoad(body, UNIT )
625- bc goTo loop
653+ genLoadTo(body, UNIT , LoadDestination .Jump (loop))
626654 markProgramPoint(failure)
627655 end match
628- UNIT
656+ LoadDestination . FallThrough
629657 }
630658
631659 def genTypeApply (t : TypeApply ): BType = (t : @ unchecked) match {
@@ -848,11 +876,16 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
848876 * Int/String values to use as keys, and a code block. The exception is the "default" case
849877 * clause which doesn't list any key (there is exactly one of these per match).
850878 */
851- private def genMatch (tree : Match ): BType = tree match {
879+ private def genMatchTo (tree : Match , expectedType : BType , dest : LoadDestination ): BType = tree match {
852880 case Match (selector, cases) =>
853881 lineNumber(tree)
854- val generatedType = tpeTK(tree)
855- val postMatch = new asm.Label
882+
883+ val (generatedType, postMatch, postMatchDest) =
884+ if dest == LoadDestination .FallThrough then
885+ val postMatch = new asm.Label
886+ (tpeTK(tree), postMatch, LoadDestination .Jump (postMatch))
887+ else
888+ (expectedType, null , dest)
856889
857890 // Only two possible selector types exist in `Match` trees at this point: Int and String
858891 if (tpeTK(selector) == INT ) {
@@ -902,8 +935,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
902935 for (sb <- switchBlocks.reverse) {
903936 val (caseLabel, caseBody) = sb
904937 markProgramPoint(caseLabel)
905- genLoad(caseBody, generatedType)
906- bc goTo postMatch
938+ genLoadTo(caseBody, generatedType, postMatchDest)
907939 }
908940 } else {
909941
@@ -968,13 +1000,14 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
9681000 }
9691001
9701002 // Push the hashCode of the string (or `0` it is `null`) onto the stack and switch on it
971- genLoadIf (
1003+ genLoadIfTo (
9721004 If (
9731005 tree.selector.select(defn.Any_== ).appliedTo(nullLiteral),
9741006 Literal (Constant (0 )),
9751007 tree.selector.select(defn.Any_hashCode ).appliedToNone
9761008 ),
977- INT
1009+ INT ,
1010+ LoadDestination .FallThrough
9781011 )
9791012 bc.emitSWITCH(mkArrayReverse(flatKeys), mkArrayL(targets.reverse), default, MIN_SWITCH_DENSITY )
9801013
@@ -993,8 +1026,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
9931026 val thisCaseMatches = new asm.Label
9941027 genCond(condp, thisCaseMatches, keepGoing, targetIfNoJump = thisCaseMatches)
9951028 markProgramPoint(thisCaseMatches)
996- genLoad(caseBody, generatedType)
997- bc goTo postMatch
1029+ genLoadTo(caseBody, generatedType, postMatchDest)
9981030 }
9991031 markProgramPoint(keepGoing)
10001032 }
@@ -1004,22 +1036,22 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
10041036 // emit blocks for common patterns
10051037 for ((caseLabel, caseBody) <- indirectBlocks.reverse) {
10061038 markProgramPoint(caseLabel)
1007- genLoad(caseBody, generatedType)
1008- bc goTo postMatch
1039+ genLoadTo(caseBody, generatedType, postMatchDest)
10091040 }
10101041 }
10111042
1012- markProgramPoint(postMatch)
1043+ if postMatch != null then
1044+ markProgramPoint(postMatch)
10131045 generatedType
10141046 }
10151047
1016- def genBlock (tree : Block , expectedType : BType ) = tree match {
1048+ def genBlockTo (tree : Block , expectedType : BType , dest : LoadDestination ) : Unit = tree match {
10171049 case Block (stats, expr) =>
10181050
10191051 val savedScope = varsInScope
10201052 varsInScope = Nil
10211053 stats foreach genStat
1022- genLoad (expr, expectedType)
1054+ genLoadTo (expr, expectedType, dest )
10231055 val end = currProgramPoint()
10241056 if (emitVars) {
10251057 // add entries to LocalVariableTable JVM attribute
0 commit comments