| 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 | |