From 1537a9d6b1458b182393c3d14e9dbc3b3500b986 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 16 Apr 2012 19:21:03 +0100 Subject: [PATCH 1/2] Fix cavalier approach to reflection. No need to recreate the Method instance thousands of times. --- compile/JavaCompiler.scala | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/compile/JavaCompiler.scala b/compile/JavaCompiler.scala index 7edd7ab24..3bd3eaeb4 100644 --- a/compile/JavaCompiler.scala +++ b/compile/JavaCompiler.scala @@ -23,17 +23,27 @@ object JavaCompiler { type Fork = (JavacContract, Seq[String], Logger) => Int + private def pwClass = classOf[PrintWriter] + private def arrayStringClass = classOf[Array[String]] + private def docletsClass = "com.sun.tools.doclets.standard.Standard" + + // The real performance gain comes if you can skip the indirection. + /* val javac = new JavacContract("javac", "com.sun.tools.javac.Main") { + def exec(args: Array[String], writer: PrintWriter): Int = + com.sun.tools.javac.Main.compile(args, writer) + } */ + val javac = new JavacContract("javac", "com.sun.tools.javac.Main") { - def exec(args: Array[String], writer: PrintWriter) = { - val m = Class.forName(clazz).getDeclaredMethod("compile", classOf[Array[String]], classOf[PrintWriter]) - m.invoke(null, args, writer).asInstanceOf[java.lang.Integer].intValue + private val execMethod = Class.forName(clazz).getDeclaredMethod("compile", arrayStringClass, pwClass) + def exec(args: Array[String], writer: PrintWriter) = { + execMethod.invoke(null, args, writer).asInstanceOf[java.lang.Integer].intValue } } val javadoc = new JavacContract("javadoc", "com.sun.tools.javadoc.Main") { - def exec(args: Array[String], writer: PrintWriter) = { - val m = Class.forName(clazz).getDeclaredMethod("execute", classOf[String], classOf[PrintWriter], classOf[PrintWriter], classOf[PrintWriter], classOf[String], classOf[Array[String]]) - m.invoke(null, name, writer, writer, writer, "com.sun.tools.doclets.standard.Standard", args).asInstanceOf[java.lang.Integer].intValue - } + private val execMethod = Class.forName(clazz).getDeclaredMethod("execute", classOf[String], pwClass, pwClass, pwClass, classOf[String], arrayStringClass) + + def exec(args: Array[String], writer: PrintWriter) = + execMethod.invoke(null, name, writer, writer, writer, docletsClass, args).asInstanceOf[java.lang.Integer].intValue } def construct(f: Fork, cp: ClasspathOptions, scalaInstance: ScalaInstance): JavaCompiler = From 6c090313dae1bc98690d3e584103742f3c5a8908 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 16 Apr 2012 19:19:27 +0100 Subject: [PATCH 2/2] Work around scalac issue causing boxing. Tableswitch slightly cheaper than a couple million trips through the Byte box. --- util/classfile/Parser.scala | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/util/classfile/Parser.scala b/util/classfile/Parser.scala index cf33fca2e..92c74d65d 100644 --- a/util/classfile/Parser.scala +++ b/util/classfile/Parser.scala @@ -5,6 +5,7 @@ package sbt package classfile import java.io.{DataInputStream, File, InputStream} +import scala.annotation.switch // Translation of jdepend.framework.ClassFileParser by Mike Clark, Clarkware Consulting, Inc. // BSD Licensed @@ -132,17 +133,18 @@ private[sbt] object Parser pool } - private def getConstant(in: DataInputStream) = - { + private def getConstant(in: DataInputStream): Constant = + { val tag = in.readByte() - tag match - { - case ConstantClass | ConstantString => new Constant(tag, in.readUnsignedShort()) - case ConstantField | ConstantMethod | ConstantInterfaceMethod | ConstantNameAndType => - new Constant(tag, in.readUnsignedShort(), in.readUnsignedShort()) - case ConstantInteger => new Constant(tag, new java.lang.Integer(in.readInt())) - case ConstantFloat => new Constant(tag, new java.lang.Float(in.readFloat())) - case ConstantLong => new Constant(tag, new java.lang.Long(in.readLong())) + + // No switch for byte scrutinees! Stupid compiler. + ((tag: Int): @switch) match { + case ConstantClass | ConstantString => new Constant(tag, in.readUnsignedShort()) + case ConstantField | ConstantMethod | ConstantInterfaceMethod | ConstantNameAndType => + new Constant(tag, in.readUnsignedShort(), in.readUnsignedShort()) + case ConstantInteger => new Constant(tag, new java.lang.Integer(in.readInt())) + case ConstantFloat => new Constant(tag, new java.lang.Float(in.readFloat())) + case ConstantLong => new Constant(tag, new java.lang.Long(in.readLong())) case ConstantDouble => new Constant(tag, new java.lang.Double(in.readDouble())) case ConstantUTF8 => new Constant(tag, in.readUTF()) case _ => error("Unknown constant: " + tag)