InstructionExecutor.scala 22.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
package uvm.refimpl.itpr

import uvm._
import uvm.comminsts._
import uvm.refimpl._
import uvm.refimpl.mem._
import uvm.ssavariables._
import uvm.types._

/**
 * Part of the InterpreterThread. It isolates the GIANT case-matching function.
 */
Kunshan Wang's avatar
Kunshan Wang committed
13
trait InstructionExecutor extends InterpreterActions with CommInstExecutor {
14 15
  import InterpreterThread.logger

Kunshan Wang's avatar
Kunshan Wang committed
16 17 18
  protected def mutator: Mutator
  implicit protected def microVM: MicroVM
  implicit protected def memorySupport: MemorySupport
19 20

  /** Interpret the current instruction. */
Kunshan Wang's avatar
Kunshan Wang committed
21
  protected def interpretCurrentInstruction(): Unit = try {
22
    logger.debug(ctx + "Executing instruction...")
Kunshan Wang's avatar
Kunshan Wang committed
23
    
Kunshan Wang's avatar
Kunshan Wang committed
24 25 26
    val statInstName = curInst.getClass.getSimpleName
    
    microVM.stats.onInstExec(statInstName)
27 28

    curInst match {
29
      case i @ InstBinOp(op, flags, opndTy, op1, op2, excClause) => {
Kunshan Wang's avatar
Kunshan Wang committed
30 31
        val statOpName = op.toString()
        microVM.stats.onInstExec(statInstName + "/" + statOpName)
32

33 34
        def doScalar(scalarTy: Type, b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
          scalarTy match {
35 36 37 38
            case TypeInt(l)   => br.asIntRaw = PrimOpHelpers.intBinOp(op, l, b1.asIntRaw, b2.asIntRaw, ctx)
            case TypeFloat()  => br.asFloat = PrimOpHelpers.floatBinOp(op, b1.asFloat, b2.asFloat, ctx)
            case TypeDouble() => br.asDouble = PrimOpHelpers.doubleBinOp(op, b1.asDouble, b2.asDouble, ctx)
            case _            => throw new UvmRuntimeException(ctx + "BinOp not suitable for type %s".format(scalarTy))
39 40
          }
        }
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
        
        def doFlags(): Unit = {
          val (n, z, c, v) = opndTy match {
            case TypeInt(l)   => PrimOpHelpers.intBinOpFlags(op, l, op1.asIntRaw, op2.asIntRaw, results(0).asIntRaw, ctx)
            case _            => throw new UvmRuntimeException(ctx + "BinOp flags are only applicable to scalar integer types. Actual type: %s".format(opndTy))
          }

          var nextResultIndex = 1
          for ((bit, res) <- BinOpStatus.ALL_FLAGS zip Seq(n,z,c,v)) {
            if ((flags & bit) != 0) {
              val resultIndex = nextResultIndex
              nextResultIndex += 1
              results(resultIndex).asBoolean = res
            }
          }
        }
57 58 59 60

        try {
          opndTy match {
            case TypeVector(scalarTy, sz) => {
61
              for (((b1, b2), br) <- ((op1.asSeq zip op2.asSeq) zip results(0).asSeq)) {
62 63 64
                doScalar(scalarTy, b1, b2, br)
              }
            }
65 66 67 68 69 70
            case scalarTy => {
              doScalar(scalarTy, op1, op2, results(0))
              if (flags != 0) {
                doFlags()
              }
            }
71 72 73 74 75 76 77 78 79 80 81 82 83
          }
          continueNormally()
        } catch {
          case e: UvmDivisionByZeroException => excClause match {
            case None => throw e
            case Some(ec) => {
              branchTo(ec.exc)
            }
          }
        }
      }

      case i @ InstCmp(op, opndTy, op1, op2) => {
Kunshan Wang's avatar
Kunshan Wang committed
84 85 86
        val statOpName = op.toString()
        microVM.stats.onInstExec(statInstName + "/" + statOpName)

87
        def doScalar(scalarTy: Type, b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
88 89 90 91 92 93 94 95 96 97 98 99 100
          br.asBoolean = scalarTy match {
            case TypeInt(l)      => PrimOpHelpers.intCmp(op, l, b1.asIntRaw, b2.asIntRaw, ctx)
            case TypeFloat()     => PrimOpHelpers.floatCmp(op, b1.asFloat, b2.asFloat, ctx)
            case TypeDouble()    => PrimOpHelpers.doubleCmp(op, b1.asDouble, b2.asDouble, ctx)
            case TypeRef(_)      => PrimOpHelpers.refCmp(op, b1.asRef, b2.asRef, ctx)
            case TypeFuncRef(_)  => PrimOpHelpers.objCmp(op, b1.asFunc, b2.asFunc, "funcref", ctx)
            case TypeStackRef()  => PrimOpHelpers.objCmp(op, b1.asStack, b2.asStack, "stackref", ctx)
            case TypeThreadRef() => PrimOpHelpers.objCmp(op, b1.asThread, b2.asThread, "threadref", ctx)
            case TypeIRef(_) => {
              val (op1b, op1o) = b1.asIRef
              val (op2b, op2o) = b2.asIRef
              PrimOpHelpers.irefCmp(op, op1b, op1o, op2b, op2o, ctx)
            }
101
            case t:AbstractPointerType  => PrimOpHelpers.intCmp(op, WORD_SIZE_BITS.toInt, b1.asPtr, b2.asPtr, ctx)
102
            case _ => throw new UvmRuntimeException(ctx + "Comparison not suitable for type %s".format(opndTy))
103 104 105 106 107
          }
        }

        opndTy match {
          case TypeVector(scalarTy, sz) => {
108
            for (((b1, b2), br) <- ((op1.asSeq zip op2.asSeq) zip results(0).asSeq)) {
109 110 111
              doScalar(scalarTy, b1, b2, br)
            }
          }
112
          case scalarTy => doScalar(scalarTy, op1, op2, results(0))
113 114 115 116 117 118
        }

        continueNormally()
      }

      case i @ InstConv(op, fromTy, toTy, opnd) => {
Kunshan Wang's avatar
Kunshan Wang committed
119 120 121
        val statOpName = op.toString()
        microVM.stats.onInstExec(statInstName + "/" + statOpName)

122 123 124
        def doScalar(scalarFromTy: Type, scalarToTy: Type, bOpnd: ValueBox, br: ValueBox): Unit = {
          def iToI(): Unit = (scalarFromTy, scalarToTy) match {
            case (TypeInt(fl), TypeInt(tl)) => {
125
              val od = bOpnd.asIntRaw
126 127 128 129 130
              val result = op match {
                case ConvOptr.TRUNC => OpHelper.trunc(od, tl)
                case ConvOptr.ZEXT  => OpHelper.zext(od, fl, tl)
                case ConvOptr.SEXT  => OpHelper.sext(od, fl, tl)
              }
131
              br.asIntRaw = result
132 133 134 135 136 137 138 139 140 141
            }
            case _ => throw new UvmRuntimeException(ctx + "Expect integer source and dest type. Found %s and %s".format(scalarFromTy, scalarToTy))
          }

          def fpToI(signed: Boolean): Unit = {
            val tl = scalarToTy match {
              case TypeInt(l) => l
              case _          => throw new UvmRuntimeException(ctx + "Expect integer dest type. Found %s".format(scalarToTy))
            }
            val result = scalarFromTy match {
142 143
              case TypeFloat()  => OpHelper.floatToI(bOpnd.asFloat, tl, signed)
              case TypeDouble() => OpHelper.doubleToI(bOpnd.asDouble, tl, signed)
144 145
              case _            => throw new UvmRuntimeException(ctx + "Expect FP source type. Found %s.".format(scalarFromTy))
            }
146
            br.asIntRaw = result
147 148 149 150 151 152 153
          }

          def iToFP(signed: Boolean): Unit = {
            val fl = scalarFromTy match {
              case TypeInt(l) => l
              case _          => throw new UvmRuntimeException(ctx + "Expect integer source type. Found %s".format(scalarFromTy))
            }
154
            val od = bOpnd.asIntRaw
155 156
            val extended = if (signed) OpHelper.prepareSigned(od, fl) else OpHelper.prepareUnsigned(od, fl)
            scalarToTy match {
157 158 159
              case TypeFloat()  => br.asFloat = extended.toFloat
              case TypeDouble() => br.asDouble = extended.toDouble
              case _            => throw new UvmRuntimeException(ctx + "Expect FP dest type. Found %s.".format(scalarToTy))
160 161 162 163
            }
          }

          def bitcast(): Unit = (scalarFromTy, scalarToTy) match {
164 165 166 167
            case (TypeInt(32), TypeFloat())  => br.asFloat = java.lang.Float.intBitsToFloat(bOpnd.asIntRaw.intValue)
            case (TypeInt(64), TypeDouble()) => br.asDouble = java.lang.Double.longBitsToDouble(bOpnd.asIntRaw.longValue)
            case (TypeFloat(), TypeInt(32))  => br.asInt32 = java.lang.Float.floatToRawIntBits(bOpnd.asFloat)
            case (TypeDouble(), TypeInt(64)) => br.asInt64 = java.lang.Double.doubleToRawLongBits(bOpnd.asDouble)
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
            case _ => throw new UvmRuntimeException(ctx +
              "BITCAST can only convert between int and FP types of the same size. Found %s and %s.".format(scalarFromTy, scalarToTy))
          }

          def refcast(): Unit = (scalarFromTy, scalarToTy) match {
            case (TypeRef(_), TypeRef(_))         => br.copyFrom(bOpnd)
            case (TypeIRef(_), TypeIRef(_))       => br.copyFrom(bOpnd)
            case (TypeFuncRef(_), TypeFuncRef(_)) => br.copyFrom(bOpnd)
            case _ => throw new UvmRuntimeException(ctx +
              "REFCAST can only convert between two types both of which are ref, iref, or func. Found %s and %s.".format(scalarFromTy, scalarToTy))
          }

          def ptrcast(): Unit = {
            (scalarFromTy, scalarToTy) match {
              case (TypeInt(_), TypeInt(_)) => throw new UvmRuntimeException(ctx +
                "PTRCAST cannot convert between two int types. Found %s and %s.".format(scalarFromTy, scalarToTy))
              case _ =>
            }
            val srcAddr: Word = scalarFromTy match {
187 188
              case TypeInt(n)             => bOpnd.getUInt(n).longValue // truncates
              case _: AbstractPointerType => bOpnd.asPtr
189 190
            }
            scalarToTy match {
191 192
              case TypeInt(n)             => br.setInt(srcAddr, Math.min(n, 64))
              case _: AbstractPointerType => br.asPtr = srcAddr
193 194 195 196
            }
          }

          op match {
197 198 199 200 201
            case ConvOptr.TRUNC   => iToI()
            case ConvOptr.ZEXT    => iToI()
            case ConvOptr.SEXT    => iToI()
            case ConvOptr.FPTRUNC => br.asFloat = bOpnd.asDouble.toFloat
            case ConvOptr.FPEXT   => br.asDouble = bOpnd.asFloat.toDouble
202 203 204 205 206 207 208 209 210 211 212 213 214 215
            case ConvOptr.FPTOUI  => fpToI(signed = false)
            case ConvOptr.FPTOSI  => fpToI(signed = true)
            case ConvOptr.UITOFP  => iToFP(signed = false)
            case ConvOptr.SITOFP  => iToFP(signed = true)
            case ConvOptr.BITCAST => bitcast()
            case ConvOptr.REFCAST => refcast()
            case ConvOptr.PTRCAST => ptrcast()
          }
        }

        (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")

216
            for ((bOpnd, br) <- (opnd.asSeq zip results(0).asSeq)) {
217 218 219
              doScalar(scalarFromTy, scalarToTy, bOpnd, br)
            }
          }
220
          case _ => doScalar(fromTy, toTy, opnd, results(0))
221 222 223 224 225 226 227
        }

        incPC()
      }

      case i @ InstSelect(condTy, opndTy, cond, ifTrue, ifFalse) => {
        def doScalar(bCond: ValueBox, bTrue: ValueBox, bFalse: ValueBox, br: ValueBox): Unit = {
228
          if (bCond.asBoolean) {
229 230 231 232 233 234 235 236
            br.copyFrom(bTrue)
          } else {
            br.copyFrom(bFalse)
          }
        }

        condTy match {
          case TypeVector(TypeInt(1), sz) => {
237
            for ((((bCond, bTrue), bFalse), br) <- (cond.asSeq zip ifTrue.asSeq zip ifFalse.asSeq zip results(0).asSeq)) {
238 239 240 241
              doScalar(bCond, bTrue, bFalse, br)
            }
          }
          case TypeInt(1) => {
242
            doScalar(cond, ifTrue, ifFalse, results(0))
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
          }
          case _ => throw new UvmRefImplException(ctx + "Condition must be either int<1> or a vector of int<1>. Found %s".format(condTy))
        }

        continueNormally()
      }

      case i @ InstBranch(dest) => {
        branchTo(dest)
      }

      case i @ InstBranch2(cond, ifTrue, ifFalse) => {
        val cv = boxOf(cond).asInstanceOf[BoxInt].value
        val dest = if (cv == 1) ifTrue else ifFalse
        branchTo(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)
            branchTo(dest)
          }
          case _ => throw new UvmRefImplException(ctx + "Operand type must be integer. %s found.".format(opndTy))
        }
      }

