[Wasm] Improve class type checks
Use wasm ref.test instad of manual type info linked list traversal
This commit is contained in:
@@ -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")
|
||||
|
||||
+21
-2
@@ -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")
|
||||
}
|
||||
|
||||
+17
-5
@@ -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
|
||||
|
||||
// ---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user