@@ -113,16 +113,6 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
113
113
}
114
114
}
115
115
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
-
126
116
/* Generate code for primitive arithmetic operations. */
127
117
def genArithmeticOp (tree : Tree , code : Int ): BType = tree match {
128
118
case Apply (fun @ DesugaredSelect (larg, _), args) =>
@@ -211,7 +201,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
211
201
generatedType
212
202
}
213
203
214
- def genLoadIf (tree : If , expectedType : BType ): BType = tree match {
204
+ def genLoadIfTo (tree : If , expectedType : BType , dest : LoadDestination ): BType = tree match {
215
205
case If (condp, thenp, elsep) =>
216
206
217
207
val success = new asm.Label
@@ -221,25 +211,37 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
221
211
case Literal (value) if value.tag == UnitTag => false
222
212
case _ => true
223
213
})
224
- val postIf = if (hasElse) new asm.Label else failure
225
214
226
215
genCond(condp, success, failure, targetIfNoJump = success)
227
216
markProgramPoint(success)
228
217
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
243
245
}
244
246
245
247
def genPrimitiveOp (tree : Apply , expectedType : BType ): BType = (tree : @ unchecked) match {
@@ -285,8 +287,13 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
285
287
}
286
288
287
289
/* 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 =
289
295
var generatedType = expectedType
296
+ var generatedDest = LoadDestination .FallThrough
290
297
291
298
lineNumber(tree)
292
299
@@ -307,24 +314,29 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
307
314
generatedType = UNIT
308
315
309
316
case t @ If (_, _, _) =>
310
- generatedType = genLoadIf(t, expectedType)
317
+ generatedType = genLoadIfTo(t, expectedType, dest)
318
+ generatedDest = dest
311
319
312
320
case t @ Labeled (_, _) =>
313
- generatedType = genLabeled(t)
321
+ generatedType = genLabeledTo(t, expectedType, dest)
322
+ generatedDest = dest
314
323
315
324
case r : Return =>
316
325
genReturn(r)
317
- generatedType = expectedType
326
+ generatedDest = LoadDestination . Return
318
327
319
328
case t @ WhileDo (_, _) =>
320
- generatedType = genWhileDo(t, expectedType)
329
+ generatedDest = genWhileDo(t)
330
+ generatedType = UNIT
321
331
322
332
case t @ Try (_, _, _) =>
323
333
generatedType = genLoadTry(t)
324
334
325
335
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
328
340
329
341
case New (tpt) =>
330
342
abort(s " Unexpected New( ${tpt.tpe.showSummary()}/ $tpt) reached GenBCode. \n " +
@@ -425,12 +437,18 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
425
437
426
438
case blck @ Block (stats, expr) =>
427
439
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
430
444
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
432
448
433
- case Typed (expr, _) => genLoad(expr, expectedType)
449
+ case Typed (expr, _) =>
450
+ genLoadTo(expr, expectedType, dest)
451
+ generatedDest = dest
434
452
435
453
case Assign (_, _) =>
436
454
generatedType = UNIT
@@ -440,7 +458,8 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
440
458
generatedType = genArrayValue(av)
441
459
442
460
case mtch @ Match (_, _) =>
443
- generatedType = genMatch(mtch)
461
+ generatedType = genMatchTo(mtch, expectedType, dest)
462
+ generatedDest = dest
444
463
445
464
case tpd.EmptyTree => if (expectedType != UNIT ) { emitZeroOf(expectedType) }
446
465
@@ -451,12 +470,29 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
451
470
case _ => abort(s " Unexpected tree in genLoad: $tree/ ${tree.getClass} at: ${tree.span}" )
452
471
}
453
472
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
456
480
adapt(generatedType, expectedType)
457
- }
458
481
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
460
496
461
497
// ---------------- field load and store ----------------
462
498
@@ -533,13 +569,23 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
533
569
}
534
570
}
535
571
536
- private def genLabeled (tree : Labeled ): BType = tree match {
572
+ private def genLabeledTo (tree : Labeled , expectedType : BType , dest : LoadDestination ): BType = tree match {
537
573
case Labeled (bind, expr) =>
538
574
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
543
589
}
544
590
545
591
private def genReturn (r : Return ): Unit = {
@@ -548,17 +594,14 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
548
594
549
595
if (NoSymbol == fromSym) {
550
596
// 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
-
557
597
cleanups match {
558
598
case Nil =>
559
599
// 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 )
561
601
case nextCleanup :: rest =>
602
+ genLoad(expr, returnType)
603
+ lineNumber(r)
604
+ val saveReturnValue = (returnType != UNIT )
562
605
if (saveReturnValue) {
563
606
// regarding return value, the protocol is: in place of a `return-stmt`, a sequence of `adapt, store, jump` are inserted.
564
607
if (earlyReturnVar == null ) {
@@ -578,54 +621,39 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
578
621
* that cross cleanup boundaries. However, in theory such crossings are valid, so we should take care
579
622
* of them.
580
623
*/
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)
585
626
}
586
627
} // end of genReturn()
587
628
588
- def genWhileDo (tree : WhileDo , expectedType : BType ): BType = tree match {
629
+ def genWhileDo (tree : WhileDo ): LoadDestination = tree match {
589
630
case WhileDo (cond, body) =>
590
631
591
632
val isInfinite = cond == tpd.EmptyTree
592
633
634
+ val loop = new asm.Label
635
+ markProgramPoint(loop)
636
+
593
637
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
608
641
else
609
642
body match
610
643
case Literal (value) if value.tag == UnitTag =>
611
644
// this is the shape of do..while loops
612
- val loop = new asm.Label
613
- markProgramPoint(loop)
614
645
val exitLoop = new asm.Label
615
646
genCond(cond, loop, exitLoop, targetIfNoJump = exitLoop)
616
647
markProgramPoint(exitLoop)
617
648
case _ =>
618
- val loop = new asm.Label
619
649
val success = new asm.Label
620
650
val failure = new asm.Label
621
- markProgramPoint(loop)
622
651
genCond(cond, success, failure, targetIfNoJump = success)
623
652
markProgramPoint(success)
624
- genLoad(body, UNIT )
625
- bc goTo loop
653
+ genLoadTo(body, UNIT , LoadDestination .Jump (loop))
626
654
markProgramPoint(failure)
627
655
end match
628
- UNIT
656
+ LoadDestination . FallThrough
629
657
}
630
658
631
659
def genTypeApply (t : TypeApply ): BType = (t : @ unchecked) match {
@@ -848,11 +876,16 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
848
876
* Int/String values to use as keys, and a code block. The exception is the "default" case
849
877
* clause which doesn't list any key (there is exactly one of these per match).
850
878
*/
851
- private def genMatch (tree : Match ): BType = tree match {
879
+ private def genMatchTo (tree : Match , expectedType : BType , dest : LoadDestination ): BType = tree match {
852
880
case Match (selector, cases) =>
853
881
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)
856
889
857
890
// Only two possible selector types exist in `Match` trees at this point: Int and String
858
891
if (tpeTK(selector) == INT ) {
@@ -902,8 +935,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
902
935
for (sb <- switchBlocks.reverse) {
903
936
val (caseLabel, caseBody) = sb
904
937
markProgramPoint(caseLabel)
905
- genLoad(caseBody, generatedType)
906
- bc goTo postMatch
938
+ genLoadTo(caseBody, generatedType, postMatchDest)
907
939
}
908
940
} else {
909
941
@@ -968,13 +1000,14 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
968
1000
}
969
1001
970
1002
// Push the hashCode of the string (or `0` it is `null`) onto the stack and switch on it
971
- genLoadIf (
1003
+ genLoadIfTo (
972
1004
If (
973
1005
tree.selector.select(defn.Any_== ).appliedTo(nullLiteral),
974
1006
Literal (Constant (0 )),
975
1007
tree.selector.select(defn.Any_hashCode ).appliedToNone
976
1008
),
977
- INT
1009
+ INT ,
1010
+ LoadDestination .FallThrough
978
1011
)
979
1012
bc.emitSWITCH(mkArrayReverse(flatKeys), mkArrayL(targets.reverse), default, MIN_SWITCH_DENSITY )
980
1013
@@ -993,8 +1026,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
993
1026
val thisCaseMatches = new asm.Label
994
1027
genCond(condp, thisCaseMatches, keepGoing, targetIfNoJump = thisCaseMatches)
995
1028
markProgramPoint(thisCaseMatches)
996
- genLoad(caseBody, generatedType)
997
- bc goTo postMatch
1029
+ genLoadTo(caseBody, generatedType, postMatchDest)
998
1030
}
999
1031
markProgramPoint(keepGoing)
1000
1032
}
@@ -1004,22 +1036,22 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
1004
1036
// emit blocks for common patterns
1005
1037
for ((caseLabel, caseBody) <- indirectBlocks.reverse) {
1006
1038
markProgramPoint(caseLabel)
1007
- genLoad(caseBody, generatedType)
1008
- bc goTo postMatch
1039
+ genLoadTo(caseBody, generatedType, postMatchDest)
1009
1040
}
1010
1041
}
1011
1042
1012
- markProgramPoint(postMatch)
1043
+ if postMatch != null then
1044
+ markProgramPoint(postMatch)
1013
1045
generatedType
1014
1046
}
1015
1047
1016
- def genBlock (tree : Block , expectedType : BType ) = tree match {
1048
+ def genBlockTo (tree : Block , expectedType : BType , dest : LoadDestination ) : Unit = tree match {
1017
1049
case Block (stats, expr) =>
1018
1050
1019
1051
val savedScope = varsInScope
1020
1052
varsInScope = Nil
1021
1053
stats foreach genStat
1022
- genLoad (expr, expectedType)
1054
+ genLoadTo (expr, expectedType, dest )
1023
1055
val end = currProgramPoint()
1024
1056
if (emitVars) {
1025
1057
// add entries to LocalVariableTable JVM attribute
0 commit comments