Skip to content

Commit 035172c

Browse files
committed
[KxSerialization] Fix "IllegalAccessError: Update to static final field"
Fixed #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
1 parent ea2e0bd commit 035172c

File tree

11 files changed

+130
-18
lines changed

11 files changed

+130
-18
lines changed

compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/codegen/AbstractJvmBlackBoxCodegenTestBase.kt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,4 @@ abstract class AbstractJvmBlackBoxCodegenTestBase<R : ResultingArtifact.Frontend
102102

103103
enableMetaInfoHandler()
104104
}
105-
106-
private fun TestConfigurationBuilder.configureModernJavaTest(jdkKind: TestJdkKind, jvmTarget: JvmTarget) {
107-
defaultDirectives {
108-
JDK_KIND with jdkKind
109-
JVM_TARGET with jvmTarget
110-
+WITH_STDLIB
111-
+USE_JAVAC_BASED_ON_JVM_TARGET
112-
+IGNORE_DEXING
113-
}
114-
}
115105
}

compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/codegen/BaseCodegenConfiguration.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,20 @@
55

66
package org.jetbrains.kotlin.test.runners.codegen
77

8+
import org.jetbrains.kotlin.config.JvmTarget
89
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
910
import org.jetbrains.kotlin.test.Constructor
1011
import org.jetbrains.kotlin.test.HandlersStepBuilder
12+
import org.jetbrains.kotlin.test.TestJdkKind
1113
import org.jetbrains.kotlin.test.backend.handlers.*
1214
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
1315
import org.jetbrains.kotlin.test.builders.*
16+
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
1417
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.DUMP_SMAP
1518
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.RUN_DEX_CHECKER
19+
import org.jetbrains.kotlin.test.directives.ConfigurationDirectives
20+
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives
21+
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives
1622
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact
1723
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
1824
import org.jetbrains.kotlin.test.model.*
@@ -181,3 +187,13 @@ fun HandlersStepBuilder<BinaryArtifacts.Jvm>.inlineHandlers() {
181187
::SMAPDumpHandler
182188
)
183189
}
190+
191+
fun TestConfigurationBuilder.configureModernJavaTest(jdkKind: TestJdkKind, jvmTarget: JvmTarget) {
192+
defaultDirectives {
193+
JvmEnvironmentConfigurationDirectives.JDK_KIND with jdkKind
194+
JvmEnvironmentConfigurationDirectives.JVM_TARGET with jvmTarget
195+
+ConfigurationDirectives.WITH_STDLIB
196+
+CodegenTestDirectives.USE_JAVAC_BASED_ON_JVM_TARGET
197+
+CodegenTestDirectives.IGNORE_DEXING
198+
}
199+
}

plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/BaseIrGenerator.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,8 @@ abstract class BaseIrGenerator(private val currentClass: IrClass, final override
376376
val kSerializerType = kSerializerClass.typeWith(compilerContext.irBuiltIns.anyType)
377377
val arrayType = compilerContext.irBuiltIns.arrayClass.typeWith(kSerializerType)
378378

379-
return addValPropertyWithJvmField(arrayType, SerialEntityNames.CACHED_CHILD_SERIALIZERS_PROPERTY_NAME) {
380-
+createArrayOfExpression(kSerializerType, cacheableSerializers.map { it ?: irNull() })
379+
return addValPropertyWithJvmFieldInitializer(arrayType, SerialEntityNames.CACHED_CHILD_SERIALIZERS_PROPERTY_NAME) {
380+
createArrayOfExpression(kSerializerType, cacheableSerializers.map { it ?: irNull() })
381381
}
382382
}
383383

plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/IrBuilderWithPluginContext.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,30 @@ interface IrBuilderWithPluginContext {
162162
}
163163
}
164164

