Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

SI-6616 Check that unsafe operations are only called on the presentat…

…ion compiler thread.

The method that checks the actual constraint is @elidable, expecting it to be used
for nightly builds but stripped-off in release builds. This way we don't lose any
performance, but 'fail-fast' in IDE nightlies.

This assumes that release builds will have at least `-Xelide-below ASSERTION`, but
this pull request does not do that.
  • Loading branch information...
commit 03aa7fc3904033f8d2f6f14a87574a03553b7c72 1 parent 9999183
Iulian Dragos dragos authored
41 src/compiler/scala/tools/nsc/interactive/Global.scala
View
@@ -20,18 +20,23 @@ import scala.tools.nsc.io.Pickler._
import scala.tools.nsc.typechecker.DivergentImplicit
import scala.annotation.tailrec
import symtab.Flags.{ACCESSOR, PARAMACCESSOR}
+import scala.annotation.elidable
import scala.language.implicitConversions
/** The main class of the presentation compiler in an interactive environment such as an IDE
*/
-class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
- extends scala.tools.nsc.Global(settings, _reporter)
- with CompilerControl
- with RangePositions
- with ContextTrees
- with RichCompilationUnits
- with ScratchPadMaker
- with Picklers {
+class Global(settings: Settings, _reporter: Reporter, projectName: String = "") extends {
+ /* Is the compiler initializing? Early def, so that the field is true during the
+ * execution of the super constructor.
+ */
+ private var initializing = true
+} with scala.tools.nsc.Global(settings, _reporter)
+ with CompilerControl
+ with RangePositions
+ with ContextTrees
+ with RichCompilationUnits
+ with ScratchPadMaker
+ with Picklers {
import definitions._
@@ -51,6 +56,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
import log.logreplay
debugLog("logger: " + log.getClass + " writing to " + (new java.io.File(logName)).getAbsolutePath)
debugLog("classpath: "+classPath)
+ Console.err.println("\n ======= CHECK THREAD ACCESS compiler build ========\n")
private var curTime = System.nanoTime
private def timeStep = {
@@ -433,7 +439,18 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
private var threadId = 0
/** The current presentation compiler runner */
- @volatile private[interactive] var compileRunner = newRunnerThread()
+ @volatile private[interactive] var compileRunner: Thread = newRunnerThread()
+
+ /** Check that the currenyly executing thread is the presentation compiler thread.
+ *
+ * Compiler initialization may happen on a different thread (signalled by globalPhase being NoPhase)
+ */
+ @elidable(elidable.WARNING)
+ override def assertCorrectThread() {
+ assert(initializing || (Thread.currentThread() eq compileRunner),
+ "Race condition detected: You are running a presentation compiler method outside the PC thread.[phase: %s]".format(globalPhase) +
+ " Please file a ticket with the current stack trace at https://www.assembla.com/spaces/scala-ide/support/tickets")
+ }
/** Create a new presentation compiler runner.
*/
@@ -1110,6 +1127,12 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
alt
}
}
+
+ /** The compiler has been initialized. Constructors are evaluated in textual order,
+ * so this is set to true only after all super constructors and the primary constructor
+ * have been executed.
+ */
+ initializing = false
}
object CancelException extends Exception
6 src/reflect/scala/reflect/internal/SymbolTable.scala
View
@@ -6,6 +6,7 @@
package scala.reflect
package internal
+import scala.annotation.elidable
import scala.collection.{ mutable, immutable }
import util._
@@ -107,6 +108,11 @@ abstract class SymbolTable extends macros.Universe
val global: SymbolTable.this.type = SymbolTable.this
} with util.TraceSymbolActivity
+ /** Check that the executing thread is the compiler thread. No-op here,
+ * overridden in interactive.Global. */
+ @elidable(elidable.WARNING)
+ def assertCorrectThread() {}
+
/** Are we compiling for Java SE? */
// def forJVM: Boolean
2  src/reflect/scala/reflect/internal/Symbols.scala
View
@@ -1213,6 +1213,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
val current = phase
try {
+ assertCorrectThread()
phase = phaseOf(infos.validFrom)
tp.complete(this)
} finally {
@@ -1283,6 +1284,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
infos = infos.prev
if (validTo < curPeriod) {
+ assertCorrectThread()
// adapt any infos that come from previous runs
val current = phase
try {
1  src/reflect/scala/reflect/internal/Types.scala
View
@@ -146,6 +146,7 @@ trait Types extends api.Types { self: SymbolTable =>
/** Undo all changes to constraints to type variables upto `limit`. */
//OPT this method is public so we can do `manual inlining`
def undoTo(limit: UndoPairs) {
+ assertCorrectThread()
while ((log ne limit) && log.nonEmpty) {
val (tv, constr) = log.head
tv.constr = constr
Please sign in to comment.
Something went wrong with that request. Please try again.