From ad14063210bec83b4ff485ebc6eb14e009356792 Mon Sep 17 00:00:00 2001 From: Filipp Zhinkin Date: Tue, 19 Nov 2024 08:31:06 -0500 Subject: [PATCH] Delegate Int|Short|Long.reverseBytes to Java Stdlib (#414) JVM's JIT compiler can't pattern match bytes reversal, so it's worth explicitly delegating to Java Stdlib functions, that are intrinsics candidates. For long values, the new implementation shows 20% perf improvement for reversal itself. Functions depending on it, like readXXXLe or writeXXXLe also show some moderate performance improvement from the change. --- core/common/src/-Util.kt | 22 ++++++++++------------ core/js/src/UtilsJs.kt | 10 ++++++++++ core/jvm/src/-UtilsJvm.kt | 10 ++++++++++ core/native/src/UtilsNative.kt | 10 ++++++++++ core/wasm/src/UtilsWasm.kt | 10 ++++++++++ 5 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 core/js/src/UtilsJs.kt create mode 100644 core/jvm/src/-UtilsJvm.kt create mode 100644 core/native/src/UtilsNative.kt create mode 100644 core/wasm/src/UtilsWasm.kt diff --git a/core/common/src/-Util.kt b/core/common/src/-Util.kt index 01848f02e..17f4f391b 100644 --- a/core/common/src/-Util.kt +++ b/core/common/src/-Util.kt @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 JetBrains s.r.o. and respective authors and developers. + * Copyright 2017-2024 JetBrains s.r.o. and respective authors and developers. * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENCE file. */ @@ -52,21 +52,27 @@ internal inline fun checkByteCount(byteCount: Long) { require(byteCount >= 0) { "byteCount ($byteCount) < 0" } } -internal fun Short.reverseBytes(): Short { +internal expect fun Short.reverseBytes(): Short + +internal inline fun Short.reverseBytesCommon(): Short { val i = toInt() and 0xffff val reversed = (i and 0xff00 ushr 8) or (i and 0x00ff shl 8) return reversed.toShort() } -internal fun Int.reverseBytes(): Int { +internal expect fun Int.reverseBytes(): Int + +internal inline fun Int.reverseBytesCommon(): Int { return (this and -0x1000000 ushr 24) or (this and 0x00ff0000 ushr 8) or (this and 0x0000ff00 shl 8) or (this and 0x000000ff shl 24) } -internal fun Long.reverseBytes(): Long { +internal expect fun Long.reverseBytes(): Long + +internal inline fun Long.reverseBytesCommon(): Long { return (this and -0x100000000000000L ushr 56) or (this and 0x00ff000000000000L ushr 40) or (this and 0x0000ff0000000000L ushr 24) or @@ -79,14 +85,6 @@ internal fun Long.reverseBytes(): Long { /* ktlint-enable no-multi-spaces indent */ -internal inline infix fun Int.leftRotate(bitCount: Int): Int { - return (this shl bitCount) or (this ushr (32 - bitCount)) -} - -internal inline infix fun Long.rightRotate(bitCount: Int): Long { - return (this ushr bitCount) or (this shl (64 - bitCount)) -} - // Syntactic sugar. internal inline infix fun Byte.shr(other: Int): Int = toInt() shr other diff --git a/core/js/src/UtilsJs.kt b/core/js/src/UtilsJs.kt new file mode 100644 index 000000000..433e62422 --- /dev/null +++ b/core/js/src/UtilsJs.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2010-2024 JetBrains s.r.o. and respective authors and developers. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENCE file. + */ + +package kotlinx.io + +internal actual fun Short.reverseBytes(): Short = reverseBytesCommon() +internal actual fun Int.reverseBytes(): Int = reverseBytesCommon() +internal actual fun Long.reverseBytes(): Long = reverseBytesCommon() diff --git a/core/jvm/src/-UtilsJvm.kt b/core/jvm/src/-UtilsJvm.kt new file mode 100644 index 000000000..108e2b15a --- /dev/null +++ b/core/jvm/src/-UtilsJvm.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2010-2024 JetBrains s.r.o. and respective authors and developers. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENCE file. + */ + +package kotlinx.io + +internal actual fun Short.reverseBytes(): Short = java.lang.Short.reverseBytes(this) +internal actual fun Int.reverseBytes(): Int = java.lang.Integer.reverseBytes(this) +internal actual fun Long.reverseBytes(): Long = java.lang.Long.reverseBytes(this) diff --git a/core/native/src/UtilsNative.kt b/core/native/src/UtilsNative.kt new file mode 100644 index 000000000..433e62422 --- /dev/null +++ b/core/native/src/UtilsNative.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2010-2024 JetBrains s.r.o. and respective authors and developers. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENCE file. + */ + +package kotlinx.io + +internal actual fun Short.reverseBytes(): Short = reverseBytesCommon() +internal actual fun Int.reverseBytes(): Int = reverseBytesCommon() +internal actual fun Long.reverseBytes(): Long = reverseBytesCommon() diff --git a/core/wasm/src/UtilsWasm.kt b/core/wasm/src/UtilsWasm.kt new file mode 100644 index 000000000..433e62422 --- /dev/null +++ b/core/wasm/src/UtilsWasm.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2010-2024 JetBrains s.r.o. and respective authors and developers. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENCE file. + */ + +package kotlinx.io + +internal actual fun Short.reverseBytes(): Short = reverseBytesCommon() +internal actual fun Int.reverseBytes(): Int = reverseBytesCommon() +internal actual fun Long.reverseBytes(): Long = reverseBytesCommon()