| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef ART_RUNTIME_MANAGED_STACK_H_ |
| #define ART_RUNTIME_MANAGED_STACK_H_ |
| |
| #include <cstdint> |
| #include <cstring> |
| #include <string> |
| |
| #include <android-base/logging.h> |
| |
| #include "base/locks.h" |
| #include "base/macros.h" |
| #include "base/bit_utils.h" |
| |
| namespace art { |
| |
| namespace mirror { |
| class Object; |
| } // namespace mirror |
| |
| class ArtMethod; |
| class ShadowFrame; |
| template <typename T> class StackReference; |
| |
| // The managed stack is used to record fragments of managed code stacks. Managed code stacks |
| // may either be shadow frames or lists of frames using fixed frame sizes. Transition records are |
| // necessary for transitions between code using different frame layouts and transitions into native |
| // code. |
| class PACKED(4) ManagedStack { |
| public: |
| static size_t constexpr kTaggedJniSpMask = 0x3; |
| |
| ManagedStack() |
| : tagged_top_quick_frame_(TaggedTopQuickFrame::CreateNotTagged(nullptr)), |
| link_(nullptr), |
| top_shadow_frame_(nullptr) {} |
| |
| void PushManagedStackFragment(ManagedStack* fragment) { |
| // Copy this top fragment into given fragment. |
| memcpy(fragment, this, sizeof(ManagedStack)); |
| // Clear this fragment, which has become the top. |
| memset(this, 0, sizeof(ManagedStack)); |
| // Link our top fragment onto the given fragment. |
| link_ = fragment; |
| } |
| |
| void PopManagedStackFragment(const ManagedStack& fragment) { |
| DCHECK(&fragment == link_); |
| // Copy this given fragment back to the top. |
| memcpy(this, &fragment, sizeof(ManagedStack)); |
| } |
| |
| ManagedStack* GetLink() const { |
| return link_; |
| } |
| |
| ArtMethod** GetTopQuickFrameKnownNotTagged() const { |
| return tagged_top_quick_frame_.GetSpKnownNotTagged(); |
| } |
| |
| ArtMethod** GetTopQuickFrame() const { |
| return tagged_top_quick_frame_.GetSp(); |
| } |
| |
| bool GetTopQuickFrameGenericJniTag() const { |
| return tagged_top_quick_frame_.GetGenericJniTag(); |
| } |
| |
| bool GetTopQuickFrameJitJniTag() const { |
| return tagged_top_quick_frame_.GetJitJniTag(); |
| } |
| |
| bool HasTopQuickFrame() const { |
| return tagged_top_quick_frame_.GetTaggedSp() != 0u; |
| } |
| |
| void SetTopQuickFrame(ArtMethod** top) { |
| DCHECK(top_shadow_frame_ == nullptr); |
| DCHECK_ALIGNED(top, 4u); |
| tagged_top_quick_frame_ = TaggedTopQuickFrame::CreateNotTagged(top); |
| } |
| |
| void SetTopQuickFrameGenericJniTagged(ArtMethod** top) { |
| DCHECK(top_shadow_frame_ == nullptr); |
| DCHECK_ALIGNED(top, 4u); |
| tagged_top_quick_frame_ = TaggedTopQuickFrame::CreateGenericJniTagged(top); |
| } |
| |
| static constexpr size_t TaggedTopQuickFrameOffset() { |
| return OFFSETOF_MEMBER(ManagedStack, tagged_top_quick_frame_); |
| } |
| |
| ALWAYS_INLINE ShadowFrame* PushShadowFrame(ShadowFrame* new_top_frame); |
| ALWAYS_INLINE ShadowFrame* PopShadowFrame(); |
| |
| ShadowFrame* GetTopShadowFrame() const { |
| return top_shadow_frame_; |
| } |
| |
| bool HasTopShadowFrame() const { |
| return GetTopShadowFrame() != nullptr; |
| } |
| |
| void SetTopShadowFrame(ShadowFrame* top) { |
| DCHECK_EQ(tagged_top_quick_frame_.GetTaggedSp(), 0u); |
| top_shadow_frame_ = top; |
| } |
| |
| static size_t TopShadowFrameOffset() { |
| return OFFSETOF_MEMBER(ManagedStack, top_shadow_frame_); |
| } |
| |
| private: |
| // Encodes the top quick frame (which must be at least 4-byte aligned) |
| // and a flag that marks the GenericJNI trampoline. |
| class TaggedTopQuickFrame { |
| public: |
| static TaggedTopQuickFrame CreateNotTagged(ArtMethod** sp) { |
| DCHECK_ALIGNED(sp, 4u); |
| return TaggedTopQuickFrame(reinterpret_cast<uintptr_t>(sp)); |
| } |
| |
| static TaggedTopQuickFrame CreateGenericJniTagged(ArtMethod** sp) { |
| DCHECK_ALIGNED(sp, 4u); |
| return TaggedTopQuickFrame(reinterpret_cast<uintptr_t>(sp) | 1u); |
| } |
| |
| // Get SP known to be not tagged and non-null. |
| ArtMethod** GetSpKnownNotTagged() const { |
| DCHECK(!GetGenericJniTag() && !GetJitJniTag()); |
| DCHECK_NE(tagged_sp_, 0u); |
| return reinterpret_cast<ArtMethod**>(tagged_sp_); |
| } |
| |
| ArtMethod** GetSp() const { |
| return reinterpret_cast<ArtMethod**>(tagged_sp_ & ~static_cast<uintptr_t>(kTaggedJniSpMask)); |
| } |
| |
| bool GetGenericJniTag() const { |
| return (tagged_sp_ & 1u) != 0u; |
| } |
| |
| bool GetJitJniTag() const { |
| return (tagged_sp_ & 2u) != 0u; |
| } |
| |
| uintptr_t GetTaggedSp() const { |
| return tagged_sp_; |
| } |
| |
| private: |
| explicit TaggedTopQuickFrame(uintptr_t tagged_sp) : tagged_sp_(tagged_sp) { } |
| |
| uintptr_t tagged_sp_; |
| }; |
| static_assert(sizeof(TaggedTopQuickFrame) == sizeof(uintptr_t), "TaggedTopQuickFrame size check"); |
| |
| TaggedTopQuickFrame tagged_top_quick_frame_; |
| ManagedStack* link_; |
| ShadowFrame* top_shadow_frame_; |
| }; |
| |
| } // namespace art |
| |
| #endif // ART_RUNTIME_MANAGED_STACK_H_ |