Skip to content

Commit a82248f

Browse files
committed
BCode: Track the exact types on the stack, rather than only the height.
1 parent 8020677 commit a82248f

File tree

2 files changed

+115
-54
lines changed

2 files changed

+115
-54
lines changed

Diff for: compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala

+62-51
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,14 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
7979

8080
tree match {
8181
case Assign(lhs @ DesugaredSelect(qual, _), rhs) =>
82-
val savedStackHeight = stackHeight
82+
val savedStackSize = stack.recordSize()
8383
val isStatic = lhs.symbol.isStaticMember
8484
if (!isStatic) {
85-
genLoadQualifier(lhs)
86-
stackHeight += 1
85+
val qualTK = genLoad(qual)
86+
stack.push(qualTK)
8787
}
8888
genLoad(rhs, symInfoTK(lhs.symbol))
89-
stackHeight = savedStackHeight
89+
stack.restoreSize(savedStackSize)
9090
lineNumber(tree)
9191
// receiverClass is used in the bytecode to access the field. using sym.owner may lead to IllegalAccessError
9292
val receiverClass = qual.tpe.typeSymbol
@@ -150,9 +150,9 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
150150
}
151151

152152
genLoad(larg, resKind)
153-
stackHeight += resKind.size
153+
stack.push(resKind)
154154
genLoad(rarg, if (isShift) INT else resKind)
155-
stackHeight -= resKind.size
155+
stack.pop()
156156

157157
(code: @switch) match {
158158
case ADD => bc add resKind
@@ -189,19 +189,19 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
189189
if (isArrayGet(code)) {
190190
// load argument on stack
191191
assert(args.length == 1, s"Too many arguments for array get operation: $tree");
192-
stackHeight += 1
192+
stack.push(k)
193193
genLoad(args.head, INT)
194-
stackHeight -= 1
194+
stack.pop()
195195
generatedType = k.asArrayBType.componentType
196196
bc.aload(elementType)
197197
}
198198
else if (isArraySet(code)) {
199199
val List(a1, a2) = args
200-
stackHeight += 1
200+
stack.push(k)
201201
genLoad(a1, INT)
202-
stackHeight += 1
202+
stack.push(INT)
203203
genLoad(a2)
204-
stackHeight -= 2
204+
stack.pop(2)
205205
generatedType = UNIT
206206
bc.astore(elementType)
207207
} else {
@@ -235,7 +235,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
235235
val resKind = if (hasUnitBranch) UNIT else tpeTK(tree)
236236

237237
val postIf = new asm.Label
238-
genLoadTo(thenp, resKind, LoadDestination.Jump(postIf, stackHeight))
238+
genLoadTo(thenp, resKind, LoadDestination.Jump(postIf, stack.recordSize()))
239239
markProgramPoint(failure)
240240
genLoadTo(elsep, resKind, LoadDestination.FallThrough)
241241
markProgramPoint(postIf)
@@ -294,8 +294,10 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
294294
)
295295
}
296296

297-
def genLoad(tree: Tree): Unit = {
298-
genLoad(tree, tpeTK(tree))
297+
def genLoad(tree: Tree): BType = {
298+
val generatedType = tpeTK(tree)
299+
genLoad(tree, generatedType)
300+
generatedType
299301
}
300302

301303
/* Generate code for trees that produce values on the stack */
@@ -364,6 +366,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
364366
case t @ Ident(_) => (t, Nil)
365367
}
366368

369+
val savedStackSize = stack.recordSize()
367370
if (!fun.symbol.isStaticMember) {
368371
// load receiver of non-static implementation of lambda
369372

@@ -372,10 +375,12 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
372375
// AbstractValidatingLambdaMetafactory.validateMetafactoryArgs
373376

374377
val DesugaredSelect(prefix, _) = fun: @unchecked
375-
genLoad(prefix)
378+
val prefixTK = genLoad(prefix)
379+
stack.push(prefixTK)
376380
}
377381

378382
genLoadArguments(env, fun.symbol.info.firstParamTypes map toTypeKind)
383+
stack.restoreSize(savedStackSize)
379384
generatedType = genInvokeDynamicLambda(NoSymbol, fun.symbol, env.size, functionalInterface)
380385

381386
case app @ Apply(_, _) =>
@@ -494,9 +499,9 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
494499
dest match
495500
case LoadDestination.FallThrough =>
496501
()
497-
case LoadDestination.Jump(label, targetStackHeight) =>
498-
if targetStackHeight < stackHeight then
499-
val stackDiff = stackHeight - targetStackHeight
502+
case LoadDestination.Jump(label, targetStackSize) =>
503+
val stackDiff = stack.heightDiffWrt(targetStackSize)
504+
if stackDiff != 0 then
500505
if expectedType == UNIT then
501506
bc dropMany stackDiff
502507
else
@@ -599,7 +604,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
599604
if dest == LoadDestination.FallThrough then
600605
val resKind = tpeTK(tree)
601606
val jumpTarget = new asm.Label
602-
registerJumpDest(labelSym, resKind, LoadDestination.Jump(jumpTarget, stackHeight))
607+
registerJumpDest(labelSym, resKind, LoadDestination.Jump(jumpTarget, stack.recordSize()))
603608
genLoad(expr, resKind)
604609
markProgramPoint(jumpTarget)
605610
resKind
@@ -657,7 +662,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
657662
markProgramPoint(loop)
658663

