< prev index next >

src/hotspot/share/compiler/oopMap.cpp

Print this page
*** 26,16 ***
  #include "code/codeBlob.hpp"
  #include "code/codeCache.hpp"
  #include "code/nmethod.hpp"
  #include "code/scopeDesc.hpp"
  #include "compiler/oopMap.hpp"
  #include "gc/shared/collectedHeap.hpp"
  #include "memory/allocation.inline.hpp"
  #include "memory/iterator.hpp"
  #include "memory/resourceArea.hpp"
- #include "memory/universe.hpp"
  #include "oops/compressedOops.hpp"
  #include "runtime/frame.inline.hpp"
  #include "runtime/handles.inline.hpp"
  #include "runtime/signature.hpp"
  #include "runtime/stackWatermarkSet.inline.hpp"
  #include "utilities/align.hpp"
--- 26,19 ---
  #include "code/codeBlob.hpp"
  #include "code/codeCache.hpp"
  #include "code/nmethod.hpp"
  #include "code/scopeDesc.hpp"
  #include "compiler/oopMap.hpp"
+ #include "compiler/oopMap.inline.hpp"
  #include "gc/shared/collectedHeap.hpp"
+ #include "logging/log.hpp"
+ #include "logging/logStream.hpp"
  #include "memory/allocation.inline.hpp"
  #include "memory/iterator.hpp"
  #include "memory/resourceArea.hpp"
  #include "oops/compressedOops.hpp"
+ #include "runtime/atomic.hpp"
  #include "runtime/frame.inline.hpp"
  #include "runtime/handles.inline.hpp"
  #include "runtime/signature.hpp"
  #include "runtime/stackWatermarkSet.inline.hpp"
  #include "utilities/align.hpp"

*** 68,27 ***
    return static_cast<derived_pointer>(derived_pointer_value(p) + offset);
  }
  
  // OopMapStream
  
! OopMapStream::OopMapStream(OopMap* oop_map) {
!   _stream = new CompressedReadStream(oop_map->write_stream()->buffer());
    _size = oop_map->omv_count();
    _position = 0;
    _valid_omv = false;
  }
  
! OopMapStream::OopMapStream(const ImmutableOopMap* oop_map) {
!   _stream = new CompressedReadStream(oop_map->data_addr());
    _size = oop_map->count();
    _position = 0;
    _valid_omv = false;
  }
  
  void OopMapStream::find_next() {
    if (_position++ < _size) {
!     _omv.read_from(_stream);
      _valid_omv = true;
      return;
    }
    _valid_omv = false;
  }
--- 71,29 ---
    return static_cast<derived_pointer>(derived_pointer_value(p) + offset);
  }
  
  // OopMapStream
  
! OopMapStream::OopMapStream(const OopMap* oop_map)
!   : _stream(oop_map->write_stream()->buffer()) {
+   // _stream = new CompressedReadStream(oop_map->write_stream()->buffer());
    _size = oop_map->omv_count();
    _position = 0;
    _valid_omv = false;
  }
  
! OopMapStream::OopMapStream(const ImmutableOopMap* oop_map)
!   : _stream(oop_map->data_addr()) {
+   // _stream = new CompressedReadStream(oop_map->data_addr());
    _size = oop_map->count();
    _position = 0;
    _valid_omv = false;
  }
  
  void OopMapStream::find_next() {
    if (_position++ < _size) {
!     _omv.read_from(&_stream);
      _valid_omv = true;
      return;
    }
    _valid_omv = false;
  }

