1 /*
2 * Copyright (c) 1997, 2020, 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 #ifndef SHARE_UTILITIES_ALIGN_HPP
26 #define SHARE_UTILITIES_ALIGN_HPP
27
28 #include "metaprogramming/enableIf.hpp"
29 #include "utilities/debug.hpp"
30 #include "utilities/globalDefinitions.hpp"
31 #include "utilities/powerOfTwo.hpp"
32 #include <type_traits>
33
34 // Compute mask to use for aligning to or testing alignment.
35 // The alignment must be a power of 2. Returns alignment - 1, which is
36 // a mask with all bits set below alignment's single bit.
37 template<typename T, ENABLE_IF(std::is_integral<T>::value)>
alignment_mask(T alignment)38 static constexpr T alignment_mask(T alignment) {
39 assert(is_power_of_2(alignment),
40 "must be a power of 2: " UINT64_FORMAT, (uint64_t)alignment);
41 return alignment - 1;
42 }
43
44 // Some "integral" constant alignments are defined via enum.
45 template<typename T, ENABLE_IF(std::is_enum<T>::value)>
alignment_mask(T alignment)46 static constexpr auto alignment_mask(T alignment) {
47 return alignment_mask(static_cast<std::underlying_type_t<T>>(alignment));
48 }
49
50 // Align integers and check for alignment.
51 // The is_integral filtering here is not for disambiguation with the T*
52 // overloads; if those match then they are a better match. Rather, the
53 // is_integral filtering is to prevent back-sliding on the use of enums
54 // as "integral" constants that need aligning.
55
56 template<typename T, typename A, ENABLE_IF(std::is_integral<T>::value)>
is_aligned(T size,A alignment)57 constexpr bool is_aligned(T size, A alignment) {
58 return (size & alignment_mask(alignment)) == 0;
59 }
60
61 template<typename T, typename A, ENABLE_IF(std::is_integral<T>::value)>
align_down(T size,A alignment)62 constexpr T align_down(T size, A alignment) {
63 // Convert mask to T before logical_not. Otherwise, if alignment is unsigned
64 // and smaller than T, the result of the logical_not will be zero-extended
65 // by integral promotion, and upper bits of size will be discarded.
66 T result = size & ~T(alignment_mask(alignment));
67 assert(is_aligned(result, alignment),
68 "must be aligned: " UINT64_FORMAT, (uint64_t)result);
69 return result;
70 }
71
72 template<typename T, typename A, ENABLE_IF(std::is_integral<T>::value)>
align_up(T size,A alignment)73 constexpr T align_up(T size, A alignment) {
74 T adjusted = size + alignment_mask(alignment);
75 return align_down(adjusted, alignment);
76 }
77
78 // Align down with a lower bound. If the aligning results in 0, return 'alignment'.
79 template <typename T, typename A>
align_down_bounded(T size,A alignment)80 constexpr T align_down_bounded(T size, A alignment) {
81 T aligned_size = align_down(size, alignment);
82 return (aligned_size > 0) ? aligned_size : T(alignment);
83 }
84
85 // Align pointers and check for alignment.
86
87 template <typename T, typename A>
align_up(T * ptr,A alignment)88 inline T* align_up(T* ptr, A alignment) {
89 return (T*)align_up((uintptr_t)ptr, alignment);
90 }
91
92 template <typename T, typename A>
align_down(T * ptr,A alignment)93 inline T* align_down(T* ptr, A alignment) {
94 return (T*)align_down((uintptr_t)ptr, alignment);
95 }
96
97 template <typename T, typename A>
is_aligned(T * ptr,A alignment)98 inline bool is_aligned(T* ptr, A alignment) {
99 return is_aligned((uintptr_t)ptr, alignment);
100 }
101
102 // Align metaspace objects by rounding up to natural word boundary
103 template <typename T>
align_metadata_size(T size)104 inline T align_metadata_size(T size) {
105 return align_up(size, 1);
106 }
107
108 // Align objects in the Java Heap by rounding up their size, in HeapWord units.
109 template <typename T>
align_object_size(T word_size)110 inline T align_object_size(T word_size) {
111 return align_up(word_size, MinObjAlignment);
112 }
113
is_object_aligned(size_t word_size)114 inline bool is_object_aligned(size_t word_size) {
115 return is_aligned(word_size, MinObjAlignment);
116 }
117
is_object_aligned(const void * addr)118 inline bool is_object_aligned(const void* addr) {
119 return is_aligned(addr, MinObjAlignmentInBytes);
120 }
121
122 // Pad out certain offsets to jlong alignment, in HeapWord units.
123 template <typename T>
align_object_offset(T offset)124 constexpr T align_object_offset(T offset) {
125 return align_up(offset, HeapWordsPerLong);
126 }
127
128 // Clamp an address to be within a specific page
129 // 1. If addr is on the page it is returned as is
130 // 2. If addr is above the page_address the start of the *next* page will be returned
131 // 3. Otherwise, if addr is below the page_address the start of the page will be returned
132 template <typename T>
clamp_address_in_page(T * addr,T * page_address,size_t page_size)133 inline T* clamp_address_in_page(T* addr, T* page_address, size_t page_size) {
134 if (align_down(addr, page_size) == align_down(page_address, page_size)) {
135 // address is in the specified page, just return it as is
136 return addr;
137 } else if (addr > page_address) {
138 // address is above specified page, return start of next page
139 return align_down(page_address, page_size) + page_size;
140 } else {
141 // address is below specified page, return start of page
142 return align_down(page_address, page_size);
143 }
144 }
145
146 #endif // SHARE_UTILITIES_ALIGN_HPP
147