Mercurial > hg > graal-jvmci-8
comparison src/share/vm/interpreter/rewriter.cpp @ 726:be93aad57795
6655646: dynamic languages need dynamically linked call sites
Summary: invokedynamic instruction (JSR 292 RI)
Reviewed-by: twisti, never
author | jrose |
---|---|
date | Tue, 21 Apr 2009 23:21:04 -0700 |
parents | 0fbdb4381b99 |
children | 75596850f863 |
comparison
equal
deleted
inserted
replaced
725:928912ce8438 | 726:be93aad57795 |
---|---|
23 */ | 23 */ |
24 | 24 |
25 # include "incls/_precompiled.incl" | 25 # include "incls/_precompiled.incl" |
26 # include "incls/_rewriter.cpp.incl" | 26 # include "incls/_rewriter.cpp.incl" |
27 | 27 |
28 | 28 // Computes a CPC map (new_index -> original_index) for constant pool entries |
29 // Computes an index_map (new_index -> original_index) for contant pool entries | |
30 // that are referred to by the interpreter at runtime via the constant pool cache. | 29 // that are referred to by the interpreter at runtime via the constant pool cache. |
31 void Rewriter::compute_index_maps(constantPoolHandle pool, intArray*& index_map, intStack*& inverse_index_map) { | 30 // Also computes a CP map (original_index -> new_index). |
32 const int length = pool->length(); | 31 // Marks entries in CP which require additional processing. |
33 index_map = new intArray(length, -1); | 32 void Rewriter::compute_index_maps() { |
34 // Choose an initial value large enough that we don't get frequent | 33 const int length = _pool->length(); |
35 // calls to grow(). | 34 init_cp_map(length); |
36 inverse_index_map = new intStack(length / 2); | |
37 for (int i = 0; i < length; i++) { | 35 for (int i = 0; i < length; i++) { |
38 switch (pool->tag_at(i).value()) { | 36 int tag = _pool->tag_at(i).value(); |
37 switch (tag) { | |
38 case JVM_CONSTANT_InterfaceMethodref: | |
39 case JVM_CONSTANT_Fieldref : // fall through | 39 case JVM_CONSTANT_Fieldref : // fall through |
40 case JVM_CONSTANT_Methodref : // fall through | 40 case JVM_CONSTANT_Methodref : // fall through |
41 case JVM_CONSTANT_InterfaceMethodref: { | 41 add_cp_cache_entry(i); |
42 index_map->at_put(i, inverse_index_map->length()); | 42 break; |
43 inverse_index_map->append(i); | 43 } |
44 } | 44 } |
45 } | 45 |
46 } | 46 guarantee((int)_cp_cache_map.length()-1 <= (int)((u2)-1), |
47 } | 47 "all cp cache indexes fit in a u2"); |
48 | 48 } |
49 | 49 |
50 // Creates a constant pool cache given an inverse_index_map | 50 |
51 int Rewriter::add_extra_cp_cache_entry(int main_entry) { | |
52 // Hack: We put it on the map as an encoded value. | |
53 // The only place that consumes this is ConstantPoolCacheEntry::set_initial_state | |
54 int encoded = constantPoolCacheOopDesc::encode_secondary_index(main_entry); | |
55 int plain_secondary_index = _cp_cache_map.append(encoded); | |
56 return constantPoolCacheOopDesc::encode_secondary_index(plain_secondary_index); | |
57 } | |
58 | |
59 | |
60 | |
61 // Creates a constant pool cache given a CPC map | |
51 // This creates the constant pool cache initially in a state | 62 // This creates the constant pool cache initially in a state |
52 // that is unsafe for concurrent GC processing but sets it to | 63 // that is unsafe for concurrent GC processing but sets it to |
53 // a safe mode before the constant pool cache is returned. | 64 // a safe mode before the constant pool cache is returned. |
54 constantPoolCacheHandle Rewriter::new_constant_pool_cache(intArray& inverse_index_map, TRAPS) { | 65 void Rewriter::make_constant_pool_cache(TRAPS) { |
55 const int length = inverse_index_map.length(); | 66 const int length = _cp_cache_map.length(); |
56 constantPoolCacheOop cache = oopFactory::new_constantPoolCache(length, | 67 constantPoolCacheOop cache = |
57 methodOopDesc::IsUnsafeConc, | 68 oopFactory::new_constantPoolCache(length, methodOopDesc::IsUnsafeConc, CHECK); |
58 CHECK_(constantPoolCacheHandle())); | 69 cache->initialize(_cp_cache_map); |
59 cache->initialize(inverse_index_map); | 70 _pool->set_cache(cache); |
60 return constantPoolCacheHandle(THREAD, cache); | 71 cache->set_constant_pool(_pool()); |
61 } | 72 } |
62 | 73 |
63 | 74 |
64 | 75 |
65 // The new finalization semantics says that registration of | 76 // The new finalization semantics says that registration of |
99 } | 110 } |
100 } | 111 } |
101 } | 112 } |
102 | 113 |
103 | 114 |
115 // Rewrite a classfile-order CP index into a native-order CPC index. | |
116 int Rewriter::rewrite_member_reference(address bcp, int offset) { | |
117 address p = bcp + offset; | |
118 int cp_index = Bytes::get_Java_u2(p); | |
119 int cache_index = cp_entry_to_cp_cache(cp_index); | |
120 Bytes::put_native_u2(p, cache_index); | |
121 return cp_index; | |
122 } | |
123 | |
124 | |
125 void Rewriter::rewrite_invokedynamic(address bcp, int offset, int delete_me) { | |
126 address p = bcp + offset; | |
127 assert(p[-1] == Bytecodes::_invokedynamic, ""); | |
128 int cp_index = Bytes::get_Java_u2(p); | |
129 int cpc = maybe_add_cp_cache_entry(cp_index); // add lazily | |
130 int cpc2 = add_extra_cp_cache_entry(cpc); | |
131 | |
132 // Replace the trailing four bytes with a CPC index for the dynamic | |
133 // call site. Unlike other CPC entries, there is one per bytecode, | |
134 // not just one per distinct CP entry. In other words, the | |
135 // CPC-to-CP relation is many-to-one for invokedynamic entries. | |
136 // This means we must use a larger index size than u2 to address | |
137 // all these entries. That is the main reason invokedynamic | |
138 // must have a five-byte instruction format. (Of course, other JVM | |
139 // implementations can use the bytes for other purposes.) | |
140 Bytes::put_native_u4(p, cpc2); | |
141 // Note: We use native_u4 format exclusively for 4-byte indexes. | |
142 } | |
143 | |
144 | |
104 // Rewrites a method given the index_map information | 145 // Rewrites a method given the index_map information |
105 methodHandle Rewriter::rewrite_method(methodHandle method, intArray& index_map, TRAPS) { | 146 void Rewriter::scan_method(methodOop method) { |
106 | 147 |
107 int nof_jsrs = 0; | 148 int nof_jsrs = 0; |
108 bool has_monitor_bytecodes = false; | 149 bool has_monitor_bytecodes = false; |
109 | 150 |
110 { | 151 { |
119 const int code_length = method->code_size(); | 160 const int code_length = method->code_size(); |
120 | 161 |
121 int bc_length; | 162 int bc_length; |
122 for (int bci = 0; bci < code_length; bci += bc_length) { | 163 for (int bci = 0; bci < code_length; bci += bc_length) { |
123 address bcp = code_base + bci; | 164 address bcp = code_base + bci; |
165 int prefix_length = 0; | |
124 c = (Bytecodes::Code)(*bcp); | 166 c = (Bytecodes::Code)(*bcp); |
125 | 167 |
126 // Since we have the code, see if we can get the length | 168 // Since we have the code, see if we can get the length |
127 // directly. Some more complicated bytecodes will report | 169 // directly. Some more complicated bytecodes will report |
128 // a length of zero, meaning we need to make another method | 170 // a length of zero, meaning we need to make another method |
133 | 175 |
134 // length_at will put us at the bytecode after the one modified | 176 // length_at will put us at the bytecode after the one modified |
135 // by 'wide'. We don't currently examine any of the bytecodes | 177 // by 'wide'. We don't currently examine any of the bytecodes |
136 // modified by wide, but in case we do in the future... | 178 // modified by wide, but in case we do in the future... |
137 if (c == Bytecodes::_wide) { | 179 if (c == Bytecodes::_wide) { |
180 prefix_length = 1; | |
138 c = (Bytecodes::Code)bcp[1]; | 181 c = (Bytecodes::Code)bcp[1]; |
139 } | 182 } |
140 } | 183 } |
141 | 184 |
142 assert(bc_length != 0, "impossible bytecode length"); | 185 assert(bc_length != 0, "impossible bytecode length"); |
157 case Bytecodes::_putstatic : // fall through | 200 case Bytecodes::_putstatic : // fall through |
158 case Bytecodes::_getfield : // fall through | 201 case Bytecodes::_getfield : // fall through |
159 case Bytecodes::_putfield : // fall through | 202 case Bytecodes::_putfield : // fall through |
160 case Bytecodes::_invokevirtual : // fall through | 203 case Bytecodes::_invokevirtual : // fall through |
161 case Bytecodes::_invokespecial : // fall through | 204 case Bytecodes::_invokespecial : // fall through |
162 case Bytecodes::_invokestatic : // fall through | 205 case Bytecodes::_invokestatic : |
163 case Bytecodes::_invokeinterface: { | 206 case Bytecodes::_invokeinterface: |
164 address p = bcp + 1; | 207 rewrite_member_reference(bcp, prefix_length+1); |
165 Bytes::put_native_u2(p, index_map[Bytes::get_Java_u2(p)]); | |
166 break; | 208 break; |
167 } | 209 case Bytecodes::_invokedynamic: |
210 rewrite_invokedynamic(bcp, prefix_length+1, int(sizeof"@@@@DELETE ME")); | |
211 break; | |
168 case Bytecodes::_jsr : // fall through | 212 case Bytecodes::_jsr : // fall through |
169 case Bytecodes::_jsr_w : nof_jsrs++; break; | 213 case Bytecodes::_jsr_w : nof_jsrs++; break; |
170 case Bytecodes::_monitorenter : // fall through | 214 case Bytecodes::_monitorenter : // fall through |
171 case Bytecodes::_monitorexit : has_monitor_bytecodes = true; break; | 215 case Bytecodes::_monitorexit : has_monitor_bytecodes = true; break; |
172 } | 216 } |
180 | 224 |
181 // The present of a jsr bytecode implies that the method might potentially | 225 // The present of a jsr bytecode implies that the method might potentially |
182 // have to be rewritten, so we run the oopMapGenerator on the method | 226 // have to be rewritten, so we run the oopMapGenerator on the method |
183 if (nof_jsrs > 0) { | 227 if (nof_jsrs > 0) { |
184 method->set_has_jsrs(); | 228 method->set_has_jsrs(); |
185 ResolveOopMapConflicts romc(method); | 229 // Second pass will revisit this method. |
186 methodHandle original_method = method; | 230 assert(method->has_jsrs(), ""); |
187 method = romc.do_potential_rewrite(CHECK_(methodHandle())); | 231 } |
188 if (method() != original_method()) { | 232 } |
189 // Insert invalid bytecode into original methodOop and set | 233 |
190 // interpreter entrypoint, so that a executing this method | 234 // After constant pool is created, revisit methods containing jsrs. |
191 // will manifest itself in an easy recognizable form. | 235 methodHandle Rewriter::rewrite_jsrs(methodHandle method, TRAPS) { |
192 address bcp = original_method->bcp_from(0); | 236 ResolveOopMapConflicts romc(method); |
193 *bcp = (u1)Bytecodes::_shouldnotreachhere; | 237 methodHandle original_method = method; |
194 int kind = Interpreter::method_kind(original_method); | 238 method = romc.do_potential_rewrite(CHECK_(methodHandle())); |
195 original_method->set_interpreter_kind(kind); | 239 if (method() != original_method()) { |
196 } | 240 // Insert invalid bytecode into original methodOop and set |
197 | 241 // interpreter entrypoint, so that a executing this method |
198 // Update monitor matching info. | 242 // will manifest itself in an easy recognizable form. |
199 if (romc.monitor_safe()) { | 243 address bcp = original_method->bcp_from(0); |
200 method->set_guaranteed_monitor_matching(); | 244 *bcp = (u1)Bytecodes::_shouldnotreachhere; |
201 } | 245 int kind = Interpreter::method_kind(original_method); |
202 } | 246 original_method->set_interpreter_kind(kind); |
203 | 247 } |
204 // Setup method entrypoints for compiler and interpreter | 248 |
205 method->link_method(method, CHECK_(methodHandle())); | 249 // Update monitor matching info. |
250 if (romc.monitor_safe()) { | |
251 method->set_guaranteed_monitor_matching(); | |
252 } | |
206 | 253 |
207 return method; | 254 return method; |
208 } | 255 } |
209 | 256 |
210 | 257 |
211 void Rewriter::rewrite(instanceKlassHandle klass, TRAPS) { | 258 void Rewriter::rewrite(instanceKlassHandle klass, TRAPS) { |
212 // gather starting points | |
213 ResourceMark rm(THREAD); | 259 ResourceMark rm(THREAD); |
214 constantPoolHandle pool (THREAD, klass->constants()); | 260 Rewriter rw(klass, CHECK); |
215 objArrayHandle methods (THREAD, klass->methods()); | 261 // (That's all, folks.) |
216 assert(pool->cache() == NULL, "constant pool cache must not be set yet"); | 262 } |
263 | |
264 Rewriter::Rewriter(instanceKlassHandle klass, TRAPS) | |
265 : _klass(klass), | |
266 // gather starting points | |
267 _pool( THREAD, klass->constants()), | |
268 _methods(THREAD, klass->methods()) | |
269 { | |
270 assert(_pool->cache() == NULL, "constant pool cache must not be set yet"); | |
217 | 271 |
218 // determine index maps for methodOop rewriting | 272 // determine index maps for methodOop rewriting |
219 intArray* index_map = NULL; | 273 compute_index_maps(); |
220 intStack* inverse_index_map = NULL; | 274 |
221 compute_index_maps(pool, index_map, inverse_index_map); | 275 if (RegisterFinalizersAtInit && _klass->name() == vmSymbols::java_lang_Object()) { |
222 | 276 int i = _methods->length(); |
223 // allocate constant pool cache | |
224 constantPoolCacheHandle cache = new_constant_pool_cache(*inverse_index_map, CHECK); | |
225 pool->set_cache(cache()); | |
226 cache->set_constant_pool(pool()); | |
227 | |
228 if (RegisterFinalizersAtInit && klass->name() == vmSymbols::java_lang_Object()) { | |
229 int i = methods->length(); | |
230 while (i-- > 0) { | 277 while (i-- > 0) { |
231 methodOop method = (methodOop)methods->obj_at(i); | 278 methodOop method = (methodOop)_methods->obj_at(i); |
232 if (method->intrinsic_id() == vmIntrinsics::_Object_init) { | 279 if (method->intrinsic_id() == vmIntrinsics::_Object_init) { |
233 // rewrite the return bytecodes of Object.<init> to register the | 280 // rewrite the return bytecodes of Object.<init> to register the |
234 // object for finalization if needed. | 281 // object for finalization if needed. |
235 methodHandle m(THREAD, method); | 282 methodHandle m(THREAD, method); |
236 rewrite_Object_init(m, CHECK); | 283 rewrite_Object_init(m, CHECK); |
237 break; | 284 break; |
238 } | 285 } |
239 } | 286 } |
240 } | 287 } |
241 | 288 |
242 // rewrite methods | 289 // rewrite methods, in two passes |
243 { int i = methods->length(); | 290 int i, len = _methods->length(); |
244 while (i-- > 0) { | 291 |
245 methodHandle m(THREAD, (methodOop)methods->obj_at(i)); | 292 for (i = len; --i >= 0; ) { |
246 m = rewrite_method(m, *index_map, CHECK); | 293 methodOop method = (methodOop)_methods->obj_at(i); |
294 scan_method(method); | |
295 } | |
296 | |
297 // allocate constant pool cache, now that we've seen all the bytecodes | |
298 make_constant_pool_cache(CHECK); | |
299 | |
300 for (i = len; --i >= 0; ) { | |
301 methodHandle m(THREAD, (methodOop)_methods->obj_at(i)); | |
302 | |
303 if (m->has_jsrs()) { | |
304 m = rewrite_jsrs(m, CHECK); | |
247 // Method might have gotten rewritten. | 305 // Method might have gotten rewritten. |
248 methods->obj_at_put(i, m()); | 306 _methods->obj_at_put(i, m()); |
249 } | 307 } |
250 } | 308 |
251 } | 309 // Set up method entry points for compiler and interpreter. |
310 m->link_method(m, CHECK); | |
311 } | |
312 } |