Skip to content

Commit 0813dd3

Browse files
committed
SI-7475 findMember and findMembers: estranged no more
Swathes of important logic are duplicated between `findMember` and `findMembers` after they separated on grounds of irreconcilable differences about how fast they should run: d905558 Variation #10 to optimze findMember fcb0c01 Attempt #9 to opimize findMember. 71d2ceb Attempt #8 to opimize findMember. 77e5692 Attempty #7 to optimize findMember 275115e Fixing problem that caused fingerprints to fail in e94252e Attemmpt #6 to optimize findMember 73e61b8 Attempt #5 to optimize findMember. 04f0b65 Attempt #4 to optimize findMember 0e3c70f Attempt #3 to optimize findMember 41f4497 Attempt #2 to optimize findMember 1a73aa0 Attempt #1 to optimize findMember This didn't actually bear fruit, and the intervening years have seen the implementations drift. Now is the time to reunite them under the banner of `FindMemberBase`. Each has a separate subclass to customise the behaviour. This is primarily used by `findMember` to cache member types and to assemble the resulting list of symbols in an low-allocation manner. While there I have introduced some polymorphic calls, the call sites are only bi-morphic, and our typical pattern of compilation involves far more `findMember` calls, so I expect that JIT will keep the virtual call cost to an absolute minimum. Test results have been updated now that `findMembers` correctly excludes constructors and doesn't inherit privates. Coming up next: we can actually fix SI-7475!
1 parent d3c6a09 commit 0813dd3

File tree

4 files changed

+70
-169
lines changed

4 files changed

+70
-169
lines changed

src/reflect/scala/reflect/internal/Types.scala

