[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:
@@ -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;
|
||||||
|
|||||||
+9
-4
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user