165+
fun IrClass.addValPropertyWithJvmFieldInitializer(
166+
type: IrType,
167+
name: Name,
168+
visibility: DescriptorVisibility = DescriptorVisibilities.PRIVATE,
169+
initializer: IrBuilderWithScope.() -> IrExpression
170+
): IrProperty {
171+
return generateSimplePropertyWithBackingField(name, type, this, visibility).apply {
172+
val field = backingField!!
173+
174+
val builder = DeclarationIrBuilder(
175+
compilerContext,
176+
field.symbol,
177+
field.startOffset,
178+
field.endOffset
179+
)
180+
field.initializer = IrExpressionBodyImpl(builder.initializer())
181+
182+
val annotationCtor = compilerContext.jvmFieldClassSymbol.constructors.single { it.owner.isPrimary }
183+
val annotationType = compilerContext.jvmFieldClassSymbol.defaultType
184+
185+
field.annotations += IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, annotationType, annotationCtor)
186+
}
187+
}
188+
165189
/**
166190
* Add all statements to the builder, except the last one.
167191
* The last statement should be an expression, it will return as a result

plugins/kotlinx-serialization/testData/codegen/Basic.asm.ir.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,6 @@ public final class ListOfUsers : java/lang/Object {
261261
AASTORE
262262
ALOAD (0)
263263
PUTSTATIC (ListOfUsers, $childSerializers, [Lkotlinx/serialization/KSerializer;)
264-
LABEL (L1)
265-
LINENUMBER (13)
266264
RETURN
267265
}
268266

plugins/kotlinx-serialization/testData/codegen/Sealed.asm.ir.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,6 @@ public final class Container : java/lang/Object {
222222
AASTORE
223223
ALOAD (0)
224224
PUTSTATIC (Container, $childSerializers, [Lkotlinx/serialization/KSerializer;)
225-
LABEL (L1)
226-
LINENUMBER (19)
227225
RETURN
228226
}
229227

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// TARGET_BACKEND: JVM_IR
2+
3+
// WITH_STDLIB
4+
// IGNORE_DEXING
5+
6+
import kotlinx.serialization.*
7+
import java.util.UUID
8+
9+
@Serializable
10+
@JvmInline
11+
value class Id(val id: @Contextual UUID) {
12+
companion object {
13+
fun random() = Id(UUID.randomUUID())
14+
}
15+
}
16+
17+
@Serializable
18+
@JvmInline
19+
value class Parametrized<T: Any>(val l: List<T>)
20+
21+
fun pageMain () {
22+
val id: Id = Id.random()
23+
println(id)
24+
}
25+
26+
27+
fun box(): String {
28+
println(System.getProperty("java.version"))
29+
pageMain()
30+
return "OK"
31+
}

plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationJdk11IrBoxTestGenerated.java

Lines changed: 33 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/TestGenerator.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ fun main(args: Array<String>) {
4444
model("boxIr")
4545
}
4646

47+
testClass<AbstractSerializationJdk11IrBoxTest> {
48+
model("jdk11BoxIr")
49+
}
50+
4751
testClass<AbstractSerializationFirBlackBoxTest> {
4852
model("boxIr")
4953
model("firMembers")

plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/runners/BoxTests.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ open class AbstractSerializationIrBoxTest : AbstractIrBlackBoxCodegenTest() {
1818
}
1919
}
2020

21+
open class AbstractSerializationJdk11IrBoxTest : AbstractIrBlackBoxCodegenTest() {
22+
override fun configure(builder: TestConfigurationBuilder) {
23+
super.configure(builder)
24+
builder.configureForKotlinxSerialization(useJdk11 = true)
25+
}
26+
}
27+
2128
open class AbstractSerializationWithoutRuntimeIrBoxTest : AbstractIrBlackBoxCodegenTest() {
2229
override fun configure(builder: TestConfigurationBuilder) {
2330
super.configure(builder)

plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/serializationConfiguration.kt

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,19 @@ package org.jetbrains.kotlinx.serialization
88
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
99
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
1010
import org.jetbrains.kotlin.config.CompilerConfiguration
11+
import org.jetbrains.kotlin.config.JvmTarget
12+
import org.jetbrains.kotlin.test.TargetBackend
13+
import org.jetbrains.kotlin.test.TestJdkKind
1114
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter
1215
import org.jetbrains.kotlin.test.bind
1316
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
1417
import org.jetbrains.kotlin.test.model.TestModule
18+
import org.jetbrains.kotlin.test.runners.codegen.configureModernJavaTest
1519
import org.jetbrains.kotlin.test.services.EnvironmentConfigurator
1620
import org.jetbrains.kotlin.test.services.RuntimeClasspathProvider
1721
import org.jetbrains.kotlin.test.services.TestServices
1822
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationComponentRegistrar
1923
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationIntrinsicsState
20-
import org.jetbrains.kotlinx.serialization.compiler.fir.FirSerializationExtensionRegistrar
2124
import java.io.File
2225

2326
private val librariesPaths = listOfNotNull(RuntimeLibraryInClasspathTest.coreLibraryPath, RuntimeLibraryInClasspathTest.jsonLibraryPath)
@@ -45,8 +48,16 @@ class SerializationRuntimeClasspathProvider(testServices: TestServices) : Runtim
4548
}
4649
}
4750

48-
fun TestConfigurationBuilder.configureForKotlinxSerialization(noLibraries: Boolean = false) {
51+
fun TestConfigurationBuilder.configureForKotlinxSerialization(
52+
noLibraries: Boolean = false,
53+
useJdk11: Boolean = false
54+
) {
4955
useConfigurators(::SerializationEnvironmentConfigurator.bind(noLibraries))
56+
57+
if (useJdk11) {
58+
configureModernJavaTest(TestJdkKind.FULL_JDK_11, JvmTarget.JVM_11)
59+
}
60+
5061
if (!noLibraries) {
5162
useCustomRuntimeClasspathProviders(::SerializationRuntimeClasspathProvider)
5263
}

0 commit comments

Comments
 (0)