659664
if isInfinite then
660-
val dest = LoadDestination.Jump(loop, stackHeight)
665+
val dest = LoadDestination.Jump(loop, stack.recordSize())
661666
genLoadTo(body, UNIT, dest)
662667
dest
663668
else
@@ -672,7 +677,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
672677
val failure = new asm.Label
673678
genCond(cond, success, failure, targetIfNoJump = success)
674679
markProgramPoint(success)
675-
genLoadTo(body, UNIT, LoadDestination.Jump(loop, stackHeight))
680+
genLoadTo(body, UNIT, LoadDestination.Jump(loop, stack.recordSize()))
676681
markProgramPoint(failure)
677682
end match
678683
LoadDestination.FallThrough
@@ -765,10 +770,10 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
765770
// on the stack (contrary to what the type in the AST says).
766771

767772
// scala/bug#10290: qual can be `this.$outer()` (not just `this`), so we call genLoad (not just ALOAD_0)
768-
genLoad(superQual)
769-
stackHeight += 1
773+
val superQualTK = genLoad(superQual)
774+
stack.push(superQualTK)
770775
genLoadArguments(args, paramTKs(app))
771-
stackHeight -= 1
776+
stack.pop()
772777
generatedType = genCallMethod(fun.symbol, InvokeStyle.Super, app.span)
773778

774779
// 'new' constructor call: Note: since constructors are
@@ -790,9 +795,10 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
790795
assert(classBTypeFromSymbol(ctor.owner) == rt, s"Symbol ${ctor.owner.showFullName} is different from $rt")
791796
mnode.visitTypeInsn(asm.Opcodes.NEW, rt.internalName)
792797
bc dup generatedType
793-
stackHeight += 2
798+
stack.push(rt)
799+
stack.push(rt)
794800
genLoadArguments(args, paramTKs(app))
795-
stackHeight -= 2
801+
stack.pop(2)
796802
genCallMethod(ctor, InvokeStyle.Special, app.span)
797803

798804
case _ =>
@@ -825,12 +831,11 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
825831
else if (app.hasAttachment(BCodeHelpers.UseInvokeSpecial)) InvokeStyle.Special
826832
else InvokeStyle.Virtual
827833

828-
val savedStackHeight = stackHeight
834+
val savedStackSize = stack.recordSize()
829835
if invokeStyle.hasInstance then
830-
genLoadQualifier(fun)
831-
stackHeight += 1
836+
stack.push(genLoadQualifier(fun))
832837
genLoadArguments(args, paramTKs(app))
833-
stackHeight = savedStackHeight
838+
stack.restoreSize(savedStackSize)
834839

835840
val DesugaredSelect(qual, name) = fun: @unchecked // fun is a Select, also checked in genLoadQualifier
836841
val isArrayClone = name == nme.clone_ && qual.tpe.widen.isInstanceOf[JavaArrayType]
@@ -888,7 +893,10 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
888893
bc iconst elems.length
889894
bc newarray elmKind
890895

891-
stackHeight += 3 // during the genLoad below, there is the result, its dup, and the index
896+
// during the genLoad below, there is the result, its dup, and the index
897+
stack.push(generatedType)
898+
stack.push(generatedType)
899+
stack.push(INT)
892900

893901
var i = 0
894902
var rest = elems
@@ -901,7 +909,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
901909
i = i + 1
902910
}
903911

904-
stackHeight -= 3
912+
stack.pop(3)
905913

906914
generatedType
907915
}
@@ -917,7 +925,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
917925
val (generatedType, postMatch, postMatchDest) =
918926
if dest == LoadDestination.FallThrough then
919927
val postMatch = new asm.Label
920-
(tpeTK(tree), postMatch, LoadDestination.Jump(postMatch, stackHeight))
928+
(tpeTK(tree), postMatch, LoadDestination.Jump(postMatch, stack.recordSize()))
921929
else
922930
(expectedType, null, dest)
923931

@@ -1179,7 +1187,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
11791187
}
11801188

