From 282ac885c53d5fca5dfc1f6bad35b57fcdd7e1b2 Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Mon, 19 Jun 2017 16:34:45 +0300 Subject: [PATCH] Added nullifying all globals on deinitialization of runtime --- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 61 ++++++++++++------- runtime/src/main/cpp/Runtime.cpp | 9 +-- 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index e02eff458d4..36e96cc3dd3 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -21,11 +21,8 @@ import llvm.* import org.jetbrains.kotlin.backend.common.descriptors.allParameters import org.jetbrains.kotlin.backend.common.descriptors.isSuspend import org.jetbrains.kotlin.backend.common.ir.ir2string -import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.backend.konan.KonanConfigKeys -import org.jetbrains.kotlin.backend.konan.KonanPhase +import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.library.LinkData -import org.jetbrains.kotlin.backend.konan.PhaseManager import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.ir.* import org.jetbrains.kotlin.backend.konan.library.KonanLibraryWriter @@ -340,21 +337,41 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// val kVoidFuncType = LLVMFunctionType(LLVMVoidType(), null, 0, 0) + val kInitFuncType = LLVMFunctionType(LLVMVoidType(), cValuesOf(LLVMInt32Type()), 1, 0) val kNodeInitType = LLVMGetTypeByName(context.llvmModule, "struct.InitNode")!! //-------------------------------------------------------------------------// fun createInitBody(initName: String): LLVMValueRef { - val initFunction = LLVMAddFunction(context.llvmModule, initName, kVoidFuncType)!! // create LLVM function + val initFunction = LLVMAddFunction(context.llvmModule, initName, kInitFuncType)!! // create LLVM function codegen.prologue(initFunction, voidType) using(FunctionScope(initFunction)) { - context.llvm.fileInitializers.forEach { - val irField = it as IrField - val descriptor = irField.descriptor - val initialization = evaluateExpression(irField.initializer!!.expression) - val globalPtr = context.llvmDeclarations.forStaticField(descriptor).storage - codegen.storeAnyGlobal(initialization, globalPtr) + val bbInit = codegen.basicBlock("init") + val bbDeinit = codegen.basicBlock("deinit") + codegen.condBr(codegen.icmpEq(LLVMGetParam(initFunction, 0)!!, kImmZero), bbDeinit, bbInit) + + codegen.appendingTo(bbDeinit) { + context.llvm.fileInitializers.forEach { + val irField = it as IrField + val descriptor = irField.descriptor + if (descriptor.type.isValueType()) + return@forEach // Is not a subject for memory management. + val globalPtr = context.llvmDeclarations.forStaticField(descriptor).storage + codegen.storeAnyGlobal(codegen.kNullObjHeaderPtr, globalPtr) + } + objects.forEach { codegen.storeAnyGlobal(codegen.kNullObjHeaderPtr, it) } + codegen.ret(null) + } + + codegen.appendingTo(bbInit) { + context.llvm.fileInitializers.forEach { + val irField = it as IrField + val descriptor = irField.descriptor + val initialization = evaluateExpression(irField.initializer!!.expression) + val globalPtr = context.llvmDeclarations.forStaticField(descriptor).storage + codegen.storeAnyGlobal(initialization, globalPtr) + } + codegen.ret(null) } - codegen.ret(null) } codegen.epilogue() @@ -392,7 +409,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid using(FileScope(declaration)) { declaration.acceptChildrenVoid(this) - if (context.llvm.fileInitializers.isEmpty()) + if (context.llvm.fileInitializers.isEmpty() && objects.isEmpty()) return // Create global initialization records. @@ -456,7 +473,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid if (constructorDescriptor.isPrimary) { if (DescriptorUtils.isObject(classDescriptor)) { if (!classDescriptor.isUnit()) { - val objectPtr = objectPtrByName(classDescriptor) + val objectPtr = getObjectInstanceStorage(classDescriptor) LLVMSetInitializer(objectPtr, codegen.kNullObjHeaderPtr) } @@ -722,7 +739,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid return codegen.theUnitInstanceRef.llvm } - var objectPtr = objectPtrByName(value.descriptor) + var objectPtr = getObjectInstanceStorage(value.descriptor) val bbCurrent = codegen.currentBlock val bbInit = codegen.basicBlock("label_init") val bbExit = codegen.basicBlock("label_continue") @@ -1283,15 +1300,19 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// - private fun objectPtrByName(descriptor: ClassDescriptor): LLVMValueRef { + private val objects = mutableSetOf() + + private fun getObjectInstanceStorage(descriptor: ClassDescriptor): LLVMValueRef { assert (!descriptor.isUnit()) - return if (codegen.isExternal(descriptor)) { + val llvmGlobal = if (!codegen.isExternal(descriptor)) { + context.llvmDeclarations.forSingleton(descriptor).instanceFieldRef + } else { val llvmType = codegen.getLLVMType(descriptor.defaultType) codegen.importGlobal(descriptor.objectInstanceFieldSymbolName, llvmType, threadLocal = true) - } else { - context.llvmDeclarations.forSingleton(descriptor).instanceFieldRef } + objects += llvmGlobal + return llvmGlobal } //-------------------------------------------------------------------------// @@ -1942,8 +1963,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private val kImmOne = LLVMConstInt(LLVMInt32Type(), 1, 1)!! private val kTrue = LLVMConstInt(LLVMInt1Type(), 1, 1)!! private val kFalse = LLVMConstInt(LLVMInt1Type(), 0, 1)!! - private val kIntPtrZero = LLVMConstInt(codegen.intPtrType, 0, 1)!! - private fun evaluateOperatorCall(callee: IrCall, args: List): LLVMValueRef { context.log{"evaluateCall : origin:${ir2string(callee)}"} diff --git a/runtime/src/main/cpp/Runtime.cpp b/runtime/src/main/cpp/Runtime.cpp index f1ea1968d21..20b977b64ce 100644 --- a/runtime/src/main/cpp/Runtime.cpp +++ b/runtime/src/main/cpp/Runtime.cpp @@ -26,7 +26,7 @@ struct RuntimeState { MemoryState* memoryState; }; -typedef void (*Initializer)(); +typedef void (*Initializer)(int initialize); struct InitNode { Initializer init; InitNode* next; @@ -37,10 +37,10 @@ namespace { InitNode* initHeadNode = nullptr; InitNode* initTailNode = nullptr; -void InitGlobalVariables() { +void InitOrDeinitGlobalVariables(int initialize) { InitNode *currNode = initHeadNode; while (currNode != nullptr) { - currNode->init(); + currNode->init(initialize); currNode = currNode->next; } } @@ -66,7 +66,7 @@ RuntimeState* InitRuntime() { RuntimeState* result = new RuntimeState(); result->memoryState = InitMemory(); // Keep global variables in state as well. - InitGlobalVariables(); + InitOrDeinitGlobalVariables(true); #if KONAN_WINDOWS // Note that this code enforces UTF-8 console output, so we may want to rethink // how we perform console IO, if it turns out, that UTF-16 is better output format. @@ -78,6 +78,7 @@ RuntimeState* InitRuntime() { void DeinitRuntime(RuntimeState* state) { if (state != nullptr) { + InitOrDeinitGlobalVariables(false); DeinitMemory(state->memoryState); delete state; }