Rework globals init. (#1336)

This commit is contained in:
Nikolay Igotti
2018-02-23 01:32:01 +03:00
committed by GitHub
parent 46f75c2226
commit 346e1aefcf
8 changed files with 108 additions and 33 deletions
@@ -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
}
@@ -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
@@ -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.
@@ -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))
}
}
}
//-------------------------------------------------------------------------//
+6
View File
@@ -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);
-9
View File
@@ -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