diff options
author | Paul Phillips <paulp@improving.org> | 2011-06-10 15:01:13 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2011-06-10 15:01:13 +0000 |
commit | 28e6744e2305f523d16458a9d8c748903e33aca5 (patch) | |
tree | 23ecfffb8c26dcb509e1bff21580b7dbf9403af3 /src/compiler | |
parent | 68808e80c4574e419a440c31d24ad206870e28b3 (diff) | |
download | scala-28e6744e2305f523d16458a9d8c748903e33aca5.tar.gz scala-28e6744e2305f523d16458a9d8c748903e33aca5.tar.bz2 scala-28e6744e2305f523d16458a9d8c748903e33aca5.zip |
A somewhat more realistic attempt to fix the bu...
A somewhat more realistic attempt to fix the build, no review. This
introduces a repl command line option -Yrepl-sync to inhibit the
asynchronous path which makes repl startup seem so snappy. And then it
uses it in the repl tests.
Diffstat (limited to 'src/compiler')
4 files changed, 57 insertions, 31 deletions
diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala index d4a15b6eb9..7f1066ec97 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala @@ -43,6 +43,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) var settings: Settings = _ var intp: IMain = _ + def isAsync = !settings.Yreplsync.value lazy val power = { val g = intp.global Power[g.type](this, g) @@ -530,8 +531,10 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } // return false if repl should exit def processLine(line: String): Boolean = { - awaitInitialized() - runThunks() + if (isAsync) { + awaitInitialized() + runThunks() + } if (line eq null) false // assume null means EOF else command(line) match { case Result(false, _) => false @@ -616,10 +619,10 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) if (isReplPower) "Already in power mode." else enablePowerMode(false) } - def enablePowerMode(isAsync: Boolean) = { + def enablePowerMode(isDuringInit: Boolean) = { replProps.power setValue true power.unleash() - if (isAsync) asyncMessage(power.banner) + if (isDuringInit) asyncMessage(power.banner) else echo(power.banner) } @@ -806,11 +809,18 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) // our best to look ready. The interlocking lazy vals tend to // inter-deadlock, so we break the cycle with a single asynchronous // message to an actor. - intp initialize initializedCallback() + if (isAsync) { + intp initialize initializedCallback() + createAsyncListener() // listens for signal to run postInitialization + } + else { + intp.initializeSynchronous() + postInitialization() + } printWelcome() try loop() - // catch AbstractOrMissingHandler() + catch AbstractOrMissingHandler() finally closeInterpreter() true diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala b/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala index a8fb619f97..f2171ad732 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala @@ -61,6 +61,10 @@ trait ILoopInit { } private val initLock = new java.util.concurrent.locks.ReentrantLock() + private val initCompilerCondition = initLock.newCondition() // signal the compiler is initialized + private val initLoopCondition = initLock.newCondition() // signal the whole repl is initialized + private val initStart = System.nanoTime + private def withLock[T](body: => T): T = { initLock.lock() try body @@ -68,41 +72,45 @@ trait ILoopInit { } // a condition used to ensure serial access to the compiler. @volatile private var initIsComplete = false - private val initCompilerCondition = initLock.newCondition() // signal the compiler is initialized - private val initLoopCondition = initLock.newCondition() // signal the whole repl is initialized - private val initStart = System.nanoTime private def elapsed() = "%.3f".format((System.nanoTime - initStart).toDouble / 1000000000L) - // Receives a single message once the interpreter is initialized. - private val initializedReactor = io.spawn { - withLock(initCompilerCondition.await()) - asyncMessage("[info] compiler init time: " + elapsed() + " s.") - postInitialization() - } - // the method to be called when the interpreter is initialized. // Very important this method does nothing synchronous (i.e. do // not try to use the interpreter) because until it returns, the // repl's lazy val `global` is still locked. protected def initializedCallback() = withLock(initCompilerCondition.signal()) + // Spins off a thread which awaits a single message once the interpreter + // has been initialized. + protected def createAsyncListener() = { + io.spawn { + withLock(initCompilerCondition.await()) + asyncMessage("[info] compiler init time: " + elapsed() + " s.") + postInitialization() + } + } + // called from main repl loop protected def awaitInitialized() { if (!initIsComplete) withLock { while (!initIsComplete) initLoopCondition.await() } } + protected def postInitThunks = List[Option[() => Unit]]( + Some(intp.setContextClassLoader _), + if (isReplPower) Some(() => enablePowerMode(true)) else None, + // do this last to avoid annoying uninterruptible startups + Some(installSigIntHandler _) + ).flatten // called once after init condition is signalled protected def postInitialization() { - addThunk(intp.setContextClassLoader()) - if (isReplPower) - addThunk(enablePowerMode(true)) - // do this last to avoid annoying uninterruptible startups - addThunk(installSigIntHandler()) - + postInitThunks foreach (f => addThunk(f())) runThunks() initIsComplete = true - asyncMessage("[info] total init time: " + elapsed() + " s.") - withLock(initLoopCondition.signal()) + + if (isAsync) { + asyncMessage("[info] total init time: " + elapsed() + " s.") + withLock(initLoopCondition.signal()) + } } // code to be executed only after the interpreter is initialized // and the lazy val `global` can be accessed without risk of deadlock. diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index f39cbd0d14..5c8679a93c 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -128,18 +128,25 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp result } } + def initializeSynchronous(): Unit = { + if (!isInitializeComplete) + _initialize() + } def isInitializeComplete = _initializeComplete /** the public, go through the future compiler */ lazy val global: Global = { - // If init hasn't been called yet you're on your own. - if (_isInitialized == null) { - repldbg("Warning: compiler accessed before init set up. Assuming no postInit code.") - initialize(()) + if (isInitializeComplete) _compiler + else { + // If init hasn't been called yet you're on your own. + if (_isInitialized == null) { + repldbg("Warning: compiler accessed before init set up. Assuming no postInit code.") + initialize(()) + } + // blocks until it is ; false means catastrophic failure + if (_isInitialized()) _compiler + else null } - // blocks until it is ; false means catastrophic failure - if (_isInitialized()) _compiler - else null } @deprecated("Use `global` for access to the compiler instance.", "2.9.0") lazy val compiler: global.type = global diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index b896883e38..2ab933f5ba 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -143,6 +143,7 @@ trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings { val Ytyperdebug = BooleanSetting ("-Ytyper-debug", "Trace all type assignments.") val Yinferdebug = BooleanSetting ("-Yinfer-debug", "Trace type inference and implicit search.") val Ypmatdebug = BooleanSetting ("-Ypmat-debug", "Trace all pattern matcher activity.") + val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup") val Yrepldebug = BooleanSetting ("-Yrepl-debug", "Trace all repl activity.") . withPostSetHook(_ => interpreter.replProps.debug setValue true) val Ycompletion = BooleanSetting ("-Ycompletion-debug", "Trace all tab completion activity.") |