1 /*
2 * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include "ci/ciArray.hpp"
26 #include "ci/ciConstant.hpp"
27 #include "ci/ciField.hpp"
28 #include "ci/ciFlatArray.hpp"
29 #include "ci/ciInlineKlass.hpp"
30 #include "ci/ciUtilities.inline.hpp"
31 #include "oops/oop.inline.hpp"
32
33 ciConstant ciFlatArray::null_marker_of_element_by_offset_impl(arrayOop ary, int index) {
34 if (ary == nullptr) {
35 return ciConstant();
36 }
37 assert(ary->is_array(), "");
38 if (index < 0 || index >= ary->length()) {
39 return ciConstant();
40 }
41 assert(ary->is_objArray(), "");
42 flatArrayOop objary = (flatArrayOop) ary;
43 jboolean elem = objary->null_marker_of_obj_at(index);
44 return ciConstant(T_BOOLEAN, elem);
45 }
46
47 ciConstant ciFlatArray::check_constant_null_marker_cache(int off) {
48 if (_constant_null_markers != nullptr) {
49 for (int i = 0; i < _constant_null_markers->length(); ++i) {
50 ConstantValue cached_val = _constant_null_markers->at(i);
51 if (cached_val.off() == off) {
52 return cached_val.value();
53 }
54 }
55 }
56 return ciConstant();
57 }
58
59 void ciFlatArray::add_to_constant_null_marker_cache(int off, ciConstant val) {
60 assert(val.is_valid(), "value must be valid");
61 assert(!check_constant_value_cache(off, val.basic_type()).is_valid(), "duplicate");
62 if (_constant_null_markers == nullptr) {
63 Arena* arena = CURRENT_ENV->arena();
64 _constant_null_markers = new (arena) GrowableArray<ConstantValue>(arena, 1, 0, ConstantValue());
65 }
66 _constant_null_markers->append(ConstantValue(off, val));
67 }
68
69 // Current value of an element.
70 // Returns T_ILLEGAL if there is no element at the given index.
71 ciConstant ciFlatArray::null_marker_of_element_by_index(int index) {
72 ciConstant value = check_constant_null_marker_cache(index);
73 if (value.is_valid()) {
74 return value;
75 }
76 GUARDED_VM_ENTRY(
77 value = null_marker_of_element_by_offset_impl(get_arrayOop(), index);)
78 add_to_constant_null_marker_cache(index, value);
79 return value;
80 }
81
82 ciConstant ciFlatArray::null_marker_of_element_by_offset(intptr_t element_offset) {
83 FlatArrayKlass* faklass;
84 GUARDED_VM_ENTRY(faklass = FlatArrayKlass::cast(get_arrayOop()->klass());)
85 int lh = faklass->layout_helper();
86 int shift = Klass::layout_helper_log2_element_size(lh);
87 intptr_t header = arrayOopDesc::base_offset_in_bytes(T_FLAT_ELEMENT);
88 intptr_t index = (element_offset - header) >> shift;
89 intptr_t offset = header + (index << shift);
90 if (offset != element_offset || index != (jint) index || index < 0 || index >= length()) {
91 return ciConstant();
92 }
93 return null_marker_of_element_by_index((jint) index);
94 }
95
96 ciConstant ciFlatArray::element_value_by_offset(intptr_t element_offset) {
97 FlatArrayKlass* faklass;
98 GUARDED_VM_ENTRY(faklass = FlatArrayKlass::cast(get_arrayOop()->klass());)
99 int lh = faklass->layout_helper();
100 int shift = Klass::layout_helper_log2_element_size(lh);
101 intptr_t header = arrayOopDesc::base_offset_in_bytes(T_FLAT_ELEMENT);
102 intptr_t index = (element_offset - header) >> shift;
103 intptr_t offset = header + (index << shift);
104 if (offset != element_offset || index != (jint) index || index < 0 || index >= length()) {
105 return ciConstant();
106 }
107 return element_value((jint) index);
108 }
109
110 ciConstant ciFlatArray::field_value_by_offset(intptr_t field_offset) {
111 ciInlineKlass* elt_type = element_type()->as_inline_klass();
112 FlatArrayKlass* faklass;
113 GUARDED_VM_ENTRY(faklass = FlatArrayKlass::cast(get_arrayOop()->klass());)
114 int lh = faklass->layout_helper();
115 int shift = Klass::layout_helper_log2_element_size(lh);
116 intptr_t header = arrayOopDesc::base_offset_in_bytes(T_FLAT_ELEMENT);
117 intptr_t index = (field_offset - header) >> shift;
118 intptr_t element_offset = header + (index << shift);
119 int field_offset_in_element = (int)(field_offset - element_offset);
120 ciField* field = elt_type->get_field_by_offset(elt_type->payload_offset() + field_offset_in_element, false);
121 if (field == nullptr) {
122 if (field_offset_in_element != elt_type->null_marker_offset_in_payload()) {
123 return ciConstant();
124 }
125 }
126
127 if (index != (jint) index || index < 0 || index >= length()) {
128 return ciConstant();
129 }
130 ciConstant elt = field_value((jint) index, field);
131
132 return elt;
133 }
134
135 ciConstant ciFlatArray::field_value(int index, ciField* field) {
136 BasicType elembt = element_basic_type();
137 ciConstant value = check_constant_value_cache(index, elembt);
138 if (value.is_valid()) {
139 if (field == nullptr) {
140 return value.as_object()->as_instance()->null_marker_value();
141 }
142 return value.as_object()->as_instance()->field_value(field);
143 }
144 GUARDED_VM_ENTRY(
145 value = element_value_impl(T_OBJECT, get_arrayOop(), index);
146 )
147
148 add_to_constant_value_cache(index, value);
149
150 if (field == nullptr) {
151 return value.as_object()->as_instance()->null_marker_value();
152 }
153 return value.as_object()->as_instance()->field_value(field);
154 }
155