Skip to content
Open
Show file tree
Hide file tree
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
95 changes: 67 additions & 28 deletions cbor/src/main/java/tools/jackson/dataformat/cbor/CBORParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,29 @@ public int getFirstTag() {
protected final static JacksonFeatureSet<StreamReadCapability> CBOR_READ_CAPABILITIES =
DEFAULT_READ_CAPABILITIES.with(StreamReadCapability.EXACT_FLOATS);

/**
* Whether VarHandles are usable on this runtime; probed once at class load.
* Being {@code static final} lets the branches in {@link #_decode32Bits()},
* {@link #_decode64Bits()} and {@link #_decodeQuad} fold away at JIT time.
*
* @since 3.3
*/
private final static boolean _VARHANDLE_AVAILABLE = _checkVarHandleAvailable();

private static boolean _checkVarHandleAvailable() {
// NOTE: this call is what first loads `CBORVarHandleUtil`, and that class
// names `VarHandle` in its field/method signatures. On a runtime lacking
// `java.lang.invoke.VarHandle` (some Android builds) loading it raises
// `NoClassDefFoundError` -- an Error, not an Exception -- so `Throwable`
// is what has to be caught here. Without this guard the failure would
// propagate out of this class's initializer and make the parser unusable.
try {
return CBORVarHandleUtil.isAvailable();
} catch (Throwable t) {
return false;
}
}

/*
/**********************************************************************
/* Configuration
Expand Down Expand Up @@ -1566,10 +1589,8 @@ private final int _nextFieldOptimized(PropertyNameMatcher matcher, final int len
int inPtr = _inputPtr;

// First quadbyte is easy
int q1 = (inBuf[inPtr++] & 0xFF);
q1 = (q1 << 8) | (inBuf[inPtr++] & 0xFF);
q1 = (q1 << 8) | (inBuf[inPtr++] & 0xFF);
q1 = (q1 << 8) | (inBuf[inPtr++] & 0xFF);
int q1 = _decodeQuad(inBuf, inPtr);
inPtr += 4;

if (len < 9) {
int q2 = (inBuf[inPtr++] & 0xFF);
Expand All @@ -1588,10 +1609,8 @@ private final int _nextFieldOptimized(PropertyNameMatcher matcher, final int len
return matcher.matchByQuad(q1, q2);
}

int q2 = (inBuf[inPtr++] & 0xFF);
q2 = (q2 << 8) | (inBuf[inPtr++] & 0xFF);
q2 = (q2 << 8) | (inBuf[inPtr++] & 0xFF);
q2 = (q2 << 8) | (inBuf[inPtr++] & 0xFF);
int q2 = _decodeQuad(inBuf, inPtr);
inPtr += 4;

if (len < 13) {
int q3 = (inBuf[inPtr++] & 0xFF);
Expand Down Expand Up @@ -1636,11 +1655,8 @@ private final int _nextFieldFromSymbolsLong(PropertyNameMatcher matcher,

final byte[] inBuf = _inputBuffer;
do {
int q = (inBuf[inPtr++] & 0xFF);
q = (q << 8) | inBuf[inPtr++] & 0xFF;
q = (q << 8) | inBuf[inPtr++] & 0xFF;
q = (q << 8) | inBuf[inPtr++] & 0xFF;
_quadBuffer[offset++] = q;
_quadBuffer[offset++] = _decodeQuad(inBuf, inPtr);
inPtr += 4;
} while ((len -= 4) > 3);
// and then leftovers
if (len > 0) {
Expand Down Expand Up @@ -3362,10 +3378,8 @@ private final String _findDecodedFromSymbols(final int len) throws JacksonExcept
int inPtr = _inputPtr;

// First quadbyte is easy
int q1 = (inBuf[inPtr++] & 0xFF);
q1 = (q1 << 8) | (inBuf[inPtr++] & 0xFF);
q1 = (q1 << 8) | (inBuf[inPtr++] & 0xFF);
q1 = (q1 << 8) | (inBuf[inPtr++] & 0xFF);
int q1 = _decodeQuad(inBuf, inPtr);
inPtr += 4;

if (len < 9) {
int q2 = _padQuadForNulls(inBuf[inPtr++]);
Expand All @@ -3384,10 +3398,8 @@ private final String _findDecodedFromSymbols(final int len) throws JacksonExcept
return _symbols.findName(q1, q2);
}

int q2 = (inBuf[inPtr++] & 0xFF);
q2 = (q2 << 8) | (inBuf[inPtr++] & 0xFF);
q2 = (q2 << 8) | (inBuf[inPtr++] & 0xFF);
q2 = (q2 << 8) | (inBuf[inPtr++] & 0xFF);
int q2 = _decodeQuad(inBuf, inPtr);
inPtr += 4;

if (len < 13) {
int q3 = _padQuadForNulls(inBuf[inPtr++]);
Expand Down Expand Up @@ -3434,11 +3446,8 @@ private final String _findDecodedLong(int len, int q1, int q2) throws JacksonExc

final byte[] inBuf = _inputBuffer;
do {
int q = (inBuf[inPtr++] & 0xFF);
q = (q << 8) | inBuf[inPtr++] & 0xFF;
q = (q << 8) | inBuf[inPtr++] & 0xFF;
q = (q << 8) | inBuf[inPtr++] & 0xFF;
_quadBuffer[offset++] = q;
_quadBuffer[offset++] = _decodeQuad(inBuf, inPtr);
inPtr += 4;
} while ((len -= 4) > 3);
// and then leftovers
if (len > 0) {
Expand Down Expand Up @@ -3484,6 +3493,23 @@ private final static int _padQuadForNulls(int firstByte) {
return (firstByte & 0xFF) | 0xFFFFFF00;
}

/**
* Helper method for decoding 4 bytes of an Object property name into the
* "quad" (big-endian {@code int}) form used by {@code ByteQuadsCanonicalizer}.
* Caller MUST have verified that 4 bytes are readable at given offset.
*
* @since 3.3
*/
private final static int _decodeQuad(byte[] buffer, int offset) {
if (_VARHANDLE_AVAILABLE) {
return CBORVarHandleUtil.getInt(buffer, offset);
}
return ((buffer[offset] & 0xFF) << 24)
| ((buffer[offset+1] & 0xFF) << 16)
| ((buffer[offset+2] & 0xFF) << 8)
| (buffer[offset+3] & 0xFF);
}

/*
/**********************************************************************
/* Internal methods, skipping
Expand Down Expand Up @@ -3776,8 +3802,14 @@ private final int _decode32Bits() throws JacksonException {
return _slow32();
}
final byte[] b = _inputBuffer;
int v = (b[ptr++] << 24) + ((b[ptr++] & 0xFF) << 16)
+ ((b[ptr++] & 0xFF) << 8) + (b[ptr++] & 0xFF);
final int v;
if (_VARHANDLE_AVAILABLE) {
v = CBORVarHandleUtil.getInt(b, ptr);
ptr += 4;
} else {
v = (b[ptr++] << 24) + ((b[ptr++] & 0xFF) << 16)
+ ((b[ptr++] & 0xFF) << 8) + (b[ptr++] & 0xFF);
}
_inputPtr = ptr;
return v;
}
Expand Down Expand Up @@ -3807,6 +3839,13 @@ private final long _decode64Bits() throws JacksonException {
return _slow64();
}
final byte[] b = _inputBuffer;
if (_VARHANDLE_AVAILABLE) {
// NOTE: identical to `_long()` of the two 32-bit halves below, since
// that is just a big-endian 8-byte read spelled out
final long l = CBORVarHandleUtil.getLong(b, ptr);
_inputPtr = ptr + 8;
return l;
}
int i1 = (b[ptr++] << 24) + ((b[ptr++] & 0xFF) << 16)
+ ((b[ptr++] & 0xFF) << 8) + (b[ptr++] & 0xFF);
int i2 = (b[ptr++] << 24) + ((b[ptr++] & 0xFF) << 16)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ static boolean isAvailable() {
return LONG_BE != null;
}

// Helper methods that write primitives via the class's own VarHandle fields.
// Only called when the corresponding field is non-null, which implies
// Helper methods that read/write primitives via the class's own VarHandle
// fields. Only called when the corresponding field is non-null, which implies
// VarHandle is available on this runtime.

static void setInt(byte[] array, int offset, int value) {
Expand All @@ -62,4 +62,24 @@ static void setInt(byte[] array, int offset, int value) {
static void setLong(byte[] array, int offset, long value) {
LONG_BE.set(array, offset, value);
}

/**
* Reads 4 bytes at given offset as a big-endian {@code int}; caller MUST
* have verified that {@code offset+4} is within bounds of given array.
*
* @since 3.3
*/
static int getInt(byte[] array, int offset) {
return (int) INT_BE.get(array, offset);
}

/**
* Reads 8 bytes at given offset as a big-endian {@code long}; caller MUST
* have verified that {@code offset+8} is within bounds of given array.
*
* @since 3.3
*/
static long getLong(byte[] array, int offset) {
return (long) LONG_BE.get(array, offset);
}
}