summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2011-01-21 15:02:37 +0000
committerMartin Odersky <odersky@gmail.com>2011-01-21 15:02:37 +0000
commit7cb70a411a8005cf9230f24b890330bce3894f9c (patch)
tree8422421e595f3399d161291c88c303cb85a089e6 /src
parente6167d9350b8f268379d0b4683400fb7950f0d13 (diff)
downloadscala-7cb70a411a8005cf9230f24b890330bce3894f9c.tar.gz
scala-7cb70a411a8005cf9230f24b890330bce3894f9c.tar.bz2
scala-7cb70a411a8005cf9230f24b890330bce3894f9c.zip
Better replays.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/interactive/CompilerControl.scala4
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Global.scala66
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Picklers.scala52
-rw-r--r--src/compiler/scala/tools/nsc/util/InterruptReq.scala2
4 files changed, 80 insertions, 44 deletions
diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
index f993d7c168..4a14bef96a 100644
--- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
+++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
@@ -48,7 +48,7 @@ trait CompilerControl { self: Global =>
override def toString = "dofirst "+source
}
- class AskLinkPosItem(sym: Symbol, val source: SourceFile, response: Response[Position]) extends WorkItem {
+ class AskLinkPosItem(val sym: Symbol, val source: SourceFile, response: Response[Position]) extends WorkItem {
def apply() = self.getLinkPos(sym, source, response)
override def toString = "linkpos "+sym+" in "+source
}
@@ -82,7 +82,7 @@ trait CompilerControl { self: Global =>
protected[interactive] val scheduler = new WorkScheduler
/** The compilation unit corresponding to a source file
- * if it does not yet exist creat a new one atomically
+ * if it does not yet exist create a new one atomically
*/
def unitOf(s: SourceFile): RichCompilationUnit = unitOfFile.synchronized {
unitOfFile get s.file match {
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index 6efe96861e..a0020272c4 100644
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -60,10 +60,6 @@ self =>
*/
var allSources: List[SourceFile] = List()
- /** The currently checked source file
- */
- var currentlyChecked: Option[RichCompilationUnit] = None
-
/** The currently active typer run */
private var currentTyperRun: TyperRun = _
newTyperRun()
@@ -115,21 +111,15 @@ self =>
try {
try {
pollForWork(old.pos)
- } catch {
+ } catch {
case ex : Throwable =>
- if (context.unit != null) integrateNew()
+ if (context.unit != null) integrateNew()
log.flush()
throw ex
- }
+ }
if (typerRun == currentTyperRun)
return
- // @Martin
- // Guard against NPEs in integrateNew if context.unit == null here.
- // But why are we doing this at all? If it was non-null previously
- // integrateNew will already have been called. If it was null previously
- // it will still be null now?
- // if (context.unit != null)
integrateNew()
throw FreshRunReq
} catch {
@@ -168,6 +158,8 @@ self =>
// ----------------- Polling ---------------------------------------
+ case class WorkEvent(atNode: Int, atMillis: Long)
+
var moreWorkAtNode: Int = -1
var nodesSeen = 0
var noWorkFoundAtNode: Int = -1
@@ -178,25 +170,13 @@ self =>
* Then, poll for work reload/typedTreeAt/doFirst commands during background checking.
*/
def pollForWork(pos: Position) {
- scheduler.pollInterrupt() match {
- case Some(ir) =>
- try {
- activeLocks += 1
- ir.execute()
- } finally {
- activeLocks -= 1
- }
- pollForWork(pos)
- case _ =>
- }
-
- def nodeWithWork(): Option[Int] = {
- if (scheduler.moreWork || pendingResponse.isCancelled) Some(nodesSeen) else None
- }
+ def nodeWithWork(): Option[WorkEvent] =
+ if (scheduler.moreWork || pendingResponse.isCancelled) Some(new WorkEvent(nodesSeen, System.currentTimeMillis))
+ else None
nodesSeen += 1
logreplay("atnode", nodeWithWork()) match {
- case Some(id) =>
+ case Some(WorkEvent(id, _)) =>
debugLog("some work at node "+id+" current = "+nodesSeen)
// assert(id >= nodesSeen)
moreWorkAtNode = id
@@ -204,6 +184,19 @@ self =>
}
if (nodesSeen >= moreWorkAtNode) {
+
+ logreplay("asked", scheduler.pollInterrupt()) match {
+ case Some(ir) =>
+ try {
+ activeLocks += 1
+ ir.execute()
+ } finally {
+ activeLocks -= 1
+ }
+ pollForWork(pos)
+ case _ =>
+ }
+
if (logreplay("cancelled", pendingResponse.isCancelled)) {
throw CancelException
}
@@ -296,6 +289,7 @@ self =>
for (s <- allSources) {
val unit = unitOf(s)
+ if (!unit.isUpToDate && unit.status != JustParsed) reset(unit) // reparse previously typechecked units.
if (unit.status == NotLoaded) parse(unit)
}
@@ -307,7 +301,7 @@ self =>
informIDE("Everything is now up to date")
}
- /** Reset unit to just-parsed state */
+ /** Reset unit to unloaded state */
def reset(unit: RichCompilationUnit): Unit = {
unit.depends.clear()
unit.defined.clear()
@@ -328,15 +322,13 @@ self =>
unit.status = JustParsed
}
- /** Make sure unit is typechecked with new typer run
+ /** Make sure unit is typechecked
*/
def typeCheck(unit: RichCompilationUnit) {
debugLog("type checking: "+unit)
- //if (currentlyChecked == Some(unit) || unit.status > JustParsed) reset(unit) // not deeded for idempotent type checker phase
if (unit.status == NotLoaded) parse(unit)
- currentlyChecked = Some(unit)
+ unit.status = PartiallyChecked
currentTyperRun.typeCheck(unit)
- currentlyChecked = None
unit.lastBody = unit.body
unit.status = currentRunId
}
@@ -361,7 +353,7 @@ self =>
/** Move list of files to front of allSources */
def moveToFront(fs: List[SourceFile]) {
- allSources = fs ++ (allSources diff fs)
+ allSources = fs ::: (allSources diff fs)
}
// ----------------- Implementations of client commands -----------------------
@@ -453,7 +445,7 @@ self =>
informIDE("typedTree" + source + " forceReload: " + forceReload)
val unit = unitOf(source)
if (forceReload) reset(unit)
- if (unit.status <= JustParsed) {
+ if (unit.status <= PartiallyChecked) {
//newTyperRun() // not deeded for idempotent type checker phase
typeCheck(unit)
}
@@ -478,7 +470,7 @@ self =>
informIDE("getLastTyped" + source)
respond(response) {
val unit = unitOf(source)
- if (unit.status > JustParsed) unit.body
+ if (unit.status > PartiallyChecked) unit.body
else if (unit.lastBody ne EmptyTree) unit.lastBody
else typedTree(source, false)
}
diff --git a/src/compiler/scala/tools/nsc/interactive/Picklers.scala b/src/compiler/scala/tools/nsc/interactive/Picklers.scala
index e9f9a98eff..1239ec5003 100644
--- a/src/compiler/scala/tools/nsc/interactive/Picklers.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Picklers.scala
@@ -1,13 +1,14 @@
package scala.tools.nsc
package interactive
-import util.{SourceFile, BatchSourceFile}
+import util.{SourceFile, BatchSourceFile, InterruptReq}
import io.{AbstractFile, PlainFile}
import util.{Position, RangePosition, NoPosition, OffsetPosition, TransparentPosition, EmptyAction}
import io.{Pickler, CondPickler}
import io.Pickler._
import collection.mutable
+import mutable.ListBuffer
trait Picklers { self: Global =>
@@ -74,6 +75,50 @@ trait Picklers { self: Global =>
implicit lazy val position: Pickler[Position] = transparentPosition | rangePosition | offsetPosition | noPosition
+ implicit lazy val namePickler: Pickler[Name] =
+ pkl[String] .wrapped {
+ str => if ((str.length > 1) && (str endsWith "!")) newTypeName(str.init) else newTermName(str)
+ } {
+ name => if (name.isTypeName) name.toString+"!" else name.toString
+ }
+
+ implicit lazy val symPickler: Pickler[Symbol] = {
+ def ownerNames(sym: Symbol, buf: ListBuffer[Name]): ListBuffer[Name] = {
+ if (!sym.isRoot) {
+ ownerNames(sym.owner, buf)
+ buf += (if (sym.isModuleClass) sym.sourceModule else sym).name
+ if (!sym.isType && !sym.isStable) {
+ val sym1 = sym.owner.info.decl(sym.name)
+ if (sym1.isOverloaded) {
+ val index = sym1.alternatives.indexOf(sym)
+ assert(index >= 0, sym1+" not found in alternatives "+sym1.alternatives)
+ buf += index.toString
+ }
+ }
+ }
+ buf
+ }
+ def makeSymbol(root: Symbol, names: List[Name]): Symbol = names match {
+ case List() =>
+ root
+ case name :: rest =>
+ val sym = root.info.decl(name)
+ if (sym.isOverloaded) makeSymbol(sym.alternatives(rest.head.toString.toInt), rest.tail)
+ else makeSymbol(sym, rest)
+ }
+ pkl[List[Name]] .wrapped { makeSymbol(definitions.RootClass, _) } { ownerNames(_, new ListBuffer).toList }
+ }
+
+ implicit def workEvent: Pickler[WorkEvent] = {
+ (pkl[Int] ~ pkl[Long])
+ .wrapped { case id ~ ms => WorkEvent(id, ms) } { w => w.atNode ~ w.atMillis }
+ }
+
+ implicit def interruptReq: Pickler[InterruptReq] = {
+ val emptyIR: InterruptReq = new InterruptReq { type R = Unit; val todo = () => () }
+ pkl[Unit] .wrapped { _ => emptyIR } { _ => () }
+ }
+
implicit def reloadItem: CondPickler[ReloadItem] =
pkl[List[SourceFile]]
.wrapped { ReloadItem(_, new Response) } { _.sources }
@@ -109,10 +154,9 @@ trait Picklers { self: Global =>
.wrapped { new AskToDoFirstItem(_) } { _.source }
.asClass (classOf[AskToDoFirstItem])
- /** We cannot pickle symbols, so we return always RootClass */
implicit def askLinkPosItem: CondPickler[AskLinkPosItem] =
- pkl[SourceFile]
- .wrapped { new AskLinkPosItem(definitions.RootClass, _, new Response) } { _.source }
+ (pkl[Symbol] ~ pkl[SourceFile])
+ .wrapped { case sym ~ source => new AskLinkPosItem(sym, source, new Response) } { item => item.sym ~ item.source }
.asClass (classOf[AskLinkPosItem])
implicit def emptyAction: CondPickler[EmptyAction] =
diff --git a/src/compiler/scala/tools/nsc/util/InterruptReq.scala b/src/compiler/scala/tools/nsc/util/InterruptReq.scala
index b9efb1f406..342284fb70 100644
--- a/src/compiler/scala/tools/nsc/util/InterruptReq.scala
+++ b/src/compiler/scala/tools/nsc/util/InterruptReq.scala
@@ -28,7 +28,7 @@ abstract class InterruptReq {
def getResult(): R = synchronized {
while (result.isEmpty) {
try {
- wait()
+ wait()
} catch { case _ : InterruptedException => () }
}