Skip to content

Commit b823132

Browse files
committed
Merge pull request scala#708 from dotty-staging/add/check-reentrant
Check that dotty is reentrant
2 parents 6561d4c + c7cc6d8 commit b823132

32 files changed

+254
-117
lines changed

src/dotty/tools/dotc/Bench.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import reporting.Reporter
1010

1111
object Bench extends Driver {
1212

13-
private var numRuns = 1
13+
@sharable private var numRuns = 1
1414

1515
def newCompiler(): Compiler = new Compiler
1616

src/dotty/tools/dotc/Compiler.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ class Compiler {
4040
List(new FrontEnd),
4141
List(new PostTyper),
4242
List(new Pickler),
43-
List(new FirstTransform),
43+
List(new FirstTransform,
44+
new CheckReentrant),
4445
List(new RefChecks,
4546
new ElimRepeated,
4647
new NormalizeFlags,

src/dotty/tools/dotc/Resident.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import scala.annotation.tailrec
2121
*
2222
* dotc> :q // quit
2323
*/
24-
object Resident extends Driver {
24+
class Resident extends Driver {
2525

2626
object residentCompiler extends Compiler
2727

src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ object desugar {
209209
else tdef
210210
}
211211

212-
private val synthetic = Modifiers(Synthetic)
212+
@sharable private val synthetic = Modifiers(Synthetic)
213213

214214
private def toDefParam(tparam: TypeDef): TypeDef =
215215
tparam.withFlags(Param)

src/dotty/tools/dotc/ast/Trees.scala

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
package dotty.tools.dotc
1+
package dotty.tools
2+
package dotc
23
package ast
34

45
import core._
@@ -26,7 +27,7 @@ object Trees {
2627
type Untyped = Null
2728

2829
/** The total number of created tree nodes, maintained if Stats.enabled */
29-
var ntrees = 0
30+
@sharable var ntrees = 0
3031

3132
/** Modifiers and annotations for definitions
3233
* @param flags The set flags
@@ -68,7 +69,7 @@ object Trees {
6869
def tokenPos: Seq[(Token, Position)] = ???
6970
}
7071

71-
private var nextId = 0 // for debugging
72+
@sharable private var nextId = 0 // for debugging
7273

7374
type LazyTree = AnyRef /* really: Tree | Lazy[Tree] */
7475
type LazyTreeList = AnyRef /* really: List[Tree] | Lazy[List[Tree]] */
@@ -723,9 +724,9 @@ object Trees {
723724
setMods(Modifiers[T](PrivateLocal))
724725
}
725726

726-
val theEmptyTree: Thicket[Type] = Thicket(Nil)
727-
val theEmptyValDef = new EmptyValDef[Type]
728-
val theEmptyModifiers = new Modifiers()
727+
@sharable val theEmptyTree: Thicket[Type] = Thicket(Nil)
728+
@sharable val theEmptyValDef = new EmptyValDef[Type]
729+
@sharable val theEmptyModifiers = new Modifiers()
729730

730731
def genericEmptyValDef[T >: Untyped]: ValDef[T] = theEmptyValDef.asInstanceOf[ValDef[T]]
731732
def genericEmptyTree[T >: Untyped]: Thicket[T] = theEmptyTree.asInstanceOf[Thicket[T]]
@@ -845,9 +846,9 @@ object Trees {
845846
type Annotated = Trees.Annotated[T]
846847
type Thicket = Trees.Thicket[T]
847848

848-
val EmptyTree: Thicket = genericEmptyTree
849-
val EmptyValDef: ValDef = genericEmptyValDef
850-
val EmptyModifiers: Modifiers = genericEmptyModifiers
849+
@sharable val EmptyTree: Thicket = genericEmptyTree
850+
@sharable val EmptyValDef: ValDef = genericEmptyValDef
851+
@sharable val EmptyModifiers: Modifiers = genericEmptyModifiers
851852

852853
// ----- Auxiliary creation methods ------------------
853854

src/dotty/tools/dotc/config/Properties.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ object Properties extends PropertiesTrait {
1212

1313
/** Scala manifest attributes.
1414
*/
15-
val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
15+
@sharable val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
1616
}
1717

1818
trait PropertiesTrait {
@@ -23,7 +23,7 @@ trait PropertiesTrait {
2323
protected val propFilename = "/" + propCategory + ".properties"
2424

2525
/** The loaded properties */
26-
protected lazy val scalaProps: java.util.Properties = {
26+
@sharable protected lazy val scalaProps: java.util.Properties = {
2727
val props = new java.util.Properties
2828
val stream = pickJarBasedOn getResourceAsStream propFilename
2929
if (stream ne null)

src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ class ScalaSettings extends Settings.SettingGroup {
151151
val YnoDeepSubtypes = BooleanSetting("-Yno-deep-subtypes", "throw an exception on deep subtyping call stacks.")
152152
val YprintSyms = BooleanSetting("-Yprint-syms", "when printing trees print info in symbols instead of corresponding info in trees.")
153153
val YtestPickler = BooleanSetting("-Ytest-pickler", "self-test for pickling functionality; should be used with -Ystop-after:pickler")
154+
val YcheckReentrant = BooleanSetting("-Ycheck-reentrant", "check that compiled program does not contain vars that can be accessed from a global root.")
154155
def stop = YstopAfter
155156

156157
/** Area-specific debug output.

src/dotty/tools/dotc/config/ScalaVersion.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* @author James Iry
22
*/
3-
package dotty.tools.dotc.config
3+
package dotty.tools
4+
package dotc.config
45

56
import scala.util.{Try, Success, Failure}
67

@@ -15,7 +16,7 @@ sealed abstract class ScalaVersion extends Ordered[ScalaVersion] {
1516
/**
1617
* A scala version that sorts higher than all actual versions
1718
*/
18-
case object NoScalaVersion extends ScalaVersion {
19+
@sharable case object NoScalaVersion extends ScalaVersion {
1920
def unparse = "none"
2021

2122
def compare(that: ScalaVersion): Int = that match {
@@ -52,7 +53,7 @@ case class SpecificScalaVersion(major: Int, minor: Int, rev: Int, build: ScalaBu
5253
/**
5354
* A Scala version that sorts lower than all actual versions
5455
*/
55-
case object AnyScalaVersion extends ScalaVersion {
56+
@sharable case object AnyScalaVersion extends ScalaVersion {
5657
def unparse = "any"
5758

5859
def compare(that: ScalaVersion): Int = that match {
@@ -64,7 +65,7 @@ case object AnyScalaVersion extends ScalaVersion {
6465
/**
6566
* Methods for parsing ScalaVersions
6667
*/
67-
object ScalaVersion {
68+
@sharable object ScalaVersion {
6869
private val dot = "\\."
6970
private val dash = "\\-"
7071
private def not(s:String) = s"[^${s}]"

src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import printing._
2828
import config.{Settings, ScalaSettings, Platform, JavaPlatform}
2929
import language.implicitConversions
3030
import DenotTransformers.DenotTransformer
31+
3132
object Contexts {
3233

3334
/** A context is passed basically everywhere in dotc.
@@ -473,7 +474,7 @@ object Contexts {
473474
gadt = new GADTMap(SimpleMap.Empty)
474475
}
475476

476-
object NoContext extends Context {
477+
@sharable object NoContext extends Context {
477478
lazy val base = unsupported("base")
478479
override val implicits: ContextualImplicits = new ContextualImplicits(Nil, null)(this)
479480
}
@@ -620,7 +621,7 @@ object Contexts {
620621
/** implicit conversion that injects all ContextBase members into a context */
621622
implicit def toBase(ctx: Context): ContextBase = ctx.base
622623

623-
val theBase = new ContextBase // !!! DEBUG, so that we can use a minimal context for reporting even in code that normally cannot access a context
624+
// @sharable val theBase = new ContextBase // !!! DEBUG, so that we can use a minimal context for reporting even in code that normally cannot access a context
624625
}
625626

626627
/** Info that changes on each compiler run */

src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ object Denotations {
556556
*/
557557
private def bringForward()(implicit ctx: Context): SingleDenotation = this match {
558558
case denot: SymDenotation if ctx.stillValid(denot) =>
559-
if (denot.exists) assert(ctx.runId > validFor.runId, s"denotation $denot invalid in run ${ctx.runId}. ValidFor: $validFor")
559+
assert(ctx.runId > validFor.runId, s"denotation $denot invalid in run ${ctx.runId}. ValidFor: $validFor")
560560
var d: SingleDenotation = denot
561561
do {
562562
d.validFor = Period(ctx.period.runId, d.validFor.firstPhaseId, d.validFor.lastPhaseId)
@@ -592,7 +592,9 @@ object Denotations {
592592
assert(false)
593593
}
594594

595-
if (valid.runId != currentPeriod.runId) initial.bringForward.current
595+
if (valid.runId != currentPeriod.runId)
596+
if (exists) initial.bringForward.current
597+
else this
596598
else {
597599
var cur = this
598600
if (currentPeriod.code > valid.code) {

src/dotty/tools/dotc/core/Flags.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ object Flags {
136136
private final val FirstNotPickledFlag = 48
137137
private final val MaxFlag = 63
138138

139-
private var flagName = Array.fill(64, 2)("")
139+
private val flagName = Array.fill(64, 2)("")
140140

141141
private def isDefinedAsFlag(idx: Int) = flagName(idx) exists (_.nonEmpty)
142142

src/dotty/tools/dotc/core/Names.scala

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
package dotty.tools.dotc
1+
package dotty.tools
2+
package dotc
23
package core
34

45
import scala.io.Codec
@@ -151,11 +152,13 @@ object Names {
151152
override def seq = toCollection(this)
152153
}
153154

154-
class TermName(val start: Int, val length: Int, private[Names] var next: TermName) extends Name {
155+
class TermName(val start: Int, val length: Int, @sharable private[Names] var next: TermName) extends Name {
156+
// `next` is @sharable because it is only modified in the synchronized block of termName.
155157
type ThisName = TermName
156158
def isTypeName = false
157159
def isTermName = true
158160

161+
@sharable // because it is only modified in the synchronized block of toTypeName.
159162
@volatile private[this] var _typeName: TypeName = null
160163

161164
def toTypeName: TypeName = {
@@ -200,44 +203,21 @@ object Names {
200203
private final val fillFactor = 0.7
201204

202205
/** Memory to store all names sequentially. */
206+
@sharable // because it's only mutated in synchronized block of termName
203207
private[dotty] var chrs: Array[Char] = new Array[Char](InitialNameSize)
204208

205209
/** The number of characters filled. */
210+
@sharable // because it's only mutated in synchronized block of termName
206211
private var nc = 0
207212

208213
/** Hashtable for finding term names quickly. */
214+
@sharable // because it's only mutated in synchronized block of termName
209215
private var table = new Array[TermName](InitialHashSize)
210216

211217
/** The number of defined names. */
218+
@sharable // because it's only mutated in synchronized block of termName
212219
private var size = 1
213220

214-
/** Make sure the capacity of the character array is at least `n` */
215-
private def ensureCapacity(n: Int) =
216-
if (n > chrs.length) {
217-
val newchrs = new Array[Char](chrs.length * 2)
218-
chrs.copyToArray(newchrs)
219-
chrs = newchrs
220-
}
221-
222-
/** Make sure the hash table is large enough for the given load factor */
223-
private def incTableSize() = {
224-
size += 1
225-
if (size.toDouble / table.size > fillFactor) {
226-
val oldTable = table
227-
table = new Array[TermName](table.size * 2)
228-
for (i <- 0 until oldTable.size) rehash(oldTable(i))
229-
}
230-
}
231-
232-
/** Rehash chain of names */
233-
private def rehash(name: TermName): Unit =
234-
if (name != null) {
235-
rehash(name.next)
236-
val h = hashValue(chrs, name.start, name.length) & (table.size - 1)
237-
name.next = table(h)
238-
table(h) = name
239-
}
240-
241221
/** The hash of a name made of from characters cs[offset..offset+len-1]. */
242222
private def hashValue(cs: Array[Char], offset: Int, len: Int): Int =
243223
if (len > 0)
@@ -257,24 +237,53 @@ object Names {
257237
i == len
258238
}
259239

260-
/** Enter characters into chrs array. */
261-
private def enterChars(cs: Array[Char], offset: Int, len: Int): Unit = {
262-
ensureCapacity(nc + len)
263-
var i = 0
264-
while (i < len) {
265-
chrs(nc + i) = cs(offset + i)
266-
i += 1
267-
}
268-
nc += len
269-
}
270-
271240
/** Create a term name from the characters in cs[offset..offset+len-1].
272241
* Assume they are already encoded.
273242
*/
274243
def termName(cs: Array[Char], offset: Int, len: Int): TermName = {
275244
util.Stats.record("termName")
276245
val h = hashValue(cs, offset, len) & (table.size - 1)
246+
277247
synchronized {
248+
249+
/** Make sure the capacity of the character array is at least `n` */
250+
def ensureCapacity(n: Int) =
251+
if (n > chrs.length) {
252+
val newchrs = new Array[Char](chrs.length * 2)
253+
chrs.copyToArray(newchrs)
254+
chrs = newchrs
255+
}
256+
257+
/** Enter characters into chrs array. */
258+
def enterChars(): Unit = {
259+
ensureCapacity(nc + len)
260+
var i = 0
261+
while (i < len) {
262+
chrs(nc + i) = cs(offset + i)
263+
i += 1
264+
}
265+
nc += len
266+
}
267+
268+
/** Rehash chain of names */
269+
def rehash(name: TermName): Unit =
270+
if (name != null) {
271+
rehash(name.next)
272+
val h = hashValue(chrs, name.start, name.length) & (table.size - 1)
273+
name.next = table(h)
274+
table(h) = name
275+
}
276+
277+
/** Make sure the hash table is large enough for the given load factor */
278+
def incTableSize() = {
279+
size += 1
280+
if (size.toDouble / table.size > fillFactor) {
281+
val oldTable = table
282+
table = new Array[TermName](table.size * 2)
283+
for (i <- 0 until oldTable.size) rehash(oldTable(i))
284+
}
285+
}
286+
278287
val next = table(h)
279288
var name = next
280289
while (name ne null) {
@@ -283,7 +292,7 @@ object Names {
283292
name = name.next
284293
}
285294
name = new TermName(nc, len, next)
286-
enterChars(cs, offset, len)
295+
enterChars()
287296
table(h) = name
288297
incTableSize()
289298
name

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
package dotty.tools.dotc
1+
package dotty.tools
2+
package dotc
23
package core
34

45
import Periods._, Contexts._, Symbols._, Denotations._, Names._, NameOps._, Annotations._
@@ -1713,8 +1714,8 @@ object SymDenotations {
17131714
validFor = Period.allInRun(NoRunId) // will be brought forward automatically
17141715
}
17151716

1716-
val NoDenotation = new NoDenotation
1717-
val NotDefinedHereDenotation = new NoDenotation
1717+
@sharable val NoDenotation = new NoDenotation
1718+
@sharable val NotDefinedHereDenotation = new NoDenotation
17181719

17191720
// ---- Completion --------------------------------------------------------
17201721

@@ -1757,7 +1758,7 @@ object SymDenotations {
17571758
val NoSymbolFn = (ctx: Context) => NoSymbol
17581759

17591760
/** A missing completer */
1760-
class NoCompleter extends LazyType {
1761+
@sharable class NoCompleter extends LazyType {
17611762
def complete(denot: SymDenotation)(implicit ctx: Context): Unit = unsupported("complete")
17621763
}
17631764

0 commit comments

Comments
 (0)