Improve memory tracing, fix 32-bit platforms (#815)
This commit is contained in:
@@ -33,6 +33,7 @@ private val dataModel: DataModel = when (System.getProperty("sun.arch.data.model
|
|||||||
else -> throw IllegalStateException()
|
else -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Must be only used in interop, contains host pointer size, not target!
|
||||||
val pointerSize: Int = dataModel.pointerSize.toInt()
|
val pointerSize: Int = dataModel.pointerSize.toInt()
|
||||||
|
|
||||||
object nativeMemUtils {
|
object nativeMemUtils {
|
||||||
|
|||||||
+5
-5
@@ -110,7 +110,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
|||||||
private var returnSlot: LLVMValueRef? = null
|
private var returnSlot: LLVMValueRef? = null
|
||||||
private var slotsPhi: LLVMValueRef? = null
|
private var slotsPhi: LLVMValueRef? = null
|
||||||
private val frameOverlaySlotCount =
|
private val frameOverlaySlotCount =
|
||||||
(LLVMStoreSizeOfType(llvmTargetData, runtime.frameOverlayType) / pointerSize).toInt()
|
(LLVMStoreSizeOfType(llvmTargetData, runtime.frameOverlayType) / runtime.pointerSize).toInt()
|
||||||
private var slotCount = frameOverlaySlotCount
|
private var slotCount = frameOverlaySlotCount
|
||||||
private var localAllocs = 0
|
private var localAllocs = 0
|
||||||
private var arenaSlot: LLVMValueRef? = null
|
private var arenaSlot: LLVMValueRef? = null
|
||||||
@@ -496,11 +496,10 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
|||||||
if (needSlots) {
|
if (needSlots) {
|
||||||
// Zero-init slots.
|
// Zero-init slots.
|
||||||
val slotsMem = bitcast(kInt8Ptr, slots)
|
val slotsMem = bitcast(kInt8Ptr, slots)
|
||||||
val pointerSize = LLVMABISizeOfType(llvmTargetData, kObjHeaderPtr).toInt()
|
|
||||||
val alignment = LLVMABIAlignmentOfType(llvmTargetData, kObjHeaderPtr)
|
|
||||||
call(context.llvm.memsetFunction,
|
call(context.llvm.memsetFunction,
|
||||||
listOf(slotsMem, Int8(0).llvm,
|
listOf(slotsMem, Int8(0).llvm,
|
||||||
Int32(slotCount * pointerSize).llvm, Int32(alignment).llvm,
|
Int32(slotCount * codegen.runtime.pointerSize).llvm,
|
||||||
|
Int32(codegen.runtime.pointerAlignment).llvm,
|
||||||
Int1(0).llvm))
|
Int1(0).llvm))
|
||||||
call(context.llvm.enterFrameFunction, listOf(slots, Int32(slotCount).llvm))
|
call(context.llvm.enterFrameFunction, listOf(slots, Int32(slotCount).llvm))
|
||||||
}
|
}
|
||||||
@@ -508,7 +507,8 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
|||||||
val slotOffset = pointerSize * slotCount
|
val slotOffset = pointerSize * slotCount
|
||||||
memScoped {
|
memScoped {
|
||||||
slotToVariableLocation.forEach { slot, variable ->
|
slotToVariableLocation.forEach { slot, variable ->
|
||||||
val expr = longArrayOf(DwarfOp.DW_OP_minus.value, slotOffset + pointerSize * slot.toLong()).toCValues()
|
val expr = longArrayOf(DwarfOp.DW_OP_minus.value,
|
||||||
|
slotOffset + runtime.pointerSize * slot.toLong()).toCValues()
|
||||||
DIInsertDeclaration(
|
DIInsertDeclaration(
|
||||||
builder = codegen.context.debugInfo.builder,
|
builder = codegen.context.debugInfo.builder,
|
||||||
value = slotsPhi,
|
value = slotsPhi,
|
||||||
|
|||||||
+9
@@ -58,4 +58,13 @@ class Runtime(bitcodeFile: String) {
|
|||||||
|
|
||||||
val kotlinObjCClassInfo by lazy { getStructType("KotlinObjCClassInfo") }
|
val kotlinObjCClassInfo by lazy { getStructType("KotlinObjCClassInfo") }
|
||||||
val objCMethodDescription by lazy { getStructType("ObjCMethodDescription") }
|
val objCMethodDescription by lazy { getStructType("ObjCMethodDescription") }
|
||||||
|
|
||||||
|
|
||||||
|
val pointerSize: Int by lazy {
|
||||||
|
LLVMABISizeOfType(targetData, objHeaderPtrType).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
val pointerAlignment: Int by lazy {
|
||||||
|
LLVMABIAlignmentOfType(targetData, objHeaderPtrType)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,6 @@
|
|||||||
#define USE_GC 1
|
#define USE_GC 1
|
||||||
// Define to 1 to print all memory operations.
|
// Define to 1 to print all memory operations.
|
||||||
#define TRACE_MEMORY 0
|
#define TRACE_MEMORY 0
|
||||||
// Trace garbage collection phases.
|
|
||||||
#define TRACE_GC_PHASES 0
|
|
||||||
|
|
||||||
ContainerHeader ObjHeader::theStaticObjectsContainer = {
|
ContainerHeader ObjHeader::theStaticObjectsContainer = {
|
||||||
CONTAINER_TAG_PERMANENT | CONTAINER_TAG_INCREMENT
|
CONTAINER_TAG_PERMANENT | CONTAINER_TAG_INCREMENT
|
||||||
@@ -44,6 +42,12 @@ constexpr container_size_t kContainerAlignment = 1024;
|
|||||||
// Single object alignment.
|
// Single object alignment.
|
||||||
constexpr container_size_t kObjectAlignment = 8;
|
constexpr container_size_t kObjectAlignment = 8;
|
||||||
|
|
||||||
|
#if TRACE_MEMORY
|
||||||
|
#define MEMORY_LOG(...) konan::consolePrintf(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define MEMORY_LOG(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if USE_GC
|
#if USE_GC
|
||||||
// Collection threshold default (collect after having so many elements in the
|
// Collection threshold default (collect after having so many elements in the
|
||||||
// release candidates set). Better be a prime number.
|
// release candidates set). Better be a prime number.
|
||||||
@@ -181,9 +185,7 @@ static inline void DeinitInstanceBodyImpl(const TypeInfo* typeInfo, void* body)
|
|||||||
for (int index = 0; index < typeInfo->objOffsetsCount_; index++) {
|
for (int index = 0; index < typeInfo->objOffsetsCount_; index++) {
|
||||||
ObjHeader** location = reinterpret_cast<ObjHeader**>(
|
ObjHeader** location = reinterpret_cast<ObjHeader**>(
|
||||||
reinterpret_cast<uintptr_t>(body) + typeInfo->objOffsets_[index]);
|
reinterpret_cast<uintptr_t>(body) + typeInfo->objOffsets_[index]);
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("Calling UpdateRef from DeinitInstanceBodyImpl\n");
|
||||||
fprintf(stderr, "Calling UpdateRef from DeinitInstanceBodyImpl\n");
|
|
||||||
#endif
|
|
||||||
UpdateRef(location, nullptr);
|
UpdateRef(location, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -306,9 +308,8 @@ void traverseContainerReferredObjects(ContainerHeader* container, func process)
|
|||||||
#if TRACE_MEMORY || USE_GC
|
#if TRACE_MEMORY || USE_GC
|
||||||
|
|
||||||
void dumpWorker(const char* prefix, ContainerHeader* header, ContainerHeaderSet* seen) {
|
void dumpWorker(const char* prefix, ContainerHeader* header, ContainerHeaderSet* seen) {
|
||||||
fprintf(stderr, "%s: %p (%08x): %d refs\n",
|
MEMORY_LOG("%s: %p (%08x): %d refs\n", prefix, header, header->refCount_,
|
||||||
prefix,
|
header->refCount_ >> CONTAINER_TAG_SHIFT);
|
||||||
header, header->refCount_, header->refCount_ >> CONTAINER_TAG_SHIFT);
|
|
||||||
seen->insert(header);
|
seen->insert(header);
|
||||||
traverseContainerReferredObjects(header, [prefix, seen](ObjHeader* ref) {
|
traverseContainerReferredObjects(header, [prefix, seen](ObjHeader* ref) {
|
||||||
auto child = ref->container();
|
auto child = ref->container();
|
||||||
@@ -322,7 +323,7 @@ void dumpWorker(const char* prefix, ContainerHeader* header, ContainerHeaderSet*
|
|||||||
void dumpReachable(const char* prefix, const ContainerHeaderSet* roots) {
|
void dumpReachable(const char* prefix, const ContainerHeaderSet* roots) {
|
||||||
ContainerHeaderSet seen;
|
ContainerHeaderSet seen;
|
||||||
for (auto container : *roots) {
|
for (auto container : *roots) {
|
||||||
fprintf(stderr, "%p is root\n", container);
|
MEMORY_LOG("%p is root\n", container);
|
||||||
dumpWorker(prefix, container, &seen);
|
dumpWorker(prefix, container, &seen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -471,12 +472,10 @@ inline void Release(ContainerHeader* header) {
|
|||||||
// do two allocations per frame (ArenaContainer + actual container).
|
// do two allocations per frame (ArenaContainer + actual container).
|
||||||
inline ArenaContainer* initedArena(ObjHeader** auxSlot) {
|
inline ArenaContainer* initedArena(ObjHeader** auxSlot) {
|
||||||
auto frame = asFrameOverlay(auxSlot);
|
auto frame = asFrameOverlay(auxSlot);
|
||||||
#if TRACE_MEMORY
|
|
||||||
fprintf(stderr, "Initializing arena at %p\n", frame);
|
|
||||||
#endif
|
|
||||||
auto arena = frame->arena;
|
auto arena = frame->arena;
|
||||||
if (!arena) {
|
if (!arena) {
|
||||||
arena = konanConstructInstance<ArenaContainer>();
|
arena = konanConstructInstance<ArenaContainer>();
|
||||||
|
MEMORY_LOG("Initializing arena in %p\n", frame);
|
||||||
arena->Init();
|
arena->Init();
|
||||||
frame->arena = arena;
|
frame->arena = arena;
|
||||||
}
|
}
|
||||||
@@ -492,8 +491,8 @@ ContainerHeader* AllocContainer(size_t size) {
|
|||||||
// is how to get actual size of container.
|
// is how to get actual size of container.
|
||||||
#endif
|
#endif
|
||||||
ContainerHeader* result = konanConstructSizedInstance<ContainerHeader>(size);
|
ContainerHeader* result = konanConstructSizedInstance<ContainerHeader>(size);
|
||||||
|
MEMORY_LOG(">>> alloc %d -> %p\n", static_cast<int>(size), result);
|
||||||
#if TRACE_MEMORY
|
#if TRACE_MEMORY
|
||||||
fprintf(stderr, ">>> alloc %d -> %p\n", static_cast<int>(size), result);
|
|
||||||
state->containers->insert(result);
|
state->containers->insert(result);
|
||||||
#endif
|
#endif
|
||||||
state->allocCount++;
|
state->allocCount++;
|
||||||
@@ -505,16 +504,12 @@ void FreeContainer(ContainerHeader* header) {
|
|||||||
auto state = memoryState;
|
auto state = memoryState;
|
||||||
#if TRACE_MEMORY
|
#if TRACE_MEMORY
|
||||||
if (isFreeable(header)) {
|
if (isFreeable(header)) {
|
||||||
fprintf(stderr, "<<< free<FreeContainer> %p\n", header);
|
MEMORY_LOG("<<< free<FreeContainer> %p\n", header);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Now let's clean all object's fields in this container.
|
// Now let's clean all object's fields in this container.
|
||||||
traverseContainerObjectFields(header, [](ObjHeader** location) {
|
traverseContainerObjectFields(header, [](ObjHeader** location) {
|
||||||
#if TRACE_MEMORY
|
|
||||||
fprintf(stderr, "Calling UpdateRef from FreeContainer\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
UpdateRef(location, nullptr);
|
UpdateRef(location, nullptr);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -546,9 +541,7 @@ void ObjectContainer::Init(const TypeInfo* type_info) {
|
|||||||
header_->setObjectCount(1);
|
header_->setObjectCount(1);
|
||||||
// header->refCount_ is zero initialized by AllocContainer().
|
// header->refCount_ is zero initialized by AllocContainer().
|
||||||
SetMeta(GetPlace(), type_info);
|
SetMeta(GetPlace(), type_info);
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("object at %p\n", GetPlace());
|
||||||
fprintf(stderr, "object at %p\n", GetPlace());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -565,9 +558,7 @@ void ArrayContainer::Init(const TypeInfo* type_info, uint32_t elements) {
|
|||||||
// header->refCount_ is zero initialized by AllocContainer().
|
// header->refCount_ is zero initialized by AllocContainer().
|
||||||
GetPlace()->count_ = elements;
|
GetPlace()->count_ = elements;
|
||||||
SetMeta(GetPlace()->obj(), type_info);
|
SetMeta(GetPlace()->obj(), type_info);
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("array at %p\n", GetPlace());
|
||||||
fprintf(stderr, "array at %p\n", GetPlace());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,15 +569,11 @@ void ArenaContainer::Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ArenaContainer::Deinit() {
|
void ArenaContainer::Deinit() {
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("Arena::Deinit start: %p\n", this);
|
||||||
fprintf(stderr, "Arena::Deinit start\n");
|
|
||||||
#endif
|
|
||||||
auto chunk = currentChunk_;
|
auto chunk = currentChunk_;
|
||||||
while (chunk != nullptr) {
|
while (chunk != nullptr) {
|
||||||
// FreeContainer() doesn't release memory when CONTAINER_TAG_STACK is set.
|
// FreeContainer() doesn't release memory when CONTAINER_TAG_STACK is set.
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("Arena::Deinit free chunk %p\n", chunk);
|
||||||
fprintf(stderr, "Arena::Deinit free chunk\n");
|
|
||||||
#endif
|
|
||||||
FreeContainer(chunk->asHeader());
|
FreeContainer(chunk->asHeader());
|
||||||
chunk = chunk->next;
|
chunk = chunk->next;
|
||||||
}
|
}
|
||||||
@@ -596,9 +583,6 @@ void ArenaContainer::Deinit() {
|
|||||||
chunk = chunk->next;
|
chunk = chunk->next;
|
||||||
konanFreeMemory(toRemove);
|
konanFreeMemory(toRemove);
|
||||||
}
|
}
|
||||||
#if TRACE_MEMORY
|
|
||||||
fprintf(stderr, "Arena::Deinit end\n");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArenaContainer::allocContainer(container_size_t minSize) {
|
bool ArenaContainer::allocContainer(container_size_t minSize) {
|
||||||
@@ -670,16 +654,12 @@ ArrayHeader* ArenaContainer::PlaceArray(const TypeInfo* type_info, uint32_t coun
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void AddRef(const ObjHeader* object) {
|
inline void AddRef(const ObjHeader* object) {
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("AddRef on %p in %p\n", object, object->container());
|
||||||
fprintf(stderr, "AddRef on %p in %p\n", object, object->container());
|
|
||||||
#endif
|
|
||||||
AddRef(object->container());
|
AddRef(object->container());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void ReleaseRef(const ObjHeader* object) {
|
inline void ReleaseRef(const ObjHeader* object) {
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("ReleaseRef on %p in %p\n", object, object->container());
|
||||||
fprintf(stderr, "ReleaseRef on %p in %p\n", object, object->container());
|
|
||||||
#endif
|
|
||||||
Release(object->container());
|
Release(object->container());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -718,10 +698,7 @@ void DeinitMemory(MemoryState* memoryState) {
|
|||||||
#if TRACE_MEMORY
|
#if TRACE_MEMORY
|
||||||
// Free all global objects, to ensure no memory leaks happens.
|
// Free all global objects, to ensure no memory leaks happens.
|
||||||
for (auto location: *memoryState->globalObjects) {
|
for (auto location: *memoryState->globalObjects) {
|
||||||
fprintf(stderr, "Release global in *%p: %p\n", location, *location);
|
MEMORY_LOG("Release global in *%p: %p\n", location, *location);
|
||||||
#if TRACE_MEMORY
|
|
||||||
fprintf(stderr, "Calling UpdateRef from DeinitMemory\n");
|
|
||||||
#endif
|
|
||||||
UpdateRef(location, nullptr);
|
UpdateRef(location, nullptr);
|
||||||
}
|
}
|
||||||
konanDestructInstance(memoryState->globalObjects);
|
konanDestructInstance(memoryState->globalObjects);
|
||||||
@@ -741,8 +718,8 @@ void DeinitMemory(MemoryState* memoryState) {
|
|||||||
|
|
||||||
#if TRACE_MEMORY
|
#if TRACE_MEMORY
|
||||||
if (memoryState->allocCount > 0) {
|
if (memoryState->allocCount > 0) {
|
||||||
fprintf(stderr, "*** Memory leaks, leaked %d containers ***\n",
|
MEMORY_LOG("*** Memory leaks, leaked %d containers ***\n",
|
||||||
memoryState->allocCount);
|
memoryState->allocCount);
|
||||||
dumpReachable("", memoryState->containers);
|
dumpReachable("", memoryState->containers);
|
||||||
}
|
}
|
||||||
konanDestructInstance(memoryState->containers);
|
konanDestructInstance(memoryState->containers);
|
||||||
@@ -760,9 +737,7 @@ OBJ_GETTER(AllocInstance, const TypeInfo* type_info) {
|
|||||||
if (isArenaSlot(OBJ_RESULT)) {
|
if (isArenaSlot(OBJ_RESULT)) {
|
||||||
auto arena = initedArena(asArenaSlot(OBJ_RESULT));
|
auto arena = initedArena(asArenaSlot(OBJ_RESULT));
|
||||||
auto result = arena->PlaceObject(type_info);
|
auto result = arena->PlaceObject(type_info);
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("instance %p in arena: %p\n", result, arena);
|
||||||
fprintf(stderr, "instance %p in arena: %p\n", result, arena);
|
|
||||||
#endif
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
RETURN_OBJ(ObjectContainer(type_info).GetPlace());
|
RETURN_OBJ(ObjectContainer(type_info).GetPlace());
|
||||||
@@ -773,9 +748,7 @@ OBJ_GETTER(AllocArrayInstance, const TypeInfo* type_info, uint32_t elements) {
|
|||||||
if (isArenaSlot(OBJ_RESULT)) {
|
if (isArenaSlot(OBJ_RESULT)) {
|
||||||
auto arena = initedArena(asArenaSlot(OBJ_RESULT));
|
auto arena = initedArena(asArenaSlot(OBJ_RESULT));
|
||||||
auto result = arena->PlaceArray(type_info, elements)->obj();
|
auto result = arena->PlaceArray(type_info, elements)->obj();
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("array[%d] %p in arena: %p\n", elements, result, arena);
|
||||||
fprintf(stderr, "array[%d] %p in arena: %p\n", elements, result, arena);
|
|
||||||
#endif
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
RETURN_OBJ(ArrayContainer(type_info, elements).GetPlace()->obj());
|
RETURN_OBJ(ArrayContainer(type_info, elements).GetPlace()->obj());
|
||||||
@@ -791,9 +764,7 @@ OBJ_GETTER(InitInstance,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ObjHeader* object = AllocInstance(type_info, OBJ_RESULT);
|
ObjHeader* object = AllocInstance(type_info, OBJ_RESULT);
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("Calling UpdateRef from InitInstance\n");
|
||||||
fprintf(stderr, "Calling UpdateRef from InitInstance\n");
|
|
||||||
#endif
|
|
||||||
UpdateRef(location, object);
|
UpdateRef(location, object);
|
||||||
#if KONAN_NO_EXCEPTIONS
|
#if KONAN_NO_EXCEPTIONS
|
||||||
ctor(object);
|
ctor(object);
|
||||||
@@ -809,13 +780,7 @@ OBJ_GETTER(InitInstance,
|
|||||||
#endif
|
#endif
|
||||||
return object;
|
return object;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
#if TRACE_MEMORY
|
|
||||||
fprintf(stderr, "Calling UpdateRef from InitInstance #2\n");
|
|
||||||
#endif
|
|
||||||
UpdateRef(OBJ_RESULT, nullptr);
|
UpdateRef(OBJ_RESULT, nullptr);
|
||||||
#if TRACE_MEMORY
|
|
||||||
fprintf(stderr, "Calling UpdateRef from InitInstance #3\n");
|
|
||||||
#endif
|
|
||||||
UpdateRef(location, nullptr);
|
UpdateRef(location, nullptr);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
@@ -823,9 +788,7 @@ OBJ_GETTER(InitInstance,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SetRef(ObjHeader** location, const ObjHeader* object) {
|
void SetRef(ObjHeader** location, const ObjHeader* object) {
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("SetRef *%p: %p\n", location, object);
|
||||||
fprintf(stderr, "SetRef *%p: %p\n", location, object);
|
|
||||||
#endif
|
|
||||||
*const_cast<const ObjHeader**>(location) = object;
|
*const_cast<const ObjHeader**>(location) = object;
|
||||||
AddRef(object);
|
AddRef(object);
|
||||||
}
|
}
|
||||||
@@ -850,9 +813,7 @@ void UpdateReturnRef(ObjHeader** returnSlot, const ObjHeader* object) {
|
|||||||
auto arena = initedArena(asArenaSlot(returnSlot));
|
auto arena = initedArena(asArenaSlot(returnSlot));
|
||||||
returnSlot = arena->getSlot();
|
returnSlot = arena->getSlot();
|
||||||
}
|
}
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("Calling UpdateRef from UpdateReturnRef\n");
|
||||||
fprintf(stderr, "Calling UpdateRef from UpdateReturnRef\n");
|
|
||||||
#endif
|
|
||||||
UpdateRef(returnSlot, object);
|
UpdateRef(returnSlot, object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -860,10 +821,7 @@ void UpdateRef(ObjHeader** location, const ObjHeader* object) {
|
|||||||
RuntimeAssert(!isArenaSlot(location), "must not be a slot");
|
RuntimeAssert(!isArenaSlot(location), "must not be a slot");
|
||||||
ObjHeader* old = *location;
|
ObjHeader* old = *location;
|
||||||
if (old != object) {
|
if (old != object) {
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("UpdateRef *%p: %p -> %p\n", location, old, object);
|
||||||
fprintf(stderr, "UpdateRef *%p: %p -> %p\n", location, old, object);
|
|
||||||
fprintf(stderr, " *%p: %p -> %p\n", location, old == nullptr ? nullptr : old->container(), object == nullptr ? nullptr : object->container());
|
|
||||||
#endif
|
|
||||||
if (object != nullptr) {
|
if (object != nullptr) {
|
||||||
AddRef(object);
|
AddRef(object);
|
||||||
}
|
}
|
||||||
@@ -875,33 +833,23 @@ void UpdateRef(ObjHeader** location, const ObjHeader* object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EnterFrame(ObjHeader** start, int count) {
|
void EnterFrame(ObjHeader** start, int count) {
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("EnterFrame %p .. %p\n", start, start + count);
|
||||||
fprintf(stderr, "EnterFrame %p .. %p\n", start, start + count);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaveFrame(ObjHeader** start, int count) {
|
void LeaveFrame(ObjHeader** start, int count) {
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("LeaveFrame %p .. %p\n", start, start + count);
|
||||||
fprintf(stderr, "LeaveFrame %p .. %p\n", start, start + count);
|
|
||||||
#endif
|
|
||||||
ReleaseRefs(start + kFrameOverlaySlots, count - kFrameOverlaySlots);
|
ReleaseRefs(start + kFrameOverlaySlots, count - kFrameOverlaySlots);
|
||||||
if (*start != nullptr) {
|
if (*start != nullptr) {
|
||||||
auto arena = initedArena(start);
|
auto arena = initedArena(start);
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("LeaveFrame: free arena %p\n", arena);
|
||||||
fprintf(stderr, "LeaveFrame: free arena %p\n", arena);
|
|
||||||
#endif
|
|
||||||
arena->Deinit();
|
arena->Deinit();
|
||||||
konanFreeMemory(arena);
|
konanFreeMemory(arena);
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("LeaveFrame: free arena done %p\n", arena);
|
||||||
fprintf(stderr, "LeaveFrame: free arena done %p\n", arena);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReleaseRefs(ObjHeader** start, int count) {
|
void ReleaseRefs(ObjHeader** start, int count) {
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("ReleaseRefs %p .. %p\n", start, start + count);
|
||||||
fprintf(stderr, "ReleaseRefs %p .. %p\n", start, start + count);
|
|
||||||
#endif
|
|
||||||
ObjHeader** current = start;
|
ObjHeader** current = start;
|
||||||
auto state = memoryState;
|
auto state = memoryState;
|
||||||
while (count-- > 0) {
|
while (count-- > 0) {
|
||||||
@@ -921,9 +869,7 @@ void GarbageCollect() {
|
|||||||
MemoryState* state = memoryState;
|
MemoryState* state = memoryState;
|
||||||
RuntimeAssert(!state->gcInProgress, "Recursive GC is disallowed");
|
RuntimeAssert(!state->gcInProgress, "Recursive GC is disallowed");
|
||||||
|
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("Garbage collect\n");
|
||||||
fprintf(stderr, "Garbage collect\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
state->gcInProgress = true;
|
state->gcInProgress = true;
|
||||||
|
|
||||||
@@ -1041,9 +987,7 @@ bool ClearSubgraphReferences(ObjHeader* root, bool checked) {
|
|||||||
if (subgraph.count(header) != 0)
|
if (subgraph.count(header) != 0)
|
||||||
continue;
|
continue;
|
||||||
subgraph.insert(header);
|
subgraph.insert(header);
|
||||||
#if TRACE_MEMORY
|
MEMORY_LOG("Calling removeFreeable from ClearSubgraphReferences\n");
|
||||||
fprintf(stderr, "Calling removeFreeable from ClearSubgraphReferences\n");
|
|
||||||
#endif
|
|
||||||
traverseContainerReferredObjects(header, [&todo](ObjHeader* ref) {
|
traverseContainerReferredObjects(header, [&todo](ObjHeader* ref) {
|
||||||
auto child = ref->container();
|
auto child = ref->container();
|
||||||
RuntimeAssert(!isArena(child), "A reference to local object is encountered");
|
RuntimeAssert(!isArena(child), "A reference to local object is encountered");
|
||||||
|
|||||||
@@ -67,6 +67,24 @@ uint32_t consoleReadUtf8(void* utf8, uint32_t maxSizeBytes) {
|
|||||||
return ::strlen(result);
|
return ::strlen(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if KONAN_INTERNAL_SNPRINTF
|
||||||
|
extern "C" int rpl_vsnprintf(char *, size_t, const char *, va_list);
|
||||||
|
#define vsnprintf_impl rpl_vsnprintf
|
||||||
|
#else
|
||||||
|
#define vsnprintf_impl ::vsnprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void consolePrintf(const char* format, ...) {
|
||||||
|
char buffer[1024];
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
int rv = vsnprintf_impl(buffer, sizeof(buffer) - 1, format, args);
|
||||||
|
va_end(args);
|
||||||
|
consoleWriteUtf8(buffer, rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Process execution.
|
// Process execution.
|
||||||
void abort() {
|
void abort() {
|
||||||
::abort();
|
::abort();
|
||||||
@@ -89,18 +107,10 @@ void* memmem(const void *big, size_t bigLen, const void *little, size_t littleLe
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The sprintf family.
|
// The sprintf family.
|
||||||
#if KONAN_INTERNAL_SNPRINTF
|
|
||||||
extern "C" int rpl_vsnprintf(char *, size_t, const char *, va_list);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int snprintf(char* buffer, size_t size, const char* format, ...) {
|
int snprintf(char* buffer, size_t size, const char* format, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
#if KONAN_INTERNAL_SNPRINTF
|
int rv = vsnprintf_impl(buffer, size, format, args);
|
||||||
int rv = rpl_vsnprintf(buffer, size, format, args);
|
|
||||||
#else
|
|
||||||
int rv = ::vsnprintf(buffer, size, format, args);
|
|
||||||
#endif
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@@ -113,22 +123,19 @@ size_t strnlen(const char* buffer, size_t maxSize) {
|
|||||||
#if KONAN_INTERNAL_DLMALLOC
|
#if KONAN_INTERNAL_DLMALLOC
|
||||||
extern "C" void* dlcalloc(size_t, size_t);
|
extern "C" void* dlcalloc(size_t, size_t);
|
||||||
extern "C" void dlfree(void*);
|
extern "C" void dlfree(void*);
|
||||||
|
#define calloc_impl dlcalloc
|
||||||
|
#define free_impl dlfree
|
||||||
|
#else
|
||||||
|
#define calloc_impl ::calloc
|
||||||
|
#define free_impl ::free
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void* calloc(size_t count, size_t size) {
|
void* calloc(size_t count, size_t size) {
|
||||||
#if KONAN_INTERNAL_DLMALLOC
|
return calloc_impl(count, size);
|
||||||
return dlcalloc(count, size);
|
|
||||||
#else
|
|
||||||
return ::calloc(count, size);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void free(void* pointer) {
|
void free(void* pointer) {
|
||||||
#if KONAN_INTERNAL_DLMALLOC
|
free_impl(pointer);
|
||||||
dlfree(pointer);
|
|
||||||
#else
|
|
||||||
::free(pointer);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if KONAN_INTERNAL_NOW
|
#if KONAN_INTERNAL_NOW
|
||||||
@@ -240,11 +247,11 @@ extern "C" {
|
|||||||
int _ZNSt3__212__next_primeEm(unsigned long n) {
|
int _ZNSt3__212__next_primeEm(unsigned long n) {
|
||||||
static unsigned long primes[] = {
|
static unsigned long primes[] = {
|
||||||
11UL,
|
11UL,
|
||||||
101UL,
|
101UL,
|
||||||
1009UL,
|
1009UL,
|
||||||
10007UL,
|
10007UL,
|
||||||
100003UL,
|
100003UL,
|
||||||
1000003UL,
|
1000003UL,
|
||||||
10000019UL,
|
10000019UL,
|
||||||
100000007UL,
|
100000007UL,
|
||||||
1000000007UL
|
1000000007UL
|
||||||
@@ -288,7 +295,7 @@ extern "C" {
|
|||||||
if (src < dst) {
|
if (src < dst) {
|
||||||
for (long i = len; i != 0; --i) {
|
for (long i = len; i != 0; --i) {
|
||||||
*((char*)dst + i - 1) = *((char*)src + i - 1);
|
*((char*)dst + i - 1) = *((char*)src + i - 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memcpy(dst, src, len);
|
memcpy(dst, src, len);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace konan {
|
|||||||
|
|
||||||
// Console operations.
|
// Console operations.
|
||||||
void consoleInit();
|
void consoleInit();
|
||||||
|
void consolePrintf(const char* format, ...);
|
||||||
void consoleWriteUtf8(const void* utf8, uint32_t sizeBytes);
|
void consoleWriteUtf8(const void* utf8, uint32_t sizeBytes);
|
||||||
void consoleErrorUtf8(const void* utf8, uint32_t sizeBytes);
|
void consoleErrorUtf8(const void* utf8, uint32_t sizeBytes);
|
||||||
uint32_t consoleReadUtf8(void* utf8, uint32_t maxSizeBytes);
|
uint32_t consoleReadUtf8(void* utf8, uint32_t maxSizeBytes);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#if KONAN_WASM
|
#if KONAN_WASM && !defined(assert)
|
||||||
// assert() is needed by WASM STL.
|
// assert() is needed by WASM STL.
|
||||||
#define assert(cond) if (!(cond)) abort()
|
#define assert(cond) if (!(cond)) abort()
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -47,11 +47,11 @@ class ClangTarget(val target: KonanTarget, konanProperties: KonanProperties) {
|
|||||||
"-DKONAN_OBJC_INTEROP=1")
|
"-DKONAN_OBJC_INTEROP=1")
|
||||||
|
|
||||||
KonanTarget.IPHONE ->
|
KonanTarget.IPHONE ->
|
||||||
listOf("-stdlib=libc++", "-arch", "arm64", "-isysroot", "$sysRoot", "-miphoneos-version-min=8.0.0",
|
listOf("-stdlib=libc++", "-arch", "arm64", "-isysroot", sysRoot, "-miphoneos-version-min=8.0.0",
|
||||||
"-DKONAN_OBJC_INTEROP=1")
|
"-DKONAN_OBJC_INTEROP=1")
|
||||||
|
|
||||||
KonanTarget.IPHONE_SIM ->
|
KonanTarget.IPHONE_SIM ->
|
||||||
listOf("-stdlib=libc++", "-isysroot", "$sysRoot", "-miphoneos-version-min=8.0.0",
|
listOf("-stdlib=libc++", "-isysroot", sysRoot, "-miphoneos-version-min=8.0.0",
|
||||||
"-DKONAN_OBJC_INTEROP=1")
|
"-DKONAN_OBJC_INTEROP=1")
|
||||||
|
|
||||||
KonanTarget.ANDROID_ARM32 ->
|
KonanTarget.ANDROID_ARM32 ->
|
||||||
|
|||||||
Reference in New Issue
Block a user