Path: blob/master/src/hotspot/share/compiler/oopMap.hpp
40930 views
/*1* Copyright (c) 1998, 2019, 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#ifndef SHARE_COMPILER_OOPMAP_HPP25#define SHARE_COMPILER_OOPMAP_HPP2627#include "code/compressedStream.hpp"28#include "code/vmreg.hpp"29#include "memory/allocation.hpp"30#include "oops/oopsHierarchy.hpp"31#include "utilities/growableArray.hpp"3233// Interface for generating the frame map for compiled code. A frame map34// describes for a specific pc whether each register and frame stack slot is:35// Oop - A GC root for current frame36// Dead - Dead; can be Zapped for debugging37// CalleeXX - Callee saved; also describes which caller register is saved38// DerivedXX - A derived oop; original oop is described.39//40// OopMapValue describes a single OopMap entry4142enum class DerivedPointerIterationMode;43class frame;44class RegisterMap;45class OopClosure;4647enum class derived_pointer : intptr_t {};4849class OopMapValue: public StackObj {50friend class VMStructs;51private:52short _value;53int value() const { return _value; }54void set_value(int value) { _value = value; }55short _content_reg;5657public:58// Constants59enum { type_bits = 2,60register_bits = BitsPerShort - type_bits };6162enum { type_shift = 0,63register_shift = type_bits };6465enum { type_mask = right_n_bits(type_bits),66type_mask_in_place = type_mask << type_shift,67register_mask = right_n_bits(register_bits),68register_mask_in_place = register_mask << register_shift };6970enum oop_types {71oop_value,72narrowoop_value,73callee_saved_value,74derived_oop_value,75unused_value = -1 // Only used as a sentinel value76};7778// Constructors79OopMapValue () { set_value(0); set_content_reg(VMRegImpl::Bad()); }80OopMapValue (VMReg reg, oop_types t, VMReg reg2) {81set_reg_type(reg, t);82set_content_reg(reg2);83}8485private:86void set_reg_type(VMReg p, oop_types t) {87set_value((p->value() << register_shift) | t);88assert(reg() == p, "sanity check" );89assert(type() == t, "sanity check" );90}9192void set_content_reg(VMReg r) {93if (is_callee_saved()) {94// This can never be a stack location, so we don't need to transform it.95assert(r->is_reg(), "Trying to callee save a stack location");96} else if (is_derived_oop()) {97assert (r->is_valid(), "must have a valid VMReg");98} else {99assert (!r->is_valid(), "valid VMReg not allowed");100}101_content_reg = r->value();102}103104public:105// Archiving106void write_on(CompressedWriteStream* stream) {107stream->write_int(value());108if(is_callee_saved() || is_derived_oop()) {109stream->write_int(content_reg()->value());110}111}112113void read_from(CompressedReadStream* stream) {114set_value(stream->read_int());115if (is_callee_saved() || is_derived_oop()) {116set_content_reg(VMRegImpl::as_VMReg(stream->read_int(), true));117}118}119120// Querying121bool is_oop() { return mask_bits(value(), type_mask_in_place) == oop_value; }122bool is_narrowoop() { return mask_bits(value(), type_mask_in_place) == narrowoop_value; }123bool is_callee_saved() { return mask_bits(value(), type_mask_in_place) == callee_saved_value; }124bool is_derived_oop() { return mask_bits(value(), type_mask_in_place) == derived_oop_value; }125126VMReg reg() const { return VMRegImpl::as_VMReg(mask_bits(value(), register_mask_in_place) >> register_shift); }127oop_types type() const { return (oop_types)mask_bits(value(), type_mask_in_place); }128129static bool legal_vm_reg_name(VMReg p) {130return (p->value() == (p->value() & register_mask));131}132133VMReg content_reg() const { return VMRegImpl::as_VMReg(_content_reg, true); }134135// Returns offset from sp.136int stack_offset() {137assert(reg()->is_stack(), "must be stack location");138return reg()->reg2stack();139}140141void print_on(outputStream* st) const;142void print() const;143};144145146class OopMap: public ResourceObj {147friend class OopMapStream;148friend class VMStructs;149private:150int _pc_offset; // offset in the code that this OopMap corresponds to151int _omv_count; // number of OopMapValues in the stream152CompressedWriteStream* _write_stream;153154debug_only( OopMapValue::oop_types* _locs_used; int _locs_length;)155156// Accessors157int omv_count() const { return _omv_count; }158void set_omv_count(int value) { _omv_count = value; }159void increment_count() { _omv_count++; }160CompressedWriteStream* write_stream() const { return _write_stream; }161void set_write_stream(CompressedWriteStream* value) { _write_stream = value; }162163private:164enum DeepCopyToken { _deep_copy_token };165OopMap(DeepCopyToken, OopMap* source); // used only by deep_copy166167void set_xxx(VMReg reg, OopMapValue::oop_types x, VMReg optional);168169public:170OopMap(int frame_size, int arg_count);171172// pc-offset handling173int offset() const { return _pc_offset; }174void set_offset(int o) { _pc_offset = o; }175int count() const { return _omv_count; }176int data_size() const { return write_stream()->position(); }177address data() const { return write_stream()->buffer(); }178179// Construction180// frame_size units are stack-slots (4 bytes) NOT intptr_t; we can name odd181// slots to hold 4-byte values like ints and floats in the LP64 build.182void set_oop ( VMReg local);183void set_narrowoop(VMReg local);184void set_callee_saved( VMReg local, VMReg caller_machine_register );185void set_derived_oop ( VMReg local, VMReg derived_from_local_register );186187int heap_size() const;188void copy_data_to(address addr) const;189OopMap* deep_copy();190191bool legal_vm_reg_name(VMReg local) {192return OopMapValue::legal_vm_reg_name(local);193}194195// Printing196void print_on(outputStream* st) const;197void print() const;198bool equals(const OopMap* other) const;199};200201class OopMapSet : public ResourceObj {202friend class VMStructs;203private:204GrowableArray<OopMap*> _list;205206void add(OopMap* value) { _list.append(value); }207208public:209OopMapSet();210211// returns the number of OopMaps in this OopMapSet212int size() const { return _list.length(); }213// returns the OopMap at a given index214OopMap* at(int index) const { return _list.at(index); }215216// Collect OopMaps.217void add_gc_map(int pc, OopMap* map);218219// Methods oops_do() and all_do() filter out NULL oops and220// oop == CompressedOops::base() before passing oops221// to closures.222223// Iterates through frame for a compiled method224static void oops_do (const frame* fr,225const RegisterMap* reg_map,226OopClosure* f,227DerivedPointerIterationMode mode);228static void update_register_map(const frame* fr, RegisterMap *reg_map);229230// Iterates through frame for a compiled method for dead ones and values, too231static void all_do(const frame* fr, const RegisterMap* reg_map,232OopClosure* oop_fn,233void derived_oop_fn(oop* base, derived_pointer* derived, OopClosure* oop_fn));234235// Printing236void print_on(outputStream* st) const;237void print() const;238};239240class ImmutableOopMapBuilder;241242class ImmutableOopMap {243friend class OopMapStream;244friend class VMStructs;245#ifdef ASSERT246friend class ImmutableOopMapBuilder;247#endif248private:249int _count; // contains the number of entries in this OopMap250251address data_addr() const { return (address) this + sizeof(ImmutableOopMap); }252public:253ImmutableOopMap(const OopMap* oopmap);254255int count() const { return _count; }256#ifdef ASSERT257int nr_of_bytes() const; // this is an expensive operation, only used in debug builds258#endif259260// Printing261void print_on(outputStream* st) const;262void print() const;263};264265class ImmutableOopMapSet;266class ImmutableOopMap;267class OopMapSet;268269class ImmutableOopMapPair {270friend class VMStructs;271private:272int _pc_offset; // program counter offset from the beginning of the method273int _oopmap_offset; // offset in the data in the ImmutableOopMapSet where the ImmutableOopMap is located274public:275ImmutableOopMapPair(int pc_offset, int oopmap_offset) : _pc_offset(pc_offset), _oopmap_offset(oopmap_offset) {276assert(pc_offset >= 0 && oopmap_offset >= 0, "check");277}278const ImmutableOopMap* get_from(const ImmutableOopMapSet* set) const;279280int pc_offset() const { return _pc_offset; }281int oopmap_offset() const { return _oopmap_offset; }282};283284class ImmutableOopMapSet {285friend class VMStructs;286private:287int _count; // nr of ImmutableOopMapPairs in the Set288int _size; // nr of bytes including ImmutableOopMapSet itself289290address data() const { return (address) this + sizeof(*this) + sizeof(ImmutableOopMapPair) * _count; }291292public:293ImmutableOopMapSet(const OopMapSet* oopmap_set, int size) : _count(oopmap_set->size()), _size(size) {}294295ImmutableOopMap* oopmap_at_offset(int offset) const {296assert(offset >= 0 && offset < _size, "must be within boundaries");297address addr = data() + offset;298return (ImmutableOopMap*) addr;299}300301ImmutableOopMapPair* get_pairs() const { return (ImmutableOopMapPair*) ((address) this + sizeof(*this)); }302303static ImmutableOopMapSet* build_from(const OopMapSet* oopmap_set);304305const ImmutableOopMap* find_map_at_offset(int pc_offset) const;306307const ImmutableOopMapPair* pair_at(int index) const { assert(index >= 0 && index < _count, "check"); return &get_pairs()[index]; }308309int count() const { return _count; }310int nr_of_bytes() const { return _size; }311312void print_on(outputStream* st) const;313void print() const;314};315316class OopMapStream : public StackObj {317private:318CompressedReadStream* _stream;319int _size;320int _position;321bool _valid_omv;322OopMapValue _omv;323void find_next();324325public:326OopMapStream(OopMap* oop_map);327OopMapStream(const ImmutableOopMap* oop_map);328bool is_done() { if(!_valid_omv) { find_next(); } return !_valid_omv; }329void next() { find_next(); }330OopMapValue current() { return _omv; }331#ifdef ASSERT332int stream_position() const { return _stream->position(); }333#endif334};335336class ImmutableOopMapBuilder {337private:338class Mapping;339340private:341const OopMapSet* _set;342const OopMap* _empty;343const OopMap* _last;344int _empty_offset;345int _last_offset;346int _offset;347int _required;348Mapping* _mapping;349ImmutableOopMapSet* _new_set;350351/* Used for bookkeeping when building ImmutableOopMaps */352class Mapping : public ResourceObj {353public:354enum kind_t { OOPMAP_UNKNOWN = 0, OOPMAP_NEW = 1, OOPMAP_EMPTY = 2, OOPMAP_DUPLICATE = 3 };355356kind_t _kind;357int _offset;358int _size;359const OopMap* _map;360const OopMap* _other;361362Mapping() : _kind(OOPMAP_UNKNOWN), _offset(-1), _size(-1), _map(NULL) {}363364void set(kind_t kind, int offset, int size, const OopMap* map = 0, const OopMap* other = 0) {365_kind = kind;366_offset = offset;367_size = size;368_map = map;369_other = other;370}371};372373public:374ImmutableOopMapBuilder(const OopMapSet* set);375376int heap_size();377ImmutableOopMapSet* build();378ImmutableOopMapSet* generate_into(address buffer);379private:380bool is_empty(const OopMap* map) const {381return map->count() == 0;382}383384bool is_last_duplicate(const OopMap* map) {385if (_last != NULL && _last->count() > 0 && _last->equals(map)) {386return true;387}388return false;389}390391#ifdef ASSERT392void verify(address buffer, int size, const ImmutableOopMapSet* set);393#endif394395bool has_empty() const {396return _empty_offset != -1;397}398399int size_for(const OopMap* map) const;400void fill_pair(ImmutableOopMapPair* pair, const OopMap* map, int offset, const ImmutableOopMapSet* set);401int fill_map(ImmutableOopMapPair* pair, const OopMap* map, int offset, const ImmutableOopMapSet* set);402void fill(ImmutableOopMapSet* set, int size);403};404405406// Derived pointer support. This table keeps track of all derived points on a407// stack. It is cleared before each scavenge/GC. During the traversal of all408// oops, it is filled in with references to all locations that contains a409// derived oop (assumed to be very few). When the GC is complete, the derived410// pointers are updated based on their base pointers new value and an offset.411#if COMPILER2_OR_JVMCI412class DerivedPointerTable : public AllStatic {413friend class VMStructs;414private:415class Entry;416static bool _active; // do not record pointers for verify pass etc.417418public:419static void clear(); // Called before scavenge/GC420static void add(derived_pointer* derived, oop *base); // Called during scavenge/GC421static void update_pointers(); // Called after scavenge/GC422static bool is_empty();423static bool is_active() { return _active; }424static void set_active(bool value) { _active = value; }425};426427// A utility class to temporarily "deactivate" the DerivedPointerTable.428// (Note: clients are responsible for any MT-safety issues)429class DerivedPointerTableDeactivate: public StackObj {430private:431bool _active;432public:433DerivedPointerTableDeactivate() {434_active = DerivedPointerTable::is_active();435if (_active) {436DerivedPointerTable::set_active(false);437}438}439440~DerivedPointerTableDeactivate() {441assert(!DerivedPointerTable::is_active(),442"Inconsistency: not MT-safe");443if (_active) {444DerivedPointerTable::set_active(true);445}446}447};448#endif // COMPILER2_OR_JVMCI449450#endif // SHARE_COMPILER_OOPMAP_HPP451452453