Skip to content

Commit 93eb3bb

Browse files
authored
Make Context a capability (#16430)
A version of the test compiler where contexts are tracked as capabilities. Two types: Context (tracked, in the future in an arena) and DetachedContext (pure, free in heap). DetachedCOntext is an opaque type. This ensures that we do not accidentally treat an arena-allocated FreshContext as a DetachedContext
2 parents b0883b5 + 99836a4 commit 93eb3bb

File tree

144 files changed

+16880
-818
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

144 files changed

+16880
-818
lines changed

compiler/src/dotty/tools/dotc/cc/CaptureSet.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ sealed abstract class CaptureSet extends Showable:
222222
/** The largest subset (via <:<) of this capture set that only contains elements
223223
* for which `p` is true.
224224
*/
225-
def filter(p: CaptureRef => Boolean)(using Context): CaptureSet =
225+
def filter(p: Context ?=> CaptureRef => Boolean)(using Context): CaptureSet =
226226
if this.isConst then
227227
val elems1 = elems.filter(p)
228228
if elems1 == elems then this
@@ -613,7 +613,7 @@ object CaptureSet:
613613

614614
/** A variable with elements given at any time as { x <- source.elems | p(x) } */
615615
class Filtered private[CaptureSet]
616-
(val source: Var, p: CaptureRef => Boolean)(using @constructorOnly ctx: Context)
616+
(val source: Var, p: Context ?=> CaptureRef => Boolean)(using @constructorOnly ctx: Context)
617617
extends DerivedVar(source.elems.filter(p)):
618618

619619
override def addNewElems(newElems: Refs, origin: CaptureSet)(using Context, VarState): CompareResult =
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
package dotty.tools
2+
package backend
3+
4+
object ScalaPrimitivesOps extends ScalaPrimitivesOps
5+
6+
class ScalaPrimitivesOps {
7+
// Arithmetic unary operations
8+
inline val POS = 1 // +x
9+
inline val NEG = 2 // -x
10+
inline val NOT = 3 // ~x
11+
12+
// Arithmetic binary operations
13+
inline val ADD = 10 // x + y
14+
inline val SUB = 11 // x - y
15+
inline val MUL = 12 // x * y
16+
inline val DIV = 13 // x / y
17+
inline val MOD = 14 // x % y
18+
19+
// Bitwise operations
20+
inline val OR = 20 // x | y
21+
inline val XOR = 21 // x ^ y
22+
inline val AND = 22 // x & y
23+
24+
// Shift operations
25+
inline val LSL = 30 // x << y
26+
inline val LSR = 31 // x >>> y
27+
inline val ASR = 32 // x >> y
28+
29+
// Comparison operations
30+
inline val ID = 40 // x eq y
31+
inline val NI = 41 // x ne y
32+
inline val EQ = 42 // x == y
33+
inline val NE = 43 // x != y
34+
inline val LT = 44 // x < y
35+
inline val LE = 45 // x <= y
36+
inline val GT = 46 // x > y
37+
inline val GE = 47 // x >= y
38+
39+
// Boolean unary operations
40+
inline val ZNOT = 50 // !x
41+
42+
// Boolean binary operations
43+
inline val ZOR = 60 // x || y
44+
inline val ZAND = 61 // x && y
45+
46+
// Array operations
47+
inline val LENGTH = 70 // x.length
48+
inline val APPLY = 71 // x(y)
49+
inline val UPDATE = 72 // x(y) = z
50+
51+
// Any operations
52+
inline val IS = 80 // x.is[y]
53+
inline val AS = 81 // x.as[y]
54+
inline val HASH = 87 // x.##
55+
56+
// AnyRef operations
57+
inline val SYNCHRONIZED = 90 // x.synchronized(y)
58+
59+
// String operations
60+
inline val CONCAT = 100 // String.valueOf(x)+String.valueOf(y)
61+
62+
// coercions
63+
inline val COERCE = 101
64+
65+
// RunTime operations
66+
inline val BOX = 110 // RunTime.box_<X>(x)
67+
inline val UNBOX = 111 // RunTime.unbox_<X>(x)
68+
inline val NEW_ZARRAY = 112 // RunTime.zarray(x)
69+
inline val NEW_BARRAY = 113 // RunTime.barray(x)
70+
inline val NEW_SARRAY = 114 // RunTime.sarray(x)
71+
inline val NEW_CARRAY = 115 // RunTime.carray(x)
72+
inline val NEW_IARRAY = 116 // RunTime.iarray(x)
73+
inline val NEW_LARRAY = 117 // RunTime.larray(x)
74+
inline val NEW_FARRAY = 118 // RunTime.farray(x)
75+
inline val NEW_DARRAY = 119 // RunTime.darray(x)
76+
inline val NEW_OARRAY = 120 // RunTime.oarray(x)
77+
78+
inline val ZARRAY_LENGTH = 131 // RunTime.zarray_length(x)
79+
inline val BARRAY_LENGTH = 132 // RunTime.barray_length(x)
80+
inline val SARRAY_LENGTH = 133 // RunTime.sarray_length(x)
81+
inline val CARRAY_LENGTH = 134 // RunTime.carray_length(x)
82+
inline val IARRAY_LENGTH = 135 // RunTime.iarray_length(x)
83+
inline val LARRAY_LENGTH = 136 // RunTime.larray_length(x)
84+
inline val FARRAY_LENGTH = 137 // RunTime.farray_length(x)
85+
inline val DARRAY_LENGTH = 138 // RunTime.darray_length(x)
86+
inline val OARRAY_LENGTH = 139 // RunTime.oarray_length(x)
87+
88+
inline val ZARRAY_GET = 140 // RunTime.zarray_get(x,y)
89+
inline val BARRAY_GET = 141 // RunTime.barray_get(x,y)
90+
inline val SARRAY_GET = 142 // RunTime.sarray_get(x,y)
91+
inline val CARRAY_GET = 143 // RunTime.carray_get(x,y)
92+
inline val IARRAY_GET = 144 // RunTime.iarray_get(x,y)
93+
inline val LARRAY_GET = 145 // RunTime.larray_get(x,y)
94+
inline val FARRAY_GET = 146 // RunTime.farray_get(x,y)
95+
inline val DARRAY_GET = 147 // RunTime.darray_get(x,y)
96+
inline val OARRAY_GET = 148 // RunTime.oarray_get(x,y)
97+
98+
inline val ZARRAY_SET = 150 // RunTime.zarray(x,y,z)
99+
inline val BARRAY_SET = 151 // RunTime.barray(x,y,z)
100+
inline val SARRAY_SET = 152 // RunTime.sarray(x,y,z)
101+
inline val CARRAY_SET = 153 // RunTime.carray(x,y,z)
102+
inline val IARRAY_SET = 154 // RunTime.iarray(x,y,z)
103+
inline val LARRAY_SET = 155 // RunTime.larray(x,y,z)
104+
inline val FARRAY_SET = 156 // RunTime.farray(x,y,z)
105+
inline val DARRAY_SET = 157 // RunTime.darray(x,y,z)
106+
inline val OARRAY_SET = 158 // RunTime.oarray(x,y,z)
107+
108+
inline val B2B = 200 // RunTime.b2b(x)
109+
inline val B2S = 201 // RunTime.b2s(x)
110+
inline val B2C = 202 // RunTime.b2c(x)
111+
inline val B2I = 203 // RunTime.b2i(x)
112+
inline val B2L = 204 // RunTime.b2l(x)
113+
inline val B2F = 205 // RunTime.b2f(x)
114+
inline val B2D = 206 // RunTime.b2d(x)
115+
116+
inline val S2B = 210 // RunTime.s2b(x)
117+
inline val S2S = 211 // RunTime.s2s(x)
118+
inline val S2C = 212 // RunTime.s2c(x)
119+
inline val S2I = 213 // RunTime.s2i(x)
120+
inline val S2L = 214 // RunTime.s2l(x)
121+
inline val S2F = 215 // RunTime.s2f(x)
122+
inline val S2D = 216 // RunTime.s2d(x)
123+
124+
inline val C2B = 220 // RunTime.c2b(x)
125+
inline val C2S = 221 // RunTime.c2s(x)
126+
inline val C2C = 222 // RunTime.c2c(x)
127+
inline val C2I = 223 // RunTime.c2i(x)
128+
inline val C2L = 224 // RunTime.c2l(x)
129+
inline val C2F = 225 // RunTime.c2f(x)
130+
inline val C2D = 226 // RunTime.c2d(x)
131+
132+
inline val I2B = 230 // RunTime.i2b(x)
133+
inline val I2S = 231 // RunTime.i2s(x)
134+
inline val I2C = 232 // RunTime.i2c(x)
135+
inline val I2I = 233 // RunTime.i2i(x)
136+
inline val I2L = 234 // RunTime.i2l(x)
137+
inline val I2F = 235 // RunTime.i2f(x)
138+
inline val I2D = 236 // RunTime.i2d(x)
139+
140+
inline val L2B = 240 // RunTime.l2b(x)
141+
inline val L2S = 241 // RunTime.l2s(x)
142+
inline val L2C = 242 // RunTime.l2c(x)
143+
inline val L2I = 243 // RunTime.l2i(x)
144+
inline val L2L = 244 // RunTime.l2l(x)
145+
inline val L2F = 245 // RunTime.l2f(x)
146+
inline val L2D = 246 // RunTime.l2d(x)
147+
148+
inline val F2B = 250 // RunTime.f2b(x)
149+
inline val F2S = 251 // RunTime.f2s(x)
150+
inline val F2C = 252 // RunTime.f2c(x)
151+
inline val F2I = 253 // RunTime.f2i(x)
152+
inline val F2L = 254 // RunTime.f2l(x)
153+
inline val F2F = 255 // RunTime.f2f(x)
154+
inline val F2D = 256 // RunTime.f2d(x)
155+
156+
inline val D2B = 260 // RunTime.d2b(x)
157+
inline val D2S = 261 // RunTime.d2s(x)
158+
inline val D2C = 262 // RunTime.d2c(x)
159+
inline val D2I = 263 // RunTime.d2i(x)
160+
inline val D2L = 264 // RunTime.d2l(x)
161+
inline val D2F = 265 // RunTime.d2f(x)
162+
inline val D2D = 266 // RunTime.d2d(x)
163+
164+
/** Check whether the given operation code is an array operation. */
165+
def isArrayOp(code: Int): Boolean =
166+
isArrayNew(code) | isArrayLength(code) | isArrayGet(code) | isArraySet(code)
167+
168+
def isArrayNew(code: Int): Boolean = code match {
169+
case NEW_ZARRAY | NEW_BARRAY | NEW_SARRAY | NEW_CARRAY |
170+
NEW_IARRAY | NEW_LARRAY | NEW_FARRAY | NEW_DARRAY |
171+
NEW_OARRAY => true
172+
case _ => false
173+
}
174+
175+
def isArrayLength(code: Int): Boolean = code match {
176+
case ZARRAY_LENGTH | BARRAY_LENGTH | SARRAY_LENGTH | CARRAY_LENGTH |
177+
IARRAY_LENGTH | LARRAY_LENGTH | FARRAY_LENGTH | DARRAY_LENGTH |
178+
OARRAY_LENGTH | LENGTH => true
179+
case _ => false
180+
}
181+
182+
def isArrayGet(code: Int): Boolean = code match {
183+
case ZARRAY_GET | BARRAY_GET | SARRAY_GET | CARRAY_GET |
184+
IARRAY_GET | LARRAY_GET | FARRAY_GET | DARRAY_GET |
185+
OARRAY_GET | APPLY => true
186+
case _ => false
187+
}
188+
189+
def isArraySet(code: Int): Boolean = code match {
190+
case ZARRAY_SET | BARRAY_SET | SARRAY_SET | CARRAY_SET |
191+
IARRAY_SET | LARRAY_SET | FARRAY_SET | DARRAY_SET |
192+
OARRAY_SET | UPDATE => true
193+
case _ => false
194+
}
195+
196+
/** Check whether the given code is a comparison operator */
197+
def isComparisonOp(code: Int): Boolean = code match {
198+
case ID | NI | EQ | NE |
199+
LT | LE | GT | GE => true
200+
201+
case _ => false
202+
}
203+
def isUniversalEqualityOp(code: Int): Boolean = (code == EQ) || (code == NE)
204+
def isReferenceEqualityOp(code: Int): Boolean = (code == ID) || (code == NI)
205+
206+
def isArithmeticOp(code: Int): Boolean = code match {
207+
case POS | NEG | NOT => true; // unary
208+
case ADD | SUB | MUL |
209+
DIV | MOD => true; // binary
210+
case OR | XOR | AND |
211+
LSL | LSR | ASR => true; // bitwise
212+
case _ => false
213+
}
214+
215+
def isLogicalOp(code: Int): Boolean = code match {
216+
case ZNOT | ZAND | ZOR => true
217+
case _ => false
218+
}
219+
220+
def isShiftOp(code: Int): Boolean = code match {
221+
case LSL | LSR | ASR => true
222+
case _ => false
223+
}
224+
225+
def isBitwiseOp(code: Int): Boolean = code match {
226+
case OR | XOR | AND => true
227+
case _ => false
228+
}
229+
230+
def isCoercion(code: Int): Boolean = (code >= B2B) && (code <= D2D)
231+
232+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package dotty.tools
2+
package backend
3+
4+
/**
5+
* Simple implementation of a worklist algorithm. A processing
6+
* function is applied repeatedly to the first element in the
7+
* worklist, as long as the stack is not empty.
8+
*
9+
* The client class should mix-in this class and initialize the worklist
10+
* field and define the `processElement` method. Then call the `run` method
11+
* providing a function that initializes the worklist.
12+
*
13+
* @author Martin Odersky
14+
* @version 1.0
15+
* @see [[scala.tools.nsc.backend.icode.Linearizers]]
16+
*/
17+
trait WorklistAlgorithm {
18+
type Elem
19+
class WList {
20+
private var list: List[Elem] = Nil
21+
def isEmpty = list.isEmpty
22+
def nonEmpty = !isEmpty
23+
def push(e: Elem): Unit = { list = e :: list }
24+
def pop(): Elem = {
25+
val head = list.head
26+
list = list.tail
27+
head
28+
}
29+
def pushAll(xs: Iterable[Elem]): Unit = xs.foreach(push)
30+
def clear(): Unit = list = Nil
31+
32+
}
33+
34+
val worklist: WList
35+
36+
/**
37+
* Run the iterative algorithm until the worklist remains empty.
38+
* The initializer is run once before the loop starts and should
39+
* initialize the worklist.
40+
*/
41+
def run(initWorklist: => Unit) = {
42+
initWorklist
43+
44+
while (worklist.nonEmpty)
45+
processElement(dequeue)
46+
}
47+
48+
/**
49+
* Process the current element from the worklist.
50+
*/
51+
def processElement(e: Elem): Unit
52+
53+
/**
54+
* Remove and return the first element to be processed from the worklist.
55+
*/
56+
def dequeue: Elem
57+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package dotty.tools
2+
package backend
3+
package jvm
4+
5+
import scala.language.unsafeNulls
6+
7+
import scala.tools.asm.tree.{AbstractInsnNode}
8+
import java.io.PrintWriter
9+
import scala.tools.asm.util.{TraceClassVisitor, TraceMethodVisitor, Textifier}
10+
import scala.tools.asm.ClassReader
11+
12+
object AsmUtils {
13+
14+
/**
15+
* Print the bytecode of methods generated by GenBCode to the standard output. Only methods
16+
* whose name contains `traceMethodPattern` are traced.
17+
*/
18+
final val traceMethodEnabled = sys.env.contains("printBCODE")
19+
final val traceMethodPattern = sys.env.getOrElse("printBCODE", "")
20+
21+
/**
22+
* Print the bytecode of classes generated by GenBCode to the standard output.
23+
*/
24+
inline val traceClassEnabled = false
25+
inline val traceClassPattern = ""
26+
27+
/**
28+
* Print the bytedcode of classes as they are serialized by the ASM library. The serialization
29+
* performed by `asm.ClassWriter` can change the code generated by GenBCode. For example, it
30+
* introduces stack map frames, it computes the maximal stack sizes, and it replaces dead
31+
* code by NOPs (see also https://github.com/scala/scala/pull/3726#issuecomment-42861780).
32+
*/
33+
inline val traceSerializedClassEnabled = false
34+
inline val traceSerializedClassPattern = ""
35+
36+
def traceMethod(mnode: MethodNode1): Unit = {
37+
println(s"Bytecode for method ${mnode.name}")
38+
val p = new Textifier
39+
val tracer = new TraceMethodVisitor(p)
40+
mnode.accept(tracer)
41+
val w = new PrintWriter(System.out)
42+
p.print(w)
43+
w.flush()
44+
}
45+
46+
def traceClass(cnode: ClassNode1): Unit = {
47+
println(s"Bytecode for class ${cnode.name}")
48+
val w = new PrintWriter(System.out)
49+
cnode.accept(new TraceClassVisitor(w))
50+
w.flush()
51+
}
52+
53+
def traceClass(bytes: Array[Byte]): Unit = traceClass(readClass(bytes))
54+
55+
def readClass(bytes: Array[Byte]): ClassNode1 = {
56+
val node = new ClassNode1()
57+
new ClassReader(bytes).accept(node, 0)
58+
node
59+
}
60+
61+
def instructionString(instruction: AbstractInsnNode): String = instruction.getOpcode match {
62+
case -1 => instruction.toString
63+
case op => scala.tools.asm.util.Printer.OPCODES(op)
64+
}
65+
}

0 commit comments

Comments
 (0)