From 7c8c5b057feace4a907dfac3d917e61089b64bc7 Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Mon, 27 Apr 2020 17:26:51 +0300 Subject: [PATCH] Extensible mechanism for plugin metadata during descriptor serialization A mechanism that allows kotlinx.serialization plugin to preserve the correct (program) order of properties after serializing/deserializing descriptors to kotlin metadata, which is needed for correct and stable json serialization of class hierarchies in incremental/multi-module scenario. It uses protobuf extensions. --- .../incremental/JavaClassesTrackerImpl.kt | 15 +----- .../codegen/ImplementationBodyCodegen.java | 2 +- .../jetbrains/kotlin/codegen/ScriptCodegen.kt | 2 +- .../kotlin/codegen/classFileUtils.kt | 15 +----- .../builtins/BuiltInsSerializer.kt | 23 +++------ .../cli/metadata/K2MetadataKlibSerializer.kt | 4 +- .../kotlin/cli/metadata/MetadataSerializer.kt | 15 +----- .../jetbrains/kotlin/resolve/resolveUtil.kt | 2 +- .../KlibMetadataIncrementalSerializer.kt | 2 +- .../KlibMetadataMonolithicSerializer.kt | 5 ++ .../metadata/KlibMetadataSerializer.kt | 8 ++-- .../jetbrains/kotlin/ir/backend/js/klib.kt | 2 +- .../serialization/DescriptorSerializer.kt | 17 +++++-- .../DescriptorSerializerPlugin.kt | 21 ++++++++ .../generators/protobuf/GenerateProtoBuf.kt | 18 ++----- .../js/KotlinJavascriptSerializationUtil.kt | 15 +----- .../konan/NativeDistributionCommonizer.kt | 2 +- .../build.gradle.kts | 1 + .../src/class_extensions.proto | 11 +++++ .../SerializationComponentRegistrar.kt | 31 +++++++----- ...DescriptorPluginForKotlinxSerialization.kt | 48 +++++++++++++++++++ ...SerializationPluginMetadataExtensions.java | 43 +++++++++++++++++ .../resolve/SerializableProperties.kt | 26 ++++++++-- ...izationIrBytecodeListingTestGenerated.java | 3 +- ...ionPluginBytecodeListingTestGenerated.java | 3 +- .../testData/codegen/Basic.ir.txt | 20 +++----- 26 files changed, 225 insertions(+), 129 deletions(-) create mode 100644 compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializerPlugin.kt create mode 100644 plugins/kotlin-serialization/kotlin-serialization-compiler/src/class_extensions.proto create mode 100644 plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationDescriptorPluginForKotlinxSerialization.kt create mode 100644 plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationPluginMetadataExtensions.java diff --git a/build-common/src/org/jetbrains/kotlin/incremental/JavaClassesTrackerImpl.kt b/build-common/src/org/jetbrains/kotlin/incremental/JavaClassesTrackerImpl.kt index 4e4294720fe..fe6f3dd1759 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/JavaClassesTrackerImpl.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/JavaClassesTrackerImpl.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2017 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. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.incremental diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 7c20d679977..fe791d73827 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.kt index 0db6225ffb8..d44d9d327cd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/classFileUtils.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/classFileUtils.kt index 8d1b64ca375..1e46b822f9a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/classFileUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/classFileUtils.kt @@ -1,17 +1,6 @@ /* - * 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. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.codegen diff --git a/compiler/builtins-serializer/src/org/jetbrains/kotlin/serialization/builtins/BuiltInsSerializer.kt b/compiler/builtins-serializer/src/org/jetbrains/kotlin/serialization/builtins/BuiltInsSerializer.kt index f0da913c251..8d4e7b00706 100644 --- a/compiler/builtins-serializer/src/org/jetbrains/kotlin/serialization/builtins/BuiltInsSerializer.kt +++ b/compiler/builtins-serializer/src/org/jetbrains/kotlin/serialization/builtins/BuiltInsSerializer.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2016 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. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.builtins @@ -97,10 +86,10 @@ class BuiltInsSerializer(dependOnOldBuiltIns: Boolean) : MetadataSerializer(Buil fqName -> val packageView = module.getPackage(fqName) PackageSerializer( - packageView.memberScope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS) + createCloneable(module), - packageView.fragments.flatMap { fragment -> DescriptorUtils.getAllDescriptors(fragment.getMemberScope()) }, - packageView.fqName, - File(destDir, BuiltInSerializerProtocol.getBuiltInsFilePath(packageView.fqName)) + packageView.memberScope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS) + createCloneable(module), + packageView.fragments.flatMap { fragment -> DescriptorUtils.getAllDescriptors(fragment.getMemberScope()) }, + packageView.fqName, + File(destDir, BuiltInSerializerProtocol.getBuiltInsFilePath(packageView.fqName)) ).run() } } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/K2MetadataKlibSerializer.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/K2MetadataKlibSerializer.kt index 5c3659df68e..e2fc3a8262b 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/K2MetadataKlibSerializer.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/K2MetadataKlibSerializer.kt @@ -1,11 +1,11 @@ /* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * 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.metadata -import org.jetbrains.kotlin.analyzer.* +import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.common.CommonDependenciesContainer import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMonolithicSerializer diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt index 1cee1ff1d2f..3be8d18f084 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2017 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. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.metadata diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/resolveUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/resolveUtil.kt index 87a703940f5..a3662f9d578 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/resolveUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/resolveUtil.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataIncrementalSerializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataIncrementalSerializer.kt index 6101fe72a77..cef61b79c44 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataIncrementalSerializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataIncrementalSerializer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataMonolithicSerializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataMonolithicSerializer.kt index 61b225a0c18..61d1fb73d51 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataMonolithicSerializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataMonolithicSerializer.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.backend.common.serialization.metadata import org.jetbrains.kotlin.config.LanguageVersionSettings diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataSerializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataSerializer.kt index 2bf9545da2f..56f6e50fd26 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataSerializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataSerializer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -98,9 +98,11 @@ abstract class KlibMetadataSerializer( val index = classSerializer.stringTable.getFqNameIndex(classDescriptor) //builder.addExtension(KlibMetadataProtoBuf.className, index) - val classes = serializeClasses(packageName/*, builder*/, + val classes = serializeClasses( + packageName/*, builder*/, classDescriptor.unsubstitutedInnerClassesScope - .getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS)) + .getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS) + ) classSerializer = previousSerializer return classes + Pair(classProto, index) diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt index 2abb6c3bed9..303b6eb37fc 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt index b02c89638aa..85c54412003 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -45,7 +45,8 @@ class DescriptorSerializer private constructor( private val extension: SerializerExtension, val typeTable: MutableTypeTable, private val versionRequirementTable: MutableVersionRequirementTable?, - private val serializeTypeTableToFunction: Boolean + private val serializeTypeTableToFunction: Boolean, + val plugins: List = emptyList() ) { private val contractSerializer = ContractSerializer() @@ -152,6 +153,8 @@ class DescriptorSerializer private constructor( extension.serializeClass(classDescriptor, builder, versionRequirementTable, this) + plugins.forEach { it.afterClass(classDescriptor, builder, versionRequirementTable, this, extension) } + writeVersionRequirementForInlineClasses(classDescriptor, builder, versionRequirementTable) val versionRequirementTableProto = versionRequirementTable.serialize() @@ -741,6 +744,13 @@ class DescriptorSerializer private constructor( ) companion object { + private val plugins: MutableSet = mutableSetOf() + + @JvmStatic + fun registerSerializerPlugin(plugin: DescriptorSerializerPlugin) { + plugins.add(plugin) + } + @JvmStatic fun createTopLevel(extension: SerializerExtension): DescriptorSerializer = DescriptorSerializer( @@ -775,7 +785,8 @@ class DescriptorSerializer private constructor( MutableTypeTable(), if (container is ClassDescriptor && !isVersionRequirementTableWrittenCorrectly(extension.metadataVersion)) parent.versionRequirementTable else MutableVersionRequirementTable(), - serializeTypeTableToFunction = false + serializeTypeTableToFunction = false, + plugins.toList() ) for (typeParameter in descriptor.declaredTypeParameters) { serializer.typeParameters.intern(typeParameter) diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializerPlugin.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializerPlugin.kt new file mode 100644 index 00000000000..23ca0170b39 --- /dev/null +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializerPlugin.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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 + +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable + +interface DescriptorSerializerPlugin { + fun afterClass( + descriptor: ClassDescriptor, + proto: ProtoBuf.Class.Builder, + versionRequirementTable: MutableVersionRequirementTable, + childSerializer: DescriptorSerializer, + extension: SerializerExtension + ) { + } +} \ No newline at end of file diff --git a/generators/tests/org/jetbrains/kotlin/generators/protobuf/GenerateProtoBuf.kt b/generators/tests/org/jetbrains/kotlin/generators/protobuf/GenerateProtoBuf.kt index 32330e03341..88dbe11a554 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/protobuf/GenerateProtoBuf.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/protobuf/GenerateProtoBuf.kt @@ -1,17 +1,6 @@ /* - * 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. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.generators.protobuf @@ -59,7 +48,8 @@ val PROTO_PATHS: List = listOf( ProtoPath("core/metadata.jvm/src/jvm_module.proto"), ProtoPath("build-common/src/java_descriptors.proto"), ProtoPath("compiler/util-klib-metadata/src/KlibMetadataProtoBuf.proto"), - ProtoPath("compiler/ir/serialization.common/src/KotlinIr.proto", false) + ProtoPath("compiler/ir/serialization.common/src/KotlinIr.proto", false), + ProtoPath("plugins/kotlin-serialization/kotlin-serialization-compiler/src/class_extensions.proto", generateDebug = false) ) private val EXT_OPTIONS_PROTO_PATH = ProtoPath("core/metadata/src/ext_options.proto") 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 e487a2e269f..52877490d9f 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 @@ -1,17 +1,6 @@ /* - * 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. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.js diff --git a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeDistributionCommonizer.kt b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeDistributionCommonizer.kt index e682eddc6f9..7715b5bfae9 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeDistributionCommonizer.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeDistributionCommonizer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/build.gradle.kts b/plugins/kotlin-serialization/kotlin-serialization-compiler/build.gradle.kts index 6cc3d6158f8..53f29ce4275 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/build.gradle.kts +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/build.gradle.kts @@ -16,6 +16,7 @@ dependencies { compileOnly(project(":compiler:ir.psi2ir")) compileOnly(project(":js:js.frontend")) compileOnly(project(":js:js.translator")) + compileOnly(project(":kotlin-util-klib-metadata")) runtime(kotlinStdlib()) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/class_extensions.proto b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/class_extensions.proto new file mode 100644 index 00000000000..85243eb4d76 --- /dev/null +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/class_extensions.proto @@ -0,0 +1,11 @@ +package org.jetbrains.kotlinx.serialization.compiler.extensions; + +import "core/metadata/src/metadata.proto"; +import "core/metadata/src/ext_options.proto"; + +option java_outer_classname = "SerializationPluginMetadataExtensions"; +option optimize_for = LITE_RUNTIME; + +extend org.jetbrains.kotlin.metadata.Class { + repeated int32 properties_names_in_program_order = 18000; +} diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationComponentRegistrar.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationComponentRegistrar.kt index 8d07ebebfd1..05a94d702fa 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationComponentRegistrar.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationComponentRegistrar.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2017 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. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.kotlinx.serialization.compiler.extensions @@ -27,8 +16,12 @@ import org.jetbrains.kotlin.container.useInstance import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor import org.jetbrains.kotlin.js.translate.extensions.JsSyntheticTranslateExtension +import org.jetbrains.kotlin.library.metadata.KlibMetadataSerializerProtocol +import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension +import org.jetbrains.kotlin.serialization.DescriptorSerializer +import org.jetbrains.kotlin.serialization.js.JsSerializerProtocol import org.jetbrains.kotlinx.serialization.compiler.diagnostic.SerializationPluginDeclarationChecker class SerializationComponentRegistrar : ComponentRegistrar { @@ -45,7 +38,19 @@ class SerializationComponentRegistrar : ComponentRegistrar { IrGenerationExtension.registerExtension(project, SerializationLoweringExtension()) StorageComponentContainerContributor.registerExtension(project, SerializationPluginComponentContainerContributor()) + + registerProtoExtensions() } + + internal val serializationDescriptorSerializer = SerializationDescriptorPluginForKotlinxSerialization() + + private fun registerProtoExtensions() { + DescriptorSerializer.registerSerializerPlugin(serializationDescriptorSerializer) + SerializationPluginMetadataExtensions.registerAllExtensions(JvmProtoBufUtil.EXTENSION_REGISTRY) + SerializationPluginMetadataExtensions.registerAllExtensions(JsSerializerProtocol.extensionRegistry) + SerializationPluginMetadataExtensions.registerAllExtensions(KlibMetadataSerializerProtocol.extensionRegistry) + } + } } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationDescriptorPluginForKotlinxSerialization.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationDescriptorPluginForKotlinxSerialization.kt new file mode 100644 index 00000000000..f1c229a2e3e --- /dev/null +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationDescriptorPluginForKotlinxSerialization.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.kotlinx.serialization.compiler.extensions + +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.serialization.DescriptorSerializer +import org.jetbrains.kotlin.serialization.DescriptorSerializerPlugin +import org.jetbrains.kotlin.serialization.SerializerExtension +import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties +import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable + +class SerializationDescriptorPluginForKotlinxSerialization : DescriptorSerializerPlugin { + private val descriptorMetadataMap: MutableMap = hashMapOf() + + private val ClassDescriptor.needSaveProgramOrder: Boolean + get() = isInternalSerializable && (modality == Modality.OPEN || modality == Modality.ABSTRACT) + + internal fun putIfNeeded(descriptor: ClassDescriptor, properties: SerializableProperties) { + if (!descriptor.needSaveProgramOrder) return + descriptorMetadataMap[descriptor] = properties + } + + override fun afterClass( + descriptor: ClassDescriptor, + proto: ProtoBuf.Class.Builder, + versionRequirementTable: MutableVersionRequirementTable, + childSerializer: DescriptorSerializer, + extension: SerializerExtension + ) { + fun Name.toIndex() = extension.stringTable.getStringIndex(asString()) + + if (!descriptor.needSaveProgramOrder) return + + val propertiesCorrectOrder = (descriptorMetadataMap[descriptor] ?: return).serializableProperties + proto.setExtension( + SerializationPluginMetadataExtensions.propertiesNamesInProgramOrder, + propertiesCorrectOrder.map { it.descriptor.name.toIndex() } + ) + descriptorMetadataMap.remove(descriptor) + } +} \ No newline at end of file diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationPluginMetadataExtensions.java b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationPluginMetadataExtensions.java new file mode 100644 index 00000000000..17ba5efe5bf --- /dev/null +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationPluginMetadataExtensions.java @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: plugins/kotlin-serialization/kotlin-serialization-compiler/src/class_extensions.proto + +package org.jetbrains.kotlinx.serialization.compiler.extensions; + +public final class SerializationPluginMetadataExtensions { + private SerializationPluginMetadataExtensions() { + } + + public static void registerAllExtensions( + org.jetbrains.kotlin.protobuf.ExtensionRegistryLite registry + ) { + registry.add( + org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginMetadataExtensions.propertiesNamesInProgramOrder); + } + + public static final int PROPERTIES_NAMES_IN_PROGRAM_ORDER_FIELD_NUMBER = 18000; + /** + * extend .org.jetbrains.kotlin.metadata.Class { ... } + */ + public static final + org.jetbrains.kotlin.protobuf.GeneratedMessageLite.GeneratedExtension< + org.jetbrains.kotlin.metadata.ProtoBuf.Class, + java.util.List> propertiesNamesInProgramOrder = org.jetbrains.kotlin.protobuf.GeneratedMessageLite + .newRepeatedGeneratedExtension( + org.jetbrains.kotlin.metadata.ProtoBuf.Class.getDefaultInstance(), + null, + null, + 18000, + org.jetbrains.kotlin.protobuf.WireFormat.FieldType.INT32, + false, + java.lang.Integer.class); + + static { + } + + // @@protoc_insertion_point(outer_class_scope) +} \ No newline at end of file diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt index eefdc19e0f2..494097a32b8 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt @@ -6,11 +6,17 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.hasBackingField import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor +import org.jetbrains.kotlin.serialization.deserialization.getName import org.jetbrains.kotlinx.serialization.compiler.diagnostic.SERIALIZABLE_PROPERTIES +import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationComponentRegistrar +import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginMetadataExtensions class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) { private val primaryConstructorParameters: List = @@ -44,7 +50,7 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val SerializableProperty( prop, primaryConstructorProperties[prop] ?: false, - prop.hasBackingField(bindingContext) + prop.hasBackingField(bindingContext) || (prop is DeserializedPropertyDescriptor && prop.backingField != null) // workaround for TODO in .hasBackingField ) } .filterNot { it.transient } @@ -56,8 +62,11 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val else SerializableProperties(supers, bindingContext).serializableProperties + first + second } + .let { unsort(serializableClass, it) } + isExternallySerializable = serializableClass.isSerializableEnum() || primaryConstructorParameters.size == primaryConstructorProperties.size + } val serializableConstructorProperties: List = @@ -79,5 +88,16 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val internal fun List.bitMaskSlotCount() = size / 32 + 1 internal fun bitMaskSlotAt(propertyIndex: Int) = propertyIndex / 32 -internal fun BindingContext.serializablePropertiesFor(classDescriptor: ClassDescriptor): SerializableProperties = - this.get(SERIALIZABLE_PROPERTIES, classDescriptor) ?: SerializableProperties(classDescriptor, this) +internal fun BindingContext.serializablePropertiesFor(classDescriptor: ClassDescriptor): SerializableProperties { + val props = this.get(SERIALIZABLE_PROPERTIES, classDescriptor) ?: SerializableProperties(classDescriptor, this) + SerializationComponentRegistrar.serializationDescriptorSerializer.putIfNeeded(classDescriptor, props) + return props +} + +private fun unsort(descriptor: ClassDescriptor, props: List): List { + if (descriptor !is DeserializedClassDescriptor) return props + val correctOrder: List = descriptor.classProto.getExtension(SerializationPluginMetadataExtensions.propertiesNamesInProgramOrder) + .map { descriptor.c.nameResolver.getName(it) } + val propsMap = props.associateBy { it.descriptor.name } + return correctOrder.map { propsMap.getValue(it) } +} \ No newline at end of file diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationIrBytecodeListingTestGenerated.java b/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationIrBytecodeListingTestGenerated.java index 1d70f5a45e3..bd9385a5141 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationIrBytecodeListingTestGenerated.java +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationIrBytecodeListingTestGenerated.java @@ -25,7 +25,8 @@ public class SerializationIrBytecodeListingTestGenerated extends AbstractSeriali } public void testAllFilesPresentInCodegen() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen"), Pattern.compile("^(.+)\\.kt$"), null, true); + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File( + "plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen"), Pattern.compile("^(.+)\\.kt$"), null, true); } @TestMetadata("Basic.kt") diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationPluginBytecodeListingTestGenerated.java b/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationPluginBytecodeListingTestGenerated.java index b48bffee20a..1e2811115c4 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationPluginBytecodeListingTestGenerated.java +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/test/org/jetbrains/kotlinx/serialization/SerializationPluginBytecodeListingTestGenerated.java @@ -25,7 +25,8 @@ public class SerializationPluginBytecodeListingTestGenerated extends AbstractSer } public void testAllFilesPresentInCodegen() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen"), Pattern.compile("^(.+)\\.kt$"), null, true); + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File( + "plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen"), Pattern.compile("^(.+)\\.kt$"), null, true); } @TestMetadata("Basic.kt") diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen/Basic.ir.txt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen/Basic.ir.txt index 97f7482d928..4a5f19f6883 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen/Basic.ir.txt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen/Basic.ir.txt @@ -200,7 +200,7 @@ public final class ListOfUsers$$serializer : java/lang/Object, kotlinx/serializa INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, , (Lkotlinx/serialization/KSerializer;)V) CHECKCAST ALOAD (2) - INVOKESTATIC (ListOfUsers, access$getList$p, (LListOfUsers;)Ljava/util/List;) + INVOKEVIRTUAL (ListOfUsers, getList, ()Ljava/util/List;) INVOKEINTERFACE (kotlinx/serialization/CompositeEncoder, encodeSerializableElement, (Lkotlinx/serialization/SerialDescriptor;ILkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V) ALOAD (4) ALOAD (3) @@ -302,8 +302,6 @@ public final class ListOfUsers : java/lang/Object { LABEL (L4) } - public final static java.util.List access$getList$p(ListOfUsers $this) - public final java.util.List getList() } @@ -488,7 +486,7 @@ public final class OptionalUser$$serializer : java/lang/Object, kotlinx/serializ INVOKEINTERFACE (kotlinx/serialization/Encoder, beginStructure, (Lkotlinx/serialization/SerialDescriptor;)Lkotlinx/serialization/CompositeEncoder;) ASTORE (4) ALOAD (2) - INVOKESTATIC (OptionalUser, access$getUser$p, (LOptionalUser;)LUser;) + INVOKEVIRTUAL (OptionalUser, getUser, ()LUser;) NEW DUP LABEL (L2) @@ -515,7 +513,7 @@ public final class OptionalUser$$serializer : java/lang/Object, kotlinx/serializ GETSTATIC (INSTANCE, LUser$$serializer;) CHECKCAST ALOAD (2) - INVOKESTATIC (OptionalUser, access$getUser$p, (LOptionalUser;)LUser;) + INVOKEVIRTUAL (OptionalUser, getUser, ()LUser;) INVOKEINTERFACE (kotlinx/serialization/CompositeEncoder, encodeSerializableElement, (Lkotlinx/serialization/SerialDescriptor;ILkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V) LABEL (L6) ALOAD (4) @@ -655,8 +653,6 @@ public final class OptionalUser : java/lang/Object { LABEL (L1) } - public final static User access$getUser$p(OptionalUser $this) - public final User getUser() } @@ -869,13 +865,13 @@ public final class User$$serializer : java/lang/Object, kotlinx/serialization/in ALOAD (3) ICONST_0 ALOAD (2) - INVOKESTATIC (User, access$getFirstName$p, (LUser;)Ljava/lang/String;) + INVOKEVIRTUAL (User, getFirstName, ()Ljava/lang/String;) INVOKEINTERFACE (kotlinx/serialization/CompositeEncoder, encodeStringElement, (Lkotlinx/serialization/SerialDescriptor;ILjava/lang/String;)V) ALOAD (4) ALOAD (3) ICONST_1 ALOAD (2) - INVOKESTATIC (User, access$getLastName$p, (LUser;)Ljava/lang/String;) + INVOKEVIRTUAL (User, getLastName, ()Ljava/lang/String;) INVOKEINTERFACE (kotlinx/serialization/CompositeEncoder, encodeStringElement, (Lkotlinx/serialization/SerialDescriptor;ILjava/lang/String;)V) ALOAD (4) ALOAD (3) @@ -1001,11 +997,7 @@ public final class User : java/lang/Object { LABEL (L6) } - public final static java.lang.String access$getFirstName$p(User $this) - - public final static java.lang.String access$getLastName$p(User $this) - public final java.lang.String getFirstName() public final java.lang.String getLastName() -} \ No newline at end of file +}