--- a/indy.patch Fri Jun 19 21:32:37 2009 -0700
+++ b/indy.patch Sat Jun 20 23:56:24 2009 -0700
@@ -1,5 +1,233 @@ changes entrained after 6655646 appear i
changes entrained after 6655646 appear in indy.patch proper
+diff --git a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
+--- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
++++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
+@@ -150,8 +150,7 @@
+ }
+
+
+-address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, bool unbox) {
+- assert(!unbox, "NYI");//6815692//
++address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step) {
+ address compiled_entry = __ pc();
+ Label cont;
+
+diff --git a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
+--- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
++++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
+@@ -156,15 +156,8 @@
+ }
+
+
+-address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, bool unbox) {
++address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step) {
+ TosState incoming_state = state;
+- if (EnableInvokeDynamic) {
+- if (unbox) {
+- incoming_state = atos;
+- }
+- } else {
+- assert(!unbox, "old behavior");
+- }
+
+ Label interpreter_entry;
+ address compiled_entry = __ pc();
+@@ -217,46 +210,6 @@
+ __ restore_bcp();
+ __ restore_locals();
+
+- Label L_fail;
+-
+- if (unbox && state != atos) {
+- // cast and unbox
+- BasicType type = as_BasicType(state);
+- if (type == T_BYTE) type = T_BOOLEAN; // FIXME
+- KlassHandle boxk = SystemDictionaryHandles::box_klass(type);
+- __ mov32(rbx, ExternalAddress((address) boxk.raw_value()));
+- __ testl(rax, rax);
+- Label L_got_value, L_get_value;
+- // convert nulls to zeroes (avoid NPEs here)
+- if (!(type == T_FLOAT || type == T_DOUBLE)) {
+- // if rax already contains zero bits, forge ahead
+- __ jcc(Assembler::zero, L_got_value);
+- } else {
+- __ jcc(Assembler::notZero, L_get_value);
+- __ fldz();
+- __ jmp(L_got_value);
+- }
+- __ bind(L_get_value);
+- __ cmp32(rbx, Address(rax, oopDesc::klass_offset_in_bytes()));
+- __ jcc(Assembler::notEqual, L_fail);
+- int offset = java_lang_boxing_object::value_offset_in_bytes(type);
+- // Cf. TemplateTable::getfield_or_static
+- switch (type) {
+- case T_BYTE: // fall through:
+- case T_BOOLEAN: __ load_signed_byte(rax, Address(rax, offset)); break;
+- case T_CHAR: __ load_unsigned_short(rax, Address(rax, offset)); break;
+- case T_SHORT: __ load_signed_short(rax, Address(rax, offset)); break;
+- case T_INT: __ movl(rax, Address(rax, offset)); break;
+- case T_FLOAT: __ fld_s(Address(rax, offset)); break;
+- case T_DOUBLE: __ fld_d(Address(rax, offset)); break;
+- // Access to java.lang.Double.value does not need to be atomic:
+- case T_LONG: { __ movl(rdx, Address(rax, offset + 4));
+- __ movl(rax, Address(rax, offset + 0)); } break;
+- default: ShouldNotReachHere();
+- }
+- __ bind(L_got_value);
+- }
+-
+ Label L_got_cache, L_giant_index;
+ if (EnableInvokeDynamic) {
+ __ cmpb(Address(rsi, 0), Bytecodes::_invokedynamic);
+@@ -264,32 +217,6 @@
+ }
+ __ get_cache_and_index_at_bcp(rbx, rcx, 1, false);
+ __ bind(L_got_cache);
+- if (unbox && state == atos) {
+- // insert a casting conversion, to keep verifier sane
+- Label L_ok, L_ok_pops;
+- __ testl(rax, rax);
+- __ jcc(Assembler::zero, L_ok);
+- __ push(rax); // save the object to check
+- __ push(rbx); // save CP cache reference
+- __ movl(rdx, Address(rax, oopDesc::klass_offset_in_bytes()));
+- __ movl(rbx, Address(rbx, rcx,
+- Address::times_4, constantPoolCacheOopDesc::base_offset() +
+- ConstantPoolCacheEntry::f1_offset()));
+- __ movl(rbx, Address(rbx, __ delayed_value(sun_dyn_CallSiteImpl::type_offset_in_bytes, rcx)));
+- __ movl(rbx, Address(rbx, __ delayed_value(java_dyn_MethodType::rtype_offset_in_bytes, rcx)));
+- __ movl(rax, Address(rbx, __ delayed_value(java_lang_Class::klass_offset_in_bytes, rcx)));
+- __ check_klass_subtype(rdx, rax, rbx, L_ok_pops);
+- __ pop(rcx); // pop and discard CP cache
+- __ mov(rbx, rax); // target supertype into rbx for L_fail
+- __ pop(rax); // failed object into rax for L_fail
+- __ jmp(L_fail);
+-
+- __ bind(L_ok_pops);
+- // restore pushed temp regs:
+- __ pop(rbx);
+- __ pop(rax);
+- __ bind(L_ok);
+- }
+ __ movl(rbx, Address(rbx, rcx,
+ Address::times_ptr, constantPoolCacheOopDesc::base_offset() +
+ ConstantPoolCacheEntry::flags_offset()));
+@@ -302,14 +229,6 @@
+ __ bind(L_giant_index);
+ __ get_cache_and_index_at_bcp(rbx, rcx, 1, true);
+ __ jmp(L_got_cache);
+-
+- if (unbox) {
+- __ bind(L_fail);
+- __ push(rbx); // missed klass (required)
+- __ push(rax); // bad object (actual)
+- __ movptr(rdx, ExternalAddress((address) &Interpreter::_throw_WrongMethodType_entry));
+- __ call(rdx);
+- }
+ }
+
+ return entry;
+diff --git a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
+--- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
++++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
+@@ -166,8 +166,7 @@
+
+
+ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
+- int step, bool unbox) {
+- assert(!unbox, "NYI");//6815692//
++ int step) {
+
+ // amd64 doesn't need to do anything special about compiled returns
+ // to the interpreter so the code that exists on x86 to place a sentinel
+diff --git a/src/cpu/x86/vm/templateTable_x86_32.cpp b/src/cpu/x86/vm/templateTable_x86_32.cpp
+--- a/src/cpu/x86/vm/templateTable_x86_32.cpp
++++ b/src/cpu/x86/vm/templateTable_x86_32.cpp
+@@ -2890,9 +2890,6 @@
+
+
+ void TemplateTable::prepare_invoke(Register method, Register index, int byte_no) {
+- bool is_invdyn_bootstrap = (byte_no < 0);
+- if (is_invdyn_bootstrap) byte_no = -byte_no;
+-
+ // determine flags
+ Bytecodes::Code code = bytecode();
+ const bool is_invokeinterface = code == Bytecodes::_invokeinterface;
+@@ -2907,8 +2904,6 @@
+ const Register flags = rdx;
+ assert_different_registers(method, index, recv, flags);
+
+- assert(!is_invdyn_bootstrap || is_invokedynamic, "byte_no<0 hack only for invdyn");
+-
+ // save 'interpreter return address'
+ __ save_bcp();
+
+@@ -2944,9 +2939,7 @@
+ // load return address
+ {
+ address table_addr;
+- if (is_invdyn_bootstrap)
+- table_addr = (address)Interpreter::return_5_unbox_addrs_by_index_table();
+- else if (is_invokeinterface || is_invokedynamic)
++ if (is_invokeinterface || is_invokedynamic)
+ table_addr = (address)Interpreter::return_5_addrs_by_index_table();
+ else
+ table_addr = (address)Interpreter::return_3_addrs_by_index_table();
+@@ -3155,52 +3148,9 @@
+
+ Label handle_unlinked_site;
+ __ movptr(rcx, Address(rax, __ delayed_value(sun_dyn_CallSiteImpl::target_offset_in_bytes, rcx)));
+- __ testptr(rcx, rcx);
+- __ jcc(Assembler::zero, handle_unlinked_site);
+-
++ __ null_check(rcx);
+ __ prepare_to_jump_from_interpreted();
+ __ jump_to_method_handle_entry(rcx, rdx);
+-
+- // Initial calls come here...
+- __ bind(handle_unlinked_site);
+- __ pop(rcx); // remove return address pushed by prepare_invoke
+-
+- // box stacked arguments into an array for the bootstrap method
+- address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::bootstrap_invokedynamic);
+- __ restore_bcp(); // rsi must be correct for call_VM
+- __ call_VM(rax, entry, rax);
+- __ movl(rdi, rax); // protect bootstrap MH from prepare_invoke
+-
+- // recompute return address
+- __ restore_bcp(); // rsi must be correct for prepare_invoke
+- prepare_invoke(rax, rbx, -byte_no); // smashes rcx, rdx
+- // rax: CallSite object (f1)
+- // rbx: unused (f2)
+- // rdi: bootstrap MH
+- // rdx: flags
+-
+- // now load up the arglist, which has been neatly boxed
+- __ get_thread(rcx);
+- __ movptr(rdx, Address(rcx, JavaThread::vm_result_2_offset()));
+- __ movptr(Address(rcx, JavaThread::vm_result_2_offset()), NULL_WORD);
+- __ verify_oop(rdx);
+- // rdx = arglist
+-
+- // save SP now, before we add the bootstrap call to the stack
+- // We must preserve a fiction that the original arguments are outgoing,
+- // because the return sequence will reset the stack to this point
+- // and then pop all those arguments. It seems error-prone to use
+- // a different argument list size just for bootstrapping.
+- __ prepare_to_jump_from_interpreted();
+-
+- // Now let's play adapter, pushing the real arguments on the stack.
+- __ pop(rbx); // return PC
+- __ push(rdi); // boot MH
+- __ push(rax); // call site
+- __ push(rdx); // arglist
+- __ push(rbx); // return PC, again
+- __ mov(rcx, rdi);
+- __ jump_to_method_handle_entry(rcx, rdx);
+ }
+
+ //----------------------------------------------------------------------------------------------------
diff --git a/src/share/vm/interpreter/bytecodeTracer.cpp b/src/share/vm/interpreter/bytecodeTracer.cpp
--- a/src/share/vm/interpreter/bytecodeTracer.cpp
+++ b/src/share/vm/interpreter/bytecodeTracer.cpp
@@ -30,6 +258,204 @@ diff --git a/src/share/vm/interpreter/by
st->print_cr(" %d <%s> <%s> ", i, name->as_C_string(), signature->as_C_string());
}
+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
+@@ -758,56 +758,6 @@
+ IRT_END
+
+
+-// Called on first time execution, and also whenever the CallSite.target is null.
+-// FIXME: Do more of this in Java code.
+-IRT_ENTRY(void, InterpreterRuntime::bootstrap_invokedynamic(JavaThread* thread, oopDesc* call_site)) {
+- methodHandle mh_invdyn(thread, (methodOop) sun_dyn_CallSiteImpl::vmmethod(call_site));
+- Handle mh_type(thread, mh_invdyn->method_handle_type());
+- objArrayHandle mh_ptypes(thread, java_dyn_MethodType::ptypes(mh_type()));
+-
+- // squish the arguments down to a single array
+- int nargs = mh_ptypes->length();
+- objArrayHandle arg_array;
+- {
+- objArrayOop aaoop = oopFactory::new_objArray(SystemDictionary::object_klass(), nargs, CHECK);
+- arg_array = objArrayHandle(thread, aaoop);
+- }
+- frame fr = thread->last_frame();
+- assert(fr.interpreter_frame_bcp() != NULL, "sanity");
+- int tos_offset = 0;
+- for (int i = nargs; --i >= 0; ) {
+- intptr_t* slot_addr = fr.interpreter_frame_tos_at(tos_offset++);
+- oop ptype = mh_ptypes->obj_at(i);
+- oop arg = NULL;
+- if (!java_lang_Class::is_primitive(ptype)) {
+- arg = *(oop*) slot_addr;
+- } else {
+- BasicType bt = java_lang_Class::primitive_type(ptype);
+- assert(frame::interpreter_frame_expression_stack_direction() < 0, "else reconsider this code");
+- jvalue value;
+- Interpreter::get_jvalue_in_slot(slot_addr, bt, &value);
+- tos_offset += type2size[bt]-1;
+- arg = java_lang_boxing_object::create(bt, &value, CHECK);
+- // FIXME: These boxing objects are not canonicalized under
+- // the Java autoboxing rules. They should be...
+- // The best approach would be to push the arglist creation into Java.
+- // The JVM should use a lower-level interface to communicate argument lists.
+- }
+- arg_array->obj_at_put(i, arg);
+- }
+-
+- // now find the bootstrap method
+- oop bootstrap_mh_oop = instanceKlass::cast(fr.interpreter_frame_method()->method_holder())->bootstrap_method();
+- assert(bootstrap_mh_oop != NULL, "resolve_invokedynamic ensures a BSM");
+-
+- // return the bootstrap method and argument array via vm_result/_2
+- thread->set_vm_result(bootstrap_mh_oop);
+- thread->set_vm_result_2(arg_array());
+-}
+-IRT_END
+-
+-
+-
+ //------------------------------------------------------------------------------------------------------------------------
+ // Miscellaneous
+
+diff --git a/src/share/vm/interpreter/interpreterRuntime.hpp b/src/share/vm/interpreter/interpreterRuntime.hpp
+--- a/src/share/vm/interpreter/interpreterRuntime.hpp
++++ b/src/share/vm/interpreter/interpreterRuntime.hpp
+@@ -88,7 +88,6 @@
+ // Calls
+ static void resolve_invoke (JavaThread* thread, Bytecodes::Code bytecode);
+ static void resolve_invokedynamic(JavaThread* thread);
+- static void bootstrap_invokedynamic(JavaThread* thread, oopDesc* call_site);
+
+ // Breakpoints
+ static void _breakpoint(JavaThread* thread, methodOopDesc* method, address bcp);
+diff --git a/src/share/vm/interpreter/templateInterpreter.cpp b/src/share/vm/interpreter/templateInterpreter.cpp
+--- a/src/share/vm/interpreter/templateInterpreter.cpp
++++ b/src/share/vm/interpreter/templateInterpreter.cpp
+@@ -178,14 +178,12 @@
+ #endif // !PRODUCT
+ EntryPoint TemplateInterpreter::_return_entry[TemplateInterpreter::number_of_return_entries];
+ EntryPoint TemplateInterpreter::_earlyret_entry;
+-EntryPoint TemplateInterpreter::_return_unbox_entry;
+ EntryPoint TemplateInterpreter::_deopt_entry [TemplateInterpreter::number_of_deopt_entries ];
+ EntryPoint TemplateInterpreter::_continuation_entry;
+ EntryPoint TemplateInterpreter::_safept_entry;
+
+ address TemplateInterpreter::_return_3_addrs_by_index[TemplateInterpreter::number_of_return_addrs];
+ address TemplateInterpreter::_return_5_addrs_by_index[TemplateInterpreter::number_of_return_addrs];
+-address TemplateInterpreter::_return_5_unbox_addrs_by_index[TemplateInterpreter::number_of_return_addrs];
+
+ DispatchTable TemplateInterpreter::_active_table;
+ DispatchTable TemplateInterpreter::_normal_table;
+@@ -253,22 +251,6 @@
+ }
+ }
+
+- if (EnableInvokeDynamic) {
+- CodeletMark cm(_masm, "unboxing return entry points");
+- Interpreter::_return_unbox_entry =
+- EntryPoint(
+- generate_return_unbox_entry_for(btos, 5),
+- generate_return_unbox_entry_for(ctos, 5),
+- generate_return_unbox_entry_for(stos, 5),
+- generate_return_unbox_entry_for(atos, 5), // cast conversion
+- generate_return_unbox_entry_for(itos, 5),
+- generate_return_unbox_entry_for(ltos, 5),
+- generate_return_unbox_entry_for(ftos, 5),
+- generate_return_unbox_entry_for(dtos, 5),
+- Interpreter::_return_entry[5].entry(vtos) // no unboxing for void
+- );
+- }
+-
+ { CodeletMark cm(_masm, "earlyret entry points");
+ Interpreter::_earlyret_entry =
+ EntryPoint(
+@@ -319,8 +301,6 @@
+ int index = Interpreter::TosState_as_index(states[j]);
+ Interpreter::_return_3_addrs_by_index[index] = Interpreter::return_entry(states[j], 3);
+ Interpreter::_return_5_addrs_by_index[index] = Interpreter::return_entry(states[j], 5);
+- if (EnableInvokeDynamic)
+- Interpreter::_return_5_unbox_addrs_by_index[index] = Interpreter::return_unbox_entry(states[j], 5);
+ }
+
+ { CodeletMark cm(_masm, "continuation entry points");
+@@ -547,18 +527,6 @@
+ }
+
+
+-address TemplateInterpreter::return_unbox_entry(TosState state, int length) {
+- assert(EnableInvokeDynamic, "");
+- if (state == vtos) {
+- // no unboxing to do, actually
+- return return_entry(state, length);
+- } else {
+- assert(length == 5, "unboxing entries generated for invokedynamic only");
+- return _return_unbox_entry.entry(state);
+- }
+-}
+-
+-
+ address TemplateInterpreter::deopt_entry(TosState state, int length) {
+ guarantee(0 <= length && length < Interpreter::number_of_deopt_entries, "illegal length");
+ return _deopt_entry[length].entry(state);
+diff --git a/src/share/vm/interpreter/templateInterpreter.hpp b/src/share/vm/interpreter/templateInterpreter.hpp
+--- a/src/share/vm/interpreter/templateInterpreter.hpp
++++ b/src/share/vm/interpreter/templateInterpreter.hpp
+@@ -110,14 +110,12 @@
+ #endif // !PRODUCT
+ static EntryPoint _return_entry[number_of_return_entries]; // entry points to return to from a call
+ static EntryPoint _earlyret_entry; // entry point to return early from a call
+- static EntryPoint _return_unbox_entry; // entry point to unbox a return value from a call
+ static EntryPoint _deopt_entry[number_of_deopt_entries]; // entry points to return to from a deoptimization
+ static EntryPoint _continuation_entry;
+ static EntryPoint _safept_entry;
+
+ static address _return_3_addrs_by_index[number_of_return_addrs]; // for invokevirtual return entries
+ static address _return_5_addrs_by_index[number_of_return_addrs]; // for invokeinterface return entries
+- static address _return_5_unbox_addrs_by_index[number_of_return_addrs]; // for invokedynamic bootstrap methods
+
+ static DispatchTable _active_table; // the active dispatch table (used by the interpreter for dispatch)
+ static DispatchTable _normal_table; // the normal dispatch table (used to set the active table in normal mode)
+@@ -160,12 +158,10 @@
+ // Support for invokes
+ static address* return_3_addrs_by_index_table() { return _return_3_addrs_by_index; }
+ static address* return_5_addrs_by_index_table() { return _return_5_addrs_by_index; }
+- static address* return_5_unbox_addrs_by_index_table() { return _return_5_unbox_addrs_by_index; }
+ static int TosState_as_index(TosState state); // computes index into return_3_entry_by_index table
+
+ static address return_entry (TosState state, int length);
+ static address deopt_entry (TosState state, int length);
+- static address return_unbox_entry(TosState state, int length);
+
+ // Safepoint support
+ static void notice_safepoints(); // stops the thread when reaching a safepoint
+diff --git a/src/share/vm/interpreter/templateInterpreterGenerator.hpp b/src/share/vm/interpreter/templateInterpreterGenerator.hpp
+--- a/src/share/vm/interpreter/templateInterpreterGenerator.hpp
++++ b/src/share/vm/interpreter/templateInterpreterGenerator.hpp
+@@ -51,10 +51,7 @@
+ address generate_WrongMethodType_handler();
+ address generate_ArrayIndexOutOfBounds_handler(const char* name);
+ address generate_continuation_for(TosState state);
+- address generate_return_entry_for(TosState state, int step, bool unbox = false);
+- address generate_return_unbox_entry_for(TosState state, int step) {
+- return generate_return_entry_for(state, step, true);
+- }
++ address generate_return_entry_for(TosState state, int step);
+ address generate_earlyret_entry_for(TosState state);
+ address generate_deopt_entry_for(TosState state, int step);
+ address generate_safept_entry_for(TosState state, address runtime_entry);
+diff --git a/src/share/vm/oops/cpCacheOop.cpp b/src/share/vm/oops/cpCacheOop.cpp
+--- a/src/share/vm/oops/cpCacheOop.cpp
++++ b/src/share/vm/oops/cpCacheOop.cpp
+@@ -226,7 +226,7 @@
+ methodOop method = (methodOop) sun_dyn_CallSiteImpl::vmmethod(call_site());
+ assert(method->is_method(), "must be initialized properly");
+ int param_size = method->size_of_parameters();
+- assert(param_size > 1, "method argument size must include MH.this & initial dynamic receiver");
++ assert(param_size >= 1, "method argument size must include MH.this");
+ param_size -= 1; // do not count MH.this; it is not stacked for invokedynamic
+ if (Atomic::cmpxchg_ptr(call_site(), &_f1, NULL) == NULL) {
+ // racing threads might be trying to install their own favorites
diff --git a/src/share/vm/oops/generateOopMap.cpp b/src/share/vm/oops/generateOopMap.cpp
--- a/src/share/vm/oops/generateOopMap.cpp
+++ b/src/share/vm/oops/generateOopMap.cpp
--- a/meth.patch Fri Jun 19 21:32:37 2009 -0700
+++ b/meth.patch Sat Jun 20 23:56:24 2009 -0700
@@ -1,5 +1,53 @@ changes entrained after 6655638 appear i
changes entrained after 6655638 appear in meth.patch proper
+diff --git a/src/cpu/x86/vm/methodHandles_x86.cpp b/src/cpu/x86/vm/methodHandles_x86.cpp
+--- a/src/cpu/x86/vm/methodHandles_x86.cpp
++++ b/src/cpu/x86/vm/methodHandles_x86.cpp
+@@ -524,6 +524,7 @@
+ break;
+
+ case _adapter_retype_only:
++ case _adapter_retype_raw:
+ // immediately jump to the next MH layer:
+ __ movptr(rcx_recv, rcx_mh_vmtarget);
+ __ verify_oop(rcx_recv);
+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
+@@ -903,19 +903,20 @@
+ // Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants):
+ enum {
+ OP_RETYPE_ONLY = 0x0, // no argument changes; straight retype
+- OP_CHECK_CAST = 0x1, // ref-to-ref conversion; requires a Class argument
+- OP_PRIM_TO_PRIM = 0x2, // converts from one primitive to another
+- OP_REF_TO_PRIM = 0x3, // unboxes a wrapper to produce a primitive
+- OP_PRIM_TO_REF = 0x4, // boxes a primitive into a wrapper (NYI)
+- OP_SWAP_ARGS = 0x5, // swap arguments (vminfo is 2nd arg)
+- OP_ROT_ARGS = 0x6, // rotate arguments (vminfo is displaced arg)
+- OP_DUP_ARGS = 0x7, // duplicates one or more arguments (at TOS)
+- OP_DROP_ARGS = 0x8, // remove one or more argument slots
+- OP_COLLECT_ARGS = 0x9, // combine one or more arguments into a varargs (NYI)
+- OP_SPREAD_ARGS = 0xA, // expand in place a varargs array (of known size)
+- OP_FLYBY = 0xB, // operate first on reified argument list (NYI)
+- OP_RICOCHET = 0xC, // run an adapter chain on the return value (NYI)
+- CONV_OP_LIMIT = 0xD, // limit of CONV_OP enumeration
++ OP_RETYPE_RAW = 0x1, // straight retype, trusted (void->int, Object->T)
++ OP_CHECK_CAST = 0x2, // ref-to-ref conversion; requires a Class argument
++ OP_PRIM_TO_PRIM = 0x3, // converts from one primitive to another
++ OP_REF_TO_PRIM = 0x4, // unboxes a wrapper to produce a primitive
++ OP_PRIM_TO_REF = 0x5, // boxes a primitive into a wrapper (NYI)
++ OP_SWAP_ARGS = 0x6, // swap arguments (vminfo is 2nd arg)
++ OP_ROT_ARGS = 0x7, // rotate arguments (vminfo is displaced arg)
++ OP_DUP_ARGS = 0x8, // duplicates one or more arguments (at TOS)
++ OP_DROP_ARGS = 0x9, // remove one or more argument slots
++ OP_COLLECT_ARGS = 0xA, // combine one or more arguments into a varargs (NYI)
++ OP_SPREAD_ARGS = 0xB, // expand in place a varargs array (of known size)
++ OP_FLYBY = 0xC, // operate first on reified argument list (NYI)
++ OP_RICOCHET = 0xD, // run an adapter chain on the return value (NYI)
++ CONV_OP_LIMIT = 0xE, // limit of CONV_OP enumeration
+
+ CONV_OP_MASK = 0xF00, // this nybble contains the conversion op field
+ CONV_VMINFO_MASK = 0x0FF, // LSB is reserved for JVM use
diff --git a/src/share/vm/interpreter/templateInterpreter.hpp b/src/share/vm/interpreter/templateInterpreter.hpp
--- a/src/share/vm/interpreter/templateInterpreter.hpp
+++ b/src/share/vm/interpreter/templateInterpreter.hpp
@@ -31,7 +79,15 @@ diff --git a/src/share/vm/prims/methodHa
diff --git a/src/share/vm/prims/methodHandles.cpp b/src/share/vm/prims/methodHandles.cpp
--- a/src/share/vm/prims/methodHandles.cpp
+++ b/src/share/vm/prims/methodHandles.cpp
-@@ -157,7 +157,8 @@
+@@ -48,6 +48,7 @@
+
+ // starting at _adapter_mh_first:
+ "adapter_retype_only", // these are for AMH...
++ "adapter_retype_raw",
+ "adapter_check_cast",
+ "adapter_prim_to_prim",
+ "adapter_ref_to_prim",
+@@ -157,7 +158,8 @@
}
methodOop MethodHandles::decode_BoundMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
@@ -41,6 +97,18 @@ diff --git a/src/share/vm/prims/methodHa
for (oop bmh = mh;;) {
// Bound MHs can be stacked to bind several arguments.
oop target = java_dyn_MethodHandle::vmtarget(bmh);
+@@ -174,10 +176,9 @@
+ } else {
+ // Optimized case: binding a receiver to a non-dispatched DMH
+ // short-circuits directly to the methodOop.
++ // (It might be another argument besides a receiver also.)
+ assert(target->is_method(), "must be a simple method");
+ methodOop m = (methodOop) target;
+- DEBUG_ONLY(int argslot = sun_dyn_BoundMethodHandle::vmargslot(bmh));
+- assert(argslot == m->size_of_parameters() - 1, "must be initial argument (receiver)");
+ decode_flags_result |= MethodHandles::_dmf_binds_method;
+ return m;
+ }
@@ -214,6 +215,9 @@
return decode_BoundMethodHandle(mh, receiver_limit_result, decode_flags_result);
} else if (mhk == SystemDictionary::AdapterMethodHandle_klass()) {
@@ -51,7 +119,287 @@ diff --git a/src/share/vm/prims/methodHa
} else {
assert(false, "cannot parse this MH");
return NULL; // random MH?
-@@ -2133,7 +2137,7 @@
+@@ -366,7 +370,13 @@
+ oop vmtarget = sun_dyn_MemberName::vmtarget(mname);
+ int vmindex = sun_dyn_MemberName::vmindex(mname);
+ if (vmindex == VM_INDEX_UNINITIALIZED) return NULL; // not resolved
+- return decode_vmtarget(vmtarget, vmindex, NULL, receiver_limit_result, decode_flags_result);
++ methodOop m = decode_vmtarget(vmtarget, vmindex, NULL, receiver_limit_result, decode_flags_result);
++ oop clazz = sun_dyn_MemberName::clazz(mname);
++ if (clazz != NULL && java_lang_Class::is_instance(clazz)) {
++ klassOop klass = java_lang_Class::as_klassOop(clazz);
++ if (klass != NULL) receiver_limit_result = klass;
++ }
++ return m;
+ }
+
+ // An unresolved member name is a mere symbolic reference.
+@@ -789,6 +799,30 @@
+ THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), msg);
+ }
+
++static const char* always_null_names[] = {
++ "java/lang/Void",
++ "java/lang/Null",
++ //"java/lang/Nothing",
++ "sun/dyn/empty/Empty",
++ NULL
++};
++
++static bool is_always_null_type(klassOop klass) {
++ if (!Klass::cast(klass)->oop_is_instance()) return false;
++ instanceKlass* ik = instanceKlass::cast(klass);
++ // Must be on the boot class path:
++ if (ik->class_loader() != NULL) return false;
++ // Check the name.
++ symbolOop name = ik->name();
++ for (int i = 0; ; i++) {
++ const char* test_name = always_null_names[i];
++ if (test_name == NULL) break;
++ if (name->equals(test_name, strlen(test_name)))
++ return true;
++ }
++ return false;
++}
++
+ bool MethodHandles::class_cast_needed(klassOop src, klassOop dst) {
+ if (src == dst || dst == SystemDictionary::object_klass())
+ return false; // quickest checks
+@@ -805,6 +839,12 @@
+ //srck = Klass::cast(SystemDictionary::object_klass());
+ return true;
+ }
++ if (is_always_null_type(src)) {
++ // some source types are known to be never instantiated;
++ // they represent references which are always null
++ // such null references never fail to convert safely
++ return false;
++ }
+ return !srck->is_subclass_of(dstk->as_klassOop());
+ }
+
+@@ -814,9 +854,15 @@
+
+ bool MethodHandles::same_basic_type_for_arguments(BasicType src,
+ BasicType dst,
++ bool raw,
+ bool for_return) {
+- // return values can always be forgotten:
+- if (for_return && dst == T_VOID) return true;
++ if (for_return) {
++ // return values can always be forgotten:
++ if (dst == T_VOID) return true;
++ if (src == T_VOID) return raw && (dst == T_INT);
++ // We allow caller to receive a garbage int, which is harmless.
++ // This trick is pulled by trusted code (see VerifyType.canPassRaw).
++ }
+ assert(src != T_VOID && dst != T_VOID, "should not be here");
+ if (src == dst) return true;
+ if (type2size[src] != type2size[dst]) return false;
+@@ -929,8 +975,8 @@
+ const char* err = NULL;
+
+ int first_ptype_pos = m_needs_receiver ? 1 : 0;
+- if (has_bound_recv && err == NULL) {
+- first_ptype_pos -= 1;
++ if (has_bound_recv) {
++ first_ptype_pos -= 1; // ptypes do not include the bound argument; start earlier in them
+ if (m_needs_receiver && bound_recv_type.is_null())
+ { err = "bound receiver is not an object"; goto die; }
+ }
+@@ -939,10 +985,10 @@
+ objArrayOop ptypes = java_dyn_MethodType::ptypes(mtype());
+ if (ptypes->length() < first_ptype_pos)
+ { err = "receiver argument is missing"; goto die; }
+- if (first_ptype_pos == -1)
++ if (has_bound_recv)
+ err = check_method_receiver(m(), bound_recv_type->as_klassOop());
+ else
+- err = check_method_receiver(m(), java_lang_Class::as_klassOop(ptypes->obj_at(0)));
++ err = check_method_receiver(m(), java_lang_Class::as_klassOop(ptypes->obj_at(first_ptype_pos-1)));
+ if (err != NULL) goto die;
+ }
+
+@@ -983,7 +1029,8 @@
+ int insert_argnum, oop insert_type,
+ int change_argnum, oop change_type,
+ int delete_argnum,
+- oop dst_mtype, int dst_beg, int dst_end) {
++ oop dst_mtype, int dst_beg, int dst_end,
++ bool raw) {
+ objArrayOop src_ptypes = java_dyn_MethodType::ptypes(src_mtype);
+ objArrayOop dst_ptypes = java_dyn_MethodType::ptypes(dst_mtype);
+
+@@ -1042,7 +1089,7 @@
+ if (src_type != dst_type) {
+ if (src_type == NULL) return "not enough arguments";
+ if (dst_type == NULL) return "too many arguments";
+- err = check_argument_type_change(src_type, dst_type, dst_idx);
++ err = check_argument_type_change(src_type, dst_type, dst_idx, raw);
+ if (err != NULL) return err;
+ }
+ }
+@@ -1051,7 +1098,7 @@
+ 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!
++ err = check_return_type_change(dst_rtype, src_rtype, raw); // note reversal!
+ if (err != NULL) return err;
+ }
+
+@@ -1061,38 +1108,45 @@
+
+
+ const char* MethodHandles::check_argument_type_change(BasicType src_type,
+- klassOop src_klass,
+- BasicType dst_type,
+- klassOop dst_klass,
+- int argnum) {
++ klassOop src_klass,
++ BasicType dst_type,
++ klassOop dst_klass,
++ int argnum,
++ bool raw) {
+ const char* err = NULL;
++ bool for_return = (argnum < 0);
+
+ // 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 (!same_basic_type_for_arguments(src_type, dst_type, raw, for_return)) {
+ if (src_type == T_OBJECT) {
++ if (raw && dst_type == T_INT && is_always_null_type(src_klass))
++ return NULL; // OK to convert a null pointer to a garbage int
+ 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)
++ 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)
++ 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)) {
++ } else if (src_type == T_OBJECT && dst_type == T_OBJECT &&
++ class_cast_needed(src_klass, dst_klass)) {
+ if (!class_cast_needed(dst_klass, src_klass)) {
+- err = ((argnum < 0)
++ if (raw)
++ return NULL; // reverse cast is OK; the MH target is trusted to enforce it
++ 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)
++ err = ((argnum >= 0)
+ ? "reference mismatch: passing a %s for method argument #%d, which expects %s"
+ : "reference mismatch: returning a %s, but caller expects %s");
+ }
+@@ -1429,10 +1483,10 @@
+ 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");
++ int target_pushes = decode_MethodHandle_stack_pushes(target());
++ assert(this_pushes == slots_pushed + target_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)
++ if (slots_pushed + target_pushes > MethodHandlePushLimit)
+ err = "too many bound parameters";
+ }
+ }
+@@ -1588,6 +1642,11 @@
+ if (err == NULL) {
+ // Check that the src/dest types are supplied if needed.
+ switch (ek) {
++ case _adapter_check_cast:
++ if (src != T_OBJECT || dest != T_OBJECT) {
++ err = "adapter requires object src/dest conversion subfields";
++ }
++ break;
+ case _adapter_prim_to_prim:
+ if (!is_java_primitive(src) || !is_java_primitive(dest) || src == dest) {
+ err = "adapter requires primitive src/dest conversion subfields"; break;
+@@ -1618,7 +1677,7 @@
+ int swap_size = type2size[src];
+ oop src_mtype = sun_dyn_AdapterMethodHandle::type(target());
+ oop dest_mtype = sun_dyn_AdapterMethodHandle::type(mh());
+- int slot_limit = sun_dyn_AdapterMethodHandle::vmslots(src_mtype);
++ int slot_limit = sun_dyn_AdapterMethodHandle::vmslots(target());
+ int src_slot = argslot;
+ int dest_slot = vminfo;
+ bool rotate_up = (src_slot > dest_slot); // upward rotation
+@@ -1729,22 +1788,22 @@
+ // 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)) {
++ int target_vmslots = java_dyn_MethodHandle::vmslots(target());
++ if (slots_pushed != (target_vmslots - this_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());
++ int target_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) {
++ if (slots_pushed + target_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 target_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");
++ assert(this_pushes == slots_pushed + target_pushes, "AMH stack motion must be correct");
+ }
+
+ if (err == NULL && vminfo != 0) {
+@@ -1761,7 +1820,11 @@
+ if (err == NULL) {
+ switch (ek) {
+ case _adapter_retype_only:
+- err = check_method_type_passthrough(src_mtype(), dst_mtype());
++ err = check_method_type_passthrough(src_mtype(), dst_mtype(), false);
++ break;
++
++ case _adapter_retype_raw:
++ err = check_method_type_passthrough(src_mtype(), dst_mtype(), true);
+ break;
+
+ case _adapter_check_cast:
+@@ -1821,6 +1884,7 @@
+ // Now it's time to finish the case analysis and pick a MethodHandleEntry.
+ switch (ek_orig) {
+ case _adapter_retype_only:
++ case _adapter_retype_raw:
+ case _adapter_check_cast:
+ case _adapter_dup_args:
+ case _adapter_drop_args:
+@@ -1888,8 +1952,7 @@
+ case _adapter_rot_args:
+ {
+ int swap_slots = type2size[src];
+- oop mtype = sun_dyn_AdapterMethodHandle::type(mh());
+- int slot_limit = sun_dyn_AdapterMethodHandle::vmslots(mtype);
++ int slot_limit = sun_dyn_AdapterMethodHandle::vmslots(mh());
+ int src_slot = argslot;
+ int dest_slot = vminfo;
+ int rotate = (ek_orig == _adapter_swap_args) ? 0 : (src_slot > dest_slot) ? 1 : -1;
+@@ -2133,7 +2196,7 @@
guarantee(MethodHandlePushLimit >= 2 && MethodHandlePushLimit <= 0xFF,
"MethodHandlePushLimit parameter must be in valid range");
return MethodHandlePushLimit;
@@ -60,7 +408,7 @@ diff --git a/src/share/vm/prims/methodHa
// return number of words per slot, signed according to stack direction
return MethodHandles::stack_move_unit();
}
-@@ -2144,7 +2148,7 @@
+@@ -2144,7 +2207,7 @@
#ifndef PRODUCT
#define EACH_NAMED_CON(template) \
template(MethodHandles,GC_JVM_PUSH_LIMIT) \
@@ -69,10 +417,26 @@ diff --git a/src/share/vm/prims/methodHa
template(MethodHandles,ETF_HANDLE_OR_METHOD_NAME) \
template(MethodHandles,ETF_DIRECT_HANDLE) \
template(MethodHandles,ETF_METHOD_NAME) \
+@@ -2157,6 +2220,7 @@
+ template(sun_dyn_MemberName,MN_SEARCH_INTERFACES) \
+ template(sun_dyn_MemberName,VM_INDEX_UNINITIALIZED) \
+ template(sun_dyn_AdapterMethodHandle,OP_RETYPE_ONLY) \
++ template(sun_dyn_AdapterMethodHandle,OP_RETYPE_RAW) \
+ template(sun_dyn_AdapterMethodHandle,OP_CHECK_CAST) \
+ template(sun_dyn_AdapterMethodHandle,OP_PRIM_TO_PRIM) \
+ template(sun_dyn_AdapterMethodHandle,OP_REF_TO_PRIM) \
diff --git a/src/share/vm/prims/methodHandles.hpp b/src/share/vm/prims/methodHandles.hpp
--- a/src/share/vm/prims/methodHandles.hpp
+++ b/src/share/vm/prims/methodHandles.hpp
-@@ -243,7 +243,7 @@
+@@ -47,6 +47,7 @@
+
+ _adapter_mh_first, // adapter sequence goes here...
+ _adapter_retype_only = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_RETYPE_ONLY,
++ _adapter_retype_raw = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_RETYPE_RAW,
+ _adapter_check_cast = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_CHECK_CAST,
+ _adapter_prim_to_prim = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_PRIM_TO_PRIM,
+ _adapter_ref_to_prim = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_REF_TO_PRIM,
+@@ -243,7 +244,7 @@
enum {
// format of query to getConstant:
GC_JVM_PUSH_LIMIT = 0,
@@ -81,3 +445,63 @@ diff --git a/src/share/vm/prims/methodHa
// format of result from getTarget / encode_target:
ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method)
+@@ -261,7 +262,8 @@
+ int insert_argnum, oop insert_type,
+ int change_argnum, oop change_type,
+ int delete_argnum,
+- oop dst_mtype, int dst_beg, int dst_end);
++ oop dst_mtype, int dst_beg, int dst_end,
++ bool raw = false);
+ static const char* check_method_type_insertion(oop src_mtype,
+ int insert_argnum, oop insert_type,
+ oop dst_mtype) {
+@@ -278,29 +280,29 @@
+ change_argnum, change_type,
+ -1, dst_mtype, 0, -1);
+ }
+- static const char* check_method_type_passthrough(oop src_mtype, oop dst_mtype) {
++ static const char* check_method_type_passthrough(oop src_mtype, oop dst_mtype, bool raw) {
+ oop no_ref = NULL;
+ return check_method_type_change(src_mtype, 0, -1,
+ -1, no_ref, -1, no_ref, -1,
+- dst_mtype, 0, -1);
++ dst_mtype, 0, -1, raw);
+ }
+
+ // These checkers operate on pairs of argument or return types:
+ static const char* check_argument_type_change(BasicType src_type, klassOop src_klass,
+ BasicType dst_type, klassOop dst_klass,
+- int argnum);
++ int argnum, bool raw = false);
+
+ static const char* check_argument_type_change(oop src_type, oop dst_type,
+- int argnum) {
++ int argnum, bool raw = false) {
+ 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);
++ dst_bt, dst_klass, argnum, raw);
+ }
+
+- 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(oop src_type, oop dst_type, bool raw = false) {
++ return check_argument_type_change(src_type, dst_type, -1, raw);
+ }
+
+ static const char* check_return_type_change(BasicType src_type, klassOop src_klass,
+@@ -357,9 +359,10 @@
+ TRAPS);
+
+ static bool same_basic_type_for_arguments(BasicType src, BasicType dst,
++ bool raw = false,
+ bool for_return = false);
+- static bool same_basic_type_for_returns(BasicType src, BasicType dst) {
+- return same_basic_type_for_arguments(src, dst, true);
++ static bool same_basic_type_for_returns(BasicType src, BasicType dst, bool raw = false) {
++ return same_basic_type_for_arguments(src, dst, raw, true);
+ }
+
+ enum { // arg_mask values