< prev index next >

src/hotspot/share/compiler/oopMap.cpp

Print this page

        

@@ -26,16 +26,20 @@
 #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 "compiler/oopMapStubGenerator.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 "memory/universe.hpp"
 #include "oops/compressedOops.hpp"
+#include "runtime/atomic.hpp"
 #include "runtime/frame.inline.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/signature.hpp"
 #include "utilities/align.hpp"
 #include "utilities/lockFreeStack.hpp"

@@ -46,29 +50,31 @@
 #include "opto/optoreg.hpp"
 #endif
 
 // OopMapStream
 
-OopMapStream::OopMapStream(OopMap* oop_map, int oop_types_mask) {
-  _stream = new CompressedReadStream(oop_map->write_stream()->buffer());
+OopMapStream::OopMapStream(const OopMap* oop_map, int oop_types_mask)
+  : _stream(oop_map->write_stream()->buffer()) {
+  // _stream = new CompressedReadStream();
   _mask = oop_types_mask;
   _size = oop_map->omv_count();
   _position = 0;
   _valid_omv = false;
 }
 
-OopMapStream::OopMapStream(const ImmutableOopMap* oop_map, int oop_types_mask) {
-  _stream = new CompressedReadStream(oop_map->data_addr());
+OopMapStream::OopMapStream(const ImmutableOopMap* oop_map, int oop_types_mask)
+  : _stream(oop_map->data_addr()) {
+  // _stream = new CompressedReadStream(oop_map->data_addr());
   _mask = oop_types_mask;
   _size = oop_map->count();
   _position = 0;
   _valid_omv = false;
 }
 
 void OopMapStream::find_next() {
   while(_position++ < _size) {
-    _omv.read_from(_stream);
+    _omv.read_from(&_stream);
     if(((int)_omv.type() & _mask) > 0) {
       _valid_omv = true;
       return;
     }
   }

@@ -82,10 +88,12 @@
 // 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;
+  _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;

@@ -97,10 +105,12 @@
   // 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();
+  _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;

@@ -121,10 +131,166 @@
 
 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, OopMapValue::callee_saved_value); !oms.is_done(); oms.next()) {
+    insert(oms.current(), _count);
+  }
+
+  int start = _count;
+  for (OopMapStream oms(_map, OopMapValue::oop_value | OopMapValue::narrowoop_value); !oms.is_done(); oms.next()) {
+    OopMapValue omv = oms.current();
+    int pos = find_position(omv, start);
+    insert(omv, pos);
+  }
+
+  for (OopMapStream oms(_map, OopMapValue::derived_oop_value); !oms.is_done(); oms.next()) {
+    OopMapValue omv = oms.current();
+    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 (%ld)", omv.type() == OopMapValue::narrowoop_value ? 'n' : 'o', i, omv.reg()->value());
+      } else {
+        tty->print_cr("[%c][%d] -> stack (%lx)", 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 (%ld) stack (%lx)", i, omv.content_reg()->value(), omv.reg()->reg2stack() * VMRegImpl::stack_slot_size);
+      } else if (omv.reg()->is_reg()) {
+        tty->print_cr("[d][%d] -> stack (%lx) reg (%ld)", 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

@@ -150,20 +316,23 @@
     o.set_content_reg(optional);
   }
 
   o.write_on(write_stream());
   increment_count();
+  if (x == OopMapValue::oop_value || x == OopMapValue::narrowoop_value)
+    increment_num_oops();
 }
 
 
 void OopMap::set_oop(VMReg reg) {
   set_xxx(reg, OopMapValue::oop_value, VMRegImpl::Bad());
 }
 
 
 void OopMap::set_value(VMReg reg) {
   // At this time, we don't need value entries in our OopMap.
+  // set_xxx(reg, OopMapValue::live_value, VMRegImpl::Bad());
 }
 
 
 void OopMap::set_narrowoop(VMReg reg) {
   set_xxx(reg, OopMapValue::narrowoop_value, VMRegImpl::Bad());

@@ -200,11 +369,11 @@
   memcpy(new_data,om_data(),om_size() * sizeof(OopMap*));
   set_om_size(new_size);
   set_om_data(new_data);
 }
 
-void OopMapSet::add_gc_map(int pc_offset, OopMap *map ) {
+int OopMapSet::add_gc_map(int pc_offset, OopMap *map ) {
   assert(om_size() != -1,"Cannot grow a fixed OopMapSet");
 
   if(om_count() >= om_size()) {
     grow_om_data();
   }

@@ -221,12 +390,15 @@
                       om_count(),last->offset(),om_count()+1,map->offset());
     }
   }
 #endif // ASSERT
 
-  set(om_count(),map);
+  int index = om_count();
+  set(index,map);
+  map->_index = index;
   increment_count();
+  return index;
 }
 
 
 int OopMapSet::heap_size() const {
   // The space we use

@@ -266,194 +438,211 @@
   OopMap* m = at(i);
   assert( m->offset() == pc_offset, "oopmap not found" );
   return m;
 }
 
