Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 16 additions & 18 deletions compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package dotty.tools
package backend
package jvm

import scala.language.unsafeNulls
import scala.annotation.{switch, tailrec}
import scala.collection.mutable.SortedMap
import scala.tools.asm
Expand Down Expand Up @@ -202,7 +201,7 @@ trait BCodeBodyBuilder(val primitives: ScalaPrimitives) extends BCodeSkelBuilder

if (isArrayGet(code)) {
// load argument on stack
assert(args.length == 1, s"Too many arguments for array get operation: $tree");
assert(args.length == 1, s"Too many arguments for array get operation: $tree")
stack.push(k)
genLoad(args.head, INT)
stack.pop()
Expand Down Expand Up @@ -335,7 +334,7 @@ trait BCodeBodyBuilder(val primitives: ScalaPrimitives) extends BCodeSkelBuilder
bc.store(idx, tk)
val localVarStart = currProgramPoint()
if (!isSynth) { // there are case <synthetic> ValDef's emitted by patmat
varsInScope ::= (sym -> localVarStart)
varsInScope = (sym -> localVarStart) :: varsInScope.nn
}
generatedType = UNIT

Expand Down Expand Up @@ -547,7 +546,7 @@ trait BCodeBodyBuilder(val primitives: ScalaPrimitives) extends BCodeSkelBuilder
private def fieldOp(field: Symbol, isLoad: Boolean, specificReceiver: Symbol | Null)(using Context): Unit = {
val useSpecificReceiver = specificReceiver != null && !field.isScalaStatic

val owner = bTypeLoader.classBTypeFromSymbol(if (useSpecificReceiver) specificReceiver else field.owner).internalName
val owner = bTypeLoader.classBTypeFromSymbol(if (useSpecificReceiver) specificReceiver.nn else field.owner).internalName
val fieldJName = field.javaSimpleName
val fieldDescr = symInfoTK(field).descriptor
val isStatic = field.isStaticMember
Expand Down Expand Up @@ -653,7 +652,7 @@ trait BCodeBodyBuilder(val primitives: ScalaPrimitives) extends BCodeSkelBuilder
if (earlyReturnVar == null) {
earlyReturnVar = locals.makeLocal(returnType, "earlyReturnVar", expr.tpe, expr.span)
}
locals.store(earlyReturnVar)
locals.store(earlyReturnVar.nn)
}
bc.goTo(nextCleanup)
shouldEmitCleanup = true
Expand Down Expand Up @@ -986,7 +985,7 @@ trait BCodeBodyBuilder(val primitives: ScalaPrimitives) extends BCodeSkelBuilder

var flatKeys: List[Int] = Nil
var targets: List[asm.Label] = Nil
var default: asm.Label = null
var default: asm.Label | Null = null
var switchBlocks: List[(asm.Label, Tree)] = Nil

genLoad(selector, INT)
Expand Down Expand Up @@ -1020,7 +1019,7 @@ trait BCodeBodyBuilder(val primitives: ScalaPrimitives) extends BCodeSkelBuilder
if !hasDefault then
default = new asm.Label

bc.emitSWITCH(mkArrayReverse(flatKeys), mkArrayL(targets.reverse), default, MIN_SWITCH_DENSITY)
bc.emitSWITCH(mkArrayReverse(flatKeys), mkArrayL(targets.reverse), default.nn, MIN_SWITCH_DENSITY)

// emit switch-blocks.
for (sb <- switchBlocks.reverse) {
Expand All @@ -1030,7 +1029,7 @@ trait BCodeBodyBuilder(val primitives: ScalaPrimitives) extends BCodeSkelBuilder
}

if !hasDefault then
markProgramPoint(default)
markProgramPoint(default.nn)
emitThrowMatchError()
} else {

Expand All @@ -1042,13 +1041,12 @@ trait BCodeBodyBuilder(val primitives: ScalaPrimitives) extends BCodeSkelBuilder
* This mirrors the way that Java compiles `switch` on Strings.
*/

var default: asm.Label = null
var indirectBlocks: List[(asm.Label, Tree)] = Nil
var default: asm.Label | Null = null
var indirectBlocks: List[(asm.Label, Tree | Null)] = Nil


// Cases grouped by their hashCode
val casesByHash = SortedMap.empty[Int, List[(String, Either[asm.Label, Tree])]]
var caseFallback: Tree = null

for (caze @ CaseDef(pat, guard, body) <- cases) {
assert(guard == tpd.EmptyTree, guard)
Expand All @@ -1062,7 +1060,7 @@ trait BCodeBodyBuilder(val primitives: ScalaPrimitives) extends BCodeSkelBuilder
case Ident(nme.WILDCARD) =>
assert(default == null, s"multiple default targets in a Match node, at ${tree.span}")
default = new asm.Label
indirectBlocks ::= (default, body)
indirectBlocks ::= (default.nn, body)
case Alternative(alts) =>
// We need an extra basic block since multiple strings can lead to this code
val indirectCaseGroupLabel = new asm.Label
Expand Down Expand Up @@ -1097,7 +1095,7 @@ trait BCodeBodyBuilder(val primitives: ScalaPrimitives) extends BCodeSkelBuilder
val hasDefault = default != null
if !hasDefault then
default = new asm.Label
indirectBlocks ::= (default, null)
indirectBlocks ::= (default.nn, null)

// Push the hashCode of the string (or `0` it is `null`) onto the stack and switch on it
genLoadIfTo(
Expand All @@ -1109,7 +1107,7 @@ trait BCodeBodyBuilder(val primitives: ScalaPrimitives) extends BCodeSkelBuilder
INT,
LoadDestination.FallThrough
)
bc.emitSWITCH(mkArrayReverse(flatKeys), mkArrayL(targets.reverse), default, MIN_SWITCH_DENSITY)
bc.emitSWITCH(mkArrayReverse(flatKeys), mkArrayL(targets.reverse), default.nn, MIN_SWITCH_DENSITY)

// emit blocks for each hash case
for ((hashLabel, caseAlternatives) <- hashBlocks.reverse) {
Expand All @@ -1130,7 +1128,7 @@ trait BCodeBodyBuilder(val primitives: ScalaPrimitives) extends BCodeSkelBuilder
}
markProgramPoint(keepGoing)
}
bc.goTo(default)
bc.goTo(default.nn)
}

