File: | jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp |
Warning: | line 55, column 3 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | ||||
2 | * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. | ||||
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 | * | ||||
19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||||
20 | * or visit www.oracle.com if you need additional information or have any | ||||
21 | * questions. | ||||
22 | * | ||||
23 | */ | ||||
24 | |||||
25 | #include "precompiled.hpp" | ||||
26 | #include "asm/assembler.hpp" | ||||
27 | #include "c1/c1_Defs.hpp" | ||||
28 | #include "c1/c1_MacroAssembler.hpp" | ||||
29 | #include "c1/c1_Runtime1.hpp" | ||||
30 | #include "ci/ciUtilities.hpp" | ||||
31 | #include "compiler/oopMap.hpp" | ||||
32 | #include "gc/shared/cardTable.hpp" | ||||
33 | #include "gc/shared/cardTableBarrierSet.hpp" | ||||
34 | #include "gc/shared/collectedHeap.hpp" | ||||
35 | #include "gc/shared/tlab_globals.hpp" | ||||
36 | #include "interpreter/interpreter.hpp" | ||||
37 | #include "memory/universe.hpp" | ||||
38 | #include "nativeInst_x86.hpp" | ||||
39 | #include "oops/compiledICHolder.hpp" | ||||
40 | #include "oops/oop.inline.hpp" | ||||
41 | #include "prims/jvmtiExport.hpp" | ||||
42 | #include "register_x86.hpp" | ||||
43 | #include "runtime/sharedRuntime.hpp" | ||||
44 | #include "runtime/signature.hpp" | ||||
45 | #include "runtime/stubRoutines.hpp" | ||||
46 | #include "runtime/vframeArray.hpp" | ||||
47 | #include "utilities/macros.hpp" | ||||
48 | #include "vmreg_x86.inline.hpp" | ||||
49 | |||||
50 | // Implementation of StubAssembler | ||||
51 | |||||
52 | int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, int args_size) { | ||||
53 | // setup registers | ||||
54 | const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread)r15_thread; // is callee-saved register (Visual C++ calling conventions) | ||||
55 | assert(!(oop_result1->is_valid() || metadata_result->is_valid()) || oop_result1 != metadata_result, "registers must be different")do { if (!(!(oop_result1->is_valid() || metadata_result-> is_valid()) || oop_result1 != metadata_result)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 55, "assert(" "!(oop_result1->is_valid() || metadata_result->is_valid()) || oop_result1 != metadata_result" ") failed", "registers must be different"); ::breakpoint(); } } while (0); | ||||
| |||||
56 | assert(oop_result1 != thread && metadata_result != thread, "registers must be different")do { if (!(oop_result1 != thread && metadata_result != thread)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 56, "assert(" "oop_result1 != thread && metadata_result != thread" ") failed", "registers must be different"); ::breakpoint(); } } while (0); | ||||
57 | assert(args_size >= 0, "illegal args_size")do { if (!(args_size >= 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 57, "assert(" "args_size >= 0" ") failed", "illegal args_size" ); ::breakpoint(); } } while (0); | ||||
58 | bool align_stack = false; | ||||
59 | #ifdef _LP641 | ||||
60 | // At a method handle call, the stack may not be properly aligned | ||||
61 | // when returning with an exception. | ||||
62 | align_stack = (stub_id() == Runtime1::handle_exception_from_callee_id); | ||||
63 | #endif | ||||
64 | |||||
65 | #ifdef _LP641 | ||||
66 | mov(c_rarg0, thread); | ||||
67 | set_num_rt_args(0); // Nothing on stack | ||||
68 | #else | ||||
69 | set_num_rt_args(1 + args_size); | ||||
70 | |||||
71 | // push java thread (becomes first argument of C function) | ||||
72 | get_thread(thread); | ||||
73 | push(thread); | ||||
74 | #endif // _LP64 | ||||
75 | |||||
76 | int call_offset = -1; | ||||
77 | if (!align_stack) { | ||||
78 | set_last_Java_frame(thread, noreg, rbp, NULL__null); | ||||
79 | } else { | ||||
80 | address the_pc = pc(); | ||||
81 | call_offset = offset(); | ||||
82 | set_last_Java_frame(thread, noreg, rbp, the_pc); | ||||
83 | andptr(rsp, -(StackAlignmentInBytes)); // Align stack | ||||
84 | } | ||||
85 | |||||
86 | // do the call | ||||
87 | call(RuntimeAddress(entry)); | ||||
88 | if (!align_stack) { | ||||
89 | call_offset = offset(); | ||||
90 | } | ||||
91 | // verify callee-saved register | ||||
92 | #ifdef ASSERT1 | ||||
93 | guarantee(thread != rax, "change this code")do { if (!(thread != rax)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 93, "guarantee(" "thread != rax" ") failed", "change this code" ); ::breakpoint(); } } while (0); | ||||
94 | push(rax); | ||||
95 | { Label L; | ||||
96 | get_thread(rax); | ||||
97 | cmpptr(thread, rax); | ||||
98 | jcc(Assembler::equal, L); | ||||
99 | int3(); | ||||
100 | stop("StubAssembler::call_RT: rdi not callee saved?"); | ||||
101 | bind(L); | ||||
102 | } | ||||
103 | pop(rax); | ||||
104 | #endif | ||||
105 | reset_last_Java_frame(thread, true); | ||||
106 | |||||
107 | // discard thread and arguments | ||||
108 | NOT_LP64(addptr(rsp, num_rt_args()*BytesPerWord)); | ||||
109 | |||||
110 | // check for pending exceptions | ||||
111 | { Label L; | ||||
112 | cmpptr(Address(thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD0L); | ||||
113 | jcc(Assembler::equal, L); | ||||
114 | // exception pending => remove activation and forward to exception handler | ||||
115 | movptr(rax, Address(thread, Thread::pending_exception_offset())); | ||||
116 | // make sure that the vm_results are cleared | ||||
117 | if (oop_result1->is_valid()) { | ||||
118 | movptr(Address(thread, JavaThread::vm_result_offset()), NULL_WORD0L); | ||||
119 | } | ||||
120 | if (metadata_result->is_valid()) { | ||||
121 | movptr(Address(thread, JavaThread::vm_result_2_offset()), NULL_WORD0L); | ||||
122 | } | ||||
123 | if (frame_size() == no_frame_size) { | ||||
124 | leave(); | ||||
125 | jump(RuntimeAddress(StubRoutines::forward_exception_entry())); | ||||
126 | } else if (_stub_id == Runtime1::forward_exception_id) { | ||||
127 | should_not_reach_here(); | ||||
128 | } else { | ||||
129 | jump(RuntimeAddress(Runtime1::entry_for(Runtime1::forward_exception_id))); | ||||
130 | } | ||||
131 | bind(L); | ||||
132 | } | ||||
133 | // get oop results if there are any and reset the values in the thread | ||||
134 | if (oop_result1->is_valid()) { | ||||
135 | get_vm_result(oop_result1, thread); | ||||
136 | } | ||||
137 | if (metadata_result->is_valid()) { | ||||
138 | get_vm_result_2(metadata_result, thread); | ||||
139 | } | ||||
140 | |||||
141 | assert(call_offset >= 0, "Should be set")do { if (!(call_offset >= 0)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 141, "assert(" "call_offset >= 0" ") failed", "Should be set" ); ::breakpoint(); } } while (0); | ||||
142 | return call_offset; | ||||
143 | } | ||||
144 | |||||
145 | |||||
146 | int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1) { | ||||
147 | #ifdef _LP641 | ||||
148 | mov(c_rarg1, arg1); | ||||
149 | #else | ||||
150 | push(arg1); | ||||
151 | #endif // _LP64 | ||||
152 | return call_RT(oop_result1, metadata_result, entry, 1); | ||||
153 | } | ||||
154 | |||||
155 | |||||
156 | int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2) { | ||||
157 | #ifdef _LP641 | ||||
158 | if (c_rarg1 == arg2) { | ||||
159 | if (c_rarg2 == arg1) { | ||||
160 | xchgq(arg1, arg2); | ||||
161 | } else { | ||||
162 | mov(c_rarg2, arg2); | ||||
163 | mov(c_rarg1, arg1); | ||||
164 | } | ||||
165 | } else { | ||||
166 | mov(c_rarg1, arg1); | ||||
167 | mov(c_rarg2, arg2); | ||||
168 | } | ||||
169 | #else | ||||
170 | push(arg2); | ||||
171 | push(arg1); | ||||
172 | #endif // _LP64 | ||||
173 | return call_RT(oop_result1, metadata_result, entry, 2); | ||||
174 | } | ||||
175 | |||||
176 | |||||
177 | int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3) { | ||||
178 | #ifdef _LP641 | ||||
179 | // if there is any conflict use the stack | ||||
180 | if (arg1 == c_rarg2 || arg1 == c_rarg3 || | ||||
181 | arg2 == c_rarg1 || arg2 == c_rarg3 || | ||||
182 | arg3 == c_rarg1 || arg3 == c_rarg2) { | ||||
183 | push(arg3); | ||||
184 | push(arg2); | ||||
185 | push(arg1); | ||||
186 | pop(c_rarg1); | ||||
187 | pop(c_rarg2); | ||||
188 | pop(c_rarg3); | ||||
189 | } else { | ||||
190 | mov(c_rarg1, arg1); | ||||
191 | mov(c_rarg2, arg2); | ||||
192 | mov(c_rarg3, arg3); | ||||
193 | } | ||||
194 | #else | ||||
195 | push(arg3); | ||||
196 | push(arg2); | ||||
197 | push(arg1); | ||||
198 | #endif // _LP64 | ||||
199 | return call_RT(oop_result1, metadata_result, entry, 3); | ||||
200 | } | ||||
201 | |||||
202 | |||||
203 | // Implementation of StubFrame | ||||
204 | |||||
205 | class StubFrame: public StackObj { | ||||
206 | private: | ||||
207 | StubAssembler* _sasm; | ||||
208 | |||||
209 | public: | ||||
210 | StubFrame(StubAssembler* sasm, const char* name, bool must_gc_arguments); | ||||
211 | void load_argument(int offset_in_words, Register reg); | ||||
212 | |||||
213 | ~StubFrame(); | ||||
214 | }; | ||||
215 | |||||
216 | void StubAssembler::prologue(const char* name, bool must_gc_arguments) { | ||||
217 | set_info(name, must_gc_arguments); | ||||
218 | enter(); | ||||
219 | } | ||||
220 | |||||
221 | void StubAssembler::epilogue() { | ||||
222 | leave(); | ||||
223 | ret(0); | ||||
224 | } | ||||
225 | |||||
226 | #define __ _sasm-> | ||||
227 | |||||
228 | StubFrame::StubFrame(StubAssembler* sasm, const char* name, bool must_gc_arguments) { | ||||
229 | _sasm = sasm; | ||||
230 | __ prologue(name, must_gc_arguments); | ||||
231 | } | ||||
232 | |||||
233 | // load parameters that were stored with LIR_Assembler::store_parameter | ||||
234 | // Note: offsets for store_parameter and load_argument must match | ||||
235 | void StubFrame::load_argument(int offset_in_words, Register reg) { | ||||
236 | __ load_parameter(offset_in_words, reg); | ||||
237 | } | ||||
238 | |||||
239 | |||||
240 | StubFrame::~StubFrame() { | ||||
241 | __ epilogue(); | ||||
242 | } | ||||
243 | |||||
244 | #undef __ | ||||
245 | |||||
246 | |||||
247 | // Implementation of Runtime1 | ||||
248 | |||||
249 | const int float_regs_as_doubles_size_in_slots = pd_nof_fpu_regs_frame_map * 2; | ||||
250 | const int xmm_regs_as_doubles_size_in_slots = FrameMap::nof_xmm_regs * 2; | ||||
251 | |||||
252 | // Stack layout for saving/restoring all the registers needed during a runtime | ||||
253 | // call (this includes deoptimization) | ||||
254 | // Note: note that users of this frame may well have arguments to some runtime | ||||
255 | // while these values are on the stack. These positions neglect those arguments | ||||
256 | // but the code in save_live_registers will take the argument count into | ||||
257 | // account. | ||||
258 | // | ||||
259 | #ifdef _LP641 | ||||
260 | #define SLOT2(x)x, x, | ||||
261 | #define SLOT_PER_WORD2 2 | ||||
262 | #else | ||||
263 | #define SLOT2(x)x, | ||||
264 | #define SLOT_PER_WORD2 1 | ||||
265 | #endif // _LP64 | ||||
266 | |||||
267 | enum reg_save_layout { | ||||
268 | // 64bit needs to keep stack 16 byte aligned. So we add some alignment dummies to make that | ||||
269 | // happen and will assert if the stack size we create is misaligned | ||||
270 | #ifdef _LP641 | ||||
271 | align_dummy_0, align_dummy_1, | ||||
272 | #endif // _LP64 | ||||
273 | #ifdef _WIN64 | ||||
274 | // Windows always allocates space for it's argument registers (see | ||||
275 | // frame::arg_reg_save_area_bytes). | ||||
276 | arg_reg_save_1, arg_reg_save_1H, // 0, 4 | ||||
277 | arg_reg_save_2, arg_reg_save_2H, // 8, 12 | ||||
278 | arg_reg_save_3, arg_reg_save_3H, // 16, 20 | ||||
279 | arg_reg_save_4, arg_reg_save_4H, // 24, 28 | ||||
280 | #endif // _WIN64 | ||||
281 | xmm_regs_as_doubles_off, // 32 | ||||
282 | float_regs_as_doubles_off = xmm_regs_as_doubles_off + xmm_regs_as_doubles_size_in_slots, // 160 | ||||
283 | fpu_state_off = float_regs_as_doubles_off + float_regs_as_doubles_size_in_slots, // 224 | ||||
284 | // fpu_state_end_off is exclusive | ||||
285 | fpu_state_end_off = fpu_state_off + (FPUStateSizeInWords / SLOT_PER_WORD2), // 352 | ||||
286 | marker = fpu_state_end_off, SLOT2(markerH)markerH, // 352, 356 | ||||
287 | extra_space_offset, // 360 | ||||
288 | #ifdef _LP641 | ||||
289 | r15_off = extra_space_offset, r15H_off, // 360, 364 | ||||
290 | r14_off, r14H_off, // 368, 372 | ||||
291 | r13_off, r13H_off, // 376, 380 | ||||
292 | r12_off, r12H_off, // 384, 388 | ||||
293 | r11_off, r11H_off, // 392, 396 | ||||
294 | r10_off, r10H_off, // 400, 404 | ||||
295 | r9_off, r9H_off, // 408, 412 | ||||
296 | r8_off, r8H_off, // 416, 420 | ||||
297 | rdi_off, rdiH_off, // 424, 428 | ||||
298 | #else | ||||
299 | rdi_off = extra_space_offset, | ||||
300 | #endif // _LP64 | ||||
301 | rsi_off, SLOT2(rsiH_off)rsiH_off, // 432, 436 | ||||
302 | rbp_off, SLOT2(rbpH_off)rbpH_off, // 440, 444 | ||||
303 | rsp_off, SLOT2(rspH_off)rspH_off, // 448, 452 | ||||
304 | rbx_off, SLOT2(rbxH_off)rbxH_off, // 456, 460 | ||||
305 | rdx_off, SLOT2(rdxH_off)rdxH_off, // 464, 468 | ||||
306 | rcx_off, SLOT2(rcxH_off)rcxH_off, // 472, 476 | ||||
307 | rax_off, SLOT2(raxH_off)raxH_off, // 480, 484 | ||||
308 | saved_rbp_off, SLOT2(saved_rbpH_off)saved_rbpH_off, // 488, 492 | ||||
309 | return_off, SLOT2(returnH_off)returnH_off, // 496, 500 | ||||
310 | reg_save_frame_size // As noted: neglects any parameters to runtime // 504 | ||||
311 | }; | ||||
312 | |||||
313 | // Save off registers which might be killed by calls into the runtime. | ||||
314 | // Tries to smart of about FP registers. In particular we separate | ||||
315 | // saving and describing the FPU registers for deoptimization since we | ||||
316 | // have to save the FPU registers twice if we describe them and on P4 | ||||
317 | // saving FPU registers which don't contain anything appears | ||||
318 | // expensive. The deopt blob is the only thing which needs to | ||||
319 | // describe FPU registers. In all other cases it should be sufficient | ||||
320 | // to simply save their current value. | ||||
321 | // | ||||
322 | // Register is a class, but it would be assigned numerical value. | ||||
323 | // "0" is assigned for rax. Thus we need to ignore -Wnonnull. | ||||
324 | PRAGMA_DIAG_PUSHGCC diagnostic push | ||||
325 | PRAGMA_NONNULL_IGNOREDGCC diagnostic ignored "-Wnonnull" | ||||
326 | static OopMap* generate_oop_map(StubAssembler* sasm, int num_rt_args, | ||||
327 | bool save_fpu_registers = true) { | ||||
328 | |||||
329 | // In 64bit all the args are in regs so there are no additional stack slots | ||||
330 | LP64_ONLY(num_rt_args = 0)num_rt_args = 0; | ||||
331 | LP64_ONLY(assert((reg_save_frame_size * VMRegImpl::stack_slot_size) % 16 == 0, "must be 16 byte aligned");)do { if (!((reg_save_frame_size * VMRegImpl::stack_slot_size) % 16 == 0)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 331, "assert(" "(reg_save_frame_size * VMRegImpl::stack_slot_size) % 16 == 0" ") failed", "must be 16 byte aligned"); ::breakpoint(); } } while (0); | ||||
332 | int frame_size_in_slots = reg_save_frame_size + num_rt_args; // args + thread | ||||
333 | sasm->set_frame_size(frame_size_in_slots / VMRegImpl::slots_per_word); | ||||
334 | |||||
335 | // record saved value locations in an OopMap | ||||
336 | // locations are offsets from sp after runtime call; num_rt_args is number of arguments in call, including thread | ||||
337 | OopMap* map = new OopMap(frame_size_in_slots, 0); | ||||
338 | map->set_callee_saved(VMRegImpl::stack2reg(rax_off + num_rt_args), rax->as_VMReg()); | ||||
339 | map->set_callee_saved(VMRegImpl::stack2reg(rcx_off + num_rt_args), rcx->as_VMReg()); | ||||
340 | map->set_callee_saved(VMRegImpl::stack2reg(rdx_off + num_rt_args), rdx->as_VMReg()); | ||||
341 | map->set_callee_saved(VMRegImpl::stack2reg(rbx_off + num_rt_args), rbx->as_VMReg()); | ||||
342 | map->set_callee_saved(VMRegImpl::stack2reg(rsi_off + num_rt_args), rsi->as_VMReg()); | ||||
343 | map->set_callee_saved(VMRegImpl::stack2reg(rdi_off + num_rt_args), rdi->as_VMReg()); | ||||
344 | #ifdef _LP641 | ||||
345 | map->set_callee_saved(VMRegImpl::stack2reg(r8_off + num_rt_args), r8->as_VMReg()); | ||||
346 | map->set_callee_saved(VMRegImpl::stack2reg(r9_off + num_rt_args), r9->as_VMReg()); | ||||
347 | map->set_callee_saved(VMRegImpl::stack2reg(r10_off + num_rt_args), r10->as_VMReg()); | ||||
348 | map->set_callee_saved(VMRegImpl::stack2reg(r11_off + num_rt_args), r11->as_VMReg()); | ||||
349 | map->set_callee_saved(VMRegImpl::stack2reg(r12_off + num_rt_args), r12->as_VMReg()); | ||||
350 | map->set_callee_saved(VMRegImpl::stack2reg(r13_off + num_rt_args), r13->as_VMReg()); | ||||
351 | map->set_callee_saved(VMRegImpl::stack2reg(r14_off + num_rt_args), r14->as_VMReg()); | ||||
352 | map->set_callee_saved(VMRegImpl::stack2reg(r15_off + num_rt_args), r15->as_VMReg()); | ||||
353 | |||||
354 | // This is stupid but needed. | ||||
355 | map->set_callee_saved(VMRegImpl::stack2reg(raxH_off + num_rt_args), rax->as_VMReg()->next()); | ||||
356 | map->set_callee_saved(VMRegImpl::stack2reg(rcxH_off + num_rt_args), rcx->as_VMReg()->next()); | ||||
357 | map->set_callee_saved(VMRegImpl::stack2reg(rdxH_off + num_rt_args), rdx->as_VMReg()->next()); | ||||
358 | map->set_callee_saved(VMRegImpl::stack2reg(rbxH_off + num_rt_args), rbx->as_VMReg()->next()); | ||||
359 | map->set_callee_saved(VMRegImpl::stack2reg(rsiH_off + num_rt_args), rsi->as_VMReg()->next()); | ||||
360 | map->set_callee_saved(VMRegImpl::stack2reg(rdiH_off + num_rt_args), rdi->as_VMReg()->next()); | ||||
361 | |||||
362 | map->set_callee_saved(VMRegImpl::stack2reg(r8H_off + num_rt_args), r8->as_VMReg()->next()); | ||||
363 | map->set_callee_saved(VMRegImpl::stack2reg(r9H_off + num_rt_args), r9->as_VMReg()->next()); | ||||
364 | map->set_callee_saved(VMRegImpl::stack2reg(r10H_off + num_rt_args), r10->as_VMReg()->next()); | ||||
365 | map->set_callee_saved(VMRegImpl::stack2reg(r11H_off + num_rt_args), r11->as_VMReg()->next()); | ||||
366 | map->set_callee_saved(VMRegImpl::stack2reg(r12H_off + num_rt_args), r12->as_VMReg()->next()); | ||||
367 | map->set_callee_saved(VMRegImpl::stack2reg(r13H_off + num_rt_args), r13->as_VMReg()->next()); | ||||
368 | map->set_callee_saved(VMRegImpl::stack2reg(r14H_off + num_rt_args), r14->as_VMReg()->next()); | ||||
369 | map->set_callee_saved(VMRegImpl::stack2reg(r15H_off + num_rt_args), r15->as_VMReg()->next()); | ||||
370 | #endif // _LP64 | ||||
371 | |||||
372 | int xmm_bypass_limit = FrameMap::nof_xmm_regs; | ||||
373 | #ifdef _LP641 | ||||
374 | if (UseAVX < 3) { | ||||
375 | xmm_bypass_limit = xmm_bypass_limit / 2; | ||||
376 | } | ||||
377 | #endif | ||||
378 | |||||
379 | if (save_fpu_registers) { | ||||
380 | #ifndef _LP641 | ||||
381 | if (UseSSE < 2) { | ||||
382 | int fpu_off = float_regs_as_doubles_off; | ||||
383 | for (int n = 0; n < FrameMap::nof_fpu_regs; n++) { | ||||
384 | VMReg fpu_name_0 = FrameMap::fpu_regname(n); | ||||
385 | map->set_callee_saved(VMRegImpl::stack2reg(fpu_off + num_rt_args), fpu_name_0); | ||||
386 | // %%% This is really a waste but we'll keep things as they were for now | ||||
387 | if (true) { | ||||
388 | map->set_callee_saved(VMRegImpl::stack2reg(fpu_off + 1 + num_rt_args), fpu_name_0->next()); | ||||
389 | } | ||||
390 | fpu_off += 2; | ||||
391 | } | ||||
392 | assert(fpu_off == fpu_state_off, "incorrect number of fpu stack slots")do { if (!(fpu_off == fpu_state_off)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 392, "assert(" "fpu_off == fpu_state_off" ") failed", "incorrect number of fpu stack slots" ); ::breakpoint(); } } while (0); | ||||
393 | |||||
394 | if (UseSSE == 1) { | ||||
395 | int xmm_off = xmm_regs_as_doubles_off; | ||||
396 | for (int n = 0; n < FrameMap::nof_fpu_regs; n++) { | ||||
397 | VMReg xmm_name_0 = as_XMMRegister(n)->as_VMReg(); | ||||
398 | map->set_callee_saved(VMRegImpl::stack2reg(xmm_off + num_rt_args), xmm_name_0); | ||||
399 | xmm_off += 2; | ||||
400 | } | ||||
401 | assert(xmm_off == float_regs_as_doubles_off, "incorrect number of xmm registers")do { if (!(xmm_off == float_regs_as_doubles_off)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 401, "assert(" "xmm_off == float_regs_as_doubles_off" ") failed" , "incorrect number of xmm registers"); ::breakpoint(); } } while (0); | ||||
402 | } | ||||
403 | } | ||||
404 | #endif // !LP64 | ||||
405 | |||||
406 | if (UseSSE >= 2) { | ||||
407 | int xmm_off = xmm_regs_as_doubles_off; | ||||
408 | for (int n = 0; n < FrameMap::nof_xmm_regs; n++) { | ||||
409 | if (n < xmm_bypass_limit) { | ||||
410 | VMReg xmm_name_0 = as_XMMRegister(n)->as_VMReg(); | ||||
411 | map->set_callee_saved(VMRegImpl::stack2reg(xmm_off + num_rt_args), xmm_name_0); | ||||
412 | // %%% This is really a waste but we'll keep things as they were for now | ||||
413 | if (true) { | ||||
414 | map->set_callee_saved(VMRegImpl::stack2reg(xmm_off + 1 + num_rt_args), xmm_name_0->next()); | ||||
415 | } | ||||
416 | } | ||||
417 | xmm_off += 2; | ||||
418 | } | ||||
419 | assert(xmm_off == float_regs_as_doubles_off, "incorrect number of xmm registers")do { if (!(xmm_off == float_regs_as_doubles_off)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 419, "assert(" "xmm_off == float_regs_as_doubles_off" ") failed" , "incorrect number of xmm registers"); ::breakpoint(); } } while (0); | ||||
420 | } | ||||
421 | } | ||||
422 | |||||
423 | return map; | ||||
424 | } | ||||
425 | PRAGMA_DIAG_POPGCC diagnostic pop | ||||
426 | |||||
427 | #define __ this-> | ||||
428 | |||||
429 | void C1_MacroAssembler::save_live_registers_no_oop_map(bool save_fpu_registers) { | ||||
430 | __ block_comment("save_live_registers"); | ||||
431 | |||||
432 | __ pusha(); // integer registers | ||||
433 | |||||
434 | // assert(float_regs_as_doubles_off % 2 == 0, "misaligned offset"); | ||||
435 | // assert(xmm_regs_as_doubles_off % 2 == 0, "misaligned offset"); | ||||
436 | |||||
437 | __ subptr(rsp, extra_space_offset * VMRegImpl::stack_slot_size); | ||||
438 | |||||
439 | #ifdef ASSERT1 | ||||
440 | __ movptr(Address(rsp, marker * VMRegImpl::stack_slot_size), (int32_t)0xfeedbeef); | ||||
441 | #endif | ||||
442 | |||||
443 | if (save_fpu_registers) { | ||||
444 | #ifndef _LP641 | ||||
445 | if (UseSSE < 2) { | ||||
446 | // save FPU stack | ||||
447 | __ fnsave(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size)); | ||||
448 | __ fwait(); | ||||
449 | |||||
450 | #ifdef ASSERT1 | ||||
451 | Label ok; | ||||
452 | __ cmpw(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size), StubRoutines::x86::fpu_cntrl_wrd_std()); | ||||
453 | __ jccb(Assembler::equal, ok)jccb_0(Assembler::equal, ok, "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 453); | ||||
454 | __ stop("corrupted control word detected"); | ||||
455 | __ bind(ok); | ||||
456 | #endif | ||||
457 | |||||
458 | // Reset the control word to guard against exceptions being unmasked | ||||
459 | // since fstp_d can cause FPU stack underflow exceptions. Write it | ||||
460 | // into the on stack copy and then reload that to make sure that the | ||||
461 | // current and future values are correct. | ||||
462 | __ movw(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size), StubRoutines::x86::fpu_cntrl_wrd_std()); | ||||
463 | __ frstor(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size)); | ||||
464 | |||||
465 | // Save the FPU registers in de-opt-able form | ||||
466 | int offset = 0; | ||||
467 | for (int n = 0; n < FrameMap::nof_fpu_regs; n++) { | ||||
468 | __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size + offset)); | ||||
469 | offset += 8; | ||||
470 | } | ||||
471 | |||||
472 | if (UseSSE == 1) { | ||||
473 | // save XMM registers as float because double not supported without SSE2(num MMX == num fpu) | ||||
474 | int offset = 0; | ||||
475 | for (int n = 0; n < FrameMap::nof_fpu_regs; n++) { | ||||
476 | XMMRegister xmm_name = as_XMMRegister(n); | ||||
477 | __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + offset), xmm_name); | ||||
478 | offset += 8; | ||||
479 | } | ||||
480 | } | ||||
481 | } | ||||
482 | #endif // !_LP64 | ||||
483 | |||||
484 | if (UseSSE >= 2) { | ||||
485 | // save XMM registers | ||||
486 | // XMM registers can contain float or double values, but this is not known here, | ||||
487 | // so always save them as doubles. | ||||
488 | // note that float values are _not_ converted automatically, so for float values | ||||
489 | // the second word contains only garbage data. | ||||
490 | int xmm_bypass_limit = FrameMap::nof_xmm_regs; | ||||
491 | int offset = 0; | ||||
492 | #ifdef _LP641 | ||||
493 | if (UseAVX < 3) { | ||||
494 | xmm_bypass_limit = xmm_bypass_limit / 2; | ||||
495 | } | ||||
496 | #endif | ||||
497 | for (int n = 0; n < xmm_bypass_limit; n++) { | ||||
498 | XMMRegister xmm_name = as_XMMRegister(n); | ||||
499 | __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + offset), xmm_name); | ||||
500 | offset += 8; | ||||
501 | } | ||||
502 | } | ||||
503 | } | ||||
504 | |||||
505 | // FPU stack must be empty now | ||||
506 | NOT_LP64( __ verify_FPU(0, "save_live_registers"); ) | ||||
507 | } | ||||
508 | |||||
509 | #undef __ | ||||
510 | #define __ sasm-> | ||||
511 | |||||
512 | static void restore_fpu(C1_MacroAssembler* sasm, bool restore_fpu_registers) { | ||||
513 | #ifdef _LP641 | ||||
514 | if (restore_fpu_registers) { | ||||
515 | // restore XMM registers | ||||
516 | int xmm_bypass_limit = FrameMap::nof_xmm_regs; | ||||
517 | if (UseAVX < 3) { | ||||
518 | xmm_bypass_limit = xmm_bypass_limit / 2; | ||||
519 | } | ||||
520 | int offset = 0; | ||||
521 | for (int n = 0; n < xmm_bypass_limit; n++) { | ||||
522 | XMMRegister xmm_name = as_XMMRegister(n); | ||||
523 | __ movdbl(xmm_name, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + offset)); | ||||
524 | offset += 8; | ||||
525 | } | ||||
526 | } | ||||
527 | #else | ||||
528 | if (restore_fpu_registers) { | ||||
529 | if (UseSSE >= 2) { | ||||
530 | // restore XMM registers | ||||
531 | int xmm_bypass_limit = FrameMap::nof_xmm_regs; | ||||
532 | int offset = 0; | ||||
533 | for (int n = 0; n < xmm_bypass_limit; n++) { | ||||
534 | XMMRegister xmm_name = as_XMMRegister(n); | ||||
535 | __ movdbl(xmm_name, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + offset)); | ||||
536 | offset += 8; | ||||
537 | } | ||||
538 | } else if (UseSSE == 1) { | ||||
539 | // restore XMM registers(num MMX == num fpu) | ||||
540 | int offset = 0; | ||||
541 | for (int n = 0; n < FrameMap::nof_fpu_regs; n++) { | ||||
542 | XMMRegister xmm_name = as_XMMRegister(n); | ||||
543 | __ movflt(xmm_name, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + offset)); | ||||
544 | offset += 8; | ||||
545 | } | ||||
546 | } | ||||
547 | |||||
548 | if (UseSSE < 2) { | ||||
549 | __ frstor(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size)); | ||||
550 | } else { | ||||
551 | // check that FPU stack is really empty | ||||
552 | __ verify_FPU(0, "restore_live_registers"); | ||||
553 | } | ||||
554 | } else { | ||||
555 | // check that FPU stack is really empty | ||||
556 | __ verify_FPU(0, "restore_live_registers"); | ||||
557 | } | ||||
558 | #endif // _LP64 | ||||
559 | |||||
560 | #ifdef ASSERT1 | ||||
561 | { | ||||
562 | Label ok; | ||||
563 | __ cmpptr(Address(rsp, marker * VMRegImpl::stack_slot_size), (int32_t)0xfeedbeef); | ||||
564 | __ jcc(Assembler::equal, ok); | ||||
565 | __ stop("bad offsets in frame"); | ||||
566 | __ bind(ok); | ||||
567 | } | ||||
568 | #endif // ASSERT | ||||
569 | |||||
570 | __ addptr(rsp, extra_space_offset * VMRegImpl::stack_slot_size); | ||||
571 | } | ||||
572 | |||||
573 | #undef __ | ||||
574 | #define __ this-> | ||||
575 | |||||
576 | void C1_MacroAssembler::restore_live_registers(bool restore_fpu_registers) { | ||||
577 | __ block_comment("restore_live_registers"); | ||||
578 | |||||
579 | restore_fpu(this, restore_fpu_registers); | ||||
580 | __ popa(); | ||||
581 | } | ||||
582 | |||||
583 | |||||
584 | void C1_MacroAssembler::restore_live_registers_except_rax(bool restore_fpu_registers) { | ||||
585 | __ block_comment("restore_live_registers_except_rax"); | ||||
586 | |||||
587 | restore_fpu(this, restore_fpu_registers); | ||||
588 | |||||
589 | #ifdef _LP641 | ||||
590 | __ movptr(r15, Address(rsp, 0)); | ||||
591 | __ movptr(r14, Address(rsp, wordSize)); | ||||
592 | __ movptr(r13, Address(rsp, 2 * wordSize)); | ||||
593 | __ movptr(r12, Address(rsp, 3 * wordSize)); | ||||
594 | __ movptr(r11, Address(rsp, 4 * wordSize)); | ||||
595 | __ movptr(r10, Address(rsp, 5 * wordSize)); | ||||
596 | __ movptr(r9, Address(rsp, 6 * wordSize)); | ||||
597 | __ movptr(r8, Address(rsp, 7 * wordSize)); | ||||
598 | __ movptr(rdi, Address(rsp, 8 * wordSize)); | ||||
599 | __ movptr(rsi, Address(rsp, 9 * wordSize)); | ||||
600 | __ movptr(rbp, Address(rsp, 10 * wordSize)); | ||||
601 | // skip rsp | ||||
602 | __ movptr(rbx, Address(rsp, 12 * wordSize)); | ||||
603 | __ movptr(rdx, Address(rsp, 13 * wordSize)); | ||||
604 | __ movptr(rcx, Address(rsp, 14 * wordSize)); | ||||
605 | |||||
606 | __ addptr(rsp, 16 * wordSize); | ||||
607 | #else | ||||
608 | |||||
609 | __ pop(rdi); | ||||
610 | __ pop(rsi); | ||||
611 | __ pop(rbp); | ||||
612 | __ pop(rbx); // skip this value | ||||
613 | __ pop(rbx); | ||||
614 | __ pop(rdx); | ||||
615 | __ pop(rcx); | ||||
616 | __ addptr(rsp, BytesPerWord); | ||||
617 | #endif // _LP64 | ||||
618 | } | ||||
619 | |||||
620 | #undef __ | ||||
621 | #define __ sasm-> | ||||
622 | |||||
623 | static OopMap* save_live_registers(StubAssembler* sasm, int num_rt_args, | ||||
624 | bool save_fpu_registers = true) { | ||||
625 | __ save_live_registers_no_oop_map(save_fpu_registers); | ||||
626 | return generate_oop_map(sasm, num_rt_args, save_fpu_registers); | ||||
627 | } | ||||
628 | |||||
629 | static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) { | ||||
630 | __ restore_live_registers(restore_fpu_registers); | ||||
631 | } | ||||
632 | |||||
633 | static void restore_live_registers_except_rax(StubAssembler* sasm, bool restore_fpu_registers = true) { | ||||
634 | sasm->restore_live_registers_except_rax(restore_fpu_registers); | ||||
635 | } | ||||
636 | |||||
637 | |||||
638 | void Runtime1::initialize_pd() { | ||||
639 | // nothing to do | ||||
640 | } | ||||
641 | |||||
642 | |||||
643 | // Target: the entry point of the method that creates and posts the exception oop. | ||||
644 | // has_argument: true if the exception needs arguments (passed on the stack because | ||||
645 | // registers must be preserved). | ||||
646 | OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address target, bool has_argument) { | ||||
647 | // Preserve all registers. | ||||
648 | int num_rt_args = has_argument ? (2 + 1) : 1; | ||||
649 | OopMap* oop_map = save_live_registers(sasm, num_rt_args); | ||||
650 | |||||
651 | // Now all registers are saved and can be used freely. | ||||
652 | // Verify that no old value is used accidentally. | ||||
653 | __ invalidate_registers(true, true, true, true, true, true); | ||||
654 | |||||
655 | // Registers used by this stub. | ||||
656 | const Register temp_reg = rbx; | ||||
657 | |||||
658 | // Load arguments for exception that are passed as arguments into the stub. | ||||
659 | if (has_argument) { | ||||
660 | #ifdef _LP641 | ||||
661 | __ movptr(c_rarg1, Address(rbp, 2*BytesPerWord)); | ||||
662 | __ movptr(c_rarg2, Address(rbp, 3*BytesPerWord)); | ||||
663 | #else | ||||
664 | __ movptr(temp_reg, Address(rbp, 3*BytesPerWord)); | ||||
665 | __ push(temp_reg); | ||||
666 | __ movptr(temp_reg, Address(rbp, 2*BytesPerWord)); | ||||
667 | __ push(temp_reg); | ||||
668 | #endif // _LP64 | ||||
669 | } | ||||
670 | int call_offset = __ call_RT(noreg, noreg, target, num_rt_args - 1); | ||||
671 | |||||
672 | OopMapSet* oop_maps = new OopMapSet(); | ||||
673 | oop_maps->add_gc_map(call_offset, oop_map); | ||||
674 | |||||
675 | __ stop("should not reach here"); | ||||
676 | |||||
677 | return oop_maps; | ||||
678 | } | ||||
679 | |||||
680 | |||||
681 | OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) { | ||||
682 | __ block_comment("generate_handle_exception"); | ||||
683 | |||||
684 | // incoming parameters | ||||
685 | const Register exception_oop = rax; | ||||
686 | const Register exception_pc = rdx; | ||||
687 | // other registers used in this stub | ||||
688 | const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread)r15_thread; | ||||
689 | |||||
690 | // Save registers, if required. | ||||
691 | OopMapSet* oop_maps = new OopMapSet(); | ||||
692 | OopMap* oop_map = NULL__null; | ||||
693 | switch (id) { | ||||
694 | case forward_exception_id: | ||||
695 | // We're handling an exception in the context of a compiled frame. | ||||
696 | // The registers have been saved in the standard places. Perform | ||||
697 | // an exception lookup in the caller and dispatch to the handler | ||||
698 | // if found. Otherwise unwind and dispatch to the callers | ||||
699 | // exception handler. | ||||
700 | oop_map = generate_oop_map(sasm, 1 /*thread*/); | ||||
701 | |||||
702 | // load and clear pending exception oop into RAX | ||||
703 | __ movptr(exception_oop, Address(thread, Thread::pending_exception_offset())); | ||||
704 | __ movptr(Address(thread, Thread::pending_exception_offset()), NULL_WORD0L); | ||||
705 | |||||
706 | // load issuing PC (the return address for this stub) into rdx | ||||
707 | __ movptr(exception_pc, Address(rbp, 1*BytesPerWord)); | ||||
708 | |||||
709 | // make sure that the vm_results are cleared (may be unnecessary) | ||||
710 | __ movptr(Address(thread, JavaThread::vm_result_offset()), NULL_WORD0L); | ||||
711 | __ movptr(Address(thread, JavaThread::vm_result_2_offset()), NULL_WORD0L); | ||||
712 | break; | ||||
713 | case handle_exception_nofpu_id: | ||||
714 | case handle_exception_id: | ||||
715 | // At this point all registers MAY be live. | ||||
716 | oop_map = save_live_registers(sasm, 1 /*thread*/, id != handle_exception_nofpu_id); | ||||
717 | break; | ||||
718 | case handle_exception_from_callee_id: { | ||||
719 | // At this point all registers except exception oop (RAX) and | ||||
720 | // exception pc (RDX) are dead. | ||||
721 | const int frame_size = 2 /*BP, return address*/ NOT_LP64(+ 1 /*thread*/) WIN64_ONLY(+ frame::arg_reg_save_area_bytes / BytesPerWord); | ||||
722 | oop_map = new OopMap(frame_size * VMRegImpl::slots_per_word, 0); | ||||
723 | sasm->set_frame_size(frame_size); | ||||
724 | WIN64_ONLY(__ subq(rsp, frame::arg_reg_save_area_bytes)); | ||||
725 | break; | ||||
726 | } | ||||
727 | default: ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 727); ::breakpoint(); } while (0); | ||||
728 | } | ||||
729 | |||||
730 | #if !defined(_LP641) && defined(COMPILER21) | ||||
731 | if (UseSSE < 2 && !CompilerConfig::is_c1_only_no_jvmci()) { | ||||
732 | // C2 can leave the fpu stack dirty | ||||
733 | __ empty_FPU_stack(); | ||||
734 | } | ||||
735 | #endif // !_LP64 && COMPILER2 | ||||
736 | |||||
737 | // verify that only rax, and rdx is valid at this time | ||||
738 | __ invalidate_registers(false, true, true, false, true, true); | ||||
739 | // verify that rax, contains a valid exception | ||||
740 | __ verify_not_null_oop(exception_oop); | ||||
741 | |||||
742 | // load address of JavaThread object for thread-local data | ||||
743 | NOT_LP64(__ get_thread(thread);) | ||||
744 | |||||
745 | #ifdef ASSERT1 | ||||
746 | // check that fields in JavaThread for exception oop and issuing pc are | ||||
747 | // empty before writing to them | ||||
748 | Label oop_empty; | ||||
749 | __ cmpptr(Address(thread, JavaThread::exception_oop_offset()), (int32_t) NULL_WORD0L); | ||||
750 | __ jcc(Assembler::equal, oop_empty); | ||||
751 | __ stop("exception oop already set"); | ||||
752 | __ bind(oop_empty); | ||||
753 | |||||
754 | Label pc_empty; | ||||
755 | __ cmpptr(Address(thread, JavaThread::exception_pc_offset()), 0); | ||||
756 | __ jcc(Assembler::equal, pc_empty); | ||||
757 | __ stop("exception pc already set"); | ||||
758 | __ bind(pc_empty); | ||||
759 | #endif | ||||
760 | |||||
761 | // save exception oop and issuing pc into JavaThread | ||||
762 | // (exception handler will load it from here) | ||||
763 | __ movptr(Address(thread, JavaThread::exception_oop_offset()), exception_oop); | ||||
764 | __ movptr(Address(thread, JavaThread::exception_pc_offset()), exception_pc); | ||||
765 | |||||
766 | // patch throwing pc into return address (has bci & oop map) | ||||
767 | __ movptr(Address(rbp, 1*BytesPerWord), exception_pc); | ||||
768 | |||||
769 | // compute the exception handler. | ||||
770 | // the exception oop and the throwing pc are read from the fields in JavaThread | ||||
771 | int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc)((address)((address_word)(exception_handler_for_pc)))); | ||||
772 | oop_maps->add_gc_map(call_offset, oop_map); | ||||
773 | |||||
774 | // rax: handler address | ||||
775 | // will be the deopt blob if nmethod was deoptimized while we looked up | ||||
776 | // handler regardless of whether handler existed in the nmethod. | ||||
777 | |||||
778 | // only rax, is valid at this time, all other registers have been destroyed by the runtime call | ||||
779 | __ invalidate_registers(false, true, true, true, true, true); | ||||
780 | |||||
781 | // patch the return address, this stub will directly return to the exception handler | ||||
782 | __ movptr(Address(rbp, 1*BytesPerWord), rax); | ||||
783 | |||||
784 | switch (id) { | ||||
785 | case forward_exception_id: | ||||
786 | case handle_exception_nofpu_id: | ||||
787 | case handle_exception_id: | ||||
788 | // Restore the registers that were saved at the beginning. | ||||
789 | restore_live_registers(sasm, id != handle_exception_nofpu_id); | ||||
790 | break; | ||||
791 | case handle_exception_from_callee_id: | ||||
792 | // WIN64_ONLY: No need to add frame::arg_reg_save_area_bytes to SP | ||||
793 | // since we do a leave anyway. | ||||
794 | |||||
795 | // Pop the return address. | ||||
796 | __ leave(); | ||||
797 | __ pop(rcx); | ||||
798 | __ jmp(rcx); // jump to exception handler | ||||
799 | break; | ||||
800 | default: ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 800); ::breakpoint(); } while (0); | ||||
801 | } | ||||
802 | |||||
803 | return oop_maps; | ||||
804 | } | ||||
805 | |||||
806 | |||||
807 | void Runtime1::generate_unwind_exception(StubAssembler *sasm) { | ||||
808 | // incoming parameters | ||||
809 | const Register exception_oop = rax; | ||||
810 | // callee-saved copy of exception_oop during runtime call | ||||
811 | const Register exception_oop_callee_saved = NOT_LP64(rsi) LP64_ONLY(r14)r14; | ||||
812 | // other registers used in this stub | ||||
813 | const Register exception_pc = rdx; | ||||
814 | const Register handler_addr = rbx; | ||||
815 | const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread)r15_thread; | ||||
816 | |||||
817 | // verify that only rax, is valid at this time | ||||
818 | __ invalidate_registers(false, true, true, true, true, true); | ||||
819 | |||||
820 | #ifdef ASSERT1 | ||||
821 | // check that fields in JavaThread for exception oop and issuing pc are empty | ||||
822 | NOT_LP64(__ get_thread(thread);) | ||||
823 | Label oop_empty; | ||||
824 | __ cmpptr(Address(thread, JavaThread::exception_oop_offset()), 0); | ||||
825 | __ jcc(Assembler::equal, oop_empty); | ||||
826 | __ stop("exception oop must be empty"); | ||||
827 | __ bind(oop_empty); | ||||
828 | |||||
829 | Label pc_empty; | ||||
830 | __ cmpptr(Address(thread, JavaThread::exception_pc_offset()), 0); | ||||
831 | __ jcc(Assembler::equal, pc_empty); | ||||
832 | __ stop("exception pc must be empty"); | ||||
833 | __ bind(pc_empty); | ||||
834 | #endif | ||||
835 | |||||
836 | // clear the FPU stack in case any FPU results are left behind | ||||
837 | NOT_LP64( __ empty_FPU_stack(); ) | ||||
838 | |||||
839 | // save exception_oop in callee-saved register to preserve it during runtime calls | ||||
840 | __ verify_not_null_oop(exception_oop); | ||||
841 | __ movptr(exception_oop_callee_saved, exception_oop); | ||||
842 | |||||
843 | NOT_LP64(__ get_thread(thread);) | ||||
844 | // Get return address (is on top of stack after leave). | ||||
845 | __ movptr(exception_pc, Address(rsp, 0)); | ||||
846 | |||||
847 | // search the exception handler address of the caller (using the return address) | ||||
848 | __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address)((address)((address_word)(SharedRuntime::exception_handler_for_return_address ))), thread, exception_pc); | ||||
849 | // rax: exception handler address of the caller | ||||
850 | |||||
851 | // Only RAX and RSI are valid at this time, all other registers have been destroyed by the call. | ||||
852 | __ invalidate_registers(false, true, true, true, false, true); | ||||
853 | |||||
854 | // move result of call into correct register | ||||
855 | __ movptr(handler_addr, rax); | ||||
856 | |||||
857 | // Restore exception oop to RAX (required convention of exception handler). | ||||
858 | __ movptr(exception_oop, exception_oop_callee_saved); | ||||
859 | |||||
860 | // verify that there is really a valid exception in rax | ||||
861 | __ verify_not_null_oop(exception_oop); | ||||
862 | |||||
863 | // get throwing pc (= return address). | ||||
864 | // rdx has been destroyed by the call, so it must be set again | ||||
865 | // the pop is also necessary to simulate the effect of a ret(0) | ||||
866 | __ pop(exception_pc); | ||||
867 | |||||
868 | // continue at exception handler (return address removed) | ||||
869 | // note: do *not* remove arguments when unwinding the | ||||
870 | // activation since the caller assumes having | ||||
871 | // all arguments on the stack when entering the | ||||
872 | // runtime to determine the exception handler | ||||
873 | // (GC happens at call site with arguments!) | ||||
874 | // rax: exception oop | ||||
875 | // rdx: throwing pc | ||||
876 | // rbx: exception handler | ||||
877 | __ jmp(handler_addr); | ||||
878 | } | ||||
879 | |||||
880 | |||||
881 | OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) { | ||||
882 | // use the maximum number of runtime-arguments here because it is difficult to | ||||
883 | // distinguish each RT-Call. | ||||
884 | // Note: This number affects also the RT-Call in generate_handle_exception because | ||||
885 | // the oop-map is shared for all calls. | ||||
886 | const int num_rt_args = 2; // thread + dummy | ||||
887 | |||||
888 | DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); | ||||
889 | assert(deopt_blob != NULL, "deoptimization blob must have been created")do { if (!(deopt_blob != __null)) { (*g_assert_poison) = 'X'; ; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 889, "assert(" "deopt_blob != __null" ") failed", "deoptimization blob must have been created" ); ::breakpoint(); } } while (0); | ||||
890 | |||||
891 | OopMap* oop_map = save_live_registers(sasm, num_rt_args); | ||||
892 | |||||
893 | #ifdef _LP641 | ||||
894 | const Register thread = r15_thread; | ||||
895 | // No need to worry about dummy | ||||
896 | __ mov(c_rarg0, thread); | ||||
897 | #else | ||||
898 | __ push(rax); // push dummy | ||||
899 | |||||
900 | const Register thread = rdi; // is callee-saved register (Visual C++ calling conventions) | ||||
901 | // push java thread (becomes first argument of C function) | ||||
902 | __ get_thread(thread); | ||||
903 | __ push(thread); | ||||
904 | #endif // _LP64 | ||||
905 | __ set_last_Java_frame(thread, noreg, rbp, NULL__null); | ||||
906 | // do the call | ||||
907 | __ call(RuntimeAddress(target)); | ||||
908 | OopMapSet* oop_maps = new OopMapSet(); | ||||
909 | oop_maps->add_gc_map(__ offset(), oop_map); | ||||
910 | // verify callee-saved register | ||||
911 | #ifdef ASSERT1 | ||||
912 | guarantee(thread != rax, "change this code")do { if (!(thread != rax)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 912, "guarantee(" "thread != rax" ") failed", "change this code" ); ::breakpoint(); } } while (0); | ||||
913 | __ push(rax); | ||||
914 | { Label L; | ||||
915 | __ get_thread(rax); | ||||
916 | __ cmpptr(thread, rax); | ||||
917 | __ jcc(Assembler::equal, L); | ||||
918 | __ stop("StubAssembler::call_RT: rdi/r15 not callee saved?"); | ||||
919 | __ bind(L); | ||||
920 | } | ||||
921 | __ pop(rax); | ||||
922 | #endif | ||||
923 | __ reset_last_Java_frame(thread, true); | ||||
924 | #ifndef _LP641 | ||||
925 | __ pop(rcx); // discard thread arg | ||||
926 | __ pop(rcx); // discard dummy | ||||
927 | #endif // _LP64 | ||||
928 | |||||
929 | // check for pending exceptions | ||||
930 | { Label L; | ||||
931 | __ cmpptr(Address(thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD0L); | ||||
932 | __ jcc(Assembler::equal, L); | ||||
933 | // exception pending => remove activation and forward to exception handler | ||||
934 | |||||
935 | __ testptr(rax, rax); // have we deoptimized? | ||||
936 | __ jump_cc(Assembler::equal, | ||||
937 | RuntimeAddress(Runtime1::entry_for(Runtime1::forward_exception_id))); | ||||
938 | |||||
939 | // the deopt blob expects exceptions in the special fields of | ||||
940 | // JavaThread, so copy and clear pending exception. | ||||
941 | |||||
942 | // load and clear pending exception | ||||
943 | __ movptr(rax, Address(thread, Thread::pending_exception_offset())); | ||||
944 | __ movptr(Address(thread, Thread::pending_exception_offset()), NULL_WORD0L); | ||||
945 | |||||
946 | // check that there is really a valid exception | ||||
947 | __ verify_not_null_oop(rax); | ||||
948 | |||||
949 | // load throwing pc: this is the return address of the stub | ||||
950 | __ movptr(rdx, Address(rsp, return_off * VMRegImpl::stack_slot_size)); | ||||
951 | |||||
952 | #ifdef ASSERT1 | ||||
953 | // check that fields in JavaThread for exception oop and issuing pc are empty | ||||
954 | Label oop_empty; | ||||
955 | __ cmpptr(Address(thread, JavaThread::exception_oop_offset()), (int32_t)NULL_WORD0L); | ||||
956 | __ jcc(Assembler::equal, oop_empty); | ||||
957 | __ stop("exception oop must be empty"); | ||||
958 | __ bind(oop_empty); | ||||
959 | |||||
960 | Label pc_empty; | ||||
961 | __ cmpptr(Address(thread, JavaThread::exception_pc_offset()), (int32_t)NULL_WORD0L); | ||||
962 | __ jcc(Assembler::equal, pc_empty); | ||||
963 | __ stop("exception pc must be empty"); | ||||
964 | __ bind(pc_empty); | ||||
965 | #endif | ||||
966 | |||||
967 | // store exception oop and throwing pc to JavaThread | ||||
968 | __ movptr(Address(thread, JavaThread::exception_oop_offset()), rax); | ||||
969 | __ movptr(Address(thread, JavaThread::exception_pc_offset()), rdx); | ||||
970 | |||||
971 | restore_live_registers(sasm); | ||||
972 | |||||
973 | __ leave(); | ||||
974 | __ addptr(rsp, BytesPerWord); // remove return address from stack | ||||
975 | |||||
976 | // Forward the exception directly to deopt blob. We can blow no | ||||
977 | // registers and must leave throwing pc on the stack. A patch may | ||||
978 | // have values live in registers so the entry point with the | ||||
979 | // exception in tls. | ||||
980 | __ jump(RuntimeAddress(deopt_blob->unpack_with_exception_in_tls())); | ||||
981 | |||||
982 | __ bind(L); | ||||
983 | } | ||||
984 | |||||
985 | |||||
986 | // Runtime will return true if the nmethod has been deoptimized during | ||||
987 | // the patching process. In that case we must do a deopt reexecute instead. | ||||
988 | |||||
989 | Label cont; | ||||
990 | |||||
991 | __ testptr(rax, rax); // have we deoptimized? | ||||
992 | __ jcc(Assembler::equal, cont); // no | ||||
993 | |||||
994 | // Will reexecute. Proper return address is already on the stack we just restore | ||||
995 | // registers, pop all of our frame but the return address and jump to the deopt blob | ||||
996 | restore_live_registers(sasm); | ||||
997 | __ leave(); | ||||
998 | __ jump(RuntimeAddress(deopt_blob->unpack_with_reexecution())); | ||||
999 | |||||
1000 | __ bind(cont); | ||||
1001 | restore_live_registers(sasm); | ||||
1002 | __ leave(); | ||||
1003 | __ ret(0); | ||||
1004 | |||||
1005 | return oop_maps; | ||||
1006 | } | ||||
1007 | |||||
1008 | |||||
1009 | OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { | ||||
1010 | |||||
1011 | // for better readability | ||||
1012 | const bool must_gc_arguments = true; | ||||
1013 | const bool dont_gc_arguments = false; | ||||
1014 | |||||
1015 | // default value; overwritten for some optimized stubs that are called from methods that do not use the fpu | ||||
1016 | bool save_fpu_registers = true; | ||||
1017 | |||||
1018 | // stub code & info for the different stubs | ||||
1019 | OopMapSet* oop_maps = NULL__null; | ||||
1020 | switch (id) { | ||||
| |||||
1021 | case forward_exception_id: | ||||
1022 | { | ||||
1023 | oop_maps = generate_handle_exception(id, sasm); | ||||
1024 | __ leave(); | ||||
1025 | __ ret(0); | ||||
1026 | } | ||||
1027 | break; | ||||
1028 | |||||
1029 | case new_instance_id: | ||||
1030 | case fast_new_instance_id: | ||||
1031 | case fast_new_instance_init_check_id: | ||||
1032 | { | ||||
1033 | Register klass = rdx; // Incoming | ||||
1034 | Register obj = rax; // Result | ||||
1035 | |||||
1036 | if (id
| ||||
1037 | __ set_info("new_instance", dont_gc_arguments); | ||||
1038 | } else if (id == fast_new_instance_id) { | ||||
1039 | __ set_info("fast new_instance", dont_gc_arguments); | ||||
1040 | } else { | ||||
1041 | assert(id == fast_new_instance_init_check_id, "bad StubID")do { if (!(id == fast_new_instance_init_check_id)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 1041, "assert(" "id == fast_new_instance_init_check_id" ") failed" , "bad StubID"); ::breakpoint(); } } while (0); | ||||
1042 | __ set_info("fast new_instance init check", dont_gc_arguments); | ||||
1043 | } | ||||
1044 | |||||
1045 | // If TLAB is disabled, see if there is support for inlining contiguous | ||||
1046 | // allocations. | ||||
1047 | // Otherwise, just go to the slow path. | ||||
1048 | if ((id
| ||||
1049 | && Universe::heap()->supports_inline_contig_alloc()) { | ||||
1050 | Label slow_path; | ||||
1051 | Register obj_size = rcx; | ||||
1052 | Register t1 = rbx; | ||||
1053 | Register t2 = rsi; | ||||
1054 | assert_different_registers(klass, obj, obj_size, t1, t2); | ||||
1055 | |||||
1056 | __ push(rdi); | ||||
1057 | __ push(rbx); | ||||
1058 | |||||
1059 | if (id == fast_new_instance_init_check_id) { | ||||
1060 | // make sure the klass is initialized | ||||
1061 | __ cmpb(Address(klass, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized); | ||||
1062 | __ jcc(Assembler::notEqual, slow_path); | ||||
1063 | } | ||||
1064 | |||||
1065 | #ifdef ASSERT1 | ||||
1066 | // assert object can be fast path allocated | ||||
1067 | { | ||||
1068 | Label ok, not_ok; | ||||
1069 | __ movl(obj_size, Address(klass, Klass::layout_helper_offset())); | ||||
1070 | __ cmpl(obj_size, 0); // make sure it's an instance (LH > 0) | ||||
1071 | __ jcc(Assembler::lessEqual, not_ok); | ||||
1072 | __ testl(obj_size, Klass::_lh_instance_slow_path_bit); | ||||
1073 | __ jcc(Assembler::zero, ok); | ||||
1074 | __ bind(not_ok); | ||||
1075 | __ stop("assert(can be fast path allocated)"); | ||||
1076 | __ should_not_reach_here(); | ||||
1077 | __ bind(ok); | ||||
1078 | } | ||||
1079 | #endif // ASSERT | ||||
1080 | |||||
1081 | const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread)r15_thread; | ||||
1082 | NOT_LP64(__ get_thread(thread)); | ||||
1083 | |||||
1084 | // get the instance size (size is postive so movl is fine for 64bit) | ||||
1085 | __ movl(obj_size, Address(klass, Klass::layout_helper_offset())); | ||||
1086 | |||||
1087 | __ eden_allocate(thread, obj, obj_size, 0, t1, slow_path); | ||||
1088 | |||||
1089 | __ initialize_object(obj, klass, obj_size, 0, t1, t2, /* is_tlab_allocated */ false); | ||||
1090 | __ verify_oop(obj)_verify_oop_checked(obj, "broken oop " "obj", "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 1090); | ||||
1091 | __ pop(rbx); | ||||
1092 | __ pop(rdi); | ||||
1093 | __ ret(0); | ||||
1094 | |||||
1095 | __ bind(slow_path); | ||||
1096 | __ pop(rbx); | ||||
1097 | __ pop(rdi); | ||||
1098 | } | ||||
1099 | |||||
1100 | __ enter(); | ||||
1101 | OopMap* map = save_live_registers(sasm, 2); | ||||
1102 | int call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_instance)((address)((address_word)(new_instance))), klass); | ||||
1103 | oop_maps = new OopMapSet(); | ||||
1104 | oop_maps->add_gc_map(call_offset, map); | ||||
1105 | restore_live_registers_except_rax(sasm); | ||||
1106 | __ verify_oop(obj)_verify_oop_checked(obj, "broken oop " "obj", "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 1106); | ||||
1107 | __ leave(); | ||||
1108 | __ ret(0); | ||||
1109 | |||||
1110 | // rax,: new instance | ||||
1111 | } | ||||
1112 | |||||
1113 | break; | ||||
1114 | |||||
1115 | case counter_overflow_id: | ||||
1116 | { | ||||
1117 | Register bci = rax, method = rbx; | ||||
1118 | __ enter(); | ||||
1119 | OopMap* map = save_live_registers(sasm, 3); | ||||
1120 | // Retrieve bci | ||||
1121 | __ movl(bci, Address(rbp, 2*BytesPerWord)); | ||||
1122 | // And a pointer to the Method* | ||||
1123 | __ movptr(method, Address(rbp, 3*BytesPerWord)); | ||||
1124 | int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, counter_overflow)((address)((address_word)(counter_overflow))), bci, method); | ||||
1125 | oop_maps = new OopMapSet(); | ||||
1126 | oop_maps->add_gc_map(call_offset, map); | ||||
1127 | restore_live_registers(sasm); | ||||
1128 | __ leave(); | ||||
1129 | __ ret(0); | ||||
1130 | } | ||||
1131 | break; | ||||
1132 | |||||
1133 | case new_type_array_id: | ||||
1134 | case new_object_array_id: | ||||
1135 | { | ||||
1136 | Register length = rbx; // Incoming | ||||
1137 | Register klass = rdx; // Incoming | ||||
1138 | Register obj = rax; // Result | ||||
1139 | |||||
1140 | if (id == new_type_array_id) { | ||||
1141 | __ set_info("new_type_array", dont_gc_arguments); | ||||
1142 | } else { | ||||
1143 | __ set_info("new_object_array", dont_gc_arguments); | ||||
1144 | } | ||||
1145 | |||||
1146 | #ifdef ASSERT1 | ||||
1147 | // assert object type is really an array of the proper kind | ||||
1148 | { | ||||
1149 | Label ok; | ||||
1150 | Register t0 = obj; | ||||
1151 | __ movl(t0, Address(klass, Klass::layout_helper_offset())); | ||||
1152 | __ sarl(t0, Klass::_lh_array_tag_shift); | ||||
1153 | int tag = ((id == new_type_array_id) | ||||
1154 | ? Klass::_lh_array_tag_type_value | ||||
1155 | : Klass::_lh_array_tag_obj_value); | ||||
1156 | __ cmpl(t0, tag); | ||||
1157 | __ jcc(Assembler::equal, ok); | ||||
1158 | __ stop("assert(is an array klass)"); | ||||
1159 | __ should_not_reach_here(); | ||||
1160 | __ bind(ok); | ||||
1161 | } | ||||
1162 | #endif // ASSERT | ||||
1163 | |||||
1164 | // If TLAB is disabled, see if there is support for inlining contiguous | ||||
1165 | // allocations. | ||||
1166 | // Otherwise, just go to the slow path. | ||||
1167 | if (!UseTLAB && Universe::heap()->supports_inline_contig_alloc()) { | ||||
1168 | Register arr_size = rsi; | ||||
1169 | Register t1 = rcx; // must be rcx for use as shift count | ||||
1170 | Register t2 = rdi; | ||||
1171 | Label slow_path; | ||||
1172 | |||||
1173 | // get the allocation size: round_up(hdr + length << (layout_helper & 0x1F)) | ||||
1174 | // since size is positive movl does right thing on 64bit | ||||
1175 | __ movl(t1, Address(klass, Klass::layout_helper_offset())); | ||||
1176 | // since size is postive movl does right thing on 64bit | ||||
1177 | __ movl(arr_size, length); | ||||
1178 | assert(t1 == rcx, "fixed register usage")do { if (!(t1 == rcx)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 1178, "assert(" "t1 == rcx" ") failed", "fixed register usage" ); ::breakpoint(); } } while (0); | ||||
1179 | __ shlptr(arr_size /* by t1=rcx, mod 32 */); | ||||
1180 | __ shrptr(t1, Klass::_lh_header_size_shift); | ||||
1181 | __ andptr(t1, Klass::_lh_header_size_mask); | ||||
1182 | __ addptr(arr_size, t1); | ||||
1183 | __ addptr(arr_size, MinObjAlignmentInBytesMask); // align up | ||||
1184 | __ andptr(arr_size, ~MinObjAlignmentInBytesMask); | ||||
1185 | |||||
1186 | // Using t2 for non 64-bit. | ||||
1187 | const Register thread = NOT_LP64(t2) LP64_ONLY(r15_thread)r15_thread; | ||||
1188 | NOT_LP64(__ get_thread(thread)); | ||||
1189 | __ eden_allocate(thread, obj, arr_size, 0, t1, slow_path); // preserves arr_size | ||||
1190 | |||||
1191 | __ initialize_header(obj, klass, length, t1, t2); | ||||
1192 | __ movb(t1, Address(klass, in_bytes(Klass::layout_helper_offset()) + (Klass::_lh_header_size_shift / BitsPerByte))); | ||||
1193 | assert(Klass::_lh_header_size_shift % BitsPerByte == 0, "bytewise")do { if (!(Klass::_lh_header_size_shift % BitsPerByte == 0)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 1193, "assert(" "Klass::_lh_header_size_shift % BitsPerByte == 0" ") failed", "bytewise"); ::breakpoint(); } } while (0); | ||||
1194 | assert(Klass::_lh_header_size_mask <= 0xFF, "bytewise")do { if (!(Klass::_lh_header_size_mask <= 0xFF)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 1194, "assert(" "Klass::_lh_header_size_mask <= 0xFF" ") failed" , "bytewise"); ::breakpoint(); } } while (0); | ||||
1195 | __ andptr(t1, Klass::_lh_header_size_mask); | ||||
1196 | __ subptr(arr_size, t1); // body length | ||||
1197 | __ addptr(t1, obj); // body start | ||||
1198 | __ initialize_body(t1, arr_size, 0, t2); | ||||
1199 | __ verify_oop(obj)_verify_oop_checked(obj, "broken oop " "obj", "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 1199); | ||||
1200 | __ ret(0); | ||||
1201 | |||||
1202 | __ bind(slow_path); | ||||
1203 | } | ||||
1204 | |||||
1205 | __ enter(); | ||||
1206 | OopMap* map = save_live_registers(sasm, 3); | ||||
1207 | int call_offset; | ||||
1208 | if (id == new_type_array_id) { | ||||
1209 | call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_type_array)((address)((address_word)(new_type_array))), klass, length); | ||||
1210 | } else { | ||||
1211 | call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_object_array)((address)((address_word)(new_object_array))), klass, length); | ||||
1212 | } | ||||
1213 | |||||
1214 | oop_maps = new OopMapSet(); | ||||
1215 | oop_maps->add_gc_map(call_offset, map); | ||||
1216 | restore_live_registers_except_rax(sasm); | ||||
1217 | |||||
1218 | __ verify_oop(obj)_verify_oop_checked(obj, "broken oop " "obj", "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 1218); | ||||
1219 | __ leave(); | ||||
1220 | __ ret(0); | ||||
1221 | |||||
1222 | // rax,: new array | ||||
1223 | } | ||||
1224 | break; | ||||
1225 | |||||
1226 | case new_multi_array_id: | ||||
1227 | { StubFrame f(sasm, "new_multi_array", dont_gc_arguments); | ||||
1228 | // rax,: klass | ||||
1229 | // rbx,: rank | ||||
1230 | // rcx: address of 1st dimension | ||||
1231 | OopMap* map = save_live_registers(sasm, 4); | ||||
1232 | int call_offset = __ call_RT(rax, noreg, CAST_FROM_FN_PTR(address, new_multi_array)((address)((address_word)(new_multi_array))), rax, rbx, rcx); | ||||
1233 | |||||
1234 | oop_maps = new OopMapSet(); | ||||
1235 | oop_maps->add_gc_map(call_offset, map); | ||||
1236 | restore_live_registers_except_rax(sasm); | ||||
1237 | |||||
1238 | // rax,: new multi array | ||||
1239 | __ verify_oop(rax)_verify_oop_checked(rax, "broken oop " "rax", "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 1239); | ||||
1240 | } | ||||
1241 | break; | ||||
1242 | |||||
1243 | case register_finalizer_id: | ||||
1244 | { | ||||
1245 | __ set_info("register_finalizer", dont_gc_arguments); | ||||
1246 | |||||
1247 | // This is called via call_runtime so the arguments | ||||
1248 | // will be place in C abi locations | ||||
1249 | |||||
1250 | #ifdef _LP641 | ||||
1251 | __ verify_oop(c_rarg0)_verify_oop_checked(c_rarg0, "broken oop " "c_rarg0", "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 1251); | ||||
1252 | __ mov(rax, c_rarg0); | ||||
1253 | #else | ||||
1254 | // The object is passed on the stack and we haven't pushed a | ||||
1255 | // frame yet so it's one work away from top of stack. | ||||
1256 | __ movptr(rax, Address(rsp, 1 * BytesPerWord)); | ||||
1257 | __ verify_oop(rax)_verify_oop_checked(rax, "broken oop " "rax", "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 1257); | ||||
1258 | #endif // _LP64 | ||||
1259 | |||||
1260 | // load the klass and check the has finalizer flag | ||||
1261 | Label register_finalizer; | ||||
1262 | Register tmp_load_klass = LP64_ONLY(rscratch1)rscratch1 NOT_LP64(noreg); | ||||
1263 | Register t = rsi; | ||||
1264 | __ load_klass(t, rax, tmp_load_klass); | ||||
1265 | __ movl(t, Address(t, Klass::access_flags_offset())); | ||||
1266 | __ testl(t, JVM_ACC_HAS_FINALIZER); | ||||
1267 | __ jcc(Assembler::notZero, register_finalizer); | ||||
1268 | __ ret(0); | ||||
1269 | |||||
1270 | __ bind(register_finalizer); | ||||
1271 | __ enter(); | ||||
1272 | OopMap* oop_map = save_live_registers(sasm, 2 /*num_rt_args */); | ||||
1273 | int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, SharedRuntime::register_finalizer)((address)((address_word)(SharedRuntime::register_finalizer)) ), rax); | ||||
1274 | oop_maps = new OopMapSet(); | ||||
1275 | oop_maps->add_gc_map(call_offset, oop_map); | ||||
1276 | |||||
1277 | // Now restore all the live registers | ||||
1278 | restore_live_registers(sasm); | ||||
1279 | |||||
1280 | __ leave(); | ||||
1281 | __ ret(0); | ||||
1282 | } | ||||
1283 | break; | ||||
1284 | |||||
1285 | case throw_range_check_failed_id: | ||||
1286 | { StubFrame f(sasm, "range_check_failed", dont_gc_arguments); | ||||
1287 | oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception)((address)((address_word)(throw_range_check_exception))), true); | ||||
1288 | } | ||||
1289 | break; | ||||
1290 | |||||
1291 | case throw_index_exception_id: | ||||
1292 | { StubFrame f(sasm, "index_range_check_failed", dont_gc_arguments); | ||||
1293 | oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception)((address)((address_word)(throw_index_exception))), true); | ||||
1294 | } | ||||
1295 | break; | ||||
1296 | |||||
1297 | case throw_div0_exception_id: | ||||
1298 | { StubFrame f(sasm, "throw_div0_exception", dont_gc_arguments); | ||||
1299 | oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception)((address)((address_word)(throw_div0_exception))), false); | ||||
1300 | } | ||||
1301 | break; | ||||
1302 | |||||
1303 | case throw_null_pointer_exception_id: | ||||
1304 | { StubFrame f(sasm, "throw_null_pointer_exception", dont_gc_arguments); | ||||
1305 | oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception)((address)((address_word)(throw_null_pointer_exception))), false); | ||||
1306 | } | ||||
1307 | break; | ||||
1308 | |||||
1309 | case handle_exception_nofpu_id: | ||||
1310 | case handle_exception_id: | ||||
1311 | { StubFrame f(sasm, "handle_exception", dont_gc_arguments); | ||||
1312 | oop_maps = generate_handle_exception(id, sasm); | ||||
1313 | } | ||||
1314 | break; | ||||
1315 | |||||
1316 | case handle_exception_from_callee_id: | ||||
1317 | { StubFrame f(sasm, "handle_exception_from_callee", dont_gc_arguments); | ||||
1318 | oop_maps = generate_handle_exception(id, sasm); | ||||
1319 | } | ||||
1320 | break; | ||||
1321 | |||||
1322 | case unwind_exception_id: | ||||
1323 | { __ set_info("unwind_exception", dont_gc_arguments); | ||||
1324 | // note: no stubframe since we are about to leave the current | ||||
1325 | // activation and we are calling a leaf VM function only. | ||||
1326 | generate_unwind_exception(sasm); | ||||
1327 | } | ||||
1328 | break; | ||||
1329 | |||||
1330 | case throw_array_store_exception_id: | ||||
1331 | { StubFrame f(sasm, "throw_array_store_exception", dont_gc_arguments); | ||||
1332 | // tos + 0: link | ||||
1333 | // + 1: return address | ||||
1334 | oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_array_store_exception)((address)((address_word)(throw_array_store_exception))), true); | ||||
1335 | } | ||||
1336 | break; | ||||
1337 | |||||
1338 | case throw_class_cast_exception_id: | ||||
1339 | { StubFrame f(sasm, "throw_class_cast_exception", dont_gc_arguments); | ||||
1340 | oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception)((address)((address_word)(throw_class_cast_exception))), true); | ||||
1341 | } | ||||
1342 | break; | ||||
1343 | |||||
1344 | case throw_incompatible_class_change_error_id: | ||||
1345 | { StubFrame f(sasm, "throw_incompatible_class_cast_exception", dont_gc_arguments); | ||||
1346 | oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error)((address)((address_word)(throw_incompatible_class_change_error ))), false); | ||||
1347 | } | ||||
1348 | break; | ||||
1349 | |||||
1350 | case slow_subtype_check_id: | ||||
1351 | { | ||||
1352 | // Typical calling sequence: | ||||
1353 | // __ push(klass_RInfo); // object klass or other subclass | ||||
1354 | // __ push(sup_k_RInfo); // array element klass or other superclass | ||||
1355 | // __ call(slow_subtype_check); | ||||
1356 | // Note that the subclass is pushed first, and is therefore deepest. | ||||
1357 | // Previous versions of this code reversed the names 'sub' and 'super'. | ||||
1358 | // This was operationally harmless but made the code unreadable. | ||||
1359 | enum layout { | ||||
1360 | rax_off, SLOT2(raxH_off)raxH_off, | ||||
1361 | rcx_off, SLOT2(rcxH_off)rcxH_off, | ||||
1362 | rsi_off, SLOT2(rsiH_off)rsiH_off, | ||||
1363 | rdi_off, SLOT2(rdiH_off)rdiH_off, | ||||
1364 | // saved_rbp_off, SLOT2(saved_rbpH_off) | ||||
1365 | return_off, SLOT2(returnH_off)returnH_off, | ||||
1366 | sup_k_off, SLOT2(sup_kH_off)sup_kH_off, | ||||
1367 | klass_off, SLOT2(superH_off)superH_off, | ||||
1368 | framesize, | ||||
1369 | result_off = klass_off // deepest argument is also the return value | ||||
1370 | }; | ||||
1371 | |||||
1372 | __ set_info("slow_subtype_check", dont_gc_arguments); | ||||
1373 | __ push(rdi); | ||||
1374 | __ push(rsi); | ||||
1375 | __ push(rcx); | ||||
1376 | __ push(rax); | ||||
1377 | |||||
1378 | // This is called by pushing args and not with C abi | ||||
1379 | __ movptr(rsi, Address(rsp, (klass_off) * VMRegImpl::stack_slot_size)); // subclass | ||||
1380 | __ movptr(rax, Address(rsp, (sup_k_off) * VMRegImpl::stack_slot_size)); // superclass | ||||
1381 | |||||
1382 | Label miss; | ||||
1383 | __ check_klass_subtype_slow_path(rsi, rax, rcx, rdi, NULL__null, &miss); | ||||
1384 | |||||
1385 | // fallthrough on success: | ||||
1386 | __ movptr(Address(rsp, (result_off) * VMRegImpl::stack_slot_size), 1); // result | ||||
1387 | __ pop(rax); | ||||
1388 | __ pop(rcx); | ||||
1389 | __ pop(rsi); | ||||
1390 | __ pop(rdi); | ||||
1391 | __ ret(0); | ||||
1392 | |||||
1393 | __ bind(miss); | ||||
1394 | __ movptr(Address(rsp, (result_off) * VMRegImpl::stack_slot_size), NULL_WORD0L); // result | ||||
1395 | __ pop(rax); | ||||
1396 | __ pop(rcx); | ||||
1397 | __ pop(rsi); | ||||
1398 | __ pop(rdi); | ||||
1399 | __ ret(0); | ||||
1400 | } | ||||
1401 | break; | ||||
1402 | |||||
1403 | case monitorenter_nofpu_id: | ||||
1404 | save_fpu_registers = false; | ||||
1405 | // fall through | ||||
1406 | case monitorenter_id: | ||||
1407 | { | ||||
1408 | StubFrame f(sasm, "monitorenter", dont_gc_arguments); | ||||
1409 | OopMap* map = save_live_registers(sasm, 3, save_fpu_registers); | ||||
1410 | |||||
1411 | // Called with store_parameter and not C abi | ||||
1412 | |||||
1413 | f.load_argument(1, rax); // rax,: object | ||||
1414 | f.load_argument(0, rbx); // rbx,: lock address | ||||
1415 | |||||
1416 | int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorenter)((address)((address_word)(monitorenter))), rax, rbx); | ||||
1417 | |||||
1418 | oop_maps = new OopMapSet(); | ||||
1419 | oop_maps->add_gc_map(call_offset, map); | ||||
1420 | restore_live_registers(sasm, save_fpu_registers); | ||||
1421 | } | ||||
1422 | break; | ||||
1423 | |||||
1424 | case monitorexit_nofpu_id: | ||||
1425 | save_fpu_registers = false; | ||||
1426 | // fall through | ||||
1427 | case monitorexit_id: | ||||
1428 | { | ||||
1429 | StubFrame f(sasm, "monitorexit", dont_gc_arguments); | ||||
1430 | OopMap* map = save_live_registers(sasm, 2, save_fpu_registers); | ||||
1431 | |||||
1432 | // Called with store_parameter and not C abi | ||||
1433 | |||||
1434 | f.load_argument(0, rax); // rax,: lock address | ||||
1435 | |||||
1436 | // note: really a leaf routine but must setup last java sp | ||||
1437 | // => use call_RT for now (speed can be improved by | ||||
1438 | // doing last java sp setup manually) | ||||
1439 | int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorexit)((address)((address_word)(monitorexit))), rax); | ||||
1440 | |||||
1441 | oop_maps = new OopMapSet(); | ||||
1442 | oop_maps->add_gc_map(call_offset, map); | ||||
1443 | restore_live_registers(sasm, save_fpu_registers); | ||||
1444 | } | ||||
1445 | break; | ||||
1446 | |||||
1447 | case deoptimize_id: | ||||
1448 | { | ||||
1449 | StubFrame f(sasm, "deoptimize", dont_gc_arguments); | ||||
1450 | const int num_rt_args = 2; // thread, trap_request | ||||
1451 | OopMap* oop_map = save_live_registers(sasm, num_rt_args); | ||||
1452 | f.load_argument(0, rax); | ||||
1453 | int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, deoptimize)((address)((address_word)(deoptimize))), rax); | ||||
1454 | oop_maps = new OopMapSet(); | ||||
1455 | oop_maps->add_gc_map(call_offset, oop_map); | ||||
1456 | restore_live_registers(sasm); | ||||
1457 | DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); | ||||
1458 | assert(deopt_blob != NULL, "deoptimization blob must have been created")do { if (!(deopt_blob != __null)) { (*g_assert_poison) = 'X'; ; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 1458, "assert(" "deopt_blob != __null" ") failed", "deoptimization blob must have been created" ); ::breakpoint(); } } while (0); | ||||
1459 | __ leave(); | ||||
1460 | __ jump(RuntimeAddress(deopt_blob->unpack_with_reexecution())); | ||||
1461 | } | ||||
1462 | break; | ||||
1463 | |||||
1464 | case access_field_patching_id: | ||||
1465 | { StubFrame f(sasm, "access_field_patching", dont_gc_arguments); | ||||
1466 | // we should set up register map | ||||
1467 | oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching)((address)((address_word)(access_field_patching)))); | ||||
1468 | } | ||||
1469 | break; | ||||
1470 | |||||
1471 | case load_klass_patching_id: | ||||
1472 | { StubFrame f(sasm, "load_klass_patching", dont_gc_arguments); | ||||
1473 | // we should set up register map | ||||
1474 | oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_klass_patching)((address)((address_word)(move_klass_patching)))); | ||||
1475 | } | ||||
1476 | break; | ||||
1477 | |||||
1478 | case load_mirror_patching_id: | ||||
1479 | { StubFrame f(sasm, "load_mirror_patching", dont_gc_arguments); | ||||
1480 | // we should set up register map | ||||
1481 | oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_mirror_patching)((address)((address_word)(move_mirror_patching)))); | ||||
1482 | } | ||||
1483 | break; | ||||
1484 | |||||
1485 | case load_appendix_patching_id: | ||||
1486 | { StubFrame f(sasm, "load_appendix_patching", dont_gc_arguments); | ||||
1487 | // we should set up register map | ||||
1488 | oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_appendix_patching)((address)((address_word)(move_appendix_patching)))); | ||||
1489 | } | ||||
1490 | break; | ||||
1491 | |||||
1492 | case dtrace_object_alloc_id: | ||||
1493 | { // rax,: object | ||||
1494 | StubFrame f(sasm, "dtrace_object_alloc", dont_gc_arguments); | ||||
1495 | // we can't gc here so skip the oopmap but make sure that all | ||||
1496 | // the live registers get saved. | ||||
1497 | save_live_registers(sasm, 1); | ||||
1498 | |||||
1499 | __ NOT_LP64(push(rax)) LP64_ONLY(mov(c_rarg0, rax))mov(c_rarg0, rax); | ||||
1500 | __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, static_cast<int (*)(oopDesc*)>(SharedRuntime::dtrace_object_alloc))((address)((address_word)(static_cast<int (*)(oopDesc*)> (SharedRuntime::dtrace_object_alloc)))))); | ||||
1501 | NOT_LP64(__ pop(rax)); | ||||
1502 | |||||
1503 | restore_live_registers(sasm); | ||||
1504 | } | ||||
1505 | break; | ||||
1506 | |||||
1507 | case fpu2long_stub_id: | ||||
1508 | { | ||||
1509 | #ifdef _LP641 | ||||
1510 | Label done; | ||||
1511 | __ cvttsd2siq(rax, Address(rsp, wordSize)); | ||||
1512 | __ cmp64(rax, ExternalAddress((address) StubRoutines::x86::double_sign_flip())); | ||||
1513 | __ jccb(Assembler::notEqual, done)jccb_0(Assembler::notEqual, done, "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 1513); | ||||
1514 | __ movq(rax, Address(rsp, wordSize)); | ||||
1515 | __ subptr(rsp, 8); | ||||
1516 | __ movq(Address(rsp, 0), rax); | ||||
1517 | __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::x86::d2l_fixup())((address)((address_word)(StubRoutines::x86::d2l_fixup()))))); | ||||
1518 | __ pop(rax); | ||||
1519 | __ bind(done); | ||||
1520 | __ ret(0); | ||||
1521 | #else | ||||
1522 | // rax, and rdx are destroyed, but should be free since the result is returned there | ||||
1523 | // preserve rsi,ecx | ||||
1524 | __ push(rsi); | ||||
1525 | __ push(rcx); | ||||
1526 | |||||
1527 | // check for NaN | ||||
1528 | Label return0, do_return, return_min_jlong, do_convert; | ||||
1529 | |||||
1530 | Address value_high_word(rsp, wordSize + 4); | ||||
1531 | Address value_low_word(rsp, wordSize); | ||||
1532 | Address result_high_word(rsp, 3*wordSize + 4); | ||||
1533 | Address result_low_word(rsp, 3*wordSize); | ||||
1534 | |||||
1535 | __ subptr(rsp, 32); // more than enough on 32bit | ||||
1536 | __ fst_d(value_low_word); | ||||
1537 | __ movl(rax, value_high_word); | ||||
1538 | __ andl(rax, 0x7ff00000); | ||||
1539 | __ cmpl(rax, 0x7ff00000); | ||||
1540 | __ jcc(Assembler::notEqual, do_convert); | ||||
1541 | __ movl(rax, value_high_word); | ||||
1542 | __ andl(rax, 0xfffff); | ||||
1543 | __ orl(rax, value_low_word); | ||||
1544 | __ jcc(Assembler::notZero, return0); | ||||
1545 | |||||
1546 | __ bind(do_convert); | ||||
1547 | __ fnstcw(Address(rsp, 0)); | ||||
1548 | __ movzwl(rax, Address(rsp, 0)); | ||||
1549 | __ orl(rax, 0xc00); | ||||
1550 | __ movw(Address(rsp, 2), rax); | ||||
1551 | __ fldcw(Address(rsp, 2)); | ||||
1552 | __ fwait(); | ||||
1553 | __ fistp_d(result_low_word); | ||||
1554 | __ fldcw(Address(rsp, 0)); | ||||
1555 | __ fwait(); | ||||
1556 | // This gets the entire long in rax on 64bit | ||||
1557 | __ movptr(rax, result_low_word); | ||||
1558 | // testing of high bits | ||||
1559 | __ movl(rdx, result_high_word); | ||||
1560 | __ mov(rcx, rax); | ||||
1561 | // What the heck is the point of the next instruction??? | ||||
1562 | __ xorl(rcx, 0x0); | ||||
1563 | __ movl(rsi, 0x80000000); | ||||
1564 | __ xorl(rsi, rdx); | ||||
1565 | __ orl(rcx, rsi); | ||||
1566 | __ jcc(Assembler::notEqual, do_return); | ||||
1567 | __ fldz(); | ||||
1568 | __ fcomp_d(value_low_word); | ||||
1569 | __ fnstsw_ax(); | ||||
1570 | __ sahf(); | ||||
1571 | __ jcc(Assembler::above, return_min_jlong); | ||||
1572 | // return max_jlong | ||||
1573 | __ movl(rdx, 0x7fffffff); | ||||
1574 | __ movl(rax, 0xffffffff); | ||||
1575 | __ jmp(do_return); | ||||
1576 | |||||
1577 | __ bind(return_min_jlong); | ||||
1578 | __ movl(rdx, 0x80000000); | ||||
1579 | __ xorl(rax, rax); | ||||
1580 | __ jmp(do_return); | ||||
1581 | |||||
1582 | __ bind(return0); | ||||
1583 | __ fpop(); | ||||
1584 | __ xorptr(rdx,rdx); | ||||
1585 | __ xorptr(rax,rax); | ||||
1586 | |||||
1587 | __ bind(do_return); | ||||
1588 | __ addptr(rsp, 32); | ||||
1589 | __ pop(rcx); | ||||
1590 | __ pop(rsi); | ||||
1591 | __ ret(0); | ||||
1592 | #endif // _LP64 | ||||
1593 | } | ||||
1594 | break; | ||||
1595 | |||||
1596 | case predicate_failed_trap_id: | ||||
1597 | { | ||||
1598 | StubFrame f(sasm, "predicate_failed_trap", dont_gc_arguments); | ||||
1599 | |||||
1600 | OopMap* map = save_live_registers(sasm, 1); | ||||
1601 | |||||
1602 | int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, predicate_failed_trap)((address)((address_word)(predicate_failed_trap)))); | ||||
1603 | oop_maps = new OopMapSet(); | ||||
1604 | oop_maps->add_gc_map(call_offset, map); | ||||
1605 | restore_live_registers(sasm); | ||||
1606 | __ leave(); | ||||
1607 | DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); | ||||
1608 | assert(deopt_blob != NULL, "deoptimization blob must have been created")do { if (!(deopt_blob != __null)) { (*g_assert_poison) = 'X'; ; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp" , 1608, "assert(" "deopt_blob != __null" ") failed", "deoptimization blob must have been created" ); ::breakpoint(); } } while (0); | ||||
1609 | |||||
1610 | __ jump(RuntimeAddress(deopt_blob->unpack_with_reexecution())); | ||||
1611 | } | ||||
1612 | break; | ||||
1613 | |||||
1614 | default: | ||||
1615 | { StubFrame f(sasm, "unimplemented entry", dont_gc_arguments); | ||||
1616 | __ movptr(rax, (int)id); | ||||
1617 | __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry)((address)((address_word)(unimplemented_entry))), rax); | ||||
1618 | __ should_not_reach_here(); | ||||
1619 | } | ||||
1620 | break; | ||||
1621 | } | ||||
1622 | return oop_maps; | ||||
1623 | } | ||||
1624 | |||||
1625 | #undef __ | ||||
1626 | |||||
1627 | const char *Runtime1::pd_name_for_address(address entry) { | ||||
1628 | return "<unknown function>"; | ||||
1629 | } |