Support plugin intrinsics for serializer() function in K2.

- Add IrPluginContext to JvmBackendContext, so plugin intrinsics can
reference external functions properly.

- Do not use module.findClassAcrossModuleDependencies as Descriptor API does not work for FIR.

- Add asm listing tests in serialization plugin for K2

- Remove Delegated.kt asm listing test as we have similar test in boxIr group.

#KT-56553 Fixed
This commit is contained in:
Leonid Startsev
2023-02-09 15:43:48 +01:00
committed by Space Team
parent 121c920099
commit 80ad6a4cd7
20 changed files with 2416 additions and 359 deletions
@@ -5,7 +5,7 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.extensions.FirIncompatiblePluginAPI
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.codegen.*
import org.jetbrains.kotlin.backend.jvm.intrinsics.IntrinsicMethod
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.Companion.pluginIn
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.Companion.pluginIntrinsicsMarkerOwner
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.Companion.pluginIntrinsicsMarkerSignature
import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
@@ -49,7 +48,6 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializersClassIds.
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializersClassIds.referenceArraySerializerId
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializersClassIds.sealedSerializerId
import org.jetbrains.kotlinx.serialization.compiler.resolve.SpecialBuiltins
import org.jetbrains.kotlinx.serialization.compiler.resolve.annotationsWithArguments
import org.jetbrains.kotlinx.serialization.compiler.resolve.getClassFromSerializationPackage
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
@@ -59,7 +57,10 @@ import org.jetbrains.org.objectweb.asm.tree.InsnList
import org.jetbrains.org.objectweb.asm.tree.LdcInsnNode
import org.jetbrains.org.objectweb.asm.tree.VarInsnNode
class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContext) : SerializationBaseContext, JvmIrIntrinsicExtension {
class SerializationJvmIrIntrinsicSupport(
private val jvmBackendContext: JvmBackendContext,
private val irPluginContext: IrPluginContext
) : SerializationBaseContext, JvmIrIntrinsicExtension {
sealed class IntrinsicType(val methodDescriptor: String) {
object Simple : IntrinsicType(stubCallDescriptor)
@@ -151,14 +152,7 @@ class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContex
private val typeSystemContext = jvmBackendContext.typeSystem
private val typeMapper = jvmBackendContext.defaultTypeMapper
/**
* This likely won't work in FIR because module is empty there and can't reference dependencies
* Proper referencing can be done via FirPluginContext, but it's not available in the intrinsics.
*/
@FirIncompatiblePluginAPI
override fun referenceClassId(classId: ClassId): IrClassSymbol? {
return module.findClassAcrossModuleDependencies(classId)?.let { jvmBackendContext.referenceClass(it) }
}
override fun referenceClassId(classId: ClassId): IrClassSymbol? = irPluginContext.referenceClass(classId)
private val currentVersion by lazy {
VersionReader.getVersionsForCurrentModuleFromTrace(module, jvmBackendContext.state.bindingTrace)
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2023 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.
*/
@@ -14,9 +14,7 @@ import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.fileParent
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
@@ -185,25 +183,23 @@ open class SerializationLoweringExtension @JvmOverloads constructor(
override fun getPlatformIntrinsicExtension(backendContext: BackendContext): IrIntrinsicExtension? {
val ctx = backendContext as? JvmBackendContext ?: return null
if (!canEnableIntrinsics(ctx)) return null
return SerializationJvmIrIntrinsicSupport(ctx)
return SerializationJvmIrIntrinsicSupport(
ctx,
requireNotNull(ctx.irPluginContext) { "Intrinsics can't be enabled with null irPluginContext, check `canEnableIntrinsics` function for bugs." })
}
private fun canEnableIntrinsics(ctx: JvmBackendContext): Boolean {
if (ctx.state.configuration[CommonConfigurationKeys.USE_FIR] == true) return false
return when (intrinsicsState) {
SerializationIntrinsicsState.FORCE_ENABLED -> true
SerializationIntrinsicsState.DISABLED -> false
SerializationIntrinsicsState.NORMAL -> {
val module = ctx.state.module
if (module.findClassAcrossModuleDependencies(
ClassId(
SerializationPackages.packageFqName,
SerialEntityNames.KSERIALIZER_NAME
)
) == null
) return false
module.getPackage(SerializationPackages.packageFqName).memberScope.getFunctionNames()
.any { it.asString() == SerializationJvmIrIntrinsicSupport.noCompiledSerializerMethodName }
val requiredFunctionsFromRuntime = ctx.irPluginContext?.referenceFunctions(
CallableId(
SerializationPackages.packageFqName,
Name.identifier(SerializationJvmIrIntrinsicSupport.noCompiledSerializerMethodName)
)
).orEmpty()
requiredFunctionsFromRuntime.isNotEmpty() && requiredFunctionsFromRuntime.all { it.isBound }
}
}
}