Skip to content

Commit a528e91

Browse files
committed
ErasurePreservation.scala: added cases for primitives; added InstructcionTypeArguments & InvokeReturnType attributes in jvm backend; added logic for injecting the two attributes; cleaned test case
1 parent c0b395b commit a528e91

File tree

12 files changed

+836
-84
lines changed

12 files changed

+836
-84
lines changed

compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import dotty.tools.dotc.core.Phases.*
2525
import dotty.tools.dotc.core.Decorators.em
2626
import dotty.tools.dotc.report
2727
import dotty.tools.dotc.ast.Trees.SyntheticUnit
28+
import dotty.tools.dotc.transform.InvokeReturnType
29+
import dotty.tools.dotc.transform.InstructionTypeArguments
2830

2931
/*
3032
*
@@ -869,7 +871,11 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
869871
defn.ObjectClass
870872
} else qualSym
871873
}
872-
generatedType = genCallMethod(sym, invokeStyle, app.span, receiverClass)
874+
// println("GenApply.case Apply:" + fun)
875+
// println(s" returnType: ${app.getAttachment(InvokeReturnType)} InstructionTypeArg: ${fun.getAttachment(InstructionTypeArguments)}")
876+
// InvokeReturnType, InstructionTypeArguments are fetched here
877+
generatedType = genCallMethod(sym, invokeStyle, app.span, receiverClass,
878+
app.getAttachment(InvokeReturnType), fun.getAttachment(InstructionTypeArguments))
873879
}
874880
}
875881
}
@@ -1397,7 +1403,8 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
13971403
* invocation instruction, otherwise `method.owner`. A specific receiver class is needed to
13981404
* prevent an IllegalAccessError, (aladdin bug 455).
13991405
*/
1400-
def genCallMethod(method: Symbol, style: InvokeStyle, pos: Span = NoSpan, specificReceiver: Symbol = null): BType = {
1406+
def genCallMethod(method: Symbol, style: InvokeStyle, pos: Span = NoSpan, specificReceiver: Symbol = null,
1407+
invokeReturnType : Option[dotty.tools.dotc.transform.TypeB] = None, instrTypeArgs : Option[List[dotty.tools.dotc.transform.TypeA]] = None): BType = {
14011408
val methodOwner = method.owner
14021409

14031410
// the class used in the invocation's method descriptor in the classfile
@@ -1450,16 +1457,20 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
14501457
val staticDesc = MethodBType(ownerBType :: bmType.argumentTypes, bmType.returnType).descriptor
14511458
val staticName = traitSuperAccessorName(method)
14521459
bc.invokestatic(receiverName, staticName, staticDesc, isInterface)
1460+
// bc.invokestatic(receiverName, staticName, staticDesc, isInterface, invokeReturnType, instrTypeArgs)
14531461
} else {
14541462
bc.invokespecial(receiverName, jname, mdescr, isInterface)
1463+
// bc.invokespecial(receiverName, jname, mdescr, isInterface, invokeReturnType, instrTypeArgs)
14551464
}
14561465
} else {
14571466
val opc = style match {
14581467
case Static => Opcodes.INVOKESTATIC
14591468
case Special => Opcodes.INVOKESPECIAL
14601469
case Virtual => if (isInterface) Opcodes.INVOKEINTERFACE else Opcodes.INVOKEVIRTUAL
14611470
}
1462-
bc.emitInvoke(opc, receiverName, jname, mdescr, isInterface)
1471+
// println("genCallMethod" + method.show + " : " + method.getAnnotation(defn.ErasurePreservationAnnot))
1472+
bc.emitInvoke(opc, receiverName, jname, mdescr, isInterface, invokeReturnType, instrTypeArgs)
1473+
// bc.emitInvoke(opc, receiverName, jname, mdescr, isInterface, invokeReturnType, instrTypeArgs)
14631474
}
14641475

14651476
bmType.returnType

compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ import dotty.tools.backend.jvm.DottyBackendInterface.symExtensions
4040
import dotty.tools.backend.jvm.attributes.MethodTypeParameterCount
4141
import dotty.tools.backend.jvm.attributes.MethodReturnType
4242
import dotty.tools.backend.jvm.attributes.MethodParameterType
43-
import dotty.tools.dotc.transform.TypeB
4443
import dotty.tools.backend.jvm.attributes.TypeHints
4544

4645
/*
@@ -223,10 +222,10 @@ trait BCodeHelpers extends BCodeIdiomatic {
223222
emitAssocs(av, assocs, BCodeHelpers.this)(this)
224223
}
225224

226-
def toJTypeB(tpe: TypeB): TypeHints.TypeB =
225+
def toJTypeB(tpe: dotty.tools.dotc.transform.TypeB): TypeHints.TypeB =
227226
tpe match
228-
case TypeB.None => TypeHints.TypeB.NO_HINT
229-
case TypeB.M(index) => new TypeHints.TypeB(TypeHints.TypeB.M_KIND, index)
227+
case dotty.tools.dotc.transform.TypeB.None => TypeHints.TypeB.NO_HINT
228+
case dotty.tools.dotc.transform.TypeB.M(index) => new TypeHints.TypeB(TypeHints.TypeB.M_KIND, index)
230229
// case _ =>
231230
// report.error("unexpected type in to Java TypeB: " + tpe)
232231
// TypeHints.TypeB.NO_HINT // fallback, should not happen
@@ -237,18 +236,18 @@ trait BCodeHelpers extends BCodeIdiomatic {
237236
mw.visitAttribute(attr)
238237
}
239238

240-
def addMethodReturnTypeAttribute(mw: asm.MethodVisitor, tpe: TypeB): Unit =
239+
def addMethodReturnTypeAttribute(mw: asm.MethodVisitor, tpe: dotty.tools.dotc.transform.TypeB): Unit =
241240
tpe match
242-
case TypeB.M(index) =>
241+
case dotty.tools.dotc.transform.TypeB.M(index) =>
243242
val typeB = new TypeHints.TypeB(TypeHints.TypeB.M_KIND, index)
244243
val attr = new MethodReturnType(typeB)
245244
mw.visitAttribute(attr)
246-
case TypeB.None => //do nothing
245+
case dotty.tools.dotc.transform.TypeB.None => //do nothing
247246
// case _ =>
248247
// report.error("Unexpected type for method return type attribute: " + tpe)
249248

250249

251-
def addMethodParameterTypeAttribute(mw: asm.MethodVisitor, lst: List[TypeB]) : Unit =
250+
def addMethodParameterTypeAttribute(mw: asm.MethodVisitor, lst: List[dotty.tools.dotc.transform.TypeB]) : Unit =
252251
if (lst.isEmpty) return
253252
val lstJTypeB = lst.map(toJTypeB)
254253
val len = lstJTypeB.length

compiler/src/dotty/tools/backend/jvm/BCodeIdiomatic.scala

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ package backend
33
package jvm
44

55
import scala.language.unsafeNulls
6+
import scala.jdk.CollectionConverters.*
67

78
import scala.tools.asm
89
import scala.annotation.switch
910
import Primitives.{NE, EQ, TestOp, ArithmeticOp}
1011
import scala.tools.asm.tree.MethodInsnNode
1112
import dotty.tools.dotc.report
13+
import dotty.tools.backend.jvm.attributes.InvokeReturnType
14+
import dotty.tools.backend.jvm.attributes.TypeHints
1215

1316
/*
1417
* A high-level facade to the ASM API for bytecode generation.
@@ -423,9 +426,42 @@ trait BCodeIdiomatic {
423426
emitInvoke(Opcodes.INVOKEVIRTUAL, owner, name, desc, itf = false)
424427
}
425428

426-
def emitInvoke(opcode: Int, owner: String, name: String, desc: String, itf: Boolean): Unit = {
429+
def toJTypeB(tpe: dotty.tools.dotc.transform.TypeB): TypeHints.TypeB =
430+
tpe match
431+
case dotty.tools.dotc.transform.TypeB.None => TypeHints.TypeB.NO_HINT
432+
case dotty.tools.dotc.transform.TypeB.M(index) => new TypeHints.TypeB(TypeHints.TypeB.M_KIND, index)
433+
434+
def toJTypeA(tpe: dotty.tools.dotc.transform.TypeA): TypeHints.TypeA =
435+
tpe match
436+
case dotty.tools.dotc.transform.TypeA.Byte => TypeHints.TypeA.TYPEA_BYTE
437+
case dotty.tools.dotc.transform.TypeA.Char => TypeHints.TypeA.TYPEA_CHAR
438+
case dotty.tools.dotc.transform.TypeA.Double => TypeHints.TypeA.TYPEA_DOUBLE
439+
case dotty.tools.dotc.transform.TypeA.Float => TypeHints.TypeA.TYPEA_FLOAT
440+
case dotty.tools.dotc.transform.TypeA.Int => TypeHints.TypeA.TYPEA_INT
441+
case dotty.tools.dotc.transform.TypeA.Long => TypeHints.TypeA.TYPEA_LONG
442+
case dotty.tools.dotc.transform.TypeA.Short => TypeHints.TypeA.TYPEA_SHORT
443+
case dotty.tools.dotc.transform.TypeA.Boolean => TypeHints.TypeA.TYPEA_BOOLEAN
444+
case dotty.tools.dotc.transform.TypeA.M(x) => TypeHints.TypeA(TypeHints.TypeA.M_KIND, x)
445+
case dotty.tools.dotc.transform.TypeA.K(x) => TypeHints.TypeA(TypeHints.TypeA.K_KIND, x)
446+
case dotty.tools.dotc.transform.TypeA.Ref => TypeHints.TypeA.TYPEA_REFERENCE
447+
448+
449+
def emitInvoke(opcode: Int, owner: String, name: String, desc: String, itf: Boolean,
450+
invokeReturnType : Option[dotty.tools.dotc.transform.TypeB] = None, instrTypeArgs : Option[List[dotty.tools.dotc.transform.TypeA]] = None): Unit = {
427451
val node = new MethodInsnNode(opcode, owner, name, desc, itf)
428452
jmethod.instructions.add(node)
453+
invokeReturnType match {
454+
case None => {}
455+
case Some(typeB) =>
456+
val bcTypeB = toJTypeB(typeB)
457+
jmethod.asInstanceOf[MethodNode1].invokeReturnTypeBs.put(node, bcTypeB);
458+
}
459+
instrTypeArgs match {
460+
case None => {}
461+
case Some(lstTypeAs) =>
462+
val bcTypeAs = lstTypeAs.map(toJTypeA)
463+
jmethod.asInstanceOf[MethodNode1].instructionTypeArgTypeAs.put(node, bcTypeAs.asJava);
464+
}
429465
}
430466

431467

compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import dotty.tools.dotc.core.Contexts.*
2121
import dotty.tools.dotc.util.Spans.*
2222
import dotty.tools.dotc.report
2323
import dotty.tools.dotc.transform.ErasedInfo
24-
import dotty.tools.dotc.transform.TypeB
2524

2625

2726
/*
@@ -720,14 +719,14 @@ trait BCodeSkelBuilder extends BCodeHelpers {
720719
val thrownExceptions: List[String] = getExceptions(excs)
721720

722721
// information for: MethodTypeParameterCount, MethodParameterType, MethodReturnType
723-
val methodDeclarationAttrs = methSymbol.getAnnotation(defn.SourceFileAnnot)
722+
val methodDeclarationAttrs = methSymbol.getAnnotation(defn.ErasurePreservationAnnot)
724723
val (cnt, paramType, retType) = methodDeclarationAttrs match {
725-
case Some(e : ErasedInfo) => (e.getParamCount, e.getParamType, e.getReturnType)
726-
case _ => (0, List.empty[TypeB], TypeB.None)
724+
case Some(e : ErasedInfo) => (e.paramCount, e.paramType, e.returnType)
725+
case _ => (0, List.empty[dotty.tools.dotc.transform.TypeB], dotty.tools.dotc.transform.TypeB.None)
727726
}
728727
//val typeBs =
729-
println(s"GenBCode.genDefDef.initJMethod: ${methSymbol.show} ${methodDeclarationAttrs} " +
730-
s"${cnt} ${paramType} ${retType}")
728+
// println(s"GenBCode.genDefDef.initJMethod: ${methSymbol.show} ${methodDeclarationAttrs} " +
729+
// s"${cnt} ${paramType} ${retType}")
731730

732731
val bytecodeName =
733732
if (isMethSymStaticCtor) CLASS_CONSTRUCTOR_NAME
@@ -942,6 +941,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {
942941
if (AsmUtils.traceMethodEnabled && mnode.name.contains(AsmUtils.traceMethodPattern))
943942
AsmUtils.traceMethod(mnode)
944943

944+
mnode.setAttribtues();
945945
mnode = null
946946
} // end of method genDefDef()
947947

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package dotty.tools.backend.jvm;
2+
3+
import scala.tools.asm.Opcodes;
4+
5+
final class Constants1 {
6+
static final int F_INSERT = 256;
7+
8+
// The JVM opcode values which are not part of the ASM public API.
9+
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html.
10+
11+
static final int LDC_W = 19;
12+
static final int LDC2_W = 20;
13+
static final int ILOAD_0 = 26;
14+
static final int ILOAD_1 = 27;
15+
static final int ILOAD_2 = 28;
16+
static final int ILOAD_3 = 29;
17+
static final int LLOAD_0 = 30;
18+
static final int LLOAD_1 = 31;
19+
static final int LLOAD_2 = 32;
20+
static final int LLOAD_3 = 33;
21+
static final int FLOAD_0 = 34;
22+
static final int FLOAD_1 = 35;
23+
static final int FLOAD_2 = 36;
24+
static final int FLOAD_3 = 37;
25+
static final int DLOAD_0 = 38;
26+
static final int DLOAD_1 = 39;
27+
static final int DLOAD_2 = 40;
28+
static final int DLOAD_3 = 41;
29+
static final int ALOAD_0 = 42;
30+
static final int ALOAD_1 = 43;
31+
static final int ALOAD_2 = 44;
32+
static final int ALOAD_3 = 45;
33+
static final int ISTORE_0 = 59;
34+
static final int ISTORE_1 = 60;
35+
static final int ISTORE_2 = 61;
36+
static final int ISTORE_3 = 62;
37+
static final int LSTORE_0 = 63;
38+
static final int LSTORE_1 = 64;
39+
static final int LSTORE_2 = 65;
40+
static final int LSTORE_3 = 66;
41+
static final int FSTORE_0 = 67;
42+
static final int FSTORE_1 = 68;
43+
static final int FSTORE_2 = 69;
44+
static final int FSTORE_3 = 70;
45+
static final int DSTORE_0 = 71;
46+
static final int DSTORE_1 = 72;
47+
static final int DSTORE_2 = 73;
48+
static final int DSTORE_3 = 74;
49+
static final int ASTORE_0 = 75;
50+
static final int ASTORE_1 = 76;
51+
static final int ASTORE_2 = 77;
52+
static final int ASTORE_3 = 78;
53+
static final int WIDE = 196;
54+
static final int GOTO_W = 200;
55+
static final int JSR_W = 201;
56+
57+
// Constants to convert between normal and wide jump instructions.
58+
59+
// The delta between the GOTO_W and JSR_W opcodes and GOTO and JUMP.
60+
static final int WIDE_JUMP_OPCODE_DELTA = GOTO_W - Opcodes.GOTO;
61+
62+
// Constants to convert JVM opcodes to the equivalent ASM specific opcodes, and vice versa.
63+
64+
// The delta between the ASM_IFEQ, ..., ASM_IF_ACMPNE, ASM_GOTO and ASM_JSR opcodes
65+
// and IFEQ, ..., IF_ACMPNE, GOTO and JSR.
66+
static final int ASM_OPCODE_DELTA = 49;
67+
68+
// The delta between the ASM_IFNULL and ASM_IFNONNULL opcodes and IFNULL and IFNONNULL.
69+
static final int ASM_IFNULL_OPCODE_DELTA = 20;
70+
71+
// ASM specific opcodes, used for long forward jump instructions.
72+
73+
static final int ASM_IFEQ = Opcodes.IFEQ + ASM_OPCODE_DELTA;
74+
static final int ASM_IFNE = Opcodes.IFNE + ASM_OPCODE_DELTA;
75+
static final int ASM_IFLT = Opcodes.IFLT + ASM_OPCODE_DELTA;
76+
static final int ASM_IFGE = Opcodes.IFGE + ASM_OPCODE_DELTA;
77+
static final int ASM_IFGT = Opcodes.IFGT + ASM_OPCODE_DELTA;
78+
static final int ASM_IFLE = Opcodes.IFLE + ASM_OPCODE_DELTA;
79+
static final int ASM_IF_ICMPEQ = Opcodes.IF_ICMPEQ + ASM_OPCODE_DELTA;
80+
static final int ASM_IF_ICMPNE = Opcodes.IF_ICMPNE + ASM_OPCODE_DELTA;
81+
static final int ASM_IF_ICMPLT = Opcodes.IF_ICMPLT + ASM_OPCODE_DELTA;
82+
static final int ASM_IF_ICMPGE = Opcodes.IF_ICMPGE + ASM_OPCODE_DELTA;
83+
static final int ASM_IF_ICMPGT = Opcodes.IF_ICMPGT + ASM_OPCODE_DELTA;
84+
static final int ASM_IF_ICMPLE = Opcodes.IF_ICMPLE + ASM_OPCODE_DELTA;
85+
static final int ASM_IF_ACMPEQ = Opcodes.IF_ACMPEQ + ASM_OPCODE_DELTA;
86+
static final int ASM_IF_ACMPNE = Opcodes.IF_ACMPNE + ASM_OPCODE_DELTA;
87+
static final int ASM_GOTO = Opcodes.GOTO + ASM_OPCODE_DELTA;
88+
static final int ASM_JSR = Opcodes.JSR + ASM_OPCODE_DELTA;
89+
static final int ASM_IFNULL = Opcodes.IFNULL + ASM_IFNULL_OPCODE_DELTA;
90+
static final int ASM_IFNONNULL = Opcodes.IFNONNULL + ASM_IFNULL_OPCODE_DELTA;
91+
static final int ASM_GOTO_W = 220;
92+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package dotty.tools.backend.jvm;
2+
3+
import scala.tools.asm.tree.AbstractInsnNode;
4+
import scala.tools.asm.util.Textifier;
5+
import scala.tools.asm.MethodVisitor;
6+
import scala.tools.asm.util.TraceMethodVisitor;
7+
8+
import java.io.PrintWriter;
9+
10+
public class InsnPrinter {
11+
public static void printInsn(AbstractInsnNode insn){
12+
Textifier textifier = new Textifier();
13+
MethodVisitor printer = new TraceMethodVisitor(textifier);
14+
insn.accept(printer);
15+
PrintWriter pw = new PrintWriter(System.out);
16+
textifier.print(pw);
17+
pw.flush();
18+
}
19+
}

0 commit comments

Comments
 (0)