1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef METADATA_LAYOUT_H
17 #define METADATA_LAYOUT_H
18 #include <cstdlib>
19
20 // metadata layout is shared between maple compiler and runtime, thus not in namespace maplert
21 // some of the reference field of metadata is stored as relative offset
22 // for example, declaring class of Fields/Methods
23 // which can be negative
24 #ifdef USE_32BIT_REF
25 using MetaRef = uint32_t; // consistent with reffield_t in address.h
26 #else
27 using MetaRef = uintptr_t; // consistent iwth reffield_t in address.h
28 #endif // USE_32BIT_REF
29
30 // DataRefOffset aims to represent a reference to data in maple file, which is already an offset.
31 // DataRefOffset is meant to have pointer size.
32 // All Xx32 data types defined in this file aim to use 32 bits to save 64-bit address, and thus are
33 // specific for 64-bit platforms.
34 struct DataRefOffset32 {
35 int32_t refOffset;
36 template <typename T>
37 inline void SetDataRef(T ref);
38 template <typename T>
39 inline T GetDataRef() const;
40 inline int32_t GetRawValue() const;
41 inline void SetRawValue(int32_t value);
42 };
43
44 struct DataRefOffsetPtr {
45 intptr_t refOffset;
46 template <typename T>
47 inline void SetDataRef(T ref);
48 template <typename T>
49 inline T GetDataRef() const;
50 inline intptr_t GetRawValue() const;
51 inline void SetRawValue(intptr_t value);
52 };
53
54 struct DataRefOffset {
55 #ifdef USE_32BIT_REF
56 DataRefOffset32 refOffset;
57 #else
58 DataRefOffsetPtr refOffset;
59 #endif
60 template <typename T>
61 inline void SetDataRef(T ref);
62 template <typename T>
63 inline T GetDataRef() const;
64 inline intptr_t GetRawValue() const;
65 inline void SetRawValue(intptr_t value);
66 };
67
68 struct MethodFieldRef {
69 // MethodFieldRef aims to represent a reference to fields/methods in maple file, which is already an offset.
70 // also, offset LSB may set 1, to indicate that it is compact fields/methods.
71 enum MethodFieldRefFormat {
72 kMethodFieldRefIsCompact = 1,
73 };
74 DataRefOffsetPtr refOffset;
75 template <typename T>
76 inline void SetDataRef(T ref);
77 template <typename T>
78 inline T GetDataRef() const;
79 inline bool IsCompact() const;
80 template <typename T>
81 inline T GetCompactData() const;
82 inline intptr_t GetRawValue() const;
83 inline void SetRawValue(intptr_t value);
84 };
85
86 // DataRef aims for reference to data in maple file (generated by maple compiler) and is aligned to at least 4 bytes.
87 // Perhaps MDataRef is more fit, still DataRef is chosen to make it common.
88 // DataRef allows 4 formats of value:
89 // 0. "label_name" for direct reference
90 // 1. "label_name - . + 1" for padding unused
91 // 2. "label_name - . + 2" for reference in offset format
92 // 3. "indirect.label_name - . + 3" for indirect reference
93 // this format aims to support lld which does not support expression "global_symbol - ."
94 // DataRef is self-decoded by also encoding the format and is defined for binary compatibility.
95 // If no compatibility problem is involved, DataRefOffsetPtr is preferred.
96 enum DataRefFormat {
97 kDataRefIsDirect = 0, // must be 0
98 kDataRefPadding = 1, // unused
99 kDataRefIsOffset = 2,
100 kDataRefIsIndirect = 3, // read-only
101 kDataRefBitMask = 3,
102 };
103
104 struct DataRef32 {
105 // be careful when *refVal* is treated as an offset which is a signed integer actually.
106 uint32_t refVal;
107 template <typename T>
108 inline T GetDataRef() const;
109 template <typename T>
110 inline void SetDataRef(T ref, DataRefFormat format = kDataRefIsDirect);
111 template <typename T>
112 inline T GetRawValue() const;
113 };
114
115 struct DataRef {
116 uintptr_t refVal;
117 template <typename T>
118 inline T GetDataRef() const;
119 template <typename T>
120 inline void SetDataRef(const T ref, const DataRefFormat format = kDataRefIsDirect);
121 template <typename T>
122 inline T GetRawValue() const;
123 };
124 // GctibRef aims to represent a reference to gctib in maple file, which is an offset by default.
125 // GctibRef is meant to have pointer size and aligned to at least 4 bytes.
126 // GctibRef allows 2 formats of value:
127 // 0. "label_name - . + 0" for reference in offset format
128 // 1. "indirect.label_name - . + 1" for indirect reference
129 // this format aims to support lld which does not support expression "global_symbol - ."
130 // GctibRef is self-decoded by also encoding the format and is defined for binary compatibility.
131 // If no compatibility problem is involved, DataRef is preferred.
132 enum GctibRefFormat {
133 kGctibRefIsOffset = 0, // default
134 kGctibRefIsIndirect = 1,
135 kGctibRefBitMask = 3
136 };
137
138 struct GctibRef32 {
139 // be careful when *refVal* is treated as an offset which is a signed integer actually.
140 uint32_t refVal;
141 template <typename T>
142 inline T GetGctibRef() const;
143 template <typename T>
144 inline void SetGctibRef(T ref, GctibRefFormat format = kGctibRefIsOffset);
145 };
146
147 struct GctibRef {
148 uintptr_t refVal;
149 template <typename T>
150 inline T GetGctibRef() const;
151 template <typename T>
152 inline void SetGctibRef(const T ref, const GctibRefFormat format = kGctibRefIsOffset);
153 };
154
155 // MByteRef is meant to represent a reference to data defined in maple file. It is a direct reference or an offset.
156 // MByteRef is self-encoded/decoded and aligned to 1 byte.
157 // Unlike DataRef, the format of MByteRef is determined by its value.
158 struct MByteRef {
159 uintptr_t refVal; // initializer prefers this field to be a pointer
160
161 #if defined(__arm__) || defined(USE_ARM32_MACRO)
162 // assume address range 0 ~ 256MB is unused in arm runtime
163 // kEncodedOffsetMin ~ kEncodedOffsetMax is the value range of encoded offset
164 static constexpr intptr_t kOffsetBound = 128 * 1024 * 1024;
165 static constexpr intptr_t kOffsetMin = -kOffsetBound;
166 static constexpr intptr_t kOffsetMax = kOffsetBound;
167
168 static constexpr intptr_t kPositiveOffsetBias = 128 * 1024 * 1024;
169 static constexpr intptr_t kEncodedOffsetMin = kPositiveOffsetBias + kOffsetMin;
170 static constexpr intptr_t kEncodedOffsetMax = kPositiveOffsetBias + kOffsetMax;
171 #else
172 enum {
173 kBiasBitPosition = sizeof(refVal) * 8 - 4, // the most significant 4 bits
174 };
175
176 static constexpr uintptr_t kOffsetBound = 256 * 1024 * 1024; // according to kDsoLoadedAddessEnd = 0xF0000000
177 static constexpr uintptr_t kPositiveOffsetMin = 0;
178 static constexpr uintptr_t kPositiveOffsetMax = kOffsetBound;
179
180 static constexpr uintptr_t kPositiveOffsetBias = static_cast<uintptr_t>(6) << kBiasBitPosition;
181 static constexpr uintptr_t kEncodedPosOffsetMin = kPositiveOffsetMin + kPositiveOffsetBias;
182 static constexpr uintptr_t kEncodedPosOffsetMax = kPositiveOffsetMax + kPositiveOffsetBias;
183 #endif
184
185 template <typename T>
186 inline T GetRef() const;
187 template <typename T>
188 inline void SetRef(const T ref);
189 inline bool IsOffset() const;
190 };
191
192 struct MByteRef32 {
193 uint32_t refVal;
194 static constexpr uint32_t kOffsetBound = 256 * 1024 * 1024; // according to kDsoLoadedAddessEnd = 0xF0000000
195 static constexpr uint32_t kPositiveOffsetMin = 0;
196 static constexpr uint32_t kPositiveOffsetMax = kOffsetBound;
197
198 static constexpr uint32_t kPositiveOffsetBias = 0x60000000; // the most significant 4 bits 0110
199 static constexpr uint32_t kEncodedPosOffsetMin = kPositiveOffsetMin + kPositiveOffsetBias;
200 static constexpr uint32_t kEncodedPosOffsetMax = kPositiveOffsetMax + kPositiveOffsetBias;
201
202 static constexpr uint32_t kDirectRefMin = 0xC0000000; // according to kDsoLoadedAddessStart = 0xC0000000
203 static constexpr uint32_t kDirectRefMax = 0xF0000000; // according to kDsoLoadedAddessEnd = 0xF0000000
204
205 static constexpr int32_t kNegativeOffsetMin = -(256 * 1024 * 1024); // -kOffsetBound
206 static constexpr int32_t kNegativeOffsetMax = 0;
207
208 template <typename T>
209 inline T GetRef() const;
210 template <typename T>
211 inline void SetRef(T ref);
212 inline bool IsOffset() const;
213 inline bool IsPositiveOffset() const;
214 inline bool IsNegativeOffset() const;
215 };
216
217 // MethodMeta defined in methodmeta.h
218 // FieldMeta defined in fieldmeta.h
219 // MethodDesc contains MethodMetadata and stack map
220 struct MethodDesc {
221 // relative offset for method metadata relative to current PC.
222 // method metadata is in compact format if this offset is odd.
223 uint32_t metadataOffset;
224
225 int16_t localRefOffset;
226 uint16_t localRefNumber;
227
228 // stack map for a methed might be placed here
229 };
230
231 // Note: class init in maplebe and cg is highly dependent on this type.
232 // update aarch64rtsupport.h if you modify this definition.
233 struct ClassMetadataRO {
234 MByteRef className;
235 MethodFieldRef fields; // point to info of fields
236 MethodFieldRef methods; // point to info of methods
237 union { // Element classinfo of array, others parent classinfo
238 DataRef superclass;
239 DataRef componentClass;
240 };
241
242 uint16_t numOfFields;
243 uint16_t numOfMethods;
244
245 #ifndef USE_32BIT_REF
246 uint16_t flag;
247 uint16_t numOfSuperclasses;
248 uint32_t padding;
249 #endif // !USE_32BIT_REF
250
251 uint32_t mod;
252 DataRefOffset32 annotation;
253 DataRefOffset32 clinitAddr;
254 };
255
256 static constexpr size_t kPageSize = 4096;
257 static constexpr size_t kCacheLine = 64;
258
259 // according to kSpaceAnchor and kFireBreak defined in bp_allocator.cpp
260 static constexpr uintptr_t kClInitStateAddrBase = 0xc0000000 - (1u << 20) * 2;
261
262 // In Kirin 980, 2 mmap memory address with odd number of page distances may have unreasonable L1&L2 cache conflict.
263 // kClassInitializedState is used as the init state for class that has no <clinit> method, it's will be loaded in many
264 // place for Decouple build App. if we set the value to kClInitStateAddrBase(0xbfe00000), it may conflict with the
265 // yieldpoind test address globalPollingPage which is defined in yieldpoint.cpp.
266 // Hence we add 1 cache line (64 byte) offset here to avoid such conflict
267 static constexpr uintptr_t kClassInitializedState = kClInitStateAddrBase + kCacheLine;
268
269 extern "C" uint8_t classInitProtectRegion[];
270
271 // Note there is no state to indicate a class is already initialized.
272 // Any state beyond listed below is treated as initialized.
273 enum ClassInitState {
274 kClassInitStateMin = 0,
275 kClassUninitialized = 1,
276 kClassInitializing = 2,
277 kClassInitFailed = 3,
278 kClassInitialized = 4,
279 kClassInitStateMax = 4,
280 };
281
282 enum SEGVAddr {
283 kSEGVAddrRangeStart = kPageSize + 0,
284
285 // Note any readable address is treated as Initialized.
286 kSEGVAddrForClassInitStateMin = kSEGVAddrRangeStart + kClassInitStateMin,
287 kSEGVAddrForClassUninitialized = kSEGVAddrForClassInitStateMin + kClassUninitialized,
288 kSEGVAddrForClassInitializing = kSEGVAddrForClassInitStateMin + kClassInitializing,
289 kSEGVAddrForClassInitFailed = kSEGVAddrForClassInitStateMin + kClassInitFailed,
290 kSEGVAddrFoClassInitStateMax = kSEGVAddrForClassInitStateMin + kClassInitStateMax,
291
292 kSEGVAddrRangeEnd,
293 };
294
295 struct ClassMetadata {
296 // object common fields
297 MetaRef shadow;
298 int32_t monitor;
299
300 // other fields
301 uint16_t clIndex; // 8bit ClassLoader index, used for querying the address of related ClassLoader instance.
302 union {
303 uint16_t objSize;
304 uint16_t componentSize;
305 } sizeInfo;
306
307 #ifdef USE_32BIT_REF // for alignment purpose
308 uint16_t flag;
309 uint16_t numOfSuperclasses;
310 #endif // USE_32BIT_REF
311
312 DataRef iTable; // iTable of current class, used for interface call, will insert the content into classinfo
313 DataRef vTable; // vTable of current class, used for virtual call, will insert the content into classinfo
314 GctibRef gctib; // for rc
315
316 #ifdef USE_32BIT_REF
317 DataRef32 classInfoRo;
318 DataRef32 cacheFalseClass;
319 #else
320 DataRef classInfoRo;
321 #endif
322
323 union {
324 uintptr_t initState; // a readable address for initState means initialized
325 DataRef cacheTrueClass;
326 };
327
328 public:
OffsetOfInitStateClassMetadata329 static inline intptr_t OffsetOfInitState()
330 {
331 ClassMetadata *base = nullptr;
332 return reinterpret_cast<intptr_t>(&(base->initState));
333 }
334
GetInitStateRawValueClassMetadata335 uintptr_t GetInitStateRawValue() const
336 {
337 return __atomic_load_n(&initState, __ATOMIC_ACQUIRE);
338 }
339
340 template <typename T>
SetInitStateRawValueClassMetadata341 void SetInitStateRawValue(T val)
342 {
343 __atomic_store_n(&initState, reinterpret_cast<uintptr_t>(val), __ATOMIC_RELEASE);
344 }
345 };
346
347 // function to set Class/Field/Method metadata's shadow field to avoid type conversion
348 // Note 1: here we don't do NULL-check and type-compatibility check
349 // NOte 2: C should be of jclass/ClassMetata* type
350 template <typename M, typename C>
MRTSetMetadataShadow(M *meta, C cls)351 static inline void MRTSetMetadataShadow(M *meta, C cls)
352 {
353 meta->shadow = static_cast<MetaRef>(reinterpret_cast<uintptr_t>(cls));
354 }
355
356 #endif // METADATA_LAYOUT_H
357