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