Mercurial > hg > graal-compiler
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 |