From 5cbd2fbc8409b446f8751792b006693e1d091055 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Fri, 14 Mar 2014 12:56:11 +0100 Subject: LazyVals phase. Creates accessors for lazy vals: 1) lazy local vals are rewritten to dotty.runtime.Lazy*** holders 2) for a non-volatile field lazy val create a non-thread-safe accessor and flag: 2.a) if lazy val type indicates that val is not nullable, uses null value as a flag 2.b) else uses boolean flag for sake of performance, method size, and allowing more jvm optimizations 3) for a volatile field lazy val use double locking scheme, that guaranties no spurious deadlocks, using long bits as bitmaps and creating companion objects to store offsets needed for unsafe methods. Conflicts: test/dotc/tests.scala --- src/dotty/runtime/LazyVals.scala | 79 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/dotty/runtime/LazyVals.scala (limited to 'src/dotty/runtime/LazyVals.scala') diff --git a/src/dotty/runtime/LazyVals.scala b/src/dotty/runtime/LazyVals.scala new file mode 100644 index 000000000..4130d4d60 --- /dev/null +++ b/src/dotty/runtime/LazyVals.scala @@ -0,0 +1,79 @@ +package dotty.runtime + +import scala.annotation.tailrec + +/** + * Helper methods used in thread-safe lazy vals. + */ +object LazyVals { + private val unsafe = scala.concurrent.util.Unsafe.instance + + final val BITS_PER_LAZY_VAL = 2 + final val LAZY_VAL_MASK = 3 + + @inline def STATE(cur: Long, ord: Long) = (cur >> (ord * BITS_PER_LAZY_VAL)) & LAZY_VAL_MASK + @inline def CAS(t: Object, offset: Long, e: Long, v: Long, ord: Int) = { + val mask = ~(LAZY_VAL_MASK << ord * BITS_PER_LAZY_VAL) + val n = (e & mask) | (v << (ord * BITS_PER_LAZY_VAL)) + compareAndSet(t, offset, e, n) + } + @inline def setFlag(t: Object, offset: Long, v: Int, ord: Int) = { + var retry = true + while (retry) { + val cur = get(t, offset) + if (STATE(cur, ord) == 1) retry = CAS(t, offset, cur, v, ord) + else { + // cur == 2, somebody is waiting on monitor + if (CAS(t, offset, cur, v, ord)) { + val monitor = getMonitor(t, ord) + monitor.synchronized { + monitor.notifyAll() + } + retry = false + } + } + } + } + @inline def wait4Notification(t: Object, offset: Long, cur: Long, ord: Int) = { + var retry = true + while (retry) { + val cur = get(t, offset) + val state = STATE(cur, ord) + if (state == 1) CAS(t, offset, cur, 2, ord) + else if (state == 2) { + val monitor = getMonitor(t, ord) + monitor.synchronized { + monitor.wait() + } + } + else retry = false + } + } + + @inline def compareAndSet(t: Object, off: Long, e: Long, v: Long) = unsafe.compareAndSwapLong(t, off, e, v) + @inline def get(t: Object, off: Long) = unsafe.getLongVolatile(t, off) + + val processors: Int = java.lang.Runtime.getRuntime.availableProcessors() + val base: Int = 8 * processors * processors + val monitors: Array[Object] = (0 to base).map { + x => new Object() + }.toArray + + @inline def getMonitor(obj: Object, fieldId: Int = 0) = { + var id = (java.lang.System.identityHashCode(obj) + fieldId) % base + if (id < 0) id += base + monitors(id) + } + + @inline def getOffset(obj: Object, name: String) = unsafe.objectFieldOffset(obj.getClass.getDeclaredField(name)) + + object Names { + final val state = "STATE" + final val cas = "CAS" + final val setFlag = "setFlag" + final val wait4Notification = "wait4Notification" + final val compareAndSet = "compareAndSet" + final val get = "get" + final val getOffset = "getOffset" + } +} -- cgit v1.2.3