*** 100,10 ***
--- 105,13 ---
  // slots to hold 4-byte values like ints and floats in the LP64 build.
  OopMap::OopMap(int frame_size, int arg_count) {
    // OopMaps are usually quite so small, so pick a small initial size
    set_write_stream(new CompressedWriteStream(32));
    set_omv_count(0);
+   _num_oops = 0;
+   _has_derived_oops = false;
+   _index = -1;
  
  #ifdef ASSERT
    _locs_length = VMRegImpl::stack2reg(0)->value() + frame_size + arg_count;
    _locs_used   = NEW_RESOURCE_ARRAY(OopMapValue::oop_types, _locs_length);
    for(int i = 0; i < _locs_length; i++) _locs_used[i] = OopMapValue::unused_value;

*** 115,10 ***
--- 123,13 ---
    // This constructor does a deep copy
    // of the source OopMap.
    set_write_stream(new CompressedWriteStream(source->omv_count() * 2));
    set_omv_count(0);
    set_offset(source->offset());
+   _num_oops = source->num_oops();
+   _has_derived_oops = source->has_derived_oops();
+   _index = -1;
  
  #ifdef ASSERT
    _locs_length = source->_locs_length;
    _locs_used = NEW_RESOURCE_ARRAY(OopMapValue::oop_types, _locs_length);
    for(int i = 0; i < _locs_length; i++) _locs_used[i] = OopMapValue::unused_value;

*** 139,10 ***
--- 150,172 ---
  
  void OopMap::copy_data_to(address addr) const {
    memcpy(addr, write_stream()->buffer(), write_stream()->position());
  }
  
+ class OopMapSort {
+ private:
+   const OopMap* _map;
+   OopMapValue* _values;
+   int _count;
+ 
+ public:
+   OopMapSort(const OopMap* map) : _map(map), _count(0) {
+     _values = NEW_RESOURCE_ARRAY(OopMapValue, _map->omv_count());
+   }
+ 
+   void sort();
+ 
+   void print();
+ 
+   void write(CompressedWriteStream* stream) {
+     for (int i = 0; i < _count; ++i) {
+       _values[i].write_on(stream);
+     }
+   }
+ 
+ private:
+   int find_derived_position(OopMapValue omv, int start) {
+     assert(omv.type() == OopMapValue::derived_oop_value, "");
+ 
+     VMReg base = omv.content_reg();
+     int i = start;
+ 
+     for (; i < _count; ++i) {
+       if (base == _values[i].reg()) {
+ 
+         for (int n = i + 1; n < _count; ++n) {
+           if (_values[i].type() != OopMapValue::derived_oop_value || _values[i].content_reg() != base) {
+             return n;
+           }
+ 
+           if (derived_cost(_values[i]) > derived_cost(omv)) {
+             return n;
+           }
+         }
+         return _count;
+       }
+     }
+ 
+     assert(false, "failed to find base");
+     return -1;
+   }
+ 
+   int find_position(OopMapValue omv, int start) {
+     assert(omv.type() != OopMapValue::derived_oop_value, "");
+ 
+     int i = start;
+     for (; i < _count; ++i) {
+       if (omv_cost(_values[i]) > omv_cost(omv)) {
+         return i;
+       }
+     }
+     assert(i < _map->omv_count(), "bounds check");
+     return i;
+   }
+ 
+   void insert(OopMapValue value, int pos) {
+     assert(pos >= 0 && pos < _map->omv_count(), "bounds check");
+     assert(pos <= _count, "sanity");
+ 
+     if (pos < _count) {
+       OopMapValue prev = _values[pos];
+ 
+       for (int i = pos; i < _count; ++i) {
+         OopMapValue tmp = _values[i+1];
+         _values[i+1] = prev;
+         prev = tmp;
+       }
+     }
+     _values[pos] = value;
+ 
+     ++_count;
+   }
+ 
+   int omv_cost(OopMapValue omv) {
+     assert(omv.type() == OopMapValue::oop_value || omv.type() == OopMapValue::narrowoop_value, "");
+     return reg_cost(omv.reg());
+   }
+ 
+   int reg_cost(VMReg reg) {
+     if (reg->is_reg()) {
+       return 0;
+     }
+     return reg->reg2stack() * VMRegImpl::stack_slot_size;
+   }
+ 
+   int derived_cost(OopMapValue omv) {
+     return reg_cost(omv.reg());
+   }
+ };
+ 
+ void OopMapSort::sort() {
+   for (OopMapStream oms(_map); !oms.is_done(); oms.next()) {
+     OopMapValue omv = oms.current();
+     assert(omv.type() == OopMapValue::oop_value || omv.type() == OopMapValue::narrowoop_value || omv.type() == OopMapValue::derived_oop_value || omv.type() == OopMapValue::callee_saved_value, "");
+   }
+ 
+   for (OopMapStream oms(_map); !oms.is_done(); oms.next()) {
+     if (oms.current().type() == OopMapValue::callee_saved_value) {
+       insert(oms.current(), _count);
+     }
+   }
+ 
+   int start = _count;
+   for (OopMapStream oms(_map); !oms.is_done(); oms.next()) {
+     OopMapValue omv = oms.current();
+     if (omv.type() == OopMapValue::oop_value || omv.type() == OopMapValue::narrowoop_value) {
+       int pos = find_position(omv, start);
+       insert(omv, pos);
+     }
+   }
+ 
+   for (OopMapStream oms(_map); !oms.is_done(); oms.next()) {
+     OopMapValue omv = oms.current();
+     if (omv.type() == OopMapValue::derived_oop_value) {
+       int pos = find_derived_position(omv, start);
+       assert(pos > 0, "");
+       insert(omv, pos);
+     }
+   }
+ }
+ 
+ void OopMapSort::print() {
+   for (int i = 0; i < _count; ++i) {
+     OopMapValue omv = _values[i];
+     if (omv.type() == OopMapValue::oop_value || omv.type() == OopMapValue::narrowoop_value) {
+       if (omv.reg()->is_reg()) {
+         tty->print_cr("[%c][%d] -> reg (" INTPTR_FORMAT ")", omv.type() == OopMapValue::narrowoop_value ? 'n' : 'o', i, omv.reg()->value());
+       } else {
+         tty->print_cr("[%c][%d] -> stack ("  INTPTR_FORMAT ")", omv.type() == OopMapValue::narrowoop_value ? 'n' : 'o', i, omv.reg()->reg2stack() * VMRegImpl::stack_slot_size);
+       }
+     } else {
+       if (omv.content_reg()->is_reg()) {
+         tty->print_cr("[d][%d] -> reg (" INTPTR_FORMAT ") stack (" INTPTR_FORMAT ")", i, omv.content_reg()->value(), omv.reg()->reg2stack() * VMRegImpl::stack_slot_size);
+       } else if (omv.reg()->is_reg()) {
+         tty->print_cr("[d][%d] -> stack (" INTPTR_FORMAT ") reg (" INTPTR_FORMAT ")", i, omv.content_reg()->reg2stack() * VMRegImpl::stack_slot_size, omv.reg()->value());
+       } else {
+         int derived_offset = omv.reg()->reg2stack() * VMRegImpl::stack_slot_size;
+         int base_offset = omv.content_reg()->reg2stack() * VMRegImpl::stack_slot_size;
+         tty->print_cr("[d][%d] -> stack (%x) stack (%x)", i, base_offset, derived_offset);
+       }
+     }
+   }
+ }
+ 
+ void OopMap::copy_and_sort_data_to(address addr) const {
+   OopMapSort sort(this);
+   sort.sort();
+   CompressedWriteStream* stream = new CompressedWriteStream(_write_stream->position());
+   sort.write(stream);
+ 
+   assert(stream->position() == write_stream()->position(), "");
+   memcpy(addr, stream->buffer(), stream->position());
+   //copy_data_to(addr);
+   //sort.print();
+ }
+ 
  int OopMap::heap_size() const {
    int size = sizeof(OopMap);
    int align = sizeof(void *) - 1;
    size += write_stream()->position();
    // Align to a reasonable ending point

*** 159,18 ***
--- 332,28 ---
    debug_only( _locs_used[reg->value()] = x; )
  
    OopMapValue o(reg, x, optional);
    o.write_on(write_stream());
    increment_count();
+   if (x == OopMapValue::oop_value || x == OopMapValue::narrowoop_value) {
+     increment_num_oops();
+   } else if (x == OopMapValue::derived_oop_value) {
+     set_has_derived_oops(true);
+   }
  }
  
  
  void OopMap::set_oop(VMReg reg) {
    set_xxx(reg, OopMapValue::oop_value, VMRegImpl::Bad());
  }
  
  
+ // void OopMap::set_value(VMReg reg) {
+ //   set_xxx(reg, OopMapValue::live_value, VMRegImpl::Bad());
+ // }
+ 
+ 
  void OopMap::set_narrowoop(VMReg reg) {
    set_xxx(reg, OopMapValue::narrowoop_value, VMRegImpl::Bad());
  }
  
  

*** 190,11 ***
  
  // OopMapSet
  
  OopMapSet::OopMapSet() : _list(MinOopMapAllocation) {}
  
! void OopMapSet::add_gc_map(int pc_offset, OopMap *map ) {
    map->set_offset(pc_offset);
  
  #ifdef ASSERT
    if(_list.length() > 0) {
      OopMap* last = _list.last();
--- 373,11 ---
  
  // OopMapSet
  
  OopMapSet::OopMapSet() : _list(MinOopMapAllocation) {}
  
! int OopMapSet::add_gc_map(int pc_offset, OopMap *map ) {
    map->set_offset(pc_offset);
  
  #ifdef ASSERT
    if(_list.length() > 0) {
      OopMap* last = _list.last();

*** 206,199 ***
                        _list.length(),last->offset(),_list.length()+1,map->offset());
      }
    }
  #endif // ASSERT
  
!   add(map);
  }
  
! static void add_derived_oop(oop* base, derived_pointer* derived, OopClosure* oop_fn) {
  #if COMPILER2_OR_JVMCI
!   DerivedPointerTable::add(derived, base);
  #endif // COMPILER2_OR_JVMCI
- }
- 
- static void ignore_derived_oop(oop* base, derived_pointer* derived, OopClosure* oop_fn) {
- }
- 
- static void process_derived_oop(oop* base, derived_pointer* derived, OopClosure* oop_fn) {
-   // All derived pointers must be processed before the base pointer of any derived pointer is processed.
-   // Otherwise, if two derived pointers use the same base, the second derived pointer will get an obscured
-   // offset, if the base pointer is processed in the first derived pointer.
-   derived_pointer derived_base = to_derived_pointer(*base);
-   intptr_t offset = *derived - derived_base;
-   *derived = derived_base;
-   oop_fn->do_oop((oop*)derived);
-   *derived = *derived + offset;
- }
- 
- 
- #ifndef PRODUCT
- static void trace_codeblob_maps(const frame *fr, const RegisterMap *reg_map) {
-   // Print oopmap and regmap
-   tty->print_cr("------ ");
-   CodeBlob* cb = fr->cb();
-   const ImmutableOopMapSet* maps = cb->oop_maps();
-   const ImmutableOopMap* map = cb->oop_map_for_return_address(fr->pc());
-   map->print();
-   if( cb->is_nmethod() ) {
-     nmethod* nm = (nmethod*)cb;
-     // native wrappers have no scope data, it is implied
-     if (nm->is_native_method()) {
-       tty->print("bci: 0 (native)");
-     } else {
-       ScopeDesc* scope  = nm->scope_desc_at(fr->pc());
-       tty->print("bci: %d ",scope->bci());
-     }
    }
!   tty->cr();
!   fr->print_on(tty);
!   tty->print("     ");
!   cb->print_value_on(tty);  tty->cr();
!   reg_map->print();
!   tty->print_cr("------ ");
! 
! }
! #endif // PRODUCT
! 
! void OopMapSet::oops_do(const frame *fr, const RegisterMap* reg_map, OopClosure* f, DerivedPointerIterationMode mode) {
!   switch (mode) {
    case DerivedPointerIterationMode::_directly:
!     all_do(fr, reg_map, f, process_derived_oop);
      break;
    case DerivedPointerIterationMode::_with_table:
!     all_do(fr, reg_map, f, add_derived_oop);
      break;
    case DerivedPointerIterationMode::_ignore:
!     all_do(fr, reg_map, f, ignore_derived_oop);
      break;
    }
  }
  
! 
! void OopMapSet::all_do(const frame *fr, const RegisterMap *reg_map,
!                        OopClosure* oop_fn, void derived_oop_fn(oop*, derived_pointer*, OopClosure*)) {
!   CodeBlob* cb = fr->cb();
!   assert(cb != NULL, "no codeblob");
! 
-   NOT_PRODUCT(if (TraceCodeBlobStacks) trace_codeblob_maps(fr, reg_map);)
- 
-   const ImmutableOopMap* map = cb->oop_map_for_return_address(fr->pc());
-   assert(map != NULL, "no ptr map found");
- 
-   // handle derived pointers first (otherwise base pointer may be
-   // changed before derived pointer offset has been collected)
-   {
-     for (OopMapStream oms(map); !oms.is_done(); oms.next()) {
-       OopMapValue omv = oms.current();
-       if (omv.type() != OopMapValue::derived_oop_value) {
-         continue;
-       }
- 
- #ifndef COMPILER2
-       COMPILER1_PRESENT(ShouldNotReachHere();)
- #if INCLUDE_JVMCI
-       if (UseJVMCICompiler) {
-         ShouldNotReachHere();
-       }
- #endif
- #endif // !COMPILER2
-       derived_pointer* derived_loc = (derived_pointer*)fr->oopmapreg_to_location(omv.reg(),reg_map);
-       guarantee(derived_loc != NULL, "missing saved register");
-       oop* base_loc = fr->oopmapreg_to_oop_location(omv.content_reg(), reg_map);
-       // Ignore NULL oops and decoded NULL narrow oops which
-       // equal to CompressedOops::base() when a narrow oop
-       // implicit null check is used in compiled code.
-       // The narrow_oop_base could be NULL or be the address
-       // of the page below heap depending on compressed oops mode.
-       if (base_loc != NULL && *base_loc != NULL && !CompressedOops::is_base(*base_loc)) {
-         derived_oop_fn(base_loc, derived_loc, oop_fn);
-       }
      }
    }
  
!   {
!     // We want coop and oop oop_types
!     for (OopMapStream oms(map); !oms.is_done(); oms.next()) {
!       OopMapValue omv = oms.current();
!       oop* loc = fr->oopmapreg_to_oop_location(omv.reg(),reg_map);
!       // It should be an error if no location can be found for a
-       // register mentioned as contained an oop of some kind.  Maybe
-       // this was allowed previously because value_value items might
-       // be missing?
-       guarantee(loc != NULL, "missing saved register");
-       if ( omv.type() == OopMapValue::oop_value ) {
-         oop val = *loc;
-         if (val == NULL || CompressedOops::is_base(val)) {
-           // Ignore NULL oops and decoded NULL narrow oops which
-           // equal to CompressedOops::base() when a narrow oop
-           // implicit null check is used in compiled code.
-           // The narrow_oop_base could be NULL or be the address
-           // of the page below heap depending on compressed oops mode.
-           continue;
-         }
-         oop_fn->do_oop(loc);
-       } else if ( omv.type() == OopMapValue::narrowoop_value ) {
-         narrowOop *nl = (narrowOop*)loc;
- #ifndef VM_LITTLE_ENDIAN
-         VMReg vmReg = omv.reg();
-         if (!vmReg->is_stack()) {
-           // compressed oops in registers only take up 4 bytes of an
-           // 8 byte register but they are in the wrong part of the
-           // word so adjust loc to point at the right place.
-           nl = (narrowOop*)((address)nl + 4);
-         }
- #endif
-         oop_fn->do_oop(nl);
-       }
      }
    }
  }
  
  
  // Update callee-saved register info for the following frame
! void OopMapSet::update_register_map(const frame *fr, RegisterMap *reg_map) {
!   ResourceMark rm;
    CodeBlob* cb = fr->cb();
    assert(cb != NULL, "no codeblob");
- 
    // Any reg might be saved by a safepoint handler (see generate_handler_blob).
    assert( reg_map->_update_for_id == NULL || fr->is_older(reg_map->_update_for_id),
           "already updated this map; do not 'update' it twice!" );
    debug_only(reg_map->_update_for_id = fr->id());
  
    // Check if caller must update oop argument
    assert((reg_map->include_argument_oops() ||
            !cb->caller_must_gc_arguments(reg_map->thread())),
           "include_argument_oops should already be set");
  
    // Scan through oopmap and find location of all callee-saved registers
    // (we do not do update in place, since info could be overwritten)
  
-   address pc = fr->pc();
-   const ImmutableOopMap* map  = cb->oop_map_for_return_address(pc);
-   assert(map != NULL, "no ptr map found");
    DEBUG_ONLY(int nof_callee = 0;)
  
!   for (OopMapStream oms(map); !oms.is_done(); oms.next()) {
      OopMapValue omv = oms.current();
!     if (omv.type() == OopMapValue::callee_saved_value) {
!       VMReg reg = omv.content_reg();
!       oop* loc = fr->oopmapreg_to_oop_location(omv.reg(), reg_map);
!       reg_map->set_location(reg, (address) loc);
-       DEBUG_ONLY(nof_callee++;)
-     }
    }
  
    // Check that runtime stubs save all callee-saved registers
  #ifdef COMPILER2
!   assert(cb->is_compiled_by_c1() || cb->is_compiled_by_jvmci() || !cb->is_runtime_stub() ||
           (nof_callee >= SAVED_ON_ENTRY_REG_COUNT || nof_callee >= C_SAVED_ON_ENTRY_REG_COUNT),
           "must save all");
  #endif // COMPILER2
  }
  
  // Printing code is present in product build for -XX:+PrintAssembly.
  
  static
  void print_register_type(OopMapValue::oop_types x, VMReg optional,
                           outputStream* st) {
--- 389,248 ---
                        _list.length(),last->offset(),_list.length()+1,map->offset());
      }
    }
  #endif // ASSERT
  
