Skip to content

Commit d5eeb43

Browse files
committed
Add calls on this in erased calls.
1 parent 55d4609 commit d5eeb43

File tree

21 files changed

+99
-57
lines changed

21 files changed

+99
-57
lines changed

compiler/src/dotty/tools/dotc/transform/linker/callgraph/CallGraphBuilder.scala

Lines changed: 70 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class CallGraphBuilder(collectedSummaries: Map[Symbol, MethodSummary], mode: Int
4747
}
4848
val targs = (0 until targsSize).map(x => new ErazedType()).toList
4949
val args = ctx.definitions.ArrayOf(ctx.definitions.StringType) :: Nil
50-
val call = CallInfoWithContext(tpe, targs, args, OuterTargs.empty, None, None)
50+
val call = CallInfoWithContext(tpe, targs, args, OuterTargs.empty, None, None, isErased = false)
5151
entryPoints(call) = entryPointId
5252
reachableMethods += call
5353
val t = ref(s.owner).tpe
@@ -81,10 +81,10 @@ class CallGraphBuilder(collectedSummaries: Map[Symbol, MethodSummary], mode: Int
8181
}
8282
if (!clas.is(JavaDefined) && clas.is(Module)) {
8383
val fields = clas.classInfo.decls.filter(x => !x.is(Method) && !x.isType)
84-
val parent = Some(CallInfoWithContext(x.tp.select(clas.primaryConstructor), x.tp.baseArgInfos(clas), Nil, x.outerTargs, None, None))
84+
val parent = Some(CallInfoWithContext(x.tp.select(clas.primaryConstructor), x.tp.baseArgInfos(clas), Nil, x.outerTargs, None, None, isErased = false))
8585
reachableMethods ++= fields.map {
8686
fieldSym =>
87-
CallInfoWithContext(x.tp.select(fieldSym), Nil, Nil, x.outerTargs, parent, None)
87+
CallInfoWithContext(x.tp.select(fieldSym), Nil, Nil, x.outerTargs, parent, None, isErased = false)
8888
}
8989
}
9090
}
@@ -189,7 +189,7 @@ class CallGraphBuilder(collectedSummaries: Map[Symbol, MethodSummary], mode: Int
189189
}.apply(OuterTargs.empty, tp)
190190
}
191191

