From 785c947782659432adf373ebe2c1347bac528184 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kuzmich Date: Sun, 13 Dec 2020 23:38:33 +0300 Subject: [PATCH] [Wasm] Improve class type checks Use wasm ref.test instad of manual type info linked list traversal --- .../kotlin/backend/wasm/WasmSymbols.kt | 1 + .../backend/wasm/ir2wasm/BodyGenerator.kt | 23 +++++++++++++++++-- .../wasm/lower/WasmTypeOperatorLowering.kt | 22 ++++++++++++++---- .../kotlin/wasm/internal/WasmInstructions.kt | 2 ++ 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt index 7835c7ef9b4..ba08495ca97 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt @@ -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") diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt index 03fd2fbbb1c..99b520f3996 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt @@ -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") } diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmTypeOperatorLowering.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmTypeOperatorLowering.kt index d050028358f..715d25e3aea 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmTypeOperatorLowering.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmTypeOperatorLowering.kt @@ -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) } } } diff --git a/libraries/stdlib/wasm/internal/kotlin/wasm/internal/WasmInstructions.kt b/libraries/stdlib/wasm/internal/kotlin/wasm/internal/WasmInstructions.kt index f19537293c1..3d5a5a1102a 100644 --- a/libraries/stdlib/wasm/internal/kotlin/wasm/internal/WasmInstructions.kt +++ b/libraries/stdlib/wasm/internal/kotlin/wasm/internal/WasmInstructions.kt @@ -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 wasm_ref_test(a: Any?): Boolean // ---