| /* |
| * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| #ifndef SHARE_RUNTIME_STACKWATERMARK_HPP |
| #define SHARE_RUNTIME_STACKWATERMARK_HPP |
| |
| #include "memory/allStatic.hpp" |
| #include "runtime/mutex.hpp" |
| #include "runtime/stackWatermarkKind.hpp" |
| #include "utilities/growableArray.hpp" |
| |
| class frame; |
| class JavaThread; |
| class RegisterMap; |
| class StackWatermarkFramesIterator; |
| |
| // The StackWatermark state is a tuple comprising the last epoch in which |
| // the watermark has been processed, and a boolean denoting whether the whole |
| // processing of the lazy snapshot has been processed or not. It is written |
| // in a way that can be used outside of locks, so that fast path checks can |
| // be performed without the need for any locking. The boolean can only be |
| // trusted if the epoch of the state is the same as the epoch_id() of the |
| // watermark. Incrementing the epoch_id() will implicitly initiate a new lazy |
| // stack snapshot, and trigger processing on it as needed, due to the cached |
| // epoch of the state being outdated. When the snapshot is_done for the current |
| // epoch_id(), there is no need to do anything further. |
| class StackWatermarkState : public AllStatic { |
| public: |
| inline static bool is_done(uint32_t state) { |
| return state & 1; |
| } |
| |
| inline static uint32_t epoch(uint32_t state) { |
| return state >> 1; |
| } |
| |
| inline static uint32_t create(uint32_t epoch, bool is_done) { |
| return (epoch << 1) | (is_done ? 1u : 0u); |
| } |
| }; |
| |
| // The StackWatermark allows lazy incremental concurrent processing of a |
| // snapshot of a stack. The lazy and incremental nature is implemented by |
| // marking a frame (the watermark) from which returns (or other forms of |
| // unwinding) will take a slow path to perform additional processing |
| // required when exposing more frames that were part of the snapshot to |
| // the system. The watermark pointer always denotes the SP of the watermark. |
| // However, active frames can grow and shrink arbitrarily compared to the |
| // snapshot view that is being processed, due to things like c2i adapters, |
| // and various register saving techniques to get into the runtime. Therefore, |
| // in order to cope with the frames growing and shrinking, comparisons |
| // against the watermark are performed with the frame pointer of a given |
| // frame against the watermark (denoting the SP). |
| // |
| // ---------- |
| // | | |
| // | caller | |
| // | | |
| // ---------- |
| // | | <-- frame fp (always above the watermark of the same frame, |
| // | callee | regardless of frame resizing) |
| // | | |
| // ---------- <-- watermark (callee SP from the snapshot, SP at the |
| // point of unwinding, might be above or below |
| // due to frame resizing) |
| class StackWatermark : public CHeapObj<mtThread> { |
| friend class StackWatermarkFramesIterator; |
| protected: |
| volatile uint32_t _state; |
| volatile uintptr_t _watermark; |
| StackWatermark* _next; |
| JavaThread* _jt; |
| StackWatermarkFramesIterator* _iterator; |
| Mutex _lock; |
| StackWatermarkKind _kind; |
| GrowableArrayCHeap<StackWatermark*, mtThread> _linked_watermarks; |
| |
| void process_one(); |
| |
| void update_watermark(); |
| void yield_processing(); |
| static bool has_barrier(const frame& f); |
| void ensure_safe(const frame& f); |
| void assert_is_frame_safe(const frame& f) NOT_DEBUG_RETURN; |
| bool is_frame_safe(const frame& f); |
| |
| // API for consumers of the stack watermark barrier. |
| // The rule for consumers is: do not perform thread transitions |
| // or take locks of rank >= special. This is all very special code. |
| virtual uint32_t epoch_id() const = 0; |
| virtual void process(const frame& f, RegisterMap& register_map, void* context) = 0; |
| virtual void start_processing_impl(void* context); |
| |
| // Set process_on_iteration to false if you don't want to move the |
| // watermark when new frames are discovered from stack walkers, as |
| // opposed to due to frames being unwound by the owning thread. |
| virtual bool process_on_iteration() { return true; } |
| |
| void process_linked_watermarks(); |
| |
| bool processing_started(uint32_t state) const; |
| bool processing_completed(uint32_t state) const; |
| |
| public: |
| StackWatermark(JavaThread* jt, StackWatermarkKind kind, uint32_t epoch); |
| virtual ~StackWatermark(); |
| |
| |
| // StackWatermarkSet support |
| StackWatermarkKind kind() const { return _kind; } |
| StackWatermark* next() const { return _next; } |
| void set_next(StackWatermark* n) { _next = n; } |
| |
| void push_linked_watermark(StackWatermark* watermark); |
| void pop_linked_watermark(); |
| |
| uintptr_t watermark(); |
| uintptr_t last_processed(); |
| uintptr_t last_processed_raw(); |
| |
| bool processing_started() const; |
| bool processing_started_acquire() const; |
| bool processing_completed() const; |
| bool processing_completed_acquire() const; |
| |
| void before_unwind(); |
| void after_unwind(); |
| |
| void on_iteration(const frame& f); |
| void on_safepoint(); |
| void start_processing(); |
| void finish_processing(void* context); |
| }; |
| |
| #endif // SHARE_RUNTIME_STACKWATERMARK_HPP |