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

InstructionExecutor.scala 22.5 KB
Newer Older
Kunshan Wang's avatar
Kunshan Wang committed
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 {
Kunshan Wang's avatar
Kunshan Wang committed
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
Kunshan Wang's avatar
Kunshan Wang committed
19 20

  /** Interpret the current instruction. */
Kunshan Wang's avatar
Kunshan Wang committed
21
  protected def interpretCurrentInstruction(): Unit = try {
Kunshan Wang's avatar
Kunshan Wang committed
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)
Kunshan Wang's avatar
Kunshan Wang committed
27 28

    curInst match {
Kunshan Wang's avatar
Kunshan Wang committed
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)
Kunshan Wang's avatar
Kunshan Wang committed
32

Kunshan Wang's avatar
Kunshan Wang committed
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))
Kunshan Wang's avatar
Kunshan Wang committed
39 40
          }
        }
Kunshan Wang's avatar
Kunshan Wang committed
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
            }
          }
        }
Kunshan Wang's avatar
Kunshan Wang committed
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)) {
Kunshan Wang's avatar
Kunshan Wang committed
62 63 64
                doScalar(scalarTy, b1, b2, br)
              }
            }
Kunshan Wang's avatar
Kunshan Wang committed
65 66 67 68 69 70
            case scalarTy => {
              doScalar(scalarTy, op1, op2, results(0))
              if (flags != 0) {
                doFlags()
              }
            }
Kunshan Wang's avatar
Kunshan Wang committed
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)

Kunshan Wang's avatar
Kunshan Wang committed
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))
Kunshan Wang's avatar
Kunshan Wang committed
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)) {
Kunshan Wang's avatar
Kunshan Wang committed
109 110 111
              doScalar(scalarTy, b1, b2, br)
            }
          }
112
          case scalarTy => doScalar(scalarTy, op1, op2, results(0))
Kunshan Wang's avatar
Kunshan Wang committed
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)

Kunshan Wang's avatar
Kunshan Wang committed
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
Kunshan Wang's avatar
Kunshan Wang committed
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
Kunshan Wang's avatar
Kunshan Wang committed
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)
Kunshan Wang's avatar
Kunshan Wang committed
144 145
              case _            => throw new UvmRuntimeException(ctx + "Expect FP source type. Found %s.".format(scalarFromTy))
            }
146
            br.asIntRaw = result
Kunshan Wang's avatar
Kunshan Wang committed
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
Kunshan Wang's avatar
Kunshan Wang committed
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))
Kunshan Wang's avatar
Kunshan Wang committed
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)
Kunshan Wang's avatar
Kunshan Wang committed
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
Kunshan Wang's avatar
Kunshan Wang committed
189 190
            }
            scalarToTy match {
191 192
              case TypeInt(n)             => br.setInt(srcAddr, Math.min(n, 64))
              case _: AbstractPointerType => br.asPtr = srcAddr
Kunshan Wang's avatar
Kunshan Wang committed
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
Kunshan Wang's avatar
Kunshan Wang committed
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)) {
Kunshan Wang's avatar
Kunshan Wang committed
217 218 219
              doScalar(scalarFromTy, scalarToTy, bOpnd, br)
            }
          }
220
          case _ => doScalar(fromTy, toTy, opnd, results(0))
Kunshan Wang's avatar
Kunshan Wang committed
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) {
Kunshan Wang's avatar
Kunshan Wang committed
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)) {
Kunshan Wang's avatar
Kunshan Wang committed
238 239 240 241
              doScalar(bCond, bTrue, bFalse, br)
            }
          }
          case TypeInt(1) => {
242
            doScalar(cond, ifTrue, ifFalse, results(0))
Kunshan Wang's avatar
Kunshan Wang committed
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")
Kunshan Wang's avatar
Kunshan Wang committed
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
        }
