1 | /* |
2 | * Copyright (c) 1997, 2019, 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/systemDictionary.hpp" |
28 | #include "classfile/vmSymbols.hpp" |
29 | #include "code/codeCache.hpp" |
30 | #include "code/debugInfoRec.hpp" |
31 | #include "code/nmethod.hpp" |
32 | #include "code/pcDesc.hpp" |
33 | #include "code/scopeDesc.hpp" |
34 | #include "interpreter/interpreter.hpp" |
35 | #include "interpreter/oopMapCache.hpp" |
36 | #include "memory/resourceArea.hpp" |
37 | #include "oops/instanceKlass.hpp" |
38 | #include "oops/oop.inline.hpp" |
39 | #include "runtime/frame.inline.hpp" |
40 | #include "runtime/handles.inline.hpp" |
41 | #include "runtime/objectMonitor.hpp" |
42 | #include "runtime/objectMonitor.inline.hpp" |
43 | #include "runtime/signature.hpp" |
44 | #include "runtime/stubRoutines.hpp" |
45 | #include "runtime/synchronizer.hpp" |
46 | #include "runtime/thread.inline.hpp" |
47 | #include "runtime/vframe.inline.hpp" |
48 | #include "runtime/vframeArray.hpp" |
49 | #include "runtime/vframe_hp.hpp" |
50 | |
51 | vframe::vframe(const frame* fr, const RegisterMap* reg_map, JavaThread* thread) |
52 | : _reg_map(reg_map), _thread(thread) { |
53 | assert(fr != NULL, "must have frame" ); |
54 | _fr = *fr; |
55 | } |
56 | |
57 | vframe::vframe(const frame* fr, JavaThread* thread) |
58 | : _reg_map(thread), _thread(thread) { |
59 | assert(fr != NULL, "must have frame" ); |
60 | _fr = *fr; |
61 | } |
62 | |
63 | vframe* vframe::new_vframe(const frame* f, const RegisterMap* reg_map, JavaThread* thread) { |
64 | // Interpreter frame |
65 | if (f->is_interpreted_frame()) { |
66 | return new interpretedVFrame(f, reg_map, thread); |
67 | } |
68 | |
69 | // Compiled frame |
70 | CodeBlob* cb = f->cb(); |
71 | if (cb != NULL) { |
72 | if (cb->is_compiled()) { |
73 | CompiledMethod* nm = (CompiledMethod*)cb; |
74 | return new compiledVFrame(f, reg_map, thread, nm); |
75 | } |
76 | |
77 | if (f->is_runtime_frame()) { |
78 | // Skip this frame and try again. |
79 | RegisterMap temp_map = *reg_map; |
80 | frame s = f->sender(&temp_map); |
81 | return new_vframe(&s, &temp_map, thread); |
82 | } |
83 | } |
84 | |
85 | // External frame |
86 | return new externalVFrame(f, reg_map, thread); |
87 | } |
88 | |
89 | vframe* vframe::sender() const { |
90 | RegisterMap temp_map = *register_map(); |
91 | assert(is_top(), "just checking" ); |
92 | if (_fr.is_entry_frame() && _fr.is_first_frame()) return NULL; |
93 | frame s = _fr.real_sender(&temp_map); |
94 | if (s.is_first_frame()) return NULL; |
95 | return vframe::new_vframe(&s, &temp_map, thread()); |
96 | } |
97 | |
98 | vframe* vframe::top() const { |
99 | vframe* vf = (vframe*) this; |
100 | while (!vf->is_top()) vf = vf->sender(); |
101 | return vf; |
102 | } |
103 | |
104 | |
105 | javaVFrame* vframe::java_sender() const { |
106 | vframe* f = sender(); |
107 | while (f != NULL) { |
108 | if (f->is_java_frame()) return javaVFrame::cast(f); |
109 | f = f->sender(); |
110 | } |
111 | return NULL; |
112 | } |
113 | |
114 | // ------------- javaVFrame -------------- |
115 | |
116 | GrowableArray<MonitorInfo*>* javaVFrame::locked_monitors() { |
117 | assert(SafepointSynchronize::is_at_safepoint() || JavaThread::current() == thread(), |
118 | "must be at safepoint or it's a java frame of the current thread" ); |
119 | |
120 | GrowableArray<MonitorInfo*>* mons = monitors(); |
121 | GrowableArray<MonitorInfo*>* result = new GrowableArray<MonitorInfo*>(mons->length()); |
122 | if (mons->is_empty()) return result; |
123 | |
124 | bool found_first_monitor = false; |
125 | ObjectMonitor *pending_monitor = thread()->current_pending_monitor(); |
126 | ObjectMonitor *waiting_monitor = thread()->current_waiting_monitor(); |
127 | oop pending_obj = (pending_monitor != NULL ? (oop) pending_monitor->object() : (oop) NULL); |
128 | oop waiting_obj = (waiting_monitor != NULL ? (oop) waiting_monitor->object() : (oop) NULL); |
129 | |
130 | for (int index = (mons->length()-1); index >= 0; index--) { |
131 | MonitorInfo* monitor = mons->at(index); |
132 | if (monitor->eliminated() && is_compiled_frame()) continue; // skip eliminated monitor |
133 | oop obj = monitor->owner(); |
134 | if (obj == NULL) continue; // skip unowned monitor |
135 | // |
136 | // Skip the monitor that the thread is blocked to enter or waiting on |
137 | // |
138 | if (!found_first_monitor && (oopDesc::equals(obj, pending_obj) || oopDesc::equals(obj, waiting_obj))) { |
139 | continue; |
140 | } |
141 | found_first_monitor = true; |
142 | result->append(monitor); |
143 | } |
144 | return result; |
145 | } |
146 | |
147 | void javaVFrame::print_locked_object_class_name(outputStream* st, Handle obj, const char* lock_state) { |
148 | if (obj.not_null()) { |
149 | st->print("\t- %s <" INTPTR_FORMAT "> " , lock_state, p2i(obj())); |
150 | if (obj->klass() == SystemDictionary::Class_klass()) { |
151 | st->print_cr("(a java.lang.Class for %s)" , java_lang_Class::as_external_name(obj())); |
152 | } else { |
153 | Klass* k = obj->klass(); |
154 | st->print_cr("(a %s)" , k->external_name()); |
155 | } |
156 | } |
157 | } |
158 | |
159 | void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) { |
160 | Thread* THREAD = Thread::current(); |
161 | ResourceMark rm(THREAD); |
162 | |
163 | // If this is the first frame and it is java.lang.Object.wait(...) |
164 | // then print out the receiver. Locals are not always available, |
165 | // e.g., compiled native frames have no scope so there are no locals. |
166 | if (frame_count == 0) { |
167 | if (method()->name() == vmSymbols::wait_name() && |
168 | method()->method_holder()->name() == vmSymbols::java_lang_Object()) { |
169 | const char *wait_state = "waiting on" ; // assume we are waiting |
170 | // If earlier in the output we reported java.lang.Thread.State == |
171 | // "WAITING (on object monitor)" and now we report "waiting on", then |
172 | // we are still waiting for notification or timeout. Otherwise if |
173 | // we earlier reported java.lang.Thread.State == "BLOCKED (on object |
174 | // monitor)", then we are actually waiting to re-lock the monitor. |
175 | StackValueCollection* locs = locals(); |
176 | if (!locs->is_empty()) { |
177 | StackValue* sv = locs->at(0); |
178 | if (sv->type() == T_OBJECT) { |
179 | Handle o = locs->at(0)->get_obj(); |
180 | if (java_lang_Thread::get_thread_status(thread()->threadObj()) == |
181 | java_lang_Thread::BLOCKED_ON_MONITOR_ENTER) { |
182 | wait_state = "waiting to re-lock in wait()" ; |
183 | } |
184 | print_locked_object_class_name(st, o, wait_state); |
185 | } |
186 | } else { |
187 | st->print_cr("\t- %s <no object reference available>" , wait_state); |
188 | } |
189 | } else if (thread()->current_park_blocker() != NULL) { |
190 | oop obj = thread()->current_park_blocker(); |
191 | Klass* k = obj->klass(); |
192 | st->print_cr("\t- %s <" INTPTR_FORMAT "> (a %s)" , "parking to wait for " , p2i(obj), k->external_name()); |
193 | } |
194 | else if (thread()->osthread()->get_state() == OBJECT_WAIT) { |
195 | // We are waiting on an Object monitor but Object.wait() isn't the |
196 | // top-frame, so we should be waiting on a Class initialization monitor. |
197 | InstanceKlass* k = thread()->class_to_be_initialized(); |
198 | if (k != NULL) { |
199 | st->print_cr("\t- waiting on the Class initialization monitor for %s" , k->external_name()); |
200 | } |
201 | } |
202 | } |
203 | |
204 | // Print out all monitors that we have locked, or are trying to lock, |
205 | // including re-locking after being notified or timing out in a wait(). |
206 | GrowableArray<MonitorInfo*>* mons = monitors(); |
207 | if (!mons->is_empty()) { |
208 | bool found_first_monitor = false; |
209 | for (int index = (mons->length()-1); index >= 0; index--) { |
210 | MonitorInfo* monitor = mons->at(index); |
211 | if (monitor->eliminated() && is_compiled_frame()) { // Eliminated in compiled code |
212 | if (monitor->owner_is_scalar_replaced()) { |
213 | Klass* k = java_lang_Class::as_Klass(monitor->owner_klass()); |
214 | // format below for lockbits matches this one. |
215 | st->print("\t- eliminated <owner is scalar replaced> (a %s)" , k->external_name()); |
216 | } else { |
217 | Handle obj(THREAD, monitor->owner()); |
218 | if (obj() != NULL) { |
219 | print_locked_object_class_name(st, obj, "eliminated" ); |
220 | } |
221 | } |
222 | continue; |
223 | } |
224 | if (monitor->owner() != NULL) { |
225 | // the monitor is associated with an object, i.e., it is locked |
226 | |
227 | markOop mark = NULL; |
228 | const char *lock_state = "locked" ; // assume we have the monitor locked |
229 | if (!found_first_monitor && frame_count == 0) { |
230 | // If this is the first frame and we haven't found an owned |
231 | // monitor before, then we need to see if we have completed |
232 | // the lock or if we are blocked trying to acquire it. Only |
233 | // an inflated monitor that is first on the monitor list in |
234 | // the first frame can block us on a monitor enter. |
235 | mark = monitor->owner()->mark(); |
236 | if (mark->has_monitor() && |
237 | ( // we have marked ourself as pending on this monitor |
238 | mark->monitor() == thread()->current_pending_monitor() || |
239 | // we are not the owner of this monitor |
240 | !mark->monitor()->is_entered(thread()) |
241 | )) { |
242 | lock_state = "waiting to lock" ; |
243 | } else { |
244 | // We own the monitor which is not as interesting so |
245 | // disable the extra printing below. |
246 | mark = NULL; |
247 | } |
248 | } |
249 | print_locked_object_class_name(st, Handle(THREAD, monitor->owner()), lock_state); |
250 | |
251 | found_first_monitor = true; |
252 | } |
253 | } |
254 | } |
255 | } |
256 | |
257 | // ------------- interpretedVFrame -------------- |
258 | |
259 | u_char* interpretedVFrame::bcp() const { |
260 | return fr().interpreter_frame_bcp(); |
261 | } |
262 | |
263 | void interpretedVFrame::set_bcp(u_char* bcp) { |
264 | fr().interpreter_frame_set_bcp(bcp); |
265 | } |
266 | |
267 | intptr_t* interpretedVFrame::locals_addr_at(int offset) const { |
268 | assert(fr().is_interpreted_frame(), "frame should be an interpreted frame" ); |
269 | return fr().interpreter_frame_local_at(offset); |
270 | } |
271 | |
272 | |
273 | GrowableArray<MonitorInfo*>* interpretedVFrame::monitors() const { |
274 | GrowableArray<MonitorInfo*>* result = new GrowableArray<MonitorInfo*>(5); |
275 | for (BasicObjectLock* current = (fr().previous_monitor_in_interpreter_frame(fr().interpreter_frame_monitor_begin())); |
276 | current >= fr().interpreter_frame_monitor_end(); |
277 | current = fr().previous_monitor_in_interpreter_frame(current)) { |
278 | result->push(new MonitorInfo(current->obj(), current->lock(), false, false)); |
279 | } |
280 | return result; |
281 | } |
282 | |
283 | int interpretedVFrame::bci() const { |
284 | return method()->bci_from(bcp()); |
285 | } |
286 | |
287 | Method* interpretedVFrame::method() const { |
288 | return fr().interpreter_frame_method(); |
289 | } |
290 | |
291 | static StackValue* create_stack_value_from_oop_map(const InterpreterOopMap& oop_mask, |
292 | int index, |
293 | const intptr_t* const addr) { |
294 | |
295 | assert(index >= 0 && |
296 | index < oop_mask.number_of_entries(), "invariant" ); |
297 | |
298 | // categorize using oop_mask |
299 | if (oop_mask.is_oop(index)) { |
300 | // reference (oop) "r" |
301 | Handle h(Thread::current(), addr != NULL ? (*(oop*)addr) : (oop)NULL); |
302 | return new StackValue(h); |
303 | } |
304 | // value (integer) "v" |
305 | return new StackValue(addr != NULL ? *addr : 0); |
306 | } |
307 | |
308 | static bool is_in_expression_stack(const frame& fr, const intptr_t* const addr) { |
309 | assert(addr != NULL, "invariant" ); |
310 | |
311 | // Ensure to be 'inside' the expresion stack (i.e., addr >= sp for Intel). |
312 | // In case of exceptions, the expression stack is invalid and the sp |
313 | // will be reset to express this condition. |
314 | if (frame::interpreter_frame_expression_stack_direction() > 0) { |
315 | return addr <= fr.interpreter_frame_tos_address(); |
316 | } |
317 | |
318 | return addr >= fr.interpreter_frame_tos_address(); |
319 | } |
320 | |
321 | static void stack_locals(StackValueCollection* result, |
322 | int length, |
323 | const InterpreterOopMap& oop_mask, |
324 | const frame& fr) { |
325 | |
326 | assert(result != NULL, "invariant" ); |
327 | |
328 | for (int i = 0; i < length; ++i) { |
329 | const intptr_t* const addr = fr.interpreter_frame_local_at(i); |
330 | assert(addr != NULL, "invariant" ); |
331 | assert(addr >= fr.sp(), "must be inside the frame" ); |
332 | |
333 | StackValue* const sv = create_stack_value_from_oop_map(oop_mask, i, addr); |
334 | assert(sv != NULL, "sanity check" ); |
335 | |
336 | result->add(sv); |
337 | } |
338 | } |
339 | |
340 | static void stack_expressions(StackValueCollection* result, |
341 | int length, |
342 | int max_locals, |
343 | const InterpreterOopMap& oop_mask, |
344 | const frame& fr) { |
345 | |
346 | assert(result != NULL, "invariant" ); |
347 | |
348 | for (int i = 0; i < length; ++i) { |
349 | const intptr_t* addr = fr.interpreter_frame_expression_stack_at(i); |
350 | assert(addr != NULL, "invariant" ); |
351 | if (!is_in_expression_stack(fr, addr)) { |
352 | // Need to ensure no bogus escapes. |
353 | addr = NULL; |
354 | } |
355 | |
356 | StackValue* const sv = create_stack_value_from_oop_map(oop_mask, |
357 | i + max_locals, |
358 | addr); |
359 | assert(sv != NULL, "sanity check" ); |
360 | |
361 | result->add(sv); |
362 | } |
363 | } |
364 | |
365 | StackValueCollection* interpretedVFrame::locals() const { |
366 | return stack_data(false); |
367 | } |
368 | |
369 | StackValueCollection* interpretedVFrame::expressions() const { |
370 | return stack_data(true); |
371 | } |
372 | |
373 | /* |
374 | * Worker routine for fetching references and/or values |
375 | * for a particular bci in the interpretedVFrame. |
376 | * |
377 | * Returns data for either "locals" or "expressions", |
378 | * using bci relative oop_map (oop_mask) information. |
379 | * |
380 | * @param expressions bool switch controlling what data to return |
381 | (false == locals / true == expression) |
382 | * |
383 | */ |
384 | StackValueCollection* interpretedVFrame::stack_data(bool expressions) const { |
385 | |
386 | InterpreterOopMap oop_mask; |
387 | method()->mask_for(bci(), &oop_mask); |
388 | const int mask_len = oop_mask.number_of_entries(); |
389 | |
390 | // If the method is native, method()->max_locals() is not telling the truth. |
391 | // For our purposes, max locals instead equals the size of parameters. |
392 | const int max_locals = method()->is_native() ? |
393 | method()->size_of_parameters() : method()->max_locals(); |
394 | |
395 | assert(mask_len >= max_locals, "invariant" ); |
396 | |
397 | const int length = expressions ? mask_len - max_locals : max_locals; |
398 | assert(length >= 0, "invariant" ); |
399 | |
400 | StackValueCollection* const result = new StackValueCollection(length); |
401 | |
402 | if (0 == length) { |
403 | return result; |
404 | } |
405 | |
406 | if (expressions) { |
407 | stack_expressions(result, length, max_locals, oop_mask, fr()); |
408 | } else { |
409 | stack_locals(result, length, oop_mask, fr()); |
410 | } |
411 | |
412 | assert(length == result->size(), "invariant" ); |
413 | |
414 | return result; |
415 | } |
416 | |
417 | void interpretedVFrame::set_locals(StackValueCollection* values) const { |
418 | if (values == NULL || values->size() == 0) return; |
419 | |
420 | // If the method is native, max_locals is not telling the truth. |
421 | // maxlocals then equals the size of parameters |
422 | const int max_locals = method()->is_native() ? |
423 | method()->size_of_parameters() : method()->max_locals(); |
424 | |
425 | assert(max_locals == values->size(), "Mismatch between actual stack format and supplied data" ); |
426 | |
427 | // handle locals |
428 | for (int i = 0; i < max_locals; i++) { |
429 | // Find stack location |
430 | intptr_t *addr = locals_addr_at(i); |
431 | |
432 | // Depending on oop/int put it in the right package |
433 | const StackValue* const sv = values->at(i); |
434 | assert(sv != NULL, "sanity check" ); |
435 | if (sv->type() == T_OBJECT) { |
436 | *(oop *) addr = (sv->get_obj())(); |
437 | } else { // integer |
438 | *addr = sv->get_int(); |
439 | } |
440 | } |
441 | } |
442 | |
443 | // ------------- cChunk -------------- |
444 | |
445 | entryVFrame::entryVFrame(const frame* fr, const RegisterMap* reg_map, JavaThread* thread) |
446 | : externalVFrame(fr, reg_map, thread) {} |
447 | |
448 | #ifdef ASSERT |
449 | void vframeStreamCommon::found_bad_method_frame() const { |
450 | // 6379830 Cut point for an assertion that occasionally fires when |
451 | // we are using the performance analyzer. |
452 | // Disable this assert when testing the analyzer with fastdebug. |
453 | // -XX:SuppressErrorAt=vframe.cpp:XXX (XXX=following line number) |
454 | fatal("invalid bci or invalid scope desc" ); |
455 | } |
456 | #endif |
457 | |
458 | // top-frame will be skipped |
459 | vframeStream::vframeStream(JavaThread* thread, frame top_frame, |
460 | bool stop_at_java_call_stub) : vframeStreamCommon(thread) { |
461 | _stop_at_java_call_stub = stop_at_java_call_stub; |
462 | |
463 | // skip top frame, as it may not be at safepoint |
464 | _prev_frame = top_frame; |
465 | _frame = top_frame.sender(&_reg_map); |
466 | while (!fill_from_frame()) { |
467 | _prev_frame = _frame; |
468 | _frame = _frame.sender(&_reg_map); |
469 | } |
470 | } |
471 | |
472 | |
473 | // Step back n frames, skip any pseudo frames in between. |
474 | // This function is used in Class.forName, Class.newInstance, Method.Invoke, |
475 | // AccessController.doPrivileged. |
476 | void vframeStreamCommon::security_get_caller_frame(int depth) { |
477 | assert(depth >= 0, "invalid depth: %d" , depth); |
478 | for (int n = 0; !at_end(); security_next()) { |
479 | if (!method()->is_ignored_by_security_stack_walk()) { |
480 | if (n == depth) { |
481 | // We have reached the desired depth; return. |
482 | return; |
483 | } |
484 | n++; // this is a non-skipped frame; count it against the depth |
485 | } |
486 | } |
487 | // NOTE: At this point there were not enough frames on the stack |
488 | // to walk to depth. Callers of this method have to check for at_end. |
489 | } |
490 | |
491 | |
492 | void vframeStreamCommon::security_next() { |
493 | if (method()->is_prefixed_native()) { |
494 | skip_prefixed_method_and_wrappers(); // calls next() |
495 | } else { |
496 | next(); |
497 | } |
498 | } |
499 | |
500 | |
501 | void vframeStreamCommon::skip_prefixed_method_and_wrappers() { |
502 | ResourceMark rm; |
503 | HandleMark hm; |
504 | |
505 | int method_prefix_count = 0; |
506 | char** method_prefixes = JvmtiExport::get_all_native_method_prefixes(&method_prefix_count); |
507 | Klass* prefixed_klass = method()->method_holder(); |
508 | const char* prefixed_name = method()->name()->as_C_string(); |
509 | size_t prefixed_name_len = strlen(prefixed_name); |
510 | int prefix_index = method_prefix_count-1; |
511 | |
512 | while (!at_end()) { |
513 | next(); |
514 | if (method()->method_holder() != prefixed_klass) { |
515 | break; // classes don't match, can't be a wrapper |
516 | } |
517 | const char* name = method()->name()->as_C_string(); |
518 | size_t name_len = strlen(name); |
519 | size_t prefix_len = prefixed_name_len - name_len; |
520 | if (prefix_len <= 0 || strcmp(name, prefixed_name + prefix_len) != 0) { |
521 | break; // prefixed name isn't prefixed version of method name, can't be a wrapper |
522 | } |
523 | for (; prefix_index >= 0; --prefix_index) { |
524 | const char* possible_prefix = method_prefixes[prefix_index]; |
525 | size_t possible_prefix_len = strlen(possible_prefix); |
526 | if (possible_prefix_len == prefix_len && |
527 | strncmp(possible_prefix, prefixed_name, prefix_len) == 0) { |
528 | break; // matching prefix found |
529 | } |
530 | } |
531 | if (prefix_index < 0) { |
532 | break; // didn't find the prefix, can't be a wrapper |
533 | } |
534 | prefixed_name = name; |
535 | prefixed_name_len = name_len; |
536 | } |
537 | } |
538 | |
539 | |
540 | void vframeStreamCommon::skip_reflection_related_frames() { |
541 | while (!at_end() && |
542 | (method()->method_holder()->is_subclass_of(SystemDictionary::reflect_MethodAccessorImpl_klass()) || |
543 | method()->method_holder()->is_subclass_of(SystemDictionary::reflect_ConstructorAccessorImpl_klass()))) { |
544 | next(); |
545 | } |
546 | } |
547 | |
548 | javaVFrame* vframeStreamCommon::asJavaVFrame() { |
549 | javaVFrame* result = NULL; |
550 | if (_mode == compiled_mode) { |
551 | guarantee(_frame.is_compiled_frame(), "expected compiled Java frame" ); |
552 | |
553 | // lazy update to register map |
554 | bool update_map = true; |
555 | RegisterMap map(_thread, update_map); |
556 | frame f = _prev_frame.sender(&map); |
557 | |
558 | guarantee(f.is_compiled_frame(), "expected compiled Java frame" ); |
559 | |
560 | compiledVFrame* cvf = compiledVFrame::cast(vframe::new_vframe(&f, &map, _thread)); |
561 | |
562 | guarantee(cvf->cb() == cb(), "wrong code blob" ); |
563 | |
564 | // get the same scope as this stream |
565 | cvf = cvf->at_scope(_decode_offset, _vframe_id); |
566 | |
567 | guarantee(cvf->scope()->decode_offset() == _decode_offset, "wrong scope" ); |
568 | guarantee(cvf->scope()->sender_decode_offset() == _sender_decode_offset, "wrong scope" ); |
569 | guarantee(cvf->vframe_id() == _vframe_id, "wrong vframe" ); |
570 | |
571 | result = cvf; |
572 | } else { |
573 | result = javaVFrame::cast(vframe::new_vframe(&_frame, &_reg_map, _thread)); |
574 | } |
575 | guarantee(result->method() == method(), "wrong method" ); |
576 | return result; |
577 | } |
578 | |
579 | |
580 | #ifndef PRODUCT |
581 | void vframe::print() { |
582 | if (WizardMode) _fr.print_value_on(tty,NULL); |
583 | } |
584 | |
585 | |
586 | void vframe::print_value() const { |
587 | ((vframe*)this)->print(); |
588 | } |
589 | |
590 | |
591 | void entryVFrame::print_value() const { |
592 | ((entryVFrame*)this)->print(); |
593 | } |
594 | |
595 | void entryVFrame::print() { |
596 | vframe::print(); |
597 | tty->print_cr("C Chunk inbetween Java" ); |
598 | tty->print_cr("C link " INTPTR_FORMAT, p2i(_fr.link())); |
599 | } |
600 | |
601 | |
602 | // ------------- javaVFrame -------------- |
603 | |
604 | static void print_stack_values(const char* title, StackValueCollection* values) { |
605 | if (values->is_empty()) return; |
606 | tty->print_cr("\t%s:" , title); |
607 | values->print(); |
608 | } |
609 | |
610 | |
611 | void javaVFrame::print() { |
612 | ResourceMark rm; |
613 | vframe::print(); |
614 | tty->print("\t" ); |
615 | method()->print_value(); |
616 | tty->cr(); |
617 | tty->print_cr("\tbci: %d" , bci()); |
618 | |
619 | print_stack_values("locals" , locals()); |
620 | print_stack_values("expressions" , expressions()); |
621 | |
622 | GrowableArray<MonitorInfo*>* list = monitors(); |
623 | if (list->is_empty()) return; |
624 | tty->print_cr("\tmonitor list:" ); |
625 | for (int index = (list->length()-1); index >= 0; index--) { |
626 | MonitorInfo* monitor = list->at(index); |
627 | tty->print("\t obj\t" ); |
628 | if (monitor->owner_is_scalar_replaced()) { |
629 | Klass* k = java_lang_Class::as_Klass(monitor->owner_klass()); |
630 | tty->print("( is scalar replaced %s)" , k->external_name()); |
631 | } else if (monitor->owner() == NULL) { |
632 | tty->print("( null )" ); |
633 | } else { |
634 | monitor->owner()->print_value(); |
635 | tty->print("(owner=" INTPTR_FORMAT ")" , p2i(monitor->owner())); |
636 | } |
637 | if (monitor->eliminated()) { |
638 | if(is_compiled_frame()) { |
639 | tty->print(" ( lock is eliminated in compiled frame )" ); |
640 | } else { |
641 | tty->print(" ( lock is eliminated, frame not compiled )" ); |
642 | } |
643 | } |
644 | tty->cr(); |
645 | tty->print("\t " ); |
646 | monitor->lock()->print_on(tty); |
647 | tty->cr(); |
648 | } |
649 | } |
650 | |
651 | |
652 | void javaVFrame::print_value() const { |
653 | Method* m = method(); |
654 | InstanceKlass* k = m->method_holder(); |
655 | tty->print_cr("frame( sp=" INTPTR_FORMAT ", unextended_sp=" INTPTR_FORMAT ", fp=" INTPTR_FORMAT ", pc=" INTPTR_FORMAT ")" , |
656 | p2i(_fr.sp()), p2i(_fr.unextended_sp()), p2i(_fr.fp()), p2i(_fr.pc())); |
657 | tty->print("%s.%s" , k->internal_name(), m->name()->as_C_string()); |
658 | |
659 | if (!m->is_native()) { |
660 | Symbol* source_name = k->source_file_name(); |
661 | int line_number = m->line_number_from_bci(bci()); |
662 | if (source_name != NULL && (line_number != -1)) { |
663 | tty->print("(%s:%d)" , source_name->as_C_string(), line_number); |
664 | } |
665 | } else { |
666 | tty->print("(Native Method)" ); |
667 | } |
668 | // Check frame size and print warning if it looks suspiciously large |
669 | if (fr().sp() != NULL) { |
670 | RegisterMap map = *register_map(); |
671 | uint size = fr().frame_size(&map); |
672 | #ifdef _LP64 |
673 | if (size > 8*K) warning("SUSPICIOUSLY LARGE FRAME (%d)" , size); |
674 | #else |
675 | if (size > 4*K) warning("SUSPICIOUSLY LARGE FRAME (%d)" , size); |
676 | #endif |
677 | } |
678 | } |
679 | |
680 | |
681 | bool javaVFrame::structural_compare(javaVFrame* other) { |
682 | // Check static part |
683 | if (method() != other->method()) return false; |
684 | if (bci() != other->bci()) return false; |
685 | |
686 | // Check locals |
687 | StackValueCollection *locs = locals(); |
688 | StackValueCollection *other_locs = other->locals(); |
689 | assert(locs->size() == other_locs->size(), "sanity check" ); |
690 | int i; |
691 | for(i = 0; i < locs->size(); i++) { |
692 | // it might happen the compiler reports a conflict and |
693 | // the interpreter reports a bogus int. |
694 | if ( is_compiled_frame() && locs->at(i)->type() == T_CONFLICT) continue; |
695 | if (other->is_compiled_frame() && other_locs->at(i)->type() == T_CONFLICT) continue; |
696 | |
697 | if (!locs->at(i)->equal(other_locs->at(i))) |
698 | return false; |
699 | } |
700 | |
701 | // Check expressions |
702 | StackValueCollection* exprs = expressions(); |
703 | StackValueCollection* other_exprs = other->expressions(); |
704 | assert(exprs->size() == other_exprs->size(), "sanity check" ); |
705 | for(i = 0; i < exprs->size(); i++) { |
706 | if (!exprs->at(i)->equal(other_exprs->at(i))) |
707 | return false; |
708 | } |
709 | |
710 | return true; |
711 | } |
712 | |
713 | |
714 | void javaVFrame::print_activation(int index) const { |
715 | // frame number and method |
716 | tty->print("%2d - " , index); |
717 | ((vframe*)this)->print_value(); |
718 | tty->cr(); |
719 | |
720 | if (WizardMode) { |
721 | ((vframe*)this)->print(); |
722 | tty->cr(); |
723 | } |
724 | } |
725 | |
726 | |
727 | void javaVFrame::verify() const { |
728 | } |
729 | |
730 | |
731 | void interpretedVFrame::verify() const { |
732 | } |
733 | |
734 | |
735 | // ------------- externalVFrame -------------- |
736 | |
737 | void externalVFrame::print() { |
738 | _fr.print_value_on(tty,NULL); |
739 | } |
740 | |
741 | |
742 | void externalVFrame::print_value() const { |
743 | ((vframe*)this)->print(); |
744 | } |
745 | #endif // PRODUCT |
746 | |