Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/hotspot/share/c1/c1_Instruction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,7 @@ class DelayedLoadIndexed : public CompilationResourceObj {
LoadIndexed* _load_instr;
ValueStack* _state_before;
ciField* _field;
int _offset;
size_t _offset;
public:
DelayedLoadIndexed(LoadIndexed* load, ValueStack* state_before)
: _load_instr(load)
Expand All @@ -1011,14 +1011,15 @@ class DelayedLoadIndexed : public CompilationResourceObj {
, _offset(0) { }

void update(ciField* field, int offset) {
assert(offset >= 0, "must be");
_field = field;
_offset += offset;
}

LoadIndexed* load_instr() const { return _load_instr; }
ValueStack* state_before() const { return _state_before; }
ciField* field() const { return _field; }
int offset() const { return _offset; }
size_t offset() const { return _offset; }
};

LEAF(StoreIndexed, AccessIndexed)
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/c1/c1_InstructionPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ void InstructionPrinter::do_ArrayLength(ArrayLength* x) {
void InstructionPrinter::do_LoadIndexed(LoadIndexed* x) {
print_indexed(x);
if (x->delayed() != nullptr) {
output()->print(" +%d", x->delayed()->offset());
output()->print(" +%zu", x->delayed()->offset());
output()->print(" (%c)", type2char(x->delayed()->field()->type()->basic_type()));
} else {
output()->print(" (%c)", type2char(x->elt_type()));
Expand Down
8 changes: 4 additions & 4 deletions src/hotspot/share/c1/c1_LIRGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1757,7 +1757,7 @@ void LIRGenerator::access_sub_element(LIRItem& array, LIRItem& index, LIR_Opr& r
}

void LIRGenerator::access_flat_array(bool is_load, LIRItem& array, LIRItem& index, LIRItem& obj_item,
ciField* field, int sub_offset) {
ciField* field, size_t sub_offset) {
assert(sub_offset == 0 || field != nullptr, "Sanity check");

// Find the starting address of the source (inside the array)
Expand All @@ -1773,7 +1773,7 @@ void LIRGenerator::access_flat_array(bool is_load, LIRItem& array, LIRItem& inde
ciField* inner_field = elem_klass->nonstatic_field_at(i);
assert(!inner_field->is_flat(), "flat fields must have been expanded");
int obj_offset = inner_field->offset_in_bytes();
int elm_offset = obj_offset - elem_klass->payload_offset() + sub_offset; // object header is not stored in array.
size_t elm_offset = obj_offset - elem_klass->payload_offset() + sub_offset; // object header is not stored in array.
BasicType field_type = inner_field->type()->basic_type();

// Types which are smaller than int are still passed in an int register.
Expand All @@ -1796,7 +1796,7 @@ void LIRGenerator::access_flat_array(bool is_load, LIRItem& array, LIRItem& inde
DecoratorSet decorators = IN_HEAP;
if (is_load) {
access_load_at(decorators, field_type,
elm_item, LIR_OprFact::intConst(elm_offset), temp,
elm_item, LIR_OprFact::longConst(elm_offset), temp,
nullptr, nullptr);
access_store_at(decorators, field_type,
obj_item, LIR_OprFact::intConst(obj_offset), temp,
Expand All @@ -1806,7 +1806,7 @@ void LIRGenerator::access_flat_array(bool is_load, LIRItem& array, LIRItem& inde
obj_item, LIR_OprFact::intConst(obj_offset), temp,
nullptr, nullptr);
access_store_at(decorators, field_type,
elm_item, LIR_OprFact::intConst(elm_offset), temp,
elm_item, LIR_OprFact::longConst(elm_offset), temp,
nullptr, nullptr);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/c1/c1_LIRGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
void do_vectorizedMismatch(Intrinsic* x);
void do_blackhole(Intrinsic* x);

void access_flat_array(bool is_load, LIRItem& array, LIRItem& index, LIRItem& obj_item, ciField* field = nullptr, int offset = 0);
void access_flat_array(bool is_load, LIRItem& array, LIRItem& index, LIRItem& obj_item, ciField* field = nullptr, size_t offset = 0);
void access_sub_element(LIRItem& array, LIRItem& index, LIR_Opr& result, ciField* field, int sub_offset);
LIR_Opr get_and_load_element_address(LIRItem& array, LIRItem& index);
bool needs_flat_array_store_check(StoreIndexed* x);
Expand Down
10 changes: 7 additions & 3 deletions src/hotspot/share/oops/flatArrayOop.inline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ inline void* flatArrayOopDesc::base() const { return arrayOopDesc::base(T_FLAT_E
inline void* flatArrayOopDesc::value_at_addr(int index, jint lh) const {
assert(is_within_bounds(index), "index out of bounds");

address addr = (address) base();
addr += (index << Klass::layout_helper_log2_element_size(lh));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because index is an int, this could go negative right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep.

address array_base = (address) base();
ptrdiff_t offset = (ptrdiff_t) index << Klass::layout_helper_log2_element_size(lh);
address addr = array_base + offset;
assert(addr >= array_base, "must be");
return (void*) addr;
}

Expand All @@ -56,7 +58,9 @@ inline oop flatArrayOopDesc::obj_at(int index, TRAPS) const {
assert(is_within_bounds(index), "index %d out of bounds %d", index, length());
FlatArrayKlass* faklass = FlatArrayKlass::cast(klass());
InlineKlass* vk = InlineKlass::cast(faklass->element_klass());
int offset = ((char*)value_at_addr(index, faklass->layout_helper())) - ((char*)(oopDesc*)this);
char* this_oop = (char*) (oopDesc*) this;
char* val = (char*) value_at_addr(index, faklass->layout_helper());
ptrdiff_t offset = val - this_oop;
oop res = vk->read_payload_from_addr((oopDesc*)this, offset, faklass->layout_kind(), CHECK_NULL);
return res;
}
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/oops/inlineKlass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ void InlineKlass::copy_payload_to_addr(void* src, void* dst, LayoutKind lk, bool
}
}

oop InlineKlass::read_payload_from_addr(const oop src, int offset, LayoutKind lk, TRAPS) {
oop InlineKlass::read_payload_from_addr(const oop src, size_t offset, LayoutKind lk, TRAPS) {
assert(src != nullptr, "Must be");
assert(is_layout_supported(lk), "Unsupported layout");
switch(lk) {
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/oops/inlineKlass.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ class InlineKlass: public InstanceKlass {
// is compatible with all the other layouts.

void write_value_to_addr(oop src, void* dst, LayoutKind lk, bool dest_is_initialized, TRAPS);
oop read_payload_from_addr(const oop src, int offset, LayoutKind lk, TRAPS);
oop read_payload_from_addr(const oop src, size_t offset, LayoutKind lk, TRAPS);
void copy_payload_to_addr(void* src, void* dst, LayoutKind lk, bool dest_is_initialized);

// oop iterate raw inline type data pointer (where oop_addr may not be an oop, but backing/array-element)
Expand Down
65 changes: 65 additions & 0 deletions test/hotspot/gtest/oops/test_flatArrayOop.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2025, 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.
*
* 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 "oops/flatArrayOop.hpp"
#include "unittest.hpp"
#include "utilities/globalDefinitions.hpp"

// INTENTIONALLY SMALL BACKING, SHOULD ONLY CONTAIN METADATA + A FEW ELEMENTS.
static unsigned char memory[1024];

// Do not perform operations on the array's memory without ensuring that the
// backing is large enough and you will not go out of bounds.
static flatArrayOop fake_flat_array(int length) {
flatArrayOop farr = flatArrayOop(cast_to_oop(memory));
// We can't ensure the backing for the length, but we can still do pointer
// arithmetic and e.g. ensure that the resulting pointers didn't overflow.
farr->set_length(length);
return farr;
}

// What FlatArrayKlass::array_layout_helper does, but w/o InlineKlass
static int make_lh(int payload_size_bytes, bool null_free) {
BasicType etype = T_FLAT_ELEMENT;
int esize = log2i_exact(round_up_power_of_2(payload_size_bytes));
int hsize = arrayOopDesc::base_offset_in_bytes(etype);
return Klass::array_layout_helper(Klass::_lh_array_tag_flat_value, null_free, hsize, etype, esize);
}

static void ensure_no_overflow(flatArrayOop farr, int lh) {
void* vaa_small = farr->value_at_addr(123, lh);
EXPECT_TRUE(vaa_small >= farr);
void* vaa_large = farr->value_at_addr(321999888, lh);
EXPECT_TRUE(vaa_large >= farr);
}

TEST_VM(flatArrayOopDesc, value_at_addr_intbox_nullable) {
flatArrayOop farr = fake_flat_array(500000000);
ensure_no_overflow(farr, make_lh(8, false));
}


TEST_VM(flatArrayOopDesc, value_at_addr_intbox_null_free) {
flatArrayOop farr = fake_flat_array(500000000);
ensure_no_overflow(farr, make_lh(4, true));
}