operationHelpers.scala 23.8 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

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

35 36 37 38 39
  // The BigInt in a BoxInt is always truncated to len bits.
  //
  // "prepare" means sign- or zero-extend the content to get the real math value.
  // "unprepare" means truncating a math value to len bits to be stored in a BoxInt.

Kunshan Wang's avatar
Kunshan Wang committed
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 92 93 94 95 96
  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;
97

Kunshan Wang's avatar
Kunshan Wang committed
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 180 181 182 183 184
    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 {
185 186 187
      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
188 189 190 191
      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) }
192
      case BinOptr.SHL  => pu(op1v) << (op2v.intValue & shiftMask)
Kunshan Wang's avatar
Kunshan Wang committed
193 194
      case BinOptr.LSHR => pu(op1v) >> (op2v.intValue & shiftMask)
      case BinOptr.ASHR => ps(op1v) >> (op2v.intValue & shiftMask)
195 196 197 198
      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
199 200 201 202 203 204 205 206 207 208
    })
  }

  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
209
      case _            => throw new UvmRuntimeException(ctx + "Binary operator %s is not suitable for float.".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
210 211 212 213 214 215 216 217 218 219
    }
  }

  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)
220
      case _            => throw new UvmRuntimeException(ctx + "Binary operator %s is not suitable for double.".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
221 222 223 224 225 226 227 228
    }
  }

  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 {
229 230
      case CmpOptr.EQ  => pu(op1v) == pu(op2v)
      case CmpOptr.NE  => pu(op1v) != pu(op2v)
Kunshan Wang's avatar
Kunshan Wang committed
231 232 233 234 235 236 237 238
      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)
239
      case _           => throw new UvmRuntimeException(ctx + "Comparison operator %s not suitable for integers".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
240 241 242 243 244 245 246 247
    }
  }

  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 {
248
      case CmpOptr.FTRUE  => true
Kunshan Wang's avatar
Kunshan Wang committed
249
      case CmpOptr.FFALSE => false
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
      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
265 266 267 268 269 270 271 272
    }
  }

  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 {
273
      case CmpOptr.FTRUE  => true
Kunshan Wang's avatar
Kunshan Wang committed
274
      case CmpOptr.FFALSE => false
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
      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
290 291 292
    }
  }
}
Kunshan Wang's avatar
Kunshan Wang committed
293

294
object MemoryOperations {
295 296 297 298 299 300 301 302 303

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

305 306 307 308 309 310 311
  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 = {
312 313 314
    def loadScalar(ty: Type, loc: Word, br: ValueBox): Unit = ty match {
      case TypeInt(l) =>
        val bi: BigInt = l match {
315 316 317 318 319
          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))
320 321 322
        }
        br.asInstanceOf[BoxInt].value = OpHelper.unprepare(bi, l)
      case _: TypeFloat =>
323
        val fv = memorySupport.loadFloat(loc, !ptr)
324 325
        br.asInstanceOf[BoxFloat].value = fv
      case _: TypeDouble =>
326
        val dv = memorySupport.loadDouble(loc, !ptr)
327 328
        br.asInstanceOf[BoxDouble].value = dv
      case _: TypeRef =>
329
        noAccessViaPointer(ptr, ty)
330
        val addr = memorySupport.loadLong(loc)
331 332
        br.asInstanceOf[BoxRef].objRef = addr
      case _: TypeIRef =>
333
        noAccessViaPointer(ptr, ty)
334 335
        val base = memorySupport.loadLong(loc)
        val offset = memorySupport.loadLong(loc + WORD_SIZE_BYTES)
336
        br.asInstanceOf[BoxIRef].oo = (base, offset)
337
      case _: TypeFuncRef =>
338
        noAccessViaPointer(ptr, ty)
339
        val fid = memorySupport.loadLong(loc).toInt
340 341
        val func = microVM.globalBundle.funcNs.get(fid)
        br.asInstanceOf[BoxFunc].func = func
342
      case _: TypeThreadRef =>
343
        noAccessViaPointer(ptr, ty)
344
        val tid = memorySupport.loadLong(loc).toInt
345 346
        val thr = microVM.threadStackManager.getThreadByID(tid)
        br.asInstanceOf[BoxThread].thread = thr
347
      case _: TypeStackRef =>
348
        noAccessViaPointer(ptr, ty)
349
        val sid = memorySupport.loadLong(loc).toInt
350 351 352
        val sta = microVM.threadStackManager.getStackByID(sid)
        br.asInstanceOf[BoxStack].stack = sta
      case _: TypeTagRef64 =>
353
        noAccessViaPointer(ptr, ty)
354
        val raw = memorySupport.loadLong(loc)
355
        br.asInstanceOf[BoxTagRef64].raw = raw
356
      case _: TypeUPtr | _: TypeUFuncPtr =>
357 358
        val addr = memorySupport.loadLong(loc, !ptr)
        br.asInstanceOf[BoxPointer].addr = addr
359 360 361 362 363
      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
364
        val brs = br.asInstanceOf[BoxSeq].values
365 366 367 368 369 370 371 372
        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
373 374
  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 {
375 376 377
      case TypeInt(l) =>
        val bi = nvb.asInstanceOf[BoxInt].value
        l match {
378 379 380 381 382
          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))
383 384 385
        }
      case _: TypeFloat =>
        val fv = nvb.asInstanceOf[BoxFloat].value
