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

InterpreterThread.scala 48.5 KB
Newer Older
Kunshan Wang's avatar
Kunshan Wang committed
1
2
3
package uvm.refimpl.itpr

import uvm._
Kunshan Wang's avatar
Kunshan Wang committed
4
5
import uvm.types._
import uvm.ssavariables._
Kunshan Wang's avatar
Kunshan Wang committed
6
import uvm.comminsts._
Kunshan Wang's avatar
Kunshan Wang committed
7
8
import uvm.refimpl._
import uvm.refimpl.mem._
Kunshan Wang's avatar
Kunshan Wang committed
9
import TypeSizes.Word
Kunshan Wang's avatar
Kunshan Wang committed
10
11
12
13
14
15
16
import scala.annotation.tailrec
import org.slf4j.LoggerFactory
import com.typesafe.scalalogging.Logger

object InterpreterThread {
  val logger = Logger(LoggerFactory.getLogger(getClass.getName))
}
Kunshan Wang's avatar
Kunshan Wang committed
17
18

class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: InterpreterStack, val mutator: Mutator) {
Kunshan Wang's avatar
Kunshan Wang committed
19
20
  import InterpreterThread._

Kunshan Wang's avatar
Kunshan Wang committed
21
  // Thread states
Kunshan Wang's avatar
Kunshan Wang committed
22
23

  /** The underlying stack. */
Kunshan Wang's avatar
Kunshan Wang committed
24
  var stack: Option[InterpreterStack] = None
Kunshan Wang's avatar
Kunshan Wang committed
25

Kunshan Wang's avatar
Kunshan Wang committed
26
  /** True if the thread is running. False only if terminated. */
Kunshan Wang's avatar
Kunshan Wang committed
27
  var isRunning: Boolean = true
Kunshan Wang's avatar
Kunshan Wang committed
28
29
30
31

  /** True if the thread is waiting in a Futex waiting queue. */
  var isFutexWaiting: Boolean = false

Kunshan Wang's avatar
Kunshan Wang committed
32
  // Initialisation
Kunshan Wang's avatar
Kunshan Wang committed
33

Kunshan Wang's avatar
Kunshan Wang committed
34
35
36
  rebindPassVoid(initialStack)

  // Public interface
Kunshan Wang's avatar
Kunshan Wang committed
37
38

  /** Execute one instruction. */
Kunshan Wang's avatar
Kunshan Wang committed
39
  def step(): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
40
41
    if (!isRunning) throw new UvmRefImplException(ctx + "Attempt to run thread after it has reached exit.")
    if (isFutexWaiting) throw new UvmRefImplException(ctx + "Attempt to run thread when it is waiting on a futex.")
Kunshan Wang's avatar
Kunshan Wang committed
42
    interpretCurrentInstruction()
Kunshan Wang's avatar
Kunshan Wang committed
43
44
  }

Kunshan Wang's avatar
Kunshan Wang committed
45
46
  /** Write the return value of futex. May be written from FutexManager */
  def futexReturn(rv: Int): Unit = {
47
48
49
50
51
52
53
54
55
56
57
    //    val validInst = curInst match {
    //      case ci: InstCommInst => ci.inst.name.get match {
    //        case "@uvm.futex.wait" => true
    //        case "@uvm.futex.wait_timeout" => true
    //        case _ => false
    //      }
    //      case _ => false
    //    }
    //
    //    if (!validInst) throw new UvmRefImplException(ctx + "The current instruction is not @uvm.futex.wait or wait_timeout.")
    //
Kunshan Wang's avatar
Kunshan Wang committed
58
59
60
61
62
    logger.debug(ctx + "Setting futex return value")
    writeIntResult(32, rv, boxOf(curInst))
    continueNormally()
  }

Kunshan Wang's avatar
Kunshan Wang committed
63
  // Convenient functions to get/set states
Kunshan Wang's avatar
Kunshan Wang committed
64

Kunshan Wang's avatar
Kunshan Wang committed
65
66
67
68
69
70
  private def curStack = stack.get
  private def top = curStack.top
  private def curBB = top.curBB
  private def curInst = top.curInst
  private def curInstHalfExecuted = top.curInstHalfExecuted
  private def curInstHalfExecuted_=(v: Boolean) = top.curInstHalfExecuted_=(v)
Kunshan Wang's avatar
Kunshan Wang committed
71

Kunshan Wang's avatar
Kunshan Wang committed
72
73
  private def incPC(): Unit = top.incPC()
  private def jump(bb: BasicBlock, ix: Int): Unit = top.jump(bb, ix)
Kunshan Wang's avatar
Kunshan Wang committed
74

Kunshan Wang's avatar
Kunshan Wang committed
75
76
  /** Get the value box of an SSA variable in a stack. */
  private def boxOf(s: InterpreterStack, v: SSAVariable): ValueBox = v match {
Kunshan Wang's avatar
Kunshan Wang committed
77
    case g: GlobalVariable => microVM.constantPool.getGlobalVarBox(g)
78
    case l: LocalVariable  => s.top.boxes(l)
Kunshan Wang's avatar
Kunshan Wang committed
79
  }
Kunshan Wang's avatar
Kunshan Wang committed
80
81
82
83

  /** Get the value box of an SSA variable in the current stack. */
  private def boxOf(v: SSAVariable): ValueBox = boxOf(curStack, v)

84
85
86
87
88
89
  /** Get the edge-assigned value box of an edge-assigned instruction in a stack. */
  private def edgeAssignedBoxOf(s: InterpreterStack, ea: EdgeAssigned): ValueBox = s.top.edgeAssignedBoxes(ea)

  /** Get the edge-assigned value box of an edge-assigned instruction in the current stack. */
  private def edgeAssignedBoxOf(ea: EdgeAssigned): ValueBox = edgeAssignedBoxOf(curStack, ea)

Kunshan Wang's avatar
Kunshan Wang committed
90
  // Context printing for debugging
Kunshan Wang's avatar
Kunshan Wang committed
91

Kunshan Wang's avatar
Kunshan Wang committed
92
93
  /** Make a string to identify the current function version, basic block and instruction for debugging. */
  private def ctx = stack match {
94
95
96
97
    case None => "(Thred not bound to stack): "
    case Some(_) => {
      val ix = top.curInstIndex
      if (ix >= curBB.insts.size) {
Kunshan Wang's avatar
Kunshan Wang committed
98
        "TID %d, FuncVer %s, BasicBlock %s, Instruction exceeds the basic block (error)".format(id, top.funcVer.repr, curBB.repr)
99
      } else {
Kunshan Wang's avatar
Kunshan Wang committed
100
101
        "TID %d, FuncVer %s, BasicBlock %s, Instruction %s (%s): ".format(id, top.funcVer.repr, curBB.repr, curInst.repr, curInst match {
          case ci: InstCommInst => ci.inst.name.get
102
          case _                => curInst.getClass.getSimpleName()
Kunshan Wang's avatar
Kunshan Wang committed
103
        })
104
105
      }
    }
Kunshan Wang's avatar
Kunshan Wang committed
106
  }
Kunshan Wang's avatar
Kunshan Wang committed
107

Kunshan Wang's avatar
Kunshan Wang committed
108
  // Interpreting
Kunshan Wang's avatar
Kunshan Wang committed
109
110

  /** Interpret the current instruction. */