// emit blocks for common patterns
Expand Down Expand Up @@ -1165,7 +1163,7 @@ trait BCodeBodyBuilder(val primitives: ScalaPrimitives) extends BCodeSkelBuilder
def emitLocalVarScopes(): Unit =
if (BackendUtils.emitVars) {
val end = currProgramPoint()
for ((sym, start) <- varsInScope.reverse) {
for ((sym, start) <- varsInScope.nn.reverse) {
emitLocalVarScope(sym, start, end)
}
}
Expand Down Expand Up @@ -1445,7 +1443,7 @@ trait BCodeBodyBuilder(val primitives: ScalaPrimitives) extends BCodeSkelBuilder
assert(style.isVirtual || style.isSuper || specificReceiver == methodOwner, s"specificReceiver can only be specified for virtual and super calls. $method - $specificReceiver")

val useSpecificReceiver = specificReceiver != null && !defn.isBottomClass(specificReceiver) && !method.isScalaStatic
val receiver = if (useSpecificReceiver) specificReceiver else methodOwner
val receiver: Symbol = if (useSpecificReceiver) specificReceiver.nn else methodOwner

// TODO this JVM bug was resolved a very long time ago, workaround could be removed?
// workaround for a JVM bug: https://bugs.openjdk.java.net/browse/JDK-8154587
Expand Down Expand Up @@ -1603,7 +1601,7 @@ trait BCodeBodyBuilder(val primitives: ScalaPrimitives) extends BCodeSkelBuilder
case Literal(Constant(null)) => true
case _ => false
}
def ifOneIsNull(l: Tree, r: Tree): Tree = if (isNull(l)) r else if (isNull(r)) l else null
def ifOneIsNull(l: Tree, r: Tree): Tree | Null = if (isNull(l)) r else if (isNull(r)) l else null
val nonNullSide = if (ScalaPrimitivesOps.isReferenceEqualityOp(code)) ifOneIsNull(l, r) else null
if (nonNullSide != null) {
// special-case reference (in)equality test for null (null eq x, x eq null)
Expand Down
5 changes: 2 additions & 3 deletions compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package dotty.tools
package backend
package jvm

import scala.language.unsafeNulls
import scala.tools.asm
import scala.tools.asm.{AnnotationVisitor, ClassWriter, Opcodes}
import scala.collection.mutable
Expand Down Expand Up @@ -205,7 +204,7 @@ trait BCodeHelpers(val bTypeLoader: BTypeLoader, val bTypes: WellKnownBTypes) ex
}