!   int index = add(map);
+   map->_index = index;
+   return index;
  }
  
! class AddDerivedOop : public DerivedOopClosure {
+  public:
+   enum {
+     SkipNull = true, NeedsLock = true
+   };
+ 
+   virtual void do_derived_oop(oop* base, derived_pointer* derived) {
  #if COMPILER2_OR_JVMCI
!     DerivedPointerTable::add(derived, base);
  #endif // COMPILER2_OR_JVMCI
    }
! };
! 
! class ProcessDerivedOop : public DerivedOopClosure {
!   OopClosure* _oop_cl;
! public:
!   ProcessDerivedOop(OopClosure* oop_cl) :
!       _oop_cl(oop_cl) {}
! 
!   enum {
!     SkipNull = true, NeedsLock = true
!   };
! 
+   virtual void do_derived_oop(oop* base, derived_pointer* derived) {
+     // All derived pointers must be processed before the base pointer of any derived pointer is processed.
+     // Otherwise, if two derived pointers use the same base, the second derived pointer will get an obscured
+     // offset, if the base pointer is processed in the first derived pointer.
+     derived_pointer derived_base = to_derived_pointer(*base);
+     intptr_t offset = *derived - derived_base;
+     *derived = derived_base;
+     _oop_cl->do_oop((oop*)derived);
+     *derived = *derived + offset;
+   }
+ };
+ 
+ class IgnoreDerivedOop : public DerivedOopClosure {
+   OopClosure* _oop_cl;
+ public:
+   enum {
+         SkipNull = true, NeedsLock = true
+   };
+ 
+   virtual void do_derived_oop(oop* base, derived_pointer* derived) {}
+ };
+ 
+ void OopMapSet::oops_do(const frame* fr, const RegisterMap* reg_map, OopClosure* f, DerivedPointerIterationMode mode) {
+   find_map(fr)->oops_do(fr, reg_map, f, mode);
+ }
+ 
+ void OopMapSet::oops_do(const frame *fr, const RegisterMap* reg_map, OopClosure* f, DerivedOopClosure* df) {
+   find_map(fr)->oops_do(fr, reg_map, f, df);
+ }
+ 
+ // void OopMapSet::all_do(const frame *fr, const RegisterMap *reg_map,
+ //                        OopClosure* oop_fn, DerivedOopClosure* derived_oop_fn,
+ //                        OopClosure* value_fn) {
+ //   find_map(fr)->oops_do(fr, reg_map, oop_fn, derived_oop_fn, value_fn);
+ // }
+ 
+ // NULL, fail, success (address)
+ // void ImmutableOopMap::generate_stub(const CodeBlob* cb) const {
+ //   /* The address of the ImmutableOopMap is put into the _freeze_stub and _thaw_stub
+ //    * if we can't generate the stub for some reason */
+ //   address default_value = Continuations::default_freeze_oops_stub();
+ //   address slow_value = Continuations::freeze_oops_slow();
+ 
+ //   assert(default_value != slow_value, "should not reach here!");
+ 
+ //   if (_freeze_stub == default_value) {
+ //     OopMapStubGenerator cgen(cb, *this);
+ //     // lock this by putting the slow path in place
+ //     if (Atomic::cmpxchg(&_freeze_stub, default_value, slow_value) == default_value) {
+ //       if (!cgen.generate()) {
+ //         Atomic::store(&_thaw_stub, (address) Continuations::thaw_oops_slow());
+ //         cgen.free();
+ //         return;
+ //       }
+ 
+ //       Atomic::store(&_freeze_stub, cgen.freeze_stub());
+ //       Atomic::store(&_thaw_stub, cgen.thaw_stub());
+ //     }
+ //   }
+ // }
+ 
+ void ImmutableOopMap::oops_do(const frame *fr, const RegisterMap *reg_map,
+                               OopClosure* oop_fn, DerivedOopClosure* derived_oop_fn) const {
+   assert(derived_oop_fn != NULL, "sanity");
+   OopMapDo<OopClosure, DerivedOopClosure, SkipNullValue> visitor(oop_fn, derived_oop_fn);
+   visitor.oops_do(fr, reg_map, this);
+ }
+ 
+ void ImmutableOopMap::oops_do(const frame *fr, const RegisterMap *reg_map,
+                               OopClosure* oop_fn, DerivedPointerIterationMode derived_mode) const {
+   ProcessDerivedOop process_cl(oop_fn);
+   AddDerivedOop add_cl;
+   IgnoreDerivedOop ignore_cl;
+   DerivedOopClosure* derived_cl;
+   switch (derived_mode) {
    case DerivedPointerIterationMode::_directly:
!     derived_cl = &process_cl;
      break;
    case DerivedPointerIterationMode::_with_table:
!     derived_cl = &add_cl;
      break;
    case DerivedPointerIterationMode::_ignore:
!     derived_cl = &ignore_cl;
      break;
    }
+   OopMapDo<OopClosure, DerivedOopClosure, SkipNullValue> visitor(oop_fn, derived_cl);
+   visitor.oops_do(fr, reg_map, this);
  }
  
