Skip to content

Optimization experiment: Drop Symbol class #16631

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 23 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
68ea6d7
Make designator a union type
odersky Jan 6, 2023
0c7b3cf
implement SymDenotation ParamInfo, SrcPos in SymDenotation
odersky Jan 6, 2023
6abc8ac
Move Symbol fields to SymDenotation
odersky Jan 8, 2023
9dd35e2
Prepare to drop overrides in Symbols
odersky Jan 8, 2023
25e43eb
Make SymDenotations Named types
odersky Jan 8, 2023
014c26e
Make Symbol and ClassSymbol stateless facade types
odersky Jan 8, 2023
0f69050
Override recomputeDenot in SymDenonation
odersky Jan 8, 2023
f7a7270
Make Symbol methods extension methods
odersky Jan 9, 2023
e20abd0
Prepare symbol constructors for unification of Symbols with SymDenota…
odersky Jan 9, 2023
47fcfdf
Avoid matches against NoSymbol
odersky Jan 27, 2023
e929d79
Introduce and use isSymbol/asSymbol extension methods
odersky Jan 27, 2023
301533a
Add backup TypeTests for Symbol and ClassSymbol
odersky Jan 27, 2023
b3c249b
Reorganize maybeOwner
odersky Jan 27, 2023
bc16e2c
Fix rebase breakage
odersky Jan 27, 2023
9aa32de
Eliminate toDenot conversions in Symbols
odersky Jan 29, 2023
979ee23
Rename is... and info extension methods in Symbol
odersky Jan 29, 2023
636db78
Disallow use of toDenot and toClassDenot conversions in Symbols
odersky Jan 29, 2023
f3b15ed
Change Symbol.exists to not use denot
odersky Jan 29, 2023
0830862
Drop private enter extension method
odersky Jan 29, 2023
7a787d6
Make Symbol accesses null-safe
odersky Jan 29, 2023
129b6da
Make Symbol and ClassSymbol opaque type aliases
odersky Jan 29, 2023
110dd20
Streamlining
odersky Jan 29, 2023
eb993a9
Bring back checkedPeriod
odersky Jan 30, 2023
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
31 changes: 16 additions & 15 deletions compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -521,20 +521,20 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
/*
* must-single-thread
*/
def fieldLoad( field: Symbol, hostClass: Symbol = null): Unit = fieldOp(field, isLoad = true, hostClass)
def fieldLoad( field: Symbol, hostClass: Symbol | Null = null): Unit = fieldOp(field, isLoad = true, hostClass)

/*
* must-single-thread
*/
def fieldStore(field: Symbol, hostClass: Symbol = null): Unit = fieldOp(field, isLoad = false, hostClass)
def fieldStore(field: Symbol, hostClass: Symbol | Null = null): Unit = fieldOp(field, isLoad = false, hostClass)

