Skip to content

Conversation

@niloc132
Copy link
Member

Generalized DCE's ability to run certain String methods at compile time to other classes specifically decorated with a new annotation. This patch delays inlining those methods at all until after no further Java optimizations have an impact, then removes inlining limitations and tries one more time to inline methods.

Currently has a small size regression (.02%) from inlining specialized methods after no other improvements can take place. Should be dealt with by #10241, might be worth waiting for that fix to land this.

Fixes #10147

@niloc132 niloc132 added this to the 2.14 milestone Jan 25, 2026
@niloc132
Copy link
Member Author

Some specific improvements noted in the Showcase app:

NumberFormat.format() references group/decimal separator characters

if (isCurrencyFormat) {
decimalSeparator = numberConstants.monetarySeparator().charAt(0);
groupingSeparator = numberConstants.monetaryGroupingSeparator().charAt(0);
} else {
decimalSeparator = numberConstants.decimalSeparator().charAt(0);
groupingSeparator = numberConstants.groupingSeparator().charAt(0);
}

Previously the charAt() was inlined before it could be DCE'd, leaving a call to NativeString.charCodeAt which can't be optimized out in this way, but now the compiler knows what the char is and can clean it up:

   if (this$static.isCurrencyFormat) {
-    decimalSeparator = (checkCriticalStringElementIndex(0, '.'.length) , '.'.charCodeAt(0));
-    groupingSeparator = (checkCriticalStringElementIndex(0, ','.length) , ','.charCodeAt(0));
+    decimalSeparator = 46;
+    groupingSeparator = 44;
   }
    else {
-    decimalSeparator = (checkCriticalStringElementIndex(0, '.'.length) , '.'.charCodeAt(0));
-    groupingSeparator = (checkCriticalStringElementIndex(0, ','.length) , ','.charCodeAt(0));
+    decimalSeparator = 46;
+    groupingSeparator = 44;
   }

Later in the same method, format() defaults to having '0' as its zeroChar

char zeroChar = numberConstants.zeroDigit().charAt(0);
if (zeroChar != '0') {
localizeDigits(digits, zeroChar);
}

Same charAt optimization:

   $addZeroAndDecimal(this$static, digits, decimalSeparator);
   useExponent && $addExponent(this$static, digits);
-  zeroChar = (checkCriticalStringElementIndex(0, '0'.length) , '0'.charCodeAt(0));
-  zeroChar != 48 && $localizeDigits(digits, zeroChar);
   $insert(digits, 0, isNegative?this$static.negativePrefix:this$static.positivePrefix);
   $append(digits, isNegative?this$static.negativeSuffix:this$static.positiveSuffix);
 }

Character.digit is often only called with radix of 10 - knowing that this is a constant lets the compiler now rewrite away the Math.min() call

public static int digit(char c, int radix) {
if (radix < MIN_RADIX || radix > MAX_RADIX) {
return -1;
}
if (c >= '0' && c < '0' + Math.min(radix, 10)) {
return c - '0';
}

 function digit(c){
-  if (c >= 48 && c < 48 + $wnd.Math.min(10, 10)) {
+  if (c >= 48 && c < 58) {
     return c - 48;
   }
   if (c >= 97 && c < 97) {
     return c - 97 + 10;
   }

MultiWordSuggestOracle's constructor takes a string whitespaceChars and loops through it, but defaults to " " - the length of this can be statically computed.

public MultiWordSuggestOracle(String whitespaceChars) {
this.whitespaceChars = new char[whitespaceChars.length()];
for (int i = 0; i < whitespaceChars.length(); i++) {
this.whitespaceChars[i] = whitespaceChars.charAt(i);
}
}

The critical check for the inlined charAt(i) with a variable as a param can't be validated automatically - but with range checks or unrolling the loop that could go away in the future.

   this.emptyResponse = new SuggestOracle$Response(new ArrayList);
   this.tree = new PrefixTree;
   this.toCandidates = new HashMap;
   this.toRealSuggestions = new HashMap;
-  this.whitespaceChars = initUnidimensionalArray(C_classLit, {3:1}, 52, ' '.length, 15, 1);
-  for (i = 0; i < ' '.length; i++) {
+  this.whitespaceChars = initUnidimensionalArray(C_classLit, {3:1}, 52, 1, 15, 1);
+  for (i = 0; i < 1; i++) {
     this.whitespaceChars[i] = (checkCriticalStringElementIndex(i, ' '.length) , ' '.charCodeAt(i));
   }
 }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing compile-time constant folding operations

1 participant