[KxSerialization] Fix "IllegalAccessError: Update to static final field"
Fixes #KT-57647 For value classes, if you add code to companion anonymous init block in IR, it will be executed in the instance constructor. This causes an error when initializing static fields, because writing to them can only occur from the <clinit> method. The solution is to transfer the static field initialization code from an anonymous init block to the IR initializer of this field Merge-request: KT-MR-9633 Merged-by: Sergey Shanshin <Sergey.Shanshin@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
803a11003f
commit
d8d643b7d7
-10
@@ -111,14 +111,4 @@ abstract class AbstractJvmBlackBoxCodegenTestBase<R : ResultingArtifact.Frontend
|
||||
|
||||
enableMetaInfoHandler()
|
||||
}
|
||||
|
||||
private fun TestConfigurationBuilder.configureModernJavaTest(jdkKind: TestJdkKind, jvmTarget: JvmTarget) {
|
||||
defaultDirectives {
|
||||
JDK_KIND with jdkKind
|
||||
JVM_TARGET with jvmTarget
|
||||
+WITH_STDLIB
|
||||
+USE_JAVAC_BASED_ON_JVM_TARGET
|
||||
+IGNORE_DEXING
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
@@ -5,14 +5,19 @@
|
||||
|
||||
package org.jetbrains.kotlin.test.runners.codegen
|
||||
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||
import org.jetbrains.kotlin.test.Constructor
|
||||
import org.jetbrains.kotlin.test.HandlersStepBuilder
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
import org.jetbrains.kotlin.test.backend.handlers.*
|
||||
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
|
||||
import org.jetbrains.kotlin.test.builders.*
|
||||
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
|
||||
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.DUMP_SMAP
|
||||
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.RUN_DEX_CHECKER
|
||||
import org.jetbrains.kotlin.test.directives.ConfigurationDirectives
|
||||
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives
|
||||
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives
|
||||
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact
|
||||
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
|
||||
@@ -188,3 +193,13 @@ fun HandlersStepBuilder<BinaryArtifacts.Jvm>.inlineHandlers() {
|
||||
::SMAPDumpHandler
|
||||
)
|
||||
}
|
||||
|
||||
fun TestConfigurationBuilder.configureModernJavaTest(jdkKind: TestJdkKind, jvmTarget: JvmTarget) {
|
||||
defaultDirectives {
|
||||
JvmEnvironmentConfigurationDirectives.JDK_KIND with jdkKind
|
||||
JvmEnvironmentConfigurationDirectives.JVM_TARGET with jvmTarget
|
||||
+ConfigurationDirectives.WITH_STDLIB
|
||||
+CodegenTestDirectives.USE_JAVAC_BASED_ON_JVM_TARGET
|
||||
+CodegenTestDirectives.IGNORE_DEXING
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -398,8 +398,8 @@ abstract class BaseIrGenerator(private val currentClass: IrClass, final override
|
||||
val kSerializerType = kSerializerClass.typeWith(compilerContext.irBuiltIns.anyType)
|
||||
val arrayType = compilerContext.irBuiltIns.arrayClass.typeWith(kSerializerType)
|
||||
|
||||
return addValPropertyWithJvmField(arrayType, SerialEntityNames.CACHED_CHILD_SERIALIZERS_PROPERTY_NAME) {
|
||||
+createArrayOfExpression(kSerializerType, cacheableSerializers.map { it ?: irNull() })
|
||||
return addValPropertyWithJvmFieldInitializer(arrayType, SerialEntityNames.CACHED_CHILD_SERIALIZERS_PROPERTY_NAME) {
|
||||
createArrayOfExpression(kSerializerType, cacheableSerializers.map { it ?: irNull() })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+24
@@ -161,6 +161,30 @@ interface IrBuilderWithPluginContext {
|
||||
}
|
||||
}
|
||||
|
||||
fun IrClass.addValPropertyWithJvmFieldInitializer(
|
||||
type: IrType,
|
||||
name: Name,
|
||||
visibility: DescriptorVisibility = DescriptorVisibilities.PRIVATE,
|
||||
initializer: IrBuilderWithScope.() -> IrExpression
|
||||
): IrProperty {
|
||||
return generateSimplePropertyWithBackingField(name, type, this, visibility).apply {
|
||||
val field = backingField!!
|
||||
|
||||
val builder = DeclarationIrBuilder(
|
||||
compilerContext,
|
||||
field.symbol,
|
||||
field.startOffset,
|
||||
field.endOffset
|
||||
)
|
||||
field.initializer = IrExpressionBodyImpl(builder.initializer())
|
||||
|
||||
val annotationCtor = compilerContext.jvmFieldClassSymbol.constructors.single { it.owner.isPrimary }
|
||||
val annotationType = compilerContext.jvmFieldClassSymbol.defaultType
|
||||
|
||||
field.annotations += IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, annotationType, annotationCtor)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all statements to the builder, except the last one.
|
||||
* The last statement should be an expression, it will return as a result
|
||||
|
||||
@@ -262,8 +262,6 @@ public final class ListOfUsers : java/lang/Object {
|
||||
AASTORE
|
||||
ALOAD (0)
|
||||
PUTSTATIC (ListOfUsers, $childSerializers, [Lkotlinx/serialization/KSerializer;)
|
||||
LABEL (L1)
|
||||
LINENUMBER (13)
|
||||
RETURN
|
||||
}
|
||||
|
||||
|
||||
@@ -223,8 +223,6 @@ public final class Container : java/lang/Object {
|
||||
AASTORE
|
||||
ALOAD (0)
|
||||
PUTSTATIC (Container, $childSerializers, [Lkotlinx/serialization/KSerializer;)
|
||||
LABEL (L1)
|
||||
LINENUMBER (19)
|
||||
RETURN
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
|
||||
// WITH_STDLIB
|
||||
// IGNORE_DEXING
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import java.util.UUID
|
||||
|
||||
@Serializable
|
||||
@JvmInline
|
||||
value class Id(val id: @Contextual UUID) {
|
||||
companion object {
|
||||
fun random() = Id(UUID.randomUUID())
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@JvmInline
|
||||
value class Parametrized<T: Any>(val l: List<T>)
|
||||
|
||||
|
||||
fun pageMain () {
|
||||
val id: Id = Id.random()
|
||||
println(id)
|
||||
}
|
||||
|
||||
|
||||
fun box(): String {
|
||||
println(System.getProperty("java.version"))
|
||||
pageMain()
|
||||
return "OK"
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlinx.serialization.runners;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlinx.serialization.TestGeneratorKt}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("plugins/kotlinx-serialization/testData/jdk11BoxIr")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class SerializationJdk11IrBoxTestGenerated extends AbstractSerializationJdk11IrBoxTest {
|
||||
@Test
|
||||
public void testAllFilesPresentInJdk11BoxIr() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/kotlinx-serialization/testData/jdk11BoxIr"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt57647.kt")
|
||||
public void testKt57647() throws Exception {
|
||||
runTest("plugins/kotlinx-serialization/testData/jdk11BoxIr/kt57647.kt");
|
||||
}
|
||||
}
|
||||
+4
@@ -48,6 +48,10 @@ fun main(args: Array<String>) {
|
||||
model("boxIr")
|
||||
}
|
||||
|
||||
testClass<AbstractSerializationJdk11IrBoxTest> {
|
||||
model("jdk11BoxIr")
|
||||
}
|
||||
|
||||
testClass<AbstractSerializationFirLightTreeBlackBoxTest> {
|
||||
model("boxIr")
|
||||
model("firMembers")
|
||||
|
||||
+7
@@ -19,6 +19,13 @@ open class AbstractSerializationIrBoxTest : AbstractIrBlackBoxCodegenTest() {
|
||||
}
|
||||
}
|
||||
|
||||
open class AbstractSerializationJdk11IrBoxTest : AbstractIrBlackBoxCodegenTest() {
|
||||
override fun configure(builder: TestConfigurationBuilder) {
|
||||
super.configure(builder)
|
||||
builder.configureForKotlinxSerialization(useJdk11 = true)
|
||||
}
|
||||
}
|
||||
|
||||
open class AbstractSerializationWithoutRuntimeIrBoxTest : AbstractIrBlackBoxCodegenTest() {
|
||||
override fun configure(builder: TestConfigurationBuilder) {
|
||||
super.configure(builder)
|
||||
|
||||
+9
-3
@@ -8,17 +8,18 @@ package org.jetbrains.kotlinx.serialization
|
||||
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
|
||||
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.test.TargetBackend
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
import org.jetbrains.kotlin.test.bind
|
||||
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.runners.codegen.configureModernJavaTest
|
||||
import org.jetbrains.kotlin.test.services.EnvironmentConfigurator
|
||||
import org.jetbrains.kotlin.test.services.RuntimeClasspathProvider
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationComponentRegistrar
|
||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationIntrinsicsState
|
||||
import org.jetbrains.kotlinx.serialization.compiler.fir.FirSerializationExtensionRegistrar
|
||||
import java.io.File
|
||||
|
||||
private val librariesPaths = listOfNotNull(RuntimeLibraryInClasspathTest.coreLibraryPath, RuntimeLibraryInClasspathTest.jsonLibraryPath)
|
||||
@@ -57,10 +58,15 @@ class SerializationRuntimeClasspathJsProvider(testServices: TestServices) : Runt
|
||||
|
||||
fun TestConfigurationBuilder.configureForKotlinxSerialization(
|
||||
noLibraries: Boolean = false,
|
||||
target: TargetBackend = TargetBackend.JVM
|
||||
target: TargetBackend = TargetBackend.JVM,
|
||||
useJdk11: Boolean = false
|
||||
) {
|
||||
useConfigurators(::SerializationEnvironmentConfigurator.bind(noLibraries))
|
||||
|
||||
if (useJdk11) {
|
||||
configureModernJavaTest(TestJdkKind.FULL_JDK_11, JvmTarget.JVM_11)
|
||||
}
|
||||
|
||||
if (!noLibraries) {
|
||||
when (target) {
|
||||
TargetBackend.JVM, TargetBackend.JVM_IR -> useCustomRuntimeClasspathProviders(::SerializationRuntimeClasspathJvmProvider)
|
||||
|
||||
Reference in New Issue
Block a user