-static void add_derived_oop(oop* base, oop* derived) {
+class AddDerivedOop : public DerivedOopClosure {
+public:
+  enum { SkipNull = true, NeedsLock = true };
+  virtual void do_derived_oop(oop* base, oop* derived) {
 #if !defined(TIERED) && !INCLUDE_JVMCI
-  COMPILER1_PRESENT(ShouldNotReachHere();)
+    COMPILER1_PRESENT(ShouldNotReachHere();)
 #endif // !defined(TIERED) && !INCLUDE_JVMCI
 #if COMPILER2_OR_JVMCI
-  DerivedPointerTable::add(derived, base);
+      DerivedPointerTable::add(derived, base);
 #endif // COMPILER2_OR_JVMCI
-}
-
-
-#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("------ ");
+};
 
+void OopMapSet::oops_do(const frame *fr, const RegisterMap* reg_map, OopClosure* f, DerivedOopClosure* df) {
+  // add_derived_oop: add derived oops to a table
+  find_map(fr)->oops_do(fr, reg_map, f, df);
+  // all_do(fr, reg_map, f, df != NULL ? df : &add_derived_oop, &do_nothing_cl);
+}
+
+// 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);
+// }
+
+ExplodedOopMap::ExplodedOopMap(const ImmutableOopMap* oopMap) {
+  _oopValues = copyOopMapValues(oopMap, OopMapValue::oop_value | OopMapValue::narrowoop_value, &_nrOopValues);
+  _calleeSavedValues = copyOopMapValues(oopMap, OopMapValue::callee_saved_value, &_nrCalleeSavedValuesCount);
+  _derivedValues = copyOopMapValues(oopMap, OopMapValue::derived_oop_value, &_nrDerivedValues);
+}
+
+OopMapValue* ExplodedOopMap::values(int mask) {
+  if (mask == (OopMapValue::oop_value | OopMapValue::narrowoop_value)) {
+    return _oopValues;
+  } else if (mask == OopMapValue::callee_saved_value) {
+    return _calleeSavedValues;
+  } else if (mask == OopMapValue::derived_oop_value) {
+    return _derivedValues;
+  } else {
+    guarantee(false, "new type?");
+    return NULL;
+  }
 }
-#endif // PRODUCT
 
-void OopMapSet::oops_do(const frame *fr, const RegisterMap* reg_map, OopClosure* f) {
-  // add derived oops to a table
-  all_do(fr, reg_map, f, add_derived_oop, &do_nothing_cl);
+int ExplodedOopMap::count(int mask) {
+  if (mask == (OopMapValue::oop_value | OopMapValue::narrowoop_value)) {
+    return _nrOopValues;
+  } else if (mask == OopMapValue::callee_saved_value) {
+    return _nrCalleeSavedValuesCount;
+  } else if (mask == OopMapValue::derived_oop_value) {
+    return _nrDerivedValues;
+  } else {
+    guarantee(false, "new type?");
+    return 0;
+  }
 }
 
+OopMapValue* ExplodedOopMap::copyOopMapValues(const ImmutableOopMap* oopMap, int mask, int* nr) {
+  OopMapValue omv;
+  int count = 0;
+  // We want coop and oop oop_types
+  for (OopMapStream oms(oopMap,mask); !oms.is_done(); oms.next()) {
+    ++count;
+  }
+  *nr = count;
 
-void OopMapSet::all_do(const frame *fr, const RegisterMap *reg_map,
-                       OopClosure* oop_fn, void derived_oop_fn(oop*, oop*),
-                       OopClosure* value_fn) {
-  CodeBlob* cb = fr->cb();
-  assert(cb != NULL, "no codeblob");
+  OopMapValue* values = (OopMapValue*) NEW_C_HEAP_ARRAY(unsigned char, sizeof(OopMapValue) * count, mtCode);
 
-  NOT_PRODUCT(if (TraceCodeBlobStacks) trace_codeblob_maps(fr, reg_map);)
+  int i = 0;
+  for (OopMapStream oms(oopMap,mask); !oms.is_done(); oms.next()) {
+    assert(i < count, "overflow");
+    values[i] = oms.current();
+    i++;
+  }
 
-  const ImmutableOopMapSet* maps = cb->oop_maps();
-  const ImmutableOopMap* map = cb->oop_map_for_return_address(fr->pc());
-  assert(map != NULL, "no ptr map found");
+  i = 0;
+  for (OopMapStream oms(oopMap,mask); !oms.is_done(); oms.next()) {
+    assert(i < count, "overflow");
+    assert(values[i].equals(oms.current()), "must");
+    i++;
+  }
 
-  // handle derived pointers first (otherwise base pointer may be
-  // changed before derived pointer offset has been collected)
-  OopMapValue omv;
-  {
-    OopMapStream oms(map,OopMapValue::derived_oop_value);
-    if (!oms.is_done()) {
-#ifndef TIERED
-      COMPILER1_PRESENT(ShouldNotReachHere();)
-#if INCLUDE_JVMCI
-      if (UseJVMCICompiler) {
-        ShouldNotReachHere();
+  return values;
+}
+
+// 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 */
+  if (_freeze_stub == NULL) {
+    OopMapStubGenerator cgen(cb, *this);
+    if (Atomic::cmpxchg((address) this, &_freeze_stub, (address) NULL) == NULL) {
+      if (!cgen.generate()) {
+        Atomic::store((address) this, &_thaw_stub);
+        cgen.free();
+        return;
       }
-#endif
-#endif // !TIERED
-      do {
-        omv = oms.current();
-        oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map);
-        guarantee(loc != NULL, "missing saved register");
-        oop *derived_loc = loc;
-        oop *base_loc    = fr->oopmapreg_to_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);
-        }
-        oms.next();
-      }  while (!oms.is_done());
+
+      Atomic::store(cgen.freeze_stub(), &_freeze_stub);
+      Atomic::store(cgen.thaw_stub(), &_thaw_stub);
     }
   }
+}
 
-  // We want coop and oop oop_types
-  int mask = OopMapValue::oop_value | OopMapValue::narrowoop_value;
-  {
-    for (OopMapStream oms(map,mask); !oms.is_done(); oms.next()) {
+void ImmutableOopMap::oops_do(const frame *fr, const RegisterMap *reg_map,
+                              OopClosure* oop_fn, DerivedOopClosure* derived_oop_fn) const {
+  AddDerivedOop add_derived_oop;
+  if (derived_oop_fn == NULL) {
+    derived_oop_fn = &add_derived_oop;
+  }
+  OopMapDo<OopClosure, DerivedOopClosure, SkipNullValue> visitor(oop_fn, derived_oop_fn);
+  visitor.oops_do(fr, reg_map, this);
+}
+
+template<typename T>
+static void iterate_all_do(const frame *fr, int mask, OopMapClosure* fn, const ImmutableOopMap* oopmap) {
+  OopMapValue omv;
+  for (T oms(oopmap,mask); !oms.is_done(); oms.next()) {
       omv = oms.current();
-      oop* loc = fr->oopmapreg_to_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;
-        }
-#ifdef ASSERT
-        if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) ||
-            !Universe::heap()->is_in_or_null(*loc)) {
-          tty->print_cr("# Found non oop pointer.  Dumping state at failure");
-          // try to dump out some helpful debugging information
-          trace_codeblob_maps(fr, reg_map);
-          omv.print();
-          tty->print_cr("register r");
-          omv.reg()->print();
-          tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc);
-          // do the real assert.
-          assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer");
-        }
-#endif // ASSERT
-        oop_fn->do_oop(loc);
-      } else if ( omv.type() == OopMapValue::narrowoop_value ) {
-        narrowOop *nl = (narrowOop*)loc;
-#ifndef VM_LITTLE_ENDIAN
-        VMReg vmReg = omv.reg();
-        // Don't do this on SPARC float registers as they can be individually addressed
-        if (!vmReg->is_stack() SPARC_ONLY(&& !vmReg->is_FloatRegister())) {
-          // 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);
-      }
-    }
+      fn->do_value(omv.reg(), omv.type());
   }
 }
 
