From 7affb3526f33e9934b51e149ff3eb31053c444aa Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Tue, 24 Nov 2009 08:56:23 -0500 Subject: [PATCH] Cache reflective lookups in the compiler interface --- compile/interface/Analyzer.scala | 22 +++++++++++----------- compile/interface/CachedMethod.scala | 27 +++++++++++++++++++++++++++ notes | 9 +++++++++ 3 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 compile/interface/CachedMethod.scala diff --git a/compile/interface/Analyzer.scala b/compile/interface/Analyzer.scala index f5fccbcd0..bc4930ebb 100644 --- a/compile/interface/Analyzer.scala +++ b/compile/interface/Analyzer.scala @@ -190,27 +190,27 @@ final class Analyzer(val global: Global, val callback: AnalysisCallback) extends } private class NewFinder extends ClassFinder { + private val findClass0 = reflect[Option[AnyRef]]("findClass", classOf[String]) + findClass0.force(classPath) // force discovery, so that an exception is thrown if method doesn't exist + private val extractClass0 = reflect[Option[AbstractFile]]("binary") def findClass(name: String): Option[AbstractFile] = - call[Option[AnyRef]](classPath, "findClass", classOf[String])(name).flatMap(extractClass) - private def extractClass(a: AnyRef) = - call[Option[AbstractFile]](a, "binary")() + findClass0(classPath, name).flatMap(a => extractClass0(a)) } private class LegacyFinder extends ClassFinder { - private val root = call[AnyRef](classPath, "root")() + private val root = { val m = reflect[AnyRef]("root"); m(classPath) } + private val find0 = reflect[AnyRef]("find", classOf[String], classOf[Boolean]) + find0.force(root) // force discovery, so that an exception is thrown if method doesn't exist + private val classFile = reflect[AbstractFile]("classFile") def findClass(name: String): Option[AbstractFile] = { - val entry = call[AnyRef](root, "find", classOf[String], classOf[Boolean])(name, boolean2Boolean(false)) + val entry = find0(root, name, boolean2Boolean(false)) if (entry eq null) None else - Some( call[AbstractFile](entry, "classFile")() ) + Some( classFile(entry) ) } } import scala.reflect.Manifest - private def call[T <: AnyRef](on: AnyRef, name: String, tpes: Class[_]*)(args: AnyRef*)(implicit mf: Manifest[T]): T = - { - val result = on.getClass.getMethod(name, tpes : _*).invoke(on, args : _*) - mf.erasure.cast(result).asInstanceOf[T] - } + private def reflect[T](name: String, tpes: Class[_]*)(implicit mf: Manifest[T]) = new CachedMethod(name, tpes : _*)(mf) } \ No newline at end of file diff --git a/compile/interface/CachedMethod.scala b/compile/interface/CachedMethod.scala new file mode 100644 index 000000000..943968fec --- /dev/null +++ b/compile/interface/CachedMethod.scala @@ -0,0 +1,27 @@ +package xsbt + +import java.lang.ref.WeakReference +import java.lang.reflect.Method +import scala.reflect.Manifest + +// replacement for structural type cache, which doesn't use weak references +// assumes type of target doesn't change +// not thread safe +private final class CachedMethod[T](name: String, tpes: Class[_]*)(mf: Manifest[T]) extends NotNull +{ + private var method = new WeakReference[Method](null) + private def getMethod(on: AnyRef): Method = + { + val m = on.getClass.getMethod(name, tpes : _*) + method = new WeakReference(m) + m + } + def force(on: AnyRef) { getMethod(on) } + def apply(on: AnyRef, args: AnyRef*): T = + { + val cached = method.get + val m = if(cached ne null) cached else getMethod(on) + val result = m.invoke(on, args : _*) + mf.erasure.cast(result).asInstanceOf[T] + } +} \ No newline at end of file diff --git a/notes b/notes index 845b4e7a0..4873309c4 100644 --- a/notes +++ b/notes @@ -1,3 +1,8 @@ +DONE +-fix caching issue for compiler interface +-fix test ClassLoader + + Goals/Guidelines for xsbt ===== As usual: @@ -13,6 +18,10 @@ TODO - allow comments in datatype definition file - tests for API extractor +update 0_6_Summary to mention different output directories. +look at permgen in Josh's ScalaTest +TrapExit handles System.exit(0) as nonzero exit code + Task engine - method tasks will be normal tasks that pull the command line from a CommandLine task - per task configuration, including logging (e.g. 'task compile log debug')