mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8213035: Pack MethodHandleInlineStrategy coder and length into a long
Reviewed-by: vlivanov, mchung
This commit is contained in:
parent
4b27547977
commit
91a2c2e340
2 changed files with 174 additions and 194 deletions
|
@ -37,119 +37,104 @@ final class StringConcatHelper {
|
|||
}
|
||||
|
||||
/**
|
||||
* Check for overflow, throw the exception on overflow.
|
||||
* @param len String length
|
||||
* @return length
|
||||
* Check for overflow, throw exception on overflow.
|
||||
* @param lengthCoder String length and coder
|
||||
* @return lengthCoder
|
||||
*/
|
||||
private static int checkOverflow(int len) {
|
||||
if (len < 0) {
|
||||
throw new OutOfMemoryError("Overflow: String length out of range");
|
||||
private static long checkOverflow(long lengthCoder) {
|
||||
if ((int)lengthCoder >= 0) {
|
||||
return lengthCoder;
|
||||
}
|
||||
return len;
|
||||
throw new OutOfMemoryError("Overflow: String length out of range");
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix value length into current length
|
||||
* Mix value length and coder into current length and coder.
|
||||
* @param current current length
|
||||
* @param value value to mix in
|
||||
* @return new length
|
||||
* @return new length and coder
|
||||
*/
|
||||
static int mixLen(int current, boolean value) {
|
||||
static long mix(long current, boolean value) {
|
||||
return checkOverflow(current + (value ? 4 : 5));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix value length into current length
|
||||
* Mix value length and coder into current length and coder.
|
||||
* @param current current length
|
||||
* @param value value to mix in
|
||||
* @return new length
|
||||
* @return new length and coder
|
||||
*/
|
||||
static int mixLen(int current, byte value) {
|
||||
return mixLen(current, (int)value);
|
||||
static long mix(long current, byte value) {
|
||||
return mix(current, (int)value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix value length into current length
|
||||
* Mix value length and coder into current length and coder.
|
||||
* @param current current length
|
||||
* @param value value to mix in
|
||||
* @return new length
|
||||
* @return new length and coder
|
||||
*/
|
||||
static int mixLen(int current, char value) {
|
||||
return checkOverflow(current + 1);
|
||||
static long mix(long current, char value) {
|
||||
return checkOverflow(current + 1) | (StringLatin1.canEncode(value) ? 0 : UTF16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix value length into current length
|
||||
* Mix value length and coder into current length and coder.
|
||||
* @param current current length
|
||||
* @param value value to mix in
|
||||
* @return new length
|
||||
* @return new length and coder
|
||||
*/
|
||||
static int mixLen(int current, short value) {
|
||||
return mixLen(current, (int)value);
|
||||
static long mix(long current, short value) {
|
||||
return mix(current, (int)value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix value length into current length
|
||||
* Mix value length and coder into current length and coder.
|
||||
* @param current current length
|
||||
* @param value value to mix in
|
||||
* @return new length
|
||||
* @return new length and coder
|
||||
*/
|
||||
static int mixLen(int current, int value) {
|
||||
static long mix(long current, int value) {
|
||||
return checkOverflow(current + Integer.stringSize(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix value length into current length
|
||||
* Mix value length and coder into current length and coder.
|
||||
* @param current current length
|
||||
* @param value value to mix in
|
||||
* @return new length
|
||||
* @return new length and coder
|
||||
*/
|
||||
static int mixLen(int current, long value) {
|
||||
static long mix(long current, long value) {
|
||||
return checkOverflow(current + Long.stringSize(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix value length into current length
|
||||
* Mix value length and coder into current length and coder.
|
||||
* @param current current length
|
||||
* @param value value to mix in
|
||||
* @return new length
|
||||
* @return new length and coder
|
||||
*/
|
||||
static int mixLen(int current, String value) {
|
||||
return checkOverflow(current + value.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix coder into current coder
|
||||
* @param current current coder
|
||||
* @param value value to mix in
|
||||
* @return new coder
|
||||
*/
|
||||
static byte mixCoder(byte current, char value) {
|
||||
return (byte)(current | (StringLatin1.canEncode(value) ? 0 : 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix coder into current coder
|
||||
* @param current current coder
|
||||
* @param value value to mix in
|
||||
* @return new coder
|
||||
*/
|
||||
static byte mixCoder(byte current, String value) {
|
||||
return (byte)(current | value.coder());
|
||||
static long mix(long current, String value) {
|
||||
current += value.length();
|
||||
if (value.coder() == String.UTF16) {
|
||||
current |= UTF16;
|
||||
}
|
||||
return checkOverflow(current);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends the stringly representation of boolean value into buffer,
|
||||
* given the coder and final index. Index is measured in chars, not in bytes!
|
||||
*
|
||||
* @param index final char index in the buffer
|
||||
* @param buf buffer to append to
|
||||
* @param coder coder to add with
|
||||
* @param value boolean value to encode
|
||||
* @return new index
|
||||
* @param indexCoder final char index in the buffer, along with coder packed
|
||||
* into higher bits.
|
||||
* @param buf buffer to append to
|
||||
* @param value boolean value to encode
|
||||
* @return updated index (coder value retained)
|
||||
*/
|
||||
static int prepend(int index, byte[] buf, byte coder, boolean value) {
|
||||
if (coder == String.LATIN1) {
|
||||
static long prepend(long indexCoder, byte[] buf, boolean value) {
|
||||
int index = (int)indexCoder;
|
||||
if (indexCoder < UTF16) {
|
||||
if (value) {
|
||||
buf[--index] = 'e';
|
||||
buf[--index] = 'u';
|
||||
|
@ -162,6 +147,7 @@ final class StringConcatHelper {
|
|||
buf[--index] = 'a';
|
||||
buf[--index] = 'f';
|
||||
}
|
||||
return index;
|
||||
} else {
|
||||
if (value) {
|
||||
StringUTF16.putChar(buf, --index, 'e');
|
||||
|
@ -175,72 +161,72 @@ final class StringConcatHelper {
|
|||
StringUTF16.putChar(buf, --index, 'a');
|
||||
StringUTF16.putChar(buf, --index, 'f');
|
||||
}
|
||||
return index | UTF16;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends the stringly representation of byte value into buffer,
|
||||
* given the coder and final index. Index is measured in chars, not in bytes!
|
||||
*
|
||||
* @param index final char index in the buffer
|
||||
* @param buf buffer to append to
|
||||
* @param coder coder to add with
|
||||
* @param value byte value to encode
|
||||
* @return new index
|
||||
* @param indexCoder final char index in the buffer, along with coder packed
|
||||
* into higher bits.
|
||||
* @param buf buffer to append to
|
||||
* @param value byte value to encode
|
||||
* @return updated index (coder value retained)
|
||||
*/
|
||||
static int prepend(int index, byte[] buf, byte coder, byte value) {
|
||||
return prepend(index, buf, coder, (int)value);
|
||||
static long prepend(long indexCoder, byte[] buf, byte value) {
|
||||
return prepend(indexCoder, buf, (int)value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends the stringly representation of char value into buffer,
|
||||
* given the coder and final index. Index is measured in chars, not in bytes!
|
||||
*
|
||||
* @param index final char index in the buffer
|
||||
* @param buf buffer to append to
|
||||
* @param coder coder to add with
|
||||
* @param value char value to encode
|
||||
* @return new index
|
||||
* @param indexCoder final char index in the buffer, along with coder packed
|
||||
* into higher bits.
|
||||
* @param buf buffer to append to
|
||||
* @param value char value to encode
|
||||
* @return updated index (coder value retained)
|
||||
*/
|
||||
static int prepend(int index, byte[] buf, byte coder, char value) {
|
||||
if (coder == String.LATIN1) {
|
||||
buf[--index] = (byte) (value & 0xFF);
|
||||
static long prepend(long indexCoder, byte[] buf, char value) {
|
||||
if (indexCoder < UTF16) {
|
||||
buf[(int)(--indexCoder)] = (byte) (value & 0xFF);
|
||||
} else {
|
||||
StringUTF16.putChar(buf, --index, value);
|
||||
StringUTF16.putChar(buf, (int)(--indexCoder), value);
|
||||
}
|
||||
return index;
|
||||
return indexCoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends the stringly representation of short value into buffer,
|
||||
* given the coder and final index. Index is measured in chars, not in bytes!
|
||||
*
|
||||
* @param index final char index in the buffer
|
||||
* @param buf buffer to append to
|
||||
* @param coder coder to add with
|
||||
* @param value short value to encode
|
||||
* @return new index
|
||||
* @param indexCoder final char index in the buffer, along with coder packed
|
||||
* into higher bits.
|
||||
* @param buf buffer to append to
|
||||
* @param value short value to encode
|
||||
* @return updated index (coder value retained)
|
||||
*/
|
||||
static int prepend(int index, byte[] buf, byte coder, short value) {
|
||||
return prepend(index, buf, coder, (int)value);
|
||||
static long prepend(long indexCoder, byte[] buf, short value) {
|
||||
return prepend(indexCoder, buf, (int)value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends the stringly representation of integer value into buffer,
|
||||
* given the coder and final index. Index is measured in chars, not in bytes!
|
||||
*
|
||||
* @param index final char index in the buffer
|
||||
* @param buf buffer to append to
|
||||
* @param coder coder to add with
|
||||
* @param value integer value to encode
|
||||
* @return new index
|
||||
* @param indexCoder final char index in the buffer, along with coder packed
|
||||
* into higher bits.
|
||||
* @param buf buffer to append to
|
||||
* @param value integer value to encode
|
||||
* @return updated index (coder value retained)
|
||||
*/
|
||||
static int prepend(int index, byte[] buf, byte coder, int value) {
|
||||
if (coder == String.LATIN1) {
|
||||
return Integer.getChars(value, index, buf);
|
||||
static long prepend(long indexCoder, byte[] buf, int value) {
|
||||
if (indexCoder < UTF16) {
|
||||
return Integer.getChars(value, (int)indexCoder, buf);
|
||||
} else {
|
||||
return StringUTF16.getChars(value, index, buf);
|
||||
return StringUTF16.getChars(value, (int)indexCoder, buf) | UTF16;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -248,17 +234,17 @@ final class StringConcatHelper {
|
|||
* Prepends the stringly representation of long value into buffer,
|
||||
* given the coder and final index. Index is measured in chars, not in bytes!
|
||||
*
|
||||
* @param index final char index in the buffer
|
||||
* @param buf buffer to append to
|
||||
* @param coder coder to add with
|
||||
* @param value long value to encode
|
||||
* @return new index
|
||||
* @param indexCoder final char index in the buffer, along with coder packed
|
||||
* into higher bits.
|
||||
* @param buf buffer to append to
|
||||
* @param value long value to encode
|
||||
* @return updated index (coder value retained)
|
||||
*/
|
||||
static int prepend(int index, byte[] buf, byte coder, long value) {
|
||||
if (coder == String.LATIN1) {
|
||||
return Long.getChars(value, index, buf);
|
||||
static long prepend(long indexCoder, byte[] buf, long value) {
|
||||
if (indexCoder < UTF16) {
|
||||
return Long.getChars(value, (int)indexCoder, buf);
|
||||
} else {
|
||||
return StringUTF16.getChars(value, index, buf);
|
||||
return StringUTF16.getChars(value, (int)indexCoder, buf) | UTF16;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,39 +252,49 @@ final class StringConcatHelper {
|
|||
* Prepends the stringly representation of String value into buffer,
|
||||
* given the coder and final index. Index is measured in chars, not in bytes!
|
||||
*
|
||||
* @param index final char index in the buffer
|
||||
* @param buf buffer to append to
|
||||
* @param coder coder to add with
|
||||
* @param value String value to encode
|
||||
* @return new index
|
||||
* @param indexCoder final char index in the buffer, along with coder packed
|
||||
* into higher bits.
|
||||
* @param buf buffer to append to
|
||||
* @param value String value to encode
|
||||
* @return updated index (coder value retained)
|
||||
*/
|
||||
static int prepend(int index, byte[] buf, byte coder, String value) {
|
||||
index -= value.length();
|
||||
value.getBytes(buf, index, coder);
|
||||
return index;
|
||||
static long prepend(long indexCoder, byte[] buf, String value) {
|
||||
indexCoder -= value.length();
|
||||
if (indexCoder < UTF16) {
|
||||
value.getBytes(buf, (int)indexCoder, String.LATIN1);
|
||||
} else {
|
||||
value.getBytes(buf, (int)indexCoder, String.UTF16);
|
||||
}
|
||||
return indexCoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates the String with given buffer and coder
|
||||
* @param buf buffer to use
|
||||
* @param index remaining index
|
||||
* @param coder coder to use
|
||||
* @return String resulting string
|
||||
* @param buf buffer to use
|
||||
* @param indexCoder remaining index (should be zero) and coder
|
||||
* @return String resulting string
|
||||
*/
|
||||
static String newString(byte[] buf, int index, byte coder) {
|
||||
static String newString(byte[] buf, long indexCoder) {
|
||||
// Use the private, non-copying constructor (unsafe!)
|
||||
if (index != 0) {
|
||||
throw new InternalError("Storage is not completely initialized, " + index + " bytes left");
|
||||
if (indexCoder == LATIN1) {
|
||||
return new String(buf, String.LATIN1);
|
||||
} else if (indexCoder == UTF16) {
|
||||
return new String(buf, String.UTF16);
|
||||
} else {
|
||||
throw new InternalError("Storage is not completely initialized, " + (int)indexCoder + " bytes left");
|
||||
}
|
||||
return new String(buf, coder);
|
||||
}
|
||||
|
||||
private static final long LATIN1 = (long)String.LATIN1 << 32;
|
||||
|
||||
private static final long UTF16 = (long)String.UTF16 << 32;
|
||||
|
||||
/**
|
||||
* Provides the initial coder for the String.
|
||||
* @return initial coder
|
||||
* @return initial coder, adjusted into the upper half
|
||||
*/
|
||||
static byte initialCoder() {
|
||||
return String.COMPACT_STRINGS ? String.LATIN1 : String.UTF16;
|
||||
static long initialCoder() {
|
||||
return String.COMPACT_STRINGS ? LATIN1 : UTF16;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -317,6 +317,13 @@ public final class StringConcatFactory {
|
|||
return elements.equals(recipe.elements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Recipe{" +
|
||||
"elements=" + elements +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return elements.hashCode();
|
||||
|
@ -367,6 +374,15 @@ public final class StringConcatFactory {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RecipeElement{" +
|
||||
"value='" + value + '\'' +
|
||||
", argPos=" + argPos +
|
||||
", tag=" + tag +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int)tag;
|
||||
|
@ -1520,24 +1536,24 @@ public final class StringConcatFactory {
|
|||
}
|
||||
|
||||
// Start building the combinator tree. The tree "starts" with (<parameters>)String, and "finishes"
|
||||
// with the (int, byte[], byte)String in String helper. The combinators are assembled bottom-up,
|
||||
// which makes the code arguably hard to read.
|
||||
// with the (byte[], long)String shape to invoke newString in StringConcatHelper. The combinators are
|
||||
// assembled bottom-up, which makes the code arguably hard to read.
|
||||
|
||||
// Drop all remaining parameter types, leave only helper arguments:
|
||||
MethodHandle mh;
|
||||
|
||||
mh = MethodHandles.dropArguments(NEW_STRING, 3, ptypes);
|
||||
mh = MethodHandles.dropArguments(NEW_STRING, 2, ptypes);
|
||||
|
||||
// Mix in prependers. This happens when (byte[], int, byte) = (storage, index, coder) is already
|
||||
// known from the combinators below. We are assembling the string backwards, so "index" is the
|
||||
// *ending* index.
|
||||
// Mix in prependers. This happens when (byte[], long) = (storage, indexCoder) is already
|
||||
// known from the combinators below. We are assembling the string backwards, so the index coded
|
||||
// into indexCoder is the *ending* index.
|
||||
for (RecipeElement el : recipe.getElements()) {
|
||||
// Do the prepend, and put "new" index at index 1
|
||||
switch (el.getTag()) {
|
||||
case TAG_CONST: {
|
||||
MethodHandle prepender = MethodHandles.insertArguments(prepender(String.class), 3, el.getValue());
|
||||
MethodHandle prepender = MethodHandles.insertArguments(prepender(String.class), 2, el.getValue());
|
||||
mh = MethodHandles.filterArgumentsWithCombiner(mh, 1, prepender,
|
||||
1, 0, 2 // index, storage, coder
|
||||
1, 0 // indexCoder, storage
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
@ -1545,8 +1561,8 @@ public final class StringConcatFactory {
|
|||
int pos = el.getArgPos();
|
||||
MethodHandle prepender = prepender(ptypes[pos]);
|
||||
mh = MethodHandles.filterArgumentsWithCombiner(mh, 1, prepender,
|
||||
1, 0, 2, // index, storage, coder
|
||||
3 + pos // selected argument
|
||||
1, 0, // indexCoder, storage
|
||||
2 + pos // selected argument
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
@ -1557,7 +1573,7 @@ public final class StringConcatFactory {
|
|||
|
||||
// Fold in byte[] instantiation at argument 0
|
||||
mh = MethodHandles.foldArgumentsWithCombiner(mh, 0, NEW_ARRAY,
|
||||
1, 2 // index, coder
|
||||
1 // index
|
||||
);
|
||||
|
||||
// Start combining length and coder mixers.
|
||||
|
@ -1569,47 +1585,28 @@ public final class StringConcatFactory {
|
|||
// Coders are more interesting. Only Object, String and char arguments (and constants)
|
||||
// can have non-Latin1 encoding. It is easier to blindly convert constants to String,
|
||||
// and deduce the coder from there. Arguments would be either converted to Strings
|
||||
// during the initial filtering, or handled by primitive specializations in CODER_MIXERS.
|
||||
// during the initial filtering, or handled by specializations in MIXERS.
|
||||
//
|
||||
// The method handle shape before and after all length and coder mixers is:
|
||||
// (int, byte, <args>)String = ("index", "coder", <args>)
|
||||
byte initialCoder = INITIAL_CODER;
|
||||
int initialLen = 0; // initial length, in characters
|
||||
// The method handle shape before and after all mixers are combined in is:
|
||||
// (long, <args>)String = ("indexCoder", <args>)
|
||||
long initialLengthCoder = INITIAL_CODER;
|
||||
for (RecipeElement el : recipe.getElements()) {
|
||||
switch (el.getTag()) {
|
||||
case TAG_CONST:
|
||||
String constant = el.getValue();
|
||||
initialCoder = (byte) coderMixer(String.class).invoke(initialCoder, constant);
|
||||
initialLen += constant.length();
|
||||
initialLengthCoder = (long)mixer(String.class).invoke(initialLengthCoder, constant);
|
||||
break;
|
||||
case TAG_ARG:
|
||||
int ac = el.getArgPos();
|
||||
|
||||
Class<?> argClass = ptypes[ac];
|
||||
MethodHandle lm = lengthMixer(argClass);
|
||||
MethodHandle mix = mixer(argClass);
|
||||
|
||||
if (argClass.isPrimitive() && argClass != char.class) {
|
||||
// Compute new "index" in-place using old value plus the appropriate argument.
|
||||
mh = MethodHandles.filterArgumentsWithCombiner(mh, 0, lm,
|
||||
0, // old-index
|
||||
2 + ac // selected argument
|
||||
);
|
||||
|
||||
} else {
|
||||
MethodHandle cm = coderMixer(argClass);
|
||||
|
||||
// Compute new "index" in-place using old value plus the appropriate argument.
|
||||
mh = MethodHandles.filterArgumentsWithCombiner(mh, 0, lm,
|
||||
0, // old-index
|
||||
2 + ac // selected argument
|
||||
);
|
||||
|
||||
// Compute new "coder" in-place using old value plus the appropriate argument.
|
||||
mh = MethodHandles.filterArgumentsWithCombiner(mh, 1, cm,
|
||||
1, // old-coder
|
||||
2 + ac // selected argument
|
||||
);
|
||||
}
|
||||
// Compute new "index" in-place using old value plus the appropriate argument.
|
||||
mh = MethodHandles.filterArgumentsWithCombiner(mh, 0, mix,
|
||||
0, // old-index
|
||||
1 + ac // selected argument
|
||||
);
|
||||
|
||||
break;
|
||||
default:
|
||||
|
@ -1617,9 +1614,9 @@ public final class StringConcatFactory {
|
|||
}
|
||||
}
|
||||
|
||||
// Insert initial lengths and coders here.
|
||||
// Insert initial length and coder value here.
|
||||
// The method handle shape here is (<args>).
|
||||
mh = MethodHandles.insertArguments(mh, 0, initialLen, initialCoder);
|
||||
mh = MethodHandles.insertArguments(mh, 0, initialLengthCoder);
|
||||
|
||||
// Apply filters, converting the arguments:
|
||||
if (filters != null) {
|
||||
|
@ -1630,45 +1627,34 @@ public final class StringConcatFactory {
|
|||
}
|
||||
|
||||
@ForceInline
|
||||
private static byte[] newArray(int length, byte coder) {
|
||||
return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, length << coder);
|
||||
private static byte[] newArray(long indexCoder) {
|
||||
byte coder = (byte)(indexCoder >> 32);
|
||||
int index = ((int)indexCoder & 0x7FFFFFFF);
|
||||
return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, index << coder);
|
||||
}
|
||||
|
||||
private static MethodHandle prepender(Class<?> cl) {
|
||||
return PREPENDERS.computeIfAbsent(cl, PREPEND);
|
||||
}
|
||||
|
||||
private static MethodHandle coderMixer(Class<?> cl) {
|
||||
return CODER_MIXERS.computeIfAbsent(cl, CODER_MIX);
|
||||
}
|
||||
|
||||
private static MethodHandle lengthMixer(Class<?> cl) {
|
||||
return LENGTH_MIXERS.computeIfAbsent(cl, LENGTH_MIX);
|
||||
private static MethodHandle mixer(Class<?> cl) {
|
||||
return MIXERS.computeIfAbsent(cl, MIX);
|
||||
}
|
||||
|
||||
// This one is deliberately non-lambdified to optimize startup time:
|
||||
private static final Function<Class<?>, MethodHandle> PREPEND = new Function<Class<?>, MethodHandle>() {
|
||||
@Override
|
||||
public MethodHandle apply(Class<?> c) {
|
||||
return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "prepend", int.class, int.class, byte[].class, byte.class,
|
||||
return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "prepend", long.class, long.class, byte[].class,
|
||||
Wrapper.asPrimitiveType(c));
|
||||
}
|
||||
};
|
||||
|
||||
// This one is deliberately non-lambdified to optimize startup time:
|
||||
private static final Function<Class<?>, MethodHandle> CODER_MIX = new Function<Class<?>, MethodHandle>() {
|
||||
private static final Function<Class<?>, MethodHandle> MIX = new Function<Class<?>, MethodHandle>() {
|
||||
@Override
|
||||
public MethodHandle apply(Class<?> c) {
|
||||
return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "mixCoder", byte.class, byte.class,
|
||||
Wrapper.asPrimitiveType(c));
|
||||
}
|
||||
};
|
||||
|
||||
// This one is deliberately non-lambdified to optimize startup time:
|
||||
private static final Function<Class<?>, MethodHandle> LENGTH_MIX = new Function<Class<?>, MethodHandle>() {
|
||||
@Override
|
||||
public MethodHandle apply(Class<?> c) {
|
||||
return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "mixLen", int.class, int.class,
|
||||
return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "mix", long.class, long.class,
|
||||
Wrapper.asPrimitiveType(c));
|
||||
}
|
||||
};
|
||||
|
@ -1676,26 +1662,24 @@ public final class StringConcatFactory {
|
|||
private static final MethodHandle NEW_STRING;
|
||||
private static final MethodHandle NEW_ARRAY;
|
||||
private static final ConcurrentMap<Class<?>, MethodHandle> PREPENDERS;
|
||||
private static final ConcurrentMap<Class<?>, MethodHandle> LENGTH_MIXERS;
|
||||
private static final ConcurrentMap<Class<?>, MethodHandle> CODER_MIXERS;
|
||||
private static final byte INITIAL_CODER;
|
||||
private static final ConcurrentMap<Class<?>, MethodHandle> MIXERS;
|
||||
private static final long INITIAL_CODER;
|
||||
static final Class<?> STRING_HELPER;
|
||||
|
||||
static {
|
||||
try {
|
||||
STRING_HELPER = Class.forName("java.lang.StringConcatHelper");
|
||||
MethodHandle initCoder = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "initialCoder", byte.class);
|
||||
INITIAL_CODER = (byte) initCoder.invoke();
|
||||
MethodHandle initCoder = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "initialCoder", long.class);
|
||||
INITIAL_CODER = (long) initCoder.invoke();
|
||||
} catch (Throwable e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
PREPENDERS = new ConcurrentHashMap<>();
|
||||
LENGTH_MIXERS = new ConcurrentHashMap<>();
|
||||
CODER_MIXERS = new ConcurrentHashMap<>();
|
||||
MIXERS = new ConcurrentHashMap<>();
|
||||
|
||||
NEW_STRING = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "newString", String.class, byte[].class, int.class, byte.class);
|
||||
NEW_ARRAY = lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleInlineCopyStrategy.class, "newArray", byte[].class, int.class, byte.class);
|
||||
NEW_STRING = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "newString", String.class, byte[].class, long.class);
|
||||
NEW_ARRAY = lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleInlineCopyStrategy.class, "newArray", byte[].class, long.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue