1 /*
2 * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25
26 #ifndef SHARE_PRIMS_STACKWALK_HPP
27 #define SHARE_PRIMS_STACKWALK_HPP
28
29 #include "jvm.h"
30 #include "oops/oop.hpp"
31 #include "runtime/continuation.hpp"
32 #include "runtime/continuationEntry.hpp"
33 #include "runtime/vframe.hpp"
34
35 // BaseFrameStream is an abstract base class for encapsulating the VM-side
36 // implementation of the StackWalker API. There are two concrete subclasses:
37 // - JavaFrameStream:
38 // -based on vframeStream; used in most instances
39 // - LiveFrameStream:
40 // -based on javaVFrame; used for retrieving locals/monitors/operands for
41 // LiveStackFrame
42 class BaseFrameStream : public StackObj {
43 private:
44 enum {
45 magic_pos = 0
46 };
47
48 JavaThread* _thread;
49 Handle _continuation;
50 jlong _anchor;
51
52 protected:
53 void fill_stackframe(Handle stackFrame, const methodHandle& method, TRAPS);
54 public:
55 BaseFrameStream(JavaThread* thread, Handle continuation);
56
57 virtual void next()=0;
58 virtual bool at_end()=0;
59
60 virtual Method* method()=0;
61 virtual int bci()=0;
62 virtual oop cont()=0; // returns the current continuation (even when walking a thread)
63
64 virtual const RegisterMap* reg_map()=0;
65
66 virtual void fill_frame(int index, refArrayHandle frames_array,
67 const methodHandle& method, TRAPS)=0;
68
69 oop continuation() { return _continuation(); }
70 void set_continuation(Handle cont);
71
72 void setup_magic_on_entry(refArrayHandle frames_array);
73 bool check_magic(refArrayHandle frames_array);
74 bool cleanup_magic_on_exit(refArrayHandle frames_array);
75
76 bool is_valid_in(Thread* thread, refArrayHandle frames_array) {
77 return (_thread == thread && check_magic(frames_array));
78 }
79
80 jlong address_value() {
81 return (jlong) this;
82 }
83
84 static BaseFrameStream* from_current(JavaThread* thread, jlong magic, refArrayHandle frames_array);
85 };
86
87 class JavaFrameStream : public BaseFrameStream {
88 private:
89 vframeStream _vfst;
90 bool _need_method_info;
91
92 public:
93 JavaFrameStream(JavaThread* thread, jint mode, Handle cont_scope, Handle cont);
94
95 const RegisterMap* reg_map() override { return _vfst.reg_map(); };
96
97 void next() override;
98 bool at_end() override { return _vfst.at_end(); }
99
100 Method* method() override { return _vfst.method(); }
101 int bci() override { return _vfst.bci(); }
102 oop cont() override { return _vfst.continuation(); }
103
104 void fill_frame(int index, refArrayHandle frames_array,
105 const methodHandle& method, TRAPS) override;
106 };
107
108 class LiveFrameStream : public BaseFrameStream {
109 private:
110 enum {
111 MODE_INTERPRETED = 0x01,
112 MODE_COMPILED = 0x02
113 };
114
115 Handle _cont_scope; // the delimitation of this walk
116
117 RegisterMap* _map;
118 javaVFrame* _jvf;
119 ContinuationEntry* _cont_entry;
120
121 void fill_live_stackframe(Handle stackFrame, const methodHandle& method, TRAPS);
122 static oop create_primitive_slot_instance(StackValueCollection* values,
123 int i, BasicType type, TRAPS);
124 static objArrayHandle monitors_to_object_array(GrowableArray<MonitorInfo*>* monitors,
125 TRAPS);
126 static objArrayHandle values_to_object_array(StackValueCollection* values, TRAPS);
127 public:
128 LiveFrameStream(JavaThread* thread, RegisterMap* rm, Handle cont_scope, Handle cont);
129
130 const RegisterMap* reg_map() override { return _map; };
131
132 void next() override;
133 bool at_end() override { return _jvf == nullptr; }
134
135 Method* method() override { return _jvf->method(); }
136 int bci() override { return _jvf->bci(); }
137 oop cont() override { return continuation() != nullptr ? continuation(): ContinuationEntry::cont_oop_or_null(_cont_entry, _map->thread()); }
138
139 void fill_frame(int index, refArrayHandle frames_array,
140 const methodHandle& method, TRAPS) override;
141 };
142
143 class StackWalk : public AllStatic {
144 private:
145 static int fill_in_frames(jint mode, BaseFrameStream& stream,
146 int buffer_size, int start_index,
147 refArrayHandle frames_array,
148 int& end_index, TRAPS);
149
150 static inline bool skip_hidden_frames(jint mode) {
151 return (mode & JVM_STACKWALK_SHOW_HIDDEN_FRAMES) == 0;
152 }
153 static inline bool live_frame_info(jint mode) {
154 return (mode & JVM_STACKWALK_FILL_LIVE_STACK_FRAMES) != 0;
155 }
156
157 public:
158 static inline bool need_method_info(jint mode) {
159 return (mode & JVM_STACKWALK_CLASS_INFO_ONLY) == 0;
160 }
161
162 static oop walk(Handle stackStream, jint mode, int skip_frames, Handle cont_scope, Handle cont,
163 int buffer_size, int start_index, refArrayHandle frames_array,
164 TRAPS);
165
166 static oop fetchFirstBatch(BaseFrameStream& stream, Handle stackStream,
167 jint mode, int skip_frames, int buffer_size,
168 int start_index, refArrayHandle frames_array, TRAPS);
169
170 static jint fetchNextBatch(Handle stackStream, jint mode, jlong magic,
171 int last_batch_count, int buffer_size, int start_index,
172 refArrayHandle frames_array, TRAPS);
173
174 static void setContinuation(Handle stackStream, jlong magic, refArrayHandle frames_array,
175 Handle cont, TRAPS);
176 };
177 #endif // SHARE_PRIMS_STACKWALK_HPP