diff options
author | Grzegorz Kossakowski <grzegorz.kossakowski@gmail.com> | 2012-08-17 11:44:24 +0200 |
---|---|---|
committer | Grzegorz Kossakowski <grzegorz.kossakowski@gmail.com> | 2012-08-20 08:11:07 +0100 |
commit | b2f8acda7586a992bfe2827e439e572eb42e917a (patch) | |
tree | da15a341ba62a0e4290dca61b2bfe781d5dd6633 | |
parent | 76d8f8bb4ba97db10d836ed5c27525089991a122 (diff) | |
download | scala-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.
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 52 | ||||
-rw-r--r-- | src/reflect/scala/reflect/runtime/SynchronizedTypes.scala | 11 |
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 |