Path: blob/master/src/hotspot/share/code/oopRecorder.hpp
40931 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_CODE_OOPRECORDER_HPP25#define SHARE_CODE_OOPRECORDER_HPP2627#include "runtime/handles.hpp"28#include "utilities/growableArray.hpp"2930// Recording and retrieval of either oop relocations or metadata in compiled code.3132class CodeBlob;3334template <class T> class ValueRecorder : public StackObj {35public:36// A two-way mapping from positive indexes to oop handles.37// The zero index is reserved for a constant (sharable) null.38// Indexes may not be negative.3940// Use the given arena to manage storage, if not NULL.41// By default, uses the current ResourceArea.42ValueRecorder(Arena* arena = NULL);4344// Generate a new index on which nmethod::oop_addr_at will work.45// allocate_index and find_index never return the same index,46// and allocate_index never returns the same index twice.47// In fact, two successive calls to allocate_index return successive ints.48int allocate_index(T h) {49return add_handle(h, false);50}5152// For a given jobject or Metadata*, this will return the same index53// repeatedly. The index can later be given to nmethod::oop_at or54// metadata_at to retrieve the oop.55// However, the oop must not be changed via nmethod::oop_addr_at.56int find_index(T h) {57int index = maybe_find_index(h);58if (index < 0) { // previously unallocated59index = add_handle(h, true);60}61return index;62}6364// returns the size of the generated oop/metadata table, for sizing the65// CodeBlob. Must be called after all oops are allocated!66int size();6768// Retrieve the value at a given index.69T at(int index);7071int count() {72if (_handles == NULL) return 0;73// there is always a NULL virtually present as first object74return _handles->length() + first_index;75}7677// Helper function; returns false for NULL or Universe::non_oop_word().78inline bool is_real(T h);7980// copy the generated table to nmethod81void copy_values_to(nmethod* nm);8283bool is_unused() { return _handles == NULL && !_complete; }84#ifdef ASSERT85bool is_complete() { return _complete; }86#endif8788private:89// variant of find_index which does not allocate if not found (yields -1)90int maybe_find_index(T h);9192// leaky hash table of handle => index, to help detect duplicate insertion93template <class X> class IndexCache : public ResourceObj {94// This class is only used by the ValueRecorder class.95friend class ValueRecorder;96enum {97_log_cache_size = 9,98_cache_size = (1<<_log_cache_size),99// Index entries are ints. The LSBit is a collision indicator.100_collision_bit_shift = 0,101_collision_bit = 1,102_index_shift = _collision_bit_shift+1103};104int _cache[_cache_size];105static juint cache_index(X handle) {106juint ci = (int) (intptr_t) handle;107ci ^= ci >> (BitsPerByte*2);108ci += ci >> (BitsPerByte*1);109return ci & (_cache_size-1);110}111int* cache_location(X handle) {112return &_cache[ cache_index(handle) ];113}114static bool cache_location_collision(int* cloc) {115return ((*cloc) & _collision_bit) != 0;116}117static int cache_location_index(int* cloc) {118return (*cloc) >> _index_shift;119}120static void set_cache_location_index(int* cloc, int index) {121int cval0 = (*cloc);122int cval1 = (index << _index_shift);123if (cval0 != 0 && cval1 != cval0) cval1 += _collision_bit;124(*cloc) = cval1;125}126IndexCache();127};128129void maybe_initialize();130int add_handle(T h, bool make_findable);131132enum { null_index = 0, first_index = 1, index_cache_threshold = 20 };133134GrowableArray<T>* _handles; // ordered list (first is always NULL)135GrowableArray<int>* _no_finds; // all unfindable indexes; usually empty136IndexCache<T>* _indexes; // map: handle -> its probable index137Arena* _arena;138bool _complete;139140#ifdef ASSERT141static int _find_index_calls, _hit_indexes, _missed_indexes;142#endif143};144145class OopRecorder;146147class ObjectLookup : public ResourceObj {148private:149class ObjectEntry {150private:151jobject _value;152int _index;153154public:155ObjectEntry(jobject value, int index) : _value(value), _index(index) {}156ObjectEntry() : _value(NULL), _index(0) {}157oop oop_value() const;158int index() { return _index; }159};160161GrowableArray<ObjectEntry> _values;162unsigned int _gc_count;163164// Utility sort functions165static int sort_by_address(oop a, oop b);166static int sort_by_address(ObjectEntry* a, ObjectEntry* b);167static int sort_oop_by_address(oop const& a, ObjectEntry const& b);168169public:170ObjectLookup();171172// Resort list if a GC has occurred since the last sort173void maybe_resort();174int find_index(jobject object, OopRecorder* oop_recorder);175};176177class OopRecorder : public ResourceObj {178private:179ValueRecorder<jobject> _oops;180ValueRecorder<Metadata*> _metadata;181ObjectLookup* _object_lookup;182public:183OopRecorder(Arena* arena = NULL, bool deduplicate = false): _oops(arena), _metadata(arena) {184if (deduplicate) {185_object_lookup = new ObjectLookup();186} else {187_object_lookup = NULL;188}189}190191int allocate_oop_index(jobject h) {192return _oops.allocate_index(h);193}194virtual int find_index(jobject h) {195return _object_lookup != NULL ? _object_lookup->find_index(h, this) : _oops.find_index(h);196}197jobject oop_at(int index) {198return _oops.at(index);199}200int oop_size() {201return _oops.size();202}203int oop_count() {204return _oops.count();205}206inline bool is_real(jobject h);207208int allocate_metadata_index(Metadata* oop) {209return _metadata.allocate_index(oop);210}211virtual int find_index(Metadata* h) {212return _metadata.find_index(h);213}214Metadata* metadata_at(int index) {215return _metadata.at(index);216}217int metadata_size() {218return _metadata.size();219}220int metadata_count() {221return _metadata.count();222}223inline bool is_real(Metadata* h);224225bool is_unused() {226return _oops.is_unused() && _metadata.is_unused();227}228229void freeze() {230_oops.size();231_metadata.size();232}233234void copy_values_to(nmethod* nm) {235if (!_oops.is_unused()) {236_oops.copy_values_to(nm);237}238if (!_metadata.is_unused()) {239_metadata.copy_values_to(nm);240}241}242243#ifdef ASSERT244bool is_complete() {245assert(_oops.is_complete() == _metadata.is_complete(), "must agree");246return _oops.is_complete();247}248#endif249};250251252#endif // SHARE_CODE_OOPRECORDER_HPP253254255