Rework globals init. (#1336)
This commit is contained in:
+2
-5
@@ -86,14 +86,11 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
private val resolver = defaultResolver(repositories, target, distribution)
|
||||
|
||||
internal val immediateLibraries: List<LibraryReaderImpl> by lazy {
|
||||
val result = resolver.resolveImmediateLibraries(
|
||||
libraryNames,
|
||||
target,
|
||||
val result = resolver.resolveImmediateLibraries(libraryNames, target,
|
||||
currentAbiVersion,
|
||||
configuration.getBoolean(KonanConfigKeys.NOSTDLIB),
|
||||
configuration.getBoolean(KonanConfigKeys.NODEFAULTLIBS),
|
||||
{ msg -> configuration.report(STRONG_WARNING, msg) }
|
||||
)
|
||||
{ msg -> configuration.report(STRONG_WARNING, msg) })
|
||||
resolver.resolveLibrariesRecursive(result, target, currentAbiVersion)
|
||||
result
|
||||
}
|
||||
|
||||
+7
-1
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.isUnit
|
||||
import org.jetbrains.kotlin.backend.konan.getObjCMethodInfo
|
||||
import org.jetbrains.kotlin.backend.konan.isExternalObjCClass
|
||||
import org.jetbrains.kotlin.backend.konan.isValueType
|
||||
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
@@ -32,7 +33,6 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.components.isVararg
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.findOriginalTopMostOverriddenDescriptors
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||
@@ -274,3 +274,9 @@ internal val ClassDescriptor.typeInfoHasVtableAttached: Boolean
|
||||
internal val ModuleDescriptor.privateFunctionsTableSymbolName get() = "private_functions_${name.asString()}"
|
||||
|
||||
internal val ModuleDescriptor.privateClassesTableSymbolName get() = "private_classes_${name.asString()}"
|
||||
|
||||
internal val String.moduleConstructorName
|
||||
get() = "_Konan_init_${this}"
|
||||
|
||||
internal val KonanLibraryReader.moduleConstructorName
|
||||
get() = uniqueName.moduleConstructorName
|
||||
|
||||
+29
-3
@@ -344,9 +344,35 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
||||
}
|
||||
}
|
||||
|
||||
val librariesToLink: List<KonanLibraryReader> get() = context.config.immediateLibraries
|
||||
.filter { (!it.isDefaultLibrary && !context.config.purgeUserLibs) || it in usedLibraries }
|
||||
.withResolvedDependencies()
|
||||
val librariesToLink: List<KonanLibraryReader> by lazy {
|
||||
context.config.immediateLibraries
|
||||
.filter { (!it.isDefaultLibrary && !context.config.purgeUserLibs) || it in usedLibraries }
|
||||
.withResolvedDependencies()
|
||||
.topoSort()
|
||||
}
|
||||
|
||||
private fun List<LibraryReaderImpl>.topoSort(): List<LibraryReaderImpl> {
|
||||
var sorted = mutableListOf<LibraryReaderImpl>()
|
||||
val visited = mutableSetOf<LibraryReaderImpl>()
|
||||
val tempMarks = mutableSetOf<LibraryReaderImpl>()
|
||||
|
||||
fun visit(node: LibraryReaderImpl, result: MutableList<LibraryReaderImpl>) {
|
||||
if (visited.contains(node)) return
|
||||
if (tempMarks.contains(node)) error("Cyclic dependency in library graph.")
|
||||
tempMarks.add(node)
|
||||
node.resolvedDependencies.forEach {
|
||||
visit(it, result)
|
||||
}
|
||||
visited.add(node)
|
||||
result += node
|
||||
}
|
||||
|
||||
this.forEach next@{
|
||||
if (visited.contains(it)) return@next
|
||||
visit(it, sorted)
|
||||
}
|
||||
return sorted
|
||||
}
|
||||
|
||||
val librariesForLibraryManifest: List<KonanLibraryReader> get() {
|
||||
// Note: library manifest should contain the list of all user libraries and frontend-used default libraries.
|
||||
|
||||
+62
-12
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.backend.konan.ir.*
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
|
||||
import org.jetbrains.kotlin.backend.konan.optimizations.*
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
@@ -41,6 +42,7 @@ import org.jetbrains.kotlin.ir.util.getArguments
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
@@ -354,13 +356,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
val kVoidFuncType = LLVMFunctionType(LLVMVoidType(), null, 0, 0)
|
||||
val kInitFuncType = LLVMFunctionType(LLVMVoidType(), cValuesOf(LLVMInt32Type()), 1, 0)
|
||||
val kVoidFuncType = LLVMFunctionType(LLVMVoidType(), null, 0, 0)!!
|
||||
val kInitFuncType = LLVMFunctionType(LLVMVoidType(), cValuesOf(LLVMInt32Type()), 1, 0)!!
|
||||
val kNodeInitType = LLVMGetTypeByName(context.llvmModule, "struct.InitNode")!!
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun createInitBody(initName: String): LLVMValueRef {
|
||||
val initFunction = LLVMAddFunction(context.llvmModule, initName, kInitFuncType)!! // create LLVM function
|
||||
LLVMSetLinkage(initFunction, LLVMLinkage.LLVMPrivateLinkage)
|
||||
generateFunction(codegen, initFunction) {
|
||||
using(FunctionScope(initFunction, initName, it)) {
|
||||
val bbInit = basicBlock("init", null)
|
||||
@@ -409,6 +412,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
private fun createInitCtor(ctorName: String, initNodePtr: LLVMValueRef) {
|
||||
val ctorFunction = LLVMAddFunction(context.llvmModule, ctorName, kVoidFuncType)!! // Create constructor function.
|
||||
LLVMSetLinkage(ctorFunction, LLVMLinkage.LLVMExternalLinkage)
|
||||
generateFunction(codegen, ctorFunction) {
|
||||
call(context.llvm.appendToInitalizersTail, listOf(initNodePtr)) // Add node to the tail of initializers list.
|
||||
ret(null)
|
||||
@@ -433,10 +437,7 @@ 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).
|
||||
val ctorName = "Konan_global_ctor_${fileName}_${context.llvm.globalInitIndex++}"
|
||||
|
||||
val ctorName = "${fileName}_${context.llvm.globalInitIndex++}"
|
||||
val initFunction = createInitBody(initName)
|
||||
val initNode = createInitNode(initFunction, nodeName)
|
||||
createInitCtor(ctorName, initNode)
|
||||
@@ -2542,14 +2543,63 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
// Append initializers of global variables in "llvm.global_ctors" array
|
||||
|
||||
fun appendStaticInitializers(initializers: List<LLVMValueRef>) {
|
||||
if (initializers.isEmpty()) return
|
||||
val ctorName = context.config.moduleId.moduleConstructorName
|
||||
val ctorFunction = LLVMAddFunction(context.llvmModule, ctorName, kVoidFuncType)!! // Create constructor function.
|
||||
LLVMSetLinkage(ctorFunction, LLVMLinkage.LLVMExternalLinkage)
|
||||
generateFunction(codegen, ctorFunction) {
|
||||
val initGuard = LLVMAddGlobal(context.llvmModule, int32Type, "Konan_init_guard")
|
||||
LLVMSetInitializer(initGuard, kImmZero)
|
||||
LLVMSetLinkage(initGuard, LLVMLinkage.LLVMPrivateLinkage)
|
||||
val bbInited = basicBlock("inited", null)
|
||||
val bbNeedInit = basicBlock("need_init", null)
|
||||
|
||||
val ctorList = initializers.map { it -> createGlobalCtor(it) }
|
||||
val globalCtors = context.llvm.staticData.placeGlobalArray("llvm.global_ctors", kCtorType, ctorList)
|
||||
LLVMSetLinkage(globalCtors.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage)
|
||||
val value = LLVMBuildLoad(builder, initGuard, "")!!
|
||||
condBr(icmpEq(value, kImmZero), bbNeedInit, bbInited)
|
||||
|
||||
appendingTo(bbInited) {
|
||||
ret(null)
|
||||
}
|
||||
|
||||
appendingTo(bbNeedInit) {
|
||||
LLVMBuildStore(builder, kImmOne, initGuard)
|
||||
|
||||
if (context.config.produce.isNativeBinary) {
|
||||
context.llvm.librariesToLink.forEach {
|
||||
val dependencyCtorFunction = context.llvm.externalFunction(
|
||||
it.moduleConstructorName, kVoidFuncType, CurrentKonanModule)
|
||||
call(dependencyCtorFunction, emptyList(), Lifetime.IRRELEVANT,
|
||||
exceptionHandler = ExceptionHandler.Caller, verbatim = true)
|
||||
}
|
||||
}
|
||||
// TODO: shall we put that into the try block?
|
||||
initializers.forEach {
|
||||
call(it, emptyList(), Lifetime.IRRELEVANT,
|
||||
exceptionHandler = ExceptionHandler.Caller, verbatim = true)
|
||||
}
|
||||
ret(null)
|
||||
}
|
||||
}
|
||||
|
||||
if (context.config.produce.isNativeBinary) {
|
||||
// Append initializers of global variables in "llvm.global_ctors" array
|
||||
val globalCtors = context.llvm.staticData.placeGlobalArray("llvm.global_ctors", kCtorType,
|
||||
listOf(createGlobalCtor(ctorFunction)))
|
||||
LLVMSetLinkage(globalCtors.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage)
|
||||
if (context.config.produce == CompilerOutputKind.PROGRAM) {
|
||||
// Provide an optional handle for calling .ctors, if standard constrcutors mechanism
|
||||
// is not available on the platform (i.e. WASM, embedded).
|
||||
val globalCtorFunction = LLVMAddFunction(context.llvmModule, "_Konan_constructors", kVoidFuncType)!!
|
||||
LLVMSetLinkage(globalCtorFunction, LLVMLinkage.LLVMExternalLinkage)
|
||||
generateFunction(codegen, globalCtorFunction) {
|
||||
// Unfortunately, LLVMAddAlias() doesn't seem to work on WASM yet.
|
||||
call(ctorFunction, emptyList(), Lifetime.IRRELEVANT,
|
||||
exceptionHandler = ExceptionHandler.Caller, verbatim = true)
|
||||
ret(null)
|
||||
}
|
||||
appendLlvmUsed("llvm.used", listOf(globalCtorFunction))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
@@ -45,6 +45,12 @@ extern "C" KInt Konan_run_start(int argc, const char** argv) {
|
||||
}
|
||||
|
||||
extern "C" RUNTIME_USED int Konan_main(int argc, const char** argv) {
|
||||
|
||||
#ifdef KONAN_NO_CTORS_SECTION
|
||||
extern void _Konan_constructors(void);
|
||||
_Konan_constructors();
|
||||
#endif
|
||||
|
||||
Kotlin_initRuntimeIfNeeded();
|
||||
|
||||
KInt exitStatus = Konan_run_start(argc, argv);
|
||||
|
||||
@@ -133,14 +133,6 @@ function stackTop() {
|
||||
return new Uint32Array(fourBytes)[0];
|
||||
}
|
||||
|
||||
function runGlobalInitializers(exports) {
|
||||
for (var property in exports) {
|
||||
if (property.startsWith("Konan_global_ctor_")) {
|
||||
exports[property]();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var konan_dependencies = {
|
||||
env: {
|
||||
abort: function() {
|
||||
@@ -220,7 +212,6 @@ function invokeModule(inst, args) {
|
||||
var exit_status = 0;
|
||||
|
||||
try {
|
||||
runGlobalInitializers(instance.exports);
|
||||
if (isBrowser()) {
|
||||
instance.exports.Kotlin_initRuntimeIfNeeded();
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ external fun EntryPointSelector(args: Array<String>)
|
||||
@ExportForCppRuntime
|
||||
private fun Konan_start(args: Array<String>): Int {
|
||||
try {
|
||||
|
||||
EntryPointSelector(args)
|
||||
|
||||
// Successfully finished:
|
||||
|
||||
@@ -135,12 +135,12 @@ class ClangArgs(private val configurables: Configurables) : Configurables by con
|
||||
KonanTarget.WASM32 ->
|
||||
listOf("-DKONAN_WASM=1", "-DKONAN_NO_FFI=1", "-DKONAN_NO_THREADS=1", "-DKONAN_NO_EXCEPTIONS=1",
|
||||
"-DKONAN_NO_MATH=1", "-DKONAN_INTERNAL_DLMALLOC=1", "-DKONAN_INTERNAL_SNPRINTF=1",
|
||||
"-DKONAN_INTERNAL_NOW=1", "-DKONAN_NO_MEMMEM")
|
||||
"-DKONAN_INTERNAL_NOW=1", "-DKONAN_NO_MEMMEM", "-DKONAN_NO_CTORS_SECTION")
|
||||
|
||||
is KonanTarget.ZEPHYR ->
|
||||
listOf( "-DKONAN_ZEPHYR=1", "-DKONAN_NO_FFI=1", "-DKONAN_NO_THREADS=1", "-DKONAN_NO_EXCEPTIONS=1",
|
||||
"-DKONAN_NO_MATH=1", "-DKONAN_INTERNAL_SNPRINTF=1", "-DKONAN_INTERNAL_NOW=1",
|
||||
"-DKONAN_NO_MEMMEM=1")
|
||||
"-DKONAN_NO_MEMMEM=1", "-DKONAN_NO_CTORS_SECTION")
|
||||
}
|
||||
|
||||
private val host = HostManager.host
|
||||
|
||||
Reference in New Issue
Block a user