Skip to content

Commit 7a5cb6e

Browse files
authored
classfile reader: handle JDK 9+ constant types in constant pool (#19533)
forward-port of scala/scala#10675 and scala/scala#8595 references scala/bug#12396 and scala/bug#11635 fixes #19527 ("bad constant pool tag 17") also fixes unreported potential "bad constant pool tag 19" and "bad constant pool tag 20" errors
2 parents 1ec17f6 + 26852de commit 7a5cb6e

File tree

5 files changed

+85
-2
lines changed

5 files changed

+85
-2
lines changed

compiler/src/dotty/tools/dotc/core/classfile/ClassfileConstants.scala

+3
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,10 @@ object ClassfileConstants {
7373

7474
inline val CONSTANT_METHODHANDLE = 15
7575
inline val CONSTANT_METHODTYPE = 16
76+
inline val CONSTANT_DYNAMIC = 17
7677
inline val CONSTANT_INVOKEDYNAMIC = 18
78+
inline val CONSTANT_MODULE = 19
79+
inline val CONSTANT_PACKAGE = 20
7780

7881
// tags describing the type of a literal in attribute values
7982
inline val BYTE_TAG = 'B'

compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala

+3-2
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,14 @@ object ClassfileParser {
106106
(in.nextByte.toInt: @switch) match {
107107
case CONSTANT_UTF8 | CONSTANT_UNICODE =>
108108
in.skip(in.nextChar)
109-
case CONSTANT_CLASS | CONSTANT_STRING | CONSTANT_METHODTYPE =>
109+
case CONSTANT_CLASS | CONSTANT_STRING | CONSTANT_METHODTYPE
110+
| CONSTANT_MODULE | CONSTANT_PACKAGE =>
110111
in.skip(2)
111112
case CONSTANT_METHODHANDLE =>
112113
in.skip(3)
113114
case CONSTANT_FIELDREF | CONSTANT_METHODREF | CONSTANT_INTFMETHODREF
114115
| CONSTANT_NAMEANDTYPE | CONSTANT_INTEGER | CONSTANT_FLOAT
115-
| CONSTANT_INVOKEDYNAMIC =>
116+
| CONSTANT_INVOKEDYNAMIC | CONSTANT_DYNAMIC =>
116117
in.skip(4)
117118
case CONSTANT_LONG | CONSTANT_DOUBLE =>
118119
in.skip(8)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package dotty.tools.backend.jvm
2+
3+
// painful to do Java reflection stuff without this
4+
import scala.language.unsafeNulls
5+
6+
import org.junit.Assert.assertEquals
7+
import org.junit.Test
8+
9+
import java.lang.reflect.Member
10+
11+
class ClassfileParserTest {
12+
@Test
13+
def noConstantPoolLag(): Unit = {
14+
def constNames(ms: List[Member]) = ms.collect {
15+
case f if f.getName.startsWith("CONSTANT_") => f.getName
16+
}.sorted
17+
18+
val toDotc = Map(
19+
"CONSTANT_INTERFACE_METHODREF" -> "CONSTANT_INTFMETHODREF",
20+
"CONSTANT_INVOKE_DYNAMIC" -> "CONSTANT_INVOKEDYNAMIC",
21+
"CONSTANT_METHOD_HANDLE" -> "CONSTANT_METHODHANDLE",
22+
"CONSTANT_METHOD_TYPE" -> "CONSTANT_METHODTYPE",
23+
"CONSTANT_NAME_AND_TYPE" -> "CONSTANT_NAMEANDTYPE",
24+
).withDefault(x => x)
25+
26+
val asmConsts = constNames(Class.forName("scala.tools.asm.Symbol").getDeclaredFields.toList)
27+
.map(_.stripSuffix("_TAG"))
28+
.map(toDotc)
29+
.::("CONSTANT_UNICODE")
30+
.sorted
31+
// in the Scala 2 version of this test, we also use Java reflection to get the constant
32+
// names out of ClassfileConstants. in Dotty, the constants are `inline val`s, invisible
33+
// to Java reflection, so we hardcode them here
34+
assertEquals(asmConsts, List(
35+
// do not add to this list without also making the corresponding change
36+
// in ClassfileConstants! that would defeat the purpose of the test
37+
"CONSTANT_CLASS",
38+
"CONSTANT_DOUBLE",
39+
"CONSTANT_DYNAMIC",
40+
"CONSTANT_FIELDREF",
41+
"CONSTANT_FLOAT",
42+
"CONSTANT_INTEGER",
43+
"CONSTANT_INTFMETHODREF",
44+
"CONSTANT_INVOKEDYNAMIC",
45+
"CONSTANT_LONG",
46+
"CONSTANT_METHODHANDLE",
47+
"CONSTANT_METHODREF",
48+
"CONSTANT_METHODTYPE",
49+
"CONSTANT_MODULE",
50+
"CONSTANT_NAMEANDTYPE",
51+
"CONSTANT_PACKAGE",
52+
"CONSTANT_STRING",
53+
"CONSTANT_UNICODE",
54+
"CONSTANT_UTF8",
55+
))
56+
}
57+
}

tests/pos/t12396/A_1.java

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// test: -jvm 21+
2+
3+
public class A_1 {
4+
public int f(Object s) {
5+
switch(s) {
6+
case Res.R -> {
7+
return 1;
8+
}
9+
default -> {
10+
return 3;
11+
}
12+
}
13+
}
14+
static enum Res {
15+
R
16+
}
17+
}

tests/pos/t12396/B_2.scala

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// test: -jvm 21+
2+
3+
class B {
4+
def bar = (new A_1).f(null)
5+
}

0 commit comments

Comments
 (0)