Kunshan Wang's avatar
Kunshan Wang committed
111
  private def interpretCurrentInstruction(): Unit = try {
Kunshan Wang's avatar
Kunshan Wang committed
112
113
    logger.debug(ctx + "Executing instruction...")

114
    curInst match {
Kunshan Wang's avatar
Kunshan Wang committed
115
116
117
118
119
120
121
      case i @ InstBinOp(op, opndTy, op1, op2, excClause) => {
        def doInt(l: Int, b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
          val op1v = b1.asInstanceOf[BoxInt].value
          val op2v = b2.asInstanceOf[BoxInt].value

          val result = PrimOpHelpers.intBinOp(op, l, op1v, op2v, ctx)

Kunshan Wang's avatar
Kunshan Wang committed
122
          val iBox = br.asInstanceOf[BoxInt]
Kunshan Wang's avatar
Kunshan Wang committed
123
124
125
126
127
128
129
130
131
          iBox.value = result
        }

        def doFloat(b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
          val op1v = b1.asInstanceOf[BoxFloat].value
          val op2v = b2.asInstanceOf[BoxFloat].value

          val result = PrimOpHelpers.floatBinOp(op, op1v, op2v, ctx)

Kunshan Wang's avatar
Kunshan Wang committed
132
          val iBox = br.asInstanceOf[BoxFloat]
Kunshan Wang's avatar
Kunshan Wang committed
133
134
135
136
137
138
139
140
141
          iBox.value = result
        }

        def doDouble(b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
          val op1v = b1.asInstanceOf[BoxDouble].value
          val op2v = b2.asInstanceOf[BoxDouble].value

          val result = PrimOpHelpers.doubleBinOp(op, op1v, op2v, ctx)

Kunshan Wang's avatar
Kunshan Wang committed
142
          val iBox = br.asInstanceOf[BoxDouble]
Kunshan Wang's avatar
Kunshan Wang committed
143
144
145
146
147
          iBox.value = result
        }

        def doScalar(scalarTy: Type, b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
          scalarTy match {
148
149
            case TypeInt(l)   => doInt(l, b1, b2, br)
            case TypeFloat()  => doFloat(b1, b2, br)
Kunshan Wang's avatar
Kunshan Wang committed
150
            case TypeDouble() => doDouble(b1, b2, br)
151
            case _            => throw new UvmRuntimeException(ctx + "BinOp not suitable for type %s".format(opndTy))
Kunshan Wang's avatar
Kunshan Wang committed
152
153
154
155
156
157
158
          }
        }

        try {
          opndTy match {
            case TypeVector(scalarTy, sz) => {
              val op1Bs = boxOf(op1).asInstanceOf[BoxVector].values
Kunshan Wang's avatar
Kunshan Wang committed
159
              val op2Bs = boxOf(op2).asInstanceOf[BoxVector].values
Kunshan Wang's avatar
Kunshan Wang committed
160
161
162
163
164
165
166
167
              val rBs = boxOf(i).asInstanceOf[BoxVector].values

              for (((b1, b2), br) <- ((op1Bs zip op2Bs) zip rBs)) {
                doScalar(scalarTy, b1, b2, br)
              }
            }
            case scalarTy => doScalar(scalarTy, boxOf(op1), boxOf(op2), boxOf(i))
          }
168
          continueNormally()
Kunshan Wang's avatar
Kunshan Wang committed
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
        } catch {
          case e: UvmDivisionByZeroException => excClause match {
            case None => throw e
            case Some(ec) => {
              branchAndMovePC(ec.exc)
            }
          }
        }
      }

      case i @ InstCmp(op, opndTy, op1, op2) => {
        def doInt(l: Int, b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
          val op1v = b1.asInstanceOf[BoxInt].value
          val op2v = b2.asInstanceOf[BoxInt].value

          val result = PrimOpHelpers.intCmp(op, l, op1v, op2v, ctx)
          writeBooleanResult(result, br)
        }

        def doFloat(b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
          val op1v = b1.asInstanceOf[BoxFloat].value
          val op2v = b2.asInstanceOf[BoxFloat].value

          val result = PrimOpHelpers.floatCmp(op, op1v, op2v, ctx)
          writeBooleanResult(result, br)
        }

        def doDouble(b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
          val op1v = b1.asInstanceOf[BoxDouble].value
          val op2v = b2.asInstanceOf[BoxDouble].value

          val result = PrimOpHelpers.doubleCmp(op, op1v, op2v, ctx)
          writeBooleanResult(result, br)
        }

204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
        def doRef(b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
          val op1v = b1.asInstanceOf[BoxRef].objRef
          val op2v = b2.asInstanceOf[BoxRef].objRef

          val result = op match {
            case CmpOptr.EQ => op1v == op2v
            case CmpOptr.NE => op1v != op2v
            case _          => throw new UvmRuntimeException(ctx + "Comparison %s not suitable for reference type %s".format(op, opndTy))
          }
          writeBooleanResult(result, br)
        }
        
        def doIRef(b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
          val op1v = b1.asInstanceOf[BoxIRef].oo
          val op2v = b2.asInstanceOf[BoxIRef].oo

          val result = op match {
            case CmpOptr.EQ => op1v == op2v
            case CmpOptr.NE => op1v != op2v
            case _          => throw new UvmRuntimeException(ctx + "Comparison %s not suitable for internal reference type %s".format(op, opndTy))
          }
          writeBooleanResult(result, br)
        }

        def doFunc(b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
          val op1v = b1.asInstanceOf[BoxFunc].func
          val op2v = b2.asInstanceOf[BoxFunc].func

          val result = op match {
            case CmpOptr.EQ => op1v == op2v
            case CmpOptr.NE => op1v != op2v
            case _          => throw new UvmRuntimeException(ctx + "Comparison %s not suitable for function type %s".format(op, opndTy))
          }
          writeBooleanResult(result, br)
        }
        
        def doStack(b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
          val op1v = b1.asInstanceOf[BoxStack].stack
          val op2v = b2.asInstanceOf[BoxStack].stack

          val result = op match {
            case CmpOptr.EQ => op1v == op2v
            case CmpOptr.NE => op1v != op2v
            case _          => throw new UvmRuntimeException(ctx + "Comparison %s not suitable for stack type %s".format(op, opndTy))
          }
          writeBooleanResult(result, br)
        }

Kunshan Wang's avatar
Kunshan Wang committed
252
253
        def doScalar(scalarTy: Type, b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
          scalarTy match {
254
255
            case TypeInt(l)   => doInt(l, b1, b2, br)
            case TypeFloat()  => doFloat(b1, b2, br)
Kunshan Wang's avatar
Kunshan Wang committed
256
            case TypeDouble() => doDouble(b1, b2, br)
257
258
259
260
            case TypeRef(_)   => doRef(b1, b2, br)
            case TypeIRef(_)  => doIRef(b1, b2, br)
            case TypeFunc(_)  => doFunc(b1, b2, br)
            case TypeStack()  => doStack(b1, b2, br)
261
            case _            => throw new UvmRuntimeException(ctx + "Comparison not suitable for type %s".format(opndTy))
Kunshan Wang's avatar
Kunshan Wang committed
262
263
264
265
266
267
          }
        }

        opndTy match {
          case TypeVector(scalarTy, sz) => {
            val op1Bs = boxOf(op1).asInstanceOf[BoxVector].values
Kunshan Wang's avatar
Kunshan Wang committed
268
            val op2Bs = boxOf(op2).asInstanceOf[BoxVector].values
Kunshan Wang's avatar
Kunshan Wang committed
269
270
271
272
273
274
275
276
277
            val rBs = boxOf(i).asInstanceOf[BoxVector].values

            for (((b1, b2), br) <- ((op1Bs zip op2Bs) zip rBs)) {
              doScalar(scalarTy, b1, b2, br)
            }
          }
          case scalarTy => doScalar(scalarTy, boxOf(op1), boxOf(op2), boxOf(i))
        }

278
        continueNormally()
Kunshan Wang's avatar
Kunshan Wang committed
279
280
281
      }

      case i @ InstConv(op, fromTy, toTy, opnd) => {
282
283
        def doScalar(scalarFromTy: Type, scalarToTy: Type, bOpnd: ValueBox, br: ValueBox): Unit = {
          def iToI(): Unit = (scalarFromTy, scalarToTy) match {
Kunshan Wang's avatar
Kunshan Wang committed
284
285
286
287
            case (TypeInt(fl), TypeInt(tl)) => {
              val od = bOpnd.asInstanceOf[BoxInt].value
              val result = op match {
                case ConvOptr.TRUNC => OpHelper.trunc(od, tl)
288
289
                case ConvOptr.ZEXT  => OpHelper.zext(od, fl, tl)
                case ConvOptr.SEXT  => OpHelper.sext(od, fl, tl)
Kunshan Wang's avatar
Kunshan Wang committed
290
291
292
              }
              br.asInstanceOf[BoxInt].value = result
            }
293
            case _ => throw new UvmRuntimeException(ctx + "Expect integer source and dest type. Found %s and %s".format(scalarFromTy, scalarToTy))
Kunshan Wang's avatar
Kunshan Wang committed
294
295
296
          }

          def fpToI(signed: Boolean): Unit = {
297
            val tl = scalarToTy match {
Kunshan Wang's avatar
Kunshan Wang committed
298
              case TypeInt(l) => l
299
              case _          => throw new UvmRuntimeException(ctx + "Expect integer dest type. Found %s".format(scalarToTy))
Kunshan Wang's avatar
Kunshan Wang committed
300
            }
301
            val result = scalarFromTy match {
302
              case TypeFloat()  => OpHelper.floatToI(bOpnd.asInstanceOf[BoxFloat].value, tl, signed)
Kunshan Wang's avatar
Kunshan Wang committed
303
              case TypeDouble() => OpHelper.doubleToI(bOpnd.asInstanceOf[BoxDouble].value, tl, signed)
304
              case _            => throw new UvmRuntimeException(ctx + "Expect FP source type. Found %s.".format(scalarFromTy))
Kunshan Wang's avatar
Kunshan Wang committed
305
306
307
308
309
            }
            br.asInstanceOf[BoxInt].value = result
          }

          def iToFP(signed: Boolean): Unit = {
310
            val fl = scalarFromTy match {
Kunshan Wang's avatar
Kunshan Wang committed
311
              case TypeInt(l) => l
312
              case _          => throw new UvmRuntimeException(ctx + "Expect integer source type. Found %s".format(scalarFromTy))
Kunshan Wang's avatar
Kunshan Wang committed
313
314
315
            }
            val od = bOpnd.asInstanceOf[BoxInt].value
            val extended = if (signed) OpHelper.prepareSigned(od, fl) else OpHelper.prepareUnsigned(od, fl)
316
            scalarToTy match {
Kunshan Wang's avatar
Kunshan Wang committed
317
318
319
320
321
322
323
324
              case TypeFloat() => {
                val result = extended.toFloat
                br.asInstanceOf[BoxFloat].value = result
              }
              case TypeDouble() => {
                val result = extended.toDouble
                br.asInstanceOf[BoxDouble].value = result
              }
325
              case _ => throw new UvmRuntimeException(ctx + "Expect FP dest type. Found %s.".format(scalarToTy))
Kunshan Wang's avatar
Kunshan Wang committed
326
327
328
            }
          }

329
          def bitcast(): Unit = (scalarFromTy, scalarToTy) match {
Kunshan Wang's avatar
Kunshan Wang committed
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
            case (TypeInt(32), TypeFloat()) => {
              val result = java.lang.Float.intBitsToFloat(bOpnd.asInstanceOf[BoxInt].value.intValue)
              br.asInstanceOf[BoxFloat].value = result
            }
            case (TypeInt(64), TypeDouble()) => {
              val result = java.lang.Double.longBitsToDouble(bOpnd.asInstanceOf[BoxInt].value.longValue)
              br.asInstanceOf[BoxDouble].value = result
            }
            case (TypeFloat(), TypeInt(32)) => {
              val result = java.lang.Float.floatToRawIntBits(bOpnd.asInstanceOf[BoxFloat].value)
              br.asInstanceOf[BoxInt].value = result
            }
            case (TypeDouble(), TypeInt(64)) => {
              val result = java.lang.Double.doubleToRawLongBits(bOpnd.asInstanceOf[BoxDouble].value)
              br.asInstanceOf[BoxInt].value = result
            }
            case _ => throw new UvmRuntimeException(ctx +
347
              "BITCAST can only convert between int and FP types of the same size. Found %s and %s.".format(scalarFromTy, scalarToTy))
Kunshan Wang's avatar
Kunshan Wang committed
348
349
          }

350
          def refcast(): Unit = (scalarFromTy, scalarToTy) match {
351
            case (TypeRef(_), TypeRef(_))   => br.copyFrom(bOpnd)
Kunshan Wang's avatar
Kunshan Wang committed
352
353
            case (TypeIRef(_), TypeIRef(_)) => br.copyFrom(bOpnd)
            case (TypeFunc(_), TypeFunc(_)) => br.copyFrom(bOpnd)
Kunshan Wang's avatar
Kunshan Wang committed
354
            case _ => throw new UvmRuntimeException(ctx +
Kunshan Wang's avatar
Kunshan Wang committed
355
              "REFCAST can only convert between two types both of which are ref, iref, or func. Found %s and %s.".format(scalarFromTy, scalarToTy))
Kunshan Wang's avatar
Kunshan Wang committed
356
357
358
359
          }

          op match {
            case ConvOptr.TRUNC => iToI()
360
361
            case ConvOptr.ZEXT  => iToI()
            case ConvOptr.SEXT  => iToI()
Kunshan Wang's avatar
Kunshan Wang committed
362
            case ConvOptr.FPTRUNC => {
363
              val od = bOpnd.asInstanceOf[BoxDouble].value
Kunshan Wang's avatar
Kunshan Wang committed
364
              val result = od.toFloat
365
              br.asInstanceOf[BoxFloat].value = result
Kunshan Wang's avatar
Kunshan Wang committed
366
367
            }
            case ConvOptr.FPEXT => {
368
              val od = bOpnd.asInstanceOf[BoxFloat].value
Kunshan Wang's avatar
Kunshan Wang committed
369
              val result = od.toDouble
370
              br.asInstanceOf[BoxDouble].value = result
Kunshan Wang's avatar
Kunshan Wang committed
371
            }
372
373
374
375
            case ConvOptr.FPTOUI  => fpToI(signed = false)
            case ConvOptr.FPTOSI  => fpToI(signed = true)
            case ConvOptr.UITOFP  => iToFP(signed = false)
            case ConvOptr.SITOFP  => iToFP(signed = true)
Kunshan Wang's avatar
Kunshan Wang committed
376
377
378
379
            case ConvOptr.BITCAST => bitcast()
            case ConvOptr.REFCAST => refcast()
          }
        }
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397

        (fromTy, toTy) match {
          case (TypeVector(scalarFromTy, sz), TypeVector(scalarToTy, sz2)) => {
            if (sz != sz2) throw new UvmRefImplException(ctx + "The source and dest vector types must have the same length")

            val bOpnds = boxOf(opnd).asInstanceOf[BoxVector].values
            val rBs = boxOf(i).asInstanceOf[BoxVector].values

            for ((bOpnd, br) <- (bOpnds zip rBs)) {
              doScalar(scalarFromTy, scalarToTy, bOpnd, br)
            }
          }
          case _ => doScalar(fromTy, toTy, boxOf(opnd), boxOf(i))
        }

        incPC()
      }

398
      case i @ InstSelect(condTy, opndTy, cond, ifTrue, ifFalse) => {
399
400
        def doScalar(bCond: ValueBox, bTrue: ValueBox, bFalse: ValueBox, br: ValueBox): Unit = {
          val c = bCond.asInstanceOf[BoxInt].value
401

402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
          if (c == 1) {
            br.copyFrom(bTrue)
          } else {
            br.copyFrom(bFalse)
          }
        }

        condTy match {
          case TypeVector(TypeInt(1), sz) => {
            val bConds = boxOf(cond).asInstanceOf[BoxVector].values
            val bTrues = boxOf(ifTrue).asInstanceOf[BoxVector].values
            val bFalses = boxOf(ifFalse).asInstanceOf[BoxVector].values
            val bResults = boxOf(i).asInstanceOf[BoxVector].values

            for ((((bCond, bTrue), bFalse), br) <- bConds.zip(bTrues).zip(bFalses).zip(bResults)) {
              doScalar(bCond, bTrue, bFalse, br)
            }
          }
          case TypeInt(1) => {
            doScalar(boxOf(cond), boxOf(ifTrue), boxOf(ifFalse), boxOf(i))
          }
423
          case _ => throw new UvmRefImplException(ctx + "Condition must be either int<1> or a vector of int<1>. Found %s".format(condTy))
424
425
426
427
        }

        continueNormally()
      }
Kunshan Wang's avatar
Kunshan Wang committed
428

429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
      case i @ InstBranch(dest) => {
        branchAndMovePC(dest)
      }

      case i @ InstBranch2(cond, ifTrue, ifFalse) => {
        val cv = boxOf(cond).asInstanceOf[BoxInt].value
        val dest = if (cv == 1) ifTrue else ifFalse
        branchAndMovePC(dest)
      }

      case i @ InstSwitch(opndTy, opnd, defDest, cases) => {
        opndTy match {
          case TypeInt(l) => {
            val ov = boxOf(opnd).asInstanceOf[BoxInt].value
            val dest = cases.find(pair => boxOf(pair._1).asInstanceOf[BoxInt].value == ov).map(_._2).getOrElse(defDest)
            branchAndMovePC(dest)
          }
446
          case _ => throw new UvmRefImplException(ctx + "Operand type must be integer. %s found.".format(opndTy))
447
448
449
        }
      }

450
      case i @ InstPhi(_, _) => throw new UvmRefImplException(ctx + "PHI instructions reached in normal execution, " +
451
452
        "but PHI must only appear in the beginning of basic blocks and not in the entry block.")

453
454
455
456
457
458
459
460
      case i @ InstCall(sig, callee, argList, excClause, keepAlives) => {
        val calleeFunc = boxOf(callee).asInstanceOf[BoxFunc].func.getOrElse {
          throw new UvmRuntimeException(ctx + "Callee must not be NULL")
        }

        val funcVer = getFuncDefOrTriggerCallback(calleeFunc)

        val argBoxes = argList.map(boxOf)
Kunshan Wang's avatar
Kunshan Wang committed
461

Kunshan Wang's avatar
Kunshan Wang committed
462
        curInstHalfExecuted = true
463
464
        curStack.pushFrame(funcVer, argBoxes)
      }
Kunshan Wang's avatar
Kunshan Wang committed
465

466
467
468
469
470
471
472
473
474
475
476
      case i @ InstTailCall(sig, callee, argList) => {
        val calleeFunc = boxOf(callee).asInstanceOf[BoxFunc].func.getOrElse {
          throw new UvmRuntimeException(ctx + "Callee must not be NULL")
        }

        val funcVer = getFuncDefOrTriggerCallback(calleeFunc)

        val argBoxes = argList.map(boxOf)

        curStack.replaceTop(funcVer, argBoxes)
      }
Kunshan Wang's avatar
Kunshan Wang committed
477

478
479
480
481
482
      case i @ InstRet(retTy, retVal) => {
        val rvb = boxOf(retVal)
        curStack.popFrame()
        val newCurInst = curInst // in the parent frame of the RET
        boxOf(newCurInst).copyFrom(rvb)
Kunshan Wang's avatar
Kunshan Wang committed
483
        finishHalfExecutedInst()
484
      }
Kunshan Wang's avatar
Kunshan Wang committed
485

486
487
      case i @ InstRetVoid() => {
        curStack.popFrame()
Kunshan Wang's avatar
Kunshan Wang committed
488
        finishHalfExecutedInst()
489
      }
Kunshan Wang's avatar
Kunshan Wang committed
490

Kunshan Wang's avatar
Kunshan Wang committed
491
492
493
494
495
      case i @ InstThrow(excVal) => {
        val exc = boxOf(excVal).asInstanceOf[BoxRef].objRef
        curStack.popFrame()
        catchException(exc)
      }
Kunshan Wang's avatar
Kunshan Wang committed
496

Kunshan Wang's avatar
Kunshan Wang committed
497
498
      case i @ InstLandingPad() => throw new UvmRefImplException(ctx + "LANDINGPAD instructions reached in normal execution, " +
        "but LANDINGPAD must only appear in the beginning of basic blocks and not in the entry block.")
Kunshan Wang's avatar
Kunshan Wang committed
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524

      case i @ InstExtractValue(strTy, index, opnd) => {
        val ob = boxOf(opnd).asInstanceOf[BoxStruct]
        val fb = ob.values(index)
        val ib = boxOf(i)
        ib.copyFrom(fb)
        continueNormally()
      }

      case i @ InstInsertValue(strTy, index, opnd, newVal) => {
        val ob = boxOf(opnd).asInstanceOf[BoxStruct]
        val nvb = boxOf(newVal)
        val ib = boxOf(i).asInstanceOf[BoxStruct]
        for (((ofb, ifb), ind) <- (ob.values zip ib.values).zipWithIndex) {
          if (ind == index) {
            ifb.copyFrom(nvb)
          } else {
            ifb.copyFrom(ofb)
          }
        }
        continueNormally()
      }

      case i @ InstExtractElement(vecTy, indTy, opnd, index) => {
        val ob = boxOf(opnd).asInstanceOf[BoxVector]
        val indb = boxOf(index).asInstanceOf[BoxInt]
525
        val ind = OpHelper.prepareUnsigned(indb.value, indTy.length)
Kunshan Wang's avatar
Kunshan Wang committed
526

527
        if (ind > vecTy.len) {
Kunshan Wang's avatar
Kunshan Wang committed
528
529
530
531
532
533
534
535
536
537
538
539
540
          throw new UvmRuntimeException(ctx + "Index %d out of range. Vector type: %s".format(ind, vecTy))
        }

        val eb = ob.values(ind.intValue())
        val ib = boxOf(i)
        ib.copyFrom(eb)
        continueNormally()
      }

      case i @ InstInsertElement(vecTy, indTy, opnd, index, newVal) => {
        val ob = boxOf(opnd).asInstanceOf[BoxVector]

        val indb = boxOf(index).asInstanceOf[BoxInt]
541
        val ind = OpHelper.prepareUnsigned(indb.value, indTy.length)
Kunshan Wang's avatar
Kunshan Wang committed
542

543
        if (ind > vecTy.len) {
Kunshan Wang's avatar
Kunshan Wang committed
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
          throw new UvmRuntimeException(ctx + "Index %d out of range. Vector type: %s".format(ind, vecTy))
        }

        val indInt = ind.intValue

        val nvb = boxOf(newVal)
        val ib = boxOf(i).asInstanceOf[BoxVector]

        for (((oeb, ieb), ind2) <- (ob.values zip ib.values).zipWithIndex) {
          if (ind2 == indInt) {
            ieb.copyFrom(nvb)
          } else {
            ieb.copyFrom(oeb)
          }
        }
        continueNormally()
      }

      case i @ InstShuffleVector(vecTy, maskTy, vec1, vec2, mask) => {
        val vecLen = vecTy.len.toInt
        val maskIntLen = maskTy.elemTy.asInstanceOf[TypeInt].length
        val vb1 = boxOf(vec1).asInstanceOf[BoxVector]
        val vb2 = boxOf(vec2).asInstanceOf[BoxVector]
        val mb = boxOf(mask).asInstanceOf[BoxVector]
        val ib = boxOf(i).asInstanceOf[BoxVector]

        for (((meb, ieb), ind) <- (mb.values zip ib.values).zipWithIndex) {
571
572
          val me = OpHelper.prepareUnsigned(meb.asInstanceOf[BoxInt].value, maskIntLen)
          if (me < vecLen) {
Kunshan Wang's avatar
Kunshan Wang committed
573
574
575
576
577
578
579
580
581
            ieb.copyFrom(vb1.values(me.intValue))
          } else if (vecLen <= me && me < vecLen * 2) {
            ieb.copyFrom(vb2.values(me.intValue - vecLen))
          } else {
            throw new UvmRuntimeException(ctx + "Index %d as the %d-th element of mask is out of range. Vector type: %s".format(me, ind, vecTy))
          }
        }
        continueNormally()
      }
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

      case i @ InstNew(allocTy, excClause) => {
        handleOutOfMemory(excClause) {
          val addr = mutator.newScalar(allocTy)
          val ib = boxOf(i).asInstanceOf[BoxRef]
          ib.objRef = addr
          continueNormally()
        }
      }

      case i @ InstNewHybrid(allocTy, lenTy, length, excClause) => {
        handleOutOfMemory(excClause) {
          val lb = boxOf(length).asInstanceOf[BoxInt]
          val len = OpHelper.prepareUnsigned(lb.value, lenTy.length)
          val addr = mutator.newHybrid(allocTy, len.longValue)
          val ib = boxOf(i).asInstanceOf[BoxRef]
          ib.objRef = addr
          continueNormally()
        }
      }

      case i @ InstAlloca(allocTy, excClause) => {
        handleOutOfMemory(excClause) {
          val addr = mutator.allocaScalar(curStack.stackMemory, allocTy)
          val ib = boxOf(i).asInstanceOf[BoxIRef]
Kunshan Wang's avatar
Kunshan Wang committed
607
608
          ib.objRef = 0L
          ib.offset = addr
609
610
611
612
613
614
615
616
617
618
          continueNormally()
        }
      }

      case i @ InstAllocaHybrid(allocTy, lenTy, length, excClause) => {
        handleOutOfMemory(excClause) {
          val lb = boxOf(length).asInstanceOf[BoxInt]
          val len = OpHelper.prepareUnsigned(lb.value, lenTy.length)
          val addr = mutator.allocaHybrid(curStack.stackMemory, allocTy, len.longValue)
          val ib = boxOf(i).asInstanceOf[BoxIRef]
Kunshan Wang's avatar
Kunshan Wang committed
619
620
          ib.objRef = 0L
          ib.offset = addr
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
          continueNormally()
        }
      }

      case i @ InstGetIRef(referentTy, opnd) => {
        val ob = boxOf(opnd).asInstanceOf[BoxRef]
        val ib = boxOf(i).asInstanceOf[BoxIRef]
        ib.objRef = ob.objRef
        ib.offset = 0L
        continueNormally()
      }

      case i @ InstGetFieldIRef(referentTy, index, opnd) => {
        val ob = boxOf(opnd).asInstanceOf[BoxIRef]
        val ib = boxOf(i).asInstanceOf[BoxIRef]
        ib.objRef = ob.objRef
        ib.offset = ob.offset + TypeSizes.fieldOffsetOf(referentTy, index)
        continueNormally()
      }

      case i @ InstGetElemIRef(referentTy, indTy, opnd, index) => {
        val ob = boxOf(opnd).asInstanceOf[BoxIRef]
        val indb = boxOf(index).asInstanceOf[BoxInt]
        val ind = OpHelper.prepareSigned(indb.value, indTy.length)
        val ib = boxOf(i).asInstanceOf[BoxIRef]
        ib.objRef = ob.objRef
        ib.offset = ob.offset + TypeSizes.elemOffsetOf(referentTy, ind.longValue())
        continueNormally()
      }

      case i @ InstShiftIRef(referentTy, offTy, opnd, offset) => {
        val ob = boxOf(opnd).asInstanceOf[BoxIRef]
        val offb = boxOf(offset).asInstanceOf[BoxInt]
        val off = OpHelper.prepareSigned(offb.value, offTy.length)
        val ib = boxOf(i).asInstanceOf[BoxIRef]
        ib.objRef = ob.objRef
        ib.offset = ob.offset + TypeSizes.shiftOffsetOf(referentTy, off.longValue())
        continueNormally()
      }
Kunshan Wang's avatar
Kunshan Wang committed
660

661
662
663
664
665
666
667
      case i @ InstGetFixedPartIRef(referentTy, opnd) => {
        val ob = boxOf(opnd).asInstanceOf[BoxIRef]
        val ib = boxOf(i).asInstanceOf[BoxIRef]
        ib.objRef = ob.objRef
        ib.offset = ob.offset
        continueNormally()
      }
Kunshan Wang's avatar
Kunshan Wang committed
668

669
670
671
672
673
674
675
      case i @ InstGetVarPartIRef(referentTy, opnd) => {
        val ob = boxOf(opnd).asInstanceOf[BoxIRef]
        val ib = boxOf(i).asInstanceOf[BoxIRef]
        ib.objRef = ob.objRef
        ib.offset = ob.offset + TypeSizes.varPartOffsetOf(referentTy)
        continueNormally()
      }
Kunshan Wang's avatar
Kunshan Wang committed
676
677

      case i @ InstLoad(ord, referentTy, loc, excClause) => {
Kunshan Wang's avatar
Kunshan Wang committed
678
        val uty = InternalTypePool.unmarkedOf(referentTy)
Kunshan Wang's avatar
Kunshan Wang committed
679
        val lb = boxOf(loc).asInstanceOf[BoxIRef]
Kunshan Wang's avatar
Kunshan Wang committed
680
        val ib = boxOf(i)
681

Kunshan Wang's avatar
Kunshan Wang committed
682
683
684
685
        val la = lb.objRef + lb.offset
        if (la == 0L) {
          nullRefError(excClause)
        } else {
Kunshan Wang's avatar
Kunshan Wang committed
686
687
688
689
          MemoryOperations.load(uty, la, ib, microVM)
          continueNormally()
        }
      }
690

Kunshan Wang's avatar
Kunshan Wang committed
691
692
693
694
695
      case i @ InstStore(ord, referentTy, loc, newVal, excClause) => {
        val uty = InternalTypePool.unmarkedOf(referentTy)
        val lb = boxOf(loc).asInstanceOf[BoxIRef]
        val nvb = boxOf(newVal)
        val ib = boxOf(i)
Kunshan Wang's avatar
Kunshan Wang committed
696

Kunshan Wang's avatar
Kunshan Wang committed
697
698
699
700
701
702
        val la = lb.objRef + lb.offset
        if (la == 0L) {
          nullRefError(excClause)
        } else {
          MemoryOperations.store(uty, la, nvb, ib, microVM)
          continueNormally()
Kunshan Wang's avatar
Kunshan Wang committed
703
        }
Kunshan Wang's avatar
Kunshan Wang committed
704
      }
705

Kunshan Wang's avatar
Kunshan Wang committed
706
707
708
709
710
711
      case i @ InstCmpXchg(weak, ordSucc, ordFail, referentTy, loc, expected, desired, excClause) => {
        val uty = InternalTypePool.unmarkedOf(referentTy)
        val lb = boxOf(loc).asInstanceOf[BoxIRef]
        val eb = boxOf(expected)
        val db = boxOf(desired)
        val ib = boxOf(i)
Kunshan Wang's avatar
Kunshan Wang committed
712

Kunshan Wang's avatar
Kunshan Wang committed
713
714
715
716
717
718
719
720
        val la = lb.objRef + lb.offset
        if (la == 0L) {
          nullRefError(excClause)
        } else {
          MemoryOperations.cmpXchg(uty, la, eb, db, ib, microVM)
          continueNormally()
        }
      }
721

Kunshan Wang's avatar
Kunshan Wang committed
722
723
724
725
726
727
728
729
730
731
732
733
734
735
      case i @ InstAtomicRMW(ord, op, referentTy, loc, opnd, excClause) => {
        val uty = InternalTypePool.unmarkedOf(referentTy)
        val lb = boxOf(loc).asInstanceOf[BoxIRef]
        val ob = boxOf(opnd)
        val ib = boxOf(i)

        val la = lb.objRef + lb.offset
        if (la == 0L) {
          nullRefError(excClause)
        } else {
          MemoryOperations.atomicRMW(uty, op, la, ob, ib, microVM)
          continueNormally()
        }
      }
736

Kunshan Wang's avatar
Kunshan Wang committed
737
738
739
      case i @ InstFence(ord) => {
        // No-op in this interpreter
        continueNormally()
Kunshan Wang's avatar
Kunshan Wang committed
740
741
      }

742
      case i @ InstTrap(retTy, excClause, keepAlives) => {
Kunshan Wang's avatar
Kunshan Wang committed
743
        doTrap(retTy, 0)
Kunshan Wang's avatar
Kunshan Wang committed
744
745
      }

746
747
748
749
      case i @ InstWatchPoint(wpID, retTy, dis, ena, exc, keepAlives) => {
        val isEnabled = microVM.trapManager.isWatchPointEnabled(wpID)

        if (isEnabled) {
Kunshan Wang's avatar
Kunshan Wang committed
750
          doTrap(retTy, wpID)
751
752
753
754
        } else {
          branchAndMovePC(dis)
        }
      }
Kunshan Wang's avatar
Kunshan Wang committed
755

756
757
758
      case i @ InstCCall(callConv, funcTy, sig, callee, argList) => {
        throw new UvmRefImplException(ctx + "The CCALL instruction is not implemented in this reference implementation")
      }
Kunshan Wang's avatar
Kunshan Wang committed
759

760
761
762
763
764
765
766
767
      case i @ InstNewStack(sig, callee, argList, excClause) => {
        val calleeFunc = boxOf(callee).asInstanceOf[BoxFunc].func.getOrElse {
          throw new UvmRuntimeException(ctx + "Stack-bottom function must not be NULL")
        }

        val funcVer = getFuncDefOrTriggerCallback(calleeFunc)

        val argBoxes = argList.map(boxOf)
Kunshan Wang's avatar
Kunshan Wang committed
768

769
770
771
772
773
774
775
776
        val ib = boxOf(i).asInstanceOf[BoxStack]

        handleOutOfMemory(excClause) {
          val sta = microVM.threadStackManager.newStack(funcVer, argBoxes, mutator)
          ib.stack = Some(sta)
          continueNormally()
        }
      }
Kunshan Wang's avatar
Kunshan Wang committed
777

778
      case i @ InstSwapStack(swappee, curStackAction, newStackAction, excClause, keepAlives) => {
Kunshan Wang's avatar
Kunshan Wang committed
779
780
781
782
783
784
785
        val oldStack = curStack
        val newStack = boxOf(swappee).asInstanceOf[BoxStack].stack.getOrElse {
          throw new UvmRuntimeException(ctx + "Swappee must not be NULL.")
        }

        curStackAction match {
          case RetWith(retTy) => {
Kunshan Wang's avatar
Kunshan Wang committed
786
787
            curInstHalfExecuted = true
            unbind(retTy)
Kunshan Wang's avatar
Kunshan Wang committed
788
789
          }
          case KillOld() => {
Kunshan Wang's avatar
Kunshan Wang committed
790
            unbindAndKillStack()
Kunshan Wang's avatar
Kunshan Wang committed
791
792
793
794
795
          }
        }

        newStackAction match {
          case PassValue(argTy, arg) => {
Kunshan Wang's avatar
Kunshan Wang committed
796
797
            val argBox = boxOf(oldStack, arg)
            rebindPassValue(newStack, argBox)
Kunshan Wang's avatar
Kunshan Wang committed
798
799
          }
          case PassVoid() => {
Kunshan Wang's avatar
Kunshan Wang committed
800
801
802
803
804
            rebindPassVoid(newStack)
          }
          case ThrowExc(exc) => {
            val excBox = boxOf(oldStack, exc)
            rebindThrowExc(newStack, excBox)
Kunshan Wang's avatar
Kunshan Wang committed
805
806
          }
        }
807
      }
Kunshan Wang's avatar
Kunshan Wang committed
808

Kunshan Wang's avatar
Kunshan Wang committed
809
810
      case i @ InstCommInst(ci, typeList, argList, excClause, keepAlives) => {
        ci.name.get match {
811
812
813
814
815
816
          // Thread and stack operations
          case "@uvm.new_thread" => {
            val Seq(s) = argList
            val sta = boxOf(s).asInstanceOf[BoxStack].stack.getOrElse {
              throw new UvmRuntimeException(ctx + "Attempt to create new thread on NULL stack.")
            }
817

Kunshan Wang's avatar
Kunshan Wang committed
818
819
820
            if (!sta.state.isInstanceOf[StackState.Ready]) {
              throw new UvmRuntimeException(ctx + "Stack not in READY<T> state. Actual state: %s".format(sta.state))
            }
821

822
823
824
825
            val thr = microVM.threadStackManager.newThread(sta)
            boxOf(i).asInstanceOf[BoxThread].thread = Some(thr)
            continueNormally()
          }
Kunshan Wang's avatar
Kunshan Wang committed
826

827
          case "@uvm.kill_stack" => {
828
829
830
831
832
833
834
            val Seq(s) = argList
            val sta = boxOf(s).asInstanceOf[BoxStack].stack.getOrElse {
              throw new UvmRuntimeException(ctx + "Attempt to kill NULL stack.")
            }
            sta.state = StackState.Dead
            continueNormally()
          }
Kunshan Wang's avatar
Kunshan Wang committed
835

Kunshan Wang's avatar
Kunshan Wang committed
836
837
838
          case "@uvm.thread_exit" => {
            threadExit()
          }
839

Kunshan Wang's avatar
Kunshan Wang committed
840
841
842
843
844
          case "@uvm.current_stack" => {
            val bi = boxOf(i)
            bi.asInstanceOf[BoxStack].stack = stack
            continueNormally()
          }
Kunshan Wang's avatar
Kunshan Wang committed
845

846
          // 64-bit Tagged Reference
Kunshan Wang's avatar
Kunshan Wang committed
847

848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
          case "@uvm.tr64.is_fp" => {
            val Seq(tr) = argList
            val raw = boxOf(tr).asInstanceOf[BoxTagRef64].raw
            val result = OpHelper.tr64IsFp(raw)
            writeBooleanResult(result, boxOf(i))
            continueNormally()
          }

          case "@uvm.tr64.is_int" => {
            val Seq(tr) = argList
            val raw = boxOf(tr).asInstanceOf[BoxTagRef64].raw
            val result = OpHelper.tr64IsInt(raw)
            writeBooleanResult(result, boxOf(i))
            continueNormally()
          }

          case "@uvm.tr64.is_ref" => {
            val Seq(tr) = argList
            val raw = boxOf(tr).asInstanceOf[BoxTagRef64].raw
            val result = OpHelper.tr64IsRef(raw)
            writeBooleanResult(result, boxOf(i))
            continueNormally()
          }
Kunshan Wang's avatar
Kunshan Wang committed
871

872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
          case "@uvm.tr64.from_fp" => {
            val Seq(v) = argList
            val vFP = boxOf(v).asInstanceOf[BoxDouble].value
            val raw = OpHelper.fpToTr64(vFP)
            boxOf(i).asInstanceOf[BoxTagRef64].raw = raw
            continueNormally()
          }

          case "@uvm.tr64.from_int" => {
            val Seq(v) = argList
            val vInt = OpHelper.prepareUnsigned(boxOf(v).asInstanceOf[BoxInt].value, 52)
            val raw = OpHelper.intToTr64(vInt.longValue())
            boxOf(i).asInstanceOf[BoxTagRef64].raw = raw
            continueNormally()
          }

          case "@uvm.tr64.from_ref" => {
            val Seq(ref, tag) = argList
            val vRef = boxOf(ref).asInstanceOf[BoxRef].objRef
            val vTag = OpHelper.prepareUnsigned(boxOf(tag).asInstanceOf[BoxInt].value, 6)
            val raw = OpHelper.refToTr64(vRef, vTag.longValue())
            boxOf(i).asInstanceOf[BoxTagRef64].raw = raw
            continueNormally()
          }
Kunshan Wang's avatar
Kunshan Wang committed
896

897
898
899
900
901
902
903
904
905
906
907
          case "@uvm.tr64.to_fp" => {
            val Seq(tr) = argList
            val raw = boxOf(tr).asInstanceOf[BoxTagRef64].raw
            if (OpHelper.tr64IsFp(raw)) {
              val result = OpHelper.tr64ToFp(raw)
              boxOf(i).asInstanceOf[BoxDouble].value = result
              continueNormally()
            } else {
              throw new UvmRuntimeException(ctx + "Attempt to extract double from a tagref64 which is not holding a double")
            }
          }
Kunshan Wang's avatar
Kunshan Wang committed
908

909
910
911
912
913
914
915
916
917
918
919
          case "@uvm.tr64.to_int" => {
            val Seq(tr) = argList
            val raw = boxOf(tr).asInstanceOf[BoxTagRef64].raw
            if (OpHelper.tr64IsInt(raw)) {
              val result = OpHelper.tr64ToInt(raw)
              boxOf(i).asInstanceOf[BoxInt].value = OpHelper.unprepare(result, 52)
              continueNormally()
            } else {
              throw new UvmRuntimeException(ctx + "Attempt to extract int from a tagref64 which is not holding a int")
            }
          }
Kunshan Wang's avatar
Kunshan Wang committed
920

921
922
923
924
925
926
927
928
929
930
931
          case "@uvm.tr64.to_ref" => {
            val Seq(tr) = argList
            val raw = boxOf(tr).asInstanceOf[BoxTagRef64].raw
            if (OpHelper.tr64IsRef(raw)) {
              val result = OpHelper.tr64ToRef(raw)
              boxOf(i).asInstanceOf[BoxRef].objRef = result
              continueNormally()
            } else {
              throw new UvmRuntimeException(ctx + "Attempt to extract ref from a tagref64 which is not holding a ref")
            }
          }
Kunshan Wang's avatar
Kunshan Wang committed
932

933
934
935
936
937
938
939
940
941
942
943
          case "@uvm.tr64.to_tag" => {
            val Seq(tr) = argList
            val raw = boxOf(tr).asInstanceOf[BoxTagRef64].raw
            if (OpHelper.tr64IsRef(raw)) {
              val result = OpHelper.tr64ToTag(raw)
              boxOf(i).asInstanceOf[BoxInt].value = OpHelper.unprepare(result, 6)
              continueNormally()
            } else {
              throw new UvmRuntimeException(ctx + "Attempt to extract tag from a tagref64 which is not holding a ref")
            }
          }
Kunshan Wang's avatar
Kunshan Wang committed
944

Kunshan Wang's avatar
Kunshan Wang committed
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
          case "@uvm.futex.wait" => {
            val Seq(ty) = typeList
            val Seq(loc, v) = argList

            val len = ty.asInstanceOf[TypeInt].length
            val bLoc = boxOf(loc).asInstanceOf[BoxIRef]
            val objRef = bLoc.objRef
            val offset = bLoc.offset
            val locWord = objRef + offset
            val bv = boxOf(v).asInstanceOf[BoxInt]

            val equal = MemoryOperations.cmpInt(len, locWord, bv)

            if (equal) {
              microVM.threadStackManager.futexManager.futexWaitNoCheck(objRef, offset, this, None)
              logger.debug(ctx + "Waiting in the futex waiting queue.")
            } else {
              logger.debug(ctx + "Memory location does not contain expected value. Don't wait.")
              futexReturn(-1)
            }
          }

          case "@uvm.futex.wait_timeout" => {
            val Seq(ty) = typeList
            val Seq(loc, v, timeout) = argList

            val len = ty.asInstanceOf[TypeInt].length
            val bLoc = boxOf(loc).asInstanceOf[BoxIRef]
            val objRef = bLoc.objRef
            val offset = bLoc.offset
            val locWord = objRef + offset
            val bv = boxOf(v).asInstanceOf[BoxInt]
            val bto = boxOf(timeout).asInstanceOf[BoxInt]
            val toVal = OpHelper.prepareSigned(bto.value, 64).longValue

            if (toVal < 0L) throw new UvmRefImplException(ctx + "This refimpl treats timeout as signed due to restriction of Java.")

            val equal = MemoryOperations.cmpInt(len, locWord, bv)

            if (equal) {
              microVM.threadStackManager.futexManager.futexWaitNoCheck(objRef, offset, this, Some(toVal))
              logger.debug(ctx + "Waiting in the futex waiting queue.")
            } else {
              logger.debug(ctx + "Memory location does not contain expected value. Don't wait.")
              futexReturn(-1)
            }
          }

          case "@uvm.futex.wake" => {
            val Seq(ty) = typeList
            val Seq(loc, nthread) = argList

            val len = ty.asInstanceOf[TypeInt].length
            val bLoc = boxOf(loc).asInstanceOf[BoxIRef]
            val objRef = bLoc.objRef
            val offset = bLoc.offset
            val locWord = objRef + offset
            val nth = OpHelper.prepareSigned(boxOf(nthread).asInstanceOf[BoxInt].value, 32).intValue

            if (nth < 0) throw new UvmRuntimeException(ctx + "nthread must not be negative")

            val nWoken = microVM.threadStackManager.futexManager.futexWake(objRef, offset, nth)
            futexReturn(nWoken)
          }

          case "@uvm.futex.cmp_requeue" => {
            val Seq(ty) = typeList
            val Seq(locSrc, locDst, expected, nthread) = argList

            val len = ty.asInstanceOf[TypeInt].length
            val (objRefSrc, offsetSrc) = boxOf(locSrc).asInstanceOf[BoxIRef].oo
            val (objRefDst, offsetDst) = boxOf(locDst).asInstanceOf[BoxIRef].oo
            val bExp = boxOf(expected).asInstanceOf[BoxInt]
            val nth = OpHelper.prepareSigned(boxOf(nthread).asInstanceOf[BoxInt].value, 32).intValue

            if (nth < 0) throw new UvmRuntimeException(ctx + "nthread must not be negative")

            val equal = MemoryOperations.cmpInt(len, objRefSrc + offsetSrc, bExp)

            if (equal) {
              val nWoken = microVM.threadStackManager.futexManager.futexRequeue(objRefSrc, offsetSrc, objRefDst, offsetDst, nth)
              futexReturn(nWoken)
            } else {
              futexReturn(-1)
            }
          }

1032
1033
1034
1035
1036
1037
          case "@uvm.kill_dependency" => {
            val Seq(v) = argList
            val vBox = boxOf(v)
            boxOf(i).copyFrom(vBox)
            continueNormally()
          }
1038

1039
1040
          // Insert more CommInsts here.

Kunshan Wang's avatar
Kunshan Wang committed
1041
1042
1043
1044
1045
1046
          case ciName => {
            throw new UvmRefImplException("Unimplemented common instruction %s".format(ciName))
          }

        }
      }
Kunshan Wang's avatar
Kunshan Wang committed
1047

Kunshan Wang's avatar
Kunshan Wang committed
1048
1049
1050
1051
      case i => {
        throw new UvmRefImplException("Unimplemented instruction %s".format(i.getClass.getName))
      }
    }
Kunshan Wang's avatar
Kunshan Wang committed
1052
1053
  } catch {
    case e: Exception => {
1054
      logger.error(ctx + "Exception thrown while interpreting instruction.")
Kunshan Wang's avatar
Kunshan Wang committed
1055
1056
      throw e
    }
Kunshan Wang's avatar
Kunshan Wang committed
1057
  }
