Mercurial > hg > graal-compiler
annotate src/share/vm/interpreter/bytecode.hpp @ 1711:a6bff45449bc
6973570: OrderAccess::storestore() scales poorly on multi-socket x64 and sparc: cache-line ping-ponging
Summary: volatile store to static variable removed in favour of a volatile store to stack to avoid excessive cache coherency traffic; verified that the volatile store is not elided by any of our current compilers.
Reviewed-by: dholmes, dice, jcoomes, kvn
author | ysr |
---|---|
date | Tue, 10 Aug 2010 14:53:35 -0700 |
parents | 136b78722a08 |
children | f95d63e2154a |
rev | line source |
---|---|
0 | 1 /* |
1579 | 2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1138
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1138
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1138
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
25 // Base class for different kinds of abstractions working | |
26 // relative to an objects 'this' pointer. | |
27 | |
28 class ThisRelativeObj VALUE_OBJ_CLASS_SPEC { | |
29 public: | |
30 // Address computation | |
31 address addr_at (int offset) const { return (address)this + offset; } | |
1565 | 32 int byte_at (int offset) const { return *(addr_at(offset)); } |
0 | 33 address aligned_addr_at (int offset) const { return (address)round_to((intptr_t)addr_at(offset), jintSize); } |
34 int aligned_offset (int offset) const { return aligned_addr_at(offset) - addr_at(0); } | |
35 | |
1565 | 36 // Word access: |
37 int get_Java_u2_at (int offset) const { return Bytes::get_Java_u2(addr_at(offset)); } | |
38 int get_Java_u4_at (int offset) const { return Bytes::get_Java_u4(addr_at(offset)); } | |
39 int get_native_u2_at (int offset) const { return Bytes::get_native_u2(addr_at(offset)); } | |
40 int get_native_u4_at (int offset) const { return Bytes::get_native_u4(addr_at(offset)); } | |
0 | 41 }; |
42 | |
43 | |
44 // The base class for different kinds of bytecode abstractions. | |
45 // Provides the primitive operations to manipulate code relative | |
46 // to an objects 'this' pointer. | |
1565 | 47 // FIXME: Make this a ResourceObj, include the enclosing methodOop, and cache the opcode. |
0 | 48 |
49 class Bytecode: public ThisRelativeObj { | |
50 protected: | |
51 u_char byte_at(int offset) const { return *addr_at(offset); } | |
1565 | 52 bool check_must_rewrite(Bytecodes::Code bc) const; |
0 | 53 |
54 public: | |
55 // Attributes | |
56 address bcp() const { return addr_at(0); } | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
0
diff
changeset
|
57 int instruction_size() const { return Bytecodes::length_at(bcp()); } |
0 | 58 |
1565 | 59 // Warning: Use code() with caution on live bytecode streams. 4926272 |
0 | 60 Bytecodes::Code code() const { return Bytecodes::code_at(addr_at(0)); } |
61 Bytecodes::Code java_code() const { return Bytecodes::java_code(code()); } | |
1565 | 62 bool must_rewrite(Bytecodes::Code code) const { return Bytecodes::can_rewrite(code) && check_must_rewrite(code); } |
0 | 63 |
64 // Creation | |
65 inline friend Bytecode* Bytecode_at(address bcp); | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
0
diff
changeset
|
66 |
1565 | 67 // Static functions for parsing bytecodes in place. |
68 int get_index_u1(Bytecodes::Code bc) const { | |
69 assert_same_format_as(bc); assert_index_size(1, bc); | |
70 return *(jubyte*)addr_at(1); | |
71 } | |
72 int get_index_u2(Bytecodes::Code bc, bool is_wide = false) const { | |
73 assert_same_format_as(bc, is_wide); assert_index_size(2, bc, is_wide); | |
74 address p = addr_at(is_wide ? 2 : 1); | |
75 if (can_use_native_byte_order(bc, is_wide)) | |
76 return Bytes::get_native_u2(p); | |
77 else return Bytes::get_Java_u2(p); | |
78 } | |
1602 | 79 int get_index_u1_cpcache(Bytecodes::Code bc) const { |
80 assert_same_format_as(bc); assert_index_size(1, bc); | |
81 return *(jubyte*)addr_at(1) + constantPoolOopDesc::CPCACHE_INDEX_TAG; | |
82 } | |
1565 | 83 int get_index_u2_cpcache(Bytecodes::Code bc) const { |
84 assert_same_format_as(bc); assert_index_size(2, bc); assert_native_index(bc); | |
1602 | 85 return Bytes::get_native_u2(addr_at(1)) + constantPoolOopDesc::CPCACHE_INDEX_TAG; |
1565 | 86 } |
87 int get_index_u4(Bytecodes::Code bc) const { | |
88 assert_same_format_as(bc); assert_index_size(4, bc); | |
89 assert(can_use_native_byte_order(bc), ""); | |
90 return Bytes::get_native_u4(addr_at(1)); | |
91 } | |
92 bool has_index_u4(Bytecodes::Code bc) const { | |
93 return bc == Bytecodes::_invokedynamic; | |
94 } | |
95 | |
96 int get_offset_s2(Bytecodes::Code bc) const { | |
97 assert_same_format_as(bc); assert_offset_size(2, bc); | |
98 return (jshort) Bytes::get_Java_u2(addr_at(1)); | |
99 } | |
100 int get_offset_s4(Bytecodes::Code bc) const { | |
101 assert_same_format_as(bc); assert_offset_size(4, bc); | |
102 return (jint) Bytes::get_Java_u4(addr_at(1)); | |
103 } | |
104 | |
105 int get_constant_u1(int offset, Bytecodes::Code bc) const { | |
106 assert_same_format_as(bc); assert_constant_size(1, offset, bc); | |
107 return *(jbyte*)addr_at(offset); | |
108 } | |
109 int get_constant_u2(int offset, Bytecodes::Code bc, bool is_wide = false) const { | |
110 assert_same_format_as(bc, is_wide); assert_constant_size(2, offset, bc, is_wide); | |
111 return (jshort) Bytes::get_Java_u2(addr_at(offset)); | |
112 } | |
113 | |
114 // These are used locally and also from bytecode streams. | |
115 void assert_same_format_as(Bytecodes::Code testbc, bool is_wide = false) const NOT_DEBUG_RETURN; | |
116 static void assert_index_size(int required_size, Bytecodes::Code bc, bool is_wide = false) NOT_DEBUG_RETURN; | |
117 static void assert_offset_size(int required_size, Bytecodes::Code bc, bool is_wide = false) NOT_DEBUG_RETURN; | |
118 static void assert_constant_size(int required_size, int where, Bytecodes::Code bc, bool is_wide = false) NOT_DEBUG_RETURN; | |
119 static void assert_native_index(Bytecodes::Code bc, bool is_wide = false) NOT_DEBUG_RETURN; | |
120 static bool can_use_native_byte_order(Bytecodes::Code bc, bool is_wide = false) { | |
121 return (!Bytes::is_Java_byte_ordering_different() || Bytecodes::native_byte_order(bc /*, is_wide*/)); | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
0
diff
changeset
|
122 } |
0 | 123 }; |
124 | |
125 inline Bytecode* Bytecode_at(address bcp) { | |
1565 | 126 // Warning: Use with caution on live bytecode streams. 4926272 |
0 | 127 return (Bytecode*)bcp; |
128 } | |
129 | |
130 | |
131 // Abstractions for lookupswitch bytecode | |
132 | |
133 class LookupswitchPair: ThisRelativeObj { | |
134 private: | |
135 int _match; | |
136 int _offset; | |
137 | |
138 public: | |
1565 | 139 int match() const { return get_Java_u4_at(0 * jintSize); } |
140 int offset() const { return get_Java_u4_at(1 * jintSize); } | |
0 | 141 }; |
142 | |
143 | |
144 class Bytecode_lookupswitch: public Bytecode { | |
145 public: | |
146 void verify() const PRODUCT_RETURN; | |
147 | |
148 // Attributes | |
1565 | 149 int default_offset() const { return get_Java_u4_at(aligned_offset(1 + 0*jintSize)); } |
150 int number_of_pairs() const { return get_Java_u4_at(aligned_offset(1 + 1*jintSize)); } | |
0 | 151 LookupswitchPair* pair_at(int i) const { assert(0 <= i && i < number_of_pairs(), "pair index out of bounds"); |
152 return (LookupswitchPair*)aligned_addr_at(1 + (1 + i)*2*jintSize); } | |
153 // Creation | |
154 inline friend Bytecode_lookupswitch* Bytecode_lookupswitch_at(address bcp); | |
155 }; | |
156 | |
157 inline Bytecode_lookupswitch* Bytecode_lookupswitch_at(address bcp) { | |
158 Bytecode_lookupswitch* b = (Bytecode_lookupswitch*)bcp; | |
1602 | 159 DEBUG_ONLY(b->verify()); |
0 | 160 return b; |
161 } | |
162 | |
163 | |
164 class Bytecode_tableswitch: public Bytecode { | |
165 public: | |
166 void verify() const PRODUCT_RETURN; | |
167 | |
168 // Attributes | |
1565 | 169 int default_offset() const { return get_Java_u4_at(aligned_offset(1 + 0*jintSize)); } |
170 int low_key() const { return get_Java_u4_at(aligned_offset(1 + 1*jintSize)); } | |
171 int high_key() const { return get_Java_u4_at(aligned_offset(1 + 2*jintSize)); } | |
0 | 172 int dest_offset_at(int i) const; |
173 int length() { return high_key()-low_key()+1; } | |
174 | |
175 // Creation | |
176 inline friend Bytecode_tableswitch* Bytecode_tableswitch_at(address bcp); | |
177 }; | |
178 | |
179 inline Bytecode_tableswitch* Bytecode_tableswitch_at(address bcp) { | |
180 Bytecode_tableswitch* b = (Bytecode_tableswitch*)bcp; | |
1602 | 181 DEBUG_ONLY(b->verify()); |
0 | 182 return b; |
183 } | |
184 | |
185 | |
1602 | 186 // Common code for decoding invokes and field references. |
0 | 187 |
1602 | 188 class Bytecode_member_ref: public ResourceObj { |
0 | 189 protected: |
190 methodHandle _method; // method containing the bytecode | |
191 int _bci; // position of the bytecode | |
192 | |
1602 | 193 Bytecode_member_ref(methodHandle method, int bci) : _method(method), _bci(bci) {} |
194 | |
195 public: | |
196 // Attributes | |
197 methodHandle method() const { return _method; } | |
198 int bci() const { return _bci; } | |
199 address bcp() const { return _method->bcp_from(bci()); } | |
200 Bytecode* bytecode() const { return Bytecode_at(bcp()); } | |
201 | |
202 int index() const; // cache index (loaded from instruction) | |
203 int pool_index() const; // constant pool index | |
204 symbolOop name() const; // returns the name of the method or field | |
205 symbolOop signature() const; // returns the signature of the method or field | |
206 | |
207 BasicType result_type(Thread* thread) const; // returns the result type of the getfield or invoke | |
208 | |
209 Bytecodes::Code code() const { return Bytecodes::code_at(bcp(), _method()); } | |
210 Bytecodes::Code java_code() const { return Bytecodes::java_code(code()); } | |
211 }; | |
212 | |
213 // Abstraction for invoke_{virtual, static, interface, special} | |
214 | |
215 class Bytecode_invoke: public Bytecode_member_ref { | |
216 protected: | |
217 Bytecode_invoke(methodHandle method, int bci) : Bytecode_member_ref(method, bci) {} | |
0 | 218 |
219 public: | |
220 void verify() const; | |
221 | |
222 // Attributes | |
223 methodHandle static_target(TRAPS); // "specified" method (from constant pool) | |
224 | |
225 // Testers | |
1602 | 226 bool is_invokeinterface() const { return java_code() == Bytecodes::_invokeinterface; } |
227 bool is_invokevirtual() const { return java_code() == Bytecodes::_invokevirtual; } | |
228 bool is_invokestatic() const { return java_code() == Bytecodes::_invokestatic; } | |
229 bool is_invokespecial() const { return java_code() == Bytecodes::_invokespecial; } | |
230 bool is_invokedynamic() const { return java_code() == Bytecodes::_invokedynamic; } | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
0
diff
changeset
|
231 |
1138
dd57230ba8fe
6893268: additional dynamic language related optimizations in C2
twisti
parents:
1135
diff
changeset
|
232 bool has_receiver() const { return !is_invokestatic() && !is_invokedynamic(); } |
0 | 233 |
234 bool is_valid() const { return is_invokeinterface() || | |
235 is_invokevirtual() || | |
236 is_invokestatic() || | |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
844
diff
changeset
|
237 is_invokespecial() || |
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
844
diff
changeset
|
238 is_invokedynamic(); } |
0 | 239 |
240 // Creation | |
241 inline friend Bytecode_invoke* Bytecode_invoke_at(methodHandle method, int bci); | |
242 | |
243 // Like Bytecode_invoke_at. Instead it returns NULL if the bci is not at an invoke. | |
244 inline friend Bytecode_invoke* Bytecode_invoke_at_check(methodHandle method, int bci); | |
245 }; | |
246 | |
247 inline Bytecode_invoke* Bytecode_invoke_at(methodHandle method, int bci) { | |
248 Bytecode_invoke* b = new Bytecode_invoke(method, bci); | |
1602 | 249 DEBUG_ONLY(b->verify()); |
0 | 250 return b; |
251 } | |
252 | |
253 inline Bytecode_invoke* Bytecode_invoke_at_check(methodHandle method, int bci) { | |
254 Bytecode_invoke* b = new Bytecode_invoke(method, bci); | |
255 return b->is_valid() ? b : NULL; | |
256 } | |
257 | |
258 | |
1602 | 259 // Abstraction for all field accesses (put/get field/static) |
260 class Bytecode_field: public Bytecode_member_ref { | |
261 protected: | |
262 Bytecode_field(methodHandle method, int bci) : Bytecode_member_ref(method, bci) {} | |
263 | |
264 public: | |
265 // Testers | |
266 bool is_getfield() const { return java_code() == Bytecodes::_getfield; } | |
267 bool is_putfield() const { return java_code() == Bytecodes::_putfield; } | |
268 bool is_getstatic() const { return java_code() == Bytecodes::_getstatic; } | |
269 bool is_putstatic() const { return java_code() == Bytecodes::_putstatic; } | |
270 | |
271 bool is_getter() const { return is_getfield() || is_getstatic(); } | |
272 bool is_static() const { return is_getstatic() || is_putstatic(); } | |
273 | |
274 bool is_valid() const { return is_getfield() || | |
275 is_putfield() || | |
276 is_getstatic() || | |
277 is_putstatic(); } | |
0 | 278 void verify() const; |
279 | |
280 // Creation | |
1602 | 281 inline friend Bytecode_field* Bytecode_field_at(methodHandle method, int bci); |
0 | 282 }; |
283 | |
1602 | 284 inline Bytecode_field* Bytecode_field_at(methodHandle method, int bci) { |
285 Bytecode_field* b = new Bytecode_field(method, bci); | |
286 DEBUG_ONLY(b->verify()); | |
0 | 287 return b; |
288 } | |
289 | |
290 | |
291 // Abstraction for checkcast | |
292 | |
293 class Bytecode_checkcast: public Bytecode { | |
294 public: | |
295 void verify() const { assert(Bytecodes::java_code(code()) == Bytecodes::_checkcast, "check checkcast"); } | |
296 | |
297 // Returns index | |
1565 | 298 long index() const { return get_index_u2(Bytecodes::_checkcast); }; |
0 | 299 |
300 // Creation | |
301 inline friend Bytecode_checkcast* Bytecode_checkcast_at(address bcp); | |
302 }; | |
303 | |
304 inline Bytecode_checkcast* Bytecode_checkcast_at(address bcp) { | |
305 Bytecode_checkcast* b = (Bytecode_checkcast*)bcp; | |
1602 | 306 DEBUG_ONLY(b->verify()); |
0 | 307 return b; |
308 } | |
309 | |
310 | |
311 // Abstraction for instanceof | |
312 | |
313 class Bytecode_instanceof: public Bytecode { | |
314 public: | |
315 void verify() const { assert(code() == Bytecodes::_instanceof, "check instanceof"); } | |
316 | |
317 // Returns index | |
1565 | 318 long index() const { return get_index_u2(Bytecodes::_instanceof); }; |
0 | 319 |
320 // Creation | |
321 inline friend Bytecode_instanceof* Bytecode_instanceof_at(address bcp); | |
322 }; | |
323 | |
324 inline Bytecode_instanceof* Bytecode_instanceof_at(address bcp) { | |
325 Bytecode_instanceof* b = (Bytecode_instanceof*)bcp; | |
1602 | 326 DEBUG_ONLY(b->verify()); |
0 | 327 return b; |
328 } | |
329 | |
330 | |
331 class Bytecode_new: public Bytecode { | |
332 public: | |
333 void verify() const { assert(java_code() == Bytecodes::_new, "check new"); } | |
334 | |
335 // Returns index | |
1565 | 336 long index() const { return get_index_u2(Bytecodes::_new); }; |
0 | 337 |
338 // Creation | |
339 inline friend Bytecode_new* Bytecode_new_at(address bcp); | |
340 }; | |
341 | |
342 inline Bytecode_new* Bytecode_new_at(address bcp) { | |
343 Bytecode_new* b = (Bytecode_new*)bcp; | |
1602 | 344 DEBUG_ONLY(b->verify()); |
0 | 345 return b; |
346 } | |
347 | |
348 | |
349 class Bytecode_multianewarray: public Bytecode { | |
350 public: | |
351 void verify() const { assert(java_code() == Bytecodes::_multianewarray, "check new"); } | |
352 | |
353 // Returns index | |
1565 | 354 long index() const { return get_index_u2(Bytecodes::_multianewarray); }; |
0 | 355 |
356 // Creation | |
357 inline friend Bytecode_multianewarray* Bytecode_multianewarray_at(address bcp); | |
358 }; | |
359 | |
360 inline Bytecode_multianewarray* Bytecode_multianewarray_at(address bcp) { | |
361 Bytecode_multianewarray* b = (Bytecode_multianewarray*)bcp; | |
1602 | 362 DEBUG_ONLY(b->verify()); |
0 | 363 return b; |
364 } | |
365 | |
366 | |
367 class Bytecode_anewarray: public Bytecode { | |
368 public: | |
369 void verify() const { assert(java_code() == Bytecodes::_anewarray, "check anewarray"); } | |
370 | |
371 // Returns index | |
1565 | 372 long index() const { return get_index_u2(Bytecodes::_anewarray); }; |
0 | 373 |
374 // Creation | |
375 inline friend Bytecode_anewarray* Bytecode_anewarray_at(address bcp); | |
376 }; | |
377 | |
378 inline Bytecode_anewarray* Bytecode_anewarray_at(address bcp) { | |
379 Bytecode_anewarray* b = (Bytecode_anewarray*)bcp; | |
1602 | 380 DEBUG_ONLY(b->verify()); |
0 | 381 return b; |
382 } | |
383 | |
384 | |
385 // Abstraction for ldc, ldc_w and ldc2_w | |
386 | |
1602 | 387 class Bytecode_loadconstant: public ResourceObj { |
388 private: | |
389 int _bci; | |
390 methodHandle _method; | |
391 | |
392 Bytecodes::Code code() const { return bytecode()->code(); } | |
393 | |
394 int raw_index() const; | |
395 | |
396 Bytecode_loadconstant(methodHandle method, int bci) : _method(method), _bci(bci) {} | |
397 | |
0 | 398 public: |
1602 | 399 // Attributes |
400 methodHandle method() const { return _method; } | |
401 int bci() const { return _bci; } | |
402 address bcp() const { return _method->bcp_from(bci()); } | |
403 Bytecode* bytecode() const { return Bytecode_at(bcp()); } | |
404 | |
0 | 405 void verify() const { |
1602 | 406 assert(_method.not_null(), "must supply method"); |
0 | 407 Bytecodes::Code stdc = Bytecodes::java_code(code()); |
408 assert(stdc == Bytecodes::_ldc || | |
409 stdc == Bytecodes::_ldc_w || | |
410 stdc == Bytecodes::_ldc2_w, "load constant"); | |
411 } | |
412 | |
1602 | 413 // Only non-standard bytecodes (fast_aldc) have CP cache indexes. |
414 bool has_cache_index() const { return code() >= Bytecodes::number_of_java_codes; } | |
0 | 415 |
1602 | 416 int pool_index() const; // index into constant pool |
417 int cache_index() const { // index into CP cache (or -1 if none) | |
418 return has_cache_index() ? raw_index() : -1; | |
419 } | |
420 | |
421 BasicType result_type() const; // returns the result type of the ldc | |
422 | |
423 oop resolve_constant(TRAPS) const; | |
424 | |
425 // Creation | |
426 inline friend Bytecode_loadconstant* Bytecode_loadconstant_at(methodHandle method, int bci); | |
0 | 427 }; |
428 | |
1602 | 429 inline Bytecode_loadconstant* Bytecode_loadconstant_at(methodHandle method, int bci) { |
430 Bytecode_loadconstant* b = new Bytecode_loadconstant(method, bci); | |
431 DEBUG_ONLY(b->verify()); | |
0 | 432 return b; |
433 } |