Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/compiler/oopMap.cpp
32285 views
/*1* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "code/codeBlob.hpp"26#include "code/codeCache.hpp"27#include "code/nmethod.hpp"28#include "code/scopeDesc.hpp"29#include "compiler/oopMap.hpp"30#include "gc_interface/collectedHeap.hpp"31#include "memory/allocation.inline.hpp"32#include "memory/resourceArea.hpp"33#include "runtime/frame.inline.hpp"34#include "runtime/signature.hpp"35#ifdef COMPILER136#include "c1/c1_Defs.hpp"37#endif3839// OopMapStream4041OopMapStream::OopMapStream(OopMap* oop_map) {42if(oop_map->omv_data() == NULL) {43_stream = new CompressedReadStream(oop_map->write_stream()->buffer());44} else {45_stream = new CompressedReadStream(oop_map->omv_data());46}47_mask = OopMapValue::type_mask_in_place;48_size = oop_map->omv_count();49_position = 0;50_valid_omv = false;51}525354OopMapStream::OopMapStream(OopMap* oop_map, int oop_types_mask) {55if(oop_map->omv_data() == NULL) {56_stream = new CompressedReadStream(oop_map->write_stream()->buffer());57} else {58_stream = new CompressedReadStream(oop_map->omv_data());59}60_mask = oop_types_mask;61_size = oop_map->omv_count();62_position = 0;63_valid_omv = false;64}656667void OopMapStream::find_next() {68while(_position++ < _size) {69_omv.read_from(_stream);70if(((int)_omv.type() & _mask) > 0) {71_valid_omv = true;72return;73}74}75_valid_omv = false;76}777879// OopMap8081// frame_size units are stack-slots (4 bytes) NOT intptr_t; we can name odd82// slots to hold 4-byte values like ints and floats in the LP64 build.83OopMap::OopMap(int frame_size, int arg_count) {84// OopMaps are usually quite so small, so pick a small initial size85set_write_stream(new CompressedWriteStream(32));86set_omv_data(NULL);87set_omv_count(0);8889#ifdef ASSERT90_locs_length = VMRegImpl::stack2reg(0)->value() + frame_size + arg_count;91_locs_used = NEW_RESOURCE_ARRAY(OopMapValue::oop_types, _locs_length);92for(int i = 0; i < _locs_length; i++) _locs_used[i] = OopMapValue::unused_value;93#endif94}959697OopMap::OopMap(OopMap::DeepCopyToken, OopMap* source) {98// This constructor does a deep copy99// of the source OopMap.100set_write_stream(new CompressedWriteStream(source->omv_count() * 2));101set_omv_data(NULL);102set_omv_count(0);103set_offset(source->offset());104105#ifdef ASSERT106_locs_length = source->_locs_length;107_locs_used = NEW_RESOURCE_ARRAY(OopMapValue::oop_types, _locs_length);108for(int i = 0; i < _locs_length; i++) _locs_used[i] = OopMapValue::unused_value;109#endif110111// We need to copy the entries too.112for (OopMapStream oms(source); !oms.is_done(); oms.next()) {113OopMapValue omv = oms.current();114omv.write_on(write_stream());115increment_count();116}117}118119120OopMap* OopMap::deep_copy() {121return new OopMap(_deep_copy_token, this);122}123124125void OopMap::copy_to(address addr) {126memcpy(addr,this,sizeof(OopMap));127memcpy(addr + sizeof(OopMap),write_stream()->buffer(),write_stream()->position());128OopMap* new_oop = (OopMap*)addr;129new_oop->set_omv_data_size(write_stream()->position());130new_oop->set_omv_data((unsigned char *)(addr + sizeof(OopMap)));131new_oop->set_write_stream(NULL);132}133134135int OopMap::heap_size() const {136int size = sizeof(OopMap);137int align = sizeof(void *) - 1;138if(write_stream() != NULL) {139size += write_stream()->position();140} else {141size += omv_data_size();142}143// Align to a reasonable ending point144size = ((size+align) & ~align);145return size;146}147148// frame_size units are stack-slots (4 bytes) NOT intptr_t; we can name odd149// slots to hold 4-byte values like ints and floats in the LP64 build.150void OopMap::set_xxx(VMReg reg, OopMapValue::oop_types x, VMReg optional) {151152assert(reg->value() < _locs_length, "too big reg value for stack size");153assert( _locs_used[reg->value()] == OopMapValue::unused_value, "cannot insert twice" );154debug_only( _locs_used[reg->value()] = x; )155156OopMapValue o(reg, x);157158if(x == OopMapValue::callee_saved_value) {159// This can never be a stack location, so we don't need to transform it.160assert(optional->is_reg(), "Trying to callee save a stack location");161o.set_content_reg(optional);162} else if(x == OopMapValue::derived_oop_value) {163o.set_content_reg(optional);164}165166o.write_on(write_stream());167increment_count();168}169170171void OopMap::set_oop(VMReg reg) {172set_xxx(reg, OopMapValue::oop_value, VMRegImpl::Bad());173}174175176void OopMap::set_value(VMReg reg) {177// At this time, we only need value entries in our OopMap when ZapDeadCompiledLocals is active.178if (ZapDeadCompiledLocals)179set_xxx(reg, OopMapValue::value_value, VMRegImpl::Bad());180}181182183void OopMap::set_narrowoop(VMReg reg) {184set_xxx(reg, OopMapValue::narrowoop_value, VMRegImpl::Bad());185}186187188void OopMap::set_callee_saved(VMReg reg, VMReg caller_machine_register ) {189set_xxx(reg, OopMapValue::callee_saved_value, caller_machine_register);190}191192193void OopMap::set_derived_oop(VMReg reg, VMReg derived_from_local_register ) {194if( reg == derived_from_local_register ) {195// Actually an oop, derived shares storage with base,196set_oop(reg);197} else {198set_xxx(reg, OopMapValue::derived_oop_value, derived_from_local_register);199}200}201202// OopMapSet203204OopMapSet::OopMapSet() {205set_om_size(MinOopMapAllocation);206set_om_count(0);207OopMap** temp = NEW_RESOURCE_ARRAY(OopMap*, om_size());208set_om_data(temp);209}210211212void OopMapSet::grow_om_data() {213int new_size = om_size() * 2;214OopMap** new_data = NEW_RESOURCE_ARRAY(OopMap*, new_size);215memcpy(new_data,om_data(),om_size() * sizeof(OopMap*));216set_om_size(new_size);217set_om_data(new_data);218}219220221void OopMapSet::copy_to(address addr) {222address temp = addr;223int align = sizeof(void *) - 1;224// Copy this225memcpy(addr,this,sizeof(OopMapSet));226temp += sizeof(OopMapSet);227temp = (address)((intptr_t)(temp + align) & ~align);228// Do the needed fixups to the new OopMapSet229OopMapSet* new_set = (OopMapSet*)addr;230new_set->set_om_data((OopMap**)temp);231// Allow enough space for the OopMap pointers232temp += (om_count() * sizeof(OopMap*));233234for(int i=0; i < om_count(); i++) {235OopMap* map = at(i);236map->copy_to((address)temp);237new_set->set(i,(OopMap*)temp);238temp += map->heap_size();239}240// This "locks" the OopMapSet241new_set->set_om_size(-1);242}243244245void OopMapSet::add_gc_map(int pc_offset, OopMap *map ) {246assert(om_size() != -1,"Cannot grow a fixed OopMapSet");247248if(om_count() >= om_size()) {249grow_om_data();250}251map->set_offset(pc_offset);252253#ifdef ASSERT254if(om_count() > 0) {255OopMap* last = at(om_count()-1);256if (last->offset() == map->offset() ) {257fatal("OopMap inserted twice");258}259if(last->offset() > map->offset()) {260tty->print_cr( "WARNING, maps not sorted: pc[%d]=%d, pc[%d]=%d",261om_count(),last->offset(),om_count()+1,map->offset());262}263}264#endif // ASSERT265266set(om_count(),map);267increment_count();268}269270271int OopMapSet::heap_size() const {272// The space we use273int size = sizeof(OopMap);274int align = sizeof(void *) - 1;275size = ((size+align) & ~align);276size += om_count() * sizeof(OopMap*);277278// Now add in the space needed for the indivdiual OopMaps279for(int i=0; i < om_count(); i++) {280size += at(i)->heap_size();281}282// We don't need to align this, it will be naturally pointer aligned283return size;284}285286287OopMap* OopMapSet::singular_oop_map() {288guarantee(om_count() == 1, "Make sure we only have a single gc point");289return at(0);290}291292293OopMap* OopMapSet::find_map_at_offset(int pc_offset) const {294int i, len = om_count();295assert( len > 0, "must have pointer maps" );296297// Scan through oopmaps. Stop when current offset is either equal or greater298// than the one we are looking for.299for( i = 0; i < len; i++) {300if( at(i)->offset() >= pc_offset )301break;302}303304assert( i < len, "oopmap not found" );305306OopMap* m = at(i);307assert( m->offset() == pc_offset, "oopmap not found" );308return m;309}310311class DoNothingClosure: public OopClosure {312public:313void do_oop(oop* p) {}314void do_oop(narrowOop* p) {}315};316static DoNothingClosure do_nothing;317318static void add_derived_oop(oop* base, oop* derived) {319#ifndef TIERED320COMPILER1_PRESENT(ShouldNotReachHere();)321#endif // TIERED322#ifdef COMPILER2323DerivedPointerTable::add(derived, base);324#endif // COMPILER2325}326327328#ifndef PRODUCT329static void trace_codeblob_maps(const frame *fr, const RegisterMap *reg_map) {330// Print oopmap and regmap331tty->print_cr("------ ");332CodeBlob* cb = fr->cb();333OopMapSet* maps = cb->oop_maps();334OopMap* map = cb->oop_map_for_return_address(fr->pc());335map->print();336if( cb->is_nmethod() ) {337nmethod* nm = (nmethod*)cb;338// native wrappers have no scope data, it is implied339if (nm->is_native_method()) {340tty->print("bci: 0 (native)");341} else {342ScopeDesc* scope = nm->scope_desc_at(fr->pc());343tty->print("bci: %d ",scope->bci());344}345}346tty->cr();347fr->print_on(tty);348tty->print(" ");349cb->print_value_on(tty); tty->cr();350reg_map->print();351tty->print_cr("------ ");352353}354#endif // PRODUCT355356void OopMapSet::oops_do(const frame *fr, const RegisterMap* reg_map, OopClosure* f) {357// add derived oops to a table358all_do(fr, reg_map, f, add_derived_oop, &do_nothing);359}360361362void OopMapSet::all_do(const frame *fr, const RegisterMap *reg_map,363OopClosure* oop_fn, void derived_oop_fn(oop*, oop*),364OopClosure* value_fn) {365CodeBlob* cb = fr->cb();366assert(cb != NULL, "no codeblob");367368NOT_PRODUCT(if (TraceCodeBlobStacks) trace_codeblob_maps(fr, reg_map);)369370OopMapSet* maps = cb->oop_maps();371OopMap* map = cb->oop_map_for_return_address(fr->pc());372assert(map != NULL, "no ptr map found");373374// handle derived pointers first (otherwise base pointer may be375// changed before derived pointer offset has been collected)376OopMapValue omv;377{378OopMapStream oms(map,OopMapValue::derived_oop_value);379if (!oms.is_done()) {380#ifndef TIERED381COMPILER1_PRESENT(ShouldNotReachHere();)382#endif // !TIERED383// Protect the operation on the derived pointers. This384// protects the addition of derived pointers to the shared385// derived pointer table in DerivedPointerTable::add().386MutexLockerEx x(DerivedPointerTableGC_lock, Mutex::_no_safepoint_check_flag);387do {388omv = oms.current();389oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map);390if ( loc != NULL ) {391oop *derived_loc = loc;392oop *base_loc = fr->oopmapreg_to_location(omv.content_reg(), reg_map);393// Ignore NULL oops and decoded NULL narrow oops which394// equal to Universe::narrow_oop_base when a narrow oop395// implicit null check is used in compiled code.396// The narrow_oop_base could be NULL or be the address397// of the page below heap depending on compressed oops mode.398if (base_loc != NULL && *base_loc != (oop)NULL && !Universe::is_narrow_oop_base(*base_loc)) {399derived_oop_fn(base_loc, derived_loc);400}401}402oms.next();403} while (!oms.is_done());404}405}406407// We want coop, value and oop oop_types408int mask = OopMapValue::oop_value | OopMapValue::value_value | OopMapValue::narrowoop_value;409{410for (OopMapStream oms(map,mask); !oms.is_done(); oms.next()) {411omv = oms.current();412oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map);413if ( loc != NULL ) {414if ( omv.type() == OopMapValue::oop_value ) {415oop val = *loc;416if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) {417// Ignore NULL oops and decoded NULL narrow oops which418// equal to Universe::narrow_oop_base when a narrow oop419// implicit null check is used in compiled code.420// The narrow_oop_base could be NULL or be the address421// of the page below heap depending on compressed oops mode.422continue;423}424#ifdef ASSERT425if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) ||426!Universe::heap()->is_in_or_null(*loc)) {427tty->print_cr("# Found non oop pointer. Dumping state at failure");428// try to dump out some helpful debugging information429trace_codeblob_maps(fr, reg_map);430omv.print();431tty->print_cr("register r");432omv.reg()->print();433tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc);434// do the real assert.435assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer");436}437#endif // ASSERT438oop_fn->do_oop(loc);439} else if ( omv.type() == OopMapValue::value_value ) {440assert((*loc) == (oop)NULL || !Universe::is_narrow_oop_base(*loc),441"found invalid value pointer");442value_fn->do_oop(loc);443} else if ( omv.type() == OopMapValue::narrowoop_value ) {444narrowOop *nl = (narrowOop*)loc;445#ifndef VM_LITTLE_ENDIAN446if (!omv.reg()->is_stack()) {447// compressed oops in registers only take up 4 bytes of an448// 8 byte register but they are in the wrong part of the449// word so adjust loc to point at the right place.450nl = (narrowOop*)((address)nl + 4);451}452#endif453oop_fn->do_oop(nl);454}455}456}457}458}459460461// Update callee-saved register info for the following frame462void OopMapSet::update_register_map(const frame *fr, RegisterMap *reg_map) {463ResourceMark rm;464CodeBlob* cb = fr->cb();465assert(cb != NULL, "no codeblob");466467// Any reg might be saved by a safepoint handler (see generate_handler_blob).468assert( reg_map->_update_for_id == NULL || fr->is_older(reg_map->_update_for_id),469"already updated this map; do not 'update' it twice!" );470debug_only(reg_map->_update_for_id = fr->id());471472// Check if caller must update oop argument473assert((reg_map->include_argument_oops() ||474!cb->caller_must_gc_arguments(reg_map->thread())),475"include_argument_oops should already be set");476477// Scan through oopmap and find location of all callee-saved registers478// (we do not do update in place, since info could be overwritten)479480address pc = fr->pc();481OopMap* map = cb->oop_map_for_return_address(pc);482assert(map != NULL, "no ptr map found");483DEBUG_ONLY(int nof_callee = 0;)484485for (OopMapStream oms(map, OopMapValue::callee_saved_value); !oms.is_done(); oms.next()) {486OopMapValue omv = oms.current();487VMReg reg = omv.content_reg();488oop* loc = fr->oopmapreg_to_location(omv.reg(), reg_map);489reg_map->set_location(reg, (address) loc);490DEBUG_ONLY(nof_callee++;)491}492493// Check that runtime stubs save all callee-saved registers494#ifdef COMPILER2495assert(cb->is_compiled_by_c1() || !cb->is_runtime_stub() ||496(nof_callee >= SAVED_ON_ENTRY_REG_COUNT || nof_callee >= C_SAVED_ON_ENTRY_REG_COUNT),497"must save all");498#endif // COMPILER2499}500501//=============================================================================502// Non-Product code503504#ifndef PRODUCT505506bool OopMap::has_derived_pointer() const {507#ifndef TIERED508COMPILER1_PRESENT(return false);509#endif // !TIERED510#ifdef COMPILER2511OopMapStream oms((OopMap*)this,OopMapValue::derived_oop_value);512return oms.is_done();513#else514return false;515#endif // COMPILER2516}517518#endif //PRODUCT519520// Printing code is present in product build for -XX:+PrintAssembly.521522static523void print_register_type(OopMapValue::oop_types x, VMReg optional,524outputStream* st) {525switch( x ) {526case OopMapValue::oop_value:527st->print("Oop");528break;529case OopMapValue::value_value:530st->print("Value");531break;532case OopMapValue::narrowoop_value:533st->print("NarrowOop");534break;535case OopMapValue::callee_saved_value:536st->print("Callers_");537optional->print_on(st);538break;539case OopMapValue::derived_oop_value:540st->print("Derived_oop_");541optional->print_on(st);542break;543default:544ShouldNotReachHere();545}546}547548549void OopMapValue::print_on(outputStream* st) const {550reg()->print_on(st);551st->print("=");552print_register_type(type(),content_reg(),st);553st->print(" ");554}555556557void OopMap::print_on(outputStream* st) const {558OopMapValue omv;559st->print("OopMap{");560for(OopMapStream oms((OopMap*)this); !oms.is_done(); oms.next()) {561omv = oms.current();562omv.print_on(st);563}564st->print("off=%d}", (int) offset());565}566567568void OopMapSet::print_on(outputStream* st) const {569int i, len = om_count();570571st->print_cr("OopMapSet contains %d OopMaps\n",len);572573for( i = 0; i < len; i++) {574OopMap* m = at(i);575st->print_cr("#%d ",i);576m->print_on(st);577st->cr();578}579}580581582583//------------------------------DerivedPointerTable---------------------------584585#ifdef COMPILER2586587class DerivedPointerEntry : public CHeapObj<mtCompiler> {588private:589oop* _location; // Location of derived pointer (also pointing to the base)590intptr_t _offset; // Offset from base pointer591public:592DerivedPointerEntry(oop* location, intptr_t offset) { _location = location; _offset = offset; }593oop* location() { return _location; }594intptr_t offset() { return _offset; }595};596597598GrowableArray<DerivedPointerEntry*>* DerivedPointerTable::_list = NULL;599bool DerivedPointerTable::_active = false;600601602void DerivedPointerTable::clear() {603// The first time, we create the list. Otherwise it should be604// empty. If not, then we have probably forgotton to call605// update_pointers after last GC/Scavenge.606assert (!_active, "should not be active");607assert(_list == NULL || _list->length() == 0, "table not empty");608if (_list == NULL) {609_list = new (ResourceObj::C_HEAP, mtCompiler) GrowableArray<DerivedPointerEntry*>(10, true); // Allocated on C heap610}611_active = true;612}613614615// Returns value of location as an int616intptr_t value_of_loc(oop *pointer) { return cast_from_oop<intptr_t>((*pointer)); }617618619void DerivedPointerTable::add(oop *derived_loc, oop *base_loc) {620assert(Universe::heap()->is_in_or_null(*base_loc), "not an oop");621assert(derived_loc != base_loc, "Base and derived in same location");622if (_active) {623assert(*derived_loc != (oop)base_loc, "location already added");624assert(_list != NULL, "list must exist");625intptr_t offset = value_of_loc(derived_loc) - value_of_loc(base_loc);626// This assert is invalid because derived pointers can be627// arbitrarily far away from their base.628// assert(offset >= -1000000, "wrong derived pointer info");629630if (TraceDerivedPointers) {631tty->print_cr(632"Add derived pointer@" INTPTR_FORMAT633" - Derived: " INTPTR_FORMAT634" Base: " INTPTR_FORMAT " (@" INTPTR_FORMAT ") (Offset: " INTX_FORMAT ")",635p2i(derived_loc), p2i((address)*derived_loc), p2i((address)*base_loc), p2i(base_loc), offset636);637}638// Set derived oop location to point to base.639*derived_loc = (oop)base_loc;640assert_lock_strong(DerivedPointerTableGC_lock);641DerivedPointerEntry *entry = new DerivedPointerEntry(derived_loc, offset);642_list->append(entry);643}644}645646647void DerivedPointerTable::update_pointers() {648assert(_list != NULL, "list must exist");649for(int i = 0; i < _list->length(); i++) {650DerivedPointerEntry* entry = _list->at(i);651oop* derived_loc = entry->location();652intptr_t offset = entry->offset();653// The derived oop was setup to point to location of base654oop base = **(oop**)derived_loc;655assert(Universe::heap()->is_in_or_null(base), "must be an oop");656657*derived_loc = (oop)(((address)base) + offset);658assert(value_of_loc(derived_loc) - value_of_loc(&base) == offset, "sanity check");659660if (TraceDerivedPointers) {661tty->print_cr("Updating derived pointer@" INTPTR_FORMAT662" - Derived: " INTPTR_FORMAT " Base: " INTPTR_FORMAT " (Offset: " INTX_FORMAT ")",663p2i(derived_loc), p2i((address)*derived_loc), p2i((address)base), offset);664}665666// Delete entry667delete entry;668_list->at_put(i, NULL);669}670// Clear list, so it is ready for next traversal (this is an invariant)671if (TraceDerivedPointers && !_list->is_empty()) {672tty->print_cr("--------------------------");673}674_list->clear();675_active = false;676}677678#endif // COMPILER2679680681