Compare commits

...

6 Commits

Author SHA1 Message Date
Leonid Startsev
f88ee92eba Use simple map instead of binding context, cleanup 2020-05-25 16:41:51 +03:00
Leonid Startsev
0c7079aa3b Rollback changes in PropertyDescriptor.hasBackingField
because they've caused some of the compiler tests to fail
2020-05-19 16:26:55 +03:00
Leonid Startsev
4f7c5c37df Fix problems with descriptors from different modules 2020-05-18 16:15:33 +03:00
Leonid Startsev
15b34bb851 Pass BindingContext to klib proto serializer
So serialization plugin proto extensions are working on Kotlin/Native.
Rework access to properties:
use accessors instead of fields whenever possible.
2020-05-18 15:15:43 +03:00
Leonid Startsev
7d96c90339 Use binding context on JS too 2020-05-18 15:15:42 +03:00
Leonid Startsev
eda1dc0469 Extensible mechanism for plugin metadata during descriptor serialization
todo: get rid of ServiceLoader
2020-05-18 15:15:42 +03:00
31 changed files with 292 additions and 145 deletions

View File

@@ -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

View File

@@ -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.
*/

View File

@@ -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.
*/

View File

@@ -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

View File

@@ -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()
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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.
*/

View File

@@ -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.
*/

View File

@@ -6,13 +6,13 @@
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.impl.IrErrorTypeImpl
import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.Variance
@@ -22,7 +22,7 @@ class SyntheticDeclarationsGenerator(context: GeneratorContext) : DeclarationDes
private val symbolTable = context.symbolTable
companion object {
private const val offset = UNDEFINED_OFFSET
private const val offset = SYNTHETIC_OFFSET
}
private fun <D : IrDeclaration> D.insertDeclaration(declarationContainer: IrDeclarationContainer): D {

View File

@@ -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.
*/

View File

@@ -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

View File

@@ -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)

View File

@@ -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.
*/

View File

@@ -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<DescriptorSerializerPlugin> = 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<DescriptorSerializerPlugin> = 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)

View File

@@ -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
) {
}
}

View File

@@ -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<ProtoPath> = 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")

View File

@@ -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

View File

@@ -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.
*/

View File

@@ -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())

View File

@@ -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;
}

View File

