Skip to content

Commit c0e7736

Browse files
committed
Cache quote unpickling
1 parent 6d0817d commit c0e7736

File tree

3 files changed

+68
-16
lines changed

3 files changed

+68
-16
lines changed

compiler/src/dotty/tools/dotc/quoted/MacroExpansion.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ object MacroExpansion {
1414
ctx.property(MacroExpansionPosition)
1515

1616
def context(inlinedFrom: tpd.Tree)(using Context): Context =
17-
ctx.fresh.setProperty(MacroExpansionPosition, SourcePosition(inlinedFrom.source, inlinedFrom.span)).setTypeAssigner(new Typer).withSource(inlinedFrom.source)
17+
QuotesCache.init(ctx.fresh).setProperty(MacroExpansionPosition, SourcePosition(inlinedFrom.source, inlinedFrom.span)).setTypeAssigner(new Typer).withSource(inlinedFrom.source)
1818
}
1919

compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,24 @@ object PickledQuotes {
5454

5555
/** Unpickle the tree contained in the TastyExpr */
5656
def unpickleTerm(pickled: String | List[String], typeHole: (Int, Seq[Any]) => scala.quoted.Type[?], termHole: (Int, Seq[Any], scala.quoted.Quotes) => scala.quoted.Expr[?])(using Context): Tree = {
57+
val t0 = System.nanoTime()
5758
val unpickled = withMode(Mode.ReadPositions)(unpickle(pickled, isType = false))
5859
val Inlined(call, Nil, expnasion) = unpickled
60+
val t1 = System.nanoTime()
5961
val inlineCtx = inlineContext(call)
62+
val t2 = System.nanoTime()
6063
val expansion1 = spliceTypes(expnasion, typeHole, termHole)(using inlineCtx)
64+
val t3 = System.nanoTime()
6165
val expansion2 = spliceTerms(expansion1, typeHole, termHole)(using inlineCtx)
62-
cpy.Inlined(unpickled)(call, Nil, expansion2)
66+
val t4 = System.nanoTime()
67+
val res = cpy.Inlined(unpickled)(call, Nil, expansion2)
68+
val t5 = System.nanoTime()
69+
// println(s"""
70+
// |unpickle> ${ (t1 - t0).toDouble / 1000 }μs
71+
// |spliceTypes> ${(t3 - t2).toDouble / 1000 }μs
72+
// |spliceTerms> ${(t4 - t3).toDouble / 1000 }μs
73+
// |""".stripMargin)
74+
res
6375
}
6476

6577
/** Unpickle the tree contained in the TastyType */
@@ -179,27 +191,41 @@ object PickledQuotes {
179191
pickled
180192
}
181193

194+
private val cache = collection.mutable.Map.empty[String | List[String], Tree]
195+
182196
/** Unpickle TASTY bytes into it's tree */
183197
private def unpickle(pickled: String | List[String], isType: Boolean)(using Context): Tree = {
184-
val bytes = pickled match
185-
case pickled: String => TastyString.unpickle(pickled)
186-
case pickled: List[String] => TastyString.unpickle(pickled)
198+
QuotesCache.get(pickled) match
199+
case Some(tree) => tree
200+
case _ =>
201+
val bytes = pickled match
202+
case pickled: String => TastyString.unpickle(pickled)
203+
case pickled: List[String] => TastyString.unpickle(pickled)
187204

188-
quotePickling.println(s"**** unpickling quote from TASTY\n${TastyPrinter.show(bytes)}")
205+
quotePickling.println(s"**** unpickling quote from TASTY\n${TastyPrinter.show(bytes)}")
189206

190-
val mode = if (isType) UnpickleMode.TypeTree else UnpickleMode.Term
191-
val unpickler = new DottyUnpickler(bytes, mode)
192-
unpickler.enter(Set.empty)
207+
val mode = if (isType) UnpickleMode.TypeTree else UnpickleMode.Term
208+
val unpickler = new DottyUnpickler(bytes, mode)
209+
unpickler.enter(Set.empty)
193210

194-
val tree = unpickler.tree
211+
val tree = unpickler.tree
195212

196-
// Make sure trees and positions are fully loaded
197-
new TreeTraverser {
198-
def traverse(tree: Tree)(using Context): Unit = traverseChildren(tree)
199-
}.traverse(tree)
213+
var holeWithCapture = false // FIXME: remove this. TypeTreeMap is probably not changing the references in the Hole
200214

201-
quotePickling.println(i"**** unpickled quote\n$tree")
202-
tree
215+
// Make sure trees and positions are fully loaded
216+
new TreeTraverser {
217+
def traverse(tree: Tree)(using Context): Unit =
218+
tree match
219+
case Hole(_, _, _ :: _) =>
220+
holeWithCapture = true
221+
case _ =>
222+
traverseChildren(tree)
223+
}.traverse(tree)
224+
225+
quotePickling.println(i"**** unpickled quote\n$tree")
226+
if !holeWithCapture then
227+
QuotesCache(pickled) = tree
228+
tree
203229
}
204230

205231
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package dotty.tools.dotc.quoted
2+
3+
import dotty.tools.dotc.core.Contexts._
4+
import dotty.tools.dotc.util.Property
5+
import dotty.tools.dotc.reporting.trace
6+
import dotty.tools.dotc.ast.tpd
7+
8+
import scala.collection.mutable
9+
10+
object QuotesCache {
11+
import tpd._
12+
13+
/** A key to be used in a context property that caches the class loader used for macro expansion */
14+
private val QuotesCacheKey = new Property.Key[collection.mutable.Map[String | List[String], Tree]]
15+
16+
/** Get the macro class loader */
17+
def get(pickled: String | List[String])(using Context): Option[Tree] =
18+
ctx.property(QuotesCacheKey).get.get(pickled)
19+
20+
def update(pickled: String | List[String], tree: Tree)(using Context): Unit =
21+
ctx.property(QuotesCacheKey).get.update(pickled, tree)
22+
23+
/** Context with a cache for */
24+
def init(ctx: FreshContext): ctx.type =
25+
ctx.setProperty(QuotesCacheKey, collection.mutable.Map.empty)
26+
}

0 commit comments

Comments
 (0)