| /* | |
| * 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); | |
| 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); | |
| void assert_is_frame_safe(const frame& f) NOT_DEBUG_RETURN; | |
| }; | |
| #endif // SHARE_RUNTIME_STACKWATERMARK_HPP |