From 4aad29592ee7b61c90c66e6e7ad8e3e177d38e88 Mon Sep 17 00:00:00 2001 From: "Flavio S. Glock" Date: Sat, 19 Sep 2026 07:05:34 +0200 Subject: [PATCH 1/2] perf: avoid BigInteger for native unsigned shifts Use Java's 64-bit unsigned-word shift semantics for ordinary integer operands while retaining the existing arbitrary-precision fallback. Generated with Codex https://openai.com/codex Co-Authored-By: Codex --- .../runtime/operators/BitwiseOperators.java | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/perlonjava/runtime/operators/BitwiseOperators.java b/src/main/java/org/perlonjava/runtime/operators/BitwiseOperators.java index 381da5eee..e7fc07adc 100644 --- a/src/main/java/org/perlonjava/runtime/operators/BitwiseOperators.java +++ b/src/main/java/org/perlonjava/runtime/operators/BitwiseOperators.java @@ -56,6 +56,17 @@ private static RuntimeScalar unsignedShiftRight(BigInteger value, long shift) { return unsignedResult(value.shiftRight((int) shift)); } + /** + * Shift an ordinary native integer as a Perl unsigned value. Java long + * overflow supplies the required low 64-bit truncation; unsignedResult + * retains a BigInteger only when the resulting UV cannot be represented + * as a non-negative signed long. + */ + private static RuntimeScalar nativeUnsignedShift(long value, long shift, boolean left) { + if (shift >= 64) return RuntimeScalarCache.scalarZero; + return unsignedResult(left ? value << (int) shift : value >>> (int) shift); + } + private static BigInteger exactInteger(RuntimeScalar scalar) { return scalar.type == RuntimeScalarType.INTEGER && scalar.value instanceof BigInteger ? (BigInteger) scalar.value : null; @@ -525,13 +536,12 @@ public static RuntimeScalar shiftLeft(RuntimeScalar runtimeScalar, RuntimeScalar // Fast path: both INTEGER with non-negative shift within Java's 64-bit word. int t1 = runtimeScalar.type; int t2 = arg2.type; - if (t1 == RuntimeScalarType.INTEGER && t2 == RuntimeScalarType.INTEGER - && exactInteger(arg2) == null) { + if (hasNativeInteger(runtimeScalar) && hasNativeInteger(arg2)) { long shift = arg2.getLong(); if (shift >= 0) { - return unsignedShiftLeft(unsignedValue(runtimeScalar), shift); + return nativeUnsignedShift(((Number) runtimeScalar.value).longValue(), shift, true); } else if (shift != Long.MIN_VALUE) { - return unsignedShiftRight(unsignedValue(runtimeScalar), -shift); + return nativeUnsignedShift(((Number) runtimeScalar.value).longValue(), -shift, false); } return RuntimeScalarCache.scalarZero; } @@ -616,13 +626,12 @@ public static RuntimeScalar shiftRight(RuntimeScalar runtimeScalar, RuntimeScala // Fast path: both INTEGER with non-negative shift within Java's 64-bit word. int t1 = runtimeScalar.type; int t2 = arg2.type; - if (t1 == RuntimeScalarType.INTEGER && t2 == RuntimeScalarType.INTEGER - && exactInteger(arg2) == null) { + if (hasNativeInteger(runtimeScalar) && hasNativeInteger(arg2)) { long shift = arg2.getLong(); if (shift >= 0) { - return unsignedShiftRight(unsignedValue(runtimeScalar), shift); + return nativeUnsignedShift(((Number) runtimeScalar.value).longValue(), shift, false); } else if (shift != Long.MIN_VALUE) { - return unsignedShiftLeft(unsignedValue(runtimeScalar), -shift); + return nativeUnsignedShift(((Number) runtimeScalar.value).longValue(), -shift, true); } return RuntimeScalarCache.scalarZero; } From 11e901c62cd02ffb461e085242408e3bdc7743ae Mon Sep 17 00:00:00 2001 From: "Flavio S. Glock" Date: Sat, 19 Sep 2026 08:27:40 +0200 Subject: [PATCH 2/2] docs: record native unsigned shift optimization Generated with Codex (https://openai.com/codex) Co-Authored-By: Codex --- docs/about/changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/about/changelog.md b/docs/about/changelog.md index 2a6e9ee11..33a1694b1 100644 --- a/docs/about/changelog.md +++ b/docs/about/changelog.md @@ -26,6 +26,9 @@ priorities and future plans. - Reuse static literal regular-expression match wrappers per runtime and call site, reducing recurring pattern-resolution and compilation overhead. +- Avoid arbitrary-precision allocation for ordinary native-integer unsigned + shifts while retaining the existing wide-integer fallback. + - Restore lexical-sub debugger dispatch and `glob` fallback behavior after an undefined `CORE::GLOBAL::glob` slot on both execution backends.