1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
|
package scala.tools.nsc
package backend.jvm
import scala.annotation.switch
/**
* Core BTypes and some other definitions. The initialization of these definitions requires access
* to symbols / types (global).
*
* The symbols used to initialize the ClassBTypes may change from one compiler run to the next. To
* make sure the definitions are consistent with the symbols in the current run, the
* `intializeCoreBTypes` method in BTypesFromSymbols creates a new instance of CoreBTypes in each
* compiler run.
*
* The class BTypesFromSymbols does not directly reference CoreBTypes, but CoreBTypesProxy. The
* reason is that having a `var bTypes: CoreBTypes` would not allow `import bTypes._`. Instead, the
* proxy class holds a `CoreBTypes` in a variable field and forwards to this instance.
*
* The definitions in `CoreBTypes` need to be lazy vals to break an initialization cycle. When
* creating a new instance to assign to the proxy, the `classBTypeFromSymbol` invoked in the
* constructor will actually go through the proxy. The lazy vals make sure the instance is assigned
* in the proxy before the fields are initialized.
*
* Note: if we did not re-create the core BTypes on each compiler run, BType.classBTypeFromInternalNameMap
* could not be a perRunCache anymore: the classes defined here need to be in that map, they are
* added when the ClassBTypes are created. The per run cache removes them, so they would be missing
* in the second run.
*/
class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
import bTypes._
import global._
import rootMirror.{requiredClass, getClassIfDefined}
import definitions._
/**
* Maps primitive types to their corresponding PrimitiveBType. The map is defined lexically above
* the first use of `classBTypeFromSymbol` because that method looks at the map.
*/
lazy val primitiveTypeMap: Map[Symbol, PrimitiveBType] = Map(
UnitClass -> UNIT,
BooleanClass -> BOOL,
CharClass -> CHAR,
ByteClass -> BYTE,
ShortClass -> SHORT,
IntClass -> INT,
LongClass -> LONG,
FloatClass -> FLOAT,
DoubleClass -> DOUBLE
)
lazy val BOXED_UNIT : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.Void])
lazy val BOXED_BOOLEAN : ClassBType = classBTypeFromSymbol(BoxedBooleanClass)
lazy val BOXED_BYTE : ClassBType = classBTypeFromSymbol(BoxedByteClass)
lazy val BOXED_SHORT : ClassBType = classBTypeFromSymbol(BoxedShortClass)
lazy val BOXED_CHAR : ClassBType = classBTypeFromSymbol(BoxedCharacterClass)
lazy val BOXED_INT : ClassBType = classBTypeFromSymbol(BoxedIntClass)
lazy val BOXED_LONG : ClassBType = classBTypeFromSymbol(BoxedLongClass)
lazy val BOXED_FLOAT : ClassBType = classBTypeFromSymbol(BoxedFloatClass)
lazy val BOXED_DOUBLE : ClassBType = classBTypeFromSymbol(BoxedDoubleClass)
/**
* Map from primitive types to their boxed class type. Useful when pushing class literals onto the
* operand stack (ldc instruction taking a class literal), see genConstant.
*/
lazy val boxedClassOfPrimitive: Map[PrimitiveBType, ClassBType] = Map(
UNIT -> BOXED_UNIT,
BOOL -> BOXED_BOOLEAN,
BYTE -> BOXED_BYTE,
SHORT -> BOXED_SHORT,
CHAR -> BOXED_CHAR,
INT -> BOXED_INT,
LONG -> BOXED_LONG,
FLOAT -> BOXED_FLOAT,
DOUBLE -> BOXED_DOUBLE
)
lazy val boxedClasses: Set[ClassBType] = boxedClassOfPrimitive.values.toSet
/**
* Maps the method symbol for a box method to the boxed type of the result. For example, the
* method symbol for `Byte.box()` is mapped to the ClassBType `java/lang/Byte`.
*/
lazy val boxResultType: Map[Symbol, ClassBType] = {
for ((valueClassSym, boxMethodSym) <- currentRun.runDefinitions.boxMethod)
yield boxMethodSym -> boxedClassOfPrimitive(primitiveTypeMap(valueClassSym))
}
/**
* Maps the method symbol for an unbox method to the primitive type of the result.
* For example, the method symbol for `Byte.unbox()`) is mapped to the PrimitiveBType BYTE. */
lazy val unboxResultType: Map[Symbol, PrimitiveBType] = {
for ((valueClassSym, unboxMethodSym) <- currentRun.runDefinitions.unboxMethod)
yield unboxMethodSym -> primitiveTypeMap(valueClassSym)
}
/*
* RT_NOTHING and RT_NULL exist at run-time only. They are the bytecode-level manifestation (in
* method signatures only) of what shows up as NothingClass resp. NullClass in Scala ASTs.
*
* Therefore, when RT_NOTHING or RT_NULL are to be emitted, a mapping is needed: the internal
* names of NothingClass and NullClass can't be emitted as-is.
*/
lazy val RT_NOTHING : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.Nothing$])
lazy val RT_NULL : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.Null$])
lazy val ObjectReference : ClassBType = classBTypeFromSymbol(ObjectClass)
lazy val objArrayReference : ArrayBType = ArrayBType(ObjectReference)
lazy val StringReference : ClassBType = classBTypeFromSymbol(StringClass)
lazy val StringBuilderReference : ClassBType = classBTypeFromSymbol(StringBuilderClass)
lazy val ThrowableReference : ClassBType = classBTypeFromSymbol(ThrowableClass)
lazy val jlCloneableReference : ClassBType = classBTypeFromSymbol(JavaCloneableClass) // java/lang/Cloneable
lazy val jlNPEReference : ClassBType = classBTypeFromSymbol(NullPointerExceptionClass) // java/lang/NullPointerException
lazy val jioSerializableReference : ClassBType = classBTypeFromSymbol(JavaSerializableClass) // java/io/Serializable
lazy val scalaSerializableReference : ClassBType = classBTypeFromSymbol(SerializableClass) // scala/Serializable
lazy val classCastExceptionReference : ClassBType = classBTypeFromSymbol(ClassCastExceptionClass) // java/lang/ClassCastException
lazy val javaUtilMapReference : ClassBType = classBTypeFromSymbol(JavaUtilMap) // java/util/Map
lazy val javaUtilHashMapReference : ClassBType = classBTypeFromSymbol(JavaUtilHashMap) // java/util/HashMap
lazy val srBooleanRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.BooleanRef])
lazy val srByteRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.ByteRef])
lazy val srCharRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.CharRef])
lazy val srIntRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.IntRef])
lazy val srLongRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.LongRef])
lazy val srFloatRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.FloatRef])
lazy val srDoubleRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.DoubleRef])
lazy val hashMethodSym: Symbol = getMember(ScalaRunTimeModule, nme.hash_)
// TODO @lry avoiding going through through missingHook for every line in the REPL: https://github.com/scala/scala/commit/8d962ed4ddd310cc784121c426a2e3f56a112540
lazy val AndroidParcelableInterface : Symbol = getClassIfDefined("android.os.Parcelable")
lazy val AndroidCreatorClass : Symbol = getClassIfDefined("android.os.Parcelable$Creator")
lazy val BeanInfoAttr: Symbol = requiredClass[scala.beans.BeanInfo]
/* The Object => String overload. */
lazy val String_valueOf: Symbol = {
getMember(StringModule, nme.valueOf) filter (sym => sym.info.paramTypes match {
case List(pt) => pt.typeSymbol == ObjectClass
case _ => false
})
}
// scala.FunctionX and scala.runtim.AbstractFunctionX
lazy val FunctionReference : Vector[ClassBType] = (0 to MaxFunctionArity).map(i => classBTypeFromSymbol(FunctionClass(i)))(collection.breakOut)
lazy val AbstractFunctionReference : Vector[ClassBType] = (0 to MaxFunctionArity).map(i => classBTypeFromSymbol(AbstractFunctionClass(i)))(collection.breakOut)
lazy val AbstractFunctionArityMap : Map[ClassBType, Int] = AbstractFunctionReference.zipWithIndex.toMap
lazy val PartialFunctionReference : ClassBType = classBTypeFromSymbol(PartialFunctionClass)
lazy val AbstractPartialFunctionReference : ClassBType = classBTypeFromSymbol(AbstractPartialFunctionClass)
lazy val BoxesRunTime: ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.BoxesRunTime])
/**
* Methods in scala.runtime.BoxesRuntime
*/
lazy val asmBoxTo : Map[BType, MethodNameAndType] = Map(
BOOL -> MethodNameAndType("boxToBoolean", MethodBType(List(BOOL), BOXED_BOOLEAN)),
BYTE -> MethodNameAndType("boxToByte", MethodBType(List(BYTE), BOXED_BYTE)),
CHAR -> MethodNameAndType("boxToCharacter", MethodBType(List(CHAR), BOXED_CHAR)),
SHORT -> MethodNameAndType("boxToShort", MethodBType(List(SHORT), BOXED_SHORT)),
INT -> MethodNameAndType("boxToInteger", MethodBType(List(INT), BOXED_INT)),
LONG -> MethodNameAndType("boxToLong", MethodBType(List(LONG), BOXED_LONG)),
FLOAT -> MethodNameAndType("boxToFloat", MethodBType(List(FLOAT), BOXED_FLOAT)),
DOUBLE -> MethodNameAndType("boxToDouble", MethodBType(List(DOUBLE), BOXED_DOUBLE))
)
lazy val asmUnboxTo: Map[BType, MethodNameAndType] = Map(
BOOL -> MethodNameAndType("unboxToBoolean", MethodBType(List(ObjectReference), BOOL)),
BYTE -> MethodNameAndType("unboxToByte", MethodBType(List(ObjectReference), BYTE)),
CHAR -> MethodNameAndType("unboxToChar", MethodBType(List(ObjectReference), CHAR)),
SHORT -> MethodNameAndType("unboxToShort", MethodBType(List(ObjectReference), SHORT)),
INT -> MethodNameAndType("unboxToInt", MethodBType(List(ObjectReference), INT)),
LONG -> MethodNameAndType("unboxToLong", MethodBType(List(ObjectReference), LONG)),
FLOAT -> MethodNameAndType("unboxToFloat", MethodBType(List(ObjectReference), FLOAT)),
DOUBLE -> MethodNameAndType("unboxToDouble", MethodBType(List(ObjectReference), DOUBLE))
)
lazy val typeOfArrayOp: Map[Int, BType] = {
import scalaPrimitives._
Map(
(List(ZARRAY_LENGTH, ZARRAY_GET, ZARRAY_SET) map (_ -> BOOL)) ++
(List(BARRAY_LENGTH, BARRAY_GET, BARRAY_SET) map (_ -> BYTE)) ++
(List(SARRAY_LENGTH, SARRAY_GET, SARRAY_SET) map (_ -> SHORT)) ++
(List(CARRAY_LENGTH, CARRAY_GET, CARRAY_SET) map (_ -> CHAR)) ++
(List(IARRAY_LENGTH, IARRAY_GET, IARRAY_SET) map (_ -> INT)) ++
(List(LARRAY_LENGTH, LARRAY_GET, LARRAY_SET) map (_ -> LONG)) ++
(List(FARRAY_LENGTH, FARRAY_GET, FARRAY_SET) map (_ -> FLOAT)) ++
(List(DARRAY_LENGTH, DARRAY_GET, DARRAY_SET) map (_ -> DOUBLE)) ++
(List(OARRAY_LENGTH, OARRAY_GET, OARRAY_SET) map (_ -> ObjectReference)) : _*
)
}
}
/**
* This trait make some core BTypes available that don't depend on a Global instance. Some core
* BTypes are required to be accessible in the BTypes trait, which does not have access to Global.
*
* BTypes cannot refer to CoreBTypesProxy because some of its members depend on global, for example
* the type Symbol in
* def primitiveTypeMap: Map[Symbol, PrimitiveBType]
*/
trait CoreBTypesProxyGlobalIndependent[BTS <: BTypes] {
val bTypes: BTS
import bTypes._
def boxedClasses: Set[ClassBType]
def RT_NOTHING : ClassBType
def RT_NULL : ClassBType
def ObjectReference : ClassBType
def jlCloneableReference : ClassBType
def jioSerializableReference : ClassBType
}
/**
* See comment in class [[CoreBTypes]].
*/
final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) extends CoreBTypesProxyGlobalIndependent[BTFS] {
import bTypes._
import global._
private[this] var _coreBTypes: CoreBTypes[bTypes.type] = _
def setBTypes(coreBTypes: CoreBTypes[BTFS]): Unit = {
_coreBTypes = coreBTypes.asInstanceOf[CoreBTypes[bTypes.type]]
}
def primitiveTypeMap: Map[Symbol, PrimitiveBType] = _coreBTypes.primitiveTypeMap
def BOXED_UNIT : ClassBType = _coreBTypes.BOXED_UNIT
def BOXED_BOOLEAN : ClassBType = _coreBTypes.BOXED_BOOLEAN
def BOXED_BYTE : ClassBType = _coreBTypes.BOXED_BYTE
def BOXED_SHORT : ClassBType = _coreBTypes.BOXED_SHORT
def BOXED_CHAR : ClassBType = _coreBTypes.BOXED_CHAR
def BOXED_INT : ClassBType = _coreBTypes.BOXED_INT
def BOXED_LONG : ClassBType = _coreBTypes.BOXED_LONG
def BOXED_FLOAT : ClassBType = _coreBTypes.BOXED_FLOAT
def BOXED_DOUBLE : ClassBType = _coreBTypes.BOXED_DOUBLE
def boxedClasses: Set[ClassBType] = _coreBTypes.boxedClasses
def boxedClassOfPrimitive: Map[PrimitiveBType, ClassBType] = _coreBTypes.boxedClassOfPrimitive
def boxResultType: Map[Symbol, ClassBType] = _coreBTypes.boxResultType
def unboxResultType: Map[Symbol, PrimitiveBType] = _coreBTypes.unboxResultType
def RT_NOTHING : ClassBType = _coreBTypes.RT_NOTHING
def RT_NULL : ClassBType = _coreBTypes.RT_NULL
def ObjectReference : ClassBType = _coreBTypes.ObjectReference
def objArrayReference : ArrayBType = _coreBTypes.objArrayReference
def StringReference : ClassBType = _coreBTypes.StringReference
def StringBuilderReference : ClassBType = _coreBTypes.StringBuilderReference
def ThrowableReference : ClassBType = _coreBTypes.ThrowableReference
def jlCloneableReference : ClassBType = _coreBTypes.jlCloneableReference
def jlNPEReference : ClassBType = _coreBTypes.jlNPEReference
def jioSerializableReference : ClassBType = _coreBTypes.jioSerializableReference
def scalaSerializableReference : ClassBType = _coreBTypes.scalaSerializableReference
def classCastExceptionReference : ClassBType = _coreBTypes.classCastExceptionReference
def javaUtilMapReference : ClassBType = _coreBTypes.javaUtilMapReference
def javaUtilHashMapReference : ClassBType = _coreBTypes.javaUtilHashMapReference
def srBooleanRef : ClassBType = _coreBTypes.srBooleanRef
def srByteRef : ClassBType = _coreBTypes.srByteRef
def srCharRef : ClassBType = _coreBTypes.srCharRef
def srIntRef : ClassBType = _coreBTypes.srIntRef
def srLongRef : ClassBType = _coreBTypes.srLongRef
def srFloatRef : ClassBType = _coreBTypes.srFloatRef
def srDoubleRef : ClassBType = _coreBTypes.srDoubleRef
def hashMethodSym: Symbol = _coreBTypes.hashMethodSym
def AndroidParcelableInterface : Symbol = _coreBTypes.AndroidParcelableInterface
def AndroidCreatorClass : Symbol = _coreBTypes.AndroidCreatorClass
def BeanInfoAttr: Symbol = _coreBTypes.BeanInfoAttr
def String_valueOf: Symbol = _coreBTypes.String_valueOf
def FunctionReference : Vector[ClassBType] = _coreBTypes.FunctionReference
def AbstractFunctionReference : Vector[ClassBType] = _coreBTypes.AbstractFunctionReference
def AbstractFunctionArityMap : Map[ClassBType, Int] = _coreBTypes.AbstractFunctionArityMap
def PartialFunctionReference : ClassBType = _coreBTypes.PartialFunctionReference
def AbstractPartialFunctionReference : ClassBType = _coreBTypes.AbstractPartialFunctionReference
def BoxesRunTime: ClassBType = _coreBTypes.BoxesRunTime
def asmBoxTo : Map[BType, MethodNameAndType] = _coreBTypes.asmBoxTo
def asmUnboxTo: Map[BType, MethodNameAndType] = _coreBTypes.asmUnboxTo
def typeOfArrayOp: Map[Int, BType] = _coreBTypes.typeOfArrayOp
}
|