Skip to content

Commit

Permalink
Use String constructor directly for short ascii values on JDK 11+ (#344)
Browse files Browse the repository at this point in the history
  • Loading branch information
brharrington authored Nov 21, 2022
1 parent 7666dba commit 3a6fec9
Showing 1 changed file with 98 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

import com.fasterxml.jackson.core.*;
Expand Down Expand Up @@ -56,6 +57,24 @@ private Feature(boolean defaultState) {
@Override public boolean enabledIn(int flags) { return (flags & getMask()) != 0; }
}

/**
* Flag to indicate if the JDK version is 11 or later. This can be used in some methods
* to choose more optimal behavior. In particular, jdk9+ have different internals for
* the String class.
*/
private static final boolean JDK11_OR_LATER;
static {
boolean recentJdk;
try {
// The strip method was added in jdk11, so use it to detect a newer version
String.class.getMethod("strip");
recentJdk = true;
} catch (Exception e) {
recentJdk = false;
}
JDK11_OR_LATER = recentJdk;
}

/*
/**********************************************************
/* Configuration
Expand Down Expand Up @@ -1538,36 +1557,46 @@ private final String _decodeShortAsciiName(int len) throws IOException
{
// note: caller ensures we have enough bytes available
// also note that since it's a short name (64 bytes), segment WILL have enough space
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
int outPtr = 0;
final byte[] inBuf = _inputBuffer;
int inPtr = _inputPtr;
if (JDK11_OR_LATER) {
// On newer JDKs the String internals changed and for ASCII strings the constructor
// that takes a byte array can be used and internally is just Arrays.copyOfRange.
final int inPtr = _inputPtr;
_inputPtr = inPtr + len;
String str = new String(_inputBuffer, inPtr, len, StandardCharsets.US_ASCII);
_textBuffer.resetWithString(str);
return str;
} else {
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
int outPtr = 0;
final byte[] inBuf = _inputBuffer;
int inPtr = _inputPtr;

// 29-Mar-2021, tatu: Still true with Java 8 / Jackson 2.13: unrolling
// does NOT appear to help here (no change, for jvm-benchmarks test,
// probably since most of the time symbol table lookup is used
/*
for (int inEnd = inPtr + len - 3; inPtr < inEnd; ) {
outBuf[outPtr++] = (char) inBuf[inPtr++];
outBuf[outPtr++] = (char) inBuf[inPtr++];
outBuf[outPtr++] = (char) inBuf[inPtr++];
outBuf[outPtr++] = (char) inBuf[inPtr++];
}
switch (len & 3) {
case 3:
outBuf[outPtr++] = (char) inBuf[inPtr++];
case 2:
outBuf[outPtr++] = (char) inBuf[inPtr++];
case 1:
outBuf[outPtr++] = (char) inBuf[inPtr++];
case 0:
}
*/
for (int inEnd = inPtr + len; inPtr < inEnd; ++inPtr) {
outBuf[outPtr++] = (char) inBuf[inPtr];
}
_inputPtr = inPtr;
return _textBuffer.setCurrentAndReturn(len);
// 29-Mar-2021, tatu: Still true with Java 8 / Jackson 2.13: unrolling
// does NOT appear to help here (no change, for jvm-benchmarks test,
// probably since most of the time symbol table lookup is used
/*
for (int inEnd = inPtr + len - 3; inPtr < inEnd; ) {
outBuf[outPtr++] = (char) inBuf[inPtr++];
outBuf[outPtr++] = (char) inBuf[inPtr++];
outBuf[outPtr++] = (char) inBuf[inPtr++];
outBuf[outPtr++] = (char) inBuf[inPtr++];
}
switch (len & 3) {
case 3:
outBuf[outPtr++] = (char) inBuf[inPtr++];
case 2:
outBuf[outPtr++] = (char) inBuf[inPtr++];
case 1:
outBuf[outPtr++] = (char) inBuf[inPtr++];
case 0:
}
*/
for (int inEnd = inPtr + len; inPtr < inEnd; ++inPtr) {
outBuf[outPtr++] = (char) inBuf[inPtr];
}
_inputPtr = inPtr;
return _textBuffer.setCurrentAndReturn(len);
}
}

/**
Expand Down Expand Up @@ -2398,36 +2427,47 @@ protected final String _decodeShortAsciiValue(int len) throws IOException
if ((_inputEnd - _inputPtr) < len) {
_loadToHaveAtLeast(len);
}
// Note: we count on fact that buffer must have at least 'len' (<= 64) empty char slots
final char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
int outPtr = 0;
final byte[] inBuf = _inputBuffer;
int inPtr = _inputPtr;

// 29-Mar-2021, tatu: Still true with Java 8 / Jackson 2.13: unrolling
// does NOT appear to help here -- slows things down by 5% (for one test)
/*
for (int inEnd = inPtr + len - 3; inPtr < inEnd; ) {
outBuf[outPtr++] = (char) inBuf[inPtr++];
outBuf[outPtr++] = (char) inBuf[inPtr++];
outBuf[outPtr++] = (char) inBuf[inPtr++];
outBuf[outPtr++] = (char) inBuf[inPtr++];
}
switch (len & 3) {
case 3:
outBuf[outPtr++] = (char) inBuf[inPtr++];
case 2:
outBuf[outPtr++] = (char) inBuf[inPtr++];
case 1:
outBuf[outPtr++] = (char) inBuf[inPtr++];
case 0:
}*/

for (final int end = inPtr + len; inPtr < end; ++inPtr) {
outBuf[outPtr++] = (char) inBuf[inPtr];
}
_inputPtr = inPtr;
return _textBuffer.setCurrentAndReturn(len);
if (JDK11_OR_LATER) {
// On newer JDKs the String internals changed and for ASCII strings the constructor
// that takes a byte array can be used and internally is just Arrays.copyOfRange.
final int inPtr = _inputPtr;
_inputPtr = inPtr + len;
String str = new String(_inputBuffer, inPtr, len, StandardCharsets.US_ASCII);
_textBuffer.resetWithString(str);
return str;
} else {
// Note: we count on fact that buffer must have at least 'len' (<= 64) empty char slots
final char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
int outPtr = 0;
final byte[] inBuf = _inputBuffer;
int inPtr = _inputPtr;

// 29-Mar-2021, tatu: Still true with Java 8 / Jackson 2.13: unrolling
// does NOT appear to help here -- slows things down by 5% (for one test)
/*
for (int inEnd = inPtr + len - 3; inPtr < inEnd; ) {
outBuf[outPtr++] = (char) inBuf[inPtr++];
outBuf[outPtr++] = (char) inBuf[inPtr++];
outBuf[outPtr++] = (char) inBuf[inPtr++];
outBuf[outPtr++] = (char) inBuf[inPtr++];
}
switch (len & 3) {
case 3:
outBuf[outPtr++] = (char) inBuf[inPtr++];
case 2:
outBuf[outPtr++] = (char) inBuf[inPtr++];
case 1:
outBuf[outPtr++] = (char) inBuf[inPtr++];
case 0:
}*/

for (final int end = inPtr + len; inPtr < end; ++inPtr) {
outBuf[outPtr++] = (char) inBuf[inPtr];
}
_inputPtr = inPtr;
return _textBuffer.setCurrentAndReturn(len);
}
}

protected final String _decodeShortUnicodeValue(final int byteLen) throws IOException
Expand Down

0 comments on commit 3a6fec9

Please sign in to comment.