[WasmJs] Add support for external class reflection

Fix #KT-64890
This commit is contained in:
Igor Yakovlev
2024-01-26 21:16:29 +01:00
parent e302420197
commit 6930fc8fed
24 changed files with 330 additions and 81 deletions
@@ -78,6 +78,7 @@ internal fun <T> wasmIsInterface(obj: Any): Boolean =
internal fun <T> wasmTypeId(): Int =
implementedAsIntrinsic
//TODO("Remove after bootstrap KT-65322")
@ExcludedFromCodegen
internal fun <T> wasmGetTypeInfoData(): TypeInfoData =
implementedAsIntrinsic
implementedAsIntrinsic
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2024 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.*
@Suppress("UNUSED_PARAMETER")
private fun getJsClassName(jsKlass: JsAny): String? =
js("jsKlass.name")
@Suppress("UNUSED_PARAMETER")
private fun instanceOf(ref: JsAny, jsKlass: JsAny): Boolean =
js("ref instanceof jsKlass")
internal class KExternalClassImpl<T : Any> @WasmPrimitiveConstructor constructor(private val jsConstructor: JsAny) : KClass<T> {
override val simpleName: String? get() = getJsClassName(jsConstructor)
override val qualifiedName: String? get() = null
override fun isInstance(value: Any?): Boolean =
value is JsExternalBox && instanceOf(value.ref, jsConstructor)
override fun equals(other: Any?): Boolean =
other is KExternalClassImpl<*> && jsConstructor == other.jsConstructor
override fun hashCode(): Int = simpleName.hashCode()
override fun toString(): String = "class $simpleName"
}
@@ -0,0 +1,19 @@
/*
* Copyright 2010-2024 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.*
@Suppress("UNUSED_PARAMETER")
private fun getConstructor(obj: JsAny): JsAny? =
js("obj.constructor")
@Suppress("UNCHECKED_CAST")
internal actual fun <T : Any> getKClassForObject(obj: Any): KClass<T> {
if (obj !is JsExternalBox) return KClassImpl(getTypeInfoTypeDataByPtr(obj.typeInfo))
val jsConstructor = getConstructor(obj.ref) ?: error("JavaScript constructor is not defined")
return KExternalClassImpl(jsConstructor)
}
@@ -2,13 +2,9 @@
* Copyright 2010-2021 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.wasm.internal
package kotlin.wasm.internal
import kotlin.reflect.*
import kotlin.wasm.internal.TypeInfoData
import kotlin.wasm.internal.getSuperTypeId
import kotlin.wasm.internal.isInterfaceById
import kotlin.wasm.internal.isInterfaceType
import kotlin.reflect.KClass
internal object NothingKClassImpl : KClass<Nothing> {
override val simpleName: String = "Nothing"
@@ -30,10 +26,10 @@ internal object ErrorKClass : KClass<Nothing> {
override fun hashCode(): Int = super.hashCode() // KT-24971
}
internal class KClassImpl<T : Any>(internal val typeData: TypeInfoData) : KClass<T> {
internal class KClassImpl<T : Any> @WasmPrimitiveConstructor constructor(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}"
override val qualifiedName: String
get() = if (typeData.packageName.isEmpty()) typeData.typeName else "${typeData.packageName}.${typeData.typeName}"
private fun checkSuperTypeInstance(obj: Any): Boolean {
var typeId = obj.typeInfo
@@ -5,7 +5,6 @@
package kotlin.wasm.internal
import kotlin.reflect.wasm.internal.KClassImpl
import kotlin.reflect.KClass
@PublishedApi
@@ -7,7 +7,6 @@ package kotlin.wasm.internal
import kotlin.reflect.KClass
import kotlin.reflect.KFunction
import kotlin.reflect.wasm.internal.*
internal object PrimitiveClasses {
@@ -3,12 +3,16 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
// a package is omitted to get declarations directly under the module
package kotlin.wasm.internal
import kotlin.reflect.*
import kotlin.reflect.wasm.internal.*
internal expect fun <T : Any> getKClassForObject(obj: Any): KClass<T>
//TODO(Replace getKClass to intrinsic argument-less implementation after bootstrap KT-65322")
//@ExcludedFromCodegen
//internal fun <T : Any> getKClass(): KClass<T> =
// implementedAsIntrinsic
internal fun <T : Any> getKClass(typeInfoData: TypeInfoData): KClass<T> =
KClassImpl(typeInfoData)
@@ -34,12 +38,12 @@ internal fun <T : Any> getKClassFromExpression(e: T): KClass<T> =
is DoubleArray -> PrimitiveClasses.doubleArrayClass
is KClass<*> -> KClass::class
is Array<*> -> PrimitiveClasses.arrayClass
else -> getKClass(getTypeInfoTypeDataByPtr(e.typeInfo))
else -> getKClassForObject(e)
} as KClass<T>
@Suppress("REIFIED_TYPE_PARAMETER_NO_INLINE")
internal inline fun <reified T : Any> wasmGetKClass(): KClass<T> =
KClassImpl(wasmGetTypeInfoData<T>())
KClassImpl(getTypeInfoTypeDataByPtr(wasmTypeId<T>()))
internal fun createKType(classifier: KClassifier, arguments: Array<KTypeProjection>, isMarkedNullable: Boolean): KType =
KTypeImpl(classifier, arguments.asList(), isMarkedNullable)
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2024 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.
*/
// a package is omitted to get declarations directly under the module
package kotlin.wasm.internal
import kotlin.reflect.*
internal actual fun <T : Any> getKClassForObject(obj: Any): KClass<T> =
KClassImpl(getTypeInfoTypeDataByPtr(obj.typeInfo))