8212995: Placing the Integer.IntegerCache and cached Integer objects in the closed archive heap region.
Summary: Support shareable archive object subgraphs in closed archive heap regions.
Reviewed-by: iklam, ccheung
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang;
/**
* Helper for string concatenation. These methods are mostly looked up with private lookups
* from {@link java.lang.invoke.StringConcatFactory}, and used in {@link java.lang.invoke.MethodHandle}
* combinators there.
*/
final class StringConcatHelper {
private StringConcatHelper() {
// no instantiation
}
/**
* Check for overflow, throw exception on overflow.
* @param lengthCoder String length and coder
* @return lengthCoder
*/
private static long checkOverflow(long lengthCoder) {
if ((int)lengthCoder >= 0) {
return lengthCoder;
}
throw new OutOfMemoryError("Overflow: String length out of range");
}
/**
* Mix value length and coder into current length and coder.
* @param current current length
* @param value value to mix in
* @return new length and coder
*/
static long mix(long current, boolean value) {
return checkOverflow(current + (value ? 4 : 5));
}
/**
* Mix value length and coder into current length and coder.
* @param current current length
* @param value value to mix in
* @return new length and coder
*/
static long mix(long current, byte value) {
return mix(current, (int)value);
}
/**
* Mix value length and coder into current length and coder.
* @param current current length
* @param value value to mix in
* @return new length and coder
*/
static long mix(long current, char value) {
return checkOverflow(current + 1) | (StringLatin1.canEncode(value) ? 0 : UTF16);
}
/**
* Mix value length and coder into current length and coder.
* @param current current length
* @param value value to mix in
* @return new length and coder
*/
static long mix(long current, short value) {
return mix(current, (int)value);
}
/**
* Mix value length and coder into current length and coder.
* @param current current length
* @param value value to mix in
* @return new length and coder
*/
static long mix(long current, int value) {
return checkOverflow(current + Integer.stringSize(value));
}
/**
* Mix value length and coder into current length and coder.
* @param current current length
* @param value value to mix in
* @return new length and coder
*/
static long mix(long current, long value) {
return checkOverflow(current + Long.stringSize(value));
}
/**
* Mix value length and coder into current length and coder.
* @param current current length
* @param value value to mix in
* @return new length and 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 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 long prepend(long indexCoder, byte[] buf, boolean value) {
int index = (int)indexCoder;
if (indexCoder < UTF16) {
if (value) {
buf[--index] = 'e';
buf[--index] = 'u';
buf[--index] = 'r';
buf[--index] = 't';
} else {
buf[--index] = 'e';
buf[--index] = 's';
buf[--index] = 'l';
buf[--index] = 'a';
buf[--index] = 'f';
}
return index;
} else {
if (value) {
StringUTF16.putChar(buf, --index, 'e');
StringUTF16.putChar(buf, --index, 'u');
StringUTF16.putChar(buf, --index, 'r');
StringUTF16.putChar(buf, --index, 't');
} else {
StringUTF16.putChar(buf, --index, 'e');
StringUTF16.putChar(buf, --index, 's');
StringUTF16.putChar(buf, --index, 'l');
StringUTF16.putChar(buf, --index, 'a');
StringUTF16.putChar(buf, --index, 'f');
}
return index | UTF16;
}
}
/**
* Prepends the stringly representation of byte value into buffer,
* given the coder and final index. Index is measured in chars, not in bytes!
*
* @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 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 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 long prepend(long indexCoder, byte[] buf, char value) {
if (indexCoder < UTF16) {
buf[(int)(--indexCoder)] = (byte) (value & 0xFF);
} else {
StringUTF16.putChar(buf, (int)(--indexCoder), value);
}
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 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 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 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 long prepend(long indexCoder, byte[] buf, int value) {
if (indexCoder < UTF16) {
return Integer.getChars(value, (int)indexCoder, buf);
} else {
return StringUTF16.getChars(value, (int)indexCoder, buf) | UTF16;
}
}
/**
* Prepends the stringly representation of long value into buffer,
* given the coder and final index. Index is measured in chars, not in bytes!
*
* @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 long prepend(long indexCoder, byte[] buf, long value) {
if (indexCoder < UTF16) {
return Long.getChars(value, (int)indexCoder, buf);
} else {
return StringUTF16.getChars(value, (int)indexCoder, buf) | UTF16;
}
}
/**
* Prepends the stringly representation of String value into buffer,
* given the coder and final index. Index is measured in chars, not in bytes!
*
* @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 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 indexCoder remaining index (should be zero) and coder
* @return String resulting string
*/
static String newString(byte[] buf, long indexCoder) {
// Use the private, non-copying constructor (unsafe!)
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");
}
}
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, adjusted into the upper half
*/
static long initialCoder() {
return String.COMPACT_STRINGS ? LATIN1 : UTF16;
}
}