WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

To protect your data, the CISO officer has suggested users to enable 2FA as soon as possible.
Currently 2.7% of users enabled 2FA.

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

3
import uvm.types._
Kunshan Wang's avatar
Kunshan Wang committed
4
5
import uvm.ssavariables._
import uvm.refimpl._
6
7
8
import uvm.refimpl.mem.TypeSizes._
import uvm.refimpl.mem.MemorySupport
import AtomicRMWOptr._
Kunshan Wang's avatar
Kunshan Wang committed
9
10
11
12
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

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;
88

Kunshan Wang's avatar
Kunshan Wang committed
89
90
91
92
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
    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 {
Kunshan Wang's avatar
Kunshan Wang committed
176
177
178
      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
179
180
181
182
      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) }
Kunshan Wang's avatar
Kunshan Wang committed
183
      case BinOptr.SHL  => pu(op1v) << (op2v.intValue & shiftMask)
Kunshan Wang's avatar
Kunshan Wang committed
184
185
      case BinOptr.LSHR => pu(op1v) >> (op2v.intValue & shiftMask)
      case BinOptr.ASHR => ps(op1v) >> (op2v.intValue & shiftMask)
Kunshan Wang's avatar
Kunshan Wang committed
186
187
188
189
      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
190
191
192
193
194
195
196
197
198
199
    })
  }

  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
Kunshan Wang's avatar
Kunshan Wang committed
200
      case _            => throw new UvmRuntimeException(ctx + "Binary operator %s is not suitable for float.".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
201
202
203
204
205
206
207
208
209
210
    }
  }

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

  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 {
Kunshan Wang's avatar
Kunshan Wang committed
220
221
      case CmpOptr.EQ  => pu(op1v) == pu(op2v)
      case CmpOptr.NE  => pu(op1v) != pu(op2v)
Kunshan Wang's avatar
Kunshan Wang committed
222
223
224
225
226
227
228
229
      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)
Kunshan Wang's avatar
Kunshan Wang committed
230
      case _           => throw new UvmRuntimeException(ctx + "Comparison operator %s not suitable for integers".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
231
232
233
234
235
236
237
238
    }
  }

  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 {
Kunshan Wang's avatar
Kunshan Wang committed
239
      case CmpOptr.FTRUE  => true
Kunshan Wang's avatar
Kunshan Wang committed
240
      case CmpOptr.FFALSE => false
Kunshan Wang's avatar
Kunshan Wang committed
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
      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
256
257
258
259
260
261
262
263
    }
  }

  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 {
Kunshan Wang's avatar
Kunshan Wang committed
264
      case CmpOptr.FTRUE  => true
Kunshan Wang's avatar
Kunshan Wang committed
265
      case CmpOptr.FFALSE => false
Kunshan Wang's avatar
Kunshan Wang committed
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
      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
281
282
283
    }
  }
}
Kunshan Wang's avatar
Kunshan Wang committed
284

285
object MemoryOperations {
Kunshan Wang's avatar
Kunshan Wang committed
286
287
288
289
290
291
292
293
294

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

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

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

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

  /**
   * Check if a memory location still holds a particular value. Used by futex.
   */
555
  def cmpInt(len: Int, loc: Word, expected: BoxInt)(implicit memorySupport: MemorySupport): Boolean = len match {
Kunshan Wang's avatar
Kunshan Wang committed
556
557
    case 64 => {
      val expNum = OpHelper.prepareSigned(expected.value, len).longValue
558
      val actualNum = memorySupport.loadLong(loc)
Kunshan Wang's avatar
Kunshan Wang committed
559
560
561
562
      expNum == actualNum
    }
    case 32 => {
      val expNum = OpHelper.prepareSigned(expected.value, len).intValue
563
      val actualNum = memorySupport.loadInt(loc)
Kunshan Wang's avatar
Kunshan Wang committed
564
565
566
567
      expNum == actualNum
    }
    case _ => throw new UnimplementedOprationException("Futex of %d bit int is not supported".format(len))
  }
Kunshan Wang's avatar
Kunshan Wang committed
568
569
}