+void ImmutableOopMap::all_do(const frame *fr, int mask, OopMapClosure* fn) const {
+  if (_exploded != NULL) {
+    iterate_all_do<ExplodedOopMapStream>(fr, mask, fn, this);
+  } else {
+    iterate_all_do<OopMapStream>(fr, mask, fn, this);
+  }
+}
 
-// Update callee-saved register info for the following frame
-void OopMapSet::update_register_map(const frame *fr, RegisterMap *reg_map) {
-  ResourceMark rm;
+template <typename T>
+static void update_register_map1(const ImmutableOopMap* oopmap, const frame* fr, RegisterMap* reg_map) {
+  for (T oms(oopmap, OopMapValue::callee_saved_value); !oms.is_done(); oms.next()) {
+    OopMapValue omv = oms.current();
+    VMReg reg = omv.content_reg();
+    oop* loc = fr->oopmapreg_to_location(omv.reg(), reg_map);
+    reg_map->set_location(reg, (address) loc);
+    //DEBUG_ONLY(nof_callee++;)
+  }
+}
+
+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)
 
-  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;)
+  if (_exploded != NULL) {
+    update_register_map1<ExplodedOopMapStream>(this, fr, reg_map);
+  } else {
+    update_register_map1<OopMapStream>(this, fr, reg_map);
+  }
 
