Introduce support for plugin-defined intrinsics in old JVM backend:

(Old is created first because all intrinsics emit bytecode anyway)

Provide intrinsic for serializer<T>() function so it won't
invoke typeOf() construction and KType->KSerializer conversion
making it fast and truly reflectionless

Add support for recalculating stack size in plugin-defined intrinsics
since it is needed for correct work:
Unify method for recalculating stack size with existing typeOf intrinsic

Add testdata for IR for future intrinsic in IR
This commit is contained in:
Leonid Startsev
2020-04-10 17:57:21 +03:00
committed by Space
parent 842f94443a
commit f9edbd825a
15 changed files with 1114 additions and 98 deletions
@@ -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.extensions
@@ -19,10 +8,17 @@ package org.jetbrains.kotlin.codegen.extensions
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.tree.InsnList
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
interface ExpressionCodegenExtension {
companion object : ProjectExtensionDescriptor<ExpressionCodegenExtension>(
@@ -46,6 +42,22 @@ interface ExpressionCodegenExtension {
*/
fun applyFunction(receiver: StackValue, resolvedCall: ResolvedCall<*>, c: Context): StackValue? = null
/**
* Called when inliner encounters [ReifiedTypeInliner.OperationKind.PLUGIN_DEFINED] marker
* to perform extension-specific operation with reified type parameter.
*
* @return Required stack size for method after inlining is performed, 0 if the size is unknown, or -1 if extension ignores this marker
*/
fun applyPluginDefinedReifiedOperationMarker(
insn: MethodInsnNode,
instructions: InsnList,
type: KotlinType,
asmType: Type,
typeMapper: KotlinTypeMapper,
typeSystem: TypeSystemCommonBackendContext,
module: ModuleDescriptor
): Int = -1
fun generateClassSyntheticParts(codegen: ImplementationBodyCodegen) {}
val shouldGenerateClassSyntheticPartsInLightClassesMode: Boolean
@@ -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.
*/
@@ -42,7 +42,7 @@ class PsiInlineCodegen(
) : InlineCodegen<ExpressionCodegen>(
codegen, state, signature, typeParameterMappings, sourceCompiler,
ReifiedTypeInliner(
typeParameterMappings, PsiInlineIntrinsicsSupport(state, reportErrorsOn), codegen.typeSystem,
typeParameterMappings, PsiInlineIntrinsicsSupport(state, reportErrorsOn, codegen.typeSystem), codegen.typeSystem,
state.languageVersionSettings, state.unifiedNullChecks
),
), CallGenerator {
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
@@ -19,15 +20,19 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.TYPEOF_NON_REIFIED_TYPE_PARAMETER_WITH_RECURSIVE_BOUND
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.TYPEOF_SUSPEND_TYPE
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
import org.jetbrains.kotlin.types.model.TypeParameterMarker
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.Type.INT_TYPE
import org.jetbrains.org.objectweb.asm.Type.VOID_TYPE
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.tree.InsnList
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
class PsiInlineIntrinsicsSupport(
override val state: GenerationState,
private val reportErrorsOn: KtElement,
private val typeSystem: TypeSystemCommonBackendContext
) : ReifiedTypeInliner.IntrinsicsSupport<KotlinType> {
override fun putClassInstance(v: InstructionAdapter, type: KotlinType) {
DescriptorAsmUtil.putJavaLangClassInstance(v, state.typeMapper.mapType(type), type, state.typeMapper)
@@ -79,4 +84,15 @@ class PsiInlineIntrinsicsSupport(
override fun reportNonReifiedTypeParameterWithRecursiveBoundUnsupported(typeParameterName: Name) {
state.diagnostics.report(TYPEOF_NON_REIFIED_TYPE_PARAMETER_WITH_RECURSIVE_BOUND.on(reportErrorsOn, typeParameterName.asString()))
}
override fun applyPluginDefinedReifiedOperationMarker(
insn: MethodInsnNode,
instructions: InsnList,
type: KotlinType,
asmType: Type
): Int {
return ExpressionCodegenExtension.getInstances(state.project)
.map { it.applyPluginDefinedReifiedOperationMarker(insn, instructions, type, asmType, state.typeMapper, typeSystem, state.module) }
.maxOrNull() ?: -1
}
}
@@ -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.inline
@@ -57,11 +46,12 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
private val unifiedNullChecks: Boolean,
) {
enum class OperationKind {
NEW_ARRAY, AS, SAFE_AS, IS, JAVA_CLASS, ENUM_REIFIED, TYPE_OF;
NEW_ARRAY, AS, SAFE_AS, IS, JAVA_CLASS, ENUM_REIFIED, TYPE_OF, PLUGIN_DEFINED;
val id: Int get() = ordinal
}
interface IntrinsicsSupport<KT : KotlinTypeMarker> {
val state: GenerationState
@@ -75,6 +65,16 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
fun reportSuspendTypeUnsupported()
fun reportNonReifiedTypeParameterWithRecursiveBoundUnsupported(typeParameterName: Name)
/**
* @return Required stack size for method after inlining is performed, 0 if the size is unknown, or -1 if plugin was not applied
*/
fun applyPluginDefinedReifiedOperationMarker(
insn: MethodInsnNode,
instructions: InsnList,
type: KotlinType,
asmType: Type
): Int = -1
}
companion object {
@@ -181,6 +181,7 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
OperationKind.JAVA_CLASS -> processJavaClass(insn, asmType)
OperationKind.ENUM_REIFIED -> processSpecialEnumFunction(insn, instructions, asmType)
OperationKind.TYPE_OF -> processTypeOf(insn, instructions, type)
OperationKind.PLUGIN_DEFINED -> processPluginDefined(insn, instructions, type, asmType)
}
) {
instructions.remove(insn.previous.previous!!) // PUSH operation ID
@@ -196,6 +197,23 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
}
}
private fun processPluginDefined(
insn: MethodInsnNode,
instructions: InsnList,
type: KT,
asmType: Type
): Boolean {
val applyResult = intrinsicsSupport.applyPluginDefinedReifiedOperationMarker(
insn,
instructions,
intrinsicsSupport.toKotlinType(type),
asmType
)
if (applyResult == -1) return false
maxStackSize = max(maxStackSize, applyResult)
return true
}
private fun reify(argument: ReificationArgument, replacementAsmType: Type, type: KT): Pair<Type, KT> =
with(typeSystem) {
val arrayType = type.arrayOf(argument.arrayDepth)
@@ -269,15 +287,11 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
instructions: InsnList,
type: KT
) = rewriteNextTypeInsn(insn, Opcodes.ACONST_NULL) { stubConstNull: AbstractInsnNode ->
val newMethodNode = MethodNode(Opcodes.API_VERSION, "fake", "()V", null, null)
val mv = wrapWithMaxLocalCalc(newMethodNode)
typeSystem.generateTypeOf(InstructionAdapter(mv), type, intrinsicsSupport)
val newMethodNode = newMethodNodeWithCorrectStackSize {
typeSystem.generateTypeOf(it, type, intrinsicsSupport)
}
// Adding a fake return (and removing it below) to trigger maxStack calculation
mv.visitInsn(Opcodes.RETURN)
mv.visitMaxs(-1, -1)
instructions.insert(insn, newMethodNode.instructions.apply { remove(last) })
instructions.insert(insn, newMethodNode.instructions)
instructions.remove(stubConstNull)
maxStackSize = max(maxStackSize, newMethodNode.maxStack)
@@ -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.
*/
@@ -229,6 +229,19 @@ internal fun isAnonymousClass(internalName: String) =
fun wrapWithMaxLocalCalc(methodNode: MethodNode) =
MaxStackFrameSizeAndLocalsCalculator(Opcodes.API_VERSION, methodNode.access, methodNode.desc, methodNode)
fun newMethodNodeWithCorrectStackSize(block: (InstructionAdapter) -> Unit): MethodNode {
val newMethodNode = MethodNode(Opcodes.API_VERSION, "fake", "()V", null, null)
val mv = wrapWithMaxLocalCalc(newMethodNode)
block(InstructionAdapter(mv))
// Adding a fake return (and removing it below) to trigger maxStack calculation
mv.visitInsn(Opcodes.RETURN)
mv.visitMaxs(-1, -1)
newMethodNode.instructions.apply { remove(last) }
return newMethodNode
}
private fun String.isInteger(radix: Int = 10) = toIntOrNull(radix) != null
internal fun isCapturedFieldName(fieldName: String): Boolean {
@@ -12,6 +12,9 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIALIZER_PROVIDER_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
import org.jetbrains.kotlinx.serialization.compiler.resolve.isKSerializer
import org.jetbrains.kotlinx.serialization.compiler.resolve.isSerializableObject
abstract class SerializableCompanionCodegen(
protected val companionDescriptor: ClassDescriptor,
@@ -20,15 +23,7 @@ abstract class SerializableCompanionCodegen(
protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorByCompanion(companionDescriptor)!!
open fun getSerializerGetterDescriptor(): FunctionDescriptor {
return companionDescriptor.unsubstitutedMemberScope.getContributedFunctions(
SERIALIZER_PROVIDER_NAME,
NoLookupLocation.FROM_BACKEND
).firstOrNull {
it.valueParameters.size == serializableDescriptor.declaredTypeParameters.size
&& it.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
&& it.valueParameters.all { p -> isKSerializer(p.type) }
&& it.returnType != null && isKSerializer(it.returnType)
} ?: throw IllegalStateException(
return findSerializerGetterOnCompanion(serializableDescriptor) ?: throw IllegalStateException(
"Can't find synthesized 'Companion.serializer()' function to generate, " +
"probably clash with user-defined function has occurred"
)
@@ -52,4 +47,19 @@ abstract class SerializableCompanionCodegen(
protected open fun generateLazySerializerGetter(methodDescriptor: FunctionDescriptor) {
generateSerializerGetter(methodDescriptor)
}
companion object {
fun findSerializerGetterOnCompanion(serializableDescriptor: ClassDescriptor): FunctionDescriptor? {
val companionObjectDesc = if (serializableDescriptor.isSerializableObject) serializableDescriptor else serializableDescriptor.companionObjectDescriptor
return companionObjectDesc?.unsubstitutedMemberScope?.getContributedFunctions(
SERIALIZER_PROVIDER_NAME,
NoLookupLocation.FROM_BACKEND
)?.firstOrNull {
it.valueParameters.size == serializableDescriptor.declaredTypeParameters.size
&& it.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
&& it.valueParameters.all { p -> isKSerializer(p.type) }
&& it.returnType != null && isKSerializer(it.returnType)
}
}
}
}
@@ -8,7 +8,9 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.context.ClassContext
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
@@ -247,56 +249,88 @@ internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(
}
}
internal fun AbstractSerialGenerator?.stackValueSerializerInstance(
expressionCodegen: ExpressionCodegen, codegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?,
iv: InstructionAdapter?,
genericIndex: Int? = null,
genericSerializerFieldGetter: (InstructionAdapter.(Int, KotlinType) -> Unit)? = null
): Boolean {
return stackValueSerializerInstance(
expressionCodegen,codegen.typeMapper,
module,
kType,
maybeSerializer,
iv,
genericIndex,
false,
genericSerializerFieldGetter
)
}
// returns false is cannot not use serializer
// use iv == null to check only (do not emit serializer onto stack)
internal fun AbstractSerialGenerator.stackValueSerializerInstance(expressionCodegen: ExpressionCodegen, classCodegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?,
iv: InstructionAdapter?,
genericIndex: Int? = null,
genericSerializerFieldGetter: (InstructionAdapter.(Int, KotlinType) -> Unit)? = null
internal fun AbstractSerialGenerator?.stackValueSerializerInstance(
expressionCodegen: ExpressionCodegen?, typeMapper: KotlinTypeMapper, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?,
iv: InstructionAdapter?,
genericIndex: Int? = null,
insertExceptionOnNoSerializer: Boolean = false,
genericSerializerFieldGetter: (InstructionAdapter.(Int, KotlinType) -> Unit)? = null,
): Boolean {
if (maybeSerializer == null && genericIndex != null) {
// get field from serializer object
iv?.run { genericSerializerFieldGetter?.invoke(this, genericIndex, kType) }
return true
}
val serializer = maybeSerializer ?: return false
val serializer = maybeSerializer ?: run {
if (insertExceptionOnNoSerializer) iv?.apply {
aconst(kType.getJetTypeFqName(false))
invokestatic(
"kotlinx/serialization/SerializersKt",
"noCompiledSerializer",
"(Ljava/lang/String;)Lkotlinx/serialization/KSerializer;",
false
)
}
return false
}
if (serializer.kind == ClassKind.OBJECT) {
// singleton serializer -- just get it
if (iv != null)
StackValue.singleton(serializer, classCodegen.typeMapper).put(kSerializerType, iv)
StackValue.singleton(serializer, typeMapper).put(kSerializerType, iv)
return true
}
// serializer is not singleton object and shall be instantiated
val argSerializers = kType.arguments.map { projection ->
// bail out from stackValueSerializerInstance if any type argument is not serializable
// check if any type argument is not serializable
val argType = projection.type
val argSerializer = if (argType.isTypeParameter()) null else {
findTypeSerializerOrContext(module, argType, sourceElement = classCodegen.descriptor.findPsi())
?: return false
}
val argSerializer =
if (argType.isTypeParameter()) null else findTypeSerializerOrContextUnchecked(module, argType)
// check if it can be properly serialized with its args recursively
if (!stackValueSerializerInstance(
expressionCodegen,
classCodegen,
typeMapper,
module,
argType,
argSerializer,
null,
argType.genericIndex,
insertExceptionOnNoSerializer = false,
genericSerializerFieldGetter
)
)
return false
) {
// bail out only if we do not need to insert exception
if (!insertExceptionOnNoSerializer) return false
}
Pair(argType, argSerializer)
}
// new serializer if needed
iv?.apply {
val serializerType = classCodegen.typeMapper.mapClass(serializer)
val serializerType = typeMapper.mapClass(serializer)
val classDescriptor = kType.toClassDescriptor!!
if (serializer.classId == enumSerializerId && !classDescriptor.useGeneratedEnumSerializer) {
// runtime contains enum serializer factory functions
val javaEnumArray = Type.getType("[Ljava/lang/Enum;")
val enumJavaType = classCodegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT)
val enumJavaType = typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT)
val serialName = classDescriptor.serialName()
if (classDescriptor.isEnumWithSerialInfoAnnotation()) {
@@ -323,7 +357,7 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(expressionCode
} else {
fillArray(annotationType, annotations) { _, annotation ->
val (annotationClass, args, consParams) = annotation
expressionCodegen.generateSyntheticAnnotationOnStack(annotationClass, args, consParams)
expressionCodegen?.generateSyntheticAnnotationOnStack(annotationClass, args, consParams)
}
}
}
@@ -361,14 +395,15 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(expressionCode
assert(
stackValueSerializerInstance(
expressionCodegen,
classCodegen,
typeMapper,
module,
argType,
argSerializer,
this,
argType.genericIndex,
insertExceptionOnNoSerializer,
genericSerializerFieldGetter
)
) || insertExceptionOnNoSerializer
)
// wrap into nullable serializer if argType is nullable
if (argType.isMarkedNullable) wrapStackValueIntoNullableSerializer()
@@ -381,16 +416,16 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(expressionCode
// support legacy serializer instantiation by constructor for old runtimes
aconst(serialName)
signature.append("Ljava/lang/String;")
val enumJavaType = classCodegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT)
val enumJavaType = typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT)
val javaEnumArray = Type.getType("[Ljava/lang/Enum;")
invokestatic(enumJavaType.internalName, "values","()[${enumJavaType.descriptor}", false)
invokestatic(enumJavaType.internalName, "values", "()[${enumJavaType.descriptor}", false)
checkcast(javaEnumArray)
signature.append(javaEnumArray.descriptor)
}
contextSerializerId, polymorphicSerializerId -> {
// a special way to instantiate enum -- need a enum KClass reference
// GENERIC_ARGUMENT forces boxing in order to obtain KClass
aconst(classCodegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT))
aconst(typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT))
AsmUtil.wrapJavaClassIntoKClass(this)
signature.append(AsmTypes.K_CLASS_TYPE.descriptor)
if (serializer.classId == contextSerializerId && serializer.constructors.any { it.valueParameters.size == 3 }) {
@@ -410,7 +445,7 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(expressionCode
}
referenceArraySerializerId -> {
// a special way to instantiate reference array serializer -- need an element KClass reference
aconst(classCodegen.typeMapper.mapType(kType.arguments[0].type, null, TypeMappingMode.GENERIC_ARGUMENT))
aconst(typeMapper.mapType(kType.arguments[0].type, null, TypeMappingMode.GENERIC_ARGUMENT))
AsmUtil.wrapJavaClassIntoKClass(this)
signature.append(AsmTypes.K_CLASS_TYPE.descriptor)
// Reference array serializer still needs serializer for its argument type
@@ -419,13 +454,13 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(expressionCode
sealedSerializerId -> {
aconst(serialName)
signature.append("Ljava/lang/String;")
aconst(classCodegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT))
aconst(typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT))
AsmUtil.wrapJavaClassIntoKClass(this)
signature.append(AsmTypes.K_CLASS_TYPE.descriptor)
val (subClasses, subSerializers) = allSealedSerializableSubclassesFor(kType.toClassDescriptor!!, module)
// KClasses vararg
fillArray(AsmTypes.K_CLASS_TYPE, subClasses) { _, type ->
aconst(classCodegen.typeMapper.mapType(type, null, TypeMappingMode.GENERIC_ARGUMENT))
aconst(typeMapper.mapType(type, null, TypeMappingMode.GENERIC_ARGUMENT))
AsmUtil.wrapJavaClassIntoKClass(this)
}
signature.append(AsmTypes.K_CLASS_ARRAY_TYPE.descriptor)
@@ -435,7 +470,7 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(expressionCode
assert(
stackValueSerializerInstance(
expressionCodegen,
classCodegen,
typeMapper,
module,
argType,
argSerializer,
@@ -446,11 +481,12 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(expressionCode
assert(
stackValueSerializerInstance(
expressionCodegen,
classCodegen,
typeMapper,
module,
(genericType.constructor.declarationDescriptor as TypeParameterDescriptor).representativeUpperBound,
module.getClassFromSerializationPackage(SpecialBuiltins.polymorphicSerializer),
this
this,
insertExceptionOnNoSerializer = insertExceptionOnNoSerializer
)
)
}
@@ -462,7 +498,7 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(expressionCode
objectSerializerId -> {
aconst(serialName)
signature.append("Ljava/lang/String;")
StackValue.singleton(kType.toClassDescriptor!!, classCodegen.typeMapper).put(Type.getType("Ljava/lang/Object;"), iv)
StackValue.singleton(kType.toClassDescriptor!!, typeMapper).put(Type.getType("Ljava/lang/Object;"), iv)
signature.append("Ljava/lang/Object;")
}
// all serializers get arguments with serializers of their generic types
@@ -0,0 +1,124 @@
/*
* Copyright 2010-2022 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.jvm
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
import org.jetbrains.kotlin.codegen.inline.newMethodNodeWithCorrectStackSize
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.ir.expressions.typeParametersCount
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
import org.jetbrains.kotlinx.serialization.compiler.backend.common.AbstractSerialGenerator
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContextUnchecked
import org.jetbrains.kotlinx.serialization.compiler.resolve.isSerializableObject
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.tree.InsnList
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
object JvmSerializerIntrinsic {
fun applyFunction(resolvedCall: ResolvedCall<*>, c: ExpressionCodegenExtension.Context): StackValue? {
val targetFunction = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return null
val isSerializerReifiedFunction =
targetFunction.fqNameSafe.asString() == "kotlinx.serialization.serializer"
&& targetFunction.valueParameters.isEmpty()
&& targetFunction.typeParametersCount == 1
&& targetFunction.dispatchReceiverParameter == null
&& targetFunction.extensionReceiverParameter == null
if (!isSerializerReifiedFunction) return null
val typeArgument =
resolvedCall.typeArguments.entries.singleOrNull()?.value ?: error("serializer() function has exactly one type parameter")
return StackValue.functionCall(kSerializerType, targetFunction.returnType) { iv ->
generateSerializerForType(typeArgument, iv, c.typeMapper, c.codegen.typeSystem, module = c.codegen.state.module)
}
}
fun applyPluginDefinedReifiedOperationMarker(
insn: MethodInsnNode,
instructions: InsnList,
type: KotlinType,
typeMapper: KotlinTypeMapper,
typeSystem: TypeSystemCommonBackendContext,
module: ModuleDescriptor
): Int {
val newMethodNode = newMethodNodeWithCorrectStackSize {
generateSerializerForType(type, it, typeMapper, typeSystem, module)
}
instructions.remove(insn.next)
instructions.insert(insn, newMethodNode.instructions)
return newMethodNode.maxStack
}
private fun InstructionAdapter.putReifyMarkerIfNeeded(type: KotlinType, typeSystem: TypeSystemCommonBackendContext): Boolean {
val typeDescriptor = (type as SimpleType).constructor.declarationDescriptor!!
if (typeDescriptor is TypeParameterDescriptor) { // need further reification
ReifiedTypeInliner.putReifiedOperationMarkerIfNeeded(
typeDescriptor,
false,
ReifiedTypeInliner.OperationKind.PLUGIN_DEFINED,
this,
typeSystem
)
invokestatic("kotlinx/serialization/SerializersKt", "serializer", "()Lkotlinx/serialization/KSerializer;", false)
return true
}
return false
}
private fun generateSerializerForType(
type: KotlinType,
adapter: InstructionAdapter,
typeMapper: KotlinTypeMapper,
typeSystem: TypeSystemCommonBackendContext,
module: ModuleDescriptor
): Unit = with(adapter) {
if (putReifyMarkerIfNeeded(type, typeSystem)) return
val typeDescriptor = (type as SimpleType).constructor.declarationDescriptor!! as ClassDescriptor
val serializerMethod = SerializableCompanionCodegen.findSerializerGetterOnCompanion(typeDescriptor)
if (serializerMethod != null) {
// fast path
val companionType = if (typeDescriptor.isSerializableObject) typeDescriptor else typeDescriptor.companionObjectDescriptor!!
StackValue.singleton(companionType, typeMapper).put(this)
val args = type.arguments.map { it.type }
args.forEach { generateSerializerForType(it, this, typeMapper, typeSystem, module) }
val signature = kSerializerType.descriptor.repeat(args.size)
invokevirtual(
typeMapper.mapType(companionType).internalName,
"serializer",
"(${signature})${kSerializerType.descriptor}",
false
)
} else {
// More general path, including special ol built-in serializers for e.g. List
val emptyGenerator: AbstractSerialGenerator? = null // stub indicating we do not look into @UseSerializers to avoid confusion
val serializer = emptyGenerator.findTypeSerializerOrContextUnchecked(module, type)
emptyGenerator.stackValueSerializerInstance(
null,
typeMapper,
module,
type,
serializer,
this,
insertExceptionOnNoSerializer = true
) { _, genericArg ->
assert(putReifyMarkerIfNeeded(genericArg, typeSystem))
}
if (type.isMarkedNullable) wrapStackValueIntoNullableSerializer()
}
}
}
@@ -1,27 +1,22 @@
/*
* 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-2021 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.codegen.ImplementationBodyCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerialInfoCodegenImpl
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCodegenImpl
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCompanionCodegenImpl
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializerCodegenImpl
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.*
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.InsnList
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
open class SerializationCodegenExtension @JvmOverloads constructor(val metadataPlugin: SerializationDescriptorSerializerPlugin? = null) : ExpressionCodegenExtension {
override fun generateClassSyntheticParts(codegen: ImplementationBodyCodegen) {
@@ -31,6 +26,22 @@ open class SerializationCodegenExtension @JvmOverloads constructor(val metadataP
SerializableCompanionCodegenImpl.generateSerializableExtensions(codegen)
}
override fun applyFunction(receiver: StackValue, resolvedCall: ResolvedCall<*>, c: ExpressionCodegenExtension.Context): StackValue? {
return JvmSerializerIntrinsic.applyFunction(resolvedCall, c)
}
override fun applyPluginDefinedReifiedOperationMarker(
insn: MethodInsnNode,
instructions: InsnList,
type: KotlinType,
asmType: Type,
typeMapper: KotlinTypeMapper,
typeSystem: TypeSystemCommonBackendContext,
module: ModuleDescriptor
): Int {
return JvmSerializerIntrinsic.applyPluginDefinedReifiedOperationMarker(insn, instructions, type, typeMapper, typeSystem, module)
}
override val shouldGenerateClassSyntheticPartsInLightClassesMode: Boolean
get() = false
}
@@ -77,7 +77,7 @@ fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): S
}
}
fun AbstractSerialGenerator.allSealedSerializableSubclassesFor(
fun AbstractSerialGenerator?.allSealedSerializableSubclassesFor(
klass: ClassDescriptor,
module: ModuleDescriptor
): Pair<List<KotlinType>, List<ClassDescriptor>> {
@@ -119,20 +119,20 @@ fun analyzeSpecialSerializers(
else -> null
}
fun AbstractSerialGenerator.findTypeSerializerOrContextUnchecked(
fun AbstractSerialGenerator?.findTypeSerializerOrContextUnchecked(
module: ModuleDescriptor,
kType: KotlinType
): ClassDescriptor? {
val annotations = kType.annotations
if (kType.isTypeParameter()) return null
annotations.serializableWith(module)?.let { return it.toClassDescriptor }
additionalSerializersInScopeOfCurrentFile[kType.toClassDescriptor to kType.isMarkedNullable]?.let { return it }
this?.additionalSerializersInScopeOfCurrentFile?.get(kType.toClassDescriptor to kType.isMarkedNullable)?.let { return it }
if (kType.isMarkedNullable) return findTypeSerializerOrContextUnchecked(module, kType.makeNotNullable())
if (kType in contextualKClassListInCurrentFile) return module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer)
if (this?.contextualKClassListInCurrentFile?.contains(kType) == true) return module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer)
return analyzeSpecialSerializers(module, annotations) ?: findTypeSerializer(module, kType)
}
fun AbstractSerialGenerator.findTypeSerializerOrContext(
fun AbstractSerialGenerator?.findTypeSerializerOrContext(
module: ModuleDescriptor,
kType: KotlinType,
sourceElement: PsiElement? = null
@@ -0,0 +1,465 @@
public final class Box$$serializer : java/lang/Object, kotlinx/serialization/internal/GeneratedSerializer {
private final kotlinx.serialization.internal.PluginGeneratedSerialDescriptor descriptor
private final kotlinx.serialization.KSerializer typeSerial0
private void <init>()
public void <init>(kotlinx.serialization.KSerializer typeSerial0)
public kotlinx.serialization.KSerializer[] childSerializers()
public Box deserialize(kotlinx.serialization.encoding.Decoder decoder)
public java.lang.Object deserialize(kotlinx.serialization.encoding.Decoder decoder)
public kotlinx.serialization.descriptors.SerialDescriptor getDescriptor()
private final kotlinx.serialization.KSerializer getTypeSerial0()
public void serialize(kotlinx.serialization.encoding.Encoder encoder, Box value)
public void serialize(kotlinx.serialization.encoding.Encoder encoder, java.lang.Object value)
public kotlinx.serialization.KSerializer[] typeParametersSerializers()
}
public final class Box$Companion : java/lang/Object {
private void <init>()
public void <init>(kotlin.jvm.internal.DefaultConstructorMarker $constructor_marker)
private final kotlinx.serialization.descriptors.SerialDescriptor get$cachedDescriptor()
public final kotlinx.serialization.KSerializer serializer(kotlinx.serialization.KSerializer typeSerial0)
}
public final class Box : java/lang/Object {
private final static kotlinx.serialization.descriptors.SerialDescriptor $cachedDescriptor
public final static Box$Companion Companion
private final java.lang.Object boxed
static void <clinit>()
public void <init>(java.lang.Object boxed)
public void <init>(int seen1, java.lang.Object boxed, kotlinx.serialization.internal.SerializationConstructorMarker serializationConstructorMarker)
public final static kotlinx.serialization.descriptors.SerialDescriptor access$get$cachedDescriptor$cp()
public final java.lang.Object component1()
public final Box copy(java.lang.Object boxed)
public static Box copy$default(Box p0, java.lang.Object p1, int p2, java.lang.Object p3)
public boolean equals(java.lang.Object other)
public final java.lang.Object getBoxed()
public int hashCode()
public java.lang.String toString()
public final static void write$Self(Box self, kotlinx.serialization.encoding.CompositeEncoder output, kotlinx.serialization.descriptors.SerialDescriptor serialDesc, kotlinx.serialization.KSerializer typeSerial0)
}
public final class IntrinsicsKt : java/lang/Object {
public final static kotlinx.serialization.KSerializer getBoxSer()
public final static kotlinx.serialization.KSerializer getSer()
public final static kotlinx.serialization.KSerializer listSer()
public final static void test() {
LABEL (L0)
LINENUMBER (28)
ICONST_0
ISTORE (0)
LABEL (L1)
LDC (LSimple;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;)Lkotlin/reflect/KType;)
LABEL (L2)
LINENUMBER (50)
INVOKESTATIC (kotlinx/serialization/SerializersKt, serializer, (Lkotlin/reflect/KType;)Lkotlinx/serialization/KSerializer;)
ASTORE (1)
LABEL (L3)
ICONST_0
ISTORE (2)
LABEL (L4)
LINENUMBER (51)
ALOAD (1)
LDC (null cannot be cast to non-null type kotlinx.serialization.KSerializer<T of kotlinx.serialization.internal.Platform_commonKt.cast>)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNull, (Ljava/lang/Object;Ljava/lang/String;)V)
LABEL (L5)
LINENUMBER (50)
NOP
LABEL (L6)
LINENUMBER (29)
ICONST_0
ISTORE (0)
LABEL (L7)
LINENUMBER (52)
ICONST_0
ISTORE (1)
LABEL (L8)
LDC (LSimple;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;)Lkotlin/reflect/KType;)
LABEL (L9)
LINENUMBER (53)
INVOKESTATIC (kotlinx/serialization/SerializersKt, serializer, (Lkotlin/reflect/KType;)Lkotlinx/serialization/KSerializer;)
ASTORE (2)
LABEL (L10)
ICONST_0
ISTORE (3)
LABEL (L11)
LINENUMBER (54)
ALOAD (2)
LDC (null cannot be cast to non-null type kotlinx.serialization.KSerializer<T of kotlinx.serialization.internal.Platform_commonKt.cast>)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNull, (Ljava/lang/Object;Ljava/lang/String;)V)
LABEL (L12)
LINENUMBER (53)
NOP
LABEL (L13)
LINENUMBER (52)
NOP
LABEL (L14)
LINENUMBER (30)
ICONST_0
ISTORE (0)
LABEL (L15)
LINENUMBER (55)
ICONST_0
ISTORE (1)
LABEL (L16)
LDC (LBox;)
GETSTATIC (kotlin/reflect/KTypeProjection, Companion, Lkotlin/reflect/KTypeProjection$Companion;)
LDC (LSimple;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;)Lkotlin/reflect/KType;)
INVOKEVIRTUAL (kotlin/reflect/KTypeProjection$Companion, invariant, (Lkotlin/reflect/KType;)Lkotlin/reflect/KTypeProjection;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;)
LABEL (L17)
LINENUMBER (56)
INVOKESTATIC (kotlinx/serialization/SerializersKt, serializer, (Lkotlin/reflect/KType;)Lkotlinx/serialization/KSerializer;)
ASTORE (2)
LABEL (L18)
ICONST_0
ISTORE (3)
LABEL (L19)
LINENUMBER (57)
ALOAD (2)
LDC (null cannot be cast to non-null type kotlinx.serialization.KSerializer<T of kotlinx.serialization.internal.Platform_commonKt.cast>)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNull, (Ljava/lang/Object;Ljava/lang/String;)V)
LABEL (L20)
LINENUMBER (56)
NOP
LABEL (L21)
LINENUMBER (55)
NOP
LABEL (L22)
LINENUMBER (31)
ICONST_0
ISTORE (0)
LABEL (L23)
LINENUMBER (58)
ICONST_0
ISTORE (1)
LABEL (L24)
LDC (LBox;)
GETSTATIC (kotlin/reflect/KTypeProjection, Companion, Lkotlin/reflect/KTypeProjection$Companion;)
LDC (LSimple;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;)Lkotlin/reflect/KType;)
INVOKEVIRTUAL (kotlin/reflect/KTypeProjection$Companion, invariant, (Lkotlin/reflect/KType;)Lkotlin/reflect/KTypeProjection;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;)
LABEL (L25)
LINENUMBER (59)
INVOKESTATIC (kotlinx/serialization/SerializersKt, serializer, (Lkotlin/reflect/KType;)Lkotlinx/serialization/KSerializer;)
ASTORE (2)
LABEL (L26)
ICONST_0
ISTORE (3)
LABEL (L27)
LINENUMBER (60)
ALOAD (2)
LDC (null cannot be cast to non-null type kotlinx.serialization.KSerializer<T of kotlinx.serialization.internal.Platform_commonKt.cast>)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNull, (Ljava/lang/Object;Ljava/lang/String;)V)
LABEL (L28)
LINENUMBER (59)
NOP
LABEL (L29)
LINENUMBER (58)
NOP
LABEL (L30)
LINENUMBER (32)
ICONST_0
ISTORE (0)
LABEL (L31)
LINENUMBER (61)
ICONST_0
ISTORE (1)
LABEL (L32)
LDC (Ljava/util/List;)
GETSTATIC (kotlin/reflect/KTypeProjection, Companion, Lkotlin/reflect/KTypeProjection$Companion;)
LDC (LSimple;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;)Lkotlin/reflect/KType;)
INVOKEVIRTUAL (kotlin/reflect/KTypeProjection$Companion, invariant, (Lkotlin/reflect/KType;)Lkotlin/reflect/KTypeProjection;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;)
LABEL (L33)
LINENUMBER (62)
INVOKESTATIC (kotlinx/serialization/SerializersKt, serializer, (Lkotlin/reflect/KType;)Lkotlinx/serialization/KSerializer;)
ASTORE (2)
LABEL (L34)
ICONST_0
ISTORE (3)
LABEL (L35)
LINENUMBER (63)
ALOAD (2)
LDC (null cannot be cast to non-null type kotlinx.serialization.KSerializer<T of kotlinx.serialization.internal.Platform_commonKt.cast>)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNull, (Ljava/lang/Object;Ljava/lang/String;)V)
LABEL (L36)
LINENUMBER (62)
NOP
LABEL (L37)
LINENUMBER (61)
NOP
LABEL (L38)
LINENUMBER (34)
ICONST_0
ISTORE (0)
LABEL (L39)
LDC (LBox;)
GETSTATIC (kotlin/reflect/KTypeProjection, Companion, Lkotlin/reflect/KTypeProjection$Companion;)
LDC (Ljava/util/List;)
GETSTATIC (kotlin/reflect/KTypeProjection, Companion, Lkotlin/reflect/KTypeProjection$Companion;)
LDC (LSimple;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;)Lkotlin/reflect/KType;)
INVOKEVIRTUAL (kotlin/reflect/KTypeProjection$Companion, invariant, (Lkotlin/reflect/KType;)Lkotlin/reflect/KTypeProjection;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;)
INVOKEVIRTUAL (kotlin/reflect/KTypeProjection$Companion, invariant, (Lkotlin/reflect/KType;)Lkotlin/reflect/KTypeProjection;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;)
LABEL (L40)
LINENUMBER (64)
INVOKESTATIC (kotlinx/serialization/SerializersKt, serializer, (Lkotlin/reflect/KType;)Lkotlinx/serialization/KSerializer;)
ASTORE (1)
LABEL (L41)
ICONST_0
ISTORE (2)
LABEL (L42)
LINENUMBER (65)
ALOAD (1)
LDC (null cannot be cast to non-null type kotlinx.serialization.KSerializer<T of kotlinx.serialization.internal.Platform_commonKt.cast>)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNull, (Ljava/lang/Object;Ljava/lang/String;)V)
LABEL (L43)
LINENUMBER (64)
NOP
LABEL (L44)
LINENUMBER (36)
ICONST_0
ISTORE (0)
LABEL (L45)
LINENUMBER (66)
ICONST_0
ISTORE (1)
LABEL (L46)
LDC (Ljava/util/List;)
GETSTATIC (kotlin/reflect/KTypeProjection, Companion, Lkotlin/reflect/KTypeProjection$Companion;)
LDC (LBox;)
GETSTATIC (kotlin/reflect/KTypeProjection, Companion, Lkotlin/reflect/KTypeProjection$Companion;)
LDC (Ljava/util/List;)
GETSTATIC (kotlin/reflect/KTypeProjection, Companion, Lkotlin/reflect/KTypeProjection$Companion;)
LDC (LSimple;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;)Lkotlin/reflect/KType;)
INVOKEVIRTUAL (kotlin/reflect/KTypeProjection$Companion, invariant, (Lkotlin/reflect/KType;)Lkotlin/reflect/KTypeProjection;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;)
INVOKEVIRTUAL (kotlin/reflect/KTypeProjection$Companion, invariant, (Lkotlin/reflect/KType;)Lkotlin/reflect/KTypeProjection;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;)
INVOKEVIRTUAL (kotlin/reflect/KTypeProjection$Companion, invariant, (Lkotlin/reflect/KType;)Lkotlin/reflect/KTypeProjection;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;)
LABEL (L47)
LINENUMBER (67)
INVOKESTATIC (kotlinx/serialization/SerializersKt, serializer, (Lkotlin/reflect/KType;)Lkotlinx/serialization/KSerializer;)
ASTORE (2)
LABEL (L48)
ICONST_0
ISTORE (3)
LABEL (L49)
LINENUMBER (68)
ALOAD (2)
LDC (null cannot be cast to non-null type kotlinx.serialization.KSerializer<T of kotlinx.serialization.internal.Platform_commonKt.cast>)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNull, (Ljava/lang/Object;Ljava/lang/String;)V)
LABEL (L50)
LINENUMBER (67)
NOP
LABEL (L51)
LINENUMBER (66)
NOP
LABEL (L52)
LINENUMBER (38)
ICONST_0
ISTORE (0)
LABEL (L53)
GETSTATIC (java/lang/Integer, TYPE, Ljava/lang/Class;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;)Lkotlin/reflect/KType;)
LABEL (L54)
LINENUMBER (69)
INVOKESTATIC (kotlinx/serialization/SerializersKt, serializer, (Lkotlin/reflect/KType;)Lkotlinx/serialization/KSerializer;)
ASTORE (1)
LABEL (L55)
ICONST_0
ISTORE (2)
LABEL (L56)
LINENUMBER (70)
ALOAD (1)
LDC (null cannot be cast to non-null type kotlinx.serialization.KSerializer<T of kotlinx.serialization.internal.Platform_commonKt.cast>)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNull, (Ljava/lang/Object;Ljava/lang/String;)V)
LABEL (L57)
LINENUMBER (69)
NOP
LABEL (L58)
LINENUMBER (40)
ICONST_0
ISTORE (0)
LABEL (L59)
LDC (LSerializableObject;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;)Lkotlin/reflect/KType;)
LABEL (L60)
LINENUMBER (71)
INVOKESTATIC (kotlinx/serialization/SerializersKt, serializer, (Lkotlin/reflect/KType;)Lkotlinx/serialization/KSerializer;)
ASTORE (1)
LABEL (L61)
ICONST_0
ISTORE (2)
LABEL (L62)
LINENUMBER (72)
ALOAD (1)
LDC (null cannot be cast to non-null type kotlinx.serialization.KSerializer<T of kotlinx.serialization.internal.Platform_commonKt.cast>)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNull, (Ljava/lang/Object;Ljava/lang/String;)V)
LABEL (L63)
LINENUMBER (71)
NOP
LABEL (L64)
LINENUMBER (42)
ICONST_0
ISTORE (0)
LABEL (L65)
LINENUMBER (73)
ICONST_0
ISTORE (1)
LABEL (L66)
LDC (Ljava/util/List;)
GETSTATIC (kotlin/reflect/KTypeProjection, Companion, Lkotlin/reflect/KTypeProjection$Companion;)
LDC (Ljava/util/List;)
GETSTATIC (kotlin/reflect/KTypeProjection, Companion, Lkotlin/reflect/KTypeProjection$Companion;)
LDC (LBox;)
GETSTATIC (kotlin/reflect/KTypeProjection, Companion, Lkotlin/reflect/KTypeProjection$Companion;)
GETSTATIC (java/lang/Integer, TYPE, Ljava/lang/Class;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;)Lkotlin/reflect/KType;)
INVOKEVIRTUAL (kotlin/reflect/KTypeProjection$Companion, invariant, (Lkotlin/reflect/KType;)Lkotlin/reflect/KTypeProjection;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;)
INVOKEVIRTUAL (kotlin/reflect/KTypeProjection$Companion, invariant, (Lkotlin/reflect/KType;)Lkotlin/reflect/KTypeProjection;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;)
INVOKEVIRTUAL (kotlin/reflect/KTypeProjection$Companion, invariant, (Lkotlin/reflect/KType;)Lkotlin/reflect/KTypeProjection;)
INVOKESTATIC (kotlin/jvm/internal/Reflection, typeOf, (Ljava/lang/Class;Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;)
LABEL (L67)
LINENUMBER (74)
INVOKESTATIC (kotlinx/serialization/SerializersKt, serializer, (Lkotlin/reflect/KType;)Lkotlinx/serialization/KSerializer;)
ASTORE (2)
LABEL (L68)
ICONST_0
ISTORE (3)
LABEL (L69)
LINENUMBER (75)
ALOAD (2)
LDC (null cannot be cast to non-null type kotlinx.serialization.KSerializer<T of kotlinx.serialization.internal.Platform_commonKt.cast>)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNull, (Ljava/lang/Object;Ljava/lang/String;)V)
LABEL (L70)
LINENUMBER (74)
NOP
LABEL (L71)
LINENUMBER (73)
NOP
LABEL (L72)
LINENUMBER (43)
RETURN
}
}
final class SerializableObject$$cachedSerializer$delegate$1 : kotlin/jvm/internal/Lambda, kotlin/jvm/functions/Function0 {
public final static SerializableObject$$cachedSerializer$delegate$1 INSTANCE
static void <clinit>()
void <init>()
public final kotlinx.serialization.KSerializer invoke()
public java.lang.Object invoke()
}
public final class SerializableObject : java/lang/Object {
private final static kotlin.Lazy $cachedSerializer$delegate
public final static SerializableObject INSTANCE
static void <clinit>()
private void <init>()
private final kotlin.Lazy get$cachedSerializer$delegate()
public final kotlinx.serialization.KSerializer serializer()
}
public final class Simple$$serializer : java/lang/Object, kotlinx/serialization/internal/GeneratedSerializer {
public final static Simple$$serializer INSTANCE
private final static kotlinx.serialization.internal.PluginGeneratedSerialDescriptor descriptor
static void <clinit>()
private void <init>()
public kotlinx.serialization.KSerializer[] childSerializers()
public Simple deserialize(kotlinx.serialization.encoding.Decoder decoder)
public java.lang.Object deserialize(kotlinx.serialization.encoding.Decoder decoder)
public kotlinx.serialization.descriptors.SerialDescriptor getDescriptor()
public void serialize(kotlinx.serialization.encoding.Encoder encoder, Simple value)
public void serialize(kotlinx.serialization.encoding.Encoder encoder, java.lang.Object value)
public kotlinx.serialization.KSerializer[] typeParametersSerializers()
}
public final class Simple$Companion : java/lang/Object {
private void <init>()
public void <init>(kotlin.jvm.internal.DefaultConstructorMarker $constructor_marker)
public final kotlinx.serialization.KSerializer serializer()
}
public final class Simple : java/lang/Object {
public final static Simple$Companion Companion
private final java.lang.String firstName
private final java.lang.String lastName
static void <clinit>()
public void <init>(java.lang.String firstName, java.lang.String lastName)
public void <init>(int seen1, java.lang.String firstName, java.lang.String lastName, kotlinx.serialization.internal.SerializationConstructorMarker serializationConstructorMarker)
public final java.lang.String getFirstName()
public final java.lang.String getLastName()
public final static void write$Self(Simple self, kotlinx.serialization.encoding.CompositeEncoder output, kotlinx.serialization.descriptors.SerialDescriptor serialDesc)
}
@@ -0,0 +1,43 @@
// CURIOUS_ABOUT test
// WITH_STDLIB
import kotlinx.serialization.*
@Serializable
class Simple(val firstName: String, val lastName: String)
@Serializable
data class Box<out T>(val boxed: T)
@Serializable
object SerializableObject {}
inline fun <reified T: Any> getSer(): KSerializer<T> {
return serializer<T>()
}
inline fun <reified T: Any> getBoxSer(): KSerializer<Box<T>> {
return serializer<Box<T>>()
}
inline fun <reified T: Any> listSer(): KSerializer<List<T>> {
return serializer<List<T>>()
}
fun test() {
serializer<Simple>()
getSer<Simple>()
getSer<Box<Simple>>()
getBoxSer<Simple>()
listSer<Simple>()
serializer<Box<List<Simple>>>()
listSer<Box<List<Simple>>>()
serializer<Int>()
serializer<SerializableObject>()
listSer<List<Box<Int>>>()
}
@@ -0,0 +1,260 @@
public final class Box$$serializer : java/lang/Object, kotlinx/serialization/internal/GeneratedSerializer {
private final kotlinx.serialization.descriptors.SerialDescriptor $$serialDesc
private kotlinx.serialization.KSerializer typeSerial0
private void <init>()
public void <init>(kotlinx.serialization.KSerializer typeSerial0)
public kotlinx.serialization.KSerializer[] childSerializers()
public Box deserialize(kotlinx.serialization.encoding.Decoder decoder)
public java.lang.Object deserialize(kotlinx.serialization.encoding.Decoder p0)
public kotlinx.serialization.descriptors.SerialDescriptor getDescriptor()
public void serialize(kotlinx.serialization.encoding.Encoder encoder, Box value)
public void serialize(kotlinx.serialization.encoding.Encoder p0, java.lang.Object p1)
public kotlinx.serialization.KSerializer[] typeParametersSerializers()
}
public final class Box$Companion : java/lang/Object {
private void <init>()
public void <init>(kotlin.jvm.internal.DefaultConstructorMarker $constructor_marker)
public final kotlinx.serialization.KSerializer serializer(kotlinx.serialization.KSerializer typeSerial0)
}
public final class Box : java/lang/Object {
private final static kotlinx.serialization.descriptors.SerialDescriptor $cachedDescriptor
public final static Box$Companion Companion
private final java.lang.Object boxed
static void <clinit>()
public void <init>(java.lang.Object boxed)
public void <init>(int seen1, java.lang.Object boxed, kotlinx.serialization.internal.SerializationConstructorMarker serializationConstructorMarker)
public final java.lang.Object component1()
public final Box copy(java.lang.Object boxed)
public static Box copy$default(Box p0, java.lang.Object p1, int p2, java.lang.Object p3)
public boolean equals(java.lang.Object p0)
public final java.lang.Object getBoxed()
public int hashCode()
public java.lang.String toString()
public final static void write$Self(Box self, kotlinx.serialization.encoding.CompositeEncoder output, kotlinx.serialization.descriptors.SerialDescriptor serialDesc, kotlinx.serialization.KSerializer typeSerial0)
}
public final class IntrinsicsKt : java/lang/Object {
public final static kotlinx.serialization.KSerializer getBoxSer()
public final static kotlinx.serialization.KSerializer getSer()
public final static kotlinx.serialization.KSerializer listSer()
public final static void test() {
LABEL (L0)
LINENUMBER (28)
GETSTATIC (Simple, Companion, LSimple$Companion;)
INVOKEVIRTUAL (Simple$Companion, serializer, ()Lkotlinx/serialization/KSerializer;)
POP
LABEL (L1)
LINENUMBER (29)
ICONST_0
ISTORE (0)
LABEL (L2)
LINENUMBER (44)
GETSTATIC (Simple, Companion, LSimple$Companion;)
INVOKEVIRTUAL (Simple$Companion, serializer, ()Lkotlinx/serialization/KSerializer;)
LABEL (L3)
POP
LABEL (L4)
LINENUMBER (30)
ICONST_0
ISTORE (0)
LABEL (L5)
LINENUMBER (45)
GETSTATIC (Box, Companion, LBox$Companion;)
GETSTATIC (Simple, Companion, LSimple$Companion;)
INVOKEVIRTUAL (Simple$Companion, serializer, ()Lkotlinx/serialization/KSerializer;)
INVOKEVIRTUAL (Box$Companion, serializer, (Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;)
LABEL (L6)
POP
LABEL (L7)
LINENUMBER (31)
ICONST_0
ISTORE (0)
LABEL (L8)
LINENUMBER (46)
GETSTATIC (Box, Companion, LBox$Companion;)
GETSTATIC (Simple, Companion, LSimple$Companion;)
INVOKEVIRTUAL (Simple$Companion, serializer, ()Lkotlinx/serialization/KSerializer;)
INVOKEVIRTUAL (Box$Companion, serializer, (Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;)
LABEL (L9)
POP
LABEL (L10)
LINENUMBER (32)
ICONST_0
ISTORE (0)
LABEL (L11)
LINENUMBER (47)
NEW (kotlinx/serialization/internal/ArrayListSerializer)
DUP
GETSTATIC (Simple, Companion, LSimple$Companion;)
INVOKEVIRTUAL (Simple$Companion, serializer, ()Lkotlinx/serialization/KSerializer;)
INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, <init>, (Lkotlinx/serialization/KSerializer;)V)
LABEL (L12)
POP
LABEL (L13)
LINENUMBER (34)
GETSTATIC (Box, Companion, LBox$Companion;)
NEW (kotlinx/serialization/internal/ArrayListSerializer)
DUP
GETSTATIC (Simple$$serializer, INSTANCE, LSimple$$serializer;)
CHECKCAST (kotlinx/serialization/KSerializer)
INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, <init>, (Lkotlinx/serialization/KSerializer;)V)
INVOKEVIRTUAL (Box$Companion, serializer, (Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;)
POP
LABEL (L14)
LINENUMBER (36)
ICONST_0
ISTORE (0)
LABEL (L15)
LINENUMBER (48)
NEW (kotlinx/serialization/internal/ArrayListSerializer)
DUP
GETSTATIC (Box, Companion, LBox$Companion;)
NEW (kotlinx/serialization/internal/ArrayListSerializer)
DUP
GETSTATIC (Simple$$serializer, INSTANCE, LSimple$$serializer;)
CHECKCAST (kotlinx/serialization/KSerializer)
INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, <init>, (Lkotlinx/serialization/KSerializer;)V)
INVOKEVIRTUAL (Box$Companion, serializer, (Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;)
INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, <init>, (Lkotlinx/serialization/KSerializer;)V)
LABEL (L16)
POP
LABEL (L17)
LINENUMBER (38)
GETSTATIC (kotlinx/serialization/internal/IntSerializer, INSTANCE, Lkotlinx/serialization/internal/IntSerializer;)
CHECKCAST (kotlinx/serialization/KSerializer)
POP
LABEL (L18)
LINENUMBER (40)
GETSTATIC (SerializableObject, INSTANCE, LSerializableObject;)
INVOKEVIRTUAL (SerializableObject, serializer, ()Lkotlinx/serialization/KSerializer;)
POP
LABEL (L19)
LINENUMBER (42)
ICONST_0
ISTORE (0)
LABEL (L20)
LINENUMBER (49)
NEW (kotlinx/serialization/internal/ArrayListSerializer)
DUP
NEW (kotlinx/serialization/internal/ArrayListSerializer)
DUP
NEW (Box$$serializer)
DUP
GETSTATIC (kotlinx/serialization/internal/IntSerializer, INSTANCE, Lkotlinx/serialization/internal/IntSerializer;)
CHECKCAST (kotlinx/serialization/KSerializer)
INVOKESPECIAL (Box$$serializer, <init>, (Lkotlinx/serialization/KSerializer;)V)
INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, <init>, (Lkotlinx/serialization/KSerializer;)V)
INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, <init>, (Lkotlinx/serialization/KSerializer;)V)
LABEL (L21)
POP
LABEL (L22)
LINENUMBER (43)
RETURN
}
}
final class SerializableObject$serializer$1 : kotlin/jvm/internal/Lambda, kotlin/jvm/functions/Function0 {
public final static SerializableObject$serializer$1 INSTANCE
static void <clinit>()
public void <init>()
public final kotlinx.serialization.KSerializer invoke()
public final java.lang.Object invoke()
}
public final class SerializableObject : java/lang/Object {
private final static kotlin.Lazy $cachedSerializer$delegate
public final static SerializableObject INSTANCE
static void <clinit>()
private void <init>()
public final kotlinx.serialization.KSerializer serializer()
}
public final class Simple$$serializer : java/lang/Object, kotlinx/serialization/internal/GeneratedSerializer {
private final static kotlinx.serialization.descriptors.SerialDescriptor $$serialDesc
public final static Simple$$serializer INSTANCE
static void <clinit>()
private void <init>()
public kotlinx.serialization.KSerializer[] childSerializers()
public Simple deserialize(kotlinx.serialization.encoding.Decoder decoder)
public java.lang.Object deserialize(kotlinx.serialization.encoding.Decoder p0)
public kotlinx.serialization.descriptors.SerialDescriptor getDescriptor()
public void serialize(kotlinx.serialization.encoding.Encoder encoder, Simple value)
public void serialize(kotlinx.serialization.encoding.Encoder p0, java.lang.Object p1)
public kotlinx.serialization.KSerializer[] typeParametersSerializers()
}
public final class Simple$Companion : java/lang/Object {
private void <init>()
public void <init>(kotlin.jvm.internal.DefaultConstructorMarker $constructor_marker)
public final kotlinx.serialization.KSerializer serializer()
}
public final class Simple : java/lang/Object {
public final static Simple$Companion Companion
private final java.lang.String firstName
private final java.lang.String lastName
static void <clinit>()
public void <init>(java.lang.String firstName, java.lang.String lastName)
public void <init>(int seen1, java.lang.String firstName, java.lang.String lastName, kotlinx.serialization.internal.SerializationConstructorMarker serializationConstructorMarker)
public final java.lang.String getFirstName()
public final java.lang.String getLastName()
public final static void write$Self(Simple self, kotlinx.serialization.encoding.CompositeEncoder output, kotlinx.serialization.descriptors.SerialDescriptor serialDesc)
}
@@ -37,6 +37,12 @@ public class SerializationAsmLikeInstructionsListingTestGenerated extends Abstra
runTest("plugins/kotlinx-serialization/testData/codegen/Delegated.kt");
}
@Test
@TestMetadata("Intrinsics.kt")
public void testIntrinsics() throws Exception {
runTest("plugins/kotlinx-serialization/testData/codegen/Intrinsics.kt");
}
@Test
@TestMetadata("Sealed.kt")
public void testSealed() throws Exception {
@@ -37,6 +37,12 @@ public class SerializationIrAsmLikeInstructionsListingTestGenerated extends Abst
runTest("plugins/kotlinx-serialization/testData/codegen/Delegated.kt");
}
@Test
@TestMetadata("Intrinsics.kt")
public void testIntrinsics() throws Exception {
runTest("plugins/kotlinx-serialization/testData/codegen/Intrinsics.kt");
}
@Test
@TestMetadata("Sealed.kt")
public void testSealed() throws Exception {