! void ImmutableOopMap::all_type_do(const frame *fr, OopMapClosure* fn) const {
!   OopMapValue omv;
!   for (OopMapStream oms(this); !oms.is_done(); oms.next()) {
!     omv = oms.current();
!     if (fn->handle_type(omv.type())) {
!       fn->do_value(omv.reg(), omv.type());
      }
    }
+ }
  
! void ImmutableOopMap::all_type_do(const frame *fr, OopMapValue::oop_types type, OopMapClosure* fn) const {
!   OopMapValue omv;
!   for (OopMapStream oms(this); !oms.is_done(); oms.next()) {
!     omv = oms.current();
!     if (omv.type() == type) {
!       fn->do_value(omv.reg(), omv.type());
      }
    }
  }
  
+ static void update_register_map1(const ImmutableOopMap* oopmap, const frame* fr, RegisterMap* reg_map) {
+   for (OopMapStream oms(oopmap); !oms.is_done(); oms.next()) {
+     OopMapValue omv = oms.current();
+     if (omv.type() == OopMapValue::callee_saved_value) {
+       VMReg reg = omv.content_reg();
+       address loc = fr->oopmapreg_to_location(omv.reg(), reg_map);
+       reg_map->set_location(reg, loc);
+       //DEBUG_ONLY(nof_callee++;)
+     }
+   }
+ }
  
  // Update callee-saved register info for the following frame
