oopRecorder.cpp revision 1472:c18cbe5936b8
1/*
2 * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25# include "incls/_precompiled.incl"
26# include "incls/_oopRecorder.cpp.incl"
27
28#ifdef ASSERT
29int OopRecorder::_find_index_calls = 0;
30int OopRecorder::_hit_indexes      = 0;
31int OopRecorder::_missed_indexes   = 0;
32#endif //ASSERT
33
34
35OopRecorder::OopRecorder(Arena* arena) {
36  _handles  = NULL;
37  _indexes  = NULL;
38  _arena    = arena;
39  _complete = false;
40}
41
42OopRecorder::IndexCache::IndexCache() {
43  assert(first_index > 0, "initial zero state of cache must be invalid index");
44  Copy::zero_to_bytes(&_cache[0], sizeof(_cache));
45}
46
47int OopRecorder::oop_size() {
48  _complete = true;
49  if (_handles == NULL)  return 0;
50  return _handles->length() * sizeof(oop);
51}
52
53void OopRecorder::copy_to(CodeBlob* code) {
54  assert(_complete, "must be frozen");
55  maybe_initialize();  // get non-null handles, even if we have no oops
56  code->copy_oops(_handles);
57}
58
59void OopRecorder::maybe_initialize() {
60  if (_handles == NULL) {
61    if (_arena != NULL) {
62      _handles  = new(_arena) GrowableArray<jobject>(_arena, 10, 0, 0);
63      _no_finds = new(_arena) GrowableArray<int>(    _arena, 10, 0, 0);
64    } else {
65      _handles  = new GrowableArray<jobject>(10, 0, 0);
66      _no_finds = new GrowableArray<int>(    10, 0, 0);
67    }
68  }
69}
70
71
72jobject OopRecorder::handle_at(int index) {
73  // there is always a NULL virtually present as first object
74  if (index == null_index)  return NULL;
75  return _handles->at(index - first_index);
76}
77
78
79// Local definition.  Used only in this module.
80inline bool OopRecorder::is_real_jobject(jobject h) {
81  return h != NULL && h != (jobject)Universe::non_oop_word();
82}
83
84
85int OopRecorder::add_handle(jobject h, bool make_findable) {
86  assert(!_complete, "cannot allocate more elements after size query");
87  maybe_initialize();
88  // indexing uses 1 as an origin--0 means null
89  int index = _handles->length() + first_index;
90  _handles->append(h);
91
92  // Support correct operation of find_index().
93  assert(!(make_findable && !is_real_jobject(h)), "nulls are not findable");
94  if (make_findable) {
95    // This index may be returned from find_index().
96    if (_indexes != NULL) {
97      int* cloc = _indexes->cache_location(h);
98      _indexes->set_cache_location_index(cloc, index);
99    } else if (index == index_cache_threshold && _arena != NULL) {
100      _indexes = new(_arena) IndexCache();
101      for (int i = 0; i < _handles->length(); i++) {
102        // Load the cache with pre-existing elements.
103        int index0 = i + first_index;
104        if (_no_finds->contains(index0))  continue;
105        int* cloc = _indexes->cache_location(_handles->at(i));
106        _indexes->set_cache_location_index(cloc, index0);
107      }
108    }
109  } else if (is_real_jobject(h)) {
110    // Remember that this index is not to be returned from find_index().
111    // This case is rare, because most or all uses of allocate_index pass
112    // a jobject argument of NULL or Universe::non_oop_word.
113    // Thus, the expected length of _no_finds is zero.
114    _no_finds->append(index);
115  }
116
117  return index;
118}
119
120
121int OopRecorder::maybe_find_index(jobject h) {
122  debug_only(_find_index_calls++);
123  assert(!_complete, "cannot allocate more elements after size query");
124  maybe_initialize();
125  if (h == NULL)  return null_index;
126  assert(is_real_jobject(h), "must be valid jobject");
127  int* cloc = (_indexes == NULL)? NULL: _indexes->cache_location(h);
128  if (cloc != NULL) {
129    int cindex = _indexes->cache_location_index(cloc);
130    if (cindex == 0) {
131      return -1;   // We know this handle is completely new.
132    }
133    if (cindex >= first_index && _handles->at(cindex - first_index) == h) {
134      debug_only(_hit_indexes++);
135      return cindex;
136    }
137    if (!_indexes->cache_location_collision(cloc)) {
138      return -1;   // We know the current cache occupant is unique to that cloc.
139    }
140  }
141
142  // Not found in cache, due to a cache collision.  (Or, no cache at all.)
143  // Do a linear search, most recent to oldest.
144  for (int i = _handles->length() - 1; i >= 0; i--) {
145    if (_handles->at(i) == h) {
146      int findex = i + first_index;
147      if (_no_finds->contains(findex))  continue;  // oops; skip this one
148      if (cloc != NULL) {
149        _indexes->set_cache_location_index(cloc, findex);
150      }
151      debug_only(_missed_indexes++);
152      return findex;
153    }
154  }
155  return -1;
156}
157