Commit 3f08206b authored by Kunshan Wang's avatar Kunshan Wang

merge from master

parents ccf57143 f77642c3
......@@ -68,7 +68,7 @@ static void init_jvm() {
exit(1);
}
new_ex_mid = (*env)->GetStaticMethodID(env, cinitiater_cls, new_ex_method, "(JJJ)J");
new_ex_mid = (*env)->GetStaticMethodID(env, cinitiater_cls, new_ex_method, "(Ljava/lang/String;)J");
if (new_ex_mid == NULL) {
printf("ERROR: method %s cannot be found.\n", new_ex_method);
......@@ -94,13 +94,22 @@ MuVM *mu_refimpl2_new() {
return (MuVM*)rv;
}
MuVM *mu_refimpl2_new_ex(int64_t heap_size, int64_t global_size, int64_t stack_size) {
MuVM *mu_refimpl2_new_ex(const char *gc_conf) {
if (jvm == NULL) {
init_jvm();
}
jstring conf_str = (*env)->NewStringUTF(env, gc_conf);
if (conf_str == NULL) {
printf("ERROR: Cannot convert gc_conf to Java String\n");
exit(1);
}
uintptr_t rv = (*env)->CallStaticLongMethod(env, cinitiater_cls, new_ex_mid,
heap_size, global_size, stack_size);
conf_str);
(*env)->DeleteLocalRef(env, conf_str);
return (MuVM*)rv;
}
......
......@@ -10,7 +10,7 @@ extern "C" {
#endif
MuVM *mu_refimpl2_new();
MuVM *mu_refimpl2_new_ex(int64_t heap_size, int64_t global_size, int64_t stack_size);
MuVM *mu_refimpl2_new_ex(const char *gc_conf);
void mu_refimpl2_close(MuVM *mvm);
......
......@@ -7,11 +7,18 @@
#include <refimpl2-start.h>
#include <muapi.h>
char *hw_string = "Hello world!\n";
char *hw2_string = "Goodbye world!\n";
const char *hw_string = "Hello world!\n";
const char *hw2_string = "Goodbye world!\n";
const char *gc_conf =
"sosSize=524288\n"
"losSize=524288\n"
"globalSize=1048576\n"
"stackSize=32768\n"
;
int main() {
MuVM *mvm = mu_refimpl2_new_ex(1048576, 1048576, 32768);
MuVM *mvm = mu_refimpl2_new_ex(gc_conf);
MuCtx *ctx = mvm->new_context(mvm);
......
......@@ -4,4 +4,3 @@ def _assert_instance(obj, *tys):
if not any(isinstance(obj, ty) for ty in tys):
raise AssertionError("{} is not an instance of {}".format(obj,
" or ".join(map(str,tys))))
......@@ -5,17 +5,17 @@ from _libmuprivcommon import _assert_instance
def _is_str_like(v):
return isinstance(v, str) or isinstance(v, unicode)
def _encode_ascii(v):
def _encode(v, encoding):
_assert_instance(v, str, unicode)
if isinstance(v, unicode):
return v.encode("ascii")
return v.encode(encoding)
else:
return v
def _decode_ascii(v):
def _decode(v, encoding):
_assert_instance(v, str, unicode)
if isinstance(v, str):
return v.decode("ascii")
return v.decode(encoding)
else:
return v
......
......@@ -3,17 +3,17 @@ from _libmuprivcommon import _assert_instance
def _is_str_like(v):
return isinstance(v, str) or isinstance(v, bytes)
def _encode_ascii(v):
def _encode(v, encoding):
_assert_instance(v, bytes, str)
if isinstance(v, str):
return v.encode("ascii")
return v.encode(encoding)
else:
return v
def _decode_ascii(v):
def _decode(v, encoding):
_assert_instance(v, bytes, str)
if isinstance(v, bytes):
return v.decode("ascii")
return v.decode(encoding)
else:
return v
......
......@@ -36,7 +36,14 @@ Then a ``MuVM`` instance can be created from that object::
or::
mu = dll.mu_refimpl2_new_ex(HEAP_SIZE, GLOBAL_SIZE, STACK_SIZE)
mu = dll.mu_refimpl2_new_ex(
sosSize = 2*1024*1024,
losSize = 2*1024*1024,
globalSize = 4*1024*1024,
stackSize = 63*1024,
gcLog = "WARN",
vmLog = "INFO",
)
A ``MuCtx`` instance can be created from the ``MuVM`` object::
......@@ -157,6 +164,9 @@ else:
import _libmuprivpython3 as _priv
import ctypes, ctypes.util
import logging
logger = logging.getLogger(__name__)
_libc = ctypes.CDLL(ctypes.util.find_library("c"))
_libc.malloc.restype = ctypes.c_void_p
......@@ -670,7 +680,7 @@ class MuCtx(_StructOfMethodsWrapper):
Arguments:
bundle_str: a str or unicode as the text-based bundle.
"""
ascii_bundle = _priv._encode_ascii(bundle_str)
ascii_bundle = _priv._encode(bundle_str, "ascii")
return self.load_bundle_(ascii_bundle, len(ascii_bundle))
def load_hail(self, hail_str):
......@@ -679,7 +689,7 @@ class MuCtx(_StructOfMethodsWrapper):
Arguments:
bundle_str: a str or unicode as the text-based HAIL script.
"""
ascii_bundle = _priv._encode_ascii(hail_str)
ascii_bundle = _priv._encode(hail_str, "ascii")
return self.load_hail_(ascii_bundle, len(ascii_bundle))
def handle_from_int(self, value, length):
......@@ -852,13 +862,13 @@ def _to_low_level_type(ty):
def _to_low_level_arg(arg):
return (arg._to_low_level_arg() if isinstance(arg, _LowLevelTypeWrapper) else
_priv._encode_ascii(arg) if _priv._is_str_like(arg) else
_priv._encode(arg, "ascii") if _priv._is_str_like(arg) else
arg)
def _from_low_level_retval(restype, low_level_rv, self):
return (restype._from_low_level_retval(low_level_rv, self)
if isinstance(restype, type) and issubclass(restype, _LowLevelTypeWrapper) else
_priv._decode_ascii(low_level_rv) if _priv._is_str_like(low_level_rv) else
_priv._decode(low_level_rv, "ascii") if _priv._is_str_like(low_level_rv) else
low_level_rv)
def _make_high_level_method(name, expected_nargs, restype, argtypes):
......@@ -924,7 +934,7 @@ def _initialize_methods(high_level_class, methods):
# make low-level struct field (function pointer)
low_level_restype = _to_low_level_type(restype)
low_level_argtypes = [_to_low_level_type(ty) for ty in argtypes]
print("Python binding:", name, low_level_restype, low_level_argtypes)
logger.debug("Python binding: %s :: %s %s", name, low_level_restype, low_level_argtypes)
funcptr = _funcptr(
low_level_restype, # return value
objtype_p, *low_level_argtypes # params. Start with a struct ptr
......@@ -1129,8 +1139,7 @@ class MuRefImpl2StartDLL(object):
dll.mu_refimpl2_new.argtypes = []
dll.mu_refimpl2_new_ex.restype = CPtrMuVM
dll.mu_refimpl2_new_ex.argtypes = [ctypes.c_int64,
ctypes.c_int64, ctypes.c_int64]
dll.mu_refimpl2_new_ex.argtypes = [ctypes.c_char_p]
dll.mu_refimpl2_close.restype = None
dll.mu_refimpl2_close.argtypes = [CPtrMuVM]
......@@ -1138,17 +1147,30 @@ class MuRefImpl2StartDLL(object):
self.dll = dll
def mu_refimpl2_new(self):
"""Create a MuVM instance using the default heap/global/stack sizes."""
"""Create a MuVM instance using the default configuration."""
ptr = self.dll.mu_refimpl2_new()
return MuVM(ptr, self)
def mu_refimpl2_new_ex(self, heap_size, global_size, stack_size):
"""Create a MuVM instance using custom heap/global/stack sizes.
def mu_refimpl2_new_ex(self, **kwargs):
"""Create a MuVM instance using custom configuration.
Currently supported keyword arguments:
sosSize: small object space size (bytes, must be 4096-byte aligned)
losSize: large object space size (bytes, must be 4096-byte aligned)
globalSize: global space size (bytes, must be 4096-byte aligned)
stackSize: stack size (bytes)
vmLog: log level for the micro VM
gcLog: log level fof the garbage collector
possible values for log levels (strings, case insensitive):
ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF
heap_size, global_size, stack_size are the sizes of the GC heap, global
memory and each stack. All of them are in bytes.
Setting to WARN will disable almost all logs. Set vmLog to INFO to see
the execution of each instruction; Set gcLog to DEBUG to see GC logs.
"""
ptr = self.dll.mu_refimpl2_new_ex(heap_size, global_size, stack_size)
conf = "".join("{}={}\n".format(k,v) for k,v in kwargs.items())
ptr = self.dll.mu_refimpl2_new_ex(_priv._encode(conf, "utf8"))
return MuVM(ptr, self)
def mu_refimpl2_close(self, muvm):
......
......@@ -5,7 +5,12 @@ import unittest
from libmu import *
dll = MuRefImpl2StartDLL(u"../cbinding/libmurefimpl2start.so")
mu = dll.mu_refimpl2_new()
mu = dll.mu_refimpl2_new_ex(
sosSize = 2*1024*1024,
losSize = 2*1024*1024,
globalSize = 4*1024*1024,
stackSize = 63*1024,
)
with mu.new_context() as ctx:
ctx.load_bundle("""
......
......@@ -45,8 +45,7 @@ public class CInitiater {
/** Called by the native program, this function creates a Mu instance. */
static long mu_refimpl2_new() {
configureLog();
MicroVM mvm = new MicroVM(MicroVM$.MODULE$.DEFAULT_HEAP_SIZE(), MicroVM$.MODULE$.DEFAULT_GLOBAL_SIZE(),
MicroVM$.MODULE$.DEFAULT_STACK_SIZE());
MicroVM mvm = MicroVM$.MODULE$.apply();
long fak = NativeClientSupport$.MODULE$.exposeMicroVM(mvm);
return fak;
}
......@@ -55,9 +54,9 @@ public class CInitiater {
* Called by the native program, this function creates a Mu instance with
* extra arguments.
*/
static long mu_refimpl2_new_ex(long heap_size, long global_size, long stack_size) {
static long mu_refimpl2_new_ex(String gcConfString) {
configureLog();
MicroVM mvm = new MicroVM(heap_size, global_size, stack_size);
MicroVM mvm = MicroVM$.MODULE$.apply(gcConfString);
long fak = NativeClientSupport$.MODULE$.exposeMicroVM(mvm);
return fak;
}
......
......@@ -13,30 +13,38 @@ import uvm.refimpl.nat.NativeCallHelper
import uvm.staticanalysis.StaticAnalyzer
object MicroVM {
val DEFAULT_HEAP_SIZE: Word = 4L * 1024L * 1024L; // 4MiB
val DEFAULT_SOS_SIZE: Word = 2L * 1024L * 1024L; // 2MiB
val DEFAULT_LOS_SIZE: Word = 2L * 1024L * 1024L; // 2MiB
val DEFAULT_GLOBAL_SIZE: Word = 1L * 1024L * 1024L; // 1MiB
val DEFAULT_STACK_SIZE: Word = 63L * 1024L; // 60KiB per stack
val FIRST_CLIENT_USABLE_ID: Int = 65536
}
class MicroVM(heapSize: Word = MicroVM.DEFAULT_HEAP_SIZE,
globalSize: Word = MicroVM.DEFAULT_GLOBAL_SIZE,
stackSize: Word = MicroVM.DEFAULT_STACK_SIZE) {
def apply(): MicroVM = {
val vmConf = new VMConf()
new MicroVM(vmConf)
}
def apply(confStr: String): MicroVM = {
val vmConf = VMConf(confStr)
new MicroVM(vmConf)
}
}
class MicroVM(vmConf: VMConf) {
// implicitly injected resources
private implicit val microVM = this
val globalBundle = new GlobalBundle()
val constantPool = new ConstantPool()
val memoryManager = new MemoryManager(heapSize, globalSize, stackSize)
val memoryManager = new MemoryManager(vmConf)
private implicit val memorySupport = memoryManager.memorySupport
implicit val nativeCallHelper = new NativeCallHelper()
val threadStackManager = new ThreadStackManager()
val trapManager = new TrapManager()
val contexts = new HashSet[MuCtx]()
......@@ -57,7 +65,7 @@ class MicroVM(heapSize: Word = MicroVM.DEFAULT_HEAP_SIZE,
}
// Some internal constants needed by the HAIL loader
for (c <- Seq(NULL_REF_VOID, NULL_IREF_VOID, NULL_FUNCREF_VV, NULL_THREADREF, NULL_STACKREF)) {
globalBundle.constantNs.add(c)
constantPool.addGlobalVar(c)
......@@ -69,7 +77,7 @@ class MicroVM(heapSize: Word = MicroVM.DEFAULT_HEAP_SIZE,
*/
def addBundle(bundle: TrantientBundle) {
staticAnalyzer.checkBundle(bundle, Some(globalBundle))
globalBundle.merge(bundle);
for (gc <- bundle.globalCellNs.all) {
......
/**
* This class allows the MicroVM to be configured from a text string. It increases the flexibility of language bindings.
* Other programming languages can set heap/global sizes and logging via this interface. It is less static than a fixed
* MicroVM constructor signature, but more options can be added/removed without changing the C binding API.
*/
package uvm.refimpl
import uvm.refimpl.mem.TypeSizes._
object VMConf {
val ReComment = """^\s*#.*$""".r
val ReBlank = """^\s*$""".r
val ReConf = """^\s*(\w+)=(\w+)\s*$""".r
def apply(confStr: String): VMConf = {
var sosSize = MicroVM.DEFAULT_SOS_SIZE
var losSize = MicroVM.DEFAULT_LOS_SIZE
var globalSize = MicroVM.DEFAULT_GLOBAL_SIZE
var stackSize = MicroVM.DEFAULT_GLOBAL_SIZE
confStr.lines foreach {
case ReComment() =>
case ReBlank() =>
case ReConf(key, value) => {
key match {
case "sosSize" => sosSize = value.toLong
case "losSize" => losSize = value.toLong
case "globalSize" => globalSize = value.toLong
case "stackSize" => stackSize = value.toLong
case "vmLog" => setLog("uvm.refimpl", value)
case "gcLog" => setLog("uvm.refimpl.mem", value)
case _ => throw new UvmRefImplException("Unrecognized option %s".format(key))
}
}
}
new VMConf(sosSize, losSize, globalSize, stackSize)
}
def setLog(name: String, levelStr: String): Unit = {
import org.slf4j.LoggerFactory
import org.slf4j.{ Logger => SLogger }
import ch.qos.logback.classic.{ Logger => LLogger, Level }
import ch.qos.logback.classic.Level._
val level = Level.toLevel(levelStr)
LoggerFactory.getLogger(name).asInstanceOf[LLogger].setLevel(level)
}
}
class VMConf(
val sosSize: Word = MicroVM.DEFAULT_SOS_SIZE,
val losSize: Word = MicroVM.DEFAULT_LOS_SIZE,
val globalSize: Word = MicroVM.DEFAULT_GLOBAL_SIZE,
val stackSize: Word = MicroVM.DEFAULT_STACK_SIZE)
......@@ -34,6 +34,7 @@ object HeaderUtils extends StrictLogging {
}
def setVarLength(objRef: Word, len: Word)(implicit memorySupport: MemorySupport) {
logger.debug("Storing varLength 0x%x at addr 0x%x".format(len, objRef + TypeSizes.GC_HEADER_OFFSET_HYBRID_LENGTH))
memorySupport.storeLong(objRef + TypeSizes.GC_HEADER_OFFSET_HYBRID_LENGTH, len)
}
......
......@@ -3,25 +3,54 @@ package uvm.refimpl.mem
import uvm.refimpl._
import TypeSizes._
import uvm.refimpl.mem.simpleimmix._
import org.slf4j.LoggerFactory
import com.typesafe.scalalogging.Logger
import uvm.refimpl.mem.los.LargeObjectSpace
class MemoryManager(val heapSize: Word, val globalSize: Word, val stackSize: Word)(implicit microVM: MicroVM) {
object MemoryManager {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
}
class MemoryManager(val vmConf: VMConf)(implicit microVM: MicroVM) {
import MemoryManager._
val totalMemorySize = heapSize + globalSize
logger.info("sosSize=%d, losSize=%d, globalSize=%d, stackSize=%d".format(
vmConf.sosSize, vmConf.losSize, vmConf.globalSize, vmConf.stackSize))
private val sosAlign = SimpleImmixSpace.BLOCK_SIZE
private val losAlign = LargeObjectSpace.BLOCK_SIZE
private val globalAlign = 4096L
require(vmConf.sosSize % sosAlign == 0, "Small object space size must be a multiple of %d bytes. actual size: %d".format(
sosAlign, vmConf.sosSize))
require(vmConf.losSize % losAlign == 0, "Large object space size must a multiple of %d bytes. actual size: %d".format(
losAlign, vmConf.losSize))
require(vmConf.globalSize % globalAlign == 0, "Global space size must be a multiple of %d bytes. actual size: %d".format(
globalAlign, vmConf.globalSize))
val totalMemorySize = vmConf.sosSize.alignUpAndAdd(losAlign, vmConf.losSize).alignUpAndAdd(globalAlign, vmConf.globalSize)
// Allocate slightly more memory to meet the SimpleImmixSpace's alignment requirement.
implicit val memorySupport = new MemorySupport(totalMemorySize + SimpleImmixSpace.BLOCK_SIZE)
val memoryBegin = memorySupport.muMemoryBegin
val heapBegin = TypeSizes.alignUp(memoryBegin, SimpleImmixSpace.BLOCK_SIZE)
val globalBegin = heapBegin + vmConf.sosSize + vmConf.losSize
val globalEnd = globalBegin + vmConf.globalSize
logger.info(("Mu memory allocated.\n memoryBegin=%d 0x%x\n heapBegin=%d 0x%x\n" +
" globalBegin=%d 0x%x\n memory end=%d 0x%x").format(
memoryBegin, memoryBegin, heapBegin, heapBegin, globalBegin, globalBegin, globalEnd, globalEnd
))
val heap = new SimpleImmixHeap(heapBegin, heapSize)
val globalMemory = new GlobalMemory(heapBegin + heapSize, globalSize)
val heap = new SimpleImmixHeap(heapBegin, vmConf.sosSize, vmConf.losSize)
val globalMemory = new GlobalMemory(globalBegin, vmConf.globalSize)
def makeMutator(): Mutator = heap.makeMutator()
def makeStackMemory(mutator: Mutator): StackMemory = {
val objRef = mutator.newHybrid(InternalTypes.BYTE_ARRAY, stackSize)
val stackMemory = new StackMemory(objRef, stackSize)
val objRef = mutator.newHybrid(InternalTypes.BYTE_ARRAY, vmConf.stackSize)
val stackMemory = new StackMemory(objRef, vmConf.stackSize)
stackMemory
}
}
......@@ -2,9 +2,16 @@ package uvm.refimpl.mem
import uvm.types._
import TypeSizes._
import com.typesafe.scalalogging.Logger
import org.slf4j.LoggerFactory
abstract class Mutator(implicit memorySupport: MemorySupport) {
object Mutator {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
}
abstract class Mutator(implicit memorySupport: MemorySupport) {
import Mutator._
def alloc(size: Word, align: Word, headerSize: Word): Word
def newScalar(ty: Type): Word = {
......@@ -13,6 +20,7 @@ abstract class Mutator(implicit memorySupport: MemorySupport) {
val align = alignOf(ty)
val objAddr = alloc(size, align, GC_HEADER_SIZE_SCALAR)
HeaderUtils.postAllocScalar(objAddr, tag)
logger.trace("newScalar: objAddr=%d 0x%x, ty=%s".format(objAddr, objAddr, ty))
objAddr
}
......@@ -22,6 +30,7 @@ abstract class Mutator(implicit memorySupport: MemorySupport) {
val align = hybridAlignOf(ty, len)
val objAddr = alloc(size, align, GC_HEADER_SIZE_HYBRID)
HeaderUtils.postAllocHybrid(objAddr, tag, len)
logger.trace("newHybrid: objAddr=%d 0x%x, len=%d 0x%x, ty=%s".format(objAddr, objAddr, len, len, ty))
objAddr
}
......@@ -31,6 +40,7 @@ abstract class Mutator(implicit memorySupport: MemorySupport) {
val align = alignOf(ty)
val objAddr = sm.alloc(size, align, GC_HEADER_SIZE_SCALAR)
HeaderUtils.postAllocScalar(objAddr, tag)
logger.trace("allocaScalar: objAddr=%d 0x%x, ty=%s".format(objAddr, objAddr, ty))
objAddr
}
......@@ -40,6 +50,7 @@ abstract class Mutator(implicit memorySupport: MemorySupport) {
val align = hybridAlignOf(ty, len)
val objAddr = sm.alloc(size, align, GC_HEADER_SIZE_HYBRID)
HeaderUtils.postAllocHybrid(objAddr, tag, len)
logger.trace("allocaHybrid: objAddr=%d 0x%x, len=%d 0x%x, ty=%s".format(objAddr, objAddr, len, len, ty))
objAddr
}
......
......@@ -160,4 +160,10 @@ object TypeSizes {
def alignDown(n: Word, alignment: Word): Word = {
return n & ~(alignment - 1);
}
implicit class MagicalWord(val word: Word) extends AnyVal {
def alignUpAndAdd(align: Word, size: Word): Word = {
return alignUp(word, align) + size
}
}
}
\ No newline at end of file
......@@ -13,12 +13,14 @@ object LargeObjectSpace {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
val BLOCK_SIZE = SimpleImmixSpace.BLOCK_SIZE / 4
private val OFFSET_PREV = 0 * TypeSizes.WORD_SIZE_BYTES
private val OFFSET_PREV = 0
private val OFFSET_NEXT = 1 * TypeSizes.WORD_SIZE_BYTES
private val OFFSET_NEXT = 8
private val OFFSET_MARK = 2 * TypeSizes.WORD_SIZE_BYTES
private val OFFSET_MARK = 16
private val BLOCK_HEADER_SIZE = 3 * TypeSizes.WORD_SIZE_BYTES
private val MARK_BIT = 0x1
}
......@@ -54,7 +56,7 @@ class LargeObjectSpace(val heap: SimpleImmixHeap, name: String, begin: Long, ext
private var head: Word = 0
def alloc(size: Word, align: Word, headerSize: Word): Word = {
val userStart = TypeSizes.alignUp(16 + headerSize, align)
val userStart = TypeSizes.alignUp(BLOCK_HEADER_SIZE + headerSize, align)
val totalSize = userStart + size
val nBlocks = (totalSize - 1) / BLOCK_SIZE + 1
if (nBlocks > 0xffffffffL) {
......
......@@ -8,6 +8,8 @@ import uvm.refimpl.itpr.OpHelper
import uvm.refimpl.itpr.InterpreterThread
import uvm.refimpl.itpr.InterpreterStack
import uvm.refimpl.UvmRefImplException
import org.slf4j.LoggerFactory
import com.typesafe.scalalogging.Logger
/**
* Handle references in the memory, value boxes or other Micro VM structures such as threads and stacks.
......@@ -37,6 +39,8 @@ trait RefFieldHandler {
}
object RefFieldUpdater {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
def updateBoxToHeap(box: HasObjRef, newObjRef: Word): Unit = box.setObjRef(newObjRef)
def updateBoxToStack(box: BoxStack, newStack: Option[InterpreterStack]) = box.stack = newStack
def updateMemToHeap(iRef: Word, isTR64: Boolean, newObjRef: Word)(implicit memorySupport: MemorySupport): Unit = {
......@@ -44,8 +48,17 @@ object RefFieldUpdater {
val oldRaw = memorySupport.loadLong(iRef)
val oldTag = OpHelper.tr64ToTag(oldRaw)
val newRaw = OpHelper.refToTr64(newObjRef, oldTag)
logger.debug {
val oldObjRef = OpHelper.tr64ToRef(oldRaw)
"Updating tagref field [0x%x] = 0x%x -> 0x%x; ref: 0x%x -> 0x%x".format(
iRef, oldRaw, newRaw, oldObjRef, newObjRef)
}
memorySupport.storeLong(iRef, newRaw)
} else {
logger.debug {
val oldObjRef = memorySupport.loadLong(iRef)
"Updating ref field [0x%x] = 0x%x -> 0x%x".format(iRef, oldObjRef, newObjRef)
}
memorySupport.storeLong(iRef, newObjRef)
}
}
......
......@@ -12,11 +12,45 @@ import org.slf4j.LoggerFactory
import com.typesafe.scalalogging.Logger
import scala.collection.mutable.ArrayBuffer
import uvm.refimpl.UvmRefImplException
import uvm.utils.HexDump
import scala.collection.mutable.HashSet
import com.typesafe.scalalogging.LazyLogging
object SimpleImmixCollector {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
}
private class MarkClearCheck extends LazyLogging {
val markedRefs = new HashSet[Word]()
val clearedRefs = new HashSet[Word]()
val diffRefs = new HashSet[Word]()
def beforeMarking(): Unit = {
markedRefs.clear
}
def marked(objRef: Word): Unit = {
markedRefs.add(objRef)
}
def beforeClearing(): Unit = {
clearedRefs.clear
}
def cleared(objRef: Word): Unit = {
clearedRefs.add(objRef)
}
def debugPrintStat(phase: String): Unit = {
diffRefs.clear()
for (r <- markedRefs if !clearedRefs.contains(r)) {
diffRefs.add(r)
}
logger.debug("After phase %s: nmarked:%d, ncleared:%d".format(phase, markedRefs.size, clearedRefs.size))
logger.debug("After phase %s: Refs marked but not cleared: \n".format(phase) + diffRefs.map(r => "0x%x\n".format(r)).mkString)
}
}
class SimpleImmixCollector(val heap: SimpleImmixHeap, val space: SimpleImmixSpace, val los: LargeObjectSpace)(
implicit microVM: MicroVM, memorySupport: MemorySupport)
extends Collector with Runnable {
......@@ -35,15 +69,22 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap, val space: SimpleImmixSpac
// The number of times GC has run.
private var gcCount: Int = 0
private val MARK_CLEAR_DEBUG = false // Set to true if you want to check if any references are marked but not cleared
private val markClearCheck = if (MARK_CLEAR_DEBUG) Some(new MarkClearCheck()) else None
protected override def collect() {
gcCount += 1
logger.debug(s"GC starts. gcCount=${gcCount}")
if (logger.underlying.isDebugEnabled()) space.debugLogBlockStates()
logger.debug("Clearing stats...")
space.clearStats()
val weakRefs = new ArrayBuffer[Word]()
markClearCheck.map(_.beforeMarking())
logger.debug("Marking and getting statistics....")
val s1 = new AllScanner(new RefFieldHandler() {
......@@ -100,9 +141,17 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap, val space: SimpleImmixSpac
}
}
if (logger.underlying.isDebugEnabled()) space.debugLogBlockStates()
markClearCheck.map(_.beforeClearing())
logger.debug("Stat finished. Unmarking....")
val s2 = new AllScanner(clearMarkHandler)
s2.scanAll()
markClearCheck.map(_.debugPrintStat("2"))
if (logger.underlying.isDebugEnabled()) space.debugLogBlockStates()
val resvSpace = space.getTotalReserveSpace
threshold = space.findThreshold(resvSpace)
......@@ -110,6 +159,10 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap, val space: SimpleImmixSpac
defragMutator = new SimpleImmixDefragMutator(heap, space)
canDefrag = true
if (logger.underlying.isDebugEnabled()) space.debugLogBlockStates()
markClearCheck.map(_.beforeMarking())
logger.debug("Mark again, maybe move objects....")
val s3 = new AllScanner(markMover)
s3.scanAll()
......@@ -133,10 +186,17 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap, val space: SimpleImmixSpac
notifyMovedObjectsToFutex()
if (logger.underlying.isDebugEnabled()) space.debugLogBlockStates()
markClearCheck.map(_.beforeClearing())
logger.debug("Blocks collected. Unmarking....")
val s4 = new AllScanner(clearMarkHandler)