! void ImmutableOopMap::update_register_map(const frame *fr, RegisterMap *reg_map) const {
!   // ResourceMark rm;
    CodeBlob* cb = fr->cb();
    assert(cb != NULL, "no codeblob");
    // Any reg might be saved by a safepoint handler (see generate_handler_blob).
    assert( reg_map->_update_for_id == NULL || fr->is_older(reg_map->_update_for_id),
           "already updated this map; do not 'update' it twice!" );
    debug_only(reg_map->_update_for_id = fr->id());
  
+ 
    // Check if caller must update oop argument
    assert((reg_map->include_argument_oops() ||
            !cb->caller_must_gc_arguments(reg_map->thread())),
           "include_argument_oops should already be set");
  
    // Scan through oopmap and find location of all callee-saved registers
    // (we do not do update in place, since info could be overwritten)
  
    DEBUG_ONLY(int nof_callee = 0;)
+   update_register_map1(this, fr, reg_map);
  
!   /*
+   for (OopMapStream oms(this, OopMapValue::callee_saved_value); !oms.is_done(); oms.next()) {
      OopMapValue omv = oms.current();
!     VMReg reg = omv.content_reg();
!     oop* loc = fr->oopmapreg_to_oop_location(omv.reg(), reg_map);
!     reg_map->set_location(reg, (address) loc);
!     DEBUG_ONLY(nof_callee++;)
    }
+   */
  
    // Check that runtime stubs save all callee-saved registers
  #ifdef COMPILER2
!   assert(cb == NULL || cb->is_compiled_by_c1() || cb->is_compiled_by_jvmci() || !cb->is_runtime_stub() ||
           (nof_callee >= SAVED_ON_ENTRY_REG_COUNT || nof_callee >= C_SAVED_ON_ENTRY_REG_COUNT),
           "must save all");
  #endif // COMPILER2
  }
  
+ const ImmutableOopMap* OopMapSet::find_map(const frame *fr) { 
+   return find_map(fr->cb(), fr->pc()); 
+ }
+ 
+ const ImmutableOopMap* OopMapSet::find_map(const CodeBlob* cb, address pc) {
+   assert(cb != NULL, "no codeblob");
+   const ImmutableOopMap* map = cb->oop_map_for_return_address(pc);
+   assert(map != NULL, "no ptr map found");
+   return map;
+ }
+ 
+ // Update callee-saved register info for the following frame
+ void OopMapSet::update_register_map(const frame *fr, RegisterMap *reg_map) {
+   find_map(fr)->update_register_map(fr, reg_map);
+ }
+ 
+ //=============================================================================
+ // Non-Product code
+ 
+ #ifndef PRODUCT
+ void OopMapSet::trace_codeblob_maps(const frame *fr, const RegisterMap *reg_map) {
+   // Print oopmap and regmap
+   tty->print_cr("------ ");
+   CodeBlob* cb = fr->cb();
+   const ImmutableOopMapSet* maps = cb->oop_maps();
+   const ImmutableOopMap* map = cb->oop_map_for_return_address(fr->pc());
+   map->print();
+   if( cb->is_nmethod() ) {
+     nmethod* nm = (nmethod*)cb;
+     // native wrappers have no scope data, it is implied
+     if (nm->is_native_method()) {
+       tty->print("bci: 0 (native)");
+     } else {
+       ScopeDesc* scope  = nm->scope_desc_at(fr->pc());
+       tty->print("bci: %d ",scope->bci());
+     }
+   }
+   tty->cr();
+   fr->print_on(tty);
+   tty->print("     ");
+   cb->print_value_on(tty);  tty->cr();
+   if (reg_map != NULL) {
+     reg_map->print();
+   }
+   tty->print_cr("------ ");
+ 
+ }
+ #endif // PRODUCT
+ 
  // Printing code is present in product build for -XX:+PrintAssembly.
  
  static
  void print_register_type(OopMapValue::oop_types x, VMReg optional,
                           outputStream* st) {

*** 505,10 ***
--- 737,25 ---
      return false;
    }
    return true;
  }
  
