Mercurial > hg > graal-compiler
comparison src/share/vm/opto/callnode.cpp @ 63:eac007780a58
6671807: (Escape Analysis) Add new ideal node to represent the state of a scalarized object at a safepoint
Summary: Values of non-static fields of a scalarized object should be saved in debug info to reallocate the object during deoptimization.
Reviewed-by: never
author | kvn |
---|---|
date | Thu, 13 Mar 2008 16:06:34 -0700 |
parents | 76256d272075 |
children | 99269dbf4ba8 |
comparison
equal
deleted
inserted
replaced
46:8b6e49187640 | 63:eac007780a58 |
---|---|
228 _caller = caller; | 228 _caller = caller; |
229 _depth = 1 + (caller == NULL ? 0 : caller->depth()); | 229 _depth = 1 + (caller == NULL ? 0 : caller->depth()); |
230 _locoff = TypeFunc::Parms; | 230 _locoff = TypeFunc::Parms; |
231 _stkoff = _locoff + _method->max_locals(); | 231 _stkoff = _locoff + _method->max_locals(); |
232 _monoff = _stkoff + _method->max_stack(); | 232 _monoff = _stkoff + _method->max_stack(); |
233 _scloff = _monoff; | |
233 _endoff = _monoff; | 234 _endoff = _monoff; |
234 _sp = 0; | 235 _sp = 0; |
235 } | 236 } |
236 JVMState::JVMState(int stack_size) { | 237 JVMState::JVMState(int stack_size) { |
237 _method = NULL; | 238 _method = NULL; |
240 _caller = NULL; | 241 _caller = NULL; |
241 _depth = 1; | 242 _depth = 1; |
242 _locoff = TypeFunc::Parms; | 243 _locoff = TypeFunc::Parms; |
243 _stkoff = _locoff; | 244 _stkoff = _locoff; |
244 _monoff = _stkoff + stack_size; | 245 _monoff = _stkoff + stack_size; |
246 _scloff = _monoff; | |
245 _endoff = _monoff; | 247 _endoff = _monoff; |
246 _sp = 0; | 248 _sp = 0; |
247 } | 249 } |
248 | 250 |
249 //--------------------------------of_depth------------------------------------- | 251 //--------------------------------of_depth------------------------------------- |
295 total += jvmp->debug_size(); | 297 total += jvmp->debug_size(); |
296 } | 298 } |
297 return total; | 299 return total; |
298 } | 300 } |
299 | 301 |
302 #ifndef PRODUCT | |
303 | |
300 //------------------------------format_helper---------------------------------- | 304 //------------------------------format_helper---------------------------------- |
301 // Given an allocation (a Chaitin object) and a Node decide if the Node carries | 305 // Given an allocation (a Chaitin object) and a Node decide if the Node carries |
302 // any defined value or not. If it does, print out the register or constant. | 306 // any defined value or not. If it does, print out the register or constant. |
303 #ifndef PRODUCT | 307 static void format_helper( PhaseRegAlloc *regalloc, outputStream* st, Node *n, const char *msg, uint i, GrowableArray<SafePointScalarObjectNode*> *scobjs ) { |
304 static void format_helper( PhaseRegAlloc *regalloc, outputStream* st, Node *n, const char *msg, uint i ) { | |
305 if (n == NULL) { st->print(" NULL"); return; } | 308 if (n == NULL) { st->print(" NULL"); return; } |
309 if (n->is_SafePointScalarObject()) { | |
310 // Scalar replacement. | |
311 SafePointScalarObjectNode* spobj = n->as_SafePointScalarObject(); | |
312 scobjs->append_if_missing(spobj); | |
313 int sco_n = scobjs->find(spobj); | |
314 assert(sco_n >= 0, ""); | |
315 st->print(" %s%d]=#ScObj" INT32_FORMAT, msg, i, sco_n); | |
316 return; | |
317 } | |
306 if( OptoReg::is_valid(regalloc->get_reg_first(n))) { // Check for undefined | 318 if( OptoReg::is_valid(regalloc->get_reg_first(n))) { // Check for undefined |
307 char buf[50]; | 319 char buf[50]; |
308 regalloc->dump_register(n,buf); | 320 regalloc->dump_register(n,buf); |
309 st->print(" %s%d]=%s",msg,i,buf); | 321 st->print(" %s%d]=%s",msg,i,buf); |
310 } else { // No register, but might be constant | 322 } else { // No register, but might be constant |
340 break; | 352 break; |
341 default: ShouldNotReachHere(); | 353 default: ShouldNotReachHere(); |
342 } | 354 } |
343 } | 355 } |
344 } | 356 } |
345 #endif | |
346 | 357 |
347 //------------------------------format----------------------------------------- | 358 //------------------------------format----------------------------------------- |
348 #ifndef PRODUCT | |
349 void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st) const { | 359 void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st) const { |
350 st->print(" #"); | 360 st->print(" #"); |
351 if( _method ) { | 361 if( _method ) { |
352 _method->print_short_name(st); | 362 _method->print_short_name(st); |
353 st->print(" @ bci:%d ",_bci); | 363 st->print(" @ bci:%d ",_bci); |
354 } else { | 364 } else { |
355 st->print_cr(" runtime stub "); | 365 st->print_cr(" runtime stub "); |
356 return; | 366 return; |
357 } | 367 } |
358 if (n->is_MachSafePoint()) { | 368 if (n->is_MachSafePoint()) { |
369 GrowableArray<SafePointScalarObjectNode*> scobjs; | |
359 MachSafePointNode *mcall = n->as_MachSafePoint(); | 370 MachSafePointNode *mcall = n->as_MachSafePoint(); |
360 uint i; | 371 uint i; |
361 // Print locals | 372 // Print locals |
362 for( i = 0; i < (uint)loc_size(); i++ ) | 373 for( i = 0; i < (uint)loc_size(); i++ ) |
363 format_helper( regalloc, st, mcall->local(this, i), "L[", i ); | 374 format_helper( regalloc, st, mcall->local(this, i), "L[", i, &scobjs ); |
364 // Print stack | 375 // Print stack |
365 for (i = 0; i < (uint)stk_size(); i++) { | 376 for (i = 0; i < (uint)stk_size(); i++) { |
366 if ((uint)(_stkoff + i) >= mcall->len()) | 377 if ((uint)(_stkoff + i) >= mcall->len()) |
367 st->print(" oob "); | 378 st->print(" oob "); |
368 else | 379 else |
369 format_helper( regalloc, st, mcall->stack(this, i), "STK[", i ); | 380 format_helper( regalloc, st, mcall->stack(this, i), "STK[", i, &scobjs ); |
370 } | 381 } |
371 for (i = 0; (int)i < nof_monitors(); i++) { | 382 for (i = 0; (int)i < nof_monitors(); i++) { |
372 Node *box = mcall->monitor_box(this, i); | 383 Node *box = mcall->monitor_box(this, i); |
373 Node *obj = mcall->monitor_obj(this, i); | 384 Node *obj = mcall->monitor_obj(this, i); |
374 if ( OptoReg::is_valid(regalloc->get_reg_first(box)) ) { | 385 if ( OptoReg::is_valid(regalloc->get_reg_first(box)) ) { |
375 while( !box->is_BoxLock() ) box = box->in(1); | 386 while( !box->is_BoxLock() ) box = box->in(1); |
376 format_helper( regalloc, st, box, "MON-BOX[", i ); | 387 format_helper( regalloc, st, box, "MON-BOX[", i, &scobjs ); |
377 } else { | 388 } else { |
378 OptoReg::Name box_reg = BoxLockNode::stack_slot(box); | 389 OptoReg::Name box_reg = BoxLockNode::stack_slot(box); |
379 st->print(" MON-BOX%d=%s+%d", | 390 st->print(" MON-BOX%d=%s+%d", |
380 i, | 391 i, |
381 OptoReg::regname(OptoReg::c_frame_pointer), | 392 OptoReg::regname(OptoReg::c_frame_pointer), |
382 regalloc->reg2offset(box_reg)); | 393 regalloc->reg2offset(box_reg)); |
383 } | 394 } |
384 format_helper( regalloc, st, obj, "MON-OBJ[", i ); | 395 format_helper( regalloc, st, obj, "MON-OBJ[", i, &scobjs ); |
396 } | |
397 | |
398 for (i = 0; i < (uint)scobjs.length(); i++) { | |
399 // Scalar replaced objects. | |
400 st->print_cr(""); | |
401 st->print(" # ScObj" INT32_FORMAT " ", i); | |
402 SafePointScalarObjectNode* spobj = scobjs.at(i); | |
403 ciKlass* cik = spobj->bottom_type()->is_oopptr()->klass(); | |
404 assert(cik->is_instance_klass() || | |
405 cik->is_array_klass(), "Not supported allocation."); | |
406 ciInstanceKlass *iklass = NULL; | |
407 if (cik->is_instance_klass()) { | |
408 cik->print_name_on(st); | |
409 iklass = cik->as_instance_klass(); | |
410 } else if (cik->is_type_array_klass()) { | |
411 cik->as_array_klass()->base_element_type()->print_name_on(st); | |
412 st->print("[%d]=", spobj->n_fields()); | |
413 } else if (cik->is_obj_array_klass()) { | |
414 ciType* cie = cik->as_array_klass()->base_element_type(); | |
415 int ndim = 1; | |
416 while (cie->is_obj_array_klass()) { | |
417 ndim += 1; | |
418 cie = cie->as_array_klass()->base_element_type(); | |
419 } | |
420 cie->print_name_on(st); | |
421 while (ndim-- > 0) { | |
422 st->print("[]"); | |
423 } | |
424 st->print("[%d]=", spobj->n_fields()); | |
425 } | |
426 st->print("{"); | |
427 uint nf = spobj->n_fields(); | |
428 if (nf > 0) { | |
429 uint first_ind = spobj->first_index(); | |
430 Node* fld_node = mcall->in(first_ind); | |
431 ciField* cifield; | |
432 if (iklass != NULL) { | |
433 st->print(" ["); | |
434 cifield = iklass->nonstatic_field_at(0); | |
435 cifield->print_name_on(st); | |
436 format_helper( regalloc, st, fld_node, ":", 0, &scobjs ); | |
437 } else { | |
438 format_helper( regalloc, st, fld_node, "[", 0, &scobjs ); | |
439 } | |
440 for (uint j = 1; j < nf; j++) { | |
441 fld_node = mcall->in(first_ind+j); | |
442 if (iklass != NULL) { | |
443 st->print(", ["); | |
444 cifield = iklass->nonstatic_field_at(j); | |
445 cifield->print_name_on(st); | |
446 format_helper( regalloc, st, fld_node, ":", j, &scobjs ); | |
447 } else { | |
448 format_helper( regalloc, st, fld_node, ", [", j, &scobjs ); | |
449 } | |
450 } | |
451 } | |
452 st->print(" }"); | |
385 } | 453 } |
386 } | 454 } |
387 st->print_cr(""); | 455 st->print_cr(""); |
388 if (caller() != NULL) caller()->format(regalloc, n, st); | 456 if (caller() != NULL) caller()->format(regalloc, n, st); |
389 } | 457 } |
390 #endif | 458 |
391 | 459 |
392 #ifndef PRODUCT | |
393 void JVMState::dump_spec(outputStream *st) const { | 460 void JVMState::dump_spec(outputStream *st) const { |
394 if (_method != NULL) { | 461 if (_method != NULL) { |
395 bool printed = false; | 462 bool printed = false; |
396 if (!Verbose) { | 463 if (!Verbose) { |
397 // The JVMS dumps make really, really long lines. | 464 // The JVMS dumps make really, really long lines. |
417 } else { | 484 } else { |
418 st->print(" runtime stub"); | 485 st->print(" runtime stub"); |
419 } | 486 } |
420 if (caller() != NULL) caller()->dump_spec(st); | 487 if (caller() != NULL) caller()->dump_spec(st); |
421 } | 488 } |
422 #endif | 489 |
423 | 490 |
424 #ifndef PRODUCT | |
425 void JVMState::dump_on(outputStream* st) const { | 491 void JVMState::dump_on(outputStream* st) const { |
426 if (_map && !((uintptr_t)_map & 1)) { | 492 if (_map && !((uintptr_t)_map & 1)) { |
427 if (_map->len() > _map->req()) { // _map->has_exceptions() | 493 if (_map->len() > _map->req()) { // _map->has_exceptions() |
428 Node* ex = _map->in(_map->req()); // _map->next_exception() | 494 Node* ex = _map->in(_map->req()); // _map->next_exception() |
429 // skip the first one; it's already being printed | 495 // skip the first one; it's already being printed |
432 ex->dump(1); | 498 ex->dump(1); |
433 } | 499 } |
434 } | 500 } |
435 _map->dump(2); | 501 _map->dump(2); |
436 } | 502 } |
437 st->print("JVMS depth=%d loc=%d stk=%d mon=%d end=%d mondepth=%d sp=%d bci=%d method=", | 503 st->print("JVMS depth=%d loc=%d stk=%d mon=%d scalar=%d end=%d mondepth=%d sp=%d bci=%d method=", |
438 depth(), locoff(), stkoff(), monoff(), endoff(), monitor_depth(), sp(), bci()); | 504 depth(), locoff(), stkoff(), monoff(), scloff(), endoff(), monitor_depth(), sp(), bci()); |
439 if (_method == NULL) { | 505 if (_method == NULL) { |
440 st->print_cr("(none)"); | 506 st->print_cr("(none)"); |
441 } else { | 507 } else { |
442 _method->print_name(st); | 508 _method->print_name(st); |
443 st->cr(); | 509 st->cr(); |
463 JVMState* n = has_method() ? new (C) JVMState(_method, _caller) : new (C) JVMState(0); | 529 JVMState* n = has_method() ? new (C) JVMState(_method, _caller) : new (C) JVMState(0); |
464 n->set_bci(_bci); | 530 n->set_bci(_bci); |
465 n->set_locoff(_locoff); | 531 n->set_locoff(_locoff); |
466 n->set_stkoff(_stkoff); | 532 n->set_stkoff(_stkoff); |
467 n->set_monoff(_monoff); | 533 n->set_monoff(_monoff); |
534 n->set_scloff(_scloff); | |
468 n->set_endoff(_endoff); | 535 n->set_endoff(_endoff); |
469 n->set_sp(_sp); | 536 n->set_sp(_sp); |
470 n->set_map(_map); | 537 n->set_map(_map); |
471 return n; | 538 return n; |
472 } | 539 } |
763 | 830 |
764 | 831 |
765 void SafePointNode::grow_stack(JVMState* jvms, uint grow_by) { | 832 void SafePointNode::grow_stack(JVMState* jvms, uint grow_by) { |
766 assert((int)grow_by > 0, "sanity"); | 833 assert((int)grow_by > 0, "sanity"); |
767 int monoff = jvms->monoff(); | 834 int monoff = jvms->monoff(); |
835 int scloff = jvms->scloff(); | |
768 int endoff = jvms->endoff(); | 836 int endoff = jvms->endoff(); |
769 assert(endoff == (int)req(), "no other states or debug info after me"); | 837 assert(endoff == (int)req(), "no other states or debug info after me"); |
770 Node* top = Compile::current()->top(); | 838 Node* top = Compile::current()->top(); |
771 for (uint i = 0; i < grow_by; i++) { | 839 for (uint i = 0; i < grow_by; i++) { |
772 ins_req(monoff, top); | 840 ins_req(monoff, top); |
773 } | 841 } |
774 jvms->set_monoff(monoff + grow_by); | 842 jvms->set_monoff(monoff + grow_by); |
843 jvms->set_scloff(scloff + grow_by); | |
775 jvms->set_endoff(endoff + grow_by); | 844 jvms->set_endoff(endoff + grow_by); |
776 } | 845 } |
777 | 846 |
778 void SafePointNode::push_monitor(const FastLockNode *lock) { | 847 void SafePointNode::push_monitor(const FastLockNode *lock) { |
779 // Add a LockNode, which points to both the original BoxLockNode (the | 848 // Add a LockNode, which points to both the original BoxLockNode (the |
780 // stack space for the monitor) and the Object being locked. | 849 // stack space for the monitor) and the Object being locked. |
781 const int MonitorEdges = 2; | 850 const int MonitorEdges = 2; |
782 assert(JVMState::logMonitorEdges == exact_log2(MonitorEdges), "correct MonitorEdges"); | 851 assert(JVMState::logMonitorEdges == exact_log2(MonitorEdges), "correct MonitorEdges"); |
783 assert(req() == jvms()->endoff(), "correct sizing"); | 852 assert(req() == jvms()->endoff(), "correct sizing"); |
853 int nextmon = jvms()->scloff(); | |
784 if (GenerateSynchronizationCode) { | 854 if (GenerateSynchronizationCode) { |
785 add_req(lock->box_node()); | 855 add_req(lock->box_node()); |
786 add_req(lock->obj_node()); | 856 add_req(lock->obj_node()); |
787 } else { | 857 } else { |
788 add_req(NULL); | 858 add_req(NULL); |
789 add_req(NULL); | 859 add_req(NULL); |
790 } | 860 } |
861 jvms()->set_scloff(nextmon+MonitorEdges); | |
791 jvms()->set_endoff(req()); | 862 jvms()->set_endoff(req()); |
792 } | 863 } |
793 | 864 |
794 void SafePointNode::pop_monitor() { | 865 void SafePointNode::pop_monitor() { |
795 // Delete last monitor from debug info | 866 // Delete last monitor from debug info |
796 debug_only(int num_before_pop = jvms()->nof_monitors()); | 867 debug_only(int num_before_pop = jvms()->nof_monitors()); |
797 const int MonitorEdges = (1<<JVMState::logMonitorEdges); | 868 const int MonitorEdges = (1<<JVMState::logMonitorEdges); |
869 int scloff = jvms()->scloff(); | |
798 int endoff = jvms()->endoff(); | 870 int endoff = jvms()->endoff(); |
871 int new_scloff = scloff - MonitorEdges; | |
799 int new_endoff = endoff - MonitorEdges; | 872 int new_endoff = endoff - MonitorEdges; |
873 jvms()->set_scloff(new_scloff); | |
800 jvms()->set_endoff(new_endoff); | 874 jvms()->set_endoff(new_endoff); |
801 while (endoff > new_endoff) del_req(--endoff); | 875 while (scloff > new_scloff) del_req(--scloff); |
802 assert(jvms()->nof_monitors() == num_before_pop-1, ""); | 876 assert(jvms()->nof_monitors() == num_before_pop-1, ""); |
803 } | 877 } |
804 | 878 |
805 Node *SafePointNode::peek_monitor_box() const { | 879 Node *SafePointNode::peek_monitor_box() const { |
806 int mon = jvms()->nof_monitors() - 1; | 880 int mon = jvms()->nof_monitors() - 1; |
819 if( !needs_polling_address_input() ) | 893 if( !needs_polling_address_input() ) |
820 return 0; | 894 return 0; |
821 | 895 |
822 return (TypeFunc::Parms == idx); | 896 return (TypeFunc::Parms == idx); |
823 } | 897 } |
898 | |
899 //============== SafePointScalarObjectNode ============== | |
900 | |
901 SafePointScalarObjectNode::SafePointScalarObjectNode(const TypeOopPtr* tp, | |
902 #ifdef ASSERT | |
903 AllocateNode* alloc, | |
904 #endif | |
905 uint first_index, | |
906 uint n_fields) : | |
907 TypeNode(tp, 1), // 1 control input -- seems required. Get from root. | |
908 #ifdef ASSERT | |
909 _alloc(alloc), | |
910 #endif | |
911 _first_index(first_index), | |
912 _n_fields(n_fields) | |
913 { | |
914 init_class_id(Class_SafePointScalarObject); | |
915 } | |
916 | |
917 | |
918 uint SafePointScalarObjectNode::ideal_reg() const { | |
919 return 0; // No matching to machine instruction | |
920 } | |
921 | |
922 const RegMask &SafePointScalarObjectNode::in_RegMask(uint idx) const { | |
923 return *(Compile::current()->matcher()->idealreg2debugmask[in(idx)->ideal_reg()]); | |
924 } | |
925 | |
926 const RegMask &SafePointScalarObjectNode::out_RegMask() const { | |
927 return RegMask::Empty; | |
928 } | |
929 | |
930 uint SafePointScalarObjectNode::match_edge(uint idx) const { | |
931 return 0; | |
932 } | |
933 | |
934 SafePointScalarObjectNode* | |
935 SafePointScalarObjectNode::clone(int jvms_adj, Dict* sosn_map) const { | |
936 void* cached = (*sosn_map)[(void*)this]; | |
937 if (cached != NULL) { | |
938 return (SafePointScalarObjectNode*)cached; | |
939 } | |
940 Compile* C = Compile::current(); | |
941 SafePointScalarObjectNode* res = (SafePointScalarObjectNode*)Node::clone(); | |
942 res->_first_index += jvms_adj; | |
943 sosn_map->Insert((void*)this, (void*)res); | |
944 return res; | |
945 } | |
946 | |
947 | |
948 #ifndef PRODUCT | |
949 void SafePointScalarObjectNode::dump_spec(outputStream *st) const { | |
950 st->print(" # fields@[%d..%d]", first_index(), | |
951 first_index() + n_fields() - 1); | |
952 } | |
953 | |
954 #endif | |
824 | 955 |
825 //============================================================================= | 956 //============================================================================= |
826 uint AllocateNode::size_of() const { return sizeof(*this); } | 957 uint AllocateNode::size_of() const { return sizeof(*this); } |
827 | 958 |
828 AllocateNode::AllocateNode(Compile* C, const TypeFunc *atype, | 959 AllocateNode::AllocateNode(Compile* C, const TypeFunc *atype, |