[Wasm] Replace ClassId and InterfaceId with single TypeId
This commit is contained in:
committed by
Space Team
parent
5a46cb1c40
commit
49beec33b4
@@ -63,6 +63,7 @@ class WasmSymbols(
|
||||
override val primitiveClassesObject = getInternalClass("PrimitiveClasses")
|
||||
override val kTypeClass: IrClassSymbol = getIrClass(FqName("kotlin.reflect.KClass"))
|
||||
|
||||
val getTypeInfoTypeDataByPtr: IrSimpleFunctionSymbol = getInternalFunction("getTypeInfoTypeDataByPtr")
|
||||
val wasmTypeInfoData: IrClassSymbol = getInternalClass("TypeInfoData")
|
||||
}
|
||||
|
||||
@@ -208,8 +209,7 @@ class WasmSymbols(
|
||||
val suiteFun = maybeGetFunction("suite", kotlinTestPackage)
|
||||
val startUnitTests = maybeGetFunction("startUnitTests", kotlinTestPackage)
|
||||
|
||||
val wasmClassId = getInternalFunction("wasmClassId")
|
||||
val wasmInterfaceId = getInternalFunction("wasmInterfaceId")
|
||||
val wasmTypeId = getInternalFunction("wasmTypeId")
|
||||
|
||||
val wasmIsInterface = getInternalFunction("wasmIsInterface")
|
||||
|
||||
|
||||
+1
-2
@@ -56,8 +56,7 @@ internal class WasmUsefulDeclarationProcessor(
|
||||
true
|
||||
}
|
||||
|
||||
context.wasmSymbols.wasmClassId,
|
||||
context.wasmSymbols.wasmInterfaceId,
|
||||
context.wasmSymbols.wasmTypeId,
|
||||
context.wasmSymbols.refCastNull,
|
||||
context.wasmSymbols.refTest,
|
||||
context.wasmSymbols.boxIntrinsic,
|
||||
|
||||
+5
-13
@@ -317,7 +317,7 @@ class BodyGenerator(
|
||||
body.buildRefNull(WasmHeapType.Simple.Data, location)
|
||||
}
|
||||
|
||||
body.buildConstI32Symbol(context.referenceClassId(klassSymbol), location)
|
||||
body.buildConstI32Symbol(context.referenceTypeId(klassSymbol), location)
|
||||
body.buildConstI32(0, location) // Any::_hashCode
|
||||
body.commentGroupEnd()
|
||||
}
|
||||
@@ -519,23 +519,15 @@ class BodyGenerator(
|
||||
val location = call.getSourceLocation()
|
||||
|
||||
when (function.symbol) {
|
||||
wasmSymbols.wasmClassId -> {
|
||||
wasmSymbols.wasmTypeId -> {
|
||||
val klass = call.getTypeArgument(0)!!.getClass()
|
||||
?: error("No class given for wasmClassId intrinsic")
|
||||
assert(!klass.isInterface)
|
||||
body.buildConstI32Symbol(context.referenceClassId(klass.symbol), location)
|
||||
}
|
||||
|
||||
wasmSymbols.wasmInterfaceId -> {
|
||||
val irInterface = call.getTypeArgument(0)!!.getClass()
|
||||
?: error("No interface given for wasmInterfaceId intrinsic")
|
||||
assert(irInterface.isInterface)
|
||||
body.buildConstI32Symbol(context.referenceInterfaceId(irInterface.symbol), location)
|
||||
?: error("No class given for wasmTypeId intrinsic")
|
||||
body.buildConstI32Symbol(context.referenceTypeId(klass.symbol), location)
|
||||
}
|
||||
|
||||
wasmSymbols.wasmIsInterface -> {
|
||||
val irInterface = call.getTypeArgument(0)!!.getClass()
|
||||
?: error("No interface given for wasmInterfaceId intrinsic")
|
||||
?: error("No interface given for wasmIsInterface intrinsic")
|
||||
assert(irInterface.isInterface)
|
||||
if (irInterface.symbol in hierarchyDisjointUnions) {
|
||||
val classITable = context.referenceClassITableGcType(irInterface.symbol)
|
||||
|
||||
+2
-2
@@ -416,7 +416,7 @@ class DeclarationGenerator(
|
||||
|
||||
val superClass = classMetadata.klass.getSuperClass(context.backendContext.irBuiltIns)
|
||||
val superTypeId = superClass?.let {
|
||||
ConstantDataIntField("SuperTypeId", context.referenceClassId(it.symbol))
|
||||
ConstantDataIntField("SuperTypeId", context.referenceTypeId(it.symbol))
|
||||
} ?: ConstantDataIntField("SuperTypeId", -1)
|
||||
|
||||
val typeInfoContent = mutableListOf(typeInfo, superTypeId)
|
||||
@@ -435,7 +435,7 @@ class DeclarationGenerator(
|
||||
val size = ConstantDataIntField("size", interfaces.size)
|
||||
val interfaceIds = ConstantDataIntArray(
|
||||
"interfaceIds",
|
||||
interfaces.map { context.referenceInterfaceId(it.symbol) },
|
||||
interfaces.map { context.referenceTypeId(it.symbol) },
|
||||
)
|
||||
|
||||
return ConstantDataStruct(
|
||||
|
||||
+27
-26
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.util.getPackageFragment
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
import org.jetbrains.kotlin.wasm.ir.*
|
||||
import org.jetbrains.kotlin.wasm.ir.source.location.SourceLocation
|
||||
|
||||
@@ -33,9 +34,7 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
||||
ReferencableAndDefinable<IrClassSymbol, WasmTypeDeclaration>()
|
||||
val classITableInterfaceSlot =
|
||||
ReferencableAndDefinable<IrClassSymbol, Int>()
|
||||
val classIds =
|
||||
ReferencableElements<IrClassSymbol, Int>()
|
||||
val interfaceId =
|
||||
val typeIds =
|
||||
ReferencableElements<IrClassSymbol, Int>()
|
||||
val stringLiteralAddress =
|
||||
ReferencableElements<String, Int>()
|
||||
@@ -119,20 +118,20 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
||||
wasmSymbol.bind(canonicalFunctionTypes.getValue(functionTypes.defined.getValue(irSymbol)))
|
||||
}
|
||||
|
||||
val klassIds = mutableMapOf<IrClassSymbol, Int>()
|
||||
var currentDataSectionAddress = 0
|
||||
for (typeInfoElement in typeInfo.elements) {
|
||||
val ir = typeInfo.wasmToIr.getValue(typeInfoElement)
|
||||
klassIds[ir] = currentDataSectionAddress
|
||||
currentDataSectionAddress += typeInfoElement.sizeInBytes
|
||||
var interfaceId = 0
|
||||
typeIds.unbound.forEach { (klassSymbol, wasmSymbol) ->
|
||||
if (klassSymbol.owner.isInterface) {
|
||||
interfaceId--
|
||||
wasmSymbol.bind(interfaceId)
|
||||
} else {
|
||||
wasmSymbol.bind(currentDataSectionAddress)
|
||||
currentDataSectionAddress += typeInfo.defined.getValue(klassSymbol).sizeInBytes
|
||||
}
|
||||
}
|
||||
|
||||
currentDataSectionAddress = alignUp(currentDataSectionAddress, INT_SIZE_BYTES)
|
||||
scratchMemAddr.bind(currentDataSectionAddress)
|
||||
|
||||
bind(classIds.unbound, klassIds)
|
||||
interfaceId.unbound.onEachIndexed { index, entry -> entry.value.bind(index) }
|
||||
|
||||
val stringDataSectionBytes = mutableListOf<Byte>()
|
||||
var stringDataSectionStart = 0
|
||||
var stringLiteralCount = 0
|
||||
@@ -160,9 +159,23 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
||||
val constData = ConstantDataIntegerArray("constant_array", constantArraySegment.first, integerSize)
|
||||
data.add(WasmData(WasmDataMode.Passive, constData.toBytes()))
|
||||
}
|
||||
typeInfo.buildData(data, address = { klassIds.getValue(it) })
|
||||
|
||||
val masterInitFunctionType = WasmFunctionType(emptyList(), emptyList())
|
||||
typeIds.unbound.forEach { (klassSymbol, typeId) ->
|
||||
if (!klassSymbol.owner.isInterface) {
|
||||
val instructions = mutableListOf<WasmInstr>()
|
||||
WasmIrExpressionBuilder(instructions).buildConstI32(
|
||||
typeId.owner,
|
||||
SourceLocation.NoLocation("Compile time data per class")
|
||||
)
|
||||
val typeData = WasmData(
|
||||
WasmDataMode.Active(0, instructions),
|
||||
typeInfo.defined.getValue(klassSymbol).toBytes()
|
||||
)
|
||||
data.add(typeData)
|
||||
}
|
||||
}
|
||||
|
||||
val masterInitFunctionType = WasmFunctionType(emptyList(), emptyList())
|
||||
val masterInitFunction = WasmFunction.Defined("__init", WasmSymbol(masterInitFunctionType))
|
||||
with(WasmIrExpressionBuilder(masterInitFunction.instructions)) {
|
||||
initFunctions.sortedBy { it.priority }.forEach {
|
||||
@@ -250,18 +263,6 @@ private fun irSymbolDebugDump(symbol: Any?): String =
|
||||
else -> symbol.toString()
|
||||
}
|
||||
|
||||
inline fun WasmCompiledModuleFragment.ReferencableAndDefinable<IrClassSymbol, ConstantDataElement>.buildData(
|
||||
into: MutableList<WasmData>,
|
||||
address: (IrClassSymbol) -> Int
|
||||
) {
|
||||
elements.mapTo(into) {
|
||||
val id = address(wasmToIr.getValue(it))
|
||||
val offset = mutableListOf<WasmInstr>()
|
||||
WasmIrExpressionBuilder(offset).buildConstI32(id, SourceLocation.NoLocation("Compile time data per class"))
|
||||
WasmData(WasmDataMode.Active(0, offset), it.toBytes())
|
||||
}
|
||||
}
|
||||
|
||||
fun alignUp(x: Int, alignment: Int): Int {
|
||||
assert(alignment and (alignment - 1) == 0) { "power of 2 expected" }
|
||||
return (x + alignment - 1) and (alignment - 1).inv()
|
||||
|
||||
+2
-6
@@ -177,12 +177,8 @@ class WasmModuleCodegenContext(
|
||||
fun referenceFunctionType(irFunction: IrFunctionSymbol): WasmSymbol<WasmFunctionType> =
|
||||
wasmFragment.functionTypes.reference(irFunction)
|
||||
|
||||
fun referenceClassId(irClass: IrClassSymbol): WasmSymbol<Int> =
|
||||
wasmFragment.classIds.reference(irClass)
|
||||
|
||||
fun referenceInterfaceId(irInterface: IrClassSymbol): WasmSymbol<Int> {
|
||||
return wasmFragment.interfaceId.reference(irInterface)
|
||||
}
|
||||
fun referenceTypeId(irClass: IrClassSymbol): WasmSymbol<Int> =
|
||||
wasmFragment.typeIds.reference(irClass)
|
||||
|
||||
fun getStructFieldRef(field: IrField): WasmSymbol<Int> {
|
||||
val klass = field.parentAsClass
|
||||
|
||||
+2
-6
@@ -90,19 +90,15 @@ private fun IrBuilderWithScope.createAssociatedObjectAdd(
|
||||
0,
|
||||
irGet(wasmSymbols.initAssociatedObjects.owner.valueParameters[0])
|
||||
)
|
||||
val classIdGetter = when (targetClass.owner.isInterface) {
|
||||
true -> wasmSymbols.wasmInterfaceId
|
||||
false -> wasmSymbols.wasmClassId
|
||||
}
|
||||
addCall.putValueArgument(
|
||||
1,
|
||||
irCall(classIdGetter, irBuiltIns.intType).also {
|
||||
irCall(wasmSymbols.wasmTypeId, irBuiltIns.intType).also {
|
||||
it.putTypeArgument(0, targetClass.defaultType)
|
||||
}
|
||||
)
|
||||
addCall.putValueArgument(
|
||||
2,
|
||||
irCall(wasmSymbols.wasmClassId, irBuiltIns.intType).also {
|
||||
irCall(wasmSymbols.wasmTypeId, irBuiltIns.intType).also {
|
||||
it.putTypeArgument(0, keyAnnotation.defaultType)
|
||||
}
|
||||
)
|
||||
|
||||
+21
-16
@@ -150,26 +150,31 @@ class BuiltInsLowering(val context: WasmBackendContext) : FileLoweringPass {
|
||||
return irCall(call, newSymbol, argumentsAsReceivers = true)
|
||||
}
|
||||
symbols.reflectionSymbols.getClassData -> {
|
||||
val infoDataCtor = symbols.reflectionSymbols.wasmTypeInfoData.constructors.first()
|
||||
val type = call.getTypeArgument(0)!!
|
||||
val isInterface = type.isInterface()
|
||||
val fqName = type.classFqName!!
|
||||
val fqnShouldBeEmitted =
|
||||
context.configuration.languageVersionSettings.getFlag(AnalysisFlags.allowFullyQualifiedNameInKClass)
|
||||
val packageName = if (fqnShouldBeEmitted) fqName.parentOrNull()?.asString() ?: "" else ""
|
||||
val typeName = fqName.shortName().asString()
|
||||
val klass = type.classOrNull?.owner ?: error("Invalid type")
|
||||
|
||||
return with(builder) {
|
||||
val wasmIdGetter = if (type.isInterface()) symbols.wasmInterfaceId else symbols.wasmClassId
|
||||
val typeId = irCall(wasmIdGetter).also {
|
||||
it.putTypeArgument(0, type)
|
||||
}
|
||||
val typeId = builder.irCall(symbols.wasmTypeId).also {
|
||||
it.putTypeArgument(0, type)
|
||||
}
|
||||
|
||||
irCallConstructor(infoDataCtor, emptyList()).also {
|
||||
if (!klass.isInterface) {
|
||||
return builder.irCall(context.wasmSymbols.reflectionSymbols.getTypeInfoTypeDataByPtr).also {
|
||||
it.putValueArgument(0, typeId)
|
||||
it.putValueArgument(1, isInterface.toIrConst(context.irBuiltIns.booleanType))
|
||||
it.putValueArgument(2, packageName.toIrConst(context.irBuiltIns.stringType))
|
||||
it.putValueArgument(3, typeName.toIrConst(context.irBuiltIns.stringType))
|
||||
}
|
||||
} else {
|
||||
val infoDataCtor = symbols.reflectionSymbols.wasmTypeInfoData.constructors.first()
|
||||
val fqName = type.classFqName!!
|
||||
val fqnShouldBeEmitted =
|
||||
context.configuration.languageVersionSettings.getFlag(AnalysisFlags.allowFullyQualifiedNameInKClass)
|
||||
val packageName = if (fqnShouldBeEmitted) fqName.parentOrNull()?.asString() ?: "" else ""
|
||||
val typeName = fqName.shortName().asString()
|
||||
|
||||
return with(builder) {
|
||||
irCallConstructor(infoDataCtor, emptyList()).also {
|
||||
it.putValueArgument(0, typeId)
|
||||
it.putValueArgument(1, packageName.toIrConst(context.irBuiltIns.stringType))
|
||||
it.putValueArgument(2, typeName.toIrConst(context.irBuiltIns.stringType))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,10 @@ internal const val TYPE_INFO_SUPER_TYPE_OFFSET = TYPE_INFO_TYPE_SIMPLE_NAME_PRT_
|
||||
internal const val TYPE_INFO_ITABLE_SIZE_OFFSET = TYPE_INFO_SUPER_TYPE_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
||||
internal const val TYPE_INFO_ITABLE_OFFSET = TYPE_INFO_ITABLE_SIZE_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
||||
|
||||
internal class TypeInfoData(val typeId: Int, val isInterface: Boolean, val packageName: String, val typeName: String)
|
||||
internal class TypeInfoData(val typeId: Int, val packageName: String, val typeName: String)
|
||||
|
||||
internal val TypeInfoData.isInterfaceType
|
||||
get() = typeId < 0
|
||||
|
||||
internal fun getTypeInfoTypeDataByPtr(typeInfoPtr: Int): TypeInfoData {
|
||||
val fqNameLength = wasm_i32_load(typeInfoPtr + TYPE_INFO_TYPE_PACKAGE_NAME_LENGTH_OFFSET)
|
||||
@@ -30,7 +33,7 @@ internal fun getTypeInfoTypeDataByPtr(typeInfoPtr: Int): TypeInfoData {
|
||||
val simpleNamePtr = wasm_i32_load(typeInfoPtr + TYPE_INFO_TYPE_SIMPLE_NAME_PRT_OFFSET)
|
||||
val packageName = stringLiteral(fqNameId, fqNamePtr, fqNameLength)
|
||||
val simpleName = stringLiteral(simpleNameId, simpleNamePtr, simpleNameLength)
|
||||
return TypeInfoData(typeInfoPtr, isInterface = false, packageName, simpleName)
|
||||
return TypeInfoData(typeInfoPtr, packageName, simpleName)
|
||||
}
|
||||
|
||||
internal fun getSuperTypeId(typeInfoPtr: Int): Int =
|
||||
@@ -57,11 +60,7 @@ internal fun <T> wasmIsInterface(obj: Any): Boolean =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@ExcludedFromCodegen
|
||||
internal fun <T> wasmClassId(): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@ExcludedFromCodegen
|
||||
internal fun <T> wasmInterfaceId(): Int =
|
||||
internal fun <T> wasmTypeId(): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@ExcludedFromCodegen
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
package kotlin.reflect
|
||||
|
||||
import kotlin.wasm.internal.wasmClassId
|
||||
import kotlin.wasm.internal.wasmTypeId
|
||||
import kotlin.wasm.internal.findAssociatedObject
|
||||
|
||||
/**
|
||||
@@ -40,4 +40,4 @@ public annotation class AssociatedObjectKey
|
||||
@ExperimentalAssociatedObjects
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
public inline fun <reified T : Annotation> KClass<*>.findAssociatedObject(): Any? =
|
||||
findAssociatedObject(this, wasmClassId<T>())
|
||||
findAssociatedObject(this, wasmTypeId<T>())
|
||||
@@ -8,6 +8,7 @@ import kotlin.reflect.*
|
||||
import kotlin.wasm.internal.TypeInfoData
|
||||
import kotlin.wasm.internal.getSuperTypeId
|
||||
import kotlin.wasm.internal.isInterfaceById
|
||||
import kotlin.wasm.internal.isInterfaceType
|
||||
|
||||
internal object NothingKClassImpl : KClass<Nothing> {
|
||||
override val simpleName: String = "Nothing"
|
||||
@@ -37,12 +38,16 @@ internal class KClassImpl<T : Any>(internal val typeData: TypeInfoData) : KClass
|
||||
return false
|
||||
}
|
||||
|
||||
override fun isInstance(value: Any?): Boolean = value?.let {
|
||||
if (typeData.isInterface) isInterfaceById(it, typeData.typeId) else checkSuperTypeInstance(it)
|
||||
} ?: false
|
||||
override fun isInstance(value: Any?): Boolean {
|
||||
if (value !is Any) return false
|
||||
return when (typeData.isInterfaceType) {
|
||||
true -> isInterfaceById(value, typeData.typeId)
|
||||
false -> checkSuperTypeInstance(value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
(this === other) || (other is KClassImpl<*> && other.typeData.isInterface == typeData.isInterface && other.typeData.typeId == typeData.typeId)
|
||||
(this === other) || (other is KClassImpl<*> && other.typeData.typeId == typeData.typeId)
|
||||
|
||||
override fun hashCode(): Int = typeData.typeId
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ fun main(args: Array<String>) {
|
||||
)
|
||||
)
|
||||
model("box/jsQualifier/", pattern = jsTranslatorTestPattern, targetBackend = TargetBackend.WASM)
|
||||
model("box/reflection/", pattern = "^(findAssociatedObject(InSeparatedFile)?)\\.kt$", targetBackend = TargetBackend.WASM)
|
||||
}
|
||||
|
||||
testClass<AbstractJsTranslatorUnitWasmTest> {
|
||||
|
||||
Generated
+23
@@ -363,4 +363,27 @@ public class JsTranslatorWasmTestGenerated extends AbstractJsTranslatorWasmTest
|
||||
runTest("js/js.translator/testData/box/jsQualifier/simple.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("js/js.translator/testData/box/reflection")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Reflection extends AbstractJsTranslatorWasmTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInReflection() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/reflection"), Pattern.compile("^(findAssociatedObject(InSeparatedFile)?)\\.kt$"), null, TargetBackend.WASM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("findAssociatedObject.kt")
|
||||
public void testFindAssociatedObject() throws Exception {
|
||||
runTest("js/js.translator/testData/box/reflection/findAssociatedObject.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("findAssociatedObjectInSeparatedFile.kt")
|
||||
public void testFindAssociatedObjectInSeparatedFile() throws Exception {
|
||||
runTest("js/js.translator/testData/box/reflection/findAssociatedObjectInSeparatedFile.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user