summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2012-08-17 11:44:24 +0200
committerGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2012-08-20 08:11:07 +0100
commitb2f8acda7586a992bfe2827e439e572eb42e917a (patch)
treeda15a341ba62a0e4290dca61b2bfe781d5dd6633 /src
parent76d8f8bb4ba97db10d836ed5c27525089991a122 (diff)
downloadscala-b2f8acda7586a992bfe2827e439e572eb42e917a.tar.gz
scala-b2f8acda7586a992bfe2827e439e572eb42e917a.tar.bz2
scala-b2f8acda7586a992bfe2827e439e572eb42e917a.zip
Rework synchronization scheme of `UndoLog` for performance.
Introduced explicit locking mechanism that allows us to make public methods of `UndoLog` that take thunks as arguments final and thus `@inline`. Once inliner is able to cope with inlining methods with exception handlers we'll be able to get rid of significant (around 5%) number of thunk allocation.
Diffstat (limited to 'src')
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala52
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedTypes.scala11
2 files changed, 42 insertions, 21 deletions
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index da92d5eb09..fcba682ad5 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -120,6 +120,21 @@ trait Types extends api.Types { self: SymbolTable =>
private type UndoPairs = List[(TypeVar, TypeConstraint)]
private var log: UndoPairs = List()
+ /*
+ * These two methods provide explicit locking mechanism that is overridden in SynchronizedUndoLog.
+ *
+ * The idea behind explicit locking mechanism is that all public methods that access mutable state
+ * will have to obtain the lock for their entire execution so both reads and writes can be kept in
+ * right order. Originally, that was achieved by overriding those public methods in
+ * `SynchronizedUndoLog` which was fine but expensive. The reason is that those public methods take
+ * thunk as argument and if we keep them non-final there's no way to make them inlined so thunks
+ * can go away.
+ *
+ * By using explicit locking we can achieve inlining.
+ */
+ protected def lock(): Unit = ()
+ protected def unlock(): Unit = ()
+
// register with the auto-clearing cache manager
perRunCaches.recordCache(this)
@@ -141,30 +156,41 @@ trait Types extends api.Types { self: SymbolTable =>
}
def clear() {
- if (settings.debug.value)
- self.log("Clearing " + log.size + " entries from the undoLog.")
-
- log = Nil
+ lock()
+ try {
+ if (settings.debug.value)
+ self.log("Clearing " + log.size + " entries from the undoLog.")
+ log = Nil
+ } finally unlock()
+ }
+ def size = {
+ lock()
+ try log.size finally unlock()
}
- def size = log.size
// `block` should not affect constraints on typevars
def undo[T](block: => T): T = {
- val before = log
+ lock()
+ try {
+ val before = log
- try block
- finally undoTo(before)
+ try block
+ finally undoTo(before)
+ } finally unlock()
}
// if `block` evaluates to false, it should not affect constraints on typevars
def undoUnless(block: => Boolean): Boolean = {
- val before = log
- var result = false
+ lock()
+ try {
+ val before = log
+ var result = false
- try result = block
- finally if (!result) undoTo(before)
+ try result = block
+ finally if (!result) undoTo(before)
- result
+ result
+ } finally unlock()
}
}
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
index e1eb7a57fe..334e821393 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
@@ -14,15 +14,10 @@ trait SynchronizedTypes extends internal.Types { self: SymbolTable =>
override def unique[T <: Type](tp: T): T = uniqueLock.synchronized { super.unique(tp) }
class SynchronizedUndoLog extends UndoLog {
+ private val actualLock = new java.util.concurrent.locks.ReentrantLock
- override def clear() =
- synchronized { super.clear() }
-
- override def undo[T](block: => T): T =
- synchronized { super.undo(block) }
-
- override def undoUnless(block: => Boolean): Boolean =
- synchronized { super.undoUnless(block) }
+ final override protected def lock(): Unit = actualLock.lock()
+ final override protected def unlock(): Unit = actualLock.unlock()
}
override protected def newUndoLog = new SynchronizedUndoLog