Lines changed: 2 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -990,65 +990,7 @@ trait Types
990990
*
991991
*/
992992
def findMembers(excludedFlags: Long, requiredFlags: Long): Scope = {
993-
// TODO refactor to use `FindMemberBase`
994-
def findMembersInternal: Scope = {
995-
var members: Scope = null
996-
if (Statistics.canEnable) Statistics.incCounter(findMembersCount)
997-
val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, findMembersNanos) else null
998-
999-
//Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG
1000-
var required = requiredFlags
1001-
var excluded = excludedFlags | DEFERRED
1002-
var retryForDeferred = true
1003-
var self: Type = null
1004-
while (retryForDeferred) {
1005-
retryForDeferred = false
1006-
val bcs0 = baseClasses
1007-
var bcs = bcs0
1008-
while (!bcs.isEmpty) {
1009-
val decls = bcs.head.info.decls
1010-
var entry = decls.elems
1011-
while (entry ne null) {
1012-
val sym = entry.sym
1013-
val flags = sym.flags
1014-
if ((flags & required) == required) {
1015-
val excl = flags & excluded
1016-
if (excl == 0L &&
1017-
(// omit PRIVATE LOCALS unless selector class is contained in class owning the def.
1018-
(bcs eq bcs0) ||
1019-
(flags & PrivateLocal) != PrivateLocal ||
1020-
(bcs0.head.hasTransOwner(bcs.head)))) {
1021-
if (members eq null) members = newFindMemberScope
1022-
var others: ScopeEntry = members.lookupEntry(sym.name)
1023-
var symtpe: Type = null
1024-
while ((others ne null) && {
1025-
val other = others.sym
1026-
(other ne sym) &&
1027-
((other.owner eq sym.owner) ||
1028-
(flags & PRIVATE) != 0 || {
1029-
if (self eq null) self = narrowForFindMember(this)
1030-
if (symtpe eq null) symtpe = self.memberType(sym)
1031-
!(self.memberType(other) matches symtpe)
1032-
})}) {
1033-
others = members lookupNextEntry others
1034-
}
1035-
if (others eq null) members enter sym
1036-
} else if (excl == DEFERRED) {
1037-
retryForDeferred = (excludedFlags & DEFERRED) == 0
1038-
}
1039-
}
1040-
entry = entry.next
1041-
} // while (entry ne null)
1042-
// excluded = excluded | LOCAL
1043-
bcs = bcs.tail
1044-
} // while (!bcs.isEmpty)
1045-
required |= DEFERRED
1046-
excluded &= ~(DEFERRED.toLong)
1047-
} // while (retryForDeferred)
1048-
if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
1049-
if (members eq null) EmptyScope else members
1050-
}
1051-
993+
def findMembersInternal = new FindMembers(this, excludedFlags, requiredFlags).apply()
1052994
if (this.isGround) findMembersInternal
1053995
else suspendingTypeVars(typeVarsInType(this))(findMembersInternal)
1054996
}
@@ -1063,115 +1005,7 @@ trait Types
10631005
* @param stableOnly If set, return only members that are types or stable values
10641006
*/
10651007
def findMember(name: Name, excludedFlags: Long, requiredFlags: Long, stableOnly: Boolean): Symbol = {
1066-
def findMemberInternal = {
1067-
// TODO delete `findMemberInternalOld`
1068-
val resultOld = findMemberInternalOld
1069-
val resultNew = findMemberInternalNew
1070-
if (resultOld.alternatives != resultNew.alternatives) {
1071-
findMemberInternalOld
1072-
findMemberInternalNew
1073-
}
1074-
assert(resultOld.alternatives == resultNew.alternatives, s"\nOLD:${resultOld.alternatives}\nNEW${resultNew.alternatives}")
1075-
resultNew
1076-
}
1077-
def findMemberInternalNew = new FindMember(this, name, excludedFlags, requiredFlags, stableOnly).apply()
1078-
def findMemberInternalOld: Symbol = {
1079-
var member: Symbol = NoSymbol
1080-
var members: List[Symbol] = null
1081-
var lastM: ::[Symbol] = null
1082-
if (Statistics.canEnable) Statistics.incCounter(findMemberCount)
1083-
val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, findMemberNanos) else null
1084-
1085-
//Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG
1086-
var membertpe: Type = null
1087-
var required = requiredFlags
1088-
var excluded = excludedFlags | DEFERRED
1089-
var continue = true
1090-
var self: Type = null
1091-
1092-
while (continue) {
1093-
continue = false
1094-
val bcs0 = baseClasses
1095-
var bcs = bcs0
1096-
// omit PRIVATE LOCALS unless selector class is contained in class owning the def.
1097-
def admitPrivateLocal(owner: Symbol): Boolean = {
1098-
val selectorClass = this match {
1099-
case tt: ThisType => tt.sym // SI-7507 the first base class is not necessarily the selector class.
1100-
case _ => bcs0.head
1101-
}
1102-
selectorClass.hasTransOwner(owner)
1103-
}
1104-
while (!bcs.isEmpty) {
1105-
val decls = bcs.head.info.decls
1106-
var entry = decls.lookupEntry(name)
1107-
while (entry ne null) {
1108-
val sym = entry.sym
1109-
val flags = sym.flags
1110-
if ((flags & required) == required) {
1111-
val excl = flags & excluded
1112-
if (excl == 0L &&
1113-
(
1114-
(bcs eq bcs0) ||
1115-
(flags & PrivateLocal) != PrivateLocal ||
1116-
admitPrivateLocal(bcs.head))) {
1117-
if (name.isTypeName || (stableOnly && sym.isStable && !sym.hasVolatileType)) {
1118-
if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
1119-
return sym
1120-
} else if (member eq NoSymbol) {
1121-
member = sym
1122-
} else if (members eq null) {
1123-
if ((member ne sym) &&
1124-
((member.owner eq sym.owner) ||
1125-
(flags & PRIVATE) != 0 || {
1126-
if (self eq null) self = narrowForFindMember(this)
1127-
if (membertpe eq null) membertpe = self.memberType(member)
1128-
!(membertpe matches self.memberType(sym))
1129-
})) {
1130-
lastM = new ::(sym, null)
1131-
members = member :: lastM
1132-
}
1133-
} else {
1134-
var others: List[Symbol] = members
1135-
var symtpe: Type = null
1136-
while ((others ne null) && {
1137-
val other = others.head
1138-
(other ne sym) &&
1139-
((other.owner eq sym.owner) ||
1140-
(flags & PRIVATE) != 0 || {
1141-
if (self eq null) self = narrowForFindMember(this)
1142-
if (symtpe eq null) symtpe = self.memberType(sym)
1143-
!(self.memberType(other) matches symtpe)
1144-
})}) {
1145-
others = others.tail
1146-
}
1147-
if (others eq null) {
1148-
val lastM1 = new ::(sym, null)
1149-
lastM.tl = lastM1
1150-
lastM = lastM1
1151-
}
1152-
}
1153-
} else if (excl == DEFERRED) {
1154-
continue = true
1155-
}
1156-
}
1157-
entry = decls lookupNextEntry entry
1158-
} // while (entry ne null)
1159-
// excluded = excluded | LOCAL
1160-
bcs = if (name == nme.CONSTRUCTOR) Nil else bcs.tail
1161-
} // while (!bcs.isEmpty)
1162-
required |= DEFERRED
1163-
excluded &= ~(DEFERRED.toLong)
1164-
} // while (continue)
1165-
if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
1166-
if (members eq null) {
1167-
if (member == NoSymbol) if (Statistics.canEnable) Statistics.incCounter(noMemberCount)
1168-
member
1169-
} else {
1170-
if (Statistics.canEnable) Statistics.incCounter(multMemberCount)
1171-
lastM.tl = Nil
1172-
baseClasses.head.newOverloaded(this, members)
1173-
}
1174-
}
1008+
def findMemberInternal = new FindMember(this, name, excludedFlags, requiredFlags, stableOnly).apply()
11751009

