--- a/meth.patch Fri Aug 15 23:49:17 2008 -0700
+++ b/meth.patch Fri Aug 15 23:51:07 2008 -0700
@@ -513,117 +513,64 @@ diff --git a/src/cpu/x86/vm/templateTabl
// rax,: Interface
// rbx,: index
-@@ -2933,35 +2936,44 @@
+@@ -2932,6 +2935,57 @@
+
// profile this call
__ profile_virtual_call(rdx, rsi, rdi);
-
-- __ movl(rdi, rdx); // Save klassOop in rdi
-+ Label no_such_interface, no_such_method;
-
-- // Compute start of first itableOffsetEntry (which is at the end of the vtable)
-- const int base = instanceKlass::vtable_start_offset() * wordSize;
-- assert(vtableEntry::size() * wordSize == 4, "adjust the scaling in the code below");
-- __ movl(rsi, Address(rdx, instanceKlass::vtable_length_offset() * wordSize)); // Get length of vtable
-- __ leal(rdx, Address(rdx, rsi, Address::times_4, base));
-- if (HeapWordsPerLong > 1) {
-- // Round up to align_object_offset boundary
-- __ round_to(rdx, BytesPerLong);
-- }
-+ __ lookup_interface_method(// inputs: rec. class, interface, itable index
-+ rdx, rax, rbx,
-+ // outputs: method, scan temp. reg
-+ rbx, rsi,
-+ no_such_interface);
-
-- Label entry, search, interface_ok;
-+ // rbx,: methodOop to call
-+ // rcx: receiver
-+ // Check for abstract method error
-+ // Note: This should be done more efficiently via a throw_abstract_method_error
-+ // interpreter entry point and a conditional jump to it in case of a null
-+ // method.
-+ __ testl(rbx, rbx);
-+ __ jcc(Assembler::zero, no_such_method);
-
-- __ jmpb(entry);
-- __ bind(search);
-- __ addl(rdx, itableOffsetEntry::size() * wordSize);
-+ // do the call
-+ // rcx: receiver
-+ // rbx,: methodOop
-+ __ jump_from_interpreted(rbx, rdx);
-+ __ should_not_reach_here();
-
-- __ bind(entry);
-+ // exception handling code follows...
-+ // note: must restore interpreter registers to canonical
-+ // state for exception handling to work correctly!
-
-- // Check that the entry is non-null. A null entry means that the receiver
-- // class doesn't implement the interface, and wasn't the same as the
-- // receiver class checked when the interface was resolved.
-- __ pushl(rdx);
-- __ movl(rdx, Address(rdx, itableOffsetEntry::interface_offset_in_bytes()));
-- __ testl(rdx, rdx);
-- __ jcc(Assembler::notZero, interface_ok);
-+ __ bind(no_such_method);
- // throw exception
-- __ popl(rdx); // pop saved register first.
-+ __ popl(rbx); // pop return address (pushed by prepare_invoke)
-+ __ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
-+ __ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
-+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
-+ // the call_VM checks for exception, so we should never return here.
-+ __ should_not_reach_here();
-+
-+ __ bind(no_such_interface);
-+ // throw exception
- __ popl(rbx); // pop return address (pushed by prepare_invoke)
- __ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
- __ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
-@@ -2969,42 +2981,6 @@
- InterpreterRuntime::throw_IncompatibleClassChangeError));
- // the call_VM checks for exception, so we should never return here.
- __ should_not_reach_here();
-- __ bind(interface_ok);
--
-- __ popl(rdx);
--
-- __ cmpl(rax, Address(rdx, itableOffsetEntry::interface_offset_in_bytes()));
-- __ jcc(Assembler::notEqual, search);
--
-- __ movl(rdx, Address(rdx, itableOffsetEntry::offset_offset_in_bytes()));
-- __ addl(rdx, rdi); // Add offset to klassOop
-- assert(itableMethodEntry::size() * wordSize == 4, "adjust the scaling in the code below");
-- __ movl(rbx, Address(rdx, rbx, Address::times_4));
-- // rbx,: methodOop to call
-- // rcx: receiver
-- // Check for abstract method error
-- // Note: This should be done more efficiently via a throw_abstract_method_error
-- // interpreter entry point and a conditional jump to it in case of a null
-- // method.
-- { Label L;
-- __ testl(rbx, rbx);
-- __ jcc(Assembler::notZero, L);
-- // throw exception
-- // note: must restore interpreter registers to canonical
-- // state for exception handling to work correctly!
-- __ popl(rbx); // pop return address (pushed by prepare_invoke)
-- __ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
-- __ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
-- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
-- // the call_VM checks for exception, so we should never return here.
-- __ should_not_reach_here();
-- __ bind(L);
-- }
--
-- // do the call
-- // rcx: receiver
-- // rbx,: methodOop
-- __ jump_from_interpreted(rbx, rdx);
- }
-
- //----------------------------------------------------------------------------------------------------
++
++ if (MethodHandles) { // %%% let's use this refactored code always
++ Label no_such_interface, no_such_method;
++
++ __ lookup_interface_method(// inputs: rec. class, interface, itable index
++ rdx, rax, rbx,
++ // outputs: method, scan temp. reg
++ rbx, rsi,
++ no_such_interface);
++
++ // rbx,: methodOop to call
++ // rcx: receiver
++ // Check for abstract method error
++ // Note: This should be done more efficiently via a throw_abstract_method_error
++ // interpreter entry point and a conditional jump to it in case of a null
++ // method.
++ __ testl(rbx, rbx);
++ __ jcc(Assembler::zero, no_such_method);
++
++ // do the call
++ // rcx: receiver
++ // rbx,: methodOop
++ __ jump_from_interpreted(rbx, rdx);
++ __ should_not_reach_here();
++
++ // exception handling code follows...
++ // note: must restore interpreter registers to canonical
++ // state for exception handling to work correctly!
++
++ __ bind(no_such_method);
++ // throw exception
++ __ popl(rbx); // pop return address (pushed by prepare_invoke)
++ __ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
++ __ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
++ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
++ // the call_VM checks for exception, so we should never return here.
++ __ should_not_reach_here();
++
++ __ bind(no_such_interface);
++ // throw exception
++ __ popl(rbx); // pop return address (pushed by prepare_invoke)
++ __ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
++ __ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
++ __ call_VM(noreg, CAST_FROM_FN_PTR(address,
++ InterpreterRuntime::throw_IncompatibleClassChangeError));
++ // the call_VM checks for exception, so we should never return here.
++ __ should_not_reach_here();
++ return;
++ }
++
++ // %%% remove this old code, in favor of the previous block:
+
+ __ movl(rdi, rdx); // Save klassOop in rdi
+
diff --git a/src/cpu/x86/vm/templateTable_x86_32.hpp b/src/cpu/x86/vm/templateTable_x86_32.hpp
--- a/src/cpu/x86/vm/templateTable_x86_32.hpp
+++ b/src/cpu/x86/vm/templateTable_x86_32.hpp
@@ -763,80 +710,88 @@ diff --git a/src/cpu/x86/vm/vtableStubs_
ResourceMark rm;
CodeBuffer cb(s->entry_point(), i486_code_length);
MacroAssembler* masm = new MacroAssembler(&cb);
-@@ -121,52 +136,26 @@
+@@ -121,8 +136,57 @@
assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx");
-+ // Most registers are in use; we'll use rax, rbx, rcx, rsi
-+ Register restore_rcx = rcx;
-+ __ pushl(restore_rcx);
++ address npe_addr = NULL, ame_addr = NULL;
++
++ if (MethodHandles) { // %%% let's use this refactored code always
++ // Most registers are in use; we'll use rax, rbx, rcx, rsi
++ Register restore_rcx = rcx;
++ __ pushl(restore_rcx);
++
++ // get receiver klass (also an implicit null-check)
++ npe_addr = __ pc();
++ __ movl(rcx, Address(rcx, oopDesc::klass_offset_in_bytes()));
++
++ const Register method = rbx;
++ Label throw_icce;
++
++ // Get methodOop and entrypoint for compiler
++ __ lookup_interface_method(// inputs: rec. class, interface, itable index
++ rcx, rax, itable_index,
++ // outputs: method, scan temp. reg
++ method, rsi,
++ throw_icce);
++
++ // Restore saved register, before possible trap.
++ __ popl(restore_rcx);
++
++ // method (rbx): methodOop
++ // rcx: receiver
++
++ #ifdef ASSERT
++ if (DebugVtables) {
++ Label L1;
++ __ cmpl(method, NULL_WORD);
++ __ jcc(Assembler::equal, L1);
++ __ cmpl(Address(method, methodOopDesc::from_compiled_offset()), NULL_WORD);
++ __ jcc(Assembler::notZero, L1);
++ __ stop("methodOop is null");
++ __ bind(L1);
++ }
++ #endif // ASSERT
++
++ ame_addr = __ pc();
++ __ jmp(Address(method, methodOopDesc::from_compiled_offset()));
++
++ __ bind(throw_icce);
++ // Restore saved register
++ __ popl(restore_rcx);
++ __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
++ } else {
++ // %%% remove this old code, in favor of the previous block:
+
// get receiver klass (also an implicit null-check)
- address npe_addr = __ pc();
-- __ movl(rbx, Address(rcx, oopDesc::klass_offset_in_bytes()));
-+ __ movl(rcx, Address(rcx, oopDesc::klass_offset_in_bytes()));
-
-- __ movl(rsi, rbx); // Save klass in free register
-- // Most registers are in use, so save a few
-- __ pushl(rdx);
-- // compute itable entry offset (in words)
-- const int base = instanceKlass::vtable_start_offset() * wordSize;
-- assert(vtableEntry::size() * wordSize == 4, "adjust the scaling in the code below");
-- __ movl(rdx, Address(rbx, instanceKlass::vtable_length_offset() * wordSize)); // Get length of vtable
-- __ leal(rbx, Address(rbx, rdx, Address::times_4, base));
-- if (HeapWordsPerLong > 1) {
-- // Round up to align_object_offset boundary
-- __ round_to(rbx, BytesPerLong);
-- }
--
-- Label hit, next, entry, throw_icce;
--
-- __ jmpb(entry);
--
-- __ bind(next);
-- __ addl(rbx, itableOffsetEntry::size() * wordSize);
--
-- __ bind(entry);
--
-- // If the entry is NULL then we've reached the end of the table
-- // without finding the expected interface, so throw an exception
-- __ movl(rdx, Address(rbx, itableOffsetEntry::interface_offset_in_bytes()));
-- __ testl(rdx, rdx);
-- __ jcc(Assembler::zero, throw_icce);
-- __ cmpl(rax, rdx);
-- __ jcc(Assembler::notEqual, next);
--
-- // We found a hit, move offset into rbx,
-- __ movl(rdx, Address(rbx, itableOffsetEntry::offset_offset_in_bytes()));
--
-- // Compute itableMethodEntry.
+- address npe_addr = __ pc();
++ npe_addr = __ pc();
+ __ movl(rbx, Address(rcx, oopDesc::klass_offset_in_bytes()));
+
+ __ movl(rsi, rbx); // Save klass in free register
+@@ -159,7 +223,7 @@
+ __ movl(rdx, Address(rbx, itableOffsetEntry::offset_offset_in_bytes()));
+
+ // Compute itableMethodEntry.
- const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) + itableMethodEntry::method_offset_in_bytes();
-+ const Register method = rbx;
-+ Label throw_icce;
++ const int method_offset = (itableMethodEntry::size() * wordSize * itable_index) + itableMethodEntry::method_offset_in_bytes();
// Get methodOop and entrypoint for compiler
-- const Register method = rbx;
-- __ movl(method, Address(rsi, rdx, Address::times_1, method_offset));
-+ __ lookup_interface_method(// inputs: rec. class, interface, itable index
-+ rcx, rax, itable_index,
-+ // outputs: method, scan temp. reg
-+ method, rsi,
-+ throw_icce);
-
- // Restore saved register, before possible trap.
-- __ popl(rdx);
-+ __ popl(restore_rcx);
-
- // method (rbx): methodOop
- // rcx: receiver
-@@ -188,11 +177,17 @@
+ const Register method = rbx;
+@@ -183,7 +247,7 @@
+ }
+ #endif // ASSERT
+
+- address ame_addr = __ pc();
++ ame_addr = __ pc();
+ __ jmp(Address(method, methodOopDesc::from_compiled_offset()));
__ bind(throw_icce);
- // Restore saved register
-- __ popl(rdx);
-+ __ popl(restore_rcx);
+@@ -191,8 +255,15 @@
+ __ popl(rdx);
__ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
++ } // %%% ...end of code to remove.
masm->flush();
+ if (PrintMiscellaneous && (WizardMode || Verbose)) {
@@ -848,15 +803,15 @@ diff --git a/src/cpu/x86/vm/vtableStubs_
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
s->set_exception_points(npe_addr, ame_addr);
-@@ -207,7 +202,7 @@
+@@ -207,6 +278,8 @@
return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0);
} else {
// Itable stub size
-- return (DebugVtables ? 144 : 64) + (CountCompiledCalls ? 6 : 0);
-+ return (DebugVtables ? 159 : 79) + (CountCompiledCalls ? 6 : 0);
++ if (MethodHandles) // %%% let's use this refactored code always
++ return (DebugVtables ? 159 : 79) + (CountCompiledCalls ? 6 : 0);
+ return (DebugVtables ? 144 : 64) + (CountCompiledCalls ? 6 : 0);
}
}
-
diff --git a/src/share/vm/c1/c1_GraphBuilder.cpp b/src/share/vm/c1/c1_GraphBuilder.cpp
--- a/src/share/vm/c1/c1_GraphBuilder.cpp
+++ b/src/share/vm/c1/c1_GraphBuilder.cpp
@@ -997,7 +952,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
-@@ -1723,6 +1723,11 @@
+@@ -1841,6 +1841,11 @@
_has_vanilla_constructor = true;
}
@@ -1265,7 +1220,7 @@ 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());
-@@ -2016,6 +2055,135 @@
+@@ -2016,6 +2055,126 @@
int offset = ik->offset_of_static_fields() + static_clock_offset;
SystemDictionary::soft_reference_klass()->long_field_put(offset, value);
@@ -1278,6 +1233,7 @@ diff --git a/src/share/vm/classfile/java
+int java_dyn_MethodHandle::_vmref_offset;
+int java_dyn_MethodHandle::_vmdata_offset;
+int java_dyn_MethodHandle::_entry_offset;
++int java_dyn_MethodHandle::_receiver_offset;
+
+void java_dyn_MethodHandle::compute_offsets() {
+ klassOop k = SystemDictionary::methodHandle_klass();
@@ -1288,8 +1244,13 @@ diff --git a/src/share/vm/classfile/java
+ compute_optional_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) _vmdata_offset += oopDesc::address_padding_in_bytes();
++ klassOop bmhk = SystemDictionary::dyn_impl_BMH_klass();
++ guarantee(bmhk != NULL, "BMH must be present also");
++ compute_optional_offset(_receiver_offset, bmhk,
++ vmSymbols::receiver_name(), vmSymbols::object_signature(), true);
+ guarantee((_vmref_offset != 0 &&
+ _vmdata_offset != 0 &&
++ _receiver_offset != 0 &&
+ _entry_offset != 0), "mismatched method handle support");
+
+ }
@@ -1324,24 +1285,9 @@ diff --git a/src/share/vm/classfile/java
+ mh->release_address_field_put(_entry_offset, (address) me);
+}
+
-+methodOop java_dyn_MethodHandle::method(oop mh) {
-+ klassOop mhk = mh->klass();
-+ if (mhk == SystemDictionary::hotspot_DMH_klass()) {
-+ oop ref = java_dyn_MethodHandle::vmref(mh);
-+ if (ref != NULL) {
-+ 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>
-+ intptr_t index = (intptr_t) java_dyn_MethodHandle::vmdata(mh);
-+ return klassItable::method_for_itable_index((klassOop)ref, index);
-+ }
-+ }
-+ }
-+ return NULL;
++oop java_dyn_MethodHandle::receiver(oop mh) {
++ assert(mh->klass() == SystemDictionary::dyn_impl_BMH_klass(), "BMH only");
++ return mh->obj_field(_receiver_offset);
+}
+
+
@@ -1401,7 +1347,7 @@ diff --git a/src/share/vm/classfile/java
}
-@@ -2354,6 +2522,10 @@
+@@ -2354,6 +2513,10 @@
java_lang_System::compute_offsets();
java_lang_Thread::compute_offsets();
java_lang_ThreadGroup::compute_offsets();
@@ -1424,7 +1370,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,93 @@
+@@ -769,6 +771,101 @@
};
@@ -1440,6 +1386,7 @@ diff --git a/src/share/vm/classfile/java
+ static int _vmref_offset;
+ static int _vmdata_offset;
+ static int _entry_offset;
++ static int _receiver_offset;
+
+ static void compute_offsets();
+
@@ -1453,16 +1400,23 @@ diff --git a/src/share/vm/classfile/java
+ static address vmdata(oop mh);
+ static void set_vmdata(oop mh, address data);
+
++ // vmdata field can store either an address or a simple int:
++ static jint vmdata_int(oop mh)
++ { return (jint)(intptr_t) vmdata(mh); }
++ static void set_vmdata_int(oop mh, jint data)
++ { set_vmdata(mh, (address)(intptr_t) data); }
++
+ static MethodEntry* entry(oop mh);
+ static void set_entry(oop mh, MethodEntry* data);
+
-+ static methodOop method(oop mh); // returns NULL if not available
++ static oop receiver(oop mh);
+
+ // 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 entry_offset_in_bytes() { return _entry_offset; }
++ static int receiver_offset_in_bytes() { return _receiver_offset; }
+};
+
+
@@ -1545,7 +1499,7 @@ diff --git a/src/share/vm/classfile/syst
int SystemDictionary::_number_of_modifications = 0;
-@@ -1660,6 +1661,10 @@
+@@ -1685,6 +1686,10 @@
// Adjust dictionary
dictionary()->oops_do(f);
@@ -1556,7 +1510,7 @@ diff --git a/src/share/vm/classfile/syst
// Partially loaded classes
placeholders()->oops_do(f);
-@@ -1732,6 +1737,8 @@
+@@ -1757,6 +1762,8 @@
void SystemDictionary::methods_do(void f(methodOop)) {
dictionary()->methods_do(f);
@@ -1565,7 +1519,7 @@ diff --git a/src/share/vm/classfile/syst
}
// ----------------------------------------------------------------------------
-@@ -1764,6 +1771,7 @@
+@@ -1789,6 +1796,7 @@
_number_of_modifications = 0;
_loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
_resolution_errors = new ResolutionErrorTable(_resolution_error_size);
@@ -1573,7 +1527,7 @@ diff --git a/src/share/vm/classfile/syst
// Allocate private object used as system class loader lock
_system_loader_lock_obj = oopFactory::new_system_objArray(0, CHECK);
-@@ -1825,6 +1833,9 @@
+@@ -1850,6 +1858,9 @@
wk_klass_name_limits[0] = s;
}
}
@@ -1583,7 +1537,7 @@ diff --git a/src/share/vm/classfile/syst
}
-@@ -1857,6 +1868,12 @@
+@@ -1882,6 +1893,12 @@
instanceKlass::cast(WK_KLASS(weak_reference_klass))->set_reference_type(REF_WEAK);
instanceKlass::cast(WK_KLASS(final_reference_klass))->set_reference_type(REF_FINAL);
instanceKlass::cast(WK_KLASS(phantom_reference_klass))->set_reference_type(REF_PHANTOM);
@@ -1596,7 +1550,7 @@ diff --git a/src/share/vm/classfile/syst
initialize_wk_klasses_until(WKID_LIMIT, scan, CHECK);
-@@ -2108,11 +2125,56 @@
+@@ -2133,11 +2150,56 @@
}
@@ -1654,7 +1608,7 @@ diff --git a/src/share/vm/classfile/syst
char* SystemDictionary::check_signature_loaders(symbolHandle signature,
Handle loader1, Handle loader2,
bool is_method, TRAPS) {
-@@ -2133,6 +2195,80 @@
+@@ -2158,6 +2220,80 @@
sig_strm.next();
}
return NULL;
@@ -1753,10 +1707,10 @@ diff --git a/src/share/vm/classfile/syst
+ \
+ /* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \
+ template(methodHandle_klass, java_dyn_MethodHandle, Opt) \
-+ template(hotspot_AMH_klass, java_dyn_hotspot_AMH, Opt) \
-+ template(hotspot_BMH_klass, java_dyn_hotspot_BMH, Opt) \
-+ template(hotspot_DMH_klass, java_dyn_hotspot_DMH, Opt) \
-+ template(hotspot_MTForm_klass, java_dyn_hotspot_MTForm, 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(methodType_klass, java_dyn_MethodType, Opt) \
+ template(methodTypeForm_klass, java_dyn_MethodTypeForm, Opt) \
+ template(WrongMethodTypeException_klass, java_dyn_WrongMethodTypeException, Opt) \
@@ -1766,7 +1720,7 @@ diff --git a/src/share/vm/classfile/syst
\
template(vector_klass, java_util_Vector, Pre) \
template(hashtable_klass, java_util_Hashtable, Pre) \
-@@ -433,6 +447,12 @@
+@@ -447,6 +461,12 @@
static char* check_signature_loaders(symbolHandle signature, Handle loader1,
Handle loader2, bool is_method, TRAPS);
@@ -1779,7 +1733,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>" :
-@@ -449,6 +469,7 @@
+@@ -463,6 +483,7 @@
enum Constants {
_loader_constraint_size = 107, // number of entries in constraint table
_resolution_error_size = 107, // number of entries in resolution error table
@@ -1787,7 +1741,7 @@ diff --git a/src/share/vm/classfile/syst
_nof_buckets = 1009 // number of buckets in hash table
};
-@@ -478,6 +499,9 @@
+@@ -492,6 +513,9 @@
// Resolution errors
static ResolutionErrorTable* _resolution_errors;
@@ -1797,7 +1751,7 @@ diff --git a/src/share/vm/classfile/syst
public:
// for VM_CounterDecay iteration support
friend class CounterDecay;
-@@ -495,6 +519,7 @@
+@@ -509,6 +533,7 @@
static PlaceholderTable* placeholders() { return _placeholders; }
static LoaderConstraintTable* constraints() { return _loader_constraints; }
static ResolutionErrorTable* resolution_errors() { return _resolution_errors; }
@@ -1829,11 +1783,11 @@ diff --git a/src/share/vm/classfile/vmSy
+ template(java_dyn_MethodTypeForm, "java/dyn/MethodTypeForm") \
+ template(java_dyn_WrongMethodTypeException, "java/dyn/WrongMethodTypeException") \
+ /* internal classes known only to the JVM: */ \
-+ template(java_dyn_hotspot_MTForm, "java/dyn/hotspot/MTForm") \
-+ template(java_dyn_hotspot_MH, "java/dyn/hotspot/MH") \
-+ template(java_dyn_hotspot_AMH, "java/dyn/hotspot/AMH") \
-+ template(java_dyn_hotspot_BMH, "java/dyn/hotspot/BMH") \
-+ template(java_dyn_hotspot_DMH, "java/dyn/hotspot/DMH") \
++ 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(methodTypeForm_signature, "Ljava/dyn/MethodTypeForm;") \
+ template(makeImpl_name, "makeImpl") /*MethodType::makeImpl*/ \
+ template(makeImpl_signature, "(Ljava/lang/Class;[Ljava/lang/Class;ZZ)Ljava/dyn/MethodType;") \
@@ -2823,9 +2777,9 @@ diff --git a/src/share/vm/oops/constantP
diff --git a/src/share/vm/oops/constantPoolKlass.cpp b/src/share/vm/oops/constantPoolKlass.cpp
--- a/src/share/vm/oops/constantPoolKlass.cpp
+++ b/src/share/vm/oops/constantPoolKlass.cpp
-@@ -382,7 +382,8 @@
- "should be symbol or instance");
+@@ -383,7 +383,8 @@
}
+ if (false) // @@@@ pseudo strings can be in non-perm
if (cp->tag_at(i).is_string()) {
- guarantee((*base)->is_perm(), "should be in permspace");
+ // %%% split pseudo-string out of string
@@ -2857,7 +2811,7 @@ diff --git a/src/share/vm/oops/constantP
diff --git a/src/share/vm/oops/constantPoolOop.hpp b/src/share/vm/oops/constantPoolOop.hpp
--- a/src/share/vm/oops/constantPoolOop.hpp
+++ b/src/share/vm/oops/constantPoolOop.hpp
-@@ -376,16 +376,16 @@
+@@ -384,16 +384,16 @@
// byte order (which comes from the bytecodes after rewriting) or,
// if "uncached" is true, a vanilla constant pool index
jint field_or_method_at(int which, bool uncached) {
@@ -3292,7 +3246,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/vm/prims/methodHandles.cpp
-@@ -0,0 +1,647 @@
+@@ -0,0 +1,852 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -3331,16 +3285,81 @@ new file mode 100644
+ "invokestatic", // how a MH emulates invokestatic
+ "invokespecial", // ditto for the other invokes...
+ "invokevirtual",
-+ "invokeinterface"
++ "invokeinterface",
++ "invokebound" // for BMH
+};
++
++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_int(mh);
++ if (ref == NULL) return NULL;
++ if (index != methodOopDesc::nonvirtual_vtable_index) {
++ 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) {
++ 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);
++ }
++ ShouldNotReachHere();
++ return NULL; // cannot parse
++}
+
+// 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) {
++methodOop MethodHandle::decode_method(oop x, int& decode_flags_result) {
++ decode_flags_result = 0;
+ klassOop xk = x->klass();
+ if (xk == Universe::methodKlassObj()) {
+ assert(x->is_method(), "");
-+ return (methodOop) x;
++ 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::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?
+ } else if (xk == SystemDictionary::reflect_method_klass()) {
+ oop clazz = java_lang_reflect_Method::clazz(x);
+ int slot = java_lang_reflect_Method::slot(x);
@@ -3353,14 +3372,13 @@ new file mode 100644
+ 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);
-+ } else if (x->is_a(SystemDictionary::methodHandle_klass())) {
-+ return java_dyn_MethodHandle::method(x);
+ } else {
+ // unrecognized object
+ assert(!x->is_method(), "got this case first");
+ }
+ return NULL;
+}
++
+
+bool MethodHandle::class_cast_needed(klassOop src, klassOop dst) {
+ if (src == dst || dst == SystemDictionary::object_klass())
@@ -3381,29 +3399,26 @@ new file mode 100644
+ return !srck->is_subclass_of(dstk->as_klassOop());
+}
+
-+const char* MethodHandle::check_method_receiver(methodHandle m,
-+ Handle mtype,
-+ objArrayHandle ptypes) {
-+ if (!m->is_static()) {
-+ if (ptypes->length() == 0)
-+ return "receiver type is missing";
-+ klassOop pklass = java_lang_Class::as_klassOop(ptypes->obj_at(0));
-+ if (pklass == NULL)
-+ return "receiver type is primitive";
-+ if (class_cast_needed(pklass, m->method_holder())) {
-+ Klass* formal = Klass::cast(m->method_holder());
-+ return SharedRuntime::generate_class_cast_message("receiver type",
-+ formal->external_name());
-+ }
++const char* MethodHandle::verify_method_receiver(methodHandle m,
++ klassOop passed_recv_type) {
++ assert(!m->is_static(), "caller resp.");
++ if (passed_recv_type == NULL)
++ return "receiver type is primitive";
++ if (class_cast_needed(passed_recv_type, m->method_holder())) {
++ Klass* formal = Klass::cast(m->method_holder());
++ return SharedRuntime::generate_class_cast_message("receiver type",
++ formal->external_name());
+ }
+ return NULL; // checks passed
+}
+
-+const char* MethodHandle::check_method_signature(methodHandle m,
++const char* MethodHandle::verify_method_signature(methodHandle m,
+ Handle mtype,
++ KlassHandle insert_ptype,
++ int first_ptype,
+ objArrayHandle ptypes,
+ TRAPS) {
-+ int pnum = m->is_static() ? 0 : 1;
++ int pnum = first_ptype;
+ int pmax = ptypes->length();
+ const char* err = NULL;
+ BasicType errtype = T_VOID;
@@ -3417,7 +3432,11 @@ new file mode 100644
+ } else {
+ if (pnum >= pmax)
+ return "not enough arguments";
-+ ptype = ptypes->obj_at(pnum++);
++ if (pnum == -1)
++ ptype = insert_ptype->java_mirror();
++ else
++ ptype = ptypes->obj_at(pnum);
++ pnum += 1;
+ }
+ errtype = ss.type();
+ klassOop pklass = java_lang_Class::as_klassOop(ptype);
@@ -3490,8 +3509,55 @@ new file mode 100644
+ }
+}
+
-+
++// Main routine for verifying the MethodHandle.type of a proposed
++// direct or bound 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
++
++ bool m_needs_receiver = !m->is_static();
++
++ const char* err = NULL;
++
++ int first_ptype_pos = m_needs_receiver ? 1 : 0;
++ 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; }
++ }
++
++ if (m_needs_receiver && err == NULL) {
++ if (ptypes->length() < first_ptype_pos)
++ { err = "receiver argument is missing"; goto done; }
++ if (first_ptype_pos == -1)
++ err = MethodHandle::verify_method_receiver(m, bound_recv_type->as_klassOop());
++ else
++ err = MethodHandle::verify_method_receiver(m, java_lang_Class::as_klassOop(ptypes->obj_at(0)));
++ }
++
++ // 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);
++}
++
++
++/// @@ assembly code must be moved
+#define __ _masm->
++#define movL_OR_Q movl
+
+address MethodEntry::start_compiled_entry(MacroAssembler* _masm,
+ address interpreted_entry) {
@@ -3526,7 +3592,7 @@ new file mode 100644
+// Code generation
+// %%% FIXME: Move this to src/cpu/<arch>/vm, of course.
+address MethodHandle::generate_method_handle_interpreter_entry(MacroAssembler* _masm,
-+ Label& wrong_method_type) {
++ Label& wrong_method_type) {
+ // rbx: methodOop
+ // rcx: receiver method handle
+ // rsi: sender SP (must preserve)
@@ -3536,9 +3602,6 @@ new file mode 100644
+ Register rcx_recv = rcx;
+ Register rax_mtype = rax;
+ Register rdx_temp = rdx;
-+
-+ address me_cookie;
-+ MethodEntry* me;
+
+ // here's where control starts out:
+ __ align(CodeEntryAlignment);
@@ -3605,17 +3668,22 @@ new file mode 100644
+ __ hlt();
+}
+
++// 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) {
-+ // rbx: methodOop
-+ // rcx: receiver method handle
-+ // rsi: sender SP (must preserve)
-+ // rdx: garbage temp, blown away
-+
-+ Register rbx_method = rbx;
++ // Here is the register state during an interpreted call,
++ // as set up by generate_method_handle_interpreter_entry():
++ // - rbx: methodOop (MethodHandle.invoke pseudo-method, unused)
++ // - rcx: receiver method handle
++ // - rax: method handle type (already checked at call site)
++ // - rsi: sender SP (must preserve)
++ // - rdx: garbage temp, can blow away
++
+ Register rcx_recv = rcx;
+ Register rax_mtype = rax;
++ Register rsi_savedsp = rsi;
++ Register rbx_method = rbx;
+ Register rdx_temp = rdx;
-+ Register rsi_savedsp = rsi;
+
+ guarantee(java_dyn_MethodHandle::vmdata_offset_in_bytes() != 0, "must have offsets");
+
@@ -3634,25 +3702,37 @@ new file mode 100644
+ __ jmp(Address(rdx_temp, MethodEntry::from_interpreted_entry_offset_in_bytes()));
+ __ hlt();
+
++ interp_entry = __ pc();
+ check_method_type(_masm, rax_mtype, rcx_recv, wrong_method_type);
+ jump_to_entry(_masm, rcx_recv, rdx_temp);
+ break;
+ }
+
+ case _invokestatic_mh:
-+ // same as TemplateTable::invokestatic,
++ case _invokespecial_mh:
++ __ movL_OR_Q(rbx_method, Address(rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes()));
++ __ verify_oop(rbx_method);
++ // same as TemplateTable::invokestatic or invokespecial,
+ // minus the CP setup and profiling:
-+ __ verify_oop(rbx_method);
++ if (ek == _invokespecial_mh) {
++ // Must load & check the first argument before entering the target method.
++ __ movL_OR_Q(rcx_recv, find_mh_argument(_masm, rax_mtype, rsi_savedsp, 0, rcx_recv));
++ __ null_check(rcx_recv);
++ __ verify_oop(rcx_recv);
++ }
+ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
+ break;
+
-+ case _invokespecial_mh:
-+ // same as TemplateTable::invokespecial,
-+ // minus the CP setup and profiling:
-+ load_mh_receiver(_masm, rax_mtype, rsi_savedsp, rcx_recv);
-+ __ null_check(rcx_recv);
-+ __ verify_oop(rbx_method);
-+ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
++ case _invokebound_mh:
++ {
++ __ movL_OR_Q(rbx_method, Address(rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes()));
++ __ verify_oop(rbx_method);
++ // replace MH with bound receiver (or first static argument):
++ __ movL_OR_Q(rcx_recv, Address(rcx_recv, java_dyn_MethodHandle::receiver_offset_in_bytes()));
++ Address recv_arg_slot = find_mh_argument(_masm, rax_mtype, rsi_savedsp, -1, rax_mtype);
++ __ movL_OR_Q(recv_arg_slot, rcx_recv);
++ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
++ }
+ break;
+
+ case _invokevirtual_mh:
@@ -3664,9 +3744,9 @@ new file mode 100644
+ // minus the CP setup and profiling:
+
+ // pick out the vtable index from the MH, and then we can discard it:
-+ __ movl(rbx_index, Address(rcx_recv, java_dyn_MethodHandle::vmdata_offset_in_bytes()));
-+
-+ load_mh_receiver(_masm, rax_mtype, rsi_savedsp, rcx_recv);
++ __ movL_OR_Q(rbx_index, Address(rcx_recv, java_dyn_MethodHandle::vmdata_offset_in_bytes()));
++
++ __ movL_OR_Q(rcx_recv, find_mh_argument(_masm, rax_mtype, rsi_savedsp, 0, rcx_recv));
+ __ null_check(rcx_recv, oopDesc::klass_offset_in_bytes());
+
+ // get receiver klass
@@ -3692,10 +3772,10 @@ new file mode 100644
+ Register rdx_intf = rdx_temp;
+ Register rbx_index = rbx_method;
+
-+ __ movl(rdx_intf, Address(rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes()));
-+ __ movl(rbx_index, Address(rcx_recv, java_dyn_MethodHandle::vmdata_offset_in_bytes()));
-+
-+ load_mh_receiver(_masm, rax_mtype, rsi_savedsp, rcx_recv);
++ __ movL_OR_Q(rdx_intf, Address(rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes()));
++ __ movL_OR_Q(rbx_index, Address(rcx_recv, java_dyn_MethodHandle::vmdata_offset_in_bytes()));
++
++ __ movL_OR_Q(rcx_recv, find_mh_argument(_masm, rax_mtype, rsi_savedsp, 0, rcx_recv));
+
+ // Free up some temps.
+ __ pushl(rcx_recv);
@@ -3710,11 +3790,13 @@ new file mode 100644
+ rbx_method, rax,
+ no_such_interface);
+
++ __ popl(rcx_recv); // restore saved receiver
+ __ verify_oop(rbx_method);
+ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
+ __ hlt();
+
+ __ bind(no_such_interface);
++ __ popl(rcx_recv); // restore saved receiver
+ // Throw an exception.
+ // For historical reasons, it will be IncompatibleClassChangeError.
+ __ should_not_reach_here(); // %%% FIXME NYI
@@ -3731,23 +3813,33 @@ new file mode 100644
+ init_entry(ek, MethodEntry::finish_compiled_entry(_masm, me_cookie));
+}
+
-+// smashes mtype_reg, but first picks out the receiver depth in the stack
-+void MethodHandle::load_mh_receiver(MacroAssembler* _masm,
-+ Register mtype_reg,
-+ Register savedsp_reg,
-+ Register recv_result) {
-+ assert_different_registers(mtype_reg, savedsp_reg, recv_result);
-+
-+ Register temp_reg = mtype_reg;
-+ __ movl(temp_reg, Address(mtype_reg, java_dyn_MethodType::form_offset_in_bytes()));
++// If which_argument is 0, picks out the first argument being passed to the MH,
++// which will be the receiver if the MH is for a non-static method.
++// If which_argument is -1, picks out the stacked method handle itself,
++// which can be overwritten by a bound receiver (for a BMH only).
++//
++// Register arguments:
++// mtype_reg - the type of the current call
++// savedsp_reg - address of the argument stack (points to _last_ argument)
++// addr_temp_reg - temporary used to form the result address (can be mtype_reg)
++Address MethodHandle::find_mh_argument(MacroAssembler* _masm,
++ Register mtype_reg,
++ Register savedsp_reg,
++ int which_argument,
++ Register addr_temp_reg) {
++ assert_different_registers(mtype_reg, savedsp_reg);
++ assert_different_registers(savedsp_reg, addr_temp_reg);
++
++ __ movl(addr_temp_reg, Address(mtype_reg, java_dyn_MethodType::form_offset_in_bytes()));
+
+ // The vmdata contains the number of parameter slots
+ // in the interpreter stack for this kind of call (see MTForm.init).
-+ __ movl(temp_reg, Address(temp_reg, java_dyn_MethodType::Form::vmdata_offset_in_bytes()));
++ __ movl(addr_temp_reg, Address(addr_temp_reg, java_dyn_MethodType::Form::vmdata_offset_in_bytes()));
+
+#ifdef ASSERT
-+ { Label L;
-+ __ testl(temp_reg, temp_reg);
++ if (which_argument >= 0) {
++ Label L;
++ __ testl(addr_temp_reg, addr_temp_reg);
+ __ jccb(Assembler::notZero, L);
+ __ stop("zero parameter count; cannot find receiver");
+ __ bind(L);
@@ -3755,45 +3847,35 @@ new file mode 100644
+#endif
+
+ // cf. TemplateTable::prepare_invoke(), if (load_receiver).
-+ int offset = -Interpreter::expr_offset_in_bytes(1);
-+ __ movl(recv_result, Address(savedsp_reg, temp_reg,
-+ Interpreter::stackElementScale(), offset));
-+ __ verify_oop(recv_result);
++ int offset = -Interpreter::expr_offset_in_bytes(which_argument + 1);
++ return Address(savedsp_reg, addr_temp_reg,
++ Interpreter::stackElementScale(), offset);
+}
+
+
+
+// direct method handles
-+JVM_ENTRY(void, MH_init_DMH(JNIEnv *env, jobject igcls, jobject mh_jh, jobject rmethod_jh, jboolean doDispatch)) {
++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:
+ Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh));
+
-+ // Early returns out of this method leave the DMH
-+ // in a broken state that will throw a WrongMethodTypeException,
-+ // but will not break the JVM:
-+ MethodEntry* me = MethodHandle::entry(MethodHandle::_wrong_method_type);
-+ java_dyn_MethodHandle::set_entry(mh(), me);
++ // 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?
-+ methodHandle m(THREAD, MethodHandle::decode_method(JNIHandles::resolve(rmethod_jh)));
++ int decode_flags = 0;
++ methodHandle m(THREAD,
++ MethodHandle::decode_method(JNIHandles::resolve(rmethod_jh),
++ decode_flags));
+ if (m.is_null()) return; // robustness
-+
-+ // Now inspect the proposed type of this guy.
-+ Handle mtype(THREAD, java_dyn_MethodHandle::type(mh()));
-+ objArrayHandle ptypes(THREAD, java_dyn_MethodType::ptypes(mtype()));
+
+ // The privileged code which invokes this routine should not make
+ // a mistake about types, but it's better to verify.
-+ const char* err = MethodHandle::check_method_receiver(m, mtype, ptypes);
-+
-+ // Check the other arguments for mistypes.
-+ if (err == NULL)
-+ err = MethodHandle::check_method_signature(m, mtype, ptypes, CHECK);
-+
-+ if (err != NULL)
-+ THROW_MSG(vmSymbols::java_dyn_WrongMethodTypeException(), err);
++ MethodHandle::verify_method_type(m, java_dyn_MethodHandle::type(mh()),
++ false, NULL, CHECK);
+
+ // Finally, after safety checks are done, link to the target method.
+ // We will follow the same path as the latter part of
@@ -3802,26 +3884,27 @@ 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 (!doDispatch && m->is_abstract()) return; // robustness
-+
-+ if (doDispatch && Klass::cast(m->method_holder())->is_interface()) {
++ if (!do_dispatch && m->is_abstract()) return; // robustness
++
++ MethodEntry* me = NULL;
++ if (do_dispatch && Klass::cast(m->method_holder())->is_interface()) {
+ // We are simulating an invokeinterface instruction.
+ // (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");
-+ intptr_t index = klassItable::compute_itable_index(m());
++ int index = klassItable::compute_itable_index(m());
+ assert(index >= 0, "");
+ // 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(), (address)index);
++ java_dyn_MethodHandle::set_vmdata_int(mh(), index);
+ me = MethodHandle::entry(MethodHandle::_invokeinterface_mh);
-+ } else if (!doDispatch || m->can_be_statically_bound()) {
++ } 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());
-+ // this does not help dispatch, but it will make it easier to parse this MH:
-+ java_dyn_MethodHandle::set_vmdata(mh(), (address)methodOopDesc::nonvirtual_vtable_index);
++ // this does not help dispatch, but it will make it possible to parse this MH:
++ java_dyn_MethodHandle::set_vmdata_int(mh(), methodOopDesc::nonvirtual_vtable_index);
+ if (m->is_static())
+ me = MethodHandle::entry(MethodHandle::_invokestatic_mh);
+ else
@@ -3830,15 +3913,16 @@ 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.
-+ intptr_t index = m->vtable_index();
++ int index = m->vtable_index();
+ assert(index >= 0, "");
-+ java_dyn_MethodHandle::set_vmdata(mh(), (address)index);
++ java_dyn_MethodHandle::set_vmdata_int(mh(), index);
+ // this does not help dispatch, but it will make decode_method happy:
+ java_dyn_MethodHandle::set_vmref(mh(), m());
+ me = MethodHandle::entry(MethodHandle::_invokevirtual_mh);
+ }
+
-+ assert(MethodHandle::decode_method(mh()) == m(), "properly stored for later decoding");
++ DEBUG_ONLY(int junk);
++ assert(MethodHandle::decode_method(mh(), junk) == m(), "properly stored for later decoding");
+
+ // Done!
+ java_dyn_MethodHandle::set_entry(mh(), me);
@@ -3847,7 +3931,81 @@ new file mode 100644
+
+// bound method handles
+JVM_ENTRY(void, MH_init_BMH(JNIEnv *env, jobject igcls, jobject mh_jh, jobject rmethod_jh, jobject recv_jh)) {
-+ tty->print_cr("*** NYI: BMH");
++ ResourceMark rm; // for error messages
++
++ // This is the guy we are initializing:
++ 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);
++
++ MethodEntry* me = NULL;
++ //java_dyn_MethodHandle::set_vmdata_int(mh(), 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_int(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_OOP(vmSymbols::java_lang_AbstractMethodError());
++ java_dyn_MethodHandle::set_vmref(mh(), disp_m);
++
++ } 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_int(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");
++
++ // Done!
++ java_dyn_MethodHandle::set_entry(mh(), MethodHandle::entry(MethodHandle::_invokebound_mh));
+}
+JVM_END
+
@@ -3879,7 +4037,8 @@ new file mode 100644
+
+// debugging
+JVM_ENTRY(jobject, MH_methodName(JNIEnv *env, jobject igcls, jobject mh_jh)) {
-+ methodHandle m(THREAD, MethodHandle::decode_method(JNIHandles::resolve(mh_jh)));
++ int junk;
++ methodHandle m(THREAD, MethodHandle::decode_method(JNIHandles::resolve(mh_jh), junk));
+ if (m.is_null()) return NULL;
+ Handle str = java_lang_String::create_from_symbol(m->name(), CHECK_NULL);
+ return JNIHandles::make_local(THREAD, str());
@@ -3899,17 +4058,17 @@ new file mode 100644
+
+#define LANG "Ljava/lang/"
+#define DYNP "Ljava/dyn/"
-+#define DYNH "Ljava/dyn/hotspot/"
++#define DYNI "Ljava/dyn/impl/"
+
+#define OBJ LANG"Object;"
+#define CLS LANG"Class;"
+#define STRG LANG"String;"
-+#define MH DYNH"MH;"
-+#define AMH DYNH"AMH;"
-+#define BMH DYNH"BMH;"
-+#define DMH DYNH"DMH;"
++#define MH DYNI"MH;"
++#define AMH DYNI"AMH;"
++#define BMH DYNI"BMH;"
++#define DMH DYNI"DMH;"
+#define MT DYNP"MethodType;"
-+#define MTFM DYNH"MTForm;"
++#define MTFM DYNI"MTForm;"
+
+#define CC (char*) /*cast a literal from (const char*)*/
+#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
@@ -3934,7 +4093,7 @@ new file mode 100644
+ int status = env->RegisterNatives(mhcls, methods, sizeof(methods)/sizeof(JNINativeMethod));
+ if (env->ExceptionOccurred()) {
+ if (PrintMiscellaneous && (Verbose || WizardMode)) {
-+ tty->print_cr("Warning: java.dyn.hotspot.MH not found.");
++ tty->print_cr("Warning: java.dyn.impl.MH not found.");
+ }
+ env->ExceptionClear();
+ }
@@ -3944,7 +4103,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/vm/prims/methodHandles.hpp
-@@ -0,0 +1,155 @@
+@@ -0,0 +1,177 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -3985,6 +4144,7 @@ new file mode 100644
+ _invokespecial_mh, // ditto for the other invokes...
+ _invokevirtual_mh,
+ _invokeinterface_mh,
++ _invokebound_mh, // invokespecial, with a saved receiver
+ _EK_LIMIT,
+ _EK_FIRST = 0
+ };
@@ -4009,7 +4169,7 @@ new file mode 100644
+ static inline address from_compiled_entry(EntryKind ek);
+ static inline address from_interpreted_entry(EntryKind ek);
+
-+public:
++ public:
+ // called from InterpreterGenerator and StubGenerator
+ static address generate_method_handle_interpreter_entry(MacroAssembler* _masm, Label& wrong_method_type);
+ static void generate_method_handle_stub(MacroAssembler* _masm, EntryKind ek);
@@ -4017,14 +4177,35 @@ new file mode 100644
+ // Lower level calls:
+ static void check_method_type(MacroAssembler* _masm, Register mtype_reg, Register recv_reg, Label& wrong_method_type);
+ static void jump_to_entry(MacroAssembler* _masm, Register recv_reg, Register temp_reg);
-+ static void load_mh_receiver(MacroAssembler* _masm,
-+ Register mtype_reg, Register savedsp_reg, Register recv_result);
++ static Address find_mh_argument(MacroAssembler* _masm,
++ Register mtype_reg,
++ Register savedsp_reg,
++ int which_argument,
++ Register addr_temp_reg);
+
+ // Runtime support
-+ static methodOop decode_method(oop x);
++ enum { // bit-encoded flags from decode_method
++ _dmf_does_dispatch = 1, // method handle performs virtual or interface dispatch
++ _dmf_is_interface = 2, // peforms interface dispatch
++ _dmf_has_receiver = 4,
++ _dmf_has_casts = 8
++ };
++ static methodOop decode_method(oop x, int& decode_flags_result);
+ static bool class_cast_needed(klassOop src, klassOop dst);
-+ static const char* check_method_receiver(methodHandle m, Handle mtype, objArrayHandle ptypes);
-+ static const char* check_method_signature(methodHandle m, Handle mtype, objArrayHandle ptypes, TRAPS);
++
++ static void verify_method_type(methodHandle m,
++ oop mtype,
++ bool has_bound_oop,
++ klassOop bound_oop_type,
++ TRAPS);
++
++ 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)
@@ -4116,7 +4297,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_hotspot_MH_registerNatives") != NULL) {
++ if (strstr(jni_name, "Java_java_dyn_impl_MH_registerNatives") != NULL) {
+ return CAST_FROM_FN_PTR(address, JVM_RegisterMethodHandleMethods);
}
if (strstr(jni_name, "Java_sun_misc_Perf_registerNatives") != NULL) {