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 // Current value of an element.
34 // Returns T_ILLEGAL if there is no element at the given index.
35 ciConstant ciFlatArray::null_marker_of_element_by_index(int index) {
36 ciConstant nm = field_value(index, nullptr);
37 postcond(!nm.is_valid() || nm.basic_type() == T_BOOLEAN);
38 return nm;
39 }
40
41 ciConstant ciFlatArray::null_marker_of_element_by_offset(intptr_t element_offset) {
42 FlatArrayKlass* faklass;
43 GUARDED_VM_ENTRY(faklass = FlatArrayKlass::cast(get_arrayOop()->klass());)
44 int lh = faklass->layout_helper();
45 int shift = Klass::layout_helper_log2_element_size(lh);
46 intptr_t header = arrayOopDesc::base_offset_in_bytes(T_FLAT_ELEMENT);
47 intptr_t index = (element_offset - header) >> shift;
48 intptr_t offset = header + (index << shift);
49 if (offset != element_offset || index != (jint) index || index < 0 || index >= length()) {
50 return ciConstant();
51 }
52 return null_marker_of_element_by_index((jint) index);
53 }
54
55 ciConstant ciFlatArray::element_value_by_offset(intptr_t element_offset) {
56 FlatArrayKlass* faklass;
57 GUARDED_VM_ENTRY(faklass = FlatArrayKlass::cast(get_arrayOop()->klass());)
58 int lh = faklass->layout_helper();
59 int shift = Klass::layout_helper_log2_element_size(lh);
60 intptr_t header = arrayOopDesc::base_offset_in_bytes(T_FLAT_ELEMENT);
61 intptr_t index = (element_offset - header) >> shift;
62 intptr_t offset = header + (index << shift);
63 if (offset != element_offset || index != (jint) index || index < 0 || index >= length()) {
64 return ciConstant();
65 }
66 return element_value((jint) index);
67 }
68
69 ciConstant ciFlatArray::field_value_by_offset(intptr_t field_offset) {
70 ciInlineKlass* elt_type = element_type()->as_inline_klass();
71 FlatArrayKlass* faklass;
72 GUARDED_VM_ENTRY(faklass = FlatArrayKlass::cast(get_arrayOop()->klass());)
73 int lh = faklass->layout_helper();
74 int shift = Klass::layout_helper_log2_element_size(lh);
75 intptr_t header = arrayOopDesc::base_offset_in_bytes(T_FLAT_ELEMENT);
76 intptr_t index = (field_offset - header) >> shift;
77 intptr_t element_offset = header + (index << shift);
78 int field_offset_in_element = (int)(field_offset - element_offset);
79 ciField* field = elt_type->get_field_by_offset(elt_type->payload_offset() + field_offset_in_element, false);
80 if (field == nullptr) {
81 if (field_offset_in_element != elt_type->null_marker_offset_in_payload()) {
82 return ciConstant();
83 }
84 }
85
86 if (index != (jint) index || index < 0 || index >= length()) {
87 return ciConstant();
88 }
89 ciConstant elt = field_value((jint) index, field);
90
91 return elt;
92 }
93
94 ciConstant ciFlatArray::field_value(int index, ciField* field) {
95 auto get_field_from_object_constant = [field](const ciConstant& v) -> ciConstant {
96 ciObject* obj = v.as_object();
97 if (obj->is_null_object()) {
98 if (field == nullptr) {
99 return ciConstant::make_zero_or_null(T_BOOLEAN);
100 }
101 return ciConstant::make_zero_or_null(field->type()->basic_type());
102 }
103 // obj cannot be an ciArray since it is an element of a flat array, so it must be a value class, which arrays are not.
104 ciInstance* inst = obj->as_instance();
105 if (field == nullptr) {
106 return ciConstant(T_BOOLEAN, 1);
107 }
108 return inst->field_value(field);
109 };
110
111 BasicType elembt = element_basic_type();
112 ciConstant value = check_constant_value_cache(index, elembt);
113 if (value.is_valid()) {
114 return get_field_from_object_constant(value);
115 }
116 GUARDED_VM_ENTRY(
117 value = element_value_impl(T_OBJECT, get_arrayOop(), index);
118 )
119
120 if (!value.is_valid()) {
121 return ciConstant();
122 }
123
124 add_to_constant_value_cache(index, value);
125 return get_field_from_object_constant(value);
126 }
127