From 3d928a084296e2493754a5d99f4ae1c3cb9d1cfb Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 17 Apr 2015 21:19:19 +0300 Subject: [PATCH] Refactor deserialization initialization in built-ins and JS BuiltinsPackageFragment was only designed to work with a single instance alive. Because of this, it was creating deserialization subsystem upon initialization. This was not working perfectly in JS where it was used, because multiple storage managers, class caches and other components were created for each package, leading to different concurrency errors and performance hits. Also in the near future another package fragment will be needed to represent the built-in package "kotlin.reflect" --- .../builtins/BuiltInsSerializerTest.kt | 18 +++-- .../js/KotlinJavascriptSerializerTest.kt | 5 +- .../builtins/BuiltInsClassDataFinder.kt | 49 ++++++++++++ .../builtins/BuiltInsSerializationUtil.kt | 16 ++-- .../builtins/BuiltinsPackageFragment.kt | 77 +++++-------------- .../kotlin/builtins/KotlinBuiltIns.java | 16 ++-- .../builtInsPackageFragmentProvider.kt | 60 +++++++++++++++ .../idea/caches/resolve/JsAnalyzerFacade.kt | 3 +- .../jetbrains/kotlin/js/config/Config.java | 18 +++-- .../js/KotlinJavascriptSerializationUtil.kt | 23 +++--- 10 files changed, 183 insertions(+), 102 deletions(-) create mode 100644 core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsClassDataFinder.kt create mode 100644 core/descriptors/src/org/jetbrains/kotlin/builtins/builtInsPackageFragmentProvider.kt diff --git a/compiler/tests/org/jetbrains/kotlin/serialization/builtins/BuiltInsSerializerTest.kt b/compiler/tests/org/jetbrains/kotlin/serialization/builtins/BuiltInsSerializerTest.kt index a7df56faf48..1c34a00bb16 100644 --- a/compiler/tests/org/jetbrains/kotlin/serialization/builtins/BuiltInsSerializerTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/serialization/builtins/BuiltInsSerializerTest.kt @@ -16,8 +16,8 @@ package org.jetbrains.kotlin.serialization.builtins -import org.jetbrains.kotlin.builtins.BuiltinsPackageFragment import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.createBuiltInPackageFragmentProvider import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime import org.jetbrains.kotlin.jvm.compiler.LoadDescriptorUtil.TEST_PACKAGE_FQNAME import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeCapabilitiesDeserializer @@ -40,19 +40,21 @@ public class BuiltInsSerializerTest : TestCaseWithTmpdir() { val module = JetTestUtils.createEmptyModule("") - val packageFragment = - BuiltinsPackageFragment(TEST_PACKAGE_FQNAME, LockBasedStorageManager(), module, FlexibleTypeCapabilitiesDeserializer.ThrowException) { - val file = File(tmpdir, it) - if (file.exists()) FileInputStream(file) else null - } + val packageFragmentProvider = createBuiltInPackageFragmentProvider( + LockBasedStorageManager(), module, setOf(TEST_PACKAGE_FQNAME), + FlexibleTypeCapabilitiesDeserializer.ThrowException + ) { + val file = File(tmpdir, it) + if (file.exists()) FileInputStream(file) else null + } - module.initialize(packageFragment.provider) + module.initialize(packageFragmentProvider) module.addDependencyOnModule(module) module.addDependencyOnModule(KotlinBuiltIns.getInstance().getBuiltInsModule()) module.seal() RecursiveDescriptorComparator.validateAndCompareDescriptorWithFile( - module.getPackage(TEST_PACKAGE_FQNAME), + module.getPackage(TEST_PACKAGE_FQNAME)!!, RecursiveDescriptorComparator.DONT_INCLUDE_METHODS_OF_OBJECT, File(source.replace(".kt", ".txt")) ) diff --git a/compiler/tests/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerTest.kt b/compiler/tests/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerTest.kt index be57058f20a..9dfa2d41a33 100644 --- a/compiler/tests/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerTest.kt @@ -25,7 +25,6 @@ import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.addKotlinSourceRoots -import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS import org.jetbrains.kotlin.js.config.LibrarySourcesConfig @@ -35,6 +34,7 @@ import org.jetbrains.kotlin.test.JetTestUtils import org.jetbrains.kotlin.test.TestCaseWithTmpdir import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils +import org.jetbrains.kotlin.utils.sure import java.io.File public class KotlinJavascriptSerializerTest : TestCaseWithTmpdir() { @@ -81,7 +81,8 @@ public class KotlinJavascriptSerializerTest : TestCaseWithTmpdir() { val metadata = KotlinJavascriptMetadataUtils.loadMetadata(metaFile) assert(metadata.size() == 1) - val provider = CompositePackageFragmentProvider(KotlinJavascriptSerializationUtil.getPackageFragmentProviders(module, metadata[0].body)) + val provider = KotlinJavascriptSerializationUtil.createPackageFragmentProvider(module, metadata[0].body) + .sure { "No package fragment provider was created" } module.initialize(provider) module.addDependencyOnModule(module) diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsClassDataFinder.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsClassDataFinder.kt new file mode 100644 index 00000000000..6d97aa5cb1b --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsClassDataFinder.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2010-2015 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. + */ + +package org.jetbrains.kotlin.builtins + +import org.jetbrains.kotlin.descriptors.PackageFragmentProvider +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.serialization.ClassData +import org.jetbrains.kotlin.serialization.ProtoBuf +import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder +import java.io.InputStream + +public class BuiltInsClassDataFinder( + private val packageFragmentProvider: PackageFragmentProvider, + private val loadResource: (path: String) -> InputStream? +) : ClassDataFinder { + override fun findClassData(classId: ClassId): ClassData? { + val packageFragment = packageFragmentProvider.getPackageFragments(classId.getPackageFqName()).singleOrNull() ?: return null + + val stream = loadResource(BuiltInsSerializationUtil.getClassMetadataPath(classId)) ?: return null + + val classProto = ProtoBuf.Class.parseFrom(stream, BuiltInsSerializationUtil.EXTENSION_REGISTRY) + val nameResolver = + (packageFragment as? BuiltinsPackageFragment ?: error("Not a built-in package fragment: $packageFragment")).nameResolver + + val expectedShortName = classId.getShortClassName() + val actualShortName = nameResolver.getClassId(classProto.getFqName()).getShortClassName() + if (!actualShortName.isSpecial() && actualShortName != expectedShortName) { + // Workaround for case-insensitive file systems, + // otherwise we'd find "Collection" for "collection" etc + return null + } + + return ClassData(nameResolver, classProto) + } +} diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsSerializationUtil.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsSerializationUtil.kt index 96bf07631b1..a3480c4e747 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsSerializationUtil.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsSerializationUtil.kt @@ -16,14 +16,23 @@ package org.jetbrains.kotlin.builtins -import org.jetbrains.kotlin.name.* +import com.google.protobuf.ExtensionRegistryLite +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf import kotlin.platform.platformStatic public object BuiltInsSerializationUtil { + public val EXTENSION_REGISTRY: ExtensionRegistryLite + + init { + EXTENSION_REGISTRY = ExtensionRegistryLite.newInstance() + BuiltInsProtoBuf.registerAllExtensions(EXTENSION_REGISTRY) + } + private val CLASS_METADATA_FILE_EXTENSION = "kotlin_class" private val PACKAGE_FILE_NAME = ".kotlin_package" private val STRING_TABLE_FILE_NAME = ".kotlin_string_table" - private val CLASS_NAMES_FILE_NAME = ".kotlin_class_names" platformStatic public fun getClassMetadataPath(classId: ClassId): String { return packageFqNameToPath(classId.getPackageFqName()) + "/" + classId.getRelativeClassName().asString() + @@ -36,9 +45,6 @@ public object BuiltInsSerializationUtil { platformStatic public fun getStringTableFilePath(fqName: FqName): String = packageFqNameToPath(fqName) + "/" + STRING_TABLE_FILE_NAME - platformStatic public fun getClassNamesFilePath(fqName: FqName): String = - packageFqNameToPath(fqName) + "/" + CLASS_NAMES_FILE_NAME - private fun packageFqNameToPath(fqName: FqName): String = fqName.asString().replace('.', '/') } diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltinsPackageFragment.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltinsPackageFragment.kt index 40fee3e09b1..0eb6093b304 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltinsPackageFragment.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltinsPackageFragment.kt @@ -16,86 +16,45 @@ package org.jetbrains.kotlin.builtins -import com.google.protobuf.ExtensionRegistryLite import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.PackageFragmentProvider -import org.jetbrains.kotlin.descriptors.PackageFragmentProviderImpl import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl -import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.serialization.ClassData import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf -import org.jetbrains.kotlin.serialization.deserialization.* +import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents +import org.jetbrains.kotlin.serialization.deserialization.NameResolver import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope import org.jetbrains.kotlin.storage.StorageManager import java.io.InputStream +import javax.inject.Inject +import kotlin.properties.Delegates public class BuiltinsPackageFragment( fqName: FqName, storageManager: StorageManager, module: ModuleDescriptor, - flexibleTypeCapabilitiesDeserializer: FlexibleTypeCapabilitiesDeserializer, private val loadResource: (path: String) -> InputStream? ) : PackageFragmentDescriptorImpl(module, fqName) { - private val extensionRegistry: ExtensionRegistryLite + val nameResolver = NameResolver.read(loadResourceSure(BuiltInsSerializationUtil.getStringTableFilePath(fqName))) - init { - extensionRegistry = ExtensionRegistryLite.newInstance() - BuiltInsProtoBuf.registerAllExtensions(extensionRegistry) - extensionRegistry + private var components: DeserializationComponents by Delegates.notNull() + + Inject + public fun setDeserializationComponents(components: DeserializationComponents) { + this.components = components } - private val nameResolver = NameResolver.read( - getStream(BuiltInsSerializationUtil.getStringTableFilePath(fqName)) - ) - - public val provider: PackageFragmentProvider = PackageFragmentProviderImpl(listOf(this)) - - private val members: DeserializedPackageMemberScope = run { - val proto = loadPackage() - val localClassResolver = LocalClassResolverImpl() - val components = DeserializationComponents( - storageManager, module, BuiltInsClassDataFinder(), - BuiltInsAnnotationAndConstantLoader(getContainingDeclaration()), - provider, localClassResolver, - flexibleTypeCapabilitiesDeserializer - ) - localClassResolver.setDeserializationComponents(components) - DeserializedPackageMemberScope(this, proto, nameResolver, components, { readClassNames(proto) }) + private val memberScope = storageManager.createLazyValue { + val stream = loadResourceSure(BuiltInsSerializationUtil.getPackageFilePath(fqName)) + val proto = ProtoBuf.Package.parseFrom(stream, BuiltInsSerializationUtil.EXTENSION_REGISTRY) + DeserializedPackageMemberScope(this, proto, nameResolver, components, classNames = { + proto.getExtension(BuiltInsProtoBuf.className)?.map { id -> nameResolver.getName(id) } ?: listOf() + }) } - private fun loadPackage(): ProtoBuf.Package { - val stream = getStream(BuiltInsSerializationUtil.getPackageFilePath(fqName)) - return ProtoBuf.Package.parseFrom(stream, extensionRegistry) - } + override fun getMemberScope() = memberScope() - private fun readClassNames(proto: ProtoBuf.Package): List { - return proto.getExtension(BuiltInsProtoBuf.className)?.map { id -> nameResolver.getName(id) } ?: listOf() - } - - override fun getMemberScope() = members - - private fun getStream(path: String): InputStream = + private fun loadResourceSure(path: String): InputStream = loadResource(path) ?: throw IllegalStateException("Resource not found in classpath: $path") - - private inner class BuiltInsClassDataFinder : ClassDataFinder { - override fun findClassData(classId: ClassId): ClassData? { - val stream = loadResource(BuiltInsSerializationUtil.getClassMetadataPath(classId)) ?: return null - - val classProto = ProtoBuf.Class.parseFrom(stream, extensionRegistry) - - val expectedShortName = classId.getShortClassName() - val actualShortName = nameResolver.getClassId(classProto.getFqName()).getShortClassName() - if (!actualShortName.isSpecial() && actualShortName != expectedShortName) { - // Workaround for case-insensitive file systems, - // otherwise we'd find "Collection" for "collection" etc - return null - } - - return ClassData(nameResolver, classProto) - } - } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index 1916111dac6..c5908163e43 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -40,6 +40,7 @@ import org.jetbrains.kotlin.types.checker.JetTypeChecker; import java.io.InputStream; import java.util.*; +import static kotlin.KotlinPackage.single; import static org.jetbrains.kotlin.builtins.PrimitiveType.*; public class KotlinBuiltIns { @@ -109,22 +110,25 @@ public class KotlinBuiltIns { private KotlinBuiltIns() { builtInsModule = new ModuleDescriptorImpl( - Name.special(""), Collections.emptyList(), PlatformToKotlinClassMap.EMPTY + Name.special(""), Collections.emptyList(), PlatformToKotlinClassMap.EMPTY ); - builtinsPackageFragment = new BuiltinsPackageFragment( - BUILT_INS_PACKAGE_FQ_NAME, new LockBasedStorageManager(), builtInsModule, - FlexibleTypeCapabilitiesDeserializer.ThrowException.INSTANCE$, - new Function1() { + + PackageFragmentProvider packageFragmentProvider = BuiltinsPackage.createBuiltInPackageFragmentProvider( + new LockBasedStorageManager(), builtInsModule, Collections.singleton(BUILT_INS_PACKAGE_FQ_NAME), + FlexibleTypeCapabilitiesDeserializer.ThrowException.INSTANCE$, new Function1() { @Override public InputStream invoke(String path) { return KotlinBuiltIns.class.getClassLoader().getResourceAsStream(path); } } ); - builtInsModule.initialize(builtinsPackageFragment.getProvider()); + + builtInsModule.initialize(packageFragmentProvider); builtInsModule.addDependencyOnModule(builtInsModule); builtInsModule.seal(); + builtinsPackageFragment = (BuiltinsPackageFragment) single(packageFragmentProvider.getPackageFragments(BUILT_INS_PACKAGE_FQ_NAME)); + primitiveTypeToNullableJetType = new EnumMap(PrimitiveType.class); primitiveTypeToArrayJetType = new EnumMap(PrimitiveType.class); primitiveJetTypeToJetArrayType = new HashMap(); diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/builtInsPackageFragmentProvider.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/builtInsPackageFragmentProvider.kt new file mode 100644 index 00000000000..97717b15657 --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/builtInsPackageFragmentProvider.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2010-2015 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. + */ + +package org.jetbrains.kotlin.builtins + +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.PackageFragmentProvider +import org.jetbrains.kotlin.descriptors.PackageFragmentProviderImpl +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents +import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeCapabilitiesDeserializer +import org.jetbrains.kotlin.serialization.deserialization.LocalClassResolverImpl +import org.jetbrains.kotlin.storage.StorageManager +import java.io.InputStream + +public fun createBuiltInPackageFragmentProvider( + storageManager: StorageManager, + module: ModuleDescriptor, + packageFqNames: Set, + flexibleTypeCapabilitiesDeserializer: FlexibleTypeCapabilitiesDeserializer, + loadResource: (String) -> InputStream? +): PackageFragmentProvider { + val packageFragments = packageFqNames.map { fqName -> + BuiltinsPackageFragment(fqName, storageManager, module, loadResource) + } + val provider = PackageFragmentProviderImpl(packageFragments) + + val localClassResolver = LocalClassResolverImpl() + + val components = DeserializationComponents( + storageManager, + module, + BuiltInsClassDataFinder(provider, loadResource), + BuiltInsAnnotationAndConstantLoader(module), + provider, + localClassResolver, + flexibleTypeCapabilitiesDeserializer + ) + + localClassResolver.setDeserializationComponents(components) + + for (packageFragment in packageFragments) { + packageFragment.setDeserializationComponents(components) + } + + return provider +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/JsAnalyzerFacade.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/JsAnalyzerFacade.kt index 0faf74c4cbb..6473da7a41a 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/JsAnalyzerFacade.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/JsAnalyzerFacade.kt @@ -66,7 +66,8 @@ public object JsAnalyzerFacade : AnalyzerFacade report); + public abstract boolean checkLibFilesAndReportErrors(@NotNull Function1 report); protected abstract void init(@NotNull List sourceFilesInLibraries, @NotNull List metadata); @@ -117,10 +118,10 @@ public abstract class Config { if (moduleDescriptors != null) return moduleDescriptors; moduleDescriptors = new SmartList(); - for(KotlinJavascriptMetadata metadataEntry : metadata) { + for (KotlinJavascriptMetadata metadataEntry : metadata) { moduleDescriptors.add(createModuleDescriptor(metadataEntry)); } - for(ModuleDescriptorImpl module : moduleDescriptors) { + for (ModuleDescriptorImpl module : moduleDescriptors) { setDependencies(module, moduleDescriptors); module.seal(); } @@ -149,18 +150,19 @@ public abstract class Config { private static ModuleDescriptorImpl createModuleDescriptor(KotlinJavascriptMetadata metadata) { ModuleDescriptorImpl moduleDescriptor = TopDownAnalyzerFacadeForJS.createJsModule("<" + metadata.getModuleName() + ">"); - List providers = KotlinJavascriptSerializationUtil - .getPackageFragmentProviders(moduleDescriptor, metadata.getBody()); - CompositePackageFragmentProvider compositePackageFragmentProvider = new CompositePackageFragmentProvider(providers); + PackageFragmentProvider provider = + KotlinJavascriptSerializationUtil.createPackageFragmentProvider(moduleDescriptor, metadata.getBody()); - moduleDescriptor.initialize(compositePackageFragmentProvider); + moduleDescriptor.initialize( + provider != null ? provider : new CompositePackageFragmentProvider(Collections.emptyList()) + ); moduleDescriptor.addDependencyOnModule(KotlinBuiltIns.getInstance().getBuiltInsModule()); return moduleDescriptor; } private static void setDependencies(ModuleDescriptorImpl module, List modules) { - for(ModuleDescriptorImpl moduleItem : modules) { + for (ModuleDescriptorImpl moduleItem : modules) { module.addDependencyOnModule(moduleItem); } } diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt index 0db37caa5aa..f6b9a14ceed 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt @@ -18,7 +18,7 @@ package org.jetbrains.kotlin.serialization.js import com.google.protobuf.ByteString import org.jetbrains.kotlin.builtins.BuiltInsSerializationUtil -import org.jetbrains.kotlin.builtins.BuiltinsPackageFragment +import org.jetbrains.kotlin.builtins.createBuiltInPackageFragmentProvider import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor @@ -44,29 +44,26 @@ public object KotlinJavascriptSerializationUtil { private val PACKAGE_FILE_SUFFIX = "/.kotlin_package" platformStatic - public fun getPackageFragmentProviders(moduleDescriptor: ModuleDescriptor, metadata: ByteArray): List { + public fun createPackageFragmentProvider(moduleDescriptor: ModuleDescriptor, metadata: ByteArray): PackageFragmentProvider? { val gzipInputStream = GZIPInputStream(ByteArrayInputStream(metadata)) val content = JsProtoBuf.Library.parseFrom(gzipInputStream) gzipInputStream.close() val contentMap: MutableMap = hashMapOf() - for(index in 0..content.getEntryCount()-1) { + for (index in content.getEntryCount().indices) { val entry = content.getEntry(index) contentMap[entry.getPath()] = entry.getContent().toByteArray() } - val packages = getPackages(contentMap) + val packageFqNames = getPackages(contentMap).map { FqName(it) }.toSet() + if (packageFqNames.isEmpty()) return null - val load = { path: String -> if (!contentMap.containsKey(path)) null else ByteArrayInputStream(contentMap.get(path)) } - - val providers = arrayListOf() - for (packageName in packages) { - val fqName = FqName(packageName) - val packageFragment = BuiltinsPackageFragment(fqName, LockBasedStorageManager(), moduleDescriptor, FlexibleTypeCapabilitiesDeserializer.Dynamic, load) - providers.add(packageFragment.provider) + return createBuiltInPackageFragmentProvider( + LockBasedStorageManager(), moduleDescriptor, packageFqNames, FlexibleTypeCapabilitiesDeserializer.Dynamic + ) { + path -> + if (!contentMap.containsKey(path)) null else ByteArrayInputStream(contentMap.get(path)) } - - return providers } public fun contentMapToByteArray(contentMap: Map): ByteArray {