[Wasm] Add fast path for null in externRefToAny

- Introduce new intrinsics `wasm_ref_cast_null` & `wasm_ref_test_null`.
- Support getting type for immediate from generic argument.
- Remove redundant null check in `tryGetOrSetExternrefBox`.
This commit is contained in:
Zalim Bashorov
2022-11-15 13:39:40 +01:00
parent b31a657494
commit 919029f34f
4 changed files with 23 additions and 8 deletions
@@ -109,8 +109,8 @@ fun WasmCompiledModuleFragment.generateJs(): String {
//language=js //language=js
val runtime = """ val runtime = """
const externrefBoxes = new WeakMap(); const externrefBoxes = new WeakMap();
// ref must be non-null
function tryGetOrSetExternrefBox(ref, ifNotCached) { function tryGetOrSetExternrefBox(ref, ifNotCached) {
if (ref == null) return null;
if (typeof ref !== 'object') return ifNotCached; if (typeof ref !== 'object') return ifNotCached;
const cachedBox = externrefBoxes.get(ref); const cachedBox = externrefBoxes.get(ref);
if (cachedBox !== void 0) return cachedBox; if (cachedBox !== void 0) return cachedBox;
@@ -461,7 +461,7 @@ class BodyGenerator(
call: IrFunctionAccessExpression, call: IrFunctionAccessExpression,
function: IrFunction function: IrFunction
): Boolean { ): Boolean {
if (tryToGenerateWasmOpIntrinsicCall(function)) { if (tryToGenerateWasmOpIntrinsicCall(call, function)) {
return true return true
} }
@@ -840,7 +840,7 @@ class BodyGenerator(
} }
// Return true if function is recognized as intrinsic. // Return true if function is recognized as intrinsic.
private fun tryToGenerateWasmOpIntrinsicCall(function: IrFunction): Boolean { private fun tryToGenerateWasmOpIntrinsicCall(call: IrFunctionAccessExpression, function: IrFunction): Boolean {
if (function.hasWasmNoOpCastAnnotation()) { if (function.hasWasmNoOpCastAnnotation()) {
return true return true
} }
@@ -853,14 +853,19 @@ class BodyGenerator(
body.buildInstr(op) body.buildInstr(op)
} }
1 -> { 1 -> {
fun getReferenceGcType(): WasmSymbol<WasmTypeDeclaration> {
val type = function.dispatchReceiverParameter?.type ?: call.getTypeArgument(0)!!
return context.referenceGcType(type.classOrNull!!)
}
val immediates = arrayOf( val immediates = arrayOf(
when (val imm = op.immediates[0]) { when (val imm = op.immediates[0]) {
WasmImmediateKind.MEM_ARG -> WasmImmediateKind.MEM_ARG ->
WasmImmediate.MemArg(0u, 0u) WasmImmediate.MemArg(0u, 0u)
WasmImmediateKind.STRUCT_TYPE_IDX -> WasmImmediateKind.STRUCT_TYPE_IDX ->
WasmImmediate.GcType(context.referenceGcType(function.dispatchReceiverParameter!!.type.classOrNull!!)) WasmImmediate.GcType(getReferenceGcType())
WasmImmediateKind.TYPE_IDX -> WasmImmediateKind.TYPE_IDX ->
WasmImmediate.TypeIdx(context.referenceGcType(function.dispatchReceiverParameter!!.type.classOrNull!!)) WasmImmediate.TypeIdx(getReferenceGcType())
else -> else ->
error("Immediate $imm is unsupported") error("Immediate $imm is unsupported")
@@ -141,13 +141,13 @@ internal fun externRefToAny(ref: ExternalInterfaceType): Any? {
// TODO rewrite it so to get something like: // TODO rewrite it so to get something like:
// block { // block {
// refAsAnyref // refAsAnyref
// br_on_cast_fail 0 $kotlin.Any // br_on_cast_fail null 0 $kotlin.Any
// return // return
// } // }
// If ref is an instance of kotlin class -- return it casted to Any // If ref is an instance of kotlin class -- return it casted to Any
val refAsAnyref = ref.externAsWasmAnyref() val refAsAnyref = ref.externAsWasmAnyref()
if (wasm_ref_test<Any>(refAsAnyref)) { if (wasm_ref_test_null<Any>(refAsAnyref)) {
return wasm_ref_cast<Any>(refAsAnyref) return wasm_ref_cast_null<Any>(refAsAnyref)
} }
// If we have Null in notNullRef -- return null // If we have Null in notNullRef -- return null
@@ -22,9 +22,19 @@ internal fun wasm_unreachable(): Nothing =
internal fun <To> wasm_ref_cast(a: Any?): To = internal fun <To> wasm_ref_cast(a: Any?): To =
implementedAsIntrinsic implementedAsIntrinsic
@Suppress("REIFIED_TYPE_PARAMETER_NO_INLINE")
@WasmOp(WasmOp.REF_CAST_NULL)
internal fun <reified To> wasm_ref_cast_null(a: Any?): To =
implementedAsIntrinsic
internal fun <To> wasm_ref_test(a: Any?): Boolean = internal fun <To> wasm_ref_test(a: Any?): Boolean =
implementedAsIntrinsic implementedAsIntrinsic
@Suppress("REIFIED_TYPE_PARAMETER_NO_INLINE")
@WasmOp(WasmOp.REF_TEST_NULL)
internal fun <reified To> wasm_ref_test_null(a: Any?): Boolean =
implementedAsIntrinsic
internal fun <T> wasm_array_copy(destination: T, destinationIndex: Int, source: T, sourceIndex: Int, length: Int): Unit = internal fun <T> wasm_array_copy(destination: T, destinationIndex: Int, source: T, sourceIndex: Int, length: Int): Unit =
implementedAsIntrinsic implementedAsIntrinsic