Split serialized package fragments metadata (#2051)

This commit is contained in:
Dmitriy Dolovov
2018-09-13 18:01:56 +03:00
committed by Nikolay Igotti
parent 7c21913990
commit c40396bf19
21 changed files with 409 additions and 95 deletions
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
import org.jetbrains.kotlin.backend.konan.descriptors.findPackageView
import org.jetbrains.kotlin.backend.konan.descriptors.getStringValue
import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass
import org.jetbrains.kotlin.backend.konan.irasdescriptors.getExternalObjCMethodInfo
@@ -21,6 +22,7 @@ import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition
import org.jetbrains.kotlin.resolve.constants.BooleanValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
@@ -75,15 +77,15 @@ private fun FunctionDescriptor.decodeObjCMethodAnnotation(): ObjCMethodInfo? {
assert (this.kind.isReal)
val methodAnnotation = this.annotations.findAnnotation(objCMethodFqName) ?: return null
val packageFragment = this.findPackage()
val packageView = this.findPackageView()
val bridgeName = methodAnnotation.getStringValue("bridge")
return objCMethodInfoByBridge(packageFragment, bridgeName)
return objCMethodInfoByBridge(packageView, bridgeName)
}
private fun objCMethodInfoByBridge(packageFragment: PackageFragmentDescriptor, bridgeName: String): ObjCMethodInfo {
val bridge = packageFragment.getMemberScope()
private fun objCMethodInfoByBridge(packageView: PackageViewDescriptor, bridgeName: String): ObjCMethodInfo {
val bridge = packageView.memberScope
.getContributedFunctions(Name.identifier(bridgeName), NoLookupLocation.FROM_BACKEND)
.single()
@@ -213,7 +215,7 @@ fun FunctionDescriptor.getObjCFactoryInitMethodInfo(): ObjCMethodInfo? {
val factoryAnnotation = this.annotations.findAnnotation(objCFactoryFqName) ?: return null
val bridgeName = factoryAnnotation.getStringValue("bridge")
return objCMethodInfoByBridge(this.findPackage(), bridgeName)
return objCMethodInfoByBridge(this.findPackageView(), bridgeName)
}
fun inferObjCSelector(descriptor: FunctionDescriptor): String = if (descriptor.valueParameters.isEmpty()) {
@@ -114,6 +114,11 @@ tailrec internal fun DeclarationDescriptor.findPackage(): PackageFragmentDescrip
else this.containingDeclaration!!.findPackage()
}
internal fun DeclarationDescriptor.findPackageView(): PackageViewDescriptor {
val packageFragment = this.findPackage()
return packageFragment.module.getPackage(packageFragment.fqName)
}
internal fun DeclarationDescriptor.allContainingDeclarations(): List<DeclarationDescriptor> {
var list = mutableListOf<DeclarationDescriptor>()
var current = this.containingDeclaration
@@ -25,7 +25,7 @@ interface KonanLibraryWriter {
class LinkData(
val module: ByteArray,
val fragments: List<ByteArray>,
val fragments: List<List<ByteArray>>,
val fragmentNames: List<String>
)
@@ -13,8 +13,16 @@ internal class MetadataWriterImpl(libraryLayout: KonanLibraryLayout): KonanLibra
fun addLinkData(linkData: LinkData) {
moduleHeaderFile.writeBytes(linkData.module)
linkData.fragments.forEachIndexed { index, it ->
val name = linkData.fragmentNames[index]
packageFile(name).writeBytes(it)
val packageFqName = linkData.fragmentNames[index]
val shortName = packageFqName.substringAfterLast(".")
val dir = packageFragmentsDir(packageFqName)
dir.deleteRecursively()
dir.mkdirs()
val numCount = it.size.toString().length
fun withLeadingZeros(i: Int) = String.format("%0${numCount}d", i)
for ((i, fragment) in it.withIndex()) {
packageFragmentFile(packageFqName, "${withLeadingZeros(i)}_$shortName").writeBytes(fragment)
}
}
}
}
@@ -615,7 +615,7 @@ class KonanDescriptorSerializer private constructor(
fun packagePartProto(packageFqName: FqName, members: Collection<DeclarationDescriptor>): ProtoBuf.Package.Builder {
val builder = ProtoBuf.Package.newBuilder()
for (declaration in sort(members)) {
for (declaration in members) {
when (declaration) {
is PropertyDescriptor -> builder.addProperty(propertyProto(declaration))
is FunctionDescriptor -> builder.addFunction(functionProto(declaration))
@@ -8,9 +8,8 @@ package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember
import org.jetbrains.kotlin.backend.konan.library.LinkData
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.name.FqName
@@ -18,6 +17,9 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter.Companion.CALLABLES
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter.Companion.CLASSIFIERS
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlin.serialization.KonanDescriptorSerializer
/*
@@ -31,39 +33,57 @@ import org.jetbrains.kotlin.serialization.KonanDescriptorSerializer
* with MemberDeserializer class.
*/
internal class KonanSerializationUtil(val context: Context, metadataVersion: BinaryVersion) {
internal class KonanSerializationUtil(val context: Context, private val metadataVersion: BinaryVersion) {
val serializerExtension = KonanSerializerExtension(context, metadataVersion)
val topSerializer = KonanDescriptorSerializer.createTopLevel(context, serializerExtension)
var classSerializer: KonanDescriptorSerializer = topSerializer
lateinit var serializerContext: SerializerContext
fun serializeClass(packageName: FqName,
builder: KonanProtoBuf.LinkDataClasses.Builder,
classDescriptor: ClassDescriptor) {
data class SerializerContext(
val serializerExtension: KonanSerializerExtension,
val topSerializer: KonanDescriptorSerializer,
var classSerializer: KonanDescriptorSerializer = topSerializer
)
val previousSerializer = classSerializer
// TODO: this is to filter out object{}. Change me.
if (classDescriptor.isExported())
classSerializer = KonanDescriptorSerializer.create(context, classDescriptor, serializerExtension)
val classProto = classSerializer.classProto(classDescriptor).build()
?: error("Class not serialized: $classDescriptor")
builder.addClasses(classProto)
val index = classSerializer.stringTable.getFqNameIndex(classDescriptor)
builder.addClassName(index)
serializeClasses(packageName, builder,
classDescriptor.unsubstitutedInnerClassesScope
.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS))
classSerializer = previousSerializer
private fun createNewContext(): SerializerContext {
val extension = KonanSerializerExtension(context, metadataVersion)
return SerializerContext(
extension,
KonanDescriptorSerializer.createTopLevel(context, extension)
)
}
fun serializeClasses(packageName: FqName,
builder: KonanProtoBuf.LinkDataClasses.Builder,
descriptors: Collection<DeclarationDescriptor>) {
private inline fun <T> withNewContext(crossinline block: SerializerContext.() -> T): T {
serializerContext = createNewContext()
return with(serializerContext, block)
}
private fun serializeClass(packageName: FqName,
builder: KonanProtoBuf.LinkDataClasses.Builder,
classDescriptor: ClassDescriptor) {
with(serializerContext) {
val previousSerializer = classSerializer
// TODO: this is to filter out object{}. Change me.
if (classDescriptor.isExported())
classSerializer = KonanDescriptorSerializer.create(context, classDescriptor, serializerExtension)
val classProto = classSerializer.classProto(classDescriptor).build()
?: error("Class not serialized: $classDescriptor")
builder.addClasses(classProto)
val index = classSerializer.stringTable.getFqNameIndex(classDescriptor)
builder.addClassName(index)
serializeClasses(packageName, builder,
classDescriptor.unsubstitutedInnerClassesScope
.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS))
classSerializer = previousSerializer
}
}
private fun serializeClasses(packageName: FqName,
builder: KonanProtoBuf.LinkDataClasses.Builder,
descriptors: Collection<DeclarationDescriptor>) {
for (descriptor in descriptors) {
if (descriptor is ClassDescriptor) {
@@ -72,51 +92,89 @@ internal class KonanSerializationUtil(val context: Context, metadataVersion: Bin
}
}
fun serializePackage(fqName: FqName, module: ModuleDescriptor) :
KonanProtoBuf.LinkDataPackageFragment? {
private fun serializePackage(fqName: FqName, module: ModuleDescriptor):
List<KonanProtoBuf.LinkDataPackageFragment> {
// TODO: ModuleDescriptor should be able to return
// the package only with the contents of that module, without dependencies
val fragments = module.getPackage(fqName).fragments.filter { it.module == module }
if (fragments.isEmpty()) return null
if (fragments.isEmpty()) return emptyList()
val classifierDescriptors = KonanDescriptorSerializer.sort(
fragments.flatMap {
it.getMemberScope().getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS)
it.getMemberScope().getDescriptorsFiltered(CLASSIFIERS)
}.filter { !it.isExpectMember || it.isSerializableExpectClass }
)
val members = fragments.flatMap { fragment ->
DescriptorUtils.getAllDescriptors(fragment.getMemberScope())
}.filter { !it.isExpectMember }
val topLevelDescriptors = KonanDescriptorSerializer.sort(
fragments.flatMap { fragment ->
fragment.getMemberScope().getDescriptorsFiltered(CALLABLES)
}.filter { !it.isExpectMember }
)
val classesBuilder = KonanProtoBuf.LinkDataClasses.newBuilder()
val result = mutableListOf<KonanProtoBuf.LinkDataPackageFragment>()
serializeClasses(fqName, classesBuilder, classifierDescriptors)
val classesProto = classesBuilder.build()
result += classifierDescriptors.chunked(TOP_LEVEL_CLASS_DECLARATION_COUNT_PER_FILE) { descriptors ->
val packageProto = topSerializer.packagePartProto(fqName, members).build()
?: error("Package fragments not serialized: $fragments")
withNewContext {
val strings = serializerExtension.stringTable
val (stringTableProto, nameTableProto) = strings.buildProto()
val classesProto = buildClassesProto { classesBuilder ->
serializeClasses(fqName, classesBuilder, descriptors)
}
val isEmpty = members.isEmpty() && classifierDescriptors.isEmpty()
val fragmentBuilder = KonanProtoBuf.LinkDataPackageFragment.newBuilder()
val typeAliases = descriptors.filterIsInstance<TypeAliasDescriptor>()
val packageProto =
if (typeAliases.isNotEmpty()) buildPackageProto(fqName, typeAliases, fragments)
else emptyPackageProto()
val fragmentProto = fragmentBuilder
.setPackage(packageProto)
.setFqName(fqName.asString())
.setClasses(classesProto)
.setStringTable(stringTableProto)
.setNameTable(nameTableProto)
.setIsEmpty(isEmpty)
.build()
buildFragment(
packageProto,
classesProto,
fqName,
descriptors.isEmpty()
)
}
}
return fragmentProto
result += topLevelDescriptors.chunked(TOP_LEVEL_DECLARATION_COUNT_PER_FILE) { descriptors ->
withNewContext {
buildFragment(
buildPackageProto(fqName, descriptors, fragments),
buildClassesProto {},
fqName,
descriptors.isEmpty())
}
}
if (result.isEmpty()) {
result += withNewContext {
buildFragment(
emptyPackageProto(),
buildClassesProto {},
fqName,
true)
}
}
return result
}
private fun buildClassesProto(action: (KonanProtoBuf.LinkDataClasses.Builder) -> Unit): KonanProtoBuf.LinkDataClasses {
val classesBuilder = KonanProtoBuf.LinkDataClasses.newBuilder()
action(classesBuilder)
return classesBuilder.build()
}
private fun emptyPackageProto(): ProtoBuf.Package = ProtoBuf.Package.newBuilder().build()
private fun SerializerContext.buildPackageProto(
fqName: FqName,
descriptors: List<DeclarationDescriptor>,
fragments: List<PackageFragmentDescriptor>) = topSerializer.packagePartProto(fqName, descriptors).build()
?: error("Package fragments not serialized: $fragments")
private fun getPackagesFqNames(module: ModuleDescriptor): Set<FqName> {
val result = mutableSetOf<FqName>()
@@ -129,25 +187,47 @@ internal class KonanSerializationUtil(val context: Context, metadataVersion: Bin
return result
}
private fun SerializerContext.buildFragment(
packageProto: ProtoBuf.Package,
classesProto: KonanProtoBuf.LinkDataClasses,
fqName: FqName,
isEmpty: Boolean
): KonanProtoBuf.LinkDataPackageFragment {
val (stringTableProto, nameTableProto) = serializerExtension.stringTable.buildProto()
return KonanProtoBuf.LinkDataPackageFragment.newBuilder()
.setPackage(packageProto)
.setClasses(classesProto)
.setIsEmpty(isEmpty)
.setFqName(fqName.asString())
.setStringTable(stringTableProto)
.setNameTable(nameTableProto)
.build()
}
internal fun serializeModule(moduleDescriptor: ModuleDescriptor): LinkData {
val libraryProto = KonanProtoBuf.LinkDataLibrary.newBuilder()
libraryProto.moduleName = moduleDescriptor.name.asString()
val fragments = mutableListOf<ByteArray>()
val fragments = mutableListOf<List<ByteArray>>()
val fragmentNames = mutableListOf<String>()
getPackagesFqNames(moduleDescriptor).forEach iteration@ {
val packageProto = serializePackage(it, moduleDescriptor)
if (packageProto == null) return@iteration
getPackagesFqNames(moduleDescriptor).forEach iteration@{ packageFqName ->
val packageProtos = serializePackage(packageFqName, moduleDescriptor)
if (packageProtos.isEmpty()) return@iteration
libraryProto.addPackageFragmentName(it.asString())
if (packageProto.isEmpty) {
libraryProto.addEmptyPackage(it.asString())
val packageFqNameStr = packageFqName.asString()
libraryProto.addPackageFragmentName(packageFqNameStr)
if (packageProtos.all { it.isEmpty }) {
libraryProto.addEmptyPackage(packageFqNameStr)
}
fragments.add(packageProto.toByteArray())
fragmentNames.add(it.asString())
fragments.add(packageProtos.map { it.toByteArray() })
fragmentNames.add(packageFqNameStr)
}
val libraryAsByteArray = libraryProto.build().toByteArray()
return LinkData(libraryAsByteArray, fragments, fragmentNames)
}
}
private const val TOP_LEVEL_DECLARATION_COUNT_PER_FILE = 128
private const val TOP_LEVEL_CLASS_DECLARATION_COUNT_PER_FILE = 64
@@ -18,8 +18,9 @@ class KonanClassDataFinder(
val nameList = proto.classNameList
val index = nameList.indexOfFirst { nameResolver.getClassId(it) == classId }
if (index == -1)
error("Could not find serialized class $classId")
if (index == -1) {
return null
}
val foundClass = proto.getClasses(index) ?: error("Could not find data for serialized class $classId")
@@ -19,7 +19,8 @@ class KonanPackageFragment(
private val library: KonanLibrary,
private val packageAccessedHandler: PackageAccessedHandler?,
storageManager: StorageManager,
module: ModuleDescriptor
module: ModuleDescriptor,
partName: String
) : DeserializedPackageFragment(fqName, storageManager, module) {
lateinit var components: DeserializationComponents
@@ -31,7 +32,7 @@ class KonanPackageFragment(
// 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()))
parsePackageFragment(library.packageMetadata(fqName.asString(), partName))
}
val proto: KonanProtoBuf.LinkDataPackageFragment
@@ -29,8 +29,12 @@ internal object KonanDeserializedPackageFragmentsFactoryImpl: KonanDeserializedP
moduleDescriptor: ModuleDescriptor,
packageAccessedHandler: PackageAccessedHandler?,
storageManager: StorageManager
) = packageFragmentNames.map {
KonanPackageFragment(FqName(it), library, packageAccessedHandler, storageManager, moduleDescriptor)
) = packageFragmentNames.flatMap {
val fqName = FqName(it)
val parts = library.packageMetadataParts(fqName.asString())
parts.map { partName ->
KonanPackageFragment(fqName, library, packageAccessedHandler, storageManager, moduleDescriptor, partName)
}
}
override fun createSyntheticPackageFragments(
@@ -23,7 +23,8 @@ class KlibPrinter(out: Appendable) {
get() = kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE
val DeclarationDescriptor.shouldBePrinted: Boolean
get() = this is ClassDescriptor && isPublicOrProtected || this is CallableMemberDescriptor && isPublicOrProtected && !isFakeOverride
get() = this is ClassifierDescriptorWithTypeParameters && isPublicOrProtected
|| this is CallableMemberDescriptor && isPublicOrProtected && !isFakeOverride
private fun Printer.printBody(header: CharSequence, block: () -> Unit) {
println()
@@ -35,7 +36,7 @@ class KlibPrinter(out: Appendable) {
println()
}
private fun ClassDescriptor.render(): String {
private fun ClassifierDescriptorWithTypeParameters.render(): String {
val renderer = when (modality) {
// Don't render 'final' modality
Modality.FINAL -> Renderers.WITHOUT_MODALITY
@@ -131,6 +132,10 @@ class KlibPrinter(out: Appendable) {
override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, data: Unit) {
printer.println(descriptor.render())
}
override fun visitTypeAliasDescriptor(descriptor: TypeAliasDescriptor, data: Unit) {
printer.println(descriptor.render())
}
}
object Renderers {
@@ -39,6 +39,12 @@ class ContentsTest {
@Test
fun topLevelFunctions() = klibContents(testLibrary("TopLevelFunctions")) {
"""
package <root> {
annotation class A constructor() : Annotation
annotation class B constructor() : Annotation
class Foo constructor()
}
package <root> {
@A @B fun a()
fun f1(x: Foo)
@@ -56,9 +62,6 @@ class ContentsTest {
inline fun <reified T> t4(x: T)
fun <T : Number> t5(x: T)
fun Foo.e()
annotation class A constructor() : Annotation
annotation class B constructor() : Annotation
class Foo constructor()
}
""".trimIndent()
}
@@ -285,6 +288,74 @@ class ContentsTest {
""".trimIndent()
}
@Test
fun topLevelPropertiesCustomPackage() = klibContents(testLibrary("TopLevelPropertiesCustomPackage")) {
"""
package custom.pkg {
typealias MyTransformer = (String) -> Int
}
package custom.pkg {
val v1: Int = 1
val v2: String = "hello"
val v3: (String) -> Int
val v4: MyTransformer /* = (String) -> Int */
}
""".trimIndent()
}
@Test
fun topLevelPropertiesRootPackage() = klibContents(testLibrary("TopLevelPropertiesRootPackage")) {
"""
package <root> {
typealias MyTransformer = (String) -> Int
}
package <root> {
val v1: Int = 1
val v2: String = "hello"
val v3: (String) -> Int
val v4: MyTransformer /* = (String) -> Int */
}
""".trimIndent()
}
@Test
fun topLevelPropertiesWithClassesCustomPackage() = klibContents(testLibrary("TopLevelPropertiesWithClassesCustomPackage")) {
"""
package custom.pkg {
object Bar
class Foo constructor()
typealias MyTransformer = (String) -> Int
}
package custom.pkg {
val v1: Int = 1
val v2: String = "hello"
val v3: (String) -> Int
val v4: MyTransformer /* = (String) -> Int */
}
""".trimIndent()
}
@Test
fun topLevelPropertiesWithClassesRootPackage() = klibContents(testLibrary("TopLevelPropertiesWithClassesRootPackage")) {
"""
package <root> {
object Bar
class Foo constructor()
typealias MyTransformer = (String) -> Int
}
package <root> {
val v1: Int = 1
val v2: String = "hello"
val v3: (String) -> Int
val v4: MyTransformer /* = (String) -> Int */
}
""".trimIndent()
}
companion object {
val LIBRARY_DIRECTORY = Paths.get("build/konan/libs").resolve( HostManager.hostName)
}
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2018 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("UNUSED_PARAMETER")
package custom.pkg
typealias MyTransformer = (String) -> Int
// top-level properties
val v1 = 1
val v2 = "hello"
val v3: (String) -> Int = { it.length }
val v4: MyTransformer = v3
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2018 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("UNUSED_PARAMETER")
typealias MyTransformer = (String) -> Int
// top-level properties
val v1 = 1
val v2 = "hello"
val v3: (String) -> Int = { it.length }
val v4: MyTransformer = v3
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2018 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("UNUSED_PARAMETER")
package custom.pkg
class Foo
typealias MyTransformer = (String) -> Int
// top-level properties
val v1 = 1
val v2 = "hello"
val v3: (String) -> Int = { it.length }
val v4: MyTransformer = v3
object Bar
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2018 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("UNUSED_PARAMETER")
class Foo
typealias MyTransformer = (String) -> Int
// top-level properties
val v1 = 1
val v2 = "hello"
val v3: (String) -> Int = { it.length }
val v4: MyTransformer = v3
object Bar
@@ -40,7 +40,8 @@ interface KonanLibrary {
val dataFlowGraph: ByteArray?
val moduleHeaderData: ByteArray
fun packageMetadata(fqName: String): ByteArray
fun packageMetadataParts(fqName: String): Set<String>
fun packageMetadata(fqName: String, partName: String): ByteArray
}
val KonanLibrary.uniqueName
@@ -63,7 +64,6 @@ val KonanLibrary.exportForwardDeclarations
.split(' ').asSequence()
.map { it.trim() }
.filter { it.isNotEmpty() }
.map { it }
.toList()
val KonanLibrary.includedHeaders
@@ -39,6 +39,9 @@ interface KonanLibraryLayout {
val dataFlowGraphFile
get() = File(linkdataDir, "module_data_flow_graph")
fun packageFile(packageName: String)
= File(linkdataDir, if (packageName == "") "root_package.knm" else "package_$packageName.knm")
fun packageFragmentsDir(packageName: String)
= File(linkdataDir, if (packageName == "") "root_package" else "package_$packageName")
fun packageFragmentFile(packageFqName: String, partName: String) =
File(packageFragmentsDir(packageFqName), "$partName$KLIB_METADATA_FILE_EXTENSION_WITH_DOT")
}
@@ -8,8 +8,11 @@ import org.jetbrains.kotlin.konan.library.impl.KonanLibraryImpl
import org.jetbrains.kotlin.konan.library.impl.zippedKonanLibraryChecks
import org.jetbrains.kotlin.konan.target.KonanTarget
val KLIB_FILE_EXTENSION = "klib"
val KLIB_FILE_EXTENSION_WITH_DOT = ".$KLIB_FILE_EXTENSION"
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"
fun File.unpackZippedKonanLibraryTo(newDir: File) {
@@ -2,5 +2,5 @@ package org.jetbrains.kotlin.konan.library
interface MetadataReader {
fun loadSerializedModule(libraryLayout: KonanLibraryLayout): ByteArray
fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String): ByteArray
fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String, partName: String): ByteArray
}
@@ -8,6 +8,6 @@ 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()
override fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String, partName: String): ByteArray =
libraryLayout.packageFragmentFile(fqName, partName).readBytes()
}
@@ -50,7 +50,24 @@ class KonanLibraryImpl(
override val moduleHeaderData: ByteArray by lazy { layout.inPlace { metadataReader.loadSerializedModule(it) } }
override fun packageMetadata(fqName: String) = layout.inPlace { metadataReader.loadSerializedPackageFragment(it, fqName) }
override fun packageMetadata(packageFqName: String, partName: String) =
layout.inPlace { metadataReader.loadSerializedPackageFragment(it, packageFqName, partName) }
override fun packageMetadataParts(fqName: String): Set<String> =
layout.inPlace { inPlaceLayout ->
val fileList =
inPlaceLayout.packageFragmentsDir(fqName)
.listFiles
.mapNotNull {
it.name
.substringBeforeLast(KLIB_METADATA_FILE_EXTENSION_WITH_DOT, missingDelimiterValue = "")
.takeIf { it.isNotEmpty() }
}
fileList.toSortedSet().also {
require(it.size == fileList.size) { "Duplicated names: ${fileList.groupingBy { it }.eachCount().filter { (_, count) -> count > 1 }}" }
}
}
override fun toString() = "$libraryName[default=$isDefault]"
}