Fixed shared globals deinit
This commit is contained in:
+20
-26
@@ -46,7 +46,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
fun functionEntryPointAddress(descriptor: FunctionDescriptor) = descriptor.entryPointAddress.llvm
|
fun functionEntryPointAddress(descriptor: FunctionDescriptor) = descriptor.entryPointAddress.llvm
|
||||||
fun functionHash(descriptor: FunctionDescriptor): LLVMValueRef = descriptor.functionName.localHash.llvm
|
fun functionHash(descriptor: FunctionDescriptor): LLVMValueRef = descriptor.functionName.localHash.llvm
|
||||||
|
|
||||||
fun getObjectInstanceStorage(descriptor: ClassDescriptor): LLVMValueRef {
|
fun getObjectInstanceStorage(descriptor: ClassDescriptor, shared: Boolean): LLVMValueRef {
|
||||||
assert (!descriptor.isUnit())
|
assert (!descriptor.isUnit())
|
||||||
val llvmGlobal = if (!isExternal(descriptor)) {
|
val llvmGlobal = if (!isExternal(descriptor)) {
|
||||||
context.llvmDeclarations.forSingleton(descriptor).instanceFieldRef
|
context.llvmDeclarations.forSingleton(descriptor).instanceFieldRef
|
||||||
@@ -56,10 +56,13 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
descriptor.objectInstanceFieldSymbolName,
|
descriptor.objectInstanceFieldSymbolName,
|
||||||
llvmType,
|
llvmType,
|
||||||
origin = descriptor.llvmSymbolOrigin,
|
origin = descriptor.llvmSymbolOrigin,
|
||||||
threadLocal = !descriptor.symbol.objectIsShared
|
threadLocal = !shared
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
context.llvm.objects += llvmGlobal
|
if (shared)
|
||||||
|
context.llvm.sharedObjects += llvmGlobal
|
||||||
|
else
|
||||||
|
context.llvm.objects += llvmGlobal
|
||||||
return llvmGlobal
|
return llvmGlobal
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -593,40 +596,31 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
|||||||
return codegen.theUnitInstanceRef.llvm
|
return codegen.theUnitInstanceRef.llvm
|
||||||
}
|
}
|
||||||
|
|
||||||
val args = mutableListOf<LLVMValueRef>()
|
val objectPtr = codegen.getObjectInstanceStorage(descriptor, shared)
|
||||||
val objectPtr = codegen.getObjectInstanceStorage(descriptor)
|
|
||||||
args += objectPtr
|
|
||||||
val bbCurrent = currentBlock
|
val bbCurrent = currentBlock
|
||||||
val bbFirstCheck = basicBlock(if (shared) "label_check_shadow" else "label_init", locationInfo)
|
val bbInit = basicBlock("label_init", locationInfo)
|
||||||
val bbExit = basicBlock("label_continue", locationInfo)
|
val bbExit = basicBlock("label_continue", locationInfo)
|
||||||
val objectVal = loadSlot(objectPtr, false)
|
val objectVal = loadSlot(objectPtr, false)
|
||||||
val objectInitialized = icmpUGt(ptrToInt(objectVal, codegen.intPtrType), codegen.immOneIntPtrType)
|
val objectInitialized = icmpUGt(ptrToInt(objectVal, codegen.intPtrType), codegen.immOneIntPtrType)
|
||||||
condBr(objectInitialized, bbExit, bbFirstCheck)
|
condBr(objectInitialized, bbExit, bbInit)
|
||||||
|
|
||||||
positionAtEnd(bbExit)
|
|
||||||
val valuePhi = phi(codegen.getLLVMType(descriptor.defaultType))
|
|
||||||
|
|
||||||
positionAtEnd(bbFirstCheck)
|
|
||||||
if (shared) {
|
|
||||||
val shadowObjectPtr = codegen.getObjectInstanceShadowStorage(descriptor)
|
|
||||||
args += shadowObjectPtr
|
|
||||||
val shadowObjectVal = loadSlot(shadowObjectPtr, false)
|
|
||||||
val shadowNotNull = icmpNe(bitcast(int8TypePtr, shadowObjectVal), kNullInt8Ptr)
|
|
||||||
val bbInit = basicBlock("label_init", locationInfo)
|
|
||||||
condBr(shadowNotNull, bbExit, bbInit)
|
|
||||||
addPhiIncoming(valuePhi, bbFirstCheck to shadowObjectVal)
|
|
||||||
positionAtEnd(bbInit)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
positionAtEnd(bbInit)
|
||||||
|
val typeInfo = codegen.typeInfoForAllocation(descriptor)
|
||||||
val defaultConstructor = descriptor.constructors.first { it.valueParameters.size == 0 }
|
val defaultConstructor = descriptor.constructors.first { it.valueParameters.size == 0 }
|
||||||
args += codegen.typeInfoForAllocation(descriptor)
|
val ctor = codegen.llvmFunction(defaultConstructor)
|
||||||
args += codegen.llvmFunction(defaultConstructor)
|
val (initFunction, args) =
|
||||||
val initFunction = if (shared) context.llvm.initSharedInstanceFunction else context.llvm.initInstanceFunction
|
if (shared) {
|
||||||
|
val shadowObjectPtr = codegen.getObjectInstanceShadowStorage(descriptor)
|
||||||
|
context.llvm.initSharedInstanceFunction to listOf(objectPtr, shadowObjectPtr, typeInfo, ctor)
|
||||||
|
} else {
|
||||||
|
context.llvm.initInstanceFunction to listOf(objectPtr, typeInfo, ctor)
|
||||||
|
}
|
||||||
val newValue = call(initFunction, args, Lifetime.GLOBAL, exceptionHandler)
|
val newValue = call(initFunction, args, Lifetime.GLOBAL, exceptionHandler)
|
||||||
val bbInitResult = currentBlock
|
val bbInitResult = currentBlock
|
||||||
br(bbExit)
|
br(bbExit)
|
||||||
|
|
||||||
positionAtEnd(bbExit)
|
positionAtEnd(bbExit)
|
||||||
|
val valuePhi = phi(codegen.getLLVMType(descriptor.defaultType))
|
||||||
addPhiIncoming(valuePhi, bbCurrent to objectVal, bbInitResult to newValue)
|
addPhiIncoming(valuePhi, bbCurrent to objectVal, bbInitResult to newValue)
|
||||||
|
|
||||||
return valuePhi
|
return valuePhi
|
||||||
|
|||||||
+1
@@ -477,6 +477,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
|||||||
val staticInitializers = mutableListOf<LLVMValueRef>()
|
val staticInitializers = mutableListOf<LLVMValueRef>()
|
||||||
val fileInitializers = mutableListOf<IrField>()
|
val fileInitializers = mutableListOf<IrField>()
|
||||||
val objects = mutableSetOf<LLVMValueRef>()
|
val objects = mutableSetOf<LLVMValueRef>()
|
||||||
|
val sharedObjects = mutableSetOf<LLVMValueRef>()
|
||||||
|
|
||||||
private object lazyRtFunction {
|
private object lazyRtFunction {
|
||||||
operator fun provideDelegate(
|
operator fun provideDelegate(
|
||||||
|
|||||||
+23
-4
@@ -358,15 +358,28 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
val kNodeInitType = LLVMGetTypeByName(context.llvmModule, "struct.InitNode")!!
|
val kNodeInitType = LLVMGetTypeByName(context.llvmModule, "struct.InitNode")!!
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
val INIT_GLOBALS = 0
|
||||||
|
val DEINIT_THREAD_LOCAL_GLOBALS = 1
|
||||||
|
val DEINIT_GLOBALS = 2
|
||||||
|
|
||||||
private fun createInitBody(): LLVMValueRef {
|
private fun createInitBody(): LLVMValueRef {
|
||||||
val initFunction = LLVMAddFunction(context.llvmModule, "", kInitFuncType)!!
|
val initFunction = LLVMAddFunction(context.llvmModule, "", kInitFuncType)!!
|
||||||
generateFunction(codegen, initFunction) {
|
generateFunction(codegen, initFunction) {
|
||||||
using(FunctionScope(initFunction, "init_body", it)) {
|
using(FunctionScope(initFunction, "init_body", it)) {
|
||||||
val bbInit = basicBlock("init", null)
|
val bbInit = basicBlock("init", null)
|
||||||
val bbDeinit = basicBlock("deinit", null)
|
val bbLocalDeinit = basicBlock("local_deinit", null)
|
||||||
condBr(functionGenerationContext.icmpEq(LLVMGetParam(initFunction, 0)!!, kImmZero), bbDeinit, bbInit)
|
val bbGlobalDeinit = basicBlock("global_deinit", null)
|
||||||
|
val bbDefault = basicBlock("default", null) {
|
||||||
|
unreachable()
|
||||||
|
}
|
||||||
|
|
||||||
appendingTo(bbDeinit) {
|
switch(LLVMGetParam(initFunction, 0)!!,
|
||||||
|
listOf(Int32(INIT_GLOBALS).llvm to bbInit,
|
||||||
|
Int32(DEINIT_THREAD_LOCAL_GLOBALS).llvm to bbLocalDeinit,
|
||||||
|
Int32(DEINIT_GLOBALS).llvm to bbGlobalDeinit),
|
||||||
|
bbDefault)
|
||||||
|
|
||||||
|
appendingTo(bbLocalDeinit) {
|
||||||
context.llvm.fileInitializers.forEach {
|
context.llvm.fileInitializers.forEach {
|
||||||
val descriptor = it
|
val descriptor = it
|
||||||
if (descriptor.type.isValueType())
|
if (descriptor.type.isValueType())
|
||||||
@@ -378,6 +391,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
ret(null)
|
ret(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appendingTo(bbGlobalDeinit) {
|
||||||
|
context.llvm.sharedObjects.forEach { storeAny(codegen.kNullObjHeaderPtr, it) }
|
||||||
|
ret(null)
|
||||||
|
}
|
||||||
|
|
||||||
appendingTo(bbInit) {
|
appendingTo(bbInit) {
|
||||||
context.llvm.fileInitializers
|
context.llvm.fileInitializers
|
||||||
.forEach {
|
.forEach {
|
||||||
@@ -424,11 +442,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
// TODO: collect those two in one place.
|
// TODO: collect those two in one place.
|
||||||
context.llvm.fileInitializers.clear()
|
context.llvm.fileInitializers.clear()
|
||||||
context.llvm.objects.clear()
|
context.llvm.objects.clear()
|
||||||
|
context.llvm.sharedObjects.clear()
|
||||||
|
|
||||||
using(FileScope(declaration)) {
|
using(FileScope(declaration)) {
|
||||||
declaration.acceptChildrenVoid(this)
|
declaration.acceptChildrenVoid(this)
|
||||||
|
|
||||||
if (context.llvm.fileInitializers.isEmpty() && context.llvm.objects.isEmpty())
|
if (context.llvm.fileInitializers.isEmpty() && context.llvm.objects.isEmpty() && context.llvm.sharedObjects.isEmpty())
|
||||||
return
|
return
|
||||||
|
|
||||||
// Create global initialization records.
|
// Create global initialization records.
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef RUNTIME_ATOMIC_H
|
||||||
|
#define RUNTIME_ATOMIC_H
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
ALWAYS_INLINE inline int atomicAdd(int* where, int what) {
|
||||||
|
#ifndef KONAN_NO_THREADS
|
||||||
|
return __sync_add_and_fetch(where, what);
|
||||||
|
#else
|
||||||
|
return *where += what;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // RUNTIME_ATOMIC_H
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "MemoryPrivate.hpp"
|
#include "MemoryPrivate.hpp"
|
||||||
#include "Natives.h"
|
#include "Natives.h"
|
||||||
#include "Porting.h"
|
#include "Porting.h"
|
||||||
|
#include "Atomic.h"
|
||||||
|
|
||||||
// If garbage collection algorithm for cyclic garbage to be used.
|
// If garbage collection algorithm for cyclic garbage to be used.
|
||||||
// We are using the Bacon's algorithm for GC, see
|
// We are using the Bacon's algorithm for GC, see
|
||||||
@@ -56,14 +57,6 @@ constexpr container_size_t kObjectAlignment = 8;
|
|||||||
#define MEMORY_LOG(...)
|
#define MEMORY_LOG(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline int atomicAdd(int* where, int what) {
|
|
||||||
#ifndef KONAN_NO_THREADS
|
|
||||||
return __sync_add_and_fetch(where, what);
|
|
||||||
#else
|
|
||||||
return *where += what;
|
|
||||||
#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).
|
// release candidates set).
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "Porting.h"
|
#include "Porting.h"
|
||||||
#include "Runtime.h"
|
#include "Runtime.h"
|
||||||
|
#include "Atomic.h"
|
||||||
|
|
||||||
struct RuntimeState {
|
struct RuntimeState {
|
||||||
MemoryState* memoryState;
|
MemoryState* memoryState;
|
||||||
@@ -35,6 +36,12 @@ namespace {
|
|||||||
InitNode* initHeadNode = nullptr;
|
InitNode* initHeadNode = nullptr;
|
||||||
InitNode* initTailNode = nullptr;
|
InitNode* initTailNode = nullptr;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
INIT_GLOBALS = 0,
|
||||||
|
DEINIT_THREAD_LOCAL_GLOBALS = 1,
|
||||||
|
DEINIT_GLOBALS = 2
|
||||||
|
};
|
||||||
|
|
||||||
void InitOrDeinitGlobalVariables(int initialize) {
|
void InitOrDeinitGlobalVariables(int initialize) {
|
||||||
InitNode *currNode = initHeadNode;
|
InitNode *currNode = initHeadNode;
|
||||||
while (currNode != nullptr) {
|
while (currNode != nullptr) {
|
||||||
@@ -45,23 +52,27 @@ void InitOrDeinitGlobalVariables(int initialize) {
|
|||||||
|
|
||||||
THREAD_LOCAL_VARIABLE RuntimeState* runtimeState = nullptr;
|
THREAD_LOCAL_VARIABLE RuntimeState* runtimeState = nullptr;
|
||||||
|
|
||||||
|
int aliveRuntimesCount = 0;
|
||||||
|
|
||||||
RuntimeState* initRuntime() {
|
RuntimeState* initRuntime() {
|
||||||
SetKonanTerminateHandler();
|
SetKonanTerminateHandler();
|
||||||
RuntimeState* result = konanConstructInstance<RuntimeState>();
|
RuntimeState* result = konanConstructInstance<RuntimeState>();
|
||||||
if (!result) return nullptr;
|
if (!result) return nullptr;
|
||||||
result->memoryState = InitMemory();
|
result->memoryState = InitMemory();
|
||||||
// Keep global variables in state as well.
|
// Keep global variables in state as well.
|
||||||
InitOrDeinitGlobalVariables(true);
|
InitOrDeinitGlobalVariables(INIT_GLOBALS);
|
||||||
konan::consoleInit();
|
konan::consoleInit();
|
||||||
|
atomicAdd(&aliveRuntimesCount, 1);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void deinitRuntime(RuntimeState* state) {
|
void deinitRuntime(RuntimeState* state) {
|
||||||
if (state != nullptr) {
|
bool lastRuntime = atomicAdd(&aliveRuntimesCount, -1) == 0;
|
||||||
InitOrDeinitGlobalVariables(false);
|
InitOrDeinitGlobalVariables(DEINIT_THREAD_LOCAL_GLOBALS);
|
||||||
DeinitMemory(state->memoryState);
|
if (lastRuntime)
|
||||||
konanDestructInstance(state);
|
InitOrDeinitGlobalVariables(DEINIT_GLOBALS);
|
||||||
}
|
DeinitMemory(state->memoryState);
|
||||||
|
konanDestructInstance(state);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user