Kunshan Wang's avatar
Kunshan Wang committed
1058

Kunshan Wang's avatar
Kunshan Wang committed
1059
  // Control flow helpers
Kunshan Wang's avatar
Kunshan Wang committed
1060

Kunshan Wang's avatar
Kunshan Wang committed
1061
1062
  /** Branch to a basic block and execute starter instructions (PHI and LANDINGPAD). */
  private def branchAndMovePC(dest: BasicBlock, excAddr: Word = 0L): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
1063
1064
1065
    val curBB = this.curBB
    var cont = true
    var i = 0
1066
1067

    // Determine the value of edge-assigned instructions (phis and landingpads), but keep them in their temporary boxes.
Kunshan Wang's avatar
Kunshan Wang committed
1068
1069
1070
    while (cont) {
      dest.insts(i) match {
        case phi @ InstPhi(opndTy, cases) => {
1071
          val caseVal = cases.find(_._1 == curBB).map(_._2).getOrElse {
Kunshan Wang's avatar
Kunshan Wang committed
1072
1073
1074
            throw new UvmRuntimeException(s"Phi node ${phi.repr} does not include the case for source basic block ${curBB.repr}")
          }
          val vb = boxOf(caseVal)
1075
          val db = edgeAssignedBoxOf(phi)
Kunshan Wang's avatar
Kunshan Wang committed
1076
1077
1078
1079
          db.copyFrom(vb)
          i += 1
        }
        case lp: InstLandingPad => {
1080
          val db = edgeAssignedBoxOf(lp).asInstanceOf[BoxRef]
Kunshan Wang's avatar
Kunshan Wang committed
1081
1082
1083
1084
1085
1086
          db.objRef = excAddr
          i += 1
        }
        case _ => cont = false
      }
    }
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096

    // Copy the values of edge-assigned instructions (phis and landingpads) to their canonical boxes.
    for (j <- 0 until i) {
      val destInst = dest.insts(j)
      val sb = edgeAssignedBoxOf(destInst.asInstanceOf[EdgeAssigned])
      val db = boxOf(destInst)
      db.copyFrom(sb)
    }

    // Continue execution
