GitLab will be upgraded to the 12.10.14-ce.0 on 28 Sept 2020 at 2.00pm (AEDT) to 2.30pm (AEDT). During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to us at N110 (b) CSIT building.

operationHelpers.scala 23.5 KB
Newer Older
Kunshan Wang's avatar
Kunshan Wang committed
1 2
package uvm.refimpl.itpr

3 4
import java.nio.charset.Charset

Kunshan Wang's avatar
Kunshan Wang committed
5
import uvm.refimpl._
6
import uvm.refimpl.mem.MemorySupport
7 8 9 10 11 12
import uvm.refimpl.mem.Mutator
import uvm.refimpl.mem.TypeSizes._
import uvm.refimpl.mem.TypeSizes
import uvm.ssavariables._
import uvm.ssavariables.AtomicRMWOptr._
import uvm.types._
Kunshan Wang's avatar
Kunshan Wang committed
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91

object OpHelper {

  val ONE = BigInt(1)

  def mask(n: Int): BigInt = {
    (ONE << n) - ONE
  }

  def truncFromBigInt(n: BigInt, len: Int): BigInt = n & mask(len)

  def zextToBigInt(n: BigInt, len: Int): BigInt = n & mask(len)

  def sextToBigInt(n: BigInt, len: Int): BigInt = {
    val bit = n.testBit(len - 1)
    if (bit) {
      n | (~mask(len - 1))
    } else {
      n & (mask(len - 1))
    }
  }

  def prepareUnsigned(n: BigInt, len: Int): BigInt = truncFromBigInt(n, len)

  def prepareSigned(n: BigInt, len: Int): BigInt = {
    sextToBigInt(truncFromBigInt(n, len), len)
  }

  def unprepare(n: BigInt, len: Int): BigInt = truncFromBigInt(n, len)

  def trunc(n: BigInt, toLen: Int): BigInt = truncFromBigInt(n, toLen)

  def zext(n: BigInt, fromLen: Int, toLen: Int): BigInt = truncFromBigInt(n, fromLen)

  def sext(n: BigInt, fromLen: Int, toLen: Int): BigInt = {
    truncFromBigInt(sextToBigInt(n, fromLen), toLen)
  }

  def maxSInt(l: Int): BigInt = (BigInt(1) << (l - 1)) - 1
  def minSIntAbs(l: Int): BigInt = BigInt(1) << (l - 1)
  def maxUInt(l: Int): BigInt = (BigInt(1) << l) - 1

  /**
   * Convert a float to an integer. The result only has the lowest iLen binary digits.
   */
  def floatToI(n: Float, iLen: Int, signed: Boolean): BigInt = {
    val lExp = Math.getExponent(n)
    val rExp = lExp - 23
    val frac = (java.lang.Float.floatToRawIntBits(n) & 0x7fffff) | 0x800000;

    if (java.lang.Float.isNaN(n)) 0
    else if (signed) {
      if (java.lang.Float.isInfinite(n)) { if (n > 0.0F) maxSInt(iLen) else minSIntAbs(iLen) }
      else {
        if (lExp >= (iLen - 1)) if (n > 0.0F) maxSInt(iLen) else minSIntAbs(iLen)
        else if (lExp < 0) 0
        else {
          val abs = BigInt(frac) << rExp
          unprepare(if (n < 0.0F) -abs else abs, iLen)
        }
      }
    } else {
      if (n < 0.0F) 0
      else if (java.lang.Float.isInfinite(n)) maxUInt(iLen)
      else {
        if (lExp >= iLen) maxUInt(iLen)
        else if (lExp < 0) 0
        else unprepare(BigInt(frac) << rExp, iLen)
      }
    }
  }

