From 7a1dc55abe5c50dae3c7a0990f852c40408454e7 Mon Sep 17 00:00:00 2001 From: Iulian Dragos Date: Wed, 29 Jun 2011 10:27:23 +0000 Subject: Check that 'info' is only called on the present... Check that 'info' is only called on the presentation compiler thread. This is a temporary debugging option for the presentation compiler. no review. --- .../scala/reflect/internal/SymbolTable.scala | 4 +++ src/compiler/scala/reflect/internal/Symbols.scala | 3 ++ src/compiler/scala/reflect/internal/Types.scala | 1 + .../scala/tools/nsc/interactive/Global.scala | 36 +++++++++++++++++----- 4 files changed, 36 insertions(+), 8 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala index 5c4d44f735..dd0994a1f6 100644 --- a/src/compiler/scala/reflect/internal/SymbolTable.scala +++ b/src/compiler/scala/reflect/internal/SymbolTable.scala @@ -31,6 +31,10 @@ abstract class SymbolTable extends /*reflect.generic.Universe def abort(msg: String): Nothing = throw new Error(msg) def abort(): Nothing = throw new Error() + /** Check that the executing thread is the compiler thread. No-op here, + * overridden in interactive.Global. */ + def assertCorrectThread() {} + /** Are we compiling for Java SE? */ // def forJVM: Boolean diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index ff3677c104..2b04f479ed 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -778,6 +778,7 @@ trait Symbols /* extends reflect.generic.Symbols*/ { self: SymbolTable => } val current = phase try { + assertCorrectThread() phase = phaseOf(infos.validFrom) tp.complete(this) } finally { @@ -828,11 +829,13 @@ trait Symbols /* extends reflect.generic.Symbols*/ { self: SymbolTable => val curPid = phaseId(curPeriod) if (validTo != NoPeriod) { + // skip any infos that concern later phases while (curPid < phaseId(infos.validFrom) && infos.prev != null) infos = infos.prev if (validTo < curPeriod) { + assertCorrectThread() // adapt any infos that come from previous runs val current = phase try { diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index f0497ca37d..0080cc98fc 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -107,6 +107,7 @@ trait Types /*extends reflect.generic.Types*/ { self: SymbolTable => /** Undo all changes to constraints to type variables upto `limit`. */ private def undoTo(limit: UndoLog) { + assertCorrectThread() while ((log ne limit) && log.nonEmpty) { val (tv, constr) = log.head tv.constr = constr diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index af5b9a9882..d61edcc654 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -24,13 +24,17 @@ import symtab.Flags.{ACCESSOR, PARAMACCESSOR} /** 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 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 Picklers { import definitions._ @@ -386,7 +390,17 @@ 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) + */ + 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. */ @@ -968,6 +982,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 -- cgit v1.2.3