[Wasm] Support for Associated Objects feature

This commit is contained in:
Igor Yakovlev
2023-03-27 19:58:51 +02:00
committed by Space Team
parent 993334e5e4
commit b8f797af00
6 changed files with 214 additions and 1 deletions
@@ -0,0 +1,43 @@
/*
* 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 kotlin.reflect
import kotlin.wasm.internal.wasmClassId
import kotlin.wasm.internal.findAssociatedObject
/**
* The experimental marker for associated objects API.
*
* Any usage of a declaration annotated with `@ExperimentalAssociatedObjects` must be accepted either by
* annotating that usage with the [OptIn] annotation, e.g. `@OptIn(ExperimentalAssociatedObjects::class)`,
* or by using the compiler argument `-opt-in=kotlin.reflect.ExperimentalAssociatedObjects`.
*/
@RequiresOptIn(level = RequiresOptIn.Level.ERROR)
@Retention(value = AnnotationRetention.BINARY)
public annotation class ExperimentalAssociatedObjects
/**
* Makes the annotated annotation class an associated object key.
*
* An associated object key annotation should have single [KClass] parameter.
* When applied to a class with reference to an object declaration as an argument, it binds
* the object to the class, making this binding discoverable at runtime using [findAssociatedObject].
*/
@ExperimentalAssociatedObjects
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.ANNOTATION_CLASS)
public annotation class AssociatedObjectKey
/**
* If [T] is an @[AssociatedObjectKey]-annotated annotation class and [this] class is annotated with @[T] (`S::class`),
* returns object `S`.
*
* Otherwise returns `null`.
*/
@ExperimentalAssociatedObjects
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
public inline fun <reified T : Annotation> KClass<*>.findAssociatedObject(): Any? =
findAssociatedObject(this, wasmClassId<T>())
@@ -23,7 +23,7 @@ internal object ErrorKClass : KClass<Nothing> {
override fun isInstance(value: Any?): Boolean = error("Can's check isInstance on ErrorKClass")
}
internal class KClassImpl<T : Any>(private val typeData: TypeInfoData) : KClass<T> {
internal class KClassImpl<T : Any>(internal val typeData: TypeInfoData) : KClass<T> {
override val simpleName: String get() = typeData.typeName
override val qualifiedName: String =
if (typeData.packageName.isEmpty()) typeData.typeName else "${typeData.packageName}.${typeData.typeName}"
@@ -0,0 +1,42 @@
/*
* 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 kotlin.wasm.internal
import kotlin.reflect.wasm.internal.KClassImpl
import kotlin.reflect.KClass
internal var associatedObjects: Map<ULong, Any>? = null
@PublishedApi
internal fun findAssociatedObject(klass: KClass<*>, key: Int): Any? {
val klassId = (klass as? KClassImpl<*>)?.typeData?.typeId ?: return null
val map = associatedObjects ?: run {
val newMap: MutableMap<ULong, Any> = mutableMapOf()
initAssociatedObjects(newMap)
associatedObjects = newMap
newMap
}
return map[packIntoULong(klassId, key)]
}
internal fun packIntoULong(a: Int, b: Int): ULong =
(a.toUInt().toULong() shl Int.SIZE_BITS) or b.toUInt().toULong()
internal fun addAssociatedObject(
mapToInit: MutableMap<ULong, Any>,
klassId: Int,
keyId: Int,
instance: Any
) {
mapToInit[packIntoULong(klassId, keyId)] = instance
}
internal fun initAssociatedObjects(@Suppress("UNUSED_PARAMETER") mapToInit: MutableMap<ULong, Any>) {
// Init implicitly with AssociatedObjectsLowering
// addAssociatedObject(mapToInit, ...)
}