-  for (OopMapStream oms(map, OopMapValue::callee_saved_value); !oms.is_done(); oms.next()) {
+  /*
+  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_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() ||
+  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
 

@@ -467,10 +656,41 @@
 #else
   return false;
 #endif // COMPILER2_OR_JVMCI
 }
 
+#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
+
+
 #endif //PRODUCT
 
 // Printing code is present in product build for -XX:+PrintAssembly.
 
 static

@@ -579,10 +799,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) {

@@ -596,17 +831,15 @@
   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()) {
+ImmutableOopMap::ImmutableOopMap(const OopMap* oopmap) : _exploded(NULL), _freeze_stub(NULL), _thaw_stub(NULL), _count(oopmap->count()), _num_oops(oopmap->num_oops()) {
+  _num_oops = oopmap->num_oops();
   address addr = data_addr();
-  oopmap->copy_data_to(addr);
+  //oopmap->copy_data_to(addr);
+  oopmap->copy_and_sort_data_to(addr);
 }
 
 #ifdef ASSERT
 int ImmutableOopMap::nr_of_bytes() const {
   OopMapStream oms(this);

@@ -695,11 +928,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");
+    //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) {

@@ -793,11 +1026,11 @@
 
 void DerivedPointerTable::add(oop *derived_loc, oop *base_loc) {
   assert(Universe::heap()->is_in_or_null(*base_loc), "not an oop");
   assert(derived_loc != base_loc, "Base and derived in same location");
   if (_active) {
-    assert(*derived_loc != (void*)base_loc, "location already added");
+    assert(*derived_loc != (oop)base_loc, "location already added");
     assert(Entry::_list != NULL, "list must exist");
     intptr_t offset = value_of_loc(derived_loc) - value_of_loc(base_loc);
     // This assert is invalid because derived pointers can be
     // arbitrarily far away from their base.
     // assert(offset >= -1000000, "wrong derived pointer info");
< prev index next >