@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
@@ -175,8 +176,35 @@ interface IrBuilderExtension {
fun KotlinType.toIrType() = compilerContext.typeTranslator.translateType(this)
// note: this method should be used only for properties from current module. Fields from other modules are private and inaccessible.
val SerializableProperty.irField: IrField get() = compilerContext.symbolTable.referenceField(this.descriptor).owner
val SerializableProperty.irProp: IrProperty
get() {
val desc = this.descriptor
// this API is used to reference both current module descriptors and external ones (because serializable class can be in any of them),
// so we use descriptor api for current module because it is not possible to obtain FQname for e.g. local classes.
return if (desc.module == compilerContext.moduleDescriptor) {
compilerContext.symbolTable.referenceProperty(desc).owner
} else {
compilerContext.referenceProperties(this.descriptor.fqNameSafe).single().owner
}
}
fun IrBuilderWithScope.getProperty(receiver: IrExpression, property: IrProperty): IrExpression {
return if (property.getter != null)
irGet(property.getter!!.returnType, receiver, property.getter!!.symbol)
else
irGetField(receiver, property.backingField!!)
}
fun IrBuilderWithScope.setProperty(receiver: IrExpression, property: IrProperty, value: IrExpression): IrExpression {
return if (property.setter != null)
irSet(property.setter!!.returnType, receiver, property.setter!!.symbol, value)
else
irSetField(receiver, property.backingField!!, value)
}
/*
The rest of the file is mainly copied from FunctionGenerator.
However, I can't use it's directly because all generateSomething methods require KtProperty (psi element)
@@ -682,4 +710,10 @@ interface IrBuilderExtension {
return forClass.declarations.filterIsInstance<IrConstructor>().single { it.isSerializationCtor() }.symbol
}
fun IrClass.getSuperClassOrAny(): IrClass {
val superClasses = superTypes.mapNotNull { it.classOrNull }.map { it.owner }
return superClasses.singleOrNull { it.kind == ClassKind.CLASS } ?: compilerContext.irBuiltIns.anyClass.owner
}
}

View File

@@ -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.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
@@ -30,11 +35,7 @@ class SerializableIrGenerator(
bindingContext: BindingContext
) : SerializableCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
private fun IrClass.getSuperClassOrAny(): IrClass {
val superClasses = superTypes.mapNotNull { it.classOrNull }.map { it.owner }
return superClasses.singleOrNull { it.kind == ClassKind.CLASS } ?: compilerContext.irBuiltIns.anyClass.owner
}
private fun IrClass.hasSerializableAnnotationWithoutArgs(): Boolean {
val annot = getAnnotation(SerializationAnnotations.serializableAnnotationFqName) ?: return false
@@ -76,12 +77,12 @@ class SerializableIrGenerator(
val prop = serializableProperties[index]
val paramRef = ctor.valueParameters[index + seenVarsOffset]
// assign this.a = a in else branch
val assignParamExpr = irSetField(irGet(thiz), prop.irField, irGet(paramRef))
val assignParamExpr = setProperty(irGet(thiz), prop.irProp, irGet(paramRef))
val ifNotSeenExpr: IrExpression = if (prop.optional) {
val initializerBody =
requireNotNull(transformFieldInitializer(prop.irField)) { "Optional value without an initializer" } // todo: filter abstract here
irSetField(irGet(thiz), prop.irField, initializerBody)
setProperty(irGet(thiz), prop.irProp, initializerBody)
} else {
irThrow(irInvoke(null, exceptionCtorRef, irString(prop.name), typeHint = exceptionType))
}

View File

@@ -13,16 +13,20 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrAnonymousInitializerImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrBranchImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.mapValueParametersIndexed
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.util.withReferenceScope
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
@@ -137,8 +141,9 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
if (classProp.transient) continue
+addFieldCall(classProp)
// add property annotations
val property = classProp.irProp
copySerialInfoAnnotationsToDescriptor(
classProp.irField.correspondingPropertySymbol?.owner?.annotations.orEmpty(),
property.annotations,
localDescriptor,
serialDescImplClass.referenceMethod(CallingConventions.addAnnotation)
)
@@ -245,16 +250,27 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
val objectToSerialize = saveFunc.valueParameters[1]
val localOutput = irTemporary(call, "output")
fun SerializableProperty.irGet(): IrGetField {
fun SerializableProperty.irGet(): IrExpression {
val ownerType = objectToSerialize.symbol.owner.type
return irGetField(
return getProperty(
irGet(
type = ownerType,
variable = objectToSerialize.symbol
), irField
), irProp
)
}
// Ignore comparing to default values of properties from superclass,
// because we do not have access to their fields (and initializers), if superclass is in another module.
// In future, IR analogue of JVM's write$Self should be implemented.
val superClass = irClass.getSuperClassOrAny().descriptor
val ignoreIndexTo = if (superClass.isInternalSerializable) {
bindingContext.serializablePropertiesFor(superClass).size
} else {
-1
}
// internal serialization via virtual calls?
for ((index, property) in serializableProperties.filter { !it.transient }.withIndex()) {
// output.writeXxxElementValue(classDesc, index, value)
@@ -287,7 +303,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
val elementCall = irInvoke(irGet(localOutput), writeFunc, typeArguments = typeArgs, valueArguments = args)
// check for call to .shouldEncodeElementDefault
if (!property.optional) {
if (!property.optional || index < ignoreIndexTo) {
// emit call right away
+elementCall
} else {

View File

@@ -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)
}
}
}

View File

@@ -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<ClassDescriptor, SerializableProperties> = 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)
}
}

View File

@@ -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;
/**
* <code>extend .org.jetbrains.kotlin.metadata.Class { ... }</code>
*/
public static final
org.jetbrains.kotlin.protobuf.GeneratedMessageLite.GeneratedExtension<
org.jetbrains.kotlin.metadata.ProtoBuf.Class,
java.util.List<java.lang.Integer>> 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)
}

View File

@@ -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<ValueParameterDescriptor> =
@@ -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<SerializableProperty> =
@@ -79,5 +88,16 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
internal fun List<SerializableProperty>.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<SerializableProperty>): List<SerializableProperty> {
if (descriptor !is DeserializedClassDescriptor) return props
val correctOrder: List<Name> = descriptor.classProto.getExtension(SerializationPluginMetadataExtensions.propertiesNamesInProgramOrder)
.map { descriptor.c.nameResolver.getName(it) }
val propsMap = props.associateBy { it.descriptor.name }
return correctOrder.map { propsMap.getValue(it) }
}

View File

@@ -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")

View File

@@ -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")

View File

@@ -200,7 +200,7 @@ public final class ListOfUsers$$serializer : java/lang/Object, kotlinx/serializa
INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, <init>, (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()
}
}