@@ -8,6 +8,9 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable
8
8
9
9
// Names
10
10
11
+ // this lock isn't subsumed by the reflection GIL
12
+ // because there's no way newXXXName methods are going to call anything reflective
13
+ // therefore we don't have a danger of a deadlock from having a fine-grained lock for name creation
11
14
private lazy val nameLock = new Object
12
15
13
16
override def newTermName (s : String ): TermName = nameLock.synchronized { super .newTermName(s) }
@@ -16,20 +19,25 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable
16
19
// BaseTypeSeqs
17
20
18
21
override protected def newBaseTypeSeq (parents : List [Type ], elems : Array [Type ]) =
19
- new BaseTypeSeq (parents, elems) with SynchronizedBaseTypeSeq
22
+ // only need to synchronize BaseTypeSeqs if they contain refined types
23
+ if (elems.filter(_.isInstanceOf [RefinedType ]).nonEmpty) new BaseTypeSeq (parents, elems) with SynchronizedBaseTypeSeq
24
+ else new BaseTypeSeq (parents, elems)
20
25
21
26
trait SynchronizedBaseTypeSeq extends BaseTypeSeq {
22
- override def apply (i : Int ): Type = synchronized { super .apply(i) }
23
- override def rawElem (i : Int ) = synchronized { super .rawElem(i) }
24
- override def typeSymbol (i : Int ): Symbol = synchronized { super .typeSymbol(i) }
25
- override def toList : List [Type ] = synchronized { super .toList }
26
- override def copy (head : Type , offset : Int ): BaseTypeSeq = synchronized { super .copy(head, offset) }
27
- override def map (f : Type => Type ): BaseTypeSeq = synchronized { super .map(f) }
28
- override def exists (p : Type => Boolean ): Boolean = synchronized { super .exists(p) }
29
- override lazy val maxDepth = synchronized { maxDepthOfElems }
30
- override def toString = synchronized { super .toString }
31
-
32
- override def lateMap (f : Type => Type ): BaseTypeSeq = new MappedBaseTypeSeq (this , f) with SynchronizedBaseTypeSeq
27
+ override def apply (i : Int ): Type = gilSynchronized { super .apply(i) }
28
+ override def rawElem (i : Int ) = gilSynchronized { super .rawElem(i) }
29
+ override def typeSymbol (i : Int ): Symbol = gilSynchronized { super .typeSymbol(i) }
30
+ override def toList : List [Type ] = gilSynchronized { super .toList }
31
+ override def copy (head : Type , offset : Int ): BaseTypeSeq = gilSynchronized { super .copy(head, offset) }
32
+ override def map (f : Type => Type ): BaseTypeSeq = gilSynchronized { super .map(f) }
33
+ override def exists (p : Type => Boolean ): Boolean = gilSynchronized { super .exists(p) }
34
+ override lazy val maxDepth = gilSynchronized { maxDepthOfElems }
35
+ override def toString = gilSynchronized { super .toString }
36
+
37
+ override def lateMap (f : Type => Type ): BaseTypeSeq =
38
+ // only need to synchronize BaseTypeSeqs if they contain refined types
39
+ if (map(f).toList.filter(_.isInstanceOf [RefinedType ]).nonEmpty) new MappedBaseTypeSeq (this , f) with SynchronizedBaseTypeSeq
40
+ else new MappedBaseTypeSeq (this , f)
33
41
}
34
42
35
43
// Scopes
@@ -38,15 +46,19 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable
38
46
override def newNestedScope (outer : Scope ): Scope = new Scope (outer) with SynchronizedScope
39
47
40
48
trait SynchronizedScope extends Scope {
41
- override def isEmpty : Boolean = synchronized { super .isEmpty }
42
- override def size : Int = synchronized { super .size }
43
- override def enter [T <: Symbol ](sym : T ): T = synchronized { super .enter(sym) }
44
- override def rehash (sym : Symbol , newname : Name ) = synchronized { super .rehash(sym, newname) }
45
- override def unlink (e : ScopeEntry ) = synchronized { super .unlink(e) }
46
- override def unlink (sym : Symbol ) = synchronized { super .unlink(sym) }
47
- override def lookupAll (name : Name ) = synchronized { super .lookupAll(name) }
48
- override def lookupEntry (name : Name ) = synchronized { super .lookupEntry(name) }
49
- override def lookupNextEntry (entry : ScopeEntry ) = synchronized { super .lookupNextEntry(entry) }
50
- override def toList : List [Symbol ] = synchronized { super .toList }
49
+ // we can keep this lock fine-grained, because methods of Scope don't do anything extraordinary, which makes deadlocks impossible
50
+ // fancy subclasses of internal.Scopes#Scope should do synchronization themselves (e.g. see PackageScope for an example)
51
+ private lazy val syncLock = new Object
52
+ def syncLockSynchronized [T ](body : => T ): T = syncLock.synchronized { body }
53
+ override def isEmpty : Boolean = syncLockSynchronized { super .isEmpty }
54
+ override def size : Int = syncLockSynchronized { super .size }
55
+ override def enter [T <: Symbol ](sym : T ): T = syncLockSynchronized { super .enter(sym) }
56
+ override def rehash (sym : Symbol , newname : Name ) = syncLockSynchronized { super .rehash(sym, newname) }
57
+ override def unlink (e : ScopeEntry ) = syncLockSynchronized { super .unlink(e) }
58
+ override def unlink (sym : Symbol ) = syncLockSynchronized { super .unlink(sym) }
59
+ override def lookupAll (name : Name ) = syncLockSynchronized { super .lookupAll(name) }
60
+ override def lookupEntry (name : Name ) = syncLockSynchronized { super .lookupEntry(name) }
61
+ override def lookupNextEntry (entry : ScopeEntry ) = syncLockSynchronized { super .lookupNextEntry(entry) }
62
+ override def toList : List [Symbol ] = syncLockSynchronized { super .toList }
51
63
}
52
64
}
0 commit comments