Skip to content

Commit 4554e02

Browse files
committed
Eagerly read from the constant pool as a basis for lazy types java class/method
I've used lazy types for field/method/class infos, which is analagous to what we do in `Unpickler` for scala originated types. We read all data needed by the inner class table and the type completers from the pool eagerly, but still be lazy about interning strings to Names and completion of the field/method types themselves. This fixes some long standing spurious cyclic errors: Manually tested with: ``` $ scalac -cp $(coursier fetch -q -p com.datastax.cassandra:dse-driver:1.0.0) test.scala test.scala:2: error: illegal cyclic reference involving class Cluster new com.datastax.driver.dse.DseCluster.Builder() ^ one error found $ /code/scala/build/quick/bin/scalac -cp $(coursier fetch -q -p com.datastax.cassandra:dse-driver:1.0.0) test.scala $ cat test.scala class Test { new com.datastax.driver.dse.DseCluster.Builder() } ``` ``` class Test { new com.datastax.driver.dse.DseCluster.Builder() } ``` It subsumes `-Ybreak-cycles`. I was to compile `pos/cycle{-jsoup,}` without the experimental `-Ybreak-cycles`. I've removed the entire `-Ybreak-cycles` option and supporting code. It also subsumes the existing implementation related to cycle avoidance (`queueLoad` / `raiseLoaderLevel`.) Descriptor, signature, constant, and param names are made available to the field/method lazy completer which can use them if and when the symbol is completed. After classfile parsing the constant pool is discarded (some entries are of course captured by the lazy type completers.) Fixes scala/bug#3809
1 parent 688bf0f commit 4554e02

File tree

15 files changed

+450
-240
lines changed

15 files changed

+450
-240
lines changed

src/compiler/scala/tools/nsc/symtab/classfile/AbstractFileReader.scala

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ package scala.tools.nsc
1414
package symtab
1515
package classfile
1616

17-
import java.lang.Float.intBitsToFloat
17+
import java.io.{ByteArrayInputStream, DataInputStream}
1818
import java.lang.Double.longBitsToDouble
19+
import java.lang.Float.intBitsToFloat
20+
import java.util
1921

2022
import scala.tools.nsc.io.AbstractFile
2123