Kunshan Wang's avatar
Kunshan Wang committed
1097
1098
    jump(dest, i)
  }
1099

Kunshan Wang's avatar
Kunshan Wang committed
1100
1101
  /** Continue normally. Work for all instructions. */
  private def continueNormally(): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
1102
    curInst match {
1103
      case wp: InstWatchPoint => {
1104
1105
1106
1107
1108
        branchAndMovePC(wp.ena)
        // NOTE: WatchPoint only "continue normally" when the current stack is rebound with value or void.
        // This includes executing a watch point. In any case, this watch point must have been enabled. If the watch
        // point is disabled during the course the stack is unbound, this watch point should still continue from the
        // destination determined WHEN THIS INSTRUCTION IS EXECUTED.
1109
      }
Kunshan Wang's avatar
Kunshan Wang committed
1110
1111
1112
1113
1114
1115
1116
      case h: HasExcClause => h.excClause match {
        case None => incPC()
        case Some(ec) => {
          branchAndMovePC(ec.nor)
        }
      }
      case _ => incPC()
Kunshan Wang's avatar
Kunshan Wang committed
1117
1118
    }
  }
Kunshan Wang's avatar
Kunshan Wang committed
1119
1120
1121
1122
1123
1124
1125

  /**
   * Finish a half-executed instruction. Some instructions (CALL, SWAPSTACK, TRAP, WATCHPOINT) can be half-executed
   *  because of switching to another stack. This function is called on the swappee. If the current instruction is not
   *  half-executed (the only case is executing a newly created stack or a newly pushed frame), it does nothing.
   */
  private def finishHalfExecutedInst(): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
