25 #include "incls/_precompiled.incl" |
25 #include "incls/_precompiled.incl" |
26 #include "incls/_methodHandles_x86.cpp.incl" |
26 #include "incls/_methodHandles_x86.cpp.incl" |
27 |
27 |
28 #define __ _masm-> |
28 #define __ _masm-> |
29 |
29 |
|
30 #ifdef PRODUCT |
|
31 #define BLOCK_COMMENT(str) /* nothing */ |
|
32 #else |
|
33 #define BLOCK_COMMENT(str) __ block_comment(str) |
|
34 #endif |
|
35 |
|
36 #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") |
|
37 |
30 address MethodHandleEntry::start_compiled_entry(MacroAssembler* _masm, |
38 address MethodHandleEntry::start_compiled_entry(MacroAssembler* _masm, |
31 address interpreted_entry) { |
39 address interpreted_entry) { |
32 // Just before the actual machine code entry point, allocate space |
40 // Just before the actual machine code entry point, allocate space |
33 // for a MethodHandleEntry::Data record, so that we can manage everything |
41 // for a MethodHandleEntry::Data record, so that we can manage everything |
34 // from one base pointer. |
42 // from one base pointer. |
62 #ifdef ASSERT |
70 #ifdef ASSERT |
63 static void verify_argslot(MacroAssembler* _masm, Register argslot_reg, |
71 static void verify_argslot(MacroAssembler* _masm, Register argslot_reg, |
64 const char* error_message) { |
72 const char* error_message) { |
65 // Verify that argslot lies within (rsp, rbp]. |
73 // Verify that argslot lies within (rsp, rbp]. |
66 Label L_ok, L_bad; |
74 Label L_ok, L_bad; |
|
75 BLOCK_COMMENT("{ verify_argslot"); |
67 __ cmpptr(argslot_reg, rbp); |
76 __ cmpptr(argslot_reg, rbp); |
68 __ jccb(Assembler::above, L_bad); |
77 __ jccb(Assembler::above, L_bad); |
69 __ cmpptr(rsp, argslot_reg); |
78 __ cmpptr(rsp, argslot_reg); |
70 __ jccb(Assembler::below, L_ok); |
79 __ jccb(Assembler::below, L_ok); |
71 __ bind(L_bad); |
80 __ bind(L_bad); |
72 __ stop(error_message); |
81 __ stop(error_message); |
73 __ bind(L_ok); |
82 __ bind(L_ok); |
|
83 BLOCK_COMMENT("} verify_argslot"); |
74 } |
84 } |
75 #endif |
85 #endif |
76 |
86 |
77 |
87 |
78 // Code generation |
88 // Code generation |
79 address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) { |
89 address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) { |
80 // rbx: methodOop |
90 // rbx: methodOop |
81 // rcx: receiver method handle (must load from sp[MethodTypeForm.vmslots]) |
91 // rcx: receiver method handle (must load from sp[MethodTypeForm.vmslots]) |
82 // rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted) |
92 // rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted) |
83 // rdx: garbage temp, blown away |
93 // rdx, rdi: garbage temp, blown away |
84 |
94 |
85 Register rbx_method = rbx; |
95 Register rbx_method = rbx; |
86 Register rcx_recv = rcx; |
96 Register rcx_recv = rcx; |
87 Register rax_mtype = rax; |
97 Register rax_mtype = rax; |
88 Register rdx_temp = rdx; |
98 Register rdx_temp = rdx; |
|
99 Register rdi_temp = rdi; |
89 |
100 |
90 // emit WrongMethodType path first, to enable jccb back-branch from main path |
101 // emit WrongMethodType path first, to enable jccb back-branch from main path |
91 Label wrong_method_type; |
102 Label wrong_method_type; |
92 __ bind(wrong_method_type); |
103 __ bind(wrong_method_type); |
|
104 Label invoke_generic_slow_path; |
|
105 assert(methodOopDesc::intrinsic_id_size_in_bytes() == sizeof(u1), "");; |
|
106 __ cmpb(Address(rbx_method, methodOopDesc::intrinsic_id_offset_in_bytes()), (int) vmIntrinsics::_invokeExact); |
|
107 __ jcc(Assembler::notEqual, invoke_generic_slow_path); |
93 __ push(rax_mtype); // required mtype |
108 __ push(rax_mtype); // required mtype |
94 __ push(rcx_recv); // bad mh (1st stacked argument) |
109 __ push(rcx_recv); // bad mh (1st stacked argument) |
95 __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry())); |
110 __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry())); |
96 |
111 |
97 // here's where control starts out: |
112 // here's where control starts out: |
104 for (jint* pchase = methodOopDesc::method_type_offsets_chain(); (*pchase) != -1; pchase++) { |
119 for (jint* pchase = methodOopDesc::method_type_offsets_chain(); (*pchase) != -1; pchase++) { |
105 __ movptr(rax_mtype, Address(tem, *pchase)); |
120 __ movptr(rax_mtype, Address(tem, *pchase)); |
106 tem = rax_mtype; // in case there is another indirection |
121 tem = rax_mtype; // in case there is another indirection |
107 } |
122 } |
108 } |
123 } |
109 Register rbx_temp = rbx_method; // done with incoming methodOop |
|
110 |
124 |
111 // given the MethodType, find out where the MH argument is buried |
125 // given the MethodType, find out where the MH argument is buried |
112 __ movptr(rdx_temp, Address(rax_mtype, |
126 __ movptr(rdx_temp, Address(rax_mtype, |
113 __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, rbx_temp))); |
127 __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, rdi_temp))); |
114 __ movl(rdx_temp, Address(rdx_temp, |
128 Register rdx_vmslots = rdx_temp; |
115 __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, rbx_temp))); |
129 __ movl(rdx_vmslots, Address(rdx_temp, |
116 __ movptr(rcx_recv, __ argument_address(rdx_temp)); |
130 __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, rdi_temp))); |
117 |
131 __ movptr(rcx_recv, __ argument_address(rdx_vmslots)); |
118 __ check_method_handle_type(rax_mtype, rcx_recv, rdx_temp, wrong_method_type); |
132 |
119 __ jump_to_method_handle_entry(rcx_recv, rdx_temp); |
133 trace_method_handle(_masm, "invokeExact"); |
|
134 |
|
135 __ check_method_handle_type(rax_mtype, rcx_recv, rdi_temp, wrong_method_type); |
|
136 __ jump_to_method_handle_entry(rcx_recv, rdi_temp); |
|
137 |
|
138 // for invokeGeneric (only), apply argument and result conversions on the fly |
|
139 __ bind(invoke_generic_slow_path); |
|
140 #ifdef ASSERT |
|
141 { Label L; |
|
142 __ cmpb(Address(rbx_method, methodOopDesc::intrinsic_id_offset_in_bytes()), (int) vmIntrinsics::_invokeGeneric); |
|
143 __ jcc(Assembler::equal, L); |
|
144 __ stop("bad methodOop::intrinsic_id"); |
|
145 __ bind(L); |
|
146 } |
|
147 #endif //ASSERT |
|
148 Register rbx_temp = rbx_method; // don't need it now |
|
149 |
|
150 // make room on the stack for another pointer: |
|
151 Register rcx_argslot = rcx_recv; |
|
152 __ lea(rcx_argslot, __ argument_address(rdx_vmslots, 1)); |
|
153 insert_arg_slots(_masm, 2 * stack_move_unit(), _INSERT_REF_MASK, |
|
154 rcx_argslot, rbx_temp, rdx_temp); |
|
155 |
|
156 // load up an adapter from the calling type (Java weaves this) |
|
157 __ movptr(rdx_temp, Address(rax_mtype, |
|
158 __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, rdi_temp))); |
|
159 Register rdx_adapter = rdx_temp; |
|
160 // movptr(rdx_adapter, Address(rdx_temp, java_dyn_MethodTypeForm::genericInvoker_offset_in_bytes())); |
|
161 // deal with old JDK versions: |
|
162 __ lea(rdi_temp, Address(rdx_temp, |
|
163 __ delayed_value(java_dyn_MethodTypeForm::genericInvoker_offset_in_bytes, rdi_temp))); |
|
164 __ cmpptr(rdi_temp, rdx_temp); |
|
165 Label sorry_no_invoke_generic; |
|
166 __ jccb(Assembler::below, sorry_no_invoke_generic); |
|
167 |
|
168 __ movptr(rdx_adapter, Address(rdi_temp, 0)); |
|
169 __ testptr(rdx_adapter, rdx_adapter); |
|
170 __ jccb(Assembler::zero, sorry_no_invoke_generic); |
|
171 __ movptr(Address(rcx_argslot, 1 * Interpreter::stackElementSize), rdx_adapter); |
|
172 // As a trusted first argument, pass the type being called, so the adapter knows |
|
173 // the actual types of the arguments and return values. |
|
174 // (Generic invokers are shared among form-families of method-type.) |
|
175 __ movptr(Address(rcx_argslot, 0 * Interpreter::stackElementSize), rax_mtype); |
|
176 // FIXME: assert that rdx_adapter is of the right method-type. |
|
177 __ mov(rcx, rdx_adapter); |
|
178 trace_method_handle(_masm, "invokeGeneric"); |
|
179 __ jump_to_method_handle_entry(rcx, rdi_temp); |
|
180 |
|
181 __ bind(sorry_no_invoke_generic); // no invokeGeneric implementation available! |
|
182 __ movptr(rcx_recv, Address(rcx_argslot, -1 * Interpreter::stackElementSize)); // recover original MH |
|
183 __ push(rax_mtype); // required mtype |
|
184 __ push(rcx_recv); // bad mh (1st stacked argument) |
|
185 __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry())); |
120 |
186 |
121 return entry_point; |
187 return entry_point; |
122 } |
188 } |
123 |
189 |
124 // Helper to insert argument slots into the stack. |
190 // Helper to insert argument slots into the stack. |
162 // That is, copy [rsp, argslot) downward by -size words. In pseudo-code: |
228 // That is, copy [rsp, argslot) downward by -size words. In pseudo-code: |
163 // rsp -= size; |
229 // rsp -= size; |
164 // for (rdx = rsp + size; rdx < argslot; rdx++) |
230 // for (rdx = rsp + size; rdx < argslot; rdx++) |
165 // rdx[-size] = rdx[0] |
231 // rdx[-size] = rdx[0] |
166 // argslot -= size; |
232 // argslot -= size; |
|
233 BLOCK_COMMENT("insert_arg_slots {"); |
167 __ mov(rdx_temp, rsp); // source pointer for copy |
234 __ mov(rdx_temp, rsp); // source pointer for copy |
168 __ lea(rsp, Address(rsp, arg_slots, Address::times_ptr)); |
235 __ lea(rsp, Address(rsp, arg_slots, Address::times_ptr)); |
169 { |
236 { |
170 Label loop; |
237 Label loop; |
171 __ bind(loop); |
238 __ BIND(loop); |
172 // pull one word down each time through the loop |
239 // pull one word down each time through the loop |
173 __ movptr(rbx_temp, Address(rdx_temp, 0)); |
240 __ movptr(rbx_temp, Address(rdx_temp, 0)); |
174 __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp); |
241 __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp); |
175 __ addptr(rdx_temp, wordSize); |
242 __ addptr(rdx_temp, wordSize); |
176 __ cmpptr(rdx_temp, rax_argslot); |
243 __ cmpptr(rdx_temp, rax_argslot); |
177 __ jccb(Assembler::less, loop); |
244 __ jccb(Assembler::less, loop); |
178 } |
245 } |
179 |
246 |
180 // Now move the argslot down, to point to the opened-up space. |
247 // Now move the argslot down, to point to the opened-up space. |
181 __ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr)); |
248 __ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr)); |
|
249 BLOCK_COMMENT("} insert_arg_slots"); |
182 } |
250 } |
183 |
251 |
184 // Helper to remove argument slots from the stack. |
252 // Helper to remove argument slots from the stack. |
185 // arg_slots must be a multiple of stack_move_unit() and >= 0 |
253 // arg_slots must be a multiple of stack_move_unit() and >= 0 |
186 void MethodHandles::remove_arg_slots(MacroAssembler* _masm, |
254 void MethodHandles::remove_arg_slots(MacroAssembler* _masm, |
227 // argslot += size; |
296 // argslot += size; |
228 // rsp += size; |
297 // rsp += size; |
229 __ lea(rdx_temp, Address(rax_argslot, -wordSize)); // source pointer for copy |
298 __ lea(rdx_temp, Address(rax_argslot, -wordSize)); // source pointer for copy |
230 { |
299 { |
231 Label loop; |
300 Label loop; |
232 __ bind(loop); |
301 __ BIND(loop); |
233 // pull one word up each time through the loop |
302 // pull one word up each time through the loop |
234 __ movptr(rbx_temp, Address(rdx_temp, 0)); |
303 __ movptr(rbx_temp, Address(rdx_temp, 0)); |
235 __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp); |
304 __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp); |
236 __ addptr(rdx_temp, -wordSize); |
305 __ addptr(rdx_temp, -wordSize); |
237 __ cmpptr(rdx_temp, rsp); |
306 __ cmpptr(rdx_temp, rsp); |
240 |
309 |
241 // Now move the argslot up, to point to the just-copied block. |
310 // Now move the argslot up, to point to the just-copied block. |
242 __ lea(rsp, Address(rsp, arg_slots, Address::times_ptr)); |
311 __ lea(rsp, Address(rsp, arg_slots, Address::times_ptr)); |
243 // And adjust the argslot address to point at the deletion point. |
312 // And adjust the argslot address to point at the deletion point. |
244 __ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr)); |
313 __ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr)); |
|
314 BLOCK_COMMENT("} remove_arg_slots"); |
245 } |
315 } |
246 |
316 |
247 #ifndef PRODUCT |
317 #ifndef PRODUCT |
248 extern "C" void print_method_handle(oop mh); |
318 extern "C" void print_method_handle(oop mh); |
249 void trace_method_handle_stub(const char* adaptername, |
319 void trace_method_handle_stub(const char* adaptername, |
250 oop mh, |
320 oop mh, |
|
321 intptr_t* saved_regs, |
251 intptr_t* entry_sp, |
322 intptr_t* entry_sp, |
252 intptr_t* saved_sp, |
323 intptr_t* saved_sp, |
253 intptr_t* saved_bp) { |
324 intptr_t* saved_bp) { |
254 // called as a leaf from native code: do not block the JVM! |
325 // called as a leaf from native code: do not block the JVM! |
255 intptr_t* last_sp = (intptr_t*) saved_bp[frame::interpreter_frame_last_sp_offset]; |
326 intptr_t* last_sp = (intptr_t*) saved_bp[frame::interpreter_frame_last_sp_offset]; |
256 intptr_t* base_sp = (intptr_t*) saved_bp[frame::interpreter_frame_monitor_block_top_offset]; |
327 intptr_t* base_sp = (intptr_t*) saved_bp[frame::interpreter_frame_monitor_block_top_offset]; |
257 printf("MH %s mh="INTPTR_FORMAT" sp=("INTPTR_FORMAT"+"INTX_FORMAT") stack_size="INTX_FORMAT" bp="INTPTR_FORMAT"\n", |
328 printf("MH %s mh="INTPTR_FORMAT" sp=("INTPTR_FORMAT"+"INTX_FORMAT") stack_size="INTX_FORMAT" bp="INTPTR_FORMAT"\n", |
258 adaptername, (intptr_t)mh, (intptr_t)entry_sp, (intptr_t)(saved_sp - entry_sp), (intptr_t)(base_sp - last_sp), (intptr_t)saved_bp); |
329 adaptername, (intptr_t)mh, (intptr_t)entry_sp, (intptr_t)(saved_sp - entry_sp), (intptr_t)(base_sp - last_sp), (intptr_t)saved_bp); |
259 if (last_sp != saved_sp) |
330 if (last_sp != saved_sp && last_sp != NULL) |
260 printf("*** last_sp="INTPTR_FORMAT"\n", (intptr_t)last_sp); |
331 printf("*** last_sp="INTPTR_FORMAT"\n", (intptr_t)last_sp); |
261 if (Verbose) print_method_handle(mh); |
332 if (Verbose) { |
|
333 printf(" reg dump: "); |
|
334 int saved_regs_count = (entry_sp-1) - saved_regs; |
|
335 // 32 bit: rdi rsi rbp rsp; rbx rdx rcx (*) rax |
|
336 int i; |
|
337 for (i = 0; i <= saved_regs_count; i++) { |
|
338 if (i > 0 && i % 4 == 0 && i != saved_regs_count) |
|
339 printf("\n + dump: "); |
|
340 printf(" %d: "INTPTR_FORMAT, i, saved_regs[i]); |
|
341 } |
|
342 printf("\n"); |
|
343 int stack_dump_count = 16; |
|
344 if (stack_dump_count < (int)(saved_bp + 2 - saved_sp)) |
|
345 stack_dump_count = (int)(saved_bp + 2 - saved_sp); |
|
346 if (stack_dump_count > 64) stack_dump_count = 48; |
|
347 for (i = 0; i < stack_dump_count; i += 4) { |
|
348 printf(" dump at SP[%d] "INTPTR_FORMAT": "INTPTR_FORMAT" "INTPTR_FORMAT" "INTPTR_FORMAT" "INTPTR_FORMAT"\n", |
|
349 i, &entry_sp[i+0], entry_sp[i+0], entry_sp[i+1], entry_sp[i+2], entry_sp[i+3]); |
|
350 } |
|
351 print_method_handle(mh); |
|
352 } |
|
353 } |
|
354 void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) { |
|
355 if (!TraceMethodHandles) return; |
|
356 BLOCK_COMMENT("trace_method_handle {"); |
|
357 __ push(rax); |
|
358 __ lea(rax, Address(rsp, wordSize*6)); // entry_sp |
|
359 __ pusha(); |
|
360 // arguments: |
|
361 __ push(rbp); // interpreter frame pointer |
|
362 __ push(rsi); // saved_sp |
|
363 __ push(rax); // entry_sp |
|
364 __ push(rcx); // mh |
|
365 __ push(rcx); |
|
366 __ movptr(Address(rsp, 0), (intptr_t) adaptername); |
|
367 __ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub), 5); |
|
368 __ popa(); |
|
369 __ pop(rax); |
|
370 BLOCK_COMMENT("} trace_method_handle"); |
262 } |
371 } |
263 #endif //PRODUCT |
372 #endif //PRODUCT |
264 |
373 |
265 // which conversion op types are implemented here? |
374 // which conversion op types are implemented here? |
266 int MethodHandles::adapter_conversion_ops_supported_mask() { |
375 int MethodHandles::adapter_conversion_ops_supported_mask() { |
322 } |
431 } |
323 |
432 |
324 address interp_entry = __ pc(); |
433 address interp_entry = __ pc(); |
325 if (UseCompressedOops) __ unimplemented("UseCompressedOops"); |
434 if (UseCompressedOops) __ unimplemented("UseCompressedOops"); |
326 |
435 |
327 #ifndef PRODUCT |
436 trace_method_handle(_masm, entry_name(ek)); |
328 if (TraceMethodHandles) { |
437 |
329 __ push(rax); __ push(rbx); __ push(rcx); __ push(rdx); __ push(rsi); __ push(rdi); |
438 BLOCK_COMMENT(entry_name(ek)); |
330 __ lea(rax, Address(rsp, wordSize*6)); // entry_sp |
|
331 // arguments: |
|
332 __ push(rbp); // interpreter frame pointer |
|
333 __ push(rsi); // saved_sp |
|
334 __ push(rax); // entry_sp |
|
335 __ push(rcx); // mh |
|
336 __ push(rcx); |
|
337 __ movptr(Address(rsp, 0), (intptr_t)entry_name(ek)); |
|
338 __ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub), 5); |
|
339 __ pop(rdi); __ pop(rsi); __ pop(rdx); __ pop(rcx); __ pop(rbx); __ pop(rax); |
|
340 } |
|
341 #endif //PRODUCT |
|
342 |
439 |
343 switch ((int) ek) { |
440 switch ((int) ek) { |
344 case _raise_exception: |
441 case _raise_exception: |
345 { |
442 { |
346 // Not a real MH entry, but rather shared code for raising an exception. |
443 // Not a real MH entry, but rather shared code for raising an exception. |