8139457: Relax alignment of array elements

Co-authored-by: Fei Yang <fyang@openjdk.org>
Co-authored-by: Thomas Stuefe <stuefe@openjdk.org>
Reviewed-by: stuefe, stefank, shade, coleenp, kdnilsen, aboldtch
This commit is contained in:
Roman Kennke 2024-02-23 10:05:25 +00:00
parent cb809f8e04
commit 336bbbe389
33 changed files with 560 additions and 171 deletions

View File

@ -1209,7 +1209,7 @@ void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) {
len,
tmp1,
tmp2,
arrayOopDesc::header_size(op->type()),
arrayOopDesc::base_offset_in_bytes(op->type()),
array_element_size(op->type()),
op->klass()->as_register(),
*op->stub()->entry());

View File

@ -188,6 +188,12 @@ void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register
if (len->is_valid()) {
strw(len, Address(obj, arrayOopDesc::length_offset_in_bytes()));
int base_offset = arrayOopDesc::length_offset_in_bytes() + BytesPerInt;
if (!is_aligned(base_offset, BytesPerWord)) {
assert(is_aligned(base_offset, BytesPerInt), "must be 4-byte aligned");
// Clear gap/first 4 bytes following the length field.
strw(zr, Address(obj, base_offset));
}
} else if (UseCompressedClassPointers) {
store_klass_gap(obj, zr);
}
@ -266,7 +272,7 @@ void C1_MacroAssembler::initialize_object(Register obj, Register klass, Register
verify_oop(obj);
}
void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1, Register t2, int header_size, int f, Register klass, Label& slow_case) {
void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1, Register t2, int base_offset_in_bytes, int f, Register klass, Label& slow_case) {
assert_different_registers(obj, len, t1, t2, klass);
// determine alignment mask
@ -279,7 +285,7 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1,
const Register arr_size = t2; // okay to be the same
// align object end
mov(arr_size, (int32_t)header_size * BytesPerWord + MinObjAlignmentInBytesMask);
mov(arr_size, (int32_t)base_offset_in_bytes + MinObjAlignmentInBytesMask);
add(arr_size, arr_size, len, ext::uxtw, f);
andr(arr_size, arr_size, ~MinObjAlignmentInBytesMask);
@ -287,8 +293,11 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1,
initialize_header(obj, klass, len, t1, t2);
// Align-up to word boundary, because we clear the 4 bytes potentially
// following the length field in initialize_header().
int base_offset = align_up(base_offset_in_bytes, BytesPerWord);
// clear rest of allocated space
initialize_body(obj, arr_size, header_size * BytesPerWord, t1, t2);
initialize_body(obj, arr_size, base_offset, t1, t2);
if (Compilation::current()->bailed_out()) {
return;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -100,7 +100,7 @@ using MacroAssembler::null_check;
// header_size: size of object header in words
// f : element scale factor
// slow_case : exit to slow case implementation if fast allocation fails
void allocate_array(Register obj, Register len, Register t, Register t2, int header_size, int f, Register klass, Label& slow_case);
void allocate_array(Register obj, Register len, Register t, Register t2, int base_offset_in_bytes, int f, Register klass, Label& slow_case);
int rsp_offset() const { return _rsp_offset; }
void set_rsp_offset(int n) { _rsp_offset = n; }

View File

@ -968,7 +968,7 @@ void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) {
op->tmp1()->as_register(),
op->tmp2()->as_register(),
op->tmp3()->as_register(),
arrayOopDesc::header_size(op->type()),
arrayOopDesc::base_offset_in_bytes(op->type()),
type2aelembytes(op->type()),
op->klass()->as_register(),
*op->stub()->entry());

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2023 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -2298,7 +2298,7 @@ void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) {
op->tmp1()->as_register(),
op->tmp2()->as_register(),
op->tmp3()->as_register(),
arrayOopDesc::header_size(op->type()),
arrayOopDesc::base_offset_in_bytes(op->type()),
type2aelembytes(op->type()),
op->klass()->as_register(),
*op->stub()->entry());

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2018 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -310,7 +310,7 @@ void C1_MacroAssembler::allocate_array(
Register t1, // temp register
Register t2, // temp register
Register t3, // temp register
int hdr_size, // object header size in words
int base_offset_in_bytes, // elements offset in bytes
int elt_size, // element size in bytes
Register klass, // object klass
Label& slow_case // continuation point if fast allocation fails
@ -342,7 +342,7 @@ void C1_MacroAssembler::allocate_array(
sldi(t1, len, log2_elt_size);
arr_len_in_bytes = t1;
}
addi(arr_size, arr_len_in_bytes, hdr_size * wordSize + MinObjAlignmentInBytesMask); // Add space for header & alignment.
addi(arr_size, arr_len_in_bytes, base_offset_in_bytes + MinObjAlignmentInBytesMask); // Add space for header & alignment.
clrrdi(arr_size, arr_size, LogMinObjAlignmentInBytes); // Align array size.
// Allocate space & initialize header.
@ -352,8 +352,18 @@ void C1_MacroAssembler::allocate_array(
// Initialize body.
const Register base = t2;
const Register index = t3;
addi(base, obj, hdr_size * wordSize); // compute address of first element
addi(index, arr_size, -(hdr_size * wordSize)); // compute index = number of bytes to clear
addi(base, obj, base_offset_in_bytes); // compute address of first element
addi(index, arr_size, -(base_offset_in_bytes)); // compute index = number of bytes to clear
// Zero first 4 bytes, if start offset is not word aligned.
if (!is_aligned(base_offset_in_bytes, BytesPerWord)) {
assert(is_aligned(base_offset_in_bytes, BytesPerInt), "must be 4-byte aligned");
li(t1, 0);
stw(t1, 0, base);
addi(base, base, BytesPerInt);
// Note: initialize_body will align index down, no need to correct it here.
}
initialize_body(base, index);
if (CURRENT_ENV->dtrace_alloc_probes()) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -80,7 +80,7 @@
Register t1, // temp register
Register t2, // temp register
Register t3, // temp register
int hdr_size, // object header size in words
int base_offset_in_bytes, // elements offset in bytes
int elt_size, // element size in bytes
Register klass, // object klass
Label& slow_case // continuation point if fast allocation fails

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -1020,7 +1020,7 @@ void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) {
len,
tmp1,
tmp2,
arrayOopDesc::header_size(op->type()),
arrayOopDesc::base_offset_in_bytes(op->type()),
array_element_size(op->type()),
op->klass()->as_register(),
*op->stub()->entry());

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -280,7 +280,7 @@ void C1_MacroAssembler::initialize_object(Register obj, Register klass, Register
verify_oop(obj);
}
void C1_MacroAssembler::allocate_array(Register obj, Register len, Register tmp1, Register tmp2, int header_size, int f, Register klass, Label& slow_case) {
void C1_MacroAssembler::allocate_array(Register obj, Register len, Register tmp1, Register tmp2, int base_offset_in_bytes, int f, Register klass, Label& slow_case) {
assert_different_registers(obj, len, tmp1, tmp2, klass);
// determine alignment mask
@ -292,7 +292,7 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, Register tmp1
const Register arr_size = tmp2; // okay to be the same
// align object end
mv(arr_size, (int32_t)header_size * BytesPerWord + MinObjAlignmentInBytesMask);
mv(arr_size, (int32_t)base_offset_in_bytes + MinObjAlignmentInBytesMask);
shadd(arr_size, len, arr_size, t0, f);
andi(arr_size, arr_size, ~(uint)MinObjAlignmentInBytesMask);
@ -300,9 +300,20 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, Register tmp1
initialize_header(obj, klass, len, tmp1, tmp2);
// Clear leading 4 bytes, if necessary.
// TODO: This could perhaps go into initialize_body() and also clear the leading 4 bytes
// for non-array objects, thereby replacing the klass-gap clearing code in initialize_header().
int base_offset = base_offset_in_bytes;
if (!is_aligned(base_offset, BytesPerWord)) {
assert(is_aligned(base_offset, BytesPerInt), "must be 4-byte aligned");
sw(zr, Address(obj, base_offset));
base_offset += BytesPerInt;
}
assert(is_aligned(base_offset, BytesPerWord), "must be word-aligned");
// clear rest of allocated space
const Register len_zero = len;
initialize_body(obj, arr_size, header_size * BytesPerWord, len_zero);
initialize_body(obj, arr_size, base_offset, len_zero);
membar(MacroAssembler::StoreStore);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -101,7 +101,7 @@ using MacroAssembler::null_check;
// header_size: size of object header in words
// f : element scale factor
// slow_case : exit to slow case implementation if fast allocation fails
void allocate_array(Register obj, Register len, Register tmp1, Register tmp2, int header_size, int f, Register klass, Label& slow_case);
void allocate_array(Register obj, Register len, Register tmp1, Register tmp2, int base_offset_in_bytes, int f, Register klass, Label& slow_case);
int rsp_offset() const { return _rsp_offset; }

View File

@ -2382,7 +2382,7 @@ void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) {
op->len()->as_register(),
op->tmp1()->as_register(),
op->tmp2()->as_register(),
arrayOopDesc::header_size(op->type()),
arrayOopDesc::base_offset_in_bytes(op->type()),
type2aelembytes(op->type()),
op->klass()->as_register(),
*op->stub()->entry());

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2023 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -271,7 +271,7 @@ void C1_MacroAssembler::allocate_array(
Register len, // array length
Register t1, // temp register
Register t2, // temp register
int hdr_size, // object header size in words
int base_offset_in_bytes, // elements offset in bytes
int elt_size, // element size in bytes
Register klass, // object klass
Label& slow_case // Continuation point if fast allocation fails.
@ -297,7 +297,7 @@ void C1_MacroAssembler::allocate_array(
case 8: z_sllg(arr_size, len, 3); break;
default: ShouldNotReachHere();
}
add2reg(arr_size, hdr_size * wordSize + MinObjAlignmentInBytesMask); // Add space for header & alignment.
add2reg(arr_size, base_offset_in_bytes + MinObjAlignmentInBytesMask); // Add space for header & alignment.
z_nill(arr_size, (~MinObjAlignmentInBytesMask) & 0xffff); // Align array size.
try_allocate(obj, arr_size, 0, t1, slow_case);
@ -308,9 +308,9 @@ void C1_MacroAssembler::allocate_array(
Label done;
Register object_fields = t1;
Register Rzero = Z_R1_scratch;
z_aghi(arr_size, -(hdr_size * BytesPerWord));
z_aghi(arr_size, -base_offset_in_bytes);
z_bre(done); // Jump if size of fields is zero.
z_la(object_fields, hdr_size * BytesPerWord, obj);
z_la(object_fields, base_offset_in_bytes, obj);
z_xgr(Rzero, Rzero);
initialize_body(object_fields, arr_size, Rzero);
bind(done);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2023 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -86,7 +86,7 @@
Register len, // array length
Register t1, // temp register
Register t2, // temp register
int hdr_size, // object header size in words
int base_offset_in_bytes, // elements offset in bytes
int elt_size, // element size in bytes
Register klass, // object klass
Label& slow_case // Continuation point if fast allocation fails.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2024, 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
@ -1618,7 +1618,7 @@ void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) {
len,
tmp1,
tmp2,
arrayOopDesc::header_size(op->type()),
arrayOopDesc::base_offset_in_bytes(op->type()),
array_element_size(op->type()),
op->klass()->as_register(),
*op->stub()->entry());

View File

@ -186,6 +186,15 @@ void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register
if (len->is_valid()) {
movl(Address(obj, arrayOopDesc::length_offset_in_bytes()), len);
#ifdef _LP64
int base_offset = arrayOopDesc::length_offset_in_bytes() + BytesPerInt;
if (!is_aligned(base_offset, BytesPerWord)) {
assert(is_aligned(base_offset, BytesPerInt), "must be 4-byte aligned");
// Clear gap/first 4 bytes following the length field.
xorl(t1, t1);
movl(Address(obj, base_offset), t1);
}
#endif
}
#ifdef _LP64
else if (UseCompressedClassPointers) {
@ -269,7 +278,7 @@ void C1_MacroAssembler::initialize_object(Register obj, Register klass, Register
verify_oop(obj);
}
void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1, Register t2, int header_size, Address::ScaleFactor f, Register klass, Label& slow_case) {
void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1, Register t2, int base_offset_in_bytes, Address::ScaleFactor f, Register klass, Label& slow_case) {
assert(obj == rax, "obj must be in rax, for cmpxchg");
assert_different_registers(obj, len, t1, t2, klass);
@ -282,7 +291,7 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1,
const Register arr_size = t2; // okay to be the same
// align object end
movptr(arr_size, header_size * BytesPerWord + MinObjAlignmentInBytesMask);
movptr(arr_size, base_offset_in_bytes + MinObjAlignmentInBytesMask);
lea(arr_size, Address(arr_size, len, f));
andptr(arr_size, ~MinObjAlignmentInBytesMask);
@ -292,7 +301,10 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1,
// clear rest of allocated space
const Register len_zero = len;
initialize_body(obj, arr_size, header_size * BytesPerWord, len_zero);
// Align-up to word boundary, because we clear the 4 bytes potentially
// following the length field in initialize_header().
int base_offset = align_up(base_offset_in_bytes, BytesPerWord);
initialize_body(obj, arr_size, base_offset, len_zero);
if (CURRENT_ENV->dtrace_alloc_probes()) {
assert(obj == rax, "must be");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2024, 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
@ -89,7 +89,7 @@
// header_size: size of object header in words
// f : element scale factor
// slow_case : exit to slow case implementation if fast allocation fails
void allocate_array(Register obj, Register len, Register t, Register t2, int header_size, Address::ScaleFactor f, Register klass, Label& slow_case);
void allocate_array(Register obj, Register len, Register t, Register t2, int base_offset_in_bytes, Address::ScaleFactor f, Register klass, Label& slow_case);
int rsp_offset() const { return _rsp_offset; }
void set_rsp_offset(int n) { _rsp_offset = n; }

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2024, 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
@ -402,6 +402,13 @@ void CollectedHeap::set_gc_cause(GCCause::Cause v) {
_gc_cause = v;
}
// Returns the header size in words aligned to the requirements of the
// array object type.
static int int_array_header_size() {
size_t typesize_in_bytes = arrayOopDesc::header_size_in_bytes();
return (int)align_up(typesize_in_bytes, HeapWordSize)/HeapWordSize;
}
size_t CollectedHeap::max_tlab_size() const {
// TLABs can't be bigger than we can fill with a int[Integer.MAX_VALUE].
// This restriction could be removed by enabling filling with multiple arrays.
@ -411,14 +418,14 @@ size_t CollectedHeap::max_tlab_size() const {
// We actually lose a little by dividing first,
// but that just makes the TLAB somewhat smaller than the biggest array,
// which is fine, since we'll be able to fill that.
size_t max_int_size = typeArrayOopDesc::header_size(T_INT) +
size_t max_int_size = int_array_header_size() +
sizeof(jint) *
((juint) max_jint / (size_t) HeapWordSize);
return align_down(max_int_size, MinObjAlignment);
}
size_t CollectedHeap::filler_array_hdr_size() {
return align_object_offset(arrayOopDesc::header_size(T_INT)); // align to Long
return align_object_offset(int_array_header_size()); // align to Long
}
size_t CollectedHeap::filler_array_min_size() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2024, 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
@ -50,7 +50,17 @@ oop XObjArrayAllocator::initialize(HeapWord* mem) const {
// time and time-to-safepoint
const size_t segment_max = XUtils::bytes_to_words(64 * K);
const BasicType element_type = ArrayKlass::cast(_klass)->element_type();
const size_t header = arrayOopDesc::header_size(element_type);
// Clear leading 32 bits, if necessary.
int base_offset = arrayOopDesc::base_offset_in_bytes(element_type);
if (!is_aligned(base_offset, HeapWordSize)) {
assert(is_aligned(base_offset, BytesPerInt), "array base must be 32 bit aligned");
*reinterpret_cast<jint*>(reinterpret_cast<char*>(mem) + base_offset) = 0;
base_offset += BytesPerInt;
}
assert(is_aligned(base_offset, HeapWordSize), "remaining array base must be 64 bit aligned");
const size_t header = heap_word_size(base_offset);
const size_t payload_size = _word_size - header;
if (payload_size <= segment_max) {

View File

@ -50,7 +50,17 @@ oop ZObjArrayAllocator::initialize(HeapWord* mem) const {
// time and time-to-safepoint
const size_t segment_max = ZUtils::bytes_to_words(64 * K);
const BasicType element_type = ArrayKlass::cast(_klass)->element_type();
const size_t header = arrayOopDesc::header_size(element_type);
// Clear leading 32 bits, if necessary.
int base_offset = arrayOopDesc::base_offset_in_bytes(element_type);
if (!is_aligned(base_offset, HeapWordSize)) {
assert(is_aligned(base_offset, BytesPerInt), "array base must be 32 bit aligned");
*reinterpret_cast<jint*>(reinterpret_cast<char*>(mem) + base_offset) = 0;
base_offset += BytesPerInt;
}
assert(is_aligned(base_offset, HeapWordSize), "remaining array base must be 64 bit aligned");
const size_t header = heap_word_size(base_offset);
const size_t payload_size = _word_size - header;
if (payload_size <= segment_max) {

View File

@ -2442,7 +2442,7 @@ C2V_END
C2V_VMENTRY_0(jint, arrayBaseOffset, (JNIEnv* env, jobject, jchar type_char))
BasicType type = JVMCIENV->typeCharToBasicType(type_char, JVMCI_CHECK_0);
return arrayOopDesc::header_size(type) * HeapWordSize;
return arrayOopDesc::base_offset_in_bytes(type);
C2V_END
C2V_VMENTRY_0(jint, arrayIndexScale, (JNIEnv* env, jobject, jchar type_char))

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2024, 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
@ -27,6 +27,7 @@
#include "oops/oop.hpp"
#include "utilities/align.hpp"
#include "utilities/globalDefinitions.hpp"
// arrayOopDesc is the abstract baseclass for all arrays. It doesn't
// declare pure virtual to enforce this because that would allocate a vtbl
@ -45,13 +46,29 @@ class arrayOopDesc : public oopDesc {
// Interpreter/Compiler offsets
private:
// Returns the address of the length "field". See length_offset_in_bytes().
static int* length_addr_impl(void* obj_ptr) {
char* ptr = static_cast<char*>(obj_ptr);
return reinterpret_cast<int*>(ptr + length_offset_in_bytes());
}
// Given a type, return true if elements of that type must be aligned to 64-bit.
static bool element_type_should_be_aligned(BasicType type) {
#ifdef _LP64
if (type == T_OBJECT || type == T_ARRAY) {
return !UseCompressedOops;
}
#endif
return type == T_DOUBLE || type == T_LONG;
}
public:
// Header size computation.
// The header is considered the oop part of this type plus the length.
// Returns the aligned header_size_in_bytes. This is not equivalent to
// sizeof(arrayOopDesc) which should not appear in the code.
// This is not equivalent to sizeof(arrayOopDesc) which should not appear in the code.
static int header_size_in_bytes() {
size_t hs = align_up(length_offset_in_bytes() + sizeof(int),
HeapWordSize);
size_t hs = length_offset_in_bytes() + sizeof(int);
#ifdef ASSERT
// make sure it isn't called before UseCompressedOops is initialized.
static size_t arrayoopdesc_hs = 0;
@ -61,20 +78,6 @@ class arrayOopDesc : public oopDesc {
return (int)hs;
}
// Returns the address of the length "field". See length_offset_in_bytes().
static int* length_addr_impl(void* obj_ptr) {
char* ptr = static_cast<char*>(obj_ptr);
return reinterpret_cast<int*>(ptr + length_offset_in_bytes());
}
// Check whether an element of a typeArrayOop with the given type must be
// aligned 0 mod 8. The typeArrayOop itself must be aligned at least this
// strongly.
static bool element_type_should_be_aligned(BasicType type) {
return type == T_DOUBLE || type == T_LONG;
}
public:
// The _length field is not declared in C++. It is allocated after the
// declared nonstatic fields in arrayOopDesc if not compressed, otherwise
// it occupies the second half of the _klass field in oopDesc.
@ -85,7 +88,8 @@ class arrayOopDesc : public oopDesc {
// Returns the offset of the first element.
static int base_offset_in_bytes(BasicType type) {
return header_size(type) * HeapWordSize;
size_t hs = header_size_in_bytes();
return (int)(element_type_should_be_aligned(type) ? align_up(hs, BytesPerLong) : hs);
}
// Returns the address of the first element. The elements in the array will not
@ -122,18 +126,7 @@ class arrayOopDesc : public oopDesc {
*length_addr_impl(mem) = length;
}
// Should only be called with constants as argument
// (will not constant fold otherwise)
// Returns the header size in words aligned to the requirements of the
// array object type.
static int header_size(BasicType type) {
size_t typesize_in_bytes = header_size_in_bytes();
return (int)(element_type_should_be_aligned(type)
? align_object_offset(typesize_in_bytes/HeapWordSize)
: typesize_in_bytes/HeapWordSize);
}
// Return the maximum length of an array of BasicType. The length can passed
// Return the maximum length of an array of BasicType. The length can be passed
// to typeArrayOop::object_size(scale, length, header_size) without causing an
// overflow. We also need to make sure that this will not overflow a size_t on
// 32 bit platforms when we convert it to a byte size.
@ -141,8 +134,12 @@ class arrayOopDesc : public oopDesc {
assert(type < T_CONFLICT, "wrong type");
assert(type2aelembytes(type) != 0, "wrong type");
size_t hdr_size_in_bytes = base_offset_in_bytes(type);
// This is rounded-up and may overlap with the first array elements.
size_t hdr_size_in_words = align_up(hdr_size_in_bytes, HeapWordSize) / HeapWordSize;
const size_t max_element_words_per_size_t =
align_down((SIZE_MAX/HeapWordSize - header_size(type)), MinObjAlignment);
align_down((SIZE_MAX/HeapWordSize - hdr_size_in_words), MinObjAlignment);
const size_t max_elements_per_size_t =
HeapWordSize * max_element_words_per_size_t / type2aelembytes(type);
if ((size_t)max_jint < max_elements_per_size_t) {
@ -150,7 +147,7 @@ class arrayOopDesc : public oopDesc {
// (CollectedHeap, Klass::oop_oop_iterate(), and more) uses an int for
// passing around the size (in words) of an object. So, we need to avoid
// overflowing an int when we add the header. See CRs 4718400 and 7110613.
return align_down(max_jint - header_size(type), MinObjAlignment);
return align_down(max_jint - hdr_size_in_words, MinObjAlignment);
}
return (int32_t)max_elements_per_size_t;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2024, 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
@ -51,32 +51,6 @@ class objArrayOopDesc : public arrayOopDesc {
return base_offset_in_bytes() + sizeof(T) * index;
}
private:
// Give size of objArrayOop in HeapWords minus the header
static int array_size(int length) {
const uint OopsPerHeapWord = HeapWordSize/heapOopSize;
assert(OopsPerHeapWord >= 1 && (HeapWordSize % heapOopSize == 0),
"Else the following (new) computation would be in error");
uint res = ((uint)length + OopsPerHeapWord - 1)/OopsPerHeapWord;
#ifdef ASSERT
// The old code is left in for sanity-checking; it'll
// go away pretty soon. XXX
// Without UseCompressedOops, this is simply:
// oop->length() * HeapWordsPerOop;
// With narrowOops, HeapWordsPerOop is 1/2 or equal 0 as an integer.
// The oop elements are aligned up to wordSize
const uint HeapWordsPerOop = heapOopSize/HeapWordSize;
uint old_res;
if (HeapWordsPerOop > 0) {
old_res = length * HeapWordsPerOop;
} else {
old_res = align_up((uint)length, OopsPerHeapWord)/OopsPerHeapWord;
}
assert(res == old_res, "Inconsistency between old and new.");
#endif // ASSERT
return res;
}
public:
// Returns the offset of the first element.
static int base_offset_in_bytes() {
@ -94,16 +68,15 @@ private:
oop replace_if_null(int index, oop exchange_value);
// Sizing
static int header_size() { return arrayOopDesc::header_size(T_OBJECT); }
size_t object_size() { return object_size(length()); }
static size_t object_size(int length) {
// This returns the object size in HeapWords.
uint asz = array_size(length);
uint osz = align_object_size(header_size() + asz);
assert(osz >= asz, "no overflow");
assert((int)osz > 0, "no overflow");
return (size_t)osz;
size_t asz = (size_t)length * heapOopSize;
size_t size_words = heap_word_size(base_offset_in_bytes() + asz);
size_t osz = align_object_size(size_words);
assert(osz < max_jint, "no overflow");
return osz;
}
Klass* element_klass();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2024, 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
@ -319,14 +319,17 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::new_array_nozero_C(Klass* array_type, int len
// Zero array here if the caller is deoptimized.
const size_t size = TypeArrayKlass::cast(array_type)->oop_size(result);
BasicType elem_type = TypeArrayKlass::cast(array_type)->element_type();
const size_t hs = arrayOopDesc::header_size(elem_type);
// Align to next 8 bytes to avoid trashing arrays's length.
const size_t aligned_hs = align_object_offset(hs);
size_t hs_bytes = arrayOopDesc::base_offset_in_bytes(elem_type);
assert(is_aligned(hs_bytes, BytesPerInt), "must be 4 byte aligned");
HeapWord* obj = cast_from_oop<HeapWord*>(result);
if (aligned_hs > hs) {
Copy::zero_to_words(obj+hs, aligned_hs-hs);
if (!is_aligned(hs_bytes, BytesPerLong)) {
*reinterpret_cast<jint*>(reinterpret_cast<char*>(obj) + hs_bytes) = 0;
hs_bytes += BytesPerInt;
}
// Optimized zeroing.
assert(is_aligned(hs_bytes, BytesPerLong), "must be 8-byte aligned");
const size_t aligned_hs = hs_bytes / BytesPerLong;
Copy::fill_to_aligned_words(obj+aligned_hs, size-aligned_hs);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2024, 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
@ -5169,18 +5169,17 @@ void TypeAryPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
}
if( _offset != 0 ) {
int header_size = objArrayOopDesc::header_size() * wordSize;
BasicType basic_elem_type = elem()->basic_type();
int header_size = arrayOopDesc::base_offset_in_bytes(basic_elem_type);
if( _offset == OffsetTop ) st->print("+undefined");
else if( _offset == OffsetBot ) st->print("+any");
else if( _offset < header_size ) st->print("+%d", _offset);
else {
BasicType basic_elem_type = elem()->basic_type();
if (basic_elem_type == T_ILLEGAL) {
st->print("+any");
} else {
int array_base = arrayOopDesc::base_offset_in_bytes(basic_elem_type);
int elem_size = type2aelembytes(basic_elem_type);
st->print("[%d]", (_offset - array_base)/elem_size);
st->print("[%d]", (_offset - header_size)/elem_size);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2024, 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
@ -67,7 +67,7 @@
#define MAX_OBJECT_SIZE \
( arrayOopDesc::header_size(T_DOUBLE) * HeapWordSize \
( arrayOopDesc::base_offset_in_bytes(T_DOUBLE) \
+ ((julong)max_jint * sizeof(double)) )
#define UNSAFE_ENTRY(result_type, header) \

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2024, 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
@ -116,13 +116,6 @@ public class Universe {
heap().printOn(tty);
}
// Check whether an element of a typeArrayOop with the given type must be
// aligned 0 mod 8. The typeArrayOop itself must be aligned at least this
// strongly.
public static boolean elementTypeShouldBeAligned(BasicType type) {
return type == BasicType.T_DOUBLE || type == BasicType.T_LONG;
}
// Check whether an object field (static/non-static) of the given type must be
// aligned 0 mod 8.
public static boolean fieldTypeShouldBeAligned(BasicType type) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2024, 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
@ -57,28 +57,27 @@ public class Array extends Oop {
private static long lengthOffsetInBytes=0;
private static long typeSize;
// Check whether an element of a arrayOop with the given type must be
// aligned 0 mod 8. The arrayOop itself must be aligned at least this
// strongly.
private static boolean elementTypeShouldBeAligned(BasicType type) {
if (VM.getVM().isLP64()) {
if (type == BasicType.T_OBJECT || type == BasicType.T_ARRAY) {
return !VM.getVM().isCompressedOopsEnabled();
}
}
return type == BasicType.T_DOUBLE || type == BasicType.T_LONG;
}
private static long headerSizeInBytes() {
if (headerSize != 0) {
return headerSize;
}
if (VM.getVM().isCompressedKlassPointersEnabled()) {
headerSize = typeSize;
} else {
headerSize = VM.getVM().alignUp(typeSize + VM.getVM().getIntSize(),
VM.getVM().getHeapWordSize());
}
headerSize = lengthOffsetInBytes() + VM.getVM().getIntSize();
return headerSize;
}
private static long headerSize(BasicType type) {
if (Universe.elementTypeShouldBeAligned(type)) {
return alignObjectSize(headerSizeInBytes())/VM.getVM().getHeapWordSize();
} else {
return headerSizeInBytes()/VM.getVM().getHeapWordSize();
}
}
private long lengthOffsetInBytes() {
private static long lengthOffsetInBytes() {
if (lengthOffsetInBytes != 0) {
return lengthOffsetInBytes;
}
@ -108,7 +107,13 @@ public class Array extends Oop {
}
public static long baseOffsetInBytes(BasicType type) {
return headerSize(type) * VM.getVM().getHeapWordSize();
long typeSizeInBytes = headerSizeInBytes();
if (elementTypeShouldBeAligned(type)) {
VM vm = VM.getVM();
return vm.alignUp(typeSizeInBytes, vm.getVM().getHeapWordSize());
} else {
return typeSizeInBytes;
}
}
public boolean isArray() { return true; }

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2024, 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
@ -27,19 +27,11 @@
#include "unittest.hpp"
#include "utilities/globalDefinitions.hpp"
class arrayOopDescTest {
public:
static int header_size_in_bytes() {
return arrayOopDesc::header_size_in_bytes();
}
};
static bool check_max_length_overflow(BasicType type) {
julong length = arrayOopDesc::max_array_length(type);
julong bytes_per_element = type2aelembytes(type);
julong bytes = length * bytes_per_element
+ arrayOopDescTest::header_size_in_bytes();
+ arrayOopDesc::base_offset_in_bytes(type);
return (julong) (size_t) bytes == bytes;
}
@ -87,3 +79,47 @@ TEST_VM(arrayOopDesc, narrowOop) {
ASSERT_PRED1(check_max_length_overflow, T_NARROWOOP);
}
// T_VOID and T_ADDRESS are not supported by max_array_length()
TEST_VM(arrayOopDesc, base_offset) {
#ifdef _LP64
if (UseCompressedClassPointers) {
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_BOOLEAN), 16);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_BYTE), 16);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_SHORT), 16);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_CHAR), 16);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_INT), 16);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_FLOAT), 16);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_LONG), 16);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_DOUBLE), 16);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_OBJECT), 16);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_ARRAY), 16);
} else {
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_BOOLEAN), 20);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_BYTE), 20);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_SHORT), 20);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_CHAR), 20);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_INT), 20);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_FLOAT), 20);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_LONG), 24);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_DOUBLE), 24);
if (UseCompressedOops) {
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_OBJECT), 20);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_ARRAY), 20);
} else {
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_OBJECT), 24);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_ARRAY), 24);
}
}
#else
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_BOOLEAN), 12);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_BYTE), 12);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_SHORT), 12);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_CHAR), 12);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_INT), 12);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_FLOAT), 12);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_LONG), 16);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_DOUBLE), 16);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_OBJECT), 12);
EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_ARRAY), 12);
#endif
}

