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