Author: reto
Date: Fri Nov 19 18:05:01 2010
New Revision: 1036963
URL: http://svn.apache.org/viewvc?rev=1036963&view=rev
Log:
faster compiler service with shared compiler, using it in ScriptEngineFactory
Modified:
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/resources/OSGI-INF/serviceComponents.xml
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/CompilerService.scala
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/ScriptEngineFactory.scala
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/TrackingCompiler.scala
incubator/clerezza/trunk/scala-scripting/tests/src/test/scala/org/apache/clerezza/scala/tests/CompilerServiceTest.scala
Modified:
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/resources/OSGI-INF/serviceComponents.xml
URL:
http://svn.apache.org/viewvc/incubator/clerezza/trunk/scala-scripting/script-engine/src/main/resources/OSGI-INF/serviceComponents.xml?rev=1036963&r1=1036962&r2=1036963&view=diff
==============================================================================
---
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/resources/OSGI-INF/serviceComponents.xml
(original)
+++
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/resources/OSGI-INF/serviceComponents.xml
Fri Nov 19 18:05:01 2010
@@ -29,6 +29,10 @@
interface="org.apache.clerezza.scala.scripting.InterpreterFactory"
cardinality="1..1"
bind="bindInterpreterFactory"
unbind="unbindInterpreterFactory"/>
+ <reference name="CompilerService"
+
interface="org.apache.clerezza.scala.scripting.CompilerService"
+ cardinality="1..1"
+ bind="bindCompilerService"
unbind="unbindCompilerService"/>
</scr:component>
<!-- <scr:component enabled="true" immediate="true"
name="org.apache.clerezza.scala.scripting.Launcher">
<implementation class="org.apache.clerezza.scala.scripting.Launcher"/>
Modified:
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/CompilerService.scala
URL:
http://svn.apache.org/viewvc/incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/CompilerService.scala?rev=1036963&r1=1036962&r2=1036963&view=diff
==============================================================================
---
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/CompilerService.scala
(original)
+++
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/CompilerService.scala
Fri Nov 19 18:05:01 2010
@@ -25,6 +25,8 @@ import org.apache.clerezza.scala.scripti
import org.apache.clerezza.scala.scripting.util.GenericFileWrapperTrait
import org.apache.clerezza.scala.scripting.util.VirtualDirectoryWrapper
import org.osgi.framework.BundleContext
+import org.osgi.framework.BundleEvent
+import org.osgi.framework.BundleListener
import org.osgi.service.component.ComponentContext;
import scala.tools.nsc._;
import scala.tools.nsc.interpreter._;
@@ -34,21 +36,55 @@ import scala.tools.nsc.reporters.Console
import scala.tools.nsc.util._
import java.io.ByteArrayOutputStream
import java.io.File
+import java.io.IOException
+import java.io.OutputStream
import java.io.PrintWriter
import java.io.Reader
import java.net._
+class CompileErrorsException(message: String) extends Exception(message) {
+ def this() = this(null)
+}
+
+class CompilerService() extends BundleListener {
-class CompilerService() {
-
protected var bundleContext : BundleContext = null;
+ protected val sharedVirtualDirectory = new VirtualDirectory("(memory)",
None)
+ protected var currentSharedCompilerOutputStream: OutputStream = null
+ protected val splipptingOutputStream = new OutputStream() {
+ def write(b: Int) {
+ if (currentSharedCompilerOutputStream == null) {
+ throw new IOException("no
currentSharedCompilerOutputStream set")
+ }
+ currentSharedCompilerOutputStream.write(b)
+ }
+ }
+ protected val splittingPrintWriter = new
PrintWriter(splipptingOutputStream, true)
+
+ protected var currentSharedCompiler: TrackingCompiler = null;
+ protected def sharedCompiler = {
+ if (currentSharedCompiler == null) {
+ synchronized {
+ if (currentSharedCompiler == null) {
+ currentSharedCompiler =
createCompiler(splittingPrintWriter, sharedVirtualDirectory)
+ }
+ }
+ }
+ currentSharedCompiler
+ }
def activate(componentContext: ComponentContext)= {
bundleContext = componentContext.getBundleContext
+ bundleContext.addBundleListener(this)
}
def deactivate(componentContext: ComponentContext) = {
- bundleContext = null
+ currentSharedCompiler = null
+ bundleContext.removeBundleListener(this)
+ }
+
+ def bundleChanged(event: BundleEvent) = {
+ currentSharedCompiler = null
}
def createCompiler(out: PrintWriter, outputSirectory: AbstractFile) :
TrackingCompiler = {
@@ -56,15 +92,39 @@ class CompilerService() {
}
def compile(sources: List[Array[Char]]): List[Class[_]] = {
+ sharedCompiler.synchronized {
+ val baos = new ByteArrayOutputStream
+ currentSharedCompilerOutputStream = baos
+ try {
+ sharedCompiler.compile(sources)
+ } catch {
+ case c: CompileErrorsException => throw new
CompileErrorsException(
+ new String(baos.toByteArray,
"utf-8"))
+ case e => throw e
+ } finally {
+ currentSharedCompilerOutputStream = null
+ }
+ }
+ }
+
+ /**
+ * compiles a set of sources with a dedicated compiler
+ */
+ def compileIsolated(sources: List[Array[Char]]): List[Class[_]] = {
val virtualDirectory = new VirtualDirectory("(memory)", None)
- compile(sources, virtualDirectory)
+ compileIsolated(sources, virtualDirectory)
}
- def compile(sources: List[Array[Char]], outputDirectory: AbstractFile):
List[Class[_]] = {
+ def compileIsolated(sources: List[Array[Char]], outputDirectory:
AbstractFile): List[Class[_]] = {
val out = new ByteArrayOutputStream
val printWriter = new PrintWriter(out)
val compiler = createCompiler(printWriter, outputDirectory)
- compiler.compile(sources)
+ try {
+ compiler.compile(sources)
+ } catch {
+ case c: CompileErrorsException => throw new
CompileErrorsException(new String(out.toByteArray, "utf-8"))
+ case e => throw e
+ }
}
Modified:
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/ScriptEngineFactory.scala
URL:
http://svn.apache.org/viewvc/incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/ScriptEngineFactory.scala?rev=1036963&r1=1036962&r2=1036963&view=diff
==============================================================================
---
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/ScriptEngineFactory.scala
(original)
+++
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/ScriptEngineFactory.scala
Fri Nov 19 18:05:01 2010
@@ -43,8 +43,6 @@ import scala.tools.nsc.interpreter._;
import scala.tools.nsc.util._
import scala.tools.nsc.io.VirtualDirectory
import scala.tools.nsc.reporters.ConsoleReporter
-import scala.tools.nsc.reporters.ConsoleReporter
-import scala.tools.nsc.reporters.ConsoleReporter
import scala.actors.Actor
import scala.actors.Actor._
@@ -55,7 +53,8 @@ class ScriptEngineFactory() extends Jav
MyScriptEngine.interpreterAction !
ScriptEngineFactory.RefreshInterpreter
}
- var factory: InterpreterFactory = null
+ private var factory: InterpreterFactory = null
+ private var compilerService: CompilerService = null
var _interpreter : Interpreter = null;
private var bundleContext: BundleContext = null
def interpreter = {
@@ -115,6 +114,14 @@ class ScriptEngineFactory() extends Jav
factory = null
_interpreter = null
}
+
+ def bindCompilerService(s: CompilerService) = {
+ compilerService = s
+ }
+
+ def unbindCompilerService(s: CompilerService) = {
+ compilerService = null
+ }
/** Inner object as it accesse interpreter
*/
object MyScriptEngine extends AbstractScriptEngine() with Compilable {
@@ -202,75 +209,48 @@ class ScriptEngineFactory() extends Jav
val virtualDirectory = new VirtualDirectory("(memory)", None)
var msgWriter = new StringWriter
- val classLoader = new AbstractFileClassLoader(virtualDirectory,
this.getClass.getClassLoader())
- //var classLoader = createClassLoader
-
- lazy val compiler = {
- AccessController.doPrivileged(new
PrivilegedAction[BundleContextScalaCompiler]() {
- override def run() = {
- val settings = new Settings
- settings.outputDirs setSingleOutput
virtualDirectory
- val out = new PrintWriter(System.out)
- new
BundleContextScalaCompiler(bundleContext, settings,
- new ConsoleReporter(settings,
null, out) {
- override def
printMessage(msg: String) {
- msgWriter write
msg
- //out.flush()
- }
- })
- }
- })
- }
override def compile(script: String): CompiledScript = {
try {
AccessController.doPrivileged(new
PrivilegedAction[CompiledScript]() {
- override def run() = {
+ override def run() = {
+ val objectName =
"CompiledScript"+classCounter
+ classCounter += 1
+ val classCode = "class " +
objectName + """ {
+ | def run($:
Map[String, Object]) = {
+ |""".stripMargin +
script +"""
+ | }
+ |}""".stripMargin
+ val sources:
List[Array[Char]] = List(classCode.toCharArray)
+ val clazz = try {
+
compilerService.compile(sources)(0)
+ } catch {
+ case e:
CompileErrorsException => throw new ScriptException(e.getMessage, "script", -1);
+ case e => throw e
+ }
+ val scriptObject =
clazz.newInstance()
- //inefficient but thread safe
- compiler.synchronized {
- val objectName =
"CompiledScript"+classCounter
- classCounter += 1
- val classCode = "class
" + objectName + """ {
- | def
run($: Map[String, Object]) = {
-
|""".stripMargin + script +"""
- | }
-
|}""".stripMargin
- val sources:
List[SourceFile] = List(new BatchSourceFile("<script>", classCode))
- (new
compiler.Run).compileSources(sources)
- if
(compiler.reporter.hasErrors) {
-
compiler.reporter.reset
- val msg =
msgWriter.toString
- msgWriter = new
StringWriter
- throw new
ScriptException(msg, "script", -1);
- }
- //val classBytes =
virtualDirectory.fileNamed(objectName+".class").toCharArray
- val clazz =
classLoader.loadClass(objectName)
- val scriptObject =
clazz.newInstance()
-
- new CompiledScript() {
-
- override def
eval(context: ScriptContext) = {
-
- var map
= Map[String, Object]()
- import
_root_.scala.collection.JavaConversions._
- for (
scope <- context.getScopes;
-
if (context.getBindings(scope.intValue) != null);
-
entry <- context.getBindings(scope.intValue)) {
-
map = map + (entry._1 -> entry._2)
- }
- val
runMethod = clazz.getMethod("run", classOf[Map[String, Object]])
- try {
-
runMethod.invoke(scriptObject, map)
- } catch
{
-
case e: InvocationTargetException => {
-
throw e.getCause
-
}
+ new CompiledScript() {
+ override def
eval(context: ScriptContext) = {
+
+ var map =
Map[String, Object]()
+ import
_root_.scala.collection.JavaConversions._
+ for ( scope
<- context.getScopes;
+
if (context.getBindings(scope.intValue) != null);
+
entry <- context.getBindings(scope.intValue)) {
+ map =
map + (entry._1 -> entry._2)
+ }
+ val runMethod =
clazz.getMethod("run", classOf[Map[String, Object]])
+ try {
+
runMethod.invoke(scriptObject, map)
+ } catch {
+ case e:
InvocationTargetException => {
+
throw e.getCause
}
}
- override def
getEngine = MyScriptEngine.this
}
+ override def getEngine
= MyScriptEngine.this
}
}
})
Modified:
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/TrackingCompiler.scala
URL:
http://svn.apache.org/viewvc/incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/TrackingCompiler.scala?rev=1036963&r1=1036962&r2=1036963&view=diff
==============================================================================
---
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/TrackingCompiler.scala
(original)
+++
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/TrackingCompiler.scala
Fri Nov 19 18:05:01 2010
@@ -35,6 +35,7 @@ import java.io.ByteArrayOutputStream
import java.io.PrintWriter
import java.net._
+
/** a compiler that keeps track of classes added to the directory
*/
class TrackingCompiler private (bundleContext : BundleContext,
@@ -47,13 +48,14 @@ class TrackingCompiler private (bundleCo
/**
* compiles a list of class sources returning a list of compiled classes
*/
+ @throws(classOf[CompileErrorsException])
def compile(sources: List[Array[Char]]): List[Class[_]] = {
writtenClasses.clear()
val sourceFiles: List[SourceFile] = for(chars <- sources) yield
new BatchSourceFile("<script>", chars)
(new Run).compileSources(sourceFiles)
if (reporter.hasErrors) {
reporter.reset
- throw new RuntimeException("compile errors, see
output");
+ throw new CompileErrorsException;
}
val classLoader = new AbstractFileClassLoader(outputDirectory,
this.getClass.getClassLoader())
val result: List[Class[_]] = for (classFile <-
writtenClasses.toList;
@@ -101,7 +103,7 @@ object TrackingCompiler {
}
new TrackingCompiler(bundleContext,
settings,
- new ConsoleReporter(null, null, out) {
+ new ConsoleReporter(settings, null, out) {
override def printMessage(msg: String) {
out write msg
out.flush()
Modified:
incubator/clerezza/trunk/scala-scripting/tests/src/test/scala/org/apache/clerezza/scala/tests/CompilerServiceTest.scala
URL:
http://svn.apache.org/viewvc/incubator/clerezza/trunk/scala-scripting/tests/src/test/scala/org/apache/clerezza/scala/tests/CompilerServiceTest.scala?rev=1036963&r1=1036962&r2=1036963&view=diff
==============================================================================
---
incubator/clerezza/trunk/scala-scripting/tests/src/test/scala/org/apache/clerezza/scala/tests/CompilerServiceTest.scala
(original)
+++
incubator/clerezza/trunk/scala-scripting/tests/src/test/scala/org/apache/clerezza/scala/tests/CompilerServiceTest.scala
Fri Nov 19 18:05:01 2010
@@ -33,8 +33,6 @@ import org.junit.Before;
import org.junit.Test;
import org.ops4j.pax.exam.Inject;
import org.osgi.framework.BundleContext;
-import java.io.Reader
-import java.io.StringReader
import org.osgi.util.tracker.ServiceTracker
import scala.actors.Actor
import scala.math.random
@@ -73,27 +71,47 @@ class CompilerServiceTest {
@Test
def checkEngine(): Unit = {
-
- Assert.assertNotNull(service)
- val s = """
- package foo {
- class TestClass() {
- println("constructing TestClass");
+ Assert.assertNotNull(service);
+ //do it once
+ {
+ val s = """
+ package foo {
+ class TestClass() {
+ println("constructing TestClass");
+ }
+ object TestClass {
+ println("constructing TestClass
Object");
+ val msg = "Hello"
+ }
}
- object TestClass {
- println("constructing TestClass Object");
- val msg = "Hello"
+ """
+ val compileResult = service.compile(List(s.toCharArray))
+ println("finished compiling")
+ Assert.assertEquals(1, compileResult.size)
+ val testClassClass: Class[_] = compileResult(0)
+ Assert.assertEquals("foo.TestClass",
testClassClass.getName)
+ val method = testClassClass.getMethod("msg")
+ Assert.assertEquals("Hello", method.invoke(null))
+ }
+ //compile different class with same name
+ {
+ val s = """
+ package foo {
+ class TestClass() {
+ println("constructing a different
TestClass");
+ }
+ object TestClass {
+ println("constructing TestClass
Object");
+ val msg = "Hello2"
+ }
}
+ """
+ val compileResult = service.compile(List(s.toCharArray))
+ val testClassClass: Class[_] = compileResult(0)
+ Assert.assertEquals("foo.TestClass",
testClassClass.getName)
+ val method = testClassClass.getMethod("msg")
+ Assert.assertEquals("Hello2", method.invoke(null))
}
- """
- println("now compiling")
- val compileResult = service.compile(List(s.toCharArray))
- println("finished compiling")
- Assert.assertEquals(1, compileResult.size)
- val testClassClass: Class[_] = compileResult(0)
- Assert.assertEquals("foo.TestClass", testClassClass.getName)
- val method = testClassClass.getMethod("msg")
- Assert.assertEquals("Hello", method.invoke(null))
}
@Test
@@ -108,8 +126,9 @@ class CompilerServiceTest {
def act() {
try {
for (i <- 1 to iterationsCount)
{
- val objectName =
"C"+(for (i <-1 to 12) yield
((random*('z'-'a'+1))+'a').asInstanceOf[Char]).mkString
- val message = "Hello
from "+objectName
+ val uniqueToken = (for
(i <-1 to 12) yield ((random*('z'-'a'+1))+'a').asInstanceOf[Char]).mkString
+ val objectName =
"MyClass"
+ val message = "Hello
from "+uniqueToken
val source = """
object """+objectName+""" {