+ int ImmutableOopMapSet::find_slot_for_offset(int pc_offset) const {
+   ImmutableOopMapPair* pairs = get_pairs();
+ 
+   for (int i = 0; i < _count; ++i) {
+     if (pairs[i].pc_offset() >= pc_offset) {
+       ImmutableOopMapPair* last = &pairs[i];
+       assert(last->pc_offset() == pc_offset, "oopmap not found");
+       return i;
+     }
+   }
+ 
+   guarantee(false, "failed to find oopmap for pc");
+   return -1;
+ }
+ 
  const ImmutableOopMap* ImmutableOopMapSet::find_map_at_offset(int pc_offset) const {
    ImmutableOopMapPair* pairs = get_pairs();
    ImmutableOopMapPair* last  = NULL;
  
    for (int i = 0; i < _count; ++i) {

*** 522,17 ***
    guarantee(last != NULL, "last may not be null");
    assert(last->pc_offset() == pc_offset, "oopmap not found");
    return last->get_from(this);
  }
  
! const ImmutableOopMap* ImmutableOopMapPair::get_from(const ImmutableOopMapSet* set) const {
!   return set->oopmap_at_offset(_oopmap_offset);
  }
  
! ImmutableOopMap::ImmutableOopMap(const OopMap* oopmap) : _count(oopmap->count()) {
!   address addr = data_addr();
!   oopmap->copy_data_to(addr);
  }
  
  #ifdef ASSERT
  int ImmutableOopMap::nr_of_bytes() const {
    OopMapStream oms(this);
--- 769,25 ---
    guarantee(last != NULL, "last may not be null");
    assert(last->pc_offset() == pc_offset, "oopmap not found");
    return last->get_from(this);
  }
  
! ImmutableOopMap::ImmutableOopMap(const OopMap* oopmap) 
!   : _count(oopmap->count()), _num_oops(oopmap->num_oops()) {
+   _num_oops = oopmap->num_oops();
+   _has_derived_oops = oopmap->has_derived_oops();
+   address addr = data_addr();
+   //oopmap->copy_data_to(addr);
+   oopmap->copy_and_sort_data_to(addr);
  }
  
! bool ImmutableOopMap::has_any(OopMapValue::oop_types type) const {
!   for (OopMapStream oms(this); !oms.is_done(); oms.next()) {
!     if (oms.current().type() == type)
+       return true;
+   }
+   return false;
  }
  
  #ifdef ASSERT
  int ImmutableOopMap::nr_of_bytes() const {
    OopMapStream oms(this);

*** 540,10 ***
--- 795,11 ---
    while (!oms.is_done()) {
      oms.next();
    }
    return sizeof(ImmutableOopMap) + oms.stream_position();
  }
+ 
  #endif
  
  ImmutableOopMapBuilder::ImmutableOopMapBuilder(const OopMapSet* set) : _set(set), _empty(NULL), _last(NULL), _empty_offset(-1), _last_offset(-1), _offset(0), _required(-1), _new_set(NULL) {
    _mapping = NEW_RESOURCE_ARRAY(Mapping, _set->size());
  }

*** 621,11 ***
      } else if (_mapping[i]._kind == Mapping::OOPMAP_DUPLICATE || _mapping[i]._kind == Mapping::OOPMAP_EMPTY) {
        fill_pair(&pairs[i], map, _mapping[i]._offset, set);
      }
  
      const ImmutableOopMap* nv = set->find_map_at_offset(map->offset());
!     assert(memcmp(map->data(), nv->data_addr(), map->data_size()) == 0, "check identity");
    }
  }
  
  #ifdef ASSERT
  void ImmutableOopMapBuilder::verify(address buffer, int size, const ImmutableOopMapSet* set) {
--- 877,11 ---
      } else if (_mapping[i]._kind == Mapping::OOPMAP_DUPLICATE || _mapping[i]._kind == Mapping::OOPMAP_EMPTY) {
        fill_pair(&pairs[i], map, _mapping[i]._offset, set);
      }
  
      const ImmutableOopMap* nv = set->find_map_at_offset(map->offset());
!     //assert(memcmp(map->data(), nv->data_addr(), map->data_size()) == 0, "check identity");
    }
  }
  
  #ifdef ASSERT
  void ImmutableOopMapBuilder::verify(address buffer, int size, const ImmutableOopMapSet* set) {
< prev index next >