Mercurial > hg > graal-jvmci-8
comparison src/share/vm/prims/methodHandleWalk.cpp @ 1133:aa62b9388fce
6894206: JVM needs a way to traverse method handle structures
Summary: We need a way to walk chained method handles in the JVM to call the right methods and to generate required bytecode adapters for the compilers.
Reviewed-by: kvn
author | twisti |
---|---|
date | Mon, 04 Jan 2010 15:52:40 +0100 |
parents | |
children | dd57230ba8fe |
comparison
equal
deleted
inserted
replaced
1131:40e7c1d24e4a | 1133:aa62b9388fce |
---|---|
1 /* | |
2 * Copyright 2008-2010 Sun Microsystems, Inc. All Rights Reserved. | |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
20 * CA 95054 USA or visit www.sun.com if you need additional information or | |
21 * have any questions. | |
22 * | |
23 */ | |
24 | |
25 /* | |
26 * JSR 292 reference implementation: method handle structure analysis | |
27 */ | |
28 | |
29 #include "incls/_precompiled.incl" | |
30 #include "incls/_methodHandleWalk.cpp.incl" | |
31 | |
32 void MethodHandleChain::set_method_handle(Handle mh, TRAPS) { | |
33 if (!java_dyn_MethodHandle::is_instance(mh())) lose("bad method handle", CHECK); | |
34 | |
35 // set current method handle and unpack partially | |
36 _method_handle = mh; | |
37 _is_last = false; | |
38 _is_bound = false; | |
39 _arg_slot = -1; | |
40 _arg_type = T_VOID; | |
41 _conversion = -1; | |
42 _last_invoke = Bytecodes::_nop; //arbitrary non-garbage | |
43 | |
44 if (sun_dyn_DirectMethodHandle::is_instance(mh())) { | |
45 set_last_method(mh(), THREAD); | |
46 return; | |
47 } | |
48 if (sun_dyn_AdapterMethodHandle::is_instance(mh())) { | |
49 _conversion = AdapterMethodHandle_conversion(); | |
50 assert(_conversion != -1, "bad conv value"); | |
51 assert(sun_dyn_BoundMethodHandle::is_instance(mh()), "also BMH"); | |
52 } | |
53 if (sun_dyn_BoundMethodHandle::is_instance(mh())) { | |
54 if (!is_adapter()) // keep AMH and BMH separate in this model | |
55 _is_bound = true; | |
56 _arg_slot = BoundMethodHandle_vmargslot(); | |
57 oop target = MethodHandle_vmtarget_oop(); | |
58 if (!is_bound() || java_dyn_MethodHandle::is_instance(target)) { | |
59 _arg_type = compute_bound_arg_type(target, NULL, _arg_slot, CHECK); | |
60 } else if (target != NULL && target->is_method()) { | |
61 _arg_type = compute_bound_arg_type(NULL, (methodOop)target, _arg_slot, CHECK); | |
62 set_last_method(mh(), CHECK); | |
63 } else { | |
64 _is_bound = false; // lose! | |
65 } | |
66 } | |
67 if (is_bound() && _arg_type == T_VOID) { | |
68 lose("bad vmargslot", CHECK); | |
69 } | |
70 if (!is_bound() && !is_adapter()) { | |
71 lose("unrecognized MH type", CHECK); | |
72 } | |
73 } | |
74 | |
75 void MethodHandleChain::set_last_method(oop target, TRAPS) { | |
76 _is_last = true; | |
77 klassOop receiver_limit_oop = NULL; | |
78 int flags = 0; | |
79 methodOop m = MethodHandles::decode_method(target, receiver_limit_oop, flags); | |
80 _last_method = methodHandle(THREAD, m); | |
81 if ((flags & MethodHandles::_dmf_has_receiver) == 0) | |
82 _last_invoke = Bytecodes::_invokestatic; | |
83 else if ((flags & MethodHandles::_dmf_does_dispatch) == 0) | |
84 _last_invoke = Bytecodes::_invokespecial; | |
85 else if ((flags & MethodHandles::_dmf_from_interface) != 0) | |
86 _last_invoke = Bytecodes::_invokeinterface; | |
87 else | |
88 _last_invoke = Bytecodes::_invokevirtual; | |
89 } | |
90 | |
91 BasicType MethodHandleChain::compute_bound_arg_type(oop target, methodOop m, int arg_slot, TRAPS) { | |
92 // There is no direct indication of whether the argument is primitive or not. | |
93 // It is implied by the _vmentry code, and by the MethodType of the target. | |
94 // FIXME: Make it explicit MethodHandleImpl refactors out from MethodHandle | |
95 BasicType arg_type = T_VOID; | |
96 if (target != NULL) { | |
97 oop mtype = java_dyn_MethodHandle::type(target); | |
98 int arg_num = MethodHandles::argument_slot_to_argnum(mtype, arg_slot); | |
99 if (arg_num >= 0) { | |
100 oop ptype = java_dyn_MethodType::ptype(mtype, arg_num); | |
101 arg_type = java_lang_Class::as_BasicType(ptype); | |
102 } | |
103 } else if (m != NULL) { | |
104 // figure out the argument type from the slot | |
105 // FIXME: make this explicit in the MH | |
106 int cur_slot = m->size_of_parameters(); | |
107 if (arg_slot >= cur_slot) | |
108 return T_VOID; | |
109 if (!m->is_static()) { | |
110 cur_slot -= type2size[T_OBJECT]; | |
111 if (cur_slot == arg_slot) | |
112 return T_OBJECT; | |
113 } | |
114 for (SignatureStream ss(m->signature()); !ss.is_done(); ss.next()) { | |
115 BasicType bt = ss.type(); | |
116 cur_slot -= type2size[bt]; | |
117 if (cur_slot <= arg_slot) { | |
118 if (cur_slot == arg_slot) | |
119 arg_type = bt; | |
120 break; | |
121 } | |
122 } | |
123 } | |
124 if (arg_type == T_ARRAY) | |
125 arg_type = T_OBJECT; | |
126 return arg_type; | |
127 } | |
128 | |
129 void MethodHandleChain::lose(const char* msg, TRAPS) { | |
130 _lose_message = msg; | |
131 if (!THREAD->is_Java_thread() || ((JavaThread*)THREAD)->thread_state() != _thread_in_vm) { | |
132 // throw a preallocated exception | |
133 THROW_OOP(Universe::virtual_machine_error_instance()); | |
134 } | |
135 THROW_MSG(vmSymbols::java_lang_InternalError(), msg); | |
136 } | |
137 | |
138 Bytecodes::Code MethodHandleWalker::conversion_code(BasicType src, BasicType dest) { | |
139 if (is_subword_type(src)) { | |
140 src = T_INT; // all subword src types act like int | |
141 } | |
142 if (src == dest) { | |
143 return Bytecodes::_nop; | |
144 } | |
145 | |
146 #define SRC_DEST(s,d) (((int)(s) << 4) + (int)(d)) | |
147 switch (SRC_DEST(src, dest)) { | |
148 case SRC_DEST(T_INT, T_LONG): return Bytecodes::_i2l; | |
149 case SRC_DEST(T_INT, T_FLOAT): return Bytecodes::_i2f; | |
150 case SRC_DEST(T_INT, T_DOUBLE): return Bytecodes::_i2d; | |
151 case SRC_DEST(T_INT, T_BYTE): return Bytecodes::_i2b; | |
152 case SRC_DEST(T_INT, T_CHAR): return Bytecodes::_i2c; | |
153 case SRC_DEST(T_INT, T_SHORT): return Bytecodes::_i2s; | |
154 | |
155 case SRC_DEST(T_LONG, T_INT): return Bytecodes::_l2i; | |
156 case SRC_DEST(T_LONG, T_FLOAT): return Bytecodes::_l2f; | |
157 case SRC_DEST(T_LONG, T_DOUBLE): return Bytecodes::_l2d; | |
158 | |
159 case SRC_DEST(T_FLOAT, T_INT): return Bytecodes::_f2i; | |
160 case SRC_DEST(T_FLOAT, T_LONG): return Bytecodes::_f2l; | |
161 case SRC_DEST(T_FLOAT, T_DOUBLE): return Bytecodes::_f2d; | |
162 | |
163 case SRC_DEST(T_DOUBLE, T_INT): return Bytecodes::_d2i; | |
164 case SRC_DEST(T_DOUBLE, T_LONG): return Bytecodes::_d2l; | |
165 case SRC_DEST(T_DOUBLE, T_FLOAT): return Bytecodes::_d2f; | |
166 } | |
167 #undef SRC_DEST | |
168 | |
169 // cannot do it in one step, or at all | |
170 return Bytecodes::_illegal; | |
171 } | |
172 | |
173 MethodHandleWalker::ArgToken | |
174 MethodHandleWalker::walk(TRAPS) { | |
175 walk_incoming_state(CHECK_NULL); | |
176 | |
177 for (;;) { | |
178 set_method_handle(chain().method_handle_oop()); | |
179 | |
180 assert(_outgoing_argc == argument_count_slow(), "empty slots under control"); | |
181 | |
182 if (chain().is_adapter()) { | |
183 int conv_op = chain().adapter_conversion_op(); | |
184 int arg_slot = chain().adapter_arg_slot(); | |
185 SlotState* arg_state = slot_state(arg_slot); | |
186 if (arg_state == NULL | |
187 && conv_op > sun_dyn_AdapterMethodHandle::OP_RETYPE_RAW) { | |
188 lose("bad argument index", CHECK_NULL); | |
189 } | |
190 | |
191 // perform the adapter action | |
192 switch (chain().adapter_conversion_op()) { | |
193 case sun_dyn_AdapterMethodHandle::OP_RETYPE_ONLY: | |
194 case sun_dyn_AdapterMethodHandle::OP_RETYPE_RAW: | |
195 // No changes to arguments; pass the bits through. | |
196 // The only difference between the two ops is that the "only" version | |
197 // is fully compatible with the verifier, while the "raw" version | |
198 // performs a few extra bitwise conversions (like long <-> double). | |
199 break; | |
200 | |
201 case sun_dyn_AdapterMethodHandle::OP_CHECK_CAST: { | |
202 // checkcast the Nth outgoing argument in place | |
203 klassOop dest_klass = NULL; | |
204 BasicType dest = java_lang_Class::as_BasicType(chain().adapter_arg_oop(), &dest_klass); | |
205 assert(dest == T_OBJECT, ""); | |
206 assert(dest == arg_state->_type, ""); | |
207 arg_state->_arg = make_conversion(T_OBJECT, dest_klass, Bytecodes::_checkcast, arg_state->_arg, CHECK_NULL); | |
208 debug_only(dest_klass = (klassOop)badOop); | |
209 break; | |
210 } | |
211 | |
212 case sun_dyn_AdapterMethodHandle::OP_PRIM_TO_PRIM: { | |
213 // i2l, etc., on the Nth outgoing argument in place | |
214 BasicType src = chain().adapter_conversion_src_type(), | |
215 dest = chain().adapter_conversion_dest_type(); | |
216 Bytecodes::Code bc = conversion_code(src, dest); | |
217 ArgToken arg = arg_state->_arg; | |
218 if (bc == Bytecodes::_nop) { | |
219 break; | |
220 } else if (bc != Bytecodes::_illegal) { | |
221 arg = make_conversion(dest, NULL, bc, arg, CHECK_NULL); | |
222 } else if (is_subword_type(dest)) { | |
223 bc = conversion_code(src, T_INT); | |
224 if (bc != Bytecodes::_illegal) { | |
225 arg = make_conversion(dest, NULL, bc, arg, CHECK_NULL); | |
226 bc = conversion_code(T_INT, dest); | |
227 arg = make_conversion(dest, NULL, bc, arg, CHECK_NULL); | |
228 } | |
229 } | |
230 if (bc == Bytecodes::_illegal) { | |
231 lose("bad primitive conversion", CHECK_NULL); | |
232 } | |
233 change_argument(src, arg_slot, dest, arg); | |
234 break; | |
235 } | |
236 | |
237 case sun_dyn_AdapterMethodHandle::OP_REF_TO_PRIM: { | |
238 // checkcast to wrapper type & call intValue, etc. | |
239 BasicType dest = chain().adapter_conversion_dest_type(); | |
240 ArgToken arg = arg_state->_arg; | |
241 arg = make_conversion(T_OBJECT, SystemDictionary::box_klass(dest), | |
242 Bytecodes::_checkcast, arg, CHECK_NULL); | |
243 vmIntrinsics::ID unboxer = vmIntrinsics::for_unboxing(dest); | |
244 if (unboxer == vmIntrinsics::_none) { | |
245 lose("no unboxing method", CHECK_NULL); | |
246 } | |
247 ArgToken arglist[2]; | |
248 arglist[0] = arg; // outgoing 'this' | |
249 arglist[1] = NULL; // sentinel | |
250 arg = make_invoke(NULL, unboxer, Bytecodes::_invokevirtual, false, 1, &arglist[0], CHECK_NULL); | |
251 change_argument(T_OBJECT, arg_slot, dest, arg); | |
252 break; | |
253 } | |
254 | |
255 case sun_dyn_AdapterMethodHandle::OP_PRIM_TO_REF: { | |
256 // call wrapper type.valueOf | |
257 BasicType src = chain().adapter_conversion_src_type(); | |
258 ArgToken arg = arg_state->_arg; | |
259 vmIntrinsics::ID boxer = vmIntrinsics::for_boxing(src); | |
260 if (boxer == vmIntrinsics::_none) { | |
261 lose("no boxing method", CHECK_NULL); | |
262 } | |
263 ArgToken arglist[2]; | |
264 arglist[0] = arg; // outgoing value | |
265 arglist[1] = NULL; // sentinel | |
266 arg = make_invoke(NULL, boxer, Bytecodes::_invokevirtual, false, 1, &arglist[0], CHECK_NULL); | |
267 change_argument(src, arg_slot, T_OBJECT, arg); | |
268 break; | |
269 } | |
270 | |
271 case sun_dyn_AdapterMethodHandle::OP_SWAP_ARGS: { | |
272 int dest_arg_slot = chain().adapter_conversion_vminfo(); | |
273 if (!slot_has_argument(dest_arg_slot)) { | |
274 lose("bad swap index", CHECK_NULL); | |
275 } | |
276 // a simple swap between two arguments | |
277 SlotState* dest_arg_state = slot_state(dest_arg_slot); | |
278 SlotState temp = (*dest_arg_state); | |
279 (*dest_arg_state) = (*arg_state); | |
280 (*arg_state) = temp; | |
281 break; | |
282 } | |
283 | |
284 case sun_dyn_AdapterMethodHandle::OP_ROT_ARGS: { | |
285 int dest_arg_slot = chain().adapter_conversion_vminfo(); | |
286 if (!slot_has_argument(dest_arg_slot) || arg_slot == dest_arg_slot) { | |
287 lose("bad rotate index", CHECK_NULL); | |
288 } | |
289 SlotState* dest_arg_state = slot_state(dest_arg_slot); | |
290 // Rotate the source argument (plus following N slots) into the | |
291 // position occupied by the dest argument (plus following N slots). | |
292 int rotate_count = type2size[dest_arg_state->_type]; | |
293 // (no other rotate counts are currently supported) | |
294 if (arg_slot < dest_arg_slot) { | |
295 for (int i = 0; i < rotate_count; i++) { | |
296 SlotState temp = _outgoing.at(arg_slot); | |
297 _outgoing.remove_at(arg_slot); | |
298 _outgoing.insert_before(dest_arg_slot + rotate_count - 1, temp); | |
299 } | |
300 } else { // arg_slot > dest_arg_slot | |
301 for (int i = 0; i < rotate_count; i++) { | |
302 SlotState temp = _outgoing.at(arg_slot + rotate_count - 1); | |
303 _outgoing.remove_at(arg_slot + rotate_count - 1); | |
304 _outgoing.insert_before(dest_arg_slot, temp); | |
305 } | |
306 } | |
307 break; | |
308 } | |
309 | |
310 case sun_dyn_AdapterMethodHandle::OP_DUP_ARGS: { | |
311 int dup_slots = chain().adapter_conversion_stack_pushes(); | |
312 if (dup_slots <= 0) { | |
313 lose("bad dup count", CHECK_NULL); | |
314 } | |
315 for (int i = 0; i < dup_slots; i++) { | |
316 SlotState* dup = slot_state(arg_slot + 2*i); | |
317 if (dup == NULL) break; // safety net | |
318 if (dup->_type != T_VOID) _outgoing_argc += 1; | |
319 _outgoing.insert_before(i, (*dup)); | |
320 } | |
321 break; | |
322 } | |
323 | |
324 case sun_dyn_AdapterMethodHandle::OP_DROP_ARGS: { | |
325 int drop_slots = -chain().adapter_conversion_stack_pushes(); | |
326 if (drop_slots <= 0) { | |
327 lose("bad drop count", CHECK_NULL); | |
328 } | |
329 for (int i = 0; i < drop_slots; i++) { | |
330 SlotState* drop = slot_state(arg_slot); | |
331 if (drop == NULL) break; // safety net | |
332 if (drop->_type != T_VOID) _outgoing_argc -= 1; | |
333 _outgoing.remove_at(arg_slot); | |
334 } | |
335 break; | |
336 } | |
337 | |
338 case sun_dyn_AdapterMethodHandle::OP_COLLECT_ARGS: { //NYI, may GC | |
339 lose("unimplemented", CHECK_NULL); | |
340 break; | |
341 } | |
342 | |
343 case sun_dyn_AdapterMethodHandle::OP_SPREAD_ARGS: { | |
344 klassOop array_klass_oop = NULL; | |
345 BasicType array_type = java_lang_Class::as_BasicType(chain().adapter_arg_oop(), | |
346 &array_klass_oop); | |
347 assert(array_type == T_OBJECT, ""); | |
348 assert(Klass::cast(array_klass_oop)->oop_is_array(), ""); | |
349 arrayKlassHandle array_klass(THREAD, array_klass_oop); | |
350 debug_only(array_klass_oop = (klassOop)badOop); | |
351 | |
352 klassOop element_klass_oop = NULL; | |
353 BasicType element_type = java_lang_Class::as_BasicType(array_klass->component_mirror(), | |
354 &element_klass_oop); | |
355 KlassHandle element_klass(THREAD, element_klass_oop); | |
356 debug_only(element_klass_oop = (klassOop)badOop); | |
357 | |
358 // Fetch the argument, which we will cast to the required array type. | |
359 assert(arg_state->_type == T_OBJECT, ""); | |
360 ArgToken array_arg = arg_state->_arg; | |
361 array_arg = make_conversion(T_OBJECT, array_klass(), Bytecodes::_checkcast, array_arg, CHECK_NULL); | |
362 change_argument(T_OBJECT, arg_slot, T_VOID, NULL); | |
363 | |
364 // Check the required length. | |
365 int spread_slots = 1 + chain().adapter_conversion_stack_pushes(); | |
366 int spread_length = spread_slots; | |
367 if (type2size[element_type] == 2) { | |
368 if (spread_slots % 2 != 0) spread_slots = -1; // force error | |
369 spread_length = spread_slots / 2; | |
370 } | |
371 if (spread_slots < 0) { | |
372 lose("bad spread length", CHECK_NULL); | |
373 } | |
374 | |
375 jvalue length_jvalue; length_jvalue.i = spread_length; | |
376 ArgToken length_arg = make_prim_constant(T_INT, &length_jvalue, CHECK_NULL); | |
377 // Call a built-in method known to the JVM to validate the length. | |
378 ArgToken arglist[3]; | |
379 arglist[0] = array_arg; // value to check | |
380 arglist[1] = length_arg; // length to check | |
381 arglist[2] = NULL; // sentinel | |
382 make_invoke(NULL, vmIntrinsics::_checkSpreadArgument, | |
383 Bytecodes::_invokestatic, false, 3, &arglist[0], CHECK_NULL); | |
384 | |
385 // Spread out the array elements. | |
386 Bytecodes::Code aload_op = Bytecodes::_aaload; | |
387 if (element_type != T_OBJECT) { | |
388 lose("primitive array NYI", CHECK_NULL); | |
389 } | |
390 int ap = arg_slot; | |
391 for (int i = 0; i < spread_length; i++) { | |
392 jvalue offset_jvalue; offset_jvalue.i = i; | |
393 ArgToken offset_arg = make_prim_constant(T_INT, &offset_jvalue, CHECK_NULL); | |
394 ArgToken element_arg = make_fetch(element_type, element_klass(), aload_op, array_arg, offset_arg, CHECK_NULL); | |
395 change_argument(T_VOID, ap, element_type, element_arg); | |
396 ap += type2size[element_type]; | |
397 } | |
398 break; | |
399 } | |
400 | |
401 case sun_dyn_AdapterMethodHandle::OP_FLYBY: //NYI, runs Java code | |
402 case sun_dyn_AdapterMethodHandle::OP_RICOCHET: //NYI, runs Java code | |
403 lose("unimplemented", CHECK_NULL); | |
404 break; | |
405 | |
406 default: | |
407 lose("bad adapter conversion", CHECK_NULL); | |
408 break; | |
409 } | |
410 } | |
411 | |
412 if (chain().is_bound()) { | |
413 // push a new argument | |
414 BasicType arg_type = chain().bound_arg_type(); | |
415 jint arg_slot = chain().bound_arg_slot(); | |
416 oop arg_oop = chain().bound_arg_oop(); | |
417 ArgToken arg = NULL; | |
418 if (arg_type == T_OBJECT) { | |
419 arg = make_oop_constant(arg_oop, CHECK_NULL); | |
420 } else { | |
421 jvalue arg_value; | |
422 BasicType bt = java_lang_boxing_object::get_value(arg_oop, &arg_value); | |
423 if (bt == arg_type) { | |
424 arg = make_prim_constant(arg_type, &arg_value, CHECK_NULL); | |
425 } else { | |
426 lose("bad bound value", CHECK_NULL); | |
427 } | |
428 } | |
429 debug_only(arg_oop = badOop); | |
430 change_argument(T_VOID, arg_slot, arg_type, arg); | |
431 } | |
432 | |
433 // this test must come after the body of the loop | |
434 if (!chain().is_last()) { | |
435 chain().next(CHECK_NULL); | |
436 } else { | |
437 break; | |
438 } | |
439 } | |
440 | |
441 // finish the sequence with a tail-call to the ultimate target | |
442 // parameters are passed in logical order (recv 1st), not slot order | |
443 ArgToken* arglist = NEW_RESOURCE_ARRAY(ArgToken, _outgoing.length() + 1); | |
444 int ap = 0; | |
445 for (int i = _outgoing.length() - 1; i >= 0; i--) { | |
446 SlotState* arg_state = slot_state(i); | |
447 if (arg_state->_type == T_VOID) continue; | |
448 arglist[ap++] = _outgoing.at(i)._arg; | |
449 } | |
450 assert(ap == _outgoing_argc, ""); | |
451 arglist[ap] = NULL; // add a sentinel, for the sake of asserts | |
452 return make_invoke(chain().last_method_oop(), | |
453 vmIntrinsics::_none, | |
454 chain().last_invoke_code(), true, | |
455 ap, arglist, THREAD); | |
456 } | |
457 | |
458 void MethodHandleWalker::walk_incoming_state(TRAPS) { | |
459 Handle mtype(THREAD, chain().method_type_oop()); | |
460 int nptypes = java_dyn_MethodType::ptype_count(mtype()); | |
461 _outgoing_argc = nptypes; | |
462 int argp = nptypes - 1; | |
463 if (argp >= 0) { | |
464 _outgoing.at_grow(argp, make_state(T_VOID, NULL)); // presize | |
465 } | |
466 for (int i = 0; i < nptypes; i++) { | |
467 klassOop arg_type_klass = NULL; | |
468 BasicType arg_type = java_lang_Class::as_BasicType( | |
469 java_dyn_MethodType::ptype(mtype(), i), &arg_type_klass); | |
470 ArgToken arg = make_parameter(arg_type, arg_type_klass, i, CHECK); | |
471 debug_only(arg_type_klass = (klassOop)NULL); | |
472 _outgoing.at_put(argp, make_state(arg_type, arg)); | |
473 if (type2size[arg_type] == 2) { | |
474 // add the extra slot, so we can model the JVM stack | |
475 _outgoing.insert_before(argp+1, make_state(T_VOID, NULL)); | |
476 } | |
477 --argp; | |
478 } | |
479 // call make_parameter at the end of the list for the return type | |
480 klassOop ret_type_klass = NULL; | |
481 BasicType ret_type = java_lang_Class::as_BasicType( | |
482 java_dyn_MethodType::rtype(mtype()), &ret_type_klass); | |
483 ArgToken ret = make_parameter(ret_type, ret_type_klass, -1, CHECK); | |
484 // ignore ret; client can catch it if needed | |
485 } | |
486 | |
487 // this is messy because some kinds of arguments are paired with | |
488 // companion slots containing an empty value | |
489 void MethodHandleWalker::change_argument(BasicType old_type, int slot, BasicType new_type, | |
490 MethodHandleWalker::ArgToken new_arg) { | |
491 int old_size = type2size[old_type]; | |
492 int new_size = type2size[new_type]; | |
493 if (old_size == new_size) { | |
494 // simple case first | |
495 _outgoing.at_put(slot, make_state(new_type, new_arg)); | |
496 } else if (old_size > new_size) { | |
497 for (int i = old_size-1; i >= new_size; i++) { | |
498 assert((i != 0) == (_outgoing.at(slot + i)._type == T_VOID), ""); | |
499 _outgoing.remove_at(slot + i); | |
500 } | |
501 if (new_size > 0) | |
502 _outgoing.at_put(slot, make_state(new_type, new_arg)); | |
503 else | |
504 _outgoing_argc -= 1; // deleted a real argument | |
505 } else { | |
506 for (int i = old_size; i < new_size; i++) { | |
507 _outgoing.insert_before(slot+i, make_state(T_VOID, NULL)); | |
508 } | |
509 _outgoing.at_put(slot, make_state(new_type, new_arg)); | |
510 if (old_size == 0) | |
511 _outgoing_argc += 1; // inserted a real argument | |
512 } | |
513 } | |
514 | |
515 | |
516 #ifdef ASSERT | |
517 int MethodHandleWalker::argument_count_slow() { | |
518 int args_seen = 0; | |
519 for (int i = _outgoing.length() - 1; i >= 0; i--) { | |
520 if (_outgoing.at(i)._type != T_VOID) { | |
521 ++args_seen; | |
522 } | |
523 } | |
524 return args_seen; | |
525 } | |
526 #endif | |
527 | |
528 | |
529 void MethodHandleCompiler::compile(TRAPS) { | |
530 assert(_thread == THREAD, "must be same thread"); | |
531 | |
532 _constant_oops.append(Handle()); // element zero is always the null constant | |
533 _constant_prims.append(NULL); | |
534 { | |
535 symbolOop sig | |
536 = java_dyn_MethodType::as_signature(chain().method_type_oop(), true, CHECK); | |
537 _signature_index = find_oop_constant(sig); | |
538 assert(signature() == sig, ""); | |
539 } | |
540 | |
541 walk(CHECK); | |
542 } | |
543 | |
544 MethodHandleWalker::ArgToken | |
545 MethodHandleCompiler::make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, | |
546 MethodHandleWalker::ArgToken src, TRAPS) { | |
547 Unimplemented(); | |
548 return NULL; | |
549 } | |
550 | |
551 MethodHandleWalker::ArgToken | |
552 MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid, | |
553 Bytecodes::Code op, bool tailcall, | |
554 int argc, MethodHandleWalker::ArgToken* argv, | |
555 TRAPS) { | |
556 // If tailcall, we have walked all the way to a direct method handle. | |
557 // Otherwise, make a recursive call to some helper routine. | |
558 #ifdef ASSERT | |
559 switch (op) { | |
560 case Bytecodes::_invokevirtual: | |
561 case Bytecodes::_invokespecial: | |
562 case Bytecodes::_invokestatic: | |
563 case Bytecodes::_invokeinterface: | |
564 break; | |
565 default: | |
566 ShouldNotReachHere(); | |
567 } | |
568 #endif //ASSERT | |
569 _bytes.put((char) op); | |
570 | |
571 Unimplemented(); | |
572 return NULL; | |
573 } | |
574 | |
575 MethodHandleWalker::ArgToken | |
576 MethodHandleCompiler::make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, | |
577 MethodHandleWalker::ArgToken base, | |
578 MethodHandleWalker::ArgToken offset, | |
579 TRAPS) { | |
580 Unimplemented(); | |
581 return NULL; | |
582 } | |
583 | |
584 int MethodHandleCompiler::find_oop_constant(oop con) { | |
585 if (con == NULL) return 0; | |
586 for (int i = 1, imax = _constant_oops.length(); i < imax; i++) { | |
587 if (_constant_oops.at(i) == con) | |
588 return i; | |
589 } | |
590 _constant_prims.append(NULL); | |
591 return _constant_oops.append(con); | |
592 } | |
593 | |
594 int MethodHandleCompiler::find_prim_constant(BasicType bt, jvalue* con) { | |
595 jvalue con_copy; | |
596 assert(bt < T_OBJECT, ""); | |
597 if (type2aelembytes(bt) < jintSize) { | |
598 // widen to int | |
599 con_copy = (*con); | |
600 con = &con_copy; | |
601 switch (bt) { | |
602 case T_BOOLEAN: con->i = (con->z ? 1 : 0); break; | |
603 case T_BYTE: con->i = con->b; break; | |
604 case T_CHAR: con->i = con->c; break; | |
605 case T_SHORT: con->i = con->s; break; | |
606 default: ShouldNotReachHere(); | |
607 } | |
608 bt = T_INT; | |
609 } | |
610 for (int i = 1, imax = _constant_prims.length(); i < imax; i++) { | |
611 PrimCon* pcon = _constant_prims.at(i); | |
612 if (pcon != NULL && pcon->_type == bt) { | |
613 bool match = false; | |
614 switch (type2size[bt]) { | |
615 case 1: if (pcon->_value.i == con->i) match = true; break; | |
616 case 2: if (pcon->_value.j == con->j) match = true; break; | |
617 } | |
618 if (match) | |
619 return i; | |
620 } | |
621 } | |
622 PrimCon* pcon = new PrimCon(); | |
623 pcon->_type = bt; | |
624 pcon->_value = (*con); | |
625 _constant_oops.append(Handle()); | |
626 return _constant_prims.append(pcon); | |
627 } | |
628 | |
629 | |
630 #ifndef PRODUCT | |
631 | |
632 // MH printer for debugging. | |
633 | |
634 class MethodHandlePrinter : public MethodHandleWalker { | |
635 private: | |
636 outputStream* _out; | |
637 bool _verbose; | |
638 int _temp_num; | |
639 stringStream _strbuf; | |
640 const char* strbuf() { | |
641 const char* s = _strbuf.as_string(); | |
642 _strbuf.reset(); | |
643 return s; | |
644 } | |
645 ArgToken token(const char* str) { | |
646 return (ArgToken) str; | |
647 } | |
648 void start_params() { | |
649 _out->print("("); | |
650 } | |
651 void end_params() { | |
652 if (_verbose) _out->print("\n"); | |
653 _out->print(") => {"); | |
654 } | |
655 void put_type_name(BasicType type, klassOop tk, outputStream* s) { | |
656 const char* kname = NULL; | |
657 if (tk != NULL) | |
658 kname = Klass::cast(tk)->external_name(); | |
659 s->print("%s", (kname != NULL) ? kname : type2name(type)); | |
660 } | |
661 ArgToken maybe_make_temp(const char* statement_op, BasicType type, const char* temp_name) { | |
662 const char* value = strbuf(); | |
663 if (!_verbose) return token(value); | |
664 // make an explicit binding for each separate value | |
665 _strbuf.print("%s%d", temp_name, ++_temp_num); | |
666 const char* temp = strbuf(); | |
667 _out->print("\n %s %s %s = %s;", statement_op, type2name(type), temp, value); | |
668 return token(temp); | |
669 } | |
670 | |
671 public: | |
672 MethodHandlePrinter(Handle root, bool verbose, outputStream* out, TRAPS) | |
673 : MethodHandleWalker(root, THREAD), | |
674 _out(out), | |
675 _verbose(verbose), | |
676 _temp_num(0) | |
677 { | |
678 start_params(); | |
679 } | |
680 virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) { | |
681 if (argnum < 0) { | |
682 end_params(); | |
683 return NULL; | |
684 } | |
685 if (argnum == 0) { | |
686 _out->print(_verbose ? "\n " : ""); | |
687 } else { | |
688 _out->print(_verbose ? ",\n " : ", "); | |
689 } | |
690 if (argnum >= _temp_num) | |
691 _temp_num = argnum; | |
692 // generate an argument name | |
693 _strbuf.print("a%d", argnum); | |
694 const char* arg = strbuf(); | |
695 put_type_name(type, tk, _out); | |
696 _out->print(" %s", arg); | |
697 return token(arg); | |
698 } | |
699 virtual ArgToken make_oop_constant(oop con, TRAPS) { | |
700 if (con == NULL) | |
701 _strbuf.print("null"); | |
702 else | |
703 con->print_value_on(&_strbuf); | |
704 if (_strbuf.size() == 0) { // yuck | |
705 _strbuf.print("(a "); | |
706 put_type_name(T_OBJECT, con->klass(), &_strbuf); | |
707 _strbuf.print(")"); | |
708 } | |
709 return maybe_make_temp("constant", T_OBJECT, "k"); | |
710 } | |
711 virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) { | |
712 java_lang_boxing_object::print(type, con, &_strbuf); | |
713 return maybe_make_temp("constant", type, "k"); | |
714 } | |
715 virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, ArgToken src, TRAPS) { | |
716 _strbuf.print("%s(%s", Bytecodes::name(op), (const char*)src); | |
717 if (tk != NULL) { | |
718 _strbuf.print(", "); | |
719 put_type_name(type, tk, &_strbuf); | |
720 } | |
721 _strbuf.print(")"); | |
722 return maybe_make_temp("convert", type, "v"); | |
723 } | |
724 virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, ArgToken base, ArgToken offset, TRAPS) { | |
725 _strbuf.print("%s(%s, %s", Bytecodes::name(op), (const char*)base, (const char*)offset); | |
726 if (tk != NULL) { | |
727 _strbuf.print(", "); | |
728 put_type_name(type, tk, &_strbuf); | |
729 } | |
730 _strbuf.print(")"); | |
731 return maybe_make_temp("fetch", type, "x"); | |
732 } | |
733 virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, | |
734 Bytecodes::Code op, bool tailcall, | |
735 int argc, ArgToken* argv, TRAPS) { | |
736 symbolOop name, sig; | |
737 if (m != NULL) { | |
738 name = m->name(); | |
739 sig = m->signature(); | |
740 } else { | |
741 name = vmSymbols::symbol_at(vmIntrinsics::name_for(iid)); | |
742 sig = vmSymbols::symbol_at(vmIntrinsics::signature_for(iid)); | |
743 } | |
744 _strbuf.print("%s %s%s(", Bytecodes::name(op), name->as_C_string(), sig->as_C_string()); | |
745 for (int i = 0; i < argc; i++) { | |
746 _strbuf.print("%s%s", (i > 0 ? ", " : ""), (const char*)argv[i]); | |
747 } | |
748 _strbuf.print(")"); | |
749 if (!tailcall) { | |
750 BasicType rt = char2type(sig->byte_at(sig->utf8_length()-1)); | |
751 if (rt == T_ILLEGAL) rt = T_OBJECT; // ';' at the end of '(...)L...;' | |
752 return maybe_make_temp("invoke", rt, "x"); | |
753 } else { | |
754 const char* ret = strbuf(); | |
755 _out->print(_verbose ? "\n return " : " "); | |
756 _out->print("%s", ret); | |
757 _out->print(_verbose ? "\n}\n" : " }"); | |
758 } | |
759 return ArgToken(); | |
760 } | |
761 | |
762 virtual void set_method_handle(oop mh) { | |
763 if (WizardMode && Verbose) { | |
764 tty->print("\n--- next target: "); | |
765 mh->print(); | |
766 } | |
767 } | |
768 | |
769 static void print(Handle root, bool verbose, outputStream* out, TRAPS) { | |
770 ResourceMark rm; | |
771 MethodHandlePrinter printer(root, verbose, out, CHECK); | |
772 printer.walk(CHECK); | |
773 out->print("\n"); | |
774 } | |
775 static void print(Handle root, bool verbose = Verbose, outputStream* out = tty) { | |
776 EXCEPTION_MARK; | |
777 ResourceMark rm; | |
778 MethodHandlePrinter printer(root, verbose, out, THREAD); | |
779 if (!HAS_PENDING_EXCEPTION) | |
780 printer.walk(THREAD); | |
781 if (HAS_PENDING_EXCEPTION) { | |
782 oop ex = PENDING_EXCEPTION; | |
783 CLEAR_PENDING_EXCEPTION; | |
784 out->print("\n*** "); | |
785 if (ex != Universe::virtual_machine_error_instance()) | |
786 ex->print_on(out); | |
787 else | |
788 out->print("lose: %s", printer.lose_message()); | |
789 out->print("\n}\n"); | |
790 } | |
791 out->print("\n"); | |
792 } | |
793 }; | |
794 | |
795 extern "C" | |
796 void print_method_handle(oop mh) { | |
797 if (java_dyn_MethodHandle::is_instance(mh)) { | |
798 MethodHandlePrinter::print(mh); | |
799 } else { | |
800 tty->print("*** not a method handle: "); | |
801 mh->print(); | |
802 } | |
803 } | |
804 | |
805 #endif // PRODUCT |