From 71e1be1a5c0bf233b43a0efccca42bb618319f0f Mon Sep 17 00:00:00 2001 From: Nikolay Igotti Date: Wed, 21 Aug 2019 16:56:38 +0300 Subject: [PATCH] Rework entry point selector. (#3266) --- backend.native/build.gradle | 3 +- .../kotlin/backend/konan/EntryPoint.kt | 92 +++++++++++++++++++ .../kotlin/backend/konan/ToplevelPhases.kt | 18 ++++ .../jetbrains/kotlin/backend/konan/ir/Ir.kt | 2 + .../kotlin/backend/konan/ir/NewIrUtils.kt | 4 +- .../backend/konan/llvm/IntrinsicGenerator.kt | 8 -- runtime/src/launcher/kotlin/konan/start.kt | 30 ------ .../kotlin/native/internal/IntrinsicType.kt | 1 - .../kotlin/native/internal/RuntimeUtils.kt | 7 +- 9 files changed, 122 insertions(+), 43 deletions(-) create mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/EntryPoint.kt delete mode 100644 runtime/src/launcher/kotlin/konan/start.kt diff --git a/backend.native/build.gradle b/backend.native/build.gradle index 680f459799a..705944ffc08 100644 --- a/backend.native/build.gradle +++ b/backend.native/build.gradle @@ -178,8 +178,7 @@ final List stdLibSrc = [ project(':Interop:Runtime').file('src/main/kotlin'), project(':Interop:Runtime').file('src/native/kotlin'), project(':Interop:JsRuntime').file('src/main/kotlin'), - project(':runtime').file('src/main/kotlin'), - project(':runtime').file('src/launcher/kotlin') + project(':runtime').file('src/main/kotlin') ] // These files are built before the 'dist' is complete, diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/EntryPoint.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/EntryPoint.kt new file mode 100644 index 00000000000..f4bc4dead08 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/EntryPoint.kt @@ -0,0 +1,92 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.konan + +import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor +import org.jetbrains.kotlin.backend.common.lower.createIrBuilder +import org.jetbrains.kotlin.backend.common.lower.irBlockBody +import org.jetbrains.kotlin.backend.konan.ir.buildSimpleAnnotation +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.ir.builders.* +import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrTryImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl +import org.jetbrains.kotlin.ir.types.typeWith +import org.jetbrains.kotlin.ir.util.irCatch +import org.jetbrains.kotlin.name.Name + +internal fun makeEntryPoint(context: Context): IrFunction { + val entryPointDescriptor = WrappedSimpleFunctionDescriptor() + val actualMain = context.ir.symbols.entryPoint!!.owner + val entryPoint = IrFunctionImpl( + actualMain.startOffset, + actualMain.startOffset, + IrDeclarationOrigin.DEFINED, + IrSimpleFunctionSymbolImpl(entryPointDescriptor), + Name.identifier("Konan_start"), + Visibilities.PRIVATE, + Modality.FINAL, + context.irBuiltIns.intType, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false + ).also { function -> + function.valueParameters.add(WrappedValueParameterDescriptor().let { + IrValueParameterImpl( + actualMain.startOffset, actualMain.startOffset, + IrDeclarationOrigin.DEFINED, + IrValueParameterSymbolImpl(it), + Name.identifier("args"), + index = 0, + varargElementType = null, + isCrossinline = false, + type = context.irBuiltIns.arrayClass.typeWith(context.irBuiltIns.stringType), + isNoinline = false + ).apply { + it.bind(this) + parent = function + } + }) + } + entryPointDescriptor.bind(entryPoint) + entryPoint.annotations += buildSimpleAnnotation(context.irBuiltIns, + actualMain.startOffset, actualMain.startOffset, + context.ir.symbols.exportForCppRuntime.owner, "Konan_start") + + val builder = context.createIrBuilder(entryPoint.symbol) + entryPoint.body = builder.irBlockBody(entryPoint) { + +IrTryImpl( + startOffset = actualMain.startOffset, + endOffset = actualMain.startOffset, + type = context.irBuiltIns.nothingType + ).apply { + tryResult = irBlock { + +irCall(actualMain).apply { + if (actualMain.valueParameters.size != 0) + putValueArgument(0, irGet(entryPoint.valueParameters[0])) + } + +irReturn(irInt(0)) + } + catches += irCatch(context.irBuiltIns.throwableType).apply { + result = irBlock { + +irCall(context.ir.symbols.onUnhandledException).apply { + putValueArgument(0, irGet(catchParameter)) + } + +irReturn(irInt(1)) + } + } + } + } + + return entryPoint +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt index bc10e9e2b30..d3a2157412b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt @@ -18,6 +18,8 @@ import org.jetbrains.kotlin.descriptors.konan.isKonanStdlib import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.util.SymbolTable +import org.jetbrains.kotlin.ir.util.addChild +import org.jetbrains.kotlin.ir.util.file import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator @@ -320,6 +322,20 @@ internal val dependenciesLowerPhase = SameTypeNamedPhaseWrapper( } }) +internal val entryPointPhase = SameTypeNamedPhaseWrapper( + name = "addEntryPoint", + description = "Add entry point for program", + prerequisite = emptySet(), + lower = object : CompilerPhase { + override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState, + context: Context, input: IrModuleFragment): IrModuleFragment { + assert(context.config.produce == CompilerOutputKind.PROGRAM) + context.ir.symbols.entryPoint!!.owner.file.addChild(makeEntryPoint(context)) + return input + } + } +) + internal val bitcodePhase = namedIrModulePhase( name = "Bitcode", description = "LLVM Bitcode generation", @@ -357,6 +373,7 @@ val toplevelPhase: CompilerPhase<*, Unit, Unit> = namedUnitPhase( allLoweringsPhase then // Lower current module first. dependenciesLowerPhase then // Then lower all libraries in topological order. // With that we guarantee that inline functions are unlowered while being inlined. + entryPointPhase then bitcodePhase then verifyBitcodePhase then printBitcodePhase then @@ -384,6 +401,7 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) { // Don't serialize anything to a final executable. disableUnless(serializerPhase, config.produce == CompilerOutputKind.LIBRARY) disableIf(dependenciesLowerPhase, config.produce == CompilerOutputKind.LIBRARY) + disableUnless(entryPointPhase, config.produce == CompilerOutputKind.PROGRAM) disableIf(bitcodePhase, config.produce == CompilerOutputKind.LIBRARY) disableUnless(linkPhase, config.produce.isNativeBinary) disableIf(testProcessorPhase, getNotNull(KonanConfigKeys.GENERATE_TEST_RUNNER) == TestRunnerKind.NONE) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index eae92289b43..1d664c73cce 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -114,6 +114,8 @@ internal class KonanSymbols( val objCMethodImp = symbolTable.referenceClass(context.interopBuiltIns.objCMethodImp) + val onUnhandledException = internalFunction("OnUnhandledException") + val interopNativePointedGetRawPointer = symbolTable.referenceSimpleFunction(context.interopBuiltIns.nativePointedGetRawPointer) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/NewIrUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/NewIrUtils.kt index 7e3b1c4dba8..1622bcb76e9 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/NewIrUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/NewIrUtils.kt @@ -89,7 +89,9 @@ fun IrClass.companionObject() = this.declarations.filterIsInstance().at fun buildSimpleAnnotation(irBuiltIns: IrBuiltIns, startOffset: Int, endOffset: Int, annotationClass: IrClass, vararg args: String): IrConstructorCall { - val constructor = annotationClass.constructors.single() + val constructor = annotationClass.constructors.let { + it.singleOrNull() ?: it.single { ctor -> ctor.valueParameters.size == args.size } + } return IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, constructor.returnType, constructor.symbol).apply { args.forEachIndexed { index, arg -> assert(constructor.valueParameters[index].type == irBuiltIns.stringType) { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt index 39e294534c7..991b838bb93 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt @@ -63,7 +63,6 @@ internal enum class IntrinsicType { IDENTITY, IMMUTABLE_BLOB, INIT_INSTANCE, - SELECT_ENTRY_POINT, // Coroutines GET_CONTINUATION, RETURN_IF_SUSPEND, @@ -239,7 +238,6 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv IntrinsicType.IDENTITY -> emitIdentity(args) IntrinsicType.GET_CONTINUATION -> emitGetContinuation() IntrinsicType.INTEROP_MEMORY_COPY -> emitMemoryCopy(callSite, args) - IntrinsicType.SELECT_ENTRY_POINT -> emitEntryPointSelection(args) IntrinsicType.RETURN_IF_SUSPEND, IntrinsicType.INTEROP_BITS_TO_FLOAT, IntrinsicType.INTEROP_BITS_TO_DOUBLE, @@ -270,12 +268,6 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv private fun FunctionGenerationContext.emitIdentity(args: List): LLVMValueRef = args.single() - private fun FunctionGenerationContext.emitEntryPointSelection(args: List): LLVMValueRef { - val entryPoint = context.ir.symbols.entryPoint?.owner ?: return unreachable()!! // TODO: Don't put start.kt in source set unless produce=PROGRAM. - return call(codegen.llvmFunction(entryPoint), args.take(entryPoint.valueParameters.size), - Lifetime.IRRELEVANT, environment.exceptionHandler) - } - private fun FunctionGenerationContext.emitListOfInternal(callSite: IrCall, args: List): LLVMValueRef { val varargExpression = callSite.getValueArgument(0) as IrVararg val vararg = args.single() diff --git a/runtime/src/launcher/kotlin/konan/start.kt b/runtime/src/launcher/kotlin/konan/start.kt deleted file mode 100644 index 39eccfe1e04..00000000000 --- a/runtime/src/launcher/kotlin/konan/start.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -import kotlin.native.internal.ExportForCppRuntime -import kotlin.native.internal.TypedIntrinsic -import kotlin.native.internal.IntrinsicType - -// This function is produced by the code generator given -// the '-entry foo.bar.main' flag. -// It calls the requested entry point. -// The default is main(Array):Unit in the root package. -@TypedIntrinsic(IntrinsicType.SELECT_ENTRY_POINT) -private external fun EntryPointSelector(args: Array) - -@SymbolName("OnUnhandledException") -private external fun OnUnhandledException(throwable: Throwable) - -@ExportForCppRuntime -private fun Konan_start(args: Array): Int { - try { - EntryPointSelector(args) - // Successfully finished: - return 0 - } catch (e: Throwable) { - OnUnhandledException(e) - return 1 - } -} diff --git a/runtime/src/main/kotlin/kotlin/native/internal/IntrinsicType.kt b/runtime/src/main/kotlin/kotlin/native/internal/IntrinsicType.kt index f69e5bcd12d..0ec8488a539 100644 --- a/runtime/src/main/kotlin/kotlin/native/internal/IntrinsicType.kt +++ b/runtime/src/main/kotlin/kotlin/native/internal/IntrinsicType.kt @@ -53,7 +53,6 @@ class IntrinsicType { const val IDENTITY = "IDENTITY" const val IMMUTABLE_BLOB = "IMMUTABLE_BLOB" const val INIT_INSTANCE = "INIT_INSTANCE" - const val SELECT_ENTRY_POINT = "SELECT_ENTRY_POINT" const val GET_CONTINUATION = "GET_CONTINUATION" const val RETURN_IF_SUSPEND = "RETURN_IF_SUSPEND" diff --git a/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt b/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt index 72c804a1fce..89a2f038fb6 100644 --- a/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt +++ b/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt @@ -180,4 +180,9 @@ internal fun listOfInternal(vararg elements: T): List { for (i in 0 until elements.size) result.add(elements[i]) return result -} \ No newline at end of file +} + + +@PublishedApi +@SymbolName("OnUnhandledException") +external internal fun OnUnhandledException(throwable: Throwable) \ No newline at end of file