diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt index 8f22728b331..c4a9989f09c 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt @@ -77,7 +77,8 @@ class WasmSymbols( getProperty(FqName.fromSegments(listOf("kotlin", "wasm", "internal", "isNotFirstWasmExportCall"))) ) - internal val tryGetAssociatedObject = getInternalFunction("tryGetAssociatedObject") + internal val initAssociatedObjects = getInternalFunction("initAssociatedObjects") + internal val addAssociatedObject = getInternalFunction("addAssociatedObject") override val throwNullPointerException = getInternalFunction("THROW_NPE") override val throwISE = getInternalFunction("THROW_ISE") diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/AssociatedObjectsLowering.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/AssociatedObjectsLowering.kt index 7f231330ae4..ab360ecb353 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/AssociatedObjectsLowering.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/AssociatedObjectsLowering.kt @@ -7,12 +7,11 @@ package org.jetbrains.kotlin.backend.wasm.lower import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.lower.createIrBuilder -import org.jetbrains.kotlin.backend.common.lower.irIfThen import org.jetbrains.kotlin.backend.wasm.WasmBackendContext import org.jetbrains.kotlin.backend.wasm.WasmSymbols import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.backend.js.utils.associatedObject import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.IrClass @@ -46,7 +45,7 @@ class AssociatedObjectsLowering(val context: WasmBackendContext) : FileLoweringP } private val visitor = object : IrElementVisitorVoid { - val tryGetAssociatedObject = (context.wasmSymbols.tryGetAssociatedObject.owner.body as IrBlockBody).statements + val initFunctionStatements = (context.wasmSymbols.initAssociatedObjects.owner.body as IrBlockBody).statements override fun visitElement(element: IrElement) { if (element is IrClass) { @@ -63,44 +62,49 @@ class AssociatedObjectsLowering(val context: WasmBackendContext) : FileLoweringP if (klassAnnotation.valueArgumentsCount != 1) continue val associatedObject = klassAnnotation.associatedObject() ?: continue - val builder = cachedBuilder ?: context.createIrBuilder(context.wasmSymbols.tryGetAssociatedObject) + val builder = cachedBuilder ?: context.createIrBuilder(context.wasmSymbols.initAssociatedObjects) cachedBuilder = builder - val selector = builder.createAssociatedObjectSelector( + val addCall = builder.createAssociatedObjectAdd( wasmSymbols = context.wasmSymbols, irBuiltIns = context.irBuiltIns, targetClass = declaration.symbol, keyAnnotation = annotationClass.symbol, associatedObject = associatedObject.symbol ) - tryGetAssociatedObject.add(0, selector) + initFunctionStatements.add(addCall) } } } } -private fun IrBuilderWithScope.createAssociatedObjectSelector( +private fun IrBuilderWithScope.createAssociatedObjectAdd( wasmSymbols: WasmSymbols, irBuiltIns: IrBuiltIns, targetClass: IrClassSymbol, keyAnnotation: IrClassSymbol, associatedObject: IrClassSymbol -): IrStatement { - val classIdParam = irGet(wasmSymbols.tryGetAssociatedObject.owner.valueParameters[0]) - val keyIdParam = irGet(wasmSymbols.tryGetAssociatedObject.owner.valueParameters[1]) - - val classId = irCall(wasmSymbols.wasmTypeId, irBuiltIns.intType).also { - it.putTypeArgument(0, targetClass.defaultType) - } - val keyId = irCall(wasmSymbols.wasmTypeId, irBuiltIns.intType).also { - it.putTypeArgument(0, keyAnnotation.defaultType) - } - - return irIfThen( - condition = irEquals(classIdParam, classId), - thenPart = irIfThen( - condition = irEquals(keyIdParam, keyId), - thenPart = irReturn(irGetObjectValue(irBuiltIns.anyType, associatedObject)) +): IrCall = buildStatement(UNDEFINED_OFFSET, UNDEFINED_OFFSET) { + irCall(wasmSymbols.addAssociatedObject, irBuiltIns.unitType).also { addCall -> + addCall.putValueArgument( + 0, + irGet(wasmSymbols.initAssociatedObjects.owner.valueParameters[0]) ) - ) + addCall.putValueArgument( + 1, + irCall(wasmSymbols.wasmTypeId, irBuiltIns.intType).also { + it.putTypeArgument(0, targetClass.defaultType) + } + ) + addCall.putValueArgument( + 2, + irCall(wasmSymbols.wasmTypeId, irBuiltIns.intType).also { + it.putTypeArgument(0, keyAnnotation.defaultType) + } + ) + addCall.putValueArgument( + 3, + irGetObjectValue(irBuiltIns.anyType, associatedObject) + ) + } } \ No newline at end of file diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsES6BoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsES6BoxTestGenerated.java index bfd1662a465..63fa5e3af79 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsES6BoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsES6BoxTestGenerated.java @@ -10314,12 +10314,6 @@ public class FirJsES6BoxTestGenerated extends AbstractFirJsES6BoxTest { runTest("js/js.translator/testData/box/reflection/findAssociatedObjectInSeparatedFile.kt"); } - @Test - @TestMetadata("findAssociatedObjectLazyness.kt") - public void testFindAssociatedObjectLazyness() throws Exception { - runTest("js/js.translator/testData/box/reflection/findAssociatedObjectLazyness.kt"); - } - @Test @TestMetadata("findAssociatedObject_oldBE.kt") public void testFindAssociatedObject_oldBE() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirLightTreeJsBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirLightTreeJsBoxTestGenerated.java index fd0828ef08a..b5844e41989 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirLightTreeJsBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirLightTreeJsBoxTestGenerated.java @@ -10208,12 +10208,6 @@ public class FirLightTreeJsBoxTestGenerated extends AbstractFirLightTreeJsBoxTes runTest("js/js.translator/testData/box/reflection/findAssociatedObjectInSeparatedFile.kt"); } - @Test - @TestMetadata("findAssociatedObjectLazyness.kt") - public void testFindAssociatedObjectLazyness() throws Exception { - runTest("js/js.translator/testData/box/reflection/findAssociatedObjectLazyness.kt"); - } - @Test @TestMetadata("findAssociatedObject_oldBE.kt") public void testFindAssociatedObject_oldBE() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirPsiJsBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirPsiJsBoxTestGenerated.java index a567059bd43..225ba71ff26 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirPsiJsBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirPsiJsBoxTestGenerated.java @@ -10208,12 +10208,6 @@ public class FirPsiJsBoxTestGenerated extends AbstractFirPsiJsBoxTest { runTest("js/js.translator/testData/box/reflection/findAssociatedObjectInSeparatedFile.kt"); } - @Test - @TestMetadata("findAssociatedObjectLazyness.kt") - public void testFindAssociatedObjectLazyness() throws Exception { - runTest("js/js.translator/testData/box/reflection/findAssociatedObjectLazyness.kt"); - } - @Test @TestMetadata("findAssociatedObject_oldBE.kt") public void testFindAssociatedObject_oldBE() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java index 5d4a3f8774b..daade41ac03 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java @@ -10314,12 +10314,6 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test { runTest("js/js.translator/testData/box/reflection/findAssociatedObjectInSeparatedFile.kt"); } - @Test - @TestMetadata("findAssociatedObjectLazyness.kt") - public void testFindAssociatedObjectLazyness() throws Exception { - runTest("js/js.translator/testData/box/reflection/findAssociatedObjectLazyness.kt"); - } - @Test @TestMetadata("findAssociatedObject_oldBE.kt") public void testFindAssociatedObject_oldBE() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java index 66211f1cbed..1818035bcc6 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java @@ -10208,12 +10208,6 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { runTest("js/js.translator/testData/box/reflection/findAssociatedObjectInSeparatedFile.kt"); } - @Test - @TestMetadata("findAssociatedObjectLazyness.kt") - public void testFindAssociatedObjectLazyness() throws Exception { - runTest("js/js.translator/testData/box/reflection/findAssociatedObjectLazyness.kt"); - } - @Test @TestMetadata("findAssociatedObject_oldBE.kt") public void testFindAssociatedObject_oldBE() throws Exception { diff --git a/js/js.translator/testData/box/reflection/findAssociatedObjectLazyness.kt b/js/js.translator/testData/box/reflection/findAssociatedObjectLazyness.kt deleted file mode 100644 index f4feb8ffdc2..00000000000 --- a/js/js.translator/testData/box/reflection/findAssociatedObjectLazyness.kt +++ /dev/null @@ -1,64 +0,0 @@ -@file:OptIn(ExperimentalAssociatedObjects::class) - -import kotlin.reflect.AssociatedObjectKey -import kotlin.reflect.ExperimentalAssociatedObjects -import kotlin.reflect.findAssociatedObject -import kotlin.reflect.KClass - -private var obj1Init = false -private var obj2Init = false -private var obj3Init = false - -@AssociatedObjectKey -annotation class KEY1(val kClass: KClass<*>) - -@AssociatedObjectKey -annotation class KEY2(val kClass: KClass<*>) - -private object OBJ1 { - init { obj1Init = true } -} - -private object OBJ2 { - init { obj2Init = true } -} - -private object OBJ3 { - init { obj3Init = true } -} - -@KEY1(OBJ1::class) -class CLS1 - -@KEY1(OBJ2::class) -@KEY2(OBJ3::class) -class CLS2 - -fun box(): String { - // No objects initialised - if (obj1Init) return "FAIL1" - if (obj2Init) return "FAIL2" - if (obj3Init) return "FAIL3" - - CLS1::class.findAssociatedObject() - if (obj1Init) return "FAIL4" - if (obj2Init) return "FAIL5" - if (obj3Init) return "FAIL6" - - CLS1::class.findAssociatedObject() - if (!obj1Init) return "FAIL7" - if (obj2Init) return "FAIL8" - if (obj3Init) return "FAIL9" - - CLS2::class.findAssociatedObject() - if (!obj1Init) return "FAIL10" - if (!obj2Init) return "FAIL11" - if (obj3Init) return "FAIL12" - - CLS2::class.findAssociatedObject() - if (!obj1Init) return "FAIL13" - if (!obj2Init) return "FAIL14" - if (!obj3Init) return "FAIL15" - - return "OK" -} \ No newline at end of file diff --git a/libraries/stdlib/wasm/src/kotlin/reflect/associatedObjectsImpl.kt b/libraries/stdlib/wasm/src/kotlin/reflect/associatedObjectsImpl.kt index ac335ee0299..2a34f36b033 100644 --- a/libraries/stdlib/wasm/src/kotlin/reflect/associatedObjectsImpl.kt +++ b/libraries/stdlib/wasm/src/kotlin/reflect/associatedObjectsImpl.kt @@ -8,16 +8,35 @@ package kotlin.wasm.internal import kotlin.reflect.wasm.internal.KClassImpl import kotlin.reflect.KClass +internal var associatedObjects: Map? = null + @PublishedApi internal fun findAssociatedObject(klass: KClass<*>, key: Int): Any? { val klassId = (klass as? KClassImpl<*>)?.typeData?.typeId ?: return null - return tryGetAssociatedObject(klassId, key) + + val map = associatedObjects ?: run { + val newMap: MutableMap = mutableMapOf() + initAssociatedObjects(newMap) + associatedObjects = newMap + newMap + } + + return map[packIntoULong(klassId, key)] } -internal fun tryGetAssociatedObject( - @Suppress("UNUSED_PARAMETER") klassId: Int, - @Suppress("UNUSED_PARAMETER") keyId: Int, -): Any? { +internal fun packIntoULong(a: Int, b: Int): ULong = + (a.toUInt().toULong() shl Int.SIZE_BITS) or b.toUInt().toULong() + +internal fun addAssociatedObject( + mapToInit: MutableMap, + klassId: Int, + keyId: Int, + instance: Any +) { + mapToInit[packIntoULong(klassId, keyId)] = instance +} + +internal fun initAssociatedObjects(@Suppress("UNUSED_PARAMETER") mapToInit: MutableMap) { // Init implicitly with AssociatedObjectsLowering - return null + // addAssociatedObject(mapToInit, ...) } \ No newline at end of file diff --git a/wasm/wasm.tests/test/org/jetbrains/kotlin/generators/tests/GenerateWasmTests.kt b/wasm/wasm.tests/test/org/jetbrains/kotlin/generators/tests/GenerateWasmTests.kt index 50fdb4cd5e8..073d50f5fa0 100644 --- a/wasm/wasm.tests/test/org/jetbrains/kotlin/generators/tests/GenerateWasmTests.kt +++ b/wasm/wasm.tests/test/org/jetbrains/kotlin/generators/tests/GenerateWasmTests.kt @@ -21,7 +21,7 @@ fun main(args: Array) { val k2BoxTestDir = "multiplatform/k2" val jsTranslatorTestPattern = "^([^_](.+))\\.kt$" - val jsTranslatorReflectionPattern = "^(findAssociatedObject(InSeparatedFile)?(Lazyness)?)\\.kt$" + val jsTranslatorReflectionPattern = "^(findAssociatedObject(InSeparatedFile)?)\\.kt$" val jsTranslatorEsModulesExcludedDirs = listOf( // JsExport is not supported for classes "jsExport", "native", "export", diff --git a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/FirWasmJsTranslatorTestGenerated.java b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/FirWasmJsTranslatorTestGenerated.java index 163fe44c708..d36789de241 100644 --- a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/FirWasmJsTranslatorTestGenerated.java +++ b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/FirWasmJsTranslatorTestGenerated.java @@ -514,7 +514,7 @@ public class FirWasmJsTranslatorTestGenerated extends AbstractFirWasmJsTranslato public class Reflection { @Test public void testAllFilesPresentInReflection() throws Exception { - KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/reflection"), Pattern.compile("^(findAssociatedObject(InSeparatedFile)?(Lazyness)?)\\.kt$"), null, TargetBackend.WASM, true); + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/reflection"), Pattern.compile("^(findAssociatedObject(InSeparatedFile)?)\\.kt$"), null, TargetBackend.WASM, true); } @Test @@ -528,12 +528,6 @@ public class FirWasmJsTranslatorTestGenerated extends AbstractFirWasmJsTranslato public void testFindAssociatedObjectInSeparatedFile() throws Exception { runTest("js/js.translator/testData/box/reflection/findAssociatedObjectInSeparatedFile.kt"); } - - @Test - @TestMetadata("findAssociatedObjectLazyness.kt") - public void testFindAssociatedObjectLazyness() throws Exception { - runTest("js/js.translator/testData/box/reflection/findAssociatedObjectLazyness.kt"); - } } @Nested diff --git a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/K1WasmJsTranslatorTestGenerated.java b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/K1WasmJsTranslatorTestGenerated.java index d7cd2711639..6d51b10f99a 100644 --- a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/K1WasmJsTranslatorTestGenerated.java +++ b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/K1WasmJsTranslatorTestGenerated.java @@ -514,7 +514,7 @@ public class K1WasmJsTranslatorTestGenerated extends AbstractK1WasmJsTranslatorT public class Reflection { @Test public void testAllFilesPresentInReflection() throws Exception { - KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/reflection"), Pattern.compile("^(findAssociatedObject(InSeparatedFile)?(Lazyness)?)\\.kt$"), null, TargetBackend.WASM, true); + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/reflection"), Pattern.compile("^(findAssociatedObject(InSeparatedFile)?)\\.kt$"), null, TargetBackend.WASM, true); } @Test @@ -528,12 +528,6 @@ public class K1WasmJsTranslatorTestGenerated extends AbstractK1WasmJsTranslatorT public void testFindAssociatedObjectInSeparatedFile() throws Exception { runTest("js/js.translator/testData/box/reflection/findAssociatedObjectInSeparatedFile.kt"); } - - @Test - @TestMetadata("findAssociatedObjectLazyness.kt") - public void testFindAssociatedObjectLazyness() throws Exception { - runTest("js/js.translator/testData/box/reflection/findAssociatedObjectLazyness.kt"); - } } @Nested