Simplify HpackHuffmanDecoder table decode logic (#9335)

Motivation

The nice change made by @carl-mastrangelo in #9307 for lookup-table
based HPACK Huffman decoding can be simplified a little to remove the
separate flags field and eliminate some intermediate operations.

Modification

Simplify HpackHuffmanDecoder::decode logic including de-dup of the
per-nibble part.

Result

Less code, possibly better performance though not noticeable in a quick
benchmark.
This commit is contained in:
Nick Hill 2019-07-08 03:04:20 -07:00 committed by Norman Maurer
parent db8dd66f09
commit 91d6e0ea8f

View File

@ -46,9 +46,9 @@ final class HpackHuffmanDecoder implements ByteProcessor {
private static final byte HUFFMAN_EMIT_SYMBOL = 1 << 1; private static final byte HUFFMAN_EMIT_SYMBOL = 1 << 1;
private static final byte HUFFMAN_FAIL = 1 << 2; private static final byte HUFFMAN_FAIL = 1 << 2;
private static final int HUFFMAN_COMPLETE_SHIFT = 1 << 8; private static final int HUFFMAN_COMPLETE_SHIFT = HUFFMAN_COMPLETE << 8;
private static final int HUFFMAN_EMIT_SYMBOL_SHIFT = 1 << 9; private static final int HUFFMAN_EMIT_SYMBOL_SHIFT = HUFFMAN_EMIT_SYMBOL << 8;
private static final int HUFFMAN_FAIL_SHIFT = 1 << 10; private static final int HUFFMAN_FAIL_SHIFT = HUFFMAN_FAIL << 8;
/** /**
* A table of byte tuples (state, flags, output). They are packed together as: * A table of byte tuples (state, flags, output). They are packed together as:
@ -4672,7 +4672,6 @@ final class HpackHuffmanDecoder implements ByteProcessor {
private byte[] dest; private byte[] dest;
private int k; private int k;
private int state; private int state;
private int flags;
HpackHuffmanDecoder() { } HpackHuffmanDecoder() { }
@ -4696,7 +4695,7 @@ final class HpackHuffmanDecoder implements ByteProcessor {
if (endIndex == -1) { if (endIndex == -1) {
// We did consume the requested length // We did consume the requested length
buf.readerIndex(readerIndex + length); buf.readerIndex(readerIndex + length);
if ((flags & HUFFMAN_COMPLETE_SHIFT) != HUFFMAN_COMPLETE_SHIFT) { if ((state & HUFFMAN_COMPLETE_SHIFT) != HUFFMAN_COMPLETE_SHIFT) {
throw BAD_ENCODING; throw BAD_ENCODING;
} }
return new AsciiString(dest, 0, k, false); return new AsciiString(dest, 0, k, false);
@ -4710,7 +4709,6 @@ final class HpackHuffmanDecoder implements ByteProcessor {
dest = null; dest = null;
k = 0; k = 0;
state = 0; state = 0;
flags = 0;
} }
} }
@ -4719,27 +4717,21 @@ final class HpackHuffmanDecoder implements ByteProcessor {
*/ */
@Override @Override
public boolean process(byte input) { public boolean process(byte input) {
int index = (state << 4) | ((input & 0xFF) >>> 4); return processNibble(input >> 4) && processNibble(input);
int row = HUFFS[index]; }
flags = row & 0x00FF00;
if ((flags & HUFFMAN_FAIL_SHIFT) != 0) {
return false;
}
if ((flags & HUFFMAN_EMIT_SYMBOL_SHIFT) != 0) {
dest[k++] = (byte) (row & 0xFF);
}
state = row >> 16;
index = (state << 4) | (input & 0x0F); private boolean processNibble(int input) {
row = HUFFS[index]; // The high nibble of the flags byte of each row is always zero
flags = row & 0x00FF00; // (low nibble after shifting row by 12), since there are only 3 flag bits
if ((flags & HUFFMAN_FAIL_SHIFT) != 0) { int index = state >> 12 | (input & 0x0F);
state = HUFFS[index];
if ((state & HUFFMAN_FAIL_SHIFT) != 0) {
return false; return false;
} }
if ((flags & HUFFMAN_EMIT_SYMBOL_SHIFT) != 0) { if ((state & HUFFMAN_EMIT_SYMBOL_SHIFT) != 0) {
dest[k++] = (byte) (row & 0xFF); // state is always positive so can cast without mask here
dest[k++] = (byte) state;
} }
state = row >> 16;
return true; return true;
} }
} }