Kunshan Wang's avatar
Kunshan Wang committed
281 282 283

        val shouldIncrementPC = curStack.callMu(calleeFunc, argBoxes)
        if (shouldIncrementPC) {
284
          throw new UvmRefImplException(ctx + "Should not continue normally immediately after calling")
Kunshan Wang's avatar
Kunshan Wang committed
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")
Kunshan Wang's avatar
Kunshan Wang committed
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")
Kunshan Wang's avatar
Kunshan Wang committed
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()
Kunshan Wang's avatar
Kunshan Wang committed
312 313 314 315
        catchException(exc)
      }

      case i @ InstExtractValue(strTy, index, opnd) => {
316
        results(0) copyFrom opnd.asSeq(index)
Kunshan Wang's avatar
Kunshan Wang committed
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) {
Kunshan Wang's avatar
Kunshan Wang committed
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
Kunshan Wang's avatar
Kunshan Wang committed
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)
Kunshan Wang's avatar
Kunshan Wang committed
340 341 342 343
        continueNormally()
      }

      case i @ InstInsertElement(vecTy, indTy, opnd, index, newVal) => {
344
        val ind = index.getUInt(indTy.length).toLong
Kunshan Wang's avatar
Kunshan Wang committed
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) {
Kunshan Wang's avatar
Kunshan Wang committed
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
Kunshan Wang's avatar
Kunshan Wang committed
370

371 372
        for (((meb, ieb), ind) <- (ms zip is).zipWithIndex) {
          val me = meb.getUInt(maskIntLen).toInt
Kunshan Wang's avatar
Kunshan Wang committed
373
          if (me < vecLen) {
374
            ieb.copyFrom(v1s(me))
Kunshan Wang's avatar
Kunshan Wang committed
375
          } else if (vecLen <= me && me < vecLen * 2) {
376
            ieb.copyFrom(v2s(me - vecLen))
Kunshan Wang's avatar
Kunshan Wang committed
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
Kunshan Wang's avatar
Kunshan Wang committed
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
Kunshan Wang's avatar
Kunshan Wang committed
397 398 399 400 401
          continueNormally()
        }
      }

      case i @ InstAlloca(allocTy, excClause) => {
Kunshan Wang's avatar
Kunshan Wang committed
402
        microVM.stats.allocaExecuted += 1
Kunshan Wang's avatar
Kunshan Wang committed
403 404
        handleOutOfMemory(excClause) {
          val addr = mutator.allocaScalar(curStack.stackMemory, allocTy)
405
          results(0).asIRef = (0L, addr)
Kunshan Wang's avatar
Kunshan Wang committed
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
Kunshan Wang's avatar
Kunshan Wang committed
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)
Kunshan Wang's avatar
Kunshan Wang committed
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)
Kunshan Wang's avatar
Kunshan Wang committed
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)
Kunshan Wang's avatar
Kunshan Wang committed
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)
Kunshan Wang's avatar
Kunshan Wang committed
439

440
        incrementBoxIRefOrPointer(ptr, opnd, results(0), addrIncr)
Kunshan Wang's avatar
Kunshan Wang committed
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))
Kunshan Wang's avatar
Kunshan Wang committed
449

450
        incrementBoxIRefOrPointer(ptr, opnd, results(0), addrIncr)
Kunshan Wang's avatar
Kunshan Wang committed
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)
Kunshan Wang's avatar
Kunshan Wang committed
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
Kunshan Wang's avatar
Kunshan Wang committed
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) => {
Kunshan Wang's avatar
Kunshan Wang committed
524 525 526
        doTrap(retTy, 0)
      }

Kunshan Wang's avatar
Kunshan Wang committed
527
      case i @ InstWatchPoint(wpID, retTy, dis, ena, exc, keepalives) => {
Kunshan Wang's avatar
Kunshan Wang committed
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) => {
Kunshan Wang's avatar
Kunshan Wang committed
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
Kunshan Wang's avatar
Kunshan Wang committed
552 553 554

        val argBoxes = argList.map(boxOf)

Kunshan Wang's avatar
Kunshan Wang committed
555
        val shouldIncrementPC = curStack.callNative(sig, addr, argBoxes, errnoBox)
Kunshan Wang's avatar
Kunshan Wang committed
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.")
Kunshan Wang's avatar
Kunshan Wang committed
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
          }
Kunshan Wang's avatar
Kunshan Wang committed
577
        }
578 579
        results(0).asThread = Some(newThread)

580
        continueNormally()
Kunshan Wang's avatar
Kunshan Wang committed
581 582
      }

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

Kunshan Wang's avatar
Kunshan Wang committed
589 590 591
        def handleOldStack() = curStackAction match {
          case RetWith(retTys) => {
            unbindRetWith(retTys)
Kunshan Wang's avatar
Kunshan Wang committed
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)
Kunshan Wang's avatar
Kunshan Wang committed
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)
Kunshan Wang's avatar
Kunshan Wang committed
608 609 610
          }
        }
      }
611

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

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