Fixed shared globals deinit

This commit is contained in:
Igor Chevdar
2018-03-28 17:19:29 +03:00
parent 6fa9ca8888
commit c76c39fafd
6 changed files with 77 additions and 44 deletions
@@ -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
@@ -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(
@@ -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.
+15
View File
@@ -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
+1 -8
View File
@@ -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).
+17 -6
View File
@@ -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