Commit 514cf45e authored by Kunshan Wang's avatar Kunshan Wang

GC tests and bug fixes.

parent 58b25069
......@@ -518,8 +518,8 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
handleOutOfMemory(excClause) {
val addr = mutator.allocaScalar(curStack.stackMemory, allocTy)
val ib = boxOf(i).asInstanceOf[BoxIRef]
ib.objRef = addr
ib.offset = 0L
ib.objRef = 0L
ib.offset = addr
continueNormally()
}
}
......@@ -530,8 +530,8 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
val len = OpHelper.prepareUnsigned(lb.value, lenTy.length)
val addr = mutator.allocaHybrid(curStack.stackMemory, allocTy, len.longValue)
val ib = boxOf(i).asInstanceOf[BoxIRef]
ib.objRef = addr
ib.offset = 0L
ib.objRef = 0L
ib.offset = addr
continueNormally()
}
}
......
......@@ -21,6 +21,7 @@ object MemoryDataScanner extends StrictLogging {
val tag = HeaderUtils.getTag(objRef)
logger.debug("Obj 0x%x, tag 0x%x".format(objRef, tag))
val ty = HeaderUtils.getType(microVM, tag)
logger.debug("Type: %s".format(ty.repr))
scanField(ty, objRef, objRef, handler)
}
......
......@@ -23,18 +23,194 @@ class UvmInterpreterGCTests extends UvmBundleTesterBase {
def gc() = microVM.memoryManager.heap.mutatorTriggerAndWaitForGCEnd(false)
/** Disable some logger for allocation-heavy parts. */
def quiet[T](f: => T): T = {
setLogLevels(
"uvm.refimpl.itpr" -> INFO,
"uvm.refimpl.mem.simpleimmix.SimpleImmixMutator$" -> INFO,
"uvm.refimpl.mem.HeaderUtils" -> INFO)
val rv = f
setLogLevels("uvm.refimpl.itpr" -> DEBUG,
"uvm.refimpl.mem.simpleimmix.SimpleImmixMutator$" -> null,
"uvm.refimpl.mem.HeaderUtils" -> null)
rv
}
"The memory manager" should "retain global reference between gc." in {
val ca = microVM.newClientAgent()
val func = ca.putFunction("@keepglobal")
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
gc()
nameOf(ca.currentInstruction(st, 0)) match {
case "@keepglobal_v1.gctrap" => {
gc()
TrapRebindPassVoid(st)
}
case "@keepglobal_v1.checktrap" => {
val Seq(obj2, obj2val) = ca.dumpKeepalives(st, 0)
obj2.vb.asRef shouldNot be(0L)
obj2val.vb.asSInt(64) shouldBe 42
TrapRebindPassVoid(st)
}
}
}
ca.close()
}
"The memory manager" should "not retain references in dead alloca cells between gc." in {
val ca = microVM.newClientAgent()
val func = ca.putFunction("@nokeepalloca")
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
nameOf(ca.currentInstruction(st, 0)) match {
case "@nokeepalloca_v1.gctrap" => {
gc()
TrapRebindPassVoid(st)
}
case "@allocatest_v1.gctrap" => {
gc()
TrapRebindPassVoid(st)
}
}
}
ca.close()
}
"The large object space" should "withstand repeated non-retained allocations" in {
val ca = microVM.newClientAgent()
quiet {
val func = ca.putFunction("@crazy_allocation_test")
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
fail("No traps in this test")
}
}
ca.close()
gc()
}
"The small object space" should "withstand repeated fragmented allocations" in {
val ca = microVM.newClientAgent()
quiet {
val func = ca.putFunction("@breadcrumbs")
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
fail("No traps in this test")
}
}
ca.close()
gc()
}
"The garbage collector" should "nullify weak references if there is no strong references to the referent" in {
val ca = microVM.newClientAgent()
val func = ca.putFunction("@testweakref")
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
nameOf(ca.currentInstruction(st, 0)) match {
case "@testweakref_v1.gctrap" => {
gc()
TrapRebindPassVoid(st)
}
case "@peekweakref_v1.checknztrap" => {
val Seq(refval) = ca.dumpKeepalives(st, 0)
refval.vb.asRef shouldNot be(0L)
TrapRebindPassVoid(st)
}
case "@testweakref_v1.checkztrap" => {
val Seq(refval) = ca.dumpKeepalives(st, 0)
refval.vb.asRef should be(0L)
TrapRebindPassVoid(st)
}
}
}
ca.close()
gc()
}
"The garbage collector" should "treat tagref64 as reference when it actually is" in {
val ca = microVM.newClientAgent()
val func = ca.putFunction("@testtagrefgc")
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
nameOf(ca.currentInstruction(st, 0)) match {
case "@testtagrefgc_v1.gctrap" => {
gc()
TrapRebindPassVoid(st)
}
case "@testtagrefgc_v1.checktrap" => {
val Seq(tr, refv, tagv, iv) = ca.dumpKeepalives(st, 0)
ca.toInt(tagv) shouldBe 13
ca.toInt(iv) shouldBe 42
TrapRebindPassVoid(st)
}
}
}
ca.close()
gc()
}
"The garbage collector" should "scan tagref64 references in the memory" in {
val ca = microVM.newClientAgent()
val func = ca.putFunction("@testtagrefgcmem")
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
nameOf(ca.currentInstruction(st, 0)) match {
case "@testtagrefgcmem_v1.gctrap" => {
gc()
TrapRebindPassVoid(st)
}
case "@testtagrefgcmem_v1.checktrap" => {
val Seq(tr, refv, tagv, iv) = ca.dumpKeepalives(st, 0)
TrapRebindPassVoid(st)
ca.toInt(tagv) shouldBe 13
ca.toInt(iv) shouldBe 42
TrapRebindPassVoid(st)
}
}
}
ca.close()
gc()
}
"The small object space" should "withstand repeated fragmented allocations when objects are referred by tagref64" in {
val ca = microVM.newClientAgent()
quiet {
val func = ca.putFunction("@breadcrumbstr64")
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
fail("No traps in this test")
}
}
ca.close()
gc()
}
}
\ No newline at end of file
......@@ -102,7 +102,6 @@
.global @g_sta <@stack>
.global @g_tr64 <@tagref64>
.const @CRAZY_ALLOC_COUNT <@i64> = 100
.const @RI64_NULL <@refi64> = NULL
.global @g_refi64 <@refi64>
......@@ -163,6 +162,8 @@
RETVOID
}
.const @CRAZY_ALLOC_COUNT <@i64> = 1000
.funcdef @crazy_allocator VERSION @crazy_allocator_v1 <@noparamsnoret> () {
%entry:
BRANCH %head
......@@ -181,12 +182,19 @@
RETVOID
}
.funcdef @crazy_allocation_test VERSION @crazy_allocation_test_v1 <@noparamsnoret> () {
%entry:
CALL <@noparamsnoret> @crazy_allocator ()
COMMINST @uvm.thread_exit
}
.typedef @refi64array = hybrid <@void @refi64>
.const @REM_SZ <@i64> = 2000
.const @REM_PER_ALLOC <@i64> = 100000
.const @NALLOCS <@i64> = 2000000
.const @NALLOCS <@i64> = 1000000
// Retain one object per @REM_SZ objects. Testing defragmentation
.funcdef @breadcrumbs VERSION @breadcrumbs_v1 <@noparamsnoret> () {
%entry:
%remember = NEWHYBRID <@refi64array @i64> @REM_SZ
......@@ -275,14 +283,16 @@
.funcdef @testtagrefgc VERSION @testtagrefgc_v1 <@noparamsnoret> () {
%entry:
%tr = CALL <@maketr64intref_sig> @maketr64intref ()
%gctrap = TRAP <@void>
%next:
%refv = COMMINST @uvm.tr64.to_ref(%tr)
%tagv = COMMINST @uvm.tr64.to_tag(%tr)
%refi = REFCAST <@refvoid @refi64> %refv
%irefi = GETIREF <@i64> %refi
%iv = LOAD <@i64> %irefi
%checktrap = TRAP <@void> KEEPALIVE (%tr %refv %tagv %iv)
COMMINST @uvm.thread_exit
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment