1 | /* |
2 | * Copyright (c) 1997, 2019, 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 "utilities/globalDefinitions.hpp" |
29 | |
30 | // Signed variants of alignment helpers. There are two versions of each, a macro |
31 | // for use in places like enum definitions that require compile-time constant |
32 | // expressions and a function for all other places so as to get type checking. |
33 | |
34 | // Using '(what) & ~align_mask(alignment)' to align 'what' down is broken when |
35 | // 'alignment' is an unsigned int and 'what' is a wider type. The & operation |
36 | // will widen the inverted mask, and not sign extend it, leading to a mask with |
37 | // zeros in the most significant bits. The use of align_mask_widened() solves |
38 | // this problem. |
39 | #define align_mask(alignment) ((alignment) - 1) |
40 | #define widen_to_type_of(what, type_carrier) (true ? (what) : (type_carrier)) |
41 | #define align_mask_widened(alignment, type_carrier) widen_to_type_of(align_mask(alignment), (type_carrier)) |
42 | |
43 | #define align_down_(size, alignment) ((size) & ~align_mask_widened((alignment), (size))) |
44 | |
45 | #define align_up_(size, alignment) (align_down_((size) + align_mask(alignment), (alignment))) |
46 | |
47 | #define is_aligned_(size, alignment) (((size) & align_mask(alignment)) == 0) |
48 | |
49 | // Temporary declaration until this file has been restructured. |
50 | template <typename T> |
51 | bool is_power_of_2_t(T x) { |
52 | return (x != T(0)) && ((x & (x - 1)) == T(0)); |
53 | } |
54 | |
55 | // Helpers to align sizes and check for alignment |
56 | |
57 | template <typename T, typename A> |
58 | inline T align_up(T size, A alignment) { |
59 | assert(is_power_of_2_t(alignment), "must be a power of 2: " UINT64_FORMAT, (uint64_t)alignment); |
60 | |
61 | T ret = align_up_(size, alignment); |
62 | assert(is_aligned_(ret, alignment), "must be aligned: " UINT64_FORMAT, (uint64_t)ret); |
63 | |
64 | return ret; |
65 | } |
66 | |
67 | template <typename T, typename A> |
68 | inline T align_down(T size, A alignment) { |
69 | assert(is_power_of_2_t(alignment), "must be a power of 2: " UINT64_FORMAT, (uint64_t)alignment); |
70 | |
71 | T ret = align_down_(size, alignment); |
72 | assert(is_aligned_(ret, alignment), "must be aligned: " UINT64_FORMAT, (uint64_t)ret); |
73 | |
74 | return ret; |
75 | } |
76 | |
77 | template <typename T, typename A> |
78 | inline bool is_aligned(T size, A alignment) { |
79 | assert(is_power_of_2_t(alignment), "must be a power of 2: " UINT64_FORMAT, (uint64_t)alignment); |
80 | |
81 | return is_aligned_(size, alignment); |
82 | } |
83 | |
84 | // Align down with a lower bound. If the aligning results in 0, return 'alignment'. |
85 | template <typename T, typename A> |
86 | inline T align_down_bounded(T size, A alignment) { |
87 | A aligned_size = align_down(size, alignment); |
88 | return aligned_size > 0 ? aligned_size : alignment; |
89 | } |
90 | |
91 | // Helpers to align pointers and check for alignment. |
92 | |
93 | template <typename T, typename A> |
94 | inline T* align_up(T* ptr, A alignment) { |
95 | return (T*)align_up((uintptr_t)ptr, alignment); |
96 | } |
97 | |
98 | template <typename T, typename A> |
99 | inline T* align_down(T* ptr, A alignment) { |
100 | return (T*)align_down((uintptr_t)ptr, alignment); |
101 | } |
102 | |
103 | template <typename T, typename A> |
104 | inline bool is_aligned(T* ptr, A alignment) { |
105 | return is_aligned((uintptr_t)ptr, alignment); |
106 | } |
107 | |
108 | // Align metaspace objects by rounding up to natural word boundary |
109 | template <typename T> |
110 | inline T align_metadata_size(T size) { |
111 | return align_up(size, 1); |
112 | } |
113 | |
114 | // Align objects in the Java Heap by rounding up their size, in HeapWord units. |
115 | template <typename T> |
116 | inline T align_object_size(T word_size) { |
117 | return align_up(word_size, MinObjAlignment); |
118 | } |
119 | |
120 | inline bool is_object_aligned(size_t word_size) { |
121 | return is_aligned(word_size, MinObjAlignment); |
122 | } |
123 | |
124 | inline bool is_object_aligned(const void* addr) { |
125 | return is_aligned(addr, MinObjAlignmentInBytes); |
126 | } |
127 | |
128 | // Pad out certain offsets to jlong alignment, in HeapWord units. |
129 | template <typename T> |
130 | inline T align_object_offset(T offset) { |
131 | return align_up(offset, HeapWordsPerLong); |
132 | } |
133 | |
134 | // Clamp an address to be within a specific page |
135 | // 1. If addr is on the page it is returned as is |
136 | // 2. If addr is above the page_address the start of the *next* page will be returned |
137 | // 3. Otherwise, if addr is below the page_address the start of the page will be returned |
138 | template <typename T> |
139 | inline T* clamp_address_in_page(T* addr, T* page_address, size_t page_size) { |
140 | if (align_down(addr, page_size) == align_down(page_address, page_size)) { |
141 | // address is in the specified page, just return it as is |
142 | return addr; |
143 | } else if (addr > page_address) { |
144 | // address is above specified page, return start of next page |
145 | return align_down(page_address, page_size) + page_size; |
146 | } else { |
147 | // address is below specified page, return start of page |
148 | return align_down(page_address, page_size); |
149 | } |
150 | } |
151 | |
152 | #endif // SHARE_UTILITIES_ALIGN_HPP |
153 | |