comparison src/share/vm/code/oopRecorder.hpp @ 6725:da91efe96a93

6964458: Reimplement class meta-data storage to use native memory Summary: Remove PermGen, allocate meta-data in metaspace linked to class loaders, rewrite GC walking, rewrite and rename metadata to be C++ classes Reviewed-by: jmasa, stefank, never, coleenp, kvn, brutisso, mgerdin, dholmes, jrose, twisti, roland Contributed-by: jmasa <jon.masamitsu@oracle.com>, stefank <stefan.karlsson@oracle.com>, mgerdin <mikael.gerdin@oracle.com>, never <tom.rodriguez@oracle.com>
author coleenp
date Sat, 01 Sep 2012 13:25:18 -0400
parents f95d63e2154a
children 9928ad27a80e
comparison
equal deleted inserted replaced
6724:36d1d483d5d6 6725:da91efe96a93
1 /* 1 /*
2 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. 2 * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * 4 *
5 * This code is free software; you can redistribute it and/or modify it 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 6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
23 */ 23 */
24 24
25 #ifndef SHARE_VM_CODE_OOPRECORDER_HPP 25 #ifndef SHARE_VM_CODE_OOPRECORDER_HPP
26 #define SHARE_VM_CODE_OOPRECORDER_HPP 26 #define SHARE_VM_CODE_OOPRECORDER_HPP
27 27
28 #include "memory/universe.hpp"
28 #include "runtime/handles.hpp" 29 #include "runtime/handles.hpp"
29 #include "utilities/growableArray.hpp" 30 #include "utilities/growableArray.hpp"
30 31
31 // Recording and retrieval of oop relocations in compiled code. 32 // Recording and retrieval of either oop relocations or metadata in compiled code.
32 33
33 class CodeBlob; 34 class CodeBlob;
34 35
35 class OopRecorder : public ResourceObj { 36 template <class T> class ValueRecorder : public StackObj {
36 public: 37 public:
37 // A two-way mapping from positive indexes to oop handles. 38 // A two-way mapping from positive indexes to oop handles.
38 // The zero index is reserved for a constant (sharable) null. 39 // The zero index is reserved for a constant (sharable) null.
39 // Indexes may not be negative. 40 // Indexes may not be negative.
40 41
41 // Use the given arena to manage storage, if not NULL. 42 // Use the given arena to manage storage, if not NULL.
42 // By default, uses the current ResourceArea. 43 // By default, uses the current ResourceArea.
43 OopRecorder(Arena* arena = NULL); 44 ValueRecorder(Arena* arena = NULL);
44 45
45 // Generate a new index on which CodeBlob::oop_addr_at will work. 46 // Generate a new index on which nmethod::oop_addr_at will work.
46 // allocate_index and find_index never return the same index, 47 // allocate_index and find_index never return the same index,
47 // and allocate_index never returns the same index twice. 48 // and allocate_index never returns the same index twice.
48 // In fact, two successive calls to allocate_index return successive ints. 49 // In fact, two successive calls to allocate_index return successive ints.
49 int allocate_index(jobject h) { 50 int allocate_index(T h) {
50 return add_handle(h, false); 51 return add_handle(h, false);
51 } 52 }
52 53
53 // For a given jobject, this will return the same index repeatedly. 54 // For a given jobject or Metadata*, this will return the same index
54 // The index can later be given to oop_at to retrieve the oop. 55 // repeatedly. The index can later be given to nmethod::oop_at or
55 // However, the oop must not be changed via CodeBlob::oop_addr_at. 56 // metadata_at to retrieve the oop.
56 int find_index(jobject h) { 57 // However, the oop must not be changed via nmethod::oop_addr_at.
58 int find_index(T h) {
57 int index = maybe_find_index(h); 59 int index = maybe_find_index(h);
58 if (index < 0) { // previously unallocated 60 if (index < 0) { // previously unallocated
59 index = add_handle(h, true); 61 index = add_handle(h, true);
60 } 62 }
61 return index; 63 return index;
62 } 64 }
63 65
64 // variant of find_index which does not allocate if not found (yields -1) 66 // returns the size of the generated oop/metadata table, for sizing the
65 int maybe_find_index(jobject h); 67 // CodeBlob. Must be called after all oops are allocated!
66 68 int size();
67 // returns the size of the generated oop table, for sizing the CodeBlob. 69
68 // must be called after all oops are allocated! 70 // Retrieve the value at a given index.
69 int oop_size(); 71 T at(int index);
70 72
71 // Retrieve the oop handle at a given index. 73 int count() {
72 jobject handle_at(int index); 74 if (_handles == NULL) return 0;
73
74 int element_count() {
75 // there is always a NULL virtually present as first object 75 // there is always a NULL virtually present as first object
76 return _handles->length() + first_index; 76 return _handles->length() + first_index;
77 } 77 }
78 78
79 // copy the generated oop table to nmethod 79 // Helper function; returns false for NULL or Universe::non_oop_word().
80 void copy_to(nmethod* nm); // => nm->copy_oops(_handles) 80 bool is_real(T h) {
81 return h != NULL && h != (T)Universe::non_oop_word();
82 }
83
84 // copy the generated table to nmethod
85 void copy_values_to(nmethod* nm);
81 86
82 bool is_unused() { return _handles == NULL && !_complete; } 87 bool is_unused() { return _handles == NULL && !_complete; }
83 #ifdef ASSERT 88 #ifdef ASSERT
84 bool is_complete() { return _complete; } 89 bool is_complete() { return _complete; }
85 #endif 90 #endif
86 91
87 private: 92 private:
93 // variant of find_index which does not allocate if not found (yields -1)
94 int maybe_find_index(T h);
95
88 // leaky hash table of handle => index, to help detect duplicate insertion 96 // leaky hash table of handle => index, to help detect duplicate insertion
89 class IndexCache: public ResourceObj { 97 template <class X> class IndexCache : public ResourceObj {
90 // This class is only used by the OopRecorder class. 98 // This class is only used by the ValueRecorder class.
91 friend class OopRecorder; 99 friend class ValueRecorder;
92 enum { 100 enum {
93 _log_cache_size = 9, 101 _log_cache_size = 9,
94 _cache_size = (1<<_log_cache_size), 102 _cache_size = (1<<_log_cache_size),
95 // Index entries are ints. The LSBit is a collision indicator. 103 // Index entries are ints. The LSBit is a collision indicator.
96 _collision_bit_shift = 0, 104 _collision_bit_shift = 0,
97 _collision_bit = 1, 105 _collision_bit = 1,
98 _index_shift = _collision_bit_shift+1 106 _index_shift = _collision_bit_shift+1
99 }; 107 };
100 int _cache[_cache_size]; 108 int _cache[_cache_size];
101 static juint cache_index(jobject handle) { 109 static juint cache_index(X handle) {
102 juint ci = (int) (intptr_t) handle; 110 juint ci = (int) (intptr_t) handle;
103 ci ^= ci >> (BitsPerByte*2); 111 ci ^= ci >> (BitsPerByte*2);
104 ci += ci >> (BitsPerByte*1); 112 ci += ci >> (BitsPerByte*1);
105 return ci & (_cache_size-1); 113 return ci & (_cache_size-1);
106 } 114 }
107 int* cache_location(jobject handle) { 115 int* cache_location(X handle) {
108 return &_cache[ cache_index(handle) ]; 116 return &_cache[ cache_index(handle) ];
109 } 117 }
110 static bool cache_location_collision(int* cloc) { 118 static bool cache_location_collision(int* cloc) {
111 return ((*cloc) & _collision_bit) != 0; 119 return ((*cloc) & _collision_bit) != 0;
112 } 120 }
120 (*cloc) = cval1; 128 (*cloc) = cval1;
121 } 129 }
122 IndexCache(); 130 IndexCache();
123 }; 131 };
124 132
125 // Helper function; returns false for NULL or Universe::non_oop_word().
126 inline bool is_real_jobject(jobject h);
127
128 void maybe_initialize(); 133 void maybe_initialize();
129 int add_handle(jobject h, bool make_findable); 134 int add_handle(T h, bool make_findable);
130 135
131 enum { null_index = 0, first_index = 1, index_cache_threshold = 20 }; 136 enum { null_index = 0, first_index = 1, index_cache_threshold = 20 };
132 137
133 GrowableArray<jobject>* _handles; // ordered list (first is always NULL) 138 GrowableArray<T>* _handles; // ordered list (first is always NULL)
134 GrowableArray<int>* _no_finds; // all unfindable indexes; usually empty 139 GrowableArray<int>* _no_finds; // all unfindable indexes; usually empty
135 IndexCache* _indexes; // map: jobject -> its probable index 140 IndexCache<T>* _indexes; // map: handle -> its probable index
136 Arena* _arena; 141 Arena* _arena;
137 bool _complete; 142 bool _complete;
138 143
139 #ifdef ASSERT 144 #ifdef ASSERT
140 static int _find_index_calls, _hit_indexes, _missed_indexes; 145 static int _find_index_calls, _hit_indexes, _missed_indexes;
141 #endif 146 #endif
142 }; 147 };
143 148
149 class OopRecorder : public ResourceObj {
150 private:
151 ValueRecorder<jobject> _oops;
152 ValueRecorder<Metadata*> _metadata;
153 public:
154 OopRecorder(Arena* arena = NULL): _oops(arena), _metadata(arena) {}
155
156 int allocate_oop_index(jobject h) {
157 return _oops.allocate_index(h);
158 }
159 int find_index(jobject h) {
160 return _oops.find_index(h);
161 }
162 jobject oop_at(int index) {
163 return _oops.at(index);
164 }
165 int oop_size() {
166 return _oops.size();
167 }
168 int oop_count() {
169 return _oops.count();
170 }
171 bool is_real(jobject h) {
172 return _oops.is_real(h);
173 }
174
175 int allocate_metadata_index(Metadata* oop) {
176 return _metadata.allocate_index(oop);
177 }
178 int find_index(Metadata* h) {
179 return _metadata.find_index(h);
180 }
181 Metadata* metadata_at(int index) {
182 return _metadata.at(index);
183 }
184 int metadata_size() {
185 return _metadata.size();
186 }
187 int metadata_count() {
188 return _metadata.count();
189 }
190 bool is_real(Metadata* h) {
191 return _metadata.is_real(h);
192 }
193
194 bool is_unused() {
195 return _oops.is_unused() && _metadata.is_unused();
196 }
197
198 void freeze() {
199 _oops.size();
200 _metadata.size();
201 }
202
203 void copy_values_to(nmethod* nm) {
204 if (!_oops.is_unused()) {
205 _oops.copy_values_to(nm);
206 }
207 if (!_metadata.is_unused()) {
208 _metadata.copy_values_to(nm);
209 }
210 }
211
212 #ifdef ASSERT
213 bool is_complete() {
214 assert(_oops.is_complete() == _metadata.is_complete(), "must agree");
215 return _oops.is_complete();
216 }
217 #endif
218 };
219
220
144 #endif // SHARE_VM_CODE_OOPRECORDER_HPP 221 #endif // SHARE_VM_CODE_OOPRECORDER_HPP