diff --git a/src/main/scala/uvm/refimpl/bootimg/BootImageBuilder.scala b/src/main/scala/uvm/refimpl/bootimg/BootImageBuilder.scala index ad2777a97bf2b042b0d9bb4cae6c8433457ea969..4dbaf2867d4735f83678194e19d8c7e0837272d2 100644 --- a/src/main/scala/uvm/refimpl/bootimg/BootImageBuilder.scala +++ b/src/main/scala/uvm/refimpl/bootimg/BootImageBuilder.scala @@ -29,293 +29,3 @@ class BootImageBuilder(implicit microVM: MicroVM) { tc.doTransitiveClosure() } } - -object TransitiveClosure { - def apply[T](initialElems: T*) = new TransitiveClosure(initialElems) -} - -class TransitiveClosure[T](initialElems: Seq[T]) { - val set = Set[T](initialElems: _*) - val queue = Queue[T](initialElems: _*) - - def hasPending = !queue.isEmpty - def dequeue() = queue.dequeue() - def maybeEnqueue(elem: T): Boolean = { - if (set.contains(elem)) { - false - } else { - set += elem - queue += elem - true - } - } - def +=(elem: T): TransitiveClosure[T] = { maybeEnqueue(elem); this } - def ++=(elems: Seq[T]): TransitiveClosure[T] = { elems.foreach(this +=); this } -} - -object TransitiveClosureBuilder { - val logger = Logger(LoggerFactory.getLogger(getClass.getName)) - - implicit class RichTransitiveClosure[T <: Identified](val tc: TransitiveClosure[T]) extends AnyVal { - def ?=(elem: SSAVariable) = { - if (elem.isInstanceOf[GlobalVariable]) { - tc += elem.asInstanceOf[T] - } - tc - } - def ??=(elems: Seq[SSAVariable]) = { - for (elem <- elems) { - this ?= elem - } - tc - } - } - - case class GlobalCellRec(begin: Word, end: Word, g: GlobalCell) -} - -class TransitiveClosureBuilder(initialSet: Seq[Int])(implicit microVM: MicroVM) extends RefFieldHandler { - import TransitiveClosureBuilder._ - - private val globalMemory: Space = microVM.memoryManager.globalMemory - private val smallObjectSpace: Space = microVM.memoryManager.heap.space - private val largeObjectSpace: Space = microVM.memoryManager.heap.los - private implicit val memorySupport = microVM.memoryManager.memorySupport - - /** - * Top-level definitions in the closure. Function versions are not considered top-level here. A function may have at - * most one function version. Only that version is serialised into the boot image. - */ - val tls = TransitiveClosure[Identified](initialSet.map(microVM.globalBundle.allNs.apply): _*) - - /** - * Global cells + heap objects. - */ - val allocs = TransitiveClosure[Word]() - - def getGlobalCellAddr(g: GlobalCell): Word = { - microVM.constantPool.getGlobalVarBox(g).asInstanceOf[BoxIRef].addr - } - - /** - * Map the global cell's starting address to the global cell itself. - */ - val globalCellMap = { - val elems = microVM.globalBundle.globalCellNs.all.toSeq.map { g => - val begin = getGlobalCellAddr(g) - val ty = g.cellTy - assert(!ty.isInstanceOf[TypeHybrid]) - val size = TypeSizes.sizeOf(ty) - val end = begin + size - (begin, GlobalCellRec(begin, end, g)) - } - TreeMap[Word, GlobalCellRec](elems: _*) - } - - def getGlobalCellRec(iref: Word): GlobalCellRec = { - require(microVM.memoryManager.globalMemory.isInSpace(iref), - "Address %d 0x%x is not in the global space".format(iref, iref)) - - val (begin, gcr) = globalCellMap.to(iref).last - assert(begin <= iref && iref < gcr.end, - "Address %d 0x%x is in the global space, but the previous global cell's address range is %d 0x%x - %d 0x%x".format( - iref, iref, begin, begin, gcr.end, gcr.end)) - - gcr - } - - def doTransitiveClosure(): Unit = { - while (tls.hasPending || allocs.hasPending) { - while (tls.hasPending) { - visitTopLevel(tls.dequeue()) - } - while (allocs.hasPending) { - visitAllocUnit(allocs.dequeue()) - } - } - } - - private def visitTopLevel(tl: Identified): Unit = { - tl match { - case t: Type => visitType(t) - case s: FuncSig => visitFuncSig(s) - case c: Constant => visitConstant(c) - case g: GlobalCell => visitGlobalCell(g) - case f: Function => visitFunction(f) - case e: ExposedFunc => visitExpFunc(e) - } - } - - private def visitType(ty: Type): Unit = ty match { - case TypeUPtr(t) => tls += t - case TypeUFuncPtr(s) => tls += s - case TypeStruct(ts) => tls ++= ts - case TypeHybrid(fs, v) => tls ++= fs += v - case TypeArray(t, _) => tls += t - case TypeVector(t, _) => tls += t - case TypeRef(t) => tls += t - case TypeIRef(t) => tls += t - case TypeWeakRef(t) => tls += t - case TypeFuncRef(s) => tls += s - case _ => // Not nested or recursive. Do nothing. - } - - private def visitFuncSig(s: FuncSig): Unit = { - tls ++= s.paramTys ++= s.retTys - } - - private def visitConstant(c: Constant): Unit = { - tls += c.constTy - - c match { - case ConstSeq(_, elems) => tls ++= elems - case _ => // Not nested. Do nothing. - } - } - - private def visitGlobalCell(g: GlobalCell): Unit = { - tls += g.cellTy - - allocs += getGlobalCellAddr(g) - } - - private def visitFunction(f: Function): Unit = { - tls += f.sig - - microVM.globalBundle.funcToVers(f).headOption match { - case None => // Undefined. Do nothing - case Some(mostRecent) => { - // Visit all TOP-LEVELS (mostly types sigs and SSA variables). - // This version, including all of its basic blocks and instructions, will be in the boot image. - for (bb <- mostRecent.bbs) { - tls ++= bb.norParams.map(_.ty) - - for (inst <- bb.insts) { - visitInstruction(inst) - } - } - } - } - } - - private def visitExpFunc(e: ExposedFunc): Unit = { - tls += e.func - tls += e.cookie - } - - private def visitInstruction(inst: Instruction): Unit = inst match { - case InstBinOp(op, opndTy, op1, op2, excClause) => tls += opndTy ?= op1 ?= op2 - case InstCmp(op, opndTy, op1, op2) => tls += opndTy ?= op1 ?= op2 - case InstConv(op, fromTy, toTy, opnd) => tls += fromTy += toTy ?= opnd - case InstSelect(condTy, opndTy, cond, ifTrue, ifFalse) => tls += condTy += opndTy ?= cond ?= ifTrue ?= ifFalse - case InstBranch(dest) => - case InstBranch2(cond, ifTrue, ifFalse) => tls ?= cond - case i @ InstSwitch(opndTy, opnd, defDest, cases) => tls += opndTy ?= opnd ??= cases.map(_._1) - case InstCall(sig, callee, argList, excClause, keepalives) => tls += sig ?= callee ??= argList - case InstTailCall(sig, callee, argList) => tls += sig ?= callee ??= argList - case InstRet(funcVer, retVals) => tls ??= retVals - case InstThrow(excVal) => tls ?= excVal - case InstExtractValue(strTy, index, opnd) => tls += strTy ?= opnd - case InstInsertValue(strTy, index, opnd, newVal) => tls += strTy ?= opnd ?= newVal - case InstExtractElement(seqTy, indTy, opnd, index) => tls += seqTy += indTy ?= opnd ?= index - case InstInsertElement(seqTy, indTy, opnd, index, newVal) => tls += seqTy += indTy ?= opnd ?= index ?= newVal - case InstShuffleVector(vecTy, maskTy, vec1, vec2, mask) => tls += vecTy += maskTy ?= vec1 ?= vec2 ?= mask - case InstNew(allocTy, excClause) => tls += allocTy - case InstNewHybrid(allocTy, lenTy, length, excClause) => tls += allocTy += lenTy ?= length - case InstAlloca(allocTy, excClause) => tls += allocTy - case InstAllocaHybrid(allocTy, lenTy, length, excClause) => tls += allocTy += lenTy ?= length - case InstGetIRef(referentTy, opnd) => tls += referentTy ?= opnd - case InstGetFieldIRef(ptr, referentTy, index, opnd) => tls += referentTy ?= opnd - case InstGetElemIRef(ptr, referentTy, indTy, opnd, index) => tls += referentTy += indTy ?= opnd ?= index - case InstShiftIRef(ptr, referentTy, offTy, opnd, offset) => tls += referentTy += offTy ?= opnd ?= offset - case InstGetVarPartIRef(ptr, referentTy, opnd) => tls += referentTy ?= opnd - case InstLoad(ptr, ord, referentTy, loc, excClause) => tls += referentTy ?= loc - case InstStore(ptr, ord, referentTy, loc, newVal, excClause) => tls += referentTy ?= loc ?= newVal - case InstCmpXchg(ptr, weak, ordSucc, ordFail, referentTy, loc, expected, desired, excClause) // This line is long ... - => tls += referentTy ?= loc ?= expected ?= desired - case InstAtomicRMW(ptr, ord, op, referentTy, loc, opnd, excClause) => tls += referentTy ?= loc ?= opnd - case InstFence(ord) => - case InstTrap(retTys, excClause, keepalives) => tls ++= retTys - case InstWatchPoint(wpID, retTys, dis, ena, exc, keepalives) => tls ++= retTys - case InstWPBranch(wpID, dis, ena) => - case InstCCall(callConv, funcTy, sig, callee, argList, excClause, keepalives) // This line is long, too... - => tls += funcTy += sig ?= callee ??= argList - case InstNewThread(stack, threadLocal, newStackAction, excClause) => { - tls ?= stack - threadLocal.foreach(tls.?=) - visitNewStackAction(newStackAction) - } - case InstSwapStack(swappee, curStackAction, newStackAction, excClause, keepalives) => { - tls ?= swappee - curStackAction match { - case RetWith(ts) => tls ++= ts - case KillOld() => - } - visitNewStackAction(newStackAction) - } - case InstCommInst(ci, flagList, typeList, funcSigList, argList, excClause, keepalives) => - tls ++= typeList ++= funcSigList ??= argList - - case _ => throw new BootImageBuilderException("Unknown instruction: " + inst.getClass.getName) - } - - private def visitNewStackAction(nsa: NewStackAction): Unit = nsa match { - case PassValues(ts, vs) => tls ++= ts ??= vs - case ThrowExc(e) => - } - - private def visitAllocUnit(addrOrObjRef: Word): Unit = { - logger.debug("Visiting allocation unit 0x%x".format(addrOrObjRef)) - if (globalMemory.isInSpace(addrOrObjRef)) { - val GlobalCellRec(begin, end, g) = getGlobalCellRec(addrOrObjRef) - logger.debug(" It's global cell. begin=0x%x, end=0x%x, type=%s".format(begin, end, g.cellTy)) - tls += g - visitAllocUnitFields(begin, g.cellTy) - } else if (smallObjectSpace.isInSpace(addrOrObjRef) || largeObjectSpace.isInSpace(addrOrObjRef)) { - val objRef = addrOrObjRef - val tag = HeaderUtils.getTag(objRef) - val ty = HeaderUtils.getType(microVM, tag) - tls += ty - visitAllocUnitFields(objRef, ty) - } else { - throw new BootImageBuilderException("Address %d 0x%x is not in the heap or global space".format(addrOrObjRef, addrOrObjRef)) - } - } - - private def visitAllocUnitFields(begin: Word, ty: Type): Unit = { - MemoryDataScanner.scanAllocUnit(begin, this) - } - - def boxToHeap(box: HasObjRef): Option[Word] = - throw new BootImageBuilderException("BUG: Box should not have been scanned during boot image building.") - - def boxToStack(box: BoxStack): Option[InterpreterStack] = - throw new BootImageBuilderException("BUG: Box should not have been scanned during boot image building.") - - def memToHeap(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean, isTR64: Boolean): Option[Word] = { - if (toObj != 0L) { - allocs += toObj - Some(toObj) - } else { - None - } - } - - def memToStack(objRef: Word, iRef: Word, toStack: Option[InterpreterStack]): Option[InterpreterStack] = { - if (toStack.isDefined) { - throw new BootImageBuilderException( - "Error: Stack reachable during boot image building. From: obj 0x%x, iref 0x%x. To stack id: %d".format( - objRef, iRef, toStack.get.id)) - } - None - } - - def stackToStackMem(stack: InterpreterStack, toObj: Word): Option[Word] = - throw new BootImageBuilderException("BUG: Stack should not have been scanned during boot image building.") - - def threadToStack(thread: InterpreterThread, toStack: Option[InterpreterStack]): Option[InterpreterStack] = - throw new BootImageBuilderException("BUG: Thread should not have been scanned during boot image building.") - - def pinSetToMem(toObj: Word): Option[Word] = - throw new BootImageBuilderException("BUG: Pin set should not have been scanned during boot image building.") -} \ No newline at end of file diff --git a/src/main/scala/uvm/refimpl/bootimg/transitiveClosure.scala b/src/main/scala/uvm/refimpl/bootimg/transitiveClosure.scala new file mode 100644 index 0000000000000000000000000000000000000000..e9267d7ced29545d55155ab0f9ba4bdc34400bd4 --- /dev/null +++ b/src/main/scala/uvm/refimpl/bootimg/transitiveClosure.scala @@ -0,0 +1,311 @@ +package uvm.refimpl.bootimg + +import scala.collection.immutable.TreeMap +import scala.collection.mutable.{ Set, Queue } + +import org.slf4j.LoggerFactory + +import com.typesafe.scalalogging.Logger + +import uvm._ +import uvm.refimpl._ +import uvm.refimpl.itpr._ +import uvm.refimpl.mem.HeaderUtils +import uvm.refimpl.mem.Space +import uvm.refimpl.mem.TypeSizes +import uvm.refimpl.mem.TypeSizes.Word +import uvm.refimpl.mem.scanning.MemoryDataScanner +import uvm.refimpl.mem.scanning.RefFieldHandler +import uvm.ssavariables._ +import uvm.types._ + + +object TransitiveClosure { + def apply[T](initialElems: T*) = new TransitiveClosure(initialElems) +} + +class TransitiveClosure[T](initialElems: Seq[T]) { + val set = Set[T](initialElems: _*) + val queue = Queue[T](initialElems: _*) + + def hasPending = !queue.isEmpty + def dequeue() = queue.dequeue() + def maybeEnqueue(elem: T): Boolean = { + if (set.contains(elem)) { + false + } else { + set += elem + queue += elem + true + } + } + def +=(elem: T): TransitiveClosure[T] = { maybeEnqueue(elem); this } + def ++=(elems: Seq[T]): TransitiveClosure[T] = { elems.foreach(this +=); this } +} + +object TransitiveClosureBuilder { + val logger = Logger(LoggerFactory.getLogger(getClass.getName)) + + implicit class RichTransitiveClosure[T <: Identified](val tc: TransitiveClosure[T]) extends AnyVal { + def ?=(elem: SSAVariable) = { + if (elem.isInstanceOf[GlobalVariable]) { + tc += elem.asInstanceOf[T] + } + tc + } + def ??=(elems: Seq[SSAVariable]) = { + for (elem <- elems) { + this ?= elem + } + tc + } + } + + case class GlobalCellRec(begin: Word, end: Word, g: GlobalCell) +} + +class TransitiveClosureBuilder(initialSet: Seq[Int])(implicit microVM: MicroVM) extends RefFieldHandler { + import TransitiveClosureBuilder._ + + private val globalMemory: Space = microVM.memoryManager.globalMemory + private val smallObjectSpace: Space = microVM.memoryManager.heap.space + private val largeObjectSpace: Space = microVM.memoryManager.heap.los + private implicit val memorySupport = microVM.memoryManager.memorySupport + + /** + * Top-level definitions in the closure. Function versions are not considered top-level here. A function may have at + * most one function version. Only that version is serialised into the boot image. + */ + val tls = TransitiveClosure[Identified](initialSet.map(microVM.globalBundle.allNs.apply): _*) + + /** + * Global cells + heap objects. + */ + val allocs = TransitiveClosure[Word]() + + def getGlobalCellAddr(g: GlobalCell): Word = { + microVM.constantPool.getGlobalVarBox(g).asInstanceOf[BoxIRef].addr + } + + /** + * Map the global cell's starting address to the global cell itself. + */ + val globalCellMap = { + val elems = microVM.globalBundle.globalCellNs.all.toSeq.map { g => + val begin = getGlobalCellAddr(g) + val ty = g.cellTy + assert(!ty.isInstanceOf[TypeHybrid]) + val size = TypeSizes.sizeOf(ty) + val end = begin + size + (begin, GlobalCellRec(begin, end, g)) + } + TreeMap[Word, GlobalCellRec](elems: _*) + } + + def getGlobalCellRec(iref: Word): GlobalCellRec = { + require(microVM.memoryManager.globalMemory.isInSpace(iref), + "Address %d 0x%x is not in the global space".format(iref, iref)) + + val (begin, gcr) = globalCellMap.to(iref).last + assert(begin <= iref && iref < gcr.end, + "Address %d 0x%x is in the global space, but the previous global cell's address range is %d 0x%x - %d 0x%x".format( + iref, iref, begin, begin, gcr.end, gcr.end)) + + gcr + } + + def doTransitiveClosure(): Unit = { + while (tls.hasPending || allocs.hasPending) { + while (tls.hasPending) { + visitTopLevel(tls.dequeue()) + } + while (allocs.hasPending) { + visitAllocUnit(allocs.dequeue()) + } + } + } + + private def visitTopLevel(tl: Identified): Unit = { + tl match { + case t: Type => visitType(t) + case s: FuncSig => visitFuncSig(s) + case c: Constant => visitConstant(c) + case g: GlobalCell => visitGlobalCell(g) + case f: Function => visitFunction(f) + case e: ExposedFunc => visitExpFunc(e) + } + } + + private def visitType(ty: Type): Unit = ty match { + case TypeUPtr(t) => tls += t + case TypeUFuncPtr(s) => tls += s + case TypeStruct(ts) => tls ++= ts + case TypeHybrid(fs, v) => tls ++= fs += v + case TypeArray(t, _) => tls += t + case TypeVector(t, _) => tls += t + case TypeRef(t) => tls += t + case TypeIRef(t) => tls += t + case TypeWeakRef(t) => tls += t + case TypeFuncRef(s) => tls += s + case _ => // Not nested or recursive. Do nothing. + } + + private def visitFuncSig(s: FuncSig): Unit = { + tls ++= s.paramTys ++= s.retTys + } + + private def visitConstant(c: Constant): Unit = { + tls += c.constTy + + c match { + case ConstSeq(_, elems) => tls ++= elems + case _ => // Not nested. Do nothing. + } + } + + private def visitGlobalCell(g: GlobalCell): Unit = { + tls += g.cellTy + + allocs += getGlobalCellAddr(g) + } + + private def visitFunction(f: Function): Unit = { + tls += f.sig + + microVM.globalBundle.funcToVers(f).headOption match { + case None => // Undefined. Do nothing + case Some(mostRecent) => { + // Visit all TOP-LEVELS (mostly types sigs and SSA variables). + // This version, including all of its basic blocks and instructions, will be in the boot image. + for (bb <- mostRecent.bbs) { + tls ++= bb.norParams.map(_.ty) + + for (inst <- bb.insts) { + visitInstruction(inst) + } + } + } + } + } + + private def visitExpFunc(e: ExposedFunc): Unit = { + tls += e.func + tls += e.cookie + } + + private def visitInstruction(inst: Instruction): Unit = inst match { + case InstBinOp(op, opndTy, op1, op2, excClause) => tls += opndTy ?= op1 ?= op2 + case InstCmp(op, opndTy, op1, op2) => tls += opndTy ?= op1 ?= op2 + case InstConv(op, fromTy, toTy, opnd) => tls += fromTy += toTy ?= opnd + case InstSelect(condTy, opndTy, cond, ifTrue, ifFalse) => tls += condTy += opndTy ?= cond ?= ifTrue ?= ifFalse + case InstBranch(dest) => + case InstBranch2(cond, ifTrue, ifFalse) => tls ?= cond + case i @ InstSwitch(opndTy, opnd, defDest, cases) => tls += opndTy ?= opnd ??= cases.map(_._1) + case InstCall(sig, callee, argList, excClause, keepalives) => tls += sig ?= callee ??= argList + case InstTailCall(sig, callee, argList) => tls += sig ?= callee ??= argList + case InstRet(funcVer, retVals) => tls ??= retVals + case InstThrow(excVal) => tls ?= excVal + case InstExtractValue(strTy, index, opnd) => tls += strTy ?= opnd + case InstInsertValue(strTy, index, opnd, newVal) => tls += strTy ?= opnd ?= newVal + case InstExtractElement(seqTy, indTy, opnd, index) => tls += seqTy += indTy ?= opnd ?= index + case InstInsertElement(seqTy, indTy, opnd, index, newVal) => tls += seqTy += indTy ?= opnd ?= index ?= newVal + case InstShuffleVector(vecTy, maskTy, vec1, vec2, mask) => tls += vecTy += maskTy ?= vec1 ?= vec2 ?= mask + case InstNew(allocTy, excClause) => tls += allocTy + case InstNewHybrid(allocTy, lenTy, length, excClause) => tls += allocTy += lenTy ?= length + case InstAlloca(allocTy, excClause) => tls += allocTy + case InstAllocaHybrid(allocTy, lenTy, length, excClause) => tls += allocTy += lenTy ?= length + case InstGetIRef(referentTy, opnd) => tls += referentTy ?= opnd + case InstGetFieldIRef(ptr, referentTy, index, opnd) => tls += referentTy ?= opnd + case InstGetElemIRef(ptr, referentTy, indTy, opnd, index) => tls += referentTy += indTy ?= opnd ?= index + case InstShiftIRef(ptr, referentTy, offTy, opnd, offset) => tls += referentTy += offTy ?= opnd ?= offset + case InstGetVarPartIRef(ptr, referentTy, opnd) => tls += referentTy ?= opnd + case InstLoad(ptr, ord, referentTy, loc, excClause) => tls += referentTy ?= loc + case InstStore(ptr, ord, referentTy, loc, newVal, excClause) => tls += referentTy ?= loc ?= newVal + case InstCmpXchg(ptr, weak, ordSucc, ordFail, referentTy, loc, expected, desired, excClause) // This line is long ... + => tls += referentTy ?= loc ?= expected ?= desired + case InstAtomicRMW(ptr, ord, op, referentTy, loc, opnd, excClause) => tls += referentTy ?= loc ?= opnd + case InstFence(ord) => + case InstTrap(retTys, excClause, keepalives) => tls ++= retTys + case InstWatchPoint(wpID, retTys, dis, ena, exc, keepalives) => tls ++= retTys + case InstWPBranch(wpID, dis, ena) => + case InstCCall(callConv, funcTy, sig, callee, argList, excClause, keepalives) // This line is long, too... + => tls += funcTy += sig ?= callee ??= argList + case InstNewThread(stack, threadLocal, newStackAction, excClause) => { + tls ?= stack + threadLocal.foreach(tls.?=) + visitNewStackAction(newStackAction) + } + case InstSwapStack(swappee, curStackAction, newStackAction, excClause, keepalives) => { + tls ?= swappee + curStackAction match { + case RetWith(ts) => tls ++= ts + case KillOld() => + } + visitNewStackAction(newStackAction) + } + case InstCommInst(ci, flagList, typeList, funcSigList, argList, excClause, keepalives) => + tls ++= typeList ++= funcSigList ??= argList + + case _ => throw new BootImageBuilderException("Unknown instruction: " + inst.getClass.getName) + } + + private def visitNewStackAction(nsa: NewStackAction): Unit = nsa match { + case PassValues(ts, vs) => tls ++= ts ??= vs + case ThrowExc(e) => + } + + private def visitAllocUnit(addrOrObjRef: Word): Unit = { + logger.debug("Visiting allocation unit 0x%x".format(addrOrObjRef)) + if (globalMemory.isInSpace(addrOrObjRef)) { + val GlobalCellRec(begin, end, g) = getGlobalCellRec(addrOrObjRef) + logger.debug(" It's global cell. begin=0x%x, end=0x%x, type=%s".format(begin, end, g.cellTy)) + tls += g + visitAllocUnitFields(begin, g.cellTy) + } else if (smallObjectSpace.isInSpace(addrOrObjRef) || largeObjectSpace.isInSpace(addrOrObjRef)) { + val objRef = addrOrObjRef + val tag = HeaderUtils.getTag(objRef) + val ty = HeaderUtils.getType(microVM, tag) + tls += ty + visitAllocUnitFields(objRef, ty) + } else { + throw new BootImageBuilderException("Address %d 0x%x is not in the heap or global space".format(addrOrObjRef, addrOrObjRef)) + } + } + + private def visitAllocUnitFields(begin: Word, ty: Type): Unit = { + MemoryDataScanner.scanAllocUnit(begin, this) + } + + def boxToHeap(box: HasObjRef): Option[Word] = + throw new BootImageBuilderException("BUG: Box should not have been scanned during boot image building.") + + def boxToStack(box: BoxStack): Option[InterpreterStack] = + throw new BootImageBuilderException("BUG: Box should not have been scanned during boot image building.") + + def memToHeap(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean, isTR64: Boolean): Option[Word] = { + if (toObj != 0L) { + allocs += toObj + Some(toObj) + } else { + None + } + } + + def memToStack(objRef: Word, iRef: Word, toStack: Option[InterpreterStack]): Option[InterpreterStack] = { + if (toStack.isDefined) { + throw new BootImageBuilderException( + "Error: Stack reachable during boot image building. From: obj 0x%x, iref 0x%x. To stack id: %d".format( + objRef, iRef, toStack.get.id)) + } + None + } + + def stackToStackMem(stack: InterpreterStack, toObj: Word): Option[Word] = + throw new BootImageBuilderException("BUG: Stack should not have been scanned during boot image building.") + + def threadToStack(thread: InterpreterThread, toStack: Option[InterpreterStack]): Option[InterpreterStack] = + throw new BootImageBuilderException("BUG: Thread should not have been scanned during boot image building.") + + def pinSetToMem(toObj: Word): Option[Word] = + throw new BootImageBuilderException("BUG: Pin set should not have been scanned during boot image building.") +} \ No newline at end of file diff --git a/tests/uvm-refimpl-test/transitive-closure.hail b/tests/uvm-refimpl-test/transitive-closure.hail index 1b5e4f743e562e6dd511254cb107eeaad2031f62..f9cf0d16a71db47952cddca15f4707630ea0bac8 100644 --- a/tests/uvm-refimpl-test/transitive-closure.hail +++ b/tests/uvm-refimpl-test/transitive-closure.hail @@ -2,12 +2,12 @@ .new $o2 <@ll> .new $o3 <@ll> +.init @llhead = $o1 +.init @llhead_void = $o1 + .init $o1 = {100 $o2} .init $o2 = {200 $o3} .init $o3 = {300 NULL} .init @gr1 = 42 .init @gr2 = &@gr1 - -.init @llhead = $o1 -.init @llhead_void = $o1