1126
1127
1128
    if (curInstHalfExecuted) {
      curInstHalfExecuted = false
      continueNormally()
1129
1130
    }
  }
Kunshan Wang's avatar
Kunshan Wang committed
1131

1132
1133
  /**
   * Attempt to catch exception in the current frame. Will repeatedly unwind the stack until the exception can be
Kunshan Wang's avatar
Kunshan Wang committed
1134
   * handled. Stack underflow is an undefined behaviour.
1135
   */
Kunshan Wang's avatar
Kunshan Wang committed
1136
  private def catchException(exc: Word): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
1137
1138
1139
1140
1141
    @tailrec
    def unwindUntilCatchable(f: InterpreterFrame): (InterpreterFrame, BasicBlock) = {
      maybeFindExceptionHandler(f.curInst) match {
        case Some(bb) => (f, bb)
        case None => f.prev match {
1142
          case None       => throw new UvmRuntimeException(ctx + "Exception is thrown out of the bottom frame.")
Kunshan Wang's avatar
Kunshan Wang committed
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
          case Some(prev) => unwindUntilCatchable(prev)
        }
      }
    }

    val s = curStack
    val f = s.top
    val (newFrame, newBB) = unwindUntilCatchable(f)
    s.top = newFrame

    branchAndMovePC(newBB, exc)
