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