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) {
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)
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>()
fun getVtableBuilder(classDescriptor: ClassDescriptor) = vtableBuilders.getOrPut(classDescriptor) {
@@ -182,9 +186,16 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
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?
var irModule: IrModuleFragment? = null
set(module: IrModuleFragment?) {
set(module) {
if (field != null) {
throw Error("Another IrModule in the context.")
}
@@ -203,7 +214,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
}
var llvmModule: LLVMModuleRef? = null
set(module: LLVMModuleRef?) {
set(module) {
if (field != null) {
throw Error("Another LLVMModule in the context.")
}
@@ -195,7 +195,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
val value = LLVMBuildLoad(builder, address, name)!!
if (isObjectRef(value) && isVar) {
val slot = alloca(LLVMTypeOf(value), variableLocation = null)
storeAnyLocal(value, slot)
storeAny(value, slot)
}
return value
}
@@ -206,15 +206,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
LLVMBuildStore(builder, value, ptr)
}
fun storeAnyLocal(value: LLVMValueRef, ptr: LLVMValueRef) {
if (isObjectRef(value)) {
updateRef(value, ptr)
} else {
LLVMBuildStore(builder, value, ptr)
}
}
fun storeAnyGlobal(value: LLVMValueRef, ptr: LLVMValueRef) {
fun storeAny(value: LLVMValueRef, ptr: LLVMValueRef) {
if (isObjectRef(value)) {
updateRef(value, ptr)
} else {
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
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.Name
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 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.descriptors.IrBuiltinOperatorDescriptorBase
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.util.getArguments
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")!!
//-------------------------------------------------------------------------//
fun createInitBody(initName: String): LLVMValueRef {
private fun createInitBody(initName: String): LLVMValueRef {
val initFunction = LLVMAddFunction(context.llvmModule, initName, kInitFuncType)!! // create LLVM function
generateFunction(codegen, initFunction) {
using(FunctionScope(initFunction, it)) {
@@ -296,26 +295,24 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
appendingTo(bbDeinit) {
context.llvm.fileInitializers.forEach {
val irField = it as IrField
val descriptor = irField.descriptor
val descriptor = it.descriptor
if (descriptor.type.isValueType())
return@forEach // Is not a subject for memory management.
val globalPtr = context.llvmDeclarations.forStaticField(descriptor).storage
storeAnyGlobal(codegen.kNullObjHeaderPtr, globalPtr)
val address = context.llvmDeclarations.forStaticField(descriptor).storage
storeAny(codegen.kNullObjHeaderPtr, address)
}
objects.forEach { storeAnyGlobal(codegen.kNullObjHeaderPtr, it) }
objects.forEach { storeAny(codegen.kNullObjHeaderPtr, it) }
ret(null)
}
appendingTo(bbInit) {
context.llvm.fileInitializers
.map { it as IrField }
.filterNot { it.initializer is IrConst<*> }
.forEach {
val descriptor = it.descriptor
val initialization = evaluateExpression(it.initializer!!.expression)
val globalPtr = context.llvmDeclarations.forStaticField(descriptor).storage
storeAnyGlobal(initialization, globalPtr)
if (it.initializer?.expression !is IrConst<*>?) {
val initialization = evaluateExpression(it.initializer!!.expression)
val address = context.llvmDeclarations.forStaticField(it.descriptor).storage
storeAny(initialization, address)
}
}
ret(null)
}
@@ -327,7 +324,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
// 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 argList = cValuesOf(initFunction, nextInitNode) // Construct array of args.
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.
generateFunction(codegen, ctorFunction) {
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) {
// TODO: collect those two in one place.
context.llvm.fileInitializers.clear()
objects.clear()
using(FileScope(declaration)) {
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 initName = "${fileName}_init_${context.llvm.globalInitIndex}"
val nodeName = "${fileName}_node_${context.llvm.globalInitIndex}"
// Make the name prefix easily parsable for the platforms lacking
// llvm.global_ctors mechanism (such as wasm).
// Make the name prefix easily parsable for the platforms lacking
// llvm.global_ctors mechanism (such as WASM).
val ctorName = "Konan_global_ctor_${fileName}_${context.llvm.globalInitIndex++}"
val initFunction = createInitBody(initName)
@@ -630,7 +628,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
context.log{"visitField : ${ir2string(declaration)}"}
debugFieldDeclaration(declaration)
val descriptor = declaration.descriptor
if (descriptor.containingDeclaration is PackageFragmentDescriptor) {
if (context.needGlobalInit(declaration)) {
val type = codegen.getLLVMType(descriptor.type)
val globalProperty = context.llvmDeclarations.forStaticField(descriptor).storage
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)
LLVMSetLinkage(globalProperty, LLVMLinkage.LLVMInternalLinkage)
// (Cannot do this before the global is initialized).
return
LLVMSetLinkage(globalProperty, LLVMLinkage.LLVMInternalLinkage)
}
}
@@ -1292,12 +1288,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (value.descriptor.dispatchReceiverParameter != null) {
val thisPtr = evaluateExpression(value.receiver!!)
functionGenerationContext.storeAnyGlobal(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor))
functionGenerationContext.storeAny(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor))
}
else {
assert (value.receiver == null)
val globalValue = context.llvmDeclarations.forStaticField(value.descriptor).storage
functionGenerationContext.storeAnyGlobal(valueToAssign, globalValue)
functionGenerationContext.storeAny(valueToAssign, globalValue)
}
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.
return context.fileEntryCache.getOrPut(sourceFileName) {
NaiveSourceBasedFileEntryImpl(sourceFileName)
}
}
context.fileEntryCache.getOrPut(sourceFileName) {
NaiveSourceBasedFileEntryImpl(sourceFileName)
}
private inner class ReturnableBlockScope(val returnableBlock: IrReturnableBlockImpl) :
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 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
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 {
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
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 {
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 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 slot = functionGenerationContext.alloca(type, descriptor.name.asString(), variableLocation)
if (value != null)
functionGenerationContext.storeAnyLocal(value, slot)
functionGenerationContext.storeAny(value, slot)
variables.add(SlotRecord(slot, functionGenerationContext.isObjectType(type), isVar))
contextVariablesToIndex[descriptor] = index
return index
@@ -113,7 +113,7 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
val index = variables.size
val slot = functionGenerationContext.alloca(type, variableLocation = null)
if (value != null)
functionGenerationContext.storeAnyLocal(value, slot)
functionGenerationContext.storeAny(value, slot)
variables.add(SlotRecord(slot, functionGenerationContext.isObjectType(type), true))
return index
}
@@ -174,4 +174,4 @@ internal fun debugInfoParameterLocation(builder: DIBuilderRef?,
type = diType)
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.
private val kNullString = "null"
private fun nullString() = "null"
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()