K/N: Rename "kotlin-native-serializer" to "kotlin-native-library-reader"

This commit is contained in:
Dmitriy Dolovov
2018-09-07 12:55:17 +03:00
committed by Mikhail Glukhikh
parent 6701dbb220
commit cb7009ace8
48 changed files with 73 additions and 73 deletions
+97
View File
@@ -0,0 +1,97 @@
/*
* 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/LICENSE.txt file.
*/
syntax = "proto2";
package org.jetbrains.kotlin.metadata.konan;
import "core/metadata/src/metadata.proto";
option java_outer_classname = "KonanProtoBuf";
option optimize_for = LITE_RUNTIME;
// Konan extensions to the "descriptors" protobuf.
extend Package {
optional int32 package_fq_name = 171;
}
extend Class {
repeated Annotation class_annotation = 170;
}
extend Constructor {
repeated Annotation constructor_annotation = 170;
optional InlineIrBody inline_constructor_ir_body = 171;
}
extend Function {
repeated Annotation function_annotation = 170;
optional InlineIrBody inline_ir_body = 171;
}
extend Property {
repeated Annotation property_annotation = 170;
optional bool has_backing_field = 171;
optional bool used_as_variable = 172;
optional Annotation.Argument.Value compile_time_value = 173;
optional InlineIrBody inline_getter_ir_body = 174;
optional InlineIrBody inline_setter_ir_body = 175;
}
extend EnumEntry {
repeated Annotation enum_entry_annotation = 170;
optional int32 enum_entry_ordinal = 171;
}
extend ValueParameter {
repeated Annotation parameter_annotation = 170;
}
extend Type {
repeated Annotation type_annotation = 170;
optional string type_text = 172; // TODO: remove me
}
extend TypeParameter {
repeated Annotation type_parameter_annotation = 170;
}
message InlineIrBody {
// We need to refer from descriptors to ir inline body.
// And in ir we need to refer local declaration descriptors
// That requires mutual import of KonanIr and KonanLinkData.
// I break the circle here by storing encoded IR.
// May be we need to merge KonanIr into KonanLinkData.
// That'd allow mutually recursive messages.
required string encoded_ir = 11;
}
// Konan Binary Linkdata structures.
message LinkDataPackageFragment {
// Make if an index?
required string fq_name = 1;
required Package package = 4;
required LinkDataClasses classes = 5;
required bool is_empty = 6;
// To construct name resolver
required QualifiedNameTable name_table = 2;
required StringTable string_table = 3;
}
message LinkDataClasses {
// Index in the QualifiedNameIndex table.
repeated int32 class_name = 1;
repeated Class classes = 2;
}
message LinkDataLibrary {
required string module_name = 1;
repeated string package_fragment_name = 2;
repeated string empty_package = 3;
}
@@ -0,0 +1,16 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.builtins.konan
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.storage.StorageManager
class KonanBuiltIns(storageManager: StorageManager) : KotlinBuiltIns(storageManager) {
override fun getSuspendFunction(parameterCount: Int) =
getBuiltInClassByName(Name.identifier("SuspendFunction$parameterCount"))
}
@@ -0,0 +1,148 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.cli.common.arguments.konan
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.Argument
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.AnalysisFlag
class K2NativeCompilerArguments : CommonCompilerArguments() {
// First go the options interesting to the general public.
// Prepend them with a single dash.
// Keep the list lexically sorted.
@Argument(value = "-enable_assertions", shortName = "-ea", description = "Enable runtime assertions in generated code")
var enableAssertions: Boolean = false
@Argument(value = "-g", description = "Enable emitting debug information")
var debug: Boolean = false
@Argument(value = "-generate_test_runner", shortName = "-tr", description = "Produce a runner for unit tests")
var generateTestRunner: Boolean = false
@Argument(value = "-includeBinary", shortName = "-ib", valueDescription = "<path>", description = "Pack external binary within the klib")
var includeBinaries: Array<String>? = null
@Argument(value = "-library", shortName = "-l", valueDescription = "<path>", description = "Link with the library")
var libraries: Array<String>? = null
@Argument(value = "-list_targets", description = "List available hardware targets")
var listTargets: Boolean = false
@Argument(value = "-manifest", valueDescription = "<path>", description = "Provide a maniferst addend file")
var manifestFile: String? = null
@Argument(value = "-module_name", valueDescription = "<name>", description = "Spicify a name for the compilation module")
var moduleName: String? = null
@Argument(value = "-nativelibrary", shortName = "-nl", valueDescription = "<path>", description = "Include the native bitcode library")
var nativeLibraries: Array<String>? = null
@Argument(value = "-nodefaultlibs", description = "Don't link the libraries from dist/klib automatically")
var nodefaultlibs: Boolean = false
@Argument(value = "-nomain", description = "Assume 'main' entry point to be provided by external libraries")
var nomain: Boolean = false
@Argument(value = "-nopack", description = "Don't pack the library into a klib file")
var nopack: Boolean = false
@Argument(value = "-linkerOpts", valueDescription = "<arg>", description = "Pass arguments to linker", delimiter = " ")
var linkerArguments: Array<String>? = null
@Argument(value = "-nostdlib", description = "Don't link with stdlib")
var nostdlib: Boolean = false
@Argument(value = "-opt", description = "Enable optimizations during compilation")
var optimization: Boolean = false
@Argument(value = "-output", shortName = "-o", valueDescription = "<name>", description = "Output name")
var outputName: String? = null
@Argument(value = "-entry", shortName = "-e", valueDescription = "<name>", description = "Qualified entry point name")
var mainPackage: String? = null
@Argument(value = "-produce", shortName = "-p",
valueDescription = "{program|static|dynamic|framework|library|bitcode}",
description = "Specify output file kind")
var produce: String? = null
@Argument(value = "-repo", shortName = "-r", valueDescription = "<path>", description = "Library search path")
var repositories: Array<String>? = null
@Argument(value = "-target", valueDescription = "<target>", description = "Set hardware target")
var target: String? = null
// The rest of the options are only interesting to the developers.
// Make sure to prepend them with a double dash.
// Keep the list lexically sorted.
@Argument(value = "--check_dependencies", description = "Check dependencies and download the missing ones")
var checkDependencies: Boolean = false
@Argument(value = "--disable", valueDescription = "<Phase>", description = "Disable backend phase")
var disablePhases: Array<String>? = null
@Argument(value = "--enable", valueDescription = "<Phase>", description = "Enable backend phase")
var enablePhases: Array<String>? = null
@Argument(value = "--list_phases", description = "List all backend phases")
var listPhases: Boolean = false
@Argument(value = "--print_bitcode", description = "Print llvm bitcode")
var printBitCode: Boolean = false
@Argument(value = "--print_descriptors", description = "Print descriptor tree")
var printDescriptors: Boolean = false
@Argument(value = "--print_ir", description = "Print IR")
var printIr: Boolean = false
@Argument(value = "--print_ir_with_descriptors", description = "Print IR with descriptors")
var printIrWithDescriptors: Boolean = false
@Argument(value = "--print_locations", description = "Print locations")
var printLocations: Boolean = false
@Argument(value = "--purge_user_libs", description = "Don't link unused libraries even explicitly specified")
var purgeUserLibs: Boolean = false
@Argument(value = "--runtime", valueDescription = "<path>", description = "Override standard 'runtime.bc' location")
var runtimeFile: String? = null
@Argument(value = "--temporary_files_dir", valueDescription = "<path>", description = "Save temporary files to the given directory")
var temporaryFilesDir: String? = null
@Argument(value = "--time", description = "Report execution time for compiler phases")
var timePhases: Boolean = false
@Argument(value = "--verbose", valueDescription = "<Phase>", description = "Trace phase execution")
var verbosePhases: Array<String>? = null
@Argument(value = "--verify_bitcode", description = "Verify llvm bitcode after each method")
var verifyBitCode: Boolean = false
@Argument(value = "--verify_descriptors", description = "Verify descriptor tree")
var verifyDescriptors: Boolean = false
@Argument(value = "--verify_ir", description = "Verify IR")
var verifyIr: Boolean = false
@Argument(
value = "-friend-modules",
valueDescription = "<path>",
description = "Paths to friend modules"
)
var friendModules: String? = null
override fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> =
super.configureAnalysisFlags(collector).also {
val useExperimental = it[AnalysisFlag.useExperimental] as List<*>
it[AnalysisFlag.useExperimental] = useExperimental + listOf("kotlin.ExperimentalUnsignedTypes")
}
}
@@ -0,0 +1,37 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.konan
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.storage.StorageManager
interface KonanModuleDescriptorFactory {
/**
* Base method for creation of any Kotlin/Native [ModuleDescriptor].
*/
fun createDescriptor(
name: Name,
storageManager: StorageManager,
builtIns: KotlinBuiltIns,
origin: KonanModuleOrigin,
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?> = emptyMap()
): ModuleDescriptorImpl
/**
* Please use this method with care: As far as it creates an instance of [KotlinBuiltIns] it should be
* normally used for creation of the very first (e.g. "stdlib") module in the set of created modules.
*/
fun createDescriptorAndNewBuiltIns(
name: Name,
storageManager: StorageManager,
origin: KonanModuleOrigin,
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?> = emptyMap()
): ModuleDescriptorImpl
}
@@ -0,0 +1,14 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.konan
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
import org.jetbrains.kotlin.name.Name
private val STDLIB_MODULE_NAME = Name.special("<$KONAN_STDLIB_NAME>")
fun ModuleDescriptor.isKonanStdlib() = name == STDLIB_MODULE_NAME
@@ -0,0 +1,32 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.konan
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.isInterop
sealed class KonanModuleOrigin {
companion object {
val CAPABILITY = ModuleDescriptor.Capability<KonanModuleOrigin>("KonanModuleOrigin")
}
}
sealed class CompiledKonanModuleOrigin: KonanModuleOrigin()
class DeserializedKonanModuleOrigin(val library: KonanLibrary) : CompiledKonanModuleOrigin()
object CurrentKonanModuleOrigin: CompiledKonanModuleOrigin()
object SyntheticModulesOrigin : KonanModuleOrigin()
internal fun KonanModuleOrigin.isInteropLibrary(): Boolean = when (this) {
is DeserializedKonanModuleOrigin -> this.library.isInterop
CurrentKonanModuleOrigin, SyntheticModulesOrigin -> false
}
val ModuleDescriptor.konanModuleOrigin get() = this.getCapability(KonanModuleOrigin.CAPABILITY)!!
@@ -0,0 +1,51 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.konan.impl
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.descriptors.konan.KonanModuleDescriptorFactory
import org.jetbrains.kotlin.descriptors.konan.KonanModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.isInteropLibrary
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.ImplicitIntegerCoercion
import org.jetbrains.kotlin.storage.StorageManager
internal object KonanModuleDescriptorFactoryImpl : KonanModuleDescriptorFactory {
override fun createDescriptor(
name: Name,
storageManager: StorageManager,
builtIns: KotlinBuiltIns,
origin: KonanModuleOrigin,
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?>
) = ModuleDescriptorImpl(
name,
storageManager,
builtIns,
capabilities = customCapabilities + mapOf(
KonanModuleOrigin.CAPABILITY to origin,
ImplicitIntegerCoercion.MODULE_CAPABILITY to origin.isInteropLibrary()
)
)
override fun createDescriptorAndNewBuiltIns(
name: Name,
storageManager: StorageManager,
origin: KonanModuleOrigin,
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?>
): ModuleDescriptorImpl {
val builtIns = KonanBuiltIns(storageManager)
val moduleDescriptor = createDescriptor(name, storageManager, builtIns, origin, customCapabilities)
builtIns.builtInsModule = moduleDescriptor
return moduleDescriptor
}
}
@@ -0,0 +1,205 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.file
import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader
import java.nio.file.*
import java.nio.file.attribute.BasicFileAttributes
data class File constructor(internal val javaPath: Path) {
constructor(parent: Path, child: String) : this(parent.resolve(child))
constructor(parent: File, child: String) : this(parent.javaPath.resolve(child))
constructor(path: String) : this(Paths.get(path))
constructor(parent: String, child: String) : this(Paths.get(parent, child))
val path: String
get() = javaPath.toString()
val absolutePath: String
get() = javaPath.toAbsolutePath().toString()
val absoluteFile: File
get() = File(absolutePath)
val name: String
get() = javaPath.fileName.toString()
val extension: String
get() = name.substringAfterLast('.', "")
val parent: String
get() = javaPath.parent.toString()
val parentFile: File
get() = File(javaPath.parent)
val exists
get() = Files.exists(javaPath)
val isDirectory
get() = Files.isDirectory(javaPath)
val isFile
get() = Files.isRegularFile(javaPath)
val isAbsolute
get() = javaPath.isAbsolute()
val listFiles: List<File>
get() = Files.newDirectoryStream(javaPath).use { stream -> stream.map { File(it) } }
val listFilesOrEmpty: List<File>
get() = if (exists) listFiles else emptyList()
fun child(name: String) = File(this, name)
fun copyTo(destination: File) {
Files.copy(javaPath, destination.javaPath, StandardCopyOption.REPLACE_EXISTING)
}
fun recursiveCopyTo(destination: File) {
val sourcePath = javaPath
val destPath = destination.javaPath
sourcePath.recursiveCopyTo(destPath)
}
fun mkdirs() = Files.createDirectories(javaPath)
fun delete() = Files.deleteIfExists(javaPath)
fun deleteRecursively() = postorder { Files.delete(it) }
fun deleteOnExitRecursively() = preorder { File(it).deleteOnExit() }
fun preorder(task: (Path) -> Unit) {
if (!this.exists) return
Files.walkFileTree(javaPath, object : SimpleFileVisitor<Path>() {
override fun visitFile(file: Path?, attrs: BasicFileAttributes?): FileVisitResult {
task(file!!)
return FileVisitResult.CONTINUE
}
override fun preVisitDirectory(dir: Path?, attrs: BasicFileAttributes?): FileVisitResult {
task(dir!!)
return FileVisitResult.CONTINUE
}
})
}
fun postorder(task: (Path) -> Unit) {
if (!this.exists) return
Files.walkFileTree(javaPath, object : SimpleFileVisitor<Path>() {
override fun visitFile(file: Path?, attrs: BasicFileAttributes?): FileVisitResult {
task(file!!)
return FileVisitResult.CONTINUE
}
override fun postVisitDirectory(dir: Path?, exc: java.io.IOException?): FileVisitResult {
task(dir!!)
return FileVisitResult.CONTINUE
}
})
}
fun deleteOnExit(): File {
// Works only on the default file system,
// but that's okay for now.
javaPath.toFile().deleteOnExit()
return this // Allow streaming.
}
fun readBytes() = Files.readAllBytes(javaPath)
fun writeBytes(bytes: ByteArray) = Files.write(javaPath, bytes)
fun appendBytes(bytes: ByteArray) = Files.write(javaPath, bytes, StandardOpenOption.APPEND)
fun writeLines(lines: Iterable<String>) {
Files.write(javaPath, lines)
}
fun writeText(text: String): Unit = writeLines(listOf(text))
fun forEachLine(action: (String) -> Unit) {
Files.lines(javaPath).use { lines ->
lines.forEach { action(it) }
}
}
fun createAsSymlink(target: String) {
val targetPath = Paths.get(target)
if (Files.isSymbolicLink(this.javaPath) && Files.readSymbolicLink(javaPath) == targetPath) {
return
}
Files.createSymbolicLink(this.javaPath, targetPath)
}
override fun toString() = path
// TODO: Consider removeing these after konanazing java.util.Properties.
fun bufferedReader() = Files.newBufferedReader(javaPath)
fun outputStream() = Files.newOutputStream(javaPath)
fun printWriter() = javaPath.toFile().printWriter()
companion object {
val userDir
get() = File(System.getProperty("user.dir"))
val userHome
get() = File(System.getProperty("user.home"))
val javaHome
get() = File(System.getProperty("java.home"))
val pathSeparator = java.io.File.pathSeparator
}
fun readStrings() = mutableListOf<String>().also { list -> forEachLine { list.add(it) } }
override fun equals(other: Any?): Boolean {
val otherFile = other as? File ?: return false
return otherFile.javaPath.toAbsolutePath() == javaPath.toAbsolutePath()
}
override fun hashCode() = javaPath.toAbsolutePath().hashCode()
}
fun String.File(): File = File(this)
fun Path.File(): File = File(this)
fun createTempFile(name: String, suffix: String? = null) = Files.createTempFile(name, suffix).File()
fun createTempDir(name: String): File = Files.createTempDirectory(name).File()
fun Path.recursiveCopyTo(destPath: Path) {
val sourcePath = this
Files.walk(sourcePath).forEach next@{ oldPath ->
val relative = sourcePath.relativize(oldPath)
val destFs = destPath.getFileSystem()
// We are copying files between file systems,
// so pass the relative path through the String.
val newPath = destFs.getPath(destPath.toString(), relative.toString())
// File systems don't allow replacing an existing root.
if (newPath == newPath.getRoot()) return@next
if (Files.isDirectory(newPath)) {
Files.createDirectories(newPath)
} else {
Files.copy(oldPath, newPath, StandardCopyOption.REPLACE_EXISTING)
}
}
}
fun bufferedReader(errorStream: InputStream?) = BufferedReader(InputStreamReader(errorStream))
// stdlib `use` function adapted for AutoCloseable.
inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R {
var closed = false
try {
return block(this)
} catch (e: Exception) {
closed = true
try {
this?.close()
} catch (closeException: Exception) {
}
throw e
} finally {
if (!closed) {
this?.close()
}
}
}
@@ -0,0 +1,55 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.file
import java.net.URI
import java.nio.file.*
private val File.zipUri: URI
get() = URI.create("jar:${this.toPath().toUri()}")
fun File.zipFileSystem(mutable: Boolean = false): FileSystem {
val zipUri = this.zipUri
val attributes = hashMapOf("create" to mutable.toString())
return try {
FileSystems.newFileSystem(zipUri, attributes, null)
} catch (e: FileSystemAlreadyExistsException) {
FileSystems.getFileSystem(zipUri)
}
}
fun FileSystem.file(file: File) = File(this.getPath(file.path))
fun FileSystem.file(path: String) = File(this.getPath(path))
private fun File.toPath() = Paths.get(this.path)
fun File.zipDirAs(unixFile: File) {
unixFile.withMutableZipFileSystem {
this.recursiveCopyTo(it.file("/"))
}
}
fun Path.unzipTo(directory: Path) {
val zipUri = URI.create("jar:" + this.toUri())
FileSystems.newFileSystem(zipUri, emptyMap<String, Any?>(), null).use { zipfs ->
val zipPath = zipfs.getPath("/")
zipPath.recursiveCopyTo(directory)
}
}
fun <T> File.withZipFileSystem(mutable: Boolean = false, action: (FileSystem) -> T): T {
val zipFileSystem = this.zipFileSystem(mutable)
return try {
action(zipFileSystem)
} finally {
zipFileSystem.close()
}
}
fun <T> File.withZipFileSystem(action: (FileSystem) -> T): T = this.withZipFileSystem(false, action)
fun <T> File.withMutableZipFileSystem(action: (FileSystem) -> T): T = this.withZipFileSystem(true, action)
@@ -0,0 +1,70 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.library
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.properties.Properties
import org.jetbrains.kotlin.konan.properties.propertyList
import org.jetbrains.kotlin.name.FqName
const val KLIB_PROPERTY_ABI_VERSION = "abi_version"
const val KLIB_PROPERTY_UNIQUE_NAME = "unique_name"
const val KLIB_PROPERTY_LINKED_OPTS = "linkerOpts"
const val KLIB_PROPERTY_DEPENDS = "depends"
const val KLIB_PROPERTY_INTEROP = "interop"
const val KLIB_PROPERTY_PACKAGE = "package"
const val KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS = "exportForwardDeclarations"
const val KLIB_PROPERTY_INCLUDED_HEADERS = "includedHeaders"
/**
* An abstraction for getting access to the information stored inside of Kotlin/Native library.
*/
interface KonanLibrary {
val libraryName: String
val libraryFile: File
// Whether this library is default (provided by Kotlin/Native distribution)?
val isDefault: Boolean
// Properties:
val manifestProperties: Properties
val abiVersion: String
val linkerOpts: List<String>
// Paths:
val bitcodePaths: List<String>
val includedPaths: List<String>
val targetList: List<String>
val dataFlowGraph: ByteArray?
val moduleHeaderData: ByteArray
fun packageMetadata(fqName: String): ByteArray
}
val KonanLibrary.uniqueName
get() = manifestProperties.getProperty(KLIB_PROPERTY_UNIQUE_NAME)!!
val KonanLibrary.unresolvedDependencies: List<String>
get() = manifestProperties.propertyList(KLIB_PROPERTY_DEPENDS)
val KonanLibrary.isInterop
get() = manifestProperties.getProperty(KLIB_PROPERTY_INTEROP) == "true"
val KonanLibrary.packageFqName
get() = manifestProperties.getProperty(KLIB_PROPERTY_PACKAGE)?.let { FqName(it) }
val KonanLibrary.exportForwardDeclarations
get() = manifestProperties.getProperty(KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS)
.split(' ').asSequence()
.map { it.trim() }
.filter { it.isNotEmpty() }
.map { FqName(it) }
.toList()
val KonanLibrary.includedHeaders
get() = manifestProperties.getProperty(KLIB_PROPERTY_INCLUDED_HEADERS).split(' ')
@@ -0,0 +1,29 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.library
import java.nio.file.Path
import java.nio.file.Paths
const val KLIB_FILE_EXTENSION = "klib"
const val KLIB_FILE_EXTENSION_WITH_DOT = ".$KLIB_FILE_EXTENSION"
const val KLIB_METADATA_FILE_EXTENSION = "knm"
const val KLIB_METADATA_FILE_EXTENSION_WITH_DOT = ".$KLIB_METADATA_FILE_EXTENSION"
const val KONAN_STDLIB_NAME = "stdlib"
val KONAN_COMMON_LIBS_PATH: Path
get() = Paths.get("klib", "common")
val KONAN_ALL_PLATFORM_LIBS_PATH: Path
get() = Paths.get("klib", "platform")
fun konanCommonLibraryPath(libraryName: String): Path = KONAN_COMMON_LIBS_PATH.resolve(libraryName)
fun konanSpecificPlatformLibrariesPath(platform: String): Path = KONAN_ALL_PLATFORM_LIBS_PATH.resolve(platform)
fun konanPlatformLibraryPath(platform: String, libraryName: String): Path = konanSpecificPlatformLibrariesPath(platform).resolve(libraryName)
@@ -0,0 +1,48 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.library
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.target.KonanTarget
/**
* This scheme describes the Kotlin/Native Library (KLIB) layout.
*/
interface KonanLibraryLayout {
val libraryName: String
val libDir: File
val target: KonanTarget?
// This is a default implementation. Can't make it an assignment.
get() = null
val manifestFile
get() = File(libDir, "manifest")
val resourcesDir
get() = File(libDir, "resources")
val targetsDir
get() = File(libDir, "targets")
val targetDir
get() = File(targetsDir, target!!.visibleName)
val kotlinDir
get() = File(targetDir, "kotlin")
val nativeDir
get() = File(targetDir, "native")
val includedDir
get() = File(targetDir, "included")
val linkdataDir
get() = File(libDir, "linkdata")
val moduleHeaderFile
get() = File(linkdataDir, "module")
val dataFlowGraphFile
get() = File(linkdataDir, "module_data_flow_graph")
fun packageFile(packageName: String) = File(linkdataDir, if (packageName == "") "root_package.knm" else "package_$packageName.knm")
}
@@ -0,0 +1,45 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.library
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.file.file
import org.jetbrains.kotlin.konan.file.withMutableZipFileSystem
import org.jetbrains.kotlin.konan.library.impl.DefaultMetadataReaderImpl
import org.jetbrains.kotlin.konan.library.impl.KonanLibraryImpl
import org.jetbrains.kotlin.konan.library.impl.zippedKonanLibraryChecks
import org.jetbrains.kotlin.konan.library.resolver.KonanLibraryResolver
import org.jetbrains.kotlin.konan.library.resolver.impl.KonanLibraryResolverImpl
import org.jetbrains.kotlin.konan.target.KonanTarget
fun File.unpackZippedKonanLibraryTo(newDir: File) {
// First, run validity checks for the given KLIB file.
zippedKonanLibraryChecks(this)
if (newDir.exists) {
if (newDir.isDirectory)
newDir.deleteRecursively()
else
newDir.delete()
}
this.withMutableZipFileSystem {
it.file("/").recursiveCopyTo(newDir)
}
check(newDir.exists) { "Could not unpack $this as $newDir." }
}
fun createKonanLibrary(
libraryFile: File,
currentAbiVersion: Int,
target: KonanTarget? = null,
isDefault: Boolean = false,
metadataReader: MetadataReader = DefaultMetadataReaderImpl
): KonanLibrary = KonanLibraryImpl(libraryFile, currentAbiVersion, target, isDefault, metadataReader)
fun SearchPathResolverWithTarget.libraryResolver(abiVersion: Int): KonanLibraryResolver =
KonanLibraryResolverImpl(this, abiVersion)
@@ -0,0 +1,11 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.library
interface MetadataReader {
fun loadSerializedModule(libraryLayout: KonanLibraryLayout): ByteArray
fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String): ByteArray
}
@@ -0,0 +1,19 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.library
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.target.KonanTarget
interface SearchPathResolver {
val searchRoots: List<File>
fun resolve(givenPath: String): File
fun defaultLinks(noStdLib: Boolean, noDefaultLibs: Boolean): List<File>
}
interface SearchPathResolverWithTarget : SearchPathResolver {
val target: KonanTarget
}
@@ -0,0 +1,18 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.library.impl
import org.jetbrains.kotlin.konan.library.KonanLibraryLayout
import org.jetbrains.kotlin.konan.library.MetadataReader
internal object DefaultMetadataReaderImpl : MetadataReader {
override fun loadSerializedModule(libraryLayout: KonanLibraryLayout): ByteArray =
libraryLayout.moduleHeaderFile.readBytes()
override fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String): ByteArray =
libraryLayout.packageFile(fqName).readBytes()
}
@@ -0,0 +1,67 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.library.impl
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.library.*
import org.jetbrains.kotlin.konan.properties.Properties
import org.jetbrains.kotlin.konan.properties.loadProperties
import org.jetbrains.kotlin.konan.properties.propertyList
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.util.defaultTargetSubstitutions
import org.jetbrains.kotlin.konan.util.substitute
internal class KonanLibraryImpl(
override val libraryFile: File,
private val currentAbiVersion: Int,
internal val target: KonanTarget?,
override val isDefault: Boolean,
private val metadataReader: MetadataReader
) : KonanLibrary {
// For the zipped libraries inPlace gives files from zip file system
// whereas realFiles extracts them to /tmp.
// For unzipped libraries inPlace and realFiles are the same
// providing files in the library directory.
private val layout = createKonanLibraryLayout(libraryFile, target)
override val libraryName: String by lazy { layout.inPlace { it.libraryName } }
override val manifestProperties: Properties by lazy {
val properties = layout.inPlace { it.manifestFile.loadProperties() }
if (target != null) substitute(properties, defaultTargetSubstitutions(target))
properties
}
override val abiVersion: String
get() {
val manifestAbiVersion = manifestProperties.getProperty(KLIB_PROPERTY_ABI_VERSION)
check(currentAbiVersion.toString() == manifestAbiVersion) {
"ABI version mismatch. Compiler expects: $currentAbiVersion, the library is $manifestAbiVersion"
}
return manifestAbiVersion
}
override val linkerOpts: List<String>
get() = manifestProperties.propertyList(KLIB_PROPERTY_LINKED_OPTS, target!!.visibleName)
override val bitcodePaths: List<String>
get() = layout.realFiles { (it.kotlinDir.listFilesOrEmpty + it.nativeDir.listFilesOrEmpty).map { it.absolutePath } }
override val includedPaths: List<String>
get() = layout.realFiles { it.includedDir.listFilesOrEmpty.map { it.absolutePath } }
override val targetList by lazy { layout.inPlace { it.targetsDir.listFiles.map { it.name } } }
override val dataFlowGraph by lazy { layout.inPlace { it.dataFlowGraphFile.let { if (it.exists) it.readBytes() else null } } }
override val moduleHeaderData: ByteArray by lazy { layout.inPlace { metadataReader.loadSerializedModule(it) } }
override fun packageMetadata(fqName: String) = layout.inPlace { metadataReader.loadSerializedPackageFragment(it, fqName) }
override fun toString() = "$libraryName[default=$isDefault]"
}
@@ -0,0 +1,96 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.library.impl
import org.jetbrains.kotlin.konan.file.*
import org.jetbrains.kotlin.konan.library.KLIB_FILE_EXTENSION
import org.jetbrains.kotlin.konan.library.KLIB_FILE_EXTENSION_WITH_DOT
import org.jetbrains.kotlin.konan.library.KonanLibraryLayout
import org.jetbrains.kotlin.konan.target.KonanTarget
import java.nio.file.FileSystem
interface KonanLibraryLayoutImpl : KonanLibraryLayout {
fun <T> inPlace(action: (KonanLibraryLayout) -> T): T
fun <T> realFiles(action: (KonanLibraryLayout) -> T): T
}
private class ZippedKonanLibraryLayout(val klibFile: File, override val target: KonanTarget?) : KonanLibraryLayoutImpl {
init {
zippedKonanLibraryChecks(klibFile)
}
override val libraryName = klibFile.path.removeSuffix(KLIB_FILE_EXTENSION_WITH_DOT)
override val libDir: File = File("/")
override fun <T> realFiles(action: (KonanLibraryLayout) -> T): T {
return action(FileExtractor(this))!!
}
override fun <T> inPlace(action: (KonanLibraryLayout) -> T): T {
return klibFile.withZipFileSystem { zipFileSystem ->
action(DirectFromZip(this, zipFileSystem))
}
}
}
internal fun zippedKonanLibraryChecks(klibFile: File) {
check(klibFile.exists) { "Could not find $klibFile." }
check(klibFile.isFile) { "Expected $klibFile to be a regular file." }
val extension = klibFile.extension
check(extension.isEmpty() || extension == KLIB_FILE_EXTENSION) { "Unexpected file extension: $extension" }
}
private class UnzippedKonanLibraryLayout(override val libDir: File, override val target: KonanTarget?) : KonanLibraryLayoutImpl {
override val libraryName = libDir.path
override fun <T> inPlace(action: (KonanLibraryLayout) -> T): T = action(this)
override fun <T> realFiles(action: (KonanLibraryLayout) -> T): T = inPlace(action)
}
private class DirectFromZip(zippedLayout: ZippedKonanLibraryLayout, val zipFileSystem: FileSystem) : KonanLibraryLayout {
override val libraryName = zippedLayout.libraryName
override val libDir = zipFileSystem.file(zippedLayout.libDir)
}
/**
* This class automatically extracts pieces of the library on first access. Use it if you need
* to pass extracted files to an external tool. Otherwise, stick to [DirectFromZip].
*/
private class FileExtractor(val zippedLibraryLayout: ZippedKonanLibraryLayout) : KonanLibraryLayout by zippedLibraryLayout {
override val manifestFile: File by lazy { extract(super.manifestFile) }
override val resourcesDir: File by lazy { extractDir(super.resourcesDir) }
override val includedDir: File by lazy { extractDir(super.includedDir) }
override val kotlinDir: File by lazy { extractDir(super.kotlinDir) }
override val nativeDir: File by lazy { extractDir(super.nativeDir) }
override val linkdataDir: File by lazy { extractDir(super.linkdataDir) }
fun extract(file: File): File = zippedLibraryLayout.klibFile.withZipFileSystem { zipFileSystem ->
val temporary = createTempFile(file.name)
zipFileSystem.file(file).copyTo(temporary)
temporary.deleteOnExit()
temporary
}
fun extractDir(directory: File): File = zippedLibraryLayout.klibFile.withZipFileSystem { zipFileSystem ->
val temporary = createTempDir(directory.name)
zipFileSystem.file(directory).recursiveCopyTo(temporary)
temporary.deleteOnExitRecursively()
temporary
}
}
internal fun createKonanLibraryLayout(klib: File, target: KonanTarget? = null) =
if (klib.isFile) ZippedKonanLibraryLayout(klib, target) else UnzippedKonanLibraryLayout(klib, target)
@@ -0,0 +1,64 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.library.resolver
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.SearchPathResolverWithTarget
typealias DuplicatedLibraryLogger = (String) -> Unit
interface KonanLibraryResolver {
val searchPathResolver: SearchPathResolverWithTarget
val abiVersion: Int
/**
* Given the list of Kotlin/Native library names, ABI version and other parameters
* resolves libraries and evaluates dependencies between them.
*/
fun resolveWithDependencies(
libraryNames: List<String>,
noStdLib: Boolean = false,
noDefaultLibs: Boolean = false,
logger: DuplicatedLibraryLogger? = null
): KonanLibraryResolveResult
}
interface KonanLibraryResolveResult {
fun filterRoots(predicate: (KonanResolvedLibrary) -> Boolean): KonanLibraryResolveResult
fun getFullList(order: LibraryOrder? = null): List<KonanLibrary>
fun forEach(action: (KonanLibrary, PackageAccessedHandler) -> Unit)
}
typealias LibraryOrder = (Iterable<KonanResolvedLibrary>) -> List<KonanResolvedLibrary>
val TopologicalLibraryOrder: LibraryOrder = { input ->
val sorted = mutableListOf<KonanResolvedLibrary>()
val visited = mutableSetOf<KonanResolvedLibrary>()
val tempMarks = mutableSetOf<KonanResolvedLibrary>()
fun visit(node: KonanResolvedLibrary, result: MutableList<KonanResolvedLibrary>) {
if (visited.contains(node)) return
if (tempMarks.contains(node)) error("Cyclic dependency in library graph.")
tempMarks.add(node)
node.resolvedDependencies.forEach {
visit(it, result)
}
visited.add(node)
result += node
}
input.forEach next@{
if (visited.contains(it)) return@next
visit(it, sorted)
}
sorted
}
@@ -0,0 +1,32 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.library.resolver
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.name.FqName
interface PackageAccessedHandler {
fun markPackageAccessed(fqName: FqName)
}
/**
* A [KonanLibrary] wrapper that is used for resolving library's dependencies.
*/
interface KonanResolvedLibrary: PackageAccessedHandler {
// The library itself.
val library: KonanLibrary
// Dependencies on other libraries.
val resolvedDependencies: List<KonanResolvedLibrary>
// Whether it is needed to linker.
val isNeededForLink: Boolean
// Is provided by the distribution?
val isDefault: Boolean
}
@@ -0,0 +1,142 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.library.resolver.impl
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.SearchPathResolverWithTarget
import org.jetbrains.kotlin.konan.library.createKonanLibrary
import org.jetbrains.kotlin.konan.library.resolver.*
import org.jetbrains.kotlin.konan.library.unresolvedDependencies
internal class KonanLibraryResolverImpl(
override val searchPathResolver: SearchPathResolverWithTarget,
override val abiVersion: Int
) : KonanLibraryResolver {
override fun resolveWithDependencies(
libraryNames: List<String>,
noStdLib: Boolean,
noDefaultLibs: Boolean,
logger: DuplicatedLibraryLogger?
) = findLibraries(libraryNames, noStdLib, noDefaultLibs)
.leaveDistinct(logger)
.resolveDependencies()
/**
* Returns the list of libraries based on [libraryNames], [noStdLib] and [noDefaultLibs] criteria.
*
* This method does not return any libraries that might be available via transitive dependencies
* from the original library set (root set).
*/
private fun findLibraries(
libraryNames: List<String>,
noStdLib: Boolean,
noDefaultLibs: Boolean
): List<KonanLibrary> {
val userProvidedLibraries = libraryNames.asSequence()
.map { searchPathResolver.resolve(it) }
.map { createKonanLibrary(it, abiVersion, searchPathResolver.target) }
.toList()
val defaultLibraries = searchPathResolver.defaultLinks(noStdLib, noDefaultLibs).map {
createKonanLibrary(it, abiVersion, searchPathResolver.target, isDefault = true)
}
// Make sure the user provided ones appear first, so that
// they have precedence over defaults when duplicates are eliminated.
return userProvidedLibraries + defaultLibraries
}
/**
* Leaves only distinct libraries (by absolute path), warns on duplicated paths.
*/
private fun List<KonanLibrary>.leaveDistinct(logger: DuplicatedLibraryLogger?) =
this.groupBy { it.libraryFile.absolutePath }.let { groupedByAbsolutePath ->
warnOnLibraryDuplicates(groupedByAbsolutePath.filter { it.value.size > 1 }.keys, logger)
groupedByAbsolutePath.map { it.value.first() }
}
private fun warnOnLibraryDuplicates(duplicatedPaths: Iterable<String>, logger: DuplicatedLibraryLogger?) {
if (logger == null) return
duplicatedPaths.forEach { logger("library included more than once: $it") }
}
/**
* Given the list of root libraries does the following:
*
* 1. Evaluates other libraries that are available via transitive dependencies.
* 2. Wraps each [KonanLibrary] into a [KonanResolvedLibrary] with information about dependencies on other libraries.
* 3. Creates resulting [KonanLibraryResolveResult] object.
*/
private fun List<KonanLibrary>.resolveDependencies(): KonanLibraryResolveResult {
val rootLibraries = this.map { KonanResolvedLibraryImpl(it) }
// As far as the list of root libraries is known from the very beginning, the result can be
// constructed from the very beginning as well.
val result = KonanLibraryResolverResultImpl(rootLibraries)
val cache = mutableMapOf<File, KonanResolvedLibrary>()
cache.putAll(rootLibraries.map { it.library.libraryFile.absoluteFile to it })
var newDependencies = rootLibraries
do {
newDependencies = newDependencies.map { library: KonanResolvedLibraryImpl ->
library.library.unresolvedDependencies.asSequence()
.map { searchPathResolver.resolve(it).absoluteFile }
.mapNotNull {
if (it in cache) {
library.addDependency(cache[it]!!)
null
} else {
val newLibrary = KonanResolvedLibraryImpl(createKonanLibrary(it, abiVersion, searchPathResolver.target))
cache[it] = newLibrary
library.addDependency(newLibrary)
newLibrary
}
}
.toList()
}.flatten()
} while (newDependencies.isNotEmpty())
return result
}
}
internal class KonanLibraryResolverResultImpl(
private val roots: List<KonanResolvedLibrary>
) : KonanLibraryResolveResult {
private val all: List<KonanResolvedLibrary> by lazy {
val result = mutableSetOf<KonanResolvedLibrary>().also { it.addAll(roots) }
var newDependencies = result.toList()
do {
newDependencies = newDependencies
.map { it -> it.resolvedDependencies }.flatten()
.filter { it !in result }
result.addAll(newDependencies)
} while (newDependencies.isNotEmpty())
result.toList()
}
override fun filterRoots(predicate: (KonanResolvedLibrary) -> Boolean) =
KonanLibraryResolverResultImpl(roots.filter(predicate))
override fun getFullList(order: LibraryOrder?) = (order?.invoke(all) ?: all).asPlain()
override fun forEach(action: (KonanLibrary, PackageAccessedHandler) -> Unit) {
all.forEach { action(it.library, it) }
}
private fun List<KonanResolvedLibrary>.asPlain() = map { it.library }
override fun toString() = "roots=$roots, all=$all"
}
@@ -0,0 +1,40 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.library.resolver.impl
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.resolver.KonanResolvedLibrary
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.konan.parseModuleHeader
internal class KonanResolvedLibraryImpl(
override val library: KonanLibrary
) : KonanResolvedLibrary {
private val _resolvedDependencies = mutableListOf<KonanResolvedLibrary>()
private val _emptyPackages by lazy { parseModuleHeader(library.moduleHeaderData).emptyPackageList }
override val resolvedDependencies: List<KonanResolvedLibrary>
get() = _resolvedDependencies
internal fun addDependency(resolvedLibrary: KonanResolvedLibrary) = _resolvedDependencies.add(resolvedLibrary)
override var isNeededForLink: Boolean = false
private set
override val isDefault: Boolean
get() = library.isDefault
override fun markPackageAccessed(fqName: FqName) {
if (!isNeededForLink // fast path
&& !_emptyPackages.contains(fqName.asString())
) {
isNeededForLink = true
}
}
override fun toString() = "library=$library, dependsOn=${_resolvedDependencies.joinToString { it.library.toString() }}"
}
@@ -0,0 +1,47 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.properties
import org.jetbrains.kotlin.konan.file.*
typealias Properties = java.util.Properties
fun File.loadProperties(): Properties {
val properties = java.util.Properties()
this.bufferedReader().use { reader ->
properties.load(reader)
}
return properties
}
fun loadProperties(path: String): Properties = File(path).loadProperties()
fun File.saveProperties(properties: Properties) {
this.outputStream().use {
properties.store(it, null)
}
}
fun Properties.saveToFile(file: File) = file.saveProperties(this)
fun Properties.propertyString(key: String, suffix: String? = null): String? = getProperty(key.suffix(suffix)) ?: this.getProperty(key)
/**
* TODO: this method working with suffixes should be replaced with
* functionality borrowed from def file parser and unified for interop tool
* and kotlin compiler.
*/
fun Properties.propertyList(key: String, suffix: String? = null): List<String> {
val value = this.getProperty(key.suffix(suffix)) ?: this.getProperty(key)
if (value?.isBlank() == true) return emptyList()
return value?.split(Regex("\\s+")) ?: emptyList()
}
fun Properties.hasProperty(key: String, suffix: String? = null): Boolean = this.getProperty(key.suffix(suffix)) != null
fun String.suffix(suf: String?): String = if (suf == null) this else "${this}.$suf"
@@ -0,0 +1,56 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.util
import org.jetbrains.kotlin.descriptors.konan.KonanModuleDescriptorFactory
import org.jetbrains.kotlin.descriptors.konan.impl.KonanModuleDescriptorFactoryImpl
import org.jetbrains.kotlin.serialization.konan.KonanDeserializedModuleDescriptorFactory
import org.jetbrains.kotlin.serialization.konan.KonanDeserializedPackageFragmentsFactory
import org.jetbrains.kotlin.serialization.konan.KonanResolvedModuleDescriptorsFactory
import org.jetbrains.kotlin.serialization.konan.impl.KonanDeserializedModuleDescriptorFactoryImpl
import org.jetbrains.kotlin.serialization.konan.impl.KonanDeserializedPackageFragmentsFactoryImpl
import org.jetbrains.kotlin.serialization.konan.impl.KonanResolvedModuleDescriptorsFactoryImpl
/**
* The default Kotlin/Native factories.
*/
object KonanFactories {
/**
* The default [KonanModuleDescriptorFactory] factory instance.
*/
val DefaultDescriptorFactory: KonanModuleDescriptorFactory = KonanModuleDescriptorFactoryImpl
/**
* The default [KonanDeserializedPackageFragmentsFactory] factory instance.
*/
val DefaultPackageFragmentsFactory: KonanDeserializedPackageFragmentsFactory =
KonanDeserializedPackageFragmentsFactoryImpl
/**
* The default [KonanDeserializedModuleDescriptorFactory] factory instance.
*/
val DefaultDeserializedDescriptorFactory: KonanDeserializedModuleDescriptorFactory =
createDefaultKonanDeserializedModuleDescriptorFactory(
DefaultDescriptorFactory, DefaultPackageFragmentsFactory
)
/**
* The default [KonanResolvedModuleDescriptorsFactory] factory instance.
*/
val DefaultResolvedDescriptorsFactory: KonanResolvedModuleDescriptorsFactory =
createDefaultKonanResolvedModuleDescriptorsFactory(DefaultDeserializedDescriptorFactory)
fun createDefaultKonanDeserializedModuleDescriptorFactory(
descriptorFactory: KonanModuleDescriptorFactory,
packageFragmentsFactory: KonanDeserializedPackageFragmentsFactory
): KonanDeserializedModuleDescriptorFactory =
KonanDeserializedModuleDescriptorFactoryImpl(descriptorFactory, packageFragmentsFactory)
fun createDefaultKonanResolvedModuleDescriptorsFactory(
moduleDescriptorFactory: KonanDeserializedModuleDescriptorFactory
): KonanResolvedModuleDescriptorsFactory = KonanResolvedModuleDescriptorsFactoryImpl(moduleDescriptorFactory)
}
@@ -0,0 +1,23 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.util
import kotlin.system.measureTimeMillis
fun printMillisec(message: String, body: () -> Unit) {
val msec = measureTimeMillis {
body()
}
println("$message: $msec msec")
}
fun profile(message: String, body: () -> Unit) = profileIf(
System.getProperty("konan.profile")?.equals("true") ?: false,
message, body
)
fun profileIf(condition: Boolean, message: String, body: () -> Unit) =
if (condition) printMillisec(message, body) else body()
@@ -0,0 +1,33 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.util
import org.jetbrains.kotlin.konan.target.KonanTarget
import java.util.*
fun defaultTargetSubstitutions(target: KonanTarget) =
mapOf(
"target" to target.visibleName,
"arch" to target.architecture.visibleName,
"family" to target.family.visibleName
)
// Performs substitution similar to:
// foo = ${foo} ${foo.${arch}} ${foo.${os}}
fun substitute(properties: Properties, substitutions: Map<String, String>) {
for (key in properties.stringPropertyNames()) {
for (substitution in substitutions.values) {
val suffix = ".$substitution"
if (key.endsWith(suffix)) {
val baseKey = key.removeSuffix(suffix)
val oldValue = properties.getProperty(baseKey, "")
val appendedValue = properties.getProperty(key, "")
val newValue = if (oldValue != "") "$oldValue $appendedValue" else appendedValue
properties.setProperty(baseKey, newValue)
}
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,22 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.konan.platform
import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.resolve.MultiTargetPlatform
import org.jetbrains.kotlin.resolve.PlatformConfigurator
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.storage.StorageManager
object KonanPlatform : TargetPlatform("Konan") {
override fun computePlatformSpecificDefaultImports(storageManager: StorageManager, result: MutableList<ImportPath>) {
result.add(ImportPath.fromString("kotlin.native.*"))
}
override val multiTargetPlatform = MultiTargetPlatform.Specific(platformName)
override val platformConfigurator: PlatformConfigurator = KonanPlatformConfigurator
}
@@ -0,0 +1,42 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.konan.platform
import org.jetbrains.kotlin.builtins.PlatformToKotlinClassMap
import org.jetbrains.kotlin.container.StorageComponentContainer
import org.jetbrains.kotlin.container.useInstance
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.checkers.ReifiedTypeParameterSubstitutionChecker
import org.jetbrains.kotlin.resolve.calls.components.SamConversionTransformer
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.lazy.DelegationFilter
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
import org.jetbrains.kotlin.types.DynamicTypesSettings
object KonanPlatformConfigurator : PlatformConfigurator(
DynamicTypesSettings(),
additionalDeclarationCheckers = listOf(ExpectedActualDeclarationChecker),
additionalCallCheckers = listOf(
org.jetbrains.kotlin.resolve.jvm.checkers.SuperCallWithDefaultArgumentsChecker(),
ReifiedTypeParameterSubstitutionChecker()
),
additionalTypeCheckers = listOf(),
additionalClassifierUsageCheckers = listOf(),
additionalAnnotationCheckers = listOf(),
identifierChecker = IdentifierChecker.Default,
overloadFilter = OverloadFilter.Default,
platformToKotlinClassMap = PlatformToKotlinClassMap.EMPTY,
delegationFilter = DelegationFilter.Default,
overridesBackwardCompatibilityHelper = OverridesBackwardCompatibilityHelper.Default,
declarationReturnTypeSanitizer = DeclarationReturnTypeSanitizer.Default
) {
override fun configureModuleComponents(container: StorageComponentContainer) {
container.useInstance(SyntheticScopes.Empty)
container.useInstance(TypeSpecificityComparator.NONE)
container.useInstance(SamConversionTransformer.Empty)
}
}
@@ -0,0 +1,34 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.serialization.konan
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.deserialization.ClassData
import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder
import org.jetbrains.kotlin.serialization.deserialization.getClassId
class KonanClassDataFinder(
private val fragment: KonanProtoBuf.LinkDataPackageFragment,
private val nameResolver: NameResolver
) : ClassDataFinder {
override fun findClassData(classId: ClassId): ClassData? {
val proto = fragment.classes
val nameList = proto.classNameList
val index = nameList.indexOfFirst { nameResolver.getClassId(it) == classId }
if (index == -1)
error("Could not find serialized class $classId")
val foundClass = proto.getClasses(index) ?: error("Could not find data for serialized class $classId")
/* TODO: binary version supposed to be read from protobuf. */
return ClassData(nameResolver, foundClass, KonanMetadataVersion.INSTANCE, SourceElement.NO_SOURCE)
}
}
@@ -0,0 +1,14 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.serialization.konan
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
fun parsePackageFragment(packageMetadata: ByteArray): KonanProtoBuf.LinkDataPackageFragment =
KonanProtoBuf.LinkDataPackageFragment.parseFrom(packageMetadata, KonanSerializerProtocol.extensionRegistry)
fun parseModuleHeader(libraryMetadata: ByteArray): KonanProtoBuf.LinkDataLibrary =
KonanProtoBuf.LinkDataLibrary.parseFrom(libraryMetadata, KonanSerializerProtocol.extensionRegistry)
@@ -0,0 +1,43 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.serialization.konan
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.descriptors.konan.KonanModuleDescriptorFactory
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.resolver.PackageAccessedHandler
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
interface KonanDeserializedModuleDescriptorFactory {
val descriptorFactory: KonanModuleDescriptorFactory
val packageFragmentsFactory: KonanDeserializedPackageFragmentsFactory
fun createDescriptor(
library: KonanLibrary,
languageVersionSettings: LanguageVersionSettings,
storageManager: StorageManager,
builtIns: KotlinBuiltIns,
packageAccessedHandler: PackageAccessedHandler? = null,
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?> = emptyMap()
): ModuleDescriptorImpl
/**
* Please use this method with care: As far as it creates an instance of [KotlinBuiltIns] it should be
* normally used for creation of the very first (e.g. "stdlib") module in the set of created modules.
*/
fun createDescriptorAndNewBuiltIns(
library: KonanLibrary,
languageVersionSettings: LanguageVersionSettings,
storageManager: StorageManager,
packageAccessedHandler: PackageAccessedHandler? = null,
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?> = emptyMap()
): ModuleDescriptorImpl
}
@@ -0,0 +1,29 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.serialization.konan
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.resolver.PackageAccessedHandler
import org.jetbrains.kotlin.storage.StorageManager
interface KonanDeserializedPackageFragmentsFactory {
fun createDeserializedPackageFragments(
library: KonanLibrary,
packageFragmentNames: List<String>,
moduleDescriptor: ModuleDescriptor,
packageAccessedHandler: PackageAccessedHandler?,
storageManager: StorageManager
): List<KonanPackageFragment>
fun createSyntheticPackageFragments(
library: KonanLibrary,
deserializedPackageFragments: List<KonanPackageFragment>,
moduleDescriptor: ModuleDescriptor
): List<PackageFragmentDescriptor>
}
@@ -0,0 +1,21 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.serialization.konan
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
class KonanMetadataVersion(vararg numbers: Int) : BinaryVersion(*numbers) {
override fun isCompatible(): Boolean = this.major == 1 && this.minor == 0
companion object {
@JvmField
val INSTANCE = KonanMetadataVersion(1, 0, 0)
@JvmField
val INVALID_VERSION = KonanMetadataVersion()
}
}
@@ -0,0 +1,88 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.serialization.konan
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.resolver.PackageAccessedHandler
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents
import org.jetbrains.kotlin.serialization.deserialization.DeserializedPackageFragment
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
import org.jetbrains.kotlin.serialization.deserialization.getClassId
import org.jetbrains.kotlin.serialization.deserialization.getName
import org.jetbrains.kotlin.storage.StorageManager
class KonanPackageFragment(
fqName: FqName,
private val library: KonanLibrary,
private val packageAccessedHandler: PackageAccessedHandler?,
storageManager: StorageManager,
module: ModuleDescriptor
) : DeserializedPackageFragment(fqName, storageManager, module) {
lateinit var components: DeserializationComponents
override fun initialize(components: DeserializationComponents) {
this.components = components
}
// The proto field is lazy so that we can load only needed
// packages from the library.
private val protoForNames: KonanProtoBuf.LinkDataPackageFragment by lazy {
parsePackageFragment(library.packageMetadata(fqName.asString()))
}
val proto: KonanProtoBuf.LinkDataPackageFragment
get() = protoForNames.also { packageAccessedHandler?.markPackageAccessed(fqName) }
private val nameResolver by lazy {
NameResolverImpl(protoForNames.stringTable, protoForNames.nameTable)
}
override val classDataFinder by lazy {
KonanClassDataFinder(proto, nameResolver)
}
private val _memberScope by lazy {
/* TODO: we fake proto binary versioning for now. */
DeserializedPackageMemberScope(
this,
proto.getPackage(),
nameResolver,
KonanMetadataVersion.INSTANCE,
/* containerSource = */ null,
components
) { loadClassNames() }
}
override fun getMemberScope(): DeserializedPackageMemberScope = _memberScope
private val classifierNames: Set<Name> by lazy {
val result = mutableSetOf<Name>()
result.addAll(loadClassNames())
protoForNames.getPackage().typeAliasList.mapTo(result) { nameResolver.getName(it.name) }
result
}
fun hasTopLevelClassifier(name: Name): Boolean = name in classifierNames
private fun loadClassNames(): Collection<Name> {
val classNameList = protoForNames.classes.classNameList
val names = classNameList.mapNotNull {
val classId = nameResolver.getClassId(it)
val shortName = classId.shortClassName
if (!classId.isNestedClass) shortName else null
}
return names
}
}
@@ -0,0 +1,56 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.serialization.konan
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.resolver.KonanLibraryResolveResult
import org.jetbrains.kotlin.storage.StorageManager
interface KonanResolvedModuleDescriptorsFactory {
val moduleDescriptorFactory: KonanDeserializedModuleDescriptorFactory
/**
* Given the [resolvedLibraries] creates the list of [ModuleDescriptorImpl]s with properly installed
* inter-dependencies. The result of this method is returned in a form of [KonanResolvedModuleDescriptors] instance.
*
* Please use this method with care: Unless this method accepts `null` for [builtIns], it is not recommended to
* invoke it this way. If you are compiling a source module, please supply the non-null [builtIns] from the
* source module, so that all modules created in your compilation session will share the same built-ins instance.
*
* Otherwise (if `null` was supplied), a new instance of [KotlinBuiltIns] will be created. The created built-ins
* instance will be shared by all modules created in this method. But this instance will have no connection
* with probably existing built-ins instance of your source module(s).
*/
fun createResolved(
resolvedLibraries: KonanLibraryResolveResult,
storageManager: StorageManager,
builtIns: KotlinBuiltIns?,
languageVersionSettings: LanguageVersionSettings,
customAction: ((KonanLibrary, ModuleDescriptorImpl) -> Unit)? = null,
customCapabilitiesGenerator: ((KonanLibrary) -> Map<ModuleDescriptor.Capability<*>, Any?>)? = null
): KonanResolvedModuleDescriptors
}
class KonanResolvedModuleDescriptors(
/**
* The list of modules each representing an individual Kotlin/Native library. All modules
* in this list have properly installed dependencies, i.e. module has all necessary dependencies
* on other modules plus a dependency on the [forwardDeclarationsModule].
*/
val resolvedDescriptors: List<ModuleDescriptorImpl>,
/**
* This is a module which "contains" forward declarations.
* Note: this module should be unique per compilation and should always be the last dependency of any module.
*/
val forwardDeclarationsModule: ModuleDescriptorImpl
)
@@ -0,0 +1,24 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.serialization.konan
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
object KonanSerializerProtocol : SerializerExtensionProtocol(
ExtensionRegistryLite.newInstance().apply { KonanProtoBuf.registerAllExtensions(this) },
KonanProtoBuf.packageFqName,
KonanProtoBuf.constructorAnnotation,
KonanProtoBuf.classAnnotation,
KonanProtoBuf.functionAnnotation,
KonanProtoBuf.propertyAnnotation,
KonanProtoBuf.enumEntryAnnotation,
KonanProtoBuf.compileTimeValue,
KonanProtoBuf.parameterAnnotation,
KonanProtoBuf.typeAnnotation,
KonanProtoBuf.typeParameterAnnotation
)
@@ -0,0 +1,20 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.serialization.konan
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer
import org.jetbrains.kotlin.types.SimpleType
object NullFlexibleTypeDeserializer : FlexibleTypeDeserializer {
override fun create(
proto: ProtoBuf.Type,
flexibleId: String,
lowerBound: SimpleType,
upperBound: SimpleType
) = error("Illegal use of flexible type deserializer.")
}
@@ -0,0 +1,140 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.serialization.konan.impl
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.NotFoundClasses
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.descriptors.PackageFragmentProviderImpl
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.descriptors.konan.DeserializedKonanModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.KonanModuleDescriptorFactory
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.resolver.PackageAccessedHandler
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
import org.jetbrains.kotlin.serialization.deserialization.*
import org.jetbrains.kotlin.serialization.konan.*
import org.jetbrains.kotlin.storage.StorageManager
internal class KonanDeserializedModuleDescriptorFactoryImpl(
override val descriptorFactory: KonanModuleDescriptorFactory,
override val packageFragmentsFactory: KonanDeserializedPackageFragmentsFactory
) : KonanDeserializedModuleDescriptorFactory {
override fun createDescriptor(
library: KonanLibrary,
languageVersionSettings: LanguageVersionSettings,
storageManager: StorageManager,
builtIns: KotlinBuiltIns,
packageAccessedHandler: PackageAccessedHandler?,
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?>
) = createDescriptorOptionalBuiltIns(
library,
languageVersionSettings,
storageManager,
builtIns,
packageAccessedHandler,
customCapabilities
)
override fun createDescriptorAndNewBuiltIns(
library: KonanLibrary,
languageVersionSettings: LanguageVersionSettings,
storageManager: StorageManager,
packageAccessedHandler: PackageAccessedHandler?,
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?>
) = createDescriptorOptionalBuiltIns(library, languageVersionSettings, storageManager, null, packageAccessedHandler, customCapabilities)
private fun createDescriptorOptionalBuiltIns(
library: KonanLibrary,
languageVersionSettings: LanguageVersionSettings,
storageManager: StorageManager,
builtIns: KotlinBuiltIns?,
packageAccessedHandler: PackageAccessedHandler?,
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?>
): ModuleDescriptorImpl {
val libraryProto = parseModuleHeader(library.moduleHeaderData)
val moduleName = Name.special(libraryProto.moduleName)
val moduleOrigin = DeserializedKonanModuleOrigin(library)
val moduleDescriptor = if (builtIns != null)
descriptorFactory.createDescriptor(moduleName, storageManager, builtIns, moduleOrigin, customCapabilities)
else
descriptorFactory.createDescriptorAndNewBuiltIns(moduleName, storageManager, moduleOrigin, customCapabilities)
val deserializationConfiguration = CompilerDeserializationConfiguration(languageVersionSettings)
val provider = createPackageFragmentProvider(
library,
packageAccessedHandler,
libraryProto.packageFragmentNameList,
storageManager,
moduleDescriptor,
deserializationConfiguration
)
moduleDescriptor.initialize(provider)
return moduleDescriptor
}
private fun createPackageFragmentProvider(
library: KonanLibrary,
packageAccessedHandler: PackageAccessedHandler?,
packageFragmentNames: List<String>,
storageManager: StorageManager,
moduleDescriptor: ModuleDescriptor,
configuration: DeserializationConfiguration
): PackageFragmentProvider {
val deserializedPackageFragments = packageFragmentsFactory.createDeserializedPackageFragments(
library, packageFragmentNames, moduleDescriptor, packageAccessedHandler, storageManager
)
val syntheticPackageFragments = packageFragmentsFactory.createSyntheticPackageFragments(
library, deserializedPackageFragments, moduleDescriptor
)
val provider = PackageFragmentProviderImpl(deserializedPackageFragments + syntheticPackageFragments)
val notFoundClasses = NotFoundClasses(storageManager, moduleDescriptor)
val annotationAndConstantLoader = AnnotationAndConstantLoaderImpl(
moduleDescriptor,
notFoundClasses,
KonanSerializerProtocol
)
val components = DeserializationComponents(
storageManager,
moduleDescriptor,
configuration,
DeserializedClassDataFinder(provider),
annotationAndConstantLoader,
provider,
LocalClassifierTypeSettings.Default,
ErrorReporter.DO_NOTHING,
LookupTracker.DO_NOTHING,
NullFlexibleTypeDeserializer,
emptyList(),
notFoundClasses,
ContractDeserializer.DEFAULT,
extensionRegistryLite = KonanSerializerProtocol.extensionRegistry
)
for (packageFragment in deserializedPackageFragments) {
packageFragment.initialize(components)
}
return provider
}
}
@@ -0,0 +1,138 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.serialization.konan.impl
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.exportForwardDeclarations
import org.jetbrains.kotlin.konan.library.isInterop
import org.jetbrains.kotlin.konan.library.packageFqName
import org.jetbrains.kotlin.konan.library.resolver.PackageAccessedHandler
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
import org.jetbrains.kotlin.serialization.konan.KonanDeserializedPackageFragmentsFactory
import org.jetbrains.kotlin.serialization.konan.KonanPackageFragment
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
// FIXME(ddol): decouple and move interop-specific logic back to Kotlin/Native.
internal object KonanDeserializedPackageFragmentsFactoryImpl : KonanDeserializedPackageFragmentsFactory {
override fun createDeserializedPackageFragments(
library: KonanLibrary,
packageFragmentNames: List<String>,
moduleDescriptor: ModuleDescriptor,
packageAccessedHandler: PackageAccessedHandler?,
storageManager: StorageManager
) = packageFragmentNames.map {
KonanPackageFragment(FqName(it), library, packageAccessedHandler, storageManager, moduleDescriptor)
}
override fun createSyntheticPackageFragments(
library: KonanLibrary,
deserializedPackageFragments: List<KonanPackageFragment>,
moduleDescriptor: ModuleDescriptor
): List<PackageFragmentDescriptor> {
if (!library.isInterop) return emptyList()
val mainPackageFqName = library.packageFqName
?: error("Inconsistent manifest: interop library ${library.libraryName} should have `package` specified")
val exportForwardDeclarations = library.exportForwardDeclarations
val aliasedPackageFragments = deserializedPackageFragments.filter { it.fqName == mainPackageFqName }
val result = mutableListOf<PackageFragmentDescriptor>()
listOf(
ForwardDeclarationsFqNames.cNamesStructs,
ForwardDeclarationsFqNames.objCNamesClasses,
ForwardDeclarationsFqNames.objCNamesProtocols
).mapTo(result) { fqName ->
ClassifierAliasingPackageFragmentDescriptor(aliasedPackageFragments, moduleDescriptor, fqName)
}
result.add(ExportedForwardDeclarationsPackageFragmentDescriptor(moduleDescriptor, mainPackageFqName, exportForwardDeclarations))
return result
}
}
/**
* The package fragment to export forward declarations from interop package namespace, i.e.
* redirect "$pkg.$name" to e.g. "cnames.structs.$name".
*/
class ExportedForwardDeclarationsPackageFragmentDescriptor(
module: ModuleDescriptor,
fqName: FqName,
declarations: List<FqName>
) : PackageFragmentDescriptorImpl(module, fqName) {
private val memberScope = object : MemberScopeImpl() {
private val nameToFqName = declarations.map { it.shortName() to it }.toMap()
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? {
val declFqName = nameToFqName[name] ?: return null
val packageView = module.getPackage(declFqName.parent())
return packageView.memberScope.getContributedClassifier(name, location)
}
override fun printScopeStructure(p: Printer) {
p.println(this::class.java.simpleName, " {")
p.pushIndent()
p.println("declarations = $declarations")
p.popIndent()
p.println("}")
}
}
override fun getMemberScope() = memberScope
}
/**
* The package fragment that redirects all requests for classifier lookup to its targets.
*/
class ClassifierAliasingPackageFragmentDescriptor(
targets: List<KonanPackageFragment>,
module: ModuleDescriptor,
fqName: FqName
) : PackageFragmentDescriptorImpl(module, fqName) {
private val memberScope = object : MemberScopeImpl() {
override fun getContributedClassifier(name: Name, location: LookupLocation) =
targets.firstNotNullResult {
if (it.hasTopLevelClassifier(name)) {
it.getMemberScope().getContributedClassifier(name, location)
} else {
null
}
}
override fun printScopeStructure(p: Printer) {
p.println(this::class.java.simpleName, " {")
p.pushIndent()
p.println("targets = $targets")
p.popIndent()
p.println("}")
}
}
override fun getMemberScope(): MemberScope = memberScope
}
@@ -0,0 +1,206 @@
/*
* 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/LICENSE.txt file.
*/
package org.jetbrains.kotlin.serialization.konan.impl
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
import org.jetbrains.kotlin.descriptors.konan.KonanModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.SyntheticModulesOrigin
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.resolver.KonanLibraryResolveResult
import org.jetbrains.kotlin.konan.library.resolver.PackageAccessedHandler
import org.jetbrains.kotlin.konan.util.profile
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
import org.jetbrains.kotlin.serialization.konan.KonanDeserializedModuleDescriptorFactory
import org.jetbrains.kotlin.serialization.konan.KonanResolvedModuleDescriptors
import org.jetbrains.kotlin.serialization.konan.KonanResolvedModuleDescriptorsFactory
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.storage.getValue
import org.jetbrains.kotlin.utils.Printer
class KonanResolvedModuleDescriptorsFactoryImpl(
override val moduleDescriptorFactory: KonanDeserializedModuleDescriptorFactory
) : KonanResolvedModuleDescriptorsFactory {
override fun createResolved(
resolvedLibraries: KonanLibraryResolveResult,
storageManager: StorageManager,
builtIns: KotlinBuiltIns?,
languageVersionSettings: LanguageVersionSettings,
customAction: ((KonanLibrary, ModuleDescriptorImpl) -> Unit)?,
customCapabilitiesGenerator: ((KonanLibrary) -> Map<ModuleDescriptor.Capability<*>, Any?>)?
): KonanResolvedModuleDescriptors {
val moduleDescriptors = mutableListOf<ModuleDescriptorImpl>()
@Suppress("NAME_SHADOWING")
var builtIns = builtIns
// Build module descriptors.
resolvedLibraries.forEach { library, packageAccessedHandler ->
profile("Loading ${library.libraryName}") {
val customCapabilities = customCapabilitiesGenerator?.invoke(library) ?: emptyMap()
// MutableModuleContext needs ModuleDescriptorImpl, rather than ModuleDescriptor.
val moduleDescriptor = createDescriptorOptionalBuiltsIns(
library, languageVersionSettings, storageManager, builtIns, packageAccessedHandler, customCapabilities
)
builtIns = moduleDescriptor.builtIns
moduleDescriptors.add(moduleDescriptor)
customAction?.invoke(library, moduleDescriptor)
}
}
val forwardDeclarationsModule = createForwardDeclarationsModule(builtIns, storageManager)
// Set inter-dependencies between module descriptors, add forwarding declarations module.
for (module in moduleDescriptors) {
// Yes, just to all of them.
module.setDependencies(moduleDescriptors + forwardDeclarationsModule)
}
return KonanResolvedModuleDescriptors(moduleDescriptors, forwardDeclarationsModule)
}
private fun createForwardDeclarationsModule(
builtIns: KotlinBuiltIns?,
storageManager: StorageManager
): ModuleDescriptorImpl {
val name = Name.special("<forward declarations>")
val module = createDescriptorOptionalBuiltsIns(name, storageManager, builtIns, SyntheticModulesOrigin)
fun createPackage(fqName: FqName, supertypeName: String, classKind: ClassKind) =
ForwardDeclarationsPackageFragmentDescriptor(
storageManager,
module,
fqName,
Name.identifier(supertypeName),
classKind
)
val packageFragmentProvider = PackageFragmentProviderImpl(
listOf(
createPackage(ForwardDeclarationsFqNames.cNamesStructs, "COpaque", ClassKind.CLASS),
createPackage(ForwardDeclarationsFqNames.objCNamesClasses, "ObjCObjectBase", ClassKind.CLASS),
createPackage(ForwardDeclarationsFqNames.objCNamesProtocols, "ObjCObject", ClassKind.INTERFACE)
)
)
module.initialize(packageFragmentProvider)
module.setDependencies(module)
return module
}
private fun createDescriptorOptionalBuiltsIns(
name: Name,
storageManager: StorageManager,
builtIns: KotlinBuiltIns?,
moduleOrigin: KonanModuleOrigin
) = if (builtIns != null)
moduleDescriptorFactory.descriptorFactory.createDescriptor(name, storageManager, builtIns, moduleOrigin)
else
moduleDescriptorFactory.descriptorFactory.createDescriptorAndNewBuiltIns(name, storageManager, moduleOrigin)
private fun createDescriptorOptionalBuiltsIns(
library: KonanLibrary,
languageVersionSettings: LanguageVersionSettings,
storageManager: StorageManager,
builtIns: KotlinBuiltIns?,
packageAccessedHandler: PackageAccessedHandler?,
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?>
) = if (builtIns != null)
moduleDescriptorFactory.createDescriptor(
library,
languageVersionSettings,
storageManager,
builtIns,
packageAccessedHandler,
customCapabilities
)
else
moduleDescriptorFactory.createDescriptorAndNewBuiltIns(
library,
languageVersionSettings,
storageManager,
packageAccessedHandler,
customCapabilities
)
}
/**
* Package fragment which creates descriptors for forward declarations on demand.
*/
private class ForwardDeclarationsPackageFragmentDescriptor(
storageManager: StorageManager,
module: ModuleDescriptor,
fqName: FqName,
supertypeName: Name,
classKind: ClassKind
) : PackageFragmentDescriptorImpl(module, fqName) {
private val memberScope = object : MemberScopeImpl() {
private val declarations = storageManager.createMemoizedFunction(this::createDeclaration)
private val supertype by storageManager.createLazyValue {
val descriptor = builtIns.builtInsModule.getPackage(ForwardDeclarationsFqNames.packageName)
.memberScope
.getContributedClassifier(supertypeName, NoLookupLocation.FROM_BACKEND) as ClassDescriptor
descriptor.defaultType
}
private fun createDeclaration(name: Name): ClassDescriptor {
return ClassDescriptorImpl(
this@ForwardDeclarationsPackageFragmentDescriptor,
name,
Modality.FINAL,
classKind,
listOf(supertype),
SourceElement.NO_SOURCE,
false,
LockBasedStorageManager.NO_LOCKS
).apply {
this.initialize(MemberScope.Empty, emptySet(), null)
}
}
override fun getContributedClassifier(name: Name, location: LookupLocation) = declarations(name)
override fun printScopeStructure(p: Printer) {
p.println(this::class.java.simpleName, "{}")
}
}
override fun getMemberScope(): MemberScope = memberScope
}
// FIXME(ddol): decouple and move interop-specific logic back to Kotlin/Native.
internal object ForwardDeclarationsFqNames {
val packageName = FqName("kotlinx.cinterop")
val cNames = FqName("cnames")
val cNamesStructs = cNames.child(Name.identifier("structs"))
val objCNames = FqName("objcnames")
val objCNamesClasses = objCNames.child(Name.identifier("classes"))
val objCNamesProtocols = objCNames.child(Name.identifier("protocols"))
}