Kunshan Wang's avatar
Kunshan Wang committed
1154
    curInstHalfExecuted = false
Kunshan Wang's avatar
Kunshan Wang committed
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
  }

  /**
   * Test if the current frame with i as the current instruction can catch an exception that unwinds the stack.
   *
   * @return Return Some(h) if i can catch the exception and h is the basic block for the exception. Return None if i
   * cannot catch exceptions.
   *
   * @throw Throw UvmRefimplException if a frame stops at an unexpected instruction. Normally the top frame can be
   * executing TRAP, WATCHPOINT, SWAPSTACK or CALL and all other frames must be executing CALL.
   */
Kunshan Wang's avatar
Kunshan Wang committed
1166
  private def maybeFindExceptionHandler(inst: Instruction): Option[BasicBlock] = {
Kunshan Wang's avatar
Kunshan Wang committed
1167
    inst match {
1168
1169
      case i: InstCall       => i.excClause.map(_.exc)
      case i: InstTrap       => i.excClause.map(_.exc)
Kunshan Wang's avatar
Kunshan Wang committed
1170
      case i: InstWatchPoint => i.exc
1171
      case i: InstSwapStack  => i.excClause.map(_.exc)
Kunshan Wang's avatar
Kunshan Wang committed
1172
      case _ => {
1173
        throw new UvmRefImplException(ctx + "Instruction %s (%s) is in a stack frame when an exception is thrown.".format(inst.repr, inst.getClass.getName))
Kunshan Wang's avatar
Kunshan Wang committed
1174
1175
      }
    }
1176
  }
