From fdccc19cc76d218d92014d933761a3d856b26bd2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 23 Jul 2020 11:05:25 +0200 Subject: [PATCH 1/4] Generalize instrumentation Make it easer to search for new calls, and include `.toString` in the list of tracked methods --- .../tools/dotc/transform/Instrumentation.scala | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala b/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala index 4c38c1119012..c8fb4298c488 100644 --- a/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala +++ b/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala @@ -11,7 +11,7 @@ import Decorators._ import ast.Trees._ import MegaPhase._ import StdNames.nme -import Names.TermName +import Names._ import Constants.Constant @@ -28,14 +28,15 @@ class Instrumentation extends MiniPhase { thisPhase => ctx.settings.YinstrumentClosures.value || ctx.settings.YinstrumentAllocations.value + private val namesOfInterest = List("::", "+=", "toString") + private var namesToRecord: Set[Name] = _ + private var consName: TermName = _ private var consEqName: TermName = _ - override def prepareForUnit(tree: Tree)(using Context): Context = { - consName = "::".toTermName - consEqName = "+=".toTermName + override def prepareForUnit(tree: Tree)(using Context): Context = + namesToRecord = namesOfInterest.map(_.toTermName).toSet ctx - } private def record(category: String, tree: Tree)(using Context): Tree = { val key = Literal(Constant(s"$category${tree.sourcePos.show}")) @@ -45,8 +46,8 @@ class Instrumentation extends MiniPhase { thisPhase => override def transformApply(tree: Apply)(using Context): Tree = tree.fun match { case Select(nu: New, _) => cpy.Block(tree)(record(i"alloc/${nu.tpe}@", tree) :: Nil, tree) - case Select(_, name) if name == consName || name == consEqName => - cpy.Block(tree)(record("alloc/::", tree) :: Nil, tree) + case Select(_, name) if namesToRecord.contains(name) => + cpy.Block(tree)(record(i"alloc/$name", tree) :: Nil, tree) case _ => tree } From 673eb7b77b99113371ad5c2bc004de7124c018ef Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 23 Jul 2020 11:44:47 +0200 Subject: [PATCH 2/4] Avoid unnecessary toString --- compiler/src/dotty/tools/dotc/core/TypeComparer.scala | 2 +- compiler/src/dotty/tools/dotc/transform/Instrumentation.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 333975223168..c1ac93756bbf 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -1087,7 +1087,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling case info2: TypeBounds => compareLower(info2, tyconIsTypeRef = true) case info2: ClassInfo => - tycon2.name.toString.startsWith("Tuple") && + tycon2.name.startsWith("Tuple") && defn.isTupleType(tp2) && recur(tp1, tp2.toNestedPairs) || tryBaseType(info2.cls) case _ => diff --git a/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala b/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala index c8fb4298c488..f1fb595c56bf 100644 --- a/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala +++ b/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala @@ -39,13 +39,13 @@ class Instrumentation extends MiniPhase { thisPhase => ctx private def record(category: String, tree: Tree)(using Context): Tree = { - val key = Literal(Constant(s"$category${tree.sourcePos.show}")) + val key = Literal(Constant(s"$category@${tree.sourcePos.show}")) ref(defn.Stats_doRecord).appliedTo(key, Literal(Constant(1))) } override def transformApply(tree: Apply)(using Context): Tree = tree.fun match { case Select(nu: New, _) => - cpy.Block(tree)(record(i"alloc/${nu.tpe}@", tree) :: Nil, tree) + cpy.Block(tree)(record(i"alloc/${nu.tpe}", tree) :: Nil, tree) case Select(_, name) if namesToRecord.contains(name) => cpy.Block(tree)(record(i"alloc/$name", tree) :: Nil, tree) case _ => From 5ed661b3f3e7537c42e2928fa3cf628e5cdc1f88 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 29 Jul 2020 18:16:04 +0200 Subject: [PATCH 3/4] Also allow to instrument Idents as calls # Conflicts: # compiler/src/dotty/tools/dotc/transform/Instrumentation.scala --- .../src/dotty/tools/dotc/transform/Instrumentation.scala | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala b/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala index f1fb595c56bf..702817945abf 100644 --- a/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala +++ b/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala @@ -28,7 +28,10 @@ class Instrumentation extends MiniPhase { thisPhase => ctx.settings.YinstrumentClosures.value || ctx.settings.YinstrumentAllocations.value - private val namesOfInterest = List("::", "+=", "toString") + private val namesOfInterest = List( + "::", "+=", "toString", + "map", "flatMap", "filter", "withFilter", "collect", "foldLeft", "foldRight", "take", + "reverse", "mapConserve", "mapconserve", "filterConserve", "zip") private var namesToRecord: Set[Name] = _ private var consName: TermName = _ @@ -46,8 +49,8 @@ class Instrumentation extends MiniPhase { thisPhase => override def transformApply(tree: Apply)(using Context): Tree = tree.fun match { case Select(nu: New, _) => cpy.Block(tree)(record(i"alloc/${nu.tpe}", tree) :: Nil, tree) - case Select(_, name) if namesToRecord.contains(name) => - cpy.Block(tree)(record(i"alloc/$name", tree) :: Nil, tree) + case ref: RefTree if namesToRecord.contains(ref.name) => + cpy.Block(tree)(record(i"call/${ref.name}", tree) :: Nil, tree) case _ => tree } From b868bc79c4d9e9a3cb108302a43321dfdf1e0ff5 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 6 Aug 2020 11:23:49 +0200 Subject: [PATCH 4/4] Also track newArray and box as allocations --- .../src/dotty/tools/dotc/transform/Instrumentation.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala b/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala index 702817945abf..f4dafd131b62 100644 --- a/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala +++ b/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala @@ -29,7 +29,7 @@ class Instrumentation extends MiniPhase { thisPhase => ctx.settings.YinstrumentAllocations.value private val namesOfInterest = List( - "::", "+=", "toString", + "::", "+=", "toString", "newArray", "box", "map", "flatMap", "filter", "withFilter", "collect", "foldLeft", "foldRight", "take", "reverse", "mapConserve", "mapconserve", "filterConserve", "zip") private var namesToRecord: Set[Name] = _ @@ -46,10 +46,13 @@ class Instrumentation extends MiniPhase { thisPhase => ref(defn.Stats_doRecord).appliedTo(key, Literal(Constant(1))) } + private def ok(using Context) = + !ctx.owner.ownersIterator.exists(_.name.toString.startsWith("Stats")) + override def transformApply(tree: Apply)(using Context): Tree = tree.fun match { case Select(nu: New, _) => cpy.Block(tree)(record(i"alloc/${nu.tpe}", tree) :: Nil, tree) - case ref: RefTree if namesToRecord.contains(ref.name) => + case ref: RefTree if namesToRecord.contains(ref.name) && ok => cpy.Block(tree)(record(i"call/${ref.name}", tree) :: Nil, tree) case _ => tree