To protect your data, the CISO officer has suggested users to enable GitLab 2FA as soon as possible.

Commit 90f3e558 authored by Kunshan Wang's avatar Kunshan Wang
Browse files

GC SOS fix and incr travis log lvl

parent 03df71ff
......@@ -12,35 +12,6 @@ addons:
script:
- pushd tests/c-snippets && make CC=gcc-6 && popd
- sbt compile
- sbt 'test-only uvm.clientsupport.text.BundleBuilderTest'
- sbt 'test-only uvm.ir.textinput.SourceInfoRepoTest'
- sbt 'test-only uvm.ir.textinput.UIRTextReaderSpec'
- sbt 'test-only uvm.NameSpaceSpec'
- sbt 'test-only uvm.refimpl.hail.UvmHailBasicTest'
- sbt 'test-only uvm.refimpl.hail.UvmHailHelloWorldTest'
- sbt 'test-only uvm.refimpl.itpr.UvmConversionOperationSpec'
- sbt 'test-only uvm.refimpl.itpr.UvmInterpreterFutexTests'
- sbt 'test-only uvm.refimpl.itpr.UvmInterpreterGCTests'
- sbt 'test-only uvm.refimpl.itpr.UvmInterpreterInt128Test'
- sbt 'test-only uvm.refimpl.itpr.UvmInterpreterMetaTests'
- sbt 'test-only uvm.refimpl.itpr.UvmInterpreterNativeCallbackTests'
- sbt 'test-only uvm.refimpl.itpr.UvmInterpreterNativeTests'
- sbt 'test-only uvm.refimpl.itpr.UvmInterpreterNativeTestsExtra'
- sbt 'test-only uvm.refimpl.itpr.UvmInterpreterSimpleSumTest'
- sbt 'test-only uvm.refimpl.itpr.UvmInterpreterSimpleTests'
- sbt 'test-only uvm.refimpl.itpr.UvmInterpreterSpec'
- sbt 'test-only uvm.refimpl.itpr.UvmInterpreterStackGCTests'
- sbt 'test-only uvm.refimpl.itpr.UvmInterpreterTestBigFunc'
- sbt 'test-only uvm.refimpl.mem.NativeMemoryAccessTest'
- sbt 'test-only uvm.refimpl.mem.ObjectPinningTest'
- sbt 'test-only uvm.refimpl.mem.UvmMemLayoutSpec'
- sbt 'test-only uvm.refimpl.mem.UvmMemOperationsSpec'
- sbt 'test-only uvm.refimpl.misc.FuncRedefTests'
- sbt 'test-only uvm.refimpl.misc.HashableSSAValueTest'
- sbt 'test-only uvm.refimpl.nat.NativeClientSupportTest'
- sbt 'test-only uvm.refimpl.nat.NativeStackKeeperTest'
- sbt 'test-only uvm.refimpl.osr.UvmOSRTests'
- sbt 'test-only uvm.staticanalysis.StaticAnalysisTest'
- sbt 'test-only uvm.testutil.HexDumpTest'
- sbt test
# vim: ts=2 sw=2 sts=2
......@@ -29,6 +29,8 @@ libraryDependencies ++= Seq(
testOptions in Test += Tests.Argument("-oF") // print full stack trace when testing
parallelExecution in Test := false // disable parallel tests because the refimpl2 is not thread-safe
antlr4Settings
antlr4PackageName in Antlr4 := Some("uvm.ir.textinput.gen")
......
......@@ -11,6 +11,7 @@ import uvm.refimpl.mem._
import uvm.refimpl.mem.TypeSizes.Word
import uvm.refimpl.nat.NativeCallHelper
import uvm.staticanalysis.StaticAnalyzer
import uvm.utils.IDFactory
object MicroVM {
val DEFAULT_SOS_SIZE: Word = 2L * 1024L * 1024L; // 2MiB
......@@ -93,13 +94,21 @@ class MicroVM(vmConf: VMConf) {
constantPool.addGlobalVar(g)
}
}
private val contextIDFactory = new IDFactory(1)
/**
* Create a new MuCtx. Part of the API.
*/
def newContext(): MuCtx = {
val mutator = microVM.memoryManager.heap.makeMutator() // This may trigger GC
val ca = new MuCtx(mutator)
def newContext(): MuCtx = newContext("user")
/**
* Create a new MuCtx. Extended to add a name for debugging.
*/
def newContext(name: String): MuCtx = {
val id = contextIDFactory.getID()
val mutator = microVM.memoryManager.heap.makeMutator("MuCtx-%d-%s".format(id, name)) // This may trigger GC
val ca = new MuCtx(id, mutator)
contexts.add(ca)
ca
}
......
......@@ -106,7 +106,7 @@ object MuCtx {
* A client context. The main part of the API. It keeps thread-local states, including a set of handles. It provides
* operations on the Mu VM.
*/
class MuCtx(_mutator: Mutator)(
class MuCtx(val ctxID: Int, _mutator: Mutator)(
implicit microVM: MicroVM, memorySupport: MemorySupport) extends ObjectPinner {
import MuCtx._
......
......@@ -358,6 +358,7 @@ trait InterpreterActions extends InterpreterThreadState {
/** Terminate the thread. Please only let the thread terminate itself. */
protected def threadExit(): Unit = {
curStack.kill()
curThread.mutator.close()
isRunning = false
}
......@@ -405,7 +406,7 @@ trait InterpreterActions extends InterpreterThreadState {
protected def doTrap(retTys: Seq[Type], wpID: Int) = {
val curCtx = ctx // save the context string for debugging
val c = microVM.newContext()
val c = microVM.newContext("trap")
val hThread = c.handleFromInterpreterThread(Some(curThread))
val hStack = c.handleFromInterpreterStack(Some(curStack))
......
......@@ -104,8 +104,8 @@ class ThreadStackManager(implicit microVM: MicroVM, nativeCallHelper: NativeCall
* Create a new thread, bind to a given stack.
*/
def newThread(stack: InterpreterStack, threadLocal: Long, htr: HowToResume): InterpreterThread = {
val mutator = microVM.memoryManager.makeMutator()
val id = threadRegistry.getID()
val mutator = microVM.memoryManager.makeMutator("Itpr-%d".format(id))
val thr = new InterpreterThread(id, stack, threadLocal, htr, mutator)
threadRegistry.put(thr)
thr
......
......@@ -98,7 +98,8 @@ abstract class Heap {
lock.unlock()
}
def makeMutator(): Mutator
/** @param who A string that identifies a mutator. Used for debug purpose. */
def makeMutator(who: String): Mutator
def getMustFreeSpace(): Boolean = mustFreeSpace
}
......@@ -46,7 +46,7 @@ class MemoryManager(val vmConf: VMConf)(implicit microVM: MicroVM) {
val heap = new SimpleImmixHeap(heapBegin, vmConf.sosSize, vmConf.losSize)
val globalMemory = new GlobalMemory(globalBegin, vmConf.globalSize)
def makeMutator(): Mutator = heap.makeMutator()
def makeMutator(name: String): Mutator = heap.makeMutator(name)
def makeStackMemory(mutator: Mutator): StackMemory = {
val objRef = mutator.newHybrid(InternalTypes.BYTE_ARRAY, vmConf.stackSize)
......
......@@ -9,7 +9,7 @@ object Mutator {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
}
abstract class Mutator(implicit memorySupport: MemorySupport) {
abstract class Mutator(val name: String)(implicit memorySupport: MemorySupport) {
import Mutator._
def alloc(size: Word, align: Word, headerSize: Word): Word
......
......@@ -12,7 +12,7 @@ object LargeObjectSpace {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
val BLOCK_SIZE = SimpleImmixSpace.BLOCK_SIZE / 4
val BLOCK_SIZE = SimpleImmixSpace.BLOCK_SIZE / 8
private val OFFSET_PREV = 0 * TypeSizes.WORD_SIZE_BYTES
......
......@@ -7,14 +7,17 @@ import com.typesafe.scalalogging.Logger
import TypeSizes.Word
import uvm.refimpl.UvmRefImplException
import uvm.utils.RetryUtils._
import uvm.utils.IDFactory
object SimpleImmixDefragMutator {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
val defragMutatorIDFactory = new IDFactory(1)
}
class SimpleImmixDefragMutator(val heap: SimpleImmixHeap, val space: SimpleImmixSpace)(
implicit memorySupport: MemorySupport)
extends Mutator with Allocator {
extends Mutator("defrag-" + SimpleImmixDefragMutator.defragMutatorIDFactory.getID()) with Allocator {
import SimpleImmixDefragMutator._
......@@ -27,7 +30,7 @@ class SimpleImmixDefragMutator(val heap: SimpleImmixHeap, val space: SimpleImmix
getNewBlock()
private def getNewBlock() {
curBlockAddr = space.getDefragBlock(curBlockAddr)
curBlockAddr = space.getDefragBlock(curBlockAddr, this)
curBlockAddr match {
case Some(addr) =>
cursor = addr
......@@ -72,6 +75,6 @@ class SimpleImmixDefragMutator(val heap: SimpleImmixHeap, val space: SimpleImmix
def close() {
logger.debug("Closing defrag mutator...")
curBlockAddr.foreach(space.returnBlock)
curBlockAddr.foreach(a => space.returnDefragBlock(a, this))
}
}
......@@ -39,8 +39,8 @@ class SimpleImmixHeap(val begin: Word, val sosSize: Word, val losSize: Word)(
collectorThread.start()
override def makeMutator(): SimpleImmixMutator = {
val mutator = new SimpleImmixMutator(this, space, los)
override def makeMutator(name: String): SimpleImmixMutator = {
val mutator = new SimpleImmixMutator(this, space, los, name)
mutator
}
......
......@@ -12,12 +12,14 @@ object SimpleImmixMutator {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
}
class SimpleImmixMutator(val heap: SimpleImmixHeap, val space: SimpleImmixSpace, val los: LargeObjectSpace)(
class SimpleImmixMutator(val heap: SimpleImmixHeap, val space: SimpleImmixSpace, val los: LargeObjectSpace, name: String)(
implicit memorySupport: MemorySupport)
extends Mutator with Allocator {
extends Mutator(name) with Allocator {
import SimpleImmixMutator._
logger.debug("Creating mutator %s...".format(name))
private var curBlockAddr: Option[Word] = None
private var cursor: Word = _
......@@ -28,8 +30,11 @@ class SimpleImmixMutator(val heap: SimpleImmixHeap, val space: SimpleImmixSpace,
private def getNewBlock(): Unit = {
val newAddr = tryRepeatedly {
space.tryGetBlock(curBlockAddr).orElse {
val toReturn = curBlockAddr
curBlockAddr = None
space.tryGetBlock(toReturn, this).orElse {
heap.mutatorTriggerAndWaitForGCEnd(true)
logger.debug("Try again to get block...")
None
}
}
......@@ -48,7 +53,7 @@ class SimpleImmixMutator(val heap: SimpleImmixHeap, val space: SimpleImmixSpace,
val userStart = TypeSizes.alignUp(gcStart + headerSize, align)
val userEnd = userStart + size
if (userEnd >= limit) {
if (userEnd - gcStart > SimpleImmixSpace.BLOCK_SIZE) {
if (userEnd - gcStart > SimpleImmixSpace.SOS_THRESHOLD) {
Some(los.alloc(size, align, headerSize))
} else {
logger.debug("Getting new block...")
......@@ -66,7 +71,7 @@ class SimpleImmixMutator(val heap: SimpleImmixHeap, val space: SimpleImmixSpace,
}
def close() {
logger.debug("Closing mutator...")
curBlockAddr.foreach(space.returnBlock)
logger.debug("Closing mutator %s...".format(name))
curBlockAddr.foreach(a => space.returnBlock(a, this))
}
}
......@@ -10,10 +10,23 @@ object SimpleImmixSpace {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
val BLOCK_SIZE = 32768L
val SOS_THRESHOLD = BLOCK_SIZE / 4L
val BLOCK_MARKED = 0x1
val BLOCK_RESERVED = 0x2
val BLOCK_PINNED = 0x4
val BLOCK_IN_MUTATOR = 0x4
val BLOCK_PINNED = 0x8
def prettyPrintFlags(flags: Int): String = {
def optStr(flag: Int, str: String): String = if ((flags & flag) != 0) str else ""
"0x%x (%s%s%s%s)".format(flags,
optStr(BLOCK_MARKED, "M"),
optStr(BLOCK_PINNED, "P"),
optStr(BLOCK_RESERVED, "R"),
optStr(BLOCK_IN_MUTATOR, "I"))
}
private val LINE_SIZE = 128L
......@@ -77,10 +90,13 @@ class SimpleImmixSpace(val heap: SimpleImmixHeap, name: String, begin: Word, ext
/** A list of buckets, for statistics. Used by defrag. */
private val buckets: Array[Word] = new Array[Word](N_BUCKETS)
/** Which mutator is using which block? */
private val blockUser: Array[Option[Mutator]] = Array.fill(nBlocks)(None)
for (i <- 0 until nReserved) { // Block 0 to nReserved-1 are reserved
defragResv(i) = i
reserve(i) // Set the reserved flat
blockFlags(i) |= BLOCK_RESERVED // Set the reserved flat
}
for (i <- nReserved until nBlocks) { // The rest of the blocks are free to allocate
......@@ -88,10 +104,10 @@ class SimpleImmixSpace(val heap: SimpleImmixHeap, name: String, begin: Word, ext
}
/**
* Try to get a free block. If not available, return None. The old block, if present, is returned from reserving.
* Try to get a free block. If not available, return None. The old block, if present, is returned.
*/
def tryGetBlock(oldBlockAddr: Option[Word]): Option[Word] = {
oldBlockAddr.foreach(returnBlock)
def tryGetBlock(oldBlockAddr: Option[Word], who: Mutator): Option[Word] = {
oldBlockAddr.foreach(a => returnBlock(a, who))
val myCursor = nextFree
if (myCursor >= freeListValidCount) {
......@@ -101,20 +117,32 @@ class SimpleImmixSpace(val heap: SimpleImmixHeap, name: String, begin: Word, ext
nextFree += 1
val blockNum = freeList(myCursor)
reserve(blockNum)
mutatorGetBlock(blockNum, who)
logger.debug("Normal mutator %s got block %d".format(who.name, blockNum))
val blockAddr = blockIndexToBlockAddr(blockNum)
MemUtils.zeroRegion(blockAddr, BLOCK_SIZE)
Some(blockAddr)
}
private def reserve(blockNum: Int) {
blockFlags(blockNum) |= BLOCK_RESERVED
private def mutatorGetBlock(blockNum: Int, who: Mutator): Unit = {
blockFlags(blockNum) |= BLOCK_IN_MUTATOR
blockUser(blockNum) = Some(who)
}
private def unreserve(blockNum: Int) {
blockFlags(blockNum) &= ~BLOCK_RESERVED
private def mutatorReleaseBlock(blockNum: Int, who: Mutator): Unit = {
val oldUser = blockUser(blockNum)
if (oldUser != Some(who)) {
throw new UvmRefImplException("Mutator %s returned a block %d which was reserved by %s".format(
who.name, blockNum, oldUser.map(_.name).getOrElse("(nobody)")))
}
blockUser(blockNum) = None
val flags = blockFlags(blockNum)
assert((flags & BLOCK_IN_MUTATOR) != 0, "Block %d (to be returned) should have flags 0x%x. Actual flags: %s".format(
blockNum, BLOCK_IN_MUTATOR, prettyPrintFlags(flags)))
blockFlags(blockNum) &= ~BLOCK_IN_MUTATOR
}
def objRefToBlockIndex(objRef: Word): Int = {
......@@ -148,49 +176,73 @@ class SimpleImmixSpace(val heap: SimpleImmixHeap, name: String, begin: Word, ext
logger.debug(s"Marked block ${blockIndex}. pin=${pin}")
}
def isPinned(pageNum: Int): Boolean = (blockFlags(pageNum) & BLOCK_MARKED) != 0
def isPinned(pageNum: Int): Boolean = (blockFlags(pageNum) & BLOCK_PINNED) != 0
def collectBlocks(): Boolean = {
logger.debug("Before collecting blocks from SOS:")
if (logger.underlying.isDebugEnabled()) {
debugLogBlockStates()
}
for (i <- 0 until nBlocks) {
val flags = blockFlags(i)
if ((flags & BLOCK_RESERVED) != 0) {
assert(flags == BLOCK_RESERVED, "Reserved block %d should have flags 0x%x. Actual flags: %s".format(
i, BLOCK_RESERVED, prettyPrintFlags(flags)))
}
}
// Shift defrag reserved blocks to the beginning;
for (i <- nextResv until defragResvFree) {
defragResv(i - nextResv) = defragResv(i)
}
var newDefragResvFree = defragResvFree - nextResv
for (i <- 0 until newDefragResvFree) {
val ind = defragResv(i)
val flags = blockFlags(ind)
assert(flags == BLOCK_RESERVED, "Block %d (from defrag freelist) should have flags 0x%x. Actual flags: %s".format(
ind, BLOCK_RESERVED, prettyPrintFlags(flags)))
}
var newNFree = 0
for (i <- 0 until nBlocks) {
var flag = blockFlags(i)
val bits = (flag & (BLOCK_MARKED | BLOCK_RESERVED | BLOCK_PINNED))
val bits = (flag & (BLOCK_MARKED | BLOCK_IN_MUTATOR | BLOCK_RESERVED | BLOCK_PINNED))
if (bits == 0) {
if (newDefragResvFree < nReserved) {
defragResv(newDefragResvFree) = i
newDefragResvFree += 1
flag |= BLOCK_RESERVED
logger.debug(s"Block ${i} added to defrag freelist")
} else {
freeList(newNFree) = i
newNFree += 1
flag &= ~BLOCK_RESERVED
logger.debug(s"Block ${i} added to normal freelist")
}
} else if ((bits & BLOCK_RESERVED) != 0) {
logger.debug(s"Block ${i} is already reserved.")
} else {
logger.debug(s"Block ${i} is not freed because flag bits is ${bits}")
}
flag &= ~(BLOCK_MARKED | BLOCK_PINNED)
flag &= ~(BLOCK_MARKED | BLOCK_PINNED) // The only place that unmarks the block
blockFlags(i) = flag
}
defragResvFree = newDefragResvFree
freeListValidCount = newNFree
nextResv = 0
nextFree = 0
if (logger.underlying.isDebugEnabled()) {
logger.debug("After collecting blocks from SOS:")
debugLogBlockStates()
}
nextResv = 0
nextFree = 0
return newNFree > 0
}
def returnBlock(blockAddr: Word) {
def returnBlock(blockAddr: Word, who: Mutator) {
val blockNum = blockAddrToBlockIndex(blockAddr)
unreserve(blockNum)
logger.debug("Block %d returned to space.".format(blockNum))
mutatorReleaseBlock(blockNum, who)
logger.debug("Block %d returned to space by %s.".format(blockNum, who.name))
}
// Statistics
......@@ -251,8 +303,8 @@ class SimpleImmixSpace(val heap: SimpleImmixHeap, name: String, begin: Word, ext
}
// Defrag
def getDefragBlock(oldBlockAddr: Option[Word]): Option[Word] = {
oldBlockAddr.foreach(returnBlock)
def getDefragBlock(oldBlockAddr: Option[Word], who: SimpleImmixDefragMutator): Option[Word] = {
oldBlockAddr.foreach(a => returnBlock(a, who))
val myCursor = nextResv
......@@ -263,27 +315,41 @@ class SimpleImmixSpace(val heap: SimpleImmixHeap, name: String, begin: Word, ext
nextResv += 1
val blockNum = defragResv(myCursor)
val flags = blockFlags(blockNum)
assert(flags == BLOCK_RESERVED, "Defrag block %d (to be used) should have flags 0x%x. Actual flags: %s".format(
blockNum, BLOCK_RESERVED, prettyPrintFlags(flags)))
blockFlags(blockNum) &= ~BLOCK_RESERVED
mutatorGetBlock(blockNum, who)
logger.debug("Defrag mutator %s got block %d".format(who.name, blockNum))
val blockAddr = blockIndexToBlockAddr(blockNum)
MemUtils.zeroRegion(blockAddr, BLOCK_SIZE)
return Some(blockAddr)
}
def returnDefragBlock(oldBlockAddr: Word, who: SimpleImmixDefragMutator): Unit = {
returnBlock(oldBlockAddr, who)
}
// Debugging
def debugLogBlockStates() {
val sb1 = new StringBuilder("Reserved freelist:")
for (i <- 0 until defragResvFree) {
for (i <- nextResv until defragResvFree) {
sb1.append(" ").append(defragResv(i))
}
logger.debug(sb1.toString)
val sb2 = new StringBuilder("Freelist:")
for (i <- 0 until freeListValidCount) {
for (i <- nextFree until freeListValidCount) {
sb2.append(" ").append(freeList(i))
}
logger.debug(sb2.toString)
for (i <- 0 until nBlocks) {
logger.debug(s"blockFlags[${i}] = ${blockFlags(i)}")
val prettyFlags = prettyPrintFlags(blockFlags(i))
val user = blockUser(i).map(m => "user: %s".format(m.name)).getOrElse("")
logger.debug("block %d: flag=%s %s".format(i, prettyFlags, user))
}
}
}
package uvm
import org.slf4j.LoggerFactory
import org.slf4j.{ Logger => SLogger }
import ch.qos.logback.classic.{ Logger => LLogger, Level }
import ch.qos.logback.classic.Level._
object LogSetter {
def setLevel(name: String, level: Level): Unit = {
LoggerFactory.getLogger(name).asInstanceOf[LLogger].setLevel(level)
}
val isTravis = {
System.getenv("TRAVIS") == "true"
}
}
trait LogSetter {
import LogSetter._
val ROOT_LOGGER_NAME = org.slf4j.Logger.ROOT_LOGGER_NAME
if (isTravis) { // Travis does not like logging, so just heighten the log level whenever we run tests.
setLevel(ROOT_LOGGER_NAME, WARN)
}
def setLogLevels(settings: (String, Level)*): Unit = if (isTravis) {
// Travis does not like logging, so just make it a no-op.
} else { // Configure logger
for ((name, lvl) <- settings) {
setLevel(name, lvl)
}
}
}
\ No newline at end of file
......@@ -3,7 +3,7 @@ package uvm
import org.scalatest.Matchers
import org.scalatest.FlatSpec
class NameSpaceSpec extends FlatSpec with Matchers {
class NameSpaceSpec extends UvmTestBase {
behavior of "NestedNamespace"
class Foo(val i: Int) extends IdentifiedSettable
......
package uvm
import org.scalatest.Matchers
import org.scalatest.FlatSpec
abstract class UvmTestBase extends FlatSpec with Matchers with LogSetter
\ No newline at end of file
......@@ -5,8 +5,10 @@ import org.scalatest.Matchers
import TextOutputMatchers._
import uvm.ir.textinput.UIRTextReader
import uvm.utils.IDFactory
import uvm.LogSetter
import uvm.UvmTestBase
class BundleBuilderTest extends FlatSpec with Matchers {
class BundleBuilderTest extends UvmTestBase {
val x = TypeName("x")
val y = TypeName("y")
......@@ -112,8 +114,7 @@ class BundleBuilderTest extends FlatSpec with Matchers {
Inst.PreSwitch(x, a, l1, IList(
SwitchCase(LocalVarName("v1"), LabelName("d1")),
SwitchCase(LocalVarName("v2"), LabelName("d2")),
SwitchCase(LocalVarName("v3"), LabelName("d3"))
)).toString shouldEqual "SWITCH <@x> %a %l1 { %v1: %d1; %v2: %d2; %v3: %d3; }"
SwitchCase(LocalVarName("v3"), LabelName("d3")))).toString shouldEqual "SWITCH <@x> %a %l1 { %v1: %d1; %v2: %d2; %v3: %d3; }"
PostExcClause(Inst.Call(s, f, IList(a, b, c), Some(KeepAliveClause(IList(a, b)))), nor, exc).toString shouldEqual
"CALL <@s> @f (%a %b %c) EXC(%nor() %exc()) KEEPALIVE(%a %b)"
Inst.TailCall(s, f, IList(a, b, c)).toString shouldEqual
......@@ -132,18 +133,18 @@ class BundleBuilderTest extends FlatSpec with Matchers {
PostExcClause(Inst.Alloca(x), nor, exc).toString shouldEqual "ALLOCA <@x> EXC(%nor() %exc())"
PostExcClause(Inst.AllocaHybrid(x, 91, a), nor, exc).toString shouldEqual "ALLOCAHYBRID <@x 91> %a EXC(%nor() %exc())"
Inst.GetIRef(x, a).toString shouldEqual "GETIREF <@x> %a"
Inst.GetFieldIRef(ptr=true, x, 3, a).toString shouldEqual "GETFIELDIREF PTR <@x 3> %a"
Inst.GetElemIRef(ptr=true, x, y, a, b).toString shouldEqual "GETELEMIREF PTR <@x @y> %a %b"
Inst.ShiftIRef(ptr=true, x, y, a, b).toString shouldEqual "SHIFTIREF PTR <@x @y> %a %b"
Inst.GetFixedPartIRef(ptr=true, x, a).toString shouldEqual "GETFIXEDPARTIREF PTR <@x> %a"
Inst.GetVarPartIRef(ptr=true, x, a).toString shouldEqual "GETVARPARTIREF PTR <@x> %a"
PostExcClause(Inst.Load(ptr=true, SeqConsistent, x, a), nor, exc).toString shouldEqual
Inst.GetFieldIRef(ptr = true, x, 3, a).toString shouldEqual "GETFIELDIREF PTR <@x 3> %a"
Inst.GetElemIRef(ptr = true, x, y, a, b).toString shouldEqual "GETELEMIREF PTR <@x @y> %a %b"
Inst.ShiftIRef(ptr = true, x, y, a, b).toString shouldEqual "SHIFTIREF PTR <@x @y> %a %b"
Inst.GetFixedPartIRef(ptr = true, x, a).toString shouldEqual "GETFIXEDPARTIREF PTR <@x> %a"
Inst.GetVarPartIRef(ptr = true, x, a).toString shouldEqual "GETVARPARTIREF PTR <@x> %a"
PostExcClause(Inst.Load(ptr = true, SeqConsistent, x, a), nor, exc).toString shouldEqual
"LOAD PTR SEQ_CST <@x> %a EXC(%nor() %exc())"