src/share/vm/prims/methodHandleWalk.cpp

Mon, 04 Jan 2010 15:52:40 +0100

author
twisti
date
Mon, 04 Jan 2010 15:52:40 +0100
changeset 1568
aa62b9388fce
child 1573
dd57230ba8fe
permissions
-rw-r--r--

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

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

mercurial