Mercurial > hg > truffle
comparison src/share/vm/prims/jvmtiEnvThreadState.cpp @ 0:a61af66fc99e jdk7-b24
Initial load
author | duke |
---|---|
date | Sat, 01 Dec 2007 00:00:00 +0000 |
parents | |
children | c18cbe5936b8 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a61af66fc99e |
---|---|
1 /* | |
2 * Copyright 2003-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
20 * CA 95054 USA or visit www.sun.com if you need additional information or | |
21 * have any questions. | |
22 * | |
23 */ | |
24 | |
25 # include "incls/_precompiled.incl" | |
26 # include "incls/_jvmtiEnvThreadState.cpp.incl" | |
27 | |
28 | |
29 /////////////////////////////////////////////////////////////// | |
30 // | |
31 // class JvmtiFramePop | |
32 // | |
33 | |
34 #ifndef PRODUCT | |
35 void JvmtiFramePop::print() { | |
36 tty->print_cr("_frame_number=%d", _frame_number); | |
37 } | |
38 #endif | |
39 | |
40 | |
41 /////////////////////////////////////////////////////////////// | |
42 // | |
43 // class JvmtiFramePops - private methods | |
44 // | |
45 | |
46 void | |
47 JvmtiFramePops::set(JvmtiFramePop& fp) { | |
48 if (_pops->find(fp.frame_number()) < 0) { | |
49 _pops->append(fp.frame_number()); | |
50 } | |
51 } | |
52 | |
53 | |
54 void | |
55 JvmtiFramePops::clear(JvmtiFramePop& fp) { | |
56 assert(_pops->length() > 0, "No more frame pops"); | |
57 | |
58 _pops->remove(fp.frame_number()); | |
59 } | |
60 | |
61 | |
62 int | |
63 JvmtiFramePops::clear_to(JvmtiFramePop& fp) { | |
64 int cleared = 0; | |
65 int index = 0; | |
66 while (index < _pops->length()) { | |
67 JvmtiFramePop pop = JvmtiFramePop(_pops->at(index)); | |
68 if (pop.above_on_stack(fp)) { | |
69 _pops->remove_at(index); | |
70 ++cleared; | |
71 } else { | |
72 ++index; | |
73 } | |
74 } | |
75 return cleared; | |
76 } | |
77 | |
78 | |
79 /////////////////////////////////////////////////////////////// | |
80 // | |
81 // class JvmtiFramePops - public methods | |
82 // | |
83 | |
84 JvmtiFramePops::JvmtiFramePops() { | |
85 _pops = new (ResourceObj::C_HEAP) GrowableArray<int> (2, true); | |
86 } | |
87 | |
88 JvmtiFramePops::~JvmtiFramePops() { | |
89 // return memory to c_heap. | |
90 delete _pops; | |
91 } | |
92 | |
93 | |
94 #ifndef PRODUCT | |
95 void JvmtiFramePops::print() { | |
96 ResourceMark rm; | |
97 | |
98 int n = _pops->length(); | |
99 for (int i=0; i<n; i++) { | |
100 JvmtiFramePop fp = JvmtiFramePop(_pops->at(i)); | |
101 tty->print("%d: ", i); | |
102 fp.print(); | |
103 tty->print_cr(""); | |
104 } | |
105 } | |
106 #endif | |
107 | |
108 /////////////////////////////////////////////////////////////// | |
109 // | |
110 // class JvmtiEnvThreadState | |
111 // | |
112 // Instances of JvmtiEnvThreadState hang off of each JvmtiThreadState, | |
113 // one per JvmtiEnv. | |
114 // | |
115 | |
116 JvmtiEnvThreadState::JvmtiEnvThreadState(JavaThread *thread, JvmtiEnvBase *env) : | |
117 _event_enable() { | |
118 _thread = thread; | |
119 _env = (JvmtiEnv*)env; | |
120 _next = NULL; | |
121 _frame_pops = NULL; | |
122 _current_bci = 0; | |
123 _current_method_id = NULL; | |
124 _breakpoint_posted = false; | |
125 _single_stepping_posted = false; | |
126 _agent_thread_local_storage_data = NULL; | |
127 } | |
128 | |
129 JvmtiEnvThreadState::~JvmtiEnvThreadState() { | |
130 delete _frame_pops; | |
131 _frame_pops = NULL; | |
132 } | |
133 | |
134 // Given that a new (potential) event has come in, | |
135 // maintain the current JVMTI location on a per-thread per-env basis | |
136 // and use it to filter out duplicate events: | |
137 // - instruction rewrites | |
138 // - breakpoint followed by single step | |
139 // - single step at a breakpoint | |
140 void JvmtiEnvThreadState::compare_and_set_current_location(methodOop new_method, | |
141 address new_location, jvmtiEvent event) { | |
142 | |
143 int new_bci = new_location - new_method->code_base(); | |
144 | |
145 // The method is identified and stored as a jmethodID which is safe in this | |
146 // case because the class cannot be unloaded while a method is executing. | |
147 jmethodID new_method_id = new_method->jmethod_id(); | |
148 | |
149 // the last breakpoint or single step was at this same location | |
150 if (_current_bci == new_bci && _current_method_id == new_method_id) { | |
151 switch (event) { | |
152 case JVMTI_EVENT_BREAKPOINT: | |
153 // Repeat breakpoint is complicated. If we previously posted a breakpoint | |
154 // event at this location and if we also single stepped at this location | |
155 // then we skip the duplicate breakpoint. | |
156 _breakpoint_posted = _breakpoint_posted && _single_stepping_posted; | |
157 break; | |
158 case JVMTI_EVENT_SINGLE_STEP: | |
159 // Repeat single step is easy: just don't post it again. | |
160 // If step is pending for popframe then it may not be | |
161 // a repeat step. The new_bci and method_id is same as current_bci | |
162 // and current method_id after pop and step for recursive calls. | |
163 // This has been handled by clearing the location | |
164 _single_stepping_posted = true; | |
165 break; | |
166 default: | |
167 assert(false, "invalid event value passed"); | |
168 break; | |
169 } | |
170 return; | |
171 } | |
172 | |
173 set_current_location(new_method_id, new_bci); | |
174 _breakpoint_posted = false; | |
175 _single_stepping_posted = false; | |
176 } | |
177 | |
178 | |
179 JvmtiFramePops* JvmtiEnvThreadState::get_frame_pops() { | |
180 #ifdef ASSERT | |
181 uint32_t debug_bits = 0; | |
182 #endif | |
183 assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), | |
184 "frame pop data only accessible from same thread or while suspended"); | |
185 | |
186 if (_frame_pops == NULL) { | |
187 _frame_pops = new JvmtiFramePops(); | |
188 assert(_frame_pops != NULL, "_frame_pops != NULL"); | |
189 } | |
190 return _frame_pops; | |
191 } | |
192 | |
193 | |
194 bool JvmtiEnvThreadState::has_frame_pops() { | |
195 return _frame_pops == NULL? false : (_frame_pops->length() > 0); | |
196 } | |
197 | |
198 void JvmtiEnvThreadState::set_frame_pop(int frame_number) { | |
199 #ifdef ASSERT | |
200 uint32_t debug_bits = 0; | |
201 #endif | |
202 assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), | |
203 "frame pop data only accessible from same thread or while suspended"); | |
204 JvmtiFramePop fpop(frame_number); | |
205 JvmtiEventController::set_frame_pop(this, fpop); | |
206 } | |
207 | |
208 | |
209 void JvmtiEnvThreadState::clear_frame_pop(int frame_number) { | |
210 #ifdef ASSERT | |
211 uint32_t debug_bits = 0; | |
212 #endif | |
213 assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), | |
214 "frame pop data only accessible from same thread or while suspended"); | |
215 JvmtiFramePop fpop(frame_number); | |
216 JvmtiEventController::clear_frame_pop(this, fpop); | |
217 } | |
218 | |
219 | |
220 void JvmtiEnvThreadState::clear_to_frame_pop(int frame_number) { | |
221 #ifdef ASSERT | |
222 uint32_t debug_bits = 0; | |
223 #endif | |
224 assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), | |
225 "frame pop data only accessible from same thread or while suspended"); | |
226 JvmtiFramePop fpop(frame_number); | |
227 JvmtiEventController::clear_to_frame_pop(this, fpop); | |
228 } | |
229 | |
230 | |
231 bool JvmtiEnvThreadState::is_frame_pop(int cur_frame_number) { | |
232 #ifdef ASSERT | |
233 uint32_t debug_bits = 0; | |
234 #endif | |
235 assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), | |
236 "frame pop data only accessible from same thread or while suspended"); | |
237 if (!get_thread()->is_interp_only_mode() || _frame_pops == NULL) { | |
238 return false; | |
239 } | |
240 JvmtiFramePop fp(cur_frame_number); | |
241 return get_frame_pops()->contains(fp); | |
242 } | |
243 | |
244 | |
245 class VM_GetCurrentLocation : public VM_Operation { | |
246 private: | |
247 JavaThread *_thread; | |
248 jmethodID _method_id; | |
249 int _bci; | |
250 | |
251 public: | |
252 VM_GetCurrentLocation(JavaThread *thread) { | |
253 _thread = thread; | |
254 } | |
255 VMOp_Type type() const { return VMOp_GetCurrentLocation; } | |
256 void doit() { | |
257 ResourceMark rmark; // _thread != Thread::current() | |
258 RegisterMap rm(_thread, false); | |
259 javaVFrame* vf = _thread->last_java_vframe(&rm); | |
260 assert(vf != NULL, "must have last java frame"); | |
261 methodOop method = vf->method(); | |
262 _method_id = method->jmethod_id(); | |
263 _bci = vf->bci(); | |
264 } | |
265 void get_current_location(jmethodID *method_id, int *bci) { | |
266 *method_id = _method_id; | |
267 *bci = _bci; | |
268 } | |
269 }; | |
270 | |
271 void JvmtiEnvThreadState::reset_current_location(jvmtiEvent event_type, bool enabled) { | |
272 assert(event_type == JVMTI_EVENT_SINGLE_STEP || event_type == JVMTI_EVENT_BREAKPOINT, | |
273 "must be single-step or breakpoint event"); | |
274 | |
275 // Current location is used to detect the following: | |
276 // 1) a breakpoint event followed by single-stepping to the same bci | |
277 // 2) single-step to a bytecode that will be transformed to a fast version | |
278 // We skip to avoid posting the duplicate single-stepping event. | |
279 | |
280 // If single-stepping is disabled, clear current location so that | |
281 // single-stepping to the same method and bcp at a later time will be | |
282 // detected if single-stepping is enabled at that time (see 4388912). | |
283 | |
284 // If single-stepping is enabled, set the current location to the | |
285 // current method and bcp. This covers the following type of case, | |
286 // e.g., the debugger stepi command: | |
287 // - bytecode single stepped | |
288 // - SINGLE_STEP event posted and SINGLE_STEP event disabled | |
289 // - SINGLE_STEP event reenabled | |
290 // - bytecode rewritten to fast version | |
291 | |
292 // If breakpoint event is disabled, clear current location only if | |
293 // single-stepping is not enabled. Otherwise, keep the thread location | |
294 // to detect any duplicate events. | |
295 | |
296 if (enabled) { | |
297 // If enabling breakpoint, no need to reset. | |
298 // Can't do anything if empty stack. | |
299 if (event_type == JVMTI_EVENT_SINGLE_STEP && _thread->has_last_Java_frame()) { | |
300 jmethodID method_id; | |
301 int bci; | |
302 // The java thread stack may not be walkable for a running thread | |
303 // so get current location at safepoint. | |
304 VM_GetCurrentLocation op(_thread); | |
305 VMThread::execute(&op); | |
306 op.get_current_location(&method_id, &bci); | |
307 set_current_location(method_id, bci); | |
308 } | |
309 } else if (event_type == JVMTI_EVENT_SINGLE_STEP || !is_enabled(JVMTI_EVENT_SINGLE_STEP)) { | |
310 // If this is to disable breakpoint, also check if single-step is not enabled | |
311 clear_current_location(); | |
312 } | |
313 } |