[JavaScript Debugger] Reduce allocations during source map parsing

According to the benchmark (tested on the vscode [source map](https://github.com/jridgewell/trace-mapping/tree/main/benchmark)) it allows to reduce allocation rate to ~25% from the size of the source map (11/43 megabytes)

Merge-request: IJ-MR-156766
Merged-by: Shumaf Lovpache <soarex16@gmail.com>
(cherry picked from commit 53150bcb4920dbb41defa90c72ced23a0e78a8fd)

IJ-CR-157267

GitOrigin-RevId: 7aa01a1cdec7d05cf23fd206e02bf10223e0b672
This commit is contained in:
Shumaf Lovpache
2025-05-14 19:33:17 +00:00
committed by intellij-monorepo-bot
parent 9edc483a5d
commit a3c4587b26
2 changed files with 34 additions and 19 deletions
@@ -17490,6 +17490,8 @@ f:org.jetbrains.io.JsonReaderEx
- lenient(Z):org.jetbrains.io.JsonReaderEx
- nextAsString():java.lang.String
- nextBoolean():Z
- nextCharSequence():java.lang.CharSequence
- nextCharSequence(Z):java.lang.CharSequence
- nextDouble():D
- nextInt():I
- nextLong():J
@@ -71,7 +71,7 @@ public final class JsonReaderEx implements Closeable {
* This is populated before a numeric value is parsed and used if that parsing
* fails.
*/
private String peekedString;
private CharSequence peekedString;
/*
* The nesting stack. Using a manual array rather than an ArrayList saves 20%.
@@ -672,13 +672,13 @@ public final class JsonReaderEx implements Closeable {
}
String result;
if (p == PEEKED_UNQUOTED_NAME) {
result = nextUnquotedValue();
result = nextUnquotedValue().toString();
}
else if (p == PEEKED_SINGLE_QUOTED_NAME) {
result = nextQuotedValue('\'');
result = nextQuotedValue('\'').toString();
}
else if (p == PEEKED_DOUBLE_QUOTED_NAME) {
result = nextQuotedValue('"');
result = nextQuotedValue('"').toString();
}
else {
if (p != PEEKED_END_OBJECT && p != PEEKED_END_ARRAY) {
@@ -713,20 +713,33 @@ public final class JsonReaderEx implements Closeable {
return nextString(false);
}
public String nextString(boolean anyPrimitiveAsString) {
return nextCharSequence(anyPrimitiveAsString).toString();
}
public CharSequence nextCharSequence() {
return nextCharSequence(false);
}
/**
* Returns the {@link JsonToken#STRING string} value of the next token,
* consuming it. If the next token is a number, this method will return its
* string form.
* <p>
* Depending on the implementation of {@link CharSequence} for the {@link JsonReaderEx#sourceSequence}
* (and the input data, of course), this method can be more efficient,
* avoiding unnecessary allocations. This may be useful when the source JSON
* contains very long strings that are immediately transformed after parsing.
*
* @throws IllegalStateException if the next token is not a string or if
* this reader is closed.
*/
public String nextString(boolean anyPrimitiveAsString) {
public CharSequence nextCharSequence(boolean anyPrimitiveAsString) {
int p = peeked;
if (p == PEEKED_NONE) {
p = doPeek();
}
String result;
CharSequence result;
if (p == PEEKED_UNQUOTED) {
result = nextUnquotedValue();
}
@@ -829,7 +842,7 @@ public final class JsonReaderEx implements Closeable {
if (p == PEEKED_NUMBER) {
int end = position + peekedNumberLength;
peekedString = sourceSequence.subSequence(position, end).toString();
peekedString = sourceSequence.subSequence(position, end);
position = end;
}
else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED) {
@@ -843,7 +856,7 @@ public final class JsonReaderEx implements Closeable {
}
peeked = PEEKED_BUFFERED;
double result = Double.parseDouble(peekedString); // don't catch this NumberFormatException.
double result = Double.parseDouble(peekedString.toString()); // don't catch this NumberFormatException.
if (!lenient && (Double.isNaN(result) || Double.isInfinite(result))) {
throw createParseError("JSON forbids NaN and infinities: " + result);
}
@@ -875,13 +888,13 @@ public final class JsonReaderEx implements Closeable {
if (p == PEEKED_NUMBER) {
int end = position + peekedNumberLength;
peekedString = sourceSequence.subSequence(position, end).toString();
peekedString = sourceSequence.subSequence(position, end);
position = end;
}
else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED) {
peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\'' : '"');
peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\'' : '"').toString();
try {
long result = Long.parseLong(peekedString);
long result = Long.parseLong(peekedString.toString());
peeked = PEEKED_NONE;
return result;
}
@@ -894,7 +907,7 @@ public final class JsonReaderEx implements Closeable {
}
peeked = PEEKED_BUFFERED;
double asDouble = Double.parseDouble(peekedString); // don't catch this NumberFormatException.
double asDouble = Double.parseDouble(peekedString.toString()); // don't catch this NumberFormatException.
long result = (long)asDouble;
if (result != asDouble) { // Make sure no precision was lost casting to 'long'.
throw new NumberFormatException("Expected a long but was " + peekedString
@@ -915,7 +928,7 @@ public final class JsonReaderEx implements Closeable {
* @throws NumberFormatException if any unicode escape sequences are
* malformed.
*/
private String nextQuotedValue(char quote) {
private CharSequence nextQuotedValue(char quote) {
// Like nextNonWhitespace, this uses locals 'p' and 'l' to save inner-loop field access.
CharSequence in = this.sourceSequence;
@@ -929,7 +942,7 @@ public final class JsonReaderEx implements Closeable {
if (c == quote) {
position = p;
if (builder == null) {
return in.subSequence(start, p - 1).toString();
return in.subSequence(start, p - 1);
}
else {
return builder.append(in, start, p - 1).toString();
@@ -964,7 +977,7 @@ public final class JsonReaderEx implements Closeable {
/**
* Returns an unquoted value as a string.
*/
private String nextUnquotedValue() {
private CharSequence nextUnquotedValue() {
int i = position;
findNonLiteralCharacter:
for (; i < limit; i++) {
@@ -990,7 +1003,7 @@ public final class JsonReaderEx implements Closeable {
}
}
String result = sourceSequence.subSequence(position, i).toString();
CharSequence result = sourceSequence.subSequence(position, i);
position = i;
return result;
}
@@ -1079,13 +1092,13 @@ public final class JsonReaderEx implements Closeable {
if (p == PEEKED_NUMBER) {
int end = position + peekedNumberLength;
peekedString = sourceSequence.subSequence(position, end).toString();
peekedString = sourceSequence.subSequence(position, end);
position = end;
}
else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED) {
peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\'' : '"');
try {
result = Integer.parseInt(peekedString);
result = Integer.parseInt(peekedString.toString());
peeked = PEEKED_NONE;
return result;
}
@@ -1098,7 +1111,7 @@ public final class JsonReaderEx implements Closeable {
}
peeked = PEEKED_BUFFERED;
double asDouble = Double.parseDouble(peekedString); // don't catch this NumberFormatException.
double asDouble = Double.parseDouble(peekedString.toString()); // don't catch this NumberFormatException.
result = (int)asDouble;
if (result != asDouble) { // Make sure no precision was lost casting to 'int'.
throw new NumberFormatException("Expected an int but was " + peekedString