/*
* must-single-thread
*/
private def fieldOp(field: Symbol, isLoad: Boolean, specificReceiver: Symbol): Unit = {
private def fieldOp(field: Symbol, isLoad: Boolean, specificReceiver: Symbol | Null): Unit = {
val useSpecificReceiver = specificReceiver != null && !field.isScalaStatic

val owner = internalName(if (useSpecificReceiver) specificReceiver else field.owner)
val owner = internalName(if (useSpecificReceiver) specificReceiver.nn else field.owner)
val fieldJName = field.javaSimpleName
val fieldDescr = symInfoTK(field).descriptor
val isStatic = field.isStaticMember
Expand Down Expand Up @@ -629,7 +629,7 @@ trait BCodeBodyBuilder 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 @@ -853,7 +853,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
bc.invokevirtual(target, sym.javaSimpleName, methodBType.descriptor)
generatedType = methodBType.returnType
} else {
val receiverClass = if (!invokeStyle.isVirtual) null else {
val receiverClass: Symbol | Null = if (!invokeStyle.isVirtual) null else {
// receiverClass is used in the bytecode to as the method receiver. using sym.owner
// may lead to IllegalAccessErrors, see 9954eaf / aladdin bug 455.
val qualSym = qual.tpe.typeSymbol
Expand Down Expand Up @@ -1213,10 +1213,11 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
def genLoadModule(tree: Tree): BType = {
val module = (
if (!tree.symbol.is(PackageClass)) tree.symbol
else tree.symbol.info.member(nme.PACKAGE).symbol match {
case NoSymbol => abort(s"SI-5604: Cannot use package as value: $tree")
case s => abort(s"SI-5604: found package class where package object expected: $tree")
}
else
val s = tree.symbol.info.member(nme.PACKAGE).symbol
if s.exists
then abort(s"SI-5604: found package class where package object expected: $tree")
else abort(s"SI-5604: Cannot use package as value: $tree")
)
lineNumber(tree)
genLoadModule(module)
Expand Down Expand Up @@ -1388,16 +1389,16 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
* invocation instruction, otherwise `method.owner`. A specific receiver class is needed to
* prevent an IllegalAccessError, (aladdin bug 455).
*/
def genCallMethod(method: Symbol, style: InvokeStyle, pos: Span = NoSpan, specificReceiver: Symbol = null): BType = {
def genCallMethod(method: Symbol, style: InvokeStyle, pos: Span = NoSpan, specificReceiver: Symbol | Null = null): BType = {
val methodOwner = method.owner

// the class used in the invocation's method descriptor in the classfile
val receiverClass = {
val receiverClass: Symbol = {
if (specificReceiver != null)
assert(style.isVirtual || specificReceiver == methodOwner, s"specificReceiver can only be specified for virtual calls. $method - $specificReceiver")

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

// workaround for a JVM bug: https://bugs.openjdk.java.net/browse/JDK-8154587
// when an interface method overrides a member of Object (note that all interfaces implicitly
Expand Down Expand Up @@ -1431,7 +1432,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
val bmType = asmMethodType(method)
val mdescr = bmType.descriptor

val isInterface = isEmittedInterface(receiverClass)
val isInterface = isEmittedInterface(receiverClass.nn)
import InvokeStyle._
if (style == Super) {
if (isInterface && !method.is(JavaDefined)) {
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {
var cnode: ClassNode1 = null
var thisName: String = null // the internal name of the class being emitted

var claszSymbol: Symbol = null
var claszSymbol: Symbol = _
var isCZParcelable = false
var isCZStaticModule = false

Expand Down Expand Up @@ -364,9 +364,9 @@ trait BCodeSkelBuilder extends BCodeHelpers {
var jMethodName: String = null
var isMethSymStaticCtor = false
var returnType: BType = null
var methSymbol: Symbol = null
var methSymbol: Symbol = _
// used by genLoadTry() and genSynchronized()
var earlyReturnVar: Symbol = null
var earlyReturnVar: Symbol | Null = null
var shouldEmitCleanup = false
// stack tracking
var stackHeight = 0
Expand Down
18 changes: 9 additions & 9 deletions compiler/src/dotty/tools/backend/jvm/BCodeSyncAndTry.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder {
// if the synchronized block returns a result, store it in a local variable.
// Just leaving it on the stack is not valid in MSIL (stack is cleaned when leaving try-blocks).
val hasResult = (expectedType != UNIT)
val monitorResult: Symbol = if (hasResult) locals.makeLocal(tpeTK(args.head), "monitorResult", defn.ObjectType, tree.span) else null
val monitorResult: Symbol | Null = if (hasResult) locals.makeLocal(tpeTK(args.head), "monitorResult", defn.ObjectType, tree.span) else null

/* ------ (1) pushing and entering the monitor, also keeping a reference to it in a local var. ------ */
genLoadQualifier(fun)
Expand All @@ -55,7 +55,7 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder {
registerCleanup(monCleanup)
genLoad(args.head, expectedType /* toTypeKind(tree.tpe.resultType) */)
unregisterCleanup(monCleanup)
if (hasResult) { locals.store(monitorResult) }
if (hasResult) { locals.store(monitorResult.nn) }
nopIfNeeded(startProtected)
val endProtected = currProgramPoint()

Expand All @@ -66,7 +66,7 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder {
*/
locals.load(monitor)
emit(asm.Opcodes.MONITOREXIT)
if (hasResult) { locals.load(monitorResult) }
if (hasResult) { locals.load(monitorResult.uncheckedNN) }
val postHandler = new asm.Label
bc goTo postHandler

Expand Down Expand Up @@ -214,7 +214,7 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder {
* please notice `tmp` has type tree.tpe, while `earlyReturnVar` has the method return type.
* Because those two types can be different, dedicated vars are needed.
*/
val tmp = if (guardResult) locals.makeLocal(tpeTK(tree), "tmp", tree.tpe, tree.span) else null
val tmp: Symbol | Null = if (guardResult) locals.makeLocal(tpeTK(tree), "tmp", tree.tpe, tree.span) else null

/*
* upon early return from the try-body or one of its EHs (but not the EH-version of the finally-clause)
Expand Down Expand Up @@ -375,8 +375,8 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder {
cleanups match {
case Nil =>
if (earlyReturnVar != null) {
locals.load(earlyReturnVar)
bc.emitRETURN(locals(earlyReturnVar).tk)
locals.load(earlyReturnVar.uncheckedNN)
bc.emitRETURN(locals(earlyReturnVar.uncheckedNN).tk)
} else {
bc emitRETURN UNIT
}
Expand All @@ -396,15 +396,15 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder {
}

/* `tmp` (if non-null) is the symbol of the local-var used to preserve the result of the try-body, see `guardResult` */
def emitFinalizer(finalizer: Tree, tmp: Symbol, isDuplicate: Boolean): Unit = {
def emitFinalizer(finalizer: Tree, tmp: Symbol | Null, isDuplicate: Boolean): Unit = {
var saved: immutable.Map[ /* Labeled */ Symbol, (BType, LoadDestination) ] = null
if (isDuplicate) {
saved = jumpDest
}
// when duplicating, the above guarantees new asm.Labels are used for LabelDefs contained in the finalizer (their vars are reused, that's ok)
if (tmp != null) { locals.store(tmp) }
if (tmp != null) { locals.store(tmp.uncheckedNN) }
genLoad(finalizer, UNIT)
if (tmp != null) { locals.load(tmp) }
if (tmp != null) { locals.load(tmp.uncheckedNN) }
if (isDuplicate) {
jumpDest = saved
}
Expand Down
34 changes: 17 additions & 17 deletions compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ class JSCodeGen()(using genCtx: Context) {
private val generatedClasses = mutable.ListBuffer.empty[js.ClassDef]
private val generatedStaticForwarderClasses = mutable.ListBuffer.empty[(Symbol, js.ClassDef)]

val currentClassSym = new ScopedVar[Symbol]
private val currentMethodSym = new ScopedVar[Symbol]
val currentClassSym = new ScopedVar[Symbol | Null]
private val currentMethodSym = new ScopedVar[Symbol | Null]
private val localNames = new ScopedVar[LocalNameGenerator]
private val thisLocalVarIdent = new ScopedVar[Option[js.LocalIdent]]
private val isModuleInitialized = new ScopedVar[ScopedVar.VarBox[Boolean]]
Expand Down Expand Up @@ -126,7 +126,7 @@ class JSCodeGen()(using genCtx: Context) {
implicit def implicitLocalNames: LocalNameGenerator = localNames.get

def currentThisType: jstpe.Type = {
encodeClassType(currentClassSym) match {
encodeClassType(currentClassSym.get.nn) match {
case tpe @ jstpe.ClassType(cls) =>
jstpe.BoxedClassToPrimType.getOrElse(cls, tpe)
case tpe =>
Expand Down Expand Up @@ -856,7 +856,7 @@ class JSCodeGen()(using genCtx: Context) {
/** Gen definitions for the fields of a class. */
private def genClassFields(td: TypeDef): List[js.MemberDef] = {
val classSym = td.symbol.asClass
assert(currentClassSym.get == classSym,
assert(currentClassSym.get eq classSym,
"genClassFields called with a ClassDef other than the current one")

val isJSClass = classSym.isNonNativeJSClass
Expand Down Expand Up @@ -1493,7 +1493,7 @@ class JSCodeGen()(using genCtx: Context) {

if (primitives.isPrimitive(sym)) {
None
} else if (sym.is(Deferred) && currentClassSym.isNonNativeJSClass) {
} else if (sym.is(Deferred) && currentClassSym.get.nn.isNonNativeJSClass) {
// scala-js/#4409: Do not emit abstract methods in non-native JS classes
None
} else if (sym.is(Deferred)) {
Expand All @@ -1503,7 +1503,7 @@ class JSCodeGen()(using genCtx: Context) {
} else if (isIgnorableDefaultParam) {
// #11592
None
} else if (sym.is(Bridge) && sym.name.is(DefaultGetterName) && currentClassSym.isNonNativeJSClass) {
} else if (sym.is(Bridge) && sym.name.is(DefaultGetterName) && currentClassSym.get.nn.isNonNativeJSClass) {
/* #12572 Bridges for default accessors in non-native JS classes must not be emitted,
* because they call another default accessor, making their entire body an
* <undefined-param> that cannot be eliminated.
Expand Down Expand Up @@ -1582,7 +1582,7 @@ class JSCodeGen()(using genCtx: Context) {
else genExpr(tree)
}

if (namespace.isStatic || !currentClassSym.isNonNativeJSClass) {
if (namespace.isStatic || !currentClassSym.get.nn.isNonNativeJSClass) {
val flags = js.MemberFlags.empty.withNamespace(namespace)
js.MethodDef(flags, methodName, originalName, jsParams, resultIRType, Some(genBody()))(
optimizerHints, None)
Expand Down Expand Up @@ -1688,7 +1688,7 @@ class JSCodeGen()(using genCtx: Context) {
tree match {
case _: This =>
val sym = tree.symbol
if (sym != currentClassSym.get && sym.is(Module))
if ((sym ne currentClassSym.get) && sym.is(Module))
genLoadModuleOrGlobalScope(sym)
else
MaybeGlobalScope.NotGlobalScope(genExpr(tree))
Expand Down Expand Up @@ -1784,7 +1784,7 @@ class JSCodeGen()(using genCtx: Context) {
genApplyDynamic(app)*/

case tree: This =>
val currentClass = currentClassSym.get
val currentClass = currentClassSym.get.nn
val symIsModuleClass = tree.symbol.is(ModuleClass)
assert(tree.symbol == currentClass || symIsModuleClass,
s"Trying to access the this of another class: tree.symbol = ${tree.symbol}, class symbol = $currentClass")
Expand Down Expand Up @@ -1886,8 +1886,8 @@ class JSCodeGen()(using genCtx: Context) {
val qualifier = lhs.qualifier

def ctorAssignment = (
currentMethodSym.get.name == nme.CONSTRUCTOR &&
currentMethodSym.get.owner == qualifier.symbol &&
currentMethodSym.get.nn.name == nme.CONSTRUCTOR &&
currentMethodSym.get.nn.owner == qualifier.symbol &&
qualifier.isInstanceOf[This]
)
// TODO This fails for OFFSET$x fields. Re-enable when we can.
Expand Down Expand Up @@ -2178,7 +2178,7 @@ class JSCodeGen()(using genCtx: Context) {
if (sym == defn.Any_getClass) {
// The only primitive that is also callable as super call
js.GetClass(genThis())
} else if (currentClassSym.isNonNativeJSClass) {
} else if (currentClassSym.get.nn.isNonNativeJSClass) {
genJSSuperCall(tree, isStat)
} else {
/* #3013 `qual` can be `this.$outer()` in some cases since Scala 2.12,
Expand All @@ -2188,10 +2188,10 @@ class JSCodeGen()(using genCtx: Context) {
genExpr(qual), sym, genActualArgs(sym, args))

// Initialize the module instance just after the super constructor call.
if (isStaticModule(currentClassSym) && !isModuleInitialized.get.value &&
currentMethodSym.get.isClassConstructor) {
if (isStaticModule(currentClassSym.get.nn) && !isModuleInitialized.get.value &&
currentMethodSym.get.nn.isClassConstructor) {
isModuleInitialized.get.value = true
val className = encodeClassName(currentClassSym)
val className = encodeClassName(currentClassSym.get.nn)
val thisType = jstpe.ClassType(className)
val initModule = js.StoreModule(className, js.This()(thisType))
js.Block(superCall, initModule)
Expand Down Expand Up @@ -3245,7 +3245,7 @@ class JSCodeGen()(using genCtx: Context) {
genApplyJSClassMethod(genReceiver, sym, genScalaArgs)
} else {
val jsSuperClassValue = explicitJSSuperClassValue.orElse {
Some(genLoadJSConstructor(currentClassSym.get.asClass.superClass))
Some(genLoadJSConstructor(currentClassSym.get.nn.asClass.superClass))
}
genApplyJSMethodGeneric(sym, MaybeGlobalScope.NotGlobalScope(genReceiver),
genJSArgs, isStat, jsSuperClassValue)(tree.sourcePos)
Expand Down Expand Up @@ -3873,7 +3873,7 @@ class JSCodeGen()(using genCtx: Context) {

case JS_NEW_TARGET =>
// js.new.target
val valid = currentMethodSym.get.isClassConstructor && currentClassSym.isNonNativeJSClass
val valid = currentMethodSym.get.nn.isClassConstructor && currentClassSym.get.nn.isNonNativeJSClass
if (!valid) {
report.error(
"Illegal use of js.`new`.target.\n" +
Expand Down
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/backend/sjs/JSExportsGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ final class JSExportsGen(jsCodeGen: JSCodeGen)(using Context) {
}

private def reportCannotDisambiguateError(jsName: JSName, alts: List[Symbol]): Unit = {
val currentClass = currentClassSym.get
val currentClass = currentClassSym.get.nn

/* Find a position that is in the current class for decent error reporting.
* If there are more than one, always use the "highest" one (i.e., the
Expand Down Expand Up @@ -623,7 +623,7 @@ final class JSExportsGen(jsCodeGen: JSCodeGen)(using Context) {
*/
private def genApplyForSingleExported(formalArgsRegistry: FormalArgsRegistry,
exported: Exported, static: Boolean): js.Tree = {
if (currentClassSym.isJSType && exported.sym.owner != currentClassSym.get) {
if (currentClassSym.get.nn.isJSType && exported.sym.owner != currentClassSym.get) {
assert(!static, s"nonsensical JS super call in static export of ${exported.sym}")
genApplyForSingleExportedJSSuperCall(formalArgsRegistry, exported)
} else {
Expand All @@ -642,7 +642,7 @@ final class JSExportsGen(jsCodeGen: JSCodeGen)(using Context) {
val allArgs = formalArgsRegistry.genAllArgsRefsForForwarder()

val superClass = {
val superClassSym = currentClassSym.asClass.superClass
val superClassSym = currentClassSym.get.nn.asClass.superClass
if (superClassSym.isNestedJSClass)
js.VarRef(js.LocalIdent(JSSuperClassParamName))(jstpe.AnyType)
else
Expand Down Expand Up @@ -806,7 +806,7 @@ final class JSExportsGen(jsCodeGen: JSCodeGen)(using Context) {
implicit pos: SourcePosition): js.Tree = {

val sym = exported.sym
val currentClass = currentClassSym.get
val currentClass = currentClassSym.get.nn

def receiver =
if (static) genLoadModule(sym.owner)
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Types._, Contexts._, Flags._
import Symbols._, Annotations._, Trees._, Symbols._, Constants.Constant
import Decorators._
import dotty.tools.dotc.transform.SymUtils._
import Symbols.TypeTests.given

/** A map that applies three functions and a substitution together to a tree and
* makes sure they are coordinated so that the result is well-typed. The functions are
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/cc/CaptureOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import config.Printers.capt
import util.Property.Key
import tpd.*
import config.Feature
import Symbols.TypeTests.given

private val Captures: Key[CaptureSet] = Key()
private val BoxedType: Key[BoxedTypeCache] = Key()
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/cc/Setup.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import transform.Recheck.*
import CaptureSet.IdentityCaptRefMap
import Synthetics.isExcluded
import util.Property
import Symbols.TypeTests.given

/** A tree traverser that prepares a compilation unit to be capture checked.
* It does the following:
Expand Down
5 changes: 3 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Annotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ast.tpd, tpd.*
import util.Spans.Span
import printing.{Showable, Printer}
import printing.Texts.Text
import Symbols.TypeTests.given

import scala.annotation.internal.sharable

Expand Down Expand Up @@ -194,7 +195,7 @@ object Annotations {
object Annotation {

def apply(tree: Tree): ConcreteAnnotation = ConcreteAnnotation(tree)

def apply(cls: ClassSymbol, span: Span)(using Context): Annotation =
apply(cls, Nil, span)

Expand All @@ -206,7 +207,7 @@ object Annotations {

def apply(atp: Type, arg: Tree, span: Span)(using Context): Annotation =
apply(atp, arg :: Nil, span)

def apply(atp: Type, args: List[Tree], span: Span)(using Context): Annotation =
apply(New(atp, args).withSpan(span))

Expand Down
Loading