View File

@ -0,0 +1,57 @@
/*
* Copyright Amazon.com Inc. 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.
*
* 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.
*/
#include "precompiled.hpp"
#include "oops/objArrayOop.hpp"
#include "unittest.hpp"
#include "utilities/globalDefinitions.hpp"
TEST_VM(objArrayOop, osize) {
static const struct {
int objal; bool ccp; bool coops; int result;
} x[] = {
// ObjAligInB, UseCCP, UseCoops, object size in heap words
#ifdef _LP64
{ 8, false, false, 4 }, // 20 byte header, 8 byte oops
{ 8, false, true, 3 }, // 20 byte header, 4 byte oops
{ 8, true, false, 3 }, // 16 byte header, 8 byte oops
{ 8, true, true, 3 }, // 16 byte header, 4 byte oops
{ 16, false, false, 4 }, // 20 byte header, 8 byte oops, 16-byte align
{ 16, false, true, 4 }, // 20 byte header, 4 byte oops, 16-byte align
{ 16, true, false, 4 }, // 16 byte header, 8 byte oops, 16-byte align
{ 16, true, true, 4 }, // 16 byte header, 4 byte oops, 16-byte align
{ 256, false, false, 32 }, // 20 byte header, 8 byte oops, 256-byte align
{ 256, false, true, 32 }, // 20 byte header, 4 byte oops, 256-byte align
{ 256, true, false, 32 }, // 16 byte header, 8 byte oops, 256-byte align
{ 256, true, true, 32 }, // 16 byte header, 4 byte oops, 256-byte align
#else
{ 8, false, false, 4 }, // 12 byte header, 4 byte oops, wordsize 4
#endif
{ -1, false, false, -1 }
};
for (int i = 0; x[i].result != -1; i++) {
if (x[i].objal == (int)ObjectAlignmentInBytes && x[i].ccp == UseCompressedClassPointers && x[i].coops == UseCompressedOops) {
EXPECT_EQ(objArrayOopDesc::object_size(1), (size_t)x[i].result);
}
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright Amazon.com Inc. 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.
*
* 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.
*
*/
/*
* This tests object array sizes by running gtests with different settings.
*/
/* @test id=with-coops-with-ccp
* @summary Run object array size tests with compressed oops and compressed class pointers
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.xml
* @run main/native GTestWrapper --gtest_filter=arrayOop -XX:+UseCompressedClassPointers -XX:+UseCompressedOops
*/
/* @test id=with-coops-no-ccp
* @summary Run object array size tests with compressed oops and compressed class pointers
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.xml
* @run main/native GTestWrapper --gtest_filter=arrayOop -XX:-UseCompressedClassPointers -XX:+UseCompressedOops
*/
/* @test id=no-coops-with-ccp
* @summary Run object array size tests with compressed oops and compressed class pointers
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.xml
* @run main/native GTestWrapper --gtest_filter=arrayOop -XX:+UseCompressedClassPointers -XX:-UseCompressedOops
*/
/* @test id=no-coops-no-ccp
* @summary Run object array size tests with compressed oops and compressed class pointers
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.xml
* @run main/native GTestWrapper --gtest_filter=arrayOop -XX:-UseCompressedClassPointers -XX:-UseCompressedOops
*/

View File

@ -0,0 +1,85 @@
/*
* Copyright Amazon.com Inc. 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.
*
* 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.
*
*/
/*
* This tests object array sizes by running gtests with different settings.
*/
/* @test id=with-coops-with-ccp
* @summary Run object array size tests with compressed oops and compressed class pointers
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.xml
* @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:+UseCompressedClassPointers -XX:+UseCompressedOops
*/
/* @test id=with-coops-no-ccp
* @summary Run object array size tests with compressed oops and compressed class pointers
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.xml
* @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:-UseCompressedClassPointers -XX:+UseCompressedOops
*/
/* @test id=no-coops-with-ccp
* @summary Run object array size tests with compressed oops and compressed class pointers
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.xml
* @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:+UseCompressedClassPointers -XX:-UseCompressedOops
*/
/* @test id=no-coops-no-ccp
* @summary Run object array size tests with compressed oops and compressed class pointers
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.xml
* @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:-UseCompressedClassPointers -XX:-UseCompressedOops
*/
/* @test id=with-coops-with-ccp-large-align
* @summary Run object array size tests with compressed oops and compressed class pointers
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.xml
* @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:ObjAlignmentInBytes=256
*/
/* @test id=with-coops-no-ccp-large-align
* @summary Run object array size tests with compressed oops and compressed class pointers
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.xml
* @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:-UseCompressedClassPointers -XX:+UseCompressedOops -XX:ObjAlignmentInBytes=256
*/
/* @test id=no-coops-with-ccp-large-align
* @summary Run object array size tests with compressed oops and compressed class pointers
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.xml
* @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:+UseCompressedClassPointers -XX:-UseCompressedOops -XX:ObjAlignmentInBytes=256
*/
/* @test id=no-coops-no-ccp-large-align
* @summary Run object array size tests with compressed oops and compressed class pointers
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.xml
* @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:-UseCompressedClassPointers -XX:-UseCompressedOops -XX:ObjAlignmentInBytes=256
*/

View File

@ -0,0 +1,113 @@
/*
* Copyright Amazon.com Inc. 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.
*
* 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.
*/
/*
* @test id=with-coops-no-ccp
* @library /test/lib
* @requires vm.bits == "64"
* @modules java.base/jdk.internal.misc
* @run main/othervm -XX:+UseCompressedOops -XX:-UseCompressedClassPointers ArrayBaseOffsets
*/
/*
* @test id=with-coops-with-ccp
* @library /test/lib
* @requires vm.bits == "64"
* @requires vm.opt.UseCompressedClassPointers != false
* @modules java.base/jdk.internal.misc
* @run main/othervm -XX:+UseCompressedOops -XX:+UseCompressedClassPointers ArrayBaseOffsets
*/
/*
* @test id=no-coops-no-ccp
* @library /test/lib
* @requires vm.bits == "64"
* @modules java.base/jdk.internal.misc
* @run main/othervm -XX:-UseCompressedOops -XX:-UseCompressedClassPointers ArrayBaseOffsets
*/
/*
* @test id=no-coops-with-ccp
* @library /test/lib
* @requires vm.bits == "64"
* @requires vm.opt.UseCompressedClassPointers != false
* @modules java.base/jdk.internal.misc
* @run main/othervm -XX:-UseCompressedOops -XX:+UseCompressedClassPointers ArrayBaseOffsets
*/
/*
* @test id=32bit
* @library /test/lib
* @requires vm.bits == "32"
* @modules java.base/jdk.internal.misc
* @run main/othervm ArrayBaseOffsets
*/
import jdk.internal.misc.Unsafe;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.List;
import jdk.test.lib.Asserts;
import jdk.test.lib.Platform;
public class ArrayBaseOffsets {
private static final boolean COOP;
private static final boolean CCP;
static {
if (Platform.is64bit()) {
RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
List<String> vmargs = runtime.getInputArguments();
CCP = !vmargs.contains("-XX:-UseCompressedClassPointers");
COOP = System.getProperty("java.vm.compressedOopsMode") != null;
} else {
COOP = CCP = false;
}
}
static public void main(String[] args) {
Unsafe unsafe = Unsafe.getUnsafe();
int intOffset, longOffset;
if (Platform.is64bit()) {
if (CCP) {
intOffset = 16;
longOffset = 16;
} else {
intOffset = 20;
longOffset = 24;
}
} else {
intOffset = 12;
longOffset = 16;
}
Asserts.assertEquals(unsafe.arrayBaseOffset(boolean[].class), intOffset, "Misplaced boolean array base");
Asserts.assertEquals(unsafe.arrayBaseOffset(byte[].class), intOffset, "Misplaced byte array base");
Asserts.assertEquals(unsafe.arrayBaseOffset(char[].class), intOffset, "Misplaced char array base");
Asserts.assertEquals(unsafe.arrayBaseOffset(short[].class), intOffset, "Misplaced short array base");
Asserts.assertEquals(unsafe.arrayBaseOffset(int[].class), intOffset, "Misplaced int array base");
Asserts.assertEquals(unsafe.arrayBaseOffset(long[].class), longOffset, "Misplaced long array base");
Asserts.assertEquals(unsafe.arrayBaseOffset(float[].class), intOffset, "Misplaced float array base");
Asserts.assertEquals(unsafe.arrayBaseOffset(double[].class), longOffset, "Misplaced double array base");
int expectedObjArrayOffset = (COOP || !Platform.is64bit()) ? intOffset : longOffset;
Asserts.assertEquals(unsafe.arrayBaseOffset(Object[].class), expectedObjArrayOffset, "Misplaced object array base");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2022, Red Hat, Inc. All rights reserved.
* Copyright (c) 2020, 2024, Red Hat, Inc. 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
@ -313,6 +313,9 @@ public class GetObjectSizeIntrinsicsTest extends ASimpleInstrumentationTestCase
static final int LARGE_INT_ARRAY_SIZE = 1024*1024*1024 + 1024;
static final int LARGE_OBJ_ARRAY_SIZE = (4096/(int)REF_SIZE)*1024*1024 + 1024;
static final boolean CCP = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedClassPointers");
static final int ARRAY_HEADER_SIZE = CCP ? 16 : (Platform.is64bit() ? 20 : 16);
final String mode;
public GetObjectSizeIntrinsicsTest(String name, String mode) {
@ -396,7 +399,7 @@ public class GetObjectSizeIntrinsicsTest extends ASimpleInstrumentationTestCase
}
private void testSize_newSmallIntArray() {
long expected = roundUp(4L*SMALL_ARRAY_SIZE + 16, OBJ_ALIGN);
long expected = roundUp(4L*SMALL_ARRAY_SIZE + ARRAY_HEADER_SIZE, OBJ_ALIGN);
for (int c = 0; c < ITERS; c++) {
assertEquals(expected, fInst.getObjectSize(new int[SMALL_ARRAY_SIZE]));
}
@ -404,7 +407,7 @@ public class GetObjectSizeIntrinsicsTest extends ASimpleInstrumentationTestCase
private void testSize_localSmallIntArray() {
int[] arr = new int[SMALL_ARRAY_SIZE];
long expected = roundUp(4L*SMALL_ARRAY_SIZE + 16, OBJ_ALIGN);
long expected = roundUp(4L*SMALL_ARRAY_SIZE + ARRAY_HEADER_SIZE, OBJ_ALIGN);
for (int c = 0; c < ITERS; c++) {
assertEquals(expected, fInst.getObjectSize(arr));
}
@ -413,14 +416,14 @@ public class GetObjectSizeIntrinsicsTest extends ASimpleInstrumentationTestCase
static int[] smallArr = new int[SMALL_ARRAY_SIZE];
private void testSize_fieldSmallIntArray() {
long expected = roundUp(4L*SMALL_ARRAY_SIZE + 16, OBJ_ALIGN);
long expected = roundUp(4L*SMALL_ARRAY_SIZE + ARRAY_HEADER_SIZE, OBJ_ALIGN);
for (int c = 0; c < ITERS; c++) {
assertEquals(expected, fInst.getObjectSize(smallArr));
}
}
private void testSize_newSmallObjArray() {
long expected = roundUp(REF_SIZE*SMALL_ARRAY_SIZE + 16, OBJ_ALIGN);
long expected = roundUp(REF_SIZE*SMALL_ARRAY_SIZE + ARRAY_HEADER_SIZE, OBJ_ALIGN);
for (int c = 0; c < ITERS; c++) {
assertEquals(expected, fInst.getObjectSize(new Object[SMALL_ARRAY_SIZE]));
}
@ -428,7 +431,7 @@ public class GetObjectSizeIntrinsicsTest extends ASimpleInstrumentationTestCase
private void testSize_localSmallObjArray() {
Object[] arr = new Object[SMALL_ARRAY_SIZE];
long expected = roundUp(REF_SIZE*SMALL_ARRAY_SIZE + 16, OBJ_ALIGN);
long expected = roundUp(REF_SIZE*SMALL_ARRAY_SIZE + ARRAY_HEADER_SIZE, OBJ_ALIGN);
for (int c = 0; c < ITERS; c++) {
assertEquals(expected, fInst.getObjectSize(arr));
}
@ -437,7 +440,7 @@ public class GetObjectSizeIntrinsicsTest extends ASimpleInstrumentationTestCase
static Object[] smallObjArr = new Object[SMALL_ARRAY_SIZE];
private void testSize_fieldSmallObjArray() {
long expected = roundUp(REF_SIZE*SMALL_ARRAY_SIZE + 16, OBJ_ALIGN);
long expected = roundUp(REF_SIZE*SMALL_ARRAY_SIZE + ARRAY_HEADER_SIZE, OBJ_ALIGN);
for (int c = 0; c < ITERS; c++) {
assertEquals(expected, fInst.getObjectSize(smallObjArr));
}
@ -445,7 +448,7 @@ public class GetObjectSizeIntrinsicsTest extends ASimpleInstrumentationTestCase
private void testSize_localLargeIntArray() {
int[] arr = new int[LARGE_INT_ARRAY_SIZE];
long expected = roundUp(4L*LARGE_INT_ARRAY_SIZE + 16, OBJ_ALIGN);
long expected = roundUp(4L*LARGE_INT_ARRAY_SIZE + ARRAY_HEADER_SIZE, OBJ_ALIGN);
for (int c = 0; c < ITERS; c++) {
assertEquals(expected, fInst.getObjectSize(arr));
}
@ -453,7 +456,7 @@ public class GetObjectSizeIntrinsicsTest extends ASimpleInstrumentationTestCase
private void testSize_localLargeObjArray() {
Object[] arr = new Object[LARGE_OBJ_ARRAY_SIZE];
long expected = roundUp(REF_SIZE*LARGE_OBJ_ARRAY_SIZE + 16, OBJ_ALIGN);
long expected = roundUp(REF_SIZE*LARGE_OBJ_ARRAY_SIZE + ARRAY_HEADER_SIZE, OBJ_ALIGN);
for (int c = 0; c < ITERS; c++) {
assertEquals(expected, fInst.getObjectSize(arr));
}