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