  /**
   * Convert a float to an integer. The result only has the lowest iLen binary digits.
   */
  def doubleToI(n: Double, iLen: Int, signed: Boolean): BigInt = {
    val lExp = Math.getExponent(n)
    val rExp = lExp - 52
    val frac = (java.lang.Double.doubleToRawLongBits(n) & 0xfffffffffffffL) | 0x10000000000000L;
92

Kunshan Wang's avatar
Kunshan Wang committed
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
    if (java.lang.Double.isNaN(n)) 0
    else if (signed) {
      if (java.lang.Double.isInfinite(n)) { if (n > 0.0D) maxSInt(iLen) else minSIntAbs(iLen) }
      else {
        if (lExp >= (iLen - 1)) if (n > 0.0D) maxSInt(iLen) else minSIntAbs(iLen)
        else if (lExp < 0) 0
        else {
          val abs = BigInt(frac) << rExp
          unprepare(if (n < 0.0D) -abs else abs, iLen)
        }
      }
    } else {
      if (n < 0.0D) 0
      else if (java.lang.Double.isInfinite(n)) maxUInt(iLen)
      else {
        if (lExp >= iLen) maxUInt(iLen)
        else if (lExp < 0) 0
        else unprepare(BigInt(frac) << rExp, iLen)
      }
    }
  }

  def tr64IsInt(opnd: Long): Boolean = {
    (opnd & 0x7ff0000000000001L) == 0x7ff0000000000001L
  }

  def tr64IsFp(opnd: Long): Boolean = {
    (opnd & 0x7ff0000000000001L) != 0x7ff0000000000001L &&
      (opnd & 0x7ff0000000000003L) != 0x7ff0000000000002L
  }

  def tr64IsRef(opnd: Long): Boolean = {
    (opnd & 0x7ff0000000000003L) == 0x7ff0000000000002L
  }

  def intToTr64(opnd: Long): Long = {
    (0x7ff0000000000001L | ((opnd & 0x7ffffffffffffL) << 1) |
      ((opnd & 0x8000000000000L) << 12))
  }

  def fpToTr64(opnd: Double): Long = {
    var bits = java.lang.Double.doubleToRawLongBits(opnd)
    if (java.lang.Double.isNaN(opnd)) {
      bits = bits & 0xfff8000000000000L | 0x0000000000000008L
    }
    bits
  }

  def refToTr64(opnd: Long, tag: Long): Long = {
    (0x7ff0000000000002L | (opnd & 0x7ffffffffff8L) | ((opnd & 0x800000000000L) << 16) |
      ((tag & 0x3eL) << 46) |
      ((tag & 0x1) << 2))
  }

  def tr64ToInt(opnd: Long): Long = {
    (((opnd & 0xffffffffffffeL) >> 1) | ((opnd & 0x8000000000000000L) >> 12) & (1L << 51))
  }

  def tr64ToFp(opnd: Long): Double = java.lang.Double.longBitsToDouble(opnd)

  def tr64ToRef(opnd: Long): Long = {
    ((opnd & 0x7ffffffffff8L) |
      (((~(((opnd & 0x8000000000000000L) << 1) - 1)) >> 17) &
        0xffff800000000000L))
  }

  def tr64ToTag(opnd: Long): Long = {
    (((opnd & 0x000f800000000000L) >> 46) | ((opnd & 0x4) >> 2))
  }
}

