0N/A/*
1879N/A * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
1472N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1472N/A * or visit www.oracle.com if you need additional information or have any
1472N/A * questions.
0N/A *
0N/A */
0N/A
1879N/A#include "precompiled.hpp"
1879N/A#include "code/codeBlob.hpp"
1879N/A#include "code/codeCache.hpp"
1879N/A#include "code/nmethod.hpp"
1879N/A#include "code/scopeDesc.hpp"
1879N/A#include "compiler/oopMap.hpp"
1879N/A#include "gc_interface/collectedHeap.hpp"
1879N/A#include "memory/allocation.inline.hpp"
1879N/A#include "memory/resourceArea.hpp"
1879N/A#include "runtime/frame.inline.hpp"
1879N/A#include "runtime/signature.hpp"
1879N/A#ifdef COMPILER1
1879N/A#include "c1/c1_Defs.hpp"
1879N/A#endif
0N/A
0N/A// OopMapStream
0N/A
0N/AOopMapStream::OopMapStream(OopMap* oop_map) {
0N/A if(oop_map->omv_data() == NULL) {
0N/A _stream = new CompressedReadStream(oop_map->write_stream()->buffer());
0N/A } else {
0N/A _stream = new CompressedReadStream(oop_map->omv_data());
0N/A }
0N/A _mask = OopMapValue::type_mask_in_place;
0N/A _size = oop_map->omv_count();
0N/A _position = 0;
0N/A _valid_omv = false;
0N/A}
0N/A
0N/A
0N/AOopMapStream::OopMapStream(OopMap* oop_map, int oop_types_mask) {
0N/A if(oop_map->omv_data() == NULL) {
0N/A _stream = new CompressedReadStream(oop_map->write_stream()->buffer());
0N/A } else {
0N/A _stream = new CompressedReadStream(oop_map->omv_data());
0N/A }
0N/A _mask = oop_types_mask;
0N/A _size = oop_map->omv_count();
0N/A _position = 0;
0N/A _valid_omv = false;
0N/A}
0N/A
0N/A
0N/Avoid OopMapStream::find_next() {
0N/A while(_position++ < _size) {
0N/A _omv.read_from(_stream);
0N/A if(((int)_omv.type() & _mask) > 0) {
0N/A _valid_omv = true;
0N/A return;
0N/A }
0N/A }
0N/A _valid_omv = false;
0N/A}
0N/A
0N/A
0N/A// OopMap
0N/A
0N/A// frame_size units are stack-slots (4 bytes) NOT intptr_t; we can name odd
0N/A// slots to hold 4-byte values like ints and floats in the LP64 build.
0N/AOopMap::OopMap(int frame_size, int arg_count) {
0N/A // OopMaps are usually quite so small, so pick a small initial size
0N/A set_write_stream(new CompressedWriteStream(32));
0N/A set_omv_data(NULL);
0N/A set_omv_count(0);
0N/A
0N/A#ifdef ASSERT
0N/A _locs_length = VMRegImpl::stack2reg(0)->value() + frame_size + arg_count;
0N/A _locs_used = NEW_RESOURCE_ARRAY(OopMapValue::oop_types, _locs_length);
0N/A for(int i = 0; i < _locs_length; i++) _locs_used[i] = OopMapValue::unused_value;
0N/A#endif
0N/A}
0N/A
0N/A
0N/AOopMap::OopMap(OopMap::DeepCopyToken, OopMap* source) {
0N/A // This constructor does a deep copy
0N/A // of the source OopMap.
0N/A set_write_stream(new CompressedWriteStream(source->omv_count() * 2));
0N/A set_omv_data(NULL);
0N/A set_omv_count(0);
0N/A set_offset(source->offset());
0N/A
0N/A#ifdef ASSERT
0N/A _locs_length = source->_locs_length;
0N/A _locs_used = NEW_RESOURCE_ARRAY(OopMapValue::oop_types, _locs_length);
0N/A for(int i = 0; i < _locs_length; i++) _locs_used[i] = OopMapValue::unused_value;
0N/A#endif
0N/A
0N/A // We need to copy the entries too.
0N/A for (OopMapStream oms(source); !oms.is_done(); oms.next()) {
0N/A OopMapValue omv = oms.current();
0N/A omv.write_on(write_stream());
0N/A increment_count();
0N/A }
0N/A}
0N/A
0N/A
0N/AOopMap* OopMap::deep_copy() {
0N/A return new OopMap(_deep_copy_token, this);
0N/A}
0N/A
0N/A
0N/Avoid OopMap::copy_to(address addr) {
0N/A memcpy(addr,this,sizeof(OopMap));
0N/A memcpy(addr + sizeof(OopMap),write_stream()->buffer(),write_stream()->position());
0N/A OopMap* new_oop = (OopMap*)addr;
0N/A new_oop->set_omv_data_size(write_stream()->position());
0N/A new_oop->set_omv_data((unsigned char *)(addr + sizeof(OopMap)));
0N/A new_oop->set_write_stream(NULL);
0N/A}
0N/A
0N/A
0N/Aint OopMap::heap_size() const {
0N/A int size = sizeof(OopMap);
0N/A int align = sizeof(void *) - 1;
0N/A if(write_stream() != NULL) {
0N/A size += write_stream()->position();
0N/A } else {
0N/A size += omv_data_size();
0N/A }
0N/A // Align to a reasonable ending point
0N/A size = ((size+align) & ~align);
0N/A return size;
0N/A}
0N/A
0N/A// frame_size units are stack-slots (4 bytes) NOT intptr_t; we can name odd
0N/A// slots to hold 4-byte values like ints and floats in the LP64 build.
0N/Avoid OopMap::set_xxx(VMReg reg, OopMapValue::oop_types x, VMReg optional) {
0N/A
0N/A assert(reg->value() < _locs_length, "too big reg value for stack size");
0N/A assert( _locs_used[reg->value()] == OopMapValue::unused_value, "cannot insert twice" );
0N/A debug_only( _locs_used[reg->value()] = x; )
0N/A
0N/A OopMapValue o(reg, x);
0N/A
0N/A if(x == OopMapValue::callee_saved_value) {
0N/A // This can never be a stack location, so we don't need to transform it.
0N/A assert(optional->is_reg(), "Trying to callee save a stack location");
0N/A o.set_content_reg(optional);
0N/A } else if(x == OopMapValue::derived_oop_value) {
0N/A o.set_content_reg(optional);
0N/A }
0N/A
0N/A o.write_on(write_stream());
0N/A increment_count();
0N/A}
0N/A
0N/A
0N/Avoid OopMap::set_oop(VMReg reg) {
0N/A set_xxx(reg, OopMapValue::oop_value, VMRegImpl::Bad());
0N/A}
0N/A
0N/A
0N/Avoid OopMap::set_value(VMReg reg) {
0N/A // At this time, we only need value entries in our OopMap when ZapDeadCompiledLocals is active.
0N/A if (ZapDeadCompiledLocals)
0N/A set_xxx(reg, OopMapValue::value_value, VMRegImpl::Bad());
0N/A}
0N/A
0N/A
113N/Avoid OopMap::set_narrowoop(VMReg reg) {
113N/A set_xxx(reg, OopMapValue::narrowoop_value, VMRegImpl::Bad());
0N/A}
0N/A
0N/A
0N/Avoid OopMap::set_callee_saved(VMReg reg, VMReg caller_machine_register ) {
0N/A set_xxx(reg, OopMapValue::callee_saved_value, caller_machine_register);
0N/A}
0N/A
0N/A
0N/Avoid OopMap::set_derived_oop(VMReg reg, VMReg derived_from_local_register ) {
0N/A if( reg == derived_from_local_register ) {
0N/A // Actually an oop, derived shares storage with base,
0N/A set_oop(reg);
0N/A } else {
0N/A set_xxx(reg, OopMapValue::derived_oop_value, derived_from_local_register);
0N/A }
0N/A}
0N/A
0N/A// OopMapSet
0N/A
0N/AOopMapSet::OopMapSet() {
0N/A set_om_size(MinOopMapAllocation);
0N/A set_om_count(0);
0N/A OopMap** temp = NEW_RESOURCE_ARRAY(OopMap*, om_size());
0N/A set_om_data(temp);
0N/A}
0N/A
0N/A
0N/Avoid OopMapSet::grow_om_data() {
0N/A int new_size = om_size() * 2;
0N/A OopMap** new_data = NEW_RESOURCE_ARRAY(OopMap*, new_size);
0N/A memcpy(new_data,om_data(),om_size() * sizeof(OopMap*));
0N/A set_om_size(new_size);
0N/A set_om_data(new_data);
0N/A}
0N/A
0N/A
0N/Avoid OopMapSet::copy_to(address addr) {
0N/A address temp = addr;
0N/A int align = sizeof(void *) - 1;
0N/A // Copy this
0N/A memcpy(addr,this,sizeof(OopMapSet));
0N/A temp += sizeof(OopMapSet);
0N/A temp = (address)((intptr_t)(temp + align) & ~align);
0N/A // Do the needed fixups to the new OopMapSet
0N/A OopMapSet* new_set = (OopMapSet*)addr;
0N/A new_set->set_om_data((OopMap**)temp);
0N/A // Allow enough space for the OopMap pointers
0N/A temp += (om_count() * sizeof(OopMap*));
0N/A
0N/A for(int i=0; i < om_count(); i++) {
0N/A OopMap* map = at(i);
0N/A map->copy_to((address)temp);
0N/A new_set->set(i,(OopMap*)temp);
0N/A temp += map->heap_size();
0N/A }
0N/A // This "locks" the OopMapSet
0N/A new_set->set_om_size(-1);
0N/A}
0N/A
0N/A
0N/Avoid OopMapSet::add_gc_map(int pc_offset, OopMap *map ) {
0N/A assert(om_size() != -1,"Cannot grow a fixed OopMapSet");
0N/A
0N/A if(om_count() >= om_size()) {
0N/A grow_om_data();
0N/A }
0N/A map->set_offset(pc_offset);
0N/A
0N/A#ifdef ASSERT
0N/A if(om_count() > 0) {
0N/A OopMap* last = at(om_count()-1);
0N/A if (last->offset() == map->offset() ) {
0N/A fatal("OopMap inserted twice");
0N/A }
0N/A if(last->offset() > map->offset()) {
0N/A tty->print_cr( "WARNING, maps not sorted: pc[%d]=%d, pc[%d]=%d",
0N/A om_count(),last->offset(),om_count()+1,map->offset());
0N/A }
0N/A }
0N/A#endif // ASSERT
0N/A
0N/A set(om_count(),map);
0N/A increment_count();
0N/A}
0N/A
0N/A
0N/Aint OopMapSet::heap_size() const {
0N/A // The space we use
0N/A int size = sizeof(OopMap);
0N/A int align = sizeof(void *) - 1;
0N/A size = ((size+align) & ~align);
0N/A size += om_count() * sizeof(OopMap*);
0N/A
0N/A // Now add in the space needed for the indivdiual OopMaps
0N/A for(int i=0; i < om_count(); i++) {
0N/A size += at(i)->heap_size();
0N/A }
0N/A // We don't need to align this, it will be naturally pointer aligned
0N/A return size;
0N/A}
0N/A
0N/A
0N/AOopMap* OopMapSet::singular_oop_map() {
0N/A guarantee(om_count() == 1, "Make sure we only have a single gc point");
0N/A return at(0);
0N/A}
0N/A
0N/A
0N/AOopMap* OopMapSet::find_map_at_offset(int pc_offset) const {
0N/A int i, len = om_count();
0N/A assert( len > 0, "must have pointer maps" );
0N/A
0N/A // Scan through oopmaps. Stop when current offset is either equal or greater
0N/A // than the one we are looking for.
0N/A for( i = 0; i < len; i++) {
0N/A if( at(i)->offset() >= pc_offset )
0N/A break;
0N/A }
0N/A
0N/A assert( i < len, "oopmap not found" );
0N/A
0N/A OopMap* m = at(i);
0N/A assert( m->offset() == pc_offset, "oopmap not found" );
0N/A return m;
0N/A}
0N/A
0N/Aclass DoNothingClosure: public OopClosure {
113N/A public:
113N/A void do_oop(oop* p) {}
113N/A void do_oop(narrowOop* p) {}
0N/A};
0N/Astatic DoNothingClosure do_nothing;
0N/A
0N/Astatic void add_derived_oop(oop* base, oop* derived) {
0N/A#ifndef TIERED
0N/A COMPILER1_PRESENT(ShouldNotReachHere();)
0N/A#endif // TIERED
0N/A#ifdef COMPILER2
0N/A DerivedPointerTable::add(derived, base);
0N/A#endif // COMPILER2
0N/A}
0N/A
0N/A
0N/A#ifndef PRODUCT
0N/Astatic void trace_codeblob_maps(const frame *fr, const RegisterMap *reg_map) {
0N/A // Print oopmap and regmap
0N/A tty->print_cr("------ ");
0N/A CodeBlob* cb = fr->cb();
0N/A OopMapSet* maps = cb->oop_maps();
0N/A OopMap* map = cb->oop_map_for_return_address(fr->pc());
0N/A map->print();
0N/A if( cb->is_nmethod() ) {
0N/A nmethod* nm = (nmethod*)cb;
0N/A // native wrappers have no scope data, it is implied
0N/A if (nm->is_native_method()) {
0N/A tty->print("bci: 0 (native)");
0N/A } else {
0N/A ScopeDesc* scope = nm->scope_desc_at(fr->pc());
0N/A tty->print("bci: %d ",scope->bci());
0N/A }
0N/A }
0N/A tty->cr();
0N/A fr->print_on(tty);
0N/A tty->print(" ");
0N/A cb->print_value_on(tty); tty->cr();
0N/A reg_map->print();
0N/A tty->print_cr("------ ");
0N/A
0N/A}
0N/A#endif // PRODUCT
0N/A
0N/Avoid OopMapSet::oops_do(const frame *fr, const RegisterMap* reg_map, OopClosure* f) {
0N/A // add derived oops to a table
113N/A all_do(fr, reg_map, f, add_derived_oop, &do_nothing);
0N/A}
0N/A
0N/A
0N/Avoid OopMapSet::all_do(const frame *fr, const RegisterMap *reg_map,
0N/A OopClosure* oop_fn, void derived_oop_fn(oop*, oop*),
113N/A OopClosure* value_fn) {
0N/A CodeBlob* cb = fr->cb();
113N/A assert(cb != NULL, "no codeblob");
0N/A
0N/A NOT_PRODUCT(if (TraceCodeBlobStacks) trace_codeblob_maps(fr, reg_map);)
0N/A
0N/A OopMapSet* maps = cb->oop_maps();
113N/A OopMap* map = cb->oop_map_for_return_address(fr->pc());
113N/A assert(map != NULL, "no ptr map found");
0N/A
0N/A // handle derived pointers first (otherwise base pointer may be
0N/A // changed before derived pointer offset has been collected)
0N/A OopMapValue omv;
0N/A {
0N/A OopMapStream oms(map,OopMapValue::derived_oop_value);
0N/A if (!oms.is_done()) {
0N/A#ifndef TIERED
0N/A COMPILER1_PRESENT(ShouldNotReachHere();)
0N/A#endif // !TIERED
0N/A // Protect the operation on the derived pointers. This
0N/A // protects the addition of derived pointers to the shared
0N/A // derived pointer table in DerivedPointerTable::add().
0N/A MutexLockerEx x(DerivedPointerTableGC_lock, Mutex::_no_safepoint_check_flag);
0N/A do {
0N/A omv = oms.current();
0N/A oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map);
0N/A if ( loc != NULL ) {
0N/A oop *base_loc = fr->oopmapreg_to_location(omv.content_reg(), reg_map);
0N/A oop *derived_loc = loc;
858N/A oop val = *base_loc;
858N/A if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) {
858N/A // Ignore NULL oops and decoded NULL narrow oops which
858N/A // equal to Universe::narrow_oop_base when a narrow oop
858N/A // implicit null check is used in compiled code.
858N/A // The narrow_oop_base could be NULL or be the address
858N/A // of the page below heap depending on compressed oops mode.
858N/A } else
858N/A derived_oop_fn(base_loc, derived_loc);
0N/A }
0N/A oms.next();
0N/A } while (!oms.is_done());
0N/A }
0N/A }
0N/A
113N/A // We want coop, value and oop oop_types
113N/A int mask = OopMapValue::oop_value | OopMapValue::value_value | OopMapValue::narrowoop_value;
0N/A {
0N/A for (OopMapStream oms(map,mask); !oms.is_done(); oms.next()) {
0N/A omv = oms.current();
0N/A oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map);
0N/A if ( loc != NULL ) {
0N/A if ( omv.type() == OopMapValue::oop_value ) {
858N/A oop val = *loc;
858N/A if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) {
858N/A // Ignore NULL oops and decoded NULL narrow oops which
858N/A // equal to Universe::narrow_oop_base when a narrow oop
858N/A // implicit null check is used in compiled code.
858N/A // The narrow_oop_base could be NULL or be the address
858N/A // of the page below heap depending on compressed oops mode.
858N/A continue;
858N/A }
0N/A#ifdef ASSERT
244N/A if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) ||
113N/A !Universe::heap()->is_in_or_null(*loc)) {
0N/A tty->print_cr("# Found non oop pointer. Dumping state at failure");
0N/A // try to dump out some helpful debugging information
0N/A trace_codeblob_maps(fr, reg_map);
0N/A omv.print();
113N/A tty->print_cr("register r");
113N/A omv.reg()->print();
0N/A tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc);
0N/A // do the real assert.
0N/A assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer");
0N/A }
0N/A#endif // ASSERT
0N/A oop_fn->do_oop(loc);
0N/A } else if ( omv.type() == OopMapValue::value_value ) {
858N/A assert((*loc) == (oop)NULL || !Universe::is_narrow_oop_base(*loc),
858N/A "found invalid value pointer");
0N/A value_fn->do_oop(loc);
113N/A } else if ( omv.type() == OopMapValue::narrowoop_value ) {
113N/A narrowOop *nl = (narrowOop*)loc;
113N/A#ifndef VM_LITTLE_ENDIAN
113N/A if (!omv.reg()->is_stack()) {
113N/A // compressed oops in registers only take up 4 bytes of an
113N/A // 8 byte register but they are in the wrong part of the
113N/A // word so adjust loc to point at the right place.
113N/A nl = (narrowOop*)((address)nl + 4);
113N/A }
113N/A#endif
113N/A oop_fn->do_oop(nl);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A}
0N/A
0N/A
0N/A// Update callee-saved register info for the following frame
0N/Avoid OopMapSet::update_register_map(const frame *fr, RegisterMap *reg_map) {
0N/A ResourceMark rm;
0N/A CodeBlob* cb = fr->cb();
0N/A assert(cb != NULL, "no codeblob");
0N/A
0N/A // Any reg might be saved by a safepoint handler (see generate_handler_blob).
0N/A const int max_saved_on_entry_reg_count = ConcreteRegisterImpl::number_of_registers;
0N/A assert( reg_map->_update_for_id == NULL || fr->is_older(reg_map->_update_for_id),
0N/A "already updated this map; do not 'update' it twice!" );
0N/A debug_only(reg_map->_update_for_id = fr->id());
0N/A
0N/A // Check if caller must update oop argument
0N/A assert((reg_map->include_argument_oops() ||
0N/A !cb->caller_must_gc_arguments(reg_map->thread())),
0N/A "include_argument_oops should already be set");
0N/A
0N/A int nof_callee = 0;
0N/A oop* locs[2*max_saved_on_entry_reg_count+1];
0N/A VMReg regs[2*max_saved_on_entry_reg_count+1];
0N/A // ("+1" because max_saved_on_entry_reg_count might be zero)
0N/A
0N/A // Scan through oopmap and find location of all callee-saved registers
0N/A // (we do not do update in place, since info could be overwritten)
0N/A
0N/A address pc = fr->pc();
0N/A
0N/A OopMap* map = cb->oop_map_for_return_address(pc);
0N/A
0N/A assert(map != NULL, " no ptr map found");
0N/A
0N/A OopMapValue omv;
0N/A for(OopMapStream oms(map,OopMapValue::callee_saved_value); !oms.is_done(); oms.next()) {
0N/A omv = oms.current();
0N/A assert(nof_callee < 2*max_saved_on_entry_reg_count, "overflow");
0N/A regs[nof_callee] = omv.content_reg();
0N/A locs[nof_callee] = fr->oopmapreg_to_location(omv.reg(),reg_map);
0N/A nof_callee++;
0N/A }
0N/A
0N/A // Check that runtime stubs save all callee-saved registers
0N/A#ifdef COMPILER2
0N/A assert(cb->is_compiled_by_c1() || !cb->is_runtime_stub() ||
0N/A (nof_callee >= SAVED_ON_ENTRY_REG_COUNT || nof_callee >= C_SAVED_ON_ENTRY_REG_COUNT),
0N/A "must save all");
0N/A#endif // COMPILER2
0N/A
0N/A // Copy found callee-saved register to reg_map
0N/A for(int i = 0; i < nof_callee; i++) {
0N/A reg_map->set_location(regs[i], (address)locs[i]);
0N/A }
0N/A}
0N/A
0N/A//=============================================================================
0N/A// Non-Product code
0N/A
0N/A#ifndef PRODUCT
0N/A
0N/Abool OopMap::has_derived_pointer() const {
0N/A#ifndef TIERED
0N/A COMPILER1_PRESENT(return false);
0N/A#endif // !TIERED
0N/A#ifdef COMPILER2
0N/A OopMapStream oms((OopMap*)this,OopMapValue::derived_oop_value);
0N/A return oms.is_done();
0N/A#else
0N/A return false;
0N/A#endif // COMPILER2
0N/A}
0N/A
100N/A#endif //PRODUCT
0N/A
100N/A// Printing code is present in product build for -XX:+PrintAssembly.
100N/A
100N/Astatic
100N/Avoid print_register_type(OopMapValue::oop_types x, VMReg optional,
100N/A outputStream* st) {
0N/A switch( x ) {
0N/A case OopMapValue::oop_value:
25N/A st->print("Oop");
0N/A break;
0N/A case OopMapValue::value_value:
4312N/A st->print("Value");
0N/A break;
113N/A case OopMapValue::narrowoop_value:
4312N/A st->print("NarrowOop");
0N/A break;
0N/A case OopMapValue::callee_saved_value:
4312N/A st->print("Callers_");
25N/A optional->print_on(st);
0N/A break;
0N/A case OopMapValue::derived_oop_value:
4312N/A st->print("Derived_oop_");
25N/A optional->print_on(st);
0N/A break;
0N/A default:
0N/A ShouldNotReachHere();
0N/A }
0N/A}
0N/A
0N/A
25N/Avoid OopMapValue::print_on(outputStream* st) const {
25N/A reg()->print_on(st);
25N/A st->print("=");
25N/A print_register_type(type(),content_reg(),st);
25N/A st->print(" ");
0N/A}
0N/A
0N/A
0N/Avoid OopMap::print_on(outputStream* st) const {
0N/A OopMapValue omv;
100N/A st->print("OopMap{");
0N/A for(OopMapStream oms((OopMap*)this); !oms.is_done(); oms.next()) {
0N/A omv = oms.current();
0N/A omv.print_on(st);
0N/A }
100N/A st->print("off=%d}", (int) offset());
0N/A}
0N/A
0N/A
0N/Avoid OopMapSet::print_on(outputStream* st) const {
0N/A int i, len = om_count();
0N/A
0N/A st->print_cr("OopMapSet contains %d OopMaps\n",len);
0N/A
0N/A for( i = 0; i < len; i++) {
0N/A OopMap* m = at(i);
100N/A st->print_cr("#%d ",i);
0N/A m->print_on(st);
100N/A st->cr();
0N/A }
0N/A}
100N/A
0N/A
0N/A
0N/A//------------------------------DerivedPointerTable---------------------------
0N/A
0N/A#ifdef COMPILER2
0N/A
3863N/Aclass DerivedPointerEntry : public CHeapObj<mtCompiler> {
0N/A private:
0N/A oop* _location; // Location of derived pointer (also pointing to the base)
0N/A intptr_t _offset; // Offset from base pointer
0N/A public:
0N/A DerivedPointerEntry(oop* location, intptr_t offset) { _location = location; _offset = offset; }
0N/A oop* location() { return _location; }
0N/A intptr_t offset() { return _offset; }
0N/A};
0N/A
0N/A
0N/AGrowableArray<DerivedPointerEntry*>* DerivedPointerTable::_list = NULL;
0N/Abool DerivedPointerTable::_active = false;
0N/A
0N/A
0N/Avoid DerivedPointerTable::clear() {
0N/A // The first time, we create the list. Otherwise it should be
0N/A // empty. If not, then we have probably forgotton to call
0N/A // update_pointers after last GC/Scavenge.
0N/A assert (!_active, "should not be active");
0N/A assert(_list == NULL || _list->length() == 0, "table not empty");
0N/A if (_list == NULL) {
3863N/A _list = new (ResourceObj::C_HEAP, mtCompiler) GrowableArray<DerivedPointerEntry*>(10, true); // Allocated on C heap
0N/A }
0N/A _active = true;
0N/A}
0N/A
0N/A
0 Error!

 

There was an error!

null

java.lang.NullPointerException