private def emitArgument(av: AnnotationVisitor,
name: String,
name: String | Null,
arg: Tree)(using Context): Unit = {
val narg = normalizeArgument(arg)
// Transformation phases are not run on annotation trees, so we need to run
Expand Down Expand Up @@ -649,7 +648,7 @@ trait BCodeHelpers(val bTypeLoader: BTypeLoader, val bTypes: WellKnownBTypes) ex
val erasedMemberType = ElimErasedValueType.elimEVT(TypeErasure.transformInfo(sym, memberTpe))
if (erasedMemberType =:= sym.denot.info)
val gensig = getGenericSignatureHelper(sym, moduleClass, memberTpe)
if gensig == null || descriptor.contentEquals(gensig) then null
if gensig == null || (descriptor != null && descriptor.contentEquals(gensig)) then null
else gensig.toString
else null
else null
Expand Down
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/backend/jvm/BCodeIdiomatic.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package dotty.tools
package backend
package jvm

import scala.language.unsafeNulls
import scala.tools.asm
import scala.annotation.switch
import scala.tools.asm.tree.MethodInsnNode
Expand Down
47 changes: 24 additions & 23 deletions compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package dotty.tools
package backend
package jvm

import scala.language.unsafeNulls
import scala.annotation.tailrec
import scala.collection.{immutable, mutable}
import scala.tools.asm
Expand All @@ -23,6 +22,8 @@ import SymbolUtils.given
import dotty.tools.dotc.core.NameOps.isStaticConstructorName
import tpd.*

import scala.compiletime.uninitialized

/*
*
* @author Miguel Garcia, http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/
Expand Down Expand Up @@ -132,14 +133,14 @@ trait BCodeSkelBuilder extends BCodeHelpers {
with BCJGenSigGen {

// Strangely I can't find this in the asm code 255, but reserving 1 for "this"
inline val MaximumJvmParameters = 254
private inline val MaximumJvmParameters = 254

// current class
var cnode: ClassNode1 = null
var thisName: String = null // the internal name of the class being emitted
private var cnode: ClassNode1 = uninitialized
private var thisName: String = uninitialized // the internal name of the class being emitted
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unfortunately given the code shape removing the need for uninitialized would require a fair amount of work. But at least we can make those private so nobody accidentally observes them when they shouldn't.


var claszSymbol: Symbol = null
var isCZStaticModule = false
protected var claszSymbol: Symbol = uninitialized
private var isCZStaticModule = false

// keep track of interfaces that are used in super calls, as they need to be directly inherited even if they are also indirectly inherited
val superCallTargets = mutable.LinkedHashSet[ClassBType]()
Expand All @@ -160,7 +161,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {

/* ---------------- helper utils for generating classes and fields ---------------- */

def genPlainClass(cd0: TypeDef)(using Context) = (cd0: @unchecked) match {
def genPlainClass(cd0: TypeDef)(using Context): ClassNode1 = (cd0: @unchecked) match {
case TypeDef(_, impl: Template) =>
assert(cnode == null, "GenBCode detected nested methods.")

Expand Down Expand Up @@ -288,7 +289,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {
TraceUtils.traceClassIfRequested(cnode)

assert(cd.symbol == claszSymbol, "Someone messed up BCodePhase.claszSymbol during genPlainClass().")

cnode
} // end of method genPlainClass()

/*
Expand Down Expand Up @@ -386,7 +387,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {
.addFlagIf(!sym.is(Mutable), ACC_FINAL)
}

def addClassField(f: Symbol)(using Context): Unit = {
private def addClassField(f: Symbol)(using Context): Unit = {
val descriptor = symInfoTK(f).descriptor
val javagensig = getGenericSignature(f, claszSymbol, descriptor)
val flags = javaFieldFlags(f)
Expand All @@ -405,7 +406,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {
emitAnnotations(jfield, f.annotations)
}

def addClassFields()(using Context): Unit =
private def addClassFields()(using Context): Unit =
/* Non-method term members are fields, except for module members. Module
* members can only happen on .NET (no flatten) for inner traits. There,
* a module symbol is generated (transformInfo in mixin) which is used
Expand All @@ -416,18 +417,18 @@ trait BCodeSkelBuilder extends BCodeHelpers {
claszSymbol.info.decls.filter(p => p.isTerm && !p.is(Method)).foreach(addClassField)

// current method
var mnode: MethodNode1 = null
var jMethodName: String = null
var isMethSymStaticCtor = false
var returnType: BType = null
var methSymbol: Symbol = null
var mnode: MethodNode1 = uninitialized
var jMethodName: String = uninitialized
private var isMethSymStaticCtor = false
var returnType: BType = uninitialized
var methSymbol: Symbol = uninitialized
// used by genLoadTry() and genSynchronized()
var earlyReturnVar: Symbol = null
var earlyReturnVar: Symbol | Null = null
var shouldEmitCleanup = false
// stack tracking
val stack = new BTypesStack
// line numbers
var lastEmittedLineNr = -1
private var lastEmittedLineNr = -1

object bc extends JCodeMethodN {
override def jmethod = PlainSkelBuilder.this.mnode
Expand All @@ -440,7 +441,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {
* The `jumpDest` map is used to find the `LoadDestination` at the end of the `Labeled` block, as well as the
* corresponding expected type. The `LoadDestination` can never be `FallThrough` here.
*/
var jumpDest: immutable.Map[ /* Labeled */ Symbol, (BType, LoadDestination) ] = null
var jumpDest: immutable.Map[ /* Labeled */ Symbol, (BType, LoadDestination) ] = immutable.Map.empty
def registerJumpDest(labelSym: Symbol, expectedType: BType, dest: LoadDestination)(using Context): Unit = {
assert(labelSym.is(Label), s"trying to register a jump-dest for a non-label symbol, at: ${labelSym.span}")
assert(dest != LoadDestination.FallThrough, s"trying to register a FallThrough dest for label, at: ${labelSym.span}")
Expand Down Expand Up @@ -484,10 +485,10 @@ trait BCodeSkelBuilder extends BCodeHelpers {
* emitted for that purpose as described in `genLoadTry()` and `genSynchronized()`.
*/
var cleanups: List[asm.Label] = Nil
def registerCleanup(finCleanup: asm.Label): Unit = {
def registerCleanup(finCleanup: asm.Label | Null): Unit = {
if (finCleanup != null) { cleanups = finCleanup :: cleanups }
}
def unregisterCleanup(finCleanup: asm.Label): Unit = {
def unregisterCleanup(finCleanup: asm.Label | Null): Unit = {
if (finCleanup != null) {
assert(cleanups.head eq finCleanup,
s"Bad nesting of cleanup operations: $cleanups trying to unregister: $finCleanup")
Expand Down Expand Up @@ -585,7 +586,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {
/* ---------------- Part 2 of program points, ie Labels in the ASM world ---------------- */

// bookkeeping the scopes of non-synthetic local vars, to emit debug info (`emitVars`).
var varsInScope: List[(Symbol, asm.Label)] = null // (local-var-sym -> start-of-scope)
var varsInScope: List[(Symbol, asm.Label)] | Null = null // (local-var-sym -> start-of-scope)

// helpers around program-points.
def lastInsn: asm.tree.AbstractInsnNode = mnode.instructions.getLast
Expand Down Expand Up @@ -806,7 +807,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {
.withAttachment(BCodeHelpers.UseInvokeSpecial, ())
})

def genDefDef(dd: DefDef)(using Context): Unit = {
private def genDefDef(dd: DefDef)(using Context): Unit = {
val rhs = dd.rhs
val vparamss = dd.termParamss
// the only method whose implementation is not emitted: getClass()
Expand Down Expand Up @@ -924,7 +925,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {

TraceUtils.traceMethodIfRequested(mnode)

mnode = null
mnode = null.asInstanceOf[MethodNode1] // for GC
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I'm assuming)

} // end of method genDefDef()

def emitLocalVarScope(sym: Symbol, start: asm.Label, end: asm.Label, force: Boolean = false): Unit = {
Expand Down
Loading
Loading