Mercurial > hg > graal-compiler
annotate src/cpu/x86/vm/methodHandles_x86.cpp @ 2007:5ddfcf4b079e
7003554: (tiered) assert(is_null_object() || handle() != NULL) failed: cannot embed null pointer
Summary: C1 with profiling doesn't check whether the MDO has been really allocated, which can silently fail if the perm gen is full. The solution is to check if the allocation failed and bailout out of inlining or compilation.
Reviewed-by: kvn, never
author | iveresov |
---|---|
date | Thu, 02 Dec 2010 17:21:12 -0800 |
parents | f95d63e2154a |
children | 8d0b933dda2d |
rev | line source |
---|---|
710 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1507
diff
changeset
|
2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. |
710 | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1507
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1507
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1507
diff
changeset
|
21 * questions. |
710 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "interpreter/interpreter.hpp" | |
27 #include "memory/allocation.inline.hpp" | |
28 #include "prims/methodHandles.hpp" | |
710 | 29 |
30 #define __ _masm-> | |
31 | |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
32 #ifdef PRODUCT |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
33 #define BLOCK_COMMENT(str) /* nothing */ |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
34 #else |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
35 #define BLOCK_COMMENT(str) __ block_comment(str) |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
36 #endif |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
37 |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
38 #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
39 |
710 | 40 address MethodHandleEntry::start_compiled_entry(MacroAssembler* _masm, |
41 address interpreted_entry) { | |
42 // Just before the actual machine code entry point, allocate space | |
43 // for a MethodHandleEntry::Data record, so that we can manage everything | |
44 // from one base pointer. | |
45 __ align(wordSize); | |
46 address target = __ pc() + sizeof(Data); | |
47 while (__ pc() < target) { | |
48 __ nop(); | |
49 __ align(wordSize); | |
50 } | |
51 | |
52 MethodHandleEntry* me = (MethodHandleEntry*) __ pc(); | |
53 me->set_end_address(__ pc()); // set a temporary end_address | |
54 me->set_from_interpreted_entry(interpreted_entry); | |
55 me->set_type_checking_entry(NULL); | |
56 | |
57 return (address) me; | |
58 } | |
59 | |
60 MethodHandleEntry* MethodHandleEntry::finish_compiled_entry(MacroAssembler* _masm, | |
61 address start_addr) { | |
62 MethodHandleEntry* me = (MethodHandleEntry*) start_addr; | |
63 assert(me->end_address() == start_addr, "valid ME"); | |
64 | |
65 // Fill in the real end_address: | |
66 __ align(wordSize); | |
67 me->set_end_address(__ pc()); | |
68 | |
69 return me; | |
70 } | |
71 | |
72 #ifdef ASSERT | |
1304 | 73 static void verify_argslot(MacroAssembler* _masm, Register argslot_reg, |
710 | 74 const char* error_message) { |
75 // Verify that argslot lies within (rsp, rbp]. | |
76 Label L_ok, L_bad; | |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
77 BLOCK_COMMENT("{ verify_argslot"); |
1304 | 78 __ cmpptr(argslot_reg, rbp); |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
79 __ jccb(Assembler::above, L_bad); |
1304 | 80 __ cmpptr(rsp, argslot_reg); |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
81 __ jccb(Assembler::below, L_ok); |
710 | 82 __ bind(L_bad); |
83 __ stop(error_message); | |
84 __ bind(L_ok); | |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
85 BLOCK_COMMENT("} verify_argslot"); |
710 | 86 } |
87 #endif | |
88 | |
89 | |
90 // Code generation | |
91 address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) { | |
92 // rbx: methodOop | |
93 // rcx: receiver method handle (must load from sp[MethodTypeForm.vmslots]) | |
94 // rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted) | |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
95 // rdx, rdi: garbage temp, blown away |
710 | 96 |
97 Register rbx_method = rbx; | |
98 Register rcx_recv = rcx; | |
99 Register rax_mtype = rax; | |
100 Register rdx_temp = rdx; | |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
101 Register rdi_temp = rdi; |
710 | 102 |
103 // emit WrongMethodType path first, to enable jccb back-branch from main path | |
104 Label wrong_method_type; | |
105 __ bind(wrong_method_type); | |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
106 Label invoke_generic_slow_path; |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
107 assert(methodOopDesc::intrinsic_id_size_in_bytes() == sizeof(u1), "");; |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
108 __ cmpb(Address(rbx_method, methodOopDesc::intrinsic_id_offset_in_bytes()), (int) vmIntrinsics::_invokeExact); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
109 __ jcc(Assembler::notEqual, invoke_generic_slow_path); |
710 | 110 __ push(rax_mtype); // required mtype |
111 __ push(rcx_recv); // bad mh (1st stacked argument) | |
112 __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry())); | |
113 | |
114 // here's where control starts out: | |
115 __ align(CodeEntryAlignment); | |
116 address entry_point = __ pc(); | |
117 | |
118 // fetch the MethodType from the method handle into rax (the 'check' register) | |
119 { | |
120 Register tem = rbx_method; | |
121 for (jint* pchase = methodOopDesc::method_type_offsets_chain(); (*pchase) != -1; pchase++) { | |
122 __ movptr(rax_mtype, Address(tem, *pchase)); | |
123 tem = rax_mtype; // in case there is another indirection | |
124 } | |
125 } | |
126 | |
127 // given the MethodType, find out where the MH argument is buried | |
1846 | 128 __ load_heap_oop(rdx_temp, Address(rax_mtype, __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, rdi_temp))); |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
129 Register rdx_vmslots = rdx_temp; |
1846 | 130 __ movl(rdx_vmslots, Address(rdx_temp, __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, rdi_temp))); |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
131 __ movptr(rcx_recv, __ argument_address(rdx_vmslots)); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
132 |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
133 trace_method_handle(_masm, "invokeExact"); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
134 |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
135 __ check_method_handle_type(rax_mtype, rcx_recv, rdi_temp, wrong_method_type); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
136 __ jump_to_method_handle_entry(rcx_recv, rdi_temp); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
137 |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
138 // for invokeGeneric (only), apply argument and result conversions on the fly |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
139 __ bind(invoke_generic_slow_path); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
140 #ifdef ASSERT |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
141 { Label L; |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
142 __ cmpb(Address(rbx_method, methodOopDesc::intrinsic_id_offset_in_bytes()), (int) vmIntrinsics::_invokeGeneric); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
143 __ jcc(Assembler::equal, L); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
144 __ stop("bad methodOop::intrinsic_id"); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
145 __ bind(L); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
146 } |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
147 #endif //ASSERT |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
148 Register rbx_temp = rbx_method; // don't need it now |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
149 |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
150 // make room on the stack for another pointer: |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
151 Register rcx_argslot = rcx_recv; |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
152 __ lea(rcx_argslot, __ argument_address(rdx_vmslots, 1)); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
153 insert_arg_slots(_masm, 2 * stack_move_unit(), _INSERT_REF_MASK, |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
154 rcx_argslot, rbx_temp, rdx_temp); |
710 | 155 |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
156 // load up an adapter from the calling type (Java weaves this) |
1846 | 157 __ load_heap_oop(rdx_temp, Address(rax_mtype, __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, rdi_temp))); |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
158 Register rdx_adapter = rdx_temp; |
1846 | 159 // __ load_heap_oop(rdx_adapter, Address(rdx_temp, java_dyn_MethodTypeForm::genericInvoker_offset_in_bytes())); |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
160 // deal with old JDK versions: |
1846 | 161 __ lea(rdi_temp, Address(rdx_temp, __ delayed_value(java_dyn_MethodTypeForm::genericInvoker_offset_in_bytes, rdi_temp))); |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
162 __ cmpptr(rdi_temp, rdx_temp); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
163 Label sorry_no_invoke_generic; |
1846 | 164 __ jcc(Assembler::below, sorry_no_invoke_generic); |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
165 |
1846 | 166 __ load_heap_oop(rdx_adapter, Address(rdi_temp, 0)); |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
167 __ testptr(rdx_adapter, rdx_adapter); |
1846 | 168 __ jcc(Assembler::zero, sorry_no_invoke_generic); |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
169 __ movptr(Address(rcx_argslot, 1 * Interpreter::stackElementSize), rdx_adapter); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
170 // As a trusted first argument, pass the type being called, so the adapter knows |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
171 // the actual types of the arguments and return values. |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
172 // (Generic invokers are shared among form-families of method-type.) |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
173 __ movptr(Address(rcx_argslot, 0 * Interpreter::stackElementSize), rax_mtype); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
174 // FIXME: assert that rdx_adapter is of the right method-type. |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
175 __ mov(rcx, rdx_adapter); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
176 trace_method_handle(_masm, "invokeGeneric"); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
177 __ jump_to_method_handle_entry(rcx, rdi_temp); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
178 |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
179 __ bind(sorry_no_invoke_generic); // no invokeGeneric implementation available! |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
180 __ movptr(rcx_recv, Address(rcx_argslot, -1 * Interpreter::stackElementSize)); // recover original MH |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
181 __ push(rax_mtype); // required mtype |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
182 __ push(rcx_recv); // bad mh (1st stacked argument) |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
183 __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry())); |
710 | 184 |
185 return entry_point; | |
186 } | |
187 | |
188 // Helper to insert argument slots into the stack. | |
189 // arg_slots must be a multiple of stack_move_unit() and <= 0 | |
190 void MethodHandles::insert_arg_slots(MacroAssembler* _masm, | |
191 RegisterOrConstant arg_slots, | |
192 int arg_mask, | |
193 Register rax_argslot, | |
1503 | 194 Register rbx_temp, Register rdx_temp, Register temp3_reg) { |
195 assert(temp3_reg == noreg, "temp3 not required"); | |
710 | 196 assert_different_registers(rax_argslot, rbx_temp, rdx_temp, |
197 (!arg_slots.is_register() ? rsp : arg_slots.as_register())); | |
198 | |
199 #ifdef ASSERT | |
200 verify_argslot(_masm, rax_argslot, "insertion point must fall within current frame"); | |
201 if (arg_slots.is_register()) { | |
202 Label L_ok, L_bad; | |
203 __ cmpptr(arg_slots.as_register(), (int32_t) NULL_WORD); | |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
204 __ jccb(Assembler::greater, L_bad); |
710 | 205 __ testl(arg_slots.as_register(), -stack_move_unit() - 1); |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
206 __ jccb(Assembler::zero, L_ok); |
710 | 207 __ bind(L_bad); |
208 __ stop("assert arg_slots <= 0 and clear low bits"); | |
209 __ bind(L_ok); | |
210 } else { | |
211 assert(arg_slots.as_constant() <= 0, ""); | |
212 assert(arg_slots.as_constant() % -stack_move_unit() == 0, ""); | |
213 } | |
214 #endif //ASSERT | |
215 | |
216 #ifdef _LP64 | |
217 if (arg_slots.is_register()) { | |
218 // clean high bits of stack motion register (was loaded as an int) | |
219 __ movslq(arg_slots.as_register(), arg_slots.as_register()); | |
220 } | |
221 #endif | |
222 | |
223 // Make space on the stack for the inserted argument(s). | |
224 // Then pull down everything shallower than rax_argslot. | |
225 // The stacked return address gets pulled down with everything else. | |
226 // That is, copy [rsp, argslot) downward by -size words. In pseudo-code: | |
227 // rsp -= size; | |
228 // for (rdx = rsp + size; rdx < argslot; rdx++) | |
229 // rdx[-size] = rdx[0] | |
230 // argslot -= size; | |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
231 BLOCK_COMMENT("insert_arg_slots {"); |
710 | 232 __ mov(rdx_temp, rsp); // source pointer for copy |
233 __ lea(rsp, Address(rsp, arg_slots, Address::times_ptr)); | |
234 { | |
235 Label loop; | |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
236 __ BIND(loop); |
710 | 237 // pull one word down each time through the loop |
238 __ movptr(rbx_temp, Address(rdx_temp, 0)); | |
239 __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp); | |
240 __ addptr(rdx_temp, wordSize); | |
241 __ cmpptr(rdx_temp, rax_argslot); | |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
242 __ jccb(Assembler::less, loop); |
710 | 243 } |
244 | |
245 // Now move the argslot down, to point to the opened-up space. | |
246 __ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr)); | |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
247 BLOCK_COMMENT("} insert_arg_slots"); |
710 | 248 } |
249 | |
250 // Helper to remove argument slots from the stack. | |
251 // arg_slots must be a multiple of stack_move_unit() and >= 0 | |
252 void MethodHandles::remove_arg_slots(MacroAssembler* _masm, | |
253 RegisterOrConstant arg_slots, | |
254 Register rax_argslot, | |
1503 | 255 Register rbx_temp, Register rdx_temp, Register temp3_reg) { |
256 assert(temp3_reg == noreg, "temp3 not required"); | |
710 | 257 assert_different_registers(rax_argslot, rbx_temp, rdx_temp, |
258 (!arg_slots.is_register() ? rsp : arg_slots.as_register())); | |
259 | |
260 #ifdef ASSERT | |
1304 | 261 // Verify that [argslot..argslot+size) lies within (rsp, rbp). |
262 __ lea(rbx_temp, Address(rax_argslot, arg_slots, Address::times_ptr)); | |
263 verify_argslot(_masm, rbx_temp, "deleted argument(s) must fall within current frame"); | |
710 | 264 if (arg_slots.is_register()) { |
265 Label L_ok, L_bad; | |
266 __ cmpptr(arg_slots.as_register(), (int32_t) NULL_WORD); | |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
267 __ jccb(Assembler::less, L_bad); |
710 | 268 __ testl(arg_slots.as_register(), -stack_move_unit() - 1); |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
269 __ jccb(Assembler::zero, L_ok); |
710 | 270 __ bind(L_bad); |
271 __ stop("assert arg_slots >= 0 and clear low bits"); | |
272 __ bind(L_ok); | |
273 } else { | |
274 assert(arg_slots.as_constant() >= 0, ""); | |
275 assert(arg_slots.as_constant() % -stack_move_unit() == 0, ""); | |
276 } | |
277 #endif //ASSERT | |
278 | |
279 #ifdef _LP64 | |
280 if (false) { // not needed, since register is positive | |
281 // clean high bits of stack motion register (was loaded as an int) | |
282 if (arg_slots.is_register()) | |
283 __ movslq(arg_slots.as_register(), arg_slots.as_register()); | |
284 } | |
285 #endif | |
286 | |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
287 BLOCK_COMMENT("remove_arg_slots {"); |
710 | 288 // Pull up everything shallower than rax_argslot. |
289 // Then remove the excess space on the stack. | |
290 // The stacked return address gets pulled up with everything else. | |
291 // That is, copy [rsp, argslot) upward by size words. In pseudo-code: | |
292 // for (rdx = argslot-1; rdx >= rsp; --rdx) | |
293 // rdx[size] = rdx[0] | |
294 // argslot += size; | |
295 // rsp += size; | |
296 __ lea(rdx_temp, Address(rax_argslot, -wordSize)); // source pointer for copy | |
297 { | |
298 Label loop; | |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
299 __ BIND(loop); |
710 | 300 // pull one word up each time through the loop |
301 __ movptr(rbx_temp, Address(rdx_temp, 0)); | |
302 __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp); | |
303 __ addptr(rdx_temp, -wordSize); | |
304 __ cmpptr(rdx_temp, rsp); | |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
305 __ jccb(Assembler::greaterEqual, loop); |
710 | 306 } |
307 | |
308 // Now move the argslot up, to point to the just-copied block. | |
309 __ lea(rsp, Address(rsp, arg_slots, Address::times_ptr)); | |
310 // And adjust the argslot address to point at the deletion point. | |
311 __ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr)); | |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
312 BLOCK_COMMENT("} remove_arg_slots"); |
710 | 313 } |
314 | |
315 #ifndef PRODUCT | |
1133
aa62b9388fce
6894206: JVM needs a way to traverse method handle structures
twisti
parents:
1108
diff
changeset
|
316 extern "C" void print_method_handle(oop mh); |
710 | 317 void trace_method_handle_stub(const char* adaptername, |
1133
aa62b9388fce
6894206: JVM needs a way to traverse method handle structures
twisti
parents:
1108
diff
changeset
|
318 oop mh, |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
319 intptr_t* saved_regs, |
710 | 320 intptr_t* entry_sp, |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
321 intptr_t* saved_sp, |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
322 intptr_t* saved_bp) { |
710 | 323 // called as a leaf from native code: do not block the JVM! |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
324 intptr_t* last_sp = (intptr_t*) saved_bp[frame::interpreter_frame_last_sp_offset]; |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
325 intptr_t* base_sp = (intptr_t*) saved_bp[frame::interpreter_frame_monitor_block_top_offset]; |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
326 printf("MH %s mh="INTPTR_FORMAT" sp=("INTPTR_FORMAT"+"INTX_FORMAT") stack_size="INTX_FORMAT" bp="INTPTR_FORMAT"\n", |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
327 adaptername, (intptr_t)mh, (intptr_t)entry_sp, (intptr_t)(saved_sp - entry_sp), (intptr_t)(base_sp - last_sp), (intptr_t)saved_bp); |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
328 if (last_sp != saved_sp && last_sp != NULL) |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
329 printf("*** last_sp="INTPTR_FORMAT"\n", (intptr_t)last_sp); |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
330 if (Verbose) { |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
331 printf(" reg dump: "); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
332 int saved_regs_count = (entry_sp-1) - saved_regs; |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
333 // 32 bit: rdi rsi rbp rsp; rbx rdx rcx (*) rax |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
334 int i; |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
335 for (i = 0; i <= saved_regs_count; i++) { |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
336 if (i > 0 && i % 4 == 0 && i != saved_regs_count) |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
337 printf("\n + dump: "); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
338 printf(" %d: "INTPTR_FORMAT, i, saved_regs[i]); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
339 } |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
340 printf("\n"); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
341 int stack_dump_count = 16; |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
342 if (stack_dump_count < (int)(saved_bp + 2 - saved_sp)) |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
343 stack_dump_count = (int)(saved_bp + 2 - saved_sp); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
344 if (stack_dump_count > 64) stack_dump_count = 48; |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
345 for (i = 0; i < stack_dump_count; i += 4) { |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
346 printf(" dump at SP[%d] "INTPTR_FORMAT": "INTPTR_FORMAT" "INTPTR_FORMAT" "INTPTR_FORMAT" "INTPTR_FORMAT"\n", |
1818
c93c652551b5
6986944: JSR 292 assert(caller_nm->is_method_handle_return(caller_frame.pc())) failed: must be MH call site
twisti
parents:
1793
diff
changeset
|
347 i, (intptr_t) &entry_sp[i+0], entry_sp[i+0], entry_sp[i+1], entry_sp[i+2], entry_sp[i+3]); |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
348 } |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
349 print_method_handle(mh); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
350 } |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
351 } |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
352 void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) { |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
353 if (!TraceMethodHandles) return; |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
354 BLOCK_COMMENT("trace_method_handle {"); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
355 __ push(rax); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
356 __ lea(rax, Address(rsp, wordSize*6)); // entry_sp |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
357 __ pusha(); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
358 // arguments: |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
359 __ push(rbp); // interpreter frame pointer |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
360 __ push(rsi); // saved_sp |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
361 __ push(rax); // entry_sp |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
362 __ push(rcx); // mh |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
363 __ push(rcx); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
364 __ movptr(Address(rsp, 0), (intptr_t) adaptername); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
365 __ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub), 5); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
366 __ popa(); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
367 __ pop(rax); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
368 BLOCK_COMMENT("} trace_method_handle"); |
710 | 369 } |
370 #endif //PRODUCT | |
371 | |
1507
cd5dbf694d45
6939134: JSR 292 adjustments to method handle invocation
jrose
parents:
1506
diff
changeset
|
372 // which conversion op types are implemented here? |
cd5dbf694d45
6939134: JSR 292 adjustments to method handle invocation
jrose
parents:
1506
diff
changeset
|
373 int MethodHandles::adapter_conversion_ops_supported_mask() { |
cd5dbf694d45
6939134: JSR 292 adjustments to method handle invocation
jrose
parents:
1506
diff
changeset
|
374 return ((1<<sun_dyn_AdapterMethodHandle::OP_RETYPE_ONLY) |
cd5dbf694d45
6939134: JSR 292 adjustments to method handle invocation
jrose
parents:
1506
diff
changeset
|
375 |(1<<sun_dyn_AdapterMethodHandle::OP_RETYPE_RAW) |
cd5dbf694d45
6939134: JSR 292 adjustments to method handle invocation
jrose
parents:
1506
diff
changeset
|
376 |(1<<sun_dyn_AdapterMethodHandle::OP_CHECK_CAST) |
cd5dbf694d45
6939134: JSR 292 adjustments to method handle invocation
jrose
parents:
1506
diff
changeset
|
377 |(1<<sun_dyn_AdapterMethodHandle::OP_PRIM_TO_PRIM) |
cd5dbf694d45
6939134: JSR 292 adjustments to method handle invocation
jrose
parents:
1506
diff
changeset
|
378 |(1<<sun_dyn_AdapterMethodHandle::OP_REF_TO_PRIM) |
cd5dbf694d45
6939134: JSR 292 adjustments to method handle invocation
jrose
parents:
1506
diff
changeset
|
379 |(1<<sun_dyn_AdapterMethodHandle::OP_SWAP_ARGS) |
cd5dbf694d45
6939134: JSR 292 adjustments to method handle invocation
jrose
parents:
1506
diff
changeset
|
380 |(1<<sun_dyn_AdapterMethodHandle::OP_ROT_ARGS) |
cd5dbf694d45
6939134: JSR 292 adjustments to method handle invocation
jrose
parents:
1506
diff
changeset
|
381 |(1<<sun_dyn_AdapterMethodHandle::OP_DUP_ARGS) |
cd5dbf694d45
6939134: JSR 292 adjustments to method handle invocation
jrose
parents:
1506
diff
changeset
|
382 |(1<<sun_dyn_AdapterMethodHandle::OP_DROP_ARGS) |
cd5dbf694d45
6939134: JSR 292 adjustments to method handle invocation
jrose
parents:
1506
diff
changeset
|
383 //|(1<<sun_dyn_AdapterMethodHandle::OP_SPREAD_ARGS) //BUG! |
cd5dbf694d45
6939134: JSR 292 adjustments to method handle invocation
jrose
parents:
1506
diff
changeset
|
384 ); |
cd5dbf694d45
6939134: JSR 292 adjustments to method handle invocation
jrose
parents:
1506
diff
changeset
|
385 // FIXME: MethodHandlesTest gets a crash if we enable OP_SPREAD_ARGS. |
cd5dbf694d45
6939134: JSR 292 adjustments to method handle invocation
jrose
parents:
1506
diff
changeset
|
386 } |
cd5dbf694d45
6939134: JSR 292 adjustments to method handle invocation
jrose
parents:
1506
diff
changeset
|
387 |
710 | 388 // Generate an "entry" field for a method handle. |
389 // This determines how the method handle will respond to calls. | |
390 void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) { | |
391 // Here is the register state during an interpreted call, | |
392 // as set up by generate_method_handle_interpreter_entry(): | |
393 // - rbx: garbage temp (was MethodHandle.invoke methodOop, unused) | |
394 // - rcx: receiver method handle | |
395 // - rax: method handle type (only used by the check_mtype entry point) | |
396 // - rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted) | |
397 // - rdx: garbage temp, can blow away | |
398 | |
399 Register rcx_recv = rcx; | |
400 Register rax_argslot = rax; | |
401 Register rbx_temp = rbx; | |
402 Register rdx_temp = rdx; | |
403 | |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
404 // This guy is set up by prepare_to_jump_from_interpreted (from interpreted calls) |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
405 // and gen_c2i_adapter (from compiled calls): |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
406 Register saved_last_sp = LP64_ONLY(r13) NOT_LP64(rsi); |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
407 |
710 | 408 guarantee(java_dyn_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets"); |
409 | |
410 // some handy addresses | |
411 Address rbx_method_fie( rbx, methodOopDesc::from_interpreted_offset() ); | |
412 | |
413 Address rcx_mh_vmtarget( rcx_recv, java_dyn_MethodHandle::vmtarget_offset_in_bytes() ); | |
414 Address rcx_dmh_vmindex( rcx_recv, sun_dyn_DirectMethodHandle::vmindex_offset_in_bytes() ); | |
415 | |
416 Address rcx_bmh_vmargslot( rcx_recv, sun_dyn_BoundMethodHandle::vmargslot_offset_in_bytes() ); | |
417 Address rcx_bmh_argument( rcx_recv, sun_dyn_BoundMethodHandle::argument_offset_in_bytes() ); | |
418 | |
419 Address rcx_amh_vmargslot( rcx_recv, sun_dyn_AdapterMethodHandle::vmargslot_offset_in_bytes() ); | |
420 Address rcx_amh_argument( rcx_recv, sun_dyn_AdapterMethodHandle::argument_offset_in_bytes() ); | |
421 Address rcx_amh_conversion( rcx_recv, sun_dyn_AdapterMethodHandle::conversion_offset_in_bytes() ); | |
422 Address vmarg; // __ argument_address(vmargslot) | |
423 | |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
424 const int java_mirror_offset = klassOopDesc::klass_part_offset_in_bytes() + Klass::java_mirror_offset_in_bytes(); |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
425 |
710 | 426 if (have_entry(ek)) { |
427 __ nop(); // empty stubs make SG sick | |
428 return; | |
429 } | |
430 | |
431 address interp_entry = __ pc(); | |
432 | |
1793
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
433 trace_method_handle(_masm, entry_name(ek)); |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
434 |
d257356e35f0
6939224: MethodHandle.invokeGeneric needs to perform the correct set of conversions
jrose
parents:
1552
diff
changeset
|
435 BLOCK_COMMENT(entry_name(ek)); |
710 | 436 |
437 switch ((int) ek) { | |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
438 case _raise_exception: |
710 | 439 { |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
440 // Not a real MH entry, but rather shared code for raising an exception. |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
441 // Extra local arguments are pushed on stack, as required type at TOS+8, |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
442 // failing object (or NULL) at TOS+4, failing bytecode type at TOS. |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
443 // Beyond those local arguments are the PC, of course. |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
444 Register rdx_code = rdx_temp; |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
445 Register rcx_fail = rcx_recv; |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
446 Register rax_want = rax_argslot; |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
447 Register rdi_pc = rdi; |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
448 __ pop(rdx_code); // TOS+0 |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
449 __ pop(rcx_fail); // TOS+4 |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
450 __ pop(rax_want); // TOS+8 |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
451 __ pop(rdi_pc); // caller PC |
710 | 452 |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
453 __ mov(rsp, rsi); // cut the stack back to where the caller started |
710 | 454 |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
455 // Repush the arguments as if coming from the interpreter. |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
456 __ push(rdx_code); |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
457 __ push(rcx_fail); |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
458 __ push(rax_want); |
710 | 459 |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
460 Register rbx_method = rbx_temp; |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
461 Label no_method; |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
462 // FIXME: fill in _raise_exception_method with a suitable sun.dyn method |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
463 __ movptr(rbx_method, ExternalAddress((address) &_raise_exception_method)); |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
464 __ testptr(rbx_method, rbx_method); |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
465 __ jccb(Assembler::zero, no_method); |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
466 int jobject_oop_offset = 0; |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
467 __ movptr(rbx_method, Address(rbx_method, jobject_oop_offset)); // dereference the jobject |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
468 __ testptr(rbx_method, rbx_method); |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
469 __ jccb(Assembler::zero, no_method); |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
470 __ verify_oop(rbx_method); |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
471 __ push(rdi_pc); // and restore caller PC |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
472 __ jmp(rbx_method_fie); |
710 | 473 |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
474 // If we get here, the Java runtime did not do its job of creating the exception. |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
475 // Do something that is at least causes a valid throw from the interpreter. |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
476 __ bind(no_method); |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
477 __ pop(rax_want); |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
478 __ pop(rcx_fail); |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
479 __ push(rax_want); |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
480 __ push(rcx_fail); |
710 | 481 __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry())); |
482 } | |
483 break; | |
484 | |
485 case _invokestatic_mh: | |
486 case _invokespecial_mh: | |
487 { | |
488 Register rbx_method = rbx_temp; | |
1846 | 489 __ load_heap_oop(rbx_method, rcx_mh_vmtarget); // target is a methodOop |
710 | 490 __ verify_oop(rbx_method); |
491 // same as TemplateTable::invokestatic or invokespecial, | |
492 // minus the CP setup and profiling: | |
493 if (ek == _invokespecial_mh) { | |
494 // Must load & check the first argument before entering the target method. | |
495 __ load_method_handle_vmslots(rax_argslot, rcx_recv, rdx_temp); | |
496 __ movptr(rcx_recv, __ argument_address(rax_argslot, -1)); | |
497 __ null_check(rcx_recv); | |
498 __ verify_oop(rcx_recv); | |
499 } | |
500 __ jmp(rbx_method_fie); | |
501 } | |
502 break; | |
503 | |
504 case _invokevirtual_mh: | |
505 { | |
506 // same as TemplateTable::invokevirtual, | |
507 // minus the CP setup and profiling: | |
508 | |
509 // pick out the vtable index and receiver offset from the MH, | |
510 // and then we can discard it: | |
511 __ load_method_handle_vmslots(rax_argslot, rcx_recv, rdx_temp); | |
512 Register rbx_index = rbx_temp; | |
513 __ movl(rbx_index, rcx_dmh_vmindex); | |
514 // Note: The verifier allows us to ignore rcx_mh_vmtarget. | |
515 __ movptr(rcx_recv, __ argument_address(rax_argslot, -1)); | |
516 __ null_check(rcx_recv, oopDesc::klass_offset_in_bytes()); | |
517 | |
518 // get receiver klass | |
519 Register rax_klass = rax_argslot; | |
520 __ load_klass(rax_klass, rcx_recv); | |
521 __ verify_oop(rax_klass); | |
522 | |
523 // get target methodOop & entry point | |
524 const int base = instanceKlass::vtable_start_offset() * wordSize; | |
525 assert(vtableEntry::size() * wordSize == wordSize, "adjust the scaling in the code below"); | |
526 Address vtable_entry_addr(rax_klass, | |
527 rbx_index, Address::times_ptr, | |
528 base + vtableEntry::method_offset_in_bytes()); | |
529 Register rbx_method = rbx_temp; | |
1108 | 530 __ movptr(rbx_method, vtable_entry_addr); |
710 | 531 |
532 __ verify_oop(rbx_method); | |
533 __ jmp(rbx_method_fie); | |
534 } | |
535 break; | |
536 | |
537 case _invokeinterface_mh: | |
538 { | |
539 // same as TemplateTable::invokeinterface, | |
540 // minus the CP setup and profiling: | |
541 | |
542 // pick out the interface and itable index from the MH. | |
543 __ load_method_handle_vmslots(rax_argslot, rcx_recv, rdx_temp); | |
544 Register rdx_intf = rdx_temp; | |
545 Register rbx_index = rbx_temp; | |
1846 | 546 __ load_heap_oop(rdx_intf, rcx_mh_vmtarget); |
547 __ movl(rbx_index, rcx_dmh_vmindex); | |
710 | 548 __ movptr(rcx_recv, __ argument_address(rax_argslot, -1)); |
549 __ null_check(rcx_recv, oopDesc::klass_offset_in_bytes()); | |
550 | |
551 // get receiver klass | |
552 Register rax_klass = rax_argslot; | |
553 __ load_klass(rax_klass, rcx_recv); | |
554 __ verify_oop(rax_klass); | |
555 | |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
556 Register rdi_temp = rdi; |
710 | 557 Register rbx_method = rbx_index; |
558 | |
559 // get interface klass | |
560 Label no_such_interface; | |
561 __ verify_oop(rdx_intf); | |
562 __ lookup_interface_method(rax_klass, rdx_intf, | |
563 // note: next two args must be the same: | |
564 rbx_index, rbx_method, | |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
565 rdi_temp, |
710 | 566 no_such_interface); |
567 | |
568 __ verify_oop(rbx_method); | |
569 __ jmp(rbx_method_fie); | |
570 __ hlt(); | |
571 | |
572 __ bind(no_such_interface); | |
573 // Throw an exception. | |
574 // For historical reasons, it will be IncompatibleClassChangeError. | |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
575 __ pushptr(Address(rdx_intf, java_mirror_offset)); // required interface |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
576 __ push(rcx_recv); // bad receiver |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
577 __ push((int)Bytecodes::_invokeinterface); // who is complaining? |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
578 __ jump(ExternalAddress(from_interpreted_entry(_raise_exception))); |
710 | 579 } |
580 break; | |
581 | |
582 case _bound_ref_mh: | |
583 case _bound_int_mh: | |
584 case _bound_long_mh: | |
585 case _bound_ref_direct_mh: | |
586 case _bound_int_direct_mh: | |
587 case _bound_long_direct_mh: | |
588 { | |
589 bool direct_to_method = (ek >= _bound_ref_direct_mh); | |
1304 | 590 BasicType arg_type = T_ILLEGAL; |
591 int arg_mask = _INSERT_NO_MASK; | |
592 int arg_slots = -1; | |
593 get_ek_bound_mh_info(ek, arg_type, arg_mask, arg_slots); | |
710 | 594 |
595 // make room for the new argument: | |
596 __ movl(rax_argslot, rcx_bmh_vmargslot); | |
597 __ lea(rax_argslot, __ argument_address(rax_argslot)); | |
598 insert_arg_slots(_masm, arg_slots * stack_move_unit(), arg_mask, | |
599 rax_argslot, rbx_temp, rdx_temp); | |
600 | |
601 // store bound argument into the new stack slot: | |
1846 | 602 __ load_heap_oop(rbx_temp, rcx_bmh_argument); |
710 | 603 Address prim_value_addr(rbx_temp, java_lang_boxing_object::value_offset_in_bytes(arg_type)); |
604 if (arg_type == T_OBJECT) { | |
605 __ movptr(Address(rax_argslot, 0), rbx_temp); | |
606 } else { | |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
607 __ load_sized_value(rdx_temp, prim_value_addr, |
710 | 608 type2aelembytes(arg_type), is_signed_subword_type(arg_type)); |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
609 __ movptr(Address(rax_argslot, 0), rdx_temp); |
710 | 610 #ifndef _LP64 |
611 if (arg_slots == 2) { | |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
612 __ movl(rdx_temp, prim_value_addr.plus_disp(wordSize)); |
1506 | 613 __ movl(Address(rax_argslot, Interpreter::stackElementSize), rdx_temp); |
710 | 614 } |
615 #endif //_LP64 | |
616 } | |
617 | |
618 if (direct_to_method) { | |
619 Register rbx_method = rbx_temp; | |
1846 | 620 __ load_heap_oop(rbx_method, rcx_mh_vmtarget); |
710 | 621 __ verify_oop(rbx_method); |
622 __ jmp(rbx_method_fie); | |
623 } else { | |
1846 | 624 __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); |
710 | 625 __ verify_oop(rcx_recv); |
626 __ jump_to_method_handle_entry(rcx_recv, rdx_temp); | |
627 } | |
628 } | |
629 break; | |
630 | |
631 case _adapter_retype_only: | |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
632 case _adapter_retype_raw: |
710 | 633 // immediately jump to the next MH layer: |
1846 | 634 __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); |
710 | 635 __ verify_oop(rcx_recv); |
636 __ jump_to_method_handle_entry(rcx_recv, rdx_temp); | |
637 // This is OK when all parameter types widen. | |
638 // It is also OK when a return type narrows. | |
639 break; | |
640 | |
641 case _adapter_check_cast: | |
642 { | |
643 // temps: | |
644 Register rbx_klass = rbx_temp; // interesting AMH data | |
645 | |
646 // check a reference argument before jumping to the next layer of MH: | |
647 __ movl(rax_argslot, rcx_amh_vmargslot); | |
648 vmarg = __ argument_address(rax_argslot); | |
649 | |
650 // What class are we casting to? | |
1846 | 651 __ load_heap_oop(rbx_klass, rcx_amh_argument); // this is a Class object! |
652 __ load_heap_oop(rbx_klass, Address(rbx_klass, java_lang_Class::klass_offset_in_bytes())); | |
710 | 653 |
654 Label done; | |
655 __ movptr(rdx_temp, vmarg); | |
1277 | 656 __ testptr(rdx_temp, rdx_temp); |
1846 | 657 __ jcc(Assembler::zero, done); // no cast if null |
710 | 658 __ load_klass(rdx_temp, rdx_temp); |
659 | |
660 // live at this point: | |
661 // - rbx_klass: klass required by the target method | |
662 // - rdx_temp: argument klass to test | |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
663 // - rcx_recv: adapter method handle |
710 | 664 __ check_klass_subtype(rdx_temp, rbx_klass, rax_argslot, done); |
665 | |
666 // If we get here, the type check failed! | |
667 // Call the wrong_method_type stub, passing the failing argument type in rax. | |
668 Register rax_mtype = rax_argslot; | |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
669 __ movl(rax_argslot, rcx_amh_vmargslot); // reload argslot field |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
670 __ movptr(rdx_temp, vmarg); |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
671 |
1846 | 672 __ load_heap_oop(rbx_klass, rcx_amh_argument); // required class |
673 __ push(rbx_klass); | |
674 __ push(rdx_temp); // bad object | |
675 __ push((int)Bytecodes::_checkcast); // who is complaining? | |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
676 __ jump(ExternalAddress(from_interpreted_entry(_raise_exception))); |
710 | 677 |
678 __ bind(done); | |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
679 // get the new MH: |
1846 | 680 __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); |
710 | 681 __ jump_to_method_handle_entry(rcx_recv, rdx_temp); |
682 } | |
683 break; | |
684 | |
685 case _adapter_prim_to_prim: | |
686 case _adapter_ref_to_prim: | |
687 // handled completely by optimized cases | |
688 __ stop("init_AdapterMethodHandle should not issue this"); | |
689 break; | |
690 | |
691 case _adapter_opt_i2i: // optimized subcase of adapt_prim_to_prim | |
692 //case _adapter_opt_f2i: // optimized subcase of adapt_prim_to_prim | |
693 case _adapter_opt_l2i: // optimized subcase of adapt_prim_to_prim | |
694 case _adapter_opt_unboxi: // optimized subcase of adapt_ref_to_prim | |
695 { | |
696 // perform an in-place conversion to int or an int subword | |
697 __ movl(rax_argslot, rcx_amh_vmargslot); | |
698 vmarg = __ argument_address(rax_argslot); | |
699 | |
700 switch (ek) { | |
701 case _adapter_opt_i2i: | |
702 __ movl(rdx_temp, vmarg); | |
703 break; | |
704 case _adapter_opt_l2i: | |
705 { | |
706 // just delete the extra slot; on a little-endian machine we keep the first | |
707 __ lea(rax_argslot, __ argument_address(rax_argslot, 1)); | |
708 remove_arg_slots(_masm, -stack_move_unit(), | |
709 rax_argslot, rbx_temp, rdx_temp); | |
1506 | 710 vmarg = Address(rax_argslot, -Interpreter::stackElementSize); |
710 | 711 __ movl(rdx_temp, vmarg); |
712 } | |
713 break; | |
714 case _adapter_opt_unboxi: | |
715 { | |
716 // Load the value up from the heap. | |
717 __ movptr(rdx_temp, vmarg); | |
718 int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_INT); | |
719 #ifdef ASSERT | |
720 for (int bt = T_BOOLEAN; bt < T_INT; bt++) { | |
721 if (is_subword_type(BasicType(bt))) | |
722 assert(value_offset == java_lang_boxing_object::value_offset_in_bytes(BasicType(bt)), ""); | |
723 } | |
724 #endif | |
725 __ null_check(rdx_temp, value_offset); | |
726 __ movl(rdx_temp, Address(rdx_temp, value_offset)); | |
727 // We load this as a word. Because we are little-endian, | |
728 // the low bits will be correct, but the high bits may need cleaning. | |
729 // The vminfo will guide us to clean those bits. | |
730 } | |
731 break; | |
732 default: | |
1304 | 733 ShouldNotReachHere(); |
710 | 734 } |
735 | |
1304 | 736 // Do the requested conversion and store the value. |
710 | 737 Register rbx_vminfo = rbx_temp; |
738 __ movl(rbx_vminfo, rcx_amh_conversion); | |
739 assert(CONV_VMINFO_SHIFT == 0, "preshifted"); | |
740 | |
741 // get the new MH: | |
1846 | 742 __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); |
710 | 743 // (now we are done with the old MH) |
744 | |
745 // original 32-bit vmdata word must be of this form: | |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
746 // | MBZ:6 | signBitCount:8 | srcDstTypes:8 | conversionOp:8 | |
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
747 __ xchgptr(rcx, rbx_vminfo); // free rcx for shifts |
710 | 748 __ shll(rdx_temp /*, rcx*/); |
749 Label zero_extend, done; | |
750 __ testl(rcx, CONV_VMINFO_SIGN_FLAG); | |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
751 __ jccb(Assembler::zero, zero_extend); |
710 | 752 |
753 // this path is taken for int->byte, int->short | |
754 __ sarl(rdx_temp /*, rcx*/); | |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
755 __ jmpb(done); |
710 | 756 |
757 __ bind(zero_extend); | |
758 // this is taken for int->char | |
759 __ shrl(rdx_temp /*, rcx*/); | |
760 | |
761 __ bind(done); | |
1304 | 762 __ movl(vmarg, rdx_temp); // Store the value. |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
763 __ xchgptr(rcx, rbx_vminfo); // restore rcx_recv |
710 | 764 |
765 __ jump_to_method_handle_entry(rcx_recv, rdx_temp); | |
766 } | |
767 break; | |
768 | |
769 case _adapter_opt_i2l: // optimized subcase of adapt_prim_to_prim | |
770 case _adapter_opt_unboxl: // optimized subcase of adapt_ref_to_prim | |
771 { | |
772 // perform an in-place int-to-long or ref-to-long conversion | |
773 __ movl(rax_argslot, rcx_amh_vmargslot); | |
774 | |
775 // on a little-endian machine we keep the first slot and add another after | |
776 __ lea(rax_argslot, __ argument_address(rax_argslot, 1)); | |
777 insert_arg_slots(_masm, stack_move_unit(), _INSERT_INT_MASK, | |
778 rax_argslot, rbx_temp, rdx_temp); | |
1506 | 779 Address vmarg1(rax_argslot, -Interpreter::stackElementSize); |
780 Address vmarg2 = vmarg1.plus_disp(Interpreter::stackElementSize); | |
710 | 781 |
782 switch (ek) { | |
783 case _adapter_opt_i2l: | |
784 { | |
1293
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
785 #ifdef _LP64 |
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
786 __ movslq(rdx_temp, vmarg1); // Load sign-extended |
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
787 __ movq(vmarg1, rdx_temp); // Store into first slot |
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
788 #else |
710 | 789 __ movl(rdx_temp, vmarg1); |
1293
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
790 __ sarl(rdx_temp, BitsPerInt - 1); // __ extend_sign() |
710 | 791 __ movl(vmarg2, rdx_temp); // store second word |
1293
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
792 #endif |
710 | 793 } |
794 break; | |
795 case _adapter_opt_unboxl: | |
796 { | |
797 // Load the value up from the heap. | |
798 __ movptr(rdx_temp, vmarg1); | |
799 int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_LONG); | |
800 assert(value_offset == java_lang_boxing_object::value_offset_in_bytes(T_DOUBLE), ""); | |
801 __ null_check(rdx_temp, value_offset); | |
1293
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
802 #ifdef _LP64 |
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
803 __ movq(rbx_temp, Address(rdx_temp, value_offset)); |
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
804 __ movq(vmarg1, rbx_temp); |
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
805 #else |
710 | 806 __ movl(rbx_temp, Address(rdx_temp, value_offset + 0*BytesPerInt)); |
807 __ movl(rdx_temp, Address(rdx_temp, value_offset + 1*BytesPerInt)); | |
808 __ movl(vmarg1, rbx_temp); | |
809 __ movl(vmarg2, rdx_temp); | |
1293
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
810 #endif |
710 | 811 } |
812 break; | |
813 default: | |
1304 | 814 ShouldNotReachHere(); |
710 | 815 } |
816 | |
1846 | 817 __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); |
710 | 818 __ jump_to_method_handle_entry(rcx_recv, rdx_temp); |
819 } | |
820 break; | |
821 | |
822 case _adapter_opt_f2d: // optimized subcase of adapt_prim_to_prim | |
823 case _adapter_opt_d2f: // optimized subcase of adapt_prim_to_prim | |
824 { | |
825 // perform an in-place floating primitive conversion | |
826 __ movl(rax_argslot, rcx_amh_vmargslot); | |
827 __ lea(rax_argslot, __ argument_address(rax_argslot, 1)); | |
828 if (ek == _adapter_opt_f2d) { | |
829 insert_arg_slots(_masm, stack_move_unit(), _INSERT_INT_MASK, | |
830 rax_argslot, rbx_temp, rdx_temp); | |
831 } | |
1506 | 832 Address vmarg(rax_argslot, -Interpreter::stackElementSize); |
710 | 833 |
834 #ifdef _LP64 | |
835 if (ek == _adapter_opt_f2d) { | |
836 __ movflt(xmm0, vmarg); | |
837 __ cvtss2sd(xmm0, xmm0); | |
838 __ movdbl(vmarg, xmm0); | |
839 } else { | |
840 __ movdbl(xmm0, vmarg); | |
841 __ cvtsd2ss(xmm0, xmm0); | |
842 __ movflt(vmarg, xmm0); | |
843 } | |
844 #else //_LP64 | |
845 if (ek == _adapter_opt_f2d) { | |
846 __ fld_s(vmarg); // load float to ST0 | |
847 __ fstp_s(vmarg); // store single | |
1304 | 848 } else { |
710 | 849 __ fld_d(vmarg); // load double to ST0 |
850 __ fstp_s(vmarg); // store single | |
851 } | |
852 #endif //_LP64 | |
853 | |
854 if (ek == _adapter_opt_d2f) { | |
855 remove_arg_slots(_masm, -stack_move_unit(), | |
856 rax_argslot, rbx_temp, rdx_temp); | |
857 } | |
858 | |
1846 | 859 __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); |
710 | 860 __ jump_to_method_handle_entry(rcx_recv, rdx_temp); |
861 } | |
862 break; | |
863 | |
864 case _adapter_prim_to_ref: | |
865 __ unimplemented(entry_name(ek)); // %%% FIXME: NYI | |
866 break; | |
867 | |
868 case _adapter_swap_args: | |
869 case _adapter_rot_args: | |
870 // handled completely by optimized cases | |
871 __ stop("init_AdapterMethodHandle should not issue this"); | |
872 break; | |
873 | |
874 case _adapter_opt_swap_1: | |
875 case _adapter_opt_swap_2: | |
876 case _adapter_opt_rot_1_up: | |
877 case _adapter_opt_rot_1_down: | |
878 case _adapter_opt_rot_2_up: | |
879 case _adapter_opt_rot_2_down: | |
880 { | |
1304 | 881 int swap_bytes = 0, rotate = 0; |
882 get_ek_adapter_opt_swap_rot_info(ek, swap_bytes, rotate); | |
710 | 883 |
884 // 'argslot' is the position of the first argument to swap | |
885 __ movl(rax_argslot, rcx_amh_vmargslot); | |
886 __ lea(rax_argslot, __ argument_address(rax_argslot)); | |
887 | |
888 // 'vminfo' is the second | |
889 Register rbx_destslot = rbx_temp; | |
890 __ movl(rbx_destslot, rcx_amh_conversion); | |
891 assert(CONV_VMINFO_SHIFT == 0, "preshifted"); | |
892 __ andl(rbx_destslot, CONV_VMINFO_MASK); | |
893 __ lea(rbx_destslot, __ argument_address(rbx_destslot)); | |
894 DEBUG_ONLY(verify_argslot(_masm, rbx_destslot, "swap point must fall within current frame")); | |
895 | |
896 if (!rotate) { | |
897 for (int i = 0; i < swap_bytes; i += wordSize) { | |
898 __ movptr(rdx_temp, Address(rax_argslot , i)); | |
899 __ push(rdx_temp); | |
900 __ movptr(rdx_temp, Address(rbx_destslot, i)); | |
901 __ movptr(Address(rax_argslot, i), rdx_temp); | |
902 __ pop(rdx_temp); | |
903 __ movptr(Address(rbx_destslot, i), rdx_temp); | |
904 } | |
905 } else { | |
906 // push the first chunk, which is going to get overwritten | |
907 for (int i = swap_bytes; (i -= wordSize) >= 0; ) { | |
908 __ movptr(rdx_temp, Address(rax_argslot, i)); | |
909 __ push(rdx_temp); | |
910 } | |
911 | |
912 if (rotate > 0) { | |
913 // rotate upward | |
914 __ subptr(rax_argslot, swap_bytes); | |
915 #ifdef ASSERT | |
916 { | |
917 // Verify that argslot > destslot, by at least swap_bytes. | |
918 Label L_ok; | |
919 __ cmpptr(rax_argslot, rbx_destslot); | |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
920 __ jccb(Assembler::aboveEqual, L_ok); |
710 | 921 __ stop("source must be above destination (upward rotation)"); |
922 __ bind(L_ok); | |
923 } | |
924 #endif | |
925 // work argslot down to destslot, copying contiguous data upwards | |
926 // pseudo-code: | |
927 // rax = src_addr - swap_bytes | |
928 // rbx = dest_addr | |
929 // while (rax >= rbx) *(rax + swap_bytes) = *(rax + 0), rax--; | |
930 Label loop; | |
931 __ bind(loop); | |
932 __ movptr(rdx_temp, Address(rax_argslot, 0)); | |
933 __ movptr(Address(rax_argslot, swap_bytes), rdx_temp); | |
934 __ addptr(rax_argslot, -wordSize); | |
935 __ cmpptr(rax_argslot, rbx_destslot); | |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
936 __ jccb(Assembler::aboveEqual, loop); |
710 | 937 } else { |
938 __ addptr(rax_argslot, swap_bytes); | |
939 #ifdef ASSERT | |
940 { | |
941 // Verify that argslot < destslot, by at least swap_bytes. | |
942 Label L_ok; | |
943 __ cmpptr(rax_argslot, rbx_destslot); | |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
944 __ jccb(Assembler::belowEqual, L_ok); |
710 | 945 __ stop("source must be below destination (downward rotation)"); |
946 __ bind(L_ok); | |
947 } | |
948 #endif | |
949 // work argslot up to destslot, copying contiguous data downwards | |
950 // pseudo-code: | |
951 // rax = src_addr + swap_bytes | |
952 // rbx = dest_addr | |
953 // while (rax <= rbx) *(rax - swap_bytes) = *(rax + 0), rax++; | |
954 Label loop; | |
955 __ bind(loop); | |
956 __ movptr(rdx_temp, Address(rax_argslot, 0)); | |
957 __ movptr(Address(rax_argslot, -swap_bytes), rdx_temp); | |
958 __ addptr(rax_argslot, wordSize); | |
959 __ cmpptr(rax_argslot, rbx_destslot); | |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
960 __ jccb(Assembler::belowEqual, loop); |
710 | 961 } |
962 | |
963 // pop the original first chunk into the destination slot, now free | |
964 for (int i = 0; i < swap_bytes; i += wordSize) { | |
965 __ pop(rdx_temp); | |
966 __ movptr(Address(rbx_destslot, i), rdx_temp); | |
967 } | |
968 } | |
969 | |
1846 | 970 __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); |
710 | 971 __ jump_to_method_handle_entry(rcx_recv, rdx_temp); |
972 } | |
973 break; | |
974 | |
975 case _adapter_dup_args: | |
976 { | |
977 // 'argslot' is the position of the first argument to duplicate | |
978 __ movl(rax_argslot, rcx_amh_vmargslot); | |
979 __ lea(rax_argslot, __ argument_address(rax_argslot)); | |
980 | |
981 // 'stack_move' is negative number of words to duplicate | |
982 Register rdx_stack_move = rdx_temp; | |
1293
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
983 __ movl2ptr(rdx_stack_move, rcx_amh_conversion); |
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
984 __ sarptr(rdx_stack_move, CONV_STACK_MOVE_SHIFT); |
710 | 985 |
986 int argslot0_num = 0; | |
987 Address argslot0 = __ argument_address(RegisterOrConstant(argslot0_num)); | |
988 assert(argslot0.base() == rsp, ""); | |
989 int pre_arg_size = argslot0.disp(); | |
990 assert(pre_arg_size % wordSize == 0, ""); | |
991 assert(pre_arg_size > 0, "must include PC"); | |
992 | |
993 // remember the old rsp+1 (argslot[0]) | |
994 Register rbx_oldarg = rbx_temp; | |
995 __ lea(rbx_oldarg, argslot0); | |
996 | |
997 // move rsp down to make room for dups | |
998 __ lea(rsp, Address(rsp, rdx_stack_move, Address::times_ptr)); | |
999 | |
1000 // compute the new rsp+1 (argslot[0]) | |
1001 Register rdx_newarg = rdx_temp; | |
1002 __ lea(rdx_newarg, argslot0); | |
1003 | |
1004 __ push(rdi); // need a temp | |
1005 // (preceding push must be done after arg addresses are taken!) | |
1006 | |
1007 // pull down the pre_arg_size data (PC) | |
1008 for (int i = -pre_arg_size; i < 0; i += wordSize) { | |
1009 __ movptr(rdi, Address(rbx_oldarg, i)); | |
1010 __ movptr(Address(rdx_newarg, i), rdi); | |
1011 } | |
1012 | |
1013 // copy from rax_argslot[0...] down to new_rsp[1...] | |
1014 // pseudo-code: | |
1015 // rbx = old_rsp+1 | |
1016 // rdx = new_rsp+1 | |
1017 // rax = argslot | |
1018 // while (rdx < rbx) *rdx++ = *rax++ | |
1019 Label loop; | |
1020 __ bind(loop); | |
1021 __ movptr(rdi, Address(rax_argslot, 0)); | |
1022 __ movptr(Address(rdx_newarg, 0), rdi); | |
1023 __ addptr(rax_argslot, wordSize); | |
1024 __ addptr(rdx_newarg, wordSize); | |
1025 __ cmpptr(rdx_newarg, rbx_oldarg); | |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
1026 __ jccb(Assembler::less, loop); |
710 | 1027 |
1028 __ pop(rdi); // restore temp | |
1029 | |
1846 | 1030 __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); |
710 | 1031 __ jump_to_method_handle_entry(rcx_recv, rdx_temp); |
1032 } | |
1033 break; | |
1034 | |
1035 case _adapter_drop_args: | |
1036 { | |
1037 // 'argslot' is the position of the first argument to nuke | |
1038 __ movl(rax_argslot, rcx_amh_vmargslot); | |
1039 __ lea(rax_argslot, __ argument_address(rax_argslot)); | |
1040 | |
1041 __ push(rdi); // need a temp | |
1042 // (must do previous push after argslot address is taken) | |
1043 | |
1044 // 'stack_move' is number of words to drop | |
1045 Register rdi_stack_move = rdi; | |
1293
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
1046 __ movl2ptr(rdi_stack_move, rcx_amh_conversion); |
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
1047 __ sarptr(rdi_stack_move, CONV_STACK_MOVE_SHIFT); |
710 | 1048 remove_arg_slots(_masm, rdi_stack_move, |
1049 rax_argslot, rbx_temp, rdx_temp); | |
1050 | |
1051 __ pop(rdi); // restore temp | |
1052 | |
1846 | 1053 __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); |
710 | 1054 __ jump_to_method_handle_entry(rcx_recv, rdx_temp); |
1055 } | |
1056 break; | |
1057 | |
1058 case _adapter_collect_args: | |
1059 __ unimplemented(entry_name(ek)); // %%% FIXME: NYI | |
1060 break; | |
1061 | |
1062 case _adapter_spread_args: | |
1063 // handled completely by optimized cases | |
1064 __ stop("init_AdapterMethodHandle should not issue this"); | |
1065 break; | |
1066 | |
1067 case _adapter_opt_spread_0: | |
1068 case _adapter_opt_spread_1: | |
1069 case _adapter_opt_spread_more: | |
1070 { | |
1071 // spread an array out into a group of arguments | |
1304 | 1072 int length_constant = get_ek_adapter_opt_spread_info(ek); |
710 | 1073 |
1074 // find the address of the array argument | |
1075 __ movl(rax_argslot, rcx_amh_vmargslot); | |
1076 __ lea(rax_argslot, __ argument_address(rax_argslot)); | |
1077 | |
1078 // grab some temps | |
1079 { __ push(rsi); __ push(rdi); } | |
1080 // (preceding pushes must be done after argslot address is taken!) | |
1081 #define UNPUSH_RSI_RDI \ | |
1082 { __ pop(rdi); __ pop(rsi); } | |
1083 | |
1084 // arx_argslot points both to the array and to the first output arg | |
1085 vmarg = Address(rax_argslot, 0); | |
1086 | |
1087 // Get the array value. | |
1088 Register rsi_array = rsi; | |
1089 Register rdx_array_klass = rdx_temp; | |
1090 BasicType elem_type = T_OBJECT; | |
1091 int length_offset = arrayOopDesc::length_offset_in_bytes(); | |
1092 int elem0_offset = arrayOopDesc::base_offset_in_bytes(elem_type); | |
1093 __ movptr(rsi_array, vmarg); | |
1094 Label skip_array_check; | |
1095 if (length_constant == 0) { | |
1096 __ testptr(rsi_array, rsi_array); | |
1097 __ jcc(Assembler::zero, skip_array_check); | |
1098 } | |
1099 __ null_check(rsi_array, oopDesc::klass_offset_in_bytes()); | |
1100 __ load_klass(rdx_array_klass, rsi_array); | |
1101 | |
1102 // Check the array type. | |
1103 Register rbx_klass = rbx_temp; | |
1846 | 1104 __ load_heap_oop(rbx_klass, rcx_amh_argument); // this is a Class object! |
1105 __ load_heap_oop(rbx_klass, Address(rbx_klass, java_lang_Class::klass_offset_in_bytes())); | |
710 | 1106 |
1107 Label ok_array_klass, bad_array_klass, bad_array_length; | |
1108 __ check_klass_subtype(rdx_array_klass, rbx_klass, rdi, ok_array_klass); | |
1109 // If we get here, the type check failed! | |
1110 __ jmp(bad_array_klass); | |
1111 __ bind(ok_array_klass); | |
1112 | |
1113 // Check length. | |
1114 if (length_constant >= 0) { | |
1115 __ cmpl(Address(rsi_array, length_offset), length_constant); | |
1116 } else { | |
1117 Register rbx_vminfo = rbx_temp; | |
1118 __ movl(rbx_vminfo, rcx_amh_conversion); | |
1119 assert(CONV_VMINFO_SHIFT == 0, "preshifted"); | |
1120 __ andl(rbx_vminfo, CONV_VMINFO_MASK); | |
1121 __ cmpl(rbx_vminfo, Address(rsi_array, length_offset)); | |
1122 } | |
1123 __ jcc(Assembler::notEqual, bad_array_length); | |
1124 | |
1125 Register rdx_argslot_limit = rdx_temp; | |
1126 | |
1127 // Array length checks out. Now insert any required stack slots. | |
1128 if (length_constant == -1) { | |
1129 // Form a pointer to the end of the affected region. | |
1506 | 1130 __ lea(rdx_argslot_limit, Address(rax_argslot, Interpreter::stackElementSize)); |
710 | 1131 // 'stack_move' is negative number of words to insert |
1132 Register rdi_stack_move = rdi; | |
1293
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
1133 __ movl2ptr(rdi_stack_move, rcx_amh_conversion); |
51db1e4b379d
6932536: JSR 292 modified JDK MethodHandlesTest fails on x86_64
twisti
parents:
1277
diff
changeset
|
1134 __ sarptr(rdi_stack_move, CONV_STACK_MOVE_SHIFT); |
710 | 1135 Register rsi_temp = rsi_array; // spill this |
1136 insert_arg_slots(_masm, rdi_stack_move, -1, | |
1137 rax_argslot, rbx_temp, rsi_temp); | |
1138 // reload the array (since rsi was killed) | |
1139 __ movptr(rsi_array, vmarg); | |
1140 } else if (length_constant > 1) { | |
1141 int arg_mask = 0; | |
1142 int new_slots = (length_constant - 1); | |
1143 for (int i = 0; i < new_slots; i++) { | |
1144 arg_mask <<= 1; | |
1145 arg_mask |= _INSERT_REF_MASK; | |
1146 } | |
1147 insert_arg_slots(_masm, new_slots * stack_move_unit(), arg_mask, | |
1148 rax_argslot, rbx_temp, rdx_temp); | |
1149 } else if (length_constant == 1) { | |
1150 // no stack resizing required | |
1151 } else if (length_constant == 0) { | |
1152 remove_arg_slots(_masm, -stack_move_unit(), | |
1153 rax_argslot, rbx_temp, rdx_temp); | |
1154 } | |
1155 | |
1156 // Copy from the array to the new slots. | |
1157 // Note: Stack change code preserves integrity of rax_argslot pointer. | |
1158 // So even after slot insertions, rax_argslot still points to first argument. | |
1159 if (length_constant == -1) { | |
1160 // [rax_argslot, rdx_argslot_limit) is the area we are inserting into. | |
1161 Register rsi_source = rsi_array; | |
1162 __ lea(rsi_source, Address(rsi_array, elem0_offset)); | |
1163 Label loop; | |
1164 __ bind(loop); | |
1165 __ movptr(rbx_temp, Address(rsi_source, 0)); | |
1166 __ movptr(Address(rax_argslot, 0), rbx_temp); | |
1167 __ addptr(rsi_source, type2aelembytes(elem_type)); | |
1506 | 1168 __ addptr(rax_argslot, Interpreter::stackElementSize); |
710 | 1169 __ cmpptr(rax_argslot, rdx_argslot_limit); |
1135
e66fd840cb6b
6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164)
twisti
parents:
1133
diff
changeset
|
1170 __ jccb(Assembler::less, loop); |
710 | 1171 } else if (length_constant == 0) { |
1172 __ bind(skip_array_check); | |
1173 // nothing to copy | |
1174 } else { | |
1175 int elem_offset = elem0_offset; | |
1176 int slot_offset = 0; | |
1177 for (int index = 0; index < length_constant; index++) { | |
1178 __ movptr(rbx_temp, Address(rsi_array, elem_offset)); | |
1179 __ movptr(Address(rax_argslot, slot_offset), rbx_temp); | |
1180 elem_offset += type2aelembytes(elem_type); | |
1506 | 1181 slot_offset += Interpreter::stackElementSize; |
710 | 1182 } |
1183 } | |
1184 | |
1185 // Arguments are spread. Move to next method handle. | |
1186 UNPUSH_RSI_RDI; | |
1846 | 1187 __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); |
710 | 1188 __ jump_to_method_handle_entry(rcx_recv, rdx_temp); |
1189 | |
1190 __ bind(bad_array_klass); | |
1191 UNPUSH_RSI_RDI; | |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
1192 __ pushptr(Address(rdx_array_klass, java_mirror_offset)); // required type |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
1193 __ pushptr(vmarg); // bad array |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
1194 __ push((int)Bytecodes::_aaload); // who is complaining? |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
1195 __ jump(ExternalAddress(from_interpreted_entry(_raise_exception))); |
710 | 1196 |
1197 __ bind(bad_array_length); | |
1198 UNPUSH_RSI_RDI; | |
1039
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
1199 __ push(rcx_recv); // AMH requiring a certain length |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
1200 __ pushptr(vmarg); // bad array |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
1201 __ push((int)Bytecodes::_arraylength); // who is complaining? |
987e948ebbc8
6815692: method handle code needs some cleanup (post-6655638)
jrose
parents:
845
diff
changeset
|
1202 __ jump(ExternalAddress(from_interpreted_entry(_raise_exception))); |
710 | 1203 |
1204 #undef UNPUSH_RSI_RDI | |
1205 } | |
1206 break; | |
1207 | |
1208 case _adapter_flyby: | |
1209 case _adapter_ricochet: | |
1210 __ unimplemented(entry_name(ek)); // %%% FIXME: NYI | |
1211 break; | |
1212 | |
1213 default: ShouldNotReachHere(); | |
1214 } | |
1215 __ hlt(); | |
1216 | |
1217 address me_cookie = MethodHandleEntry::start_compiled_entry(_masm, interp_entry); | |
1218 __ unimplemented(entry_name(ek)); // %%% FIXME: NYI | |
1219 | |
1220 init_entry(ek, MethodHandleEntry::finish_compiled_entry(_masm, me_cookie)); | |
1221 } |