diff options
author | Paul Phillips <paulp@improving.org> | 2011-08-23 22:57:15 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2011-08-23 22:57:15 +0000 |
commit | 0e74720c491ce13e5e904e0bc39e9a60af26f37c (patch) | |
tree | 739584c007c30a6b1974a42674bb1e9b5aa4c721 | |
parent | 3a1463cd833175bdaa7a31d96a41a0d926b0e9db (diff) | |
download | scala-0e74720c491ce13e5e904e0bc39e9a60af26f37c.tar.gz scala-0e74720c491ce13e5e904e0bc39e9a60af26f37c.tar.bz2 scala-0e74720c491ce13e5e904e0bc39e9a60af26f37c.zip |
Some 11th hour modifications with the dual purp...
Some 11th hour modifications with the dual purpose of a smooth console
life for sbt and so the repl can be used on google app engine. Although
this patch may look largish to be entering at RC4, there isn't a lot
going on. It's trying to make these dangerous things:
- property and environment variable accesses
- thread creation
- signal handler installation
happpen in a sufficiently uniform way that people who don't want them
and places who don't allow them are not left with an unfixable situation
where things blow up inside private methods. Also, the (ahem) lower than
usual elegance levels are due to it being intended for 2.9.x as well.
Review by harrah.
9 files changed, 96 insertions, 35 deletions
diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala index 9e59c1d509..9ba47c2d8b 100644 --- a/src/compiler/scala/reflect/internal/SymbolTable.scala +++ b/src/compiler/scala/reflect/internal/SymbolTable.scala @@ -119,7 +119,6 @@ abstract class SymbolTable extends api.Universe object perRunCaches { import java.lang.ref.WeakReference - import scala.tools.util.Signallable import scala.runtime.ScalaRunTime.stringOf // We can allow ourselves a structural type, these methods @@ -143,9 +142,9 @@ abstract class SymbolTable extends api.Universe )) } } - if (settings.debug.value) { - println(Signallable("dump compiler caches")(dumpCaches())) - } + // if (settings.debug.value) { + // println(Signallable("dump compiler caches")(dumpCaches())) + // } def recordCache[T <: Clearable](cache: T): T = { caches += new WeakReference(cache) diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala index 457a34f9dc..e9d36e0bdb 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala @@ -66,7 +66,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) // Install a signal handler so we can be prodded. private val signallable = - if (isReplDebug) Signallable("Dump repl state.")(dumpCommand()) + if (isReplDebug && !settings.Yreplsync.value) + Signallable("Dump repl state.")(dumpCommand()) else null // classpath entries added via :cp @@ -95,19 +96,21 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) override lazy val formatting = new Formatting { def prompt = ILoop.this.prompt } - override protected def createLineManager() = new Line.Manager { - override def onRunaway(line: Line[_]): Unit = { - val template = """ - |// She's gone rogue, captain! Have to take her out! - |// Calling Thread.stop on runaway %s with offending code: - |// scala> %s""".stripMargin - - echo(template.format(line.thread, line.code)) - // XXX no way to suppress the deprecation warning - line.thread.stop() - in.redrawLine() + override protected def createLineManager(): Line.Manager = + if (ReplPropsKludge.noThreadCreation(settings)) null else new Line.Manager { + override def onRunaway(line: Line[_]): Unit = { + val template = """ + |// She's gone rogue, captain! Have to take her out! + |// Calling Thread.stop on runaway %s with offending code: + |// scala> %s""".stripMargin + + echo(template.format(line.thread, line.code)) + // XXX no way to suppress the deprecation warning + line.thread.stop() + in.redrawLine() + } } - } + override protected def parentClassLoader = settings.explicitParentLoader.getOrElse( classOf[ILoop].getClassLoader ) } diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala b/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala index a9c092861f..6ebe3f7362 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala @@ -47,7 +47,7 @@ trait ILoopInit { } ignoring(classOf[Exception]) { SignalManager("INT") = { - if (intp == null) + if (intp == null || intp.lineManager == null) onExit() else if (intp.lineManager.running) intp.lineManager.cancel() diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index 0a5104f824..9d042f2401 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -265,7 +265,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends /** Create a line manager. Overridable. */ protected def createLineManager(): Line.Manager = - if (replProps.noThreads) null else new Line.Manager + if (ReplPropsKludge.noThreadCreation(settings)) null else new Line.Manager /** Instantiate a compiler. Overridable. */ protected def newCompiler(settings: Settings, reporter: Reporter) = { @@ -967,7 +967,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends /** load and run the code using reflection */ def loadAndRun: (String, Boolean) = { - if (replProps.noThreads) return { + if (lineManager == null) return { try { ("" + (lineRep call sessionNames.print), true) } catch { case ex => (lineRep.bindError(ex), false) } } diff --git a/src/compiler/scala/tools/nsc/interpreter/ReplProps.scala b/src/compiler/scala/tools/nsc/interpreter/ReplProps.scala index 72bfb2eeff..99489b7c99 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ReplProps.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ReplProps.scala @@ -24,3 +24,9 @@ class ReplProps { val powerInitCode = Prop[JFile]("scala.repl.power.initcode") val powerBanner = Prop[JFile]("scala.repl.power.banner") } + +object ReplPropsKludge { + // !!! short term binary compatibility hack for 2.9.1 to put this + // here - needed a not previously existing object. + def noThreadCreation(settings: Settings) = replProps.noThreads || settings.Yreplsync.value +} diff --git a/src/compiler/scala/tools/reflect/WrappedProperties.scala b/src/compiler/scala/tools/reflect/WrappedProperties.scala new file mode 100644 index 0000000000..2ca374cf01 --- /dev/null +++ b/src/compiler/scala/tools/reflect/WrappedProperties.scala @@ -0,0 +1,39 @@ +/* NSC -- new Scala compiler + * Copyright 2006-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools +package reflect + +import scala.util.PropertiesTrait +import java.security.AccessControlException + +/** For placing a wrapper function around property functions. + * Motivated by places like google app engine throwing exceptions + * on property lookups. + */ +trait WrappedProperties extends PropertiesTrait { + def wrap[T](body: => T): Option[T] + + protected def propCategory = "wrapped" + protected def pickJarBasedOn = this.getClass + + override def propIsSet(name: String) = wrap(super.propIsSet(name)) exists (x => x) + override def propOrElse(name: String, alt: String) = wrap(super.propOrElse(name, alt)) getOrElse alt + override def setProp(name: String, value: String) = wrap(super.setProp(name, value)) orNull + override def clearProp(name: String) = wrap(super.clearProp(name)) orNull + override def envOrElse(name: String, alt: String) = wrap(super.envOrElse(name, alt)) getOrElse alt + override def envOrNone(name: String) = wrap(super.envOrNone(name)).flatten + + def systemProperties: Iterator[(String, String)] = { + import scala.collection.JavaConverters._ + wrap(System.getProperties.asScala.iterator) getOrElse Iterator.empty + } +} + +object WrappedProperties { + object AccessControl extends WrappedProperties { + def wrap[T](body: => T) = try Some(body) catch { case _: AccessControlException => None } + } +} diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala index 3ea5aa1703..c5d0e1edea 100644 --- a/src/compiler/scala/tools/util/PathResolver.scala +++ b/src/compiler/scala/tools/util/PathResolver.scala @@ -7,7 +7,7 @@ package scala.tools package util import java.net.{ URL, MalformedURLException } -import scala.util.Properties._ +import scala.tools.reflect.WrappedProperties.AccessControl import nsc.{ Settings, GenericRunnerSettings } import nsc.util.{ ClassPath, JavaClassPath, ScalaClassLoader } import nsc.io.{ File, Directory, Path, AbstractFile } @@ -18,6 +18,10 @@ import PartialFunction.condOpt // https://wiki.scala-lang.org/display/SW/Classpath object PathResolver { + // Imports property/environment functions which suppress + // security exceptions. + import AccessControl._ + def firstNonEmpty(xs: String*) = xs find (_ != "") getOrElse "" /** Map all classpath elements to absolute paths and reconstruct the classpath. @@ -34,10 +38,9 @@ object PathResolver { /** Values found solely by inspecting environment or property variables. */ object Environment { - private def searchForBootClasspath = { - import scala.collection.JavaConversions._ - System.getProperties find (_._1 endsWith ".boot.class.path") map (_._2) getOrElse "" - } + private def searchForBootClasspath = ( + systemProperties find (_._1 endsWith ".boot.class.path") map (_._2) getOrElse "" + ) /** Environment variables which java pays attention to so it * seems we do as well. diff --git a/src/compiler/scala/tools/util/Signallable.scala b/src/compiler/scala/tools/util/Signallable.scala index 2979e196e3..af98bfac83 100644 --- a/src/compiler/scala/tools/util/Signallable.scala +++ b/src/compiler/scala/tools/util/Signallable.scala @@ -6,11 +6,17 @@ package scala.tools package util +import java.security.AccessControlException + /** A class for things which are signallable. */ abstract class Signallable[T] private (val signal: String, val description: String) { private var last: Option[T] = None - private def lastString = last filterNot (_ == ()) map (_.toString) getOrElse "" + private def lastString = last match { + case Some(()) => "" + case Some(x) => "" + x + case _ => "" + } /** The most recent result from the signal handler. */ def lastResult: Option[T] = last @@ -29,8 +35,9 @@ abstract class Signallable[T] private (val signal: String, val description: Stri object Signallable { /** Same as the other apply, but an open signal is found for you. */ - def apply[T](description: String)(body: => T): Signallable[T] = + def apply[T](description: String)(body: => T): Signallable[T] = wrap { apply(SignalManager.findOpenSignal().name, description)(body) + } /** Given a signal name, a description, and a handler body, this * registers a signal handler and returns the Signallable instance. @@ -38,16 +45,21 @@ object Signallable { * SignalManager.info(), or sending SIGINFO to the manager will * dump it to console. */ - def apply[T](signal: String, description: String)(body: => T): Signallable[T] = { - val result = new Signallable[T](signal, description) { - def onSignal(): T = { + def apply[T](signal: String, description: String)(body: => T): Signallable[T] = wrap { + val result = create[T](signal, description, body) + SignalManager.public(signal, description)(result.onSignal()) + result + } + + private def wrap[T](body: => Signallable[T]): Signallable[T] = + try body catch { case _: AccessControlException => null } + + private def create[T](signal: String, description: String, body: => T): Signallable[T] = + new Signallable[T](signal, description) { + def onSignal = { val result = body last = Some(result) result } } - SignalManager.public(signal, description)(result.onSignal()) - result - } } - diff --git a/src/partest/scala/tools/partest/nest/DirectRunner.scala b/src/partest/scala/tools/partest/nest/DirectRunner.scala index 757f9bda1a..4246fce4c4 100644 --- a/src/partest/scala/tools/partest/nest/DirectRunner.scala +++ b/src/partest/scala/tools/partest/nest/DirectRunner.scala @@ -11,7 +11,6 @@ package nest import java.io.{ File } import java.util.StringTokenizer import scala.util.Properties.{ setProp } -import scala.tools.util.Signallable import scala.tools.nsc.util.ScalaClassLoader import scala.tools.nsc.io.Path import scala.collection.{ mutable, immutable } |