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 d5677bb1575..9609cfe8c7e 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 @@ -189,8 +189,8 @@ class WasmSymbols( val refEq = getInternalFunction("wasm_ref_eq") val refIsNull = getInternalFunction("wasm_ref_is_null") val externRefIsNull = getInternalFunction("wasm_externref_is_null") - val refTest = getInternalFunction("wasm_ref_test_deprecated") - val refCastNull = getInternalFunction("wasm_ref_cast_deprecated") + val refTest = getInternalFunction("wasm_ref_test") + val refCastNull = getInternalFunction("wasm_ref_cast_null") val wasmArrayCopy = getInternalFunction("wasm_array_copy") val wasmArrayNewData0 = getInternalFunction("array_new_data0") 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 ffe8881ffd3..90444f18cf7 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 @@ -435,7 +435,7 @@ class BodyGenerator( body.commentGroupStart { "virtual call: ${function.fqNameWhenAvailable}" } //TODO: check why it could be needed - generateRefNullCast(receiver.type, klass.defaultType, location) + generateRefCast(receiver.type, klass.defaultType, location) body.buildStructGet(context.referenceGcType(klass.symbol), WasmSymbol(0), location) body.buildStructGet(context.referenceVTableGcType(klass.symbol), WasmSymbol(vfSlot), location) @@ -450,7 +450,7 @@ class BodyGenerator( body.buildStructGet(context.referenceGcType(irBuiltIns.anyClass), WasmSymbol(1), location) val classITableReference = context.referenceClassITableGcType(symbol) - body.buildRefCastNullStatic(classITableReference, location) + body.buildRefCastStatic(classITableReference, location) body.buildStructGet(classITableReference, context.referenceClassITableInterfaceSlot(symbol), location) val vfSlot = context.getInterfaceMetadata(symbol).methods @@ -486,6 +486,15 @@ class BodyGenerator( } } + private fun generateRefCast(fromType: IrType, toType: IrType, location: SourceLocation) { + if (!isDownCastAlwaysSuccessInRuntime(fromType, toType)) { + body.buildRefCastStatic( + toType = context.referenceGcType(toType.getRuntimeClass(irBuiltIns).symbol), + location + ) + } + } + private fun generateRefTest(fromType: IrType, toType: IrType, location: SourceLocation) { if (!isDownCastAlwaysSuccessInRuntime(fromType, toType)) { body.buildRefTestStatic( @@ -537,7 +546,14 @@ class BodyGenerator( body.buildBlock("isInterface", WasmRefNullType(WasmHeapType.Simple.Data)) { innerLabel -> body.buildGetLocal(parameterLocal, location) body.buildStructGet(context.referenceGcType(irBuiltIns.anyClass), WasmSymbol(1), location) - body.buildBrInstr(WasmOp.BR_ON_CAST_FAIL_DEPRECATED, innerLabel, classITable, location) + + body.buildBrInstr( + WasmOp.BR_ON_CAST_FAIL, + innerLabel, + classITable, + location, + ) + body.buildStructGet(classITable, context.referenceClassITableInterfaceSlot(irInterface.symbol), location) body.buildInstr(WasmOp.REF_IS_NULL, location) body.buildInstr(WasmOp.I32_EQZ, location) @@ -581,7 +597,7 @@ class BodyGenerator( val klass: IrClass = backendContext.inlineClassesUtils.getInlinedClass(toType)!! val field = getInlineClassBackingField(klass) - generateRefNullCast(fromType, toType, location) + generateRefCast(fromType, toType, location) generateInstanceFieldAccess(field, location) } @@ -593,15 +609,17 @@ class BodyGenerator( body.buildBlock("returnIfAny", WasmAnyRef) { innerLabel -> body.buildGetLocal(functionContext.referenceLocal(0), location) body.buildInstr(WasmOp.EXTERN_INTERNALIZE, location) - body.buildBrInstr(WasmOp.BR_ON_NON_DATA_DEPRECATED, innerLabel, location) + body.buildBrInstr( - WasmOp.BR_ON_CAST_FAIL_DEPRECATED, + WasmOp.BR_ON_CAST_FAIL, innerLabel, context.referenceGcType(backendContext.irBuiltIns.anyClass), - location + location, ) + body.buildInstr(WasmOp.RETURN, location) } + body.buildDrop(location) } wasmSymbols.wasmArrayCopy -> { @@ -770,7 +788,7 @@ class BodyGenerator( // REF -> REF -> REF_CAST if (!expectedIsPrimitive) { if (expectedClassErased.isSubclassOf(actualClassErased)) { - generateRefNullCast(actualTypeErased, expectedTypeErased, location) + generateRefCast(actualTypeErased, expectedTypeErased, location) } else { body.buildUnreachableForVerifier() } diff --git a/libraries/stdlib/wasm/internal/kotlin/wasm/internal/ExternalWrapper.kt b/libraries/stdlib/wasm/internal/kotlin/wasm/internal/ExternalWrapper.kt index b8be92c7538..ebcf85c0692 100644 --- a/libraries/stdlib/wasm/internal/kotlin/wasm/internal/ExternalWrapper.kt +++ b/libraries/stdlib/wasm/internal/kotlin/wasm/internal/ExternalWrapper.kt @@ -159,7 +159,7 @@ internal fun isNullish(ref: ExternalInterfaceType?): Boolean = * } * ``` */ -internal fun returnArgumentIfItIsKotlinAny(ref: ExternalInterfaceType): Unit = implementedAsIntrinsic +internal fun returnArgumentIfItIsKotlinAny(): Unit = implementedAsIntrinsic internal fun externRefToAny(ref: ExternalInterfaceType): Any? { // TODO rewrite it so to get something like: @@ -169,7 +169,7 @@ internal fun externRefToAny(ref: ExternalInterfaceType): Any? { // return // } // If ref is an instance of kotlin class -- return it casted to Any - returnArgumentIfItIsKotlinAny(ref) + returnArgumentIfItIsKotlinAny() // If we have Null in notNullRef -- return null // If we already have a box -- return it, diff --git a/libraries/stdlib/wasm/internal/kotlin/wasm/internal/WasmInstructions.kt b/libraries/stdlib/wasm/internal/kotlin/wasm/internal/WasmInstructions.kt index a7d68896543..7f097b84ee9 100644 --- a/libraries/stdlib/wasm/internal/kotlin/wasm/internal/WasmInstructions.kt +++ b/libraries/stdlib/wasm/internal/kotlin/wasm/internal/WasmInstructions.kt @@ -20,11 +20,16 @@ internal fun wasm_unreachable(): Nothing = implementedAsIntrinsic @Suppress("REIFIED_TYPE_PARAMETER_NO_INLINE") -internal fun wasm_ref_cast_deprecated(a: Any?): To = +internal fun wasm_ref_cast_null(a: Any?): To = implementedAsIntrinsic @Suppress("REIFIED_TYPE_PARAMETER_NO_INLINE") -internal fun wasm_ref_test_deprecated(a: Any?): Boolean = +internal fun wasm_ref_test(a: Any?): Boolean = + implementedAsIntrinsic + +@Suppress("REIFIED_TYPE_PARAMETER_NO_INLINE") +@WasmOp(WasmOp.REF_TEST_NULL) +internal fun wasm_ref_test_null(a: Any?): Boolean = implementedAsIntrinsic internal fun wasm_array_copy(destination: T, destinationIndex: Int, source: T, sourceIndex: Int, length: Int): Unit = diff --git a/libraries/stdlib/wasm/src/generated/wasm/internal/_WasmOp.kt b/libraries/stdlib/wasm/src/generated/wasm/internal/_WasmOp.kt index f0fe98b932e..766593ade86 100644 --- a/libraries/stdlib/wasm/src/generated/wasm/internal/_WasmOp.kt +++ b/libraries/stdlib/wasm/src/generated/wasm/internal/_WasmOp.kt @@ -247,12 +247,14 @@ internal annotation class WasmOp(val name: String) { const val I31_GET_S = "I31_GET_S" const val I31_GET_U = "I31_GET_U" const val REF_EQ = "REF_EQ" + const val REF_TEST = "REF_TEST" + const val REF_TEST_NULL = "REF_TEST_NULL" + const val REF_CAST = "REF_CAST" + const val REF_CAST_NULL = "REF_CAST_NULL" + const val BR_ON_CAST = "BR_ON_CAST" + const val BR_ON_CAST_FAIL = "BR_ON_CAST_FAIL" const val EXTERN_INTERNALIZE = "EXTERN_INTERNALIZE" const val EXTERN_EXTERNALIZE = "EXTERN_EXTERNALIZE" - const val REF_TEST_DEPRECATED = "REF_TEST_DEPRECATED" - const val REF_CAST_DEPRECATED = "REF_CAST_DEPRECATED" - const val BR_ON_CAST_FAIL_DEPRECATED = "BR_ON_CAST_FAIL_DEPRECATED" - const val BR_ON_NON_DATA_DEPRECATED = "BR_ON_NON_DATA_DEPRECATED" const val GET_UNIT = "GET_UNIT" const val PSEUDO_COMMENT_PREVIOUS_INSTR = "PSEUDO_COMMENT_PREVIOUS_INSTR" const val PSEUDO_COMMENT_GROUP_START = "PSEUDO_COMMENT_GROUP_START" diff --git a/libraries/stdlib/wasm/src/kotlin/js/JsReference.kt b/libraries/stdlib/wasm/src/kotlin/js/JsReference.kt index a53138ba6c2..0745da258d5 100644 --- a/libraries/stdlib/wasm/src/kotlin/js/JsReference.kt +++ b/libraries/stdlib/wasm/src/kotlin/js/JsReference.kt @@ -24,6 +24,6 @@ public fun T.toJsReference(): JsReference = /** Retrieve original Kotlin value from JsReference */ public fun JsReference.get(): T { - returnArgumentIfItIsKotlinAny(this) + returnArgumentIfItIsKotlinAny() throw ClassCastException("JsReference doesn't contain a Kotlin type") } \ No newline at end of file diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Operators.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Operators.kt index 720f1136412..d27413574fa 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Operators.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Operators.kt @@ -374,32 +374,17 @@ enum class WasmOp( I31_GET_U("i31.get_u", 0xFB_22), REF_EQ("ref.eq", 0xD5), -// Not yet supported by Binaryen -// REF_TEST("ref.test", 0xFB_40, HEAP_TYPE), -// REF_TEST_NULL("ref.test null", 0xFB_48, HEAP_TYPE), -// REF_CAST("ref.cast", 0xFB_41, HEAP_TYPE), -// REF_CAST_NULL("ref.cast null", 0xFB_49, HEAP_TYPE), + REF_TEST("ref.test", 0xFB_40, HEAP_TYPE), + REF_TEST_NULL("ref.test null", 0xFB_48, HEAP_TYPE), + REF_CAST("ref.cast", 0xFB_41, HEAP_TYPE), + REF_CAST_NULL("ref.cast null", 0xFB_49, HEAP_TYPE), -// Not yet supported by V8 -// BR_ON_CAST("br_on_cast", 0xFB42, listOf(LABEL_IDX, HEAP_TYPE)), -// BR_ON_CAST_NULL("br_on_cast null", 0xFB4A, listOf(LABEL_IDX, HEAP_TYPE)), -// BR_ON_CAST_FAIL("br_on_cast_fail", 0xFB43, listOf(LABEL_IDX, HEAP_TYPE)), -// BR_ON_CAST_FAIL_NULL("br_on_cast_fail null", 0xFB4B, listOf(LABEL_IDX, HEAP_TYPE)), + BR_ON_CAST("br_on_cast", 0xFB_42, listOf(LABEL_IDX, HEAP_TYPE)), + BR_ON_CAST_FAIL("br_on_cast_fail", 0xFB_43, listOf(LABEL_IDX, HEAP_TYPE)), EXTERN_INTERNALIZE("extern.internalize", 0xfb70), // externref -> anyref EXTERN_EXTERNALIZE("extern.externalize", 0xfb71), // anyref -> externref - // ------------------------ - // Deprecated instructions - // TODO Remove as soon as V8 & Binaryen support new instructions. - // Revert 7f8f7aa0. - - REF_TEST_DEPRECATED("ref.test", 0xFB_44, STRUCT_TYPE_IDX), - REF_CAST_DEPRECATED("ref.cast", 0xFB_45, STRUCT_TYPE_IDX), - - BR_ON_CAST_FAIL_DEPRECATED("br_on_cast_fail", 0xFB_47, listOf(LABEL_IDX, STRUCT_TYPE_IDX)), - BR_ON_NON_DATA_DEPRECATED("br_on_non_data_fail", 0xFB_64, listOf(LABEL_IDX)), - // ============================================================ // Pseudo-instruction, just alias for a normal call. It's used to easily spot get_unit on the wasm level. GET_UNIT("call", 0x10, FUNC_IDX), diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt index adf7215ee16..1de080746ce 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt @@ -98,7 +98,7 @@ abstract class WasmExpressionBuilder { fun buildBrInstr(brOp: WasmOp, absoluteBlockLevel: Int, symbol: WasmSymbolReadOnly, location: SourceLocation) { val relativeLevel = numberOfNestedBlocks - absoluteBlockLevel assert(relativeLevel >= 0) { "Negative relative block index" } - buildInstr(brOp, location, WasmImmediate.LabelIdx(relativeLevel), WasmImmediate.TypeIdx(symbol)) + buildInstr(brOp, location, WasmImmediate.LabelIdx(relativeLevel), WasmImmediate.HeapType(WasmHeapType.Type(symbol))) } fun buildBr(absoluteBlockLevel: Int, location: SourceLocation) { @@ -179,11 +179,15 @@ abstract class WasmExpressionBuilder { } fun buildRefCastNullStatic(toType: WasmSymbolReadOnly, location: SourceLocation) { - buildInstr(WasmOp.REF_CAST_DEPRECATED, location, WasmImmediate.TypeIdx(toType)) + buildInstr(WasmOp.REF_CAST_NULL, location, WasmImmediate.HeapType(WasmHeapType.Type(toType))) + } + + fun buildRefCastStatic(toType: WasmSymbolReadOnly, location: SourceLocation) { + buildInstr(WasmOp.REF_CAST, location, WasmImmediate.HeapType(WasmHeapType.Type(toType))) } fun buildRefTestStatic(toType: WasmSymbolReadOnly, location: SourceLocation) { - buildInstr(WasmOp.REF_TEST_DEPRECATED, location, WasmImmediate.TypeIdx(toType)) + buildInstr(WasmOp.REF_TEST, location, WasmImmediate.HeapType(WasmHeapType.Type(toType))) } fun buildRefNull(type: WasmHeapType, location: SourceLocation) {