File: | jdk/src/hotspot/share/prims/jvmtiImpl.cpp |
Warning: | line 224, column 10 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright (c) 2003, 2021, 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 | #include "precompiled.hpp" | |||
26 | #include "classfile/javaClasses.hpp" | |||
27 | #include "classfile/symbolTable.hpp" | |||
28 | #include "code/nmethod.hpp" | |||
29 | #include "interpreter/interpreter.hpp" | |||
30 | #include "interpreter/oopMapCache.hpp" | |||
31 | #include "jvmtifiles/jvmtiEnv.hpp" | |||
32 | #include "logging/log.hpp" | |||
33 | #include "logging/logStream.hpp" | |||
34 | #include "memory/allocation.inline.hpp" | |||
35 | #include "memory/resourceArea.hpp" | |||
36 | #include "oops/instanceKlass.hpp" | |||
37 | #include "oops/klass.inline.hpp" | |||
38 | #include "oops/oop.inline.hpp" | |||
39 | #include "oops/oopHandle.inline.hpp" | |||
40 | #include "prims/jvmtiAgentThread.hpp" | |||
41 | #include "prims/jvmtiEventController.inline.hpp" | |||
42 | #include "prims/jvmtiImpl.hpp" | |||
43 | #include "prims/jvmtiRedefineClasses.hpp" | |||
44 | #include "runtime/deoptimization.hpp" | |||
45 | #include "runtime/frame.inline.hpp" | |||
46 | #include "runtime/handles.inline.hpp" | |||
47 | #include "runtime/interfaceSupport.inline.hpp" | |||
48 | #include "runtime/javaCalls.hpp" | |||
49 | #include "runtime/jniHandles.hpp" | |||
50 | #include "runtime/os.hpp" | |||
51 | #include "runtime/serviceThread.hpp" | |||
52 | #include "runtime/signature.hpp" | |||
53 | #include "runtime/thread.inline.hpp" | |||
54 | #include "runtime/threadSMR.hpp" | |||
55 | #include "runtime/vframe.hpp" | |||
56 | #include "runtime/vframe_hp.hpp" | |||
57 | #include "runtime/vmOperations.hpp" | |||
58 | #include "utilities/exceptions.hpp" | |||
59 | ||||
60 | // | |||
61 | // class JvmtiAgentThread | |||
62 | // | |||
63 | // JavaThread used to wrap a thread started by an agent | |||
64 | // using the JVMTI method RunAgentThread. | |||
65 | // | |||
66 | ||||
67 | JvmtiAgentThread::JvmtiAgentThread(JvmtiEnv* env, jvmtiStartFunction start_fn, const void *start_arg) | |||
68 | : JavaThread(start_function_wrapper) { | |||
69 | _env = env; | |||
70 | _start_fn = start_fn; | |||
71 | _start_arg = start_arg; | |||
72 | } | |||
73 | ||||
74 | void | |||
75 | JvmtiAgentThread::start_function_wrapper(JavaThread *thread, TRAPSJavaThread* __the_thread__) { | |||
76 | // It is expected that any Agent threads will be created as | |||
77 | // Java Threads. If this is the case, notification of the creation | |||
78 | // of the thread is given in JavaThread::thread_main(). | |||
79 | assert(thread == JavaThread::current(), "sanity check")do { if (!(thread == JavaThread::current())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 79, "assert(" "thread == JavaThread::current()" ") failed", "sanity check"); ::breakpoint(); } } while (0); | |||
80 | ||||
81 | JvmtiAgentThread *dthread = (JvmtiAgentThread *)thread; | |||
82 | dthread->call_start_function(); | |||
83 | } | |||
84 | ||||
85 | void | |||
86 | JvmtiAgentThread::call_start_function() { | |||
87 | ThreadToNativeFromVM transition(this); | |||
88 | _start_fn(_env->jvmti_external(), jni_environment(), (void*)_start_arg); | |||
89 | } | |||
90 | ||||
91 | ||||
92 | // | |||
93 | // class GrowableCache - private methods | |||
94 | // | |||
95 | ||||
96 | void GrowableCache::recache() { | |||
97 | int len = _elements->length(); | |||
98 | ||||
99 | FREE_C_HEAP_ARRAY(address, _cache)FreeHeap((char*)(_cache)); | |||
100 | _cache = NEW_C_HEAP_ARRAY(address,len+1, mtInternal)(address*) (AllocateHeap((len+1) * sizeof(address), mtInternal )); | |||
101 | ||||
102 | for (int i=0; i<len; i++) { | |||
103 | _cache[i] = _elements->at(i)->getCacheValue(); | |||
104 | // | |||
105 | // The cache entry has gone bad. Without a valid frame pointer | |||
106 | // value, the entry is useless so we simply delete it in product | |||
107 | // mode. The call to remove() will rebuild the cache again | |||
108 | // without the bad entry. | |||
109 | // | |||
110 | if (_cache[i] == NULL__null) { | |||
111 | assert(false, "cannot recache NULL elements")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 111, "assert(" "false" ") failed", "cannot recache NULL elements" ); ::breakpoint(); } } while (0); | |||
112 | remove(i); | |||
113 | return; | |||
114 | } | |||
115 | } | |||
116 | _cache[len] = NULL__null; | |||
117 | ||||
118 | _listener_fun(_this_obj,_cache); | |||
119 | } | |||
120 | ||||
121 | bool GrowableCache::equals(void* v, GrowableElement *e2) { | |||
122 | GrowableElement *e1 = (GrowableElement *) v; | |||
123 | assert(e1 != NULL, "e1 != NULL")do { if (!(e1 != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 123, "assert(" "e1 != __null" ") failed", "e1 != NULL"); :: breakpoint(); } } while (0); | |||
124 | assert(e2 != NULL, "e2 != NULL")do { if (!(e2 != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 124, "assert(" "e2 != __null" ") failed", "e2 != NULL"); :: breakpoint(); } } while (0); | |||
125 | ||||
126 | return e1->equals(e2); | |||
127 | } | |||
128 | ||||
129 | // | |||
130 | // class GrowableCache - public methods | |||
131 | // | |||
132 | ||||
133 | GrowableCache::GrowableCache() { | |||
134 | _this_obj = NULL__null; | |||
135 | _listener_fun = NULL__null; | |||
136 | _elements = NULL__null; | |||
137 | _cache = NULL__null; | |||
138 | } | |||
139 | ||||
140 | GrowableCache::~GrowableCache() { | |||
141 | clear(); | |||
142 | delete _elements; | |||
143 | FREE_C_HEAP_ARRAY(address, _cache)FreeHeap((char*)(_cache)); | |||
144 | } | |||
145 | ||||
146 | void GrowableCache::initialize(void *this_obj, void listener_fun(void *, address*) ) { | |||
147 | _this_obj = this_obj; | |||
148 | _listener_fun = listener_fun; | |||
149 | _elements = new (ResourceObj::C_HEAP, mtServiceability) GrowableArray<GrowableElement*>(5, mtServiceability); | |||
150 | recache(); | |||
151 | } | |||
152 | ||||
153 | // number of elements in the collection | |||
154 | int GrowableCache::length() { | |||
155 | return _elements->length(); | |||
156 | } | |||
157 | ||||
158 | // get the value of the index element in the collection | |||
159 | GrowableElement* GrowableCache::at(int index) { | |||
160 | GrowableElement *e = (GrowableElement *) _elements->at(index); | |||
161 | assert(e != NULL, "e != NULL")do { if (!(e != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 161, "assert(" "e != __null" ") failed", "e != NULL"); ::breakpoint (); } } while (0); | |||
162 | return e; | |||
163 | } | |||
164 | ||||
165 | int GrowableCache::find(GrowableElement* e) { | |||
166 | return _elements->find(e, GrowableCache::equals); | |||
167 | } | |||
168 | ||||
169 | // append a copy of the element to the end of the collection | |||
170 | void GrowableCache::append(GrowableElement* e) { | |||
171 | GrowableElement *new_e = e->clone(); | |||
172 | _elements->append(new_e); | |||
173 | recache(); | |||
174 | } | |||
175 | ||||
176 | // remove the element at index | |||
177 | void GrowableCache::remove (int index) { | |||
178 | GrowableElement *e = _elements->at(index); | |||
179 | assert(e != NULL, "e != NULL")do { if (!(e != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 179, "assert(" "e != __null" ") failed", "e != NULL"); ::breakpoint (); } } while (0); | |||
180 | _elements->remove(e); | |||
181 | delete e; | |||
182 | recache(); | |||
183 | } | |||
184 | ||||
185 | // clear out all elements, release all heap space and | |||
186 | // let our listener know that things have changed. | |||
187 | void GrowableCache::clear() { | |||
188 | int len = _elements->length(); | |||
189 | for (int i=0; i<len; i++) { | |||
190 | delete _elements->at(i); | |||
191 | } | |||
192 | _elements->clear(); | |||
193 | recache(); | |||
194 | } | |||
195 | ||||
196 | // | |||
197 | // class JvmtiBreakpoint | |||
198 | // | |||
199 | ||||
200 | JvmtiBreakpoint::JvmtiBreakpoint(Method* m_method, jlocation location) | |||
201 | : _method(m_method), _bci((int)location) { | |||
202 | assert(_method != NULL, "No method for breakpoint.")do { if (!(_method != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 202, "assert(" "_method != __null" ") failed", "No method for breakpoint." ); ::breakpoint(); } } while (0); | |||
203 | assert(_bci >= 0, "Negative bci for breakpoint.")do { if (!(_bci >= 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 203, "assert(" "_bci >= 0" ") failed", "Negative bci for breakpoint." ); ::breakpoint(); } } while (0); | |||
204 | oop class_holder_oop = _method->method_holder()->klass_holder(); | |||
205 | _class_holder = OopHandle(JvmtiExport::jvmti_oop_storage(), class_holder_oop); | |||
206 | } | |||
207 | ||||
208 | JvmtiBreakpoint::~JvmtiBreakpoint() { | |||
209 | _class_holder.release(JvmtiExport::jvmti_oop_storage()); | |||
210 | } | |||
211 | ||||
212 | void JvmtiBreakpoint::copy(JvmtiBreakpoint& bp) { | |||
213 | _method = bp._method; | |||
214 | _bci = bp._bci; | |||
215 | _class_holder = OopHandle(JvmtiExport::jvmti_oop_storage(), bp._class_holder.resolve()); | |||
216 | } | |||
217 | ||||
218 | bool JvmtiBreakpoint::equals(JvmtiBreakpoint& bp) { | |||
219 | return _method == bp._method | |||
220 | && _bci == bp._bci; | |||
221 | } | |||
222 | ||||
223 | address JvmtiBreakpoint::getBcp() const { | |||
224 | return _method->bcp_from(_bci); | |||
| ||||
225 | } | |||
226 | ||||
227 | void JvmtiBreakpoint::each_method_version_do(method_action meth_act) { | |||
228 | ((Method*)_method->*meth_act)(_bci); | |||
229 | ||||
230 | // add/remove breakpoint to/from versions of the method that are EMCP. | |||
231 | Thread *thread = Thread::current(); | |||
232 | InstanceKlass* ik = _method->method_holder(); | |||
233 | Symbol* m_name = _method->name(); | |||
234 | Symbol* m_signature = _method->signature(); | |||
235 | ||||
236 | // search previous versions if they exist | |||
237 | for (InstanceKlass* pv_node = ik->previous_versions(); | |||
238 | pv_node != NULL__null; | |||
239 | pv_node = pv_node->previous_versions()) { | |||
240 | Array<Method*>* methods = pv_node->methods(); | |||
241 | ||||
242 | for (int i = methods->length() - 1; i >= 0; i--) { | |||
243 | Method* method = methods->at(i); | |||
244 | // Only set breakpoints in EMCP methods. | |||
245 | // EMCP methods are old but not obsolete. Equivalent | |||
246 | // Modulo Constant Pool means the method is equivalent except | |||
247 | // the constant pool and instructions that access the constant | |||
248 | // pool might be different. | |||
249 | // If a breakpoint is set in a redefined method, its EMCP methods | |||
250 | // must have a breakpoint also. | |||
251 | // None of the methods are deleted until none are running. | |||
252 | // This code could set a breakpoint in a method that | |||
253 | // is never reached, but this won't be noticeable to the programmer. | |||
254 | if (!method->is_obsolete() && | |||
255 | method->name() == m_name && | |||
256 | method->signature() == m_signature) { | |||
257 | ResourceMark rm; | |||
258 | log_debug(redefine, class, breakpoint)(!(LogImpl<(LogTag::_redefine), (LogTag::_class), (LogTag:: _breakpoint), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag ::__NO_TAG)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl <(LogTag::_redefine), (LogTag::_class), (LogTag::_breakpoint ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Debug> | |||
259 | ("%sing breakpoint in %s(%s)", meth_act == &Method::set_breakpoint ? "sett" : "clear", | |||
260 | method->name()->as_C_string(), method->signature()->as_C_string()); | |||
261 | (method->*meth_act)(_bci); | |||
262 | break; | |||
263 | } | |||
264 | } | |||
265 | } | |||
266 | } | |||
267 | ||||
268 | void JvmtiBreakpoint::set() { | |||
269 | each_method_version_do(&Method::set_breakpoint); | |||
270 | } | |||
271 | ||||
272 | void JvmtiBreakpoint::clear() { | |||
273 | each_method_version_do(&Method::clear_breakpoint); | |||
274 | } | |||
275 | ||||
276 | void JvmtiBreakpoint::print_on(outputStream* out) const { | |||
277 | #ifndef PRODUCT | |||
278 | ResourceMark rm; | |||
279 | const char *class_name = (_method == NULL__null) ? "NULL" : _method->klass_name()->as_C_string(); | |||
| ||||
280 | const char *method_name = (_method
| |||
281 | out->print("Breakpoint(%s,%s,%d,%p)", class_name, method_name, _bci, getBcp()); | |||
282 | #endif | |||
283 | } | |||
284 | ||||
285 | ||||
286 | // | |||
287 | // class VM_ChangeBreakpoints | |||
288 | // | |||
289 | // Modify the Breakpoints data structure at a safepoint | |||
290 | // | |||
291 | ||||
292 | void VM_ChangeBreakpoints::doit() { | |||
293 | switch (_operation) { | |||
294 | case SET_BREAKPOINT: | |||
295 | _breakpoints->set_at_safepoint(*_bp); | |||
296 | break; | |||
297 | case CLEAR_BREAKPOINT: | |||
298 | _breakpoints->clear_at_safepoint(*_bp); | |||
299 | break; | |||
300 | default: | |||
301 | assert(false, "Unknown operation")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 301, "assert(" "false" ") failed", "Unknown operation"); :: breakpoint(); } } while (0); | |||
302 | } | |||
303 | } | |||
304 | ||||
305 | // | |||
306 | // class JvmtiBreakpoints | |||
307 | // | |||
308 | // a JVMTI internal collection of JvmtiBreakpoint | |||
309 | // | |||
310 | ||||
311 | JvmtiBreakpoints::JvmtiBreakpoints(void listener_fun(void *,address *)) { | |||
312 | _bps.initialize(this,listener_fun); | |||
313 | } | |||
314 | ||||
315 | JvmtiBreakpoints:: ~JvmtiBreakpoints() {} | |||
316 | ||||
317 | void JvmtiBreakpoints::print() { | |||
318 | #ifndef PRODUCT | |||
319 | LogTarget(Trace, jvmti)LogTargetImpl<LogLevel::Trace, (LogTag::_jvmti), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG)> log; | |||
320 | LogStream log_stream(log); | |||
321 | ||||
322 | int n = _bps.length(); | |||
323 | for (int i=0; i<n; i++) { | |||
324 | JvmtiBreakpoint& bp = _bps.at(i); | |||
325 | log_stream.print("%d: ", i); | |||
326 | bp.print_on(&log_stream); | |||
327 | log_stream.cr(); | |||
328 | } | |||
329 | #endif | |||
330 | } | |||
331 | ||||
332 | ||||
333 | void JvmtiBreakpoints::set_at_safepoint(JvmtiBreakpoint& bp) { | |||
334 | assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint")do { if (!(SafepointSynchronize::is_at_safepoint())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 334, "assert(" "SafepointSynchronize::is_at_safepoint()" ") failed" , "must be at safepoint"); ::breakpoint(); } } while (0); | |||
335 | ||||
336 | int i = _bps.find(bp); | |||
337 | if (i == -1) { | |||
338 | _bps.append(bp); | |||
339 | bp.set(); | |||
340 | } | |||
341 | } | |||
342 | ||||
343 | void JvmtiBreakpoints::clear_at_safepoint(JvmtiBreakpoint& bp) { | |||
344 | assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint")do { if (!(SafepointSynchronize::is_at_safepoint())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 344, "assert(" "SafepointSynchronize::is_at_safepoint()" ") failed" , "must be at safepoint"); ::breakpoint(); } } while (0); | |||
345 | ||||
346 | int i = _bps.find(bp); | |||
347 | if (i != -1) { | |||
348 | _bps.remove(i); | |||
349 | bp.clear(); | |||
350 | } | |||
351 | } | |||
352 | ||||
353 | int JvmtiBreakpoints::length() { return _bps.length(); } | |||
354 | ||||
355 | int JvmtiBreakpoints::set(JvmtiBreakpoint& bp) { | |||
356 | if ( _bps.find(bp) != -1) { | |||
357 | return JVMTI_ERROR_DUPLICATE; | |||
358 | } | |||
359 | VM_ChangeBreakpoints set_breakpoint(VM_ChangeBreakpoints::SET_BREAKPOINT, &bp); | |||
360 | VMThread::execute(&set_breakpoint); | |||
361 | return JVMTI_ERROR_NONE; | |||
362 | } | |||
363 | ||||
364 | int JvmtiBreakpoints::clear(JvmtiBreakpoint& bp) { | |||
365 | if ( _bps.find(bp) == -1) { | |||
366 | return JVMTI_ERROR_NOT_FOUND; | |||
367 | } | |||
368 | ||||
369 | VM_ChangeBreakpoints clear_breakpoint(VM_ChangeBreakpoints::CLEAR_BREAKPOINT, &bp); | |||
370 | VMThread::execute(&clear_breakpoint); | |||
371 | return JVMTI_ERROR_NONE; | |||
372 | } | |||
373 | ||||
374 | void JvmtiBreakpoints::clearall_in_class_at_safepoint(Klass* klass) { | |||
375 | bool changed = true; | |||
376 | // We are going to run thru the list of bkpts | |||
377 | // and delete some. This deletion probably alters | |||
378 | // the list in some implementation defined way such | |||
379 | // that when we delete entry i, the next entry might | |||
380 | // no longer be at i+1. To be safe, each time we delete | |||
381 | // an entry, we'll just start again from the beginning. | |||
382 | // We'll stop when we make a pass thru the whole list without | |||
383 | // deleting anything. | |||
384 | while (changed) { | |||
385 | int len = _bps.length(); | |||
386 | changed = false; | |||
387 | for (int i = 0; i < len; i++) { | |||
388 | JvmtiBreakpoint& bp = _bps.at(i); | |||
389 | if (bp.method()->method_holder() == klass) { | |||
390 | bp.clear(); | |||
391 | _bps.remove(i); | |||
392 | // This changed 'i' so we have to start over. | |||
393 | changed = true; | |||
394 | break; | |||
395 | } | |||
396 | } | |||
397 | } | |||
398 | } | |||
399 | ||||
400 | // | |||
401 | // class JvmtiCurrentBreakpoints | |||
402 | // | |||
403 | ||||
404 | JvmtiBreakpoints *JvmtiCurrentBreakpoints::_jvmti_breakpoints = NULL__null; | |||
405 | address * JvmtiCurrentBreakpoints::_breakpoint_list = NULL__null; | |||
406 | ||||
407 | ||||
408 | JvmtiBreakpoints& JvmtiCurrentBreakpoints::get_jvmti_breakpoints() { | |||
409 | if (_jvmti_breakpoints != NULL__null) return (*_jvmti_breakpoints); | |||
410 | _jvmti_breakpoints = new JvmtiBreakpoints(listener_fun); | |||
411 | assert(_jvmti_breakpoints != NULL, "_jvmti_breakpoints != NULL")do { if (!(_jvmti_breakpoints != __null)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 411, "assert(" "_jvmti_breakpoints != __null" ") failed", "_jvmti_breakpoints != NULL" ); ::breakpoint(); } } while (0); | |||
412 | return (*_jvmti_breakpoints); | |||
413 | } | |||
414 | ||||
415 | void JvmtiCurrentBreakpoints::listener_fun(void *this_obj, address *cache) { | |||
416 | JvmtiBreakpoints *this_jvmti = (JvmtiBreakpoints *) this_obj; | |||
417 | assert(this_jvmti != NULL, "this_jvmti != NULL")do { if (!(this_jvmti != __null)) { (*g_assert_poison) = 'X'; ; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 417, "assert(" "this_jvmti != __null" ") failed", "this_jvmti != NULL" ); ::breakpoint(); } } while (0); | |||
418 | ||||
419 | debug_only(int n = this_jvmti->length();)int n = this_jvmti->length();; | |||
420 | assert(cache[n] == NULL, "cache must be NULL terminated")do { if (!(cache[n] == __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 420, "assert(" "cache[n] == __null" ") failed", "cache must be NULL terminated" ); ::breakpoint(); } } while (0); | |||
421 | ||||
422 | set_breakpoint_list(cache); | |||
423 | } | |||
424 | ||||
425 | /////////////////////////////////////////////////////////////// | |||
426 | // | |||
427 | // class VM_GetOrSetLocal | |||
428 | // | |||
429 | ||||
430 | // Constructor for non-object getter | |||
431 | VM_GetOrSetLocal::VM_GetOrSetLocal(JavaThread* thread, jint depth, jint index, BasicType type) | |||
432 | : _thread(thread) | |||
433 | , _calling_thread(NULL__null) | |||
434 | , _depth(depth) | |||
435 | , _index(index) | |||
436 | , _type(type) | |||
437 | , _jvf(NULL__null) | |||
438 | , _set(false) | |||
439 | , _eb(false, NULL__null, NULL__null) | |||
440 | , _result(JVMTI_ERROR_NONE) | |||
441 | { | |||
442 | } | |||
443 | ||||
444 | // Constructor for object or non-object setter | |||
445 | VM_GetOrSetLocal::VM_GetOrSetLocal(JavaThread* thread, jint depth, jint index, BasicType type, jvalue value) | |||
446 | : _thread(thread) | |||
447 | , _calling_thread(NULL__null) | |||
448 | , _depth(depth) | |||
449 | , _index(index) | |||
450 | , _type(type) | |||
451 | , _value(value) | |||
452 | , _jvf(NULL__null) | |||
453 | , _set(true) | |||
454 | , _eb(type == T_OBJECT, JavaThread::current(), thread) | |||
455 | , _result(JVMTI_ERROR_NONE) | |||
456 | { | |||
457 | } | |||
458 | ||||
459 | // Constructor for object getter | |||
460 | VM_GetOrSetLocal::VM_GetOrSetLocal(JavaThread* thread, JavaThread* calling_thread, jint depth, int index) | |||
461 | : _thread(thread) | |||
462 | , _calling_thread(calling_thread) | |||
463 | , _depth(depth) | |||
464 | , _index(index) | |||
465 | , _type(T_OBJECT) | |||
466 | , _jvf(NULL__null) | |||
467 | , _set(false) | |||
468 | , _eb(true, calling_thread, thread) | |||
469 | , _result(JVMTI_ERROR_NONE) | |||
470 | { | |||
471 | } | |||
472 | ||||
473 | vframe *VM_GetOrSetLocal::get_vframe() { | |||
474 | if (!_thread->has_last_Java_frame()) { | |||
475 | return NULL__null; | |||
476 | } | |||
477 | RegisterMap reg_map(_thread); | |||
478 | vframe *vf = _thread->last_java_vframe(®_map); | |||
479 | int d = 0; | |||
480 | while ((vf != NULL__null) && (d < _depth)) { | |||
481 | vf = vf->java_sender(); | |||
482 | d++; | |||
483 | } | |||
484 | return vf; | |||
485 | } | |||
486 | ||||
487 | javaVFrame *VM_GetOrSetLocal::get_java_vframe() { | |||
488 | vframe* vf = get_vframe(); | |||
489 | if (vf == NULL__null) { | |||
490 | _result = JVMTI_ERROR_NO_MORE_FRAMES; | |||
491 | return NULL__null; | |||
492 | } | |||
493 | javaVFrame *jvf = (javaVFrame*)vf; | |||
494 | ||||
495 | if (!vf->is_java_frame()) { | |||
496 | _result = JVMTI_ERROR_OPAQUE_FRAME; | |||
497 | return NULL__null; | |||
498 | } | |||
499 | return jvf; | |||
500 | } | |||
501 | ||||
502 | // Check that the klass is assignable to a type with the given signature. | |||
503 | // Another solution could be to use the function Klass::is_subtype_of(type). | |||
504 | // But the type class can be forced to load/initialize eagerly in such a case. | |||
505 | // This may cause unexpected consequences like CFLH or class-init JVMTI events. | |||
506 | // It is better to avoid such a behavior. | |||
507 | bool VM_GetOrSetLocal::is_assignable(const char* ty_sign, Klass* klass, Thread* thread) { | |||
508 | assert(ty_sign != NULL, "type signature must not be NULL")do { if (!(ty_sign != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 508, "assert(" "ty_sign != __null" ") failed", "type signature must not be NULL" ); ::breakpoint(); } } while (0); | |||
509 | assert(thread != NULL, "thread must not be NULL")do { if (!(thread != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 509, "assert(" "thread != __null" ") failed", "thread must not be NULL" ); ::breakpoint(); } } while (0); | |||
510 | assert(klass != NULL, "klass must not be NULL")do { if (!(klass != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 510, "assert(" "klass != __null" ") failed", "klass must not be NULL" ); ::breakpoint(); } } while (0); | |||
511 | ||||
512 | int len = (int) strlen(ty_sign); | |||
513 | if (ty_sign[0] == JVM_SIGNATURE_CLASS && | |||
514 | ty_sign[len-1] == JVM_SIGNATURE_ENDCLASS) { // Need pure class/interface name | |||
515 | ty_sign++; | |||
516 | len -= 2; | |||
517 | } | |||
518 | TempNewSymbol ty_sym = SymbolTable::new_symbol(ty_sign, len); | |||
519 | if (klass->name() == ty_sym) { | |||
520 | return true; | |||
521 | } | |||
522 | // Compare primary supers | |||
523 | int super_depth = klass->super_depth(); | |||
524 | int idx; | |||
525 | for (idx = 0; idx < super_depth; idx++) { | |||
526 | if (klass->primary_super_of_depth(idx)->name() == ty_sym) { | |||
527 | return true; | |||
528 | } | |||
529 | } | |||
530 | // Compare secondary supers | |||
531 | const Array<Klass*>* sec_supers = klass->secondary_supers(); | |||
532 | for (idx = 0; idx < sec_supers->length(); idx++) { | |||
533 | if (((Klass*) sec_supers->at(idx))->name() == ty_sym) { | |||
534 | return true; | |||
535 | } | |||
536 | } | |||
537 | return false; | |||
538 | } | |||
539 | ||||
540 | // Checks error conditions: | |||
541 | // JVMTI_ERROR_INVALID_SLOT | |||
542 | // JVMTI_ERROR_TYPE_MISMATCH | |||
543 | // Returns: 'true' - everything is Ok, 'false' - error code | |||
544 | ||||
545 | bool VM_GetOrSetLocal::check_slot_type_lvt(javaVFrame* jvf) { | |||
546 | Method* method = jvf->method(); | |||
547 | jint num_entries = method->localvariable_table_length(); | |||
548 | if (num_entries == 0) { | |||
549 | _result = JVMTI_ERROR_INVALID_SLOT; | |||
550 | return false; // There are no slots | |||
551 | } | |||
552 | int signature_idx = -1; | |||
553 | int vf_bci = jvf->bci(); | |||
554 | LocalVariableTableElement* table = method->localvariable_table_start(); | |||
555 | for (int i = 0; i < num_entries; i++) { | |||
556 | int start_bci = table[i].start_bci; | |||
557 | int end_bci = start_bci + table[i].length; | |||
558 | ||||
559 | // Here we assume that locations of LVT entries | |||
560 | // with the same slot number cannot be overlapped | |||
561 | if (_index == (jint) table[i].slot && start_bci <= vf_bci && vf_bci <= end_bci) { | |||
562 | signature_idx = (int) table[i].descriptor_cp_index; | |||
563 | break; | |||
564 | } | |||
565 | } | |||
566 | if (signature_idx == -1) { | |||
567 | _result = JVMTI_ERROR_INVALID_SLOT; | |||
568 | return false; // Incorrect slot index | |||
569 | } | |||
570 | Symbol* sign_sym = method->constants()->symbol_at(signature_idx); | |||
571 | BasicType slot_type = Signature::basic_type(sign_sym); | |||
572 | ||||
573 | switch (slot_type) { | |||
574 | case T_BYTE: | |||
575 | case T_SHORT: | |||
576 | case T_CHAR: | |||
577 | case T_BOOLEAN: | |||
578 | slot_type = T_INT; | |||
579 | break; | |||
580 | case T_ARRAY: | |||
581 | slot_type = T_OBJECT; | |||
582 | break; | |||
583 | default: | |||
584 | break; | |||
585 | }; | |||
586 | if (_type != slot_type) { | |||
587 | _result = JVMTI_ERROR_TYPE_MISMATCH; | |||
588 | return false; | |||
589 | } | |||
590 | ||||
591 | jobject jobj = _value.l; | |||
592 | if (_set && slot_type == T_OBJECT && jobj != NULL__null) { // NULL reference is allowed | |||
593 | // Check that the jobject class matches the return type signature. | |||
594 | oop obj = JNIHandles::resolve_external_guard(jobj); | |||
595 | NULL_CHECK(obj, (_result = JVMTI_ERROR_INVALID_OBJECT, false))if ((obj) == __null) { return ((_result = JVMTI_ERROR_INVALID_OBJECT , false)); }; | |||
596 | Klass* ob_k = obj->klass(); | |||
597 | NULL_CHECK(ob_k, (_result = JVMTI_ERROR_INVALID_OBJECT, false))if ((ob_k) == __null) { return ((_result = JVMTI_ERROR_INVALID_OBJECT , false)); }; | |||
598 | ||||
599 | const char* signature = (const char *) sign_sym->as_utf8(); | |||
600 | if (!is_assignable(signature, ob_k, VMThread::vm_thread())) { | |||
601 | _result = JVMTI_ERROR_TYPE_MISMATCH; | |||
602 | return false; | |||
603 | } | |||
604 | } | |||
605 | return true; | |||
606 | } | |||
607 | ||||
608 | bool VM_GetOrSetLocal::check_slot_type_no_lvt(javaVFrame* jvf) { | |||
609 | Method* method = jvf->method(); | |||
610 | jint extra_slot = (_type == T_LONG || _type == T_DOUBLE) ? 1 : 0; | |||
611 | ||||
612 | if (_index < 0 || _index + extra_slot >= method->max_locals()) { | |||
613 | _result = JVMTI_ERROR_INVALID_SLOT; | |||
614 | return false; | |||
615 | } | |||
616 | StackValueCollection *locals = _jvf->locals(); | |||
617 | BasicType slot_type = locals->at(_index)->type(); | |||
618 | ||||
619 | if (slot_type == T_CONFLICT) { | |||
620 | _result = JVMTI_ERROR_INVALID_SLOT; | |||
621 | return false; | |||
622 | } | |||
623 | if (extra_slot) { | |||
624 | BasicType extra_slot_type = locals->at(_index + 1)->type(); | |||
625 | if (extra_slot_type != T_INT) { | |||
626 | _result = JVMTI_ERROR_INVALID_SLOT; | |||
627 | return false; | |||
628 | } | |||
629 | } | |||
630 | if (_type != slot_type && (_type == T_OBJECT || slot_type != T_INT)) { | |||
631 | _result = JVMTI_ERROR_TYPE_MISMATCH; | |||
632 | return false; | |||
633 | } | |||
634 | return true; | |||
635 | } | |||
636 | ||||
637 | static bool can_be_deoptimized(vframe* vf) { | |||
638 | return (vf->is_compiled_frame() && vf->fr().can_be_deoptimized()); | |||
639 | } | |||
640 | ||||
641 | bool VM_GetOrSetLocal::doit_prologue() { | |||
642 | if (!_eb.deoptimize_objects(_depth, _depth)) { | |||
643 | // The target frame is affected by a reallocation failure. | |||
644 | _result = JVMTI_ERROR_OUT_OF_MEMORY; | |||
645 | return false; | |||
646 | } | |||
647 | ||||
648 | return true; | |||
649 | } | |||
650 | ||||
651 | void VM_GetOrSetLocal::doit() { | |||
652 | _jvf = _jvf == NULL__null ? get_java_vframe() : _jvf; | |||
653 | if (_jvf == NULL__null) { | |||
654 | return; | |||
655 | }; | |||
656 | ||||
657 | Method* method = _jvf->method(); | |||
658 | if (getting_receiver()) { | |||
659 | if (method->is_static()) { | |||
660 | _result = JVMTI_ERROR_INVALID_SLOT; | |||
661 | return; | |||
662 | } | |||
663 | } else { | |||
664 | if (method->is_native()) { | |||
665 | _result = JVMTI_ERROR_OPAQUE_FRAME; | |||
666 | return; | |||
667 | } | |||
668 | ||||
669 | if (!check_slot_type_no_lvt(_jvf)) { | |||
670 | return; | |||
671 | } | |||
672 | if (method->has_localvariable_table() && | |||
673 | !check_slot_type_lvt(_jvf)) { | |||
674 | return; | |||
675 | } | |||
676 | } | |||
677 | ||||
678 | InterpreterOopMap oop_mask; | |||
679 | _jvf->method()->mask_for(_jvf->bci(), &oop_mask); | |||
680 | if (oop_mask.is_dead(_index)) { | |||
681 | // The local can be invalid and uninitialized in the scope of current bci | |||
682 | _result = JVMTI_ERROR_INVALID_SLOT; | |||
683 | return; | |||
684 | } | |||
685 | if (_set) { | |||
686 | // Force deoptimization of frame if compiled because it's | |||
687 | // possible the compiler emitted some locals as constant values, | |||
688 | // meaning they are not mutable. | |||
689 | if (can_be_deoptimized(_jvf)) { | |||
690 | ||||
691 | // Schedule deoptimization so that eventually the local | |||
692 | // update will be written to an interpreter frame. | |||
693 | Deoptimization::deoptimize_frame(_jvf->thread(), _jvf->fr().id()); | |||
694 | ||||
695 | // Now store a new value for the local which will be applied | |||
696 | // once deoptimization occurs. Note however that while this | |||
697 | // write is deferred until deoptimization actually happens | |||
698 | // can vframe created after this point will have its locals | |||
699 | // reflecting this update so as far as anyone can see the | |||
700 | // write has already taken place. | |||
701 | ||||
702 | // If we are updating an oop then get the oop from the handle | |||
703 | // since the handle will be long gone by the time the deopt | |||
704 | // happens. The oop stored in the deferred local will be | |||
705 | // gc'd on its own. | |||
706 | if (_type == T_OBJECT) { | |||
707 | _value.l = cast_from_oop<jobject>(JNIHandles::resolve_external_guard(_value.l)); | |||
708 | } | |||
709 | // Re-read the vframe so we can see that it is deoptimized | |||
710 | // [ Only need because of assert in update_local() ] | |||
711 | _jvf = get_java_vframe(); | |||
712 | ((compiledVFrame*)_jvf)->update_local(_type, _index, _value); | |||
713 | return; | |||
714 | } | |||
715 | StackValueCollection *locals = _jvf->locals(); | |||
716 | Thread* current_thread = VMThread::vm_thread(); | |||
717 | HandleMark hm(current_thread); | |||
718 | ||||
719 | switch (_type) { | |||
720 | case T_INT: locals->set_int_at (_index, _value.i); break; | |||
721 | case T_LONG: locals->set_long_at (_index, _value.j); break; | |||
722 | case T_FLOAT: locals->set_float_at (_index, _value.f); break; | |||
723 | case T_DOUBLE: locals->set_double_at(_index, _value.d); break; | |||
724 | case T_OBJECT: { | |||
725 | Handle ob_h(current_thread, JNIHandles::resolve_external_guard(_value.l)); | |||
726 | locals->set_obj_at (_index, ob_h); | |||
727 | break; | |||
728 | } | |||
729 | default: ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 729); ::breakpoint(); } while (0); | |||
730 | } | |||
731 | _jvf->set_locals(locals); | |||
732 | } else { | |||
733 | if (_jvf->method()->is_native() && _jvf->is_compiled_frame()) { | |||
734 | assert(getting_receiver(), "Can only get here when getting receiver")do { if (!(getting_receiver())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 734, "assert(" "getting_receiver()" ") failed", "Can only get here when getting receiver" ); ::breakpoint(); } } while (0); | |||
735 | oop receiver = _jvf->fr().get_native_receiver(); | |||
736 | _value.l = JNIHandles::make_local(_calling_thread, receiver); | |||
737 | } else { | |||
738 | StackValueCollection *locals = _jvf->locals(); | |||
739 | ||||
740 | switch (_type) { | |||
741 | case T_INT: _value.i = locals->int_at (_index); break; | |||
742 | case T_LONG: _value.j = locals->long_at (_index); break; | |||
743 | case T_FLOAT: _value.f = locals->float_at (_index); break; | |||
744 | case T_DOUBLE: _value.d = locals->double_at(_index); break; | |||
745 | case T_OBJECT: { | |||
746 | // Wrap the oop to be returned in a local JNI handle since | |||
747 | // oops_do() no longer applies after doit() is finished. | |||
748 | oop obj = locals->obj_at(_index)(); | |||
749 | _value.l = JNIHandles::make_local(_calling_thread, obj); | |||
750 | break; | |||
751 | } | |||
752 | default: ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 752); ::breakpoint(); } while (0); | |||
753 | } | |||
754 | } | |||
755 | } | |||
756 | } | |||
757 | ||||
758 | ||||
759 | bool VM_GetOrSetLocal::allow_nested_vm_operations() const { | |||
760 | return true; // May need to deoptimize | |||
761 | } | |||
762 | ||||
763 | ||||
764 | VM_GetReceiver::VM_GetReceiver( | |||
765 | JavaThread* thread, JavaThread* caller_thread, jint depth) | |||
766 | : VM_GetOrSetLocal(thread, caller_thread, depth, 0) {} | |||
767 | ||||
768 | ///////////////////////////////////////////////////////////////////////////////////////// | |||
769 | ||||
770 | // | |||
771 | // class JvmtiSuspendControl - see comments in jvmtiImpl.hpp | |||
772 | // | |||
773 | ||||
774 | bool JvmtiSuspendControl::suspend(JavaThread *java_thread) { | |||
775 | return java_thread->java_suspend(); | |||
776 | } | |||
777 | ||||
778 | bool JvmtiSuspendControl::resume(JavaThread *java_thread) { | |||
779 | return java_thread->java_resume(); | |||
780 | } | |||
781 | ||||
782 | void JvmtiSuspendControl::print() { | |||
783 | #ifndef PRODUCT | |||
784 | ResourceMark rm; | |||
785 | LogStreamHandle(Trace, jvmti)LogStreamTemplate<LogLevel::Trace, (LogTag::_jvmti), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG)> log_stream; | |||
786 | log_stream.print("Suspended Threads: ["); | |||
787 | for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) { | |||
788 | #ifdef JVMTI_TRACE | |||
789 | const char *name = JvmtiTrace::safe_get_thread_name(thread); | |||
790 | #else | |||
791 | const char *name = ""; | |||
792 | #endif /*JVMTI_TRACE */ | |||
793 | log_stream.print("%s(%c ", name, thread->is_suspended() ? 'S' : '_'); | |||
794 | if (!thread->has_last_Java_frame()) { | |||
795 | log_stream.print("no stack"); | |||
796 | } | |||
797 | log_stream.print(") "); | |||
798 | } | |||
799 | log_stream.print_cr("]"); | |||
800 | #endif | |||
801 | } | |||
802 | ||||
803 | JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_load_event( | |||
804 | nmethod* nm) { | |||
805 | JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_LOAD); | |||
806 | event._event_data.compiled_method_load = nm; | |||
807 | return event; | |||
808 | } | |||
809 | ||||
810 | JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_unload_event( | |||
811 | jmethodID id, const void* code) { | |||
812 | JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_UNLOAD); | |||
813 | event._event_data.compiled_method_unload.method_id = id; | |||
814 | event._event_data.compiled_method_unload.code_begin = code; | |||
815 | return event; | |||
816 | } | |||
817 | ||||
818 | JvmtiDeferredEvent JvmtiDeferredEvent::dynamic_code_generated_event( | |||
819 | const char* name, const void* code_begin, const void* code_end) { | |||
820 | JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_DYNAMIC_CODE_GENERATED); | |||
821 | // Need to make a copy of the name since we don't know how long | |||
822 | // the event poster will keep it around after we enqueue the | |||
823 | // deferred event and return. strdup() failure is handled in | |||
824 | // the post() routine below. | |||
825 | event._event_data.dynamic_code_generated.name = os::strdup(name); | |||
826 | event._event_data.dynamic_code_generated.code_begin = code_begin; | |||
827 | event._event_data.dynamic_code_generated.code_end = code_end; | |||
828 | return event; | |||
829 | } | |||
830 | ||||
831 | JvmtiDeferredEvent JvmtiDeferredEvent::class_unload_event(const char* name) { | |||
832 | JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_CLASS_UNLOAD); | |||
833 | // Need to make a copy of the name since we don't know how long | |||
834 | // the event poster will keep it around after we enqueue the | |||
835 | // deferred event and return. strdup() failure is handled in | |||
836 | // the post() routine below. | |||
837 | event._event_data.class_unload.name = os::strdup(name); | |||
838 | return event; | |||
839 | } | |||
840 | ||||
841 | void JvmtiDeferredEvent::post() { | |||
842 | assert(Thread::current()->is_service_thread(),do { if (!(Thread::current()->is_service_thread())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 843, "assert(" "Thread::current()->is_service_thread()" ") failed" , "Service thread must post enqueued events"); ::breakpoint() ; } } while (0) | |||
843 | "Service thread must post enqueued events")do { if (!(Thread::current()->is_service_thread())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 843, "assert(" "Thread::current()->is_service_thread()" ") failed" , "Service thread must post enqueued events"); ::breakpoint() ; } } while (0); | |||
844 | switch(_type) { | |||
845 | case TYPE_COMPILED_METHOD_LOAD: { | |||
846 | nmethod* nm = _event_data.compiled_method_load; | |||
847 | JvmtiExport::post_compiled_method_load(nm); | |||
848 | break; | |||
849 | } | |||
850 | case TYPE_COMPILED_METHOD_UNLOAD: { | |||
851 | JvmtiExport::post_compiled_method_unload( | |||
852 | _event_data.compiled_method_unload.method_id, | |||
853 | _event_data.compiled_method_unload.code_begin); | |||
854 | break; | |||
855 | } | |||
856 | case TYPE_DYNAMIC_CODE_GENERATED: { | |||
857 | JvmtiExport::post_dynamic_code_generated_internal( | |||
858 | // if strdup failed give the event a default name | |||
859 | (_event_data.dynamic_code_generated.name == NULL__null) | |||
860 | ? "unknown_code" : _event_data.dynamic_code_generated.name, | |||
861 | _event_data.dynamic_code_generated.code_begin, | |||
862 | _event_data.dynamic_code_generated.code_end); | |||
863 | if (_event_data.dynamic_code_generated.name != NULL__null) { | |||
864 | // release our copy | |||
865 | os::free((void *)_event_data.dynamic_code_generated.name); | |||
866 | } | |||
867 | break; | |||
868 | } | |||
869 | case TYPE_CLASS_UNLOAD: { | |||
870 | JvmtiExport::post_class_unload_internal( | |||
871 | // if strdup failed give the event a default name | |||
872 | (_event_data.class_unload.name == NULL__null) | |||
873 | ? "unknown_class" : _event_data.class_unload.name); | |||
874 | if (_event_data.class_unload.name != NULL__null) { | |||
875 | // release our copy | |||
876 | os::free((void *)_event_data.class_unload.name); | |||
877 | } | |||
878 | break; | |||
879 | } | |||
880 | default: | |||
881 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 881); ::breakpoint(); } while (0); | |||
882 | } | |||
883 | } | |||
884 | ||||
885 | void JvmtiDeferredEvent::post_compiled_method_load_event(JvmtiEnv* env) { | |||
886 | assert(_type == TYPE_COMPILED_METHOD_LOAD, "only user of this method")do { if (!(_type == TYPE_COMPILED_METHOD_LOAD)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 886, "assert(" "_type == TYPE_COMPILED_METHOD_LOAD" ") failed" , "only user of this method"); ::breakpoint(); } } while (0); | |||
887 | nmethod* nm = _event_data.compiled_method_load; | |||
888 | JvmtiExport::post_compiled_method_load(env, nm); | |||
889 | } | |||
890 | ||||
891 | void JvmtiDeferredEvent::run_nmethod_entry_barriers() { | |||
892 | if (_type == TYPE_COMPILED_METHOD_LOAD) { | |||
893 | _event_data.compiled_method_load->run_nmethod_entry_barrier(); | |||
894 | } | |||
895 | } | |||
896 | ||||
897 | ||||
898 | // Keep the nmethod for compiled_method_load from being unloaded. | |||
899 | void JvmtiDeferredEvent::oops_do(OopClosure* f, CodeBlobClosure* cf) { | |||
900 | if (cf != NULL__null && _type == TYPE_COMPILED_METHOD_LOAD) { | |||
901 | cf->do_code_blob(_event_data.compiled_method_load); | |||
902 | } | |||
903 | } | |||
904 | ||||
905 | // The sweeper calls this and marks the nmethods here on the stack so that | |||
906 | // they cannot be turned into zombies while in the queue. | |||
907 | void JvmtiDeferredEvent::nmethods_do(CodeBlobClosure* cf) { | |||
908 | if (cf != NULL__null && _type == TYPE_COMPILED_METHOD_LOAD) { | |||
909 | cf->do_code_blob(_event_data.compiled_method_load); | |||
910 | } | |||
911 | } | |||
912 | ||||
913 | ||||
914 | bool JvmtiDeferredEventQueue::has_events() { | |||
915 | // We save the queued events before the live phase and post them when it starts. | |||
916 | // This code could skip saving the events on the queue before the live | |||
917 | // phase and ignore them, but this would change how we do things now. | |||
918 | // Starting the service thread earlier causes this to be called before the live phase begins. | |||
919 | // The events on the queue should all be posted after the live phase so this is an | |||
920 | // ok check. Before the live phase, DynamicCodeGenerated events are posted directly. | |||
921 | // If we add other types of events to the deferred queue, this could get ugly. | |||
922 | return JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE && _queue_head != NULL__null; | |||
923 | } | |||
924 | ||||
925 | void JvmtiDeferredEventQueue::enqueue(JvmtiDeferredEvent event) { | |||
926 | // Events get added to the end of the queue (and are pulled off the front). | |||
927 | QueueNode* node = new QueueNode(event); | |||
928 | if (_queue_tail == NULL__null) { | |||
929 | _queue_tail = _queue_head = node; | |||
930 | } else { | |||
931 | assert(_queue_tail->next() == NULL, "Must be the last element in the list")do { if (!(_queue_tail->next() == __null)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 931, "assert(" "_queue_tail->next() == __null" ") failed" , "Must be the last element in the list"); ::breakpoint(); } } while (0); | |||
932 | _queue_tail->set_next(node); | |||
933 | _queue_tail = node; | |||
934 | } | |||
935 | ||||
936 | assert((_queue_head == NULL) == (_queue_tail == NULL),do { if (!((_queue_head == __null) == (_queue_tail == __null) )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 937, "assert(" "(_queue_head == __null) == (_queue_tail == __null)" ") failed", "Inconsistent queue markers"); ::breakpoint(); } } while (0) | |||
937 | "Inconsistent queue markers")do { if (!((_queue_head == __null) == (_queue_tail == __null) )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 937, "assert(" "(_queue_head == __null) == (_queue_tail == __null)" ") failed", "Inconsistent queue markers"); ::breakpoint(); } } while (0); | |||
938 | } | |||
939 | ||||
940 | JvmtiDeferredEvent JvmtiDeferredEventQueue::dequeue() { | |||
941 | assert(_queue_head != NULL, "Nothing to dequeue")do { if (!(_queue_head != __null)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 941, "assert(" "_queue_head != __null" ") failed", "Nothing to dequeue" ); ::breakpoint(); } } while (0); | |||
942 | ||||
943 | if (_queue_head == NULL__null) { | |||
944 | // Just in case this happens in product; it shouldn't but let's not crash | |||
945 | return JvmtiDeferredEvent(); | |||
946 | } | |||
947 | ||||
948 | QueueNode* node = _queue_head; | |||
949 | _queue_head = _queue_head->next(); | |||
950 | if (_queue_head == NULL__null) { | |||
951 | _queue_tail = NULL__null; | |||
952 | } | |||
953 | ||||
954 | assert((_queue_head == NULL) == (_queue_tail == NULL),do { if (!((_queue_head == __null) == (_queue_tail == __null) )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 955, "assert(" "(_queue_head == __null) == (_queue_tail == __null)" ") failed", "Inconsistent queue markers"); ::breakpoint(); } } while (0) | |||
955 | "Inconsistent queue markers")do { if (!((_queue_head == __null) == (_queue_tail == __null) )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/prims/jvmtiImpl.cpp" , 955, "assert(" "(_queue_head == __null) == (_queue_tail == __null)" ") failed", "Inconsistent queue markers"); ::breakpoint(); } } while (0); | |||
956 | ||||
957 | JvmtiDeferredEvent event = node->event(); | |||
958 | delete node; | |||
959 | return event; | |||
960 | } | |||
961 | ||||
962 | void JvmtiDeferredEventQueue::post(JvmtiEnv* env) { | |||
963 | // Post events while nmethods are still in the queue and can't be unloaded or made zombie | |||
964 | while (_queue_head != NULL__null) { | |||
965 | _queue_head->event().post_compiled_method_load_event(env); | |||
966 | dequeue(); | |||
967 | } | |||
968 | } | |||
969 | ||||
970 | void JvmtiDeferredEventQueue::run_nmethod_entry_barriers() { | |||
971 | for(QueueNode* node = _queue_head; node != NULL__null; node = node->next()) { | |||
972 | node->event().run_nmethod_entry_barriers(); | |||
973 | } | |||
974 | } | |||
975 | ||||
976 | ||||
977 | void JvmtiDeferredEventQueue::oops_do(OopClosure* f, CodeBlobClosure* cf) { | |||
978 | for(QueueNode* node = _queue_head; node != NULL__null; node = node->next()) { | |||
979 | node->event().oops_do(f, cf); | |||
980 | } | |||
981 | } | |||
982 | ||||
983 | void JvmtiDeferredEventQueue::nmethods_do(CodeBlobClosure* cf) { | |||
984 | for(QueueNode* node = _queue_head; node != NULL__null; node = node->next()) { | |||
985 | node->event().nmethods_do(cf); | |||
986 | } | |||
987 | } |