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 // These are just a couple of aliases
task stdlib(dependsOn: "${hostName}Stdlib") task stdlib(dependsOn: "${hostName}Stdlib")
task start(dependsOn: "${hostName}Start")
def commonSrc = file('build/stdlib') 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/main/kotlin'),
project(':Interop:Runtime').file('src/native/kotlin'), project(':Interop:Runtime').file('src/native/kotlin'),
project(':Interop:JsRuntime').file('src/main/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) { task zipStdLibSources(type: Zip, dependsOn: unzipStdlibSources) {
@@ -244,21 +244,6 @@ targetList.each { target ->
dependsOn ":runtime:${target}Runtime" dependsOn ":runtime:${target}Runtime"
dependsOn ":distCompiler" 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 { task run {
@@ -29,7 +29,6 @@ internal fun produceCStubs(context: Context) {
internal fun produceOutput(context: Context) { internal fun produceOutput(context: Context) {
val llvmModule = context.llvmModule!!
val config = context.config.configuration val config = context.config.configuration
val tempFiles = context.config.tempFiles val tempFiles = context.config.tempFiles
val produce = config.get(KonanConfigKeys.PRODUCE) val produce = config.get(KonanConfigKeys.PRODUCE)
@@ -42,7 +41,7 @@ internal fun produceOutput(context: Context) {
val output = tempFiles.nativeBinaryFileName val output = tempFiles.nativeBinaryFileName
context.bitcodeFileName = output context.bitcodeFileName = output
val generatedBitcodeFiles = val generatedBitcodeFiles =
if (produce == CompilerOutputKind.DYNAMIC || produce == CompilerOutputKind.STATIC) { if (produce == CompilerOutputKind.DYNAMIC || produce == CompilerOutputKind.STATIC) {
produceCAdapterBitcode( produceCAdapterBitcode(
context.config.clang, context.config.clang,
@@ -57,16 +56,15 @@ internal fun produceOutput(context: Context) {
generatedBitcodeFiles generatedBitcodeFiles
for (library in nativeLibraries) { for (library in nativeLibraries) {
parseAndLinkBitcodeFile(llvmModule, library) parseAndLinkBitcodeFile(context.llvmModule!!, library)
} }
LLVMWriteBitcodeToFile(llvmModule, output) LLVMWriteBitcodeToFile(context.llvmModule!!, output)
} }
CompilerOutputKind.LIBRARY -> { CompilerOutputKind.LIBRARY -> {
val output = context.config.outputFiles.outputName val output = context.config.outputFiles.outputName
val libraryName = context.config.moduleId val libraryName = context.config.moduleId
val neededLibraries val neededLibraries = context.librariesWithDependencies
= context.llvm.librariesForLibraryManifest
val abiVersion = KonanAbiVersion.CURRENT val abiVersion = KonanAbiVersion.CURRENT
val compilerVersion = KonanVersion.CURRENT val compilerVersion = KonanVersion.CURRENT
val libraryVersion = config.get(KonanConfigKeys.LIBRARY_VERSION) val libraryVersion = config.get(KonanConfigKeys.LIBRARY_VERSION)
@@ -85,7 +83,7 @@ internal fun produceOutput(context: Context) {
target, target,
output, output,
libraryName, libraryName,
llvmModule, null,
nopack, nopack,
manifestProperties, manifestProperties,
context.dataFlowGraph) context.dataFlowGraph)
@@ -96,7 +94,7 @@ internal fun produceOutput(context: Context) {
CompilerOutputKind.BITCODE -> { CompilerOutputKind.BITCODE -> {
val output = context.config.outputFile val output = context.config.outputFile
context.bitcodeFileName = output 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, DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS,
descriptor, descriptor,
outerClass.defaultType outerClass.defaultType
) ).apply {
parent = innerClass
}
} }
fun getLoweredEnum(enumClass: IrClass): LoweredEnum { fun getLoweredEnum(enumClass: IrClass): LoweredEnum {
@@ -109,25 +111,8 @@ internal class SpecialDeclarationsFactory(val context: Context) {
} }
} }
private fun assignOrdinalsToEnumEntries(classDescriptor: ClassDescriptor): Map<ClassDescriptor, Int> { fun getEnumEntryOrdinal(enumEntry: IrEnumEntry) =
val enumEntryOrdinals = mutableMapOf<ClassDescriptor, Int>() enumEntry.parentAsClass.declarations.filterIsInstance<IrEnumEntry>().indexOf(enumEntry)
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 getBridge(overriddenFunction: OverriddenFunctionInfo): IrSimpleFunction { fun getBridge(overriddenFunction: OverriddenFunctionInfo): IrSimpleFunction {
val irFunction = overriddenFunction.function val irFunction = overriddenFunction.function
@@ -295,6 +280,8 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
return true return true
} }
lateinit var irModules: Map<String, IrModuleFragment>
// TODO: make lateinit? // TODO: make lateinit?
var irModule: IrModuleFragment? = null var irModule: IrModuleFragment? = null
set(module) { set(module) {
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.konan.properties.loadProperties
import org.jetbrains.kotlin.konan.target.* import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.KonanAbiVersion import org.jetbrains.kotlin.konan.KonanAbiVersion
import org.jetbrains.kotlin.konan.KonanVersion 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.library.toUnresolvedLibraries
import org.jetbrains.kotlin.konan.parseKonanVersion import org.jetbrains.kotlin.konan.parseKonanVersion
@@ -105,7 +106,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
fun librariesWithDependencies(moduleDescriptor: ModuleDescriptor?): List<KonanLibrary> { 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.") 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 { internal val defaultNativeLibraries: List<String> = mutableListOf<String>().apply {
@@ -190,7 +190,7 @@ internal val innerClassPhase = makeKonanFileLoweringPhase(
::InnerClassLowering, ::InnerClassLowering,
name = "InnerClasses", name = "InnerClasses",
description = "Inner classes lowering", description = "Inner classes lowering",
prerequisite = setOf(defaultParameterExtentPhase, genSyntheticFieldsPhase ) prerequisite = setOf(defaultParameterExtentPhase)
) )
internal val forLoopsPhase = makeKonanFileLoweringPhase( internal val forLoopsPhase = makeKonanFileLoweringPhase(
@@ -5,5 +5,7 @@ import org.jetbrains.kotlin.name.FqName
object RuntimeNames { object RuntimeNames {
val symbolName = FqName("kotlin.native.SymbolName") val symbolName = FqName("kotlin.native.SymbolName")
val exportForCppRuntime = FqName("kotlin.native.internal.ExportForCppRuntime") 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") 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.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings 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.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
@@ -65,22 +66,39 @@ internal val psiToIrPhase = konanUnitPhase(
forwardDeclarationsModuleDescriptor forwardDeclarationsModuleDescriptor
) )
val irModules = moduleDescriptor.allDependencyModules.map { val modules = mutableMapOf<String, IrModuleFragment>()
val library = it.konanLibrary
if (library == null) { var dependenciesCount = 0
return@map null 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) } for (dependency in dependencies) {
}.filterNotNull() 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 symbols = KonanSymbols(this, generatorContext.symbolTable, generatorContext.symbolTable.lazyWrapper)
val module = translator.generateModuleFragment(generatorContext, environment.getSourceFiles(), deserializer) val module = translator.generateModuleFragment(generatorContext, environment.getSourceFiles(), deserializer)
irModules.forEach { modules.values.forEach {
it.patchDeclarationParents() it.patchDeclarationParents()
} }
irModule = module irModule = module
irModules = modules
ir.symbols = symbols ir.symbols = symbols
// validateIrModule(this, module) // validateIrModule(this, module)
@@ -102,12 +120,6 @@ internal val irGeneratorPluginsPhase = konanUnitPhase(
description = "Plugged-in ir generators" 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, // 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. // because the current infrastructure doesn't allow us to get them at deserialization stage.
// That requires some design and implementation work. // That requires some design and implementation work.
@@ -128,15 +140,13 @@ internal val patchDeclarationParents0Phase = konanUnitPhase(
internal val serializerPhase = konanUnitPhase( internal val serializerPhase = konanUnitPhase(
op = { op = {
val declarationTable = DeclarationTable(irModule!!.irBuiltins, DescriptorTable()) val declarationTable = DeclarationTable(irModule!!.irBuiltins, DescriptorTable())
val serializedIr = IrModuleSerializer( val serializedIr = IrModuleSerializer(this, declarationTable).serializedIrModule(irModule!!)
this, declarationTable, bodiesOnlyForInlines = config.isInteropStubs).serializedIrModule(irModule!!)
val serializer = KonanSerializationUtil(this, config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)!!, declarationTable) val serializer = KonanSerializationUtil(this, config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)!!, declarationTable)
serializedLinkData = serializedLinkData =
serializer.serializeModule(moduleDescriptor, /*if (!config.isInteropStubs) serializedIr else null*/ serializedIr) serializer.serializeModule(moduleDescriptor, /*if (!config.isInteropStubs) serializedIr else null*/ serializedIr)
}, },
name = "Serializer", name = "Serializer",
description = "Serialize descriptor tree and inline IR bodies", description = "Serialize descriptor tree and inline IR bodies"
prerequisite = setOf(genSyntheticFieldsPhase)
) )
internal val setUpLinkStagePhase = konanUnitPhase( internal val setUpLinkStagePhase = konanUnitPhase(
@@ -165,13 +175,108 @@ internal val linkPhase = namedUnitPhase(
linkerPhase 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( internal val toplevelPhase = namedUnitPhase(
name = "Compiler", name = "Compiler",
description = "The whole compilation process", description = "The whole compilation process",
lower = frontendPhase then lower = frontendPhase then
psiToIrPhase then psiToIrPhase then
irGeneratorPluginsPhase then irGeneratorPluginsPhase then
genSyntheticFieldsPhase then
copyDefaultValuesToActualPhase then copyDefaultValuesToActualPhase then
patchDeclarationParents0Phase then patchDeclarationParents0Phase then
serializerPhase then serializerPhase then
@@ -179,67 +284,16 @@ internal val toplevelPhase = namedUnitPhase(
name = "Backend", name = "Backend",
description = "All backend", description = "All backend",
lower = takeFromContext<Context, Unit, IrModuleFragment> { it.irModule!! } then lower = takeFromContext<Context, Unit, IrModuleFragment> { it.irModule!! } then
namedIrModulePhase( allLoweringsPhase then // Lower current module first.
name = "IrLowering", dependenciesLowerPhase then // Then lower all libraries in topological order.
description = "IR Lowering", // With that we guarantee that inline functions are unlowered while being inlined.
lower = removeExpectDeclarationsPhase then moduleIndexForCodegenPhase then
lowerBeforeInlinePhase then buildDFGPhase then
inlinePhase then serializeDFGPhase then
lowerAfterInlinePhase then bitcodePhase then
interopPart1Phase then produceOutputPhase 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
verifyBitcodePhase then verifyBitcodePhase then
printBitcodePhase printBitcodePhase then
then
unitSink() unitSink()
) then ) then
linkPhase linkPhase
@@ -256,6 +310,8 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
// Don't serialize anything to a final executable. // Don't serialize anything to a final executable.
switch(serializerPhase, config.produce == CompilerOutputKind.LIBRARY) switch(serializerPhase, config.produce == CompilerOutputKind.LIBRARY)
switch(dependenciesLowerPhase, config.produce != CompilerOutputKind.LIBRARY)
switch(bitcodePhase, config.produce != CompilerOutputKind.LIBRARY)
switch(linkPhase, config.produce.isNativeBinary) switch(linkPhase, config.produce.isNativeBinary)
switch(testProcessorPhase, getNotNull(KonanConfigKeys.GENERATE_TEST_RUNNER) != TestRunnerKind.NONE) 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.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol 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.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl 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.common.atMostOne
import org.jetbrains.kotlin.backend.konan.descriptors.getArgumentValueOrNull 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.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.SourceManager
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol 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.ir.util.explicitParameters
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.ir.util.isFunction import org.jetbrains.kotlin.ir.util.isFunction
import org.jetbrains.kotlin.ir.util.isSuspendFunction import org.jetbrains.kotlin.ir.util.isSuspendFunction
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
val IrConstructor.constructedClass get() = this.parent as IrClass 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? val IrProperty.konanBackingField: IrField?
get() { get() {
assert(this.isReal) assert(this.isReal)
this.backingField?.let { return it } return this.backingField
(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
} }
val IrFunction.isReal get() = this.origin != IrDeclarationOrigin.FAKE_OVERRIDE val IrFunction.isReal get() = this.origin != IrDeclarationOrigin.FAKE_OVERRIDE
@@ -121,14 +121,14 @@ internal fun buildLibrary(
target: KonanTarget, target: KonanTarget,
output: String, output: String,
moduleName: String, moduleName: String,
llvmModule: LLVMModuleRef, llvmModule: LLVMModuleRef?,
nopack: Boolean, nopack: Boolean,
manifestProperties: Properties?, manifestProperties: Properties?,
dataFlowGraph: ByteArray?): KonanLibraryWriter { dataFlowGraph: ByteArray?): KonanLibraryWriter {
val library = LibraryWriterImpl(File(output), moduleName, versions, target, nopack) val library = LibraryWriterImpl(File(output), moduleName, versions, target, nopack)
library.addKotlinBitcode(llvmModule) llvmModule?.let { library.addKotlinBitcode(it) }
library.addLinkData(linkData) library.addLinkData(linkData)
natives.forEach { natives.forEach {
library.addNativeBitcode(it) library.addNativeBitcode(it)
@@ -107,7 +107,7 @@ private val cnameAnnotation = FqName("kotlin.native.CName")
private val exportForCppRuntimeAnnotation = RuntimeNames.exportForCppRuntime private val exportForCppRuntimeAnnotation = RuntimeNames.exportForCppRuntime
private val exportForCompilerAnnotation = FqName("kotlin.native.internal.ExportForCompiler") private val exportForCompilerAnnotation = RuntimeNames.exportForCompilerAnnotation
private val publishedApiAnnotation = FqName("kotlin.PublishedApi") private val publishedApiAnnotation = FqName("kotlin.PublishedApi")
@@ -151,9 +151,9 @@ internal val cStubsPhase = makeKonanModuleOpPhase(
op = { context, _ -> produceCStubs(context) } op = { context, _ -> produceCStubs(context) }
) )
internal val bitcodeLinkerPhase = makeKonanModuleOpPhase( internal val produceOutputPhase = makeKonanModuleOpPhase(
name = "BitcodeLinker", name = "ProduceOutput",
description = "Bitcode linking", description = "Produce output",
op = { context, _ -> produceOutput(context) } op = { context, _ -> produceOutput(context) }
) )
@@ -142,12 +142,7 @@ internal interface ContextUtils : RuntimeAware {
get() = context.llvm.staticData get() = context.llvm.staticData
fun isExternal(declaration: IrDeclaration): Boolean { fun isExternal(declaration: IrDeclaration): Boolean {
val pkg = declaration.findPackage() return false
return when (pkg) {
is IrFile -> pkg.packageFragmentDescriptor.containingDeclaration != context.moduleDescriptor
is IrExternalPackageFragment -> true
else -> error(pkg)
}
} }
/** /**
@@ -367,19 +362,6 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
.getFullList(TopologicalLibraryOrder) .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) val staticData = StaticData(context)
private val target = context.config.target private val target = context.config.target
@@ -40,10 +40,9 @@ internal fun findMainEntryPoint(context: Context): FunctionDescriptor? {
candidates.singleOrNull { it.hasSingleArrayOfStringParameter } ?: candidates.singleOrNull { it.hasSingleArrayOfStringParameter } ?:
candidates.singleOrNull { it.hasNoParameters } ?: candidates.singleOrNull { it.hasNoParameters } ?:
context.reportCompilationError("Could not find '$entryName' in '$packageName' package.") 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.") context.reportCompilationError("Entry point can not be a suspend function.")
}
return main return main
} }
@@ -58,6 +58,7 @@ internal enum class IntrinsicType {
IDENTITY, IDENTITY,
IMMUTABLE_BLOB, IMMUTABLE_BLOB,
INIT_INSTANCE, INIT_INSTANCE,
SELECT_ENTRY_POINT,
// Coroutines // Coroutines
GET_CONTINUATION, GET_CONTINUATION,
RETURN_IF_SUSPEND, RETURN_IF_SUSPEND,
@@ -218,6 +219,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
IntrinsicType.IDENTITY -> emitIdentity(args) IntrinsicType.IDENTITY -> emitIdentity(args)
IntrinsicType.GET_CONTINUATION -> emitGetContinuation() IntrinsicType.GET_CONTINUATION -> emitGetContinuation()
IntrinsicType.INTEROP_MEMORY_COPY -> emitMemoryCopy(callSite, args) IntrinsicType.INTEROP_MEMORY_COPY -> emitMemoryCopy(callSite, args)
IntrinsicType.SELECT_ENTRY_POINT -> emitEntryPointSelection(args)
IntrinsicType.RETURN_IF_SUSPEND, IntrinsicType.RETURN_IF_SUSPEND,
IntrinsicType.INTEROP_BITS_TO_FLOAT, IntrinsicType.INTEROP_BITS_TO_FLOAT,
IntrinsicType.INTEROP_BITS_TO_DOUBLE, IntrinsicType.INTEROP_BITS_TO_DOUBLE,
@@ -246,6 +248,12 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
private fun FunctionGenerationContext.emitIdentity(args: List<LLVMValueRef>): LLVMValueRef = private fun FunctionGenerationContext.emitIdentity(args: List<LLVMValueRef>): LLVMValueRef =
args.single() 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 { private fun FunctionGenerationContext.emitListOfInternal(callSite: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
val varargExpression = callSite.getValueArgument(0) as IrVararg val varargExpression = callSite.getValueArgument(0) as IrVararg
val vararg = args.single() 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.used", context.llvm.usedFunctions + context.llvm.usedGlobals)
appendLlvmUsed("llvm.compiler.used", context.llvm.compilerUsedGlobals) appendLlvmUsed("llvm.compiler.used", context.llvm.compilerUsedGlobals)
appendStaticInitializers() appendStaticInitializers()
appendEntryPointSelector(context.ir.symbols.entryPoint?.owner)
if (context.isNativeLibrary) { if (context.isNativeLibrary) {
appendCAdapters() appendCAdapters()
} }
@@ -2336,14 +2335,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
appendingTo(bbNeedInit) { appendingTo(bbNeedInit) {
LLVMBuildStore(builder, kImmOne, initGuard) 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? // TODO: shall we put that into the try block?
context.llvm.staticInitializers.forEach { context.llvm.staticInitializers.forEach {
call(it, emptyList(), Lifetime.IRRELEVANT, call(it, emptyList(), Lifetime.IRRELEVANT,
@@ -212,7 +212,7 @@ internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, origin:
val found = LLVMGetNamedGlobal(context.llvmModule, name) val found = LLVMGetNamedGlobal(context.llvmModule, name)
if (found != null) { if (found != null) {
assert (getGlobalType(found) == type) assert (getGlobalType(found) == type)
assert (LLVMGetInitializer(found) == null) assert (LLVMGetInitializer(found) == null) { "$name is already declared in the current module" }
if (threadLocal) if (threadLocal)
assert(LLVMGetThreadLocalMode(found) == context.llvm.tlsMode) assert(LLVMGetThreadLocalMode(found) == context.llvm.tlsMode)
return found 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 = internal fun StaticData.createInitializer(type: IrClass, vararg fields: ConstValue): ConstValue =
Struct(objHeader(type.typeInfoPtr), *fields) 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. * 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) { override fun visitField(declaration: IrField) {
// TODO: inlining a function returning an object // 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. // That is a bug, most probably.
// We workaround the issue with question marks here. // We workaround the issue with question marks here.
(declaration.descriptor as? WrappedFieldDescriptor)?.bind(declaration) (declaration.descriptor as? WrappedFieldDescriptor)?.bind(declaration)
@@ -136,10 +136,10 @@ internal class EnumUsageLowering(val context: Context)
internal class EnumClassLowering(val context: Context) : ClassLoweringPass { internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
fun run(irFile: IrFile) { fun run(irFile: IrFile) {
runOnFilePostfix(irFile)
// EnumWhenLowering should be performed before EnumUsageLowering because // EnumWhenLowering should be performed before EnumUsageLowering because
// the latter performs lowering of IrGetEnumValue // the latter performs lowering of IrGetEnumValue
EnumWhenLowering(context).lower(irFile) EnumWhenLowering(context).lower(irFile)
runOnFilePostfix(irFile)
EnumUsageLowering(context).lower(irFile) EnumUsageLowering(context).lower(irFile)
} }
@@ -238,7 +238,7 @@ internal class EnumConstructorsLowering(val context: Context) : ClassLoweringPas
override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression { override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression {
val name = enumEntry.name.asString() val name = enumEntry.name.asString()
val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(enumEntry.descriptor) val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(enumEntry)
val startOffset = enumConstructorCall.startOffset val startOffset = enumConstructorCall.startOffset
val endOffset = enumConstructorCall.endOffset 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 && if (lhs is IrValueAccessExpression && lhs.symbol.owner == topmostSubject && rhs is IrGetEnumValue &&
// Both entries should belong to the same class: // Both entries should belong to the same class:
topmostSubject.type.classifierOrNull?.owner == rhs.symbol.owner.parent) { 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 val subjectOrdinal = topmostOrdinalProvider.value
return IrCallImpl(call.startOffset, call.endOffset, areEqualByValue.owner.returnType, areEqualByValue).apply { return IrCallImpl(call.startOffset, call.endOffset, areEqualByValue.owner.returnType, areEqualByValue).apply {
putValueArgument(0, 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.Context
import org.jetbrains.kotlin.backend.konan.ir.KonanIrReturnableBlockImpl import org.jetbrains.kotlin.backend.konan.ir.KonanIrReturnableBlockImpl
import org.jetbrains.kotlin.backend.konan.irasdescriptors.file 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.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.* 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.types.IrType
import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.declarations.* 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.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
@@ -169,6 +175,24 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
else -> error("Unknown ReturnTarget: $this") 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>, private fun performHighLevelJump(tryScopes: List<TryScope>,
index: Int, index: Int,
jump: HighLevelJump, jump: HighLevelJump,
@@ -181,7 +205,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
val currentTryScope = tryScopes[index] val currentTryScope = tryScopes[index]
currentTryScope.jumps.getOrPut(jump) { currentTryScope.jumps.getOrPut(jump) {
val type = (jump as? Return)?.target?.owner?.returnType ?: value.type val type = (jump as? Return)?.target?.owner?.returnType ?: value.type
val symbol = IrReturnableBlockSymbolImpl(WrappedSimpleFunctionDescriptor()) val symbol = IrReturnableBlockSymbolImpl(createSyntheticFunctionDescriptor("\$Finally$index"))
with(currentTryScope) { with(currentTryScope) {
irBuilder.run { irBuilder.run {
val inlinedFinally = irInlineFinally(symbol, type, expression, finallyExpression) val inlinedFinally = irInlineFinally(symbol, type, expression, finallyExpression)
@@ -252,7 +276,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
) )
using(TryScope(syntheticTry, transformedFinallyExpression, this)) { using(TryScope(syntheticTry, transformedFinallyExpression, this)) {
val fallThroughType = aTry.type val fallThroughType = aTry.type
val fallThroughSymbol = IrReturnableBlockSymbolImpl(WrappedSimpleFunctionDescriptor()) val fallThroughSymbol = IrReturnableBlockSymbolImpl(createSyntheticFunctionDescriptor("\$Fallthrough"))
val transformedResult = aTry.tryResult.transform(transformer, null) val transformedResult = aTry.tryResult.transform(transformer, null)
transformedTry.tryResult = irReturn(fallThroughSymbol, transformedResult) transformedTry.tryResult = irReturn(fallThroughSymbol, transformedResult)
for (aCatch in aTry.catches) { for (aCatch in aTry.catches) {
@@ -131,6 +131,9 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
if (descriptor.isInlineConstructor) { 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 val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
irBuilder.run { irBuilder.run {
val constructorDescriptor = delegatingConstructorCall.descriptor.original val constructorDescriptor = delegatingConstructorCall.descriptor.original
@@ -44,6 +44,7 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
} }
private fun createOuterThisField() { private fun createOuterThisField() {
irClass.declarations += context.specialDeclarationsFactory.getOuterThisField(irClass)
outerThisFieldSymbol = context.specialDeclarationsFactory.getOuterThisField(irClass).symbol outerThisFieldSymbol = context.specialDeclarationsFactory.getOuterThisField(irClass).symbol
} }
@@ -628,7 +628,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
descriptor.getExternalObjCMethodInfo()?.let { methodInfo -> descriptor.getExternalObjCMethodInfo()?.let { methodInfo ->
val isInteropStubsFile = 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; // Special case: bridge from Objective-C method implementation template to Kotlin method;
// handled in CodeGeneratorVisitor.callVirtual. // 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.LoggingContext
import org.jetbrains.kotlin.backend.common.ir.ir2string 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.findTopLevelDeclaration
import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember
import org.jetbrains.kotlin.backend.konan.descriptors.isSerializableExpectClass 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.symbols.*
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl 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.CombinedIrFileWriter
import org.jetbrains.kotlin.konan.library.impl.DeclarationId import org.jetbrains.kotlin.konan.library.impl.DeclarationId
import org.jetbrains.kotlin.metadata.KonanIr import org.jetbrains.kotlin.metadata.KonanIr
@@ -1058,6 +1063,7 @@ internal class IrModuleSerializer(
val proto = KonanIr.IrFile.newBuilder() val proto = KonanIr.IrFile.newBuilder()
.setFileEntry(serializeFileEntry(file.fileEntry)) .setFileEntry(serializeFileEntry(file.fileEntry))
.setFqName(serializeString(file.fqName.toString())) .setFqName(serializeString(file.fqName.toString()))
.setAnnotations(serializeAnnotations(file.annotations))
file.declarations.forEach { file.declarations.forEach {
if (it is IrTypeAlias || (it.descriptor.isExpectMember && !it.descriptor.isSerializableExpectClass)) { 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) writer.addDeclaration(DeclarationId(uniqId.index, uniqId.isLocal), byteArray)
proto.addDeclarationId(protoUniqId(uniqId)) 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() return proto.build()
} }
@@ -89,6 +89,8 @@ message IrFile {
repeated UniqId declaration_id = 1; repeated UniqId declaration_id = 1;
required FileEntry file_entry = 2; required FileEntry file_entry = 2;
required String fq_name = 3; 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 { 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( val fileEntry = NaiveSourceBasedFileEntryImpl(
deserializeString(fileProto.fileEntry.name), deserializeString(fileProto.fileEntry.name),
fileProto.fileEntry.lineStartOffsetsList.toIntArray() fileProto.fileEntry.lineStartOffsetsList.toIntArray()
@@ -327,15 +327,22 @@ class KonanIrModuleDeserializer(
val uniqIdKey = it.uniqIdKey(moduleDescriptor) val uniqIdKey = it.uniqIdKey(moduleDescriptor)
reversedFileIndex.put(uniqIdKey, file) reversedFileIndex.put(uniqIdKey, file)
if (deserializeAllDeclarations) { if (deseralizationStrategy == DeserializationStrategy.ALL) {
file.declarations.add(deserializeTopLevelDeclaration(uniqIdKey)) 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 return file
} }
fun deserializeIrModule(proto: KonanIr.IrModule, moduleDescriptor: ModuleDescriptor, deserializeAllDeclarations: Boolean): IrModuleFragment { fun deserializeIrModuleHeader(proto: KonanIr.IrModule, moduleDescriptor: ModuleDescriptor, deserializationStrategy: DeserializationStrategy): IrModuleFragment {
deserializedModuleDescriptor = moduleDescriptor deserializedModuleDescriptor = moduleDescriptor
deserializedModuleProtoSymbolTables.put(moduleDescriptor, proto.symbolTable) deserializedModuleProtoSymbolTables.put(moduleDescriptor, proto.symbolTable)
@@ -343,7 +350,7 @@ class KonanIrModuleDeserializer(
deserializedModuleProtoTypeTables.put(moduleDescriptor, proto.typeTable) deserializedModuleProtoTypeTables.put(moduleDescriptor, proto.typeTable)
val files = proto.fileList.map { val files = proto.fileList.map {
deserializeIrFile(it, moduleDescriptor, deserializeAllDeclarations) deserializeIrFile(it, moduleDescriptor, deserializationStrategy)
} }
val module = IrModuleFragmentImpl(moduleDescriptor, builtIns, files) val module = IrModuleFragmentImpl(moduleDescriptor, builtIns, files)
@@ -351,8 +358,14 @@ class KonanIrModuleDeserializer(
return module 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) 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) { override fun serializeEnumEntry(descriptor: ClassDescriptor, proto: ProtoBuf.EnumEntry.Builder) {
uniqId(descriptor) ?.let { proto.setExtension(KonanProtoBuf.enumEntryUniqId, it) } uniqId(descriptor) ?.let { proto.setExtension(KonanProtoBuf.enumEntryUniqId, it) }
// Serialization doesn't preserve enum entry order, so we need to serialize ordinal. // 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) super.serializeEnumEntry(descriptor, proto)
} }
-5
View File
@@ -340,7 +340,6 @@ targetList.each { target ->
task("${target}CrossDistRuntime", type: Copy) { task("${target}CrossDistRuntime", type: Copy) {
dependsOn ":runtime:${target}Runtime" dependsOn ":runtime:${target}Runtime"
dependsOn ":backend.native:${target}Stdlib" dependsOn ":backend.native:${target}Stdlib"
dependsOn ":backend.native:${target}Start"
destinationDir distDir destinationDir distDir
@@ -357,10 +356,6 @@ targetList.each { target ->
include('**') include('**')
into(stdlib) into(stdlib)
} }
from(project(':runtime').file("build/${target}Start.bc")) {
rename("${target}Start.bc", 'start.bc')
into("konan/targets/$target/native")
}
if (target == 'wasm32') { if (target == 'wasm32') {
into("$stdlib/targets/wasm32/included") { into("$stdlib/targets/wasm32/included") {
from(project(':runtime').file('src/main/js')) from(project(':runtime').file('src/main/js'))
+5 -3
View File
@@ -4,16 +4,18 @@
*/ */
import kotlin.native.internal.ExportForCppRuntime import kotlin.native.internal.ExportForCppRuntime
import kotlin.native.internal.TypedIntrinsic
import kotlin.native.internal.IntrinsicType
// This function is produced by the code generator given // This function is produced by the code generator given
// the '-entry foo.bar.main' flag. // the '-entry foo.bar.main' flag.
// It calls the requested entry point. // It calls the requested entry point.
// The default is main(Array<String>):Unit in the root package. // The default is main(Array<String>):Unit in the root package.
@SymbolName("EntryPointSelector") @TypedIntrinsic(IntrinsicType.SELECT_ENTRY_POINT)
external fun EntryPointSelector(args: Array<String>) private external fun EntryPointSelector(args: Array<String>)
@SymbolName("OnUnhandledException") @SymbolName("OnUnhandledException")
external private fun OnUnhandledException(throwable: Throwable) private external fun OnUnhandledException(throwable: Throwable)
@ExportForCppRuntime @ExportForCppRuntime
private fun Konan_start(args: Array<String>): Int { 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 ReportUnhandledException(KRef throwable);
extern "C" void ExceptionReporterLaunchpad(KRef reporter, KRef throwable); extern "C" void ExceptionReporterLaunchpad(KRef reporter, KRef throwable);
@@ -52,6 +52,7 @@ class IntrinsicType {
const val IDENTITY = "IDENTITY" const val IDENTITY = "IDENTITY"
const val IMMUTABLE_BLOB = "IMMUTABLE_BLOB" const val IMMUTABLE_BLOB = "IMMUTABLE_BLOB"
const val INIT_INSTANCE = "INIT_INSTANCE" const val INIT_INSTANCE = "INIT_INSTANCE"
const val SELECT_ENTRY_POINT = "SELECT_ENTRY_POINT"
const val GET_CONTINUATION = "GET_CONTINUATION" const val GET_CONTINUATION = "GET_CONTINUATION"
const val RETURN_IF_SUSPEND = "RETURN_IF_SUSPEND" 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" 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 val dependenciesDir = DependencyProcessor.defaultDependenciesRoot.absolutePath