This is an automated email from the ASF dual-hosted git repository.
gengliangwang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/master by this push:
new 6bbf226633d6 [SPARK-57177][SQL] Simplify Acosh codegen by extracting a
static Java helper
6bbf226633d6 is described below
commit 6bbf226633d6ab9832f09e2c3bf60915eb3d39a9
Author: Gengliang Wang <[email protected]>
AuthorDate: Wed Jun 3 08:12:50 2026 -0700
[SPARK-57177][SQL] Simplify Acosh codegen by extracting a static Java helper
### What changes were proposed in this pull request?
Add `ExpressionImplUtils.acosh(double x)` (the fdlibm `e_acosh.c`
algorithm) and route `Acosh`'s eval and codegen paths through it.
`Acosh.doGenCode` previously emitted a 12-line inline five-branch if/else; it
now emits a single `ExpressionImplUtils.acosh(...)` call via `defineCodeGen`,
and the eval path (the `UnaryMathExpression` function) calls the same helper
instead of an inline lambda copy of the algorithm.
`acosh` returns a primitive `double` (`NaN` for out-of-domain input), so
the helper is a clean drop-in for both paths with no boxing and no null
handling.
This is a plain (non-ANSI, non-try/catch) type-independent block, in line
with the broadened goal of SPARK-56908 to move fixed generated-Java logic into
static Java helpers.
### Why are the changes needed?
Part of SPARK-56908 (umbrella). Collapsing the duplicated 12-line algorithm
to a single call shrinks the generated Java for every stage that uses `acosh`,
and removes the eval/codegen duplication of the same fdlibm algorithm, helping
with the JVM 64KB method / constant-pool limits, Janino compile time, and JIT
work.
### Does this PR introduce _any_ user-facing change?
No. The compiled behavior is identical; only the emitted Java source text
changes.
### How was this patch tested?
```
build/sbt "catalyst/testOnly *MathExpressionsSuite"
```
54/54 pass, including `acosh` and `SPARK-56089: asinh/acosh fdlibm
algorithm coverage` (exercised both with and without whole-stage codegen).
### Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Opus 4.8)
Closes #56228 from gengliangwang/spark-acosh-codegen.
Authored-by: Gengliang Wang <[email protected]>
Signed-off-by: Gengliang Wang <[email protected]>
---
.../catalyst/expressions/ExpressionImplUtils.java | 21 ++++++++++++
.../sql/catalyst/expressions/mathExpressions.scala | 37 +++-------------------
2 files changed, 25 insertions(+), 33 deletions(-)
diff --git
a/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/ExpressionImplUtils.java
b/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/ExpressionImplUtils.java
index 6db52b7af46f..4343f6631c0c 100644
---
a/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/ExpressionImplUtils.java
+++
b/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/ExpressionImplUtils.java
@@ -346,6 +346,27 @@ public class ExpressionImplUtils {
return UTF8String.fromString(qtChar + sp + qtChar);
}
+ /**
+ * Inverse hyperbolic cosine for the {@code acosh} expression, using the
+ * fdlibm {@code e_acosh.c} algorithm (returns {@code NaN} for {@code x <
1}).
+ * Shared by the eval and codegen paths so the generated Java is a single
call
+ * rather than an inline five-branch if/else.
+ */
+ public static double acosh(double x) {
+ if (x < 1.0) {
+ return Double.NaN;
+ } else if (x >= (1 << 28)) {
+ return StrictMath.log(x) + StrictMath.log(2.0);
+ } else if (x == 1.0) {
+ return 0.0;
+ } else if (x > 2.0) {
+ return StrictMath.log(2.0 * x - 1.0 / (x + Math.sqrt(x * x - 1.0)));
+ } else {
+ double t = x - 1.0;
+ return StrictMath.log1p(t + Math.sqrt(2.0 * t + t * t));
+ }
+ }
+
/**
* Returns the single-character string for the {@code chr} expression: the
* ASCII/Latin-1 character for {@code longVal & 0xFF}. A negative argument
diff --git
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala
index d816043e710d..2f62e1427d16 100644
---
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala
+++
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala
@@ -418,40 +418,11 @@ case class Cosh(child: Expression) extends
UnaryMathExpression(math.cosh, "COSH"
since = "3.0.0",
group = "math_funcs")
case class Acosh(child: Expression)
- extends UnaryMathExpression((x: Double) => {
- // fdlibm e_acosh.c algorithm
- if (x < 1.0) {
- Double.NaN
- } else if (x >= (1 << 28)) {
- StrictMath.log(x) + StrictMath.log(2.0)
- } else if (x == 1.0) {
- 0.0
- } else if (x > 2.0) {
- StrictMath.log(2.0 * x - 1.0 / (x + math.sqrt(x * x - 1.0)))
- } else {
- val t = x - 1.0
- StrictMath.log1p(t + math.sqrt(2.0 * t + t * t))
- }
- }, "ACOSH") {
+ // fdlibm e_acosh.c algorithm, shared with codegen via
ExpressionImplUtils.acosh.
+ extends UnaryMathExpression((x: Double) => ExpressionImplUtils.acosh(x),
"ACOSH") {
override def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = {
- nullSafeCodeGen(ctx, ev, c => {
- val sm = "java.lang.StrictMath"
- val t = ctx.freshName("t")
- s"""
- |if ($c < 1.0) {
- | ${ev.value} = java.lang.Double.NaN;
- |} else if ($c >= ${1 << 28}.0) {
- | ${ev.value} = $sm.log($c) + $sm.log(2.0);
- |} else if ($c == 1.0) {
- | ${ev.value} = 0.0;
- |} else if ($c > 2.0) {
- | ${ev.value} = $sm.log(2.0 * $c - 1.0 / ($c +
java.lang.Math.sqrt($c * $c - 1.0)));
- |} else {
- | double $t = $c - 1.0;
- | ${ev.value} = $sm.log1p($t + java.lang.Math.sqrt(2.0 * $t + $t *
$t));
- |}
- |""".stripMargin
- })
+ val utils = classOf[ExpressionImplUtils].getName
+ defineCodeGen(ctx, ev, c => s"$utils.acosh($c)")
}
override protected def withNewChildInternal(newChild: Expression): Acosh =
copy(child = newChild)
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]