1177

1178
  // Misc helper
Kunshan Wang's avatar
Kunshan Wang committed
1179

1180
1181
1182
1183
  private def writeBooleanResult(result: Boolean, box: ValueBox): Unit = {
    box.asInstanceOf[BoxInt].value = if (result) 1 else 0
  }

Kunshan Wang's avatar
Kunshan Wang committed
1184
1185
1186
1187
  private def writeIntResult(len: Int, result: BigInt, box: ValueBox): Unit = {
    box.asInstanceOf[BoxInt].value = OpHelper.unprepare(result, len)
  }

Kunshan Wang's avatar
Kunshan Wang committed
1188
1189
1190
1191
1192
1193
1194
1195
  // Thread termination

  /** Terminate the thread. Please only let the thread terminate itself. */
  private def threadExit(): Unit = {
    curStack.state = StackState.Dead
    isRunning = false
  }

Kunshan Wang's avatar
Kunshan Wang committed
1196
  // Thread/stack binding and unbinding
Kunshan Wang's avatar
Kunshan Wang committed
1197
1198
1199

  /** Unbind the current thread from the stack. */
  private def unbind(readyType: Type): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
1200
1201
1202
1203
    curStack.state = StackState.Ready(readyType)
    stack = None
  }

Kunshan Wang's avatar
Kunshan Wang committed
1204
1205
  /** Unbind and kill the current stack. */
  private def unbindAndKillStack(): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
