Mercurial > hg > truffle
annotate src/cpu/x86/vm/interp_masm_x86_64.cpp @ 20304:a22acf6d7598
8048112: G1 Full GC needs to support the case when the very first region is not available
Summary: Refactor preparation for compaction during Full GC so that it lazily initializes the first compaction point. This also avoids problems later when the first region may not be committed. Also reviewed by K. Barrett.
Reviewed-by: brutisso
author | tschatzl |
---|---|
date | Mon, 21 Jul 2014 10:00:31 +0200 |
parents | ea79ab313e98 |
children | 096c224171c4 d3f14809b051 |
rev | line source |
---|---|
0 | 1 /* |
10105
aeaca88565e6
8010862: The Method counter fields used for profiling can be allocated lazily.
jiangli
parents:
7180
diff
changeset
|
2 * Copyright (c) 2003, 2013, 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:
1506
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
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:
1506
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
12962
5ccbab1c69f3
8026251: New type profiling points: parameters to methods
roland
parents:
12882
diff
changeset
|
26 #include "interp_masm_x86.hpp" |
1972 | 27 #include "interpreter/interpreter.hpp" |
28 #include "interpreter/interpreterRuntime.hpp" | |
29 #include "oops/arrayOop.hpp" | |
30 #include "oops/markOop.hpp" | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
31 #include "oops/methodData.hpp" |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
32 #include "oops/method.hpp" |
1972 | 33 #include "prims/jvmtiExport.hpp" |
34 #include "prims/jvmtiRedefineClassesTrace.hpp" | |
35 #include "prims/jvmtiThreadState.hpp" | |
36 #include "runtime/basicLock.hpp" | |
37 #include "runtime/biasedLocking.hpp" | |
38 #include "runtime/sharedRuntime.hpp" | |
7180
f34d701e952e
8003935: Simplify the needed includes for using Thread::current()
stefank
parents:
6725
diff
changeset
|
39 #include "runtime/thread.inline.hpp" |
0 | 40 |
41 | |
42 // Implementation of InterpreterMacroAssembler | |
43 | |
304 | 44 #ifdef CC_INTERP |
45 void InterpreterMacroAssembler::get_method(Register reg) { | |
520
52a431267315
6791168: Fix invalid code in bytecodeInterpreter that can cause gcc ICE
coleenp
parents:
362
diff
changeset
|
46 movptr(reg, Address(rbp, -((int)sizeof(BytecodeInterpreter) + 2 * wordSize))); |
304 | 47 movptr(reg, Address(reg, byte_offset_of(BytecodeInterpreter, _method))); |
48 } | |
49 #endif // CC_INTERP | |
50 | |
51 #ifndef CC_INTERP | |
52 | |
0 | 53 void InterpreterMacroAssembler::call_VM_leaf_base(address entry_point, |
54 int number_of_arguments) { | |
55 // interpreter specific | |
56 // | |
57 // Note: No need to save/restore bcp & locals (r13 & r14) pointer | |
58 // since these are callee saved registers and no blocking/ | |
59 // GC can happen in leaf calls. | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
60 // Further Note: DO NOT save/restore bcp/locals. If a caller has |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
61 // already saved them so that it can use esi/edi as temporaries |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
62 // then a save/restore here will DESTROY the copy the caller |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
63 // saved! There used to be a save_bcp() that only happened in |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
64 // the ASSERT path (no restore_bcp). Which caused bizarre failures |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
65 // when jvm built with ASSERTs. |
0 | 66 #ifdef ASSERT |
67 { | |
68 Label L; | |
304 | 69 cmpptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); |
0 | 70 jcc(Assembler::equal, L); |
71 stop("InterpreterMacroAssembler::call_VM_leaf_base:" | |
72 " last_sp != NULL"); | |
73 bind(L); | |
74 } | |
75 #endif | |
76 // super call | |
77 MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments); | |
78 // interpreter specific | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
79 // Used to ASSERT that r13/r14 were equal to frame's bcp/locals |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
80 // but since they may not have been saved (and we don't want to |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
81 // save thme here (see note above) the assert is invalid. |
0 | 82 } |
83 | |
84 void InterpreterMacroAssembler::call_VM_base(Register oop_result, | |
85 Register java_thread, | |
86 Register last_java_sp, | |
87 address entry_point, | |
88 int number_of_arguments, | |
89 bool check_exceptions) { | |
90 // interpreter specific | |
91 // | |
92 // Note: Could avoid restoring locals ptr (callee saved) - however doesn't | |
93 // really make a difference for these runtime calls, since they are | |
94 // slow anyway. Btw., bcp must be saved/restored since it may change | |
95 // due to GC. | |
96 // assert(java_thread == noreg , "not expecting a precomputed java thread"); | |
97 save_bcp(); | |
98 #ifdef ASSERT | |
99 { | |
100 Label L; | |
304 | 101 cmpptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); |
0 | 102 jcc(Assembler::equal, L); |
103 stop("InterpreterMacroAssembler::call_VM_leaf_base:" | |
104 " last_sp != NULL"); | |
105 bind(L); | |
106 } | |
107 #endif /* ASSERT */ | |
108 // super call | |
109 MacroAssembler::call_VM_base(oop_result, noreg, last_java_sp, | |
110 entry_point, number_of_arguments, | |
111 check_exceptions); | |
112 // interpreter specific | |
113 restore_bcp(); | |
114 restore_locals(); | |
115 } | |
116 | |
117 | |
118 void InterpreterMacroAssembler::check_and_handle_popframe(Register java_thread) { | |
119 if (JvmtiExport::can_pop_frame()) { | |
120 Label L; | |
121 // Initiate popframe handling only if it is not already being | |
122 // processed. If the flag has the popframe_processing bit set, it | |
123 // means that this code is called *during* popframe handling - we | |
124 // don't want to reenter. | |
125 // This method is only called just after the call into the vm in | |
126 // call_VM_base, so the arg registers are available. | |
127 movl(c_rarg0, Address(r15_thread, JavaThread::popframe_condition_offset())); | |
128 testl(c_rarg0, JavaThread::popframe_pending_bit); | |
129 jcc(Assembler::zero, L); | |
130 testl(c_rarg0, JavaThread::popframe_processing_bit); | |
131 jcc(Assembler::notZero, L); | |
132 // Call Interpreter::remove_activation_preserving_args_entry() to get the | |
133 // address of the same-named entrypoint in the generated interpreter code. | |
134 call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_preserving_args_entry)); | |
135 jmp(rax); | |
136 bind(L); | |
137 } | |
138 } | |
139 | |
140 | |
141 void InterpreterMacroAssembler::load_earlyret_value(TosState state) { | |
304 | 142 movptr(rcx, Address(r15_thread, JavaThread::jvmti_thread_state_offset())); |
0 | 143 const Address tos_addr(rcx, JvmtiThreadState::earlyret_tos_offset()); |
144 const Address oop_addr(rcx, JvmtiThreadState::earlyret_oop_offset()); | |
145 const Address val_addr(rcx, JvmtiThreadState::earlyret_value_offset()); | |
146 switch (state) { | |
304 | 147 case atos: movptr(rax, oop_addr); |
148 movptr(oop_addr, (int32_t)NULL_WORD); | |
0 | 149 verify_oop(rax, state); break; |
304 | 150 case ltos: movptr(rax, val_addr); break; |
0 | 151 case btos: // fall through |
152 case ctos: // fall through | |
153 case stos: // fall through | |
154 case itos: movl(rax, val_addr); break; | |
155 case ftos: movflt(xmm0, val_addr); break; | |
156 case dtos: movdbl(xmm0, val_addr); break; | |
157 case vtos: /* nothing to do */ break; | |
158 default : ShouldNotReachHere(); | |
159 } | |
160 // Clean up tos value in the thread object | |
161 movl(tos_addr, (int) ilgl); | |
304 | 162 movl(val_addr, (int32_t) NULL_WORD); |
0 | 163 } |
164 | |
165 | |
166 void InterpreterMacroAssembler::check_and_handle_earlyret(Register java_thread) { | |
167 if (JvmtiExport::can_force_early_return()) { | |
168 Label L; | |
304 | 169 movptr(c_rarg0, Address(r15_thread, JavaThread::jvmti_thread_state_offset())); |
170 testptr(c_rarg0, c_rarg0); | |
0 | 171 jcc(Assembler::zero, L); // if (thread->jvmti_thread_state() == NULL) exit; |
172 | |
173 // Initiate earlyret handling only if it is not already being processed. | |
174 // If the flag has the earlyret_processing bit set, it means that this code | |
175 // is called *during* earlyret handling - we don't want to reenter. | |
176 movl(c_rarg0, Address(c_rarg0, JvmtiThreadState::earlyret_state_offset())); | |
177 cmpl(c_rarg0, JvmtiThreadState::earlyret_pending); | |
178 jcc(Assembler::notEqual, L); | |
179 | |
180 // Call Interpreter::remove_activation_early_entry() to get the address of the | |
181 // same-named entrypoint in the generated interpreter code. | |
304 | 182 movptr(c_rarg0, Address(r15_thread, JavaThread::jvmti_thread_state_offset())); |
0 | 183 movl(c_rarg0, Address(c_rarg0, JvmtiThreadState::earlyret_tos_offset())); |
184 call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_early_entry), c_rarg0); | |
185 jmp(rax); | |
186 bind(L); | |
187 } | |
188 } | |
189 | |
190 | |
191 void InterpreterMacroAssembler::get_unsigned_2_byte_index_at_bcp( | |
192 Register reg, | |
193 int bcp_offset) { | |
194 assert(bcp_offset >= 0, "bcp is still pointing to start of bytecode"); | |
13034
ea79ab313e98
8027252: Crash in interpreter because get_unsigned_2_byte_index_at_bcp reads 4 bytes
mgerdin
parents:
12962
diff
changeset
|
195 load_unsigned_short(reg, Address(r13, bcp_offset)); |
0 | 196 bswapl(reg); |
197 shrl(reg, 16); | |
198 } | |
199 | |
200 | |
1108 | 201 void InterpreterMacroAssembler::get_cache_index_at_bcp(Register index, |
202 int bcp_offset, | |
1565 | 203 size_t index_size) { |
1108 | 204 assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); |
1565 | 205 if (index_size == sizeof(u2)) { |
1108 | 206 load_unsigned_short(index, Address(r13, bcp_offset)); |
1565 | 207 } else if (index_size == sizeof(u4)) { |
2416
38fea01eb669
6817525: turn on method handle functionality by default for JSR 292
twisti
parents:
2118
diff
changeset
|
208 assert(EnableInvokeDynamic, "giant index used only for JSR 292"); |
1108 | 209 movl(index, Address(r13, bcp_offset)); |
210 // Check if the secondary index definition is still ~x, otherwise | |
211 // we have to change the following assembler code to calculate the | |
212 // plain index. | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
213 assert(ConstantPool::decode_invokedynamic_index(~123) == 123, "else change next line"); |
1108 | 214 notl(index); // convert to plain index |
1565 | 215 } else if (index_size == sizeof(u1)) { |
216 load_unsigned_byte(index, Address(r13, bcp_offset)); | |
217 } else { | |
218 ShouldNotReachHere(); | |
1108 | 219 } |
220 } | |
221 | |
222 | |
0 | 223 void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, |
224 Register index, | |
1108 | 225 int bcp_offset, |
1565 | 226 size_t index_size) { |
3852
fdb992d83a87
7071653: JSR 292: call site change notification should be pushed not pulled
twisti
parents:
3808
diff
changeset
|
227 assert_different_registers(cache, index); |
1565 | 228 get_cache_index_at_bcp(index, bcp_offset, index_size); |
304 | 229 movptr(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize)); |
0 | 230 assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below"); |
231 // convert from field index to ConstantPoolCacheEntry index | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
232 assert(exact_log2(in_words(ConstantPoolCacheEntry::size())) == 2, "else change next line"); |
0 | 233 shll(index, 2); |
234 } | |
235 | |
236 | |
3852
fdb992d83a87
7071653: JSR 292: call site change notification should be pushed not pulled
twisti
parents:
3808
diff
changeset
|
237 void InterpreterMacroAssembler::get_cache_and_index_and_bytecode_at_bcp(Register cache, |
fdb992d83a87
7071653: JSR 292: call site change notification should be pushed not pulled
twisti
parents:
3808
diff
changeset
|
238 Register index, |
fdb992d83a87
7071653: JSR 292: call site change notification should be pushed not pulled
twisti
parents:
3808
diff
changeset
|
239 Register bytecode, |
fdb992d83a87
7071653: JSR 292: call site change notification should be pushed not pulled
twisti
parents:
3808
diff
changeset
|
240 int byte_no, |
fdb992d83a87
7071653: JSR 292: call site change notification should be pushed not pulled
twisti
parents:
3808
diff
changeset
|
241 int bcp_offset, |
fdb992d83a87
7071653: JSR 292: call site change notification should be pushed not pulled
twisti
parents:
3808
diff
changeset
|
242 size_t index_size) { |
fdb992d83a87
7071653: JSR 292: call site change notification should be pushed not pulled
twisti
parents:
3808
diff
changeset
|
243 get_cache_and_index_at_bcp(cache, index, bcp_offset, index_size); |
fdb992d83a87
7071653: JSR 292: call site change notification should be pushed not pulled
twisti
parents:
3808
diff
changeset
|
244 // We use a 32-bit load here since the layout of 64-bit words on |
fdb992d83a87
7071653: JSR 292: call site change notification should be pushed not pulled
twisti
parents:
3808
diff
changeset
|
245 // little-endian machines allow us that. |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
246 movl(bytecode, Address(cache, index, Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset())); |
3852
fdb992d83a87
7071653: JSR 292: call site change notification should be pushed not pulled
twisti
parents:
3808
diff
changeset
|
247 const int shift_count = (1 + byte_no) * BitsPerByte; |
6266
1d7922586cf6
7023639: JSR 292 method handle invocation needs a fast path for compiled code
twisti
parents:
3960
diff
changeset
|
248 assert((byte_no == TemplateTable::f1_byte && shift_count == ConstantPoolCacheEntry::bytecode_1_shift) || |
1d7922586cf6
7023639: JSR 292 method handle invocation needs a fast path for compiled code
twisti
parents:
3960
diff
changeset
|
249 (byte_no == TemplateTable::f2_byte && shift_count == ConstantPoolCacheEntry::bytecode_2_shift), |
1d7922586cf6
7023639: JSR 292 method handle invocation needs a fast path for compiled code
twisti
parents:
3960
diff
changeset
|
250 "correct shift count"); |
3852
fdb992d83a87
7071653: JSR 292: call site change notification should be pushed not pulled
twisti
parents:
3808
diff
changeset
|
251 shrl(bytecode, shift_count); |
6266
1d7922586cf6
7023639: JSR 292 method handle invocation needs a fast path for compiled code
twisti
parents:
3960
diff
changeset
|
252 assert(ConstantPoolCacheEntry::bytecode_1_mask == ConstantPoolCacheEntry::bytecode_2_mask, "common mask"); |
1d7922586cf6
7023639: JSR 292 method handle invocation needs a fast path for compiled code
twisti
parents:
3960
diff
changeset
|
253 andl(bytecode, ConstantPoolCacheEntry::bytecode_1_mask); |
3852
fdb992d83a87
7071653: JSR 292: call site change notification should be pushed not pulled
twisti
parents:
3808
diff
changeset
|
254 } |
fdb992d83a87
7071653: JSR 292: call site change notification should be pushed not pulled
twisti
parents:
3808
diff
changeset
|
255 |
fdb992d83a87
7071653: JSR 292: call site change notification should be pushed not pulled
twisti
parents:
3808
diff
changeset
|
256 |
0 | 257 void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, |
258 Register tmp, | |
1108 | 259 int bcp_offset, |
1565 | 260 size_t index_size) { |
0 | 261 assert(cache != tmp, "must use different register"); |
1565 | 262 get_cache_index_at_bcp(tmp, bcp_offset, index_size); |
0 | 263 assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below"); |
264 // convert from field index to ConstantPoolCacheEntry index | |
265 // and from word offset to byte offset | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
266 assert(exact_log2(in_bytes(ConstantPoolCacheEntry::size_in_bytes())) == 2 + LogBytesPerWord, "else change next line"); |
0 | 267 shll(tmp, 2 + LogBytesPerWord); |
304 | 268 movptr(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize)); |
0 | 269 // skip past the header |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
270 addptr(cache, in_bytes(ConstantPoolCache::base_offset())); |
304 | 271 addptr(cache, tmp); // construct pointer to cache entry |
0 | 272 } |
273 | |
10105
aeaca88565e6
8010862: The Method counter fields used for profiling can be allocated lazily.
jiangli
parents:
7180
diff
changeset
|
274 void InterpreterMacroAssembler::get_method_counters(Register method, |
aeaca88565e6
8010862: The Method counter fields used for profiling can be allocated lazily.
jiangli
parents:
7180
diff
changeset
|
275 Register mcs, Label& skip) { |
aeaca88565e6
8010862: The Method counter fields used for profiling can be allocated lazily.
jiangli
parents:
7180
diff
changeset
|
276 Label has_counters; |
aeaca88565e6
8010862: The Method counter fields used for profiling can be allocated lazily.
jiangli
parents:
7180
diff
changeset
|
277 movptr(mcs, Address(method, Method::method_counters_offset())); |
aeaca88565e6
8010862: The Method counter fields used for profiling can be allocated lazily.
jiangli
parents:
7180
diff
changeset
|
278 testptr(mcs, mcs); |
aeaca88565e6
8010862: The Method counter fields used for profiling can be allocated lazily.
jiangli
parents:
7180
diff
changeset
|
279 jcc(Assembler::notZero, has_counters); |
aeaca88565e6
8010862: The Method counter fields used for profiling can be allocated lazily.
jiangli
parents:
7180
diff
changeset
|
280 call_VM(noreg, CAST_FROM_FN_PTR(address, |
aeaca88565e6
8010862: The Method counter fields used for profiling can be allocated lazily.
jiangli
parents:
7180
diff
changeset
|
281 InterpreterRuntime::build_method_counters), method); |
aeaca88565e6
8010862: The Method counter fields used for profiling can be allocated lazily.
jiangli
parents:
7180
diff
changeset
|
282 movptr(mcs, Address(method,Method::method_counters_offset())); |
aeaca88565e6
8010862: The Method counter fields used for profiling can be allocated lazily.
jiangli
parents:
7180
diff
changeset
|
283 testptr(mcs, mcs); |
aeaca88565e6
8010862: The Method counter fields used for profiling can be allocated lazily.
jiangli
parents:
7180
diff
changeset
|
284 jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory |
aeaca88565e6
8010862: The Method counter fields used for profiling can be allocated lazily.
jiangli
parents:
7180
diff
changeset
|
285 bind(has_counters); |
aeaca88565e6
8010862: The Method counter fields used for profiling can be allocated lazily.
jiangli
parents:
7180
diff
changeset
|
286 } |
aeaca88565e6
8010862: The Method counter fields used for profiling can be allocated lazily.
jiangli
parents:
7180
diff
changeset
|
287 |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
288 // Load object from cpool->resolved_references(index) |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
289 void InterpreterMacroAssembler::load_resolved_reference_at_index( |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
290 Register result, Register index) { |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
291 assert_different_registers(result, index); |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
292 // convert from field index to resolved_references() index and from |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
293 // word index to byte offset. Since this is a java object, it can be compressed |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
294 Register tmp = index; // reuse |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
295 shll(tmp, LogBytesPerHeapOop); |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
296 |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
297 get_constant_pool(result); |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
298 // load pointer for resolved_references[] objArray |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
299 movptr(result, Address(result, ConstantPool::resolved_references_offset_in_bytes())); |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
300 // JNIHandles::resolve(obj); |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
301 movptr(result, Address(result, 0)); |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
302 // Add in the index |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
303 addptr(result, tmp); |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
304 load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
305 } |
0 | 306 |
307 // Generate a subtype check: branch to ok_is_subtype if sub_klass is a | |
308 // subtype of super_klass. | |
309 // | |
310 // Args: | |
311 // rax: superklass | |
312 // Rsub_klass: subklass | |
313 // | |
314 // Kills: | |
315 // rcx, rdi | |
316 void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, | |
317 Label& ok_is_subtype) { | |
318 assert(Rsub_klass != rax, "rax holds superklass"); | |
319 assert(Rsub_klass != r14, "r14 holds locals"); | |
320 assert(Rsub_klass != r13, "r13 holds bcp"); | |
321 assert(Rsub_klass != rcx, "rcx holds 2ndary super array length"); | |
322 assert(Rsub_klass != rdi, "rdi holds 2ndary super array scan ptr"); | |
323 | |
324 // Profile the not-null value's klass. | |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
625
diff
changeset
|
325 profile_typecheck(rcx, Rsub_klass, rdi); // blows rcx, reloads rdi |
0 | 326 |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
625
diff
changeset
|
327 // Do the check. |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
625
diff
changeset
|
328 check_klass_subtype(Rsub_klass, rax, rcx, ok_is_subtype); // blows rcx |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
329 |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
625
diff
changeset
|
330 // Profile the failure of the check. |
0 | 331 profile_typecheck_failed(rcx); // blows rcx |
332 } | |
333 | |
334 | |
304 | 335 |
0 | 336 // Java Expression Stack |
337 | |
338 void InterpreterMacroAssembler::pop_ptr(Register r) { | |
304 | 339 pop(r); |
0 | 340 } |
341 | |
342 void InterpreterMacroAssembler::pop_i(Register r) { | |
304 | 343 // XXX can't use pop currently, upper half non clean |
0 | 344 movl(r, Address(rsp, 0)); |
304 | 345 addptr(rsp, wordSize); |
0 | 346 } |
347 | |
348 void InterpreterMacroAssembler::pop_l(Register r) { | |
349 movq(r, Address(rsp, 0)); | |
1506 | 350 addptr(rsp, 2 * Interpreter::stackElementSize); |
0 | 351 } |
352 | |
353 void InterpreterMacroAssembler::pop_f(XMMRegister r) { | |
354 movflt(r, Address(rsp, 0)); | |
304 | 355 addptr(rsp, wordSize); |
0 | 356 } |
357 | |
358 void InterpreterMacroAssembler::pop_d(XMMRegister r) { | |
359 movdbl(r, Address(rsp, 0)); | |
1506 | 360 addptr(rsp, 2 * Interpreter::stackElementSize); |
0 | 361 } |
362 | |
363 void InterpreterMacroAssembler::push_ptr(Register r) { | |
304 | 364 push(r); |
0 | 365 } |
366 | |
367 void InterpreterMacroAssembler::push_i(Register r) { | |
304 | 368 push(r); |
0 | 369 } |
370 | |
371 void InterpreterMacroAssembler::push_l(Register r) { | |
1506 | 372 subptr(rsp, 2 * wordSize); |
0 | 373 movq(Address(rsp, 0), r); |
374 } | |
375 | |
376 void InterpreterMacroAssembler::push_f(XMMRegister r) { | |
304 | 377 subptr(rsp, wordSize); |
0 | 378 movflt(Address(rsp, 0), r); |
379 } | |
380 | |
381 void InterpreterMacroAssembler::push_d(XMMRegister r) { | |
1506 | 382 subptr(rsp, 2 * wordSize); |
0 | 383 movdbl(Address(rsp, 0), r); |
384 } | |
385 | |
386 void InterpreterMacroAssembler::pop(TosState state) { | |
387 switch (state) { | |
388 case atos: pop_ptr(); break; | |
389 case btos: | |
390 case ctos: | |
391 case stos: | |
392 case itos: pop_i(); break; | |
393 case ltos: pop_l(); break; | |
394 case ftos: pop_f(); break; | |
395 case dtos: pop_d(); break; | |
396 case vtos: /* nothing to do */ break; | |
397 default: ShouldNotReachHere(); | |
398 } | |
399 verify_oop(rax, state); | |
400 } | |
401 | |
402 void InterpreterMacroAssembler::push(TosState state) { | |
403 verify_oop(rax, state); | |
404 switch (state) { | |
405 case atos: push_ptr(); break; | |
406 case btos: | |
407 case ctos: | |
408 case stos: | |
409 case itos: push_i(); break; | |
410 case ltos: push_l(); break; | |
411 case ftos: push_f(); break; | |
412 case dtos: push_d(); break; | |
413 case vtos: /* nothing to do */ break; | |
414 default : ShouldNotReachHere(); | |
415 } | |
416 } | |
417 | |
418 | |
1506 | 419 // Helpers for swap and dup |
420 void InterpreterMacroAssembler::load_ptr(int n, Register val) { | |
304 | 421 movptr(val, Address(rsp, Interpreter::expr_offset_in_bytes(n))); |
0 | 422 } |
423 | |
1506 | 424 void InterpreterMacroAssembler::store_ptr(int n, Register val) { |
425 movptr(Address(rsp, Interpreter::expr_offset_in_bytes(n)), val); | |
0 | 426 } |
427 | |
428 | |
710 | 429 void InterpreterMacroAssembler::prepare_to_jump_from_interpreted() { |
0 | 430 // set sender sp |
304 | 431 lea(r13, Address(rsp, wordSize)); |
0 | 432 // record last_sp |
304 | 433 movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), r13); |
710 | 434 } |
435 | |
436 | |
437 // Jump to from_interpreted entry of a call unless single stepping is possible | |
438 // in this thread in which case we must call the i2i entry | |
439 void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) { | |
440 prepare_to_jump_from_interpreted(); | |
0 | 441 |
442 if (JvmtiExport::can_post_interpreter_events()) { | |
443 Label run_compiled_code; | |
444 // JVMTI events, such as single-stepping, are implemented partly by avoiding running | |
445 // compiled code in threads for which the event is enabled. Check here for | |
446 // interp_only_mode if these events CAN be enabled. | |
447 // interp_only is an int, on little endian it is sufficient to test the byte only | |
1976
0fc262af204f
6780143: hs203t003 hits SIGSEGV/EXCEPTION_ACCESS_VIOLATION with -XX:+UseCompressedOops
coleenp
parents:
1972
diff
changeset
|
448 // Is a cmpl faster? |
0fc262af204f
6780143: hs203t003 hits SIGSEGV/EXCEPTION_ACCESS_VIOLATION with -XX:+UseCompressedOops
coleenp
parents:
1972
diff
changeset
|
449 cmpb(Address(r15_thread, JavaThread::interp_only_mode_offset()), 0); |
3808
341a57af9b0a
6990212: JSR 292 JVMTI MethodEnter hook is not called for JSR 292 bootstrap and target methods
never
parents:
3336
diff
changeset
|
450 jccb(Assembler::zero, run_compiled_code); |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
451 jmp(Address(method, Method::interpreter_entry_offset())); |
0 | 452 bind(run_compiled_code); |
453 } | |
454 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
455 jmp(Address(method, Method::from_interpreted_offset())); |
0 | 456 |
457 } | |
458 | |
459 | |
460 // The following two routines provide a hook so that an implementation | |
461 // can schedule the dispatch in two parts. amd64 does not do this. | |
462 void InterpreterMacroAssembler::dispatch_prolog(TosState state, int step) { | |
463 // Nothing amd64 specific to be done here | |
464 } | |
465 | |
466 void InterpreterMacroAssembler::dispatch_epilog(TosState state, int step) { | |
467 dispatch_next(state, step); | |
468 } | |
469 | |
470 void InterpreterMacroAssembler::dispatch_base(TosState state, | |
471 address* table, | |
472 bool verifyoop) { | |
473 verify_FPU(1, state); | |
474 if (VerifyActivationFrameSize) { | |
475 Label L; | |
304 | 476 mov(rcx, rbp); |
477 subptr(rcx, rsp); | |
478 int32_t min_frame_size = | |
0 | 479 (frame::link_offset - frame::interpreter_frame_initial_sp_offset) * |
480 wordSize; | |
304 | 481 cmpptr(rcx, (int32_t)min_frame_size); |
0 | 482 jcc(Assembler::greaterEqual, L); |
483 stop("broken stack frame"); | |
484 bind(L); | |
485 } | |
486 if (verifyoop) { | |
487 verify_oop(rax, state); | |
488 } | |
489 lea(rscratch1, ExternalAddress((address)table)); | |
490 jmp(Address(rscratch1, rbx, Address::times_8)); | |
491 } | |
492 | |
493 void InterpreterMacroAssembler::dispatch_only(TosState state) { | |
494 dispatch_base(state, Interpreter::dispatch_table(state)); | |
495 } | |
496 | |
497 void InterpreterMacroAssembler::dispatch_only_normal(TosState state) { | |
498 dispatch_base(state, Interpreter::normal_table(state)); | |
499 } | |
500 | |
501 void InterpreterMacroAssembler::dispatch_only_noverify(TosState state) { | |
502 dispatch_base(state, Interpreter::normal_table(state), false); | |
503 } | |
504 | |
505 | |
506 void InterpreterMacroAssembler::dispatch_next(TosState state, int step) { | |
507 // load next bytecode (load before advancing r13 to prevent AGI) | |
508 load_unsigned_byte(rbx, Address(r13, step)); | |
509 // advance r13 | |
304 | 510 increment(r13, step); |
0 | 511 dispatch_base(state, Interpreter::dispatch_table(state)); |
512 } | |
513 | |
514 void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) { | |
515 // load current bytecode | |
516 load_unsigned_byte(rbx, Address(r13, 0)); | |
517 dispatch_base(state, table); | |
518 } | |
519 | |
520 // remove activation | |
521 // | |
522 // Unlock the receiver if this is a synchronized method. | |
523 // Unlock any Java monitors from syncronized blocks. | |
524 // Remove the activation from the stack. | |
525 // | |
526 // If there are locked Java monitors | |
527 // If throw_monitor_exception | |
528 // throws IllegalMonitorStateException | |
529 // Else if install_monitor_exception | |
530 // installs IllegalMonitorStateException | |
531 // Else | |
532 // no error processing | |
533 void InterpreterMacroAssembler::remove_activation( | |
534 TosState state, | |
535 Register ret_addr, | |
536 bool throw_monitor_exception, | |
537 bool install_monitor_exception, | |
538 bool notify_jvmdi) { | |
539 // Note: Registers rdx xmm0 may be in use for the | |
540 // result check if synchronized method | |
541 Label unlocked, unlock, no_unlock; | |
542 | |
543 // get the value of _do_not_unlock_if_synchronized into rdx | |
544 const Address do_not_unlock_if_synchronized(r15_thread, | |
545 in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); | |
546 movbool(rdx, do_not_unlock_if_synchronized); | |
547 movbool(do_not_unlock_if_synchronized, false); // reset the flag | |
548 | |
549 // get method access flags | |
304 | 550 movptr(rbx, Address(rbp, frame::interpreter_frame_method_offset * wordSize)); |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
551 movl(rcx, Address(rbx, Method::access_flags_offset())); |
0 | 552 testl(rcx, JVM_ACC_SYNCHRONIZED); |
553 jcc(Assembler::zero, unlocked); | |
554 | |
555 // Don't unlock anything if the _do_not_unlock_if_synchronized flag | |
556 // is set. | |
557 testbool(rdx); | |
558 jcc(Assembler::notZero, no_unlock); | |
559 | |
560 // unlock monitor | |
561 push(state); // save result | |
562 | |
563 // BasicObjectLock will be first in list, since this is a | |
564 // synchronized method. However, need to check that the object has | |
565 // not been unlocked by an explicit monitorexit bytecode. | |
566 const Address monitor(rbp, frame::interpreter_frame_initial_sp_offset * | |
567 wordSize - (int) sizeof(BasicObjectLock)); | |
568 // We use c_rarg1 so that if we go slow path it will be the correct | |
569 // register for unlock_object to pass to VM directly | |
304 | 570 lea(c_rarg1, monitor); // address of first monitor |
0 | 571 |
304 | 572 movptr(rax, Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes())); |
573 testptr(rax, rax); | |
0 | 574 jcc(Assembler::notZero, unlock); |
575 | |
576 pop(state); | |
577 if (throw_monitor_exception) { | |
578 // Entry already unlocked, need to throw exception | |
579 call_VM(noreg, CAST_FROM_FN_PTR(address, | |
580 InterpreterRuntime::throw_illegal_monitor_state_exception)); | |
581 should_not_reach_here(); | |
582 } else { | |
583 // Monitor already unlocked during a stack unroll. If requested, | |
584 // install an illegal_monitor_state_exception. Continue with | |
585 // stack unrolling. | |
586 if (install_monitor_exception) { | |
587 call_VM(noreg, CAST_FROM_FN_PTR(address, | |
588 InterpreterRuntime::new_illegal_monitor_state_exception)); | |
589 } | |
590 jmp(unlocked); | |
591 } | |
592 | |
593 bind(unlock); | |
594 unlock_object(c_rarg1); | |
595 pop(state); | |
596 | |
597 // Check that for block-structured locking (i.e., that all locked | |
598 // objects has been unlocked) | |
599 bind(unlocked); | |
600 | |
601 // rax: Might contain return value | |
602 | |
603 // Check that all monitors are unlocked | |
604 { | |
605 Label loop, exception, entry, restart; | |
606 const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; | |
607 const Address monitor_block_top( | |
608 rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize); | |
609 const Address monitor_block_bot( | |
610 rbp, frame::interpreter_frame_initial_sp_offset * wordSize); | |
611 | |
612 bind(restart); | |
613 // We use c_rarg1 so that if we go slow path it will be the correct | |
614 // register for unlock_object to pass to VM directly | |
304 | 615 movptr(c_rarg1, monitor_block_top); // points to current entry, starting |
0 | 616 // with top-most entry |
304 | 617 lea(rbx, monitor_block_bot); // points to word before bottom of |
0 | 618 // monitor block |
619 jmp(entry); | |
620 | |
621 // Entry already locked, need to throw exception | |
622 bind(exception); | |
623 | |
624 if (throw_monitor_exception) { | |
625 // Throw exception | |
626 MacroAssembler::call_VM(noreg, | |
627 CAST_FROM_FN_PTR(address, InterpreterRuntime:: | |
628 throw_illegal_monitor_state_exception)); | |
629 should_not_reach_here(); | |
630 } else { | |
631 // Stack unrolling. Unlock object and install illegal_monitor_exception. | |
632 // Unlock does not block, so don't have to worry about the frame. | |
633 // We don't have to preserve c_rarg1 since we are going to throw an exception. | |
634 | |
635 push(state); | |
636 unlock_object(c_rarg1); | |
637 pop(state); | |
638 | |
639 if (install_monitor_exception) { | |
640 call_VM(noreg, CAST_FROM_FN_PTR(address, | |
641 InterpreterRuntime:: | |
642 new_illegal_monitor_state_exception)); | |
643 } | |
644 | |
645 jmp(restart); | |
646 } | |
647 | |
648 bind(loop); | |
649 // check if current entry is used | |
304 | 650 cmpptr(Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes()), (int32_t) NULL); |
0 | 651 jcc(Assembler::notEqual, exception); |
652 | |
304 | 653 addptr(c_rarg1, entry_size); // otherwise advance to next entry |
0 | 654 bind(entry); |
304 | 655 cmpptr(c_rarg1, rbx); // check if bottom reached |
0 | 656 jcc(Assembler::notEqual, loop); // if not at bottom then check this entry |
657 } | |
658 | |
659 bind(no_unlock); | |
660 | |
661 // jvmti support | |
662 if (notify_jvmdi) { | |
663 notify_method_exit(state, NotifyJVMTI); // preserve TOSCA | |
664 } else { | |
665 notify_method_exit(state, SkipNotifyJVMTI); // preserve TOSCA | |
666 } | |
667 | |
668 // remove activation | |
669 // get sender sp | |
304 | 670 movptr(rbx, |
671 Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize)); | |
0 | 672 leave(); // remove frame anchor |
304 | 673 pop(ret_addr); // get return address |
674 mov(rsp, rbx); // set sp to sender sp | |
0 | 675 } |
676 | |
304 | 677 #endif // C_INTERP |
678 | |
0 | 679 // Lock object |
680 // | |
681 // Args: | |
682 // c_rarg1: BasicObjectLock to be used for locking | |
683 // | |
684 // Kills: | |
685 // rax | |
686 // c_rarg0, c_rarg1, c_rarg2, c_rarg3, .. (param regs) | |
687 // rscratch1, rscratch2 (scratch regs) | |
688 void InterpreterMacroAssembler::lock_object(Register lock_reg) { | |
689 assert(lock_reg == c_rarg1, "The argument is only for looks. It must be c_rarg1"); | |
690 | |
691 if (UseHeavyMonitors) { | |
692 call_VM(noreg, | |
693 CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), | |
694 lock_reg); | |
695 } else { | |
696 Label done; | |
697 | |
698 const Register swap_reg = rax; // Must use rax for cmpxchg instruction | |
699 const Register obj_reg = c_rarg3; // Will contain the oop | |
700 | |
701 const int obj_offset = BasicObjectLock::obj_offset_in_bytes(); | |
702 const int lock_offset = BasicObjectLock::lock_offset_in_bytes (); | |
703 const int mark_offset = lock_offset + | |
704 BasicLock::displaced_header_offset_in_bytes(); | |
705 | |
706 Label slow_case; | |
707 | |
708 // Load object pointer into obj_reg %c_rarg3 | |
304 | 709 movptr(obj_reg, Address(lock_reg, obj_offset)); |
0 | 710 |
711 if (UseBiasedLocking) { | |
712 biased_locking_enter(lock_reg, obj_reg, swap_reg, rscratch1, false, done, &slow_case); | |
713 } | |
714 | |
715 // Load immediate 1 into swap_reg %rax | |
716 movl(swap_reg, 1); | |
717 | |
718 // Load (object->mark() | 1) into swap_reg %rax | |
304 | 719 orptr(swap_reg, Address(obj_reg, 0)); |
0 | 720 |
721 // Save (object->mark() | 1) into BasicLock's displaced header | |
304 | 722 movptr(Address(lock_reg, mark_offset), swap_reg); |
0 | 723 |
724 assert(lock_offset == 0, | |
725 "displached header must be first word in BasicObjectLock"); | |
726 | |
727 if (os::is_MP()) lock(); | |
304 | 728 cmpxchgptr(lock_reg, Address(obj_reg, 0)); |
0 | 729 if (PrintBiasedLockingStatistics) { |
730 cond_inc32(Assembler::zero, | |
731 ExternalAddress((address) BiasedLocking::fast_path_entry_count_addr())); | |
732 } | |
733 jcc(Assembler::zero, done); | |
734 | |
735 // Test if the oopMark is an obvious stack pointer, i.e., | |
736 // 1) (mark & 7) == 0, and | |
737 // 2) rsp <= mark < mark + os::pagesize() | |
738 // | |
739 // These 3 tests can be done by evaluating the following | |
740 // expression: ((mark - rsp) & (7 - os::vm_page_size())), | |
741 // assuming both stack pointer and pagesize have their | |
742 // least significant 3 bits clear. | |
743 // NOTE: the oopMark is in swap_reg %rax as the result of cmpxchg | |
304 | 744 subptr(swap_reg, rsp); |
745 andptr(swap_reg, 7 - os::vm_page_size()); | |
0 | 746 |
747 // Save the test result, for recursive case, the result is zero | |
304 | 748 movptr(Address(lock_reg, mark_offset), swap_reg); |
0 | 749 |
750 if (PrintBiasedLockingStatistics) { | |
751 cond_inc32(Assembler::zero, | |
752 ExternalAddress((address) BiasedLocking::fast_path_entry_count_addr())); | |
753 } | |
754 jcc(Assembler::zero, done); | |
755 | |
756 bind(slow_case); | |
757 | |
758 // Call the runtime routine for slow case | |
759 call_VM(noreg, | |
760 CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), | |
761 lock_reg); | |
762 | |
763 bind(done); | |
764 } | |
765 } | |
766 | |
767 | |
768 // Unlocks an object. Used in monitorexit bytecode and | |
769 // remove_activation. Throws an IllegalMonitorException if object is | |
770 // not locked by current thread. | |
771 // | |
772 // Args: | |
773 // c_rarg1: BasicObjectLock for lock | |
774 // | |
775 // Kills: | |
776 // rax | |
777 // c_rarg0, c_rarg1, c_rarg2, c_rarg3, ... (param regs) | |
778 // rscratch1, rscratch2 (scratch regs) | |
779 void InterpreterMacroAssembler::unlock_object(Register lock_reg) { | |
780 assert(lock_reg == c_rarg1, "The argument is only for looks. It must be rarg1"); | |
781 | |
782 if (UseHeavyMonitors) { | |
783 call_VM(noreg, | |
784 CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), | |
785 lock_reg); | |
786 } else { | |
787 Label done; | |
788 | |
789 const Register swap_reg = rax; // Must use rax for cmpxchg instruction | |
790 const Register header_reg = c_rarg2; // Will contain the old oopMark | |
791 const Register obj_reg = c_rarg3; // Will contain the oop | |
792 | |
793 save_bcp(); // Save in case of exception | |
794 | |
795 // Convert from BasicObjectLock structure to object and BasicLock | |
796 // structure Store the BasicLock address into %rax | |
304 | 797 lea(swap_reg, Address(lock_reg, BasicObjectLock::lock_offset_in_bytes())); |
0 | 798 |
799 // Load oop into obj_reg(%c_rarg3) | |
304 | 800 movptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset_in_bytes())); |
0 | 801 |
802 // Free entry | |
304 | 803 movptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()), (int32_t)NULL_WORD); |
0 | 804 |
805 if (UseBiasedLocking) { | |
806 biased_locking_exit(obj_reg, header_reg, done); | |
807 } | |
808 | |
809 // Load the old header from BasicLock structure | |
304 | 810 movptr(header_reg, Address(swap_reg, |
811 BasicLock::displaced_header_offset_in_bytes())); | |
0 | 812 |
813 // Test for recursion | |
304 | 814 testptr(header_reg, header_reg); |
0 | 815 |
816 // zero for recursive case | |
817 jcc(Assembler::zero, done); | |
818 | |
819 // Atomic swap back the old header | |
820 if (os::is_MP()) lock(); | |
304 | 821 cmpxchgptr(header_reg, Address(obj_reg, 0)); |
0 | 822 |
823 // zero for recursive case | |
824 jcc(Assembler::zero, done); | |
825 | |
826 // Call the runtime routine for slow case. | |
304 | 827 movptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()), |
0 | 828 obj_reg); // restore obj |
829 call_VM(noreg, | |
830 CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), | |
831 lock_reg); | |
832 | |
833 bind(done); | |
834 | |
835 restore_bcp(); | |
836 } | |
837 } | |
838 | |
304 | 839 #ifndef CC_INTERP |
0 | 840 |
841 void InterpreterMacroAssembler::test_method_data_pointer(Register mdp, | |
842 Label& zero_continue) { | |
843 assert(ProfileInterpreter, "must be profiling interpreter"); | |
304 | 844 movptr(mdp, Address(rbp, frame::interpreter_frame_mdx_offset * wordSize)); |
845 testptr(mdp, mdp); | |
0 | 846 jcc(Assembler::zero, zero_continue); |
847 } | |
848 | |
849 | |
850 // Set the method data pointer for the current bcp. | |
851 void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() { | |
852 assert(ProfileInterpreter, "must be profiling interpreter"); | |
2118
dd031b2226de
4930919: race condition in MDO creation at back branch locations
iveresov
parents:
1976
diff
changeset
|
853 Label set_mdp; |
304 | 854 push(rax); |
855 push(rbx); | |
0 | 856 |
857 get_method(rbx); | |
858 // Test MDO to avoid the call if it is NULL. | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
859 movptr(rax, Address(rbx, in_bytes(Method::method_data_offset()))); |
304 | 860 testptr(rax, rax); |
2118
dd031b2226de
4930919: race condition in MDO creation at back branch locations
iveresov
parents:
1976
diff
changeset
|
861 jcc(Assembler::zero, set_mdp); |
0 | 862 // rbx: method |
863 // r13: bcp | |
864 call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::bcp_to_di), rbx, r13); | |
865 // rax: mdi | |
2118
dd031b2226de
4930919: race condition in MDO creation at back branch locations
iveresov
parents:
1976
diff
changeset
|
866 // mdo is guaranteed to be non-zero here, we checked for it before the call. |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
867 movptr(rbx, Address(rbx, in_bytes(Method::method_data_offset()))); |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
868 addptr(rbx, in_bytes(MethodData::data_offset())); |
2118
dd031b2226de
4930919: race condition in MDO creation at back branch locations
iveresov
parents:
1976
diff
changeset
|
869 addptr(rax, rbx); |
dd031b2226de
4930919: race condition in MDO creation at back branch locations
iveresov
parents:
1976
diff
changeset
|
870 bind(set_mdp); |
dd031b2226de
4930919: race condition in MDO creation at back branch locations
iveresov
parents:
1976
diff
changeset
|
871 movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), rax); |
304 | 872 pop(rbx); |
873 pop(rax); | |
0 | 874 } |
875 | |
876 void InterpreterMacroAssembler::verify_method_data_pointer() { | |
877 assert(ProfileInterpreter, "must be profiling interpreter"); | |
878 #ifdef ASSERT | |
879 Label verify_continue; | |
304 | 880 push(rax); |
881 push(rbx); | |
882 push(c_rarg3); | |
883 push(c_rarg2); | |
0 | 884 test_method_data_pointer(c_rarg3, verify_continue); // If mdp is zero, continue |
885 get_method(rbx); | |
886 | |
887 // If the mdp is valid, it will point to a DataLayout header which is | |
888 // consistent with the bcp. The converse is highly probable also. | |
622
56aae7be60d4
6812678: macro assembler needs delayed binding of a few constants (for 6655638)
jrose
parents:
520
diff
changeset
|
889 load_unsigned_short(c_rarg2, |
56aae7be60d4
6812678: macro assembler needs delayed binding of a few constants (for 6655638)
jrose
parents:
520
diff
changeset
|
890 Address(c_rarg3, in_bytes(DataLayout::bci_offset()))); |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
891 addptr(c_rarg2, Address(rbx, Method::const_offset())); |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
892 lea(c_rarg2, Address(c_rarg2, ConstMethod::codes_offset())); |
304 | 893 cmpptr(c_rarg2, r13); |
0 | 894 jcc(Assembler::equal, verify_continue); |
895 // rbx: method | |
896 // r13: bcp | |
897 // c_rarg3: mdp | |
898 call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp), | |
899 rbx, r13, c_rarg3); | |
900 bind(verify_continue); | |
304 | 901 pop(c_rarg2); |
902 pop(c_rarg3); | |
903 pop(rbx); | |
904 pop(rax); | |
0 | 905 #endif // ASSERT |
906 } | |
907 | |
908 | |
909 void InterpreterMacroAssembler::set_mdp_data_at(Register mdp_in, | |
910 int constant, | |
911 Register value) { | |
912 assert(ProfileInterpreter, "must be profiling interpreter"); | |
913 Address data(mdp_in, constant); | |
304 | 914 movptr(data, value); |
0 | 915 } |
916 | |
917 | |
918 void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, | |
919 int constant, | |
920 bool decrement) { | |
921 // Counter address | |
922 Address data(mdp_in, constant); | |
923 | |
924 increment_mdp_data_at(data, decrement); | |
925 } | |
926 | |
927 void InterpreterMacroAssembler::increment_mdp_data_at(Address data, | |
928 bool decrement) { | |
929 assert(ProfileInterpreter, "must be profiling interpreter"); | |
304 | 930 // %%% this does 64bit counters at best it is wasting space |
931 // at worst it is a rare bug when counters overflow | |
0 | 932 |
933 if (decrement) { | |
934 // Decrement the register. Set condition codes. | |
304 | 935 addptr(data, (int32_t) -DataLayout::counter_increment); |
0 | 936 // If the decrement causes the counter to overflow, stay negative |
937 Label L; | |
938 jcc(Assembler::negative, L); | |
304 | 939 addptr(data, (int32_t) DataLayout::counter_increment); |
0 | 940 bind(L); |
941 } else { | |
942 assert(DataLayout::counter_increment == 1, | |
943 "flow-free idiom only works with 1"); | |
944 // Increment the register. Set carry flag. | |
304 | 945 addptr(data, DataLayout::counter_increment); |
0 | 946 // If the increment causes the counter to overflow, pull back by 1. |
304 | 947 sbbptr(data, (int32_t)0); |
0 | 948 } |
949 } | |
950 | |
951 | |
952 void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, | |
953 Register reg, | |
954 int constant, | |
955 bool decrement) { | |
956 Address data(mdp_in, reg, Address::times_1, constant); | |
957 | |
958 increment_mdp_data_at(data, decrement); | |
959 } | |
960 | |
961 void InterpreterMacroAssembler::set_mdp_flag_at(Register mdp_in, | |
962 int flag_byte_constant) { | |
963 assert(ProfileInterpreter, "must be profiling interpreter"); | |
964 int header_offset = in_bytes(DataLayout::header_offset()); | |
965 int header_bits = DataLayout::flag_mask_to_header_mask(flag_byte_constant); | |
966 // Set the flag | |
967 orl(Address(mdp_in, header_offset), header_bits); | |
968 } | |
969 | |
970 | |
971 | |
972 void InterpreterMacroAssembler::test_mdp_data_at(Register mdp_in, | |
973 int offset, | |
974 Register value, | |
975 Register test_value_out, | |
976 Label& not_equal_continue) { | |
977 assert(ProfileInterpreter, "must be profiling interpreter"); | |
978 if (test_value_out == noreg) { | |
304 | 979 cmpptr(value, Address(mdp_in, offset)); |
0 | 980 } else { |
981 // Put the test value into a register, so caller can use it: | |
304 | 982 movptr(test_value_out, Address(mdp_in, offset)); |
983 cmpptr(test_value_out, value); | |
0 | 984 } |
985 jcc(Assembler::notEqual, not_equal_continue); | |
986 } | |
987 | |
988 | |
989 void InterpreterMacroAssembler::update_mdp_by_offset(Register mdp_in, | |
990 int offset_of_disp) { | |
991 assert(ProfileInterpreter, "must be profiling interpreter"); | |
992 Address disp_address(mdp_in, offset_of_disp); | |
304 | 993 addptr(mdp_in, disp_address); |
994 movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp_in); | |
0 | 995 } |
996 | |
997 | |
998 void InterpreterMacroAssembler::update_mdp_by_offset(Register mdp_in, | |
999 Register reg, | |
1000 int offset_of_disp) { | |
1001 assert(ProfileInterpreter, "must be profiling interpreter"); | |
1002 Address disp_address(mdp_in, reg, Address::times_1, offset_of_disp); | |
304 | 1003 addptr(mdp_in, disp_address); |
1004 movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp_in); | |
0 | 1005 } |
1006 | |
1007 | |
1008 void InterpreterMacroAssembler::update_mdp_by_constant(Register mdp_in, | |
1009 int constant) { | |
1010 assert(ProfileInterpreter, "must be profiling interpreter"); | |
304 | 1011 addptr(mdp_in, constant); |
1012 movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp_in); | |
0 | 1013 } |
1014 | |
1015 | |
1016 void InterpreterMacroAssembler::update_mdp_for_ret(Register return_bci) { | |
1017 assert(ProfileInterpreter, "must be profiling interpreter"); | |
304 | 1018 push(return_bci); // save/restore across call_VM |
0 | 1019 call_VM(noreg, |
1020 CAST_FROM_FN_PTR(address, InterpreterRuntime::update_mdp_for_ret), | |
1021 return_bci); | |
304 | 1022 pop(return_bci); |
0 | 1023 } |
1024 | |
1025 | |
1026 void InterpreterMacroAssembler::profile_taken_branch(Register mdp, | |
1027 Register bumped_count) { | |
1028 if (ProfileInterpreter) { | |
1029 Label profile_continue; | |
1030 | |
1031 // If no method data exists, go to profile_continue. | |
1032 // Otherwise, assign to mdp | |
1033 test_method_data_pointer(mdp, profile_continue); | |
1034 | |
1035 // We are taking a branch. Increment the taken count. | |
1036 // We inline increment_mdp_data_at to return bumped_count in a register | |
1037 //increment_mdp_data_at(mdp, in_bytes(JumpData::taken_offset())); | |
1038 Address data(mdp, in_bytes(JumpData::taken_offset())); | |
304 | 1039 movptr(bumped_count, data); |
0 | 1040 assert(DataLayout::counter_increment == 1, |
1041 "flow-free idiom only works with 1"); | |
304 | 1042 addptr(bumped_count, DataLayout::counter_increment); |
1043 sbbptr(bumped_count, 0); | |
1044 movptr(data, bumped_count); // Store back out | |
0 | 1045 |
1046 // The method data pointer needs to be updated to reflect the new target. | |
1047 update_mdp_by_offset(mdp, in_bytes(JumpData::displacement_offset())); | |
1048 bind(profile_continue); | |
1049 } | |
1050 } | |
1051 | |
1052 | |
1053 void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) { | |
1054 if (ProfileInterpreter) { | |
1055 Label profile_continue; | |
1056 | |
1057 // If no method data exists, go to profile_continue. | |
1058 test_method_data_pointer(mdp, profile_continue); | |
1059 | |
1060 // We are taking a branch. Increment the not taken count. | |
1061 increment_mdp_data_at(mdp, in_bytes(BranchData::not_taken_offset())); | |
1062 | |
1063 // The method data pointer needs to be updated to correspond to | |
1064 // the next bytecode | |
1065 update_mdp_by_constant(mdp, in_bytes(BranchData::branch_data_size())); | |
1066 bind(profile_continue); | |
1067 } | |
1068 } | |
1069 | |
1070 void InterpreterMacroAssembler::profile_call(Register mdp) { | |
1071 if (ProfileInterpreter) { | |
1072 Label profile_continue; | |
1073 | |
1074 // If no method data exists, go to profile_continue. | |
1075 test_method_data_pointer(mdp, profile_continue); | |
1076 | |
1077 // We are making a call. Increment the count. | |
1078 increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); | |
1079 | |
1080 // The method data pointer needs to be updated to reflect the new target. | |
1081 update_mdp_by_constant(mdp, in_bytes(CounterData::counter_data_size())); | |
1082 bind(profile_continue); | |
1083 } | |
1084 } | |
1085 | |
1086 | |
1087 void InterpreterMacroAssembler::profile_final_call(Register mdp) { | |
1088 if (ProfileInterpreter) { | |
1089 Label profile_continue; | |
1090 | |
1091 // If no method data exists, go to profile_continue. | |
1092 test_method_data_pointer(mdp, profile_continue); | |
1093 | |
1094 // We are making a call. Increment the count. | |
1095 increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); | |
1096 | |
1097 // The method data pointer needs to be updated to reflect the new target. | |
1098 update_mdp_by_constant(mdp, | |
1099 in_bytes(VirtualCallData:: | |
1100 virtual_call_data_size())); | |
1101 bind(profile_continue); | |
1102 } | |
1103 } | |
1104 | |
1105 | |
1106 void InterpreterMacroAssembler::profile_virtual_call(Register receiver, | |
1107 Register mdp, | |
1108 | 1108 Register reg2, |
1109 bool receiver_can_be_null) { | |
0 | 1110 if (ProfileInterpreter) { |
1111 Label profile_continue; | |
1112 | |
1113 // If no method data exists, go to profile_continue. | |
1114 test_method_data_pointer(mdp, profile_continue); | |
1115 | |
1108 | 1116 Label skip_receiver_profile; |
1117 if (receiver_can_be_null) { | |
1206
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1118 Label not_null; |
1108 | 1119 testptr(receiver, receiver); |
1206
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1120 jccb(Assembler::notZero, not_null); |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1121 // We are making a call. Increment the count for null receiver. |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1122 increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1123 jmp(skip_receiver_profile); |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1124 bind(not_null); |
1108 | 1125 } |
1126 | |
0 | 1127 // Record the receiver type. |
1206
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1128 record_klass_in_profile(receiver, mdp, reg2, true); |
1108 | 1129 bind(skip_receiver_profile); |
0 | 1130 |
1131 // The method data pointer needs to be updated to reflect the new target. | |
1132 update_mdp_by_constant(mdp, | |
1133 in_bytes(VirtualCallData:: | |
1134 virtual_call_data_size())); | |
1135 bind(profile_continue); | |
1136 } | |
1137 } | |
1138 | |
1139 // This routine creates a state machine for updating the multi-row | |
1140 // type profile at a virtual call site (or other type-sensitive bytecode). | |
1141 // The machine visits each row (of receiver/count) until the receiver type | |
1142 // is found, or until it runs out of rows. At the same time, it remembers | |
1143 // the location of the first empty row. (An empty row records null for its | |
1144 // receiver, and can be allocated for a newly-observed receiver type.) | |
1145 // Because there are two degrees of freedom in the state, a simple linear | |
1146 // search will not work; it must be a decision tree. Hence this helper | |
1147 // function is recursive, to generate the required tree structured code. | |
1148 // It's the interpreter, so we are trading off code space for speed. | |
1149 // See below for example code. | |
1150 void InterpreterMacroAssembler::record_klass_in_profile_helper( | |
1151 Register receiver, Register mdp, | |
1206
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1152 Register reg2, int start_row, |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1153 Label& done, bool is_virtual_call) { |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1154 if (TypeProfileWidth == 0) { |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1155 if (is_virtual_call) { |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1156 increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1157 } |
967
6918603297f7
6858208: jvm crash when specifying TypeProfileWidth=0 on jdk 6.0
poonam
parents:
826
diff
changeset
|
1158 return; |
1206
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1159 } |
967
6918603297f7
6858208: jvm crash when specifying TypeProfileWidth=0 on jdk 6.0
poonam
parents:
826
diff
changeset
|
1160 |
0 | 1161 int last_row = VirtualCallData::row_limit() - 1; |
1162 assert(start_row <= last_row, "must be work left to do"); | |
1163 // Test this row for both the receiver and for null. | |
1164 // Take any of three different outcomes: | |
1165 // 1. found receiver => increment count and goto done | |
1166 // 2. found null => keep looking for case 1, maybe allocate this cell | |
1167 // 3. found something else => keep looking for cases 1 and 2 | |
1168 // Case 3 is handled by a recursive call. | |
1169 for (int row = start_row; row <= last_row; row++) { | |
1170 Label next_test; | |
1171 bool test_for_null_also = (row == start_row); | |
1172 | |
1173 // See if the receiver is receiver[n]. | |
1174 int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); | |
1175 test_mdp_data_at(mdp, recvr_offset, receiver, | |
1176 (test_for_null_also ? reg2 : noreg), | |
1177 next_test); | |
1178 // (Reg2 now contains the receiver from the CallData.) | |
1179 | |
1180 // The receiver is receiver[n]. Increment count[n]. | |
1181 int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); | |
1182 increment_mdp_data_at(mdp, count_offset); | |
1183 jmp(done); | |
1184 bind(next_test); | |
1185 | |
1186 if (test_for_null_also) { | |
1206
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1187 Label found_null; |
0 | 1188 // Failed the equality check on receiver[n]... Test for null. |
304 | 1189 testptr(reg2, reg2); |
0 | 1190 if (start_row == last_row) { |
1191 // The only thing left to do is handle the null case. | |
1206
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1192 if (is_virtual_call) { |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1193 jccb(Assembler::zero, found_null); |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1194 // Receiver did not match any saved receiver and there is no empty row for it. |
1251
576e77447e3c
6923002: assert(false,"this call site should not be polymorphic")
kvn
parents:
1206
diff
changeset
|
1195 // Increment total counter to indicate polymorphic case. |
1206
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1196 increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1197 jmp(done); |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1198 bind(found_null); |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1199 } else { |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1200 jcc(Assembler::notZero, done); |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1201 } |
0 | 1202 break; |
1203 } | |
1204 // Since null is rare, make it be the branch-taken case. | |
1205 jcc(Assembler::zero, found_null); | |
1206 | |
1207 // Put all the "Case 3" tests here. | |
1206
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1208 record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call); |
0 | 1209 |
1210 // Found a null. Keep searching for a matching receiver, | |
1211 // but remember that this is an empty (unused) slot. | |
1212 bind(found_null); | |
1213 } | |
1214 } | |
1215 | |
1216 // In the fall-through case, we found no matching receiver, but we | |
1217 // observed the receiver[start_row] is NULL. | |
1218 | |
1219 // Fill in the receiver field and increment the count. | |
1220 int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row)); | |
1221 set_mdp_data_at(mdp, recvr_offset, receiver); | |
1222 int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); | |
1223 movl(reg2, DataLayout::counter_increment); | |
1224 set_mdp_data_at(mdp, count_offset, reg2); | |
1206
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1225 if (start_row > 0) { |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1226 jmp(done); |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1227 } |
0 | 1228 } |
1229 | |
1230 // Example state machine code for three profile rows: | |
1231 // // main copy of decision tree, rooted at row[1] | |
1232 // if (row[0].rec == rec) { row[0].incr(); goto done; } | |
1233 // if (row[0].rec != NULL) { | |
1234 // // inner copy of decision tree, rooted at row[1] | |
1235 // if (row[1].rec == rec) { row[1].incr(); goto done; } | |
1236 // if (row[1].rec != NULL) { | |
1237 // // degenerate decision tree, rooted at row[2] | |
1238 // if (row[2].rec == rec) { row[2].incr(); goto done; } | |
1206
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1239 // if (row[2].rec != NULL) { count.incr(); goto done; } // overflow |
0 | 1240 // row[2].init(rec); goto done; |
1241 // } else { | |
1242 // // remember row[1] is empty | |
1243 // if (row[2].rec == rec) { row[2].incr(); goto done; } | |
1244 // row[1].init(rec); goto done; | |
1245 // } | |
1246 // } else { | |
1247 // // remember row[0] is empty | |
1248 // if (row[1].rec == rec) { row[1].incr(); goto done; } | |
1249 // if (row[2].rec == rec) { row[2].incr(); goto done; } | |
1250 // row[0].init(rec); goto done; | |
1251 // } | |
1206
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1252 // done: |
0 | 1253 |
1254 void InterpreterMacroAssembler::record_klass_in_profile(Register receiver, | |
1206
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1255 Register mdp, Register reg2, |
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1256 bool is_virtual_call) { |
0 | 1257 assert(ProfileInterpreter, "must be profiling"); |
1258 Label done; | |
1259 | |
1206
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1260 record_klass_in_profile_helper(receiver, mdp, reg2, 0, done, is_virtual_call); |
0 | 1261 |
1262 bind (done); | |
1263 } | |
1264 | |
1265 void InterpreterMacroAssembler::profile_ret(Register return_bci, | |
1266 Register mdp) { | |
1267 if (ProfileInterpreter) { | |
1268 Label profile_continue; | |
1269 uint row; | |
1270 | |
1271 // If no method data exists, go to profile_continue. | |
1272 test_method_data_pointer(mdp, profile_continue); | |
1273 | |
1274 // Update the total ret count. | |
1275 increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); | |
1276 | |
1277 for (row = 0; row < RetData::row_limit(); row++) { | |
1278 Label next_test; | |
1279 | |
1280 // See if return_bci is equal to bci[n]: | |
1281 test_mdp_data_at(mdp, | |
1282 in_bytes(RetData::bci_offset(row)), | |
1283 return_bci, noreg, | |
1284 next_test); | |
1285 | |
1286 // return_bci is equal to bci[n]. Increment the count. | |
1287 increment_mdp_data_at(mdp, in_bytes(RetData::bci_count_offset(row))); | |
1288 | |
1289 // The method data pointer needs to be updated to reflect the new target. | |
1290 update_mdp_by_offset(mdp, | |
1291 in_bytes(RetData::bci_displacement_offset(row))); | |
1292 jmp(profile_continue); | |
1293 bind(next_test); | |
1294 } | |
1295 | |
1296 update_mdp_for_ret(return_bci); | |
1297 | |
1298 bind(profile_continue); | |
1299 } | |
1300 } | |
1301 | |
1302 | |
1303 void InterpreterMacroAssembler::profile_null_seen(Register mdp) { | |
1304 if (ProfileInterpreter) { | |
1305 Label profile_continue; | |
1306 | |
1307 // If no method data exists, go to profile_continue. | |
1308 test_method_data_pointer(mdp, profile_continue); | |
1309 | |
826
3f06f139ef53
6851908: interpreter null check profiling broken causing extra compilation invalidation
never
parents:
710
diff
changeset
|
1310 set_mdp_flag_at(mdp, BitData::null_seen_byte_constant()); |
3f06f139ef53
6851908: interpreter null check profiling broken causing extra compilation invalidation
never
parents:
710
diff
changeset
|
1311 |
0 | 1312 // The method data pointer needs to be updated. |
1313 int mdp_delta = in_bytes(BitData::bit_data_size()); | |
1314 if (TypeProfileCasts) { | |
1315 mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); | |
1316 } | |
1317 update_mdp_by_constant(mdp, mdp_delta); | |
1318 | |
1319 bind(profile_continue); | |
1320 } | |
1321 } | |
1322 | |
1323 | |
1324 void InterpreterMacroAssembler::profile_typecheck_failed(Register mdp) { | |
1325 if (ProfileInterpreter && TypeProfileCasts) { | |
1326 Label profile_continue; | |
1327 | |
1328 // If no method data exists, go to profile_continue. | |
1329 test_method_data_pointer(mdp, profile_continue); | |
1330 | |
1331 int count_offset = in_bytes(CounterData::count_offset()); | |
1332 // Back up the address, since we have already bumped the mdp. | |
1333 count_offset -= in_bytes(VirtualCallData::virtual_call_data_size()); | |
1334 | |
1335 // *Decrement* the counter. We expect to see zero or small negatives. | |
1336 increment_mdp_data_at(mdp, count_offset, true); | |
1337 | |
1338 bind (profile_continue); | |
1339 } | |
1340 } | |
1341 | |
1342 | |
1343 void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass, Register reg2) { | |
1344 if (ProfileInterpreter) { | |
1345 Label profile_continue; | |
1346 | |
1347 // If no method data exists, go to profile_continue. | |
1348 test_method_data_pointer(mdp, profile_continue); | |
1349 | |
1350 // The method data pointer needs to be updated. | |
1351 int mdp_delta = in_bytes(BitData::bit_data_size()); | |
1352 if (TypeProfileCasts) { | |
1353 mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); | |
1354 | |
1355 // Record the object type. | |
1206
87684f1a88b5
6614597: Performance variability in jvm2008 xml.validation
kvn
parents:
1108
diff
changeset
|
1356 record_klass_in_profile(klass, mdp, reg2, false); |
0 | 1357 } |
1358 update_mdp_by_constant(mdp, mdp_delta); | |
1359 | |
1360 bind(profile_continue); | |
1361 } | |
1362 } | |
1363 | |
1364 | |
1365 void InterpreterMacroAssembler::profile_switch_default(Register mdp) { | |
1366 if (ProfileInterpreter) { | |
1367 Label profile_continue; | |
1368 | |
1369 // If no method data exists, go to profile_continue. | |
1370 test_method_data_pointer(mdp, profile_continue); | |
1371 | |
1372 // Update the default case count | |
1373 increment_mdp_data_at(mdp, | |
1374 in_bytes(MultiBranchData::default_count_offset())); | |
1375 | |
1376 // The method data pointer needs to be updated. | |
1377 update_mdp_by_offset(mdp, | |
1378 in_bytes(MultiBranchData:: | |
1379 default_displacement_offset())); | |
1380 | |
1381 bind(profile_continue); | |
1382 } | |
1383 } | |
1384 | |
1385 | |
1386 void InterpreterMacroAssembler::profile_switch_case(Register index, | |
1387 Register mdp, | |
1388 Register reg2) { | |
1389 if (ProfileInterpreter) { | |
1390 Label profile_continue; | |
1391 | |
1392 // If no method data exists, go to profile_continue. | |
1393 test_method_data_pointer(mdp, profile_continue); | |
1394 | |
1395 // Build the base (index * per_case_size_in_bytes()) + | |
1396 // case_array_offset_in_bytes() | |
1397 movl(reg2, in_bytes(MultiBranchData::per_case_size())); | |
304 | 1398 imulptr(index, reg2); // XXX l ? |
1399 addptr(index, in_bytes(MultiBranchData::case_array_offset())); // XXX l ? | |
0 | 1400 |
1401 // Update the case count | |
1402 increment_mdp_data_at(mdp, | |
1403 index, | |
1404 in_bytes(MultiBranchData::relative_count_offset())); | |
1405 | |
1406 // The method data pointer needs to be updated. | |
1407 update_mdp_by_offset(mdp, | |
1408 index, | |
1409 in_bytes(MultiBranchData:: | |
1410 relative_displacement_offset())); | |
1411 | |
1412 bind(profile_continue); | |
1413 } | |
1414 } | |
1415 | |
1416 | |
304 | 1417 |
0 | 1418 void InterpreterMacroAssembler::verify_oop(Register reg, TosState state) { |
1419 if (state == atos) { | |
1420 MacroAssembler::verify_oop(reg); | |
1421 } | |
1422 } | |
1423 | |
1424 void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { | |
1425 } | |
304 | 1426 #endif // !CC_INTERP |
0 | 1427 |
1428 | |
1429 void InterpreterMacroAssembler::notify_method_entry() { | |
1430 // Whenever JVMTI is interp_only_mode, method entry/exit events are sent to | |
1431 // track stack depth. If it is possible to enter interp_only_mode we add | |
1432 // the code to check if the event should be sent. | |
1433 if (JvmtiExport::can_post_interpreter_events()) { | |
1434 Label L; | |
1435 movl(rdx, Address(r15_thread, JavaThread::interp_only_mode_offset())); | |
1436 testl(rdx, rdx); | |
1437 jcc(Assembler::zero, L); | |
1438 call_VM(noreg, CAST_FROM_FN_PTR(address, | |
1439 InterpreterRuntime::post_method_entry)); | |
1440 bind(L); | |
1441 } | |
1442 | |
1443 { | |
1444 SkipIfEqual skip(this, &DTraceMethodProbes, false); | |
1445 get_method(c_rarg1); | |
1446 call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), | |
1447 r15_thread, c_rarg1); | |
1448 } | |
610
70998f2e05ef
6805864: 4/3 Problem with jvmti->redefineClasses: some methods don't get redefined
dcubed
parents:
362
diff
changeset
|
1449 |
70998f2e05ef
6805864: 4/3 Problem with jvmti->redefineClasses: some methods don't get redefined
dcubed
parents:
362
diff
changeset
|
1450 // RedefineClasses() tracing support for obsolete method entry |
70998f2e05ef
6805864: 4/3 Problem with jvmti->redefineClasses: some methods don't get redefined
dcubed
parents:
362
diff
changeset
|
1451 if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { |
70998f2e05ef
6805864: 4/3 Problem with jvmti->redefineClasses: some methods don't get redefined
dcubed
parents:
362
diff
changeset
|
1452 get_method(c_rarg1); |
70998f2e05ef
6805864: 4/3 Problem with jvmti->redefineClasses: some methods don't get redefined
dcubed
parents:
362
diff
changeset
|
1453 call_VM_leaf( |
70998f2e05ef
6805864: 4/3 Problem with jvmti->redefineClasses: some methods don't get redefined
dcubed
parents:
362
diff
changeset
|
1454 CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), |
70998f2e05ef
6805864: 4/3 Problem with jvmti->redefineClasses: some methods don't get redefined
dcubed
parents:
362
diff
changeset
|
1455 r15_thread, c_rarg1); |
70998f2e05ef
6805864: 4/3 Problem with jvmti->redefineClasses: some methods don't get redefined
dcubed
parents:
362
diff
changeset
|
1456 } |
0 | 1457 } |
1458 | |
1459 | |
1460 void InterpreterMacroAssembler::notify_method_exit( | |
1461 TosState state, NotifyMethodExitMode mode) { | |
1462 // Whenever JVMTI is interp_only_mode, method entry/exit events are sent to | |
1463 // track stack depth. If it is possible to enter interp_only_mode we add | |
1464 // the code to check if the event should be sent. | |
1465 if (mode == NotifyJVMTI && JvmtiExport::can_post_interpreter_events()) { | |
1466 Label L; | |
1467 // Note: frame::interpreter_frame_result has a dependency on how the | |
1468 // method result is saved across the call to post_method_exit. If this | |
1469 // is changed then the interpreter_frame_result implementation will | |
1470 // need to be updated too. | |
304 | 1471 |
1472 // For c++ interpreter the result is always stored at a known location in the frame | |
1473 // template interpreter will leave it on the top of the stack. | |
1474 NOT_CC_INTERP(push(state);) | |
0 | 1475 movl(rdx, Address(r15_thread, JavaThread::interp_only_mode_offset())); |
1476 testl(rdx, rdx); | |
1477 jcc(Assembler::zero, L); | |
1478 call_VM(noreg, | |
1479 CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit)); | |
1480 bind(L); | |
304 | 1481 NOT_CC_INTERP(pop(state)); |
0 | 1482 } |
1483 | |
1484 { | |
1485 SkipIfEqual skip(this, &DTraceMethodProbes, false); | |
304 | 1486 NOT_CC_INTERP(push(state)); |
0 | 1487 get_method(c_rarg1); |
1488 call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), | |
1489 r15_thread, c_rarg1); | |
304 | 1490 NOT_CC_INTERP(pop(state)); |
0 | 1491 } |
1492 } | |
1783 | 1493 |
1494 // Jump if ((*counter_addr += increment) & mask) satisfies the condition. | |
1495 void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, | |
1496 int increment, int mask, | |
1497 Register scratch, bool preloaded, | |
1498 Condition cond, Label* where) { | |
1499 if (!preloaded) { | |
1500 movl(scratch, counter_addr); | |
1501 } | |
1502 incrementl(scratch, increment); | |
1503 movl(counter_addr, scratch); | |
1504 andl(scratch, mask); | |
1505 jcc(cond, *where); | |
1506 } |