[Wasm] Improve class type checks

Use wasm ref.test instad of manual type info linked list traversal
This commit is contained in:
Svyatoslav Kuzmich
2020-12-13 23:38:33 +03:00
parent b6ad1584c9
commit 785c947782
4 changed files with 41 additions and 7 deletions
@@ -113,6 +113,7 @@ class WasmSymbols(
val booleanAnd = getInternalFunction("wasm_i32_and")
val refEq = getInternalFunction("wasm_ref_eq")
val refIsNull = getInternalFunction("wasm_ref_is_null")
val refTest = getInternalFunction("wasm_ref_test")
val intToLong = getInternalFunction("wasm_i64_extend_i32_s")
val wasmRefCast = getInternalFunction("wasm_ref_cast")
@@ -258,7 +258,7 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
call: IrFunctionAccessExpression,
function: IrFunction
): Boolean {
if (tryToGenerateWasmOpIntrinsicCall(function)) {
if (tryToGenerateWasmOpIntrinsicCall(call, function)) {
return true
}
@@ -489,7 +489,7 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
}
// Return true if function is recognized as intrinsic.
fun tryToGenerateWasmOpIntrinsicCall(function: IrFunction): Boolean {
fun tryToGenerateWasmOpIntrinsicCall(call: IrFunctionAccessExpression, function: IrFunction): Boolean {
if (function.hasWasmReinterpretAnnotation()) {
return true
}
@@ -513,6 +513,25 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
}
)
}
2 -> {
when (op) {
WasmOp.REF_TEST -> {
val fromIrType = call.getValueArgument(0)!!.type
val fromWasmType = context.transformBoxedType(fromIrType)
val toIrType = call.getTypeArgument(0)!!
val toWasmType = context.transformBoxedType(toIrType)
immediates = arrayOf(
WasmImmediate.HeapType(fromWasmType),
WasmImmediate.HeapType(toWasmType),
)
// ref.test takes RTT as a second operand
generateTypeRTT(toIrType)
}
else ->
error("Op $opString is unsupported")
}
}
else ->
error("Op $opString is unsupported")
}
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irNot
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
import org.jetbrains.kotlin.backend.wasm.ir2wasm.erasedUpperBound
import org.jetbrains.kotlin.ir.util.isPure
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
@@ -276,12 +275,25 @@ class WasmBaseTypeOperatorTransformer(val context: WasmBackendContext) : IrEleme
}
private fun generateIsSubClass(argument: IrExpression, toType: IrType): IrExpression {
val classId = builder.irCall(symbols.wasmClassId).apply {
putTypeArgument(0, toType)
val fromType = argument.type
val fromTypeErased = fromType.erasedType
val toTypeErased = toType.erasedType
if (fromTypeErased.isSubtypeOfClass(toTypeErased.classOrNull!!)) {
return builder.irComposite {
+argument
+builder.irTrue()
}
}
return builder.irCall(symbols.isSubClass).apply {
if (!toTypeErased.isSubtypeOfClass(fromTypeErased.classOrNull!!)) {
return builder.irComposite {
+argument
+builder.irFalse()
}
}
return builder.irCall(symbols.refTest).apply {
putValueArgument(0, argument)
putValueArgument(1, classId)
putTypeArgument(0, toType)
}
}
}
@@ -254,6 +254,8 @@ public external fun wasm_ref_is_null(a: Any?): Boolean
@WasmOp(WasmOp.REF_EQ)
public external fun wasm_ref_eq(a: Any?, b: Any?): Boolean
@WasmOp(WasmOp.REF_TEST)
public external fun <T> wasm_ref_test(a: Any?): Boolean
// ---