Implemented code generation of combined IR of all libraries

This commit is contained in:
Igor Chevdar
2019-02-19 12:43:37 +05:00
parent 49493e6dd9
commit e3efd75e55
36 changed files with 268 additions and 277 deletions
+2 -17
View File
@@ -153,7 +153,6 @@ classes.dependsOn 'compilerClasses', 'cli_bcClasses', 'bc_frontendClasses'
// These are just a couple of aliases
task stdlib(dependsOn: "${hostName}Stdlib")
task start(dependsOn: "${hostName}Start")
def commonSrc = file('build/stdlib')
@@ -180,7 +179,8 @@ final List<File> 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/main/kotlin'),
project(':runtime').file('src/launcher/kotlin')
]
task zipStdLibSources(type: Zip, dependsOn: unzipStdlibSources) {
@@ -244,21 +244,6 @@ targetList.each { target ->
dependsOn ":runtime:${target}Runtime"
dependsOn ":distCompiler"
}
task("${target}Start", type: JavaExec) {
main = 'org.jetbrains.kotlin.cli.bc.K2NativeKt'
classpath = project.configurations.cli_bc
jvmArgs = konanJvmArgs
args = [*konanArgs, '-produce', 'bitcode',
'-output', project(':runtime').file("build/${target}Start"),
'-library', project(':runtime').file("build/${target}Stdlib"),
project(':runtime').file('src/launcher/kotlin')]
inputs.dir(project(':runtime').file('src/launcher/kotlin'))
outputs.file(project(':runtime').file("build/${target}Start.bc"))
dependsOn ":runtime:${target}Runtime", "${target}Stdlib"
}
}
task run {
@@ -29,7 +29,6 @@ internal fun produceCStubs(context: Context) {
internal fun produceOutput(context: Context) {
val llvmModule = context.llvmModule!!
val config = context.config.configuration
val tempFiles = context.config.tempFiles
val produce = config.get(KonanConfigKeys.PRODUCE)
@@ -42,7 +41,7 @@ internal fun produceOutput(context: Context) {
val output = tempFiles.nativeBinaryFileName
context.bitcodeFileName = output
val generatedBitcodeFiles =
val generatedBitcodeFiles =
if (produce == CompilerOutputKind.DYNAMIC || produce == CompilerOutputKind.STATIC) {
produceCAdapterBitcode(
context.config.clang,
@@ -57,16 +56,15 @@ internal fun produceOutput(context: Context) {
generatedBitcodeFiles
for (library in nativeLibraries) {
parseAndLinkBitcodeFile(llvmModule, library)
parseAndLinkBitcodeFile(context.llvmModule!!, library)
}
LLVMWriteBitcodeToFile(llvmModule, output)
LLVMWriteBitcodeToFile(context.llvmModule!!, output)
}
CompilerOutputKind.LIBRARY -> {
val output = context.config.outputFiles.outputName
val libraryName = context.config.moduleId
val neededLibraries
= context.llvm.librariesForLibraryManifest
val neededLibraries = context.librariesWithDependencies
val abiVersion = KonanAbiVersion.CURRENT
val compilerVersion = KonanVersion.CURRENT
val libraryVersion = config.get(KonanConfigKeys.LIBRARY_VERSION)
@@ -85,7 +83,7 @@ internal fun produceOutput(context: Context) {
target,
output,
libraryName,
llvmModule,
null,
nopack,
manifestProperties,
context.dataFlowGraph)
@@ -96,7 +94,7 @@ internal fun produceOutput(context: Context) {
CompilerOutputKind.BITCODE -> {
val output = context.config.outputFile
context.bitcodeFileName = output
LLVMWriteBitcodeToFile(llvmModule, output)
LLVMWriteBitcodeToFile(context.llvmModule!!, output)
}
}
}
@@ -99,7 +99,9 @@ internal class SpecialDeclarationsFactory(val context: Context) {
DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS,
descriptor,
outerClass.defaultType
)
).apply {
parent = innerClass
}
}
fun getLoweredEnum(enumClass: IrClass): LoweredEnum {
@@ -109,25 +111,8 @@ internal class SpecialDeclarationsFactory(val context: Context) {
}
}
private fun assignOrdinalsToEnumEntries(classDescriptor: ClassDescriptor): Map<ClassDescriptor, Int> {
val enumEntryOrdinals = mutableMapOf<ClassDescriptor, Int>()
classDescriptor.enumEntries.forEachIndexed { index, entry ->
enumEntryOrdinals[entry] = index
}
return enumEntryOrdinals
}
fun getEnumEntryOrdinal(entryDescriptor: ClassDescriptor): Int {
val enumClassDescriptor = entryDescriptor.containingDeclaration as ClassDescriptor
// If enum came from another module then we need to get serialized ordinal number.
// We serialize ordinal because current serialization cannot preserve enum entry order.
if (enumClassDescriptor is DeserializedClassDescriptor) {
return enumClassDescriptor.classProto.enumEntryList
.first { entryDescriptor.name == enumClassDescriptor.c.nameResolver.getName(it.name) }
.getExtension(KonanProtoBuf.enumEntryOrdinal)
}
return ordinals.getOrPut(enumClassDescriptor) { assignOrdinalsToEnumEntries(enumClassDescriptor) }[entryDescriptor]!!
}
fun getEnumEntryOrdinal(enumEntry: IrEnumEntry) =
enumEntry.parentAsClass.declarations.filterIsInstance<IrEnumEntry>().indexOf(enumEntry)
fun getBridge(overriddenFunction: OverriddenFunctionInfo): IrSimpleFunction {
val irFunction = overriddenFunction.function
@@ -295,6 +280,8 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
return true
}
lateinit var irModules: Map<String, IrModuleFragment>
// TODO: make lateinit?
var irModule: IrModuleFragment? = null
set(module) {
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.konan.properties.loadProperties
import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.KonanAbiVersion
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.library.resolver.TopologicalLibraryOrder
import org.jetbrains.kotlin.konan.library.toUnresolvedLibraries
import org.jetbrains.kotlin.konan.parseKonanVersion
@@ -105,7 +106,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
fun librariesWithDependencies(moduleDescriptor: ModuleDescriptor?): List<KonanLibrary> {
if (moduleDescriptor == null) error("purgeUnneeded() only works correctly after resolve is over, and we have successfully marked package files as needed or not needed.")
return resolvedLibraries.filterRoots { (!it.isDefault && !this.purgeUserLibs) || it.isNeededForLink }.getFullList()
return resolvedLibraries.filterRoots { (!it.isDefault && !this.purgeUserLibs) || it.isNeededForLink }.getFullList(TopologicalLibraryOrder)
}
internal val defaultNativeLibraries: List<String> = mutableListOf<String>().apply {
@@ -190,7 +190,7 @@ internal val innerClassPhase = makeKonanFileLoweringPhase(
::InnerClassLowering,
name = "InnerClasses",
description = "Inner classes lowering",
prerequisite = setOf(defaultParameterExtentPhase, genSyntheticFieldsPhase )
prerequisite = setOf(defaultParameterExtentPhase)
)
internal val forLoopsPhase = makeKonanFileLoweringPhase(
@@ -5,5 +5,7 @@ import org.jetbrains.kotlin.name.FqName
object RuntimeNames {
val symbolName = FqName("kotlin.native.SymbolName")
val exportForCppRuntime = FqName("kotlin.native.internal.ExportForCppRuntime")
val exportForCompilerAnnotation = FqName("kotlin.native.internal.ExportForCompiler")
val exportTypeInfoAnnotation = FqName("kotlin.native.internal.ExportTypeInfo")
val cCall = FqName("kotlinx.cinterop.internal.CCall")
}
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.konan.serialization.*
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
@@ -65,22 +66,39 @@ internal val psiToIrPhase = konanUnitPhase(
forwardDeclarationsModuleDescriptor
)
val irModules = moduleDescriptor.allDependencyModules.map {
val library = it.konanLibrary
if (library == null) {
return@map null
val modules = mutableMapOf<String, IrModuleFragment>()
var dependenciesCount = 0
while (true) {
// context.config.librariesWithDependencies could change at each iteration.
val dependencies = moduleDescriptor.allDependencyModules.filter {
config.librariesWithDependencies(moduleDescriptor).contains(it.konanLibrary)
}
library.irHeader?.let { header -> deserializer.deserializeIrModule(it, header) }
}.filterNotNull()
for (dependency in dependencies) {
val konanLibrary = dependency.konanLibrary!!
if (modules.containsKey(konanLibrary.libraryName)) continue
konanLibrary.irHeader?.let { header ->
val deserializationStrategy = when {
config.produce.isNativeBinary -> DeserializationStrategy.EXPLICITLY_EXPORTED
else -> DeserializationStrategy.ONLY_REFERENCED
}
modules[konanLibrary.libraryName] = deserializer.deserializeIrModuleHeader(dependency, header, deserializationStrategy)
}
}
if (dependencies.size == dependenciesCount) break
dependenciesCount = dependencies.size
}
val symbols = KonanSymbols(this, generatorContext.symbolTable, generatorContext.symbolTable.lazyWrapper)
val module = translator.generateModuleFragment(generatorContext, environment.getSourceFiles(), deserializer)
irModules.forEach {
modules.values.forEach {
it.patchDeclarationParents()
}
irModule = module
irModules = modules
ir.symbols = symbols
// validateIrModule(this, module)
@@ -102,12 +120,6 @@ internal val irGeneratorPluginsPhase = konanUnitPhase(
description = "Plugged-in ir generators"
)
internal val genSyntheticFieldsPhase = konanUnitPhase(
op = { markBackingFields(this) },
name = "GenSyntheticFields",
description = "Generate synthetic fields"
)
// TODO: We copy default value expressions from expects to actuals before IR serialization,
// because the current infrastructure doesn't allow us to get them at deserialization stage.
// That requires some design and implementation work.
@@ -128,15 +140,13 @@ internal val patchDeclarationParents0Phase = konanUnitPhase(
internal val serializerPhase = konanUnitPhase(
op = {
val declarationTable = DeclarationTable(irModule!!.irBuiltins, DescriptorTable())
val serializedIr = IrModuleSerializer(
this, declarationTable, bodiesOnlyForInlines = config.isInteropStubs).serializedIrModule(irModule!!)
val serializedIr = IrModuleSerializer(this, declarationTable).serializedIrModule(irModule!!)
val serializer = KonanSerializationUtil(this, config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)!!, declarationTable)
serializedLinkData =
serializer.serializeModule(moduleDescriptor, /*if (!config.isInteropStubs) serializedIr else null*/ serializedIr)
},
name = "Serializer",
description = "Serialize descriptor tree and inline IR bodies",
prerequisite = setOf(genSyntheticFieldsPhase)
description = "Serialize descriptor tree and inline IR bodies"
)
internal val setUpLinkStagePhase = konanUnitPhase(
@@ -165,13 +175,108 @@ internal val linkPhase = namedUnitPhase(
linkerPhase
)
internal val allLoweringsPhase = namedIrModulePhase(
name = "IrLowering",
description = "IR Lowering",
lower = removeExpectDeclarationsPhase then
lowerBeforeInlinePhase then
inlinePhase then
lowerAfterInlinePhase then
interopPart1Phase then
patchDeclarationParents1Phase then
performByIrFile(
name = "IrLowerByFile",
description = "IR Lowering by file",
lower = lateinitPhase then
stringConcatenationPhase then
enumConstructorsPhase then
initializersPhase then
sharedVariablesPhase then
localFunctionsPhase then
tailrecPhase then
defaultParameterExtentPhase then
innerClassPhase then
forLoopsPhase then
dataClassesPhase then
builtinOperatorPhase then
finallyBlocksPhase then
testProcessorPhase then
enumClassPhase then
delegationPhase then
callableReferencePhase then
interopPart2Phase then
varargPhase then
compileTimeEvaluatePhase then
coroutinesPhase then
typeOperatorPhase then
bridgesPhase then
autoboxPhase then
returnsInsertionPhase
) then
checkDeclarationParentsPhase
// validateIrModulePhase // Temporarily disabled until moving to new IR finished.
)
internal val dependenciesLowerPhase = SameTypeNamedPhaseWrapper(
name = "LowerLibIR",
description = "Lower library's IR",
prerequisite = emptySet(),
dumperVerifier = EmptyDumperVerifier(),
lower = object : CompilerPhase<Context, IrModuleFragment, IrModuleFragment> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, irModule: IrModuleFragment): IrModuleFragment {
val files = mutableListOf<IrFile>()
files += irModule.files
irModule.files.clear()
// TODO: KonanLibraryResolver.TopologicalLibraryOrder actually returns libraries in the reverse topological order.
context.librariesWithDependencies
.reversed()
.forEach {
val libModule = context.irModules[it.libraryName]
?: return@forEach
irModule.files += libModule.files
allLoweringsPhase.invoke(phaseConfig, phaserState, context, irModule)
irModule.files.clear()
}
// Save all files for codegen in reverse topological order.
// This guarantees that libraries initializers are emitted in correct order.
context.librariesWithDependencies
.forEach {
val libModule = context.irModules[it.libraryName]
?: return@forEach
irModule.files += libModule.files
}
irModule.files += files
return irModule
}
})
internal val bitcodePhase = namedIrModulePhase(
name = "Bitcode",
description = "LLVM Bitcode generation",
lower = contextLLVMSetupPhase then
RTTIPhase then
generateDebugInfoHeaderPhase then
deserializeDFGPhase then
devirtualizationPhase then
escapeAnalysisPhase then
codegenPhase then
finalizeDebugInfoPhase then
cStubsPhase
)
internal val toplevelPhase = namedUnitPhase(
name = "Compiler",
description = "The whole compilation process",
lower = frontendPhase then
psiToIrPhase then
irGeneratorPluginsPhase then
genSyntheticFieldsPhase then
copyDefaultValuesToActualPhase then
patchDeclarationParents0Phase then
serializerPhase then
@@ -179,67 +284,16 @@ internal val toplevelPhase = namedUnitPhase(
name = "Backend",
description = "All backend",
lower = takeFromContext<Context, Unit, IrModuleFragment> { it.irModule!! } then
namedIrModulePhase(
name = "IrLowering",
description = "IR Lowering",
lower = removeExpectDeclarationsPhase then
lowerBeforeInlinePhase then
inlinePhase then
lowerAfterInlinePhase then
interopPart1Phase then
patchDeclarationParents1Phase then
performByIrFile(
name = "IrLowerByFile",
description = "IR Lowering by file",
lower = lateinitPhase then
stringConcatenationPhase then
enumConstructorsPhase then
initializersPhase then
sharedVariablesPhase then
localFunctionsPhase then
tailrecPhase then
defaultParameterExtentPhase then
innerClassPhase then
forLoopsPhase then
dataClassesPhase then
builtinOperatorPhase then
finallyBlocksPhase then
testProcessorPhase then
enumClassPhase then
delegationPhase then
callableReferencePhase then
interopPart2Phase then
varargPhase then
compileTimeEvaluatePhase then
coroutinesPhase then
typeOperatorPhase then
bridgesPhase then
autoboxPhase then
returnsInsertionPhase
) then
checkDeclarationParentsPhase then
// validateIrModulePhase then // Temporarily disabled until moving to new IR finished.
moduleIndexForCodegenPhase
) then
namedIrModulePhase(
name = "Bitcode",
description = "LLVM Bitcode generation",
lower = contextLLVMSetupPhase then
RTTIPhase then
generateDebugInfoHeaderPhase then
buildDFGPhase then
deserializeDFGPhase then
devirtualizationPhase then
escapeAnalysisPhase then
serializeDFGPhase then
codegenPhase then
finalizeDebugInfoPhase then
cStubsPhase then
bitcodeLinkerPhase
) then
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.
moduleIndexForCodegenPhase then
buildDFGPhase then
serializeDFGPhase then
bitcodePhase then
produceOutputPhase then
verifyBitcodePhase then
printBitcodePhase
then
printBitcodePhase then
unitSink()
) then
linkPhase
@@ -256,6 +310,8 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
// Don't serialize anything to a final executable.
switch(serializerPhase, config.produce == CompilerOutputKind.LIBRARY)
switch(dependenciesLowerPhase, config.produce != CompilerOutputKind.LIBRARY)
switch(bitcodePhase, config.produce != CompilerOutputKind.LIBRARY)
switch(linkPhase, config.produce.isNativeBinary)
switch(testProcessorPhase, getNotNull(KonanConfigKeys.GENERATE_TEST_RUNNER) != TestRunnerKind.NONE)
}
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
@@ -7,25 +7,22 @@ package org.jetbrains.kotlin.backend.konan.irasdescriptors
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.konan.descriptors.getArgumentValueOrNull
import org.jetbrains.kotlin.backend.konan.descriptors.konanBackingField
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.SourceManager
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.isMarkedNullable
import org.jetbrains.kotlin.ir.util.explicitParameters
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.ir.util.isFunction
import org.jetbrains.kotlin.ir.util.isSuspendFunction
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
val IrConstructor.constructedClass get() = this.parent as IrClass
@@ -95,23 +92,7 @@ fun IrClass.getSuperInterfaces() = this.superClasses.map { it.owner }.filter { i
val IrProperty.konanBackingField: IrField?
get() {
assert(this.isReal)
this.backingField?.let { return it }
(this.descriptor as? DeserializedPropertyDescriptor)?.konanBackingField?.let { backingFieldDescriptor ->
val result = IrFieldImpl(
this.startOffset,
this.endOffset,
IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
backingFieldDescriptor,
this.getter!!.returnType
).also {
it.parent = this.parent
}
this.backingField = result
return result
}
return null
return this.backingField
}
val IrFunction.isReal get() = this.origin != IrDeclarationOrigin.FAKE_OVERRIDE
@@ -121,14 +121,14 @@ internal fun buildLibrary(
target: KonanTarget,
output: String,
moduleName: String,
llvmModule: LLVMModuleRef,
llvmModule: LLVMModuleRef?,
nopack: Boolean,
manifestProperties: Properties?,
dataFlowGraph: ByteArray?): KonanLibraryWriter {
val library = LibraryWriterImpl(File(output), moduleName, versions, target, nopack)
library.addKotlinBitcode(llvmModule)
llvmModule?.let { library.addKotlinBitcode(it) }
library.addLinkData(linkData)
natives.forEach {
library.addNativeBitcode(it)
@@ -107,7 +107,7 @@ private val cnameAnnotation = FqName("kotlin.native.CName")
private val exportForCppRuntimeAnnotation = RuntimeNames.exportForCppRuntime
private val exportForCompilerAnnotation = FqName("kotlin.native.internal.ExportForCompiler")
private val exportForCompilerAnnotation = RuntimeNames.exportForCompilerAnnotation
private val publishedApiAnnotation = FqName("kotlin.PublishedApi")
@@ -151,9 +151,9 @@ internal val cStubsPhase = makeKonanModuleOpPhase(
op = { context, _ -> produceCStubs(context) }
)
internal val bitcodeLinkerPhase = makeKonanModuleOpPhase(
name = "BitcodeLinker",
description = "Bitcode linking",
internal val produceOutputPhase = makeKonanModuleOpPhase(
name = "ProduceOutput",
description = "Produce output",
op = { context, _ -> produceOutput(context) }
)
@@ -142,12 +142,7 @@ internal interface ContextUtils : RuntimeAware {
get() = context.llvm.staticData
fun isExternal(declaration: IrDeclaration): Boolean {
val pkg = declaration.findPackage()
return when (pkg) {
is IrFile -> pkg.packageFragmentDescriptor.containingDeclaration != context.moduleDescriptor
is IrExternalPackageFragment -> true
else -> error(pkg)
}
return false
}
/**
@@ -367,19 +362,6 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
.getFullList(TopologicalLibraryOrder)
}
val librariesForLibraryManifest: List<KonanLibrary>
get() {
// Note: library manifest should contain the list of all user libraries and frontend-used default libraries.
// However this would result into linking too many default libraries into the application which uses current
// library. This problem should probably be fixed by adding different kind of dependencies to library
// manifest.
// Currently the problem is workarounded like this:
return this.librariesToLink
// This list contains all user libraries and the default libraries required for link (not frontend).
// That's why the workaround doesn't work only in very special cases, e.g. when `-nodefaultlibs` is enabled
// when compiling the application, while the library API uses types from default libs.
}
val staticData = StaticData(context)
private val target = context.config.target
@@ -40,10 +40,9 @@ internal fun findMainEntryPoint(context: Context): FunctionDescriptor? {
candidates.singleOrNull { it.hasSingleArrayOfStringParameter } ?:
candidates.singleOrNull { it.hasNoParameters } ?:
context.reportCompilationError("Could not find '$entryName' in '$packageName' package.")
if (main.isSuspend) {
if (main.isSuspend)
context.reportCompilationError("Entry point can not be a suspend function.")
}
return main
}
@@ -58,6 +58,7 @@ internal enum class IntrinsicType {
IDENTITY,
IMMUTABLE_BLOB,
INIT_INSTANCE,
SELECT_ENTRY_POINT,
// Coroutines
GET_CONTINUATION,
RETURN_IF_SUSPEND,
@@ -218,6 +219,7 @@ 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,
@@ -246,6 +248,12 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
private fun FunctionGenerationContext.emitIdentity(args: List<LLVMValueRef>): LLVMValueRef =
args.single()
private fun FunctionGenerationContext.emitEntryPointSelection(args: List<LLVMValueRef>): 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>): LLVMValueRef {
val varargExpression = callSite.getValueArgument(0) as IrVararg
val vararg = args.single()
@@ -324,7 +324,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
appendLlvmUsed("llvm.used", context.llvm.usedFunctions + context.llvm.usedGlobals)
appendLlvmUsed("llvm.compiler.used", context.llvm.compilerUsedGlobals)
appendStaticInitializers()
appendEntryPointSelector(context.ir.symbols.entryPoint?.owner)
if (context.isNativeLibrary) {
appendCAdapters()
}
@@ -2336,14 +2335,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
appendingTo(bbNeedInit) {
LLVMBuildStore(builder, kImmOne, initGuard)
if (context.config.produce.isNativeBinary) {
context.llvm.librariesToLink.forEach {
val dependencyCtorFunction = context.llvm.externalFunction(
it.moduleConstructorName, kVoidFuncType, CurrentKonanModuleOrigin)
call(dependencyCtorFunction, emptyList(), Lifetime.IRRELEVANT,
exceptionHandler = ExceptionHandler.Caller, verbatim = true)
}
}
// TODO: shall we put that into the try block?
context.llvm.staticInitializers.forEach {
call(it, emptyList(), Lifetime.IRRELEVANT,
@@ -212,7 +212,7 @@ internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, origin:
val found = LLVMGetNamedGlobal(context.llvmModule, name)
if (found != null) {
assert (getGlobalType(found) == type)
assert (LLVMGetInitializer(found) == null)
assert (LLVMGetInitializer(found) == null) { "$name is already declared in the current module" }
if (threadLocal)
assert(LLVMGetThreadLocalMode(found) == context.llvm.tlsMode)
return found
@@ -86,15 +86,6 @@ internal fun StaticData.createConstKotlinObject(type: IrClass, vararg fields: Co
internal fun StaticData.createInitializer(type: IrClass, vararg fields: ConstValue): ConstValue =
Struct(objHeader(type.typeInfoPtr), *fields)
private fun StaticData.getArrayListClass(): ClassDescriptor {
val module = context.irModule!!.descriptor
val pkg = module.getPackage(FqName.fromSegments(listOf("kotlin", "collections")))
val classifier = pkg.memberScope.getContributedClassifier(Name.identifier("ArrayList"),
NoLookupLocation.FROM_BACKEND)
return classifier as ClassDescriptor
}
/**
* Creates static instance of `kotlin.collections.ArrayList<elementType>` with given values of fields.
*
@@ -59,7 +59,7 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
override fun visitField(declaration: IrField) {
// TODO: inlining a function returning an object
// we get PropertyDescriptors from whithin that object here.
// we get PropertyDescriptors from within that object here.
// That is a bug, most probably.
// We workaround the issue with question marks here.
(declaration.descriptor as? WrappedFieldDescriptor)?.bind(declaration)
@@ -136,10 +136,10 @@ internal class EnumUsageLowering(val context: Context)
internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
fun run(irFile: IrFile) {
runOnFilePostfix(irFile)
// EnumWhenLowering should be performed before EnumUsageLowering because
// the latter performs lowering of IrGetEnumValue
EnumWhenLowering(context).lower(irFile)
runOnFilePostfix(irFile)
EnumUsageLowering(context).lower(irFile)
}
@@ -238,7 +238,7 @@ internal class EnumConstructorsLowering(val context: Context) : ClassLoweringPas
override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression {
val name = enumEntry.name.asString()
val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(enumEntry.descriptor)
val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(enumEntry)
val startOffset = enumConstructorCall.startOffset
val endOffset = enumConstructorCall.endOffset
@@ -143,7 +143,7 @@ internal class EnumWhenLowering(private val context: Context) : IrElementTransfo
if (lhs is IrValueAccessExpression && lhs.symbol.owner == topmostSubject && rhs is IrGetEnumValue &&
// Both entries should belong to the same class:
topmostSubject.type.classifierOrNull?.owner == rhs.symbol.owner.parent) {
val entryOrdinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(rhs.descriptor)
val entryOrdinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(rhs.symbol.owner)
val subjectOrdinal = topmostOrdinalProvider.value
return IrCallImpl(call.startOffset, call.endOffset, areEqualByValue.owner.returnType, areEqualByValue).apply {
putValueArgument(0,
@@ -12,6 +12,10 @@ import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.ir.KonanIrReturnableBlockImpl
import org.jetbrains.kotlin.backend.konan.irasdescriptors.file
import org.jetbrains.kotlin.backend.konan.SYNTHETIC_OFFSET
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
@@ -24,6 +28,8 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.util.defaultType
@@ -169,6 +175,24 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
else -> error("Unknown ReturnTarget: $this")
}
private fun createSyntheticFunctionDescriptor(name: String): SimpleFunctionDescriptor {
val descriptor = WrappedSimpleFunctionDescriptor()
descriptor.bind(IrFunctionImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(descriptor),
Name.identifier(name),
Visibilities.PUBLIC,
Modality.FINAL,
context.irBuiltIns.unitType,
false,
false,
false,
false)
)
return descriptor
}
private fun performHighLevelJump(tryScopes: List<TryScope>,
index: Int,
jump: HighLevelJump,
@@ -181,7 +205,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
val currentTryScope = tryScopes[index]
currentTryScope.jumps.getOrPut(jump) {
val type = (jump as? Return)?.target?.owner?.returnType ?: value.type
val symbol = IrReturnableBlockSymbolImpl(WrappedSimpleFunctionDescriptor())
val symbol = IrReturnableBlockSymbolImpl(createSyntheticFunctionDescriptor("\$Finally$index"))
with(currentTryScope) {
irBuilder.run {
val inlinedFinally = irInlineFinally(symbol, type, expression, finallyExpression)
@@ -252,7 +276,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
)
using(TryScope(syntheticTry, transformedFinallyExpression, this)) {
val fallThroughType = aTry.type
val fallThroughSymbol = IrReturnableBlockSymbolImpl(WrappedSimpleFunctionDescriptor())
val fallThroughSymbol = IrReturnableBlockSymbolImpl(createSyntheticFunctionDescriptor("\$Fallthrough"))
val transformedResult = aTry.tryResult.transform(transformer, null)
transformedTry.tryResult = irReturn(fallThroughSymbol, transformedResult)
for (aCatch in aTry.catches) {
@@ -131,6 +131,9 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
if (descriptor.isInlineConstructor) {
// Copier sets parent to be the current function but
// constructor's parent cannot be a function.
copiedCallee.parent = callee.parent
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
irBuilder.run {
val constructorDescriptor = delegatingConstructorCall.descriptor.original
@@ -44,6 +44,7 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
}
private fun createOuterThisField() {
irClass.declarations += context.specialDeclarationsFactory.getOuterThisField(irClass)
outerThisFieldSymbol = context.specialDeclarationsFactory.getOuterThisField(irClass).symbol
}
@@ -628,7 +628,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
descriptor.getExternalObjCMethodInfo()?.let { methodInfo ->
val isInteropStubsFile =
currentFile.fileAnnotations.any { it.fqName == FqName("kotlinx.cinterop.InteropStubs") }
currentFile.annotations.hasAnnotation(FqName("kotlinx.cinterop.InteropStubs"))
// Special case: bridge from Objective-C method implementation template to Kotlin method;
// handled in CodeGeneratorVisitor.callVirtual.
@@ -1,54 +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.
*/
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.util.addChild
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
internal class BackingFieldVisitor(val context: Context) : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitProperty(declaration: IrProperty) {
super.visitProperty(declaration)
if (declaration.isDelegated) {
val irClass = declaration.parent as? IrClass
val list = irClass?.let { context.ir.classesDelegatedBackingFields.getOrPut(irClass.descriptor) { mutableListOf() } }
list?.add(declaration.backingField!!.descriptor)
}
if (declaration.backingField == null || declaration.isDelegated) return
assert(declaration.backingField!!.descriptor == declaration.descriptor) {
"backing field descriptor mismatch: ${declaration.backingField!!.descriptor} != ${declaration.descriptor}"
}
context.ir.propertiesWithBackingFields.add(declaration.descriptor)
}
override fun visitClass(declaration: IrClass) {
if (declaration.isInner)
declaration.declarations += context.specialDeclarationsFactory.getOuterThisField(declaration)
// Mark all dangling fields (they are created when class is inherited via delegation).
declaration.declarations.filterIsInstance<IrField>().forEach {
val list = context.ir.classesDelegatedBackingFields.getOrPut(declaration.descriptor) { mutableListOf() }
list.add(it.descriptor)
}
super.visitClass(declaration)
}
}
internal fun markBackingFields(context: Context) {
context.irModule!!.accept(BackingFieldVisitor(context), null)
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.konan.RuntimeNames
import org.jetbrains.kotlin.backend.konan.descriptors.findTopLevelDeclaration
import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember
import org.jetbrains.kotlin.backend.konan.descriptors.isSerializableExpectClass
@@ -39,6 +40,10 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrUnaryPrimitiveImpl
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.util.dump
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.library.impl.CombinedIrFileWriter
import org.jetbrains.kotlin.konan.library.impl.DeclarationId
import org.jetbrains.kotlin.metadata.KonanIr
@@ -1058,6 +1063,7 @@ internal class IrModuleSerializer(
val proto = KonanIr.IrFile.newBuilder()
.setFileEntry(serializeFileEntry(file.fileEntry))
.setFqName(serializeString(file.fqName.toString()))
.setAnnotations(serializeAnnotations(file.annotations))
file.declarations.forEach {
if (it is IrTypeAlias || (it.descriptor.isExpectMember && !it.descriptor.isSerializableExpectClass)) {
@@ -1070,6 +1076,26 @@ internal class IrModuleSerializer(
writer.addDeclaration(DeclarationId(uniqId.index, uniqId.isLocal), byteArray)
proto.addDeclarationId(protoUniqId(uniqId))
}
file.acceptVoid(object: IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitFunction(declaration: IrFunction) {
if (declaration.descriptor.annotations.hasAnnotation(RuntimeNames.exportForCppRuntime)
|| declaration.descriptor.annotations.hasAnnotation(RuntimeNames.exportForCompilerAnnotation))
proto.addExplicitlyExportedToCompiler(serializeIrSymbol(declaration.symbol))
super.visitDeclaration(declaration)
}
override fun visitClass(declaration: IrClass) {
if (declaration.descriptor.annotations.hasAnnotation(RuntimeNames.exportTypeInfoAnnotation))
proto.addExplicitlyExportedToCompiler(serializeIrSymbol(declaration.symbol))
super.visitDeclaration(declaration)
}
})
return proto.build()
}
@@ -89,6 +89,8 @@ message IrFile {
repeated UniqId declaration_id = 1;
required FileEntry file_entry = 2;
required String fq_name = 3;
required Annotations annotations = 4;
repeated IrSymbol explicitly_exported_to_compiler = 5; // Symbols referenced by C runtime. TODO: Make an extension?
}
message IrModule {
@@ -309,7 +309,7 @@ class KonanIrModuleDeserializer(
}
}
fun deserializeIrFile(fileProto: KonanIr.IrFile, moduleDescriptor: ModuleDescriptor, deserializeAllDeclarations: Boolean): IrFile {
fun deserializeIrFile(fileProto: KonanIr.IrFile, moduleDescriptor: ModuleDescriptor, deseralizationStrategy: DeserializationStrategy): IrFile {
val fileEntry = NaiveSourceBasedFileEntryImpl(
deserializeString(fileProto.fileEntry.name),
fileProto.fileEntry.lineStartOffsetsList.toIntArray()
@@ -327,15 +327,22 @@ class KonanIrModuleDeserializer(
val uniqIdKey = it.uniqIdKey(moduleDescriptor)
reversedFileIndex.put(uniqIdKey, file)
if (deserializeAllDeclarations) {
if (deseralizationStrategy == DeserializationStrategy.ALL) {
file.declarations.add(deserializeTopLevelDeclaration(uniqIdKey))
}
}
val annotations = deserializeAnnotations(fileProto.annotations)
file.annotations.addAll(annotations)
if (deseralizationStrategy == DeserializationStrategy.EXPLICITLY_EXPORTED)
fileProto.explicitlyExportedToCompilerList.forEach { deserializeIrSymbol(it) }
return file
}
fun deserializeIrModule(proto: KonanIr.IrModule, moduleDescriptor: ModuleDescriptor, deserializeAllDeclarations: Boolean): IrModuleFragment {
fun deserializeIrModuleHeader(proto: KonanIr.IrModule, moduleDescriptor: ModuleDescriptor, deserializationStrategy: DeserializationStrategy): IrModuleFragment {
deserializedModuleDescriptor = moduleDescriptor
deserializedModuleProtoSymbolTables.put(moduleDescriptor, proto.symbolTable)
@@ -343,7 +350,7 @@ class KonanIrModuleDeserializer(
deserializedModuleProtoTypeTables.put(moduleDescriptor, proto.typeTable)
val files = proto.fileList.map {
deserializeIrFile(it, moduleDescriptor, deserializeAllDeclarations)
deserializeIrFile(it, moduleDescriptor, deserializationStrategy)
}
val module = IrModuleFragmentImpl(moduleDescriptor, builtIns, files)
@@ -351,8 +358,14 @@ class KonanIrModuleDeserializer(
return module
}
fun deserializeIrModule(moduleDescriptor: ModuleDescriptor, byteArray: ByteArray, deserializeAllDeclarations: Boolean = false): IrModuleFragment {
fun deserializeIrModuleHeader(moduleDescriptor: ModuleDescriptor, byteArray: ByteArray, deserializationStrategy: DeserializationStrategy = DeserializationStrategy.ONLY_REFERENCED): IrModuleFragment {
val proto = KonanIr.IrModule.parseFrom(byteArray.codedInputStream, KonanSerializerProtocol.extensionRegistry)
return deserializeIrModule(proto, moduleDescriptor, deserializeAllDeclarations)
return deserializeIrModuleHeader(proto, moduleDescriptor, deserializationStrategy)
}
}
enum class DeserializationStrategy {
ONLY_REFERENCED,
ALL,
EXPLICITLY_EXPORTED
}
@@ -53,8 +53,6 @@ internal class KonanSerializerExtension(val context: Context, override val metad
override fun serializeEnumEntry(descriptor: ClassDescriptor, proto: ProtoBuf.EnumEntry.Builder) {
uniqId(descriptor) ?.let { proto.setExtension(KonanProtoBuf.enumEntryUniqId, it) }
// Serialization doesn't preserve enum entry order, so we need to serialize ordinal.
val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(descriptor)
proto.setExtension(KonanProtoBuf.enumEntryOrdinal, ordinal)
super.serializeEnumEntry(descriptor, proto)
}
-5
View File
@@ -340,7 +340,6 @@ targetList.each { target ->
task("${target}CrossDistRuntime", type: Copy) {
dependsOn ":runtime:${target}Runtime"
dependsOn ":backend.native:${target}Stdlib"
dependsOn ":backend.native:${target}Start"
destinationDir distDir
@@ -357,10 +356,6 @@ targetList.each { target ->
include('**')
into(stdlib)
}
from(project(':runtime').file("build/${target}Start.bc")) {
rename("${target}Start.bc", 'start.bc')
into("konan/targets/$target/native")
}
if (target == 'wasm32') {
into("$stdlib/targets/wasm32/included") {
from(project(':runtime').file('src/main/js'))
+5 -3
View File
@@ -4,16 +4,18 @@
*/
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<String>):Unit in the root package.
@SymbolName("EntryPointSelector")
external fun EntryPointSelector(args: Array<String>)
@TypedIntrinsic(IntrinsicType.SELECT_ENTRY_POINT)
private external fun EntryPointSelector(args: Array<String>)
@SymbolName("OnUnhandledException")
external private fun OnUnhandledException(throwable: Throwable)
private external fun OnUnhandledException(throwable: Throwable)
@ExportForCppRuntime
private fun Konan_start(args: Array<String>): Int {
+1 -1
View File
@@ -59,7 +59,7 @@ class AutoFree {
}
};
// RuntimeUtiks.kt
// RuntimeUtils.kt
extern "C" void ReportUnhandledException(KRef throwable);
extern "C" void ExceptionReporterLaunchpad(KRef reporter, KRef throwable);
@@ -52,6 +52,7 @@ 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"
@@ -81,7 +81,7 @@ class Distribution(
fun runtime(target: KonanTarget) = runtimeFileOverride ?: "$stdlib/targets/${target.visibleName}/native/runtime.bc"
val launcherFiles = listOf("start.bc", "launcher.bc")
val launcherFiles = listOf("launcher.bc")
val dependenciesDir = DependencyProcessor.defaultDependenciesRoot.absolutePath