Skip to content
Permalink
Browse files
8238369: [lworld] Incorrect layout of inline type in flattened array.
Reviewed-by: fparain
  • Loading branch information
David Simms committed Nov 17, 2020
1 parent 928c29e commit cc1f08e177213b091cf3a141ffa935a8bcf8872f
Showing 4 changed files with 81 additions and 44 deletions.
@@ -164,7 +164,7 @@ oop FlatArrayKlass::multi_allocate(int rank, jint* last_size, TRAPS) {

jint FlatArrayKlass::array_layout_helper(InlineKlass* vk) {
BasicType etype = T_INLINE_TYPE;
int esize = upper_log2(vk->raw_value_byte_size());
int esize = upper_log2(vk->get_exact_size_in_bytes());
int hsize = arrayOopDesc::base_offset_in_bytes(etype);

int lh = Klass::array_layout_helper(_lh_array_tag_vt_value, true, hsize, etype, esize);
@@ -87,44 +87,6 @@ int InlineKlass::first_field_offset_old() {
return base_offset;
}

int InlineKlass::raw_value_byte_size() {
int heapOopAlignedSize = nonstatic_field_size() << LogBytesPerHeapOop;
// If bigger than 64 bits or needs oop alignment, then use jlong aligned
// which for values should be jlong aligned, asserts in raw_field_copy otherwise
if (heapOopAlignedSize >= longSize || contains_oops()) {
return heapOopAlignedSize;
}
// Small primitives...
// If a few small basic type fields, return the actual size, i.e.
// 1 byte = 1
// 2 byte = 2
// 3 byte = 4, because pow2 needed for element stores
int first_offset = first_field_offset();
int last_offset = 0; // find the last offset, add basic type size
int last_tsz = 0;
for (AllFieldStream fs(this); !fs.done(); fs.next()) {
if (fs.access_flags().is_static()) {
continue;
} else if (fs.offset() > last_offset) {
BasicType type = Signature::basic_type(fs.signature());
if (is_java_primitive(type)) {
last_tsz = type2aelembytes(type);
} else if (type == T_INLINE_TYPE) {
// Not just primitives. Layout aligns embedded value, so use jlong aligned it is
return heapOopAlignedSize;
} else {
guarantee(0, "Unknown type %d", type);
}
assert(last_tsz != 0, "Invariant");
last_offset = fs.offset();
}
}
// Assumes VT with no fields are meaningless and illegal
last_offset += last_tsz;
assert(last_offset > first_offset && last_tsz, "Invariant");
return 1 << upper_log2(last_offset - first_offset);
}

instanceOop InlineKlass::allocate_instance(TRAPS) {
int size = size_helper(); // Query before forming handle.

@@ -183,7 +145,7 @@ bool InlineKlass::flatten_array() {
return false;
}
// Too big
int elem_bytes = raw_value_byte_size();
int elem_bytes = get_exact_size_in_bytes();
if ((FlatArrayElementMaxSize >= 0) && (elem_bytes > FlatArrayElementMaxSize)) {
return false;
}
@@ -182,9 +182,6 @@ class InlineKlass: public InstanceKlass {
// returning to Java (i.e.: inline_copy)
instanceOop allocate_instance_buffer(TRAPS);

// minimum number of bytes occupied by nonstatic fields, HeapWord aligned or pow2
int raw_value_byte_size();

address data_for_oop(oop o) const;
oop oop_for_data(address data) const;

@@ -33,7 +33,10 @@
* @library /test/lib
* @compile -XDallowWithFieldOperator InlineTypeDensity.java
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -Xint -XX:FlatArrayElementMaxSize=-1
* @run main/othervm -Xint -XX:FlatArrayElementMaxSize=-1 -XX:+UseCompressedOops
* -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI InlineTypeDensity
* @run main/othervm -Xint -XX:FlatArrayElementMaxSize=-1 -XX:-UseCompressedOops
* -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI InlineTypeDensity
* @run main/othervm -Xcomp -XX:FlatArrayElementMaxSize=-1
@@ -47,6 +50,7 @@
public class InlineTypeDensity {

private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
private static final boolean VM_FLAG_FORCENONTEARABLE = WHITE_BOX.getStringVMFlag("ForceNonTearable").equals("*");

public InlineTypeDensity() {
if (WHITE_BOX.getIntxVMFlag("FlatArrayElementMaxSize") != -1) {
@@ -229,8 +233,82 @@ public void ensureArraySizeWin() {
Asserts.assertLessThan(flatArraySize, objectArraySize, "Flat array accounts for more heap than object array + elements !");
}

static inline class MyByte { byte v = 0; }
static inline class MyShort { short v = 0; }
static inline class MyInt { int v = 0; }
static inline class MyLong { long v = 0; }

void assertArraySameSize(Object a, Object b, int nofElements) {
long aSize = WHITE_BOX.getObjectSize(a);
long bSize = WHITE_BOX.getObjectSize(b);
Asserts.assertEquals(aSize, bSize,
a + "(" + aSize + " bytes) not equivalent size " +
b + "(" + bSize + " bytes)" +
(nofElements >= 0 ? " (array of " + nofElements + " elements)" : ""));
}

void testByteArraySizesSame(int[] testSizes) {
for (int testSize : testSizes) {
byte[] ba = new byte[testSize];
MyByte[] mba = new MyByte[testSize];
assertArraySameSize(ba, mba, testSize);
}
}

void testShortArraySizesSame(int[] testSizes) {
for (int testSize : testSizes) {
short[] sa = new short[testSize];
MyShort[] msa = new MyShort[testSize];
assertArraySameSize(sa, msa, testSize);
}
}

void testIntArraySizesSame(int[] testSizes) {
for (int testSize : testSizes) {
int[] ia = new int[testSize];
MyInt[] mia = new MyInt[testSize];
assertArraySameSize(ia, mia, testSize);
}
}

void testLongArraySizesSame(int[] testSizes) {
for (int testSize : testSizes) {
long[] la = new long[testSize];
MyLong[] mla = new MyLong[testSize];
assertArraySameSize(la, mla, testSize);
}
}

public void testPrimitiveArraySizesSame() {
int[] testSizes = new int[] { 0, 1, 2, 3, 4, 7, 10, 257 };
testByteArraySizesSame(testSizes);
testShortArraySizesSame(testSizes);
testIntArraySizesSame(testSizes);
testLongArraySizesSame(testSizes);
}

static inline class bbValue { byte b = 0; byte b2 = 0;}
static inline class bsValue { byte b = 0; short s = 0;}
static inline class siValue { short s = 0; int i = 0;}
static inline class ssiValue { short s = 0; short s2 = 0; int i = 0;}
static inline class blValue { byte b = 0; long l = 0; }

// Expect aligned array addressing to nearest pow2
void testAlignedSize() {
int testSize = 10;
if (!VM_FLAG_FORCENONTEARABLE) {
assertArraySameSize(new short[testSize], new bbValue[testSize], testSize);
assertArraySameSize(new long[testSize], new siValue[testSize], testSize);
assertArraySameSize(new long[testSize], new ssiValue[testSize], testSize);
assertArraySameSize(new long[testSize*2], new blValue[testSize], testSize);
}
assertArraySameSize(new int[testSize], new bsValue[testSize], testSize);
}

public void test() {
ensureArraySizeWin();
testPrimitiveArraySizesSame();
testAlignedSize();
}

public static void main(String[] args) {

0 comments on commit cc1f08e

Please sign in to comment.