[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 booleanAnd = getInternalFunction("wasm_i32_and")
val refEq = getInternalFunction("wasm_ref_eq") val refEq = getInternalFunction("wasm_ref_eq")
val refIsNull = getInternalFunction("wasm_ref_is_null") val refIsNull = getInternalFunction("wasm_ref_is_null")
val refTest = getInternalFunction("wasm_ref_test")
val intToLong = getInternalFunction("wasm_i64_extend_i32_s") val intToLong = getInternalFunction("wasm_i64_extend_i32_s")
val wasmRefCast = getInternalFunction("wasm_ref_cast") val wasmRefCast = getInternalFunction("wasm_ref_cast")
@@ -258,7 +258,7 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
call: IrFunctionAccessExpression, call: IrFunctionAccessExpression,
function: IrFunction function: IrFunction
): Boolean { ): Boolean {
if (tryToGenerateWasmOpIntrinsicCall(function)) { if (tryToGenerateWasmOpIntrinsicCall(call, function)) {
return true return true
} }
@@ -489,7 +489,7 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
} }
// Return true if function is recognized as intrinsic. // Return true if function is recognized as intrinsic.
fun tryToGenerateWasmOpIntrinsicCall(function: IrFunction): Boolean { fun tryToGenerateWasmOpIntrinsicCall(call: IrFunctionAccessExpression, function: IrFunction): Boolean {
if (function.hasWasmReinterpretAnnotation()) { if (function.hasWasmReinterpretAnnotation()) {
return true 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 -> else ->
error("Op $opString is unsupported") 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.common.lower.irNot
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
import org.jetbrains.kotlin.backend.wasm.ir2wasm.erasedUpperBound 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.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter 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 { private fun generateIsSubClass(argument: IrExpression, toType: IrType): IrExpression {
val classId = builder.irCall(symbols.wasmClassId).apply { val fromType = argument.type
putTypeArgument(0, toType) 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(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) @WasmOp(WasmOp.REF_EQ)
public external fun wasm_ref_eq(a: Any?, b: Any?): Boolean 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
// --- // ---