0N/A/*
1499N/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#ifndef SHARE_VM_CODE_OOPRECORDER_HPP
1879N/A#define SHARE_VM_CODE_OOPRECORDER_HPP
1879N/A
1879N/A#include "runtime/handles.hpp"
1879N/A#include "utilities/growableArray.hpp"
1879N/A
0N/A// Recording and retrieval of oop relocations in compiled code.
0N/A
0N/Aclass CodeBlob;
0N/A
0N/Aclass OopRecorder : public ResourceObj {
0N/A public:
0N/A // A two-way mapping from positive indexes to oop handles.
0N/A // The zero index is reserved for a constant (sharable) null.
0N/A // Indexes may not be negative.
0N/A
0N/A // Use the given arena to manage storage, if not NULL.
0N/A // By default, uses the current ResourceArea.
0N/A OopRecorder(Arena* arena = NULL);
0N/A
0N/A // Generate a new index on which CodeBlob::oop_addr_at will work.
0N/A // allocate_index and find_index never return the same index,
0N/A // and allocate_index never returns the same index twice.
0N/A // In fact, two successive calls to allocate_index return successive ints.
0N/A int allocate_index(jobject h) {
0N/A return add_handle(h, false);
0N/A }
0N/A
0N/A // For a given jobject, this will return the same index repeatedly.
0N/A // The index can later be given to oop_at to retrieve the oop.
0N/A // However, the oop must not be changed via CodeBlob::oop_addr_at.
0N/A int find_index(jobject h) {
0N/A int index = maybe_find_index(h);
0N/A if (index < 0) { // previously unallocated
0N/A index = add_handle(h, true);
0N/A }
0N/A return index;
0N/A }
0N/A
0N/A // variant of find_index which does not allocate if not found (yields -1)
0N/A int maybe_find_index(jobject h);
0N/A
0N/A // returns the size of the generated oop table, for sizing the CodeBlob.
0N/A // must be called after all oops are allocated!
0N/A int oop_size();
0N/A
0N/A // Retrieve the oop handle at a given index.
0N/A jobject handle_at(int index);
0N/A
0N/A int element_count() {
0N/A // there is always a NULL virtually present as first object
0N/A return _handles->length() + first_index;
0N/A }
0N/A
1483N/A // copy the generated oop table to nmethod
1483N/A void copy_to(nmethod* nm); // => nm->copy_oops(_handles)
0N/A
0N/A bool is_unused() { return _handles == NULL && !_complete; }
0N/A#ifdef ASSERT
0N/A bool is_complete() { return _complete; }
0N/A#endif
0N/A
0N/A private:
0N/A // leaky hash table of handle => index, to help detect duplicate insertion
0N/A class IndexCache: public ResourceObj {
0N/A // This class is only used by the OopRecorder class.
0N/A friend class OopRecorder;
0N/A enum {
0N/A _log_cache_size = 9,
0N/A _cache_size = (1<<_log_cache_size),
0N/A // Index entries are ints. The LSBit is a collision indicator.
0N/A _collision_bit_shift = 0,
0N/A _collision_bit = 1,
0N/A _index_shift = _collision_bit_shift+1
0N/A };
0N/A int _cache[_cache_size];
0N/A static juint cache_index(jobject handle) {
0N/A juint ci = (int) (intptr_t) handle;
0N/A ci ^= ci >> (BitsPerByte*2);
0N/A ci += ci >> (BitsPerByte*1);
0N/A return ci & (_cache_size-1);
0N/A }
0N/A int* cache_location(jobject handle) {
0N/A return &_cache[ cache_index(handle) ];
0N/A }
0N/A static bool cache_location_collision(int* cloc) {
0N/A return ((*cloc) & _collision_bit) != 0;
0N/A }
0N/A static int cache_location_index(int* cloc) {
0N/A return (*cloc) >> _index_shift;
0N/A }
0N/A static void set_cache_location_index(int* cloc, int index) {
0N/A int cval0 = (*cloc);
0N/A int cval1 = (index << _index_shift);
0N/A if (cval0 != 0 && cval1 != cval0) cval1 += _collision_bit;
0N/A (*cloc) = cval1;
0N/A }
0N/A IndexCache();
0N/A };
0N/A
0N/A // Helper function; returns false for NULL or Universe::non_oop_word().
0N/A inline bool is_real_jobject(jobject h);
0N/A
0N/A void maybe_initialize();
0N/A int add_handle(jobject h, bool make_findable);
0N/A
0N/A enum { null_index = 0, first_index = 1, index_cache_threshold = 20 };
0N/A
0N/A GrowableArray<jobject>* _handles; // ordered list (first is always NULL)
0N/A GrowableArray<int>* _no_finds; // all unfindable indexes; usually empty
0N/A IndexCache* _indexes; // map: jobject -> its probable index
0N/A Arena* _arena;
0N/A bool _complete;
0N/A
0N/A#ifdef ASSERT
0N/A static int _find_index_calls, _hit_indexes, _missed_indexes;
0N/A#endif
0N/A};
1879N/A
1879N/A#endif // SHARE_VM_CODE_OOPRECORDER_HPP