--- a/meth.patch Wed Nov 12 22:25:14 2008 -0800
+++ b/meth.patch Wed Dec 24 19:53:52 2008 -0800
@@ -69,7 +69,7 @@ diff --git a/src/cpu/sparc/vm/assembler_
+ assert_different_registers(mh_reg, temp_reg);
+
+ // pick out the interpreted side of the handler
-+ ld_ptr(mh_reg, delayed_value(java_dyn_MethodHandle::entry_offset_in_bytes, temp_reg), temp_reg);
++ ld_ptr(mh_reg, delayed_value(java_dyn_MethodHandle::vmentry_offset_in_bytes, temp_reg), temp_reg);
+
+ // off we go...
+ ld_ptr(temp_reg, MethodEntry::from_interpreted_entry_offset_in_bytes(), temp_reg);
@@ -457,7 +457,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp
-@@ -0,0 +1,444 @@
+@@ -0,0 +1,443 @@
+/*
+ * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -523,7 +523,7 @@ new file mode 100644
+ // I5_savedSP: sender SP (must preserve)
+ // G4 (Gargs): incoming argument list (must preserve)
+ // G5_method: invoke methodOop; becomes method type.
-+ // G3_method_handle: receiver method handle (must load from sp[MTForm.vmdata])
++ // G3_method_handle: receiver method handle (must load from sp[MethodTypeForm.vmslots])
+ // O0, O1: garbage temps, blown away
+ Register O0_argslot = O0;
+ Register O1_scratch = O1;
@@ -543,11 +543,10 @@ new file mode 100644
+
+ // given the MethodType, find out where the MH argument is buried
+ __ ld_ptr(G5_method_type,
-+ __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, O1_scratch,
-+ oopDesc::address_padding_in_bytes()),
++ __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, O1_scratch),
+ O0_argslot);
+ __ ldx(O0_argslot,
-+ __ delayed_value(java_dyn_MethodType::Form::vmdata_offset_in_bytes, O1_scratch),
++ __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, O1_scratch),
+ O0_argslot);
+ __ ld_ptr(Gargs, __ argument_offset(O0_argslot), G3_method_handle);
+
@@ -582,14 +581,14 @@ new file mode 100644
+ Register O1_scratch = O1;
+ Register G5_index = G5;
+
-+ guarantee(java_dyn_MethodHandle::vmdata_offset_in_bytes() != 0, "must have offsets");
++ guarantee(java_dyn_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets");
+
+ // some handy addresses
-+ Address G5_method_fie( G5_method, 0, in_bytes(methodOopDesc::from_interpreted_offset()) );
-+ Address G3_mh_vmref( G3_method_handle, 0, java_dyn_MethodHandle::vmref_offset_in_bytes() );
-+ Address G3_mh_vmargslot( G3_method_handle, 0, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes() );
-+ Address G3_mh_vmindex( G3_method_handle, 0, java_dyn_MethodHandle::vmdata_index_offset_in_bytes() );
-+ Address G3_method_target( G3_method_handle, 0, java_dyn_MethodHandle::target_offset_in_bytes() ); //AMH
++ Address G5_method_fie( G5_method, 0, in_bytes(methodOopDesc::from_interpreted_offset()) );
++ Address G3_mh_vmref( G3_method_handle, 0, java_dyn_MethodHandle::vmref_offset_in_bytes() );
++ Address G3_mh_vmargslot( G3_method_handle, 0, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes() );
++ Address G3_mh_vmindex( G3_method_handle, 0, java_dyn_MethodHandle::vmdata_index_offset_in_bytes() );
++ Address G3_amh_target( G3_method_handle, 0, java_dyn_MethodHandle::vmtarget_offset_in_bytes() ); //AMH
+
+ if (have_entry(ek)) {
+ __ nop(); // empty stubs make SG sick
@@ -778,7 +777,7 @@ new file mode 100644
+ }
+
+ // immediately jump to the next MH layer:
-+ __ ld_ptr(G3_method_target, G3_method_handle);
++ __ ld_ptr(G3_amh_target, G3_method_handle);
+ __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
+ __ delayed()->nop();
+ // This is OK when all parameter types widen.
@@ -801,7 +800,7 @@ new file mode 100644
+ RegisterConstant arg = __ argument_offset(O0_argslot);
+
+ // get the new MH:
-+ __ ld_ptr(G3_method_target, G3_method_handle);
++ __ ld_ptr(G3_amh_target, G3_method_handle);
+ // (now we are done with the old MH)
+
+ if (ak == _adapt_test_boolean) {
@@ -852,7 +851,7 @@ new file mode 100644
+ __ ld_ptr(G3_mh_vmref, G5_klass);
+
+ // get the new MH:
-+ __ ld_ptr(G3_method_target, G3_method_handle);
++ __ ld_ptr(G3_amh_target, G3_method_handle);
+ // (now we are done with the old MH)
+
+ Label done;
@@ -1002,7 +1001,36 @@ diff --git a/src/cpu/x86/vm/assembler_x8
diff --git a/src/cpu/x86/vm/assembler_x86.cpp b/src/cpu/x86/vm/assembler_x86.cpp
--- a/src/cpu/x86/vm/assembler_x86.cpp
+++ b/src/cpu/x86/vm/assembler_x86.cpp
-@@ -7088,6 +7088,223 @@
+@@ -6244,6 +6244,28 @@
+ return off;
+ }
+
++void MacroAssembler::load_sized_value(Register dst, Address src,
++ int size_in_bytes, bool is_signed) {
++ switch (size_in_bytes ^ (is_signed ? -1 : 0)) {
++#ifndef _LP64
++ // For case 8, caller is responsible for manually loading
++ // the high word into another register.
++ case ~8: // fall through:
++ case 8: movl( dst, src ); break;
++#else
++ case ~8: // fall through:
++ case 8: movq( dst, src ); break;
++#endif
++ case ~4: // fall through:
++ case 4: movl( dst, src ); break;
++ case ~2: load_signed_word( dst, src ); break;
++ case 2: load_unsigned_word( dst, src ); break;
++ case ~1: load_signed_byte( dst, src ); break;
++ case 1: load_unsigned_byte( dst, src ); break;
++ default: ShouldNotReachHere();
++ }
++}
++
+ void MacroAssembler::mov32(AddressLiteral dst, Register src) {
+ if (reachable(dst)) {
+ movl(as_Address(dst), src);
+@@ -7088,6 +7110,241 @@
// call indirectly to solve generation ordering problem
movptr(rax, ExternalAddress(StubRoutines::verify_oop_subroutine_entry_address()));
call(rax);
@@ -1185,6 +1213,22 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+}
+
+
++void MacroAssembler::load_method_handle_vmslots(Register vmslots_reg, Register mh_reg,
++ Register temp_reg) {
++ if (UseCompressedOops) unimplemented(); // field accesses must decode
++ // load mh.type.form.vmslots
++ if (java_dyn_MethodHandle::vmslots_offset_in_bytes() != 0) {
++ // hoist vmslots into every mh to avoid dependent load chain
++ movl(vmslots_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::vmslots_offset_in_bytes, temp_reg)));
++ } else {
++ Register temp2_reg = vmslots_reg;
++ movptr(temp2_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg)));
++ movptr(temp2_reg, Address(temp2_reg, delayed_value(java_dyn_MethodType::form_offset_in_bytes, temp_reg)));
++ movl(vmslots_reg, Address(temp2_reg, delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, temp_reg)));
++ }
++}
++
++
+// registers on entry:
+// - rcx: method handle
+// - rdx: killable temp (interpreted only)
@@ -1196,7 +1240,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ if (UseCompressedOops) unimplemented(); // field accesses must decode
+
+ // pick out the interpreted side of the handler
-+ movptr(temp_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::entry_offset_in_bytes, temp_reg)));
++ movptr(temp_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::vmentry_offset_in_bytes, temp_reg)));
+
+ // off we go...
+ jmp(Address(temp_reg, MethodEntry::from_interpreted_entry_offset_in_bytes()));
@@ -1209,10 +1253,12 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+Address MacroAssembler::argument_address(RegisterConstant arg_slot,
+ int extra_slot_offset) {
+ // cf. TemplateTable::prepare_invoke(), if (load_receiver).
-+ int stackElementSize = Interpreter::stackElementWords() * wordSize;
++ int stackElementSize = Interpreter::stackElementSize();
+ int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
++#ifdef ASSERT
+ int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1);
+ assert(offset1 - offset == stackElementSize, "correct arithmetic");
++#endif
+ Register scale_reg = noreg;
+ Address::ScaleFactor scale_factor = Address::no_scale;
+ if (arg_slot.is_constant()) {
@@ -1272,7 +1318,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
private:
Register _base;
-@@ -197,6 +226,16 @@
+@@ -197,6 +226,22 @@
"inconsistent address");
}
@@ -1286,10 +1332,16 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ "inconsistent address");
+ }
+
++ Address plus_disp(int disp) {
++ Address result = (*this);
++ result._disp += disp;
++ return result;
++ }
++
// The following two overloads are used in connection with the
// ByteSize type (see sizes.hpp). They simplify the use of
// ByteSize'd arguments in assembly code. Note that their equivalent
-@@ -224,6 +263,17 @@
+@@ -224,6 +269,17 @@
assert(!index->is_valid() == (scale == Address::no_scale),
"inconsistent address");
}
@@ -1307,7 +1359,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
#endif // ASSERT
// accessors
-@@ -240,6 +290,14 @@
+@@ -240,6 +296,14 @@
static Address make_array(ArrayAddress);
@@ -1322,10 +1374,21 @@ diff --git a/src/cpu/x86/vm/assembler_x8
private:
bool base_needs_rex() const {
-@@ -1721,6 +1779,37 @@
+@@ -1404,6 +1468,9 @@
+ // Support for sign-extension (hi:lo = extend_sign(lo))
+ void extend_sign(Register hi, Register lo);
+
++ // Loading values by size and signed-ness
++ void load_sized_value(Register dst, Address src, int size_in_bytes, bool is_signed);
++
+ // Support for inc/dec with optimal instruction selection depending on value
+
+ void increment(Register reg, int value = 1) { LP64_ONLY(incrementq(reg, value)) NOT_LP64(incrementl(reg, value)) ; }
+@@ -1720,6 +1787,39 @@
+ Label& slow_case // continuation point if fast allocation fails
);
void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case);
-
++
+ // small bootstrap problems
+ RegisterConstant delayed_value(intptr_t* delayed_value_addr, Register tmp);
+ RegisterConstant delayed_value(int(*value_fn)(), Register tmp) {
@@ -1347,6 +1410,8 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ void check_method_handle_type(Register mtype_reg, Register mh_reg,
+ Register temp_reg,
+ Label& wrong_method_type);
++ void load_method_handle_vmslots(Register vmslots_reg, Register mh_reg,
++ Register temp_reg);
+ void jump_to_method_handle_entry(Register mh_reg, Register temp_reg);
+ Address argument_address(RegisterConstant arg_slot, int extra_slot_offset = 0);
+
@@ -1356,10 +1421,9 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ Register super_klass,
+ Register temp_reg,
+ Label& L_success);
-+
+
//----
void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0
-
diff --git a/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp b/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp
--- a/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp
+++ b/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp
@@ -1598,7 +1662,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/cpu/x86/vm/methodHandles_x86.cpp
-@@ -0,0 +1,441 @@
+@@ -0,0 +1,1010 @@
+/*
+ * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -1662,7 +1726,7 @@ new file mode 100644
+address MethodHandle::generate_method_handle_interpreter_entry(MacroAssembler* _masm,
+ Label& wrong_method_type) {
+ // rbx: methodOop
-+ // rcx: receiver method handle (must load from sp[MTForm.vmdata])
++ // rcx: receiver method handle (must load from sp[MethodTypeForm.vmslots])
+ // rsi: sender SP (must preserve)
+ // rdx: garbage temp, blown away
+
@@ -1687,11 +1751,9 @@ new file mode 100644
+
+ // given the MethodType, find out where the MH argument is buried
+ __ movptr(rdx_temp, Address(rax_mtype,
-+ __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, rbx_temp),
-+ Address::times_1,
-+ oopDesc::address_padding_in_bytes()));
++ __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, rbx_temp)));
+ __ movl(rdx_temp, Address(rdx_temp,
-+ __ delayed_value(java_dyn_MethodType::Form::vmdata_offset_in_bytes, rbx_temp)));
++ __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, rbx_temp)));
+ __ movptr(rcx_recv, __ argument_address(rdx_temp));
+
+ __ check_method_handle_type(rax_mtype, rcx_recv, rdx_temp, wrong_method_type);
@@ -1709,9 +1771,177 @@ new file mode 100644
+ return entry_point;
+}
+
++// Helper to insert argument slots into the stack.
++// arg_slots must be a multiple of stack_move_unit() and <= 0
++void MethodHandle::insert_arg_slots(MacroAssembler* _masm,
++ RegisterConstant 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 that argslot lies within (rsp, rbp].
++ Label L_ok, L_bad;
++ __ cmpptr(rax_argslot, rbp);
++ __ jcc(Assembler::above, L_bad);
++ __ cmpptr(rsp, rax_argslot);
++ __ jcc(Assembler::below, L_ok);
++ __ bind(L_bad);
++ __ stop("insertion point must fall within current frame");
++ __ bind(L_ok);
++ }
++ if (arg_slots.is_register()) {
++ Label L_ok, L_bad;
++ __ 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);
++ __ bind(L_bad);
++ __ stop("assert arg_slots <= 0 and clear low bits");
++ __ bind(L_ok);
++ } else {
++ assert(arg_slots.as_constant() <= 0, "");
++ assert(arg_slots.as_constant() % -stack_move_unit() == 0, "");
++ }
++#endif //ASSERT
++
++ // 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.
++ // That is, copy [rsp, argslot) downward by -size words. In pseudo-code:
++ // rsp -= size;
++ // for (rdx = rsp + size; rdx < argslot; rdx++)
++ // rdx[-size] = rdx[0]
++ // argslot -= size;
++ __ mov(rdx_temp, rsp); // source pointer for copy
++ __ lea(rsp, Address(rsp, arg_slots, Address::times_ptr));
++ {
++ Label loop;
++ __ bind(loop);
++ // pull one word down each time through the loop
++ __ movptr(rbx_temp, Address(rdx_temp, 0));
++ __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp);
++ __ addptr(rdx_temp, wordSize);
++ __ cmpptr(rdx_temp, rax_argslot);
++ __ jcc(Assembler::less, loop);
++ }
++
++ // 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) {
++ 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);
++ int slot_offset = Interpreter::stackElementSize() * slot;
++ Address tag_addr(rax_argslot, slot_offset + tag_offset);
++ __ movptr(tag_addr, frame::tag_for_basic_type(slot_type));
++ }
++ // Note that the new argument slots are tagged properly but contain
++ // garbage at this point. The value portions must be initialized
++ // by the caller. (Especially references!)
++ }
++}
++
++// Helper to remove argument slots from the stack.
++// arg_slots must be a multiple of stack_move_unit() and >= 0
++void MethodHandle::remove_arg_slots(MacroAssembler* _masm,
++ RegisterConstant arg_slots,
++ 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()));
++
++#ifdef ASSERT
++ {
++ // Verify that [argslot..argslot+size) lies within (rsp, rbp).
++ Label L_ok, L_bad;
++ __ lea(rbx_temp, Address(rax_argslot, arg_slots, Address::times_ptr));
++ __ cmpptr(rbx_temp, rbp);
++ __ jcc(Assembler::above, L_bad);
++ __ cmpptr(rsp, rax_argslot);
++ __ jcc(Assembler::below, L_ok);
++ __ bind(L_bad);
++ __ stop("deleted argument(s) must fall within current frame");
++ __ bind(L_ok);
++ }
++ if (arg_slots.is_register()) {
++ Label L_ok, L_bad;
++ __ 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);
++ __ bind(L_bad);
++ __ stop("assert arg_slots >= 0 and clear low bits");
++ __ bind(L_ok);
++ } else {
++ assert(arg_slots.as_constant() >= 0, "");
++ assert(arg_slots.as_constant() % -stack_move_unit() == 0, "");
++ }
++#endif //ASSERT
++
++#ifdef _LP64
++ if (false) { // not needed, since register is positive
++ // clean high bits of stack motion register (was loaded as an int)
++ if (arg_slots.is_register())
++ __ movslq(arg_slots.as_register(), arg_slots.as_register());
++ }
++#endif
++
++ // Pull up everything shallower than rax_argslot.
++ // Then remove the excess space on the stack.
++ // The stacked return address gets pulled up with everything else.
++ // That is, copy [rsp, argslot) upward by size words. In pseudo-code:
++ // for (rdx = argslot-1; rdx >= rsp; --rdx)
++ // rdx[size] = rdx[0]
++ // argslot += size;
++ // rsp += size;
++ __ lea(rdx_temp, Address(rax_argslot, -wordSize)); // source pointer for copy
++ {
++ Label loop;
++ __ bind(loop);
++ // pull one word up each time through the loop
++ __ movptr(rbx_temp, Address(rdx_temp, 0));
++ __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp);
++ __ addptr(rdx_temp, -wordSize);
++ __ cmpptr(rdx_temp, rsp);
++ __ jcc(Assembler::greaterEqual, loop);
++ }
++
++ // Now move the argslot up, to point to the just-copied block.
++ __ lea(rsp, Address(rsp, arg_slots, Address::times_ptr));
++ // And adjust the argslot address to point at the deletion point.
++ __ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr));
++}
++
++#ifndef PRODUCT
++void trace_method_handle_stub(const char* adaptername,
++ oop mh,
++ 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);
++}
++#endif //PRODUCT
++
+// Generate an "entry" field for a method handle.
+// This determines how the method handle will respond to calls.
-+void MethodHandle::generate_method_handle_stub(MacroAssembler* _masm, MethodHandle::EntryKind ek) {
++void MethodHandle::generate_method_handle_stub(MacroAssembler* _masm, MethodHandle::EntryKind ek) {
+ // Here is the register state during an interpreted call,
+ // as set up by generate_method_handle_interpreter_entry():
+ // - rbx: garbage temp (was MethodHandle.invoke methodOop, unused)
@@ -1722,17 +1952,30 @@ new file mode 100644
+
+ Register rcx_recv = rcx;
+ Register rax_argslot = rax;
-+ Register rbx_index = rbx;
++ Register rbx_temp = rbx;
+ Register rdx_temp = rdx;
+
-+ guarantee(java_dyn_MethodHandle::vmdata_offset_in_bytes() != 0, "must have offsets");
++ guarantee(java_dyn_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets");
+
+ // some handy addresses
-+ Address rbx_method_fie( rbx, methodOopDesc::from_interpreted_offset() );
-+ Address rcx_mh_vmref( rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes() );
-+ Address rcx_mh_vmargslot( rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes() );
-+ Address rcx_mh_vmindex( rcx_recv, java_dyn_MethodHandle::vmdata_index_offset_in_bytes() );
-+ Address rcx_method_target( rcx_recv, java_dyn_MethodHandle::target_offset_in_bytes() ); //AMH
++ Address rbx_method_fie( rbx, methodOopDesc::from_interpreted_offset() );
++
++ Address rcx_mh_vmtarget( rcx_recv, java_dyn_MethodHandle::vmtarget_offset_in_bytes() );
++ Address rcx_dmh_vmindex( rcx_recv, impl_java_dyn_DirectMethodHandle::vmindex_offset_in_bytes() );
++
++ Address rcx_bmh_vmargslot( rcx_recv, impl_java_dyn_BoundMethodHandle::vmargslot_offset_in_bytes() );
++ Address rcx_bmh_argument( rcx_recv, impl_java_dyn_BoundMethodHandle::argument_offset_in_bytes() );
++
++ Address rcx_amh_vmargslot( rcx_recv, impl_java_dyn_AdapterMethodHandle::vmargslot_offset_in_bytes() );
++ Address rcx_amh_argument( rcx_recv, impl_java_dyn_AdapterMethodHandle::argument_offset_in_bytes() );
++ Address rcx_amh_conversion( rcx_recv, impl_java_dyn_AdapterMethodHandle::conversion_offset_in_bytes() );
++ Address vmarg; // __ argument_address(vmargslot)
++
++ int tag_offset = -1;
++ if (TaggedStackInterpreter) {
++ tag_offset = Interpreter::tag_offset_in_bytes() - Interpreter::value_offset_in_bytes();
++ assert(tag_offset = wordSize, "stack grows as expected");
++ }
+
+ if (have_entry(ek)) {
+ __ nop(); // empty stubs make SG sick
@@ -1741,6 +1984,25 @@ new file mode 100644
+
+ 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);
++ __ lea(rax, Address(rsp, wordSize*6)); // entry_sp
++ // arguments:
++ __ push(rsi); // saved_sp
++ __ push(rax); // entry_sp
++ __ push(rcx); // mh
++ __ push(rcx);
++ __ movptr(Address(rsp, 0), (intptr_t)entry_name(ek));
++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub), 4);
++ __ pop(rdi); __ pop(rsi); __ pop(rdx); __ pop(rcx); __ pop(rbx); __ pop(rax);
++ }
++#endif //PRODUCT
+
+ switch ((int) ek) {
+ case _check_mtype:
@@ -1765,15 +2027,15 @@ new file mode 100644
+ case _invokestatic_mh:
+ case _invokespecial_mh:
+ {
-+ Register rbx_method = rbx_index;
-+ __ movptr(rbx_method, rcx_mh_vmref);
++ Register rbx_method = rbx_temp;
++ __ movptr(rbx_method, rcx_mh_vmtarget); // target is a methodOop
+ __ verify_oop(rbx_method);
+ // same as TemplateTable::invokestatic or invokespecial,
+ // minus the CP setup and profiling:
+ if (ek == _invokespecial_mh) {
+ // Must load & check the first argument before entering the target method.
-+ __ movl(rax_argslot, rcx_mh_vmargslot);
-+ __ movptr(rcx_recv, __ argument_address(rax_argslot));
++ __ load_method_handle_vmslots(rax_argslot, rcx_recv, rdx_temp);
++ __ movptr(rcx_recv, __ argument_address(rax_argslot, -1));
+ __ null_check(rcx_recv);
+ __ verify_oop(rcx_recv);
+ }
@@ -1781,56 +2043,6 @@ new file mode 100644
+ }
+ break;
+
-+ case _invokebound_mh:
-+ {
-+ Register rbx_temp = rbx_index;
-+ __ movl(rax_argslot, rcx_mh_vmargslot);
-+ // get address of inserted argument (-1 means after sp is decremented)
-+ __ leal(rax_argslot, __ argument_address(rax_argslot, -1));
-+#ifdef ASSERT
-+ {
-+ Label L_ok, L_bad;
-+ __ cmpl(rax_argslot, rbp);
-+ __ jcc(Assembler::aboveEqual, L_bad);
-+ __ cmpl(rsp, rax_argslot);
-+ __ jcc(Assembler::belowEqual, L_ok);
-+ __ bind(L_bad);
-+ __ stop("first argument must fall within current frame");
-+ __ bind(L_ok);
-+ }
-+#endif //ASSERT
-+
-+ // Make space on the stack for the prepended argument.
-+ // Everything shallower than rax_argslot, including the
-+ // return address, will be pulled down by one slot width.
-+ Label loop, done;
-+ __ subl(rsp, Interpreter::stackElementSize()); // decrement sp
-+ __ movl(rdx_temp, rsp);
-+ {
-+ __ bind(loop);
-+ // pull one word down by 4 (or 8 if TaggedStackInterpreter)
-+ __ movl(rbx_temp, Address(rdx_temp, Interpreter::stackElementSize()));
-+ __ movl(Address(rdx_temp, 0), rbx_temp);
-+ __ addl(rdx_temp, wordSize);
-+ __ cmpl(rdx_temp, rax_argslot);
-+ __ jcc(Assembler::less, loop);
-+ }
-+
-+ Register rbx_method = rbx_temp;
-+ __ movptr(rbx_method, rcx_mh_vmref);
-+ __ verify_oop(rbx_method);
-+
-+ // replace MH with bound receiver (or first static argument):
-+ Address rcx_method_receiver(rcx_recv, java_dyn_MethodHandle::receiver_offset_in_bytes());
-+ __ movptr(rcx_recv, rcx_method_receiver);
-+ __ movptr(Address(rax_argslot, 0), rcx_recv);
-+ if (TaggedStackInterpreter) {
-+ __ movptr(Address(rax_argslot, wordSize), frame::TagReference);
-+ }
-+ __ jmp(rbx_method_fie);
-+ }
-+ break;
-+
+ case _invokevirtual_mh:
+ {
+ // same as TemplateTable::invokevirtual,
@@ -1838,9 +2050,11 @@ new file mode 100644
+
+ // pick out the vtable index and receiver offset from the MH,
+ // and then we can discard it:
-+ __ movl(rax_argslot, rcx_mh_vmargslot);
-+ __ movl(rbx_index, rcx_mh_vmindex);
-+ __ movptr(rcx_recv, __ argument_address(rax_argslot));
++ __ load_method_handle_vmslots(rax_argslot, rcx_recv, rdx_temp);
++ Register rbx_index = rbx_temp;
++ __ movl(rbx_index, rcx_dmh_vmindex);
++ // Note: The verifier allows us to ignore rcx_mh_vmtarget.
++ __ movptr(rcx_recv, __ argument_address(rax_argslot, -1));
+ __ null_check(rcx_recv, oopDesc::klass_offset_in_bytes());
+
+ // get receiver klass
@@ -1851,8 +2065,11 @@ new file mode 100644
+ // get target methodOop & entry point
+ const int base = instanceKlass::vtable_start_offset() * wordSize;
+ assert(vtableEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
-+ Register rbx_method = rbx_index;
-+ __ movl(rbx_method, Address(rax_klass, rbx_index, Address::times_ptr, base + vtableEntry::method_offset_in_bytes()));
++ Address vtable_entry_addr(rax_klass,
++ rbx_index, Address::times_ptr,
++ base + vtableEntry::method_offset_in_bytes());
++ Register rbx_method = rbx_temp;
++ __ movl(rbx_method, vtable_entry_addr);
+
+ __ verify_oop(rbx_method);
+ __ jmp(rbx_method_fie);
@@ -1865,12 +2082,12 @@ new file mode 100644
+ // minus the CP setup and profiling:
+
+ // pick out the interface and itable index from the MH.
++ __ load_method_handle_vmslots(rax_argslot, rcx_recv, rdx_temp);
+ Register rdx_intf = rdx_temp;
-+
-+ __ movptr(rdx_intf, rcx_mh_vmref);
-+ __ movl(rax_argslot, rcx_mh_vmargslot);
-+ __ movl(rbx_index, rcx_mh_vmindex);
-+ __ movptr(rcx_recv, __ argument_address(rax_argslot));
++ Register rbx_index = rbx_temp;
++ __ movptr(rdx_intf, rcx_mh_vmtarget);
++ __ movl(rbx_index, rcx_dmh_vmindex);
++ __ movptr(rcx_recv, __ argument_address(rax_argslot, -1));
+ __ null_check(rcx_recv, oopDesc::klass_offset_in_bytes());
+
+ // get receiver klass
@@ -1883,6 +2100,7 @@ new file mode 100644
+
+ // get interface klass
+ Label no_such_interface;
++ __ verify_oop(rdx_intf);
+ __ lookup_interface_method(rax_klass, rdx_intf,
+ // note: next two args must be the same:
+ rbx_index, rbx_method,
@@ -1900,99 +2118,92 @@ new file mode 100644
+ }
+ break;
+
++ case _bound_ref_mh:
++ case _bound_int_mh:
++ case _bound_long_mh:
++ case _bound_ref_direct_mh:
++ case _bound_int_direct_mh:
++ case _bound_long_direct_mh:
++ {
++ bool direct_to_method = (ek >= _bound_ref_direct_mh);
++ BasicType arg_type = T_ILLEGAL;
++ if (ek == _bound_long_mh || ek == _bound_long_direct_mh) {
++ arg_type = T_LONG;
++ } else if (ek == _bound_int_mh || ek == _bound_int_direct_mh) {
++ arg_type = T_INT;
++ } else {
++ assert(ek == _bound_ref_mh || ek == _bound_ref_direct_mh, "must be ref");
++ arg_type = T_OBJECT;
++ }
++ int arg_slots = type2size[arg_type];
++ int arg_mask = (arg_type == T_OBJECT ? _INSERT_REF_MASK :
++ arg_slots == 1 ? _INSERT_INT_MASK : _INSERT_LONG_MASK);
++
++ // make room for the new argument:
++ __ movl(rax_argslot, rcx_bmh_vmargslot);
++ __ lea(rax_argslot, __ argument_address(rax_argslot));
++ insert_arg_slots(_masm, arg_slots * stack_move_unit(), arg_mask,
++ rax_argslot, rbx_temp, rdx_temp);
++
++ // store bound argument into the new stack slot:
++ __ movptr(rbx_temp, rcx_bmh_argument);
++ Address prim_value_addr(rbx_temp, java_lang_boxing_object::value_offset_in_bytes(arg_type));
++ if (arg_type == T_OBJECT) {
++ __ movptr(Address(rax_argslot, 0), rbx_temp);
++ } else {
++ __ load_sized_value(rbx_temp, prim_value_addr,
++ type2aelembytes(arg_type), is_signed_subword_type(arg_type));
++ __ movptr(Address(rax_argslot, 0), rbx_temp);
++#ifndef _LP64
++ if (arg_slots == 2) {
++ __ movl(rbx_temp, prim_value_addr.plus_disp(wordSize));
++ __ movptr(Address(rax_argslot, Interpreter::stackElementSize()), rbx_temp);
++ }
++#endif //_LP64
++ break;
++ }
++
++ if (direct_to_method) {
++ Register rbx_method = rbx_temp;
++ __ movptr(rbx_method, rcx_mh_vmtarget);
++ __ verify_oop(rbx_method);
++ __ jmp(rbx_method_fie);
++ } else {
++ __ movptr(rcx_recv, rcx_mh_vmtarget);
++ __ verify_oop(rcx_recv);
++ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
++ }
++ }
++ break;
++
+ case _adapter_mh_first+_adapt_retype_only:
-+ case _adapter_mh_first+_adapt_drop_initial:
-+ case _adapter_mh_first+_adapt_drop_final:
-+ {
-+ AdapterKind ak = AdapterKind(ek - _adapter_mh_first);
-+ if (ak == _adapt_drop_final) {
-+ // 'argslot' is number of slots to drop
-+ // this is also the rightmost (shallowest) kept argument slot
-+ __ movl(rax_argslot, rcx_mh_vmargslot);
-+ Address arg = __ argument_address(rax_argslot);
-+ __ pop(rdx_temp); // return PC
-+ __ lea(rsp, arg); // pop some arguments
-+ __ push(rdx_temp); // restore PC
-+ }
-+
-+ // immediately jump to the next MH layer:
-+ __ movptr(rcx_recv, rcx_method_target);
-+ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
-+ // This is OK when all parameter types widen.
-+ // It is also OK when a return type narrows.
-+ // Finally, we can simply ignore leading arguments from here on,
-+ // without touching the stack.
-+ }
-+ break;
-+
-+ case _adapter_mh_first+_adapt_extend_sign:
-+ case _adapter_mh_first+_adapt_extend_zero:
-+ case _adapter_mh_first+_adapt_test_boolean:
-+ {
-+ AdapterKind ak = AdapterKind(ek - _adapter_mh_first);
-+ // check an argument, or perform a simple in-place conversion,
-+ // before jumping to the next layer of MH:
-+ __ movl(rax_argslot, rcx_mh_vmargslot);
-+ if (ak == _adapt_extend_zero || ak == _adapt_extend_sign)
-+ __ movl(rbx_index, rcx_mh_vmindex);
-+ Address arg = __ argument_address(rax_argslot);
-+
-+ // get the new MH:
-+ __ movptr(rcx_recv, rcx_method_target);
-+ // (now we are done with the old MH)
-+
-+ if (ak == _adapt_test_boolean) {
-+ // convert a 32-bit integer value into a one-bit subword, C-style
-+ __ cmpl(arg, (jint)0);
-+ Label skip;
-+ __ jccb(Assembler::equal, skip);
-+ __ movptr(arg, (jint)1);
-+ __ bind(skip);
-+
-+ } else {
-+ // original 32-bit vmdata word must be of this form:
-+ // | argumentNumber:16 | lowBitCount:8 | conversion:8 |
-+ __ xchgl(rcx, rbx_index); // free rcx for shifts
-+ __ shrl(rcx, 8); // shift in 2nd LSB
-+ __ negl(rcx); // left shift by 32-lowBitCount
-+ __ movptr(rdx_temp, arg);
-+ __ shll(rdx_temp /*, rcx*/);
-+ if (ak == _adapt_extend_sign) {
-+ // this path is taken for int->byte, int->short
-+ __ sarl(rdx_temp /*, rcx*/);
-+ } else if (ak == _adapt_extend_zero) {
-+ // this is taken for int->char
-+ __ shrl(rdx_temp /*, rcx*/);
-+ } else {
-+ ShouldNotReachHere();
-+ }
-+ __ movptr(arg, rdx_temp);
-+ __ xchgl(rcx, rbx_index); // restore rcx_recv
-+ }
-+
-+ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
-+ }
++ // immediately jump to the next MH layer:
++ __ movptr(rcx_recv, rcx_mh_vmtarget);
++ __ verify_oop(rcx_recv);
++ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
++ // This is OK when all parameter types widen.
++ // It is also OK when a return type narrows.
+ break;
+
+ case _adapter_mh_first+_adapt_check_cast:
+ {
+ // temps:
-+ Register rbx_klass = rbx_index; // interesting AMH data
-+
-+ // check an argument, or perform a simple in-place conversion,
-+ // before jumping to the next layer of MH:
-+ __ movl(rax_argslot, rcx_mh_vmargslot);
-+ Address arg = __ argument_address(rax_argslot);
++ Register rbx_klass = rbx_temp; // interesting AMH data
++
++ // check a reference argument before jumping to the next layer of MH:
++ __ movl(rax_argslot, rcx_amh_vmargslot);
++ vmarg = __ argument_address(rax_argslot);
+
+ // What class are we casting to?
-+ __ movptr(rbx_klass, rcx_mh_vmref);
++ __ movptr(rbx_klass, rcx_amh_argument); // this is a Class object!
++ __ movptr(rbx_klass, Address(rbx_klass, java_lang_Class::klass_offset_in_bytes()));
+
+ // get the new MH:
-+ __ movptr(rcx_recv, rcx_method_target);
++ __ movptr(rcx_recv, rcx_mh_vmtarget);
+ // (now we are done with the old MH)
+
+ Label done;
-+ __ movptr(rdx_temp, arg);
++ __ 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()));
@@ -2022,12 +2233,434 @@ new file mode 100644
+ }
+ break;
+
-+ case _adapter_mh_first+_adapt_swap_argument:
-+ case _adapter_mh_first+_adapt_push_argument:
-+ case _adapter_mh_first+_adapt_push_primitive:
-+ case _adapter_mh_first+_adapt_push_reference:
++ case _adapter_mh_first+_adapt_prim_to_prim:
++ case _adapter_mh_first+_adapt_ref_to_prim:
++ // handled completely by optimized cases
++ __ stop("init_AdapterMethodHandle should not issue this");
++ break;
++
++ 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
++ {
++ // perform an in-place conversion to int or an int subword
++ __ movl(rax_argslot, rcx_amh_vmargslot);
++ vmarg = __ argument_address(rax_argslot);
++
++ switch (ek) {
++ case _adapter_opt_i2i:
++ __ movl(rdx_temp, vmarg);
++ break;
++ case _adapter_opt_l2i:
++ {
++ // just delete the extra slot; on a little-endian machine we keep the first
++ __ lea(rax_argslot, __ argument_address(rax_argslot, 1));
++ remove_arg_slots(_masm, -stack_move_unit(),
++ rax_argslot, rbx_temp, rdx_temp);
++ vmarg = Address(rax_argslot, -Interpreter::stackElementSize());
++ __ movl(rdx_temp, vmarg);
++ }
++ break;
++ case _adapter_opt_a2i:
++ {
++ // Load the value up from the heap.
++ __ movptr(rdx_temp, vmarg);
++ int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_INT);
++#ifdef ASSERT
++ for (int bt = T_BOOLEAN; bt < T_INT; bt++) {
++ if (is_subword_type(BasicType(bt)))
++ assert(value_offset == java_lang_boxing_object::value_offset_in_bytes(BasicType(bt)), "");
++ }
++#endif
++ __ null_check(rdx_temp, value_offset);
++ __ movl(rdx_temp, Address(rdx_temp, value_offset));
++ // We load this as a word. Because we are little-endian,
++ // the low bits will be correct, but the high bits may need cleaning.
++ // The vminfo will guide us to clean those bits.
++ }
++ break;
++ default:
++ assert(false, "");
++ }
++ goto finish_int_conversion;
++ }
++
++ finish_int_conversion:
++ {
++ Register rbx_vminfo = rbx_temp;
++ __ movl(rbx_vminfo, rcx_amh_conversion);
++ assert(_CONV_VMINFO_SHIFT == 0, "preshifted");
++
++ // get the new MH:
++ __ movptr(rcx_recv, rcx_mh_vmtarget);
++ // (now we are done with the old MH)
++
++ // original 32-bit vmdata word must be of this form:
++ // | MBZ:16 | signBitCount:8 | srcDstTypes:8 | conversionOp:8 |
++ __ xchgl(rcx, rbx_vminfo); // free rcx for shifts
++ __ shll(rdx_temp /*, rcx*/);
++ Label zero_extend, done;
++ __ testl(rcx, _CONV_VMINFO_SIGN_FLAG);
++ __ jcc(Assembler::zero, zero_extend);
++
++ // this path is taken for int->byte, int->short
++ __ sarl(rdx_temp /*, rcx*/);
++ __ jmp(done);
++
++ __ bind(zero_extend);
++ // this is taken for int->char
++ __ shrl(rdx_temp /*, rcx*/);
++
++ __ bind(done);
++ __ movptr(vmarg, rdx_temp);
++ __ xchgl(rcx, rbx_vminfo); // restore rcx_recv
++
++ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
++ }
++ break;
++
++ case _adapter_opt_i2l: // optimized subcase of adapt_prim_to_prim
++ case _adapter_opt_a2l: // 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);
++
++ // on a little-endian machine we keep the first slot and add another after
++ __ lea(rax_argslot, __ argument_address(rax_argslot, 1));
++ insert_arg_slots(_masm, stack_move_unit(), _INSERT_INT_MASK,
++ rax_argslot, rbx_temp, rdx_temp);
++ Address vmarg1(rax_argslot, -Interpreter::stackElementSize());
++ Address vmarg2 = vmarg1.plus_disp(Interpreter::stackElementSize());
++
++ switch (ek) {
++ case _adapter_opt_i2l:
++ {
++ __ movl(rdx_temp, vmarg1);
++ __ extend_sign(rbx_temp, rdx_temp);
++ __ movl(vmarg2, rbx_temp); // store second word
++ }
++ break;
++ case _adapter_opt_a2l:
++ {
++ // Load the value up from the heap.
++ __ movptr(rdx_temp, vmarg1);
++ int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_LONG);
++ assert(value_offset == java_lang_boxing_object::value_offset_in_bytes(T_DOUBLE), "");
++ __ null_check(rdx_temp, value_offset);
++ __ movl(rbx_temp, Address(rdx_temp, value_offset + 0*BytesPerInt));
++ __ movl(rdx_temp, Address(rdx_temp, value_offset + 1*BytesPerInt));
++ __ movl(vmarg1, rbx_temp);
++ __ movl(vmarg2, rdx_temp);
++ }
++ break;
++ default:
++ assert(false, "");
++ }
++
++ __ movptr(rcx_recv, rcx_mh_vmtarget);
++ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
++ }
++ break;
++
++ case _adapter_opt_f2d: // optimized subcase of adapt_prim_to_prim
++ case _adapter_opt_d2f: // optimized subcase of adapt_prim_to_prim
++ {
++ // perform an in-place floating primitive conversion
++ __ movl(rax_argslot, rcx_amh_vmargslot);
++ __ lea(rax_argslot, __ argument_address(rax_argslot, 1));
++ if (ek == _adapter_opt_f2d) {
++ insert_arg_slots(_masm, stack_move_unit(), _INSERT_INT_MASK,
++ rax_argslot, rbx_temp, rdx_temp);
++ }
++ Address vmarg(rax_argslot, -Interpreter::stackElementSize());
++
++#ifdef _LP64
++ if (ek == _adapter_opt_f2d) {
++ __ movflt(xmm0, vmarg);
++ __ cvtss2sd(xmm0, xmm0);
++ __ movdbl(vmarg, xmm0);
++ } else {
++ __ movdbl(xmm0, vmarg);
++ __ cvtsd2ss(xmm0, xmm0);
++ __ movflt(vmarg, xmm0);
++ }
++#else //_LP64
++ if (ek == _adapter_opt_f2d) {
++ __ fld_s(vmarg); // load float to ST0
++ __ fstp_s(vmarg); // store single
++ } else if (!TaggedStackInterpreter) {
++ __ fld_d(vmarg); // load double to ST0
++ __ fstp_s(vmarg); // store single
++ } else {
++ Address vmarg_tag = vmarg.plus_disp(tag_offset);
++ Address vmarg2 = vmarg.plus_disp(Interpreter::stackElementSize());
++ // vmarg2_tag does not participate in this code
++ Register rbx_tag = rbx_temp;
++ __ movl(rbx_tag, vmarg_tag); // preserve tag
++ __ movl(rdx_temp, vmarg2); // get second word of double
++ __ movl(vmarg_tag, rdx_temp); // align with first word
++ __ fld_d(vmarg); // load double to ST0
++ __ movl(vmarg_tag, rbx_tag); // restore tag
++ __ fstp_s(vmarg); // store single
++ }
++#endif //_LP64
++
++ if (ek == _adapter_opt_d2f) {
++ remove_arg_slots(_masm, -stack_move_unit(),
++ rax_argslot, rbx_temp, rdx_temp);
++ }
++
++ __ movptr(rcx_recv, rcx_mh_vmtarget);
++ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
++ }
++ break;
++
++ case _adapter_mh_first+_adapt_prim_to_ref:
++ case _adapter_mh_first+_adapt_swap_args:
++ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
++ break;
++
++ case _adapter_mh_first+_adapt_dup_args:
++ {
++ // 'argslot' is the position of the first argument to duplicate
++ __ movl(rax_argslot, rcx_amh_vmargslot);
++ __ lea(rax_argslot, __ argument_address(rax_argslot));
++
++ // '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);
++
++ Address argslot0 = __ argument_address(0);
++ assert(argslot0.base() == rsp, "");
++ int pre_arg_size = argslot0.disp();
++ assert(pre_arg_size % wordSize == 0, "");
++ assert(pre_arg_size > 0, "must include PC");
++
++ // remember the old rsp+1 (argslot[0])
++ Register rbx_oldarg = rbx_temp;
++ __ lea(rbx_oldarg, argslot0);
++
++ // move rsp down to make room for dups
++ __ lea(rsp, Address(rsp, rdx_stack_move, Address::times_ptr));
++
++ // compute the new rsp+1 (argslot[0])
++ Register rdx_newarg = rdx_temp;
++ __ lea(rdx_newarg, argslot0);
++
++ __ push(rdi); // need a temp
++ // (preceding push must be done after arg addresses are taken!)
++
++ // pull down the pre_arg_size data (PC)
++ for (int i = -pre_arg_size; i < 0; i += wordSize) {
++ __ movptr(rdi, Address(rbx_oldarg, i));
++ __ movptr(Address(rdx_newarg, i), rdi);
++ }
++
++ // copy from rax_argslot[0...] down to new_rsp[1...]
++ // pseudo-code:
++ // rbx = old_rsp+1
++ // rdx = new_rsp+1
++ // rax = argslot
++ // while (rdx < rbx) *rdx++ = *rax++
++ Label loop;
++ __ bind(loop);
++ __ movptr(rdi, Address(rax_argslot, 0));
++ __ movptr(Address(rdx_newarg, 0), rdi);
++ __ addptr(rax_argslot, wordSize);
++ __ addptr(rdx_newarg, wordSize);
++ __ cmpptr(rdx_newarg, rbx_oldarg);
++ __ jcc(Assembler::less, loop);
++
++ __ pop(rdi); // restore temp
++
++ __ movptr(rcx_recv, rcx_mh_vmtarget);
++ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
++ }
++ break;
++
++ case _adapter_mh_first+_adapt_drop_args:
++ {
++ // 'argslot' is the position of the first argument to nuke
++ __ movl(rax_argslot, rcx_amh_vmargslot);
++ __ lea(rax_argslot, __ argument_address(rax_argslot));
++
++ __ push(rdi); // need a temp
++ // (must do previous push after argslot address is taken)
++
++ // '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);
++ remove_arg_slots(_masm, rdi_stack_move,
++ rax_argslot, rbx_temp, rdx_temp);
++
++ __ pop(rdi); // restore temp
++
++ __ movptr(rcx_recv, rcx_mh_vmtarget);
++ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
++ }
++ break;
++
++ case _adapter_mh_first+_adapt_collect_args:
++ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
++ break;
++
++ case _adapter_mh_first+_adapt_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:
++ {
++ // 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;
++ }
++
++ // find the address of the array argument
++ __ movl(rax_argslot, rcx_amh_vmargslot);
++ __ lea(rax_argslot, __ argument_address(rax_argslot));
++
++ // grab some temps
++ { __ push(rsi); __ push(rdi); }
++ // (preceding pushes must be done after argslot address is taken!)
++#define UNPUSH_RSI_RDI \
++ { __ pop(rdi); __ pop(rsi); }
++
++ // arx_argslot points both to the array and to the first output arg
++ vmarg = Address(rax_argslot, 0);
++
++ // Get the array value.
++ Register rsi_array = rsi;
++ Register rdx_array_klass = rdx_temp;
++ BasicType elem_type = T_OBJECT;
++ int length_offset = arrayOopDesc::length_offset_in_bytes();
++ int elem0_offset = arrayOopDesc::base_offset_in_bytes(elem_type);
++ __ movptr(rsi_array, vmarg);
++ Label skip_array_check;
++ if (length_constant == 0) {
++ __ testptr(rsi_array, rsi_array);
++ __ 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()));
++
++ // Check the array type.
++ Register rbx_klass = rbx_temp;
++ __ movptr(rbx_klass, rcx_amh_argument); // this is a Class object!
++ __ movptr(rbx_klass, Address(rbx_klass, java_lang_Class::klass_offset_in_bytes()));
++
++ Label ok_array_klass, bad_array_klass, bad_array_length;
++ __ check_klass_subtype(rdx_array_klass, rbx_klass, rdi, ok_array_klass);
++ // If we get here, the type check failed!
++ __ jmp(bad_array_klass);
++ __ bind(ok_array_klass);
++
++ // Check length.
++ if (length_constant >= 0) {
++ __ cmpl(Address(rsi_array, length_offset), length_constant);
++ } else {
++ Register rbx_vminfo = rbx_temp;
++ __ movl(rbx_vminfo, rcx_amh_conversion);
++ 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);
++
++ Register rdx_argslot_limit = rdx_temp;
++
++ // Array length checks out. Now insert any required stack slots.
++ if (length_constant == -1) {
++ // Form a pointer to the end of the affected region.
++ __ lea(rdx_argslot_limit, Address(rax_argslot, Interpreter::stackElementSize()));
++ // '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);
++ Register rsi_temp = rsi_array; // spill this
++ insert_arg_slots(_masm, rdi_stack_move, -1,
++ rax_argslot, rbx_temp, rsi_temp);
++ // reload the array (since rsi was killed)
++ __ movptr(rsi_array, vmarg);
++ } else if (length_constant > 1) {
++ int arg_mask = 0;
++ int new_slots = (length_constant - 1);
++ for (int i = 0; i < new_slots; i++) {
++ arg_mask <<= 1;
++ arg_mask |= _INSERT_REF_MASK;
++ }
++ insert_arg_slots(_masm, new_slots * stack_move_unit(), arg_mask,
++ rax_argslot, rbx_temp, rdx_temp);
++ } else if (length_constant == 1) {
++ // no stack resizing required
++ } else if (length_constant == 0) {
++ remove_arg_slots(_masm, -stack_move_unit(),
++ rax_argslot, rbx_temp, rdx_temp);
++ }
++
++ // Copy from the array to the new slots.
++ // Note: Stack change code preserves integrity of rax_argslot pointer.
++ // So even after slot insertions, rax_argslot still points to first argument.
++ if (length_constant == -1) {
++ // [rax_argslot, rdx_argslot_limit) is the area we are inserting into.
++ Register rsi_source = rsi_array;
++ __ lea(rsi_source, Address(rsi_array, elem0_offset));
++ Label loop;
++ __ bind(loop);
++ __ movptr(rbx_temp, Address(rsi_source, 0));
++ __ movptr(Address(rax_argslot, 0), rbx_temp);
++ __ addptr(rsi_source, type2aelembytes(elem_type));
++ if (TaggedStackInterpreter) {
++ __ movptr(Address(rax_argslot, tag_offset),
++ frame::tag_for_basic_type(elem_type));
++ }
++ __ addptr(rax_argslot, Interpreter::stackElementSize());
++ __ cmpptr(rax_argslot, rdx_argslot_limit);
++ __ jcc(Assembler::less, loop);
++ } else if (length_constant == 0) {
++ __ bind(skip_array_check);
++ // nothing to copy
++ } else {
++ int elem_offset = elem0_offset;
++ int slot_offset = 0;
++ for (int index = 0; index < length_constant; index++) {
++ __ movptr(rbx_temp, Address(rsi_array, elem_offset));
++ __ movptr(Address(rax_argslot, slot_offset), rbx_temp);
++ elem_offset += type2aelembytes(elem_type);
++ if (TaggedStackInterpreter) {
++ __ movptr(Address(rax_argslot, slot_offset + tag_offset),
++ frame::tag_for_basic_type(elem_type));
++ }
++ slot_offset += Interpreter::stackElementSize();
++ }
++ }
++
++ // Arguments are spread. Move to next method handle.
++ UNPUSH_RSI_RDI;
++ __ movptr(rcx_recv, rcx_mh_vmtarget);
++ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
++
++ __ bind(bad_array_klass);
++ UNPUSH_RSI_RDI;
++ __ stop("bad array klass NYI");
++
++ __ bind(bad_array_length);
++ UNPUSH_RSI_RDI;
++ __ stop("bad array length NYI");
++
++#undef UNPUSH_RSI_RDI
++ }
++ break;
++
++ case _adapter_mh_first+_adapt_flyby:
+ case _adapter_mh_first+_adapt_ricochet:
-+ case _adapter_mh_first+_adapt_flyby:
+ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
+ break;
+
@@ -2059,7 +2692,7 @@ diff --git a/src/cpu/x86/vm/stubGenerato
generate_arraycopy_stubs();
+
+ // generic method handle stubs
-+ if (MethodHandles && SystemDictionary::java_dyn_MethodHandle_klass() != NULL) {
++ if (MethodHandles && SystemDictionary::MethodHandle_klass() != NULL) {
+ for (MethodHandle::EntryKind ek = MethodHandle::_EK_FIRST;
+ ek < MethodHandle::_EK_LIMIT;
+ ek = MethodHandle::EntryKind(1 + (int)ek)) {
@@ -2542,7 +3175,7 @@ diff --git a/src/share/vm/asm/assembler.
diff --git a/src/share/vm/asm/assembler.cpp b/src/share/vm/asm/assembler.cpp
--- a/src/share/vm/asm/assembler.cpp
+++ b/src/share/vm/asm/assembler.cpp
-@@ -239,6 +239,65 @@
+@@ -239,6 +239,69 @@
}
}
@@ -2559,7 +3192,11 @@ diff --git a/src/share/vm/asm/assembler.
+ }
+ static void update_all();
+};
++
+DelayedConstant DelayedConstant::delayed_constants[DC_LIMIT];
++// Default C structure initialization rules have the following effect here:
++// = { { (BasicType)0, (intptr_t)NULL }, ... };
++
+DelayedConstant* DelayedConstant::add(BasicType type,
+ DelayedConstant::value_fn_t cfn) {
+ for (int i = 0; i < DC_LIMIT; i++) {
@@ -2675,7 +3312,7 @@ diff --git a/src/share/vm/classfile/clas
diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile/classFileParser.cpp
--- a/src/share/vm/classfile/classFileParser.cpp
+++ b/src/share/vm/classfile/classFileParser.cpp
-@@ -1838,6 +1838,11 @@
+@@ -1839,6 +1839,11 @@
_has_vanilla_constructor = true;
}
@@ -2687,6 +3324,112 @@ diff --git a/src/share/vm/classfile/clas
return m;
}
+@@ -2462,6 +2467,78 @@
+ }
+
+
++void ClassFileParser::java_dyn_MethodHandle_fix_pre(constantPoolHandle cp,
++ typeArrayHandle* fields_ptr,
++ FieldAllocationCount *fac_ptr,
++ TRAPS) {
++ // Add fake fields for java.dyn.MethodHandle instances
++ //
++ // This is not particularly nice, but since there is no way to express
++ // a native wordSize field in Java, we must do it at this level.
++
++ if (!MethodHandles) return;
++
++ int word_sig_index = 0;
++ const int cp_size = cp->length();
++ for (int index = 1; index < cp_size; index++) {
++ if (cp->tag_at(index).is_utf8() &&
++ cp->symbol_at(index) == vmSymbols::machine_word_signature()) {
++ word_sig_index = index;
++ break;
++ }
++ }
++
++ if (word_sig_index == 0)
++ THROW_MSG(vmSymbols::java_lang_VirtualMachineError(),
++ "missing I or J signature (for vmentry) in java.dyn.MethodHandle");
++
++ bool found_vmentry = false;
++
++ const int n = (*fields_ptr)()->length();
++ for (int i = 0; i < n; i += instanceKlass::next_offset) {
++ int name_index = (*fields_ptr)->ushort_at(i + instanceKlass::name_index_offset);
++ int sig_index = (*fields_ptr)->ushort_at(i + instanceKlass::signature_index_offset);
++ int acc_flags = (*fields_ptr)->ushort_at(i + instanceKlass::access_flags_offset);
++ symbolOop f_name = cp->symbol_at(name_index);
++ symbolOop f_sig = cp->symbol_at(sig_index);
++ if (f_sig == vmSymbols::byte_signature() &&
++ f_name == vmSymbols::vmentry_name() &&
++ (acc_flags & JVM_ACC_STATIC) == 0) {
++ // Adjust the field type from byte to an unmanaged pointer.
++ assert(fac_ptr->nonstatic_byte_count > 0, "");
++ fac_ptr->nonstatic_byte_count -= 1;
++ (*fields_ptr)->ushort_at_put(i + instanceKlass::signature_index_offset,
++ word_sig_index);
++ if (wordSize == jintSize) {
++ fac_ptr->nonstatic_word_count += 1;
++ } else {
++ fac_ptr->nonstatic_double_count += 1;
++ }
++
++ FieldAllocationType atype = (FieldAllocationType) (*fields_ptr)->ushort_at(i+4);
++ assert(atype == NONSTATIC_BYTE, "");
++ FieldAllocationType new_atype = NONSTATIC_WORD;
++ if (wordSize > jintSize) {
++ if (Universe::field_type_should_be_aligned(T_LONG)) {
++ atype = NONSTATIC_ALIGNED_DOUBLE;
++ } else {
++ atype = NONSTATIC_DOUBLE;
++ }
++ }
++ (*fields_ptr)->ushort_at_put(i+4, new_atype);
++
++ found_vmentry = true;
++ break;
++ }
++ }
++
++ if (!found_vmentry)
++ THROW_MSG(vmSymbols::java_lang_VirtualMachineError(),
++ "missing vmentry byte field in java.dyn.MethodHandle");
++
++}
++
++
+ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
+ Handle class_loader,
+ Handle protection_domain,
+@@ -2802,6 +2879,11 @@
+ // Add fake fields for java.lang.Class instances (also see below)
+ if (class_name() == vmSymbols::java_lang_Class() && class_loader.is_null()) {
+ java_lang_Class_fix_pre(&methods, &fac, CHECK_(nullHandle));
++ }
++
++ // adjust the vmentry field declaration in java.dyn.MethodHandle
++ if (MethodHandles && class_name() == vmSymbols::impl_java_dyn_MethodHandleImpl() && class_loader.is_null()) {
++ java_dyn_MethodHandle_fix_pre(cp, &fields, &fac, CHECK_(nullHandle));
+ }
+
+ // Add a fake "discovered" field if it is not present
+diff --git a/src/share/vm/classfile/classFileParser.hpp b/src/share/vm/classfile/classFileParser.hpp
+--- a/src/share/vm/classfile/classFileParser.hpp
++++ b/src/share/vm/classfile/classFileParser.hpp
+@@ -145,6 +145,11 @@
+ // Adjust the next_nonstatic_oop_offset to place the fake fields
+ // before any Java fields.
+ void java_lang_Class_fix_post(int* next_nonstatic_oop_offset);
++ // Adjust the field allocation counts for java.dyn.MethodHandle to add
++ // a fake address (void*) field.
++ void java_dyn_MethodHandle_fix_pre(constantPoolHandle cp,
++ typeArrayHandle* fields_ptr,
++ FieldAllocationCount *fac_ptr, TRAPS);
+
+ // Format checker methods
+ void classfile_parse_error(const char* msg, TRAPS);
diff --git a/src/share/vm/classfile/dictionary.cpp b/src/share/vm/classfile/dictionary.cpp
--- a/src/share/vm/classfile/dictionary.cpp
+++ b/src/share/vm/classfile/dictionary.cpp
@@ -2913,7 +3656,36 @@ diff --git a/src/share/vm/classfile/java
Handle java_lang_String::basic_create(int length, bool tenured, TRAPS) {
// Create the String object first, so there's a chance that the String
-@@ -1970,6 +1983,21 @@
+@@ -412,6 +425,8 @@
+
+
+ bool java_lang_Class::is_primitive(oop java_class) {
++ // should assert:
++ //assert(java_lang_Class::is_instance(java_class), "must be a Class object");
+ klassOop k = klassOop(java_class->obj_field(klass_offset));
+ return k == NULL;
+ }
+@@ -429,6 +444,19 @@
+ }
+ assert(Universe::java_mirror(type) == java_class, "must be consistent");
+ return type;
++}
++
++BasicType java_lang_Class::as_BasicType(oop java_class, klassOop* reference_klass) {
++ assert(java_lang_Class::is_instance(java_class), "must be a Class object");
++ if (is_primitive(java_class)) {
++ if (reference_klass != NULL)
++ (*reference_klass) = NULL;
++ return primitive_type(java_class);
++ } else {
++ if (reference_klass != NULL)
++ (*reference_klass) = as_klassOop(java_class);
++ return T_OBJECT;
++ }
+ }
+
+
+@@ -1970,6 +1998,21 @@
}
@@ -2935,61 +3707,56 @@ diff --git a/src/share/vm/classfile/java
// Support for java_lang_ref_Reference
oop java_lang_ref_Reference::pending_list_lock() {
instanceKlass* ik = instanceKlass::cast(SystemDictionary::reference_klass());
-@@ -2017,6 +2045,161 @@
-
- SystemDictionary::soft_reference_klass()->long_field_put(offset, value);
+@@ -2019,12 +2062,220 @@
}
-+
-+
+
+
+// Support for java_dyn_MethodHandle
+
+int java_dyn_MethodHandle::_type_offset;
-+int java_dyn_MethodHandle::_vmref_offset;
-+int java_dyn_MethodHandle::_vmdata_offset;
-+int java_dyn_MethodHandle::_vmdata_argslot_offset;
-+int java_dyn_MethodHandle::_vmdata_index_offset;
-+int java_dyn_MethodHandle::_entry_offset;
-+int java_dyn_MethodHandle::_receiver_offset;
-+int java_dyn_MethodHandle::_target_offset;
++int java_dyn_MethodHandle::_vmtarget_offset;
++int java_dyn_MethodHandle::_vmentry_offset;
++int java_dyn_MethodHandle::_vmslots_offset;
++
++int impl_java_dyn_DirectMethodHandle::_vmindex_offset;
++
++int impl_java_dyn_BoundMethodHandle::_argument_offset;
++int impl_java_dyn_BoundMethodHandle::_vmargslot_offset;
++
++int impl_java_dyn_AdapterMethodHandle::_conversion_offset;
+
+void java_dyn_MethodHandle::compute_offsets() {
-+ klassOop k = SystemDictionary::java_dyn_MethodHandle_klass();
++ klassOop k = SystemDictionary::MethodHandle_klass();
+ if (k != NULL && MethodHandles) {
-+ compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_dyn_MethodType_signature(), true);
-+ compute_offset(_vmref_offset, k, vmSymbols::vmref_name(), vmSymbols::object_signature(), true);
-+ compute_offset(_vmdata_offset, k, vmSymbols::vmdata_name(), vmSymbols::long_signature(), true);
-+ compute_offset(_entry_offset, k, vmSymbols::entry_name(), vmSymbols::long_signature(), true);
-+ if (_entry_offset != 0) _entry_offset += oopDesc::address_padding_in_bytes();
-+ if (_vmdata_offset != 0) {
-+ // Detect the ordering of halves in vmdata [ index:32 | argslot:32 ].
-+ int ioff = 0, aoff = 0;
-+ if (Bytes::is_Java_byte_ordering_different()) {
-+ ioff += jintSize; // Little-endian ordering {argslot, index}
-+ } else {
-+ aoff += jintSize; // Big-endian ordering {index, argslot}
-+ }
-+ _vmdata_index_offset = _vmdata_offset + ioff;
-+ _vmdata_argslot_offset = _vmdata_offset + aoff;
-+#ifdef ASSERT
-+ { // test it another way, just to make sure:
-+ union { jlong as_long; jint as_ints[2]; } vmdata;
-+ vmdata.as_long = jlong_from('i', 'a');
-+ if (vmdata.as_ints[0] == 'i' && vmdata.as_ints[1] == 'a')
-+ { assert(aoff != 0, "big-endian"); }
-+ else if (vmdata.as_ints[0] == 'a' && vmdata.as_ints[1] == 'i')
-+ { assert(ioff != 0, "little-endian"); }
-+ else { assert(false, "no-endian!?"); }
-+ }
-+#endif
-+ }
-+ klassOop bmhk = SystemDictionary::dyn_impl_BMH_klass();
-+ guarantee(bmhk != NULL, "BMH must be present also");
-+ compute_offset(_receiver_offset, bmhk,
-+ vmSymbols::receiver_name(), vmSymbols::object_signature(), true);
-+ klassOop amhk = SystemDictionary::dyn_impl_AMH_klass();
-+ guarantee(amhk != NULL, "AMH must be present also");
-+ compute_offset(_target_offset, amhk,
-+ vmSymbols::target_name(), vmSymbols::java_dyn_MethodHandle_signature(), true);
++ compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_dyn_MethodType_signature(), true);
++ compute_offset(_vmtarget_offset, k, vmSymbols::vmtarget_name(), vmSymbols::object_signature(), true);
++ compute_offset(_vmentry_offset, k, vmSymbols::vmentry_name(), vmSymbols::machine_word_signature(), true);
++
++ // Note: MH.vmslots (if it is present) is a hoisted copy of MH.type.form.vmslots.
++ // It is optional pending experiments to keep or toss.
++ compute_optional_offset(_vmslots_offset, k, vmSymbols::vmslots_name(), vmSymbols::int_signature(), true);
++ }
++}
++
++void impl_java_dyn_DirectMethodHandle::compute_offsets() {
++ klassOop k = SystemDictionary::DirectMethodHandle_klass();
++ if (k != NULL && MethodHandles) {
++ compute_offset(_vmindex_offset, k, vmSymbols::vmindex_name(), vmSymbols::int_signature(), true);
++ }
++}
++
++void impl_java_dyn_BoundMethodHandle::compute_offsets() {
++ klassOop k = SystemDictionary::BoundMethodHandle_klass();
++ if (k != NULL && MethodHandles) {
++ compute_offset(_vmargslot_offset, k, vmSymbols::vmargslot_name(), vmSymbols::int_signature(), true);
++ compute_offset(_argument_offset, k, vmSymbols::argument_name(), vmSymbols::object_signature(), true);
++ }
++}
++
++void impl_java_dyn_AdapterMethodHandle::compute_offsets() {
++ klassOop k = SystemDictionary::AdapterMethodHandle_klass();
++ if (k != NULL && MethodHandles) {
++ compute_offset(_conversion_offset, k, vmSymbols::conversion_name(), vmSymbols::int_signature(), true);
+ }
+}
+
@@ -2997,29 +3764,52 @@ diff --git a/src/share/vm/classfile/java
+ return mh->obj_field(_type_offset);
+}
+
-+oop java_dyn_MethodHandle::vmref(oop mh) {
-+ return mh->obj_field(_vmref_offset);
-+}
-+
-+void java_dyn_MethodHandle::set_vmref(oop mh, oop ref) {
-+ mh->obj_field_put(_vmref_offset, ref);
-+}
-+
-+jlong java_dyn_MethodHandle::vmdata(oop mh) {
-+ return mh->long_field(_vmdata_offset);
-+}
-+
-+void java_dyn_MethodHandle::set_vmdata(oop mh, jlong data) {
-+ mh->long_field_put(_vmdata_offset, data);
-+}
-+
-+MethodEntry* java_dyn_MethodHandle::entry(oop mh) {
-+ return (MethodEntry*) mh->address_field(_entry_offset);
-+}
-+
-+void java_dyn_MethodHandle::set_entry(oop mh, MethodEntry* me) {
++void java_dyn_MethodHandle::set_type(oop mh, oop mtype) {
++ mh->obj_field_put(_type_offset, mtype);
++}
++
++int java_dyn_MethodHandle::vmslots(oop mh) {
++ int vmslots_offset = _vmslots_offset;
++ if (vmslots_offset != 0) {
++#ifdef ASSERT
++ int x = mh->int_field(vmslots_offset);
++ int y = compute_vmslots(mh);
++ assert(x == y, "correct hoisted value");
++#endif
++ return mh->int_field(vmslots_offset);
++ } else {
++ return compute_vmslots(mh);
++ }
++}
++
++// if MH.vmslots exists, hoist into it the value of type.form.vmslots
++void java_dyn_MethodHandle::init_vmslots(oop mh) {
++ int vmslots_offset = _vmslots_offset;
++ if (vmslots_offset != 0) {
++ mh->int_field_put(vmslots_offset, compute_vmslots(mh));
++ }
++}
++
++// fetch type.form.vmslots, which is the number of JVM stack slots
++// required to carry the arguments of this MH
++int java_dyn_MethodHandle::compute_vmslots(oop mh) {
++ oop mtype = type(mh);
++ if (mtype == NULL) return 0; // Java code would get NPE
++ oop form = java_dyn_MethodType::form(mtype);
++ if (form == NULL) return 0; // Java code would get NPE
++ return java_dyn_MethodTypeForm::vmslots(form);
++}
++
++// fetch the low-level entry point for this mh
++MethodEntry* java_dyn_MethodHandle::vmentry(oop mh) {
++ return (MethodEntry*) mh->address_field(_vmentry_offset);
++}
++
++void java_dyn_MethodHandle::set_vmentry(oop mh, MethodEntry* me) {
++ assert(_vmentry_offset != 0, "must be present");
++
+ // This is always the final step that initializes a valid method handle:
-+ mh->release_address_field_put(_entry_offset, (address) me);
++ mh->release_address_field_put(_vmentry_offset, (address) me);
+
+ // There should be enough memory barriers on exit from native methods
+ // to ensure that the MH is fully initialized to all threads before
@@ -3027,14 +3817,44 @@ diff --git a/src/share/vm/classfile/java
+ // But just in case, we use release_address_field_put.
+}
+
-+oop java_dyn_MethodHandle::BMH_receiver(oop mh) {
-+ assert(mh->klass() == SystemDictionary::dyn_impl_BMH_klass(), "BMH only");
-+ return mh->obj_field(_receiver_offset);
-+}
-+
-+oop java_dyn_MethodHandle::AMH_target(oop mh) {
-+ assert(mh->klass() == SystemDictionary::dyn_impl_AMH_klass(), "AMH only");
-+ return mh->obj_field(_target_offset);
++oop java_dyn_MethodHandle::vmtarget(oop mh) {
++ assert(Klass::cast(mh->klass())->is_subclass_of(SystemDictionary::MethodHandle_klass()), "wrong type");
++ return mh->obj_field(_vmtarget_offset);
++}
++
++void java_dyn_MethodHandle::set_vmtarget(oop mh, oop ref) {
++ assert(Klass::cast(mh->klass())->is_subclass_of(SystemDictionary::MethodHandle_klass()), "wrong type");
++ mh->obj_field_put(_vmtarget_offset, ref);
++}
++
++int impl_java_dyn_DirectMethodHandle::vmindex(oop mh) {
++ assert(Klass::cast(mh->klass())->is_subclass_of(SystemDictionary::DirectMethodHandle_klass()), "wrong type");
++ return mh->int_field(_vmindex_offset);
++}
++
++void impl_java_dyn_DirectMethodHandle::set_vmindex(oop mh, int index) {
++ assert(Klass::cast(mh->klass())->is_subclass_of(SystemDictionary::DirectMethodHandle_klass()), "wrong type");
++ mh->int_field_put(_vmindex_offset, index);
++}
++
++int impl_java_dyn_BoundMethodHandle::vmargslot(oop mh) {
++ assert(Klass::cast(mh->klass())->is_subclass_of(SystemDictionary::BoundMethodHandle_klass()), "wrong type");
++ return mh->int_field(_vmargslot_offset);
++}
++
++oop impl_java_dyn_BoundMethodHandle::argument(oop mh) {
++ assert(Klass::cast(mh->klass())->is_subclass_of(SystemDictionary::BoundMethodHandle_klass()), "wrong type");
++ return mh->obj_field(_argument_offset);
++}
++
++int impl_java_dyn_AdapterMethodHandle::conversion(oop mh) {
++ assert(mh->klass() == SystemDictionary::AdapterMethodHandle_klass(), "AMH only");
++ return mh->int_field(_conversion_offset);
++}
++
++void impl_java_dyn_AdapterMethodHandle::set_conversion(oop mh, int conv) {
++ assert(mh->klass() == SystemDictionary::AdapterMethodHandle_klass(), "AMH only");
++ mh->int_field_put(_conversion_offset, conv);
+}
+
+
@@ -3043,72 +3863,88 @@ diff --git a/src/share/vm/classfile/java
+int java_dyn_MethodType::_rtype_offset;
+int java_dyn_MethodType::_ptypes_offset;
+int java_dyn_MethodType::_form_offset;
-+int java_dyn_MethodType::Form::_vmref_offset;
-+int java_dyn_MethodType::Form::_vmdata_offset;
+
+void java_dyn_MethodType::compute_offsets() {
-+ klassOop k = SystemDictionary::java_dyn_MethodType_klass();
++ klassOop k = SystemDictionary::MethodType_klass();
+ if (k != NULL) {
+ compute_offset(_rtype_offset, k, vmSymbols::rtype_name(), vmSymbols::class_signature());
+ compute_offset(_ptypes_offset, k, vmSymbols::ptypes_name(), vmSymbols::class_array_signature());
+ compute_offset(_form_offset, k, vmSymbols::form_name(), vmSymbols::java_dyn_MethodTypeForm_signature());
+ }
-+ java_dyn_MethodType::Form::compute_offsets();
-+}
-+
-+void java_dyn_MethodType::Form::compute_offsets() {
-+ klassOop k = SystemDictionary::java_dyn_MethodTypeForm_klass();
++}
++
++oop java_dyn_MethodType::rtype(oop mt) {
++ assert(is_instance(mt), "must be a MethodType");
++ return mt->obj_field(_rtype_offset);
++}
++
++objArrayOop java_dyn_MethodType::ptypes(oop mt) {
++ assert(is_instance(mt), "must be a MethodType");
++ return (objArrayOop) mt->obj_field(_ptypes_offset);
++}
++
++oop java_dyn_MethodType::form(oop mt) {
++ assert(is_instance(mt), "must be a MethodType");
++ return mt->obj_field(_form_offset);
++}
++
++oop java_dyn_MethodType::ptype(oop mt, int idx) {
++ return ptypes(mt)->obj_at(idx);
++}
++
++
++
++// Support for java_dyn_MethodTypeForm
++
++int java_dyn_MethodTypeForm::_vmslots_offset;
++int java_dyn_MethodTypeForm::_erasedType_offset;
++
++void java_dyn_MethodTypeForm::compute_offsets() {
++ klassOop k = SystemDictionary::MethodTypeForm_klass();
+ if (k != NULL) {
-+ compute_optional_offset(_vmref_offset, k, vmSymbols::vmref_name(), vmSymbols::object_signature(), true);
-+ compute_optional_offset(_vmdata_offset, k, vmSymbols::vmdata_name(), vmSymbols::long_signature(), true);
-+ if (_vmdata_offset != 0) _vmdata_offset += oopDesc::address_padding_in_bytes();
-+ }
-+}
-+
-+oop java_dyn_MethodType::rtype(oop mt) {
-+ return mt->obj_field(_rtype_offset);
-+}
-+
-+objArrayOop java_dyn_MethodType::ptypes(oop mt) {
-+ return (objArrayOop) mt->obj_field(_ptypes_offset);
-+}
-+
-+oop java_dyn_MethodType::form(oop mt) {
-+ return mt->obj_field(_form_offset);
-+}
-+
-+oop java_dyn_MethodType::Form::vmref(oop mtform) {
-+ return mtform->obj_field(_vmref_offset);
-+}
-+
-+void java_dyn_MethodType::Form::set_vmref(oop mtform, oop ref) {
-+ mtform->obj_field_put(_vmref_offset, ref);
-+}
-+
-+address java_dyn_MethodType::Form::vmdata(oop mtform) {
-+ return mtform->address_field(_vmdata_offset);
-+}
-+
-+void java_dyn_MethodType::Form::set_vmdata(oop mtform, address data) {
-+ mtform->address_field_put(_vmdata_offset, data);
-+}
-+
-+
-
-
++ compute_optional_offset(_vmslots_offset, k, vmSymbols::vmslots_name(), vmSymbols::int_signature(), true);
++ compute_optional_offset(_erasedType_offset, k, vmSymbols::erasedType_name(), vmSymbols::java_dyn_MethodType_signature(), true);
++ }
++}
++
++int java_dyn_MethodTypeForm::vmslots(oop mtform) {
++ assert(mtform->klass() == SystemDictionary::MethodTypeForm_klass(), "MTForm only");
++ return mtform->int_field(_vmslots_offset);
++}
++
++oop java_dyn_MethodTypeForm::erasedType(oop mtform) {
++ assert(mtform->klass() == SystemDictionary::MethodTypeForm_klass(), "MTForm only");
++ return mtform->obj_field(_erasedType_offset);
++}
++
++
++
++
// Support for java_security_AccessControlContext
-@@ -2354,6 +2537,10 @@
+
+ int java_security_AccessControlContext::_context_offset = 0;
+ int java_security_AccessControlContext::_privilegedContext_offset = 0;
+ int java_security_AccessControlContext::_isPrivileged_offset = 0;
+-
+
+ void java_security_AccessControlContext::compute_offsets() {
+ assert(_isPrivileged_offset == 0, "offsets should be initialized only once");
+@@ -2354,6 +2605,14 @@
java_lang_System::compute_offsets();
java_lang_Thread::compute_offsets();
java_lang_ThreadGroup::compute_offsets();
+ if (MethodHandles) {
+ java_dyn_MethodHandle::compute_offsets();
++ impl_java_dyn_DirectMethodHandle::compute_offsets();
++ impl_java_dyn_BoundMethodHandle::compute_offsets();
++ impl_java_dyn_AdapterMethodHandle::compute_offsets();
+ java_dyn_MethodType::compute_offsets();
++ java_dyn_MethodTypeForm::compute_offsets();
+ }
java_security_AccessControlContext::compute_offsets();
// Initialize reflection classes. The layouts of these classes
// changed with the new reflection implementation in JDK 1.4, and
-@@ -2371,6 +2558,9 @@
+@@ -2371,6 +2630,9 @@
sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets();
}
sun_misc_AtomicLongCSImpl::compute_offsets();
@@ -3121,7 +3957,15 @@ diff --git a/src/share/vm/classfile/java
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
-@@ -665,6 +665,8 @@
+@@ -148,6 +148,7 @@
+ static oop create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS);
+ // Conversion
+ static klassOop as_klassOop(oop java_class);
++ static BasicType as_BasicType(oop java_class, klassOop* reference_klass = NULL);
+ // Testing
+ static bool is_instance(oop obj) {
+ return obj != NULL && obj->klass() == SystemDictionary::class_klass();
+@@ -665,6 +666,8 @@
static BasicType basic_type(oop box);
static bool is_instance(oop box) { return basic_type(box) != T_ILLEGAL; }
static bool is_instance(oop box, BasicType type) { return basic_type(box) == type; }
@@ -3130,7 +3974,7 @@ diff --git a/src/share/vm/classfile/java
static int value_offset_in_bytes(BasicType type) {
return ( type == T_LONG || type == T_DOUBLE ) ? long_value_offset :
-@@ -769,6 +771,107 @@
+@@ -769,6 +772,154 @@
};
@@ -3142,47 +3986,91 @@ diff --git a/src/share/vm/classfile/java
+ friend class JavaClasses;
+
+ private:
-+ static int _type_offset;
-+ static int _vmref_offset;
-+ static int _vmdata_offset;
-+ static int _vmdata_argslot_offset; // arithmetic low half of vmdata
-+ static int _vmdata_index_offset; // arithmetic high half of vmdata
-+ static int _entry_offset;
-+ static int _receiver_offset;
-+ static int _target_offset;
++ static int _vmentry_offset; // assembly code trampoline for MH
++ static int _vmtarget_offset; // class-specific target reference
++ static int _type_offset; // the MethodType of this MH
++ static int _vmslots_offset; // OPTIONAL hoisted type.form.vmslots
+
+ static void compute_offsets();
+
+ public:
+ // Accessors
+ static oop type(oop mh);
-+
-+ static oop vmref(oop mh);
-+ static void set_vmref(oop mh, oop ref);
-+
-+ static jlong vmdata(oop mh);
-+ static void set_vmdata(oop mh, jlong data);
-+
-+ static jint vmdata_argslot(oop mh) { return low(vmdata(mh)); }
-+ static jint vmdata_index(oop mh) { return high(vmdata(mh)); }
-+ static void set_vmdata(oop mh, jint index, jint argslot)
-+ { set_vmdata(mh, jlong_from(index, argslot)); }
-+
-+ static MethodEntry* entry(oop mh);
-+ static void set_entry(oop mh, MethodEntry* data);
-+
-+ static oop BMH_receiver(oop mh);
-+ static oop AMH_target(oop mh);
++ static void set_type(oop mh, oop mtype);
++
++ static oop vmtarget(oop mh);
++ static void set_vmtarget(oop mh, oop target);
++
++ static MethodEntry* vmentry(oop mh);
++ static void set_vmentry(oop mh, MethodEntry* data);
++
++ static int vmslots(oop mh);
++ static void init_vmslots(oop mh);
++ static int compute_vmslots(oop mh);
++
++ // Testers
++ static bool is_subclass(klassOop klass) {
++ return Klass::cast(klass)->is_subclass_of(SystemDictionary::MethodHandle_klass());
++ }
++ static bool is_instance(oop obj) {
++ return obj != NULL && is_subclass(obj->klass());
++ }
+
+ // Accessors for code generation:
+ static int type_offset_in_bytes() { return _type_offset; }
-+ static int vmref_offset_in_bytes() { return _vmref_offset; }
-+ static int vmdata_offset_in_bytes() { return _vmdata_offset; }
-+ static int vmdata_argslot_offset_in_bytes() { return _vmdata_argslot_offset; }
-+ static int vmdata_index_offset_in_bytes() { return _vmdata_index_offset; }
-+ static int entry_offset_in_bytes() { return _entry_offset; }
-+ static int receiver_offset_in_bytes() { return _receiver_offset; }
-+ static int target_offset_in_bytes() { return _target_offset; }
++ static int vmtarget_offset_in_bytes() { return _vmtarget_offset; }
++ static int vmentry_offset_in_bytes() { return _vmentry_offset; }
++ static int vmslots_offset_in_bytes() { return _vmslots_offset; }
++};
++
++class impl_java_dyn_DirectMethodHandle: public java_dyn_MethodHandle {
++ friend class JavaClasses;
++
++ private:
++ // _vmtarget_offset; // method or class or interface
++ static int _vmindex_offset; // negative or vtable idx or itable idx
++ static void compute_offsets();
++
++ public:
++ // Accessors
++ static int vmindex(oop mh);
++ static void set_vmindex(oop mh, int index);
++
++ // Accessors for code generation:
++ static int vmindex_offset_in_bytes() { return _vmindex_offset; }
++};
++
++class impl_java_dyn_BoundMethodHandle: public java_dyn_MethodHandle {
++ friend class JavaClasses;
++
++ private:
++ static int _argument_offset; // argument value bound into this MH
++ static int _vmargslot_offset; // relevant argument slot (<= vmslots)
++ static void compute_offsets();
++
++public:
++ static oop argument(oop mh);
++ static void set_argument(oop mh, oop ref);
++
++ static jint vmargslot(oop mh);
++ static void set_vmargslot(oop mh, jint slot);
++
++ static int argument_offset_in_bytes() { return _argument_offset; }
++ static int vmargslot_offset_in_bytes() { return _vmargslot_offset; }
++};
++
++class impl_java_dyn_AdapterMethodHandle: public impl_java_dyn_BoundMethodHandle {
++ friend class JavaClasses;
++
++ private:
++ static int _conversion_offset; // type of conversion to apply
++ static void compute_offsets();
++
++public:
++ static int conversion(oop mh);
++ static void set_conversion(oop mh, int conv);
++
++ static int conversion_offset_in_bytes() { return _conversion_offset; }
+};
+
+
@@ -3204,35 +4092,38 @@ diff --git a/src/share/vm/classfile/java
+ static objArrayOop ptypes(oop mh);
+ static oop form(oop mh);
+
++ static oop ptype(oop mh, int index);
++
++ static bool is_instance(oop obj) {
++ return obj != NULL && obj->klass() == SystemDictionary::MethodType_klass();
++ }
++
+ // Accessors for code generation:
+ static int rtype_offset_in_bytes() { return _rtype_offset; }
+ static int ptypes_offset_in_bytes() { return _ptypes_offset; }
+ static int form_offset_in_bytes() { return _form_offset; }
-+
-+ class Form: AllStatic {
-+ friend class JavaClasses;
-+ friend class java_dyn_MethodType;
-+
-+ private:
-+ static int _vmref_offset;
-+ static int _vmdata_offset;
-+
-+ static void compute_offsets();
-+
-+ public:
-+ // Accessors
-+ static oop vmref(oop mh);
-+ static void set_vmref(oop mh, oop ref);
-+
-+ static address vmdata(oop mh);
-+ static void set_vmdata(oop mh, address data);
-+
-+ // Accessors for code generation:
-+ static int vmref_offset_in_bytes() { return _vmref_offset; }
-+ static int vmdata_offset_in_bytes() { return _vmdata_offset; }
-+ };
-+
+};
++
++class java_dyn_MethodTypeForm: AllStatic {
++ friend class JavaClasses;
++
++ private:
++ static int _vmslots_offset; // number of argument slots needed
++ static int _erasedType_offset; // erasedType = canonical MethodType
++
++ static void compute_offsets();
++
++ public:
++ // Accessors
++ static int vmslots(oop mh);
++ static oop erasedType(oop mh);
++
++ // Accessors for code generation:
++ static int vmslots_offset_in_bytes() { return _vmslots_offset; }
++ static int erasedType_offset_in_bytes() { return _erasedType_offset; }
++};
++
++
+
+
// Interface to java.security.AccessControlContext objects
@@ -3300,7 +4191,7 @@ diff --git a/src/share/vm/classfile/syst
_number_of_modifications = 0;
_loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
_resolution_errors = new ResolutionErrorTable(_resolution_error_size);
-+ //_invoke_method_table = new SymbolPropertyTable(_invoke_method_size);
++ // _invoke_method_table is allocated lazily in find_method_handle_invoke()
// Allocate private object used as system class loader lock
_system_loader_lock_obj = oopFactory::new_system_objArray(0, CHECK);
@@ -3319,8 +4210,8 @@ diff --git a/src/share/vm/classfile/syst
instanceKlass::cast(WK_KLASS(final_reference_klass))->set_reference_type(REF_FINAL);
instanceKlass::cast(WK_KLASS(phantom_reference_klass))->set_reference_type(REF_PHANTOM);
+
-+ WKID meth_group_start = WK_KLASS_ENUM_NAME(java_dyn_MethodHandle_klass);
-+ WKID meth_group_end = WK_KLASS_ENUM_NAME(java_dyn_WrongMethodTypeException_klass);
++ WKID meth_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass);
++ WKID meth_group_end = WK_KLASS_ENUM_NAME(WrongMethodTypeException_klass);
+ initialize_wk_klasses_until(meth_group_start, scan, CHECK);
+ if (MethodHandles) {
+ initialize_wk_klasses_through(meth_group_start, scan, CHECK);
@@ -3430,7 +4321,7 @@ diff --git a/src/share/vm/classfile/syst
+ Handle mt = compute_method_handle_type(signature(),
+ class_loader, protection_domain,
+ CHECK_NULL);
-+ KlassHandle mh_klass = KlassHandles::java_dyn_MethodHandle_klass();
++ KlassHandle mh_klass = KlassHandles::MethodHandle_klass();
+ methodHandle m = methodOopDesc::make_invoke_method(mh_klass, signature,
+ mt, CHECK_NULL);
+ // Now grab the lock. We might have to throw away the new method,
@@ -3489,7 +4380,7 @@ diff --git a/src/share/vm/classfile/syst
+ args.push_int(trusted);
+ JavaValue result(T_OBJECT);
+ JavaCalls::call_static(&result,
-+ SystemDictionary::java_dyn_MethodType_klass(),
++ SystemDictionary::MethodType_klass(),
+ vmSymbols::makeImpl_name(), vmSymbols::makeImpl_signature(),
+ &args, CHECK_(empty));
+ return Handle(THREAD, (oop) result.get_jobject());
@@ -3512,14 +4403,14 @@ diff --git a/src/share/vm/classfile/syst
template(reflect_unsafe_static_field_accessor_impl_klass, sun_reflect_UnsafeStaticFieldAccessorImpl, Opt_Only_JDK15) \
\
+ /* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \
-+ template(java_dyn_MethodHandle_klass, java_dyn_MethodHandle, Opt) \
-+ template(dyn_impl_AMH_klass, java_dyn_impl_AMH, Opt) \
-+ template(dyn_impl_BMH_klass, java_dyn_impl_BMH, Opt) \
-+ template(dyn_impl_DMH_klass, java_dyn_impl_DMH, Opt) \
-+ template(dyn_impl_MTForm_klass, java_dyn_impl_MTForm, Opt) \
-+ template(java_dyn_MethodType_klass, java_dyn_MethodType, Opt) \
-+ template(java_dyn_MethodTypeForm_klass, java_dyn_MethodTypeForm, Opt) \
-+ template(java_dyn_WrongMethodTypeException_klass, java_dyn_WrongMethodTypeException, Opt) \
++ template(MethodHandle_klass, java_dyn_MethodHandle, Opt) \
++ template(MethodHandleImpl_klass, impl_java_dyn_MethodHandleImpl, Opt) \
++ template(AdapterMethodHandle_klass, impl_java_dyn_AdapterMethodHandle, Opt) \
++ template(BoundMethodHandle_klass, impl_java_dyn_BoundMethodHandle, Opt) \
++ template(DirectMethodHandle_klass, impl_java_dyn_DirectMethodHandle, Opt) \
++ template(MethodType_klass, java_dyn_MethodType, Opt) \
++ template(MethodTypeForm_klass, java_dyn_MethodTypeForm, Opt) \
++ template(WrongMethodTypeException_klass, java_dyn_WrongMethodTypeException, Opt) \
template(vector_klass, java_util_Vector, Pre) \
template(hashtable_klass, java_util_Hashtable, Pre) \
template(stringBuffer_klass, java_lang_StringBuffer, Pre) \
@@ -3531,7 +4422,7 @@ diff --git a/src/share/vm/classfile/syst
NOT_PRODUCT(friend class instanceKlassKlass;)
public:
-@@ -447,6 +458,17 @@
+@@ -443,6 +454,17 @@
static char* check_signature_loaders(symbolHandle signature, Handle loader1,
Handle loader2, bool is_method, TRAPS);
@@ -3549,7 +4440,7 @@ diff --git a/src/share/vm/classfile/syst
// Utility for printing loader "name" as part of tracing constraints
static const char* loader_name(oop loader) {
return ((loader) == NULL ? "<bootloader>" :
-@@ -463,6 +485,7 @@
+@@ -459,6 +481,7 @@
enum Constants {
_loader_constraint_size = 107, // number of entries in constraint table
_resolution_error_size = 107, // number of entries in resolution error table
@@ -3557,7 +4448,7 @@ diff --git a/src/share/vm/classfile/syst
_nof_buckets = 1009 // number of buckets in hash table
};
-@@ -492,6 +515,9 @@
+@@ -488,6 +511,9 @@
// Resolution errors
static ResolutionErrorTable* _resolution_errors;
@@ -3567,7 +4458,7 @@ diff --git a/src/share/vm/classfile/syst
public:
// for VM_CounterDecay iteration support
friend class CounterDecay;
-@@ -509,6 +535,7 @@
+@@ -505,6 +531,7 @@
static PlaceholderTable* placeholders() { return _placeholders; }
static LoaderConstraintTable* constraints() { return _loader_constraints; }
static ResolutionErrorTable* resolution_errors() { return _resolution_errors; }
@@ -3575,7 +4466,7 @@ diff --git a/src/share/vm/classfile/syst
// Basic loading operations
static klassOop resolve_instance_class_or_null(symbolHandle class_name, Handle class_loader, Handle protection_domain, TRAPS);
-@@ -598,3 +625,17 @@
+@@ -594,3 +621,17 @@
static bool _has_loadClassInternal;
static bool _has_checkPackageAccess;
};
@@ -3596,7 +4487,7 @@ diff --git a/src/share/vm/classfile/vmSy
diff --git a/src/share/vm/classfile/vmSymbols.hpp b/src/share/vm/classfile/vmSymbols.hpp
--- a/src/share/vm/classfile/vmSymbols.hpp
+++ b/src/share/vm/classfile/vmSymbols.hpp
-@@ -214,7 +214,24 @@
+@@ -214,7 +214,25 @@
template(sun_reflect_UnsafeStaticFieldAccessorImpl, "sun/reflect/UnsafeStaticFieldAccessorImpl")\
template(base_name, "base") \
\
@@ -3604,42 +4495,47 @@ diff --git a/src/share/vm/classfile/vmSy
+ /* Support for JSR 292 & invokedynamic (JDK 1.7 and above) */ \
+ template(java_dyn_MethodHandle, "java/dyn/MethodHandle") \
+ template(java_dyn_MethodType, "java/dyn/MethodType") \
-+ template(java_dyn_MethodTypeForm, "java/dyn/MethodTypeForm") \
+ template(java_dyn_WrongMethodTypeException, "java/dyn/WrongMethodTypeException") \
+ template(java_dyn_MethodType_signature, "Ljava/dyn/MethodType;") \
+ template(java_dyn_MethodHandle_signature, "Ljava/dyn/MethodHandle;") \
++ /* internal classes known only to the JVM: */ \
++ template(java_dyn_MethodTypeForm, "java/dyn/MethodTypeForm") \
+ template(java_dyn_MethodTypeForm_signature, "Ljava/dyn/MethodTypeForm;") \
-+ /* internal classes known only to the JVM: */ \
-+ template(java_dyn_impl_MTForm, "java/dyn/impl/MTForm") \
-+ template(java_dyn_impl_MH, "java/dyn/impl/MH") \
-+ template(java_dyn_impl_AMH, "java/dyn/impl/AMH") \
-+ template(java_dyn_impl_BMH, "java/dyn/impl/BMH") \
-+ template(java_dyn_impl_DMH, "java/dyn/impl/DMH") \
++ template(impl_java_dyn_MethodHandleImpl, "impl/java/dyn/MethodHandleImpl") \
++ template(impl_java_dyn_AdapterMethodHandle, "impl/java/dyn/AdapterMethodHandle") \
++ template(impl_java_dyn_BoundMethodHandle, "impl/java/dyn/BoundMethodHandle") \
++ template(impl_java_dyn_DirectMethodHandle, "impl/java/dyn/DirectMethodHandle") \
+ template(makeImpl_name, "makeImpl") /*MethodType::makeImpl*/ \
+ template(makeImpl_signature, "(Ljava/lang/Class;[Ljava/lang/Class;ZZ)Ljava/dyn/MethodType;") \
++ NOT_LP64( do_alias(machine_word_signature, int_signature) ) \
++ LP64_ONLY( do_alias(machine_word_signature, long_signature) ) \
+ \
+ /* common method and field names */ \
template(object_initializer_name, "<init>") \
template(class_initializer_name, "<clinit>") \
template(println_name, "println") \
-@@ -284,6 +301,16 @@
+@@ -284,6 +302,20 @@
template(value_name, "value") \
template(frontCacheEnabled_name, "frontCacheEnabled") \
template(stringCacheEnabled_name, "stringCacheEnabled") \
+ template(toString_name, "toString") \
-+ template(target_name, "target") \
+ template(values_name, "values") \
+ template(receiver_name, "receiver") \
-+ template(vmdata_name, "vmdata") \
-+ template(vmref_name, "vmref") \
++ template(vmtarget_name, "vmtarget") \
++ template(vmentry_name, "vmentry") \
++ template(vmslots_name, "vmslots") \
++ template(vmindex_name, "vmindex") \
++ template(vmargslot_name, "vmargslot") \
++ template(argument_name, "argument") \
++ template(conversion_name, "conversion") \
+ template(rtype_name, "rtype") \
+ template(ptypes_name, "ptypes") \
+ template(form_name, "form") \
-+ template(entry_name, "entry") \
++ template(erasedType_name, "erasedType") \
\
/* non-intrinsic name/signature pairs: */ \
template(register_method_name, "register") \
-@@ -347,6 +374,7 @@
+@@ -347,6 +379,7 @@
template(void_classloader_signature, "()Ljava/lang/ClassLoader;") \
template(void_object_signature, "()Ljava/lang/Object;") \
template(void_class_signature, "()Ljava/lang/Class;") \
@@ -3685,7 +4581,7 @@ diff --git a/src/share/vm/includeDB_core
interpreter_<arch_model>.cpp methodOop.hpp
interpreter_<arch_model>.cpp oop.inline.hpp
interpreter_<arch_model>.cpp sharedRuntime.hpp
-@@ -2808,6 +2811,22 @@
+@@ -2809,6 +2812,23 @@
methodDataOop.hpp orderAccess.hpp
methodDataOop.hpp universe.hpp
@@ -3697,6 +4593,7 @@ diff --git a/src/share/vm/includeDB_core
+methodHandles.cpp interpreter.hpp
+methodHandles.cpp javaCalls.hpp
+methodHandles.cpp methodHandles.hpp
++methodHandles.cpp oopFactory.hpp
+methodHandles.cpp reflection.hpp
+methodHandles.cpp signature.hpp
+methodHandles.cpp symbolTable.hpp
@@ -3708,7 +4605,7 @@ diff --git a/src/share/vm/includeDB_core
methodKlass.cpp collectedHeap.inline.hpp
methodKlass.cpp constMethodKlass.hpp
methodKlass.cpp gcLocker.hpp
-@@ -3057,6 +3076,7 @@
+@@ -3058,6 +3078,7 @@
oop.inline.hpp arrayOop.hpp
oop.inline.hpp atomic.hpp
oop.inline.hpp barrierSet.inline.hpp
@@ -3716,7 +4613,7 @@ diff --git a/src/share/vm/includeDB_core
oop.inline.hpp cardTableModRefBS.hpp
oop.inline.hpp collectedHeap.inline.hpp
oop.inline.hpp compactingPermGenGen.hpp
-@@ -3667,6 +3687,7 @@
+@@ -3669,6 +3690,7 @@
sharedRuntime.cpp interpreter.hpp
sharedRuntime.cpp javaCalls.hpp
sharedRuntime.cpp jvmtiExport.hpp
@@ -3724,7 +4621,7 @@ diff --git a/src/share/vm/includeDB_core
sharedRuntime.cpp nativeInst_<arch>.hpp
sharedRuntime.cpp nativeLookup.hpp
sharedRuntime.cpp oop.inline.hpp
-@@ -3852,6 +3873,7 @@
+@@ -3854,6 +3876,7 @@
stubGenerator_<arch_model>.cpp handles.inline.hpp
stubGenerator_<arch_model>.cpp instanceOop.hpp
stubGenerator_<arch_model>.cpp interpreter.hpp
@@ -3808,7 +4705,7 @@ diff --git a/src/share/vm/interpreter/in
diff --git a/src/share/vm/interpreter/interpreterRuntime.cpp b/src/share/vm/interpreter/interpreterRuntime.cpp
--- a/src/share/vm/interpreter/interpreterRuntime.cpp
+++ b/src/share/vm/interpreter/interpreterRuntime.cpp
-@@ -292,6 +292,29 @@
+@@ -292,6 +292,24 @@
// create exception
THROW_MSG(vmSymbols::java_lang_ClassCastException(), message);
IRT_END
@@ -3822,11 +4719,6 @@ diff --git a/src/share/vm/interpreter/in
+ char* message = SharedRuntime::generate_wrong_method_type_message(thread, required, actual);
+
+ if (ProfileTraps) {
-+ /* %%% do it this way?
-+ if (SharedRuntime::wrong_method_type_is_for_single_argument(thread, required) != NULL)
-+ note_trap(thread, Deoptimization::Reason_class_check, CHECK);
-+ else
-+ */
+ note_trap(thread, Deoptimization::Reason_constraint, CHECK);
+ }
+
@@ -3860,7 +4752,7 @@ diff --git a/src/share/vm/interpreter/li
+
+void LinkResolver::lookup_implicit_method(methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS) {
+ if (MethodHandles &&
-+ name == vmSymbolHandles::invoke_name() && klass() == SystemDictionary::java_dyn_MethodHandle_klass()) {
++ name == vmSymbolHandles::invoke_name() && klass() == SystemDictionary::MethodHandle_klass()) {
+ methodOop result_oop = SystemDictionary::find_method_handle_invoke(signature,
+ Handle(),
+ Handle(),
@@ -3966,6 +4858,239 @@ diff --git a/src/share/vm/memory/dump.cp
GenCollectedHeap* gch = GenCollectedHeap::heap();
// At this point, many classes have been loaded.
+diff --git a/src/share/vm/oops/instanceKlass.cpp b/src/share/vm/oops/instanceKlass.cpp
+--- a/src/share/vm/oops/instanceKlass.cpp
++++ b/src/share/vm/oops/instanceKlass.cpp
+@@ -1996,9 +1996,11 @@
+
+ // Printing
+
++#define BULLET " - "
++
+ void FieldPrinter::do_field(fieldDescriptor* fd) {
+- if (fd->is_static() == (_obj == NULL)) {
+- _st->print(" - ");
++ _st->print(BULLET);
++ if (fd->is_static() || (_obj == NULL)) {
+ fd->print_on(_st);
+ _st->cr();
+ } else {
+@@ -2019,7 +2021,7 @@
+ value->is_typeArray() &&
+ offset <= (juint) value->length() &&
+ offset + length <= (juint) value->length()) {
+- st->print("string: ");
++ st->print(BULLET"string: ");
+ Handle h_obj(obj);
+ java_lang_String::print(h_obj, st);
+ st->cr();
+@@ -2027,22 +2029,22 @@
+ }
+ }
+
+- st->print_cr("fields:");
++ st->print_cr(BULLET"---- fields (total size %d words):", oop_size(obj));
+ FieldPrinter print_nonstatic_field(st, obj);
+ do_nonstatic_fields(&print_nonstatic_field);
+
+ if (as_klassOop() == SystemDictionary::class_klass()) {
+ klassOop mirrored_klass = java_lang_Class::as_klassOop(obj);
+- st->print(" - fake entry for mirror: ");
++ st->print(BULLET"fake entry for mirror: ");
+ mirrored_klass->print_value_on(st);
+ st->cr();
+- st->print(" - fake entry resolved_constructor: ");
++ st->print(BULLET"fake entry resolved_constructor: ");
+ methodOop ctor = java_lang_Class::resolved_constructor(obj);
+ ctor->print_value_on(st);
+ klassOop array_klass = java_lang_Class::array_klass(obj);
+- st->print(" - fake entry for array: ");
++ st->cr();
++ st->print(BULLET"fake entry for array: ");
+ array_klass->print_value_on(st);
+- st->cr();
+ st->cr();
+ }
+ }
+@@ -2051,6 +2053,28 @@
+ st->print("a ");
+ name()->print_value_on(st);
+ obj->print_address_on(st);
++ if (as_klassOop() == SystemDictionary::string_klass()
++ && java_lang_String::value(obj) != NULL) {
++ ResourceMark rm;
++ int len = java_lang_String::length(obj);
++ int plen = (len < 24 ? len : 12);
++ char* str = java_lang_String::as_utf8_string(obj, 0, plen);
++ st->print(" = \"%s\"", str);
++ if (len > plen)
++ st->print("...[%d]", len);
++ } else if (as_klassOop() == SystemDictionary::class_klass()) {
++ klassOop k = java_lang_Class::as_klassOop(obj);
++ st->print(" = ");
++ if (k != NULL) {
++ k->print_value_on(st);
++ } else {
++ const char* tname = type2name(java_lang_Class::primitive_type(obj));
++ st->print("%s", tname ? tname : "type?");
++ }
++ } else if (java_lang_boxing_object::is_instance(obj)) {
++ st->print(" = ");
++ java_lang_boxing_object::print(obj, st);
++ }
+ }
+
+ #endif // ndef PRODUCT
+diff --git a/src/share/vm/oops/instanceKlassKlass.cpp b/src/share/vm/oops/instanceKlassKlass.cpp
+--- a/src/share/vm/oops/instanceKlassKlass.cpp
++++ b/src/share/vm/oops/instanceKlassKlass.cpp
+@@ -487,6 +487,8 @@
+
+ // Printing
+
++#define BULLET " - "
++
+ static const char* state_names[] = {
+ "unparseable_by_gc", "allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error"
+ };
+@@ -497,13 +499,13 @@
+ instanceKlass* ik = instanceKlass::cast(klassOop(obj));
+ klassKlass::oop_print_on(obj, st);
+
+- st->print(" - instance size: %d", ik->size_helper()); st->cr();
+- st->print(" - klass size: %d", ik->object_size()); st->cr();
+- st->print(" - access: "); ik->access_flags().print_on(st); st->cr();
+- st->print(" - state: "); st->print_cr(state_names[ik->_init_state]);
+- st->print(" - name: "); ik->name()->print_value_on(st); st->cr();
+- st->print(" - super: "); ik->super()->print_value_on(st); st->cr();
+- st->print(" - sub: ");
++ st->print(BULLET"instance size: %d", ik->size_helper()); st->cr();
++ st->print(BULLET"klass size: %d", ik->object_size()); st->cr();
++ st->print(BULLET"access: "); ik->access_flags().print_on(st); st->cr();
++ st->print(BULLET"state: "); st->print_cr(state_names[ik->_init_state]);
++ st->print(BULLET"name: "); ik->name()->print_value_on(st); st->cr();
++ st->print(BULLET"super: "); ik->super()->print_value_on(st); st->cr();
++ st->print(BULLET"sub: ");
+ Klass* sub = ik->subklass();
+ int n;
+ for (n = 0; sub != NULL; n++, sub = sub->next_sibling()) {
+@@ -516,12 +518,12 @@
+ st->cr();
+
+ if (ik->is_interface()) {
+- st->print_cr(" - nof implementors: %d", ik->nof_implementors());
++ st->print_cr(BULLET"nof implementors: %d", ik->nof_implementors());
+ int print_impl = 0;
+ for (int i = 0; i < instanceKlass::implementors_limit; i++) {
+ if (ik->implementor(i) != NULL) {
+ if (++print_impl == 1)
+- st->print_cr(" - implementor: ");
++ st->print_cr(BULLET"implementor: ");
+ st->print(" ");
+ ik->implementor(i)->print_value_on(st);
+ }
+@@ -529,34 +531,33 @@
+ if (print_impl > 0) st->cr();
+ }
+
+- st->print(" - arrays: "); ik->array_klasses()->print_value_on(st); st->cr();
+- st->print(" - methods: "); ik->methods()->print_value_on(st); st->cr();
++ st->print(BULLET"arrays: "); ik->array_klasses()->print_value_on(st); st->cr();
++ st->print(BULLET"methods: "); ik->methods()->print_value_on(st); st->cr();
+ if (Verbose) {
+ objArrayOop methods = ik->methods();
+ for(int i = 0; i < methods->length(); i++) {
+ tty->print("%d : ", i); methods->obj_at(i)->print_value(); tty->cr();
+ }
+ }
+- st->print(" - method ordering: "); ik->method_ordering()->print_value_on(st); st->cr();
+- st->print(" - local interfaces: "); ik->local_interfaces()->print_value_on(st); st->cr();
+- st->print(" - trans. interfaces: "); ik->transitive_interfaces()->print_value_on(st); st->cr();
+- st->print(" - constants: "); ik->constants()->print_value_on(st); st->cr();
+- st->print(" - class loader: "); ik->class_loader()->print_value_on(st); st->cr();
+- st->print(" - protection domain: "); ik->protection_domain()->print_value_on(st); st->cr();
+- st->print(" - host class: "); ik->host_klass()->print_value_on(st); st->cr();
+- st->print(" - signers: "); ik->signers()->print_value_on(st); st->cr();
++ st->print(BULLET"method ordering: "); ik->method_ordering()->print_value_on(st); st->cr();
++ st->print(BULLET"local interfaces: "); ik->local_interfaces()->print_value_on(st); st->cr();
++ st->print(BULLET"trans. interfaces: "); ik->transitive_interfaces()->print_value_on(st); st->cr();
++ st->print(BULLET"constants: "); ik->constants()->print_value_on(st); st->cr();
++ st->print(BULLET"class loader: "); ik->class_loader()->print_value_on(st); st->cr();
++ st->print(BULLET"protection domain: "); ik->protection_domain()->print_value_on(st); st->cr();
++ st->print(BULLET"host class: "); ik->host_klass()->print_value_on(st); st->cr();
++ st->print(BULLET"signers: "); ik->signers()->print_value_on(st); st->cr();
+ if (ik->source_file_name() != NULL) {
+- st->print(" - source file: ");
++ st->print(BULLET"source file: ");
+ ik->source_file_name()->print_value_on(st);
+ st->cr();
+ }
+ if (ik->source_debug_extension() != NULL) {
+- st->print(" - source debug extension: ");
++ st->print(BULLET"source debug extension: ");
+ ik->source_debug_extension()->print_value_on(st);
+ st->cr();
+ }
+
+- st->print_cr(" - previous version: ");
+ {
+ ResourceMark rm;
+ // PreviousVersionInfo objects returned via PreviousVersionWalker
+@@ -564,38 +565,43 @@
+ // GrowableArray _after_ the PreviousVersionWalker destructor
+ // has destroyed the handles.
+ {
++ bool have_pv = false;
+ PreviousVersionWalker pvw(ik);
+ for (PreviousVersionInfo * pv_info = pvw.next_previous_version();
+ pv_info != NULL; pv_info = pvw.next_previous_version()) {
++ if (!have_pv)
++ st->print(BULLET"previous version: ");
++ have_pv = true;
+ pv_info->prev_constant_pool_handle()()->print_value_on(st);
+ }
+- st->cr();
++ if (have_pv) st->cr();
+ } // pvw is cleaned up
+ } // rm is cleaned up
+
+ if (ik->generic_signature() != NULL) {
+- st->print(" - generic signature: ");
++ st->print(BULLET"generic signature: ");
+ ik->generic_signature()->print_value_on(st);
++ st->cr();
+ }
+- st->print(" - inner classes: "); ik->inner_classes()->print_value_on(st); st->cr();
+- st->print(" - java mirror: "); ik->java_mirror()->print_value_on(st); st->cr();
+- st->print(" - vtable length %d (start addr: " INTPTR_FORMAT ")", ik->vtable_length(), ik->start_of_vtable()); st->cr();
+- st->print(" - itable length %d (start addr: " INTPTR_FORMAT ")", ik->itable_length(), ik->start_of_itable()); st->cr();
+- st->print_cr(" - static fields:");
++ st->print(BULLET"inner classes: "); ik->inner_classes()->print_value_on(st); st->cr();
++ st->print(BULLET"java mirror: "); ik->java_mirror()->print_value_on(st); st->cr();
++ st->print(BULLET"vtable length %d (start addr: " INTPTR_FORMAT ")", ik->vtable_length(), ik->start_of_vtable()); st->cr();
++ st->print(BULLET"itable length %d (start addr: " INTPTR_FORMAT ")", ik->itable_length(), ik->start_of_itable()); st->cr();
++ st->print_cr(BULLET"---- static fields (%d words):", ik->static_field_size());
+ FieldPrinter print_static_field(st);
+ ik->do_local_static_fields(&print_static_field);
+- st->print_cr(" - non-static fields:");
+- FieldPrinter print_nonstatic_field(st, obj);
++ st->print_cr(BULLET"---- non-static fields (%d words):", ik->nonstatic_field_size());
++ FieldPrinter print_nonstatic_field(st);
+ ik->do_nonstatic_fields(&print_nonstatic_field);
+
+- st->print(" - static oop maps: ");
++ st->print(BULLET"static oop maps: ");
+ if (ik->static_oop_field_size() > 0) {
+ int first_offset = ik->offset_of_static_fields();
+ st->print("%d-%d", first_offset, first_offset + ik->static_oop_field_size() - 1);
+ }
+ st->cr();
+
+- st->print(" - non-static oop maps: ");
++ st->print(BULLET"non-static oop maps: ");
+ OopMapBlock* map = ik->start_of_nonstatic_oop_maps();
+ OopMapBlock* end_map = map + ik->nonstatic_oop_map_size();
+ while (map < end_map) {
diff --git a/src/share/vm/oops/klassVtable.cpp b/src/share/vm/oops/klassVtable.cpp
--- a/src/share/vm/oops/klassVtable.cpp
+++ b/src/share/vm/oops/klassVtable.cpp
@@ -4028,16 +5153,17 @@ diff --git a/src/share/vm/oops/methodKla
if (m->method_data() != NULL) {
st->print_cr(" - method data: " INTPTR_FORMAT, (address)m->method_data());
}
-@@ -293,6 +298,13 @@
+@@ -293,6 +298,14 @@
m->code()->print_value_on(st);
st->cr();
}
-+ if (m->is_native()) {
++ if (m->is_method_handle_invoke()) {
++ st->print_cr(" - invoke method type: " INTPTR_FORMAT, (address) m->method_handle_type());
++ // m is classified as native, but it does not have an interesting
++ // native_function or signature handler
++ } else if (m->is_native()) {
+ st->print_cr(" - native function: " INTPTR_FORMAT, m->native_function());
+ st->print_cr(" - signature handler: " INTPTR_FORMAT, m->signature_handler());
-+ }
-+ if (m->is_method_handle_invoke()) {
-+ st->print_cr(" - invoke method type: " INTPTR_FORMAT, (address) m->method_handle_type());
+ }
}
@@ -4045,18 +5171,19 @@ diff --git a/src/share/vm/oops/methodOop
diff --git a/src/share/vm/oops/methodOop.cpp b/src/share/vm/oops/methodOop.cpp
--- a/src/share/vm/oops/methodOop.cpp
+++ b/src/share/vm/oops/methodOop.cpp
-@@ -564,6 +564,10 @@
+@@ -564,6 +564,11 @@
bool methodOopDesc::is_not_compilable(int comp_level) const {
-+ if (is_method_handle_invoke())
++ if (is_method_handle_invoke()) {
+ // compilers must recognize this method specially, or not at all
+ return true;
++ }
+
methodDataOop mdo = method_data();
if (mdo != NULL
&& (uint)mdo->decompile_count() > (uint)PerMethodRecompilationCutoff) {
-@@ -651,7 +655,7 @@
+@@ -651,7 +656,7 @@
assert(entry != NULL, "interpreter entry must be non-null");
// Sets both _i2i_entry and _from_interpreted_entry
set_interpreter_entry(entry);
@@ -4065,7 +5192,7 @@ diff --git a/src/share/vm/oops/methodOop
set_native_function(
SharedRuntime::native_method_throw_unsatisfied_link_error_entry(),
!native_bind_event_is_interesting);
-@@ -782,6 +786,100 @@
+@@ -782,6 +787,100 @@
// caching this method should be just fine
return false;
}
@@ -4081,7 +5208,7 @@ diff --git a/src/share/vm/oops/methodOop
+oop methodOopDesc::method_handle_type() const {
+ if (!is_method_handle_invoke()) { assert(false, "caller resp."); return NULL; }
+ oop mt = constants()->resolved_string_at(_imcp_method_type_value);
-+ assert(mt->klass() == SystemDictionary::java_dyn_MethodType_klass(), "");
++ assert(mt->klass() == SystemDictionary::MethodType_klass(), "");
+ return mt;
+}
+
@@ -4102,7 +5229,7 @@ diff --git a/src/share/vm/oops/methodOop
+ Handle method_type, TRAPS) {
+ methodHandle empty;
+
-+ assert(holder() == SystemDictionary::java_dyn_MethodHandle_klass(),
++ assert(holder() == SystemDictionary::MethodHandle_klass(),
+ "must be a JSR 292 magic type");
+
+ if (TraceMethodHandles) {
@@ -4183,7 +5310,7 @@ diff --git a/src/share/vm/oops/methodOop
+ oop method_handle_type() const;
+ static jint* method_type_pointer_chase();
+ // presize interpreter frames for extra stack slots, if needed
-+ static int extra_stack() { return MethodHandles ? 2 : 0; }
++ static int extra_stack() { return MethodHandles ? (int)MethodHandlePushLimit : 0; }
// RedefineClasses() support:
bool is_old() const { return access_flags().is_old(); }
void set_is_old() { _access_flags.set_is_old(); }
@@ -4216,35 +5343,10 @@ diff --git a/src/share/vm/oops/oop.hpp b
// printing functions for VM debugging
void print_on(outputStream* st) const; // First level print
void print_value_on(outputStream* st) const; // Second level print.
-@@ -397,4 +400,10 @@
- static int mark_offset_in_bytes() { return offset_of(oopDesc, _mark); }
- static int klass_offset_in_bytes() { return offset_of(oopDesc, _metadata._klass); }
- static int klass_gap_offset_in_bytes();
-+
-+ // Machine addresses may be stored in jlong fields.
-+ // On 32-bit big-endian machines, we must increase field offset by four
-+ // in order to address raw address embedded in the jlong field.
-+ // (The goal is to preserve the value even if it is cast between jlong and intptr_t.)
-+ static int address_padding_in_bytes();
- };
diff --git a/src/share/vm/oops/oop.inline.hpp b/src/share/vm/oops/oop.inline.hpp
--- a/src/share/vm/oops/oop.inline.hpp
+++ b/src/share/vm/oops/oop.inline.hpp
-@@ -96,6 +96,13 @@
- } else {
- _metadata._klass = (klassOop)k;
- }
-+}
-+
-+inline int oopDesc::address_padding_in_bytes() {
-+ if (longSize > wordSize && !Bytes::is_Java_byte_ordering_different())
-+ // On a big-endian 32-bit system, push address fields 4 bytes into containing jlong fields.
-+ return (longSize - wordSize);
-+ return 0;
- }
-
- inline void oopDesc::init_mark() { set_mark(markOopDesc::prototype_for_object(this)); }
-@@ -347,6 +354,9 @@
+@@ -347,6 +347,9 @@
inline jdouble oopDesc::double_field_acquire(int offset) const { return OrderAccess::load_acquire(double_field_addr(offset)); }
inline void oopDesc::release_double_field_put(int offset, jdouble contents) { OrderAccess::release_store(double_field_addr(offset), contents); }
@@ -4258,7 +5360,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/vm/prims/methodHandles.cpp
-@@ -0,0 +1,662 @@
+@@ -0,0 +1,1537 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -4291,121 +5393,205 @@ new file mode 100644
+#include "incls/_methodHandles.cpp.incl"
+
+MethodEntry* MethodHandle::_entries[MethodHandle::_EK_LIMIT] = {NULL};
-+const char* MethodHandle::_entry_names[_EK_LIMIT] = {
++const char* MethodHandle::_entry_names[_EK_LIMIT+1] = {
+ "check_mtype",
-+ "wrong_method_type", // what happens when there is a type mismatch
-+ "invokestatic", // how a MH emulates invokestatic
-+ "invokespecial", // ditto for the other invokes...
++ "wrong_method_type", // what happens when there is a type mismatch
++ "invokestatic", // how a MH emulates invokestatic
++ "invokespecial", // ditto for the other invokes...
+ "invokevirtual",
+ "invokeinterface",
-+ "invokebound", // for BMH
-+ "adapt_retype_only", // these are for AMH
-+ "adapt_drop_initial",
-+ "adapt_drop_final",
++ "bound_ref", // these are for BMH...
++ "bound_int",
++ "bound_long",
++ "bound_ref_direct", // (direct versions have a direct methodOop)
++ "bound_int_direct",
++ "bound_long_direct",
++
++ // starting at _adapter_mh_first:
++ "adapt_retype_only", // these are for AMH...
+ "adapt_check_cast",
-+ "adapt_extend_sign",
-+ "adapt_extend_zero",
-+ "adapt_test_boolean",
-+ "adapt_swap_argument",
-+ "adapt_push_argument",
-+ "adapt_push_primitive",
-+ "adapt_push_reference",
++ "adapt_prim_to_prim",
++ "adapt_ref_to_prim",
++ "adapt_prim_to_ref",
++ "adapt_swap_args",
++ "adapt_dup_args",
++ "adapt_drop_args",
++ "adapt_collect_args",
++ "adapt_spread_args",
++ "adapt_flyby",
+ "adapt_ricochet",
-+ "adapt_flyby"
++
++ // optimized adapter types:
++ "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",
++
++ NULL
+};
+
-+static methodOop decode_DMH(oop mh, int& decode_flags_result) {
-+ assert(mh->klass() == SystemDictionary::dyn_impl_DMH_klass(), "");
-+ oop ref = java_dyn_MethodHandle::vmref(mh);
-+ int index = java_dyn_MethodHandle::vmdata_index(mh);
-+ if (ref == NULL) return NULL;
++#ifdef ASSERT
++bool MethodHandle::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"), "");
++ return true;
++}
++#endif
++
++methodOop MethodHandle::decode_DirectMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
++ oop target = java_dyn_MethodHandle::vmtarget(mh);
++ int index = impl_java_dyn_DirectMethodHandle::vmindex(mh);
++ if (target == NULL) return NULL;
+ index = (short) index; // ignore high order bits
-+ if (index != methodOopDesc::nonvirtual_vtable_index) {
++ assert(methodOopDesc::nonvirtual_vtable_index < 0, "encoding");
++ if (index < 0) {
++ // an invokestatic or invokespecial DMH mentions the method directly
++ methodOop m = (methodOop) target;
++ int mflags = 0;
++ decode_methodOop(m, mflags);
++ if ((mflags & _dmf_has_receiver) != 0) {
++ decode_flags_result |= _dmf_has_receiver;
++ // Extract receiver type restriction from mh.type.ptypes[0].
++ oop mtype = java_dyn_MethodHandle::type(mh);
++ objArrayOop ptypes = (mtype == NULL) ? NULL : java_dyn_MethodType::ptypes(mtype);
++ oop ptype0 = (ptypes == NULL || ptypes->length() < 1) ? NULL : ptypes->obj_at(0);
++ receiver_limit_result = (ptype0 == NULL) ? NULL : java_lang_Class::as_klassOop(ptype0);
++ }
++ return m;
++ } else {
+ decode_flags_result |= MethodHandle::_dmf_does_dispatch;
-+ }
-+ if (ref->is_method()) {
-+ // an invokestatic or invokespecial DMH mentions the method
-+ // to make things easier, an invokevirtual DMH also mentions it
-+ return (methodOop) ref;
-+ }
-+ if (ref->is_klass() && Klass::cast((klassOop)ref)->is_interface()) {
-+ // an itable linkage is <interface, itable indemh>
-+ decode_flags_result |= MethodHandle::_dmf_is_interface;
-+ return klassItable::method_for_itable_index((klassOop)ref, index);
-+ }
-+ ShouldNotReachHere();
-+ return NULL; // cannot parse
-+}
-+
-+static methodOop decode_BMH(oop mh, int& decode_flags_result) {
-+ assert(mh->klass() == SystemDictionary::dyn_impl_BMH_klass(), "");
-+ oop ref = java_dyn_MethodHandle::vmref(mh);
-+ if (ref == NULL) return NULL;
-+ if (ref->is_method()) {
-+ // the ref of a BMH should always be an exact method
-+ decode_flags_result |= MethodHandle::_dmf_has_receiver;
-+ return (methodOop) ref;
-+ }
-+ ShouldNotReachHere();
-+ return NULL; // cannot parse
-+}
-+
-+static methodOop decode_AMH(oop mh, int& decode_flags_result) {
-+ for (;;) {
-+ assert(mh->klass() == SystemDictionary::dyn_impl_AMH_klass(), "");
-+ oop ref = java_dyn_MethodHandle::vmref(mh);
-+ if (ref == NULL) return NULL;
-+ if (ref->klass() == SystemDictionary::dyn_impl_DMH_klass()) {
-+ decode_flags_result |= MethodHandle::_dmf_has_casts;
-+ return decode_DMH(ref, decode_flags_result);
-+ }
-+ if (ref->klass() == SystemDictionary::dyn_impl_BMH_klass()) {
-+ decode_flags_result |= MethodHandle::_dmf_has_casts;
-+ return decode_BMH(ref, decode_flags_result);
-+ }
-+ if (ref->klass() == SystemDictionary::dyn_impl_AMH_klass()) {
-+ // adapters can be stacked:
-+ mh = ref;
++ assert(target->is_klass(), "must be class or interface");
++ receiver_limit_result = (klassOop)target;
++ Klass* tk = Klass::cast((klassOop)target);
++ if (tk->is_interface()) {
++ // an itable linkage is <interface, itable indemh>
++ decode_flags_result |= MethodHandle::_dmf_from_interface;
++ return klassItable::method_for_itable_index((klassOop)target, index);
+ } else {
-+ break;
-+ }
-+ }
-+ ShouldNotReachHere();
-+ return NULL; // cannot parse
++ if (!tk->oop_is_instance())
++ tk = instanceKlass::cast(SystemDictionary::object_klass());
++ return ((instanceKlass*)tk)->method_at_vtable(index);
++ }
++ }
++}
++
++methodOop MethodHandle::decode_BoundMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
++ assert(mh->klass() == SystemDictionary::BoundMethodHandle_klass(), "");
++ for (oop bmh = mh;;) {
++ // Bound MHs can be stacked to bind several arguments.
++ oop target = java_dyn_MethodHandle::vmtarget(bmh);
++ if (target == NULL) return NULL;
++ decode_flags_result |= MethodHandle::_dmf_binds_argument;
++ klassOop tk = target->klass();
++ if (tk == SystemDictionary::BoundMethodHandle_klass()) {
++ bmh = target;
++ continue;
++ } else {
++ if (java_dyn_MethodHandle::is_subclass(tk)) {
++ //assert(tk == SystemDictionary::DirectMethodHandle_klass(), "end of BMH chain must be DMH");
++ return decode_MethodHandle(target, receiver_limit_result, decode_flags_result);
++ } else {
++ // Optimized case: binding a receiver to a non-dispatched DMH
++ // short-circuits directly to the methodOop.
++ assert(target->is_method(), "must be a simple method");
++ methodOop m = (methodOop) target;
++ DEBUG_ONLY(int argslot = impl_java_dyn_BoundMethodHandle::vmargslot(bmh));
++ assert(argslot == m->size_of_parameters() - 1, "must be initial argument (receiver)");
++ decode_flags_result |= MethodHandle::_dmf_binds_method;
++ return m;
++ }
++ }
++ }
++}
++
++methodOop MethodHandle::decode_AdapterMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
++ 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);
++ oop target = java_dyn_MethodHandle::vmtarget(amh);
++ if (target == NULL) return NULL;
++ klassOop tk = target->klass();
++ if (tk == SystemDictionary::AdapterMethodHandle_klass()) {
++ amh = target;
++ continue;
++ } else {
++ // must be a BMH (which will bind some more arguments) or a DMH (for the final call)
++ return MethodHandle::decode_MethodHandle(target, receiver_limit_result, decode_flags_result);
++ }
++ }
++}
++
++methodOop MethodHandle::decode_MethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
++ klassOop mhk = mh->klass();
++ assert(java_dyn_MethodHandle::is_subclass(mhk), "must be a MethodHandle");
++ if (mhk == SystemDictionary::DirectMethodHandle_klass()) {
++ return decode_DirectMethodHandle(mh, receiver_limit_result, decode_flags_result);
++ } else if (mhk == SystemDictionary::BoundMethodHandle_klass()) {
++ return decode_BoundMethodHandle(mh, receiver_limit_result, decode_flags_result);
++ } else if (mhk == SystemDictionary::AdapterMethodHandle_klass()) {
++ return decode_AdapterMethodHandle(mh, receiver_limit_result, decode_flags_result);
++ } else {
++ assert(false, "cannot parse this MH");
++ return NULL; // random MH?
++ }
++}
++
++methodOop MethodHandle::decode_methodOop(methodOop m, int& decode_flags_result) {
++ assert(m->is_method(), "");
++ if (m->is_static()) {
++ // check that signature begins '(L' or '([' (not '(I', '()', etc.)
++ symbolOop sig = m->signature();
++ BasicType recv_bt = char2type(sig->byte_at(1));
++ // Note: recv_bt might be T_ILLEGAL if byte_at(2) is ')'
++ assert(sig->byte_at(0) == '(', "must be method sig");
++ if (recv_bt == T_OBJECT || recv_bt == T_ARRAY)
++ decode_flags_result |= _dmf_has_receiver;
++ } else {
++ // non-static method
++ decode_flags_result |= _dmf_has_receiver;
++ if (!m->can_be_statically_bound() && !m->is_initializer()) {
++ decode_flags_result |= _dmf_does_dispatch;
++ if (Klass::cast(m->method_holder())->is_interface())
++ decode_flags_result |= _dmf_from_interface;
++ }
++ }
++ return m;
+}
+
+// A trusted party is handing us a cookie to determine a method.
+// Let's boil it down to the method oop they really want.
-+methodOop MethodHandle::decode_method(oop x, int& decode_flags_result) {
++methodOop MethodHandle::decode_method(oop x, klassOop& receiver_limit_result, int& decode_flags_result) {
+ decode_flags_result = 0;
++ receiver_limit_result = NULL;
+ klassOop xk = x->klass();
+ if (xk == Universe::methodKlassObj()) {
-+ assert(x->is_method(), "");
-+ methodOop xm = (methodOop) x;
-+ if (!xm->can_be_statically_bound())
-+ decode_flags_result |= _dmf_does_dispatch;
-+ return xm;
-+ } else if (Klass::cast(xk)->is_subclass_of(SystemDictionary::java_dyn_MethodHandle_klass())) {
-+ if (xk == SystemDictionary::dyn_impl_DMH_klass())
-+ return decode_DMH(x, decode_flags_result);
-+ else if (xk == SystemDictionary::dyn_impl_BMH_klass())
-+ return decode_BMH(x, decode_flags_result);
-+ else if (xk == SystemDictionary::dyn_impl_AMH_klass())
-+ return decode_AMH(x, decode_flags_result);
-+ else
-+ return NULL; // random MH?
++ return decode_methodOop((methodOop) x, decode_flags_result);
++ } else if (java_dyn_MethodHandle::is_subclass(xk)) {
++ return decode_MethodHandle(x, receiver_limit_result, decode_flags_result);
+ } else if (xk == SystemDictionary::reflect_method_klass()) {
+ oop clazz = java_lang_reflect_Method::clazz(x);
+ int slot = java_lang_reflect_Method::slot(x);
+ klassOop k = java_lang_Class::as_klassOop(clazz);
+ if (k != NULL && Klass::cast(k)->oop_is_instance())
-+ return instanceKlass::cast(k)->method_with_idnum(slot);
++ return decode_methodOop(instanceKlass::cast(k)->method_with_idnum(slot),
++ decode_flags_result);
+ } else if (xk == SystemDictionary::reflect_constructor_klass()) {
+ oop clazz = java_lang_reflect_Constructor::clazz(x);
+ int slot = java_lang_reflect_Constructor::slot(x);
+ klassOop k = java_lang_Class::as_klassOop(clazz);
+ if (k != NULL && Klass::cast(k)->oop_is_instance())
-+ return instanceKlass::cast(k)->method_with_idnum(slot);
++ return decode_methodOop(instanceKlass::cast(k)->method_with_idnum(slot),
++ decode_flags_result);
+ } else {
+ // unrecognized object
+ assert(!x->is_method(), "got this case first");
@@ -4413,26 +5599,127 @@ new file mode 100644
+ return NULL;
+}
+
-+// Decode the vmref field of a method handle.
++
++int MethodHandle::decode_MethodHandle_stack_pushes(oop mh) {
++ if (mh->klass() == SystemDictionary::DirectMethodHandle_klass())
++ return 0; // no push/pop
++ int this_vmslots = java_dyn_MethodHandle::vmslots(mh);
++ int last_vmslots = 0;
++ oop last_mh = mh;
++ for (;;) {
++ oop target = java_dyn_MethodHandle::vmtarget(last_mh);
++ if (target->klass() == SystemDictionary::DirectMethodHandle_klass()) {
++ last_vmslots = java_dyn_MethodHandle::vmslots(last_mh);
++ break;
++ } else if (!java_dyn_MethodHandle::is_instance(target)) {
++ // might be klass or method
++ assert(target->is_method(), "must get here with a direct ref to method");
++ last_vmslots = methodOop(target)->size_of_parameters();
++ break;
++ } else {
++ last_mh = target;
++ continue;
++ }
++ }
++ // If I am called with fewer VM slots than my ultimate callee,
++ // it must be that I push the additionally needed slots.
++ // Likewise if am called with more VM slots, I will pop them.
++ return (last_vmslots - this_vmslots);
++}
++
++
++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();
++}
++
++
++// Decode the vmtarget field of a method handle.
+// Sanitize out methodOops, klassOops, and any other non-Java data.
-+oop MethodHandle::decode_vmref(oop x, int& decode_flags_result) {
-+ if (x == NULL) return NULL;
-+ decode_flags_result = 0;
-+ klassOop xk = x->klass();
-+ if (Klass::cast(xk)->is_subclass_of(SystemDictionary::java_dyn_MethodHandle_klass())) {
-+ x = java_dyn_MethodHandle::vmref(x);
-+ if (x == NULL) return NULL;
-+ xk = x->klass();
-+ }
-+ // at this point is it known not to be an MH
-+ if (Klass::cast(xk)->oop_is_instance())
-+ return x;
-+ if (Klass::cast(xk)->oop_is_klass())
-+ return Klass::cast(klassOop(x))->java_mirror();
-+ // it's inscrutable!
++// This is for debugging and reflection.
++oop MethodHandle::encode_target(oop mh, int format, TRAPS) {
++ assert(java_dyn_MethodHandle::is_instance(mh), "must be a MH");
++ if (format == _etf_handle_or_method_info) {
++ oop target = java_dyn_MethodHandle::vmtarget(target);
++ if (target == NULL) {
++ return NULL; // unformed MH
++ }
++ klassOop tklass = target->klass();
++ if (Klass::cast(tklass)->is_subclass_of(SystemDictionary::object_klass())){
++ return target; // target is another MH (or something else?)
++ }
++ }
++ if (format == _etf_direct_handle) {
++ oop target = mh;
++ for (;;) {
++ if (target->klass() == SystemDictionary::DirectMethodHandle_klass()) {
++ return target;
++ }
++ if (!java_dyn_MethodHandle::is_instance(target)){
++ return NULL; // unformed MH
++ }
++ target = java_dyn_MethodHandle::vmtarget(target);
++ }
++ }
++ // cases of metadata in MH.vmtarget:
++ // - AMH can have methodOop for static invoke with bound receiver
++ // - DMH can have methodOop for static invoke (on variable receiver)
++ // - 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);
++ if (m == NULL) return NULL;
++ switch (format) {
++ case _etf_name:
++ return StringTable::intern(m->name(), THREAD);
++
++ case _etf_reflect_method:
++ // same as jni_ToReflectedMethod:
++ if (m->is_initializer()) {
++ return Reflection::new_constructor(m, THREAD);
++ } else {
++ return Reflection::new_method(m, UseNewReflection, false, THREAD);
++ }
++
++ case _etf_handle_or_method_info: // method, not handle
++ case _etf_method_info:
++ {
++ objArrayHandle tuple; {
++ objArrayOop tuple_oop = oopFactory::new_objectArray(_MI_LENGTH, CHECK_NULL);
++ tuple = objArrayHandle(THREAD, tuple_oop);
++ }
++ tuple->obj_at_put(_mi_declaring_class,
++ Klass::cast(m->method_holder())->java_mirror());
++ oop name = StringTable::intern(m->name(), CHECK_NULL);
++ tuple->obj_at_put(_mi_name, name);
++ oop sig = StringTable::intern(m->signature(), CHECK_NULL);
++ tuple->obj_at_put(_mi_signature, sig);
++ if (receiver_limit != NULL && receiver_limit != m->method_holder())
++ tuple->obj_at_put(_mi_reference_class,
++ Klass::cast(receiver_limit)->java_mirror());
++ return tuple();
++ }
++ }
++
++ // Unknown format code.
++ throw_IllegalArgumentException(THREAD);
+ return NULL;
+}
-+
+
+bool MethodHandle::class_cast_needed(klassOop src, klassOop dst) {
+ if (src == dst || dst == SystemDictionary::object_klass())
@@ -4453,8 +5740,30 @@ new file mode 100644
+ return !srck->is_subclass_of(dstk->as_klassOop());
+}
+
-+const char* MethodHandle::verify_method_receiver(methodHandle m,
-+ klassOop passed_recv_type) {
++static oop object_java_mirror() {
++ return Klass::cast(SystemDictionary::object_klass())->java_mirror();
++}
++
++bool MethodHandle::same_basic_type_for_arguments(BasicType src,
++ BasicType dst,
++ bool for_return) {
++ // return values can always be forgotten:
++ if (for_return && dst == T_VOID) return true;
++ assert(src != T_VOID && dst != T_VOID, "should not be here");
++ if (src == dst) return true;
++ if (is_subword_type(src)) { // subwords can fit in int or other subwords
++ if (dst == T_INT) // any subword fits in an int
++ return true;
++ if (src == T_BOOLEAN) // boolean fits in any subword
++ return is_subword_type(dst);
++ if (src == T_BYTE && dst == T_SHORT)
++ return true; // remaining case: byte fits in short
++ }
++ return false;
++}
++
++const char* MethodHandle::check_method_receiver(methodHandle m,
++ klassOop passed_recv_type) {
+ assert(!m->is_static(), "caller resp.");
+ if (passed_recv_type == NULL)
+ return "receiver type is primitive";
@@ -4466,112 +5775,81 @@ new file mode 100644
+ return NULL; // checks passed
+}
+
-+const char* MethodHandle::verify_method_signature(methodHandle m,
-+ Handle mtype,
-+ KlassHandle insert_ptype,
-+ int first_ptype,
-+ objArrayHandle ptypes,
-+ TRAPS) {
-+ int pnum = first_ptype;
++// Verify that m's signature can be called type-safely by a method handle
++// of the given method type 'mtype'.
++// It takes a TRAPS argument because it must perform symbol lookups.
++void MethodHandle::verify_method_signature(methodHandle m,
++ 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();
++ int mnum = 0; // method argument
+ const char* err = NULL;
-+ BasicType errtype = T_VOID;
-+ klassOop errklass = NULL;
+ for (SignatureStream ss(m->signature()); !ss.is_done(); ss.next()) {
-+ oop ptype = NULL;
++ oop ptype_oop = NULL;
+ if (ss.at_return_type()) {
+ if (pnum != pmax)
-+ return "too many arguments";
-+ ptype = java_dyn_MethodType::rtype(mtype());
++ { err = "too many arguments"; break; }
++ ptype_oop = java_dyn_MethodType::rtype(mtype());
+ } else {
+ if (pnum >= pmax)
-+ return "not enough arguments";
-+ if (pnum == -1)
-+ ptype = insert_ptype->java_mirror();
++ { err = "not enough arguments"; break; }
++ if (pnum >= 0)
++ ptype_oop = ptypes->obj_at(pnum);
++ else if (insert_ptype.is_null())
++ ptype_oop = NULL;
+ else
-+ ptype = ptypes->obj_at(pnum);
++ ptype_oop = insert_ptype->java_mirror();
+ pnum += 1;
-+ }
-+ errtype = ss.type();
-+ klassOop pklass = java_lang_Class::as_klassOop(ptype);
-+ BasicType pt = (pklass != NULL) ? T_OBJECT : java_lang_Class::primitive_type(ptype);
-+ if (!ss.is_object()) {
-+ // primitives must match exactly, except perhaps for subword types
-+ if (pt == T_OBJECT) {
-+ err = (ss.at_return_type()
-+ ? "returning %s, but expecting a reference"
-+ : "argument #%d expected %s, got a reference");
-+ break;
++ mnum += 1;
++ }
++ klassOop mklass = NULL;
++ BasicType mtype = ss.type();
++ if (mtype == T_ARRAY) mtype = T_OBJECT; // fold all refs to T_OBJECT
++ if (mtype == T_OBJECT) {
++ if (ptype_oop == NULL) {
++ // null matches any reference
++ continue;
+ }
-+ if (ss.at_return_type()) {
-+ if (!same_basic_type_for_returns(ss.type(), pt)) {
-+ err = "returning %s, but expecting a different value";
-+ break;
-+ }
-+ } else {
-+ if (!same_basic_type_for_arguments(pt, ss.type())) {
-+ err = "argument #%d expected %s, got a different value";
-+ break;
-+ }
-+ }
++ // If we fail to resolve types at this point, we will throw an error.
++ symbolOop name_oop = ss.as_symbol(CHECK);
++ symbolHandle name(THREAD, name_oop);
++ instanceKlass* mk = instanceKlass::cast(m->method_holder());
++ Handle loader(THREAD, mk->class_loader());
++ Handle domain(THREAD, mk->protection_domain());
++ mklass = SystemDictionary::resolve_or_fail(name, loader, domain,
++ true, CHECK);
++ }
++ if (ptype_oop == NULL) {
++ // null does not match any non-reference; use Object to report the error
++ ptype_oop = object_java_mirror();
++ }
++ klassOop pklass = NULL;
++ BasicType ptype = java_lang_Class::as_BasicType(ptype_oop, &pklass);
++ if (!ss.at_return_type()) {
++ err = check_argument_type_change(ptype, pklass, mtype, mklass, mnum);
+ } else {
-+ symbolOop name_oop = ss.as_symbol(CHECK_NULL);
-+ symbolHandle name(THREAD, name_oop);
-+ klassOop mklass = SystemDictionary::resolve_or_fail(name, true, CHECK_NULL);
-+ if (mklass != pklass) {
-+ errtype = T_OBJECT;
-+ errklass = mklass;
-+ if (pt != T_OBJECT) {
-+ err = (ss.at_return_type()
-+ ? "returning %s, but expecting a value"
-+ : "argument #%d expected %s, got a value");
-+ break;
-+ }
-+ if (ss.at_return_type()) {
-+ if (class_cast_needed(mklass, pklass)) {
-+ err = "returning %s, but expecting a different reference";
-+ break;
-+ }
-+ } else {
-+ if (class_cast_needed(pklass, mklass)) {
-+ err = "argument %#d expected %s, got a different reference";
-+ break;
-+ }
-+ }
-+ }
-+ }
-+ }
-+ if (err == NULL) {
-+ return NULL;
-+ } else {
-+ // format, format, format
-+ char msgbuf[1000];
-+ const char* errarg = "";
-+ if (errtype == T_OBJECT && errklass != NULL)
-+ errarg = Klass::cast(errklass)->external_name();
-+ else
-+ errarg = type2name(errtype);
-+ if (errarg == NULL) errarg = "unknown type";
-+ if (strstr(err, "%d")) {
-+ jio_snprintf(msgbuf, sizeof(msgbuf)-1, err, pnum, errarg);
-+ } else {
-+ jio_snprintf(msgbuf, sizeof(msgbuf)-1, err, errarg);
-+ }
-+ char* msg = NEW_RESOURCE_ARRAY(char, strlen(msgbuf)+1);
-+ strcpy(msg, msgbuf);
-+ return msg;
++ err = check_return_type_change(mtype, mklass, ptype, pklass); // note reversal!
++ }
++ if (err != NULL) break;
++ }
++
++ if (err != NULL) {
++ throw_InternalError(err, CHECK);
+ }
+}
+
+// Main routine for verifying the MethodHandle.type of a proposed
-+// direct or bound method handle.
++// direct or bound-direct method handle.
+void MethodHandle::verify_method_type(methodHandle m,
+ oop mtype_oop,
+ bool has_bound_recv,
+ klassOop bound_recv_type_oop,
+ TRAPS) {
+ Handle mtype(THREAD, mtype_oop);
-+ objArrayHandle ptypes(THREAD, java_dyn_MethodType::ptypes(mtype()));
+ KlassHandle bound_recv_type(THREAD, bound_recv_type_oop);
+
+ mtype_oop = NULL; bound_recv_type_oop = NULL; // better safe than sorry
@@ -4584,69 +5862,291 @@ new file mode 100644
+ if (has_bound_recv && err == NULL) {
+ first_ptype_pos -= 1;
+ if (m_needs_receiver && bound_recv_type.is_null())
-+ { err = "bound receiver is not an object"; goto done; }
++ { err = "bound receiver is not an object"; goto die; }
+ }
+
+ if (m_needs_receiver && err == NULL) {
++ objArrayOop ptypes = java_dyn_MethodType::ptypes(mtype());
+ if (ptypes->length() < first_ptype_pos)
-+ { err = "receiver argument is missing"; goto done; }
++ { err = "receiver argument is missing"; goto die; }
+ if (first_ptype_pos == -1)
-+ err = MethodHandle::verify_method_receiver(m, bound_recv_type->as_klassOop());
++ err = check_method_receiver(m, bound_recv_type->as_klassOop());
+ else
-+ err = MethodHandle::verify_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;
+ }
+
+ // Check the other arguments for mistypes.
-+ if (err == NULL)
-+ err = MethodHandle::verify_method_signature(m, mtype,
-+ bound_recv_type,
-+ first_ptype_pos,
-+ ptypes, CHECK);
-+
-+ done:
-+ if (err != NULL)
-+ THROW_MSG(vmSymbols::java_dyn_WrongMethodTypeException(), err);
-+}
-+
-+
++ verify_method_signature(m, mtype, first_ptype_pos, bound_recv_type, CHECK);
++ return;
++
++ die:
++ throw_InternalError(err, CHECK);
++}
++
++void MethodHandle::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); }
++}
++
++void MethodHandle::verify_vmargslot(Handle mh, int argnum, TRAPS) {
++ // Verify MH.vmargslot, which should point at the given argnum.
++ int have_slot = impl_java_dyn_BoundMethodHandle::vmargslot(mh());
++ int check_slot = argument_slot(java_dyn_MethodHandle::type(mh()), argnum);
++ if (have_slot != check_slot) {
++ const char* fmt = "for argnum of %d, vmargslot is %d, should be %d";
++ int msglen = strlen(fmt) + 3*11 + 1;
++ char* msg = NEW_RESOURCE_ARRAY(char, msglen);
++ jio_snprintf(msg, msglen, fmt, argnum, have_slot, check_slot);
++ throw_InternalError(msg, CHECK);
++ }
++}
++
++// Verify the correspondence between two method types.
++// 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 MethodHandle::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) {
++ objArrayOop src_ptypes = java_dyn_MethodType::ptypes(src_mtype);
++ objArrayOop dst_ptypes = java_dyn_MethodType::ptypes(dst_mtype);
++
++ int src_max = src_ptypes->length();
++ int dst_max = dst_ptypes->length();
++
++ if (src_end == -1) src_end = src_max;
++ if (dst_end == -1) dst_end = dst_max;
++
++ assert(0 <= src_beg && src_beg <= src_end && src_end <= src_max, "oob");
++ assert(0 <= dst_beg && dst_beg <= dst_end && dst_end <= dst_max, "oob");
++
++ // pending actions; set to -1 when done:
++ int ins_idx = insert_argnum, chg_idx = change_argnum, del_idx = delete_argnum;
++
++ const char* err = NULL;
++
++ // Walk along each array of parameter types, including a virtual
++ // NULL end marker at the end of each.
++ for (int src_idx = src_beg, dst_idx = dst_beg;
++ (src_idx <= src_end && dst_idx <= dst_end);
++ src_idx++, dst_idx++) {
++ oop src_type = (src_idx == src_end) ? NULL : src_ptypes->obj_at(src_idx);
++ oop dst_type = (dst_idx == dst_end) ? NULL : dst_ptypes->obj_at(dst_idx);
++ bool fix_null_src_type = false;
++
++ // Perform requested edits.
++ if (ins_idx == src_idx) {
++ // note that the inserted guy is never affected by a change or deletion
++ ins_idx = -1;
++ src_type = insert_type;
++ fix_null_src_type = true;
++ --src_idx; // back up to process src type on next loop
++ src_idx = src_end;
++ } else {
++ // note that the changed guy can be immediately deleted
++ if (chg_idx == src_idx) {
++ chg_idx = -1;
++ assert(src_idx < src_end, "oob");
++ src_type = change_type;
++ fix_null_src_type = true;
++ }
++ if (del_idx == src_idx) {
++ del_idx = -1;
++ assert(src_idx < src_end, "oob");
++ --dst_idx;
++ continue; // rerun loop after skipping this position
++ }
++ }
++
++ if (src_type == NULL && fix_null_src_type)
++ // explicit null in this case matches any dest reference
++ src_type = (java_lang_Class::is_primitive(dst_type) ? object_java_mirror() : dst_type);
++
++ // 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 (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!
++ }
++ }
++
++ if (err != NULL) { throw_InternalError(err, CHECK); }
++}
++
++// Handy wrapper for check_argument_type_change, to verify one src/dest pair.
++void MethodHandle::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); }
++}
++
++
++const char* MethodHandle::check_argument_type_change(BasicType src_type,
++ klassOop src_klass,
++ BasicType dst_type,
++ klassOop dst_klass,
++ int argnum) {
++ const char* err = NULL;
++
++ // just in case:
++ if (src_type == T_ARRAY) src_type = T_OBJECT;
++ if (dst_type == T_ARRAY) dst_type = T_OBJECT;
++
++ // Produce some nice messages if VerifyMethodHandles is turned on:
++ if (!same_basic_type_for_arguments(src_type, dst_type, (argnum < 0))) {
++ if (src_type == T_OBJECT) {
++ err = ((argnum >= 0)
++ ? "type mismatch: passing a %s for method argument #%d, which expects primitive %s"
++ : "type mismatch: returning a %s, but caller expects primitive %s");
++ } else if (dst_type == T_OBJECT) {
++ err = ((argnum < 0)
++ ? "type mismatch: passing a primitive %s for method argument #%d, which expects %s"
++ : "type mismatch: returning a primitive %s, but caller expects %s");
++ } else {
++ err = ((argnum < 0)
++ ? "type mismatch: passing a %s for method argument #%d, which expects %s"
++ : "type mismatch: returning a %s, but caller expects %s");
++ }
++ } else if (src_type == T_OBJECT && class_cast_needed(src_klass, dst_klass)) {
++ if (!class_cast_needed(dst_klass, src_klass)) {
++ err = ((argnum < 0)
++ ? "cast required: passing a %s for method argument #%d, which expects %s"
++ : "cast required: returning a %s, but caller expects %s");
++ } else {
++ err = ((argnum < 0)
++ ? "reference mismatch: passing a %s for method argument #%d, which expects %s"
++ : "reference mismatch: returning a %s, but caller expects %s");
++ }
++ } else {
++ // passed the obstacle course
++ return NULL;
++ }
++
++ // format, format, format
++ const char* src_name = type2name(src_type);
++ const char* dst_name = type2name(dst_type);
++ if (src_type == T_OBJECT) src_name = Klass::cast(src_klass)->external_name();
++ if (dst_type == T_OBJECT) dst_name = Klass::cast(dst_klass)->external_name();
++ if (src_name == NULL) src_name = "unknown type";
++ if (dst_name == NULL) dst_name = "unknown type";
++
++ int msglen = strlen(err) + strlen(src_name) + strlen(dst_name) + (argnum < 10 ? 1 : 11);
++ char* msg = NEW_RESOURCE_ARRAY(char, msglen + 1);
++ if (argnum >= 0) {
++ assert(strstr(err, "%d") != NULL, "");
++ jio_snprintf(msg, msglen, err, src_name, argnum, dst_name);
++ } else {
++ assert(strstr(err, "%d") == NULL, "");
++ jio_snprintf(msg, msglen, err, src_name, dst_name);
++ }
++ return msg;
++}
++
++// Compute the depth within the stack of the given argument.
++// For the last argument (ptypes.length-1) this will be zero.
++// For the first argument (0) this will be the size of all
++// arguments but that one. For the special number -1, this
++// will be the size of all arguments, including the first.
++// If the argument is neither -1 nor a valid argument index,
++// then return a negative number. Otherwise, the result
++// is in the range [0..vmslots] inclusive.
+int MethodHandle::argument_slot(oop method_type, int arg) {
+ objArrayOop ptypes = java_dyn_MethodType::ptypes(method_type);
+ int result = 0;
-+ for (int i = arg+1, imax = ptypes->length(); i < imax; i++) {
-+ oop ptype = ptypes->obj_at(i);
-+ BasicType bt = T_OBJECT;
-+ if (java_lang_Class::is_primitive(ptype))
-+ bt = java_lang_Class::primitive_type(ptype);
++ int len = ptypes->length();
++ if (arg < -1 || arg >= len) return -99;
++ for (int i = arg+1; i < len; i++) {
++ BasicType bt = java_lang_Class::as_BasicType(ptypes->obj_at(i));
+ result += type2size[bt];
+ }
+ return result;
+}
+
-+// direct method handles
-+JVM_ENTRY(void, MH_init_DMH(JNIEnv *env, jobject igcls, jobject mh_jh, jobject rmethod_jh, jboolean do_dispatch)) {
-+ ResourceMark rm; // for error messages
-+
-+ // This is the guy we are initializing:
-+ if (mh_jh == NULL) return;
-+ Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh));
-+
-+ // Early returns out of this method leave the DMH in an unfinished state.
-+ // Caller is responsible for checking that entry != 0.
-+ java_dyn_MethodHandle::set_entry(mh(), NULL);
-+
-+ // which method are we really talking about?
-+ int decode_flags = 0;
-+ methodHandle m(THREAD,
-+ MethodHandle::decode_method(JNIHandles::resolve(rmethod_jh),
-+ decode_flags));
-+ if (m.is_null()) return; // robustness
-+
-+ int argslot = m->size_of_parameters() - 1; // pos. of 1st arg.
++methodOop MethodHandle::dispatch_decoded_method(methodOop m,
++ klassOop receiver_limit,
++ int decode_flags,
++ klassOop 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())))
++ // 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;
++
++ if (receiver_limit != NULL &&
++ (receiver_klass != NULL && !Klass::cast(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;
++
++ if (!(decode_flags & MethodHandle::_dmf_does_dispatch)) {
++ // pre-dispatched or static method (null receiver is OK for static)
++ return m;
++
++ } else if (receiver_klass == NULL) {
++ // null receiver value; cannot dispatch
++ return NULL;
++
++ } else if (!(decode_flags & MethodHandle::_dmf_from_interface)) {
++ // perform virtual dispatch
++ int vtable_index = m->vtable_index();
++ guarantee(vtable_index >= 0, "valid vtable index");
++
++ // 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);
++ DEBUG_ONLY(inst->verify_vtable_index(vtable_index));
++ return inst->method_at_vtable(vtable_index);
++
++ } else {
++ // perform interface dispatch
++ 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);
++ }
++}
++
++void MethodHandle::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); }
++
++ 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.
-+ MethodHandle::verify_method_type(m, java_dyn_MethodHandle::type(mh()),
-+ false, NULL, CHECK);
++ 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); }
++ }
+
+ // Finally, after safety checks are done, link to the target method.
+ // We will follow the same path as the latter part of
@@ -4655,7 +6155,8 @@ new file mode 100644
+ // that links the interpreter calls to the method. We need the same
+ // bits, and will use the same calling sequence code.
+
-+ if (!do_dispatch && m->is_abstract()) return; // robustness
++ int vmindex = methodOopDesc::garbage_vtable_index;
++ oop vmtarget = NULL;
+
+ MethodEntry* me = NULL;
+ if (do_dispatch && Klass::cast(m->method_holder())->is_interface()) {
@@ -4663,20 +6164,18 @@ new file mode 100644
+ // (We might also be simulating an invokevirtual on a miranda method,
+ // but it is safe to treat it as an invokeinterface.)
+ assert(!m->can_be_statically_bound(), "no final methods on interfaces");
-+ int index = klassItable::compute_itable_index(m());
-+ assert(index >= 0, "");
++ vmindex = klassItable::compute_itable_index(m());
++ assert(vmindex >= 0, "(>=0) == do_dispatch");
+ // Set up same bits as ConstantPoolCacheEntry::set_interface_call().
-+ klassOop interf = m->method_holder();
-+ java_dyn_MethodHandle::set_vmref(mh(), interf);
-+ java_dyn_MethodHandle::set_vmdata(mh(), index, argslot);
++ vmtarget = m->method_holder(); // the interface
+ me = MethodHandle::entry(MethodHandle::_invokeinterface_mh);
+ } else if (!do_dispatch || m->can_be_statically_bound()) {
+ // We are simulating an invokestatic or invokespecial instruction.
+ // Set up the method pointer, just like ConstantPoolCacheEntry::set_method().
-+ java_dyn_MethodHandle::set_vmref(mh(), m());
++ vmtarget = m();
+ // this does not help dispatch, but it will make it possible to parse this MH:
-+ int index = methodOopDesc::nonvirtual_vtable_index;
-+ java_dyn_MethodHandle::set_vmdata(mh(), index, m->is_static() ? -1 : argslot);
++ vmindex = methodOopDesc::nonvirtual_vtable_index;
++ assert(vmindex < 0, "(>=0) == do_dispatch");
+ if (m->is_static())
+ me = MethodHandle::entry(MethodHandle::_invokestatic_mh);
+ else
@@ -4685,157 +6184,627 @@ new file mode 100644
+ // We are simulating an invokevirtual instruction.
+ // Set up the vtable index, just like ConstantPoolCacheEntry::set_method().
+ // The key logic is LinkResolver::runtime_resolve_virtual_method.
-+ int index = m->vtable_index();
-+ assert(index >= 0, "");
-+ java_dyn_MethodHandle::set_vmdata(mh(), index, argslot);
-+ java_dyn_MethodHandle::set_vmref(mh(), m());
++ vmindex = m->vtable_index();
++ vmtarget = m->method_holder();
+ me = MethodHandle::entry(MethodHandle::_invokevirtual_mh);
+ }
+
-+ DEBUG_ONLY(int junk);
-+ assert(MethodHandle::decode_method(mh(), junk) == m(), "properly stored for later decoding");
++ if (me == NULL) { throw_InternalError(CHECK); }
++
++ impl_java_dyn_DirectMethodHandle::set_vmtarget(mh(), vmtarget);
++ impl_java_dyn_DirectMethodHandle::set_vmindex(mh(), vmindex);
++ DEBUG_ONLY(int flags; klassOop rlimit);
++ assert(MethodHandle::decode_method(mh(), rlimit, flags) == m(), "properly stored for later decoding");
++ DEBUG_ONLY(bool actual_do_dispatch = ((flags & _dmf_does_dispatch) != 0));
++ assert(!(actual_do_dispatch && !do_dispatch),
++ "do not perform dispatch if !do_dispatch specified");
++ assert(actual_do_dispatch == (vmindex >= 0), "proper later decoding of do_dispatch");
++ assert(decode_MethodHandle_stack_pushes(mh()) == 0, "DMH does not move stack");
+
+ // Done!
-+ java_dyn_MethodHandle::set_entry(mh(), me);
-+}
-+JVM_END
-+
-+// bound method handles
-+JVM_ENTRY(void, MH_init_BMH(JNIEnv *env, jobject igcls, jobject mh_jh, jobject rmethod_jh, jobject recv_jh)) {
-+ ResourceMark rm; // for error messages
-+
-+ // This is the guy we are initializing:
-+ if (mh_jh == NULL) return;
-+ Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh));
-+
-+ // Early returns out of this method leave the BMH in an unfinished state.
-+ // Caller is responsible for checking that entry != 0.
-+ java_dyn_MethodHandle::set_entry(mh(), NULL);
-+
-+ if (rmethod_jh == NULL) return;
-+ Handle rmethod(THREAD, JNIHandles::resolve_non_null(rmethod_jh));
-+ if (rmethod->klass() != SystemDictionary::dyn_impl_DMH_klass()) {
-+ assert(false, "BMH on non-DMH");
-+ return; // caller must pass a DMH
-+ }
-+
-+ // which method are we really talking about?
-+ int decode_flags = 0;
-+ methodHandle m(THREAD, MethodHandle::decode_method(rmethod(), decode_flags));
-+ if (m.is_null()) return; // robustness
-+
-+ // If the method is virtual or interface, resolve it now.
-+ KlassHandle recv_klass;
-+ if (recv_jh != NULL)
-+ recv_klass = KlassHandle(THREAD, JNIHandles::resolve_non_null(recv_jh)->klass());
-+
-+ // The privileged code which invokes this routine should not make
-+ // a mistake about types, but it's better to verify.
-+ MethodHandle::verify_method_type(m, java_dyn_MethodHandle::type(mh()),
-+ true, recv_klass->as_klassOop(), CHECK);
++ java_dyn_MethodHandle::set_vmentry(mh(), me);
++}
++
++// Initialize a BMH with a receiver bound directly to a methodOop.
++void MethodHandle::init_BoundMethodHandle_with_receiver(Handle mh,
++ methodOop original_m_oop,
++ klassOop receiver_limit_oop,
++ int decode_flags,
++ TRAPS) {
++ // Check arguments.
++ if (mh.is_null() || original_m_oop == NULL)
++ { throw_InternalError(CHECK); }
++
++ 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 ? 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());
++
++ 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 ? 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, CHECK);
++ //verify_vmslots(mh, CHECK);
++
++ // Verify vmslots.
++ if (java_dyn_MethodHandle::vmslots(mh()) != receiver_pos)
++ { throw_InternalError("bad vmslots in BMH (receiver)", CHECK); }
++ }
++
++ impl_java_dyn_BoundMethodHandle::set_vmtarget(mh(), m());
++
++ DEBUG_ONLY(int junk; klassOop junk2);
++ assert(MethodHandle::decode_method(mh(), junk2, junk) == m(), "properly stored for later decoding");
++ assert(decode_MethodHandle_stack_pushes(mh()) == 1, "BMH pushes one stack slot");
++
++ // Done!
++ java_dyn_MethodHandle::set_vmentry(mh(), MethodHandle::entry(MethodHandle::_bound_ref_direct_mh));
++}
++
++void MethodHandle::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); }
++
++ java_dyn_MethodHandle::init_vmslots(mh());
++
++ if (VerifyMethodHandles) {
++ int insert_after = argnum - 1;
++ verify_vmargslot(mh, insert_after, CHECK);
++ verify_vmslots(mh, CHECK);
++ }
++
++ // If (a) the target is a direct non-dispatched method handle,
++ // or (b) the target is a dispatched direct method handle and we
++ // are binding the receiver, cut out the middle-man.
++ // Do this by decoding the DMH and using its methodOop directly as vmtarget.
++ bool direct_to_method = false;
++ 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); }
++ 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(),
++ receiver_limit, decode_flags,
++ CHECK);
++ return;
++ }
++
++ // Even if it is not a bound receiver, we still might be able
++ // to bind another argument and still invoke the methodOop directly.
++ if (!(decode_flags & _dmf_does_dispatch)) {
++ direct_to_method = true;
++ impl_java_dyn_BoundMethodHandle::set_vmtarget(mh(), m());
++ }
++ }
++ if (!direct_to_method)
++ impl_java_dyn_BoundMethodHandle::set_vmtarget(mh(), target());
++
++ // 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");
++ 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);
++ }
+
+ MethodEntry* me = NULL;
-+ //java_dyn_MethodHandle::set_vmdata(mh(), 0, 0);
-+ if ((decode_flags & MethodHandle::_dmf_does_dispatch) == 0) {
-+ // copy contents of target DMH, which is pre-dispatched
-+ java_dyn_MethodHandle::set_vmref(mh(), m());
-+
-+ } else if ((decode_flags & MethodHandle::_dmf_is_interface) == 0) {
-+ // perform virtual dispatch
-+ assert(java_dyn_MethodHandle::vmref(mh()) == m(), "");
-+ if (!recv_klass->is_subtype_of(m->method_holder()))
-+ return; // caller should check, but...
-+
-+ int vtable_index = java_dyn_MethodHandle::vmdata_index(mh());
-+ guarantee(vtable_index >= 0, "valid vtable index");
-+
-+ // recv_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*)recv_klass()->klass_part();
-+ DEBUG_ONLY(inst->verify_vtable_index(vtable_index));
-+ methodOop disp_m = inst->method_at_vtable(vtable_index);
-+ if (disp_m->is_abstract())
-+ THROW(vmSymbols::java_lang_AbstractMethodError());
-+ java_dyn_MethodHandle::set_vmref(mh(), disp_m);
-+
++ if (ptype == T_OBJECT) {
++ if (direct_to_method) me = MethodHandle::entry(_bound_ref_direct_mh);
++ else me = MethodHandle::entry(_bound_ref_mh);
++ } else if (slots_pushed == 2) {
++ if (direct_to_method) me = MethodHandle::entry(_bound_long_direct_mh);
++ else me = MethodHandle::entry(_bound_long_mh);
++ } else if (slots_pushed == 1) {
++ if (direct_to_method) me = MethodHandle::entry(_bound_int_direct_mh);
++ else me = MethodHandle::entry(_bound_int_mh);
+ } else {
-+ // perform interface dispatch
-+ assert(java_dyn_MethodHandle::vmref(mh()) == m->method_holder(), "");
-+ if (!recv_klass->is_subtype_of(m->method_holder()))
-+ return; // caller should check, but...
-+
-+ int itable_index = java_dyn_MethodHandle::vmdata_index(mh());
-+ guarantee(itable_index >= 0, "valid itable index");
-+
-+ instanceKlass* inst = instanceKlass::cast(recv_klass());
-+ methodOop disp_m = inst->method_at_itable(m->method_holder(), itable_index, CHECK);
-+ java_dyn_MethodHandle::set_vmref(mh(), disp_m);
-+ }
-+
-+ DEBUG_ONLY(int junk);
-+ assert(MethodHandle::decode_method(mh(), junk) == m(), "properly stored for later decoding");
++ assert(false, "");
++ }
+
+ // Done!
-+ java_dyn_MethodHandle::set_entry(mh(), MethodHandle::entry(MethodHandle::_invokebound_mh));
-+}
-+JVM_END
-+
-+// adapter method handles
-+JVM_ENTRY(void, MH_init_AMH(JNIEnv *env, jobject igcls, jobject mh_jh,
-+ int argslot, int conversion, jobject vmref_jh)) {
-+ MethodHandle::AdapterKind ak = MethodHandle::AdapterKind(conversion & MethodHandle::_AK_MASK);
-+ if (ak < MethodHandle::_adapt_retype_only || ak > MethodHandle::_AK_LIMIT)
-+ return; // bad data
++ java_dyn_MethodHandle::set_vmentry(mh(), me);
++}
++
++void MethodHandle::init_AdapterMethodHandle(Handle mh, Handle target, int argnum, TRAPS) {
++ jint conversion = impl_java_dyn_AdapterMethodHandle::conversion(mh());
++ oop argument = impl_java_dyn_AdapterMethodHandle::argument(mh());
+
+ // adjust the adapter code to the internal EntryKind enumeration:
-+ conversion += MethodHandle::_adapter_mh_first;
-+
-+ assert((conversion & ~MethodHandle::_AK_MASK) == 0
-+ || ak == MethodHandle::_adapt_extend_sign
-+ || ak == MethodHandle::_adapt_extend_zero
-+ || ak == MethodHandle::_adapt_swap_argument
-+ || ak == MethodHandle::_adapt_push_argument
-+ || ak == MethodHandle::_adapt_ricochet,
-+ "optional fields must be zero, or adapter must take an optional argument");
-+
++ AdapterKind ak = adapter_conversion_op(conversion);
++ EntryKind ek = (EntryKind)(MethodHandle::_adapter_mh_first + (int)ak);
++
++ 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());
++
++ 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, CHECK);
++ verify_vmslots(mh, CHECK);
++
++ 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 (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; }
++ }
++ }
++ 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) {
++ // 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_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) {
++ err = "vminfo subfield is reserved to the JVM";
++ }
++
++ if (err != NULL) { throw_InternalError(err, CHECK); }
++ }
++
++ // 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()));
++ }
++
++ // Now it's time to finish the case analysis and pick a MethodEntry.
+ switch (ak) {
-+ case MethodHandle::_adapt_swap_argument:
-+ case MethodHandle::_adapt_push_argument:
-+ case MethodHandle::_adapt_push_primitive:
-+ case MethodHandle::_adapt_push_reference:
-+ case MethodHandle::_adapt_ricochet:
-+ case MethodHandle::_adapt_flyby:
++ case _adapt_retype_only:
++ if (VerifyMethodHandles) {
++ verify_method_type_passthrough(src_mtype(), dst_mtype(), CHECK);
++ }
++ 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;
++
++ case _adapt_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.
++ switch (type2size[src] *4+ type2size[dest]) {
++ 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;
++ 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;
++ vminfo = adapter_subword_vminfo(dest);
++ } else if (src == T_DOUBLE && dest == T_FLOAT) {
++ ek = _adapter_opt_d2f;
++ } else {
++ assert(false, "");
++ }
++ break;
++ case 1 *4+ 2:
++ if (src == T_INT && dest == T_LONG) {
++ ek = _adapter_opt_i2l;
++ } else if (src == T_FLOAT && dest == T_DOUBLE) {
++ ek = _adapter_opt_f2d;
++ } else {
++ assert(false, "");
++ }
++ break;
++ default:
++ assert(false, "");
++ break;
++ }
++ }
++ break;
++
++ case _adapt_ref_to_prim:
++ {
++ switch (type2size[dest]) {
++ case 1:
++ ek = _adapter_opt_a2i;
++ vminfo = adapter_subword_vminfo(dest);
++ break;
++ case 2:
++ ek = _adapter_opt_a2l;
++ break;
++ default:
++ assert(false, "");
++ break;
++ }
++ }
++ break;
++
++ case _adapt_prim_to_ref:
++ goto throw_not_impl; // allocates, hence could block
++
++ case _adapt_dup_args:
++ case _adapt_drop_args:
++ // these work fine via general case code
++ break;
++
++ case _adapt_collect_args:
++ goto throw_not_impl; // allocates, hence could block
++
++ case _adapt_spread_args:
++ {
++ // vminfo will be the required length of the array
++ int slots_pushed = stack_move / stack_move_unit();
++ int array_size = slots_pushed + 1;
++ 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;
++ }
++ if ((vminfo & _CONV_VMINFO_MASK) != vminfo)
++ goto throw_not_impl; // overflow
++ }
++ break;
++
++ case _adapt_flyby:
++ case _adapt_ricochet:
++ goto throw_not_impl; // runs Java code, hence could block
++
++ throw_not_impl:
+ // FIXME: these adapters are NYI
-+ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), MethodHandle::adapter_entry_name(ak));
-+ }
-+
-+ // This is the guy we are initializing:
-+ if (mh_jh == NULL) return;
-+ Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh));
-+
-+ java_dyn_MethodHandle::set_vmdata(JNIHandles::resolve_non_null(mh_jh),
-+ conversion, argslot);
-+
-+ if (vmref_jh != NULL) {
-+ oop vmref = JNIHandles::resolve_non_null(vmref_jh);
-+ if (java_lang_Class::is_instance(vmref))
-+ vmref = java_lang_Class::as_klassOop(vmref);
-+ java_dyn_MethodHandle::set_vmref(mh(), vmref);
-+ }
++ throw_InternalError(adapter_entry_name(ak), CHECK);
++ 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, "");
++
++ // Finalize the conversion field. (Note that it is final to Java code.)
++ impl_java_dyn_AdapterMethodHandle::set_conversion(mh(), new_conversion);
+
+ // Done!
-+ MethodHandle::EntryKind ek = MethodHandle::EntryKind(MethodHandle::_adapter_mh_first + (int)ak);
-+ java_dyn_MethodHandle::set_entry(mh(), MethodHandle::entry(ek));
++ java_dyn_MethodHandle::set_vmentry(mh(), entry(ek));
+
+ // There should be enough memory barriers on exit from native methods
+ // to ensure that the MH is fully initialized to all threads before
+ // Java code can publish it in global data structures.
+}
++
++
++//
++// Here are the native methods on impl.java.dyn.MethodHandleImpl.
++// They are the private interface between this JVM and the HotSpot-specific
++// Java code that implements JSR 292 method handles.
++//
++
++// direct method handles for invokestatic or invokespecial
++JVM_ENTRY(void, MHI_init_DMH(JNIEnv *env, jobject igcls, jobject mh_jh,
++ jobject target_jh, jboolean do_dispatch)) {
++ ResourceMark rm; // for error messages
++
++ // This is the guy we are initializing:
++ if (mh_jh == NULL) { throw_InternalError(CHECK); }
++ 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?
++ int decode_flags = 0; klassOop receiver_limit = NULL;
++ methodHandle m(THREAD,
++ MethodHandle::decode_method(JNIHandles::resolve(target_jh),
++ receiver_limit, decode_flags));
++ if (m.is_null()) { throw_InternalError(CHECK); }
++
++ MethodHandle::init_DirectMethodHandle(mh, m, do_dispatch, CHECK);
++}
+JVM_END
+
++// bound method handles
++JVM_ENTRY(void, MHI_init_BMH(JNIEnv *env, jobject igcls, jobject mh_jh,
++ jobject target_jh, int argnum)) {
++ ResourceMark rm; // for error messages
++
++ // This is the guy we are initializing:
++ if (mh_jh == NULL) { throw_InternalError(CHECK); }
++ 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); }
++ 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 = MethodHandle::decode_method(target(),
++ receiver_limit, decode_flags);
++ MethodHandle::init_BoundMethodHandle_with_receiver(mh, m,
++ receiver_limit,
++ decode_flags,
++ CHECK);
++ return;
++ }
++
++ // Build a BMH on top of a DMH or another BMH:
++ MethodHandle::init_BoundMethodHandle(mh, target, argnum, CHECK);
++}
++JVM_END
++
++// adapter method handles
++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); }
++ Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh));
++ Handle target(THREAD, JNIHandles::resolve_non_null(target_jh));
++
++ // Early returns out of this method leave the AMH in an unfinished state.
++ assert(java_dyn_MethodHandle::vmentry(mh()) == NULL, "must be safely null");
++
++ MethodHandle::init_AdapterMethodHandle(mh, target, argnum, CHECK);
++}
++JVM_END
++
+// method type forms
-+JVM_ENTRY(void, MH_init_MTForm(JNIEnv *env, jobject igcls, jobject form_jh, jobject erased_jh)) {
++JVM_ENTRY(void, MHI_init_MT(JNIEnv *env, jobject igcls, jobject erased_jh)) {
+ if (erased_jh == NULL) return;
+ if (TraceMethodHandles) {
+ tty->print("creating MethodType form ");
@@ -4854,22 +6823,27 @@ new file mode 100644
+}
+JVM_END
+
-+// debugging
-+JVM_ENTRY(jobject, MH_methodName(JNIEnv *env, jobject igcls, jobject mh_jh)) {
-+ int junk;
-+ methodHandle m(THREAD, MethodHandle::decode_method(JNIHandles::resolve(mh_jh), junk));
-+ if (m.is_null()) return NULL;
-+ oop str_oop = StringTable::intern(m->name(), CHECK_NULL);
-+ return JNIHandles::make_local(THREAD, str_oop);
++// 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; }
++ oop target = MethodHandle::encode_target(mh, format, CHECK_NULL);
++ return JNIHandles::make_local(THREAD, target);
+}
+JVM_END
+
-+
-+JVM_ENTRY(jobject, MH_vmref(JNIEnv *env, jobject igcls, jobject mh_jh)) {
-+ int junk;
-+ if (mh_jh == NULL) return NULL;
-+ oop vmref = MethodHandle::decode_vmref(JNIHandles::resolve(mh_jh), junk);
-+ return JNIHandles::make_local(THREAD, vmref);
++JVM_ENTRY(jint, MHI_getConstant(JNIEnv *env, jobject igcls, jint which)) {
++ switch (which) {
++ case 0: // JVM_PUSH_LIMIT
++ guarantee(MethodHandlePushLimit >= 2 && MethodHandlePushLimit <= 0xFF,
++ "MethodHandlePushLimit parameter must be in valid range");
++ return MethodHandlePushLimit;
++ case 1: // JVM_STACK_MOVE_UNIT
++ // return number of words per slot, signed according to stack direction
++ return MethodHandle::stack_move_unit();
++ }
++ return 0;
+}
+JVM_END
+
@@ -4879,53 +6853,56 @@ new file mode 100644
+#define ADR "J"
+
+#define LANG "Ljava/lang/"
-+#define DYNP "Ljava/dyn/"
-+#define DYNI "Ljava/dyn/impl/"
++#define JDYN "Ljava/dyn/"
++#define IDYN "Limpl/java/dyn/"
+
+#define OBJ LANG"Object;"
+#define CLS LANG"Class;"
+#define STRG LANG"String;"
-+#define MH DYNI"MH;"
-+#define AMH DYNI"AMH;"
-+#define BMH DYNI"BMH;"
-+#define DMH DYNI"DMH;"
-+#define MT DYNP"MethodType;"
-+#define MTFM DYNI"MTForm;"
++#define MT JDYN"MethodType;"
++#define MH JDYN"MethodHandle;"
++#define MHI IDYN"MethodHandleImpl;"
++#define AMH IDYN"AdapterMethodHandle;"
++#define BMH IDYN"BoundMethodHandle;"
++#define DMH IDYN"DirectMethodHandle;"
+
+#define CC (char*) /*cast a literal from (const char*)*/
+#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
+
-+// These are the correct methods, moving forward:
++// These are the native methods on impl.java.dyn.MethodHandleImpl.
+static JNINativeMethod methods[] = {
-+ {CC"init", CC"("AMH"II"OBJ")V", FN_PTR(MH_init_AMH)},
-+ {CC"init", CC"("BMH OBJ OBJ")V", FN_PTR(MH_init_BMH)},
-+ {CC"init", CC"("DMH OBJ"Z)V", FN_PTR(MH_init_DMH)},
-+ {CC"init", CC"("MTFM MT")V", FN_PTR(MH_init_MTForm)},
-+ {CC"getMethodName", CC"("MH")"STRG, FN_PTR(MH_methodName)},
-+ {CC"getVMRef", CC"("MH")"OBJ, FN_PTR(MH_vmref)}
++ {CC"init", CC"("AMH""MH"I)V", FN_PTR(MHI_init_AMH)},
++ {CC"init", CC"("BMH OBJ"I)V", FN_PTR(MHI_init_BMH)},
++ {CC"init", CC"("DMH OBJ"Z)V", FN_PTR(MHI_init_DMH)},
++ {CC"init", CC"("MT")V", FN_PTR(MHI_init_MT)},
++ {CC"getTarget", CC"("MHI"I)"OBJ, FN_PTR(MHI_getTarget)},
++ {CC"getConstant", CC"(I)I", FN_PTR(MHI_getConstant)}
+};
+
+
+// This one function is exported, used by NativeLookup.
+
-+JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass mhcls))
++JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass mhcls)) {
++ assert(MethodHandle::spot_check_entry_names(), "entry enum is OK");
++
+ {
+ ThreadToNativeFromVM ttnfv(thread);
+
+ int status = env->RegisterNatives(mhcls, methods, sizeof(methods)/sizeof(JNINativeMethod));
+ if (env->ExceptionOccurred()) {
+ if (PrintMiscellaneous && (Verbose || WizardMode)) {
-+ tty->print_cr("Warning: java.dyn.impl.MH not found.");
++ tty->print_cr("Warning: impl.java.dyn.impl.MH not found.");
+ }
+ env->ExceptionClear();
+ }
+ }
++}
+JVM_END
diff --git a/src/share/vm/prims/methodHandles.hpp b/src/share/vm/prims/methodHandles.hpp
new file mode 100644
--- /dev/null
+++ b/src/share/vm/prims/methodHandles.hpp
-@@ -0,0 +1,198 @@
+@@ -0,0 +1,391 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -4960,22 +6937,28 @@ new file mode 100644
+ // 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 java/dyn/impl/AMH.java:
-+ _adapt_retype_only = 0, // retype with no argument changes
-+ _adapt_drop_initial, // pass through after ignoring deep stack
-+ _adapt_drop_final, // pass through after popping shallow stack
-+ _adapt_check_cast, // pass through with one argument checkcast
-+ _adapt_extend_sign, // mask an argument down to a subword type
-+ _adapt_extend_zero, // mask an argument down to a subword type
-+ _adapt_test_boolean, // zero-test an argument down to a boolean 1/0
-+ _adapt_swap_argument, // swap two arguments (or two pairs)
-+ _adapt_push_argument, // push copy of existing argument (or pair)
-+ _adapt_push_primitive, // push a primitive constant (from a wrapper)
-+ _adapt_push_reference, // push a reference parameter
-+ _adapt_ricochet, // make a call, then another call on return value
-+ _adapt_flyby, // make a call on reified arglist, then make another call
-+ _AK_LIMIT,
-+ _AK_MASK = 0xFF
++ // 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_dup_args = 0x6, // duplicates one or more arguments (at TOS)
++ _adapt_drop_args = 0x7, // remove one or more argument slots
++ _adapt_collect_args = 0x8, // combine one or more arguments into a varargs (NYI)
++ _adapt_spread_args = 0x9, // expand in place a varargs array (of known size)
++ _adapt_flyby = 0xA, // operate first on reified argument list (NYI)
++ _adapt_ricochet = 0xB, // 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
@@ -4984,17 +6967,44 @@ new file mode 100644
+ _invokespecial_mh, // ditto for the other invokes...
+ _invokevirtual_mh,
+ _invokeinterface_mh,
-+ _invokebound_mh, // invokespecial, with a saved receiver
++ _bound_ref_mh, // reference argument is bound
++ _bound_int_mh, // int argument is bound (via an Integer or Float)
++ _bound_long_mh, // long argument is bound (via a Long or Double)
++ _bound_ref_direct_mh, // same as above, with direct linkage to methodOop
++ _bound_int_direct_mh,
++ _bound_long_direct_mh,
+
+ _adapter_mh_first, // adapter sequence goes here...
+ _adapter_mh_last = _adapter_mh_first + (_AK_LIMIT - 1),
++
++ // Optimized adapter types
++
++ // primitive single to single:
++ _adapter_opt_i2i, // i2c, i2z, i2b, i2s
++ // primitive double to single:
++ _adapter_opt_l2i,
++ _adapter_opt_d2f,
++ // primitive single to double:
++ _adapter_opt_i2l,
++ _adapter_opt_f2d,
++ // conversion between floating point and integer type is handled by Java
++
++ // reference to primitive:
++ _adapter_opt_a2i,
++ _adapter_opt_a2l,
++
++ // spreading (array length cases 0, 1, >=2)
++ _adapt_opt_spread_0,
++ _adapt_opt_spread_1,
++ _adapt_opt_spread_more,
+
+ _EK_LIMIT,
+ _EK_FIRST = 0
+ };
++
+ private:
+ static MethodEntry* _entries[_EK_LIMIT];
-+ static const char* _entry_names[_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; }
+
@@ -5013,8 +7023,70 @@ new file mode 100644
+ _entries[ek] = me;
+ }
+
++ static jint adapter_conversion(AdapterKind ak, 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)
++ );
++ }
++ static AdapterKind adapter_conversion_op(jint conv) {
++ return (AdapterKind)((conv >> _CONV_OP_SHIFT) & 0xF);
++ }
++ static BasicType adapter_conversion_src_type(jint conv) {
++ return (BasicType)((conv >> _CONV_SRC_TYPE_SHIFT) & 0xF);
++ }
++ static BasicType adapter_conversion_dest_type(jint conv) {
++ return (BasicType)((conv >> _CONV_DEST_TYPE_SHIFT) & 0xF);
++ }
++ static int adapter_conversion_stack_move(jint conv) {
++ return (conv >> _CONV_STACK_MOVE_SHIFT);
++ }
++ static int adapter_conversion_vminfo(jint conv) {
++ return (conv >> _CONV_VMINFO_SHIFT) & _CONV_VMINFO_MASK;
++ }
++
++ // Offset in words that the interpreter stack pointer moves when an argument is pushed.
++ // The stack_move value must always be a multiple of this.
++ static int stack_move_unit() {
++ return frame::interpreter_frame_expression_stack_direction() * Interpreter::stackElementWords();
++ }
++
++ 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;
++ 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) {
++ return (jint)tem >> vminfo;
++ } else {
++ return (juint)tem >> vminfo;
++ }
++ }
++
+ static inline address from_compiled_entry(EntryKind ek);
+ static inline address from_interpreted_entry(EntryKind ek);
++
++ // helpers for decode_method.
++ static methodOop decode_methodOop(methodOop m, int& decode_flags_result);
++ static methodOop decode_MethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result);
++ static methodOop decode_DirectMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result);
++ static methodOop decode_BoundMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result);
++ static methodOop decode_AdapterMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result);
++
++ // Find out how many stack slots an mh pushes or pops.
++ // The result is *not* reported as a multiple of stack_move_unit();
++ // It is a signed net number of pushes (a difference in vmslots).
++ // To compare with a stack_move value, first multiply by stack_move_unit().
++ static int decode_MethodHandle_stack_pushes(oop mh);
+
+ public:
+ // called from InterpreterGenerator and StubGenerator
@@ -5023,52 +7095,150 @@ new file mode 100644
+
+ // argument list parsing
+ static int argument_slot(oop method_type, int arg);
++ static int argument_slot_count(oop method_type) { return argument_slot(method_type, -1); }
+
+ // Runtime support
+ enum { // bit-encoded flags from decode_method or decode_vmref
-+ _dmf_does_dispatch = 0x01, // method handle performs virtual or interface dispatch
-+ _dmf_is_interface = 0x02, // peforms interface dispatch
-+ _dmf_has_receiver = 0x04,
-+ _dmf_has_klass = 0x08,
-+ _dmf_has_casts = 0x10
++ _dmf_has_receiver = 0x01, // target method has leading reference argument
++ _dmf_does_dispatch = 0x02, // method handle performs virtual or interface dispatch
++ _dmf_from_interface = 0x04, // peforms interface dispatch
++ _DMF_DIRECT_MASK = (_dmf_from_interface*2 - _dmf_has_receiver),
++ _dmf_binds_method = 0x08,
++ _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
+ };
-+ static methodOop decode_method(oop x, int& decode_flags_result);
-+ static oop decode_vmref(oop x, int& decode_flags_result);
-+ static bool class_cast_needed(klassOop src, klassOop dst);
-+
-+ static void verify_method_type(methodHandle m,
-+ oop mtype,
-+ bool has_bound_oop,
-+ klassOop bound_oop_type,
-+ TRAPS);
++ static methodOop decode_method(oop x, klassOop& receiver_limit_result, int& decode_flags_result);
++ enum { // format of result from encode_target
++ _etf_handle_or_method_info, // all available data (immediate MH or method)
++ _etf_direct_handle, // ultimate method handle (will be a DMH, may be self)
++ _etf_method_info, // ultimate method as tuple {declClass, name, sig, refClass}
++ _etf_reflect_method, // ultimate method as java.lang.reflect object (sans refClass)
++ _etf_name // ultimate method name only
++ };
++ enum { // format of method_info tuple (Object[4])
++ _mi_declaring_class,
++ _mi_name,
++ _mi_signature,
++ _mi_reference_class,
++ _MI_LENGTH
++ };
++ static oop encode_target(oop 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, 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) {
++ 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);
++ }
++ static void verify_method_type_conversion(oop src_mtype,
++ int change_argnum, oop change_type,
++ oop dst_mtype, TRAPS) {
++ 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);
++ }
++ static void verify_method_type_passthrough(oop src_mtype, oop dst_mtype, TRAPS) {
++ oop no_ref = NULL;
++ verify_method_type_change(src_mtype, 0, -1,
++ -1, no_ref, -1, no_ref, -1,
++ dst_mtype, 0, -1, THREAD);
++ }
++
++ 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);
++
++ static const char* check_argument_type_change(BasicType src_type, klassOop src_klass,
++ BasicType dst_type, klassOop dst_klass,
++ int argnum);
++
++ static const char* check_argument_type_change(oop src_type, oop dst_type,
++ int argnum) {
++ klassOop src_klass = NULL, dst_klass = NULL;
++ BasicType src_bt = java_lang_Class::as_BasicType(src_type, &src_klass);
++ BasicType dst_bt = java_lang_Class::as_BasicType(dst_type, &dst_klass);
++ return check_argument_type_change(src_bt, src_klass,
++ dst_bt, dst_klass, argnum);
++ }
++
++ static const char* check_return_type_change(oop src_type, oop dst_type) {
++ return check_argument_type_change(src_type, dst_type, -1);
++ }
++
++ static const char* check_return_type_change(BasicType src_type, klassOop src_klass,
++ BasicType dst_type, klassOop dst_klass) {
++ 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);
++
++
++ // 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);
++
++ // 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,
++ int decode_flags,
++ TRAPS);
++
++ // Fill in the fields of an AdapterMethodHandle mh. (MH.type must be pre-filled.)
++ static void init_AdapterMethodHandle(Handle mh, Handle target, int argnum, TRAPS);
++
++#ifdef ASSERT
++ static bool spot_check_entry_names();
++#endif
+
+ private:
-+ static const char* verify_method_receiver(methodHandle m, klassOop passed_recv_type);
-+ static const char* verify_method_signature(methodHandle m, Handle mtype,
-+ KlassHandle insert_ptype,
-+ int first_ptype,
-+ objArrayHandle ptypes,
-+ TRAPS);
-+
-+ static BasicType subword_to_int(BasicType t) {
-+ if (t == T_BOOLEAN || t == T_CHAR || t == T_BYTE || t == T_SHORT)
-+ // these guys are processed exactly like T_INT in calling sequences:
-+ return T_INT;
-+ return t;
-+ }
-+
-+ static bool same_basic_type_for_arguments(BasicType src, BasicType dst) {
-+ assert(src != T_VOID && dst != T_VOID, "should not be here");
-+ if (src == dst) return true;
-+ if (src <= T_INT && dst <= T_INT) return subword_to_int(src) == subword_to_int(dst);
-+ return false;
-+ }
-+
++ static methodOop dispatch_decoded_method(methodOop m, klassOop receiver_limit, int decode_flags,
++ klassOop receiver_klass,
++ TRAPS);
++
++ static bool same_basic_type_for_arguments(BasicType src, BasicType dst,
++ bool for_return = false);
+ static bool same_basic_type_for_returns(BasicType src, BasicType dst) {
-+ if (dst == T_VOID) return true; // return values can always be forgotten
-+ return same_basic_type_for_arguments(src, dst);
-+ }
-+
++ return same_basic_type_for_arguments(src, dst, true);
++ }
++
++ enum { // arg_mask values
++ _INSERT_NO_MASK = -1,
++ _INSERT_REF_MASK = 0,
++ _INSERT_INT_MASK = 1,
++ _INSERT_LONG_MASK = 3
++ };
++ static void insert_arg_slots(MacroAssembler* _masm,
++ RegisterConstant arg_slots,
++ int arg_mask,
++ Register rax_argslot,
++ Register rbx_temp, Register rdx_temp);
++
++ static void remove_arg_slots(MacroAssembler* _masm,
++ RegisterConstant arg_slots,
++ Register rax_argslot,
++ Register rbx_temp, Register rdx_temp);
+};
+
+
@@ -5140,7 +7310,7 @@ diff --git a/src/share/vm/prims/nativeLo
if (strstr(jni_name, "Java_sun_misc_Unsafe_registerNatives") != NULL) {
return CAST_FROM_FN_PTR(address, JVM_RegisterUnsafeMethods);
+ }
-+ if (strstr(jni_name, "Java_java_dyn_impl_MH_registerNatives") != NULL) {
++ if (strstr(jni_name, "Java_impl_java_dyn_MethodHandleImpl_registerNatives") != NULL) {
+ return CAST_FROM_FN_PTR(address, JVM_RegisterMethodHandleMethods);
}
if (strstr(jni_name, "Java_sun_misc_Perf_registerNatives") != NULL) {
@@ -5148,7 +7318,7 @@ diff --git a/src/share/vm/runtime/argume
diff --git a/src/share/vm/runtime/arguments.cpp b/src/share/vm/runtime/arguments.cpp
--- a/src/share/vm/runtime/arguments.cpp
+++ b/src/share/vm/runtime/arguments.cpp
-@@ -2573,6 +2573,13 @@
+@@ -2593,6 +2593,13 @@
}
#endif // PRODUCT
@@ -5176,15 +7346,24 @@ diff --git a/src/share/vm/runtime/global
diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp
--- a/src/share/vm/runtime/globals.hpp
+++ b/src/share/vm/runtime/globals.hpp
-@@ -3233,6 +3233,12 @@
+@@ -3240,6 +3240,21 @@
product(bool, AnonymousClasses, false, \
"support sun.misc.Unsafe.defineAnonymousClass") \
\
+ product(bool, MethodHandles, false, \
+ "support method handles") \
+ \
++ diagnostic(intx, MethodHandlePushLimit, 3, \
++ "number of additional stack slots a method handle may push") \
++ \
+ develop(bool, TraceMethodHandles, false, \
+ "trace internal method handle operations") \
++ \
++ diagnostic(bool, VerifyMethodHandles, trueInDebug, \
++ "perform extra checks when constructing method handles") \
++ \
++ diagnostic(bool, OptimizeMethodHandles, true, \
++ "when constructing method handles, try to improve them") \
+ \
product(bool, TaggedStackInterpreter, false, \
"Insert tags in interpreter execution stack for oopmap generaion")\
@@ -5210,7 +7389,7 @@ diff --git a/src/share/vm/runtime/shared
diff --git a/src/share/vm/runtime/sharedRuntime.cpp b/src/share/vm/runtime/sharedRuntime.cpp
--- a/src/share/vm/runtime/sharedRuntime.cpp
+++ b/src/share/vm/runtime/sharedRuntime.cpp
-@@ -660,48 +660,6 @@
+@@ -665,48 +665,6 @@
JRT_ENTRY(void, SharedRuntime::yield_all(JavaThread* thread, int attempts))
os::yield_all(attempts);
JRT_END
@@ -5259,7 +7438,7 @@ diff --git a/src/share/vm/runtime/shared
JRT_ENTRY_NO_ASYNC(void, SharedRuntime::register_finalizer(JavaThread* thread, oopDesc* obj))
-@@ -1500,9 +1458,72 @@
+@@ -1505,9 +1463,73 @@
return generate_class_cast_message(objName, targetKlass->external_name());
}
@@ -5275,7 +7454,7 @@ diff --git a/src/share/vm/runtime/shared
+ klassOop ak = (actual->is_klass()
+ ? (klassOop)actual
+ : actual->klass());
-+ objName = Klass::cast(actual->klass())->external_name();
++ objName = Klass::cast(ak)->external_name();
+ }
+ Klass* targetKlass = Klass::cast(required->is_klass()
+ ? (klassOop)required
@@ -5301,8 +7480,9 @@ diff --git a/src/share/vm/runtime/shared
+ targetType = target->signature()->as_C_string();
+ }
+ }
-+ int ignore;
-+ methodOop actual_method = MethodHandle::decode_method(actual, ignore);
++ klassOop kignore; int fignore;
++ methodOop actual_method = MethodHandle::decode_method(actual,
++ kignore, fignore);
+ if (actual_method != NULL) {
+ if (actual_method->name() == vmSymbols::invoke_name())
+ mhName = "$";
@@ -5312,7 +7492,7 @@ diff --git a/src/share/vm/runtime/shared
+ mhName = actual_method->signature()->as_C_string();
+ }
+ return generate_class_cast_message(mhName, targetType,
-+ " cannot called as ");
++ " cannot be called as ");
+ }
+}
+
@@ -5388,15 +7568,16 @@ diff --git a/src/share/vm/utilities/acce
diff --git a/src/share/vm/utilities/accessFlags.hpp b/src/share/vm/utilities/accessFlags.hpp
--- a/src/share/vm/utilities/accessFlags.hpp
+++ b/src/share/vm/utilities/accessFlags.hpp
-@@ -47,6 +47,7 @@
+@@ -47,6 +47,8 @@
JVM_ACC_IS_OLD = 0x00010000, // RedefineClasses() has replaced this method
JVM_ACC_IS_OBSOLETE = 0x00020000, // RedefineClasses() has made method obsolete
JVM_ACC_IS_PREFIXED_NATIVE = 0x00040000, // JVMTI has prefixed this native method
-+ JVM_MH_INVOKE_BITS = (JVM_ACC_NATIVE | JVM_ACC_SYNTHETIC | JVM_ACC_MONITOR_MATCH),
++ JVM_MH_INVOKE_BITS // = 0x10001100 // MethodHandle.invoke quasi-native
++ = (JVM_ACC_NATIVE | JVM_ACC_SYNTHETIC | JVM_ACC_MONITOR_MATCH),
// klassOop flags
JVM_ACC_HAS_MIRANDA_METHODS = 0x10000000, // True if this class has miranda methods in it's vtable
-@@ -72,6 +73,7 @@
+@@ -72,6 +74,7 @@
// flags accepted by set_field_flags()
JVM_ACC_FIELD_FLAGS = 0x00008000 | JVM_ACC_WRITTEN_FLAGS
@@ -5404,15 +7585,23 @@ diff --git a/src/share/vm/utilities/acce
};
-@@ -113,6 +115,7 @@
+@@ -113,6 +116,15 @@
bool is_old () const { return (_flags & JVM_ACC_IS_OLD ) != 0; }
bool is_obsolete () const { return (_flags & JVM_ACC_IS_OBSOLETE ) != 0; }
bool is_prefixed_native () const { return (_flags & JVM_ACC_IS_PREFIXED_NATIVE ) != 0; }
++
++ // JSR 292: A method of the form MethodHandle.invoke(A...)R method is
++ // neither bytecoded nor a JNI native, but rather a fast call through
++ // a lightweight method handle object. Because it is not bytecoded,
++ // it has the native bit set, but the monitor-match bit is also set
++ // to distinguish it from a JNI native (which never has the match bit set).
++ // The synthetic bit is also present, because such a method is never
++ // explicitly defined in Java code.
+ bool is_method_handle_invoke () const { return (_flags & JVM_MH_INVOKE_BITS) == JVM_MH_INVOKE_BITS; }
// klassOop flags
bool has_miranda_methods () const { return (_flags & JVM_ACC_HAS_MIRANDA_METHODS ) != 0; }
-@@ -199,6 +202,14 @@
+@@ -199,6 +211,14 @@
jshort as_short() { return (jshort)_flags; }
jint as_int() { return _flags; }
@@ -5427,214 +7616,22 @@ diff --git a/src/share/vm/utilities/acce
+ af._flags = flags;
+ return af;
+}
-diff --git a/src/share/vm/utilities/array.hpp b/src/share/vm/utilities/array.hpp
---- a/src/share/vm/utilities/array.hpp
-+++ b/src/share/vm/utilities/array.hpp
-@@ -40,11 +40,18 @@
- _length = 0;
- _data = NULL;
- DEBUG_ONLY(init_nesting();)
-+ // client may call initialize, at most once
- }
-
-
- ResourceArray(size_t esize, int length) {
-+ DEBUG_ONLY(_data = NULL);
-+ initialize(esize, length);
-+ }
-+
-+ void initialize(size_t esize, int length) {
- assert(length >= 0, "illegal length");
-+ assert(_data == NULL, "must be new object");
- _length = length;
- _data = resource_allocate_bytes(esize * length);
- DEBUG_ONLY(init_nesting();)
-@@ -111,7 +118,10 @@
- /* creation */ \
- array_name() : base_class() {} \
- array_name(const int length) : base_class(esize, length) {} \
-- array_name(const int length, const etype fx) : base_class(esize, length) { \
-+ array_name(const int length, const etype fx) { initialize(length, fx); } \
-+ void initialize(const int length) { base_class::initialize(esize, length); } \
-+ void initialize(const int length, const etype fx) { \
-+ initialize(length); \
- for (int i = 0; i < length; i++) ((etype*)_data)[i] = fx; \
- } \
- \
-@@ -157,16 +167,29 @@
- \
- public: \
- /* creation */ \
-- stack_name() : array_name() { _size = 0; } \
-- stack_name(const int size) : array_name(size){ _length = 0; _size = size; } \
-- stack_name(const int size, const etype fx) : array_name(size, fx) { _size = size; } \
-+ stack_name() : array_name() { _size = 0; } \
-+ stack_name(const int size) { initialize(size); } \
-+ stack_name(const int size, const etype fx) { initialize(size, fx); } \
-+ void initialize(const int size, const etype fx) { \
-+ _size = size; \
-+ array_name::initialize(size, fx); \
-+ /* _length == size, allocation and size are the same */ \
-+ } \
-+ void initialize(const int size) { \
-+ _size = size; \
-+ array_name::initialize(size); \
-+ _length = 0; /* reset length to zero; _size records the allocation */ \
-+ } \
- \
- /* standard operations */ \
- int size() const { return _size; } \
- \
-- void push(const etype x) { \
-- if (length() >= size()) expand(esize, length(), _size); \
-- ((etype*)_data)[_length++] = x; \
-+ int push(const etype x) { \
-+ int len = length(); \
-+ if (len >= size()) expand(esize, len, _size); \
-+ ((etype*)_data)[len] = x; \
-+ _length = len+1; \
-+ return len; \
- } \
- \
- etype pop() { \
-@@ -235,7 +258,7 @@
- int capacity() const { return size(); } \
- void clear() { truncate(0); } \
- void trunc_to(const int length) { truncate(length); } \
-- void append(const etype x) { push(x); } \
-+ int append(const etype x) { return push(x); } \
- void appendAll(const stack_name* stack) { push_all(stack); } \
- etype last() const { return top(); } \
- }; \
-diff --git a/src/share/vm/utilities/debug.cpp b/src/share/vm/utilities/debug.cpp
---- a/src/share/vm/utilities/debug.cpp
-+++ b/src/share/vm/utilities/debug.cpp
-@@ -567,7 +567,7 @@
- }
- // the InlineCacheBuffer is using stubs generated into a buffer blob
- if (InlineCacheBuffer::contains(addr)) {
-- tty->print_cr(INTPTR_FORMAT "is pointing into InlineCacheBuffer", addr);
-+ tty->print_cr(INTPTR_FORMAT " is pointing into InlineCacheBuffer", addr);
- return;
- }
- VtableStub* v = VtableStubs::stub_containing(addr);
-@@ -595,7 +595,7 @@
- return;
- }
-
-- if (Universe::heap()->is_in_reserved(addr)) {
-+ if (Universe::heap()->is_in(addr)) {
- HeapWord* p = Universe::heap()->block_start(addr);
- bool print = false;
- // If we couldn't find it it just may mean that heap wasn't parseable
-@@ -621,24 +621,28 @@
- }
- return;
- }
-+ } else if (Universe::heap()->is_in_reserved(addr)) {
-+ tty->print_cr(INTPTR_FORMAT " is an unallocated location in the heap", addr);
-+ return;
- }
-+
- if (JNIHandles::is_global_handle((jobject) addr)) {
-- tty->print_cr(INTPTR_FORMAT "is a global jni handle", addr);
-+ tty->print_cr(INTPTR_FORMAT " is a global jni handle", addr);
- return;
- }
- if (JNIHandles::is_weak_global_handle((jobject) addr)) {
-- tty->print_cr(INTPTR_FORMAT "is a weak global jni handle", addr);
-+ tty->print_cr(INTPTR_FORMAT " is a weak global jni handle", addr);
- return;
- }
- if (JNIHandleBlock::any_contains((jobject) addr)) {
-- tty->print_cr(INTPTR_FORMAT "is a local jni handle", addr);
-+ tty->print_cr(INTPTR_FORMAT " is a local jni handle", addr);
- return;
- }
-
- for(JavaThread *thread = Threads::first(); thread; thread = thread->next()) {
-- // Check for priviledge stack
-+ // Check for privilege stack
- if (thread->privileged_stack_top() != NULL && thread->privileged_stack_top()->contains(addr)) {
-- tty->print_cr(INTPTR_FORMAT "is pointing into the priviledge stack for thread: " INTPTR_FORMAT, addr, thread);
-+ tty->print_cr(INTPTR_FORMAT " is pointing into the privilege stack for thread: " INTPTR_FORMAT, addr, thread);
- return;
- }
- // If the addr is a java thread print information about that.
-@@ -659,7 +663,7 @@
- return;
- }
-
-- tty->print_cr(INTPTR_FORMAT "is pointing to unknown location", addr);
-+ tty->print_cr(INTPTR_FORMAT " is pointing to unknown location", addr);
+diff --git a/src/share/vm/utilities/globalDefinitions.hpp b/src/share/vm/utilities/globalDefinitions.hpp
+--- a/src/share/vm/utilities/globalDefinitions.hpp
++++ b/src/share/vm/utilities/globalDefinitions.hpp
+@@ -407,6 +407,15 @@
+ return T_BOOLEAN <= t && t <= T_LONG;
}
-
-diff --git a/src/share/vm/utilities/growableArray.hpp b/src/share/vm/utilities/growableArray.hpp
---- a/src/share/vm/utilities/growableArray.hpp
-+++ b/src/share/vm/utilities/growableArray.hpp
-@@ -111,6 +111,12 @@
- }
-
- void* raw_allocate(int elementSize);
-+
-+ // some uses pass the Thread explicitly for speed (4990299 tuning)
-+ void* raw_allocate(Thread* thread, int elementSize) {
-+ assert(on_stack(), "fast ResourceObj path only");
-+ return (void*)resource_allocate_bytes(thread, elementSize * _max);
-+ }
- };
-
- template<class E> class GrowableArray : public GenericGrowableArray {
-@@ -121,6 +127,11 @@
- void raw_at_put_grow(int i, const E& p, const E& fill);
- void clear_and_deallocate();
- public:
-+ GrowableArray(Thread* thread, int initial_size) : GenericGrowableArray(initial_size, 0, false) {
-+ _data = (E*)raw_allocate(thread, sizeof(E));
-+ for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E();
-+ }
-+
- GrowableArray(int initial_size, bool C_heap = false) : GenericGrowableArray(initial_size, 0, C_heap) {
- _data = (E*)raw_allocate(sizeof(E));
- for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E();
-@@ -159,10 +170,12 @@
-
- void print();
-
-- void append(const E& elem) {
-+ int append(const E& elem) {
- check_nesting();
- if (_len == _max) grow(_len);
-- _data[_len++] = elem;
-+ int idx = _len++;
-+ _data[idx] = elem;
-+ return idx;
- }
-
- void append_if_missing(const E& elem) {
-diff --git a/src/share/vm/utilities/hashtable.cpp b/src/share/vm/utilities/hashtable.cpp
---- a/src/share/vm/utilities/hashtable.cpp
-+++ b/src/share/vm/utilities/hashtable.cpp
-@@ -43,9 +43,11 @@
- entry = _free_list;
- _free_list = _free_list->next();
- } else {
-- const int block_size = 500;
-- if (_first_free_entry == _end_block) {
-+ if (_first_free_entry + _entry_size >= _end_block) {
-+ int block_size = MIN2(512, MAX2((int)_table_size / 2, (int)_number_of_entries));
- int len = _entry_size * block_size;
-+ len = 1 << log2_intptr(len); // round down to power of 2
-+ assert(len >= _entry_size, "");
- _first_free_entry = NEW_C_HEAP_ARRAY(char, len);
- _end_block = _first_free_entry + len;
- }
-@@ -53,6 +55,7 @@
- _first_free_entry += _entry_size;
- }
-
-+ assert(_entry_size % HeapWordSize == 0, "");
- entry->set_hash(hashValue);
- return entry;
- }
++inline bool is_subword_type(BasicType t) {
++ // these guys are processed exactly like T_INT in calling sequences:
++ return (t == T_BOOLEAN || t == T_CHAR || t == T_BYTE || t == T_SHORT);
++}
++
++inline bool is_signed_subword_type(BasicType t) {
++ return (t == T_BYTE || t == T_SHORT);
++}
++
+ // Convert a char from a classfile signature to a BasicType
+ inline BasicType char2type(char c) {
+ switch( c ) {