--- old/agent/src/share/classes/sun/jvm/hotspot/HSDB.java 2015-04-29 16:51:16.650356829 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/HSDB.java 2015-04-29 16:51:16.578353741 +0200 @@ -27,9 +27,7 @@ import java.io.*; import java.awt.*; import java.awt.event.*; -import java.math.*; import javax.swing.*; -import javax.swing.tree.*; import java.util.*; import sun.jvm.hotspot.code.*; @@ -928,7 +926,7 @@ boolean shouldSkipOopMaps = false; if (curVFrame.isCompiledFrame()) { CodeBlob cb = VM.getVM().getCodeCache().findBlob(curFrame.getPC()); - OopMapSet maps = cb.getOopMaps(); + ImmutableOopMapSet maps = cb.getOopMaps(); if ((maps == null) || (maps.getSize() == 0)) { shouldSkipOopMaps = true; } @@ -977,7 +975,7 @@ } while (nextVFrame != null && nextFrame.equals(curFrame)); if (shouldSkipOopMaps) { - anno = anno + "\nNOTE: null or empty OopMapSet found for this CodeBlob"; + anno = anno + "\nNOTE: null or empty ImmutableOopMapSet found for this CodeBlob"; } if (curFrame.getFP() != null) { --- old/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java 2015-04-29 16:51:16.970370551 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java 2015-04-29 16:51:16.890367119 +0200 @@ -171,17 +171,17 @@ public boolean isLockedByVM() { return false; } /** OopMap for frame; can return null if none available */ - public OopMapSet getOopMaps() { + public ImmutableOopMapSet getOopMaps() { Address oopMapsAddr = oopMapsField.getValue(addr); if (oopMapsAddr == null) { return null; } - return new OopMapSet(oopMapsAddr); + return new ImmutableOopMapSet(oopMapsAddr); } // FIXME: not yet implementable - // void set_oop_maps(OopMapSet* p); + // void set_oop_maps(ImmutableOopMapSet* p); - public OopMap getOopMapForReturnAddress(Address returnAddress, boolean debugging) { + public ImmutableOopMap getOopMapForReturnAddress(Address returnAddress, boolean debugging) { Address pc = returnAddress; if (Assert.ASSERTS_ENABLED) { Assert.that(getOopMaps() != null, "nope"); --- old/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapStream.java 2015-04-29 16:51:17.326385816 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapStream.java 2015-04-29 16:51:17.234381871 +0200 @@ -28,30 +28,26 @@ public class OopMapStream { private CompressedReadStream stream; - private OopMap oopMap; + private ImmutableOopMap oopMap; private int mask; private int size; private int position; private OopMapValue omv; private boolean omvValid; - public OopMapStream(OopMap oopMap) { + public OopMapStream(ImmutableOopMap oopMap) { this(oopMap, (OopMapValue.OopTypes[]) null); } - public OopMapStream(OopMap oopMap, OopMapValue.OopTypes type) { + public OopMapStream(ImmutableOopMap oopMap, OopMapValue.OopTypes type) { this(oopMap, (OopMapValue.OopTypes[]) null); mask = type.getValue(); } - public OopMapStream(OopMap oopMap, OopMapValue.OopTypes[] types) { - if (oopMap.getOMVData() == null) { - stream = new CompressedReadStream(oopMap.getWriteStream().getBuffer()); - } else { - stream = new CompressedReadStream(oopMap.getOMVData()); - } + public OopMapStream(ImmutableOopMap oopMap, OopMapValue.OopTypes[] types) { + stream = new CompressedReadStream(oopMap.getData()); mask = computeMask(types); - size = (int) oopMap.getOMVCount(); + size = (int) oopMap.getCount(); position = 0; omv = new OopMapValue(); omvValid = false; --- old/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java 2015-04-29 16:51:17.686401255 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java 2015-04-29 16:51:17.594397310 +0200 @@ -26,14 +26,12 @@ import java.io.*; import java.util.*; -import sun.jvm.hotspot.*; + import sun.jvm.hotspot.code.*; import sun.jvm.hotspot.compiler.*; -import sun.jvm.hotspot.c1.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.interpreter.*; import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.runtime.sparc.SPARCFrame; import sun.jvm.hotspot.types.*; import sun.jvm.hotspot.utilities.*; @@ -626,7 +624,7 @@ Assert.that(cb != null, "sanity check"); } if (cb.getOopMaps() != null) { - OopMapSet.oopsDo(this, cb, regMap, oopVisitor, VM.getVM().isDebugging()); + ImmutableOopMapSet.oopsDo(this, cb, regMap, oopVisitor, VM.getVM().isDebugging()); // FIXME: add in traversal of argument oops (skipping this for // now until we have the other stuff tested) --- old/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java 2015-04-29 16:51:18.058417206 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java 2015-04-29 16:51:17.962413091 +0200 @@ -358,7 +358,7 @@ map.setIncludeArgumentOops(cb.callerMustGCArguments()); if (cb.getOopMaps() != null) { - OopMapSet.updateRegisterMap(this, cb, map, true); + ImmutableOopMapSet.updateRegisterMap(this, cb, map, true); } } --- old/agent/src/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCFrame.java 2015-04-29 16:51:18.414432473 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCFrame.java 2015-04-29 16:51:18.326428700 +0200 @@ -24,8 +24,6 @@ package sun.jvm.hotspot.runtime.sparc; -import java.util.*; - import sun.jvm.hotspot.asm.sparc.*; import sun.jvm.hotspot.code.*; import sun.jvm.hotspot.compiler.*; @@ -34,7 +32,6 @@ import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.runtime.posix.*; -import sun.jvm.hotspot.types.*; import sun.jvm.hotspot.utilities.*; /** Specialization of and implementation of abstract methods of the @@ -592,7 +589,7 @@ map.setIncludeArgumentOops(true); } if (cb.getOopMaps() != null) { - OopMapSet.updateRegisterMap(this, cb, map, VM.getVM().isDebugging()); + ImmutableOopMapSet.updateRegisterMap(this, cb, map, VM.getVM().isDebugging()); } } } --- old/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java 2015-04-29 16:51:18.790448597 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java 2015-04-29 16:51:18.694444481 +0200 @@ -394,7 +394,7 @@ map.setIncludeArgumentOops(cb.callerMustGCArguments()); if (cb.getOopMaps() != null) { - OopMapSet.updateRegisterMap(this, cb, map, true); + ImmutableOopMapSet.updateRegisterMap(this, cb, map, true); } // Since the prolog does the save and restore of EBP there is no oopmap --- old/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java 2015-04-29 16:51:19.150464036 +0200 +++ new/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java 2015-04-29 16:51:19.058460090 +0200 @@ -31,11 +31,9 @@ import sun.jvm.hotspot.compiler.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.interpreter.*; -import sun.jvm.hotspot.memory.*; import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.tools.jcore.*; -import sun.jvm.hotspot.types.*; import sun.jvm.hotspot.utilities.*; public class HTMLGenerator implements /* imports */ ClassConstants { @@ -887,7 +885,7 @@ private Formatter buf; private SymbolFinder symFinder = createSymbolFinder(); private long pc; - private OopMapSet oms; + private ImmutableOopMapSet oms; private CodeBlob blob; private NMethod nmethod; @@ -954,13 +952,13 @@ if (oms != null) { long base = addressToLong(blob.codeBegin()); - for (int i = 0, imax = (int)oms.getSize(); i < imax; i++) { - OopMap om = oms.getMapAt(i); - long omspc = base + om.getOffset(); + for (int i = 0, imax = oms.getCount(); i < imax; i++) { + ImmutableOopMapPair pair = oms.getPairAt(i); + long omspc = base + pair.getPC(); if (omspc > pc) { if (omspc <= endPc) { buf.br(); - buf.append(genOopMapInfo(om)); + buf.append(genOopMapInfo(oms.getMap(pair))); // st.move_to(column); // visitor.print("; "); // om.print_on(st); @@ -1167,7 +1165,7 @@ } } - protected String genHTMLForOopMap(OopMap map) { + protected String genHTMLForOopMap(ImmutableOopMap map) { final int stack0 = VMRegImpl.getStack0().getValue(); Formatter buf = new Formatter(genHTML); @@ -1237,11 +1235,11 @@ protected String genOopMapInfo(NMethod nmethod, PCDesc pcDesc) { - OopMapSet mapSet = nmethod.getOopMaps(); + ImmutableOopMapSet mapSet = nmethod.getOopMaps(); if (mapSet == null || (mapSet.getSize() <= 0)) return ""; int pcOffset = pcDesc.getPCOffset(); - OopMap map = mapSet.findMapAtOffset(pcOffset, VM.getVM().isDebugging()); + ImmutableOopMap map = mapSet.findMapAtOffset(pcOffset, VM.getVM().isDebugging()); if (map == null) { throw new IllegalArgumentException("no oopmap at safepoint!"); } @@ -1249,7 +1247,7 @@ return genOopMapInfo(map); } - protected String genOopMapInfo(OopMap map) { + protected String genOopMapInfo(ImmutableOopMap map) { Formatter buf = new Formatter(genHTML); buf.beginTag("pre"); buf.append("OopMap: "); --- old/src/share/vm/c1/c1_Runtime1.cpp 2015-04-29 16:51:19.542480845 +0200 +++ new/src/share/vm/c1/c1_Runtime1.cpp 2015-04-29 16:51:19.442476557 +0200 @@ -1018,7 +1018,7 @@ // NOTE we use pc() not original_pc() because we already know they are // identical otherwise we'd have never entered this block of code - OopMap* map = caller_code->oop_map_for_return_address(caller_frame.pc()); + const ImmutableOopMap* map = caller_code->oop_map_for_return_address(caller_frame.pc()); assert(map != NULL, "null check"); map->print(); tty->cr(); --- old/src/share/vm/code/codeBlob.cpp 2015-04-29 16:51:19.930497484 +0200 +++ new/src/share/vm/code/codeBlob.cpp 2015-04-29 16:51:19.838493538 +0200 @@ -129,9 +129,7 @@ // Danger Will Robinson! This method allocates a big // chunk of memory, its your job to free it. if (p != NULL) { - // We need to allocate a chunk big enough to hold the OopMapSet and all of its OopMaps - _oop_maps = (OopMapSet* )NEW_C_HEAP_ARRAY(unsigned char, p->heap_size(), mtCode); - p->copy_to((address)_oop_maps); + _oop_maps = ImmutableOopMapSet::build_from(p); } else { _oop_maps = NULL; } @@ -175,7 +173,7 @@ } -OopMap* CodeBlob::oop_map_for_return_address(address return_address) { +const ImmutableOopMap* CodeBlob::oop_map_for_return_address(address return_address) { assert(oop_maps() != NULL, "nope"); return oop_maps()->find_map_at_offset((intptr_t) return_address - (intptr_t) code_begin()); } --- old/src/share/vm/code/codeBlob.hpp 2015-04-29 16:51:20.302513436 +0200 +++ new/src/share/vm/code/codeBlob.hpp 2015-04-29 16:51:20.206509319 +0200 @@ -77,7 +77,7 @@ // which we don't detect. int _data_offset; // offset to where data region begins int _frame_size; // size of stack frame - OopMapSet* _oop_maps; // OopMap for this CodeBlob + ImmutableOopMapSet* _oop_maps; // OopMap for this CodeBlob CodeStrings _strings; public: @@ -171,9 +171,9 @@ virtual bool is_alive() const = 0; // OopMap for frame - OopMapSet* oop_maps() const { return _oop_maps; } + ImmutableOopMapSet* oop_maps() const { return _oop_maps; } void set_oop_maps(OopMapSet* p); - OopMap* oop_map_for_return_address(address return_address); + const ImmutableOopMap* oop_map_for_return_address(address return_address); virtual void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { ShouldNotReachHere(); } // Frame support --- old/src/share/vm/code/codeCache.cpp 2015-04-29 16:51:20.666529045 +0200 +++ new/src/share/vm/code/codeCache.cpp 2015-04-29 16:51:20.570524929 +0200 @@ -1371,10 +1371,10 @@ if (cb->is_alive()) { number_of_blobs++; code_size += cb->code_size(); - OopMapSet* set = cb->oop_maps(); + ImmutableOopMapSet* set = cb->oop_maps(); if (set != NULL) { - number_of_oop_maps += set->size(); - map_size += set->heap_size(); + number_of_oop_maps += set->count(); + map_size += set->size(); } } } --- old/src/share/vm/code/nmethod.cpp 2015-04-29 16:51:21.046545341 +0200 +++ new/src/share/vm/code/nmethod.cpp 2015-04-29 16:51:20.946541052 +0200 @@ -2987,11 +2987,12 @@ // We use the odd half-closed interval so that oop maps and scope descs // which are tied to the byte after a call are printed with the call itself. address base = code_begin(); - OopMapSet* oms = oop_maps(); + ImmutableOopMapSet* oms = oop_maps(); if (oms != NULL) { for (int i = 0, imax = oms->size(); i < imax; i++) { - OopMap* om = oms->at(i); - address pc = base + om->offset(); + const ImmutableOopMapPair* pair = oms->pair_at(i); + const ImmutableOopMap* om = pair->get_from(oms); + address pc = base + pair->pc_offset(); if (pc > begin) { if (pc <= end) { st->move_to(column); --- old/src/share/vm/compiler/oopMap.cpp 2015-04-29 16:51:21.450562666 +0200 +++ new/src/share/vm/compiler/oopMap.cpp 2015-04-29 16:51:21.354558549 +0200 @@ -42,27 +42,18 @@ // OopMapStream -OopMapStream::OopMapStream(OopMap* oop_map) { - if(oop_map->omv_data() == NULL) { - _stream = new CompressedReadStream(oop_map->write_stream()->buffer()); - } else { - _stream = new CompressedReadStream(oop_map->omv_data()); - } - _mask = OopMapValue::type_mask_in_place; +OopMapStream::OopMapStream(OopMap* oop_map, int oop_types_mask) { + _stream = new CompressedReadStream(oop_map->write_stream()->buffer()); + _mask = oop_types_mask; _size = oop_map->omv_count(); _position = 0; _valid_omv = false; } - -OopMapStream::OopMapStream(OopMap* oop_map, int oop_types_mask) { - if(oop_map->omv_data() == NULL) { - _stream = new CompressedReadStream(oop_map->write_stream()->buffer()); - } else { - _stream = new CompressedReadStream(oop_map->omv_data()); - } +OopMapStream::OopMapStream(const ImmutableOopMap* oop_map, int oop_types_mask) { + _stream = new CompressedReadStream(oop_map->data_addr()); _mask = oop_types_mask; - _size = oop_map->omv_count(); + _size = oop_map->count(); _position = 0; _valid_omv = false; } @@ -87,7 +78,6 @@ 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_data(NULL); set_omv_count(0); #ifdef ASSERT @@ -102,7 +92,6 @@ // This constructor does a deep copy // of the source OopMap. set_write_stream(new CompressedWriteStream(source->omv_count() * 2)); - set_omv_data(NULL); set_omv_count(0); set_offset(source->offset()); @@ -125,25 +114,14 @@ return new OopMap(_deep_copy_token, this); } - -void OopMap::copy_to(address addr) { - memcpy(addr,this,sizeof(OopMap)); - memcpy(addr + sizeof(OopMap),write_stream()->buffer(),write_stream()->position()); - OopMap* new_oop = (OopMap*)addr; - new_oop->set_omv_data_size(write_stream()->position()); - new_oop->set_omv_data((unsigned char *)(addr + sizeof(OopMap))); - new_oop->set_write_stream(NULL); +void OopMap::copy_data_to(address addr) const { + memcpy(addr, write_stream()->buffer(), write_stream()->position()); } - int OopMap::heap_size() const { int size = sizeof(OopMap); int align = sizeof(void *) - 1; - if(write_stream() != NULL) { - size += write_stream()->position(); - } else { - size += omv_data_size(); - } + size += write_stream()->position(); // Align to a reasonable ending point size = ((size+align) & ~align); return size; @@ -222,30 +200,6 @@ } -void OopMapSet::copy_to(address addr) { - address temp = addr; - int align = sizeof(void *) - 1; - // Copy this - memcpy(addr,this,sizeof(OopMapSet)); - temp += sizeof(OopMapSet); - temp = (address)((intptr_t)(temp + align) & ~align); - // Do the needed fixups to the new OopMapSet - OopMapSet* new_set = (OopMapSet*)addr; - new_set->set_om_data((OopMap**)temp); - // Allow enough space for the OopMap pointers - temp += (om_count() * sizeof(OopMap*)); - - for(int i=0; i < om_count(); i++) { - OopMap* map = at(i); - map->copy_to((address)temp); - new_set->set(i,(OopMap*)temp); - temp += map->heap_size(); - } - // This "locks" the OopMapSet - new_set->set_om_size(-1); -} - - void OopMapSet::add_gc_map(int pc_offset, OopMap *map ) { assert(om_size() != -1,"Cannot grow a fixed OopMapSet"); @@ -334,8 +288,8 @@ // Print oopmap and regmap tty->print_cr("------ "); CodeBlob* cb = fr->cb(); - OopMapSet* maps = cb->oop_maps(); - OopMap* map = cb->oop_map_for_return_address(fr->pc()); + 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; @@ -371,8 +325,8 @@ NOT_PRODUCT(if (TraceCodeBlobStacks) trace_codeblob_maps(fr, reg_map);) - OopMapSet* maps = cb->oop_maps(); - OopMap* map = cb->oop_map_for_return_address(fr->pc()); + ImmutableOopMapSet* maps = cb->oop_maps(); + 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 @@ -483,7 +437,7 @@ // (we do not do update in place, since info could be overwritten) address pc = fr->pc(); - OopMap* map = cb->oop_map_for_return_address(pc); + const ImmutableOopMap* map = cb->oop_map_for_return_address(pc); assert(map != NULL, "no ptr map found"); DEBUG_ONLY(int nof_callee = 0;) @@ -508,7 +462,7 @@ #ifndef PRODUCT -bool OopMap::has_derived_pointer() const { +bool ImmutableOopMap::has_derived_pointer() const { #ifndef TIERED COMPILER1_PRESENT(return false); #endif // !TIERED @@ -550,7 +504,6 @@ } } - void OopMapValue::print_on(outputStream* st) const { reg()->print_on(st); st->print("="); @@ -558,6 +511,15 @@ st->print(" "); } +void ImmutableOopMap::print_on(outputStream* st) const { + OopMapValue omv; + st->print("ImmutableOopMap{"); + for(OopMapStream oms(this); !oms.is_done(); oms.next()) { + omv = oms.current(); + omv.print_on(st); + } + st->print("}"); +} void OopMap::print_on(outputStream* st) const { OopMapValue omv; @@ -569,6 +531,20 @@ st->print("off=%d}", (int) offset()); } +void ImmutableOopMapSet::print_on(outputStream* st) const { + const ImmutableOopMap* last = NULL; + for (int i = 0; i < _count; ++i) { + const ImmutableOopMapPair* pair = pair_at(i); + const ImmutableOopMap* map = pair->get_from(this); + if (map != last) { + st->cr(); + map->print_on(st); + st->print("pc offsets: "); + } + last = map; + st->print("%d ", pair->pc_offset()); + } +} void OopMapSet::print_on(outputStream* st) const { int i, len = om_count(); @@ -583,6 +559,208 @@ } } +bool OopMap::equals(const OopMap* other) const { + if (other->_omv_count != _omv_count) { + return false; + } + if (other->write_stream()->position() != write_stream()->position()) { + return false; + } + if (memcmp(other->write_stream()->buffer(), write_stream()->buffer(), write_stream()->position()) != 0) { + return false; + } + return true; +} + +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) { + if (pairs[i].pc_offset() >= pc_offset) { + last = &pairs[i]; + break; + } + } + + 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); +} + +class ImmutableOopMapBuilder { +public: + /* Used for bookkeeping when building ImmutableOopMaps */ + class Mapping : public ResourceObj { + public: + enum kind_t { OOPMAP_UNKNOWN = 0, OOPMAP_NEW = 1, OOPMAP_EMPTY = 2, OOPMAP_DUPLICATE = 3 }; + + Mapping() : _kind(OOPMAP_UNKNOWN), _offset(-1), _size(-1), _map(NULL) {} + + void set(kind_t kind, int offset, int size, const OopMap* map = 0, const OopMap* other = 0) { + _kind = kind; + _offset = offset; + _size = size; + _map = map; + _other = other; + } + + kind_t _kind; + int _offset; + int _size; + const OopMap* _map; + const OopMap* _other; + }; + + ImmutableOopMapBuilder(const OopMapSet* set) : _set(set), _new_set(NULL), _empty(NULL), _last(NULL), _empty_offset(-1), _last_offset(-1), _offset(0) { + _mapping = NEW_RESOURCE_ARRAY(Mapping, _set->size()); + } + + int heap_size(); + ImmutableOopMapSet* build(); +private: + bool is_empty(const OopMap* map) const { + return map->count() == 0; + } + + bool is_last_duplicate(const OopMap* map) { + if (_last != NULL && _last->count() > 0 && _last->equals(map)) { + return true; + } + return false; + } + + void verify(address buffer, int size); + + bool has_empty() const { + return _empty_offset != -1; + } + + int size_for(const OopMap* map) const; + void fill_pair(ImmutableOopMapPair* pair, const OopMap* map, int offset); + int fill_map(ImmutableOopMapPair* pair, const OopMap* map, int offset); + void fill(ImmutableOopMapSet* set, int size); + + const OopMapSet* _set; + const OopMap* _empty; + const OopMap* _last; + int _empty_offset; + int _last_offset; + int _offset; + Mapping* _mapping; + ImmutableOopMapSet* _new_set; +}; + +int ImmutableOopMapBuilder::size_for(const OopMap* map) const { + return align_size_up(sizeof(ImmutableOopMap) + map->data_size(), 8); +} + +int ImmutableOopMapBuilder::heap_size() { + int base = sizeof(ImmutableOopMapSet); + base = align_size_up(base, 8); + + // all of ours pc / offset pairs + int pairs = _set->size() * sizeof(ImmutableOopMapPair); + pairs = align_size_up(pairs, 8); + + for (int i = 0; i < _set->size(); ++i) { + int size = 0; + OopMap* map = _set->at(i); + + if (is_empty(map)) { + /* only keep a single empty map in the set */ + if (has_empty()) { + _mapping[i].set(Mapping::OOPMAP_EMPTY, _empty_offset, 0, map, _empty); + } else { + _empty_offset = _offset; + _empty = map; + size = size_for(map); + _mapping[i].set(Mapping::OOPMAP_NEW, _offset, size, map); + } + } else if (is_last_duplicate(map)) { + /* if this entry is identical to the previous one, just point it there */ + _mapping[i].set(Mapping::OOPMAP_DUPLICATE, _last_offset, 0, map, _last); + } else { + /* not empty, not an identical copy of the previous entry */ + size = size_for(map); + _mapping[i].set(Mapping::OOPMAP_NEW, _offset, size, map); + _last_offset = _offset; + _last = map; + } + + assert(_mapping[i]._map == map, "check"); + _offset += size; + } + + int total = base + pairs + _offset; + DEBUG_ONLY(total += 8); + return total; +} + +void ImmutableOopMapBuilder::fill_pair(ImmutableOopMapPair* pair, const OopMap* map, int offset) { + new ((address) pair) ImmutableOopMapPair(map->offset(), offset); +} + +int ImmutableOopMapBuilder::fill_map(ImmutableOopMapPair* pair, const OopMap* map, int offset) { + fill_pair(pair, map, offset); + address addr = (address) pair->get_from(_new_set); // location of the ImmutableOopMap + + new (addr) ImmutableOopMap(map); + return align_size_up(sizeof(ImmutableOopMap) + map->data_size(), 8); +} + +void ImmutableOopMapBuilder::fill(ImmutableOopMapSet* set, int sz) { + ImmutableOopMapPair* pairs = set->get_pairs(); + + for (int i = 0; i < set->count(); ++i) { + const OopMap* map = _mapping[i]._map; + ImmutableOopMapPair* pair = NULL; + int size = 0; + + if (_mapping[i]._kind == Mapping::OOPMAP_NEW) { + size = fill_map(&pairs[i], map, _mapping[i]._offset); + } else if (_mapping[i]._kind == Mapping::OOPMAP_DUPLICATE || _mapping[i]._kind == Mapping::OOPMAP_EMPTY) { + fill_pair(&pairs[i], map, _mapping[i]._offset); + } + + const ImmutableOopMap* nv = set->find_map_at_offset(map->offset()); + assert(memcmp(map->data(), nv->data_addr(), map->data_size()) == 0, "check identity"); + } +} + +void ImmutableOopMapBuilder::verify(address buffer, int size) { + for (int i = 0; i < 8; ++i) { + assert(buffer[size - 8 + i] == (unsigned char) 0xff, "overwritten memory check"); + } +} + +ImmutableOopMapSet* ImmutableOopMapBuilder::build() { + int required = heap_size(); + + // We need to allocate a chunk big enough to hold the ImmutableOopMapSet and all of its ImmutableOopMaps + address buffer = (address) NEW_C_HEAP_ARRAY(unsigned char, required, mtCode); + DEBUG_ONLY(memset(&buffer[required-8], 0xff, 8)); + + _new_set = new (buffer) ImmutableOopMapSet(_set, required); + fill(_new_set, required); + + DEBUG_ONLY(verify(buffer, required)); + + return _new_set; +} + +ImmutableOopMapSet* ImmutableOopMapSet::build_from(const OopMapSet* oopmap_set) { + ImmutableOopMapBuilder builder(oopmap_set); + return builder.build(); +} //------------------------------DerivedPointerTable--------------------------- --- old/src/share/vm/compiler/oopMap.hpp 2015-04-29 16:51:21.822578617 +0200 +++ new/src/share/vm/compiler/oopMap.hpp 2015-04-29 16:51:21.726574502 +0200 @@ -143,19 +143,13 @@ friend class OopMapStream; friend class VMStructs; private: - int _pc_offset; - int _omv_count; - int _omv_data_size; - unsigned char* _omv_data; + int _pc_offset; // offset in the code that this OopMap corresponds to + int _omv_count; // number of OopMapValues in the stream CompressedWriteStream* _write_stream; debug_only( OopMapValue::oop_types* _locs_used; int _locs_length;) // Accessors - unsigned char* omv_data() const { return _omv_data; } - void set_omv_data(unsigned char* value) { _omv_data = value; } - int omv_data_size() const { return _omv_data_size; } - void set_omv_data_size(int value) { _omv_data_size = value; } int omv_count() const { return _omv_count; } void set_omv_count(int value) { _omv_count = value; } void increment_count() { _omv_count++; } @@ -172,6 +166,9 @@ // pc-offset handling int offset() const { return _pc_offset; } void set_offset(int o) { _pc_offset = o; } + int count() const { return _omv_count; } + int data_size() const { return write_stream()->position(); } + address data() const { return write_stream()->buffer(); } // Check to avoid double insertion debug_only(OopMapValue::oop_types locs_used( int indx ) { return _locs_used[indx]; }) @@ -188,11 +185,9 @@ void set_xxx(VMReg reg, OopMapValue::oop_types x, VMReg optional); int heap_size() const; - void copy_to(address addr); + void copy_data_to(address addr) const; OopMap* deep_copy(); - bool has_derived_pointer() const PRODUCT_RETURN0; - bool legal_vm_reg_name(VMReg local) { return OopMapValue::legal_vm_reg_name(local); } @@ -200,6 +195,7 @@ // Printing void print_on(outputStream* st) const; void print() const { print_on(tty); } + bool equals(const OopMap* other) const; }; @@ -239,7 +235,6 @@ OopMap* find_map_at_offset(int pc_offset) const; int heap_size() const; - void copy_to(address addr); // Methods oops_do() and all_do() filter out NULL oops and // oop == Universe::narrow_oop_base() before passing oops @@ -261,6 +256,79 @@ void print() const { print_on(tty); } }; +class ImmutableOopMapBuilder; + +class ImmutableOopMap { + friend class OopMapStream; + friend class VMStructs; +#ifdef ASSERT + friend class ImmutableOopMapBuilder; +#endif +private: + int _count; // contains the number of entries in this OopMap + + address data_addr() const { return (address) this + sizeof(ImmutableOopMap); } +public: + ImmutableOopMap(const OopMap* oopmap); + + bool has_derived_pointer() const PRODUCT_RETURN0; + int count() const { return _count; } + + // Printing + void print_on(outputStream* st) const; + void print() const { print_on(tty); } +}; + +class ImmutableOopMapSet; +class ImmutableOopMap; +class OopMapSet; + +class ImmutableOopMapPair { + friend class VMStructs; +private: + int _pc_offset; // program counter offset from the beginning of the method + int _oopmap_offset; // offset in the data in the ImmutableOopMapSet where the ImmutableOopMap is located +public: + ImmutableOopMapPair(int pc_offset, int oopmap_offset) : _pc_offset(pc_offset), _oopmap_offset(oopmap_offset) { + assert(pc_offset >= 0 && oopmap_offset >= 0, "check"); + } + const ImmutableOopMap* get_from(const ImmutableOopMapSet* set) const; + + int pc_offset() const { return _pc_offset; } + int oopmap_offset() const { return _oopmap_offset; } +}; + +class ImmutableOopMapSet { + friend class VMStructs; +private: + int _count; // nr of ImmutableOopMapPairs in the Set + int _size; // nr of bytes including ImmutableOopMapSet itself + + address data() const { return (address) this + sizeof(*this) + sizeof(ImmutableOopMapPair) * _count; } + +public: + ImmutableOopMapSet(const OopMapSet* oopmap_set, int size) : _count(oopmap_set->size()), _size(size) {} + + ImmutableOopMap* oopmap_at_offset(int offset) const { + assert(offset >= 0 && offset < _size, "must be within boundaries"); + address addr = data() + offset; + return (ImmutableOopMap*) addr; + } + + ImmutableOopMapPair* get_pairs() const { return (ImmutableOopMapPair*) ((address) this + sizeof(*this)); } + + static ImmutableOopMapSet* build_from(const OopMapSet* oopmap_set); + + const ImmutableOopMap* find_map_at_offset(int pc_offset) const; + + const ImmutableOopMapPair* pair_at(int index) const { assert(index >= 0 && index < _count, "check"); return &get_pairs()[index]; } + + int count() const { return _count; } + int size() const { return _size; } + + void print_on(outputStream* st) const; + void print() const { print_on(tty); } +}; class OopMapStream : public StackObj { private: @@ -273,8 +341,8 @@ void find_next(); public: - OopMapStream(OopMap* oop_map); - OopMapStream(OopMap* oop_map, int oop_types_mask); + OopMapStream(OopMap* oop_map, int oop_types_mask = OopMapValue::type_mask_in_place); + OopMapStream(const ImmutableOopMap* oop_map, int oop_types_mask = OopMapValue::type_mask_in_place); bool is_done() { if(!_valid_omv) { find_next(); } return !_valid_omv; } void next() { find_next(); } OopMapValue current() { return _omv; } --- old/src/share/vm/runtime/interfaceSupport.cpp 2015-04-29 16:51:22.190594399 +0200 +++ new/src/share/vm/runtime/interfaceSupport.cpp 2015-04-29 16:51:22.094590282 +0200 @@ -239,7 +239,7 @@ CodeBlob* cb = sfs.current()->cb(); if (cb != NULL && cb->oop_maps() ) { // Find oopmap for current method - OopMap* map = cb->oop_map_for_return_address(sfs.current()->pc()); + const ImmutableOopMap* map = cb->oop_map_for_return_address(sfs.current()->pc()); assert(map != NULL, "no oopmap found for pc"); found = map->has_derived_pointer(); } --- old/src/share/vm/runtime/vmStructs.cpp 2015-04-29 16:51:22.574610866 +0200 +++ new/src/share/vm/runtime/vmStructs.cpp 2015-04-29 16:51:22.466606234 +0200 @@ -862,7 +862,7 @@ nonstatic_field(CodeBlob, _frame_complete_offset, int) \ nonstatic_field(CodeBlob, _data_offset, int) \ nonstatic_field(CodeBlob, _frame_size, int) \ - nonstatic_field(CodeBlob, _oop_maps, OopMapSet*) \ + nonstatic_field(CodeBlob, _oop_maps, ImmutableOopMapSet*) \ \ nonstatic_field(RuntimeStub, _caller_must_gc_arguments, bool) \ \ @@ -968,13 +968,19 @@ \ nonstatic_field(OopMap, _pc_offset, int) \ nonstatic_field(OopMap, _omv_count, int) \ - nonstatic_field(OopMap, _omv_data_size, int) \ - nonstatic_field(OopMap, _omv_data, unsigned char*) \ nonstatic_field(OopMap, _write_stream, CompressedWriteStream*) \ nonstatic_field(OopMapSet, _om_count, int) \ nonstatic_field(OopMapSet, _om_size, int) \ nonstatic_field(OopMapSet, _om_data, OopMap**) \ \ + nonstatic_field(ImmutableOopMapSet, _count, int) \ + nonstatic_field(ImmutableOopMapSet, _size, int) \ + \ + nonstatic_field(ImmutableOopMapPair, _pc_offset, int) \ + nonstatic_field(ImmutableOopMapPair, _oopmap_offset, int) \ + \ + nonstatic_field(ImmutableOopMap, _count, int) \ + \ /*********************************/ \ /* JNIHandles and JNIHandleBlock */ \ /*********************************/ \ @@ -1692,6 +1698,9 @@ \ declare_toplevel_type(OopMap) \ declare_toplevel_type(OopMapSet) \ + declare_toplevel_type(ImmutableOopMapSet) \ + declare_toplevel_type(ImmutableOopMapPair) \ + declare_toplevel_type(ImmutableOopMap) \ \ /********************/ \ /* CompressedStream */ \ --- old/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMap.java 2015-04-29 16:51:22.990628706 +0200 +++ /dev/null 2015-03-20 09:32:23.917785769 +0100 @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -package sun.jvm.hotspot.compiler; - -import java.util.*; - -import sun.jvm.hotspot.code.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; - -public class OopMap extends VMObject { - private static CIntegerField pcOffsetField; - private static CIntegerField omvCountField; - private static CIntegerField omvDataSizeField; - private static AddressField omvDataField; - private static AddressField compressedWriteStreamField; - - // This is actually a field inside class CompressedStream - private static AddressField compressedStreamBufferField; - - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static void initialize(TypeDataBase db) { - Type type = db.lookupType("OopMap"); - - pcOffsetField = type.getCIntegerField("_pc_offset"); - omvCountField = type.getCIntegerField("_omv_count"); - omvDataSizeField = type.getCIntegerField("_omv_data_size"); - omvDataField = type.getAddressField("_omv_data"); - compressedWriteStreamField = type.getAddressField("_write_stream"); - - type = db.lookupType("CompressedStream"); - compressedStreamBufferField = type.getAddressField("_buffer"); - } - - public OopMap(Address addr) { - super(addr); - } - - public long getOffset() { - return pcOffsetField.getValue(addr); - } - - //-------------------------------------------------------------------------------- - // Internals only below this point - // - - // Accessors -- package private for now - Address getOMVData() { - return omvDataField.getValue(addr); - } - - long getOMVDataSize() { - return omvDataSizeField.getValue(addr); - } - - long getOMVCount() { - return omvCountField.getValue(addr); - } - - CompressedWriteStream getWriteStream() { - Address wsAddr = compressedWriteStreamField.getValue(addr); - if (wsAddr == null) { - return null; - } - Address bufferAddr = compressedStreamBufferField.getValue(wsAddr); - if (bufferAddr == null) { - return null; - } - return new CompressedWriteStream(bufferAddr); - } -} --- old/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapSet.java 2015-04-29 16:51:23.218638483 +0200 +++ /dev/null 2015-03-20 09:32:23.917785769 +0100 @@ -1,289 +0,0 @@ -/* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -package sun.jvm.hotspot.compiler; - -import java.util.*; - -import sun.jvm.hotspot.code.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.*; - -public class OopMapSet extends VMObject { - private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.compiler.OopMapSet.DEBUG") != null; - - private static CIntegerField omCountField; - private static CIntegerField omSizeField; - private static AddressField omDataField; - private static int REG_COUNT; - private static int SAVED_ON_ENTRY_REG_COUNT; - private static int C_SAVED_ON_ENTRY_REG_COUNT; - private static class MyVisitor implements OopMapVisitor { - private AddressVisitor addressVisitor; - - public MyVisitor(AddressVisitor oopVisitor) { - setAddressVisitor(oopVisitor); - } - - public void setAddressVisitor(AddressVisitor addressVisitor) { - this.addressVisitor = addressVisitor; - } - - public void visitOopLocation(Address oopAddr) { - addressVisitor.visitAddress(oopAddr); - } - - public void visitDerivedOopLocation(Address baseOopAddr, Address derivedOopAddr) { - if (VM.getVM().isClientCompiler()) { - Assert.that(false, "should not reach here"); - } else if (VM.getVM().isServerCompiler() && - VM.getVM().useDerivedPointerTable()) { - Assert.that(false, "FIXME: add derived pointer table"); - } - } - - public void visitValueLocation(Address valueAddr) { - } - - public void visitNarrowOopLocation(Address narrowOopAddr) { - addressVisitor.visitCompOopAddress(narrowOopAddr); - } - } - - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static void initialize(TypeDataBase db) { - Type type = db.lookupType("OopMapSet"); - - omCountField = type.getCIntegerField("_om_count"); - omSizeField = type.getCIntegerField("_om_size"); - omDataField = type.getAddressField("_om_data"); - - if (!VM.getVM().isCore()) { - REG_COUNT = db.lookupIntConstant("REG_COUNT").intValue(); - if (VM.getVM().isServerCompiler()) { - SAVED_ON_ENTRY_REG_COUNT = (int) db.lookupIntConstant("SAVED_ON_ENTRY_REG_COUNT").intValue(); - C_SAVED_ON_ENTRY_REG_COUNT = (int) db.lookupIntConstant("C_SAVED_ON_ENTRY_REG_COUNT").intValue(); - } - } - } - - public OopMapSet(Address addr) { - super(addr); - } - - /** Returns the number of OopMaps in this OopMapSet */ - public long getSize() { - return omCountField.getValue(addr); - } - - /** returns the OopMap at a given index */ - public OopMap getMapAt(int index) { - if (Assert.ASSERTS_ENABLED) { - Assert.that((index >= 0) && (index <= getSize()),"bad index"); - } - Address omDataAddr = omDataField.getValue(addr); - Address oopMapAddr = omDataAddr.getAddressAt(index * VM.getVM().getAddressSize()); - if (oopMapAddr == null) { - return null; - } - return new OopMap(oopMapAddr); - } - - public OopMap findMapAtOffset(long pcOffset, boolean debugging) { - int i; - int len = (int) getSize(); - if (Assert.ASSERTS_ENABLED) { - Assert.that(len > 0, "must have pointer maps"); - } - - // Scan through oopmaps. Stop when current offset is either equal or greater - // than the one we are looking for. - for (i = 0; i < len; i++) { - if (getMapAt(i).getOffset() >= pcOffset) { - break; - } - } - - if (!debugging) { - if (Assert.ASSERTS_ENABLED) { - Assert.that(i < len, "oopmap not found for pcOffset = " + pcOffset + "; len = " + len); - Assert.that(getMapAt(i).getOffset() == pcOffset, "oopmap not found"); - } - } else { - if (i == len) { - if (DEBUG) { - System.out.println("can't find oopmap at " + pcOffset); - System.out.print("Oopmap offsets are [ "); - for (i = 0; i < len; i++) { - System.out.print(getMapAt(i).getOffset()); - } - System.out.println("]"); - } - i = len - 1; - return getMapAt(i); - } - } - - OopMap m = getMapAt(i); - return m; - } - - /** Visitation -- iterates through the frame for a compiled method. - This is a very generic mechanism that requires the Address to be - dereferenced by the callee. Other, more specialized, visitation - mechanisms are given below. */ - public static void oopsDo(Frame fr, CodeBlob cb, RegisterMap regMap, AddressVisitor oopVisitor, boolean debugging) { - allDo(fr, cb, regMap, new MyVisitor(oopVisitor), debugging); - } - - /** Note that there are 4 required AddressVisitors: one for oops, - one for derived oops, one for values, and one for dead values */ - public static void allDo(Frame fr, CodeBlob cb, RegisterMap regMap, OopMapVisitor visitor, boolean debugging) { - if (Assert.ASSERTS_ENABLED) { - CodeBlob tmpCB = VM.getVM().getCodeCache().findBlob(fr.getPC()); - Assert.that(tmpCB != null && cb.equals(tmpCB), "wrong codeblob passed in"); - } - - OopMapSet maps = cb.getOopMaps(); - OopMap map = cb.getOopMapForReturnAddress(fr.getPC(), debugging); - if (Assert.ASSERTS_ENABLED) { - Assert.that(map != null, "no ptr map found"); - } - - // handle derived pointers first (otherwise base pointer may be - // changed before derived pointer offset has been collected) - OopMapValue omv; - { - for (OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.DERIVED_OOP_VALUE); !oms.isDone(); oms.next()) { - if (VM.getVM().isClientCompiler()) { - Assert.that(false, "should not reach here"); - } - omv = oms.getCurrent(); - Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap); - if (loc != null) { - Address baseLoc = fr.oopMapRegToLocation(omv.getContentReg(), regMap); - Address derivedLoc = loc; - visitor.visitDerivedOopLocation(baseLoc, derivedLoc); - } - } - } - - // We want narow oop, value and oop oop_types - OopMapValue.OopTypes[] values = new OopMapValue.OopTypes[] { - OopMapValue.OopTypes.OOP_VALUE, OopMapValue.OopTypes.VALUE_VALUE, OopMapValue.OopTypes.NARROWOOP_VALUE - }; - - { - for (OopMapStream oms = new OopMapStream(map, values); !oms.isDone(); oms.next()) { - omv = oms.getCurrent(); - Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap); - if (loc != null) { - if (omv.getType() == OopMapValue.OopTypes.OOP_VALUE) { - // This assert commented out because this will be useful - // to detect in the debugging system - // assert(Universe::is_heap_or_null(*loc), "found non oop pointer"); - visitor.visitOopLocation(loc); - } else if (omv.getType() == OopMapValue.OopTypes.VALUE_VALUE) { - visitor.visitValueLocation(loc); - } else if (omv.getType() == OopMapValue.OopTypes.NARROWOOP_VALUE) { - visitor.visitNarrowOopLocation(loc); - } - } - } - } - } - - /** Update callee-saved register info for the following frame. - Should only be called in non-core builds. */ - public static void updateRegisterMap(Frame fr, CodeBlob cb, RegisterMap regMap, boolean debugging) { - if (Assert.ASSERTS_ENABLED) { - Assert.that(!VM.getVM().isCore(), "non-core builds only"); - } - - if (!VM.getVM().isDebugging()) { - if (Assert.ASSERTS_ENABLED) { - OopMapSet maps = cb.getOopMaps(); - Assert.that((maps != null) && (maps.getSize() > 0), "found null or empty OopMapSet for CodeBlob"); - } - } else { - // Hack for some topmost frames that have been found with empty - // OopMapSets. (Actually have not seen the null case, but don't - // want to take any chances.) See HSDB.showThreadStackMemory(). - OopMapSet maps = cb.getOopMaps(); - if ((maps == null) || (maps.getSize() == 0)) { - return; - } - } - - // Check if caller must update oop argument - regMap.setIncludeArgumentOops(cb.callerMustGCArguments()); - - int nofCallee = 0; - Address[] locs = new Address[2 * REG_COUNT + 1]; - VMReg [] regs = new VMReg [2 * REG_COUNT + 1]; - // ("+1" because REG_COUNT might be zero) - - // Scan through oopmap and find location of all callee-saved registers - // (we do not do update in place, since info could be overwritten) - OopMap map = cb.getOopMapForReturnAddress(fr.getPC(), debugging); - if (Assert.ASSERTS_ENABLED) { - Assert.that(map != null, "no ptr map found"); - } - - OopMapValue omv = null; - for(OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE); !oms.isDone(); oms.next()) { - omv = oms.getCurrent(); - if (Assert.ASSERTS_ENABLED) { - Assert.that(nofCallee < 2 * REG_COUNT, "overflow"); - } - regs[nofCallee] = omv.getContentReg(); - locs[nofCallee] = fr.oopMapRegToLocation(omv.getReg(), regMap); - nofCallee++; - } - - // Check that runtime stubs save all callee-saved registers - // After adapter frames were deleted C2 doesn't use callee save registers at present - if (Assert.ASSERTS_ENABLED) { - if (VM.getVM().isServerCompiler()) { - Assert.that(!cb.isRuntimeStub() || - (nofCallee >= SAVED_ON_ENTRY_REG_COUNT || nofCallee >= C_SAVED_ON_ENTRY_REG_COUNT), - "must save all"); - } - } - - // Copy found callee-saved register to reg_map - for (int i = 0; i < nofCallee; i++) { - regMap.setLocation(regs[i], locs[i]); - } - } -} --- /dev/null 2015-03-20 09:32:23.917785769 +0100 +++ new/agent/src/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMap.java 2015-04-29 16:51:23.358644486 +0200 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.compiler; + +import java.util.*; + +import sun.jvm.hotspot.code.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; + +public class ImmutableOopMap extends VMObject { + private static CIntegerField countField; + private static long classSize; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static void initialize(TypeDataBase db) { + Type type = db.lookupType("ImmutableOopMap"); + countField = type.getCIntegerField("_count"); + classSize = type.getSize(); + } + + public ImmutableOopMap(Address addr) { + super(addr); + } + + //-------------------------------------------------------------------------------- + // Internals only below this point + // + + long getCount() { + return countField.getValue(addr); + } + + public Address getData() { + return addr.addOffsetTo(classSize); + } +} --- /dev/null 2015-03-20 09:32:23.917785769 +0100 +++ new/agent/src/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapPair.java 2015-04-29 16:51:23.682658381 +0200 @@ -0,0 +1,50 @@ +package sun.jvm.hotspot.compiler; + +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.runtime.VM; +import sun.jvm.hotspot.types.CIntegerField; +import sun.jvm.hotspot.types.Type; +import sun.jvm.hotspot.types.TypeDataBase; + +import java.util.Observable; +import java.util.Observer; + +public class ImmutableOopMapPair { + private static CIntegerField pcField; + private static CIntegerField offsetField; + private static long classSize; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private final Address address; + + public ImmutableOopMapPair(Address address) { + this.address = address; + } + + public static long classSize() { + return classSize; + } + + public int getPC() { + return (int) pcField.getValue(address); + } + + public int getOffset() { + return (int) offsetField.getValue(address); + } + + private static void initialize(TypeDataBase db) { + Type type = db.lookupType("ImmutableOopMapSet"); + + pcField = type.getCIntegerField("_pc_offset"); + offsetField = type.getCIntegerField("_oopmap_offset"); + classSize = type.getSize(); + } +} --- /dev/null 2015-03-20 09:32:23.917785769 +0100 +++ new/agent/src/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapSet.java 2015-04-29 16:51:24.002672103 +0200 @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.compiler; + +import java.util.*; + +import sun.jvm.hotspot.code.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.utilities.*; + +public class ImmutableOopMapSet extends VMObject { + private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.compiler.ImmutableOopMapSet.DEBUG") != null; + + private static CIntegerField countField; + private static CIntegerField sizeField; + private static AddressField omDataField; + private static int REG_COUNT; + private static int SAVED_ON_ENTRY_REG_COUNT; + private static int C_SAVED_ON_ENTRY_REG_COUNT; + private static long classSize; + + private static class MyVisitor implements OopMapVisitor { + private AddressVisitor addressVisitor; + + public MyVisitor(AddressVisitor oopVisitor) { + setAddressVisitor(oopVisitor); + } + + public void setAddressVisitor(AddressVisitor addressVisitor) { + this.addressVisitor = addressVisitor; + } + + public void visitOopLocation(Address oopAddr) { + addressVisitor.visitAddress(oopAddr); + } + + public void visitDerivedOopLocation(Address baseOopAddr, Address derivedOopAddr) { + if (VM.getVM().isClientCompiler()) { + Assert.that(false, "should not reach here"); + } else if (VM.getVM().isServerCompiler() && + VM.getVM().useDerivedPointerTable()) { + Assert.that(false, "FIXME: add derived pointer table"); + } + } + + public void visitValueLocation(Address valueAddr) { + } + + public void visitNarrowOopLocation(Address narrowOopAddr) { + addressVisitor.visitCompOopAddress(narrowOopAddr); + } + } + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static void initialize(TypeDataBase db) { + Type type = db.lookupType("ImmutableOopMapSet"); + + countField = type.getCIntegerField("_count"); + sizeField = type.getCIntegerField("_size"); + classSize = type.getSize(); + + if (!VM.getVM().isCore()) { + REG_COUNT = db.lookupIntConstant("REG_COUNT").intValue(); + if (VM.getVM().isServerCompiler()) { + SAVED_ON_ENTRY_REG_COUNT = (int) db.lookupIntConstant("SAVED_ON_ENTRY_REG_COUNT").intValue(); + C_SAVED_ON_ENTRY_REG_COUNT = (int) db.lookupIntConstant("C_SAVED_ON_ENTRY_REG_COUNT").intValue(); + } + } + } + + public ImmutableOopMapSet(Address addr) { + super(addr); + } + + /** + * Returns the number of OopMaps in this ImmutableOopMapSet + */ + public long getSize() { + return countField.getValue(addr); + } + + public int getCount() { return (int) countField.getValue(addr); } + + private Address dataStart() { + return (addr.addOffsetTo(ImmutableOopMapSet.classSize * getCount())); + } + + public ImmutableOopMapPair pairAt(int index) { + Assert.that((index >= 0) && (index < getCount()), "bad index"); + return new ImmutableOopMapPair(addr.addOffsetTo(index * ImmutableOopMapPair.classSize())); + } + + /** + * returns the OopMap at a given index + */ + public ImmutableOopMap getMapAt(int index) { + if (Assert.ASSERTS_ENABLED) { + Assert.that((index >= 0) && (index <= getSize()), "bad index"); + } + + ImmutableOopMapPair immutableOopMapPair = pairAt(index); + return getMap(immutableOopMapPair); + } + + public ImmutableOopMap findMapAtOffset(long pcOffset, boolean debugging) { + int i; + int len = (int) getSize(); + if (Assert.ASSERTS_ENABLED) { + Assert.that(len > 0, "must have pointer maps"); + } + + // Scan through oopmaps. Stop when current offset is either equal or greater + // than the one we are looking for. + for (i = 0; i < len; i++) { + if (pairAt(i).getPC() >= pcOffset) { + break; + } + } + + if (!debugging) { + if (Assert.ASSERTS_ENABLED) { + Assert.that(i < len, "oopmap not found for pcOffset = " + pcOffset + "; len = " + len); + Assert.that(pairAt(i).getPC() == pcOffset, "oopmap not found"); + } + } else { + if (i == len) { + if (DEBUG) { + System.out.println("can't find oopmap at " + pcOffset); + System.out.print("Oopmap offsets are [ "); + for (i = 0; i < len; i++) { + System.out.print(pairAt(i).getPC()); + } + System.out.println("]"); + } + i = len - 1; + return getMapAt(i); + } + } + + ImmutableOopMap m = getMapAt(i); + return m; + } + + /** + * Visitation -- iterates through the frame for a compiled method. + * This is a very generic mechanism that requires the Address to be + * dereferenced by the callee. Other, more specialized, visitation + * mechanisms are given below. + */ + public static void oopsDo(Frame fr, CodeBlob cb, RegisterMap regMap, AddressVisitor oopVisitor, boolean debugging) { + allDo(fr, cb, regMap, new MyVisitor(oopVisitor), debugging); + } + + /** + * Note that there are 4 required AddressVisitors: one for oops, + * one for derived oops, one for values, and one for dead values + */ + public static void allDo(Frame fr, CodeBlob cb, RegisterMap regMap, OopMapVisitor visitor, boolean debugging) { + if (Assert.ASSERTS_ENABLED) { + CodeBlob tmpCB = VM.getVM().getCodeCache().findBlob(fr.getPC()); + Assert.that(tmpCB != null && cb.equals(tmpCB), "wrong codeblob passed in"); + } + + ImmutableOopMapSet maps = cb.getOopMaps(); + ImmutableOopMap map = cb.getOopMapForReturnAddress(fr.getPC(), debugging); + if (Assert.ASSERTS_ENABLED) { + Assert.that(map != null, "no ptr map found"); + } + + // handle derived pointers first (otherwise base pointer may be + // changed before derived pointer offset has been collected) + OopMapValue omv; + { + for (OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.DERIVED_OOP_VALUE); !oms.isDone(); oms.next()) { + if (VM.getVM().isClientCompiler()) { + Assert.that(false, "should not reach here"); + } + omv = oms.getCurrent(); + Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap); + if (loc != null) { + Address baseLoc = fr.oopMapRegToLocation(omv.getContentReg(), regMap); + Address derivedLoc = loc; + visitor.visitDerivedOopLocation(baseLoc, derivedLoc); + } + } + } + + // We want narow oop, value and oop oop_types + OopMapValue.OopTypes[] values = new OopMapValue.OopTypes[]{ + OopMapValue.OopTypes.OOP_VALUE, OopMapValue.OopTypes.VALUE_VALUE, OopMapValue.OopTypes.NARROWOOP_VALUE + }; + + { + for (OopMapStream oms = new OopMapStream(map, values); !oms.isDone(); oms.next()) { + omv = oms.getCurrent(); + Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap); + if (loc != null) { + if (omv.getType() == OopMapValue.OopTypes.OOP_VALUE) { + // This assert commented out because this will be useful + // to detect in the debugging system + // assert(Universe::is_heap_or_null(*loc), "found non oop pointer"); + visitor.visitOopLocation(loc); + } else if (omv.getType() == OopMapValue.OopTypes.VALUE_VALUE) { + visitor.visitValueLocation(loc); + } else if (omv.getType() == OopMapValue.OopTypes.NARROWOOP_VALUE) { + visitor.visitNarrowOopLocation(loc); + } + } + } + } + } + + /** + * Update callee-saved register info for the following frame. + * Should only be called in non-core builds. + */ + public static void updateRegisterMap(Frame fr, CodeBlob cb, RegisterMap regMap, boolean debugging) { + if (Assert.ASSERTS_ENABLED) { + Assert.that(!VM.getVM().isCore(), "non-core builds only"); + } + + if (!VM.getVM().isDebugging()) { + if (Assert.ASSERTS_ENABLED) { + ImmutableOopMapSet maps = cb.getOopMaps(); + Assert.that((maps != null) && (maps.getSize() > 0), "found null or empty ImmutableOopMapSet for CodeBlob"); + } + } else { + // Hack for some topmost frames that have been found with empty + // OopMapSets. (Actually have not seen the null case, but don't + // want to take any chances.) See HSDB.showThreadStackMemory(). + ImmutableOopMapSet maps = cb.getOopMaps(); + if ((maps == null) || (maps.getSize() == 0)) { + return; + } + } + + // Check if caller must update oop argument + regMap.setIncludeArgumentOops(cb.callerMustGCArguments()); + + int nofCallee = 0; + Address[] locs = new Address[2 * REG_COUNT + 1]; + VMReg[] regs = new VMReg[2 * REG_COUNT + 1]; + // ("+1" because REG_COUNT might be zero) + + // Scan through oopmap and find location of all callee-saved registers + // (we do not do update in place, since info could be overwritten) + ImmutableOopMap map = cb.getOopMapForReturnAddress(fr.getPC(), debugging); + if (Assert.ASSERTS_ENABLED) { + Assert.that(map != null, "no ptr map found"); + } + + OopMapValue omv = null; + for (OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE); !oms.isDone(); oms.next()) { + omv = oms.getCurrent(); + if (Assert.ASSERTS_ENABLED) { + Assert.that(nofCallee < 2 * REG_COUNT, "overflow"); + } + regs[nofCallee] = omv.getContentReg(); + locs[nofCallee] = fr.oopMapRegToLocation(omv.getReg(), regMap); + nofCallee++; + } + + // Check that runtime stubs save all callee-saved registers + // After adapter frames were deleted C2 doesn't use callee save registers at present + if (Assert.ASSERTS_ENABLED) { + if (VM.getVM().isServerCompiler()) { + Assert.that(!cb.isRuntimeStub() || + (nofCallee >= SAVED_ON_ENTRY_REG_COUNT || nofCallee >= C_SAVED_ON_ENTRY_REG_COUNT), + "must save all"); + } + } + + // Copy found callee-saved register to reg_map + for (int i = 0; i < nofCallee; i++) { + regMap.setLocation(regs[i], locs[i]); + } + } + + public ImmutableOopMapPair getPairAt(int index) { + return pairAt(index); + } + + public ImmutableOopMap getMap(ImmutableOopMapPair pair) { + Assert.that(pair.getOffset() < (int) sizeField.getValue(), "boundary check"); + return new ImmutableOopMap(dataStart().addOffsetTo(pair.getOffset())); + } +}