1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_RUNTIME_MANAGED_STACK_H_ 18 #define ART_RUNTIME_MANAGED_STACK_H_ 19 20 #include <cstdint> 21 #include <cstring> 22 #include <string> 23 24 #include <android-base/logging.h> 25 26 #include "base/locks.h" 27 #include "base/macros.h" 28 #include "base/bit_utils.h" 29 30 namespace art HIDDEN { 31 32 namespace mirror { 33 class Object; 34 } // namespace mirror 35 36 class ArtMethod; 37 class ShadowFrame; 38 template <typename T> class StackReference; 39 40 // The managed stack is used to record fragments of managed code stacks. Managed code stacks 41 // may either be shadow frames or lists of frames using fixed frame sizes. Transition records are 42 // necessary for transitions between code using different frame layouts and transitions into native 43 // code. 44 // 45 // Each ManagedStack fragment may contain either a quick code's sp or address to a shadow frame. 46 // It is an invariant that both are never set at the same time. 47 // 48 // Each fragment may contain a mini stack, more than one call frame. For quick code, we extract the 49 // call's frame size (known a priori) to obtain the caller's sp. The walk for this fragment 50 // terminates when a potential caller's sp contains null (instead of a valid ArtMethod*). A 51 // null-valued sp is set up by a quick code stub. For shadow frames, we chase the link_ pointer 52 // until null. Once a mini stack is completely walked, we move onto the next fragment. 53 // 54 // The topmost fragment is always held in the thread's TLS region. 55 class PACKED(4) ManagedStack { 56 public: 57 static size_t constexpr kTaggedJniSpMask = 0x3; 58 ManagedStack()59 ManagedStack() 60 : tagged_top_quick_frame_(TaggedTopQuickFrame::CreateNotTagged(nullptr)), 61 link_(nullptr), 62 top_shadow_frame_(nullptr) {} 63 PushManagedStackFragment(ManagedStack * fragment)64 void PushManagedStackFragment(ManagedStack* fragment) { 65 // Copy this top fragment into given fragment. 66 memcpy(fragment, this, sizeof(ManagedStack)); 67 // Clear this fragment, which has become the top. 68 memset(this, 0, sizeof(ManagedStack)); 69 // Link our top fragment onto the given fragment. 70 link_ = fragment; 71 } 72 PopManagedStackFragment(const ManagedStack & fragment)73 void PopManagedStackFragment(const ManagedStack& fragment) { 74 DCHECK(&fragment == link_); 75 // Copy this given fragment back to the top. 76 memcpy(this, &fragment, sizeof(ManagedStack)); 77 } 78 GetLink()79 ManagedStack* GetLink() const { 80 return link_; 81 } 82 GetTopQuickFrameKnownNotTagged()83 ArtMethod** GetTopQuickFrameKnownNotTagged() const { 84 return tagged_top_quick_frame_.GetSpKnownNotTagged(); 85 } 86 GetTopQuickFrame()87 ArtMethod** GetTopQuickFrame() const { 88 return tagged_top_quick_frame_.GetSp(); 89 } 90 GetTopQuickFrameGenericJniTag()91 bool GetTopQuickFrameGenericJniTag() const { 92 return tagged_top_quick_frame_.GetGenericJniTag(); 93 } 94 GetTopQuickFrameJitJniTag()95 bool GetTopQuickFrameJitJniTag() const { 96 return tagged_top_quick_frame_.GetJitJniTag(); 97 } 98 HasTopQuickFrame()99 bool HasTopQuickFrame() const { 100 return tagged_top_quick_frame_.GetTaggedSp() != 0u; 101 } 102 SetTopQuickFrame(ArtMethod ** top)103 void SetTopQuickFrame(ArtMethod** top) { 104 DCHECK(top_shadow_frame_ == nullptr); 105 DCHECK_ALIGNED(top, 4u); 106 tagged_top_quick_frame_ = TaggedTopQuickFrame::CreateNotTagged(top); 107 } 108 SetTopQuickFrameGenericJniTagged(ArtMethod ** top)109 void SetTopQuickFrameGenericJniTagged(ArtMethod** top) { 110 DCHECK(top_shadow_frame_ == nullptr); 111 DCHECK_ALIGNED(top, 4u); 112 tagged_top_quick_frame_ = TaggedTopQuickFrame::CreateGenericJniTagged(top); 113 } 114 TaggedTopQuickFrameOffset()115 static constexpr size_t TaggedTopQuickFrameOffset() { 116 return OFFSETOF_MEMBER(ManagedStack, tagged_top_quick_frame_); 117 } 118 119 ALWAYS_INLINE ShadowFrame* PushShadowFrame(ShadowFrame* new_top_frame); 120 ALWAYS_INLINE ShadowFrame* PopShadowFrame(); 121 GetTopShadowFrame()122 ShadowFrame* GetTopShadowFrame() const { 123 return top_shadow_frame_; 124 } 125 HasTopShadowFrame()126 bool HasTopShadowFrame() const { 127 return GetTopShadowFrame() != nullptr; 128 } 129 SetTopShadowFrame(ShadowFrame * top)130 void SetTopShadowFrame(ShadowFrame* top) { 131 DCHECK_EQ(tagged_top_quick_frame_.GetTaggedSp(), 0u); 132 top_shadow_frame_ = top; 133 } 134 TopShadowFrameOffset()135 static size_t TopShadowFrameOffset() { 136 return OFFSETOF_MEMBER(ManagedStack, top_shadow_frame_); 137 } 138 139 private: 140 // Encodes the top quick frame (which must be at least 4-byte aligned) 141 // and a flag that marks the GenericJNI trampoline. 142 class TaggedTopQuickFrame { 143 public: CreateNotTagged(ArtMethod ** sp)144 static TaggedTopQuickFrame CreateNotTagged(ArtMethod** sp) { 145 DCHECK_ALIGNED(sp, 4u); 146 return TaggedTopQuickFrame(reinterpret_cast<uintptr_t>(sp)); 147 } 148 CreateGenericJniTagged(ArtMethod ** sp)149 static TaggedTopQuickFrame CreateGenericJniTagged(ArtMethod** sp) { 150 DCHECK_ALIGNED(sp, 4u); 151 return TaggedTopQuickFrame(reinterpret_cast<uintptr_t>(sp) | 1u); 152 } 153 154 // Get SP known to be not tagged and non-null. GetSpKnownNotTagged()155 ArtMethod** GetSpKnownNotTagged() const { 156 DCHECK(!GetGenericJniTag() && !GetJitJniTag()); 157 DCHECK_NE(tagged_sp_, 0u); 158 return reinterpret_cast<ArtMethod**>(tagged_sp_); 159 } 160 GetSp()161 ArtMethod** GetSp() const { 162 return reinterpret_cast<ArtMethod**>(tagged_sp_ & ~static_cast<uintptr_t>(kTaggedJniSpMask)); 163 } 164 GetGenericJniTag()165 bool GetGenericJniTag() const { 166 return (tagged_sp_ & 1u) != 0u; 167 } 168 GetJitJniTag()169 bool GetJitJniTag() const { 170 return (tagged_sp_ & 2u) != 0u; 171 } 172 GetTaggedSp()173 uintptr_t GetTaggedSp() const { 174 return tagged_sp_; 175 } 176 177 private: TaggedTopQuickFrame(uintptr_t tagged_sp)178 explicit TaggedTopQuickFrame(uintptr_t tagged_sp) : tagged_sp_(tagged_sp) { } 179 180 uintptr_t tagged_sp_; 181 }; 182 static_assert(sizeof(TaggedTopQuickFrame) == sizeof(uintptr_t), "TaggedTopQuickFrame size check"); 183 184 TaggedTopQuickFrame tagged_top_quick_frame_; 185 ManagedStack* link_; 186 ShadowFrame* top_shadow_frame_; 187 }; 188 189 } // namespace art 190 191 #endif // ART_RUNTIME_MANAGED_STACK_H_ 192