Kunshan Wang's avatar
Kunshan Wang committed
271
      case i @ InstCall(sig, callee, argList, excClause, keepalives) => {
272
        val calleeFunc = callee.asFunc.getOrElse {
273
          throw new UvmNullGenRefException(ctx + "Callee must not be NULL")
274 275 276
        }

        val argBoxes = argList.map(boxOf)
Kunshan Wang's avatar
Kunshan Wang committed
277 278 279 280
        
        if (i.excClause.isDefined) {
          microVM.stats.peiCalled += 1
        }
281 282 283

        val shouldIncrementPC = curStack.callMu(calleeFunc, argBoxes)
        if (shouldIncrementPC) {
284
          throw new UvmRefImplException(ctx + "Should not continue normally immediately after calling")
285 286 287 288
        }
      }

      case i @ InstTailCall(sig, callee, argList) => {
289
        val calleeFunc = callee.asFunc.getOrElse {
290
          throw new UvmNullGenRefException(ctx + "Callee must not be NULL")
291 292 293 294 295 296
        }

        val argBoxes = argList.map(boxOf)

        val shouldIncrementPC = curStack.tailCallMu(calleeFunc, argBoxes)
        if (shouldIncrementPC) {
297
          throw new UvmRefImplException(ctx + "Should not continue normally immediately after tail-calling")
298 299 300 301 302 303 304 305 306 307 308 309
        }
      }

      case i @ InstRet(funcVer, retVals) => {
        val rvbs = retVals.map(boxOf)
        val shouldIncrementPC = curStack.retFromMu(rvbs)
        if (shouldIncrementPC) {
          continueNormally()
        }
      }

      case i @ InstThrow(excVal) => {
310
        val exc = excVal.asRef
311
        curStack.popMuFrameForThrow()
312 313 314 315
        catchException(exc)
      }

      case i @ InstExtractValue(strTy, index, opnd) => {
316
        results(0) copyFrom opnd.asSeq(index)
317 318 319 320 321
        continueNormally()
      }

      case i @ InstInsertValue(strTy, index, opnd, newVal) => {
        val nvb = boxOf(newVal)
322
        for (((ofb, ifb), ind) <- (opnd.asSeq zip results(0).asSeq).zipWithIndex) {
323 324 325 326 327 328 329 330 331 332
          if (ind == index) {
            ifb.copyFrom(nvb)
          } else {
            ifb.copyFrom(ofb)
          }
        }
        continueNormally()
      }

      case i @ InstExtractElement(vecTy, indTy, opnd, index) => {
333
        val ind = index.getUInt(indTy.length).toLong
334 335 336 337 338

        if (ind > vecTy.len) {
          throw new UvmRuntimeException(ctx + "Index %d out of range. Vector type: %s".format(ind, vecTy))
        }

339
        results(0) copyFrom opnd.asSeq(ind.toInt)
340 341 342 343
        continueNormally()
      }

      case i @ InstInsertElement(vecTy, indTy, opnd, index, newVal) => {
344
        val ind = index.getUInt(indTy.length).toLong
345 346 347 348 349 350 351 352

        if (ind > vecTy.len) {
          throw new UvmRuntimeException(ctx + "Index %d out of range. Vector type: %s".format(ind, vecTy))
        }

        val indInt = ind.intValue
        val nvb = boxOf(newVal)

353
        for (((oeb, ieb), ind2) <- (opnd.asSeq zip results(0).asSeq).zipWithIndex) {
354 355 356 357 358 359 360 361 362 363 364 365
          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
366 367 368 369
        val v1s = vec1.asSeq
        val v2s = vec2.asSeq
        val ms = mask.asSeq
        val is = results(0).asSeq
370

371 372
        for (((meb, ieb), ind) <- (ms zip is).zipWithIndex) {
          val me = meb.getUInt(maskIntLen).toInt
373
          if (me < vecLen) {
374
            ieb.copyFrom(v1s(me))
375
          } else if (vecLen <= me && me < vecLen * 2) {
376
            ieb.copyFrom(v2s(me - vecLen))
377 378 379 380 381 382 383 384 385 386
          } 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()
      }

      case i @ InstNew(allocTy, excClause) => {
        handleOutOfMemory(excClause) {
          val addr = mutator.newScalar(allocTy)
387
          results(0).asRef = addr
388 389 390 391 392 393
          continueNormally()
        }
      }

      case i @ InstNewHybrid(allocTy, lenTy, length, excClause) => {
        handleOutOfMemory(excClause) {
394 395 396
          val len = length.getUInt(lenTy.length).longValue
          val addr = mutator.newHybrid(allocTy, len)
          results(0).asRef = addr
397 398 399 400 401
          continueNormally()
        }
      }

      case i @ InstAlloca(allocTy, excClause) => {
Kunshan Wang's avatar
Kunshan Wang committed
402
        microVM.stats.allocaExecuted += 1
403 404
        handleOutOfMemory(excClause) {
          val addr = mutator.allocaScalar(curStack.stackMemory, allocTy)
405
          results(0).asIRef = (0L, addr)
406 407 408 409 410
          continueNormally()
        }
      }

      case i @ InstAllocaHybrid(allocTy, lenTy, length, excClause) => {
Kunshan Wang's avatar
Kunshan Wang committed
411
        microVM.stats.allocaExecuted += 1
412
        handleOutOfMemory(excClause) {
413 414 415
          val len = length.getUInt(lenTy.length).longValue
          val addr = mutator.allocaHybrid(curStack.stackMemory, allocTy, len)
          results(0).asIRef = (0L, addr)
416 417 418 419 420
          continueNormally()
        }
      }

      case i @ InstGetIRef(referentTy, opnd) => {
421 422
        val baseAddr = opnd.asRef
        if (baseAddr == 0L) {
423
          throw new UvmNullGenRefException(ctx + "Attempted to use GETIREF on a NULL reference")
424 425
        }
        results(0).asIRef = (baseAddr, 0L)
426 427 428 429 430 431
        continueNormally()
      }

      case i @ InstGetFieldIRef(ptr, referentTy, index, opnd) => {
        val addrIncr = TypeSizes.fieldOffsetOf(referentTy, index)

432
        incrementBoxIRefOrPointer(ptr, opnd, results(0), addrIncr)
433 434 435 436
        continueNormally()
      }

      case i @ InstGetElemIRef(ptr, referentTy, indTy, opnd, index) => {
437 438
        val ind = index.getSInt(indTy.length).longValue
        val addrIncr = TypeSizes.elemOffsetOf(referentTy, ind)
439

440
        incrementBoxIRefOrPointer(ptr, opnd, results(0), addrIncr)
441 442 443 444
        continueNormally()
      }

      case i @ InstShiftIRef(ptr, referentTy, offTy, opnd, offset) => {
445 446
        val off = offset.getSInt(offTy.length).longValue
        val addrIncr = TypeSizes.shiftOffsetOf(referentTy, off)
447 448
        
        logger.trace("SHIFTIREF(0x%x by 0x%x)".format(opnd.asIRefLoc, addrIncr))
449

450
        incrementBoxIRefOrPointer(ptr, opnd, results(0), addrIncr)
451 452 453 454 455 456
        continueNormally()
      }

      case i @ InstGetVarPartIRef(ptr, referentTy, opnd) => {
        val addrIncr = TypeSizes.varPartOffsetOf(referentTy)

457
        incrementBoxIRefOrPointer(ptr, opnd, results(0), addrIncr)
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
        continueNormally()
      }

      case i @ InstLoad(ptr, ord, referentTy, loc, excClause) => {
        val uty = InternalTypePool.unmarkedOf(referentTy)
        val ib = resultBox(0)

        val addr = addressOf(ptr, loc)
        if (addr == 0L) {
          nullRefError(excClause)
        } else {
          MemoryOperations.load(ptr, uty, addr, ib)
          continueNormally()
        }
      }

      case i @ InstStore(ptr, ord, referentTy, loc, newVal, excClause) => {
        val uty = InternalTypePool.unmarkedOf(referentTy)
        val nvb = boxOf(newVal)

        val addr = addressOf(ptr, loc)
        if (addr == 0L) {
          nullRefError(excClause)
        } else {
          MemoryOperations.store(ptr, uty, addr, nvb)
          continueNormally()
        }
      }

      case i @ InstCmpXchg(ptr, weak, ordSucc, ordFail, referentTy, loc, expected, desired, excClause) => {
        val uty = InternalTypePool.unmarkedOf(referentTy)
        val eb = boxOf(expected)
        val db = boxOf(desired)
        val br = resultBox(0)
        val bs = resultBox(1)

        val addr = addressOf(ptr, loc)
        if (addr == 0L) {
          nullRefError(excClause)
        } else {
          val succ = MemoryOperations.cmpXchg(ptr, uty, addr, eb, db, br)
499
          bs.asBoolean = succ
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
          continueNormally()
        }
      }

      case i @ InstAtomicRMW(ptr, ord, op, referentTy, loc, opnd, excClause) => {
        val uty = InternalTypePool.unmarkedOf(referentTy)
        val ob = boxOf(opnd)
        val ib = resultBox(0)

        val addr = addressOf(ptr, loc)
        if (addr == 0L) {
          nullRefError(excClause)
        } else {
          MemoryOperations.atomicRMW(ptr, uty, op, addr, ob, ib)
          continueNormally()
        }
      }

      case i @ InstFence(ord) => {
        // No-op in this interpreter
        continueNormally()
      }

Kunshan Wang's avatar
Kunshan Wang committed
523
      case i @ InstTrap(retTy, excClause, keepalives) => {
524 525 526
        doTrap(retTy, 0)
      }

Kunshan Wang's avatar
Kunshan Wang committed
527
      case i @ InstWatchPoint(wpID, retTy, dis, ena, exc, keepalives) => {
528 529 530 531 532 533 534 535 536
        val isEnabled = microVM.trapManager.isWatchPointEnabled(wpID)

        if (isEnabled) {
          doTrap(retTy, wpID)
        } else {
          branchTo(dis)
        }
      }

537 538 539 540 541 542 543 544 545
      case i @ InstWPBranch(wpID, dis, ena) => {
        val isEnabled = microVM.trapManager.isWatchPointEnabled(wpID)
        if (isEnabled) {
          branchTo(ena)
        } else {
          branchTo(dis)
        }
      }

Kunshan Wang's avatar
Kunshan Wang committed
546
      case i @ InstCCall(callConv, funcTy, sig, callee, argList, excClause, keepalives) => {
547 548 549 550
        if (callConv != Flag("#DEFAULT")) {
          throw new UvmRefImplException(ctx + "Currently only support the #DEFAULT callConv. %s found.".format(callConv.name))
        }

551
        val addr = callee.asPtr
552 553 554

        val argBoxes = argList.map(boxOf)

555
        val shouldIncrementPC = curStack.callNative(sig, addr, argBoxes, errnoBox)
556 557 558 559 560
        if (shouldIncrementPC) {
          continueNormally()
        }
      }

Kunshan Wang's avatar
Kunshan Wang committed
561
      case i @ InstNewThread(stack, threadLocal, newStackAction, excClause) => {
562
        val newStack = stack.asStack.getOrElse {
563
          throw new UvmNullGenRefException(ctx + "Attempt to bind a new thread to a NULL stack.")
564
        }
565 566 567
        
        val threadLocalAddr = threadLocal.map(tl => tl.asRef).getOrElse(0L)
        
568
        val newThread = newStackAction match {
Kunshan Wang's avatar
Kunshan Wang committed
569 570
          case PassValues(argTys, args) => {
            val argBoxes = args.map(boxOf)
571
            microVM.threadStackManager.newThread(newStack, threadLocalAddr, HowToResume.PassValues(argBoxes))
Kunshan Wang's avatar
Kunshan Wang committed
572 573
          }
          case ThrowExc(exc) => {
574
            val excAddr = exc.asRef
575
            microVM.threadStackManager.newThread(newStack, threadLocalAddr, HowToResume.ThrowExc(excAddr))
Kunshan Wang's avatar
Kunshan Wang committed
576
          }
577
        }
578 579
        results(0).asThread = Some(newThread)

580
        continueNormally()
581 582
      }

Kunshan Wang's avatar
Kunshan Wang committed
583
      case i @ InstSwapStack(swappee, curStackAction, newStackAction, excClause, keepalives) => {
584
        val oldStack = curStack
585
        val newStack = swappee.asStack.getOrElse {
586
          throw new UvmNullGenRefException(ctx + "Swappee must not be NULL.")
587 588
        }

Kunshan Wang's avatar
Kunshan Wang committed
589 590 591
        def handleOldStack() = curStackAction match {
          case RetWith(retTys) => {
            unbindRetWith(retTys)
592 593 594 595 596 597 598
          }
          case KillOld() => {
            unbindAndKillStack()
          }
        }

        newStackAction match {
Kunshan Wang's avatar
Kunshan Wang committed
599 600 601 602
          case PassValues(argTys, args) => {
            val argBoxes = args.map(boxOf)
            handleOldStack()
            rebindPassValues(newStack, argBoxes)
603 604
          }
          case ThrowExc(exc) => {
605
            val excBox = boxOf(exc) // need to get the box before the stack is destroyed.
Kunshan Wang's avatar
Kunshan Wang committed
606
            handleOldStack()
607
            rebindThrowExc(newStack, excBox.asRef)
608 609 610
          }
        }
      }
611

Kunshan Wang's avatar
Kunshan Wang committed
612
      case i: InstCommInst => interpretCurrentCommonInstruction()
613 614

      case i => {
615
        throw new UvmUnimplementedOperationException("Unimplemented instruction %s".format(i.getClass.getName))
616 617 618 619 620 621 622 623 624
      }
    }
  } catch {
    case e: Exception => {
      logger.error(ctx + "Exception thrown while interpreting instruction.")
      throw e
    }
  }
}