@@ -25,6 +25,46 @@ abstract class BCodeTypes extends SubComponent with BytecodeWriters {
25
25
26
26
val isLateClosuresOn = (settings.isClosureConvDelegating || settings.isClosureConvMH)
27
27
28
+ def isCustomValueClass (csym : Symbol ): Boolean = enteringErasure(csym.isDerivedValueClass)
29
+
30
+ /*
31
+ * The set `knownModClassStatification` contains
32
+ * those module-classes of static-modules as well as those module-classes of custom-value-classes
33
+ * that fulfill the conditions for `statification` checked by `isStatifiableModuleClass()`
34
+ *
35
+ * The module-class of a custom-value-class may have a side-effecting class-initializer, as the following examples show.
36
+ *
37
+ * Example 1:
38
+ * class A { println("A") }
39
+ * object B extends A { }
40
+ * class B(val underlying: Int) extends AnyVal { }
41
+ *
42
+ * Example 2:
43
+ * object C {
44
+ * val singleton1 = ...
45
+ * }
46
+ * class C(val underlying: Int) extends AnyVal { }
47
+ *
48
+ */
49
+ val knownModClassStatification = mutable.Set .empty[BType ]
50
+
51
+ /*
52
+ * "Statification" is a GenBCode-level transform that turns into static the members of those module classes
53
+ * that fulfill the conditions checked in `isStatifiableModuleClass()` EXCEPT those members overriding methods in the Object API.
54
+ * Usage sites are also adapted.
55
+ */
56
+ def shouldStatifyClass (bt : BType ): Boolean = { knownModClassStatification(bt) }
57
+
58
+ def shouldStatifyClass (csym : Symbol ): Boolean = {
59
+ shouldStatifyClass(exemplar(csym).c)
60
+ }
61
+
62
+ def shouldStatifyMethod (msym : Symbol , owner : BType , methodName : String ): Boolean = {
63
+ (methodName != nme.CONSTRUCTOR .toString) &&
64
+ shouldStatifyClass(owner) &&
65
+ (msym.overriddenSymbol(definitions.ObjectClass ) == NoSymbol )
66
+ }
67
+
28
68
object BT {
29
69
30
70
import global .chrs
@@ -963,6 +1003,7 @@ abstract class BCodeTypes extends SubComponent with BytecodeWriters {
963
1003
def clearBCodeTypes () {
964
1004
symExemplars.clear()
965
1005
exemplars.clear()
1006
+ knownModClassStatification.clear()
966
1007
clearBCodeOpt()
967
1008
}
968
1009
@@ -1291,15 +1332,20 @@ abstract class BCodeTypes extends SubComponent with BytecodeWriters {
1291
1332
1292
1333
/*
1293
1334
* must-single-thread
1335
+ *
1336
+ * @param csym denotes either a "plain class" or a "module class", see `exemplar()`
1337
+ * @param key the BType for csym's javaBinaryName
1294
1338
*/
1295
1339
private def buildExemplar (key : BType , csym : Symbol ): Tracked = {
1340
+ val isImplClass = csym.isImplClass
1296
1341
val sc =
1297
- if (csym. isImplClass) definitions.ObjectClass
1342
+ if (isImplClass) definitions.ObjectClass
1298
1343
else csym.superClass
1344
+ val isInterface = csym.isInterface
1299
1345
assert(
1300
1346
if (csym == definitions.ObjectClass )
1301
1347
sc == NoSymbol
1302
- else if (csym. isInterface)
1348
+ else if (isInterface)
1303
1349
sc == definitions.ObjectClass
1304
1350
else
1305
1351
((sc != NoSymbol ) && ! sc.isInterface) || isCompilingStdLib,
@@ -1323,9 +1369,104 @@ abstract class BCodeTypes extends SubComponent with BytecodeWriters {
1323
1369
1324
1370
val innersChain = saveInnerClassesFor(csym, key)
1325
1371
1372
+ if (! isImplClass && ! isInterface) {
1373
+ // collect info needed later about custom value classes
1374
+ if (csym.isModuleClass) {
1375
+ trackModuleClass(csym, key)
1376
+ } else if (isCustomValueClass(csym)) {
1377
+ val mcBT = brefType(key.getInternalName + " $" )
1378
+ val modCSym = enteringErasure{ csym.linkedClassOfClass }
1379
+ trackCustomValueClass(csym, modCSym, mcBT)
1380
+ // notice we're not adding exemplar for the module-class --- someone else will do that
1381
+ }
1382
+ }
1383
+
1326
1384
Tracked (key, flags, tsc, ifacesArr, innersChain)
1327
1385
}
1328
1386
1387
+ /*
1388
+ * Track the module class of a custom value class that fulfills the criteria for "statification".
1389
+ */
1390
+ private def trackCustomValueClass (plainClass : Symbol , modClass : Symbol , modClassBT : BType ) {
1391
+
1392
+ assert(modClass != NoSymbol )
1393
+
1394
+ if (knownModClassStatification(modClassBT)) { return }
1395
+
1396
+ val isAnnotated = (modClass hasAnnotation definitions.ReallyStaticClass ) || (
1397
+ (plainClass != NoSymbol ) && (plainClass hasAnnotation definitions.ReallyStaticClass )
1398
+ )
1399
+
1400
+ if (! isAnnotated || ! isStatifiableModuleClass(modClass)) { return }
1401
+ knownModClassStatification += modClassBT
1402
+
1403
+ // // collect syms of extension methods
1404
+ // val extMSyms = enteringErasure {
1405
+ // plainClass.info.members.collect{ case m if m.isMethodWithExtension => extensionMethods.extensionMethod(m) }
1406
+ // }
1407
+
1408
+ }
1409
+
1410
+ /*
1411
+ * Track the module-classes of static-modules that fulfill the criteria for "statification".
1412
+ */
1413
+ private def trackModuleClass (modClass : Symbol , modClassBT : BType ) {
1414
+ if (knownModClassStatification(modClassBT)) { return }
1415
+ val isAnnotated = (modClass hasAnnotation definitions.ReallyStaticClass )
1416
+ if (! isAnnotated || ! isStatifiableModuleClass(modClass)) { return }
1417
+ knownModClassStatification += modClassBT
1418
+ }
1419
+
1420
+ /*
1421
+ * @return true iff all of the conditions below hold:
1422
+ * (1) modClass is a static module
1423
+ * (2) modClass is direct subclass of AnyRef
1424
+ * (3) modClass doesn't extend any non-marker interfaces (thus, the members of the mod-class can be made static).
1425
+ *
1426
+ * Please notice the invoker has to test for the presence of @reallyStatic.
1427
+ *
1428
+ * must-single-thread
1429
+ *
1430
+ */
1431
+ private def isStatifiableModuleClass (modClass : Symbol ): Boolean = {
1432
+ val msg = impedimentsToStatifiabilityOfModuleClass(modClass)
1433
+ if (msg == null ) true
1434
+ else { log(msg); false }
1435
+ }
1436
+
1437
+ /*
1438
+ * @return null iff the modClass is statifiable (please notice no check for @reallyStatic is performed here).
1439
+ * Otherwise returns a String listing restrictions not fulfilled by modClass and that prevent statifiability.
1440
+ */
1441
+ def impedimentsToStatifiabilityOfModuleClass (modClass : Symbol ): String = {
1442
+ assert(modClass != NoSymbol )
1443
+
1444
+ var result : List [String ] = Nil
1445
+
1446
+ if (modClass.isJavaDefined) { result ::= " is a Java-defined class" }
1447
+ if (! isStaticModule(modClass)) { result ::= " isn't a static module (ie has an outer-instance" }
1448
+
1449
+ val scSym = modClass.superClass
1450
+ if (scSym != definitions.ObjectClass && scSym != NoSymbol ) {
1451
+ result ::= s " has a superClass other than AnyRef: ${scSym.fullName}"
1452
+ }
1453
+
1454
+ def isMarkerInterface (isym : Symbol ): Boolean = {
1455
+ isym.info.declarations.isEmpty &&
1456
+ (isym.mixinClasses forall isMarkerInterface)
1457
+ }
1458
+
1459
+ val nonMarkerIfaces = modClass.mixinClasses filter { iface => ! isMarkerInterface(iface) }
1460
+ if (! nonMarkerIfaces.isEmpty) {
1461
+ result ::= s " extends non-marker interfaces ${prettyPrintFullnames(nonMarkerIfaces)}"
1462
+ }
1463
+
1464
+ if (result.isEmpty) null
1465
+ else {
1466
+ s " Won't statify the static module class of ${modClass.fullName} because it " + result.mkString(" . Moreover, it " )
1467
+ }
1468
+ }
1469
+
1329
1470
// ---------------- utilities around interfaces represented by Tracked instances. ----------------
1330
1471
1331
1472
/* Drop redundant interfaces (those which are implemented by some other).
0 commit comments