[Wasm] Replace ClassId and InterfaceId with single TypeId

This commit is contained in:
Igor Yakovlev
2023-03-30 20:27:47 +02:00
committed by Space Team
parent 5a46cb1c40
commit 49beec33b4
13 changed files with 103 additions and 86 deletions
@@ -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")
@@ -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,
@@ -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)
@@ -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(
@@ -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()
@@ -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
@@ -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)
}
)
@@ -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))
}
}
}
}