Support ObjCExport with dynamic cache
This commit is contained in:
committed by
SvyatoslavScherbina
parent
806bd37d67
commit
a8494434ab
+7
@@ -65,4 +65,11 @@ internal class CachedLibraries(
|
||||
Cache.Kind.DYNAMIC -> false
|
||||
}
|
||||
}
|
||||
|
||||
val hasDynamicCaches = allCaches.values.any {
|
||||
when (it.kind) {
|
||||
Cache.Kind.STATIC -> false
|
||||
Cache.Kind.DYNAMIC -> true
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
interface LlvmModuleSpecification {
|
||||
val isFinal: Boolean
|
||||
fun importsKotlinDeclarationsFromOtherObjectFiles(): Boolean
|
||||
fun importsKotlinDeclarationsFromOtherSharedLibraries(): Boolean
|
||||
fun containsLibrary(library: KotlinLibrary): Boolean
|
||||
fun containsModule(module: ModuleDescriptor): Boolean
|
||||
fun containsModule(module: IrModuleFragment): Boolean
|
||||
|
||||
+3
@@ -24,6 +24,9 @@ internal class LlvmModuleSpecificationImpl(
|
||||
override fun importsKotlinDeclarationsFromOtherObjectFiles(): Boolean =
|
||||
cachedLibraries.hasStaticCaches // A bit conservative but still valid.
|
||||
|
||||
override fun importsKotlinDeclarationsFromOtherSharedLibraries(): Boolean =
|
||||
cachedLibraries.hasDynamicCaches // A bit conservative but still valid.
|
||||
|
||||
override fun containsLibrary(library: KotlinLibrary): Boolean = if (producingCache) {
|
||||
library in librariesToCache
|
||||
} else {
|
||||
|
||||
+70
-12
@@ -12,12 +12,14 @@ import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.backend.konan.ir.allParameters
|
||||
import org.jetbrains.kotlin.backend.konan.ir.isOverridable
|
||||
import org.jetbrains.kotlin.backend.konan.ir.isUnit
|
||||
import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.objc.ObjCCodeGenerator
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.objc.ObjCDataGenerator
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.*
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.resolveFakeOverrideMaybeAbstract
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.konan.CompiledKlibModuleOrigin
|
||||
import org.jetbrains.kotlin.descriptors.konan.CurrentKlibModuleOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
@@ -60,6 +62,8 @@ internal class ObjCExportCodeGenerator(
|
||||
|
||||
val referencedSelectors = mutableMapOf<String, MethodBridge>()
|
||||
|
||||
val externalGlobalInitializers = mutableMapOf<LLVMValueRef, ConstValue>()
|
||||
|
||||
// TODO: currently bridges don't have any custom `landingpad`s,
|
||||
// so it is correct to use [callAtFunctionScope] here.
|
||||
// However, exception handling probably should be refactored
|
||||
@@ -235,6 +239,14 @@ internal class ObjCExportCodeGenerator(
|
||||
|
||||
objCTypeAdapters += createTypeAdapter(objCClassForAny, superClass = null)
|
||||
|
||||
emitTypeAdapters()
|
||||
|
||||
emitSelectorsHolder()
|
||||
|
||||
emitStaticInitializers()
|
||||
}
|
||||
|
||||
private fun emitTypeAdapters() {
|
||||
val placedClassAdapters = mutableMapOf<String, ConstPointer>()
|
||||
val placedInterfaceAdapters = mutableMapOf<String, ConstPointer>()
|
||||
|
||||
@@ -251,7 +263,12 @@ internal class ObjCExportCodeGenerator(
|
||||
descriptorToAdapter[adapter.objCName] = typeAdapter
|
||||
|
||||
if (irClass != null) {
|
||||
setObjCExportTypeInfo(irClass, typeAdapter = typeAdapter)
|
||||
if (!context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
|
||||
setObjCExportTypeInfo(irClass, typeAdapter = typeAdapter)
|
||||
} else {
|
||||
// Optimization: avoid generating huge initializers;
|
||||
// handled with "Kotlin_ObjCExport_initTypeAdapters" below.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,14 +282,37 @@ internal class ObjCExportCodeGenerator(
|
||||
val sortedAdaptersPointer = staticData.placeGlobalConstArray("", type, sortedAdapters)
|
||||
|
||||
// Note: this globals replace runtime globals with weak linkage:
|
||||
replaceExternalWeakOrCommonGlobal(prefix, sortedAdaptersPointer)
|
||||
replaceExternalWeakOrCommonGlobal("${prefix}Num", Int32(sortedAdapters.size))
|
||||
val origin = context.standardLlvmSymbolsOrigin
|
||||
replaceExternalWeakOrCommonGlobal(prefix, sortedAdaptersPointer, origin)
|
||||
replaceExternalWeakOrCommonGlobal("${prefix}Num", Int32(sortedAdapters.size), origin)
|
||||
}
|
||||
}
|
||||
|
||||
emitSortedAdapters(placedClassAdapters, "Kotlin_ObjCExport_sortedClassAdapters")
|
||||
emitSortedAdapters(placedInterfaceAdapters, "Kotlin_ObjCExport_sortedProtocolAdapters")
|
||||
emitSelectorsHolder()
|
||||
|
||||
if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
|
||||
replaceExternalWeakOrCommonGlobal(
|
||||
"Kotlin_ObjCExport_initTypeAdapters",
|
||||
Int1(1),
|
||||
context.standardLlvmSymbolsOrigin
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun emitStaticInitializers() {
|
||||
if (externalGlobalInitializers.isEmpty()) return
|
||||
|
||||
val initializer = generateFunction(codegen, functionType(voidType, false), "initObjCExportGlobals") {
|
||||
externalGlobalInitializers.forEach { (global, value) ->
|
||||
store(value.llvm, global)
|
||||
}
|
||||
ret(null)
|
||||
}
|
||||
|
||||
LLVMSetLinkage(initializer, LLVMLinkage.LLVMInternalLinkage)
|
||||
|
||||
context.llvm.otherStaticInitializers += initializer
|
||||
}
|
||||
|
||||
// TODO: consider including this into ObjCExportCodeSpec.
|
||||
@@ -390,13 +430,23 @@ internal class ObjCExportCodeGenerator(
|
||||
|
||||
}
|
||||
|
||||
private fun ObjCExportCodeGenerator.replaceExternalWeakOrCommonGlobal(name: String, value: ConstValue) {
|
||||
val global = staticData.placeGlobal(name, value, isExported = true)
|
||||
private fun ObjCExportCodeGenerator.replaceExternalWeakOrCommonGlobal(
|
||||
name: String,
|
||||
value: ConstValue,
|
||||
origin: CompiledKlibModuleOrigin
|
||||
) {
|
||||
if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
|
||||
val global = codegen.importGlobal(name, value.llvmType, origin)
|
||||
externalGlobalInitializers[global] = value
|
||||
} else {
|
||||
context.llvmImports.add(origin)
|
||||
val global = staticData.placeGlobal(name, value, isExported = true)
|
||||
|
||||
if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) {
|
||||
// Note: actually this is required only if global's weak/common definition is in other object file,
|
||||
// but it is simpler to do this for all globals, considering that all usages can't be removed by DCE anyway.
|
||||
context.llvm.usedGlobals += global.llvmGlobal
|
||||
if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) {
|
||||
// Note: actually this is required only if global's weak/common definition is in another object file,
|
||||
// but it is simpler to do this for all globals, considering that all usages can't be removed by DCE anyway.
|
||||
context.llvm.usedGlobals += global.llvmGlobal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -421,7 +471,11 @@ private fun ObjCExportCodeGenerator.setObjCExportTypeInfo(
|
||||
|
||||
if (codegen.isExternal(irClass)) {
|
||||
// Note: this global replaces the external one with common linkage.
|
||||
replaceExternalWeakOrCommonGlobal(irClass.writableTypeInfoSymbolName, writableTypeInfoValue)
|
||||
replaceExternalWeakOrCommonGlobal(
|
||||
irClass.writableTypeInfoSymbolName,
|
||||
writableTypeInfoValue,
|
||||
irClass.llvmSymbolOrigin
|
||||
)
|
||||
} else {
|
||||
context.llvmDeclarations.forClass(irClass).writableTypeInfoGlobal!!.also {
|
||||
it.setLinkage(LLVMLinkage.LLVMExternalLinkage)
|
||||
@@ -493,7 +547,11 @@ private fun ObjCExportCodeGenerator.emitBlockToKotlinFunctionConverters() {
|
||||
).pointer.getElementPtr(0)
|
||||
|
||||
// Note: this global replaces the weak global defined in runtime.
|
||||
replaceExternalWeakOrCommonGlobal("Kotlin_ObjCExport_blockToFunctionConverters", ptr)
|
||||
replaceExternalWeakOrCommonGlobal(
|
||||
"Kotlin_ObjCExport_blockToFunctionConverters",
|
||||
ptr,
|
||||
context.standardLlvmSymbolsOrigin
|
||||
)
|
||||
}
|
||||
|
||||
private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
|
||||
|
||||
@@ -315,6 +315,8 @@ __attribute__((weak)) int Kotlin_ObjCExport_sortedClassAdaptersNum = 0;
|
||||
__attribute__((weak)) const ObjCTypeAdapter** Kotlin_ObjCExport_sortedProtocolAdapters = nullptr;
|
||||
__attribute__((weak)) int Kotlin_ObjCExport_sortedProtocolAdaptersNum = 0;
|
||||
|
||||
__attribute__((weak)) bool Kotlin_ObjCExport_initTypeAdapters = false;
|
||||
|
||||
static const ObjCTypeAdapter* findClassAdapter(Class clazz) {
|
||||
return findAdapterByName(class_getName(clazz),
|
||||
Kotlin_ObjCExport_sortedClassAdapters,
|
||||
@@ -416,7 +418,26 @@ static void SwiftObject_releaseAsAssociatedObjectImp(id self, SEL cmd);
|
||||
|
||||
static void checkLoadedOnce();
|
||||
|
||||
static void initTypeAdaptersFrom(const ObjCTypeAdapter** adapters, int count) {
|
||||
for (int index = 0; index < count; ++index) {
|
||||
const ObjCTypeAdapter* adapter = adapters[index];
|
||||
const TypeInfo* typeInfo = adapter->kotlinTypeInfo;
|
||||
if (typeInfo != nullptr) {
|
||||
typeInfo->writableInfo_->objCExport.typeAdapter = adapter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void initTypeAdapters() {
|
||||
if (!Kotlin_ObjCExport_initTypeAdapters) return;
|
||||
|
||||
initTypeAdaptersFrom(Kotlin_ObjCExport_sortedClassAdapters, Kotlin_ObjCExport_sortedClassAdaptersNum);
|
||||
initTypeAdaptersFrom(Kotlin_ObjCExport_sortedProtocolAdapters, Kotlin_ObjCExport_sortedProtocolAdaptersNum);
|
||||
}
|
||||
|
||||
static void initializeObjCExport() {
|
||||
initTypeAdapters();
|
||||
|
||||
SEL toKotlinSelector = @selector(toKotlin:);
|
||||
Method toKotlinMethod = class_getClassMethod([NSObject class], toKotlinSelector);
|
||||
RuntimeAssert(toKotlinMethod != nullptr, "");
|
||||
|
||||
Reference in New Issue
Block a user