1206
1207
1208
1209
    curStack.state = StackState.Dead
    stack = None
  }

Kunshan Wang's avatar
Kunshan Wang committed
1210
1211
  /** Rebind to a stack. */
  private def rebind(newStack: InterpreterStack): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
1212
    stack = Some(newStack)
Kunshan Wang's avatar
Kunshan Wang committed
1213
    curStack.state = StackState.Running
Kunshan Wang's avatar
Kunshan Wang committed
1214
1215
  }

Kunshan Wang's avatar
Kunshan Wang committed
1216
1217
  /** Rebind to a stack and pass a value. */
  private def rebindPassValue(newStack: InterpreterStack, value: ValueBox): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
    rebind(newStack)

    try {
      boxOf(curInst).copyFrom(value)
    } catch {
      case e: Exception => {
        throw new UvmRuntimeException(ctx + "Error during rebinding while assigning the value passed to a stack " +
          "to the instruction waiting for rebinding. This is usually caused by the mismatching between the type of " +
          "READY<T> and the actual value type. The passed value box is a %s.".format(value.getClass.getName), e)
      }
    }

    finishHalfExecutedInst()
  }

Kunshan Wang's avatar
Kunshan Wang committed
1233
1234
  /** Rebind to a stack and pass void. */
  private def rebindPassVoid(newStack: InterpreterStack): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
1235
1236
1237
1238
1239
    rebind(newStack)

    finishHalfExecutedInst()
  }

Kunshan Wang's avatar
Kunshan Wang committed
1240
1241
  /** Rebind to a stack and throw an exception on that stack. */
  private def rebindThrowExc(newStack: InterpreterStack, exc: ValueBox): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
1242
1243
1244
1245
1246
1247
    rebind(newStack)

    val excObjRef = exc.asInstanceOf[BoxRef].objRef

    catchException(excObjRef)
  }
Kunshan Wang's avatar
Kunshan Wang committed
1248

Kunshan Wang's avatar
Kunshan Wang committed
1249
1250
  // Trap and watchpoint handling

Kunshan Wang's avatar
Kunshan Wang committed
1251
1252
  /** Execute the trap handler in the Client. Work for both TRAP and WATCHPOINT. */
  private def doTrap(retTy: uvm.types.Type, wpID: Int) = {
Kunshan Wang's avatar
Kunshan Wang committed
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
    val curCtx = ctx // save the context string for debugging

    val ca = microVM.newClientAgent()

    val hThread = ca.putThread(Some(this))
    val hStack = ca.putStack(Some(curStack))