Implement recording all modules used during bitcode generation

This commit is contained in:
Svyatoslav Scherbina
2017-10-23 17:49:18 +03:00
committed by SvyatoslavScherbina
parent c4b8fa806f
commit 4431f8cbd9
7 changed files with 138 additions and 19 deletions
@@ -19,8 +19,12 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.* import kotlinx.cinterop.*
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.CurrentKonanModule
import org.jetbrains.kotlin.backend.konan.descriptors.DeserializedKonanModule
import org.jetbrains.kotlin.backend.konan.descriptors.LlvmSymbolOrigin
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.backend.konan.hash.GlobalHash import org.jetbrains.kotlin.backend.konan.hash.GlobalHash
import org.jetbrains.kotlin.backend.konan.library.impl.LibraryReaderImpl
import org.jetbrains.kotlin.descriptors.ClassDescriptor 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
@@ -167,7 +171,8 @@ internal interface ContextUtils : RuntimeAware {
} }
return if (isExternal(this)) { return if (isExternal(this)) {
context.llvm.externalFunction(this.symbolName, getLlvmFunctionType(this)) context.llvm.externalFunction(this.symbolName, getLlvmFunctionType(this),
origin = this.llvmSymbolOrigin)
} else { } else {
context.llvmDeclarations.forFunction(this).llvmFunction context.llvmDeclarations.forFunction(this).llvmFunction
} }
@@ -185,7 +190,8 @@ internal interface ContextUtils : RuntimeAware {
val ClassDescriptor.typeInfoPtr: ConstPointer val ClassDescriptor.typeInfoPtr: ConstPointer
get() { get() {
return if (isExternal(this)) { return if (isExternal(this)) {
constPointer(importGlobal(this.typeInfoSymbolName, runtime.typeInfoType)) constPointer(importGlobal(this.typeInfoSymbolName, runtime.typeInfoType,
origin = this.llvmSymbolOrigin))
} else { } else {
context.llvmDeclarations.forClass(this).typeInfo context.llvmDeclarations.forClass(this).typeInfo
} }
@@ -280,7 +286,9 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
return LLVMAddFunction(llvmModule, "llvm.memset.p0i8.i32", functionType)!! return LLVMAddFunction(llvmModule, "llvm.memset.p0i8.i32", functionType)!!
} }
internal fun externalFunction(name: String, type: LLVMTypeRef): LLVMValueRef { internal fun externalFunction(name: String, type: LLVMTypeRef, origin: LlvmSymbolOrigin): LLVMValueRef {
this.imports.add(origin)
val found = LLVMGetNamedFunction(llvmModule, name) val found = LLVMGetNamedFunction(llvmModule, name)
if (found != null) { if (found != null) {
assert (getFunctionType(found) == type) assert (getFunctionType(found) == type)
@@ -291,12 +299,32 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
} }
} }
private fun externalNounwindFunction(name: String, type: LLVMTypeRef): LLVMValueRef { private fun externalNounwindFunction(name: String, type: LLVMTypeRef, origin: LlvmSymbolOrigin): LLVMValueRef {
val function = externalFunction(name, type) val function = externalFunction(name, type, origin)
LLVMAddFunctionAttr(function, LLVMNoUnwindAttribute) LLVMAddFunctionAttr(function, LLVMNoUnwindAttribute)
return function return function
} }
private val usedLibraries = mutableSetOf<LibraryReaderImpl>()
val imports = object : LlvmImports {
private val allLibraries = context.librariesWithDependencies.toSet()
override fun add(origin: LlvmSymbolOrigin) {
val reader = when (origin) {
CurrentKonanModule -> return
is DeserializedKonanModule -> origin.reader
}
if (reader !in allLibraries) {
error("$reader (${reader.libraryName}) is used but not requested")
}
usedLibraries.add(reader as LibraryReaderImpl)
}
}
val staticData = StaticData(context) val staticData = StaticData(context)
val runtimeFile = context.config.distribution.runtime val runtimeFile = context.config.distribution.runtime
@@ -335,9 +363,21 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
else -> "__gxx_personality_v0" else -> "__gxx_personality_v0"
} }
val gxxPersonalityFunction = externalNounwindFunction(personalityFunctionName, functionType(int32Type, true)) val gxxPersonalityFunction = externalNounwindFunction(
val cxaBeginCatchFunction = externalNounwindFunction("__cxa_begin_catch", functionType(int8TypePtr, false, int8TypePtr)) personalityFunctionName,
val cxaEndCatchFunction = externalNounwindFunction("__cxa_end_catch", functionType(voidType, false)) functionType(int32Type, true),
origin = context.standardLlvmSymbolsOrigin
)
val cxaBeginCatchFunction = externalNounwindFunction(
"__cxa_begin_catch",
functionType(int8TypePtr, false, int8TypePtr),
origin = context.standardLlvmSymbolsOrigin
)
val cxaEndCatchFunction = externalNounwindFunction(
"__cxa_end_catch",
functionType(voidType, false),
origin = context.standardLlvmSymbolsOrigin
)
val memsetFunction = importMemset() val memsetFunction = importMemset()
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.konan.llvm
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.LlvmSymbolOrigin
import org.jetbrains.kotlin.backend.konan.descriptors.SyntheticModules
import org.jetbrains.kotlin.backend.konan.descriptors.origin
import org.jetbrains.kotlin.backend.konan.descriptors.stdlibModule
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.resolve.descriptorUtil.module
internal interface LlvmImports {
fun add(origin: LlvmSymbolOrigin)
}
internal val DeclarationDescriptor.llvmSymbolOrigin: LlvmSymbolOrigin
get() {
val module = this.module
val moduleOrigin = module.origin
when (moduleOrigin) {
is LlvmSymbolOrigin -> return moduleOrigin
SyntheticModules -> error("Declaration is synthetic and can't be an origin of LLVM symbol:\n${this}")
}
}
internal val Context.standardLlvmSymbolsOrigin: LlvmSymbolOrigin get() = this.stdlibModule.llvmSymbolOrigin
@@ -1273,8 +1273,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
context.llvmDeclarations.forSingleton(descriptor).instanceFieldRef context.llvmDeclarations.forSingleton(descriptor).instanceFieldRef
} else { } else {
val llvmType = codegen.getLLVMType(descriptor.defaultType) val llvmType = codegen.getLLVMType(descriptor.defaultType)
codegen.importGlobal(descriptor.objectInstanceFieldSymbolName, llvmType, codegen.importGlobal(
threadLocal = true) descriptor.objectInstanceFieldSymbolName,
llvmType,
origin = descriptor.llvmSymbolOrigin,
threadLocal = true
)
} }
objects += llvmGlobal objects += llvmGlobal
return llvmGlobal return llvmGlobal
@@ -2114,8 +2118,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
assert(!classDescriptor.isInterface) assert(!classDescriptor.isInterface)
return if (classDescriptor.isExternalObjCClass()) { return if (classDescriptor.isExternalObjCClass()) {
context.llvm.imports.add(classDescriptor.llvmSymbolOrigin)
val lookUpFunction = context.llvm.externalFunction("Kotlin_Interop_getObjCClass", val lookUpFunction = context.llvm.externalFunction("Kotlin_Interop_getObjCClass",
functionType(int8TypePtr, false, int8TypePtr)) functionType(int8TypePtr, false, int8TypePtr),
origin = context.standardLlvmSymbolsOrigin
)
call(lookUpFunction, call(lookUpFunction,
listOf(codegen.staticData.cStringLiteral(classDescriptor.name.asString()).llvm)) listOf(codegen.staticData.cStringLiteral(classDescriptor.name.asString()).llvm))
@@ -2160,8 +2168,17 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val functionType = functionType(int8TypePtr, true, int8TypePtr, int8TypePtr) val functionType = functionType(int8TypePtr, true, int8TypePtr, int8TypePtr)
val normalMessenger = context.llvm.externalFunction("objc_msgSend$messengerNameSuffix", functionType) val libobjc = context.standardLlvmSymbolsOrigin
val superMessenger = context.llvm.externalFunction("objc_msgSendSuper$messengerNameSuffix", functionType) val normalMessenger = context.llvm.externalFunction(
"objc_msgSend$messengerNameSuffix",
functionType,
origin = libobjc
)
val superMessenger = context.llvm.externalFunction(
"objc_msgSendSuper$messengerNameSuffix",
functionType,
origin = libobjc
)
val superClass = args.single() val superClass = args.single()
val messenger = LLVMBuildSelect(gen.builder, val messenger = LLVMBuildSelect(gen.builder,
@@ -43,8 +43,14 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
val companionObjectDescriptor = descriptor.companionObjectDescriptor val companionObjectDescriptor = descriptor.companionObjectDescriptor
val classMethods = companionObjectDescriptor?.generateOverridingMethodDescs() ?: emptyList() val classMethods = companionObjectDescriptor?.generateOverridingMethodDescs() ?: emptyList()
val superclassName = descriptor.getSuperClassNotAny()!!.name.asString() val superclassName = descriptor.getSuperClassNotAny()!!.let {
val protocolNames = descriptor.getSuperInterfaces().map { it.name.asString().removeSuffix("Protocol") } context.llvm.imports.add(it.llvmSymbolOrigin)
it.name.asString()
}
val protocolNames = descriptor.getSuperInterfaces().map {
context.llvm.imports.add(it.llvmSymbolOrigin)
it.name.asString().removeSuffix("Protocol")
}
val bodySize = val bodySize =
LLVMStoreSizeOfType(llvmTargetData, context.llvmDeclarations.forClass(descriptor).bodyType).toInt() LLVMStoreSizeOfType(llvmTargetData, context.llvmDeclarations.forClass(descriptor).bodyType).toInt()
@@ -123,7 +129,11 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
private fun generateMethodDesc(info: ObjCMethodInfo) = ObjCMethodDesc( private fun generateMethodDesc(info: ObjCMethodInfo) = ObjCMethodDesc(
info.selector, info.selector,
info.encoding, info.encoding,
context.llvm.externalFunction(info.imp, functionType(voidType)) context.llvm.externalFunction(
info.imp,
functionType(voidType),
origin = info.bridge.llvmSymbolOrigin
)
) )
private fun ClassDescriptor.generateOverridingMethodDescs(): List<ObjCMethodDesc> = private fun ClassDescriptor.generateOverridingMethodDescs(): List<ObjCMethodDesc> =
@@ -372,7 +372,10 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
return return
} }
context.llvm.externalFunction(descriptor.symbolName, llvmFunctionType) context.llvm.externalFunction(descriptor.symbolName, llvmFunctionType,
// Assume that `external fun` is defined in native libs attached to this module:
origin = descriptor.llvmSymbolOrigin
)
} else { } else {
val symbolName = if (descriptor.isExported()) { val symbolName = if (descriptor.isExported()) {
descriptor.symbolName descriptor.symbolName
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.* import kotlinx.cinterop.*
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.konan.descriptors.LlvmSymbolOrigin
internal val LLVMValueRef.type: LLVMTypeRef internal val LLVMValueRef.type: LLVMTypeRef
get() = LLVMTypeOf(this)!! get() = LLVMTypeOf(this)!!
@@ -191,8 +192,11 @@ internal fun ContextUtils.addGlobal(name: String, type: LLVMTypeRef, isExported:
return result return result
} }
internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, origin: LlvmSymbolOrigin,
threadLocal: Boolean = false): LLVMValueRef { threadLocal: Boolean = false): LLVMValueRef {
context.llvm.imports.add(origin)
val found = LLVMGetNamedGlobal(context.llvmModule, name) val found = LLVMGetNamedGlobal(context.llvmModule, name)
if (found != null) { if (found != null) {
assert (getGlobalType(found) == type) assert (getGlobalType(found) == type)
@@ -159,7 +159,11 @@ internal val ContextUtils.theUnitInstanceRef: ConstPointer
get() { get() {
val unitDescriptor = context.builtIns.unit val unitDescriptor = context.builtIns.unit
return if (isExternal(unitDescriptor)) { return if (isExternal(unitDescriptor)) {
constPointer(importGlobal(theUnitInstanceName, context.llvm.runtime.objHeaderType)) constPointer(importGlobal(
theUnitInstanceName,
context.llvm.runtime.objHeaderType,
origin = unitDescriptor.llvmSymbolOrigin
))
} else { } else {
context.llvmDeclarations.getUnitInstanceRef() context.llvmDeclarations.getUnitInstanceRef()
} }