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: Int) = (cur >> (ord * BITS_PER_LAZY_VAL)) & LAZY_VAL_MASK
@inline def CAS(t: Object, offset: Long, e: Long, v: Int, 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) + */ // should be here, but #548
fieldId) % base
if (id < 0) id += base
monitors(id)
}
@inline def getOffset(clz: Class[_], name: String) = unsafe.objectFieldOffset(clz.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"
}
}