indy: move platform-specific code from meth.patch into indy-$arch.patch
authorjrose
Wed Apr 22 20:43:21 2009 -0700 (7 months ago)
changeset 4640852f028895
parent 455cb83bb7bf49
child 474f32d5550915
indy: move platform-specific code from meth.patch into indy-$arch.patch
indy-amd64.patch
indy-sparc.patch
indy.patch
meth.patch
series
--- a/indy-amd64.patch Wed Apr 22 19:13:35 2009 -0700
+++ b/indy-amd64.patch Wed Apr 22 20:43:21 2009 -0700
@@ -1,3 +1,7 @@ diff --git a/src/cpu/x86/vm/interp_masm_
+6829192: JSR 292 needs to support 64-bit x86
+Summary: changes for method handles and invokedynamic
+Reviewed-by: ?, ?
+
diff --git a/src/cpu/x86/vm/interp_masm_x86_64.cpp b/src/cpu/x86/vm/interp_masm_x86_64.cpp
--- a/src/cpu/x86/vm/interp_masm_x86_64.cpp
+++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp
@@ -98,10 +102,94 @@ diff --git a/src/cpu/x86/vm/interp_masm_
void profile_ret(Register return_bci, Register mdp);
void profile_null_seen(Register mdp);
void profile_typecheck(Register mdp, Register klass, Register scratch);
+diff --git a/src/cpu/x86/vm/interpreter_x86_64.cpp b/src/cpu/x86/vm/interpreter_x86_64.cpp
+--- a/src/cpu/x86/vm/interpreter_x86_64.cpp
++++ b/src/cpu/x86/vm/interpreter_x86_64.cpp
+@@ -277,12 +277,11 @@
+ address entry_point = __ pc();
+
+ // abstract method entry
+- // remove return address. Not really needed, since exception
+- // handling throws away expression stack
+- __ pop(rbx);
+
+- // adjust stack to what a normal return would do
+- __ mov(rsp, r13);
++ // pop return address, reset last_sp to NULL
++ __ empty_expression_stack();
++ __ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
++ __ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
+
+ // throw exception
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address,
+@@ -300,7 +299,10 @@
+ if (!EnableMethodHandles) {
+ return generate_abstract_entry();
+ }
+- return generate_abstract_entry(); //6815692//
++
++ address entry_point = MethodHandles::generate_method_handle_interpreter_entry(_masm);
++
++ return entry_point;
+ }
+
+
+diff --git a/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/src/cpu/x86/vm/stubGenerator_x86_64.cpp
+--- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp
++++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp
+@@ -2933,6 +2933,16 @@
+
+ // arraycopy stubs used by compilers
+ generate_arraycopy_stubs();
++
++ // generic method handle stubs
++ if (EnableMethodHandles && SystemDictionary::MethodHandle_klass() != NULL) {
++ for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST;
++ ek < MethodHandles::_EK_LIMIT;
++ ek = MethodHandles::EntryKind(1 + (int)ek)) {
++ StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
++ MethodHandles::generate_method_handle_stub(_masm, ek);
++ }
++ }
+ }
+
+ public:
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
-@@ -172,7 +172,15 @@
+@@ -100,21 +100,26 @@
+ return entry;
+ }
+
+-// Arguments are: required type in rarg1, failing object (or NULL) in rarg2
++// Arguments are: required type at TOS+8, failing object (or NULL) at TOS+4.
+ address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
+ address entry = __ pc();
+
+ __ pop(c_rarg2); // failing object is at TOS
+ __ pop(c_rarg1); // required type is at TOS+8
+
+- // expression stack must be empty before entering the VM if an
+- // exception happened
++ __ verify_oop(rbx);
++ __ verify_oop(rax);
++
++ // Various method handle types use interpreter registers as temps.
++ __ restore_bcp();
++ __ restore_locals();
++
++ // Expression stack must be empty before entering the VM for an exception.
+ __ empty_expression_stack();
+
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+- InterpreterRuntime::
+- throw_WrongMethodTypeException),
++ InterpreterRuntime::throw_WrongMethodTypeException),
+ // pass required type, failing object (or NULL)
+ c_rarg1, c_rarg2);
+ return entry;
+@@ -167,7 +172,15 @@
address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
int step, bool unbox) {
@@ -118,7 +206,7 @@ diff --git a/src/cpu/x86/vm/templateInte
// 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
-@@ -188,7 +196,14 @@
+@@ -183,7 +196,14 @@
__ restore_bcp();
__ restore_locals();
@@ -134,7 +222,7 @@ diff --git a/src/cpu/x86/vm/templateInte
__ movl(rbx, Address(rbx, rcx,
Address::times_8,
in_bytes(constantPoolCacheOopDesc::base_offset()) +
-@@ -197,6 +212,12 @@
+@@ -192,6 +212,12 @@
if (TaggedStackInterpreter) __ shll(rbx, 1); // 2 slots per parameter.
__ lea(rsp, Address(rsp, rbx, Address::times_8));
__ dispatch_next(state, step);
--- a/indy-sparc.patch Wed Apr 22 19:13:35 2009 -0700
+++ b/indy-sparc.patch Wed Apr 22 20:43:21 2009 -0700
@@ -1,3 +1,7 @@ diff --git a/src/cpu/sparc/vm/interp_mas
+6829193: JSR 292 needs to support SPARC
+Summary: changes for method handles and invokedynamic
+Reviewed-by: ?, ?
+
diff --git a/src/cpu/sparc/vm/interp_masm_sparc.cpp b/src/cpu/sparc/vm/interp_masm_sparc.cpp
--- a/src/cpu/sparc/vm/interp_masm_sparc.cpp
+++ b/src/cpu/sparc/vm/interp_masm_sparc.cpp
@@ -77,6 +81,444 @@ diff --git a/src/cpu/sparc/vm/interp_mas
void profile_ret(TosState state, Register return_bci, Register scratch);
void profile_null_seen(Register scratch);
void profile_typecheck(Register klass, Register scratch);
+diff --git a/src/cpu/sparc/vm/interpreter_sparc.cpp b/src/cpu/sparc/vm/interpreter_sparc.cpp
+--- a/src/cpu/sparc/vm/interpreter_sparc.cpp
++++ b/src/cpu/sparc/vm/interpreter_sparc.cpp
+@@ -242,7 +242,21 @@
+ if (!EnableMethodHandles) {
+ return generate_abstract_entry();
+ }
+- return generate_abstract_entry(); //6815692//
++#error remove everywhere: //6815692//
++
++ // incoming registers: O0 (mh), G5 (mtype), O1... (args)
++ Register O0_recv = O0;
++
++ Label wrong_method_type;
++ address entry_point = MethodHandles::generate_method_handle_interpreter_entry(_masm, wrong_method_type);
++
++ __ bind(wrong_method_type);
++ __ mov(O0_recv, O1); // bad mh (actual)
++ __ mov(G5_method_type, O0); // missed mtype (required)
++ DEBUG_ONLY(__ get_pc(O2));
++ __ throw_if_not_x(Assembler::never, Interpreter::_throw_WrongMethodType_entry, G3_scratch);
++
++ return entry_point;
+ }
+
+
+diff --git a/src/cpu/sparc/vm/methodHandles_sparc.cpp b/src/cpu/sparc/vm/methodHandles_sparc.cpp
+--- a/src/cpu/sparc/vm/methodHandles_sparc.cpp
++++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp
+@@ -60,12 +60,385 @@
+ // Code generation
+ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm,
+ Label& wrong_method_type) {
+- ShouldNotReachHere(); //NYI, 6815692
+- return NULL;
++ // 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[MethodTypeForm.vmslots])
++ // O0, O1: garbage temps, blown away
++ Register O0_argslot = O0;
++ Register O1_scratch = O1;
++
++ // here's where control starts out:
++ __ align(CodeEntryAlignment);
++ address entry_point = __ pc();
++
++ // fetch the MethodType from the method handle into G5_method_type
++ {
++ Register tem = G5_method;
++ for (jint* pchase = methodOopDesc::method_type_offsets_chain(); (*pchase) != -1; pchase++) {
++ __ ld_ptr(tem, *pchase, G5_method_type);
++ tem = G5_method_type; // yes, it's the same register...
++ }
++ }
++
++ // 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),
++ O0_argslot);
++ __ ldx(O0_argslot,
++ __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, O1_scratch),
++ O0_argslot);
++ __ ld_ptr(Gargs, __ argument_offset(O0_argslot), G3_method_handle);
++
++ __ check_method_handle_type(G5_method_type, G3_method_handle, O1_scratch, wrong_method_type);
++ __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
++ __ delayed()->nop();
++
++ // save away the wrong_method_type entry point
++ address wmt_jump_addr = __ pc();
++ __ ba(false, wrong_method_type);
++ __ delayed()->nop();
++
++ address me_cookie = MethodHandleEntry::start_compiled_entry(_masm, wmt_jump_addr);
++ __ unimplemented("compiled _wrong_method_type NYI"); // %%% FIXME
++ init_entry(_wrong_method_type, MethodHandleEntry::finish_compiled_entry(_masm, me_cookie));
++
++ return entry_point;
+ }
+
+ // Generate an "entry" field for a method handle.
+ // This determines how the method handle will respond to calls.
+ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) {
+- ShouldNotReachHere(); //NYI, 6815692
++ ShouldNotReachHere();
++#if 0
++ // Here is the register state during an interpreted call,
++ // as set up by generate_method_handle_interpreter_entry():
++ // - G5: garbage temp (was MethodHandle.invoke methodOop, unused)
++ // - O0: receiver method handle
++ // - I5_savedSP: sender SP (must preserve)
++
++ Register O0_argslot = O0;
++ Register O1_scratch = O1;
++ Register G5_index = G5;
++
++ 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_amh_target( G3_method_handle, 0, java_dyn_MethodHandle::vmtarget_offset_in_bytes() ); //AMH
++
++ if (have_entry(ek)) {
++ __ nop(); // empty stubs make SG sick
++ return;
++ }
++
++ address interp_entry = __ pc();
++ if (UseCompressedOops) __ unimplemented("UseCompressedOops");
++
++ switch ((int) ek) {
++ case _check_mtype:
++ {
++ // this stub is special, because it requires a live mtype argument
++ Label wrong_method_type;
++ __ bind(wrong_method_type);
++ Address wmt_entry(O1_scratch, (address) &_entries[_wrong_method_type]);
++ __ load_ptr_contents(wmt_entry, O1_scratch);
++ Address wmt_fie(O1_scratch, 0, MethodHandleEntry::from_interpreted_entry_offset_in_bytes());
++ __ jump_indirect_to(wmt_fie, O1_scratch);
++ __ delayed()->nop();
++
++ interp_entry = __ pc();
++ __ check_method_handle_type(G5_method_type, G3_method_handle, O1_scratch, wrong_method_type);
++ // now G5_method_type is dead; subsequent stubs will use it as a temp
++
++ __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
++ __ delayed()->nop();
++ }
++ break;
++
++ case _invokestatic_mh:
++ case _invokespecial_mh:
++ {
++ assert(G5_method == G5_index, "");
++ __ ld_ptr(G3_mh_vmref, G5_method);
++ __ verify_oop(G5_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.
++ __ lduw(G3_mh_vmargslot, O0_argslot);
++ __ ld_ptr(Gargs, __ argument_offset(O0_argslot), O0_argslot);
++ __ null_check(O0_argslot);
++ __ verify_oop(O0_argslot);
++ }
++ __ jump_indirect_to(G5_method_fie, G3_scratch);
++ __ delayed()->nop();
++ }
++ break;
++
++ case _invokebound_mh:
++ {
++ Register G5_scratch = G5_method;
++ __ lduw(G3_mh_vmargslot, O0_argslot);
++ // get address of inserted argument (-1 means after sp is decremented)
++ __ add(Gargs, __ argument_offset(O0_argslot, -1), O0_argslot);
++#ifdef ASSERT
++ {
++ Label L_ok, L_bad;
++ __ dec(O0_argslot, STACK_BIAS);
++ __ cmp(O0_argslot, FP);
++ __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, L_bad);
++ __ delayed()->cmp(SP, O0_argslot);
++ __ br(Assembler::lessEqualUnsigned, false, Assembler::pt, L_ok);
++ __ delayed()->inc(O0_argslot, STACK_BIAS);
++ __ 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 O0_argslot, including the
++ // return address, will be pulled down by one slot width.
++ Label loop, done;
++ __ sub(Gargs, Interpreter::stackElementSize(), Gargs); // decrement sp
++ __ mov(Gargs, O1_scratch);
++ {
++ __ bind(loop);
++ // pull one word down by 4 (or 8 if TaggedStackInterpreter)
++ __ ld_ptr(O1_scratch, Interpreter::stackElementSize(), G5_scratch);
++ __ st_ptr(G5_scratch, O1_scratch, 0);
++ __ inc(O1_scratch, wordSize);
++ __ cmp(O1_scratch, O0_argslot);
++ __ br(Assembler::less, false, Assembler::pn, loop);
++ __ delayed()->nop();
++ }
++
++ __ ld_ptr(G3_mh_vmref, G5_method);
++ __ verify_oop(G5_method);
++
++ // replace MH with bound receiver (or first static argument):
++ Address G3_method_receiver(G3_method_handle, 0, java_dyn_MethodHandle::receiver_offset_in_bytes());
++ __ ld_ptr(G3_method_receiver, O1_scratch);
++ __ st_ptr(O1_scratch, O0_argslot, 0);
++ if (TaggedStackInterpreter) {
++ __ mov(frame::TagReference, O1_scratch);
++ __ st_ptr(O1_scratch, O0_argslot, wordSize);
++ }
++ __ jump_indirect_to(G5_method_fie, G3_scratch);
++ __ delayed()->nop();
++ }
++ break;
++
++ case _invokevirtual_mh:
++ {
++ // same as TemplateTable::invokevirtual,
++ // minus the CP setup and profiling:
++
++ // pick out the vtable index and receiver offset from the MH,
++ // and then we can discard it:
++ __ lduw( G3_mh_vmargslot, O0_argslot );
++ __ lduw( G3_mh_vmindex, G5_index );
++ __ ld_ptr(Gargs, __ argument_offset(O0_argslot), O0_argslot);
++ __ null_check(O0_argslot, oopDesc::klass_offset_in_bytes());
++ // get receiver klass
++ Register O0_klass = O0_argslot;
++ // !UseCompressedOops
++ __ ld_ptr(O0_argslot, oopDesc::klass_offset_in_bytes(), O0_klass);
++ __ verify_oop(O0_klass);
++
++ // 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");
++ assert(G5_method == G5_index, "");
++ __ sll_ptr(G5_index, LogBytesPerWord, G5_index);
++ __ inc(O0_klass, base + vtableEntry::method_offset_in_bytes());
++ __ ld_ptr(O0_klass, G5_index, G5_method);
++
++ __ verify_oop(G5_method);
++ __ jump_indirect_to(G5_method_fie, G3_scratch);
++ __ delayed()->nop();
++ }
++ break;
++
++ case _invokeinterface_mh:
++ {
++ // same as TemplateTable::invokeinterface,
++ // minus the CP setup and profiling:
++
++ // pick out the interface and itable index from the MH.
++ Register O1_intf = O1_scratch;
++
++ __ ld_ptr( G3_mh_vmref, O1_intf );
++ __ lduw( G3_mh_vmargslot, O0_argslot );
++ __ lduw( G3_mh_vmindex, G5_index );
++ __ ld_ptr(Gargs, __ argument_offset(O0_argslot), O0_argslot);
++ __ null_check(O0_argslot, oopDesc::klass_offset_in_bytes());
++
++ // get receiver klass
++ Register O0_klass = O0_argslot;
++ // !UseCompressedOops
++ __ ld_ptr(O0_argslot, oopDesc::klass_offset_in_bytes(), O0_klass);
++ __ verify_oop(O0_klass);
++
++ // get interface klass
++ Label no_such_interface;
++ __ lookup_interface_method(O0_klass, O1_intf,
++ // note: next two args must be the same:
++ G5_index, G5_method,
++ G3_scratch,
++ no_such_interface);
++
++ __ verify_oop(G5_method);
++ __ jump_indirect_to(G5_method_fie, G3_scratch);
++ __ delayed()->nop();
++
++ __ bind(no_such_interface);
++ // Throw an exception.
++ // For historical reasons, it will be IncompatibleClassChangeError.
++ __ should_not_reach_here(); // %%% FIXME NYI
++ }
++ 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
++ __ lduw(G3_mh_vmargslot, O0_argslot);
++ RegisterOrConstant arg = __ argument_offset(O0_argslot);
++ __ add(Gargs, arg, Gargs); // pop some arguments
++ }
++
++ // immediately jump to the next MH layer:
++ __ 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.
++ // 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:
++ __ lduw(G3_mh_vmargslot, O0_argslot);
++ if (ak == _adapt_extend_zero || ak == _adapt_extend_sign)
++ __ lduw(G3_mh_vmindex, G5_index);
++ RegisterOrConstant arg = __ argument_offset(O0_argslot);
++
++ // get the new MH:
++ __ ld_ptr(G3_amh_target, G3_method_handle);
++ // (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
++ __ ld_ptr(Gargs, arg, O1_scratch);
++ __ tst(O1_scratch);
++ Label skip;
++ __ br(Assembler::equal, false, Assembler::pt, skip);
++ __ delayed()->set((jint)true, O1_scratch);
++ __ st_ptr(O1_scratch, Gargs, arg);
++ __ bind(skip);
++
++ } else {
++ // original 32-bit vmdata word must be of this form:
++ // | argumentNumber:16 | lowBitCount:8 | conversion:8 |
++ __ srl(G5_index, 8, G5_index); // shift in 2nd LSB
++ __ sub(G0, G5_index, G5_index); // left shift by 32-lowBitCount
++ __ ld_ptr(Gargs, arg, O1_scratch);
++ __ sll_ptr(O1_scratch, G5_index, O1_scratch);
++ if (ak == _adapt_extend_sign) {
++ // this path is taken for int->byte, int->short
++ __ sra(O1_scratch, G5_index, O1_scratch); // 32-bit only!
++ } else if (ak == _adapt_extend_zero) {
++ // this is taken for int->char
++ __ srl(O1_scratch, G5_index, O1_scratch); // 32-bit only!
++ } else {
++ ShouldNotReachHere();
++ }
++ __ st_ptr(O1_scratch, Gargs, arg);
++ }
++
++ __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
++ __ delayed()->nop();
++ }
++ break;
++
++ case _adapter_mh_first+_adapt_check_cast:
++ {
++ // temps:
++ Register G5_klass = G5_index; // interesting AMH data
++
++ // check an argument, or perform a simple in-place conversion,
++ // before jumping to the next layer of MH:
++ __ lduw(G3_mh_vmargslot, O0_argslot);
++ RegisterOrConstant arg = __ argument_offset(O0_argslot);
++
++ // What class are we casting to?
++ __ ld_ptr(G3_mh_vmref, G5_klass);
++
++ // get the new MH:
++ __ ld_ptr(G3_amh_target, G3_method_handle);
++ // (now we are done with the old MH)
++
++ Label done;
++ __ ld_ptr(Gargs, arg, O1_scratch);
++ __ tst(O1_scratch);
++ __ br(Assembler::zero, false, Assembler::pn, done); // no cast if null
++ __ delayed()->nop();
++ // !UseCompressedOops
++ __ ld_ptr(O1_scratch, oopDesc::klass_offset_in_bytes(), O1_scratch);
++
++ // live at this point:
++ // - G5_klass: klass required by the target method
++ // - O1_scratch: argument klass to test
++ // - G3_method_handle: method handle to invoke (after cast succeeds)
++ __ check_klass_subtype(O1_scratch, G5_klass, O0_argslot, done);
++
++ // If we get here, the type check failed!
++ // Call the wrong_method_type stub, passing the failing argument type in rax.
++ __ mov(G5_klass, G5_method_type); // missed klass (required)
++ __ mov(O1_scratch, G3_method_handle); // bad object (actual)
++
++ Address wmt_entry(O1_scratch, (address) &_entries[_wrong_method_type]);
++ __ load_ptr_contents(wmt_entry, O1_scratch);
++ Address wmt_fie(O1_scratch, 0, MethodHandleEntry::from_interpreted_entry_offset_in_bytes());
++ __ jump_indirect_to(wmt_fie, O1_scratch);
++
++ __ bind(done);
++ __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
++ __ delayed()->nop();
++ }
++ 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_ricochet:
++ case _adapter_mh_first+_adapt_flyby:
++ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
++ break;
++
++ default: ShouldNotReachHere();
++ }
++
++ address me_cookie = MethodHandleEntry::start_compiled_entry(_masm, interp_entry);
++ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
++
++ init_entry(ek, MethodHandleEntry::finish_compiled_entry(_masm, me_cookie));
++#endif
+ }
+diff --git a/src/cpu/sparc/vm/stubGenerator_sparc.cpp b/src/cpu/sparc/vm/stubGenerator_sparc.cpp
+--- a/src/cpu/sparc/vm/stubGenerator_sparc.cpp
++++ b/src/cpu/sparc/vm/stubGenerator_sparc.cpp
+@@ -2887,6 +2887,16 @@
+
+ // arraycopy stubs used by compilers
+ generate_arraycopy_stubs();
++
++ // generic method handle stubs
++ if (EnableMethodHandles && SystemDictionary::MethodHandle_klass() != NULL) {
++ for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST;
++ ek < MethodHandles::_EK_LIMIT;
++ ek = MethodHandles::EntryKind(1 + (int)ek)) {
++ StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
++ MethodHandles::generate_method_handle_stub(_masm, ek);
++ }
++ }
+ }
+
+
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
--- a/indy.patch Wed Apr 22 19:13:35 2009 -0700
+++ b/indy.patch Wed Apr 22 20:43:21 2009 -0700
@@ -0,0 +1,2 @@
+changes entrained after 6655646 appear in indy.patch proper
+
--- a/meth.patch Wed Apr 22 19:13:35 2009 -0700
+++ b/meth.patch Wed Apr 22 20:43:21 2009 -0700
@@ -1,541 +1,5 @@ changes entrained after 6655638 appear i
changes entrained after 6655638 appear in meth.patch proper
-diff --git a/src/cpu/sparc/vm/interpreter_sparc.cpp b/src/cpu/sparc/vm/interpreter_sparc.cpp
---- a/src/cpu/sparc/vm/interpreter_sparc.cpp
-+++ b/src/cpu/sparc/vm/interpreter_sparc.cpp
-@@ -242,7 +242,21 @@
- if (!EnableMethodHandles) {
- return generate_abstract_entry();
- }
-- return generate_abstract_entry(); //6815692//
-+#error remove everywhere: //6815692//
-+
-+ // incoming registers: O0 (mh), G5 (mtype), O1... (args)
-+ Register O0_recv = O0;
-+
-+ Label wrong_method_type;
-+ address entry_point = MethodHandles::generate_method_handle_interpreter_entry(_masm, wrong_method_type);
-+
-+ __ bind(wrong_method_type);
-+ __ mov(O0_recv, O1); // bad mh (actual)
-+ __ mov(G5_method_type, O0); // missed mtype (required)
-+ DEBUG_ONLY(__ get_pc(O2));
-+ __ throw_if_not_x(Assembler::never, Interpreter::_throw_WrongMethodType_entry, G3_scratch);
-+
-+ return entry_point;
- }
-
-
-diff --git a/src/cpu/sparc/vm/methodHandles_sparc.cpp b/src/cpu/sparc/vm/methodHandles_sparc.cpp
---- a/src/cpu/sparc/vm/methodHandles_sparc.cpp
-+++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp
-@@ -60,12 +60,385 @@
- // Code generation
- address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm,
- Label& wrong_method_type) {
-- ShouldNotReachHere(); //NYI, 6815692
-- return NULL;
-+ // 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[MethodTypeForm.vmslots])
-+ // O0, O1: garbage temps, blown away
-+ Register O0_argslot = O0;
-+ Register O1_scratch = O1;
-+
-+ // here's where control starts out:
-+ __ align(CodeEntryAlignment);
-+ address entry_point = __ pc();
-+
-+ // fetch the MethodType from the method handle into G5_method_type
-+ {
-+ Register tem = G5_method;
-+ for (jint* pchase = methodOopDesc::method_type_offsets_chain(); (*pchase) != -1; pchase++) {
-+ __ ld_ptr(tem, *pchase, G5_method_type);
-+ tem = G5_method_type; // yes, it's the same register...
-+ }
-+ }
-+
-+ // 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),
-+ O0_argslot);
-+ __ ldx(O0_argslot,
-+ __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, O1_scratch),
-+ O0_argslot);
-+ __ ld_ptr(Gargs, __ argument_offset(O0_argslot), G3_method_handle);
-+
-+ __ check_method_handle_type(G5_method_type, G3_method_handle, O1_scratch, wrong_method_type);
-+ __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
-+ __ delayed()->nop();
-+
-+ // save away the wrong_method_type entry point
-+ address wmt_jump_addr = __ pc();
-+ __ ba(false, wrong_method_type);
-+ __ delayed()->nop();
-+
-+ address me_cookie = MethodHandleEntry::start_compiled_entry(_masm, wmt_jump_addr);
-+ __ unimplemented("compiled _wrong_method_type NYI"); // %%% FIXME
-+ init_entry(_wrong_method_type, MethodHandleEntry::finish_compiled_entry(_masm, me_cookie));
-+
-+ return entry_point;
- }
-
- // Generate an "entry" field for a method handle.
- // This determines how the method handle will respond to calls.
- void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) {
-- ShouldNotReachHere(); //NYI, 6815692
-+ ShouldNotReachHere();
-+#if 0
-+ // Here is the register state during an interpreted call,
-+ // as set up by generate_method_handle_interpreter_entry():
-+ // - G5: garbage temp (was MethodHandle.invoke methodOop, unused)
-+ // - O0: receiver method handle
-+ // - I5_savedSP: sender SP (must preserve)
-+
-+ Register O0_argslot = O0;
-+ Register O1_scratch = O1;
-+ Register G5_index = G5;
-+
-+ 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_amh_target( G3_method_handle, 0, java_dyn_MethodHandle::vmtarget_offset_in_bytes() ); //AMH
-+
-+ if (have_entry(ek)) {
-+ __ nop(); // empty stubs make SG sick
-+ return;
-+ }
-+
-+ address interp_entry = __ pc();
-+ if (UseCompressedOops) __ unimplemented("UseCompressedOops");
-+
-+ switch ((int) ek) {
-+ case _check_mtype:
-+ {
-+ // this stub is special, because it requires a live mtype argument
-+ Label wrong_method_type;
-+ __ bind(wrong_method_type);
-+ Address wmt_entry(O1_scratch, (address) &_entries[_wrong_method_type]);
-+ __ load_ptr_contents(wmt_entry, O1_scratch);
-+ Address wmt_fie(O1_scratch, 0, MethodHandleEntry::from_interpreted_entry_offset_in_bytes());
-+ __ jump_indirect_to(wmt_fie, O1_scratch);
-+ __ delayed()->nop();
-+
-+ interp_entry = __ pc();
-+ __ check_method_handle_type(G5_method_type, G3_method_handle, O1_scratch, wrong_method_type);
-+ // now G5_method_type is dead; subsequent stubs will use it as a temp
-+
-+ __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
-+ __ delayed()->nop();
-+ }
-+ break;
-+
-+ case _invokestatic_mh:
-+ case _invokespecial_mh:
-+ {
-+ assert(G5_method == G5_index, "");
-+ __ ld_ptr(G3_mh_vmref, G5_method);
-+ __ verify_oop(G5_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.
-+ __ lduw(G3_mh_vmargslot, O0_argslot);
-+ __ ld_ptr(Gargs, __ argument_offset(O0_argslot), O0_argslot);
-+ __ null_check(O0_argslot);
-+ __ verify_oop(O0_argslot);
-+ }
-+ __ jump_indirect_to(G5_method_fie, G3_scratch);
-+ __ delayed()->nop();
-+ }
-+ break;
-+
-+ case _invokebound_mh:
-+ {
-+ Register G5_scratch = G5_method;
-+ __ lduw(G3_mh_vmargslot, O0_argslot);
-+ // get address of inserted argument (-1 means after sp is decremented)
-+ __ add(Gargs, __ argument_offset(O0_argslot, -1), O0_argslot);
-+#ifdef ASSERT
-+ {
-+ Label L_ok, L_bad;
-+ __ dec(O0_argslot, STACK_BIAS);
-+ __ cmp(O0_argslot, FP);
-+ __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, L_bad);
-+ __ delayed()->cmp(SP, O0_argslot);
-+ __ br(Assembler::lessEqualUnsigned, false, Assembler::pt, L_ok);
-+ __ delayed()->inc(O0_argslot, STACK_BIAS);
-+ __ 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 O0_argslot, including the
-+ // return address, will be pulled down by one slot width.
-+ Label loop, done;
-+ __ sub(Gargs, Interpreter::stackElementSize(), Gargs); // decrement sp
-+ __ mov(Gargs, O1_scratch);
-+ {
-+ __ bind(loop);
-+ // pull one word down by 4 (or 8 if TaggedStackInterpreter)
-+ __ ld_ptr(O1_scratch, Interpreter::stackElementSize(), G5_scratch);
-+ __ st_ptr(G5_scratch, O1_scratch, 0);
-+ __ inc(O1_scratch, wordSize);
-+ __ cmp(O1_scratch, O0_argslot);
-+ __ br(Assembler::less, false, Assembler::pn, loop);
-+ __ delayed()->nop();
-+ }
-+
-+ __ ld_ptr(G3_mh_vmref, G5_method);
-+ __ verify_oop(G5_method);
-+
-+ // replace MH with bound receiver (or first static argument):
-+ Address G3_method_receiver(G3_method_handle, 0, java_dyn_MethodHandle::receiver_offset_in_bytes());
-+ __ ld_ptr(G3_method_receiver, O1_scratch);
-+ __ st_ptr(O1_scratch, O0_argslot, 0);
-+ if (TaggedStackInterpreter) {
-+ __ mov(frame::TagReference, O1_scratch);
-+ __ st_ptr(O1_scratch, O0_argslot, wordSize);
-+ }
-+ __ jump_indirect_to(G5_method_fie, G3_scratch);
-+ __ delayed()->nop();
-+ }
-+ break;
-+
-+ case _invokevirtual_mh:
-+ {
-+ // same as TemplateTable::invokevirtual,
-+ // minus the CP setup and profiling:
-+
-+ // pick out the vtable index and receiver offset from the MH,
-+ // and then we can discard it:
-+ __ lduw( G3_mh_vmargslot, O0_argslot );
-+ __ lduw( G3_mh_vmindex, G5_index );
-+ __ ld_ptr(Gargs, __ argument_offset(O0_argslot), O0_argslot);
-+ __ null_check(O0_argslot, oopDesc::klass_offset_in_bytes());
-+ // get receiver klass
-+ Register O0_klass = O0_argslot;
-+ // !UseCompressedOops
-+ __ ld_ptr(O0_argslot, oopDesc::klass_offset_in_bytes(), O0_klass);
-+ __ verify_oop(O0_klass);
-+
-+ // 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");
-+ assert(G5_method == G5_index, "");
-+ __ sll_ptr(G5_index, LogBytesPerWord, G5_index);
-+ __ inc(O0_klass, base + vtableEntry::method_offset_in_bytes());
-+ __ ld_ptr(O0_klass, G5_index, G5_method);
-+
-+ __ verify_oop(G5_method);
-+ __ jump_indirect_to(G5_method_fie, G3_scratch);
-+ __ delayed()->nop();
-+ }
-+ break;
-+
-+ case _invokeinterface_mh:
-+ {
-+ // same as TemplateTable::invokeinterface,
-+ // minus the CP setup and profiling:
-+
-+ // pick out the interface and itable index from the MH.
-+ Register O1_intf = O1_scratch;
-+
-+ __ ld_ptr( G3_mh_vmref, O1_intf );
-+ __ lduw( G3_mh_vmargslot, O0_argslot );
-+ __ lduw( G3_mh_vmindex, G5_index );
-+ __ ld_ptr(Gargs, __ argument_offset(O0_argslot), O0_argslot);
-+ __ null_check(O0_argslot, oopDesc::klass_offset_in_bytes());
-+
-+ // get receiver klass
-+ Register O0_klass = O0_argslot;
-+ // !UseCompressedOops
-+ __ ld_ptr(O0_argslot, oopDesc::klass_offset_in_bytes(), O0_klass);
-+ __ verify_oop(O0_klass);
-+
-+ // get interface klass
-+ Label no_such_interface;
-+ __ lookup_interface_method(O0_klass, O1_intf,
-+ // note: next two args must be the same:
-+ G5_index, G5_method,
-+ G3_scratch,
-+ no_such_interface);
-+
-+ __ verify_oop(G5_method);
-+ __ jump_indirect_to(G5_method_fie, G3_scratch);
-+ __ delayed()->nop();
-+
-+ __ bind(no_such_interface);
-+ // Throw an exception.
-+ // For historical reasons, it will be IncompatibleClassChangeError.
-+ __ should_not_reach_here(); // %%% FIXME NYI
-+ }
-+ 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
-+ __ lduw(G3_mh_vmargslot, O0_argslot);
-+ RegisterOrConstant arg = __ argument_offset(O0_argslot);
-+ __ add(Gargs, arg, Gargs); // pop some arguments
-+ }
-+
-+ // immediately jump to the next MH layer:
-+ __ 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.
-+ // 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:
-+ __ lduw(G3_mh_vmargslot, O0_argslot);
-+ if (ak == _adapt_extend_zero || ak == _adapt_extend_sign)
-+ __ lduw(G3_mh_vmindex, G5_index);
-+ RegisterOrConstant arg = __ argument_offset(O0_argslot);
-+
-+ // get the new MH:
-+ __ ld_ptr(G3_amh_target, G3_method_handle);
-+ // (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
-+ __ ld_ptr(Gargs, arg, O1_scratch);
-+ __ tst(O1_scratch);
-+ Label skip;
-+ __ br(Assembler::equal, false, Assembler::pt, skip);
-+ __ delayed()->set((jint)true, O1_scratch);
-+ __ st_ptr(O1_scratch, Gargs, arg);
-+ __ bind(skip);
-+
-+ } else {
-+ // original 32-bit vmdata word must be of this form:
-+ // | argumentNumber:16 | lowBitCount:8 | conversion:8 |
-+ __ srl(G5_index, 8, G5_index); // shift in 2nd LSB
-+ __ sub(G0, G5_index, G5_index); // left shift by 32-lowBitCount
-+ __ ld_ptr(Gargs, arg, O1_scratch);
-+ __ sll_ptr(O1_scratch, G5_index, O1_scratch);
-+ if (ak == _adapt_extend_sign) {
-+ // this path is taken for int->byte, int->short
-+ __ sra(O1_scratch, G5_index, O1_scratch); // 32-bit only!
-+ } else if (ak == _adapt_extend_zero) {
-+ // this is taken for int->char
-+ __ srl(O1_scratch, G5_index, O1_scratch); // 32-bit only!
-+ } else {
-+ ShouldNotReachHere();
-+ }
-+ __ st_ptr(O1_scratch, Gargs, arg);
-+ }
-+
-+ __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
-+ __ delayed()->nop();
-+ }
-+ break;
-+
-+ case _adapter_mh_first+_adapt_check_cast:
-+ {
-+ // temps:
-+ Register G5_klass = G5_index; // interesting AMH data
-+
-+ // check an argument, or perform a simple in-place conversion,
-+ // before jumping to the next layer of MH:
-+ __ lduw(G3_mh_vmargslot, O0_argslot);
-+ RegisterOrConstant arg = __ argument_offset(O0_argslot);
-+
-+ // What class are we casting to?
-+ __ ld_ptr(G3_mh_vmref, G5_klass);
-+
-+ // get the new MH:
-+ __ ld_ptr(G3_amh_target, G3_method_handle);
-+ // (now we are done with the old MH)
-+
-+ Label done;
-+ __ ld_ptr(Gargs, arg, O1_scratch);
-+ __ tst(O1_scratch);
-+ __ br(Assembler::zero, false, Assembler::pn, done); // no cast if null
-+ __ delayed()->nop();
-+ // !UseCompressedOops
-+ __ ld_ptr(O1_scratch, oopDesc::klass_offset_in_bytes(), O1_scratch);
-+
-+ // live at this point:
-+ // - G5_klass: klass required by the target method
-+ // - O1_scratch: argument klass to test
-+ // - G3_method_handle: method handle to invoke (after cast succeeds)
-+ __ check_klass_subtype(O1_scratch, G5_klass, O0_argslot, done);
-+
-+ // If we get here, the type check failed!
-+ // Call the wrong_method_type stub, passing the failing argument type in rax.
-+ __ mov(G5_klass, G5_method_type); // missed klass (required)
-+ __ mov(O1_scratch, G3_method_handle); // bad object (actual)
-+
-+ Address wmt_entry(O1_scratch, (address) &_entries[_wrong_method_type]);
-+ __ load_ptr_contents(wmt_entry, O1_scratch);
-+ Address wmt_fie(O1_scratch, 0, MethodHandleEntry::from_interpreted_entry_offset_in_bytes());
-+ __ jump_indirect_to(wmt_fie, O1_scratch);
-+
-+ __ bind(done);
-+ __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
-+ __ delayed()->nop();
-+ }
-+ 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_ricochet:
-+ case _adapter_mh_first+_adapt_flyby:
-+ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
-+ break;
-+
-+ default: ShouldNotReachHere();
-+ }
-+
-+ address me_cookie = MethodHandleEntry::start_compiled_entry(_masm, interp_entry);
-+ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
-+
-+ init_entry(ek, MethodHandleEntry::finish_compiled_entry(_masm, me_cookie));
-+#endif
- }
-diff --git a/src/cpu/sparc/vm/stubGenerator_sparc.cpp b/src/cpu/sparc/vm/stubGenerator_sparc.cpp
---- a/src/cpu/sparc/vm/stubGenerator_sparc.cpp
-+++ b/src/cpu/sparc/vm/stubGenerator_sparc.cpp
-@@ -2887,6 +2887,16 @@
-
- // arraycopy stubs used by compilers
- generate_arraycopy_stubs();
-+
-+ // generic method handle stubs
-+ if (EnableMethodHandles && SystemDictionary::MethodHandle_klass() != NULL) {
-+ for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST;
-+ ek < MethodHandles::_EK_LIMIT;
-+ ek = MethodHandles::EntryKind(1 + (int)ek)) {
-+ StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
-+ MethodHandles::generate_method_handle_stub(_masm, ek);
-+ }
-+ }
- }
-
-
-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
-@@ -28,6 +28,7 @@
- address generate_asm_interpreter_entry(bool synchronized);
- address generate_native_entry(bool synchronized);
- address generate_abstract_entry(void);
-+ address generate_method_handle_entry(void);
- address generate_math_entry(AbstractInterpreter::MethodKind kind);
- address generate_empty_entry(void);
- address generate_accessor_entry(void);
-diff --git a/src/cpu/x86/vm/interpreter_x86_64.cpp b/src/cpu/x86/vm/interpreter_x86_64.cpp
---- a/src/cpu/x86/vm/interpreter_x86_64.cpp
-+++ b/src/cpu/x86/vm/interpreter_x86_64.cpp
-@@ -277,12 +277,11 @@
- address entry_point = __ pc();
-
- // abstract method entry
-- // remove return address. Not really needed, since exception
-- // handling throws away expression stack
-- __ pop(rbx);
-
-- // adjust stack to what a normal return would do
-- __ mov(rsp, r13);
-+ // pop return address, reset last_sp to NULL
-+ __ empty_expression_stack();
-+ __ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
-+ __ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
-
- // throw exception
- __ call_VM(noreg, CAST_FROM_FN_PTR(address,
-@@ -300,7 +299,10 @@
- if (!EnableMethodHandles) {
- return generate_abstract_entry();
- }
-- return generate_abstract_entry(); //6815692//
-+
-+ address entry_point = MethodHandles::generate_method_handle_interpreter_entry(_masm);
-+
-+ return entry_point;
- }
-
-
-diff --git a/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/src/cpu/x86/vm/stubGenerator_x86_64.cpp
---- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp
-+++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp
-@@ -2933,6 +2933,16 @@
-
- // arraycopy stubs used by compilers
- generate_arraycopy_stubs();
-+
-+ // generic method handle stubs
-+ if (EnableMethodHandles && SystemDictionary::MethodHandle_klass() != NULL) {
-+ for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST;
-+ ek < MethodHandles::_EK_LIMIT;
-+ ek = MethodHandles::EntryKind(1 + (int)ek)) {
-+ StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
-+ MethodHandles::generate_method_handle_stub(_masm, ek);
-+ }
-+ }
- }
-
- public:
-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
-@@ -100,21 +100,26 @@
- return entry;
- }
-
--// Arguments are: required type in rarg1, failing object (or NULL) in rarg2
-+// Arguments are: required type at TOS+8, failing object (or NULL) at TOS+4.
- address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
- address entry = __ pc();
-
- __ pop(c_rarg2); // failing object is at TOS
- __ pop(c_rarg1); // required type is at TOS+8
-
-- // expression stack must be empty before entering the VM if an
-- // exception happened
-+ __ verify_oop(rbx);
-+ __ verify_oop(rax);
-+
-+ // Various method handle types use interpreter registers as temps.
-+ __ restore_bcp();
-+ __ restore_locals();
-+
-+ // Expression stack must be empty before entering the VM for an exception.
- __ empty_expression_stack();
-
- __ call_VM(noreg,
- CAST_FROM_FN_PTR(address,
-- InterpreterRuntime::
-- throw_WrongMethodTypeException),
-+ InterpreterRuntime::throw_WrongMethodTypeException),
- // pass required type, failing object (or NULL)
- c_rarg1, c_rarg2);
- return entry;
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
--- a/series Wed Apr 22 19:13:35 2009 -0700
+++ b/series Wed Apr 22 20:43:21 2009 -0700
@@ -11,8 +11,8 @@ meth.patch #-/meth
indy-6655646.patch #-/indy #+05f8c84c5daa
indy.patch #-/indy #+05f8c84c5daa
-indy-amd64.patch #-/indy #+05f8c84c5daa
-indy-sparc.patch #-/indy #+05f8c84c5daa
+indy-amd64.patch #-/indy #+05f8c84c5daa #-buildable
+indy-sparc.patch #-/indy #+05f8c84c5daa #-buildable
annot.patch #-/annot #+d1605aabd0a1 #+jdk7-b30 #-testable
inti.patch #-/inti #+d1605aabd0a1 #+jdk7-b30 #-buildable