Fix object init/deinit bug, refactoring (#1000)
This commit is contained in:
+15
-4
@@ -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.")
|
||||
}
|
||||
|
||||
+2
-10
@@ -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 {
|
||||
|
||||
+2
-2
@@ -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>()
|
||||
}
|
||||
|
||||
+29
-33
@@ -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)
|
||||
|
||||
+4
-4
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user