[WASM] Optimise interop adapters

This commit is contained in:
Igor Yakovlev
2022-09-22 16:07:59 +02:00
parent 6627b62c21
commit 5218acd5c9
10 changed files with 127 additions and 83 deletions
@@ -114,11 +114,7 @@ private external fun doubleToExternref(x: Double): ExternalInterfaceType
@JsFun("(lhs, rhs) => lhs === rhs")
private external fun externrefEquals(lhs: ExternalInterfaceType, rhs: ExternalInterfaceType): Boolean
@JsFun("(ref) => (typeof ref !== 'object' || ref === null) ? null : (externrefBoxes.get(ref) ?? null)")
private external fun getExternrefBoxOrNull(ref: ExternalInterfaceType): JsExternalBox?
@JsFun("(ref, box) => { if (typeof ref === 'object' && ref !== null) { externrefBoxes.set(ref, box); } }")
private external fun setExternrefBox(ref: ExternalInterfaceType, box: JsExternalBox)
private external fun tryGetOrSetExternrefBox(ref: ExternalInterfaceType, ifNotCached: JsExternalBox): JsExternalBox?
@WasmNoOpCast
@Suppress("unused")
@@ -130,11 +126,11 @@ private fun ExternalInterfaceType.externAsWasmAnyref(): anyref =
implementedAsIntrinsic
@WasmOp(WasmOp.EXTERN_EXTERNALIZE)
private fun Any?.asWasmExternRef(): ExternalInterfaceType =
private fun Any.asWasmExternRef(): ExternalInterfaceType =
implementedAsIntrinsic
@JsFun("(ref) => ref == null")
internal external fun isNullish(ref: ExternalInterfaceType): Boolean
internal external fun isNullish(ref: ExternalInterfaceType?): Boolean
internal fun externRefToAny(ref: ExternalInterfaceType): Any? {
// If ref is an instance of kotlin class -- return it cased to Any
@@ -146,15 +142,10 @@ internal fun externRefToAny(ref: ExternalInterfaceType): Any? {
}
}
if (isNullish(ref))
return null
// If we have Null in notNullRef -- return null
// If we already have a box -- return it,
// otherwise -- create a new box and remember it.
return getExternrefBoxOrNull(ref)
?: JsExternalBox(ref).also {
setExternrefBox(ref, it)
}
// otherwise -- remember new box and return it.
return tryGetOrSetExternrefBox(ref, JsExternalBox(ref))
}
@@ -182,7 +173,7 @@ internal fun kotlinToJsStringAdapter(x: String?): ExternalInterfaceType? {
// Using nullable String to represent default value
// for parameters with default values
if (x == null) return null
if (x.isEmpty()) return jsEmptyString()
if (x.isEmpty()) return jsEmptyString
val srcArray = x.chars
val stringLength = srcArray.len()
@@ -202,6 +193,9 @@ internal fun kotlinToJsStringAdapter(x: String?): ExternalInterfaceType? {
return importStringFromWasm(memBuffer, stringLength - srcStartIndex, result)
}
internal fun jsCheckIsNullOrUndefinedAdapter(x: ExternalInterfaceType?): ExternalInterfaceType? =
x.takeIf { !isNullish(it) }
// js string to kotlin string import
// TODO Uint16Array may work with byte endian different with Wasm (i.e. little endian)
//language=js
@@ -244,19 +238,23 @@ internal fun jsToKotlinStringAdapter(x: ExternalInterfaceType): String {
@JsFun("() => ''")
internal external fun jsEmptyString(): ExternalInterfaceType
private external fun getJsEmptyString(): ExternalInterfaceType
@JsFun("() => true")
internal external fun jsTrue(): ExternalInterfaceType
private external fun getJsTrue(): ExternalInterfaceType
@JsFun("() => false")
internal external fun jsFalse(): ExternalInterfaceType
private external fun getJsFalse(): ExternalInterfaceType
internal fun kotlinToJsAnyAdapter(x: Any): ExternalInterfaceType =
anyToExternRef(x)
private val jsEmptyString by lazy(::getJsEmptyString)
private val jsTrue by lazy(::getJsTrue)
private val jsFalse by lazy(::getJsFalse)
internal fun jsToKotlinAnyAdapter(x: ExternalInterfaceType): Any? =
externRefToAny(x)
internal fun kotlinToJsAnyAdapter(x: Any?): ExternalInterfaceType? =
if (x == null) null else anyToExternRef(x)
internal fun jsToKotlinAnyAdapter(x: ExternalInterfaceType?): Any? =
if (x == null) null else externRefToAny(x)
internal fun jsToKotlinByteAdapter(x: Int): Byte = x.toByte()
internal fun jsToKotlinShortAdapter(x: Int): Short = x.toShort()
@@ -282,7 +280,7 @@ internal fun kotlinIntToExternRefAdapter(x: Int): ExternalInterfaceType =
intToExternref(x)
internal fun kotlinBooleanToExternRefAdapter(x: Boolean): ExternalInterfaceType =
if (x) jsTrue() else jsFalse()
if (x) jsTrue else jsFalse
internal fun kotlinLongToExternRefAdapter(x: Long): ExternalInterfaceType =
longToExternref(x)
@@ -65,9 +65,6 @@ internal fun nullableDoubleIeee754Equals(lhs: Double?, rhs: Double?): Boolean {
return wasm_f64_eq(lhs, rhs)
}
internal fun <T : Any> ensureNotNull(v: T?): T = if (v == null) THROW_NPE() else v
@ExcludedFromCodegen
internal fun <T, R> boxIntrinsic(x: T): R =
implementedAsIntrinsic
@@ -13,6 +13,7 @@ import kotlin.wasm.internal.reftypes.anyref
import kotlin.wasm.internal.reftypes.dataref
import kotlin.wasm.internal.reftypes.funcref
import kotlin.wasm.internal.reftypes.i31ref
import kotlin.wasm.internal.ExternalInterfaceType
@WasmOp(WasmOp.UNREACHABLE)
internal fun wasm_unreachable(): Nothing =
@@ -384,4 +385,7 @@ internal external fun wasm_ref_is_i31(x: anyref): Boolean
internal external fun wasm_ref_as_data(x: anyref): dataref
@WasmOp(WasmOp.REF_AS_I31)
internal external fun wasm_ref_as_i31(x: anyref): i31ref
internal external fun wasm_ref_as_i31(x: anyref): i31ref
@WasmOp(WasmOp.REF_IS_NULL)
internal external fun wasm_externref_is_null(a: ExternalInterfaceType?): Boolean