| /* | |
| * Copyright (c) 2000, 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. | |
| * | |
| */ | |
| #ifndef SHARE_OOPS_ARRAY_HPP | |
| #define SHARE_OOPS_ARRAY_HPP | |
| #include "runtime/atomic.hpp" | |
| #include "utilities/align.hpp" | |
| #include "utilities/exceptions.hpp" | |
| #include "utilities/globalDefinitions.hpp" | |
| #include "utilities/ostream.hpp" | |
| // Array for metadata allocation | |
| template <typename T> | |
| class Array: public MetaspaceObj { | |
| friend class ArchiveBuilder; | |
| friend class MetadataFactory; | |
| friend class VMStructs; | |
| friend class JVMCIVMStructs; | |
| friend class MethodHandleCompiler; // special case | |
| friend class WhiteBox; | |
| friend class FieldInfoStream; | |
| protected: | |
| int _length; // the number of array elements | |
| T _data[1]; // the array memory | |
| void initialize(int length) { | |
| _length = length; | |
| } | |
| private: | |
| NONCOPYABLE(Array); | |
| inline void* operator new(size_t size, ClassLoaderData* loader_data, int length, TRAPS) throw(); | |
| inline void* operator new(size_t size, ClassLoaderData* loader_data, int length) throw(); | |
| // Work-around -- see JDK-8331086 | |
| inline void* operator new(size_t size, int length, MemTag flags) throw(); | |
| static size_t byte_sizeof(int length, size_t elm_byte_size) { | |
| return sizeof(Array<T>) + MAX2(length - 1, 0) * elm_byte_size; | |
| } | |
| static size_t byte_sizeof(int length) { return byte_sizeof(length, sizeof(T)); } | |
| // WhiteBox API helper. | |
| // Can't distinguish between array of length 0 and length 1, | |
| // will always return 0 in those cases. | |
| static int bytes_to_length(size_t bytes) { | |
| assert(is_aligned(bytes, BytesPerWord), "Must be, for now"); | |
| if (sizeof(Array<T>) >= bytes) { | |
| return 0; | |
| } | |
| size_t left = bytes - sizeof(Array<T>); | |
| assert(is_aligned(left, sizeof(T)), "Must be"); | |
| size_t elements = left / sizeof(T); | |
| assert(elements <= (size_t)INT_MAX, "number of elements %zu doesn't fit into an int.", elements); | |
| int length = (int)elements; | |
| assert((size_t)size(length) * BytesPerWord == (size_t)bytes, | |
| "Expected: %zu got: %zu", | |
| bytes, (size_t)size(length) * BytesPerWord); | |
| return length; | |
| } | |
| explicit Array(int length) : _length(length) { | |
| assert(length >= 0, "illegal length"); | |
| } | |
| Array(int length, T init) : _length(length) { | |
| assert(length >= 0, "illegal length"); | |
| for (int i = 0; i < length; i++) { | |
| data()[i] = init; | |
| } | |
| } | |
| public: | |
| // standard operations | |
| int length() const { return _length; } | |
| T* data() { | |
| return reinterpret_cast<T*>( | |
| reinterpret_cast<char*>(this) + base_offset_in_bytes()); | |
| } | |
| const T* data() const { | |
| return reinterpret_cast<const T*>( | |
| reinterpret_cast<const char*>(this) + base_offset_in_bytes()); | |
| } | |
| bool is_empty() const { return length() == 0; } | |
| int index_of(const T& x) const { | |
| int i = length(); | |
| while (i-- > 0 && data()[i] != x) ; | |
| return i; | |
| } | |
| // sort the array. | |
| bool contains(const T& x) const { return index_of(x) >= 0; } | |
| T at(int i) const { assert(i >= 0 && i< _length, "oob: 0 <= %d < %d", i, _length); return data()[i]; } | |
| void at_put(const int i, const T& x) { assert(i >= 0 && i< _length, "oob: 0 <= %d < %d", i, _length); data()[i] = x; } | |
| T* adr_at(const int i) { assert(i >= 0 && i< _length, "oob: 0 <= %d < %d", i, _length); return &data()[i]; } | |
| int find(const T& x) { return index_of(x); } | |
| T at_acquire(const int i) { return Atomic::load_acquire(adr_at(i)); } | |
| void release_at_put(int i, T x) { Atomic::release_store(adr_at(i), x); } | |
| static int size(int length) { | |
| size_t bytes = align_up(byte_sizeof(length), BytesPerWord); | |
| size_t words = bytes / BytesPerWord; | |
| assert(words <= INT_MAX, "Overflow: %zu", words); | |
| return (int)words; | |
| } | |
| int size() { | |
| return size(_length); | |
| } | |
| static int length_offset_in_bytes() { return (int) (offset_of(Array<T>, _length)); } | |
| // Note, this offset don't have to be wordSize aligned. | |
| static int base_offset_in_bytes() { return (int) (offset_of(Array<T>, _data)); }; | |
| // FIXME: How to handle this? | |
| void print_value_on(outputStream* st) const { | |
| st->print("Array<T>(" PTR_FORMAT ")", p2i(this)); | |
| } | |
| #ifndef PRODUCT | |
| void print(outputStream* st) { | |
| for (int i = 0; i< _length; i++) { | |
| st->print_cr("%d: " INTPTR_FORMAT, i, (intptr_t)at(i)); | |
| } | |
| } | |
| void print() { print(tty); } | |
| #endif // PRODUCT | |
| }; | |
| #endif // SHARE_OOPS_ARRAY_HPP |