xref: /aosp_15_r20/art/runtime/oat/oat_quick_method_header.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2011 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_RUNTIME_OAT_OAT_QUICK_METHOD_HEADER_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_RUNTIME_OAT_OAT_QUICK_METHOD_HEADER_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include <optional>
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker #include "arch/instruction_set.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/locks.h"
24*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
25*795d594fSAndroid Build Coastguard Worker #include "base/utils.h"
26*795d594fSAndroid Build Coastguard Worker #include "quick/quick_method_frame_info.h"
27*795d594fSAndroid Build Coastguard Worker #include "stack_map.h"
28*795d594fSAndroid Build Coastguard Worker 
29*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker class ArtMethod;
32*795d594fSAndroid Build Coastguard Worker 
33*795d594fSAndroid Build Coastguard Worker // Size in bytes of the should_deoptimize flag on stack.
34*795d594fSAndroid Build Coastguard Worker // We just need 4 bytes for our purpose regardless of the architecture. Frame size
35*795d594fSAndroid Build Coastguard Worker // calculation will automatically do alignment for the final frame size.
36*795d594fSAndroid Build Coastguard Worker static constexpr size_t kShouldDeoptimizeFlagSize = 4;
37*795d594fSAndroid Build Coastguard Worker 
38*795d594fSAndroid Build Coastguard Worker // OatQuickMethodHeader precedes the raw code chunk generated by the compiler.
39*795d594fSAndroid Build Coastguard Worker class PACKED(4) OatQuickMethodHeader {
40*795d594fSAndroid Build Coastguard Worker  public:
41*795d594fSAndroid Build Coastguard Worker   OatQuickMethodHeader(uint32_t code_info_offset = 0) {
42*795d594fSAndroid Build Coastguard Worker     SetCodeInfoOffset(code_info_offset);
43*795d594fSAndroid Build Coastguard Worker   }
44*795d594fSAndroid Build Coastguard Worker 
45*795d594fSAndroid Build Coastguard Worker   static OatQuickMethodHeader* NterpMethodHeader;
46*795d594fSAndroid Build Coastguard Worker   EXPORT static ArrayRef<const uint8_t> NterpWithClinitImpl;
47*795d594fSAndroid Build Coastguard Worker   EXPORT static ArrayRef<const uint8_t> NterpImpl;
48*795d594fSAndroid Build Coastguard Worker 
49*795d594fSAndroid Build Coastguard Worker   EXPORT bool IsNterpMethodHeader() const;
50*795d594fSAndroid Build Coastguard Worker 
IsNterpPc(uintptr_t pc)51*795d594fSAndroid Build Coastguard Worker   static bool IsNterpPc(uintptr_t pc) {
52*795d594fSAndroid Build Coastguard Worker     return OatQuickMethodHeader::NterpMethodHeader != nullptr &&
53*795d594fSAndroid Build Coastguard Worker         OatQuickMethodHeader::NterpMethodHeader->Contains(pc);
54*795d594fSAndroid Build Coastguard Worker   }
55*795d594fSAndroid Build Coastguard Worker 
FromCodePointer(const void * code_ptr)56*795d594fSAndroid Build Coastguard Worker   static OatQuickMethodHeader* FromCodePointer(const void* code_ptr) {
57*795d594fSAndroid Build Coastguard Worker     uintptr_t code = reinterpret_cast<uintptr_t>(code_ptr);
58*795d594fSAndroid Build Coastguard Worker     uintptr_t header = code - OFFSETOF_MEMBER(OatQuickMethodHeader, code_);
59*795d594fSAndroid Build Coastguard Worker     DCHECK(IsAlignedParam(code, GetInstructionSetCodeAlignment(kRuntimeQuickCodeISA)) ||
60*795d594fSAndroid Build Coastguard Worker            IsAlignedParam(header, GetInstructionSetCodeAlignment(kRuntimeQuickCodeISA)))
61*795d594fSAndroid Build Coastguard Worker         << std::hex << code << " " << std::hex << header;
62*795d594fSAndroid Build Coastguard Worker     return reinterpret_cast<OatQuickMethodHeader*>(header);
63*795d594fSAndroid Build Coastguard Worker   }
64*795d594fSAndroid Build Coastguard Worker 
FromEntryPoint(const void * entry_point)65*795d594fSAndroid Build Coastguard Worker   static OatQuickMethodHeader* FromEntryPoint(const void* entry_point) {
66*795d594fSAndroid Build Coastguard Worker     return FromCodePointer(EntryPointToCodePointer(entry_point));
67*795d594fSAndroid Build Coastguard Worker   }
68*795d594fSAndroid Build Coastguard Worker 
InstructionAlignedSize()69*795d594fSAndroid Build Coastguard Worker   static size_t InstructionAlignedSize() {
70*795d594fSAndroid Build Coastguard Worker     return RoundUp(sizeof(OatQuickMethodHeader),
71*795d594fSAndroid Build Coastguard Worker                    GetInstructionSetCodeAlignment(kRuntimeQuickCodeISA));
72*795d594fSAndroid Build Coastguard Worker   }
73*795d594fSAndroid Build Coastguard Worker 
74*795d594fSAndroid Build Coastguard Worker   OatQuickMethodHeader(const OatQuickMethodHeader&) = default;
75*795d594fSAndroid Build Coastguard Worker   OatQuickMethodHeader& operator=(const OatQuickMethodHeader&) = default;
76*795d594fSAndroid Build Coastguard Worker 
NativeQuickPcOffset(const uintptr_t pc)77*795d594fSAndroid Build Coastguard Worker   uintptr_t NativeQuickPcOffset(const uintptr_t pc) const {
78*795d594fSAndroid Build Coastguard Worker     return pc - reinterpret_cast<uintptr_t>(GetEntryPoint());
79*795d594fSAndroid Build Coastguard Worker   }
80*795d594fSAndroid Build Coastguard Worker 
81*795d594fSAndroid Build Coastguard Worker   // Check if this is hard-written assembly (i.e. inside libart.so).
82*795d594fSAndroid Build Coastguard Worker   // Returns std::nullop on Mac.
83*795d594fSAndroid Build Coastguard Worker   static std::optional<bool> IsStub(const uint8_t* pc);
84*795d594fSAndroid Build Coastguard Worker 
IsOptimized()85*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE bool IsOptimized() const {
86*795d594fSAndroid Build Coastguard Worker     if (code_ == NterpWithClinitImpl.data() || code_ == NterpImpl.data()) {
87*795d594fSAndroid Build Coastguard Worker       DCHECK(IsStub(code_).value_or(true));
88*795d594fSAndroid Build Coastguard Worker       return false;
89*795d594fSAndroid Build Coastguard Worker     }
90*795d594fSAndroid Build Coastguard Worker     DCHECK(!IsStub(code_).value_or(false));
91*795d594fSAndroid Build Coastguard Worker     return true;
92*795d594fSAndroid Build Coastguard Worker   }
93*795d594fSAndroid Build Coastguard Worker 
GetOptimizedCodeInfoPtr()94*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE const uint8_t* GetOptimizedCodeInfoPtr() const {
95*795d594fSAndroid Build Coastguard Worker     uint32_t offset = GetCodeInfoOffset();
96*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(offset, 0u);
97*795d594fSAndroid Build Coastguard Worker     return code_ - offset;
98*795d594fSAndroid Build Coastguard Worker   }
99*795d594fSAndroid Build Coastguard Worker 
GetOptimizedCodeInfoPtr()100*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE uint8_t* GetOptimizedCodeInfoPtr() {
101*795d594fSAndroid Build Coastguard Worker     uint32_t offset = GetCodeInfoOffset();
102*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(offset, 0u);
103*795d594fSAndroid Build Coastguard Worker     return code_ - offset;
104*795d594fSAndroid Build Coastguard Worker   }
105*795d594fSAndroid Build Coastguard Worker 
GetCode()106*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE const uint8_t* GetCode() const {
107*795d594fSAndroid Build Coastguard Worker     return code_;
108*795d594fSAndroid Build Coastguard Worker   }
109*795d594fSAndroid Build Coastguard Worker 
GetCodeSize()110*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE uint32_t GetCodeSize() const {
111*795d594fSAndroid Build Coastguard Worker     if (code_ == NterpWithClinitImpl.data()) {
112*795d594fSAndroid Build Coastguard Worker       return NterpWithClinitImpl.size();
113*795d594fSAndroid Build Coastguard Worker     }
114*795d594fSAndroid Build Coastguard Worker     if (code_ == NterpImpl.data()) {
115*795d594fSAndroid Build Coastguard Worker       return NterpImpl.size();
116*795d594fSAndroid Build Coastguard Worker     }
117*795d594fSAndroid Build Coastguard Worker     return CodeInfo::DecodeCodeSize(GetOptimizedCodeInfoPtr());
118*795d594fSAndroid Build Coastguard Worker   }
119*795d594fSAndroid Build Coastguard Worker 
GetCodeInfoOffset()120*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE uint32_t GetCodeInfoOffset() const {
121*795d594fSAndroid Build Coastguard Worker     DCHECK(IsOptimized());
122*795d594fSAndroid Build Coastguard Worker     return code_info_offset_;
123*795d594fSAndroid Build Coastguard Worker   }
124*795d594fSAndroid Build Coastguard Worker 
SetCodeInfoOffset(uint32_t offset)125*795d594fSAndroid Build Coastguard Worker   void SetCodeInfoOffset(uint32_t offset) { code_info_offset_ = offset; }
126*795d594fSAndroid Build Coastguard Worker 
Contains(uintptr_t pc)127*795d594fSAndroid Build Coastguard Worker   bool Contains(uintptr_t pc) const {
128*795d594fSAndroid Build Coastguard Worker     uintptr_t code_start = reinterpret_cast<uintptr_t>(code_);
129*795d594fSAndroid Build Coastguard Worker // Let's not make assumptions about other architectures.
130*795d594fSAndroid Build Coastguard Worker #if defined(__aarch64__) || defined(__riscv__) || defined(__riscv)
131*795d594fSAndroid Build Coastguard Worker     // Verify that the code pointer is not tagged. Memory for code gets allocated with
132*795d594fSAndroid Build Coastguard Worker     // mspace_memalign or memory mapped from a file, neither of which is tagged by MTE/HWASan.
133*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(code_start, reinterpret_cast<uintptr_t>(code_start) & ((UINT64_C(1) << 56) - 1));
134*795d594fSAndroid Build Coastguard Worker #endif
135*795d594fSAndroid Build Coastguard Worker     static_assert(kRuntimeQuickCodeISA != InstructionSet::kThumb2,
136*795d594fSAndroid Build Coastguard Worker                   "kThumb2 cannot be a runtime ISA");
137*795d594fSAndroid Build Coastguard Worker     if (kRuntimeQuickCodeISA == InstructionSet::kArm) {
138*795d594fSAndroid Build Coastguard Worker       // On Thumb-2, the pc is offset by one.
139*795d594fSAndroid Build Coastguard Worker       code_start++;
140*795d594fSAndroid Build Coastguard Worker     }
141*795d594fSAndroid Build Coastguard Worker     return code_start <= pc && pc <= (code_start + GetCodeSize());
142*795d594fSAndroid Build Coastguard Worker   }
143*795d594fSAndroid Build Coastguard Worker 
GetEntryPoint()144*795d594fSAndroid Build Coastguard Worker   const uint8_t* GetEntryPoint() const {
145*795d594fSAndroid Build Coastguard Worker     // When the runtime architecture is ARM, `kRuntimeQuickCodeISA` is set to `kArm`
146*795d594fSAndroid Build Coastguard Worker     // (not `kThumb2`), *but* we always generate code for the Thumb-2
147*795d594fSAndroid Build Coastguard Worker     // instruction set anyway. Thumb-2 requires the entrypoint to be of
148*795d594fSAndroid Build Coastguard Worker     // offset 1.
149*795d594fSAndroid Build Coastguard Worker     static_assert(kRuntimeQuickCodeISA != InstructionSet::kThumb2,
150*795d594fSAndroid Build Coastguard Worker                   "kThumb2 cannot be a runtime ISA");
151*795d594fSAndroid Build Coastguard Worker     return (kRuntimeQuickCodeISA == InstructionSet::kArm)
152*795d594fSAndroid Build Coastguard Worker         ? reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(code_) | 1)
153*795d594fSAndroid Build Coastguard Worker         : code_;
154*795d594fSAndroid Build Coastguard Worker   }
155*795d594fSAndroid Build Coastguard Worker 
156*795d594fSAndroid Build Coastguard Worker   template <bool kCheckFrameSize = true>
GetFrameSizeInBytes()157*795d594fSAndroid Build Coastguard Worker   uint32_t GetFrameSizeInBytes() const {
158*795d594fSAndroid Build Coastguard Worker     uint32_t result = GetFrameInfo().FrameSizeInBytes();
159*795d594fSAndroid Build Coastguard Worker     if (kCheckFrameSize) {
160*795d594fSAndroid Build Coastguard Worker       DCHECK_ALIGNED(result, kStackAlignment);
161*795d594fSAndroid Build Coastguard Worker     }
162*795d594fSAndroid Build Coastguard Worker     return result;
163*795d594fSAndroid Build Coastguard Worker   }
164*795d594fSAndroid Build Coastguard Worker 
GetFrameInfo()165*795d594fSAndroid Build Coastguard Worker   QuickMethodFrameInfo GetFrameInfo() const {
166*795d594fSAndroid Build Coastguard Worker     DCHECK(IsOptimized());
167*795d594fSAndroid Build Coastguard Worker     return CodeInfo::DecodeFrameInfo(GetOptimizedCodeInfoPtr());
168*795d594fSAndroid Build Coastguard Worker   }
169*795d594fSAndroid Build Coastguard Worker 
GetShouldDeoptimizeFlagOffset()170*795d594fSAndroid Build Coastguard Worker   size_t GetShouldDeoptimizeFlagOffset() const {
171*795d594fSAndroid Build Coastguard Worker     DCHECK(IsOptimized());
172*795d594fSAndroid Build Coastguard Worker     QuickMethodFrameInfo frame_info = GetFrameInfo();
173*795d594fSAndroid Build Coastguard Worker     size_t frame_size = frame_info.FrameSizeInBytes();
174*795d594fSAndroid Build Coastguard Worker     size_t core_spill_size =
175*795d594fSAndroid Build Coastguard Worker         POPCOUNT(frame_info.CoreSpillMask()) * GetBytesPerGprSpillLocation(kRuntimeQuickCodeISA);
176*795d594fSAndroid Build Coastguard Worker     size_t fpu_spill_size =
177*795d594fSAndroid Build Coastguard Worker         POPCOUNT(frame_info.FpSpillMask()) * GetBytesPerFprSpillLocation(kRuntimeQuickCodeISA);
178*795d594fSAndroid Build Coastguard Worker     return frame_size - core_spill_size - fpu_spill_size - kShouldDeoptimizeFlagSize;
179*795d594fSAndroid Build Coastguard Worker   }
180*795d594fSAndroid Build Coastguard Worker 
181*795d594fSAndroid Build Coastguard Worker   // For non-catch handlers. Only used in test code.
182*795d594fSAndroid Build Coastguard Worker   EXPORT uintptr_t ToNativeQuickPc(ArtMethod* method,
183*795d594fSAndroid Build Coastguard Worker                                    const uint32_t dex_pc,
184*795d594fSAndroid Build Coastguard Worker                                    bool abort_on_failure = true) const;
185*795d594fSAndroid Build Coastguard Worker 
186*795d594fSAndroid Build Coastguard Worker   // For catch handlers.
187*795d594fSAndroid Build Coastguard Worker   uintptr_t ToNativeQuickPcForCatchHandlers(ArtMethod* method,
188*795d594fSAndroid Build Coastguard Worker                                             ArrayRef<const uint32_t> dex_pc_list,
189*795d594fSAndroid Build Coastguard Worker                                             /* out */ uint32_t* stack_map_row,
190*795d594fSAndroid Build Coastguard Worker                                             bool abort_on_failure = true) const;
191*795d594fSAndroid Build Coastguard Worker 
192*795d594fSAndroid Build Coastguard Worker   uint32_t ToDexPc(ArtMethod** frame,
193*795d594fSAndroid Build Coastguard Worker                    const uintptr_t pc,
194*795d594fSAndroid Build Coastguard Worker                    bool abort_on_failure = true) const
195*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_);
196*795d594fSAndroid Build Coastguard Worker 
HasShouldDeoptimizeFlag()197*795d594fSAndroid Build Coastguard Worker   bool HasShouldDeoptimizeFlag() const {
198*795d594fSAndroid Build Coastguard Worker     return IsOptimized() && CodeInfo::HasShouldDeoptimizeFlag(GetOptimizedCodeInfoPtr());
199*795d594fSAndroid Build Coastguard Worker   }
200*795d594fSAndroid Build Coastguard Worker 
201*795d594fSAndroid Build Coastguard Worker  private:
202*795d594fSAndroid Build Coastguard Worker   uint32_t code_info_offset_ = 0u;
203*795d594fSAndroid Build Coastguard Worker   uint8_t code_[0];     // The actual method code.
204*795d594fSAndroid Build Coastguard Worker };
205*795d594fSAndroid Build Coastguard Worker 
206*795d594fSAndroid Build Coastguard Worker }  // namespace art
207*795d594fSAndroid Build Coastguard Worker 
208*795d594fSAndroid Build Coastguard Worker #endif  // ART_RUNTIME_OAT_OAT_QUICK_METHOD_HEADER_H_
209