object PrimOpHelpers {
  @throws(classOf[UvmDivisionByZeroException])
  def intBinOp(op: BinOptr.BinOptr, l: Int, op1v: BigInt, op2v: BigInt, ctx: => String): BigInt = {
    def pu(v: BigInt): BigInt = OpHelper.prepareUnsigned(v, l)
    def ps(v: BigInt): BigInt = OpHelper.prepareSigned(v, l)
    def up(v: BigInt): BigInt = OpHelper.unprepare(v, l)
    def shiftMask = {
      var i = 1
      while (i < l) { i <<= 1 }
      i - 1
    }
    def checkDivByZero(): Unit = {
      if (op2v == 0) throw new UvmDivisionByZeroException(ctx + "Division by zero.")
    }

    up(op match {
180 181 182
      case BinOptr.ADD  => pu(op1v) + pu(op2v)
      case BinOptr.SUB  => pu(op1v) - pu(op2v)
      case BinOptr.MUL  => pu(op1v) * pu(op2v)
Kunshan Wang's avatar
Kunshan Wang committed
183 184 185 186
      case BinOptr.UDIV => { checkDivByZero(); pu(op1v) / pu(op2v) }
      case BinOptr.SDIV => { checkDivByZero(); ps(op1v) / ps(op2v) }
      case BinOptr.UREM => { checkDivByZero(); pu(op1v) % pu(op2v) }
      case BinOptr.SREM => { checkDivByZero(); ps(op1v) % ps(op2v) }
187
      case BinOptr.SHL  => pu(op1v) << (op2v.intValue & shiftMask)
Kunshan Wang's avatar
Kunshan Wang committed
188 189
      case BinOptr.LSHR => pu(op1v) >> (op2v.intValue & shiftMask)
      case BinOptr.ASHR => ps(op1v) >> (op2v.intValue & shiftMask)
190 191 192 193
      case BinOptr.AND  => pu(op1v) & pu(op2v)
      case BinOptr.OR   => pu(op1v) | pu(op2v)
      case BinOptr.XOR  => pu(op1v) ^ pu(op2v)
      case _            => throw new UvmRuntimeException(ctx + "Binary operator %s is not suitable for integer.".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
194 195 196 197 198 199 200 201 202 203
    })
  }

  def floatBinOp(op: BinOptr.BinOptr, op1v: Float, op2v: Float, ctx: => String): Float = {
    op match {
      case BinOptr.FADD => op1v + op2v
      case BinOptr.FSUB => op1v - op2v
      case BinOptr.FMUL => op1v * op2v
      case BinOptr.FDIV => op1v / op2v
      case BinOptr.FREM => Math.IEEEremainder(op1v, op2v).toFloat
204
      case _            => throw new UvmRuntimeException(ctx + "Binary operator %s is not suitable for float.".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
205 206 207 208 209 210 211 212 213 214
    }
  }

  def doubleBinOp(op: BinOptr.BinOptr, op1v: Double, op2v: Double, ctx: => String): Double = {
    op match {
      case BinOptr.FADD => op1v + op2v
      case BinOptr.FSUB => op1v - op2v
      case BinOptr.FMUL => op1v * op2v
      case BinOptr.FDIV => op1v / op2v
      case BinOptr.FREM => Math.IEEEremainder(op1v, op2v)
215
      case _            => throw new UvmRuntimeException(ctx + "Binary operator %s is not suitable for double.".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
216 217 218 219 220 221 222 223
    }
  }

  def intCmp(op: CmpOptr.CmpOptr, l: Int, op1v: BigInt, op2v: BigInt, ctx: => String): Boolean = {
    def pu(v: BigInt): BigInt = OpHelper.prepareUnsigned(v, l)
    def ps(v: BigInt): BigInt = OpHelper.prepareSigned(v, l)

    op match {
224 225
      case CmpOptr.EQ  => pu(op1v) == pu(op2v)
      case CmpOptr.NE  => pu(op1v) != pu(op2v)
Kunshan Wang's avatar
Kunshan Wang committed
226 227 228 229 230 231 232 233
      case CmpOptr.UGT => pu(op1v) > pu(op2v)
      case CmpOptr.UGE => pu(op1v) >= pu(op2v)
      case CmpOptr.ULT => pu(op1v) < pu(op2v)
      case CmpOptr.ULE => pu(op1v) <= pu(op2v)
      case CmpOptr.SGT => ps(op1v) > ps(op2v)
      case CmpOptr.SGE => ps(op1v) >= ps(op2v)
      case CmpOptr.SLT => ps(op1v) < ps(op2v)
      case CmpOptr.SLE => ps(op1v) <= ps(op2v)
234
      case _           => throw new UvmRuntimeException(ctx + "Comparison operator %s not suitable for integers".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
235 236 237 238 239 240 241 242
    }
  }

  def floatCmp(op: CmpOptr.CmpOptr, op1v: Float, op2v: Float, ctx: => String): Boolean = {
    import java.lang.Float.isNaN
    def ord = !isNaN(op1v) && !isNaN(op2v)
    def uno = isNaN(op1v) || isNaN(op2v)
    op match {
243
      case CmpOptr.FTRUE  => true
Kunshan Wang's avatar
Kunshan Wang committed
244
      case CmpOptr.FFALSE => false
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
      case CmpOptr.FOEQ   => ord && op1v == op2v
      case CmpOptr.FONE   => ord && op1v != op2v
      case CmpOptr.FOGT   => ord && op1v > op2v
      case CmpOptr.FOGE   => ord && op1v >= op2v
      case CmpOptr.FOLT   => ord && op1v < op2v
      case CmpOptr.FOLE   => ord && op1v <= op2v
      case CmpOptr.FORD   => ord
      case CmpOptr.FUEQ   => uno || op1v == op2v
      case CmpOptr.FUNE   => uno || op1v != op2v
      case CmpOptr.FUGT   => uno || op1v > op2v
      case CmpOptr.FUGE   => uno || op1v >= op2v
      case CmpOptr.FULT   => uno || op1v < op2v
      case CmpOptr.FULE   => uno || op1v <= op2v
      case CmpOptr.FUNO   => uno
      case _              => throw new UvmRuntimeException(ctx + "Comparison operator %s is not suitable for float.".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
260 261 262 263 264 265 266 267
    }
  }

  def doubleCmp(op: CmpOptr.CmpOptr, op1v: Double, op2v: Double, ctx: => String): Boolean = {
    import java.lang.Double.isNaN
    def ord = !isNaN(op1v) && !isNaN(op2v)
    def uno = isNaN(op1v) || isNaN(op2v)
    op match {
268
      case CmpOptr.FTRUE  => true
Kunshan Wang's avatar
Kunshan Wang committed
269
      case CmpOptr.FFALSE => false
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
      case CmpOptr.FOEQ   => ord && op1v == op2v
      case CmpOptr.FONE   => ord && op1v != op2v
      case CmpOptr.FOGT   => ord && op1v > op2v
      case CmpOptr.FOGE   => ord && op1v >= op2v
      case CmpOptr.FOLT   => ord && op1v < op2v
      case CmpOptr.FOLE   => ord && op1v <= op2v
      case CmpOptr.FORD   => ord
      case CmpOptr.FUEQ   => uno || op1v == op2v
      case CmpOptr.FUNE   => uno || op1v != op2v
      case CmpOptr.FUGT   => uno || op1v > op2v
      case CmpOptr.FUGE   => uno || op1v >= op2v
      case CmpOptr.FULT   => uno || op1v < op2v
      case CmpOptr.FULE   => uno || op1v <= op2v
      case CmpOptr.FUNO   => uno
      case _              => throw new UvmRuntimeException(ctx + "Comparison operator %s is not suitable for double.".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
285 286 287
    }
  }
}
Kunshan Wang's avatar
Kunshan Wang committed
288

289
object MemoryOperations {
290 291 292 293 294 295 296 297 298

  def addressOf(ptr: Boolean, vb: ValueBox): Word = {
    if (ptr) {
      vb.asInstanceOf[BoxPointer].addr
    } else {
      val lb = vb.asInstanceOf[BoxIRef]
      lb.objRef + lb.offset
    }
  }
299

300 301 302 303 304 305 306
  def noAccessViaPointer(ptr: Boolean, ty: Type) {
    if (ptr) {
      throw new UvmIllegalMemoryAccessException("Cannot access type %s via pointer".format(ty.repr))
    }
  }

  def load(ptr: Boolean, ty: Type, loc: Word, br: ValueBox)(implicit microVM: MicroVM, memorySupport: MemorySupport): Unit = {
307 308 309
    def loadScalar(ty: Type, loc: Word, br: ValueBox): Unit = ty match {
      case TypeInt(l) =>
        val bi: BigInt = l match {
310 311 312 313 314
          case 8  => memorySupport.loadByte(loc, !ptr)
          case 16 => memorySupport.loadShort(loc, !ptr)
          case 32 => memorySupport.loadInt(loc, !ptr)
          case 64 => memorySupport.loadLong(loc, !ptr)
          case _  => throw new UnimplementedOprationException("Loading int of length %d is not supported".format(l))
315 316 317
        }
        br.asInstanceOf[BoxInt].value = OpHelper.unprepare(bi, l)
      case _: TypeFloat =>
318
        val fv = memorySupport.loadFloat(loc, !ptr)
319 320
        br.asInstanceOf[BoxFloat].value = fv
      case _: TypeDouble =>
321
        val dv = memorySupport.loadDouble(loc, !ptr)
322 323
        br.asInstanceOf[BoxDouble].value = dv
      case _: TypeRef =>
324
        noAccessViaPointer(ptr, ty)
325
        val addr = memorySupport.loadLong(loc)
326 327
        br.asInstanceOf[BoxRef].objRef = addr
      case _: TypeIRef =>
328
        noAccessViaPointer(ptr, ty)
329 330
        val base = memorySupport.loadLong(loc)
        val offset = memorySupport.loadLong(loc + WORD_SIZE_BYTES)
331
        br.asInstanceOf[BoxIRef].oo = (base, offset)
332
      case _: TypeFuncRef =>
333
        noAccessViaPointer(ptr, ty)
334
        val fid = memorySupport.loadLong(loc).toInt
335 336
        val func = microVM.globalBundle.funcNs.get(fid)
        br.asInstanceOf[BoxFunc].func = func
337
      case _: TypeThreadRef =>
338
        noAccessViaPointer(ptr, ty)
339
        val tid = memorySupport.loadLong(loc).toInt
340 341
        val thr = microVM.threadStackManager.getThreadByID(tid)
        br.asInstanceOf[BoxThread].thread = thr
342
      case _: TypeStackRef =>
343
        noAccessViaPointer(ptr, ty)
344
        val sid = memorySupport.loadLong(loc).toInt
345 346 347
        val sta = microVM.threadStackManager.getStackByID(sid)
        br.asInstanceOf[BoxStack].stack = sta
      case _: TypeTagRef64 =>
348
        noAccessViaPointer(ptr, ty)
349
        val raw = memorySupport.loadLong(loc)
350
        br.asInstanceOf[BoxTagRef64].raw = raw
351
      case _: TypeUPtr | _: TypeUFuncPtr =>
352 353
        val addr = memorySupport.loadLong(loc, !ptr)
        br.asInstanceOf[BoxPointer].addr = addr
354 355 356 357 358
      case _ => throw new UnimplementedOprationException("Loading of type %s is not supporing".format(ty.getClass.getName))
    }

    ty match {
      case TypeVector(ety, len) =>
Kunshan Wang's avatar
Kunshan Wang committed
359
        val brs = br.asInstanceOf[BoxSeq].values
360 361 362 363 364 365 366 367
        val elemSkip = alignUp(sizeOf(ety), alignOf(ety))
        for ((brElem, i) <- brs.zipWithIndex) {
          loadScalar(ety, loc + elemSkip * i, brElem)
        }
      case sty => loadScalar(sty, loc, br)
    }
  }

Kunshan Wang's avatar
Kunshan Wang committed
368 369
  def store(ptr: Boolean, ty: Type, loc: Word, nvb: ValueBox)(implicit memorySupport: MemorySupport): Unit = {
    def storeScalar(ty: Type, loc: Word, nvb: ValueBox): Unit = ty match {
370 371 372
      case TypeInt(l) =>
        val bi = nvb.asInstanceOf[BoxInt].value
        l match {
373 374 375 376 377
          case 8  => memorySupport.storeByte(loc, bi.byteValue, !ptr)
          case 16 => memorySupport.storeShort(loc, bi.shortValue, !ptr)
          case 32 => memorySupport.storeInt(loc, bi.intValue, !ptr)
          case 64 => memorySupport.storeLong(loc, bi.longValue, !ptr)
          case _  => throw new UnimplementedOprationException("Storing int of length %d is not supported".format(l))
378 379 380
        }
      case _: TypeFloat =>
        val fv = nvb.asInstanceOf[BoxFloat].value
381
        memorySupport.storeFloat(loc, fv, !ptr)
382 383
      case _: TypeDouble =>
        val dv = nvb.asInstanceOf[BoxDouble].value
384
        memorySupport.storeDouble(loc, dv, !ptr)
385
      case _: TypeRef =>
386
        noAccessViaPointer(ptr, ty)
387
        val addr = nvb.asInstanceOf[BoxRef].objRef
388
        memorySupport.storeLong(loc, addr)
389
      case _: TypeIRef =>
390
        noAccessViaPointer(ptr, ty)
391
        val BoxIRef(base, offset) = nvb.asInstanceOf[BoxIRef]
392 393
        memorySupport.storeLong(loc, base)
        memorySupport.storeLong(loc + WORD_SIZE_BYTES, offset)
394
      case _: TypeFuncRef =>
395
        noAccessViaPointer(ptr, ty)
396
        val fid = nvb.asInstanceOf[BoxFunc].func.map(_.id).getOrElse(0)
397
        memorySupport.storeLong(loc, fid.toLong & 0xFFFFFFFFL)
398
      case _: TypeThreadRef =>
399
        noAccessViaPointer(ptr, ty)
400
        val tid = nvb.asInstanceOf[BoxThread].thread.map(_.id).getOrElse(0)
401
        memorySupport.storeLong(loc, tid.toLong & 0xFFFFFFFFL)
402
      case _: TypeStackRef =>
403
        noAccessViaPointer(ptr, ty)
404
        val sid = nvb.asInstanceOf[BoxStack].stack.map(_.id).getOrElse(0)
405
        memorySupport.storeLong(loc, sid.toLong & 0xFFFFFFFFL)
406
      case _: TypeTagRef64 =>
407
        noAccessViaPointer(ptr, ty)
408
        val raw = nvb.asInstanceOf[BoxTagRef64].raw
409
        memorySupport.storeLong(loc, raw)
410
      case _: TypeUPtr | _: TypeUFuncPtr =>
411 412
        val addr = nvb.asInstanceOf[BoxPointer].addr
        memorySupport.storeLong(loc, addr, !ptr)
413 414 415 416 417
      case _ => throw new UnimplementedOprationException("Storing of type %s is not supporing".format(ty.getClass.getName))
    }

    ty match {
      case TypeVector(ety, len) =>
Kunshan Wang's avatar
Kunshan Wang committed
418
        val nvbs = nvb.asInstanceOf[BoxSeq].values
419
        val elemSkip = alignUp(sizeOf(ety), alignOf(ety))
Kunshan Wang's avatar
Kunshan Wang committed
420 421
        for ((nvbElem, i) <- nvbs.zipWithIndex) {
          storeScalar(ety, loc + elemSkip * i, nvbElem)
422
        }
Kunshan Wang's avatar
Kunshan Wang committed
423
      case sty => storeScalar(sty, loc, nvb)
424 425 426 427 428 429
    }
  }

  /**
   * Compare exchange. The result (the old value) is written into br. Return true if successful, false otherwise.
   */
430
  def cmpXchg(ptr: Boolean, ty: Type, loc: Word, eb: ValueBox, db: ValueBox, br: ValueBox)(implicit microVM: MicroVM, memorySupport: MemorySupport): Boolean = {
431 432 433 434 435 436
    ty match {
      case TypeInt(l) =>
        val ebi = eb.asInstanceOf[BoxInt].value
        val dbi = db.asInstanceOf[BoxInt].value
        val (succ, rbi) = l match {
          case 32 => {
437
            val (succ2, rv) = memorySupport.cmpXchgInt(loc, ebi.intValue, dbi.intValue, !ptr)
438 439 440
            (succ2, BigInt(rv))
          }
          case 64 => {
441
            val (succ2, rv) = memorySupport.cmpXchgLong(loc, ebi.longValue, dbi.longValue, !ptr)
442 443 444 445 446 447 448
            (succ2, BigInt(rv))
          }
          case _ => throw new UnimplementedOprationException("CmpXchg on int of length %d is not supported".format(l))
        }
        br.asInstanceOf[BoxInt].value = OpHelper.unprepare(rbi, l)
        succ
      case _: TypeRef =>
449
        noAccessViaPointer(ptr, ty)
450 451
        val el = eb.asInstanceOf[BoxRef].objRef
        val dl = db.asInstanceOf[BoxRef].objRef
452
        val (succ, rl) = memorySupport.cmpXchgLong(loc, el, dl)
453 454 455
        br.asInstanceOf[BoxRef].objRef = rl
        succ
      case _: TypeIRef =>
456
        noAccessViaPointer(ptr, ty)
457 458
        val BoxIRef(el, eh) = eb.asInstanceOf[BoxIRef]
        val BoxIRef(dl, dh) = db.asInstanceOf[BoxIRef]
459
        val (succ, (rl, rh)) = memorySupport.cmpXchgI128(loc, (el, eh), (dl, dh))
460 461
        br.asInstanceOf[BoxIRef].oo = (rl, rh)
        succ
462
      case _: TypeFuncRef =>
463
        noAccessViaPointer(ptr, ty)
464 465
        val el = eb.asInstanceOf[BoxFunc].func.map(_.id).getOrElse(0).toLong
        val dl = db.asInstanceOf[BoxFunc].func.map(_.id).getOrElse(0).toLong
466
        val (succ, rl) = memorySupport.cmpXchgLong(loc, el, dl)
467 468 469
        val rf = microVM.globalBundle.funcNs.get(rl.toInt)
        br.asInstanceOf[BoxFunc].func = rf
        succ
470
      case _: TypeThreadRef =>
471
        noAccessViaPointer(ptr, ty)
472 473
        val el = eb.asInstanceOf[BoxThread].thread.map(_.id).getOrElse(0).toLong
        val dl = db.asInstanceOf[BoxThread].thread.map(_.id).getOrElse(0).toLong
474
        val (succ, rl) = memorySupport.cmpXchgLong(loc, el, dl)
475 476 477
        val rt = microVM.threadStackManager.getThreadByID(rl.toInt)
        br.asInstanceOf[BoxThread].thread = rt
        succ
478
      case _: TypeStackRef =>
479
        noAccessViaPointer(ptr, ty)
480 481
        val el = eb.asInstanceOf[BoxStack].stack.map(_.id).getOrElse(0).toLong
        val dl = db.asInstanceOf[BoxStack].stack.map(_.id).getOrElse(0).toLong
482
        val (succ, rl) = memorySupport.cmpXchgLong(loc, el, dl)
483 484 485
        val rs = microVM.threadStackManager.getStackByID(rl.toInt)
        br.asInstanceOf[BoxStack].stack = rs
        succ
486
      case _: TypeUPtr | _: TypeUFuncPtr =>
487 488 489 490 491
        val el = eb.asInstanceOf[BoxPointer].addr
        val dl = db.asInstanceOf[BoxPointer].addr
        val (succ, rl) = memorySupport.cmpXchgLong(loc, el, dl, !ptr)
        br.asInstanceOf[BoxPointer].addr = rl
        succ
492 493 494 495
      case _ => throw new UnimplementedOprationException("CmpXchg of type %s is not supporing".format(ty.getClass.getName))
    }
  }

496
  def atomicRMW(ptr: Boolean, ty: Type, op: AtomicRMWOptr, loc: Word, ob: ValueBox, br: ValueBox)(implicit microVM: MicroVM, memorySupport: MemorySupport): Unit = {
497 498 499 500
    ty match {
      case TypeInt(l) =>
        val obi = ob.asInstanceOf[BoxInt].value
        val rbi: BigInt = l match {
501 502 503
          case 32 => memorySupport.atomicRMWInt(op, loc, obi.intValue, !ptr)
          case 64 => memorySupport.atomicRMWLong(op, loc, obi.longValue, !ptr)
          case _  => throw new UnimplementedOprationException("AtomicRMW on int of length %d is not supported".format(l))
504 505 506 507 508 509 510 511
        }
        br.asInstanceOf[BoxInt].value = OpHelper.unprepare(rbi, l)
      case _ =>
        if (op != XCHG) {
          throw new UnimplementedOprationException("AtomicRMW operation other than XCHG only supports int. %s found.".format(ty.getClass.getName))
        } else {
          ty match {
            case _: TypeRef =>
512
              noAccessViaPointer(ptr, ty)
513
              val ol = ob.asInstanceOf[BoxRef].objRef
514
              val rl = memorySupport.atomicRMWLong(op, loc, ol)
515 516
              br.asInstanceOf[BoxRef].objRef = rl
            case _: TypeIRef =>
517
              noAccessViaPointer(ptr, ty)
518
              val BoxIRef(ol, oh) = ob.asInstanceOf[BoxIRef]
519
              val (rl, rh) = memorySupport.xchgI128(loc, (ol, oh))
520
              br.asInstanceOf[BoxIRef].oo = (rl, rh)
521
            case _: TypeFuncRef =>
522
              noAccessViaPointer(ptr, ty)
523
              val ol = ob.asInstanceOf[BoxFunc].func.map(_.id).getOrElse(0).toLong
524
              val rl = memorySupport.atomicRMWLong(op, loc, ol)
525 526
              val rf = microVM.globalBundle.funcNs.get(rl.toInt)
              br.asInstanceOf[BoxFunc].func = rf
527
            case _: TypeThreadRef =>
528
              noAccessViaPointer(ptr, ty)
529
              val ol = ob.asInstanceOf[BoxThread].thread.map(_.id).getOrElse(0).toLong
530
              val rl = memorySupport.atomicRMWLong(op, loc, ol)
531 532
              val rt = microVM.threadStackManager.getThreadByID(rl.toInt)
              br.asInstanceOf[BoxThread].thread = rt
533
            case _: TypeStackRef =>
534
              noAccessViaPointer(ptr, ty)
535
              val ol = ob.asInstanceOf[BoxStack].stack.map(_.id).getOrElse(0).toLong
536
              val rl = memorySupport.atomicRMWLong(op, loc, ol)
537 538 539
              val rs = microVM.threadStackManager.getStackByID(rl.toInt)
              br.asInstanceOf[BoxStack].stack = rs
            case _: TypeTagRef64 =>
540
              noAccessViaPointer(ptr, ty)
541
              val ol = ob.asInstanceOf[BoxTagRef64].raw
542
              val rl = memorySupport.atomicRMWLong(op, loc, ol)
543
              br.asInstanceOf[BoxTagRef64].raw = rl
544
            case _: TypeUPtr | _: TypeUFuncPtr =>
545 546 547
              val ol = ob.asInstanceOf[BoxPointer].addr
              val rl = memorySupport.atomicRMWLong(op, loc, ol, !ptr)
              br.asInstanceOf[BoxPointer].addr = rl
548 549 550 551 552
            case _ =>
              throw new UnimplementedOprationException("AtomicRMW XCHG of type %s is not supporing".format(ty.getClass.getName))
          }
        }
    }
Kunshan Wang's avatar
Kunshan Wang committed
553
  }
Kunshan Wang's avatar
Kunshan Wang committed
554 555 556 557

  /**
   * Check if a memory location still holds a particular value. Used by futex.
   */
558
  def cmpInt(len: Int, loc: Word, expected: BoxInt)(implicit memorySupport: MemorySupport): Boolean = len match {
Kunshan Wang's avatar
Kunshan Wang committed
559 560
    case 64 => {
      val expNum = OpHelper.prepareSigned(expected.value, len).longValue
561
      val actualNum = memorySupport.loadLong(loc)
Kunshan Wang's avatar
Kunshan Wang committed
562 563 564 565
      expNum == actualNum
    }
    case 32 => {
      val expNum = OpHelper.prepareSigned(expected.value, len).intValue
566
      val actualNum = memorySupport.loadInt(loc)
Kunshan Wang's avatar
Kunshan Wang committed
567 568 569 570
      expNum == actualNum
    }
    case _ => throw new UnimplementedOprationException("Futex of %d bit int is not supported".format(len))
  }
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604

  val US_ASCII = Charset.forName("US-ASCII")

  /**
   * Read an ASCII string from the memory.
   *
   * @param loc A ref to a @uvm.meta.bytes object.
   */
  def bytesToStr(loc: Word)(implicit memorySupport: MemorySupport): String = {
    // It is a hybrid<@i64 @i8> object. The length is determined by the fixed part. 
    val len = memorySupport.loadLong(loc)
    val bytes = new Array[Byte](len.toInt)
    val begin = loc + TypeSizes.WORD_SIZE_BYTES
    memorySupport.loadBytes(begin, bytes, 0, len, true)

    val result = new String(bytes, US_ASCII)
    result
  }

  /**
   * Create a Mu @uvm.meta.bytes object to hold an ASCII string.
   *
   * @return The address of the allocated object.
   */
  def strToBytes(str: String)(implicit memorySupport: MemorySupport, mutator: Mutator): Word = {
    val bytes = str.getBytes(US_ASCII)
    val len = bytes.length
    val loc = mutator.newHybrid(InternalTypes.BYTES, len)
    memorySupport.storeLong(loc, bytes.length.toLong)
    val begin = loc + TypeSizes.WORD_SIZE_BYTES
    memorySupport.storeBytes(begin, bytes, 0, len, true)
    
    loc
  }
Kunshan Wang's avatar
Kunshan Wang committed
605 606
}