summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2012-08-17 15:55:06 +0200
committerGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2012-08-20 08:11:09 +0100
commit82c61687d82deef42f317f8e26f89382bba2c6fa (patch)
treea93fe5d0986e6966b259723e7409889c0ad8c47c
parentc2aae3faa5bdb0bb8797ebcf951857e911e5c3f3 (diff)
downloadscala-82c61687d82deef42f317f8e26f89382bba2c6fa.tar.gz
scala-82c61687d82deef42f317f8e26f89382bba2c6fa.tar.bz2
scala-82c61687d82deef42f317f8e26f89382bba2c6fa.zip
Manaul inling of `UndoLog.undoUnless`.
Inline `UndoLog.undoUnless` into `isSubType` and `isSameType` methods. They are responsible for 20% of all Function0 allocations. I had to do manual inlining because inlier doesn't cope with exception handlers well. Let it be noted that I almost cried while doing this ugly change. I'll want to see inliner being fixed so we can revert this change ASAP.
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala92
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedTypes.scala4
2 files changed, 71 insertions, 25 deletions
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 78b595bc13..101097a32f 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -118,7 +118,8 @@ trait Types extends api.Types { self: SymbolTable =>
class UndoLog extends Clearable {
private type UndoPairs = List[(TypeVar, TypeConstraint)]
- private var log: UndoPairs = List()
+ //OPT this method is public so we can do `manual inlining`
+ var log: UndoPairs = List()
/*
* These two methods provide explicit locking mechanism that is overridden in SynchronizedUndoLog.
@@ -131,15 +132,20 @@ trait Types extends api.Types { self: SymbolTable =>
* can go away.
*
* By using explicit locking we can achieve inlining.
+ *
+ * NOTE: They are made public for now so we can apply 'manual inlining' (copy&pasting into hot
+ * places implementation of `undo` or `undoUnless`). This should be changed back to protected
+ * once inliner is fixed.
*/
- protected def lock(): Unit = ()
- protected def unlock(): Unit = ()
+ def lock(): Unit = ()
+ def unlock(): Unit = ()
// register with the auto-clearing cache manager
perRunCaches.recordCache(this)
/** Undo all changes to constraints to type variables upto `limit`. */
- private def undoTo(limit: UndoPairs) {
+ //OPT this method is public so we can do `manual inlining`
+ def undoTo(limit: UndoPairs) {
while ((log ne limit) && log.nonEmpty) {
val (tv, constr) = log.head
tv.constr = constr
@@ -5292,9 +5298,22 @@ trait Types extends api.Types { self: SymbolTable =>
def isSameType(tp1: Type, tp2: Type): Boolean = try {
Statistics.incCounter(sametypeCount)
subsametypeRecursions += 1
- undoLog undoUnless {
- isSameType1(tp1, tp2)
- }
+ //OPT cutdown on Function0 allocation
+ //was:
+// undoLog undoUnless {
+// isSameType1(tp1, tp2)
+// }
+
+ undoLog.lock()
+ try {
+ val before = undoLog.log
+ var result = false
+
+ try result = {
+ isSameType1(tp1, tp2)
+ } finally if (!result) undoLog.undoTo(before)
+ result
+ } finally undoLog.unlock()
} finally {
subsametypeRecursions -= 1
// XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866)
@@ -5645,22 +5664,49 @@ trait Types extends api.Types { self: SymbolTable =>
def isSubType(tp1: Type, tp2: Type, depth: Int): Boolean = try {
subsametypeRecursions += 1
- undoLog undoUnless { // if subtype test fails, it should not affect constraints on typevars
- if (subsametypeRecursions >= LogPendingSubTypesThreshold) {
- val p = new SubTypePair(tp1, tp2)
- if (pendingSubTypes(p))
- false
- else
- try {
- pendingSubTypes += p
- isSubType2(tp1, tp2, depth)
- } finally {
- pendingSubTypes -= p
- }
- } else {
- isSubType2(tp1, tp2, depth)
- }
- }
+ //OPT cutdown on Function0 allocation
+ //was:
+// undoLog undoUnless { // if subtype test fails, it should not affect constraints on typevars
+// if (subsametypeRecursions >= LogPendingSubTypesThreshold) {
+// val p = new SubTypePair(tp1, tp2)
+// if (pendingSubTypes(p))
+// false
+// else
+// try {
+// pendingSubTypes += p
+// isSubType2(tp1, tp2, depth)
+// } finally {
+// pendingSubTypes -= p
+// }
+// } else {
+// isSubType2(tp1, tp2, depth)
+// }
+// }
+
+ undoLog.lock()
+ try {
+ val before = undoLog.log
+ var result = false
+
+ try result = { // if subtype test fails, it should not affect constraints on typevars
+ if (subsametypeRecursions >= LogPendingSubTypesThreshold) {
+ val p = new SubTypePair(tp1, tp2)
+ if (pendingSubTypes(p))
+ false
+ else
+ try {
+ pendingSubTypes += p
+ isSubType2(tp1, tp2, depth)
+ } finally {
+ pendingSubTypes -= p
+ }
+ } else {
+ isSubType2(tp1, tp2, depth)
+ }
+ } finally if (!result) undoLog.undoTo(before)
+
+ result
+ } finally undoLog.unlock()
} finally {
subsametypeRecursions -= 1
// XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866)
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
index 334e821393..de029ca658 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
@@ -16,8 +16,8 @@ trait SynchronizedTypes extends internal.Types { self: SymbolTable =>
class SynchronizedUndoLog extends UndoLog {
private val actualLock = new java.util.concurrent.locks.ReentrantLock
- final override protected def lock(): Unit = actualLock.lock()
- final override protected def unlock(): Unit = actualLock.unlock()
+ final override def lock(): Unit = actualLock.lock()
+ final override def unlock(): Unit = actualLock.unlock()
}
override protected def newUndoLog = new SynchronizedUndoLog