Fix object init/deinit bug, refactoring (#1000)

This commit is contained in:
Nikolay Igotti
2017-11-02 14:37:25 +03:00
committed by GitHub
parent 5f1dc68efc
commit 915d4bc826
6 changed files with 55 additions and 56 deletions
@@ -156,10 +156,14 @@ internal class SpecialDeclarationsFactory(val context: Context) {
internal class Context(config: KonanConfig) : KonanBackendContext(config) { internal class Context(config: KonanConfig) : KonanBackendContext(config) {
lateinit var moduleDescriptor: ModuleDescriptor lateinit var moduleDescriptor: ModuleDescriptor
override val builtIns: KonanBuiltIns by lazy(PUBLICATION) { moduleDescriptor.builtIns as KonanBuiltIns } override val builtIns: KonanBuiltIns by lazy(PUBLICATION) {
moduleDescriptor.builtIns as KonanBuiltIns
}
val specialDeclarationsFactory = SpecialDeclarationsFactory(this) val specialDeclarationsFactory = SpecialDeclarationsFactory(this)
override val reflectionTypes: ReflectionTypes by lazy(PUBLICATION) { ReflectionTypes(moduleDescriptor, FqName("konan.internal")) } override val reflectionTypes: ReflectionTypes by lazy(PUBLICATION) {
ReflectionTypes(moduleDescriptor, FqName("konan.internal"))
}
private val vtableBuilders = mutableMapOf<ClassDescriptor, ClassVtablesBuilder>() private val vtableBuilders = mutableMapOf<ClassDescriptor, ClassVtablesBuilder>()
fun getVtableBuilder(classDescriptor: ClassDescriptor) = vtableBuilders.getOrPut(classDescriptor) { fun getVtableBuilder(classDescriptor: ClassDescriptor) = vtableBuilders.getOrPut(classDescriptor) {
@@ -182,9 +186,16 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
config.librariesWithDependencies(moduleDescriptor) config.librariesWithDependencies(moduleDescriptor)
} }
fun needGlobalInit(field: IrField): Boolean {
if (field.descriptor.containingDeclaration !is PackageFragmentDescriptor) return false
// TODO: add some smartness here. Maybe if package of the field is in never accessed
// assume its global init can be actually omitted.
return true
}
// TODO: make lateinit? // TODO: make lateinit?
var irModule: IrModuleFragment? = null var irModule: IrModuleFragment? = null
set(module: IrModuleFragment?) { set(module) {
if (field != null) { if (field != null) {
throw Error("Another IrModule in the context.") throw Error("Another IrModule in the context.")
} }
@@ -203,7 +214,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
} }
var llvmModule: LLVMModuleRef? = null var llvmModule: LLVMModuleRef? = null
set(module: LLVMModuleRef?) { set(module) {
if (field != null) { if (field != null) {
throw Error("Another LLVMModule in the context.") throw Error("Another LLVMModule in the context.")
} }
@@ -195,7 +195,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
val value = LLVMBuildLoad(builder, address, name)!! val value = LLVMBuildLoad(builder, address, name)!!
if (isObjectRef(value) && isVar) { if (isObjectRef(value) && isVar) {
val slot = alloca(LLVMTypeOf(value), variableLocation = null) val slot = alloca(LLVMTypeOf(value), variableLocation = null)
storeAnyLocal(value, slot) storeAny(value, slot)
} }
return value return value
} }
@@ -206,15 +206,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
LLVMBuildStore(builder, value, ptr) LLVMBuildStore(builder, value, ptr)
} }
fun storeAnyLocal(value: LLVMValueRef, ptr: LLVMValueRef) { fun storeAny(value: LLVMValueRef, ptr: LLVMValueRef) {
if (isObjectRef(value)) {
updateRef(value, ptr)
} else {
LLVMBuildStore(builder, value, ptr)
}
}
fun storeAnyGlobal(value: LLVMValueRef, ptr: LLVMValueRef) {
if (isObjectRef(value)) { if (isObjectRef(value)) {
updateRef(value, ptr) updateRef(value, ptr)
} else { } else {
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
@@ -343,5 +343,5 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
val usedFunctions = mutableListOf<LLVMValueRef>() val usedFunctions = mutableListOf<LLVMValueRef>()
val staticInitializers = mutableListOf<LLVMValueRef>() val staticInitializers = mutableListOf<LLVMValueRef>()
val fileInitializers = mutableListOf<IrElement>() val fileInitializers = mutableListOf<IrField>()
} }
@@ -34,7 +34,6 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
@@ -286,7 +285,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val kNodeInitType = LLVMGetTypeByName(context.llvmModule, "struct.InitNode")!! val kNodeInitType = LLVMGetTypeByName(context.llvmModule, "struct.InitNode")!!
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun createInitBody(initName: String): LLVMValueRef { private fun createInitBody(initName: String): LLVMValueRef {
val initFunction = LLVMAddFunction(context.llvmModule, initName, kInitFuncType)!! // create LLVM function val initFunction = LLVMAddFunction(context.llvmModule, initName, kInitFuncType)!! // create LLVM function
generateFunction(codegen, initFunction) { generateFunction(codegen, initFunction) {
using(FunctionScope(initFunction, it)) { using(FunctionScope(initFunction, it)) {
@@ -296,26 +295,24 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
appendingTo(bbDeinit) { appendingTo(bbDeinit) {
context.llvm.fileInitializers.forEach { context.llvm.fileInitializers.forEach {
val irField = it as IrField val descriptor = it.descriptor
val descriptor = irField.descriptor
if (descriptor.type.isValueType()) if (descriptor.type.isValueType())
return@forEach // Is not a subject for memory management. return@forEach // Is not a subject for memory management.
val globalPtr = context.llvmDeclarations.forStaticField(descriptor).storage val address = context.llvmDeclarations.forStaticField(descriptor).storage
storeAnyGlobal(codegen.kNullObjHeaderPtr, globalPtr) storeAny(codegen.kNullObjHeaderPtr, address)
} }
objects.forEach { storeAnyGlobal(codegen.kNullObjHeaderPtr, it) } objects.forEach { storeAny(codegen.kNullObjHeaderPtr, it) }
ret(null) ret(null)
} }
appendingTo(bbInit) { appendingTo(bbInit) {
context.llvm.fileInitializers context.llvm.fileInitializers
.map { it as IrField }
.filterNot { it.initializer is IrConst<*> }
.forEach { .forEach {
val descriptor = it.descriptor if (it.initializer?.expression !is IrConst<*>?) {
val initialization = evaluateExpression(it.initializer!!.expression) val initialization = evaluateExpression(it.initializer!!.expression)
val globalPtr = context.llvmDeclarations.forStaticField(descriptor).storage val address = context.llvmDeclarations.forStaticField(it.descriptor).storage
storeAnyGlobal(initialization, globalPtr) storeAny(initialization, address)
}
} }
ret(null) ret(null)
} }
@@ -327,7 +324,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
// Creates static struct InitNode $nodeName = {$initName, NULL}; // Creates static struct InitNode $nodeName = {$initName, NULL};
fun createInitNode(initFunction: LLVMValueRef, nodeName: String): LLVMValueRef { private fun createInitNode(initFunction: LLVMValueRef, nodeName: String): LLVMValueRef {
val nextInitNode = LLVMConstNull(pointerType(kNodeInitType)) // Set InitNode.next = NULL. val nextInitNode = LLVMConstNull(pointerType(kNodeInitType)) // Set InitNode.next = NULL.
val argList = cValuesOf(initFunction, nextInitNode) // Construct array of args. val argList = cValuesOf(initFunction, nextInitNode) // Construct array of args.
val initNode = LLVMConstNamedStruct(kNodeInitType, argList, 2)!! // Create static object of class InitNode. val initNode = LLVMConstNamedStruct(kNodeInitType, argList, 2)!! // Create static object of class InitNode.
@@ -336,7 +333,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun createInitCtor(ctorName: String, initNodePtr: LLVMValueRef) { private fun createInitCtor(ctorName: String, initNodePtr: LLVMValueRef) {
val ctorFunction = LLVMAddFunction(context.llvmModule, ctorName, kVoidFuncType)!! // Create constructor function. val ctorFunction = LLVMAddFunction(context.llvmModule, ctorName, kVoidFuncType)!! // Create constructor function.
generateFunction(codegen, ctorFunction) { generateFunction(codegen, ctorFunction) {
call(context.llvm.appendToInitalizersTail, listOf(initNodePtr)) // Add node to the tail of initializers list. call(context.llvm.appendToInitalizersTail, listOf(initNodePtr)) // Add node to the tail of initializers list.
@@ -348,8 +345,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
override fun visitFile(declaration: IrFile) { override fun visitFile(declaration: IrFile) {
// TODO: collect those two in one place.
context.llvm.fileInitializers.clear() context.llvm.fileInitializers.clear()
objects.clear()
using(FileScope(declaration)) { using(FileScope(declaration)) {
declaration.acceptChildrenVoid(this) declaration.acceptChildrenVoid(this)
@@ -361,8 +359,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val fileName = declaration.name.takeLastWhile { it != '/' }.dropLastWhile { it != '.' }.dropLast(1) val fileName = declaration.name.takeLastWhile { it != '/' }.dropLastWhile { it != '.' }.dropLast(1)
val initName = "${fileName}_init_${context.llvm.globalInitIndex}" val initName = "${fileName}_init_${context.llvm.globalInitIndex}"
val nodeName = "${fileName}_node_${context.llvm.globalInitIndex}" val nodeName = "${fileName}_node_${context.llvm.globalInitIndex}"
// Make the name prefix easily parsable for the platforms lacking // Make the name prefix easily parsable for the platforms lacking
// llvm.global_ctors mechanism (such as wasm). // llvm.global_ctors mechanism (such as WASM).
val ctorName = "Konan_global_ctor_${fileName}_${context.llvm.globalInitIndex++}" val ctorName = "Konan_global_ctor_${fileName}_${context.llvm.globalInitIndex++}"
val initFunction = createInitBody(initName) val initFunction = createInitBody(initName)
@@ -630,7 +628,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
context.log{"visitField : ${ir2string(declaration)}"} context.log{"visitField : ${ir2string(declaration)}"}
debugFieldDeclaration(declaration) debugFieldDeclaration(declaration)
val descriptor = declaration.descriptor val descriptor = declaration.descriptor
if (descriptor.containingDeclaration is PackageFragmentDescriptor) { if (context.needGlobalInit(declaration)) {
val type = codegen.getLLVMType(descriptor.type) val type = codegen.getLLVMType(descriptor.type)
val globalProperty = context.llvmDeclarations.forStaticField(descriptor).storage val globalProperty = context.llvmDeclarations.forStaticField(descriptor).storage
if (declaration.initializer!!.expression is IrConst<*>) { if (declaration.initializer!!.expression is IrConst<*>) {
@@ -640,10 +638,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
context.llvm.fileInitializers.add(declaration) context.llvm.fileInitializers.add(declaration)
LLVMSetLinkage(globalProperty, LLVMLinkage.LLVMInternalLinkage)
// (Cannot do this before the global is initialized). // (Cannot do this before the global is initialized).
LLVMSetLinkage(globalProperty, LLVMLinkage.LLVMInternalLinkage)
return
} }
} }
@@ -1292,12 +1288,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (value.descriptor.dispatchReceiverParameter != null) { if (value.descriptor.dispatchReceiverParameter != null) {
val thisPtr = evaluateExpression(value.receiver!!) val thisPtr = evaluateExpression(value.receiver!!)
functionGenerationContext.storeAnyGlobal(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor)) functionGenerationContext.storeAny(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor))
} }
else { else {
assert (value.receiver == null) assert (value.receiver == null)
val globalValue = context.llvmDeclarations.forStaticField(value.descriptor).storage val globalValue = context.llvmDeclarations.forStaticField(value.descriptor).storage
functionGenerationContext.storeAnyGlobal(valueToAssign, globalValue) functionGenerationContext.storeAny(valueToAssign, globalValue)
} }
assert (value.type.isUnit()) assert (value.type.isUnit())
@@ -1411,12 +1407,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun getFileEntry(sourceFileName: String): SourceManager.FileEntry { fun getFileEntry(sourceFileName: String): SourceManager.FileEntry =
// We must cache file entries, otherwise we reparse same file many times. // We must cache file entries, otherwise we reparse same file many times.
return context.fileEntryCache.getOrPut(sourceFileName) { context.fileEntryCache.getOrPut(sourceFileName) {
NaiveSourceBasedFileEntryImpl(sourceFileName) NaiveSourceBasedFileEntryImpl(sourceFileName)
} }
}
private inner class ReturnableBlockScope(val returnableBlock: IrReturnableBlockImpl) : private inner class ReturnableBlockScope(val returnableBlock: IrReturnableBlockImpl) :
FileScope(IrFileImpl(getFileEntry(returnableBlock.sourceFileName))) { FileScope(IrFileImpl(getFileEntry(returnableBlock.sourceFileName))) {
@@ -2336,7 +2331,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun delegatingConstructorCall(descriptor: ClassConstructorDescriptor, args: List<LLVMValueRef>): LLVMValueRef { private fun delegatingConstructorCall(
descriptor: ClassConstructorDescriptor, args: List<LLVMValueRef>): LLVMValueRef {
val constructedClass = functionGenerationContext.constructedClass!! val constructedClass = functionGenerationContext.constructedClass!!
val thisPtr = currentCodeContext.genGetValue(constructedClass.thisAsReceiverParameter) val thisPtr = currentCodeContext.genGetValue(constructedClass.thisAsReceiverParameter)
@@ -2359,7 +2355,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun appendLlvmUsed(args: List<LLVMValueRef>) { private fun appendLlvmUsed(args: List<LLVMValueRef>) {
if (args.isEmpty()) return if (args.isEmpty()) return
memScoped { memScoped {
@@ -2374,7 +2370,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun entryPointSelector(entryPoint: LLVMValueRef, private fun entryPointSelector(entryPoint: LLVMValueRef,
entryPointType: LLVMTypeRef, selectorName: String): LLVMValueRef { entryPointType: LLVMTypeRef, selectorName: String): LLVMValueRef {
assert(LLVMCountParams(entryPoint) == 1) assert(LLVMCountParams(entryPoint) == 1)
@@ -2395,7 +2391,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun appendEntryPointSelector(descriptor: FunctionDescriptor?) { private fun appendEntryPointSelector(descriptor: FunctionDescriptor?) {
if (descriptor == null) return if (descriptor == null) return
val entryPoint = codegen.llvmFunction(descriptor) val entryPoint = codegen.llvmFunction(descriptor)
@@ -34,7 +34,7 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
inner class SlotRecord(val address: LLVMValueRef, val refSlot: Boolean, val isVar: Boolean) : Record { inner class SlotRecord(val address: LLVMValueRef, val refSlot: Boolean, val isVar: Boolean) : Record {
override fun load() : LLVMValueRef = functionGenerationContext.loadSlot(address, isVar) override fun load() : LLVMValueRef = functionGenerationContext.loadSlot(address, isVar)
override fun store(value: LLVMValueRef) = functionGenerationContext.storeAnyLocal(value, address) override fun store(value: LLVMValueRef) = functionGenerationContext.storeAny(value, address)
override fun address() : LLVMValueRef = this.address override fun address() : LLVMValueRef = this.address
override fun toString() = (if (refSlot) "refslot" else "slot") + " for ${address}" override fun toString() = (if (refSlot) "refslot" else "slot") + " for ${address}"
} }
@@ -82,7 +82,7 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
val type = functionGenerationContext.getLLVMType(descriptor.type) val type = functionGenerationContext.getLLVMType(descriptor.type)
val slot = functionGenerationContext.alloca(type, descriptor.name.asString(), variableLocation) val slot = functionGenerationContext.alloca(type, descriptor.name.asString(), variableLocation)
if (value != null) if (value != null)
functionGenerationContext.storeAnyLocal(value, slot) functionGenerationContext.storeAny(value, slot)
variables.add(SlotRecord(slot, functionGenerationContext.isObjectType(type), isVar)) variables.add(SlotRecord(slot, functionGenerationContext.isObjectType(type), isVar))
contextVariablesToIndex[descriptor] = index contextVariablesToIndex[descriptor] = index
return index return index
@@ -113,7 +113,7 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
val index = variables.size val index = variables.size
val slot = functionGenerationContext.alloca(type, variableLocation = null) val slot = functionGenerationContext.alloca(type, variableLocation = null)
if (value != null) if (value != null)
functionGenerationContext.storeAnyLocal(value, slot) functionGenerationContext.storeAny(value, slot)
variables.add(SlotRecord(slot, functionGenerationContext.isObjectType(type), true)) variables.add(SlotRecord(slot, functionGenerationContext.isObjectType(type), true))
return index return index
} }
@@ -174,4 +174,4 @@ internal fun debugInfoParameterLocation(builder: DIBuilderRef?,
type = diType) type = diType)
return VariableDebugLocation(localVariable = variableDeclaration!!, location = location, file = file, line = line) return VariableDebugLocation(localVariable = variableDeclaration!!, location = location, file = file, line = line)
} }
+3 -3
View File
@@ -56,10 +56,10 @@ public final class String : Comparable<String>, CharSequence {
} }
// TODO: in big Kotlin this operations are in kotlin.kotlin_builtins. // TODO: in big Kotlin this operations are in kotlin.kotlin_builtins.
private val kNullString = "null" private fun nullString() = "null"
public operator fun kotlin.String?.plus(other: kotlin.Any?): kotlin.String = public operator fun kotlin.String?.plus(other: kotlin.Any?): kotlin.String =
(this?.toString() ?: kNullString).plus(other?.toString() ?: kNullString) (this?.toString() ?: nullString()).plus(other?.toString() ?: nullString())
public fun Any?.toString() = this?.toString() ?: kNullString public fun Any?.toString() = this?.toString() ?: nullString()