@@ -25,11 +27,13 @@ import scala.tools.nsc.io.AbstractFile
2527
* @author Philippe Altherr
2628
* @version 1.0, 23/03/2004
2729
*/
28-
class AbstractFileReader(val file: AbstractFile) {
30+
final class AbstractFileReader(buf0: Array[Byte]) extends DataReader {
31+
private[this] var buf = buf0
2932

30-
/** the buffer containing the file
31-
*/
32-
val buf: Array[Byte] = file.toByteArray
33+
@deprecated("Use other constructor", "2.13.0")
34+
def this(file: AbstractFile) {
35+
this(file.toByteArray)
36+
}
3337

3438
/** the current input pointer
3539
*/
@@ -62,17 +66,25 @@ class AbstractFileReader(val file: AbstractFile) {
6266
((nextByte & 0xff) << 24) + ((nextByte & 0xff) << 16) +
6367
((nextByte & 0xff) << 8) + (nextByte & 0xff)
6468

69+
/** extract a byte at position bp from buf
70+
*/
71+
def getByte(mybp: Int): Byte =
72+
buf(mybp)
73+
74+
def getBytes(mybp: Int, bytes: Array[Byte]): Unit = {
75+
System.arraycopy(buf, mybp, bytes, 0, bytes.length)
76+
}
6577

6678
/** extract a character at position bp from buf
6779
*/
6880
def getChar(mybp: Int): Char =
69-
(((buf(mybp) & 0xff) << 8) + (buf(mybp+1) & 0xff)).toChar
81+
(((getByte(mybp) & 0xff) << 8) + (getByte(mybp+1) & 0xff)).toChar
7082

7183
/** extract an integer at position bp from buf
7284
*/
7385
def getInt(mybp: Int): Int =
74-
((buf(mybp ) & 0xff) << 24) + ((buf(mybp+1) & 0xff) << 16) +
75-
((buf(mybp+2) & 0xff) << 8) + (buf(mybp+3) & 0xff)
86+
((getByte(mybp) & 0xff) << 24) + ((getByte(mybp + 1) & 0xff) << 16) +
87+
((getByte(mybp + 2) & 0xff) << 8) + (getByte(mybp + 3) & 0xff)
7688

7789
/** extract a long integer at position bp from buf
7890
*/
@@ -87,8 +99,11 @@ class AbstractFileReader(val file: AbstractFile) {
8799
*/
88100
def getDouble(mybp: Int): Double = longBitsToDouble(getLong(mybp))
89101

102+
def getUTF(mybp: Int, len: Int): String = {
103+
new DataInputStream(new ByteArrayInputStream(buf, mybp, len)).readUTF
104+
}
105+
90106
/** skip next 'n' bytes
91107
*/
92108
def skip(n: Int): Unit = { bp += n }
93-
94109
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Scala (https://www.scala-lang.org)
3+
*
4+
* Copyright EPFL and Lightbend, Inc.
5+
*
6+
* Licensed under Apache License 2.0
7+
* (http://www.apache.org/licenses/LICENSE-2.0).
8+
*
9+
* See the NOTICE file distributed with this work for
10+
* additional information regarding copyright ownership.
11+
*/
12+
13+
package scala.tools.nsc.symtab.classfile
14+
15+
import java.io.{DataInputStream, InputStream}
16+
import java.nio.{BufferUnderflowException, ByteBuffer}
17+
18+
19+
final class ByteBufferDataReader(data0: ByteBuffer) extends DataReader {
20+
private[this] var data = data0
21+
private[this] val stream = new InputStream {
22+
override def read(): Int = try {
23+
data.get & 0xff
24+
} catch {
25+
case _: BufferUnderflowException => -1
26+
}
27+
override def markSupported(): Boolean = false
28+
}
29+
private[this] val reader = new DataInputStream(stream)
30+
@throws(classOf[IndexOutOfBoundsException])
31+
def nextByte: Byte = data.get
32+
33+
def nextBytes(len: Int): Array[Byte] = {
34+
val result = new Array[Byte](len)
35+
reader.readFully(result)
36+
result
37+
}
38+
39+
def nextChar: Char = data.getChar()
40+
41+
def nextInt: Int = data.getInt()
42+
43+
def getChar(mybp: Int): Char = {
44+
data.getChar(mybp)
45+
}
46+
47+
def getInt(mybp: Int): Int = {
48+
data.getInt(mybp)
49+
}
50+
51+
def getLong(mybp: Int): Long = {
52+
data.getLong(mybp)
53+
}
54+
55+
def getFloat(mybp: Int): Float = {
56+
data.getFloat(mybp)
57+
}
58+
59+
def getDouble(mybp: Int): Double = {
60+
data.getDouble(mybp)
61+
}
62+
63+
def skip(n: Int): Unit = {
64+
data.position(data.position() + n)
65+
}
66+
def bp: Int = data.position()
67+
def bp_=(i: Int): Unit = data.position(i)
68+
69+
def getByte(mybp: Int): Byte = {
70+
data.get(mybp)
71+
}
72+
def getBytes(mybp: Int, bytes: Array[Byte]): Unit = {
73+
val saved = data.position
74+
data.position(mybp)
75+
try reader.readFully(bytes)
76+
finally data.position(saved)
77+
}
78+
def getUTF(mybp: Int, len: Int): String = {
79+
val saved = data.position
80+
val savedLimit = data.limit()
81+
data.position(mybp)
82+
data.limit(mybp + len)
83+
try reader.readUTF()
84+
finally {
85+
data.limit(savedLimit)
86+
data.position(saved)
87+
}
88+
}
89+
}

0 commit comments

Comments
 (0)