--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/meth-6655638.03.patch Tue Apr 07 01:55:20 2009 -0700
@@ -0,0 +1,2554 @@
+diff --git a/src/cpu/x86/vm/methodHandles_x86.cpp b/src/cpu/x86/vm/methodHandles_x86.cpp
+--- a/src/cpu/x86/vm/methodHandles_x86.cpp
++++ b/src/cpu/x86/vm/methodHandles_x86.cpp
+@@ -29,6 +29,9 @@
+
+ address MethodHandleEntry::start_compiled_entry(MacroAssembler* _masm,
+ address interpreted_entry) {
++ // Just before the actual machine code entry point, allocate space
++ // for a MethodHandleEntry::Data record, so that we can manage everything
++ // from one base pointer.
+ __ align(wordSize);
+ address target = __ pc() + sizeof(Data);
+ while (__ pc() < target) {
+@@ -98,7 +101,7 @@
+ // fetch the MethodType from the method handle into rax (the 'check' register)
+ {
+ Register tem = rbx_method;
+- for (int* pchase = methodOopDesc::method_type_offsets_chain(); (*pchase) != -1; pchase++) {
++ for (jint* pchase = methodOopDesc::method_type_offsets_chain(); (*pchase) != -1; pchase++) {
+ __ movptr(rax_mtype, Address(tem, *pchase));
+ tem = rax_mtype; // in case there is another indirection
+ }
+@@ -121,30 +124,18 @@
+ // Helper to insert argument slots into the stack.
+ // arg_slots must be a multiple of stack_move_unit() and <= 0
+ void MethodHandles::insert_arg_slots(MacroAssembler* _masm,
+- RegisterOrConstant arg_slots,
+- int arg_mask,
+- Register rax_argslot,
+- Register rbx_temp, Register rdx_temp) {
++ RegisterOrConstant arg_slots,
++ int arg_mask,
++ Register rax_argslot,
++ Register rbx_temp, Register rdx_temp) {
+ assert_different_registers(rax_argslot, rbx_temp, rdx_temp,
+ (!arg_slots.is_register() ? rsp : arg_slots.as_register()));
+
+- int constant_arg_slots = 0;
+- if (arg_slots.is_constant()) {
+- constant_arg_slots = arg_slots.as_constant() / stack_move_unit();
+- } else {
+- assert(arg_mask == _INSERT_NO_MASK,
+- "cannot specify arg_mask with non-constant slot count");
+-#ifdef _LP64
+- // clean high bits of stack motion register (was loaded as an int)
+- __ movslq(arg_slots.as_register(), arg_slots.as_register());
+-#endif
+- }
+-
+ #ifdef ASSERT
+ verify_argslot(_masm, rax_argslot, "insertion point must fall within current frame");
+ if (arg_slots.is_register()) {
+ Label L_ok, L_bad;
+- __ cmpptr(arg_slots.as_register(), (int32_t) NULL_WORD);
++ __ cmpptr(arg_slots.as_register(), NULL_WORD);
+ __ jcc(Assembler::greater, L_bad);
+ __ testl(arg_slots.as_register(), -stack_move_unit() - 1);
+ __ jcc(Assembler::zero, L_ok);
+@@ -157,6 +148,13 @@
+ }
+ #endif //ASSERT
+
++#ifdef _LP64
++ if (arg_slots.is_register()) {
++ // clean high bits of stack motion register (was loaded as an int)
++ __ movslq(arg_slots.as_register(), arg_slots.as_register());
++ }
++#endif
++
+ // Make space on the stack for the inserted argument(s).
+ // Then pull down everything shallower than rax_argslot.
+ // The stacked return address gets pulled down with everything else.
+@@ -181,7 +179,10 @@
+ // Now move the argslot down, to point to the opened-up space.
+ __ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr));
+
+- if (TaggedStackInterpreter) {
++ if (TaggedStackInterpreter && arg_mask != _INSERT_NO_MASK) {
++ // The caller has specified a bitmask of tags to put into the opened space.
++ // This only works when the arg_slots value is an assembly-time constant.
++ int constant_arg_slots = arg_slots.as_constant() / stack_move_unit();
+ int tag_offset = Interpreter::tag_offset_in_bytes() - Interpreter::value_offset_in_bytes();
+ for (int slot = 0; slot < constant_arg_slots; slot++) {
+ BasicType slot_type = ((arg_mask & (1 << slot)) == 0 ? T_OBJECT : T_INT);
+@@ -219,7 +220,7 @@
+ }
+ if (arg_slots.is_register()) {
+ Label L_ok, L_bad;
+- __ cmpptr(arg_slots.as_register(), (int32_t) NULL_WORD);
++ __ cmpptr(arg_slots.as_register(), NULL_WORD);
+ __ jcc(Assembler::less, L_bad);
+ __ testl(arg_slots.as_register(), -stack_move_unit() - 1);
+ __ jcc(Assembler::zero, L_ok);
+@@ -272,7 +273,7 @@
+ intptr_t* entry_sp,
+ intptr_t* saved_sp) {
+ // called as a leaf from native code: do not block the JVM!
+- printf("MH %s %p %p %d\n", adaptername, mh, entry_sp, entry_sp - saved_sp);
++ printf("MH %s "PTR_FORMAT" "PTR_FORMAT" "INTX_FORMAT"\n", adaptername, mh, entry_sp, entry_sp - saved_sp);
+ }
+ #endif //PRODUCT
+
+@@ -283,7 +284,7 @@
+ // as set up by generate_method_handle_interpreter_entry():
+ // - rbx: garbage temp (was MethodHandle.invoke methodOop, unused)
+ // - rcx: receiver method handle
+- // - rax: method handle type (already checked at call site, then unused)
++ // - rax: method handle type (only used by the check_mtype entry point)
+ // - rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted)
+ // - rdx: garbage temp, can blow away
+
+@@ -322,10 +323,6 @@
+ address interp_entry = __ pc();
+ if (UseCompressedOops) __ unimplemented("UseCompressedOops");
+
+- AdapterKind ak = _adapt_retype_only;
+- if ((int)ek > (int)_adapter_mh_first)
+- ak = AdapterKind((int)ek - (int)_adapter_mh_first);
+-
+ #ifndef PRODUCT
+ if (TraceMethodHandles) {
+ __ push(rax); __ push(rbx); __ push(rcx); __ push(rdx); __ push(rsi); __ push(rdi);
+@@ -409,7 +406,7 @@
+
+ // get receiver klass
+ Register rax_klass = rax_argslot;
+- __ movl(rax_klass, Address(rcx_recv, oopDesc::klass_offset_in_bytes()));
++ __ load_klass(rax_klass, rcx_recv);
+ __ verify_oop(rax_klass);
+
+ // get target methodOop & entry point
+@@ -442,7 +439,7 @@
+
+ // get receiver klass
+ Register rax_klass = rax_argslot;
+- __ movl(rax_klass, Address(rcx_recv, oopDesc::klass_offset_in_bytes()));
++ __ load_klass(rax_klass, rcx_recv);
+ __ verify_oop(rax_klass);
+
+ Register rcx_temp = rcx_recv;
+@@ -526,7 +523,7 @@
+ }
+ break;
+
+- case _adapter_mh_first+_adapt_retype_only:
++ case _adapter_retype_only:
+ // immediately jump to the next MH layer:
+ __ movptr(rcx_recv, rcx_mh_vmtarget);
+ __ verify_oop(rcx_recv);
+@@ -535,7 +532,7 @@
+ // It is also OK when a return type narrows.
+ break;
+
+- case _adapter_mh_first+_adapt_check_cast:
++ case _adapter_check_cast:
+ {
+ // temps:
+ Register rbx_klass = rbx_temp; // interesting AMH data
+@@ -556,7 +553,7 @@
+ __ movptr(rdx_temp, vmarg);
+ __ testl(rdx_temp, rdx_temp);
+ __ jcc(Assembler::zero, done); // no cast if null
+- __ movl(rdx_temp, Address(rdx_temp, oopDesc::klass_offset_in_bytes()));
++ __ load_klass(rdx_temp, rdx_temp);
+
+ // live at this point:
+ // - rbx_klass: klass required by the target method
+@@ -576,8 +573,8 @@
+ }
+ break;
+
+- case _adapter_mh_first+_adapt_prim_to_prim:
+- case _adapter_mh_first+_adapt_ref_to_prim:
++ case _adapter_prim_to_prim:
++ case _adapter_ref_to_prim:
+ // handled completely by optimized cases
+ __ stop("init_AdapterMethodHandle should not issue this");
+ break;
+@@ -585,7 +582,7 @@
+ case _adapter_opt_i2i: // optimized subcase of adapt_prim_to_prim
+ //case _adapter_opt_f2i: // optimized subcase of adapt_prim_to_prim
+ case _adapter_opt_l2i: // optimized subcase of adapt_prim_to_prim
+- case _adapter_opt_a2i: // optimized subcase of adapt_ref_to_prim
++ case _adapter_opt_unboxi: // optimized subcase of adapt_ref_to_prim
+ {
+ // perform an in-place conversion to int or an int subword
+ __ movl(rax_argslot, rcx_amh_vmargslot);
+@@ -605,7 +602,7 @@
+ __ movl(rdx_temp, vmarg);
+ }
+ break;
+- case _adapter_opt_a2i:
++ case _adapter_opt_unboxi:
+ {
+ // Load the value up from the heap.
+ __ movptr(rdx_temp, vmarg);
+@@ -633,7 +630,7 @@
+ {
+ Register rbx_vminfo = rbx_temp;
+ __ movl(rbx_vminfo, rcx_amh_conversion);
+- assert(_CONV_VMINFO_SHIFT == 0, "preshifted");
++ assert(CONV_VMINFO_SHIFT == 0, "preshifted");
+
+ // get the new MH:
+ __ movptr(rcx_recv, rcx_mh_vmtarget);
+@@ -644,7 +641,7 @@
+ __ xchgl(rcx, rbx_vminfo); // free rcx for shifts
+ __ shll(rdx_temp /*, rcx*/);
+ Label zero_extend, done;
+- __ testl(rcx, _CONV_VMINFO_SIGN_FLAG);
++ __ testl(rcx, CONV_VMINFO_SIGN_FLAG);
+ __ jcc(Assembler::zero, zero_extend);
+
+ // this path is taken for int->byte, int->short
+@@ -664,7 +661,7 @@
+ break;
+
+ case _adapter_opt_i2l: // optimized subcase of adapt_prim_to_prim
+- case _adapter_opt_a2l: // optimized subcase of adapt_ref_to_prim
++ case _adapter_opt_unboxl: // optimized subcase of adapt_ref_to_prim
+ {
+ // perform an in-place int-to-long or ref-to-long conversion
+ __ movl(rax_argslot, rcx_amh_vmargslot);
+@@ -684,7 +681,7 @@
+ __ movl(vmarg2, rdx_temp); // store second word
+ }
+ break;
+- case _adapter_opt_a2l:
++ case _adapter_opt_unboxl:
+ {
+ // Load the value up from the heap.
+ __ movptr(rdx_temp, vmarg1);
+@@ -759,12 +756,12 @@
+ }
+ break;
+
+- case _adapter_mh_first+_adapt_prim_to_ref:
++ case _adapter_prim_to_ref:
+ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
+ break;
+
+- case _adapter_mh_first+_adapt_swap_args:
+- case _adapter_mh_first+_adapt_rot_args:
++ case _adapter_swap_args:
++ case _adapter_rot_args:
+ // handled completely by optimized cases
+ __ stop("init_AdapterMethodHandle should not issue this");
+ break;
+@@ -797,8 +794,8 @@
+ // 'vminfo' is the second
+ Register rbx_destslot = rbx_temp;
+ __ movl(rbx_destslot, rcx_amh_conversion);
+- assert(_CONV_VMINFO_SHIFT == 0, "preshifted");
+- __ andl(rbx_destslot, _CONV_VMINFO_MASK);
++ assert(CONV_VMINFO_SHIFT == 0, "preshifted");
++ __ andl(rbx_destslot, CONV_VMINFO_MASK);
+ __ lea(rbx_destslot, __ argument_address(rbx_destslot));
+ DEBUG_ONLY(verify_argslot(_masm, rbx_destslot, "swap point must fall within current frame"));
+
+@@ -881,7 +878,7 @@
+ }
+ break;
+
+- case _adapter_mh_first+_adapt_dup_args:
++ case _adapter_dup_args:
+ {
+ // 'argslot' is the position of the first argument to duplicate
+ __ movl(rax_argslot, rcx_amh_vmargslot);
+@@ -890,7 +887,7 @@
+ // 'stack_move' is negative number of words to duplicate
+ Register rdx_stack_move = rdx_temp;
+ __ movl(rdx_stack_move, rcx_amh_conversion);
+- __ sarl(rdx_stack_move, _CONV_STACK_MOVE_SHIFT);
++ __ sarl(rdx_stack_move, CONV_STACK_MOVE_SHIFT);
+
+ int argslot0_num = 0;
+ Address argslot0 = __ argument_address(RegisterOrConstant(argslot0_num));
+@@ -941,7 +938,7 @@
+ }
+ break;
+
+- case _adapter_mh_first+_adapt_drop_args:
++ case _adapter_drop_args:
+ {
+ // 'argslot' is the position of the first argument to nuke
+ __ movl(rax_argslot, rcx_amh_vmargslot);
+@@ -953,7 +950,7 @@
+ // 'stack_move' is number of words to drop
+ Register rdi_stack_move = rdi;
+ __ movl(rdi_stack_move, rcx_amh_conversion);
+- __ sarl(rdi_stack_move, _CONV_STACK_MOVE_SHIFT);
++ __ sarl(rdi_stack_move, CONV_STACK_MOVE_SHIFT);
+ remove_arg_slots(_masm, rdi_stack_move,
+ rax_argslot, rbx_temp, rdx_temp);
+
+@@ -964,24 +961,24 @@
+ }
+ break;
+
+- case _adapter_mh_first+_adapt_collect_args:
++ case _adapter_collect_args:
+ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
+ break;
+
+- case _adapter_mh_first+_adapt_spread_args:
++ case _adapter_spread_args:
+ // handled completely by optimized cases
+ __ stop("init_AdapterMethodHandle should not issue this");
+ break;
+
+- case _adapt_opt_spread_0:
+- case _adapt_opt_spread_1:
+- case _adapt_opt_spread_more:
++ case _adapter_opt_spread_0:
++ case _adapter_opt_spread_1:
++ case _adapter_opt_spread_more:
+ {
+ // spread an array out into a group of arguments
+ int length_constant = -1;
+ switch (ek) {
+- case _adapt_opt_spread_0: length_constant = 0; break;
+- case _adapt_opt_spread_1: length_constant = 1; break;
++ case _adapter_opt_spread_0: length_constant = 0; break;
++ case _adapter_opt_spread_1: length_constant = 1; break;
+ }
+
+ // find the address of the array argument
+@@ -1010,7 +1007,7 @@
+ __ jcc(Assembler::zero, skip_array_check);
+ }
+ __ null_check(rsi_array, oopDesc::klass_offset_in_bytes());
+- __ movl(rdx_array_klass, Address(rsi_array, oopDesc::klass_offset_in_bytes()));
++ __ load_klass(rdx_array_klass, rsi_array);
+
+ // Check the array type.
+ Register rbx_klass = rbx_temp;
+@@ -1029,8 +1026,8 @@
+ } else {
+ Register rbx_vminfo = rbx_temp;
+ __ movl(rbx_vminfo, rcx_amh_conversion);
+- assert(_CONV_VMINFO_SHIFT == 0, "preshifted");
+- __ andl(rbx_vminfo, _CONV_VMINFO_MASK);
++ assert(CONV_VMINFO_SHIFT == 0, "preshifted");
++ __ andl(rbx_vminfo, CONV_VMINFO_MASK);
+ __ cmpl(rbx_vminfo, Address(rsi_array, length_offset));
+ }
+ __ jcc(Assembler::notEqual, bad_array_length);
+@@ -1044,7 +1041,7 @@
+ // 'stack_move' is negative number of words to insert
+ Register rdi_stack_move = rdi;
+ __ movl(rdi_stack_move, rcx_amh_conversion);
+- __ sarl(rdi_stack_move, _CONV_STACK_MOVE_SHIFT);
++ __ sarl(rdi_stack_move, CONV_STACK_MOVE_SHIFT);
+ Register rsi_temp = rsi_array; // spill this
+ insert_arg_slots(_masm, rdi_stack_move, -1,
+ rax_argslot, rbx_temp, rsi_temp);
+@@ -1120,8 +1117,8 @@
+ }
+ break;
+
+- case _adapter_mh_first+_adapt_flyby:
+- case _adapter_mh_first+_adapt_ricochet:
++ case _adapter_flyby:
++ case _adapter_ricochet:
+ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
+ break;
+
+diff --git a/src/share/vm/classfile/javaClasses.hpp b/src/share/vm/classfile/javaClasses.hpp
+--- a/src/share/vm/classfile/javaClasses.hpp
++++ b/src/share/vm/classfile/javaClasses.hpp
+@@ -151,6 +151,12 @@
+ // Conversion
+ static klassOop as_klassOop(oop java_class);
+ static BasicType as_BasicType(oop java_class, klassOop* reference_klass = NULL);
++ static BasicType as_BasicType(oop java_class, KlassHandle* reference_klass) {
++ klassOop refk_oop = NULL;
++ BasicType result = as_BasicType(java_class, &refk_oop);
++ (*reference_klass) = KlassHandle(refk_oop);
++ return result;
++ }
+ static symbolOop as_signature(oop java_class, bool intern_if_not_found, TRAPS);
+ static void print_signature(oop java_class, outputStream *st);
+ // Testing
+@@ -896,25 +902,26 @@
+
+ // Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants):
+ enum {
+- RETYPE_ONLY = 0x000, // no argument changes; straight retype
+- CHECK_CAST = 0x100, // ref-to-ref conversion; requires a Class argument
+- PRIM_TO_PRIM = 0x200, // converts from one primitive to another
+- REF_TO_PRIM = 0x300, // unboxes a wrapper to produce a primitive
+- PRIM_TO_REF = 0x400, // boxes a primitive into a wrapper (NYI)
+- SWAP_ARGS = 0x500, // swap arguments (vminfo is 2nd arg)
+- ROT_ARGS = 0x600, // rotate arguments (vminfo is displaced arg)
+- DUP_ARGS = 0x700, // duplicates one or more arguments (at TOS)
+- DROP_ARGS = 0x800, // remove one or more argument slots
+- COLLECT_ARGS = 0x900, // combine one or more arguments into a varargs (NYI)
+- SPREAD_ARGS = 0xA00, // expand in place a varargs array (of known size)
+- FLYBY = 0xB00, // operate first on reified argument list (NYI)
+- RICOCHET = 0xC00, // run an adapter chain on the return value (NYI)
++ OP_RETYPE_ONLY = 0x0, // no argument changes; straight retype
++ OP_CHECK_CAST = 0x1, // ref-to-ref conversion; requires a Class argument
++ OP_PRIM_TO_PRIM = 0x2, // converts from one primitive to another
++ OP_REF_TO_PRIM = 0x3, // unboxes a wrapper to produce a primitive
++ OP_PRIM_TO_REF = 0x4, // boxes a primitive into a wrapper (NYI)
++ OP_SWAP_ARGS = 0x5, // swap arguments (vminfo is 2nd arg)
++ OP_ROT_ARGS = 0x6, // rotate arguments (vminfo is displaced arg)
++ OP_DUP_ARGS = 0x7, // duplicates one or more arguments (at TOS)
++ OP_DROP_ARGS = 0x8, // remove one or more argument slots
++ OP_COLLECT_ARGS = 0x9, // combine one or more arguments into a varargs (NYI)
++ OP_SPREAD_ARGS = 0xA, // expand in place a varargs array (of known size)
++ OP_FLYBY = 0xB, // operate first on reified argument list (NYI)
++ OP_RICOCHET = 0xC, // run an adapter chain on the return value (NYI)
++ CONV_OP_LIMIT = 0xD, // limit of CONV_OP enumeration
+
+- CONV_OP_MASK = 0xF00, // byte 3 contains the conversion op field
++ CONV_OP_MASK = 0xF00, // this nybble contains the conversion op field
+ CONV_VMINFO_MASK = 0x0FF, // LSB is reserved for JVM use
+ CONV_VMINFO_SHIFT = 0, // position of bits in CONV_VMINFO_MASK
+ CONV_OP_SHIFT = 8, // position of bits in CONV_OP_MASK
+- CONV_DEST_TYPE_SHIFT = 12, // byte 3 has the adapter BasicType (if needed)
++ CONV_DEST_TYPE_SHIFT = 12, // byte 2 has the adapter BasicType (if needed)
+ CONV_SRC_TYPE_SHIFT = 16, // byte 2 has the source BasicType (if needed)
+ CONV_STACK_MOVE_SHIFT = 20, // high 12 bits give signed SP change
+ CONV_STACK_MOVE_MASK = (1 << (32 - CONV_STACK_MOVE_SHIFT)) - 1
+diff --git a/src/share/vm/includeDB_core b/src/share/vm/includeDB_core
+--- a/src/share/vm/includeDB_core
++++ b/src/share/vm/includeDB_core
+@@ -2817,6 +2817,7 @@
+ methodHandles.hpp frame.inline.hpp
+ methodHandles.hpp globals.hpp
+ methodHandles.hpp interfaceSupport.hpp
++methodHandles.hpp javaClasses.hpp
+ methodHandles.hpp vmSymbols.hpp
+
+ methodHandles.cpp allocation.inline.hpp
+diff --git a/src/share/vm/prims/methodHandles.cpp b/src/share/vm/prims/methodHandles.cpp
+--- a/src/share/vm/prims/methodHandles.cpp
++++ b/src/share/vm/prims/methodHandles.cpp
+@@ -47,19 +47,19 @@
+ "bound_long_direct",
+
+ // starting at _adapter_mh_first:
+- "adapt_retype_only", // these are for AMH...
+- "adapt_check_cast",
+- "adapt_prim_to_prim",
+- "adapt_ref_to_prim",
+- "adapt_prim_to_ref",
+- "adapt_swap_args",
+- "adapt_rot_args",
+- "adapt_dup_args",
+- "adapt_drop_args",
+- "adapt_collect_args",
+- "adapt_spread_args",
+- "adapt_flyby",
+- "adapt_ricochet",
++ "adapter_retype_only", // these are for AMH...
++ "adapter_check_cast",
++ "adapter_prim_to_prim",
++ "adapter_ref_to_prim",
++ "adapter_prim_to_ref",
++ "adapter_swap_args",
++ "adapter_rot_args",
++ "adapter_dup_args",
++ "adapter_drop_args",
++ "adapter_collect_args",
++ "adapter_spread_args",
++ "adapter_flyby",
++ "adapter_ricochet",
+
+ // optimized adapter types:
+ "adapter_swap_args/1",
+@@ -68,16 +68,16 @@
+ "adapter_rot_args/1,down",
+ "adapter_rot_args/2,up",
+ "adapter_rot_args/2,down",
+- "adapt_prim_to_prim/i2i",
+- "adapt_prim_to_prim/l2i",
+- "adapt_prim_to_prim/d2f",
+- "adapt_prim_to_prim/i2l",
+- "adapt_prim_to_prim/f2d",
+- "adapt_prim_to_prim/a2i",
+- "adapt_prim_to_prim/a2l",
+- "adapt_spread_args/0",
+- "adapt_spread_args/1",
+- "adapt_spread_args/more",
++ "adapter_prim_to_prim/i2i",
++ "adapter_prim_to_prim/l2i",
++ "adapter_prim_to_prim/d2f",
++ "adapter_prim_to_prim/i2l",
++ "adapter_prim_to_prim/f2d",
++ "adapter_ref_to_prim/unboxi",
++ "adapter_ref_to_prim/unboxl",
++ "adapter_spread_args/0",
++ "adapter_spread_args/1",
++ "adapter_spread_args/more",
+
+ NULL
+ };
+@@ -86,8 +86,9 @@
+ bool MethodHandles::spot_check_entry_names() {
+ assert(!strcmp(entry_name(_invokestatic_mh), "invokestatic"), "");
+ assert(!strcmp(entry_name(_bound_ref_mh), "bound_ref"), "");
+- assert(!strcmp(adapter_entry_name(_adapt_retype_only), "adapt_retype_only"), "");
+- assert(!strcmp(adapter_entry_name(_adapt_ricochet), "adapt_ricochet"), "");
++ assert(!strcmp(entry_name(_adapter_retype_only), "adapter_retype_only"), "");
++ assert(!strcmp(entry_name(_adapter_ricochet), "adapter_ricochet"), "");
++ assert(!strcmp(entry_name(_adapter_opt_unboxi), "adapter_ref_to_prim/unboxi"), "");
+ return true;
+ }
+ #endif
+@@ -99,6 +100,11 @@
+ }
+ }
+
++// Note: A method which does not have a TRAPS argument cannot block in the GC
++// or throw exceptions. Such methods are used in this file to do something quick
++// and local, like parse a data structure. For speed, such methods work on plain
++// oops, not handles. Trapping methods uniformly operate on handles.
++
+ methodOop MethodHandles::decode_vmtarget(oop vmtarget, int vmindex, oop mtype,
+ klassOop& receiver_limit_result, int& decode_flags_result) {
+ if (vmtarget == NULL) return NULL;
+@@ -183,8 +189,8 @@
+ assert(mh->klass() == SystemDictionary::AdapterMethodHandle_klass(), "");
+ for (oop amh = mh;;) {
+ // Adapter MHs can be stacked to convert several arguments.
+- AdapterKind ak = adapter_conversion_op(impl_java_dyn_AdapterMethodHandle::conversion(amh));
+- decode_flags_result |= (_dmf_adapter_lsb << ak);
++ int conv_op = adapter_conversion_op(impl_java_dyn_AdapterMethodHandle::conversion(amh));
++ decode_flags_result |= (_dmf_adapter_lsb << conv_op) & _DMF_ADAPTER_MASK;
+ oop target = java_dyn_MethodHandle::vmtarget(amh);
+ if (target == NULL) return NULL;
+ klassOop tk = target->klass();
+@@ -299,26 +305,6 @@
+ }
+
+
+-static void throw_IllegalArgumentException(TRAPS) {
+- THROW(vmSymbols::java_lang_IllegalArgumentException());
+- ShouldNotReachHere();
+-}
+-
+-static void throw_IllegalArgumentException(const char* message, TRAPS) {
+- THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), message);
+- ShouldNotReachHere();
+-}
+-
+-static void throw_InternalError(const char* message, TRAPS) {
+- THROW_MSG(vmSymbols::java_lang_InternalError(), message);
+- ShouldNotReachHere();
+-}
+-
+-static void throw_InternalError(TRAPS) {
+- THROW(vmSymbols::java_lang_InternalError());
+- ShouldNotReachHere();
+-}
+-
+ // MemberName support
+
+ // import impl_java_dyn_MemberName.*
+@@ -352,7 +338,7 @@
+
+ void MethodHandles::init_MemberName(oop mname_oop, methodOop m, bool do_dispatch) {
+ int flags = ((m->is_initializer() ? IS_CONSTRUCTOR : IS_METHOD)
+- | (jushort) m->access_flags().as_short());
++ | (jushort)( m->access_flags().as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS ));
+ oop vmtarget = m;
+ int vmindex = methodOopDesc::invalid_vtable_index; // implies no info yet
+ if (!do_dispatch || (flags & IS_CONSTRUCTOR) || m->can_be_statically_bound())
+@@ -364,7 +350,7 @@
+ }
+
+ void MethodHandles::init_MemberName(oop mname_oop, klassOop field_holder, AccessFlags mods, int offset) {
+- int flags = (IS_FIELD | (jushort) mods.as_short());
++ int flags = (IS_FIELD | (jushort)( mods.as_short() & JVM_RECOGNIZED_FIELD_MODIFIERS ));
+ oop vmtarget = field_holder;
+ int vmindex = offset; // implies no info yet
+ assert(vmindex != VM_INDEX_UNINITIALIZED, "bad alias on vmindex");
+@@ -405,18 +391,21 @@
+ oop type_str = impl_java_dyn_MemberName::type(mname());
+ int flags = impl_java_dyn_MemberName::flags(mname());
+
+- if (defc_oop == NULL || name_str == NULL || type_str == NULL)
+- { throw_IllegalArgumentException("nothing to resolve", CHECK); }
++ if (defc_oop == NULL || name_str == NULL || type_str == NULL) {
++ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "nothing to resolve");
++ }
+ klassOop defc_klassOop = java_lang_Class::as_klassOop(defc_oop);
+ defc_oop = NULL; // safety
++ if (defc_klassOop == NULL) return; // a primitive; no resolution possible
+ if (!Klass::cast(defc_klassOop)->oop_is_instance()) {
+ if (!Klass::cast(defc_klassOop)->oop_is_array()) return;
+ defc_klassOop = SystemDictionary::object_klass();
+ }
+ instanceKlassHandle defc(THREAD, defc_klassOop);
+ defc_klassOop = NULL; // safety
+- if (defc.is_null())
+- { throw_InternalError("primitive class", CHECK); }
++ if (defc.is_null()) {
++ THROW_MSG(vmSymbols::java_lang_InternalError(), "primitive class");
++ }
+ defc->link_class(CHECK);
+
+ // convert the external string name to an internal symbol
+@@ -439,7 +428,7 @@
+ type_sym = java_lang_String::as_symbol_or_null(type_str);
+ }
+ } else {
+- throw_InternalError("unrecognized type", CHECK);
++ THROW_MSG(vmSymbols::java_lang_InternalError(), "unrecognized type");
+ }
+ if (type_sym != NULL)
+ type = symbolHandle(THREAD, type_sym);
+@@ -486,9 +475,10 @@
+ } else {
+ vmtarget = result.resolved_klass()->as_klassOop();
+ }
++ int mods = (m->access_flags().as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS);
+ impl_java_dyn_MemberName::set_vmtarget(mname(), vmtarget);
+ impl_java_dyn_MemberName::set_vmindex(mname(), vmindex);
+- impl_java_dyn_MemberName::set_modifiers(mname(), m->access_flags().as_short());
++ impl_java_dyn_MemberName::set_modifiers(mname(), mods);
+ DEBUG_ONLY(int junk; klassOop junk2);
+ assert(decode_MemberName(mname(), junk2, junk) == result.resolved_method()(),
+ "properly stored for later decoding");
+@@ -514,9 +504,10 @@
+ methodHandle m = result.resolved_method();
+ oop vmtarget = m();
+ int vmindex = methodOopDesc::nonvirtual_vtable_index;
++ int mods = (m->access_flags().as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS);
+ impl_java_dyn_MemberName::set_vmtarget(mname(), vmtarget);
+ impl_java_dyn_MemberName::set_vmindex(mname(), vmindex);
+- impl_java_dyn_MemberName::set_modifiers(mname(), m->access_flags().as_short());
++ impl_java_dyn_MemberName::set_modifiers(mname(), mods);
+ DEBUG_ONLY(int junk; klassOop junk2);
+ assert(decode_MemberName(mname(), junk2, junk) == result.resolved_method()(),
+ "properly stored for later decoding");
+@@ -531,14 +522,15 @@
+ if (sel_klass.is_null()) return;
+ oop vmtarget = sel_klass->as_klassOop();
+ int vmindex = fd.offset();
++ int mods = (fd.access_flags().as_short() & JVM_RECOGNIZED_FIELD_MODIFIERS);
+ if (vmindex == VM_INDEX_UNINITIALIZED) break; // should not happen
+ impl_java_dyn_MemberName::set_vmtarget(mname(), vmtarget);
+ impl_java_dyn_MemberName::set_vmindex(mname(), vmindex);
+- impl_java_dyn_MemberName::set_modifiers(mname(), fd.access_flags().as_short());
++ impl_java_dyn_MemberName::set_modifiers(mname(), mods);
+ return;
+ }
+ }
+- throw_InternalError("unrecognized MemberName format", THREAD);
++ THROW_MSG(vmSymbols::java_lang_InternalError(), "unrecognized MemberName format");
+ }
+
+ // Conversely, a member name which is only initialized from JVM internals
+@@ -549,8 +541,9 @@
+ assert(impl_java_dyn_MemberName::is_instance(mname()), "");
+ oop vmtarget = impl_java_dyn_MemberName::vmtarget(mname());
+ int vmindex = impl_java_dyn_MemberName::vmindex(mname());
+- if (vmtarget == NULL || vmindex == VM_INDEX_UNINITIALIZED)
+- { throw_IllegalArgumentException("nothing to expand", CHECK); }
++ if (vmtarget == NULL || vmindex == VM_INDEX_UNINITIALIZED) {
++ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "nothing to expand");
++ }
+
+ bool have_defc = (impl_java_dyn_MemberName::clazz(mname()) != NULL);
+ bool have_name = (impl_java_dyn_MemberName::name(mname()) != NULL);
+@@ -617,7 +610,7 @@
+ return;
+ }
+ }
+- throw_InternalError("unrecognized MemberName format", THREAD);
++ THROW_MSG(vmSymbols::java_lang_InternalError(), "unrecognized MemberName format");
+ }
+
+ int MethodHandles::find_MemberNames(klassOop k,
+@@ -734,10 +727,10 @@
+ // Decode the vmtarget field of a method handle.
+ // Sanitize out methodOops, klassOops, and any other non-Java data.
+ // This is for debugging and reflection.
+-oop MethodHandles::encode_target(oop mh, int format, TRAPS) {
+- assert(java_dyn_MethodHandle::is_instance(mh), "must be a MH");
++oop MethodHandles::encode_target(Handle mh, int format, TRAPS) {
++ assert(java_dyn_MethodHandle::is_instance(mh()), "must be a MH");
+ if (format == ETF_HANDLE_OR_METHOD_NAME) {
+- oop target = java_dyn_MethodHandle::vmtarget(mh);
++ oop target = java_dyn_MethodHandle::vmtarget(mh());
+ if (target == NULL) {
+ return NULL; // unformed MH
+ }
+@@ -747,7 +740,7 @@
+ }
+ }
+ if (format == ETF_DIRECT_HANDLE) {
+- oop target = mh;
++ oop target = mh();
+ for (;;) {
+ if (target->klass() == SystemDictionary::DirectMethodHandle_klass()) {
+ return target;
+@@ -764,7 +757,7 @@
+ // - DMH can have klassOop for dispatched (non-static) invoke
+ klassOop receiver_limit = NULL;
+ int decode_flags = 0;
+- methodOop m = decode_MethodHandle(mh, receiver_limit, decode_flags);
++ methodOop m = decode_MethodHandle(mh(), receiver_limit, decode_flags);
+ if (m == NULL) return NULL;
+ switch (format) {
+ case ETF_REFLECT_METHOD:
+@@ -791,8 +784,9 @@
+ }
+
+ // Unknown format code.
+- throw_IllegalArgumentException(THREAD);
+- return NULL;
++ char msg[50];
++ jio_snprintf(msg, sizeof(msg), "unknown getTarget format=%d", format);
++ THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), msg);
+ }
+
+ bool MethodHandles::class_cast_needed(klassOop src, klassOop dst) {
+@@ -843,8 +837,8 @@
+ return false;
+ }
+
+-const char* MethodHandles::check_method_receiver(methodHandle m,
+- klassOop passed_recv_type) {
++const char* MethodHandles::check_method_receiver(methodOop m,
++ klassOop passed_recv_type) {
+ assert(!m->is_static(), "caller resp.");
+ if (passed_recv_type == NULL)
+ return "receiver type is primitive";
+@@ -860,10 +854,10 @@
+ // of the given method type 'mtype'.
+ // It takes a TRAPS argument because it must perform symbol lookups.
+ void MethodHandles::verify_method_signature(methodHandle m,
+- Handle mtype,
+- int first_ptype_pos,
+- KlassHandle insert_ptype,
+- TRAPS) {
++ Handle mtype,
++ int first_ptype_pos,
++ KlassHandle insert_ptype,
++ TRAPS) {
+ objArrayHandle ptypes(THREAD, java_dyn_MethodType::ptypes(mtype()));
+ int pnum = first_ptype_pos;
+ int pmax = ptypes->length();
+@@ -919,22 +913,17 @@
+ }
+
+ if (err != NULL) {
+- throw_InternalError(err, CHECK);
++ THROW_MSG(vmSymbols::java_lang_InternalError(), err);
+ }
+ }
+
+ // Main routine for verifying the MethodHandle.type of a proposed
+ // direct or bound-direct method handle.
+ void MethodHandles::verify_method_type(methodHandle m,
+- oop mtype_oop,
+- bool has_bound_recv,
+- klassOop bound_recv_type_oop,
+- TRAPS) {
+- Handle mtype(THREAD, mtype_oop);
+- KlassHandle bound_recv_type(THREAD, bound_recv_type_oop);
+-
+- mtype_oop = NULL; bound_recv_type_oop = NULL; // better safe than sorry
+-
++ Handle mtype,
++ bool has_bound_recv,
++ KlassHandle bound_recv_type,
++ TRAPS) {
+ bool m_needs_receiver = !m->is_static();
+
+ const char* err = NULL;
+@@ -951,9 +940,9 @@
+ if (ptypes->length() < first_ptype_pos)
+ { err = "receiver argument is missing"; goto die; }
+ if (first_ptype_pos == -1)
+- err = check_method_receiver(m, bound_recv_type->as_klassOop());
++ err = check_method_receiver(m(), bound_recv_type->as_klassOop());
+ else
+- err = check_method_receiver(m, java_lang_Class::as_klassOop(ptypes->obj_at(0)));
++ err = check_method_receiver(m(), java_lang_Class::as_klassOop(ptypes->obj_at(0)));
+ if (err != NULL) goto die;
+ }
+
+@@ -962,14 +951,15 @@
+ return;
+
+ die:
+- throw_InternalError(err, CHECK);
++ THROW_MSG(vmSymbols::java_lang_InternalError(), err);
+ }
+
+ void MethodHandles::verify_vmslots(Handle mh, TRAPS) {
+ // Verify vmslots.
+ int check_slots = argument_slot_count(java_dyn_MethodHandle::type(mh()));
+- if (java_dyn_MethodHandle::vmslots(mh()) != check_slots)
+- { throw_InternalError("bad vmslots in BMH", CHECK); }
++ if (java_dyn_MethodHandle::vmslots(mh()) != check_slots) {
++ THROW_MSG(vmSymbols::java_lang_InternalError(), "bad vmslots in BMH");
++ }
+ }
+
+ void MethodHandles::verify_vmargslot(Handle mh, int argnum, int argslot, TRAPS) {
+@@ -980,7 +970,7 @@
+ size_t msglen = strlen(fmt) + 3*11 + 1;
+ char* msg = NEW_RESOURCE_ARRAY(char, msglen);
+ jio_snprintf(msg, msglen, fmt, argnum, argslot, check_slot);
+- throw_InternalError(msg, CHECK);
++ THROW_MSG(vmSymbols::java_lang_InternalError(), msg);
+ }
+ }
+
+@@ -988,12 +978,12 @@
+ // Apart from the advertised changes, caller method type X must
+ // be able to invoke the callee method Y type with no violations
+ // of type integrity.
+-void MethodHandles::verify_method_type_change(oop src_mtype, int src_beg, int src_end,
+- int insert_argnum, oop insert_type,
+- int change_argnum, oop change_type,
+- int delete_argnum,
+- oop dst_mtype, int dst_beg, int dst_end,
+- TRAPS) {
++// Return NULL if all is well, else a short error message.
++const char* MethodHandles::check_method_type_change(oop src_mtype, int src_beg, int src_end,
++ int insert_argnum, oop insert_type,
++ int change_argnum, oop change_type,
++ int delete_argnum,
++ oop dst_mtype, int dst_beg, int dst_end) {
+ objArrayOop src_ptypes = java_dyn_MethodType::ptypes(src_mtype);
+ objArrayOop dst_ptypes = java_dyn_MethodType::ptypes(dst_mtype);
+
+@@ -1050,31 +1040,23 @@
+
+ // Compare the two argument types.
+ if (src_type != dst_type) {
+- if (src_type == NULL) err = "not enough arguments";
+- if (dst_type == NULL) err = "too many arguments";
+- if (err == NULL)
+- err = check_argument_type_change(src_type, dst_type, dst_idx);
+- if (err != NULL) break;
++ if (src_type == NULL) return "not enough arguments";
++ if (dst_type == NULL) return "too many arguments";
++ err = check_argument_type_change(src_type, dst_type, dst_idx);
++ if (err != NULL) return err;
+ }
+ }
+
+- if (err == NULL) {
+- // Now compare return types also.
+- oop src_rtype = java_dyn_MethodType::rtype(src_mtype);
+- oop dst_rtype = java_dyn_MethodType::rtype(dst_mtype);
+- if (src_rtype != dst_rtype) {
+- err = check_return_type_change(dst_rtype, src_rtype); // note reversal!
+- }
++ // Now compare return types also.
++ oop src_rtype = java_dyn_MethodType::rtype(src_mtype);
++ oop dst_rtype = java_dyn_MethodType::rtype(dst_mtype);
++ if (src_rtype != dst_rtype) {
++ err = check_return_type_change(dst_rtype, src_rtype); // note reversal!
++ if (err != NULL) return err;
+ }
+
+- if (err != NULL) { throw_InternalError(err, CHECK); }
+-}
+-
+-// Handy wrapper for check_argument_type_change, to verify one src/dest pair.
+-void MethodHandles::verify_argument_type_change(oop src_type, oop dst_type,
+- int argnum, TRAPS) {
+- const char* err = check_argument_type_change(src_type, dst_type, argnum);
+- if (err != NULL) { throw_InternalError(err, CHECK); }
++ assert(err == NULL, "");
++ return NULL; // all is well
+ }
+
+
+@@ -1176,33 +1158,33 @@
+ return -99; // oob slot, or splitting a double-slot arg
+ }
+
+-methodOop MethodHandles::dispatch_decoded_method(methodOop m,
+- klassOop receiver_limit,
+- int decode_flags,
+- klassOop receiver_klass,
+- TRAPS) {
++methodHandle MethodHandles::dispatch_decoded_method(methodHandle m,
++ KlassHandle receiver_limit,
++ int decode_flags,
++ KlassHandle receiver_klass,
++ TRAPS) {
+ assert((decode_flags & ~_DMF_DIRECT_MASK) == 0, "must be direct method reference");
+ assert((decode_flags & _dmf_has_receiver) != 0, "must have a receiver or first reference argument");
+
+ if (!m->is_static() &&
+- (receiver_klass == NULL || !Klass::cast(receiver_klass)->is_subtype_of(m->method_holder())))
++ (receiver_klass.is_null() || !receiver_klass->is_subtype_of(m->method_holder())))
+ // given type does not match class of method, or receiver is null!
+ // caller should have checked this, but let's be extra careful...
+- return NULL;
++ return methodHandle();
+
+- if (receiver_limit != NULL &&
+- (receiver_klass != NULL && !Klass::cast(receiver_klass)->is_subtype_of(receiver_limit)))
++ if (receiver_limit.not_null() &&
++ (receiver_klass.not_null() && !receiver_klass->is_subtype_of(receiver_limit())))
+ // given type is not limited to the receiver type
+ // note that a null receiver can match any reference value, for a static method
+- return NULL;
++ return methodHandle();
+
+ if (!(decode_flags & MethodHandles::_dmf_does_dispatch)) {
+ // pre-dispatched or static method (null receiver is OK for static)
+ return m;
+
+- } else if (receiver_klass == NULL) {
++ } else if (receiver_klass.is_null()) {
+ // null receiver value; cannot dispatch
+- return NULL;
++ return methodHandle();
+
+ } else if (!(decode_flags & MethodHandles::_dmf_from_interface)) {
+ // perform virtual dispatch
+@@ -1212,37 +1194,45 @@
+ // receiver_klass might be an arrayKlassOop but all vtables start at
+ // the same place. The cast is to avoid virtual call and assertion.
+ // See also LinkResolver::runtime_resolve_virtual_method.
+- instanceKlass* inst = (instanceKlass*)Klass::cast(receiver_klass);
++ instanceKlass* inst = (instanceKlass*)Klass::cast(receiver_klass());
+ DEBUG_ONLY(inst->verify_vtable_index(vtable_index));
+- return inst->method_at_vtable(vtable_index);
++ methodOop m_oop = inst->method_at_vtable(vtable_index);
++ return methodHandle(THREAD, m_oop);
+
+ } else {
+ // perform interface dispatch
+- int itable_index = klassItable::compute_itable_index(m);
++ int itable_index = klassItable::compute_itable_index(m());
+ guarantee(itable_index >= 0, "valid itable index");
+- instanceKlass* inst = instanceKlass::cast(receiver_klass);
+- return inst->method_at_itable(m->method_holder(), itable_index, THREAD);
++ instanceKlass* inst = instanceKlass::cast(receiver_klass());
++ methodOop m_oop = inst->method_at_itable(m->method_holder(), itable_index, THREAD);
++ return methodHandle(THREAD, m_oop);
++ }
++}
++
++void MethodHandles::verify_DirectMethodHandle(Handle mh, methodHandle m, TRAPS) {
++ // Verify type.
++ Handle mtype(THREAD, java_dyn_MethodHandle::type(mh()));
++ verify_method_type(m, mtype, false, KlassHandle(), CHECK);
++
++ // Verify vmslots.
++ if (java_dyn_MethodHandle::vmslots(mh()) != m->size_of_parameters()) {
++ THROW_MSG(vmSymbols::java_lang_InternalError(), "bad vmslots in DMH");
+ }
+ }
+
+ void MethodHandles::init_DirectMethodHandle(Handle mh, methodHandle m, bool do_dispatch, TRAPS) {
+ // Check arguments.
+ if (mh.is_null() || m.is_null() ||
+- (!do_dispatch && m->is_abstract()))
+- { throw_InternalError(CHECK); }
++ (!do_dispatch && m->is_abstract())) {
++ THROW(vmSymbols::java_lang_InternalError());
++ }
+
+ java_dyn_MethodHandle::init_vmslots(mh());
+
+- // The privileged code which invokes this routine should not make
+- // a mistake about types, but it's better to verify.
+ if (VerifyMethodHandles) {
+- // Verify type.
+- verify_method_type(m, java_dyn_MethodHandle::type(mh()),
+- false, NULL, CHECK);
+-
+- // Verify vmslots.
+- if (java_dyn_MethodHandle::vmslots(mh()) != m->size_of_parameters())
+- { throw_InternalError("bad vmslots in DMH", CHECK); }
++ // The privileged code which invokes this routine should not make
++ // a mistake about types, but it's better to verify.
++ verify_DirectMethodHandle(mh, m, CHECK);
+ }
+
+ // Finally, after safety checks are done, link to the target method.
+@@ -1295,7 +1285,7 @@
+ me = MethodHandles::entry(MethodHandles::_invokevirtual_mh);
+ }
+
+- if (me == NULL) { throw_InternalError(CHECK); }
++ if (me == NULL) { THROW(vmSymbols::java_lang_InternalError()); }
+
+ impl_java_dyn_DirectMethodHandle::set_vmtarget(mh(), vmtarget);
+ impl_java_dyn_DirectMethodHandle::set_vmindex(mh(), vmindex);
+@@ -1312,48 +1302,56 @@
+ java_dyn_MethodHandle::set_vmentry(mh(), me);
+ }
+
++void MethodHandles::verify_BoundMethodHandle_with_receiver(Handle mh,
++ methodHandle m,
++ TRAPS) {
++ // Verify type.
++ oop receiver = impl_java_dyn_BoundMethodHandle::argument(mh());
++ Handle mtype(THREAD, java_dyn_MethodHandle::type(mh()));
++ KlassHandle bound_recv_type;
++ if (receiver != NULL) bound_recv_type = KlassHandle(THREAD, receiver->klass());
++ verify_method_type(m, mtype, true, bound_recv_type, CHECK);
++
++ int receiver_pos = m->size_of_parameters() - 1;
++
++ // Verify MH.vmargslot, which should point at the bound receiver.
++ verify_vmargslot(mh, -1, impl_java_dyn_BoundMethodHandle::vmargslot(mh()), CHECK);
++ //verify_vmslots(mh, CHECK);
++
++ // Verify vmslots.
++ if (java_dyn_MethodHandle::vmslots(mh()) != receiver_pos) {
++ THROW_MSG(vmSymbols::java_lang_InternalError(), "bad vmslots in BMH (receiver)");
++ }
++}
++
+ // Initialize a BMH with a receiver bound directly to a methodOop.
+ void MethodHandles::init_BoundMethodHandle_with_receiver(Handle mh,
+- methodOop original_m_oop,
+- klassOop receiver_limit_oop,
+- int decode_flags,
+- TRAPS) {
++ methodHandle original_m,
++ KlassHandle receiver_limit,
++ int decode_flags,
++ TRAPS) {
+ // Check arguments.
+- if (mh.is_null() || original_m_oop == NULL)
+- { throw_InternalError(CHECK); }
++ if (mh.is_null() || original_m.is_null()) {
++ THROW(vmSymbols::java_lang_InternalError());
++ }
+
+- oop arg_oop = impl_java_dyn_BoundMethodHandle::argument(mh());
+- methodOop m_oop = dispatch_decoded_method(original_m_oop,
+- receiver_limit_oop, decode_flags,
+- (arg_oop == NULL ? klassOop(NULL) : arg_oop->klass()),
+- CHECK);
+- // do not use bare oops after this point:
+- original_m_oop = NULL; receiver_limit_oop = NULL; arg_oop = NULL;
+-
+- if (m_oop == NULL) { throw_InternalError(CHECK); }
+- methodHandle m(THREAD, m_oop); m_oop = NULL;
+-
+- if (m->is_abstract())
+- THROW(vmSymbols::java_lang_AbstractMethodError());
++ KlassHandle receiver_klass;
++ {
++ oop receiver_oop = impl_java_dyn_BoundMethodHandle::argument(mh());
++ if (receiver_oop != NULL)
++ receiver_klass = KlassHandle(THREAD, receiver_oop->klass());
++ }
++ methodHandle m = dispatch_decoded_method(original_m,
++ receiver_limit, decode_flags,
++ receiver_klass,
++ CHECK);
++ if (m.is_null()) { THROW(vmSymbols::java_lang_InternalError()); }
++ if (m->is_abstract()) { THROW(vmSymbols::java_lang_AbstractMethodError()); }
+
+ java_dyn_MethodHandle::init_vmslots(mh());
+
+ if (VerifyMethodHandles) {
+- // Verify type.
+- oop receiver = impl_java_dyn_BoundMethodHandle::argument(mh());
+- verify_method_type(m, java_dyn_MethodHandle::type(mh()),
+- true, (receiver == NULL ? klassOop(NULL) : receiver->klass()),
+- CHECK);
+-
+- int receiver_pos = m->size_of_parameters() - 1;
+-
+- // Verify MH.vmargslot, which should point at the bound receiver.
+- verify_vmargslot(mh, -1, impl_java_dyn_BoundMethodHandle::vmargslot(mh()), CHECK);
+- //verify_vmslots(mh, CHECK);
+-
+- // Verify vmslots.
+- if (java_dyn_MethodHandle::vmslots(mh()) != receiver_pos)
+- { throw_InternalError("bad vmslots in BMH (receiver)", CHECK); }
++ verify_BoundMethodHandle_with_receiver(mh, m, CHECK);
+ }
+
+ impl_java_dyn_BoundMethodHandle::set_vmtarget(mh(), m());
+@@ -1366,10 +1364,96 @@
+ java_dyn_MethodHandle::set_vmentry(mh(), MethodHandles::entry(MethodHandles::_bound_ref_direct_mh));
+ }
+
++void MethodHandles::verify_BoundMethodHandle(Handle mh, Handle target, int argnum,
++ bool direct_to_method, TRAPS) {
++ Handle ptype_handle(THREAD,
++ java_dyn_MethodType::ptype(java_dyn_MethodHandle::type(target()), argnum));
++ KlassHandle ptype_klass;
++ BasicType ptype = java_lang_Class::as_BasicType(ptype_handle(), &ptype_klass);
++ int slots_pushed = type2size[ptype];
++
++ oop argument = impl_java_dyn_BoundMethodHandle::argument(mh());
++
++ const char* err = NULL;
++
++ switch (ptype) {
++ case T_OBJECT:
++ if (argument != NULL)
++ // we must implicitly convert from the arg type to the outgoing ptype
++ err = check_argument_type_change(T_OBJECT, argument->klass(), ptype, ptype_klass(), argnum);
++ break;
++
++ case T_ARRAY: case T_VOID:
++ assert(false, "array, void do not appear here");
++ default:
++ if (ptype != T_INT && !is_subword_type(ptype)) {
++ err = "unexpected parameter type";
++ break;
++ }
++ // check subrange of Integer.value, if necessary
++ if (argument == NULL || argument->klass() != SystemDictionary::int_klass()) {
++ err = "bound integer argument must be of type java.lang.Integer";
++ break;
++ }
++ if (ptype != T_INT) {
++ int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_INT);
++ jint value = argument->int_field(value_offset);
++ int vminfo = adapter_subword_vminfo(ptype);
++ jint subword = truncate_subword_from_vminfo(value, vminfo);
++ if (value != subword) {
++ err = "bound subword value does not fit into the subword type";
++ break;
++ }
++ }
++ break;
++ case T_FLOAT:
++ case T_DOUBLE:
++ case T_LONG:
++ {
++ // we must implicitly convert from the unboxed arg type to the outgoing ptype
++ BasicType argbox = java_lang_boxing_object::basic_type(argument);
++ if (argbox != ptype) {
++ err = check_argument_type_change(T_OBJECT, (argument == NULL
++ ? SystemDictionary::object_klass()
++ : argument->klass()),
++ ptype, ptype_klass(), argnum);
++ assert(err != NULL, "this must be an error");
++ }
++ break;
++ }
++ }
++
++ if (err == NULL) {
++ DEBUG_ONLY(int this_pushes = decode_MethodHandle_stack_pushes(mh()));
++ if (direct_to_method) {
++ assert(this_pushes == slots_pushed, "BMH pushes one or two stack slots");
++ assert(slots_pushed <= MethodHandlePushLimit, "");
++ } else {
++ int prev_pushes = decode_MethodHandle_stack_pushes(target());
++ assert(this_pushes == slots_pushed + prev_pushes, "BMH stack motion must be correct");
++ // do not blow the stack; use a Java-based adapter if this limit is exceeded
++ if (slots_pushed + prev_pushes > MethodHandlePushLimit)
++ err = "too many bound parameters";
++ }
++ }
++
++ if (err == NULL) {
++ // Verify the rest of the method type.
++ err = check_method_type_insertion(java_dyn_MethodHandle::type(mh()),
++ argnum, ptype_handle(),
++ java_dyn_MethodHandle::type(target()));
++ }
++
++ if (err != NULL) {
++ THROW_MSG(vmSymbols::java_lang_InternalError(), err);
++ }
++}
++
+ void MethodHandles::init_BoundMethodHandle(Handle mh, Handle target, int argnum, TRAPS) {
+ // Check arguments.
+- if (mh.is_null() || target.is_null() || !java_dyn_MethodHandle::is_instance(target()))
+- { throw_InternalError(CHECK); }
++ if (mh.is_null() || target.is_null() || !java_dyn_MethodHandle::is_instance(target())) {
++ THROW(vmSymbols::java_lang_InternalError());
++ }
+
+ java_dyn_MethodHandle::init_vmslots(mh());
+
+@@ -1387,13 +1471,14 @@
+ if (OptimizeMethodHandles &&
+ target->klass() == SystemDictionary::DirectMethodHandle_klass() &&
+ (argnum == 0 || impl_java_dyn_DirectMethodHandle::vmindex(target()) < 0)) {
+- int decode_flags = 0; klassOop receiver_limit = NULL;
+- methodHandle m(THREAD, decode_method(target(), receiver_limit, decode_flags));
+- if (m.is_null()) { throw_InternalError("DMH failed to decode", CHECK); }
++ int decode_flags = 0; klassOop receiver_limit_oop = NULL;
++ methodHandle m(THREAD, decode_method(target(), receiver_limit_oop, decode_flags));
++ if (m.is_null()) { THROW_MSG(vmSymbols::java_lang_InternalError(), "DMH failed to decode"); }
+ DEBUG_ONLY(int m_vmslots = m->size_of_parameters() - 1); // pos. of 1st arg.
+ assert(impl_java_dyn_BoundMethodHandle::vmslots(mh()) == m_vmslots, "type w/ m sig");
+ if (argnum == 0 && (decode_flags & _dmf_has_receiver) != 0) {
+- init_BoundMethodHandle_with_receiver(mh, m(),
++ KlassHandle receiver_limit(THREAD, receiver_limit_oop);
++ init_BoundMethodHandle_with_receiver(mh, m,
+ receiver_limit, decode_flags,
+ CHECK);
+ return;
+@@ -1409,84 +1494,14 @@
+ if (!direct_to_method)
+ impl_java_dyn_BoundMethodHandle::set_vmtarget(mh(), target());
+
++ if (VerifyMethodHandles) {
++ verify_BoundMethodHandle(mh, target, argnum, direct_to_method, CHECK);
++ }
++
+ // Next question: Is this a ref, int, or long bound value?
+- oop target_mtype = java_dyn_MethodHandle::type(target());
+- klassOop ptype_klass = NULL;
+- oop ptype_oop = java_dyn_MethodType::ptype(target_mtype, argnum);
+- BasicType ptype = java_lang_Class::as_BasicType(ptype_oop, &ptype_klass);
+- assert(ptype != T_ARRAY && ptype != T_VOID, "does not appear here");
++ oop ptype_oop = java_dyn_MethodType::ptype(java_dyn_MethodHandle::type(target()), argnum);
++ BasicType ptype = java_lang_Class::as_BasicType(ptype_oop);
+ int slots_pushed = type2size[ptype];
+- if (VerifyMethodHandles) {
+- oop argument = impl_java_dyn_BoundMethodHandle::argument(mh());
+- const char* err = NULL;
+- switch (ptype) {
+- case T_OBJECT:
+- if (argument != NULL)
+- // we must implicitly convert from the arg type to the outgoing ptype
+- err = check_argument_type_change(T_OBJECT, argument->klass(), ptype, ptype_klass, argnum);
+- break;
+- case T_ARRAY: case T_VOID:
+- assert(false, "array, void do not appear here");
+- default:
+- if (ptype != T_INT && !is_subword_type(ptype)) {
+- err = "unexpected parameter type";
+- break;
+- }
+- // check subrange of Integer.value, if necessary
+- if (argument == NULL || argument->klass() != SystemDictionary::int_klass()) {
+- err = "bound integer argument must be of type java.lang.Integer";
+- break;
+- }
+- if (ptype != T_INT) {
+- int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_INT);
+- jint value = argument->int_field(value_offset);
+- int vminfo = adapter_subword_vminfo(ptype);
+- jint subword = truncate_subword_from_vminfo(value, vminfo);
+- if (value != subword) {
+- err = "bound subword value does not fit into the subword type";
+- break;
+- }
+- }
+- break;
+- case T_FLOAT:
+- case T_DOUBLE:
+- case T_LONG:
+- {
+- // we must implicitly convert from the unboxed arg type to the outgoing ptype
+- BasicType argbox = java_lang_boxing_object::basic_type(argument);
+- if (argbox != ptype) {
+- err = check_argument_type_change(T_OBJECT, (argument == NULL
+- ? SystemDictionary::object_klass()
+- : argument->klass()),
+- ptype, ptype_klass, argnum);
+- assert(err != NULL, "this must be an error");
+- }
+- break;
+- }
+- }
+-
+- if (err == NULL) {
+- DEBUG_ONLY(int this_pushes = decode_MethodHandle_stack_pushes(mh()));
+- if (direct_to_method) {
+- assert(this_pushes == slots_pushed, "BMH pushes one or two stack slots");
+- assert(slots_pushed <= MethodHandlePushLimit, "");
+- } else {
+- int prev_pushes = decode_MethodHandle_stack_pushes(target());
+- assert(this_pushes == slots_pushed + prev_pushes, "BMH stack motion must be correct");
+- // do not blow the stack; use a Java-based adapter if this limit is exceeded
+- if (slots_pushed + prev_pushes > MethodHandlePushLimit)
+- err = "too many bound parameters";
+- }
+- }
+-
+- if (err != NULL)
+- { throw_InternalError(err, CHECK); }
+-
+- // Verify the rest of the method type.
+- verify_method_type_insertion(java_dyn_MethodHandle::type(mh()),
+- argnum, ptype_oop,
+- java_dyn_MethodHandle::type(target()), CHECK);
+- }
+
+ MethodHandleEntry* me = NULL;
+ if (ptype == T_OBJECT) {
+@@ -1506,275 +1521,313 @@
+ java_dyn_MethodHandle::set_vmentry(mh(), me);
+ }
+
+-void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnum, TRAPS) {
++static void throw_InternalError_for_bad_conversion(int conversion, const char* err, TRAPS) {
++ char msg[200];
++ jio_snprintf(msg, sizeof(msg), "bad adapter (conversion=0x%08x): %s", conversion, err);
++ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), msg);
++}
++
++void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
+ jint conversion = impl_java_dyn_AdapterMethodHandle::conversion(mh());
+- oop argument = impl_java_dyn_AdapterMethodHandle::argument(mh());
+ int argslot = impl_java_dyn_AdapterMethodHandle::vmargslot(mh());
+
+- // adjust the adapter code to the internal EntryKind enumeration:
+- AdapterKind ak = adapter_conversion_op(conversion);
+- EntryKind ek = (EntryKind)(MethodHandles::_adapter_mh_first + (int)ak);
++ verify_vmargslot(mh, argnum, argslot, CHECK);
++ verify_vmslots(mh, CHECK);
+
+- if (ak < _adapt_retype_only || ak > _AK_LIMIT)
+- { throw_InternalError("bad conversion", CHECK); }
+-
+- // Finalize the vmtarget field (Java initialized it to null).
+- impl_java_dyn_AdapterMethodHandle::set_vmtarget(mh(), target());
++ jint conv_op = adapter_conversion_op(conversion);
++ if (!conv_op_valid(conv_op)) {
++ throw_InternalError_for_bad_conversion(conversion, "unknown conversion op", THREAD);
++ return;
++ }
++ EntryKind ek = adapter_entry_kind(conv_op);
+
+ int stack_move = adapter_conversion_stack_move(conversion);
+ BasicType src = adapter_conversion_src_type(conversion);
+ BasicType dest = adapter_conversion_dest_type(conversion);
+ int vminfo = adapter_conversion_vminfo(conversion); // should be zero
+
+- if (VerifyMethodHandles) {
+- verify_vmargslot(mh, argnum, argslot, CHECK);
+- verify_vmslots(mh, CHECK);
++ Handle argument(THREAD, impl_java_dyn_AdapterMethodHandle::argument(mh()));
++ Handle target(THREAD, impl_java_dyn_AdapterMethodHandle::vmtarget(mh()));
++ Handle src_mtype(THREAD, java_dyn_MethodHandle::type(mh()));
++ Handle dst_mtype(THREAD, java_dyn_MethodHandle::type(target()));
+
+- const char* err = NULL;
++ const char* err = NULL;
+
+- if (err == NULL) {
+- if (!java_dyn_MethodHandle::is_instance(target()))
+- err = "adapter target is not a method handle";
++ if (err == NULL) {
++ // Check that the correct argument is supplied, but only if it is required.
++ switch (ek) {
++ case _adapter_check_cast: // target type of cast
++ case _adapter_ref_to_prim: // wrapper type from which to unbox
++ case _adapter_prim_to_ref: // wrapper type to box into
++ case _adapter_collect_args: // array type to collect into
++ case _adapter_spread_args: // array type to spread from
++ if (!java_lang_Class::is_instance(argument())
++ || java_lang_Class::is_primitive(argument()))
++ { err = "adapter requires argument of type java.lang.Class"; break; }
++ if (ek == _adapter_collect_args ||
++ ek == _adapter_spread_args) {
++ // Make sure it is a suitable collection type. (Array, for now.)
++ Klass* ak = Klass::cast(java_lang_Class::as_klassOop(argument()));
++ if (!ak->oop_is_objArray()) {
++ { err = "adapter requires argument of type java.lang.Class<Object[]>"; break; }
++ }
++ }
++ break;
++ case _adapter_flyby:
++ case _adapter_ricochet:
++ if (!java_dyn_MethodHandle::is_instance(argument()))
++ { err = "MethodHandle adapter argument required"; break; }
++ break;
++ default:
++ if (argument.not_null())
++ { err = "adapter has spurious argument"; break; }
++ break;
+ }
++ }
+
+- if (err == NULL) {
+- // Check that the correct argument is supplied, but only if it is required.
+- switch (ak) {
+- case _adapt_check_cast: // target type of cast
+- case _adapt_ref_to_prim: // wrapper type from which to unbox
+- case _adapt_prim_to_ref: // wrapper type to box into
+- case _adapt_collect_args: // array type to collect into
+- case _adapt_spread_args: // array type to spread from
+- if (!java_lang_Class::is_instance(argument)
+- || java_lang_Class::is_primitive(argument))
+- { err = "adapter requires argument of type java.lang.Class"; break; }
+- if (ak == _adapt_collect_args ||
+- ak == _adapt_spread_args) {
+- // Make sure it is a suitable collection type. (Array, for now.)
+- Klass* ak = Klass::cast(java_lang_Class::as_klassOop(argument));
+- if (!ak->oop_is_objArray()) {
+- { err = "adapter requires argument of type java.lang.Class<Object[]>"; break; }
++ if (err == NULL) {
++ // Check that the src/dest types are supplied if needed.
++ switch (ek) {
++ case _adapter_prim_to_prim:
++ if (!is_java_primitive(src) || !is_java_primitive(dest) || src == dest) {
++ err = "adapter requires primitive src/dest conversion subfields"; break;
++ }
++ if ( (src == T_FLOAT || src == T_DOUBLE) && !(dest == T_FLOAT || dest == T_DOUBLE) ||
++ !(src == T_FLOAT || src == T_DOUBLE) && (dest == T_FLOAT || dest == T_DOUBLE)) {
++ err = "adapter cannot convert beween floating and fixed-point"; break;
++ }
++ break;
++ case _adapter_ref_to_prim:
++ if (src != T_OBJECT || !is_java_primitive(dest)
++ || argument() != Klass::cast(SystemDictionary::box_klass(dest))->java_mirror()) {
++ err = "adapter requires primitive dest conversion subfield"; break;
++ }
++ break;
++ case _adapter_prim_to_ref:
++ if (!is_java_primitive(src) || dest != T_OBJECT
++ || argument() != Klass::cast(SystemDictionary::box_klass(src))->java_mirror()) {
++ err = "adapter requires primitive src conversion subfield"; break;
++ }
++ break;
++ case _adapter_swap_args:
++ case _adapter_rot_args:
++ {
++ if (!src || src != dest) {
++ err = "adapter requires src/dest conversion subfields for swap"; break;
++ }
++ int swap_size = type2size[src];
++ oop src_mtype = impl_java_dyn_AdapterMethodHandle::type(target());
++ oop dest_mtype = impl_java_dyn_AdapterMethodHandle::type(mh());
++ int slot_limit = impl_java_dyn_AdapterMethodHandle::vmslots(src_mtype);
++ int src_slot = argslot;
++ int dest_slot = vminfo;
++ bool rotate_up = (src_slot > dest_slot); // upward rotation
++ int src_arg = argnum;
++ int dest_arg = argument_slot_to_argnum(dest_mtype, dest_slot);
++ verify_vmargslot(mh, dest_arg, dest_slot, CHECK);
++ if (!(dest_slot >= src_slot + swap_size) &&
++ !(src_slot >= dest_slot + swap_size)) {
++ err = "source, destination slots must be distinct";
++ } else if (ek == _adapter_swap_args && !(src_slot > dest_slot)) {
++ err = "source of swap must be deeper in stack";
++ } else if (ek == _adapter_swap_args) {
++ err = check_argument_type_change(java_dyn_MethodType::ptype(src_mtype, dest_arg),
++ java_dyn_MethodType::ptype(dest_mtype, src_arg),
++ dest_arg);
++ } else if (ek == _adapter_rot_args) {
++ if (rotate_up) {
++ assert((src_slot > dest_slot) && (src_arg < dest_arg), "");
++ // rotate up: [dest_slot..src_slot-ss] --> [dest_slot+ss..src_slot]
++ // that is: [src_arg+1..dest_arg] --> [src_arg..dest_arg-1]
++ for (int i = src_arg+1; i <= dest_arg && err == NULL; i++) {
++ err = check_argument_type_change(java_dyn_MethodType::ptype(src_mtype, i),
++ java_dyn_MethodType::ptype(dest_mtype, i-1),
++ i);
++ }
++ } else { // rotate down
++ assert((src_slot < dest_slot) && (src_arg > dest_arg), "");
++ // rotate down: [src_slot+ss..dest_slot] --> [src_slot..dest_slot-ss]
++ // that is: [dest_arg..src_arg-1] --> [dst_arg+1..src_arg]
++ for (int i = dest_arg; i <= src_arg-1 && err == NULL; i++) {
++ err = check_argument_type_change(java_dyn_MethodType::ptype(src_mtype, i),
++ java_dyn_MethodType::ptype(dest_mtype, i+1),
++ i);
++ }
+ }
+ }
+- break;
+- case _adapt_flyby:
+- case _adapt_ricochet:
+- if (!java_dyn_MethodHandle::is_instance(argument))
+- { err = "MethodHandle adapter argument required"; break; }
+- break;
+- default:
+- if (argument != NULL)
+- { err = "adapter has spurious argument"; break; }
+- break;
++ if (err == NULL)
++ err = check_argument_type_change(java_dyn_MethodType::ptype(src_mtype, src_arg),
++ java_dyn_MethodType::ptype(dest_mtype, dest_arg),
++ src_arg);
++ }
++ break;
++ case _adapter_collect_args:
++ case _adapter_spread_args:
++ {
++ BasicType coll_type = (ek == _adapter_collect_args) ? dest : src;
++ BasicType elem_type = (ek == _adapter_collect_args) ? src : dest;
++ if (coll_type != T_OBJECT || elem_type != T_OBJECT) {
++ err = "adapter requires src/dest subfields"; break;
++ // later:
++ // - consider making coll be a primitive array
++ // - consider making coll be a heterogeneous collection
++ }
++ }
++ break;
++ default:
++ if (src != 0 || dest != 0) {
++ err = "adapter has spurious src/dest conversion subfields"; break;
++ }
++ break;
++ }
++ }
++
++ if (err == NULL) {
++ // Check the stack_move subfield.
++ // It must always report the net change in stack size, positive or negative.
++ int slots_pushed = stack_move / stack_move_unit();
++ switch (ek) {
++ case _adapter_prim_to_prim:
++ case _adapter_ref_to_prim:
++ case _adapter_prim_to_ref:
++ if (slots_pushed != type2size[dest] - type2size[src]) {
++ err = "wrong stack motion for primitive conversion";
++ }
++ break;
++ case _adapter_dup_args:
++ if (slots_pushed <= 0) {
++ err = "adapter requires conversion subfield slots_pushed > 0";
++ }
++ break;
++ case _adapter_drop_args:
++ if (slots_pushed >= 0) {
++ err = "adapter requires conversion subfield slots_pushed < 0";
++ }
++ break;
++ case _adapter_collect_args:
++ if (slots_pushed > 1) {
++ err = "adapter requires conversion subfield slots_pushed <= 1";
++ }
++ break;
++ case _adapter_spread_args:
++ if (slots_pushed < -1) {
++ err = "adapter requires conversion subfield slots_pushed >= -1";
++ }
++ break;
++ default:
++ if (stack_move != 0) {
++ err = "adapter has spurious stack_move conversion subfield";
++ }
++ break;
++ }
++ if (err == NULL && stack_move != slots_pushed * stack_move_unit()) {
++ err = "stack_move conversion subfield must be multiple of stack_move_unit";
++ }
++ }
++
++ if (err == NULL) {
++ // Make sure this adapter does not push too deeply.
++ int slots_pushed = stack_move / stack_move_unit();
++ int this_vmslots = java_dyn_MethodHandle::vmslots(mh());
++ int prev_vmslots = java_dyn_MethodHandle::vmslots(target());
++ if (slots_pushed != (this_vmslots - prev_vmslots)) {
++ err = "stack_move inconsistent with previous and current MethodType vmslots";
++ } else if (slots_pushed > 0) {
++ // verify stack_move against MethodHandlePushLimit
++ int prev_pushes = decode_MethodHandle_stack_pushes(target());
++ // do not blow the stack; use a Java-based adapter if this limit is exceeded
++ if (slots_pushed + prev_pushes > MethodHandlePushLimit) {
++ err = "adapter pushes too many parameters";
+ }
+ }
+
+- if (err == NULL) {
+- // Check that the src/dest types are supplied if needed.
+- switch (ak) {
+- case _adapt_prim_to_prim:
+- if (!is_java_primitive(src) || !is_java_primitive(dest) || src == dest) {
+- err = "adapter requires primitive src/dest conversion subfields"; break;
+- }
+- if ( (src == T_FLOAT || src == T_DOUBLE) && !(dest == T_FLOAT || dest == T_DOUBLE) ||
+- !(src == T_FLOAT || src == T_DOUBLE) && (dest == T_FLOAT || dest == T_DOUBLE)) {
+- err = "adapter cannot convert beween floating and fixed-point"; break;
+- }
+- break;
+- case _adapt_ref_to_prim:
+- if (src != T_OBJECT || !is_java_primitive(dest)
+- || argument != Klass::cast(SystemDictionary::box_klass(dest))->java_mirror()) {
+- err = "adapter requires primitive dest conversion subfield"; break;
+- }
+- break;
+- case _adapt_prim_to_ref:
+- if (!is_java_primitive(src) || dest != T_OBJECT
+- || argument != Klass::cast(SystemDictionary::box_klass(src))->java_mirror()) {
+- err = "adapter requires primitive src conversion subfield"; break;
+- }
+- break;
+- case _adapt_swap_args:
+- case _adapt_rot_args:
+- {
+- if (!src || src != dest) {
+- err = "adapter requires src/dest conversion subfields for swap"; break;
+- }
+- int swap_size = type2size[src];
+- oop src_mtype = impl_java_dyn_AdapterMethodHandle::type(target());
+- oop dest_mtype = impl_java_dyn_AdapterMethodHandle::type(mh());
+- int slot_limit = impl_java_dyn_AdapterMethodHandle::vmslots(src_mtype);
+- int src_slot = argslot;
+- int dest_slot = vminfo;
+- bool rotate_up = (src_slot > dest_slot); // upward rotation
+- int src_arg = argnum;
+- int dest_arg = argument_slot_to_argnum(dest_mtype, dest_slot);
+- verify_vmargslot(mh, dest_arg, dest_slot, CHECK);
+- if (!(dest_slot >= src_slot + swap_size) &&
+- !(src_slot >= dest_slot + swap_size)) {
+- err = "source, destination slots must be distinct";
+- } else if (ak == _adapt_swap_args && !(src_slot > dest_slot)) {
+- err = "source of swap must be deeper in stack";
+- } else if (ak == _adapt_swap_args) {
+- err = check_argument_type_change(java_dyn_MethodType::ptype(src_mtype, dest_arg),
+- java_dyn_MethodType::ptype(dest_mtype, src_arg),
+- dest_arg);
+- } else if (ak == _adapt_rot_args) {
+- if (rotate_up) {
+- assert((src_slot > dest_slot) && (src_arg < dest_arg), "");
+- // rotate up: [dest_slot..src_slot-ss] --> [dest_slot+ss..src_slot]
+- // that is: [src_arg+1..dest_arg] --> [src_arg..dest_arg-1]
+- for (int i = src_arg+1; i <= dest_arg && err == NULL; i++) {
+- err = check_argument_type_change(java_dyn_MethodType::ptype(src_mtype, i),
+- java_dyn_MethodType::ptype(dest_mtype, i-1),
+- i);
+- }
+- } else { // rotate down
+- assert((src_slot < dest_slot) && (src_arg > dest_arg), "");
+- // rotate down: [src_slot+ss..dest_slot] --> [src_slot..dest_slot-ss]
+- // that is: [dest_arg..src_arg-1] --> [dst_arg+1..src_arg]
+- for (int i = dest_arg; i <= src_arg-1 && err == NULL; i++) {
+- err = check_argument_type_change(java_dyn_MethodType::ptype(src_mtype, i),
+- java_dyn_MethodType::ptype(dest_mtype, i+1),
+- i);
+- }
+- }
+- }
+- if (err == NULL)
+- err = check_argument_type_change(java_dyn_MethodType::ptype(src_mtype, src_arg),
+- java_dyn_MethodType::ptype(dest_mtype, dest_arg),
+- src_arg);
+- }
+- break;
+- case _adapt_collect_args:
+- case _adapt_spread_args:
+- {
+- BasicType coll_type = (ak == _adapt_collect_args) ? dest : src;
+- BasicType elem_type = (ak == _adapt_collect_args) ? src : dest;
+- if (coll_type != T_OBJECT || elem_type != T_OBJECT) {
+- err = "adapter requires src/dest subfields"; break;
+- // later:
+- // - consider making coll be a primitive array
+- // - consider making coll be a heterogeneous collection
+- }
+- }
+- break;
+- default:
+- if (src != 0 || dest != 0) {
+- err = "adapter has spurious src/dest conversion subfields"; break;
+- }
+- break;
+- }
+- }
+-
+- if (err == NULL) {
+- // Check the stack_move subfield.
+- // It must always report the net change in stack size, positive or negative.
+- int slots_pushed = stack_move / stack_move_unit();
+- switch (ak) {
+- case _adapt_prim_to_prim:
+- case _adapt_ref_to_prim:
+- case _adapt_prim_to_ref:
+- if (slots_pushed != type2size[dest] - type2size[src]) {
+- err = "wrong stack motion for primitive conversion";
+- }
+- break;
+- case _adapt_dup_args:
+- if (slots_pushed <= 0) {
+- err = "adapter requires conversion subfield slots_pushed > 0";
+- }
+- break;
+- case _adapt_drop_args:
+- if (slots_pushed >= 0) {
+- err = "adapter requires conversion subfield slots_pushed < 0";
+- }
+- break;
+- case _adapt_collect_args:
+- if (slots_pushed > 1) {
+- err = "adapter requires conversion subfield slots_pushed <= 1";
+- }
+- break;
+- case _adapt_spread_args:
+- if (slots_pushed < -1) {
+- err = "adapter requires conversion subfield slots_pushed >= -1";
+- }
+- break;
+- default:
+- if (stack_move != 0) {
+- err = "adapter has spurious stack_move conversion subfield";
+- }
+- break;
+- }
+- if (err == NULL && stack_move != slots_pushed * stack_move_unit()) {
+- err = "stack_move conversion subfield must be multiple of stack_move_unit";
+- }
+- }
+-
+- if (err == NULL) {
+- // Make sure this adapter does not push too deeply.
+- int slots_pushed = stack_move / stack_move_unit();
+- int this_vmslots = java_dyn_MethodHandle::vmslots(mh());
+- int prev_vmslots = java_dyn_MethodHandle::vmslots(target());
+- if (slots_pushed != (this_vmslots - prev_vmslots)) {
+- err = "stack_move inconsistent with previous and current MethodType vmslots";
+- } else if (slots_pushed > 0) {
+- // verify stack_move against MethodHandlePushLimit
+- int prev_pushes = decode_MethodHandle_stack_pushes(target());
+- // do not blow the stack; use a Java-based adapter if this limit is exceeded
+- if (slots_pushed + prev_pushes > MethodHandlePushLimit) {
+- err = "adapter pushes too many parameters";
+- }
+- }
+-
+- // While we're at it, check that the stack motion decoder works:
+- DEBUG_ONLY(int prev_pushes = decode_MethodHandle_stack_pushes(target()));
+- DEBUG_ONLY(int this_pushes = decode_MethodHandle_stack_pushes(mh()));
+- assert(this_pushes == slots_pushed + prev_pushes, "AMH stack motion must be correct");
+- }
+-
+- if (err == NULL && vminfo != 0) {
+- switch (ak) {
+- case _adapt_swap_args:
+- case _adapt_rot_args:
+- break; // OK
+- default:
+- err = "vminfo subfield is reserved to the JVM";
+- }
+- }
+-
+- if (err != NULL) { throw_InternalError(err, CHECK); }
++ // While we're at it, check that the stack motion decoder works:
++ DEBUG_ONLY(int prev_pushes = decode_MethodHandle_stack_pushes(target()));
++ DEBUG_ONLY(int this_pushes = decode_MethodHandle_stack_pushes(mh()));
++ assert(this_pushes == slots_pushed + prev_pushes, "AMH stack motion must be correct");
+ }
+
+- // Here are the source and destination types, if we need to look at them.
+- Handle src_mtype, dst_mtype;
+- if (VerifyMethodHandles) {
+- src_mtype = Handle(THREAD, java_dyn_MethodHandle::type(mh()));
+- dst_mtype = Handle(THREAD, java_dyn_MethodHandle::type(target()));
++ if (err == NULL && vminfo != 0) {
++ switch (ek) {
++ case _adapter_swap_args:
++ case _adapter_rot_args:
++ break; // OK
++ default:
++ err = "vminfo subfield is reserved to the JVM";
++ }
+ }
+
++ // Do additional ad hoc checks.
++ if (err == NULL) {
++ switch (ek) {
++ case _adapter_retype_only:
++ err = check_method_type_passthrough(src_mtype(), dst_mtype());
++ break;
++
++ case _adapter_check_cast:
++ {
++ // The actual value being checked must be a reference:
++ err = check_argument_type_change(java_dyn_MethodType::ptype(src_mtype(), argnum),
++ object_java_mirror(), argnum);
++ if (err != NULL) break;
++
++ // The output of the cast must fit with the destination argument:
++ Handle cast_class = argument;
++ err = check_method_type_conversion(src_mtype(),
++ argnum, cast_class(),
++ dst_mtype());
++ }
++ break;
++
++ // %%% TO DO: continue in remaining cases to verify src/dst_mtype if VerifyMethodHandles
++ }
++ }
++
++ if (err != NULL) {
++ throw_InternalError_for_bad_conversion(conversion, err, THREAD);
++ return;
++ }
++
++}
++
++void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnum, TRAPS) {
++ oop argument = impl_java_dyn_AdapterMethodHandle::argument(mh());
++ int argslot = impl_java_dyn_AdapterMethodHandle::vmargslot(mh());
++ jint conversion = impl_java_dyn_AdapterMethodHandle::conversion(mh());
++ jint conv_op = adapter_conversion_op(conversion);
++
++ // adjust the adapter code to the internal EntryKind enumeration:
++ EntryKind ek_orig = adapter_entry_kind(conv_op);
++ EntryKind ek_opt = ek_orig; // may be optimized
++
++ // Finalize the vmtarget field (Java initialized it to null).
++ if (!java_dyn_MethodHandle::is_instance(target())) {
++ throw_InternalError_for_bad_conversion(conversion, "bad target", THREAD);
++ return;
++ }
++ impl_java_dyn_AdapterMethodHandle::set_vmtarget(mh(), target());
++
++ if (VerifyMethodHandles) {
++ verify_AdapterMethodHandle(mh, argnum, CHECK);
++ }
++
++ int stack_move = adapter_conversion_stack_move(conversion);
++ BasicType src = adapter_conversion_src_type(conversion);
++ BasicType dest = adapter_conversion_dest_type(conversion);
++ int vminfo = adapter_conversion_vminfo(conversion); // should be zero
++
++ const char* err = NULL;
++
+ // Now it's time to finish the case analysis and pick a MethodHandleEntry.
+- switch (ak) {
+- case _adapt_retype_only:
+- if (VerifyMethodHandles) {
+- verify_method_type_passthrough(src_mtype(), dst_mtype(), CHECK);
+- }
++ switch (ek_orig) {
++ case _adapter_retype_only:
++ case _adapter_check_cast:
++ case _adapter_dup_args:
++ case _adapter_drop_args:
++ // these work fine via general case code
+ break;
+
+- case _adapt_check_cast:
+- if (VerifyMethodHandles) {
+- // The actual value being checked must be a reference:
+- verify_argument_type_change(java_dyn_MethodType::ptype(src_mtype(), argnum),
+- object_java_mirror(), argnum, CHECK);
+- // The output of the cast must fit with the destination argument:
+- oop cast_class = argument;
+- verify_method_type_conversion(src_mtype(),
+- argnum, cast_class,
+- dst_mtype(), CHECK);
+- }
+- break;
+-
+- // %%% TO DO: continue in remaining cases to verify src/dst_mtype if VerifyMethodHandles
+-
+- case _adapt_prim_to_prim:
++ case _adapter_prim_to_prim:
+ {
+ // Non-subword cases are {int,float,long,double} -> {int,float,long,double}.
+ // And, the {float,double} -> {int,long} cases must be handled by Java.
+@@ -1782,24 +1835,24 @@
+ case 1 *4+ 1:
+ assert(src == T_INT || is_subword_type(src), "source is not float");
+ // Subword-related cases are int -> {boolean,byte,char,short}.
+- ek = _adapter_opt_i2i;
++ ek_opt = _adapter_opt_i2i;
+ vminfo = adapter_subword_vminfo(dest);
+ break;
+ case 2 *4+ 1:
+ if (src == T_LONG && (dest == T_INT || is_subword_type(dest))) {
+- ek = _adapter_opt_l2i;
++ ek_opt = _adapter_opt_l2i;
+ vminfo = adapter_subword_vminfo(dest);
+ } else if (src == T_DOUBLE && dest == T_FLOAT) {
+- ek = _adapter_opt_d2f;
++ ek_opt = _adapter_opt_d2f;
+ } else {
+ assert(false, "");
+ }
+ break;
+ case 1 *4+ 2:
+ if (src == T_INT && dest == T_LONG) {
+- ek = _adapter_opt_i2l;
++ ek_opt = _adapter_opt_i2l;
+ } else if (src == T_FLOAT && dest == T_DOUBLE) {
+- ek = _adapter_opt_f2d;
++ ek_opt = _adapter_opt_f2d;
+ } else {
+ assert(false, "");
+ }
+@@ -1811,15 +1864,15 @@
+ }
+ break;
+
+- case _adapt_ref_to_prim:
++ case _adapter_ref_to_prim:
+ {
+ switch (type2size[dest]) {
+ case 1:
+- ek = _adapter_opt_a2i;
++ ek_opt = _adapter_opt_unboxi;
+ vminfo = adapter_subword_vminfo(dest);
+ break;
+ case 2:
+- ek = _adapter_opt_a2l;
++ ek_opt = _adapter_opt_unboxl;
+ break;
+ default:
+ assert(false, "");
+@@ -1828,26 +1881,26 @@
+ }
+ break;
+
+- case _adapt_prim_to_ref:
++ case _adapter_prim_to_ref:
+ goto throw_not_impl; // allocates, hence could block
+
+- case _adapt_swap_args:
+- case _adapt_rot_args:
++ case _adapter_swap_args:
++ case _adapter_rot_args:
+ {
+ int swap_slots = type2size[src];
+ oop mtype = impl_java_dyn_AdapterMethodHandle::type(mh());
+ int slot_limit = impl_java_dyn_AdapterMethodHandle::vmslots(mtype);
+ int src_slot = argslot;
+ int dest_slot = vminfo;
+- int rotate = (ak == _adapt_swap_args) ? 0 : (src_slot > dest_slot) ? 1 : -1;
++ int rotate = (ek_orig == _adapter_swap_args) ? 0 : (src_slot > dest_slot) ? 1 : -1;
+ switch (swap_slots) {
+ case 1:
+- ek = (!rotate ? _adapter_opt_swap_1 :
+- rotate > 0 ? _adapter_opt_rot_1_up : _adapter_opt_rot_1_down);
++ ek_opt = (!rotate ? _adapter_opt_swap_1 :
++ rotate > 0 ? _adapter_opt_rot_1_up : _adapter_opt_rot_1_down);
+ break;
+ case 2:
+- ek = (!rotate ? _adapter_opt_swap_2 :
+- rotate > 0 ? _adapter_opt_rot_2_up : _adapter_opt_rot_2_down);
++ ek_opt = (!rotate ? _adapter_opt_swap_2 :
++ rotate > 0 ? _adapter_opt_rot_2_up : _adapter_opt_rot_2_down);
+ break;
+ default:
+ assert(false, "");
+@@ -1856,15 +1909,10 @@
+ }
+ break;
+
+- case _adapt_dup_args:
+- case _adapt_drop_args:
+- // these work fine via general case code
+- break;
+-
+- case _adapt_collect_args:
++ case _adapter_collect_args:
+ goto throw_not_impl; // allocates, hence could block
+
+- case _adapt_spread_args:
++ case _adapter_spread_args:
+ {
+ // vminfo will be the required length of the array
+ int slots_pushed = stack_move / stack_move_unit();
+@@ -1872,44 +1920,43 @@
+ assert(array_size >= 0, "");
+ vminfo = array_size;
+ switch (array_size) {
+- case 0: ek = _adapt_opt_spread_0; break;
+- case 1: ek = _adapt_opt_spread_1; break;
+- default: ek = _adapt_opt_spread_more; break;
++ case 0: ek_opt = _adapter_opt_spread_0; break;
++ case 1: ek_opt = _adapter_opt_spread_1; break;
++ default: ek_opt = _adapter_opt_spread_more; break;
+ }
+- if ((vminfo & _CONV_VMINFO_MASK) != vminfo)
++ if ((vminfo & CONV_VMINFO_MASK) != vminfo)
+ goto throw_not_impl; // overflow
+ }
+ break;
+
+- case _adapt_flyby:
+- case _adapt_ricochet:
++ case _adapter_flyby:
++ case _adapter_ricochet:
+ goto throw_not_impl; // runs Java code, hence could block
+
++ default:
++ // should have failed much earlier; must be a missing case here
++ assert(false, "incomplete switch");
++ // and fall through:
++
+ throw_not_impl:
+ // FIXME: these adapters are NYI
+- throw_InternalError(adapter_entry_name(ak), CHECK);
++ err = "adapter not yet implemented in the JVM";
++ break;
++ }
++
++ if (err != NULL) {
++ throw_InternalError_for_bad_conversion(conversion, err, THREAD);
+ return;
+ }
+
+ // Rebuild the conversion value; maybe parts of it were changed.
+- jint new_conversion = (((int)ak << _CONV_OP_SHIFT) |
+- (src << _CONV_SRC_TYPE_SHIFT) |
+- (dest << _CONV_DEST_TYPE_SHIFT) |
+- (stack_move << _CONV_STACK_MOVE_SHIFT) |
+- (vminfo << _CONV_VMINFO_SHIFT) );
+-
+- // Take it apart again, just to make sure:
+- assert(adapter_conversion_op(new_conversion) == ak, "");
+- assert(adapter_conversion_vminfo(new_conversion) == vminfo, "");
+- assert(adapter_conversion_src_type(new_conversion) == src, "");
+- assert(adapter_conversion_dest_type(new_conversion) == dest, "");
+- assert(adapter_conversion_stack_move(new_conversion) == stack_move, "");
++ jint new_conversion = adapter_conversion(conv_op, src, dest, stack_move, vminfo);
+
+ // Finalize the conversion field. (Note that it is final to Java code.)
+ impl_java_dyn_AdapterMethodHandle::set_conversion(mh(), new_conversion);
+
+ // Done!
+- java_dyn_MethodHandle::set_vmentry(mh(), entry(ek));
++ java_dyn_MethodHandle::set_vmentry(mh(), entry(ek_opt));
+
+ // There should be enough memory barriers on exit from native methods
+ // to ensure that the MH is fully initialized to all threads before
+@@ -1929,6 +1976,9 @@
+ // They are the private interface between this JVM and the HotSpot-specific
+ // Java code that implements JSR 292 method handles.
+ //
++// Note: We use a JVM_ENTRY macro to define each of these, for this is the way
++// that intrinsic (non-JNI) native methods are defined in HotSpot.
++//
+
+ // direct method handles for invokestatic or invokespecial
+ // void init(DirectMethodHandle self, MemberName ref, boolean doDispatch, Class<?> caller);
+@@ -1937,14 +1987,14 @@
+ ResourceMark rm; // for error messages
+
+ // This is the guy we are initializing:
+- if (mh_jh == NULL) { throw_InternalError(CHECK); }
++ if (mh_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); }
+ Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh));
+
+ // Early returns out of this method leave the DMH in an unfinished state.
+ assert(java_dyn_MethodHandle::vmentry(mh()) == NULL, "must be safely null");
+
+ // which method are we really talking about?
+- if (target_jh == NULL) { throw_InternalError(CHECK); }
++ if (target_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); }
+ oop target_oop = JNIHandles::resolve_non_null(target_jh);
+ if (impl_java_dyn_MemberName::is_instance(target_oop) &&
+ impl_java_dyn_MemberName::vmindex(target_oop) == VM_INDEX_UNINITIALIZED) {
+@@ -1957,7 +2007,7 @@
+ methodHandle m(THREAD,
+ MethodHandles::decode_method(target_oop,
+ receiver_limit, decode_flags));
+- if (m.is_null()) { throw_InternalError("no such method", CHECK); }
++ if (m.is_null()) { THROW_MSG(vmSymbols::java_lang_InternalError(), "no such method"); }
+
+ // The trusted Java code that calls this method should already have performed
+ // access checks on behalf of the given caller. But, we can verify this.
+@@ -1970,14 +2020,14 @@
+ klassOop reference_klass = m->method_holder(); // OK approximation
+ if (receiver_limit != NULL && receiver_limit != reference_klass) {
+ if (!Klass::cast(receiver_limit)->is_subtype_of(reference_klass))
+- throw_InternalError("receiver limit out of bounds", CHECK); // Java code bug
++ THROW_MSG(vmSymbols::java_lang_InternalError(), "receiver limit out of bounds"); // Java code bug
+ reference_klass = receiver_limit;
+ }
+ // Emulate LinkResolver::check_klass_accessability.
+ if (!Reflection::verify_class_access(caller->as_klassOop(),
+ reference_klass,
+ true)) {
+- throw_InternalError(Klass::cast(m->method_holder())->external_name(), CHECK);
++ THROW_MSG(vmSymbols::java_lang_InternalError(), Klass::cast(m->method_holder())->external_name());
+ }
+ // If there were a bytecode, the next step would be to lookup the method
+ // in the reference class, then then check the method's access bits.
+@@ -1991,7 +2041,7 @@
+ bool same_pm = Reflection::is_same_package_member(caller->as_klassOop(),
+ reference_klass, THREAD);
+ if (!same_pm) {
+- throw_InternalError(m->name_and_sig_as_C_string(), CHECK);
++ THROW_MSG(vmSymbols::java_lang_InternalError(), m->name_and_sig_as_C_string());
+ }
+ }
+ }
+@@ -2006,22 +2056,25 @@
+ ResourceMark rm; // for error messages
+
+ // This is the guy we are initializing:
+- if (mh_jh == NULL) { throw_InternalError(CHECK); }
++ if (mh_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); }
+ Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh));
+
+ // Early returns out of this method leave the BMH in an unfinished state.
+ assert(java_dyn_MethodHandle::vmentry(mh()) == NULL, "must be safely null");
+
+- if (target_jh == NULL) { throw_InternalError(CHECK); }
++ if (target_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); }
+ Handle target(THREAD, JNIHandles::resolve_non_null(target_jh));
+
+ if (!java_dyn_MethodHandle::is_instance(target())) {
+ // Target object is a reflective method. (%%% Do we need this alternate path?)
+ Untested("init_BMH of non-MH");
+- if (argnum != 0) { throw_InternalError(CHECK); }
+- int decode_flags = 0; klassOop receiver_limit = NULL;
+- methodOop m = MethodHandles::decode_method(target(),
+- receiver_limit, decode_flags);
++ if (argnum != 0) { THROW(vmSymbols::java_lang_InternalError()); }
++ int decode_flags = 0; klassOop receiver_limit_oop = NULL;
++ methodHandle m(THREAD,
++ MethodHandles::decode_method(target(),
++ receiver_limit_oop,
++ decode_flags));
++ KlassHandle receiver_limit(THREAD, receiver_limit_oop);
+ MethodHandles::init_BoundMethodHandle_with_receiver(mh, m,
+ receiver_limit,
+ decode_flags,
+@@ -2038,8 +2091,9 @@
+ JVM_ENTRY(void, MHI_init_AMH(JNIEnv *env, jobject igcls, jobject mh_jh,
+ jobject target_jh, int argnum)) {
+ // This is the guy we are initializing:
+- if (mh_jh == NULL || target_jh == NULL)
+- { throw_InternalError(CHECK); }
++ if (mh_jh == NULL || target_jh == NULL) {
++ THROW(vmSymbols::java_lang_InternalError());
++ }
+ Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh));
+ Handle target(THREAD, JNIHandles::resolve_non_null(target_jh));
+
+@@ -2072,9 +2126,10 @@
+
+ // debugging and reflection
+ JVM_ENTRY(jobject, MHI_getTarget(JNIEnv *env, jobject igcls, jobject mh_jh, jint format)) {
+- oop mh = JNIHandles::resolve(mh_jh);
+- if (!java_dyn_MethodHandle::is_instance(mh))
+- { throw_IllegalArgumentException(THREAD); return NULL; }
++ Handle mh(THREAD, JNIHandles::resolve(mh_jh));
++ if (!java_dyn_MethodHandle::is_instance(mh())) {
++ THROW_NULL(vmSymbols::java_lang_IllegalArgumentException());
++ }
+ oop target = MethodHandles::encode_target(mh, format, CHECK_NULL);
+ return JNIHandles::make_local(THREAD, target);
+ }
+@@ -2109,19 +2164,20 @@
+ template(impl_java_dyn_MemberName,MN_SEARCH_SUPERCLASSES) \
+ template(impl_java_dyn_MemberName,MN_SEARCH_INTERFACES) \
+ template(impl_java_dyn_MemberName,VM_INDEX_UNINITIALIZED) \
+- template(impl_java_dyn_AdapterMethodHandle,RETYPE_ONLY) \
+- template(impl_java_dyn_AdapterMethodHandle,CHECK_CAST) \
+- template(impl_java_dyn_AdapterMethodHandle,PRIM_TO_PRIM) \
+- template(impl_java_dyn_AdapterMethodHandle,REF_TO_PRIM) \
+- template(impl_java_dyn_AdapterMethodHandle,PRIM_TO_REF) \
+- template(impl_java_dyn_AdapterMethodHandle,SWAP_ARGS) \
+- template(impl_java_dyn_AdapterMethodHandle,ROT_ARGS) \
+- template(impl_java_dyn_AdapterMethodHandle,DUP_ARGS) \
+- template(impl_java_dyn_AdapterMethodHandle,DROP_ARGS) \
+- template(impl_java_dyn_AdapterMethodHandle,COLLECT_ARGS) \
+- template(impl_java_dyn_AdapterMethodHandle,SPREAD_ARGS) \
+- template(impl_java_dyn_AdapterMethodHandle,FLYBY) \
+- template(impl_java_dyn_AdapterMethodHandle,RICOCHET) \
++ template(impl_java_dyn_AdapterMethodHandle,OP_RETYPE_ONLY) \
++ template(impl_java_dyn_AdapterMethodHandle,OP_CHECK_CAST) \
++ template(impl_java_dyn_AdapterMethodHandle,OP_PRIM_TO_PRIM) \
++ template(impl_java_dyn_AdapterMethodHandle,OP_REF_TO_PRIM) \
++ template(impl_java_dyn_AdapterMethodHandle,OP_PRIM_TO_REF) \
++ template(impl_java_dyn_AdapterMethodHandle,OP_SWAP_ARGS) \
++ template(impl_java_dyn_AdapterMethodHandle,OP_ROT_ARGS) \
++ template(impl_java_dyn_AdapterMethodHandle,OP_DUP_ARGS) \
++ template(impl_java_dyn_AdapterMethodHandle,OP_DROP_ARGS) \
++ template(impl_java_dyn_AdapterMethodHandle,OP_COLLECT_ARGS) \
++ template(impl_java_dyn_AdapterMethodHandle,OP_SPREAD_ARGS) \
++ template(impl_java_dyn_AdapterMethodHandle,OP_FLYBY) \
++ template(impl_java_dyn_AdapterMethodHandle,OP_RICOCHET) \
++ template(impl_java_dyn_AdapterMethodHandle,CONV_OP_LIMIT) \
+ template(impl_java_dyn_AdapterMethodHandle,CONV_OP_MASK) \
+ template(impl_java_dyn_AdapterMethodHandle,CONV_VMINFO_MASK) \
+ template(impl_java_dyn_AdapterMethodHandle,CONV_VMINFO_SHIFT) \
+@@ -2166,7 +2222,7 @@
+
+ // void init(MemberName self, AccessibleObject ref)
+ JVM_ENTRY(void, MHI_init_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jobject target_jh)) {
+- if (mname_jh == NULL || target_jh == NULL) { throw_InternalError(CHECK); }
++ if (mname_jh == NULL || target_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); }
+ Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh));
+ oop target_oop = JNIHandles::resolve_non_null(target_jh);
+ MethodHandles::init_MemberName(mname(), target_oop);
+@@ -2175,7 +2231,7 @@
+
+ // void expand(MemberName self)
+ JVM_ENTRY(void, MHI_expand_Mem(JNIEnv *env, jobject igcls, jobject mname_jh)) {
+- if (mname_jh == NULL) { throw_InternalError(CHECK); }
++ if (mname_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); }
+ Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh));
+ MethodHandles::expand_MemberName(mname, 0, CHECK);
+ }
+@@ -2183,7 +2239,7 @@
+
+ // void resolve(MemberName self, Class<?> caller)
+ JVM_ENTRY(void, MHI_resolve_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jclass caller_jh)) {
+- if (mname_jh == NULL) { throw_InternalError(CHECK); }
++ if (mname_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); }
+ Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh));
+ // %%% take caller into account!
+ MethodHandles::resolve_MemberName(mname, CHECK);
+diff --git a/src/share/vm/prims/methodHandles.hpp b/src/share/vm/prims/methodHandles.hpp
+--- a/src/share/vm/prims/methodHandles.hpp
++++ b/src/share/vm/prims/methodHandles.hpp
+@@ -31,31 +31,6 @@
+ // in java.dyn and java.dyn.hotspot.
+ // See also javaClasses for layouts java_dyn_Method{Handle,Type,Type::Form}.
+ public:
+- enum AdapterKind {
+- // these constants must align with a set of values in impl/java/dyn/AMH.java:
+- _adapt_retype_only = 0x0, // no argument changes; straight retype
+- _adapt_check_cast = 0x1, // ref-to-ref conversion; requires a Class argument
+- _adapt_prim_to_prim = 0x2, // converts from one primitive to another
+- _adapt_ref_to_prim = 0x3, // unboxes a wrapper to produce a primitive
+- _adapt_prim_to_ref = 0x4, // boxes a primitive into a wrapper (NYI)
+- _adapt_swap_args = 0x5, // permutes arguments (NYI)
+- _adapt_rot_args = 0x6, // permutes arguments (NYI)
+- _adapt_dup_args = 0x7, // duplicates one or more arguments (at TOS)
+- _adapt_drop_args = 0x8, // remove one or more argument slots
+- _adapt_collect_args = 0x9, // combine one or more arguments into a varargs (NYI)
+- _adapt_spread_args = 0xA, // expand in place a varargs array (of known size)
+- _adapt_flyby = 0xB, // operate first on reified argument list (NYI)
+- _adapt_ricochet = 0xC, // run an adapter chain on the return value (NYI)
+- _AK_LIMIT
+- };
+- enum { // format of AMH.conversion field
+- _CONV_VMINFO_MASK = 0x0FF, // LSB is reserved for JVM use
+- _CONV_VMINFO_SHIFT = 0, // position of bits in CONV_VMINFO_MASK
+- _CONV_OP_SHIFT = 8, // position of bits in CONV_OP_MASK
+- _CONV_DEST_TYPE_SHIFT = 12, // byte 3 has the target BasicType (if needed)
+- _CONV_SRC_TYPE_SHIFT = 16, // byte 2 has the source BasicType (if needed)
+- _CONV_STACK_MOVE_SHIFT = 20 // high 12 bits give signed SP change
+- };
+ enum EntryKind {
+ _check_mtype, // how a caller calls a MH
+ _wrong_method_type, // what happens when there is a type mismatch
+@@ -70,8 +45,21 @@
+ _bound_int_direct_mh,
+ _bound_long_direct_mh,
+
+- _adapter_mh_first, // adapter sequence goes here...
+- _adapter_mh_last = _adapter_mh_first + (_AK_LIMIT - 1),
++ _adapter_mh_first, // adapter sequence goes here...
++ _adapter_retype_only = _adapter_mh_first + impl_java_dyn_AdapterMethodHandle::OP_RETYPE_ONLY,
++ _adapter_check_cast = _adapter_mh_first + impl_java_dyn_AdapterMethodHandle::OP_CHECK_CAST,
++ _adapter_prim_to_prim = _adapter_mh_first + impl_java_dyn_AdapterMethodHandle::OP_PRIM_TO_PRIM,
++ _adapter_ref_to_prim = _adapter_mh_first + impl_java_dyn_AdapterMethodHandle::OP_REF_TO_PRIM,
++ _adapter_prim_to_ref = _adapter_mh_first + impl_java_dyn_AdapterMethodHandle::OP_PRIM_TO_REF,
++ _adapter_swap_args = _adapter_mh_first + impl_java_dyn_AdapterMethodHandle::OP_SWAP_ARGS,
++ _adapter_rot_args = _adapter_mh_first + impl_java_dyn_AdapterMethodHandle::OP_ROT_ARGS,
++ _adapter_dup_args = _adapter_mh_first + impl_java_dyn_AdapterMethodHandle::OP_DUP_ARGS,
++ _adapter_drop_args = _adapter_mh_first + impl_java_dyn_AdapterMethodHandle::OP_DROP_ARGS,
++ _adapter_collect_args = _adapter_mh_first + impl_java_dyn_AdapterMethodHandle::OP_COLLECT_ARGS,
++ _adapter_spread_args = _adapter_mh_first + impl_java_dyn_AdapterMethodHandle::OP_SPREAD_ARGS,
++ _adapter_flyby = _adapter_mh_first + impl_java_dyn_AdapterMethodHandle::OP_FLYBY,
++ _adapter_ricochet = _adapter_mh_first + impl_java_dyn_AdapterMethodHandle::OP_RICOCHET,
++ _adapter_mh_last = _adapter_mh_first + impl_java_dyn_AdapterMethodHandle::CONV_OP_LIMIT - 1,
+
+ // Optimized adapter types
+
+@@ -93,13 +81,13 @@
+ // conversion between floating point and integer type is handled by Java
+
+ // reference to primitive:
+- _adapter_opt_a2i,
+- _adapter_opt_a2l,
++ _adapter_opt_unboxi,
++ _adapter_opt_unboxl,
+
+ // spreading (array length cases 0, 1, >=2)
+- _adapt_opt_spread_0,
+- _adapt_opt_spread_1,
+- _adapt_opt_spread_more,
++ _adapter_opt_spread_0,
++ _adapter_opt_spread_1,
++ _adapter_opt_spread_more,
+
+ _EK_LIMIT,
+ _EK_FIRST = 0
+@@ -110,11 +98,23 @@
+ static void set_enabled(bool z);
+
+ private:
++ enum { // import impl_java_dyn_AdapterMethodHandle::CONV_OP_*
++ CONV_OP_LIMIT = impl_java_dyn_AdapterMethodHandle::CONV_OP_LIMIT,
++ CONV_OP_MASK = impl_java_dyn_AdapterMethodHandle::CONV_OP_MASK,
++ CONV_VMINFO_MASK = impl_java_dyn_AdapterMethodHandle::CONV_VMINFO_MASK,
++ CONV_VMINFO_SHIFT = impl_java_dyn_AdapterMethodHandle::CONV_VMINFO_SHIFT,
++ CONV_OP_SHIFT = impl_java_dyn_AdapterMethodHandle::CONV_OP_SHIFT,
++ CONV_DEST_TYPE_SHIFT = impl_java_dyn_AdapterMethodHandle::CONV_DEST_TYPE_SHIFT,
++ CONV_SRC_TYPE_SHIFT = impl_java_dyn_AdapterMethodHandle::CONV_SRC_TYPE_SHIFT,
++ CONV_STACK_MOVE_SHIFT = impl_java_dyn_AdapterMethodHandle::CONV_STACK_MOVE_SHIFT,
++ CONV_STACK_MOVE_MASK = impl_java_dyn_AdapterMethodHandle::CONV_STACK_MOVE_MASK
++ };
++
+ static bool _enabled;
+ static MethodHandleEntry* _entries[_EK_LIMIT];
+ static const char* _entry_names[_EK_LIMIT+1];
+ static bool ek_valid(EntryKind ek) { return (uint)ek < (uint)_EK_LIMIT; }
+- static bool ak_valid(AdapterKind ak) { return (uint)ak < (uint)_AK_LIMIT; }
++ static bool conv_op_valid(int op) { return (uint)op < (uint)CONV_OP_LIMIT; }
+
+ public:
+ static bool have_entry(EntryKind ek) { return ek_valid(ek) && _entries[ek] != NULL; }
+@@ -122,8 +122,8 @@
+ return _entries[ek]; }
+ static const char* entry_name(EntryKind ek) { assert(ek_valid(ek), "oob");
+ return _entry_names[ek]; }
+- static const char* adapter_entry_name(AdapterKind ak) { assert(ak_valid(ak), "oob");
+- return entry_name(EntryKind(_adapter_mh_first + (int)ak)); }
++ static EntryKind adapter_entry_kind(int op) { assert(conv_op_valid(op), "oob");
++ return EntryKind(_adapter_mh_first + op); }
+
+ static void init_entry(EntryKind ek, MethodHandleEntry* me) {
+ assert(ek_valid(ek), "oob");
+@@ -131,29 +131,36 @@
+ _entries[ek] = me;
+ }
+
+- static jint adapter_conversion(AdapterKind ak, BasicType src, BasicType dest,
++ static jint adapter_conversion(int conv_op, BasicType src, BasicType dest,
+ int stack_move = 0, int vminfo = 0) {
+- return (((int)ak << _CONV_OP_SHIFT)
+- | (src << _CONV_SRC_TYPE_SHIFT)
+- | (dest << _CONV_DEST_TYPE_SHIFT)
+- | (stack_move << _CONV_STACK_MOVE_SHIFT)
+- | (vminfo << _CONV_VMINFO_SHIFT)
+- );
++ assert(conv_op_valid(conv_op), "oob");
++ jint conv = ((conv_op << CONV_OP_SHIFT)
++ | (src << CONV_SRC_TYPE_SHIFT)
++ | (dest << CONV_DEST_TYPE_SHIFT)
++ | (stack_move << CONV_STACK_MOVE_SHIFT)
++ | (vminfo << CONV_VMINFO_SHIFT)
++ );
++ assert(adapter_conversion_op(conv) == conv_op, "decode conv_op");
++ assert(adapter_conversion_src_type(conv) == src, "decode src");
++ assert(adapter_conversion_dest_type(conv) == dest, "decode dest");
++ assert(adapter_conversion_stack_move(conv) == stack_move, "decode stack_move");
++ assert(adapter_conversion_vminfo(conv) == vminfo, "decode vminfo");
++ return conv;
+ }
+- static AdapterKind adapter_conversion_op(jint conv) {
+- return (AdapterKind)((conv >> _CONV_OP_SHIFT) & 0xF);
++ static int adapter_conversion_op(jint conv) {
++ return ((conv >> CONV_OP_SHIFT) & 0xF);
+ }
+ static BasicType adapter_conversion_src_type(jint conv) {
+- return (BasicType)((conv >> _CONV_SRC_TYPE_SHIFT) & 0xF);
++ return (BasicType)((conv >> CONV_SRC_TYPE_SHIFT) & 0xF);
+ }
+ static BasicType adapter_conversion_dest_type(jint conv) {
+- return (BasicType)((conv >> _CONV_DEST_TYPE_SHIFT) & 0xF);
++ return (BasicType)((conv >> CONV_DEST_TYPE_SHIFT) & 0xF);
+ }
+ static int adapter_conversion_stack_move(jint conv) {
+- return (conv >> _CONV_STACK_MOVE_SHIFT);
++ return (conv >> CONV_STACK_MOVE_SHIFT);
+ }
+ static int adapter_conversion_vminfo(jint conv) {
+- return (conv >> _CONV_VMINFO_SHIFT) & _CONV_VMINFO_MASK;
++ return (conv >> CONV_VMINFO_SHIFT) & CONV_VMINFO_MASK;
+ }
+
+ // Offset in words that the interpreter stack pointer moves when an argument is pushed.
+@@ -162,18 +169,18 @@
+ return frame::interpreter_frame_expression_stack_direction() * Interpreter::stackElementWords();
+ }
+
+- enum { _CONV_VMINFO_SIGN_FLAG = 0x80 };
++ enum { CONV_VMINFO_SIGN_FLAG = 0x80 };
+ static int adapter_subword_vminfo(BasicType dest) {
+ if (dest == T_BOOLEAN) return (BitsPerInt - 1);
+ if (dest == T_CHAR) return (BitsPerInt - 16);
+- if (dest == T_BYTE) return (BitsPerInt - 8) | _CONV_VMINFO_SIGN_FLAG;
+- if (dest == T_SHORT) return (BitsPerInt - 16) | _CONV_VMINFO_SIGN_FLAG;
++ if (dest == T_BYTE) return (BitsPerInt - 8) | CONV_VMINFO_SIGN_FLAG;
++ if (dest == T_SHORT) return (BitsPerInt - 16) | CONV_VMINFO_SIGN_FLAG;
+ return 0; // case T_INT
+ }
+ // Here is the transformation the i2i adapter must perform:
+ static int truncate_subword_from_vminfo(jint value, int vminfo) {
+ jint tem = value << vminfo;
+- if ((vminfo & _CONV_VMINFO_SIGN_FLAG) != 0) {
++ if ((vminfo & CONV_VMINFO_SIGN_FLAG) != 0) {
+ return (jint)tem >> vminfo;
+ } else {
+ return (juint)tem >> vminfo;
+@@ -230,7 +237,7 @@
+ _dmf_binds_argument = 0x10,
+ _DMF_BOUND_MASK = (_dmf_binds_argument*2 - _dmf_binds_method),
+ _dmf_adapter_lsb = 0x20,
+- _DMF_ADAPTER_MASK = (_dmf_adapter_lsb << _AK_LIMIT) - _dmf_adapter_lsb
++ _DMF_ADAPTER_MASK = (_dmf_adapter_lsb << CONV_OP_LIMIT) - _dmf_adapter_lsb
+ };
+ static methodOop decode_method(oop x, klassOop& receiver_limit_result, int& decode_flags_result);
+ enum {
+@@ -244,52 +251,41 @@
+ ETF_METHOD_NAME = 2, // ultimate method as MemberName
+ ETF_REFLECT_METHOD = 3 // ultimate method as java.lang.reflect object (sans refClass)
+ };
+- static int get_named_constant(int which, oop name_box, TRAPS);
+- static oop encode_target(oop mh, int format, TRAPS); // report vmtarget (to Java code)
++ static int get_named_constant(int which, Handle name_box, TRAPS);
++ static oop encode_target(Handle mh, int format, TRAPS); // report vmtarget (to Java code)
+ static bool class_cast_needed(klassOop src, klassOop dst);
+
+- static void verify_vmslots(Handle mh, TRAPS);
+- static void verify_vmargslot(Handle mh, int argnum, int argslot, TRAPS);
+- static void verify_method_type_change(oop src_mtype, int src_beg, int src_end,
+- int insert_argnum, oop insert_type,
+- int change_argnum, oop change_type,
+- int delete_argnum,
+- oop dst_mtype, int dst_beg, int dst_end,
+- TRAPS);
+- static void verify_argument_type_change(oop src_type, oop dst_type,
+- int argnum, TRAPS);
+- static void verify_method_type_insertion(oop src_mtype,
+- int insert_argnum, oop insert_type,
+- oop dst_mtype, TRAPS) {
++ private:
++ // These checkers operate on a pair of whole MethodTypes:
++ static const char* check_method_type_change(oop src_mtype, int src_beg, int src_end,
++ int insert_argnum, oop insert_type,
++ int change_argnum, oop change_type,
++ int delete_argnum,
++ oop dst_mtype, int dst_beg, int dst_end);
++ static const char* check_method_type_insertion(oop src_mtype,
++ int insert_argnum, oop insert_type,
++ oop dst_mtype) {
+ oop no_ref = NULL;
+- verify_method_type_change(src_mtype, 0, -1,
+- insert_argnum, insert_type,
+- -1, no_ref, -1, dst_mtype, 0, -1, THREAD);
++ return check_method_type_change(src_mtype, 0, -1,
++ insert_argnum, insert_type,
++ -1, no_ref, -1, dst_mtype, 0, -1);
+ }
+- static void verify_method_type_conversion(oop src_mtype,
+- int change_argnum, oop change_type,
+- oop dst_mtype, TRAPS) {
++ static const char* check_method_type_conversion(oop src_mtype,
++ int change_argnum, oop change_type,
++ oop dst_mtype) {
+ oop no_ref = NULL;
+- verify_method_type_change(src_mtype, 0, -1, -1, no_ref,
+- change_argnum, change_type,
+- -1, dst_mtype, 0, -1, THREAD);
++ return check_method_type_change(src_mtype, 0, -1, -1, no_ref,
++ change_argnum, change_type,
++ -1, dst_mtype, 0, -1);
+ }
+- static void verify_method_type_passthrough(oop src_mtype, oop dst_mtype, TRAPS) {
++ static const char* check_method_type_passthrough(oop src_mtype, oop dst_mtype) {
+ oop no_ref = NULL;
+- verify_method_type_change(src_mtype, 0, -1,
+- -1, no_ref, -1, no_ref, -1,
+- dst_mtype, 0, -1, THREAD);
++ return check_method_type_change(src_mtype, 0, -1,
++ -1, no_ref, -1, no_ref, -1,
++ dst_mtype, 0, -1);
+ }
+
+- static void verify_method_type(methodHandle m, oop mtype,
+- bool has_bound_oop,
+- klassOop bound_oop_type,
+- TRAPS);
+-
+- static void verify_method_signature(methodHandle m, Handle mtype,
+- int first_ptype_pos,
+- KlassHandle insert_ptype, TRAPS);
+-
++ // These checkers operate on pairs of argument or return types:
+ static const char* check_argument_type_change(BasicType src_type, klassOop src_klass,
+ BasicType dst_type, klassOop dst_klass,
+ int argnum);
+@@ -312,8 +308,28 @@
+ return check_argument_type_change(src_type, src_klass, dst_type, dst_klass, -1);
+ }
+
+- static const char* check_method_receiver(methodHandle m, klassOop passed_recv_type);
++ static const char* check_method_receiver(methodOop m, klassOop passed_recv_type);
+
++ // These verifiers can block, and will throw an error if the checking fails:
++ static void verify_vmslots(Handle mh, TRAPS);
++ static void verify_vmargslot(Handle mh, int argnum, int argslot, TRAPS);
++
++ static void verify_method_type(methodHandle m, Handle mtype,
++ bool has_bound_oop,
++ KlassHandle bound_oop_type,
++ TRAPS);
++
++ static void verify_method_signature(methodHandle m, Handle mtype,
++ int first_ptype_pos,
++ KlassHandle insert_ptype, TRAPS);
++
++ static void verify_DirectMethodHandle(Handle mh, methodHandle m, TRAPS);
++ static void verify_BoundMethodHandle(Handle mh, Handle target, int argnum,
++ bool direct_to_method, TRAPS);
++ static void verify_BoundMethodHandle_with_receiver(Handle mh, methodHandle m, TRAPS);
++ static void verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS);
++
++ public:
+
+ // Fill in the fields of a DirectMethodHandle mh. (MH.type must be pre-filled.)
+ static void init_DirectMethodHandle(Handle mh, methodHandle method, bool do_dispatch, TRAPS);
+@@ -321,8 +337,8 @@
+ // Fill in the fields of a BoundMethodHandle mh. (MH.type, BMH.argument must be pre-filled.)
+ static void init_BoundMethodHandle(Handle mh, Handle target, int argnum, TRAPS);
+ static void init_BoundMethodHandle_with_receiver(Handle mh,
+- methodOop original_m_oop,
+- klassOop receiver_limit_oop,
++ methodHandle original_m,
++ KlassHandle receiver_limit,
+ int decode_flags,
+ TRAPS);
+
+@@ -334,9 +350,11 @@
+ #endif
+
+ private:
+- static methodOop dispatch_decoded_method(methodOop m, klassOop receiver_limit, int decode_flags,
+- klassOop receiver_klass,
+- TRAPS);
++ static methodHandle dispatch_decoded_method(methodHandle m,
++ KlassHandle receiver_limit,
++ int decode_flags,
++ KlassHandle receiver_klass,
++ TRAPS);
+
+ static bool same_basic_type_for_arguments(BasicType src, BasicType dst,
+ bool for_return = false);
+diff --git a/src/share/vm/runtime/sharedRuntime.hpp b/src/share/vm/runtime/sharedRuntime.hpp
+--- a/src/share/vm/runtime/sharedRuntime.hpp
++++ b/src/share/vm/runtime/sharedRuntime.hpp
+@@ -234,6 +234,7 @@
+ *
+ * @param name the name of the class of the object attempted to be cast
+ * @param klass the name of the target klass attempt
++ * @param gripe the specific kind of problem being reported
+ * @return the dynamically allocated exception message (must be freed
+ * by the caller using a resource mark)
+ *
+diff --git a/src/share/vm/utilities/exceptions.hpp b/src/share/vm/utilities/exceptions.hpp
+--- a/src/share/vm/utilities/exceptions.hpp
++++ b/src/share/vm/utilities/exceptions.hpp
+@@ -237,6 +237,9 @@
+ #define THROW_ARG_0(name, signature, arg) THROW_ARG_(name, signature, arg, 0)
+ #define THROW_MSG_CAUSE_0(name, message, cause) THROW_MSG_CAUSE_(name, message, cause, 0)
+
++#define THROW_NULL(name) THROW_(name, NULL)
++#define THROW_MSG_NULL(name, message) THROW_MSG_(name, message, NULL)
++
+ // The CATCH macro checks that no exception has been thrown by a function; it is used at
+ // call sites about which is statically known that the callee cannot throw an exception
+ // even though it is declared with TRAPS.