11761010
if (this.isGround) findMemberInternal
11771011
else suspendingTypeVars(typeVarsInType(this))(findMemberInternal)

src/reflect/scala/reflect/internal/tpe/FindMembers.scala

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,31 @@ trait FindMembers {
150150
protected def memberTypeLow(sym: Symbol): Type = self.memberType(sym)
151151
}
152152

153+
private[reflect] final class FindMembers(tpe: Type, excludedFlags: Long, requiredFlags: Long)
154+
extends FindMemberBase[Scope](tpe, nme.ANYname, excludedFlags, requiredFlags) {
155+
private[this] var _membersScope: Scope = null
156+
private def membersScope: Scope = {
157+
if (_membersScope eq null) _membersScope = newFindMemberScope
158+
_membersScope
159+
}
160+
161+
protected def shortCircuit(sym: Symbol): Boolean = false
162+
protected def result: Scope = membersScope
163+
164+
protected def addMemberIfNew(sym: Symbol): Unit = {
165+
val members = membersScope
166+
var others = members.lookupEntry(sym.name)
167+
var isNew = true
168+
while (others ne null) {
169+
val member = others.sym
170+
if (!isNewMember(member, sym))
171+
isNew = false
172+
others = members lookupNextEntry others // next existing member with the same name.
173+
}
174+
if (isNew) members.enter(sym)
175+
}
176+
}
177+
153178
private[reflect] final class FindMember(tpe: Type, name: Name, excludedFlags: Long, requiredFlags: Long, stableOnly: Boolean)
154179
extends FindMemberBase[Symbol](tpe, name, excludedFlags, requiredFlags) {
155180
// Gathering the results into a hand rolled ListBuffer

src/reflect/scala/reflect/runtime/JavaUniverseForce.scala

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,29 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
2727

2828
this.settings
2929
this.treeInfo
30+
// inaccessible: this.scala$reflect$runtime$Gil$$gil
31+
// inaccessible: this.uniqueLock
32+
// inaccessible: this._skolemizationLevel
33+
// inaccessible: this._undoLog
34+
// inaccessible: this._intersectionWitness
35+
// inaccessible: this._volatileRecursions
36+
// inaccessible: this._pendingVolatiles
37+
// inaccessible: this._subsametypeRecursions
38+
// inaccessible: this._pendingSubTypes
39+
// inaccessible: this._basetypeRecursions
40+
// inaccessible: this._pendingBaseTypes
41+
// inaccessible: this._lubResults
42+
// inaccessible: this._glbResults
43+
// inaccessible: this._indent
44+
// inaccessible: this._toStringRecursions
45+
// inaccessible: this._toStringSubjects
46+
// inaccessible: this.atomicIds
47+
// inaccessible: this.atomicExistentialIds
48+
// inaccessible: this._recursionTable
49+
// inaccessible: this.mirrors
3050
this.rootMirror
3151
this.treeBuild
52+
// inaccessible: this.SimpleNameOrdering
3253
this.traceSymbols
3354
this.perRunCaches
3455
this.FreshNameExtractor
@@ -40,22 +61,27 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
4061
this.SubpatternsAttachment
4162
this.noPrint
4263
this.typeDebug
64+
// inaccessible: this.maxFree
4365
this.Range
4466
// inaccessible: this.posAssigner
4567
this.ConsoleWriter
4668
this.RefTree
4769
this.PackageDef
70+
this.ClassDef
4871
this.ModuleDef
4972
this.ValOrDefDef
5073
this.ValDef
74+
this.DefDef
5175
this.TypeDef
5276
this.LabelDef
5377
this.ImportSelector
5478
this.Import
5579
this.Template
80+
this.Block
5681
this.CaseDef
5782
this.Alternative
5883
this.Star
84+
this.Bind
5985
this.UnApply
6086
this.ArrayValue
6187
this.Function
@@ -64,12 +90,16 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
6490
this.If
6591
this.Match
6692
this.Return
93+
this.Try
6794
this.Throw
6895
this.New
6996
this.Typed
7097
this.TypeApply
98+
this.Apply
7199
this.ApplyDynamic
100+
this.Super
72101
this.This
102+
this.Select
73103
this.Ident
74104
this.ReferenceToBoxed
75105
this.Literal
@@ -78,13 +108,16 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
78108
this.SelectFromTypeTree
79109
this.CompoundTypeTree
80110
this.AppliedTypeTree
111+
this.TypeBoundsTree
81112
this.ExistentialTypeTree
113+
this.TypeTree
82114
this.Modifiers
83115
this.EmptyTree
84116
this.noSelfType
85117
this.pendingSuperCall
86118
this.emptyValDef
87119
this.EmptyTreeTypeSubstituter
120+
// inaccessible: this.duplicator
88121
this.UnmappableAnnotArg
89122
this.LiteralAnnotArg
90123
this.ArrayAnnotArg
@@ -95,6 +128,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
95128
this.UnmappableAnnotation
96129
this.ErroneousAnnotation
97130
this.ThrownException
131+
// inaccessible: this.compactify
98132
this.tpnme
99133
this.fulltpnme
100134
this.binarynme
@@ -114,6 +148,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
114148
this.ProperTypeKind
115149
this.TypeConKind
116150
this.inferKind
151+
// inaccessible: this.substTypeMapCache
117152
this.UnmappableTree
118153
this.ErrorType
119154
this.WildcardType
@@ -150,6 +185,9 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
150185
this.unwrapToStableClass
151186
this.unwrapWrapperTypes
152187
this.RecoverableCyclicReference
188+
// inaccessible: this._undoLog
189+
// inaccessible: this.numericLoBound
190+
// inaccessible: this.numericHiBound
153191
this.TypeConstraint
154192
this.normalizeAliases
155193
this.dropSingletonType
@@ -161,15 +199,18 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
161199
this.typeVarToOriginMap
162200
this.ErroneousCollector
163201
this.adaptToNewRunMap
202+
// inaccessible: this.commonOwnerMapObj
164203
this.SubTypePair
165204
this.SymbolKind
166205
this.NoSymbol
167206
this.CyclicReference
207+
// inaccessible: this.TypeHistory
168208
this.TermName
169209
this.TypeName
170210
this.Liftable
171211
this.Unliftable
172212
this.BooleanFlag
213+
// inaccessible: this.CachedNames
173214
this.WeakTypeTag
174215
this.TypeTag
175216
this.Expr
@@ -386,12 +427,14 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
386427
definitions.languageFeatureModule
387428
definitions.metaAnnotations
388429
definitions.AnnotationDefaultAttr
430+
// inaccessible: definitions.erasurePhase
389431
definitions.isPhantomClass
390432
definitions.syntheticCoreClasses
391433
definitions.syntheticCoreMethods
392434
definitions.hijackedCoreClasses
393435
definitions.symbolsNotPresentInBytecode
394436
definitions.isPossibleSyntheticParent
437+
// inaccessible: definitions.boxedValueClassesSet
395438
definitions.abbrvTag
396439
definitions.numericWeight
397440
definitions.boxedModule

test/files/run/reflection-magicsymbols-invoke.check

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ Array
8282
it's important to print the list of Array's members
8383
if some of them change (possibly, adding and/or removing magic symbols), we must update this test
8484
constructor Array: (_length: Int)Array[T]
85-
constructor Cloneable: ()java.lang.Cloneable
8685
method !=: (x$1: Any)Boolean
8786
method !=: (x$1: AnyRef)Boolean
8887
method ##: ()Int

0 commit comments

Comments
 (0)