aboutsummaryrefslogblamecommitdiff
path: root/src/dotty/runtime/LazyVals.scala
blob: 38deec6f58ac54b888567b7d813d378eab3c6787 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13












                                                            
                                                                                             
                                                                         














































                                                                                                             



                                                                               



                          
                                                                                                           










                                                     
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"
  }
}