Skip to content

use String constructor directly for short ascii values #344

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 21, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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