386
        memorySupport.storeFloat(loc, fv, !ptr)
387 388
      case _: TypeDouble =>
        val dv = nvb.asInstanceOf[BoxDouble].value
389
        memorySupport.storeDouble(loc, dv, !ptr)
390
      case _: TypeRef =>
391
        noAccessViaPointer(ptr, ty)
392
        val addr = nvb.asInstanceOf[BoxRef].objRef
393
        memorySupport.storeLong(loc, addr)
394
      case _: TypeIRef =>
395
        noAccessViaPointer(ptr, ty)
396
        val BoxIRef(base, offset) = nvb.asInstanceOf[BoxIRef]
397 398
        memorySupport.storeLong(loc, base)
        memorySupport.storeLong(loc + WORD_SIZE_BYTES, offset)
399
      case _: TypeFuncRef =>
400
        noAccessViaPointer(ptr, ty)
401
        val fid = nvb.asInstanceOf[BoxFunc].func.map(_.id).getOrElse(0)
402
        memorySupport.storeLong(loc, fid.toLong & 0xFFFFFFFFL)
403
      case _: TypeThreadRef =>
404
        noAccessViaPointer(ptr, ty)
405
        val tid = nvb.asInstanceOf[BoxThread].thread.map(_.id).getOrElse(0)
406
        memorySupport.storeLong(loc, tid.toLong & 0xFFFFFFFFL)
407
      case _: TypeStackRef =>
408
        noAccessViaPointer(ptr, ty)
409
        val sid = nvb.asInstanceOf[BoxStack].stack.map(_.id).getOrElse(0)
410
        memorySupport.storeLong(loc, sid.toLong & 0xFFFFFFFFL)
411
      case _: TypeTagRef64 =>
412
        noAccessViaPointer(ptr, ty)
413
        val raw = nvb.asInstanceOf[BoxTagRef64].raw
414
        memorySupport.storeLong(loc, raw)
415
      case _: TypeUPtr | _: TypeUFuncPtr =>
416 417
        val addr = nvb.asInstanceOf[BoxPointer].addr
        memorySupport.storeLong(loc, addr, !ptr)
418 419 420 421 422
      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
423
        val nvbs = nvb.asInstanceOf[BoxSeq].values
424
        val elemSkip = alignUp(sizeOf(ety), alignOf(ety))
Kunshan Wang's avatar
Kunshan Wang committed
425 426
        for ((nvbElem, i) <- nvbs.zipWithIndex) {
          storeScalar(ety, loc + elemSkip * i, nvbElem)
427
        }
Kunshan Wang's avatar
Kunshan Wang committed
428
      case sty => storeScalar(sty, loc, nvb)
429 430 431 432 433 434
    }
  }

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

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

  /**
   * Check if a memory location still holds a particular value. Used by futex.
   */
563
  def cmpInt(len: Int, loc: Word, expected: BoxInt)(implicit memorySupport: MemorySupport): Boolean = len match {
Kunshan Wang's avatar
Kunshan Wang committed
564 565
    case 64 => {
      val expNum = OpHelper.prepareSigned(expected.value, len).longValue
566
      val actualNum = memorySupport.loadLong(loc)
Kunshan Wang's avatar
Kunshan Wang committed
567 568 569 570
      expNum == actualNum
    }
    case 32 => {
      val expNum = OpHelper.prepareSigned(expected.value, len).intValue
571
      val actualNum = memorySupport.loadInt(loc)
Kunshan Wang's avatar
Kunshan Wang committed
572 573 574 575
      expNum == actualNum
    }
    case _ => throw new UnimplementedOprationException("Futex of %d bit int is not supported".format(len))
  }
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 605 606 607 608 609

  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
610 611
}