192-
private def instantiateCallSite(caller: CallInfoWithContext, rec: Type, callee: CallInfo, types: Traversable[TypeWithContext]): Traversable[CallInfoWithContext] = {
192+
private def instantiateCallSite(caller: CallInfoWithContext, rec: Type, callee: CallInfo, types: Traversable[TypeWithContext], isErased: Boolean = false): Traversable[CallInfoWithContext] = {
193193

194194
lazy val someCaller = Some(caller)
195195
lazy val someCallee = Some(callee)
@@ -200,6 +200,10 @@ class CallGraphBuilder(collectedSummaries: Map[Symbol, MethodSummary], mode: Int
200200
val calleeSymbol = callee.call.termSymbol.asTerm
201201
val callerSymbol = caller.call.termSymbol
202202

203+
def mkCallInfoWithContext(call: Type, targs: List[Type], args: List[Type], outerTargs: OuterTargs) = {
204+
CallInfoWithContext(call, targs, args, outerTargs, someCaller, someCallee, isErased)
205+
}
206+
203207
val tpamsOuter = caller.call.widen match {
204208
case t: PolyType =>
205209
OuterTargs.empty.addAll(callerSymbol, t.paramNames, caller.targs)
@@ -309,10 +313,10 @@ class CallGraphBuilder(collectedSummaries: Map[Symbol, MethodSummary], mode: Int
309313
assert(call.exists)
310314
t.underlying.select(call)
311315
}
312-
CallInfoWithContext(preciseSelectCall, targs, args, outerTargs, someCaller, someCallee) :: Nil
316+
mkCallInfoWithContext(preciseSelectCall, targs, args, outerTargs) :: Nil
313317
case t: ClosureType if calleeSymbol.name eq t.implementedMethod.name =>
314318
val methodSym = t.meth.meth.symbol.asTerm
315-
CallInfoWithContext(TermRef.withFixedSym(t.underlying, methodSym.name, methodSym), targs, t.meth.env.map(_.tpe) ++ args, outerTargs ++ t.outerTargs, someCaller, someCallee) :: Nil
319+
mkCallInfoWithContext(TermRef.withFixedSym(t.underlying, methodSym.name, methodSym), targs, t.meth.env.map(_.tpe) ++ args, outerTargs ++ t.outerTargs) :: Nil
316320
case AndType(tp1, tp2) =>
317321
dispatchCalls(tp1).toSet.intersect(dispatchCalls(tp2).toSet)
318322
case _ =>
@@ -330,7 +334,7 @@ class CallGraphBuilder(collectedSummaries: Map[Symbol, MethodSummary], mode: Int
330334
alt <- tp.tp.member(calleeSymbol.name).altsWith(p => p.asSeenFrom(tp.tp).matches(calleeSymbol.asSeenFrom(tp.tp)))
331335
if alt.exists
332336
} yield {
333-
CallInfoWithContext(tp.tp.select(alt.symbol), targs, args, outerTargs ++ tp.outerTargs, someCaller, someCallee)
337+
mkCallInfoWithContext(tp.tp.select(alt.symbol), targs, args, outerTargs ++ tp.outerTargs)
334338
}
335339
}
336340

@@ -355,7 +359,7 @@ class CallGraphBuilder(collectedSummaries: Map[Symbol, MethodSummary], mode: Int
355359
(uncastedSig.paramTypess.flatten zip castedSig.paramTypess.flatten) foreach (x => addCast(x._2, x._1))
356360
addCast(uncastedSig.finalResultType, castedSig.finalResultType)
357361

358-
CallInfoWithContext(tp.tp.select(alt.symbol), targs, args, outerTargs ++ tp.outerTargs, someCaller, someCallee)
362+
mkCallInfoWithContext(tp.tp.select(alt.symbol), targs, args, outerTargs ++ tp.outerTargs)
359363
}
360364
}
361365

@@ -380,7 +384,7 @@ class CallGraphBuilder(collectedSummaries: Map[Symbol, MethodSummary], mode: Int
380384
Nil
381385
case NoPrefix => // inner method
382386
assert(calleeSymbol.is(ParamAccessor) || calleeSymbol.owner.is(Method) || calleeSymbol.owner.isLocalDummy)
383-
CallInfoWithContext(TermRef.withFixedSym(caller.call.normalizedPrefix, calleeSymbol.name, calleeSymbol), targs, args, outerTargs, someCaller, someCallee) :: Nil
387+
mkCallInfoWithContext(TermRef.withFixedSym(caller.call.normalizedPrefix, calleeSymbol.name, calleeSymbol), targs, args, outerTargs) :: Nil
384388

385389
case t if calleeSymbol.isConstructor =>
386390

@@ -418,7 +422,7 @@ class CallGraphBuilder(collectedSummaries: Map[Symbol, MethodSummary], mode: Int
418422
propagateTargs(receiver).select(calleeSymbol)
419423
}
420424

421-
CallInfoWithContext(call, targs, args, outerTargs, someCaller, someCallee) :: Nil
425+
mkCallInfoWithContext(call, targs, args, outerTargs) :: Nil
422426

423427
// super call in a class (know target precisely)
424428
case st: SuperType =>
@@ -430,7 +434,7 @@ class CallGraphBuilder(collectedSummaries: Map[Symbol, MethodSummary], mode: Int
430434
val thisTpePropagated = propagateTargs(thisTpe)
431435

432436

433-
CallInfoWithContext(TermRef.withFixedSym(thisTpePropagated, targetMethod.name, targetMethod), targs, args, outerTargs, someCaller, someCallee) :: Nil
437+
mkCallInfoWithContext(TermRef.withFixedSym(thisTpePropagated, targetMethod.name, targetMethod), targs, args, outerTargs) :: Nil
434438

435439
// super call in a trait
436440
case t if calleeSymbol.is(SuperAccessor) =>
@@ -452,7 +456,7 @@ class CallGraphBuilder(collectedSummaries: Map[Symbol, MethodSummary], mode: Int
452456
if (s.nonEmpty) {
453457
val parentMethod = ResolveSuper.rebindSuper(x.tp.widenDealias.classSymbol, calleeSymbol).asTerm
454458
// todo: outerTargs are here defined in terms of location of the subclass. Is this correct?
455-
CallInfoWithContext(TermRef.withFixedSym(t, parentMethod.name, parentMethod), targs, args, outerTargs, someCaller, someCallee) :: Nil
459+
mkCallInfoWithContext(TermRef.withFixedSym(t, parentMethod.name, parentMethod), targs, args, outerTargs) :: Nil
456460

457461
} else Nil
458462
}
@@ -461,14 +465,16 @@ class CallGraphBuilder(collectedSummaries: Map[Symbol, MethodSummary], mode: Int
461465
val dropUntil = thisType.tref.classSymbol
462466
var currentThis = caller.call.normalizedPrefix
463467
var currentOwner = caller.call.termSymbol.owner
464-
while ((currentOwner ne dropUntil) && (currentThis ne NoType)) {
465-
if (!currentOwner.is(Method))
466-
currentThis = currentThis.normalizedPrefix
467-
currentOwner = currentOwner.owner.enclosingClass
468+
if (!dropUntil.is(Trait)) {
469+
while ((currentOwner ne dropUntil) && (currentThis ne NoType)) {
470+
if (!currentOwner.is(Method))
471+
currentThis = currentThis.normalizedPrefix
472+
currentOwner = currentOwner.owner.enclosingClass
473+
}
468474
}
469475
if (currentThis.derivesFrom(thisType.cls)) {
470476
if (calleeSymbol.is(Private)) {
471-
CallInfoWithContext(TermRef.withFixedSym(currentThis, calleeSymbol.name, calleeSymbol), targs, args, outerTargs, someCaller, someCallee) :: Nil
477+
mkCallInfoWithContext(TermRef.withFixedSym(currentThis, calleeSymbol.name, calleeSymbol), targs, args, outerTargs) :: Nil
472478
} else {
473479
val fullThisType = AndType.apply(currentThis, thisType.tref)
474480
dispatchCalls(propagateTargs(fullThisType))
@@ -548,60 +554,69 @@ class CallGraphBuilder(collectedSummaries: Map[Symbol, MethodSummary], mode: Int
548554
if (defn.isPrimitiveClass(argType.classSymbol) || isJavaClass(argType.widenDealias.classSymbol)) {
549555
Set.empty
550556
} else {
551-
def potentialCall(decl: Symbol) = {
552-
def paramTypes = decl.info.paramTypess.flatten
553-
val call = new TermRefWithFixedSym(argType, decl.name.asTermName, decl.asTerm)
554-
val targs = call.widenDealias match {
555-
case call: PolyType =>
556-
def erasedBounds(tp: TypeBounds): Type = tp.hi match {
557-
case RefinedType(parent, refinedName, refinedInfo: TypeBounds) =>
558-
RefinedType(parent, refinedName, erasedBounds(refinedInfo))
559-
case t => t
560-
}
561-
call.paramBounds.map(erasedBounds)
557+
def potentialCall(decl: Symbol): Option[CallInfo] = {
558+
if (!decl.owner.is(JavaDefined) && decl.isTerm && !decl.isConstructor && decl.name != nme.COMPANION_MODULE_METHOD &&
559+
decl.name != nme.isInstanceOf_ && decl.name != nme.asInstanceOf_ && decl.name != nme.synchronized_ && decl.name != nme.getClass_) {
560+
None
561+
} else {
562+
def paramTypes = decl.info.paramTypess.flatten
562563

563-
case _ => Nil
564-
}
564+
val call = new TermRefWithFixedSym(argType, decl.name.asTermName, decl.asTerm)
565+
val targs = call.widenDealias match {
566+
case call: PolyType =>
567+
def erasedBounds(tp: TypeBounds): Type = tp.hi match {
568+
case RefinedType(parent, refinedName, refinedInfo: TypeBounds) =>
569+
RefinedType(parent, refinedName, erasedBounds(refinedInfo))
570+
case t => t
571+
}
565572

566-
def isDefinedInJavaClass(sym: Symbol) =
567-
sym.owner == defn.AnyClass || sym.owner.is(JavaDefined)
573+
call.paramBounds.map(erasedBounds)
568574

569-
val definedInJavaClass: Boolean =
570-
isDefinedInJavaClass(decl) || decl.allOverriddenSymbols.exists(isDefinedInJavaClass)
575+
case _ => Nil
576+
}
571577

572-
argType match {
573-
case argType: PreciseType =>
574-
if (!definedInJavaClass) Nil
575-
else List(CallInfo(call, targs, paramTypes))
578+
def isDefinedInJavaClass(sym: Symbol) =
579+
sym.owner == defn.AnyClass || sym.owner.is(JavaDefined)
576580

577-
case _ =>
578-
val argTypeWiden = argType.widenDealias
579-
lazy val sym = argTypeWiden.classSymbol.requiredMethod(decl.name, paramTypes)
580-
if (!argTypeWiden.member(decl.name).exists || !definedInJavaClass || (sym.isEffectivelyFinal && isDefinedInJavaClass(decl))) Nil
581-
else List(CallInfo(TermRef(argType, sym), targs, paramTypes))
581+
val definedInJavaClass: Boolean =
582+
isDefinedInJavaClass(decl) || decl.allOverriddenSymbols.exists(isDefinedInJavaClass)
582583

584+
argType match {
585+
case argType: PreciseType =>
586+
if (!definedInJavaClass) None
587+
else Some(CallInfo(call, targs, paramTypes))
588+
589+
case _ =>
590+
val argTypeWiden = argType.widenDealias
591+
lazy val sym = argTypeWiden.classSymbol.requiredMethod(decl.name, paramTypes)
592+
if (!argTypeWiden.member(decl.name).exists || !definedInJavaClass || (sym.isEffectivelyFinal && isDefinedInJavaClass(decl))) None
593+
else Some(CallInfo(TermRef(argType, sym), targs, paramTypes))
594+
595+
}
583596
}
584597
}
585598

586-
for {
587-
decl <- allDecls(argType)
588-
if decl.isTerm && !decl.isConstructor && decl.name != nme.COMPANION_MODULE_METHOD
589-
if decl.name != nme.isInstanceOf_ && decl.name != nme.asInstanceOf_ && decl.name != nme.synchronized_
590-
callInfo <- potentialCall(decl)
591-
} yield callInfo
599+
allDecls(argType).flatMap(potentialCall)
592600
}
593601
}
594602

595-
// FIXME java method could potentially call this.xyz()
596-
// addAllPotentialCallsFor(method.call.normalizedPrefix)
603+
def filterParams(params: List[Type]) = {
604+
val parents = method.parents
605+
params.distinct.filter(param => !parents.exists(_.call.normalizedPrefix == param))
606+
}
607+
608+
val collapsedMethod =
609+
if (method.isErased) method.parent.get else method
610+
597611
for {
598-
rec <- method.argumentsPassed.distinct
612+
rec <- filterParams(method.call.normalizedPrefix :: method.argumentsPassed.distinct)
613+
if !collapsedMethod.addAndHasErasedType(rec.widenDealias)
599614
potentialCall <- allPotentialCallsFor(rec)
600-
if method.getOutEdges(potentialCall).isEmpty
615+
if collapsedMethod.getOutEdges(potentialCall).isEmpty
601616
} {
602-
val nw = instantiateCallSite(method, rec, potentialCall, instantiatedTypes)
617+
val nw = instantiateCallSite(collapsedMethod, rec, potentialCall, instantiatedTypes, isErased = true)
603618
reachableMethods ++= nw
604-
method.addOutEdges(potentialCall, nw)
619+
collapsedMethod.addOutEdges(potentialCall, nw)
605620
}
606621
}
607622

compiler/src/dotty/tools/dotc/transform/linker/callgraph/CallInfoWithContext.scala

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@ import dotty.tools.dotc.transform.linker.summaries.{AbstractCallInfo, CallInfo}
77
import scala.collection.mutable
88

99
case class CallInfoWithContext(call: Type, targs: List[Type], argumentsPassed: List[Type], outerTargs: OuterTargs,
10-
parent: Option[CallInfoWithContext], callee: Option[CallInfo])(implicit ctx: Context) extends AbstractCallInfo {
10+
parent: Option[CallInfoWithContext], callee: Option[CallInfo], isErased: Boolean)(implicit ctx: Context) extends AbstractCallInfo {
11+
12+
assert(!isErased || parent.nonEmpty)
1113

1214
private val outEdges = mutable.HashMap[CallInfo, List[CallInfoWithContext]]().withDefault(x => Nil)
1315

16+
private val erasedTypes = mutable.HashSet.empty[Type]
17+
1418
def outEdgesIterator: Iterator[(CallInfo, List[CallInfoWithContext])] = outEdges.iterator
1519

1620
def getOutEdges(callSite: CallInfo): List[CallInfoWithContext] = outEdges(callSite)
@@ -27,6 +31,15 @@ case class CallInfoWithContext(call: Type, targs: List[Type], argumentsPassed: L
2731
def edgeCount: Int =
2832
outEdges.values.foldLeft(0)(_ + _.size)
2933

34+
def addAndHasErasedType(tp: Type): Boolean = {
35+
val res = erasedTypes.contains(tp)
36+
if (!res)
37+
erasedTypes += tp
38+
res
39+
}
40+
3041
def source: Option[CallInfo] = callee.flatMap(_.source)
3142

43+
def parents: List[CallInfoWithContext] =
44+
parent.fold(List.empty[CallInfoWithContext])(p => p :: p.parents)
3245
}

tests/link-dce/link-code-from-java-5.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import scala.annotation.internal
22
import scala.math.Ordering
33

44
object Test {
5-
@internal.link.CallGraphBounds(reachableClasses = 152, classesWithReachableMethods = 21, reachableMethods = 90)
5+
@internal.link.CallGraphBounds(reachableClasses = 154, classesWithReachableMethods = 24, reachableMethods = 93)
66
def main(args: Array[String]): Unit = {
77
val arr = new Array[Object](1)
88
arr(0) = 42

tests/link-dce/link-fillStackTrace-2.check

Whitespace-only changes.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import scala.annotation.internal
2+
3+
object Test {
4+
@internal.link.CallGraphBounds(reachableClasses = 22, classesWithReachableMethods = 6, reachableMethods = 21)
5+
def main(args: Array[String]): Unit = {
6+
new BreakControl
7+
}
8+
}
9+
10+
class BreakControl extends NoStackTrace
11+
12+
trait NoStackTrace extends Throwable {
13+
override def fillInStackTrace(): Throwable = super.fillInStackTrace()
14+
}

0 commit comments

Comments
 (0)