11811189
/* Emit code to Load the qualifier of `tree` on top of the stack. */
1182-
def genLoadQualifier(tree: Tree): Unit = {
1190+
def genLoadQualifier(tree: Tree): BType = {
11831191
lineNumber(tree)
11841192
tree match {
11851193
case DesugaredSelect(qualifier, _) => genLoad(qualifier)
@@ -1188,6 +1196,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
11881196
case Some(sel) => genLoadQualifier(sel)
11891197
case None =>
11901198
assert(t.symbol.owner == this.claszSymbol)
1199+
UNIT
11911200
}
11921201
case _ => abort(s"Unknown qualifier $tree")
11931202
}
@@ -1200,14 +1209,14 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
12001209
btpes match
12011210
case btpe :: btpes1 =>
12021211
genLoad(arg, btpe)
1203-
stackHeight += btpe.size
1212+
stack.push(btpe)
12041213
loop(args1, btpes1)
12051214
case _ =>
12061215
case _ =>
12071216

1208-
val savedStackHeight = stackHeight
1217+
val savedStackSize = stack.recordSize()
12091218
loop(args, btpes)
1210-
stackHeight = savedStackHeight
1219+
stack.restoreSize(savedStackSize)
12111220
end genLoadArguments
12121221

12131222
def genLoadModule(tree: Tree): BType = {
@@ -1307,13 +1316,13 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
13071316
}.sum
13081317
bc.genNewStringBuilder(approxBuilderSize)
13091318

1310-
stackHeight += 1 // during the genLoad below, there is a reference to the StringBuilder on the stack
1319+
stack.push(jlStringBuilderRef) // during the genLoad below, there is a reference to the StringBuilder on the stack
13111320
for (elem <- concatArguments) {
13121321
val elemType = tpeTK(elem)
13131322
genLoad(elem, elemType)
13141323
bc.genStringBuilderAppend(elemType)
13151324
}
1316-
stackHeight -= 1
1325+
stack.pop()
13171326

13181327
bc.genStringBuilderEnd
13191328
} else {
@@ -1331,15 +1340,17 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
13311340
var totalArgSlots = 0
13321341
var countConcats = 1 // ie. 1 + how many times we spilled
13331342

1334-
val savedStackHeight = stackHeight
1343+
val savedStackSize = stack.recordSize()
13351344

13361345
for (elem <- concatArguments) {
13371346
val tpe = tpeTK(elem)
13381347
val elemSlots = tpe.size
13391348

13401349
// Unlikely spill case
13411350
if (totalArgSlots + elemSlots >= MaxIndySlots) {
1342-
stackHeight = savedStackHeight + countConcats
1351+
stack.restoreSize(savedStackSize)
1352+
for _ <- 0 until countConcats do
1353+
stack.push(StringRef)
13431354
bc.genIndyStringConcat(recipe.toString, argTypes.result(), constVals.result())
13441355
countConcats += 1
13451356
totalArgSlots = 0
@@ -1364,10 +1375,10 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
13641375
val tpe = tpeTK(elem)
13651376
argTypes += tpe.toASMType
13661377
genLoad(elem, tpe)
1367-
stackHeight += 1
1378+
stack.push(tpe)
13681379
}
13691380
}
1370-
stackHeight = savedStackHeight
1381+
stack.restoreSize(savedStackSize)
13711382
bc.genIndyStringConcat(recipe.toString, argTypes.result(), constVals.result())
13721383

13731384
// If we spilled, generate one final concat
@@ -1562,9 +1573,9 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
15621573
} else {
15631574
val tk = tpeTK(l).maxType(tpeTK(r))
15641575
genLoad(l, tk)
1565-
stackHeight += tk.size
1576+
stack.push(tk)
15661577
genLoad(r, tk)
1567-
stackHeight -= tk.size
1578+
stack.pop()
15681579
genCJUMP(success, failure, op, tk, targetIfNoJump)
15691580
}
15701581
}
@@ -1679,9 +1690,9 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
16791690
}
16801691

16811692
genLoad(l, ObjectRef)
1682-
stackHeight += 1
1693+
stack.push(ObjectRef)
16831694
genLoad(r, ObjectRef)
1684-
stackHeight -= 1
1695+
stack.pop()
16851696
genCallMethod(equalsMethod, InvokeStyle.Static)
16861697
genCZJUMP(success, failure, Primitives.NE, BOOL, targetIfNoJump)
16871698
}
@@ -1697,9 +1708,9 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
16971708
} else if (isNonNullExpr(l)) {
16981709
// SI-7852 Avoid null check if L is statically non-null.
16991710
genLoad(l, ObjectRef)
1700-
stackHeight += 1
1711+
stack.push(ObjectRef)
17011712
genLoad(r, ObjectRef)
1702-
stackHeight -= 1
1713+
stack.pop()
17031714
genCallMethod(defn.Any_equals, InvokeStyle.Virtual)
17041715
genCZJUMP(success, failure, Primitives.NE, BOOL, targetIfNoJump)
17051716
} else {
@@ -1709,9 +1720,9 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
17091720
val lNonNull = new asm.Label
17101721

17111722
genLoad(l, ObjectRef)
1712-
stackHeight += 1
1723+
stack.push(ObjectRef)
17131724
genLoad(r, ObjectRef)
1714-
stackHeight -= 1
1725+
stack.pop()
17151726
locals.store(eqEqTempLocal)
17161727
bc dup ObjectRef
17171728
genCZJUMP(lNull, lNonNull, Primitives.EQ, ObjectRef, targetIfNoJump = lNull)

0 commit comments

Comments
 (0)