From d1d8c8f02aca30df638841d2216ebee849da4983 Mon Sep 17 00:00:00 2001 From: lxw Date: Thu, 4 Jul 2024 16:34:02 +0800 Subject: [PATCH] [Runtime] optimize BigDecimal.divide Summary: Use binary search in zero stripping of BigDecimal.divide Testing: jtreg Reviewers: Issue: https://github.com/dragonwell-project/dragonwell11/issues/ CR: https://github.com/dragonwell-project/dragonwell11/pull/ --- src/hotspot/share/runtime/arguments.cpp | 4 ++ src/hotspot/share/runtime/globals_ext.hpp | 3 ++ .../share/classes/java/math/BigDecimal.java | 45 +++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 1e8b7319bb3..dcc7f8c8a6f 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -4115,6 +4115,10 @@ jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) { DumpAppCDSWithKlassId = true; } + if (UseBigDecimalOpt) { + PropertyList_add(&_system_properties, new SystemProperty("java.math.BigDecimal.opt", "true", true)); + } + // Set object alignment values. set_object_alignment(); diff --git a/src/hotspot/share/runtime/globals_ext.hpp b/src/hotspot/share/runtime/globals_ext.hpp index e36fb6a27f3..1a54881c4f5 100644 --- a/src/hotspot/share/runtime/globals_ext.hpp +++ b/src/hotspot/share/runtime/globals_ext.hpp @@ -93,6 +93,9 @@ product(bool, ReduceNMethodSize, false, \ "Move immutable data of nmethod out of code cache") \ \ + product(bool, UseBigDecimalOpt, true, \ + "use binary search in zero stripping of BigDecimal") \ + \ //add new AJDK specific flags here diff --git a/src/java.base/share/classes/java/math/BigDecimal.java b/src/java.base/share/classes/java/math/BigDecimal.java index ff9a6daf47b..4835963d862 100644 --- a/src/java.base/share/classes/java/math/BigDecimal.java +++ b/src/java.base/share/classes/java/math/BigDecimal.java @@ -368,6 +368,16 @@ protected StringBuilderHelper initialValue() { */ private static final BigDecimal ONE_HALF = valueOf(5L, 1); + private static boolean opt; + static { + try { + opt = Boolean.parseBoolean(System.getProperty("java.math.BigDecimal.optimization")); + } catch (SecurityException e) { + // When user define some secure environment, system property here may be inaccessible. + opt = false; + } + } + // Constructors /** @@ -4860,6 +4870,38 @@ private static boolean needIncrement(MutableBigInteger mdivisor, int roundingMod return commonNeedIncrement(roundingMode, qsign, cmpFracHalf, mq.isOdd()); } + /** + * Remove insignificant trailing zeros from this + * {@code BigInteger} value until the preferred scale is reached or no + * more zeros can be removed. This is a faster version of createAndStripZerosToMatchScale + * using binary search instead of linear search. + * + * @return new {@code BigDecimal} with a scale possibly reduced + * to be closed to the preferred scale. + */ + private static BigDecimal createAndStripZerosToMatchScaleFast(BigInteger intVal, int scale, long preferredScale) { + BigInteger qr[]; // quotient-remainder pair + int scaleStep; + while (intVal.compareMagnitude(BigInteger.TEN) >= 0 + && scale > preferredScale) { + scaleStep = checkScale(intVal, Math.max(((long) scale - preferredScale) / 2, 1l)); + if (intVal.getLowestSetBit() >= scaleStep) { // intVal can be divided by pow(10, scaleStep) only if intVal has more trailing zeros than scaleStep + qr = intVal.divideAndRemainder(bigTenToThe(scaleStep)); + if (qr[1].signum() == 0) { + intVal = qr[0]; + scale = checkScale(intVal, (long) scale - scaleStep); // could Overflow + continue; + } + } + if (scaleStep == 1) { + break; + } else { + preferredScale = scale - scaleStep; + } + } + return valueOf(intVal, scale, 0); + } + /** * Remove insignificant trailing zeros from this * {@code BigInteger} value until the preferred scale is reached or no @@ -4870,6 +4912,9 @@ private static boolean needIncrement(MutableBigInteger mdivisor, int roundingMod * to be closed to the preferred scale. */ private static BigDecimal createAndStripZerosToMatchScale(BigInteger intVal, int scale, long preferredScale) { + if (opt && preferredScale >= Integer.MIN_VALUE) { + return createAndStripZerosToMatchScaleFast(intVal, scale, preferredScale); + } BigInteger qr[]; // quotient-remainder pair while (intVal.compareMagnitude(BigInteger.TEN) >= 0 && scale > preferredScale) {