From 09427fe6cf3bbf6d9448ab62282da8afc7724d35 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 6 Apr 2026 19:01:38 +0000 Subject: [PATCH] =?UTF-8?q?perf:=20direct=20Math.unsignedMultiplyHigh=20ca?= =?UTF-8?q?ll=20=E2=80=94=20eliminate=20MethodHandle=20boxing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The JVM target is Java 21, so Math.unsignedMultiplyHigh (Java 18+) can be called directly without MethodHandle reflection. The previous approach used MethodHandle.invokeExact which Kotlin compiles with Object return type, causing Long boxing on every call (3 box/unbox per invocation × 16 calls per field multiply = 48 boxed objects per mul). Direct call compiles to a single UMULH instruction with zero overhead. This is the most performance-critical function: called ~12,000× per signature verification. https://claude.ai/code/session_01BhU63WUe9AhikZxRdw3Lpg --- .../utils/secp256k1/MultiplyHigh.jvm.kt | 49 +++---------------- 1 file changed, 8 insertions(+), 41 deletions(-) diff --git a/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/secp256k1/MultiplyHigh.jvm.kt b/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/secp256k1/MultiplyHigh.jvm.kt index bc0a32242..d11b90f43 100644 --- a/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/secp256k1/MultiplyHigh.jvm.kt +++ b/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/secp256k1/MultiplyHigh.jvm.kt @@ -31,48 +31,15 @@ internal actual fun multiplyHigh( ): Long = Math.multiplyHigh(a, b) /** - * JVM: uses Math.unsignedMultiplyHigh (Java 18+) if available, else fallback. - * The HAS_UNSIGNED_MULTIPLY_HIGH check is evaluated once at class init and the - * JIT will devirtualize the hot branch after a few invocations. + * JVM implementation using Math.unsignedMultiplyHigh (Java 18+). + * Direct call — no MethodHandle, no boxing, no branch. + * The JIT compiles this to a single UMULH instruction on x86-64/ARM64. + * + * This is the single most performance-critical function in the entire + * secp256k1 implementation: called 16× per field multiply, ~12,000× + * per signature verification. */ internal actual fun unsignedMultiplyHigh( a: Long, b: Long, -): Long = - if (HAS_UNSIGNED_MULTIPLY_HIGH) { - unsignedMultiplyHighNative(a, b) - } else { - unsignedMultiplyHighFallback(a, b) - } - -/** - * Tries to resolve Math.unsignedMultiplyHigh (Java 18+) as a MethodHandle. - * If available, invoking it compiles to a single UMULH instruction, saving - * 4 correction instructions per product vs the signed multiplyHigh + fixup path. - * This saves ~64 instructions per field multiplication (16 products × 4 insns). - * - * MethodHandle.invokeExact is JIT-inlined to the same cost as a direct call. - */ -private val UNSIGNED_MUL_HIGH: java.lang.invoke.MethodHandle? = - try { - java.lang.invoke.MethodHandles.lookup().findStatic( - Math::class.java, - "unsignedMultiplyHigh", - java.lang.invoke.MethodType.methodType( - java.lang.Long.TYPE, - java.lang.Long.TYPE, - java.lang.Long.TYPE, - ), - ) - } catch (_: Throwable) { - null - } - -/** True if the native unsigned multiply high is available (Java 18+). */ -internal val HAS_UNSIGNED_MULTIPLY_HIGH: Boolean = UNSIGNED_MUL_HIGH != null - -/** Call Math.unsignedMultiplyHigh via MethodHandle (only when HAS_UNSIGNED_MULTIPLY_HIGH is true). */ -internal fun unsignedMultiplyHighNative( - a: Long, - b: Long, -): Long = UNSIGNED_MUL_HIGH!!.invokeExact(a, b) as Long +): Long = Math.unsignedMultiplyHigh(a, b)