Skip to content

Commit fe1cbd2

Browse files
committed
Minor cleanups and comments in GenBCode
1 parent b664a48 commit fe1cbd2

File tree

6 files changed

+80
-21
lines changed

6 files changed

+80
-21
lines changed

src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
460460
// Can't call .toInterface (at this phase) or we trip an assertion.
461461
// See PackratParser#grow for a method which fails with an apparent mismatch
462462
// between "object PackratParsers$class" and "trait PackratParsers"
463+
// TODO @lry do we have a test for that?
463464
if (sym.isImplClass) {
464465
// pos/spec-List.scala is the sole failure if we don't check for NoSymbol
465466
val traitSym = sym.owner.info.decl(tpnme.interfaceName(sym.name))
@@ -469,6 +470,8 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
469470
}
470471
}
471472

473+
// TODO @lry: code duplication between here and method asmClassType.
474+
472475
assert(hasInternalName(sym), s"Invoked for a symbol lacking JVM internal name: ${sym.fullName}")
473476
assert(!phantomTypeMap.contains(sym), "phantom types not supposed to reach here.")
474477

src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ abstract class BCodeTypes extends BCodeIdiomatic {
2121
import global._
2222
import bTypes._
2323

24-
// when compiling the Scala library, some assertions don't hold (e.g., scala.Boolean has null superClass although it's not an interface)
25-
val isCompilingStdLib = !(settings.sourcepath.isDefault)
24+
// Used only for assertions. When compiling the Scala library, some assertions don't hold
25+
// (e.g., scala.Boolean has null superClass although it's not an interface)
26+
private val isCompilingStdLib = !(settings.sourcepath.isDefault)
2627

2728
// special names
2829
var StringReference : ClassBType = null
@@ -175,12 +176,21 @@ abstract class BCodeTypes extends BCodeIdiomatic {
175176
// ------------------------------------------------
176177

177178
/**
178-
* TODO @lry should probably be a map form ClassBType to Tracked
179+
* Type information for classBTypes.
180+
*
181+
* TODO rename Tracked
179182
*/
180-
val exemplars = new java.util.concurrent.ConcurrentHashMap[BType, Tracked]
183+
val exemplars = new java.util.concurrent.ConcurrentHashMap[ClassBType, Tracked]
181184

182185
/**
183186
* Maps class symbols to their corresponding `Tracked` instance.
187+
*
188+
* This map is only used during the first backend phase (Worker1) where ClassDef trees are
189+
* transformed into ClassNode asm trees. In this phase, ClassBTypes and their Tracked are created
190+
* and added to the `exemplars` map. The `symExemplars` map is only used to know if a symbol has
191+
* already been visited.
192+
*
193+
* TODO move this map to the builder class. it's only used during building. can be gc'd with the builder.
184194
*/
185195
val symExemplars = new java.util.concurrent.ConcurrentHashMap[Symbol, Tracked]
186196

@@ -313,7 +323,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
313323
final def isDeprecated(sym: Symbol): Boolean = { sym.annotations exists (_ matches definitions.DeprecatedAttr) }
314324

315325
/* must-single-thread */
316-
final def hasInternalName(sym: Symbol) = { sym.isClass || (sym.isModule && !sym.isMethod) }
326+
final def hasInternalName(sym: Symbol) = sym.isClass || sym.isModuleNotMethod
317327

318328
/* must-single-thread */
319329
def getSuperInterfaces(csym: Symbol): List[Symbol] = {
@@ -702,6 +712,10 @@ abstract class BCodeTypes extends BCodeIdiomatic {
702712
var x = ics
703713
while (x ne NoSymbol) {
704714
assert(x.isClass, s"not a class symbol: ${x.fullName}")
715+
// Uses `rawowner` because `owner` reflects changes in the owner chain due to flattening.
716+
// The owner chain of a class only contains classes. This is because the lambdalift phase
717+
// changes the `rawowner` destructively to point to the enclosing class. Before, the owner
718+
// might be for example a method.
705719
val isInner = !x.rawowner.isPackageClass
706720
if (isInner) {
707721
chain ::= x
@@ -794,14 +808,23 @@ abstract class BCodeTypes extends BCodeIdiomatic {
794808
* must-single-thread
795809
*/
796810
def javaFlags(sym: Symbol): Int = {
797-
// constructors of module classes should be private
798-
// PP: why are they only being marked private at this stage and not earlier?
811+
// constructors of module classes should be private. introduced in b06edbc, probably to prevent
812+
// creating module instances from java. for nested modules, the constructor needs to be public
813+
// since they are created by the outer class and stored in a field. a java client can create
814+
// new instances via outerClassInstance.new InnerModuleClass$().
815+
// TODO: do this early, mark the symbol private.
799816
val privateFlag =
800817
sym.isPrivate || (sym.isPrimaryConstructor && isTopLevelModule(sym.owner))
801818

802-
// Final: the only fields which can receive ACC_FINAL are eager vals.
803-
// Neither vars nor lazy vals can, because:
819+
// Symbols marked in source as `final` have the FINAL flag. (In the past, the flag was also
820+
// added to modules and module classes, not anymore since 296b706).
821+
// Note that the presence of the `FINAL` flag on a symbol does not correspond 1:1 to emitting
822+
// ACC_FINAL in bytecode.
823+
//
824+
// Top-level modules are marked ACC_FINAL in bytecode (even without the FINAL flag). Nested
825+
// objects don't get the flag to allow overriding (under -Yoverride-objects, SI-5676).
804826
//
827+
// For fields, only eager val fields can receive ACC_FINAL. vars or lazy vals can't:
805828
// Source: http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.3
806829
// "Another problem is that the specification allows aggressive
807830
// optimization of final fields. Within a thread, it is permissible to
@@ -818,7 +841,6 @@ abstract class BCodeTypes extends BCodeIdiomatic {
818841
// we can exclude lateFINAL. Such symbols are eligible for inlining, but to
819842
// avoid breaking proxy software which depends on subclassing, we do not
820843
// emit ACC_FINAL.
821-
// Nested objects won't receive ACC_FINAL in order to allow for their overriding.
822844

823845
val finalFlag = (
824846
(((sym.rawflags & symtab.Flags.FINAL) != 0) || isTopLevelModule(sym))
@@ -845,6 +867,10 @@ abstract class BCodeTypes extends BCodeIdiomatic {
845867
if (sym.isVarargsMethod) ACC_VARARGS else 0,
846868
if (sym.hasFlag(symtab.Flags.SYNCHRONIZED)) ACC_SYNCHRONIZED else 0
847869
)
870+
// TODO @lry should probably also check / add "deprectated"
871+
// all call sites of "javaFlags" seem to check for deprecation rigth after.
872+
// Exception: the call below in javaFieldFlags. However, the caller of javaFieldFlags then
873+
// does the check.
848874
}
849875

850876
/*

src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,24 @@ abstract class BTypes[G <: Global](val __global_dont_use: G) {
235235
/**
236236
* Class or Interface type.
237237
*
238-
* Classes are represented using their name as a slice of the `chrs` array. This representation is
239-
* efficient because the JVM class name is initially created using `classSymbol.javaBinaryName`.
240-
* This already adds the necessary string to the `chrs` array, so it makes sense to reuse the same
241-
* name table in the backend.
238+
* The information for creating a ClassBType (superClass, interfaces, etc) is obtained
239+
* - either from a ClassSymbol, for classes being compiled or referenced from source (see
240+
* BCodeTypes)
241+
* - or, during inlining, from ASM ClassNodes that are parsed from class files.
242+
*
243+
* The class name is represented as a slice of the `chrs` array. This representation is efficient
244+
* because the JVM class name is obtained through `classSymbol.javaBinaryName`. This already adds
245+
* the necessary string to the `chrs` array, so it makes sense to reuse the same name table in the
246+
* backend.
247+
*
248+
* Not a case class because that would expose the constructor that takes (offset, length)
249+
* parameters (I didn't find a way to make it private, also the factory in the companion).
250+
*
251+
* @param offset See below
252+
* @param length The class name is represented as offset and length in the `chrs` array.
253+
* The (public) constructors of ClassBType take a BTypeName, which are
254+
* hash-consed. This ensures that two ClassBType instances for the same name
255+
* have the same offset and length.
242256
*
243257
* Not a case class because that would expose the (Int, Int) constructor (didn't find a way to
244258
* make it private, also the factory in the companion).

src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,9 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
636636
innerSym.rawname + innerSym.moduleSuffix
637637

638638
// add inner classes which might not have been referenced yet
639+
// TODO @lry according to the spec, all nested classes should be added, also local and
640+
// anonymous. This seems to add only member classes - or not? it's exitingErasure, so maybe
641+
// local / anonymous classes have been lifted by lambdalift. are they in the "decls" though?
639642
exitingErasure {
640643
for (sym <- List(csym, csym.linkedClassOfClass); m <- sym.info.decls.map(innerClassSymbolFor) if m.isClass)
641644
innerClassBuffer += m

src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ abstract class GenBCode extends BCodeSyncAndTry {
271271
override def run() {
272272

273273
arrivalPos = 0 // just in case
274-
scalaPrimitives.init
274+
scalaPrimitives.init()
275275
initBCodeTypes()
276276

277277
// initBytecodeWriter invokes fullName, thus we have to run it before the typer-dependent thread is activated.

src/reflect/scala/reflect/internal/Symbols.scala

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,13 +1099,25 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
10991099

11001100
// ------ owner attribute --------------------------------------------------------------
11011101

1102-
/** In general when seeking the owner of a symbol, one should call `owner`.
1103-
* The other possibilities include:
1104-
* - call `safeOwner` if it is expected that the target may be NoSymbol
1105-
* - call `assertOwner` if it is an unrecoverable error if the target is NoSymbol
1102+
/**
1103+
* The owner of a symbol. Changes over time to adapt to the structure of the trees:
1104+
* - Up to lambdalift, the owner is the lexically enclosing definition. For definitions
1105+
* in a local block, the owner is also the next enclosing definition.
1106+
* - After lambdalift, all local method and class definitions (those not owned by a class
1107+
* or package class) change their owner to the enclosing class. This is done through
1108+
* a destructive "sym.owner = sym.owner.enclClass". The old owner is saved by
1109+
* saveOriginalOwner for the backend (needed to generate the EnclosingMethod attribute).
1110+
* - After flatten, all classes are owned by a PackageClass. This is done through a
1111+
* phase check (if after flatten) in the (overridden) method "def owner" in
1112+
* ModuleSymbol / ClassSymbol. The `rawowner` field is not modified.
1113+
*
1114+
* In general when seeking the owner of a symbol, one should call `owner`.
1115+
* The other possibilities include:
1116+
* - call `safeOwner` if it is expected that the target may be NoSymbol
1117+
* - call `assertOwner` if it is an unrecoverable error if the target is NoSymbol
11061118
*
1107-
* `owner` behaves like `safeOwner`, but logs NoSymbol.owner calls under -Xdev.
1108-
* `assertOwner` aborts compilation immediately if called on NoSymbol.
1119+
* `owner` behaves like `safeOwner`, but logs NoSymbol.owner calls under -Xdev.
1120+
* `assertOwner` aborts compilation immediately if called on NoSymbol.
11091121
*/
11101122
def owner: Symbol = {
11111123
if (Statistics.hotEnabled) Statistics.incCounter(ownerCount)
@@ -2811,6 +2823,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
28112823

28122824
override def owner = {
28132825
if (Statistics.hotEnabled) Statistics.incCounter(ownerCount)
2826+
// a module symbol may have the lateMETHOD flag after refchecks, see isModuleNotMethod
28142827
if (!isMethod && needsFlatClasses) rawowner.owner
28152828
else rawowner
28162829
}

0 commit comments

Comments
 (0)