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