@@ -13,7 +13,7 @@ import scala.tools.nsc.symtab._
13
13
import scala .annotation .switch
14
14
15
15
import scala .tools .asm
16
- import asm .tree .{FieldNode , MethodInsnNode , MethodNode }
16
+ import scala . tools . asm .tree .{FieldInsnNode , FieldNode , MethodInsnNode , MethodNode }
17
17
18
18
/*
19
19
* Prepare in-memory representations of classfiles using the ASM Tree API, and serialize them to disk.
@@ -739,6 +739,8 @@ abstract class GenBCode extends BCodeOptInter {
739
739
val closuresForDelegates = mutable.Map .empty[MethodSymbol , DClosureEndpoint ]
740
740
741
741
private var claszSymbol : Symbol = null
742
+ private var thisBT : BType = null
743
+ private var statifyThisClass = false
742
744
private var isCZParcelable = false
743
745
private var isCZStaticModule = false
744
746
private var isCZRemote = false
@@ -1011,6 +1013,31 @@ abstract class GenBCode extends BCodeOptInter {
1011
1013
cnode.isStaticModule = isCZStaticModule
1012
1014
1013
1015
initJClass(cnode)
1016
+ thisBT = exemplar(claszSymbol).c
1017
+ statifyThisClass = shouldStatifyClass(thisBT)
1018
+
1019
+ /*
1020
+ * In case GenBCode can't honor a request for really-static-ness, a descriptive error is emitted.
1021
+ */
1022
+ if (statifyThisClass) {
1023
+ log(s " Will statify ${thisBT.getInternalName}" )
1024
+ } else {
1025
+ if (claszSymbol hasAnnotation definitions.ReallyStaticClass ) {
1026
+ if (claszSymbol.isImplClass) { cunit.error(cd.pos, " The @reallyStatic annotation isn't applicable to implementation-classes" ) }
1027
+ else if (claszSymbol.isInterface) { cunit.error(cd.pos, " The @reallyStatic annotation isn't applicable to interfaces" ) }
1028
+ else {
1029
+ val toTest : Symbol = if (claszSymbol.isModuleClass) { claszSymbol } else { claszSymbol.linkedClassOfClass }
1030
+ if (toTest == NoSymbol ) {
1031
+ cunit.error(cd.pos, " Not amenable to statification: " + claszSymbol.fullName)
1032
+ } else {
1033
+ val msg = impedimentsToStatifiabilityOfModuleClass(toTest)
1034
+ if (msg != null ) {
1035
+ cunit.error(cd.pos, msg)
1036
+ }
1037
+ }
1038
+ }
1039
+ }
1040
+ }
1014
1041
1015
1042
val hasStaticCtor = methodSymbols(cd) exists (_.isStaticConstructor)
1016
1043
if (! hasStaticCtor) {
@@ -1128,7 +1155,9 @@ abstract class GenBCode extends BCodeOptInter {
1128
1155
*/
1129
1156
def initJMethod (flags : Int , paramAnnotations : List [List [AnnotationInfo ]]) {
1130
1157
1131
- val jgensig = getGenericSignature(methSymbol, claszSymbol)
1158
+ // a java-signature computed for an instance field can't in general be used for a field statified after-the-fact.
1159
+ val jgensig = if (statifyThisClass) null else getGenericSignature(methSymbol, claszSymbol)
1160
+
1132
1161
addRemoteExceptionAnnot(isCZRemote, hasPublicBitSet(flags), methSymbol)
1133
1162
val (excs, others) = methSymbol.annotations partition (_.symbol == definitions.ThrowsClass )
1134
1163
val thrownExceptions : List [String ] = getExceptions(excs)
@@ -1191,9 +1220,13 @@ abstract class GenBCode extends BCodeOptInter {
1191
1220
* No code is needed for this module symbol.
1192
1221
*/
1193
1222
for (f <- fieldSymbols(claszSymbol)) {
1194
- val javagensig = getGenericSignature(f, claszSymbol)
1223
+
1224
+ // a java-signature computed for an instance field can't in general be used for a field statified after-the-fact.
1225
+ val javagensig = if (statifyThisClass) null else getGenericSignature(f, claszSymbol)
1226
+
1195
1227
val flags = mkFlags(
1196
1228
javaFieldFlags(f),
1229
+ if (statifyThisClass) asm.Opcodes .ACC_STATIC else 0 ,
1197
1230
if (isDeprecated(f)) asm.Opcodes .ACC_DEPRECATED else 0 // ASM pseudo access flag
1198
1231
)
1199
1232
@@ -1231,6 +1264,35 @@ abstract class GenBCode extends BCodeOptInter {
1231
1264
}
1232
1265
}
1233
1266
1267
+ /* Usages sites of fields and methods that are "statified after-the-fact" by GenBCode
1268
+ * result in bytecode being emitted to load the receiver. Usually GETSTATIC C.MODULE$ , othertimes ALOAD 0,
1269
+ * but also a method invocation. Due to statification, the receiver should be removed from the operand stack.
1270
+ * */
1271
+ private def adaptReceiverDueToStatification (modClassBT : BType ) {
1272
+ val stream = mnode.instructions
1273
+ val last = stream.getLast
1274
+ last.getOpcode match {
1275
+
1276
+ case asm.Opcodes .GETSTATIC =>
1277
+ val fi = last.asInstanceOf [FieldInsnNode ]
1278
+ assert(fi.owner == modClassBT.getInternalName)
1279
+ stream.remove(fi)
1280
+
1281
+ case _ =>
1282
+ if (asm.optimiz.Util .isLOAD(last)) {
1283
+ val load = last.asInstanceOf [asm.tree.VarInsnNode ]
1284
+ assert(
1285
+ if (load.`var` == 0 ) { thisBT == modClassBT } else true ,
1286
+ " Found ALOAD_0 in a context where adaptReceiverDueToStatification() expected to " +
1287
+ s " load a ${modClassBT.getInternalName}} instance, but instead ${thisBT.getInternalName}} was loaded. "
1288
+ )
1289
+ stream.remove(last)
1290
+ } else {
1291
+ stream.add(new asm.tree.InsnNode (asm.Opcodes .POP ))
1292
+ }
1293
+ }
1294
+ }
1295
+
1234
1296
def genDefDef (dd : DefDef ) {
1235
1297
// the only method whose implementation is not emitted: getClass()
1236
1298
if (definitions.isGetClass(dd.symbol)) { return }
@@ -1242,7 +1304,15 @@ abstract class GenBCode extends BCodeOptInter {
1242
1304
1243
1305
methSymbol = dd.symbol
1244
1306
jMethodName = methSymbol.javaSimpleName.toString
1245
- returnType = asmMethodType(dd.symbol).getReturnType
1307
+
1308
+ val mTypeBT = asmMethodType(dd.symbol)
1309
+
1310
+ val statifyAfterTheFact = {
1311
+ ! dd.symbol.isStaticMember &&
1312
+ shouldStatifyMethod(dd.symbol, thisBT, jMethodName)
1313
+ }
1314
+
1315
+ returnType = mTypeBT.getReturnType
1246
1316
isMethSymStaticCtor = methSymbol.isStaticConstructor
1247
1317
isMethSymBridge = methSymbol.isBridge
1248
1318
@@ -1256,14 +1326,15 @@ abstract class GenBCode extends BCodeOptInter {
1256
1326
val DefDef (_, _, _, vparamss, _, rhs) = dd
1257
1327
assert(vparamss.isEmpty || vparamss.tail.isEmpty, " Malformed parameter list: " + vparamss)
1258
1328
val params = if (vparamss.isEmpty) Nil else vparamss.head
1259
- nxtIdx = if (methSymbol.isStaticMember) 0 else 1 ;
1329
+ nxtIdx = if (methSymbol.isStaticMember || statifyAfterTheFact ) 0 else 1 ;
1260
1330
for (p <- params) { makeLocal(p.symbol) }
1261
1331
// debug assert((params.map(p => locals(p.symbol).tk)) == asmMethodType(methSymbol).getArgumentTypes.toList, "debug")
1262
1332
1263
1333
val isNative = methSymbol.hasAnnotation(definitions.NativeAttr )
1264
1334
val isAbstractMethod = (methSymbol.isDeferred || methSymbol.owner.isInterface)
1265
1335
val flags = mkFlags(
1266
1336
javaFlags(methSymbol),
1337
+ if (statifyAfterTheFact) asm.Opcodes .ACC_STATIC else 0 ,
1267
1338
if (claszSymbol.isInterface) asm.Opcodes .ACC_ABSTRACT else 0 ,
1268
1339
if (methSymbol.isStrictFP) asm.Opcodes .ACC_STRICT else 0 ,
1269
1340
if (isNative) asm.Opcodes .ACC_NATIVE else 0 , // native methods of objects are generated in mirror classes
@@ -1425,9 +1496,22 @@ abstract class GenBCode extends BCodeOptInter {
1425
1496
case Assign (lhs @ Select (_, _), rhs) =>
1426
1497
val isStatic = lhs.symbol.isStaticMember
1427
1498
if (! isStatic) { genLoadQualifier(lhs) }
1428
- genLoad(rhs, symInfoTK(lhs.symbol) )
1499
+ val fieldTK = symInfoTK(lhs.symbol)
1429
1500
lineNumber(tree)
1430
- fieldStore(lhs.symbol)
1501
+ val hostClassBT = exemplar(lhs.symbol.owner).c
1502
+ if (! isStatic && shouldStatifyClass(hostClassBT)) {
1503
+ adaptReceiverDueToStatification(hostClassBT)
1504
+ genLoad(rhs, fieldTK)
1505
+ val field = lhs.symbol
1506
+ val owner = hostClassBT.getInternalName
1507
+ val fieldJName = field.javaSimpleName.toString
1508
+ val fieldDescr = fieldTK.getDescriptor
1509
+ val opc = asm.Opcodes .PUTSTATIC
1510
+ mnode.visitFieldInsn(opc, owner, fieldJName, fieldDescr)
1511
+ } else {
1512
+ genLoad(rhs, fieldTK)
1513
+ fieldStore(lhs.symbol)
1514
+ }
1431
1515
1432
1516
case Assign (lhs, rhs) =>
1433
1517
val s = lhs.symbol
@@ -2014,7 +2098,9 @@ abstract class GenBCode extends BCodeOptInter {
2014
2098
assert(tree.symbol == claszSymbol || symIsModuleClass,
2015
2099
" Trying to access the this of another class: " +
2016
2100
" tree.symbol = " + tree.symbol + " , class symbol = " + claszSymbol + " compilation unit:" + cunit)
2017
- if (symIsModuleClass && tree.symbol != claszSymbol) {
2101
+ if (symIsModuleClass &&
2102
+ (tree.symbol != claszSymbol || statifyThisClass)
2103
+ ) {
2018
2104
generatedType = genLoadModule(tree)
2019
2105
}
2020
2106
else {
@@ -2041,13 +2127,25 @@ abstract class GenBCode extends BCodeOptInter {
2041
2127
genLoadQualUnlessElidable()
2042
2128
genLoadModule(tree)
2043
2129
}
2044
- else if (sym.isStaticMember) {
2045
- genLoadQualUnlessElidable()
2046
- fieldLoad(sym, hostClass)
2047
- }
2048
2130
else {
2049
- genLoadQualifier(tree)
2050
- fieldLoad(sym, hostClass)
2131
+ if (sym.isStaticMember) {
2132
+ genLoadQualUnlessElidable()
2133
+ fieldLoad(sym, hostClass)
2134
+ }
2135
+ else {
2136
+ genLoadQualifier(tree)
2137
+ val hostClassBT = exemplar(hostClass).c // hostClass shouldn't be null, but in that case field.owner will do.
2138
+ if (shouldStatifyClass(hostClassBT)) {
2139
+ adaptReceiverDueToStatification(hostClassBT)
2140
+ val field = sym
2141
+ val owner = hostClassBT.getInternalName
2142
+ val fieldJName = field.javaSimpleName.toString
2143
+ val fieldDescr = symInfoTK(field).getDescriptor
2144
+ mnode.visitFieldInsn(asm.Opcodes .GETSTATIC , owner, fieldJName, fieldDescr)
2145
+ } else {
2146
+ fieldLoad(sym, hostClass)
2147
+ }
2148
+ }
2051
2149
}
2052
2150
2053
2151
case Ident (name) =>
@@ -2445,10 +2543,33 @@ abstract class GenBCode extends BCodeOptInter {
2445
2543
2446
2544
} // end of genNormalMethodCall()
2447
2545
2448
- genNormalMethodCall()
2546
+ val symOwnerBT = exemplar(sym.owner).c
2547
+ val jname = sym.javaSimpleName.toString
2548
+ if (! sym.isStaticMember && shouldStatifyMethod(sym, symOwnerBT, jname)) {
2549
+ genLoadQualifier(fun)
2550
+ adaptReceiverDueToStatification(symOwnerBT)
2551
+ genLoadArguments(args, paramTKs(app))
2552
+ val jowner = symOwnerBT.getInternalName
2553
+ val bmType = asmMethodType(sym)
2554
+ val mdescr = bmType.getDescriptor
2555
+ val callsite = new MethodInsnNode (asm.Opcodes .INVOKESTATIC , jowner, jname, mdescr)
2556
+ mnode.instructions.add(callsite)
2557
+ // prepare for inlining if needed
2558
+ if (isIntraProgramOpt) {
2559
+ val knockOuts = (isMethSymBridge || (sym == methSymbol))
2560
+ if (! knockOuts && hasInline(sym)) {
2561
+ val isHiO = isHigherOrderMethod(bmType)
2562
+ val inlnTarget = new InlineTarget (callsite, cunit, app.pos)
2563
+ if (isHiO) { cgn.hiOs ::= inlnTarget }
2564
+ else { cgn.procs ::= inlnTarget }
2565
+ }
2566
+ }
2567
+ } else {
2568
+ genNormalMethodCall()
2569
+ }
2449
2570
2450
2571
generatedType = asmMethodType(sym).getReturnType
2451
- }
2572
+ }
2452
2573
2453
2574
}
2454
2575
@@ -2504,9 +2625,12 @@ abstract class GenBCode extends BCodeOptInter {
2504
2625
val arity = abstractFunctionArity(castToBT)
2505
2626
2506
2627
val delegateSym = fakeCallsite.symbol.asInstanceOf [MethodSymbol ]
2507
- val hasStaticModuleOwner = isStaticModule(delegateSym.owner)
2628
+ val delegateOwner = delegateSym.owner
2629
+ val hasStaticModuleOwner = {
2630
+ isStaticModule(delegateOwner) || shouldStatifyClass(delegateOwner)
2631
+ }
2508
2632
val hasOuter = ! delegateSym.isStaticMember && ! hasStaticModuleOwner
2509
- val isStaticImplMethod = delegateSym.owner .isImplClass
2633
+ val isStaticImplMethod = delegateOwner .isImplClass
2510
2634
2511
2635
assert(
2512
2636
uncurry.closureDelegates.contains(delegateSym),
@@ -2526,7 +2650,7 @@ abstract class GenBCode extends BCodeOptInter {
2526
2650
// checking working assumptions
2527
2651
2528
2652
// outerTK is a poor name choice because sometimes there's no outer instance yet there's always a delegateOwnerTK
2529
- val outerTK = brefType(internalName(delegateSym.owner))
2653
+ val outerTK = exemplar(delegateOwner).c
2530
2654
val enclClassBT = brefType(cnode.name)
2531
2655
assert(outerTK.hasObjectSort, s " Not of object sort: $outerTK" )
2532
2656
assert(
@@ -2935,7 +3059,11 @@ abstract class GenBCode extends BCodeOptInter {
2935
3059
val ultimateMT = BT .getMethodType(ultimate.desc)
2936
3060
2937
3061
// in order to invoke the delegate, load the receiver if any
2938
- if (hasStaticModuleOwner) {
3062
+ val statifyOuter = shouldStatifyClass(outerTK)
3063
+ if (statifyOuter) {
3064
+ ()
3065
+ }
3066
+ else if (hasStaticModuleOwner) {
2939
3067
// GETSTATIC the/module/Class$.MODULE$ : Lthe/module/Class;
2940
3068
ultimate.visitFieldInsn(
2941
3069
asm.Opcodes .GETSTATIC ,
@@ -2974,7 +3102,8 @@ abstract class GenBCode extends BCodeOptInter {
2974
3102
}
2975
3103
2976
3104
val callOpc =
2977
- if (hasOuter || hasStaticModuleOwner) asm.Opcodes .INVOKEVIRTUAL
3105
+ if (statifyOuter) asm.Opcodes .INVOKESTATIC
3106
+ else if (hasOuter || hasStaticModuleOwner) asm.Opcodes .INVOKEVIRTUAL
2978
3107
else asm.Opcodes .INVOKESTATIC
2979
3108
ultimate.visitMethodInsn(
2980
3109
callOpc,
@@ -3239,7 +3368,7 @@ abstract class GenBCode extends BCodeOptInter {
3239
3368
}
3240
3369
3241
3370
def genLoadModule (module : Symbol ) {
3242
- if (claszSymbol == module.moduleClass && jMethodName != " readResolve" ) {
3371
+ if (claszSymbol == module.moduleClass && jMethodName != " readResolve" && ! statifyThisClass ) {
3243
3372
mnode.visitVarInsn(asm.Opcodes .ALOAD , 0 )
3244
3373
} else {
3245
3374
val mbt = asmClassType(module)
0 commit comments