jrose@1145: /* trims@1907: * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. jrose@1145: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jrose@1145: * jrose@1145: * This code is free software; you can redistribute it and/or modify it jrose@1145: * under the terms of the GNU General Public License version 2 only, as jrose@1145: * published by the Free Software Foundation. jrose@1145: * jrose@1145: * This code is distributed in the hope that it will be useful, but WITHOUT jrose@1145: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jrose@1145: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jrose@1145: * version 2 for more details (a copy is included in the LICENSE file that jrose@1145: * accompanied this code). jrose@1145: * jrose@1145: * You should have received a copy of the GNU General Public License version jrose@1145: * 2 along with this work; if not, write to the Free Software Foundation, jrose@1145: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jrose@1145: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. jrose@1145: * jrose@1145: */ jrose@1145: jrose@1145: #include "incls/_precompiled.incl" jrose@1145: #include "incls/_methodHandles_sparc.cpp.incl" jrose@1145: jrose@1145: #define __ _masm-> jrose@1145: twisti@2204: #ifdef PRODUCT twisti@2204: #define BLOCK_COMMENT(str) /* nothing */ twisti@2204: #else twisti@2204: #define BLOCK_COMMENT(str) __ block_comment(str) twisti@2204: #endif twisti@2204: twisti@2204: #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") twisti@2204: jrose@1145: address MethodHandleEntry::start_compiled_entry(MacroAssembler* _masm, jrose@1145: address interpreted_entry) { twisti@1858: // Just before the actual machine code entry point, allocate space twisti@1858: // for a MethodHandleEntry::Data record, so that we can manage everything twisti@1858: // from one base pointer. jrose@1145: __ align(wordSize); jrose@1145: address target = __ pc() + sizeof(Data); jrose@1145: while (__ pc() < target) { jrose@1145: __ nop(); jrose@1145: __ align(wordSize); jrose@1145: } jrose@1145: jrose@1145: MethodHandleEntry* me = (MethodHandleEntry*) __ pc(); jrose@1145: me->set_end_address(__ pc()); // set a temporary end_address jrose@1145: me->set_from_interpreted_entry(interpreted_entry); jrose@1145: me->set_type_checking_entry(NULL); jrose@1145: jrose@1145: return (address) me; jrose@1145: } jrose@1145: jrose@1145: MethodHandleEntry* MethodHandleEntry::finish_compiled_entry(MacroAssembler* _masm, jrose@1145: address start_addr) { jrose@1145: MethodHandleEntry* me = (MethodHandleEntry*) start_addr; jrose@1145: assert(me->end_address() == start_addr, "valid ME"); jrose@1145: jrose@1145: // Fill in the real end_address: jrose@1145: __ align(wordSize); jrose@1145: me->set_end_address(__ pc()); jrose@1145: jrose@1145: return me; jrose@1145: } jrose@1145: jrose@1145: jrose@1145: // Code generation jrose@1145: address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) { twisti@1858: // I5_savedSP: sender SP (must preserve) twisti@1858: // G4 (Gargs): incoming argument list (must preserve) twisti@1858: // G5_method: invoke methodOop; becomes method type. twisti@1858: // G3_method_handle: receiver method handle (must load from sp[MethodTypeForm.vmslots]) twisti@1858: // O0, O1: garbage temps, blown away twisti@1858: Register O0_argslot = O0; twisti@1858: Register O1_scratch = O1; jrose@2266: Register O2_scratch = O2; jrose@2266: Register O3_scratch = O3; jrose@2266: Register O4_argbase = O4; jrose@2266: Register O5_mtype = O5; twisti@1858: twisti@1858: // emit WrongMethodType path first, to enable back-branch from main path twisti@1858: Label wrong_method_type; twisti@1858: __ bind(wrong_method_type); jrose@2266: Label invoke_generic_slow_path; jrose@2266: assert(methodOopDesc::intrinsic_id_size_in_bytes() == sizeof(u1), "");; jrose@2266: __ ldub(Address(G5_method, methodOopDesc::intrinsic_id_offset_in_bytes()), O1_scratch); jrose@2266: __ cmp(O1_scratch, (int) vmIntrinsics::_invokeExact); jrose@2266: __ brx(Assembler::notEqual, false, Assembler::pt, invoke_generic_slow_path); jrose@2266: __ delayed()->nop(); jrose@2266: __ mov(O5_mtype, G5_method_type); // required by throw_WrongMethodType jrose@2266: // mov(G3_method_handle, G3_method_handle); // already in this register twisti@1858: __ jump_to(AddressLiteral(Interpreter::throw_WrongMethodType_entry()), O1_scratch); twisti@1858: __ delayed()->nop(); twisti@1858: twisti@1858: // here's where control starts out: twisti@1858: __ align(CodeEntryAlignment); twisti@1858: address entry_point = __ pc(); twisti@1858: jrose@2266: // fetch the MethodType from the method handle twisti@1858: { twisti@1858: Register tem = G5_method; twisti@1858: for (jint* pchase = methodOopDesc::method_type_offsets_chain(); (*pchase) != -1; pchase++) { jrose@2266: __ ld_ptr(Address(tem, *pchase), O5_mtype); jrose@2266: tem = O5_mtype; // in case there is another indirection twisti@1858: } twisti@1858: } twisti@1858: twisti@1858: // given the MethodType, find out where the MH argument is buried jrose@2266: __ load_heap_oop(Address(O5_mtype, __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, O1_scratch)), O0_argslot); jrose@2266: __ ldsw( Address(O0_argslot, __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, O1_scratch)), O0_argslot); jrose@2266: __ add(Gargs, __ argument_offset(O0_argslot, 1), O4_argbase); jrose@2266: // Note: argument_address uses its input as a scratch register! jrose@2266: __ ld_ptr(Address(O4_argbase, -Interpreter::stackElementSize), G3_method_handle); twisti@1858: jrose@2266: trace_method_handle(_masm, "invokeExact"); jrose@2266: jrose@2266: __ check_method_handle_type(O5_mtype, G3_method_handle, O1_scratch, wrong_method_type); twisti@1858: __ jump_to_method_handle_entry(G3_method_handle, O1_scratch); twisti@1858: jrose@2266: // for invokeGeneric (only), apply argument and result conversions on the fly jrose@2266: __ bind(invoke_generic_slow_path); jrose@2266: #ifdef ASSERT jrose@2266: { Label L; jrose@2266: __ ldub(Address(G5_method, methodOopDesc::intrinsic_id_offset_in_bytes()), O1_scratch); jrose@2266: __ cmp(O1_scratch, (int) vmIntrinsics::_invokeGeneric); jrose@2266: __ brx(Assembler::equal, false, Assembler::pt, L); jrose@2266: __ delayed()->nop(); jrose@2266: __ stop("bad methodOop::intrinsic_id"); jrose@2266: __ bind(L); jrose@2266: } jrose@2266: #endif //ASSERT jrose@2266: jrose@2266: // make room on the stack for another pointer: jrose@2266: insert_arg_slots(_masm, 2 * stack_move_unit(), _INSERT_REF_MASK, jrose@2266: O4_argbase, O1_scratch, O2_scratch, O3_scratch); jrose@2266: // load up an adapter from the calling type (Java weaves this) jrose@2266: Register O2_form = O2_scratch; jrose@2266: Register O3_adapter = O3_scratch; jrose@2266: __ load_heap_oop(Address(O5_mtype, __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, O1_scratch)), O2_form); jrose@2266: // load_heap_oop(Address(O2_form, __ delayed_value(java_dyn_MethodTypeForm::genericInvoker_offset_in_bytes, O1_scratch)), O3_adapter); jrose@2266: // deal with old JDK versions: jrose@2266: __ add( Address(O2_form, __ delayed_value(java_dyn_MethodTypeForm::genericInvoker_offset_in_bytes, O1_scratch)), O3_adapter); jrose@2266: __ cmp(O3_adapter, O2_form); jrose@2266: Label sorry_no_invoke_generic; jrose@2266: __ brx(Assembler::lessUnsigned, false, Assembler::pn, sorry_no_invoke_generic); jrose@2266: __ delayed()->nop(); jrose@2266: jrose@2266: __ load_heap_oop(Address(O3_adapter, 0), O3_adapter); jrose@2266: __ tst(O3_adapter); jrose@2266: __ brx(Assembler::zero, false, Assembler::pn, sorry_no_invoke_generic); jrose@2266: __ delayed()->nop(); jrose@2266: __ st_ptr(O3_adapter, Address(O4_argbase, 1 * Interpreter::stackElementSize)); jrose@2266: // As a trusted first argument, pass the type being called, so the adapter knows jrose@2266: // the actual types of the arguments and return values. jrose@2266: // (Generic invokers are shared among form-families of method-type.) jrose@2266: __ st_ptr(O5_mtype, Address(O4_argbase, 0 * Interpreter::stackElementSize)); jrose@2266: // FIXME: assert that O3_adapter is of the right method-type. jrose@2266: __ mov(O3_adapter, G3_method_handle); jrose@2266: trace_method_handle(_masm, "invokeGeneric"); jrose@2266: __ jump_to_method_handle_entry(G3_method_handle, O1_scratch); jrose@2266: jrose@2266: __ bind(sorry_no_invoke_generic); // no invokeGeneric implementation available! jrose@2266: __ mov(O5_mtype, G5_method_type); // required by throw_WrongMethodType jrose@2266: // mov(G3_method_handle, G3_method_handle); // already in this register jrose@2266: __ jump_to(AddressLiteral(Interpreter::throw_WrongMethodType_entry()), O1_scratch); jrose@2266: __ delayed()->nop(); jrose@2266: twisti@1858: return entry_point; jrose@1145: } jrose@1145: twisti@1858: twisti@1858: #ifdef ASSERT twisti@1858: static void verify_argslot(MacroAssembler* _masm, Register argslot_reg, Register temp_reg, const char* error_message) { twisti@1858: // Verify that argslot lies within (Gargs, FP]. twisti@1858: Label L_ok, L_bad; twisti@2204: BLOCK_COMMENT("{ verify_argslot"); twisti@1858: #ifdef _LP64 twisti@1858: __ add(FP, STACK_BIAS, temp_reg); twisti@1858: __ cmp(argslot_reg, temp_reg); twisti@1858: #else twisti@1858: __ cmp(argslot_reg, FP); twisti@1858: #endif twisti@1858: __ brx(Assembler::greaterUnsigned, false, Assembler::pn, L_bad); twisti@1858: __ delayed()->nop(); twisti@1858: __ cmp(Gargs, argslot_reg); twisti@1858: __ brx(Assembler::lessEqualUnsigned, false, Assembler::pt, L_ok); twisti@1858: __ delayed()->nop(); twisti@1858: __ bind(L_bad); twisti@1858: __ stop(error_message); twisti@1858: __ bind(L_ok); twisti@2204: BLOCK_COMMENT("} verify_argslot"); twisti@1858: } twisti@1858: #endif twisti@1858: twisti@1858: twisti@1858: // Helper to insert argument slots into the stack. twisti@1858: // arg_slots must be a multiple of stack_move_unit() and <= 0 twisti@1858: void MethodHandles::insert_arg_slots(MacroAssembler* _masm, twisti@1858: RegisterOrConstant arg_slots, twisti@1858: int arg_mask, twisti@1858: Register argslot_reg, twisti@1858: Register temp_reg, Register temp2_reg, Register temp3_reg) { twisti@1858: assert(temp3_reg != noreg, "temp3 required"); twisti@1858: assert_different_registers(argslot_reg, temp_reg, temp2_reg, temp3_reg, twisti@1858: (!arg_slots.is_register() ? Gargs : arg_slots.as_register())); twisti@1858: twisti@1858: #ifdef ASSERT twisti@1858: verify_argslot(_masm, argslot_reg, temp_reg, "insertion point must fall within current frame"); twisti@1858: if (arg_slots.is_register()) { twisti@1858: Label L_ok, L_bad; twisti@1858: __ cmp(arg_slots.as_register(), (int32_t) NULL_WORD); twisti@1858: __ br(Assembler::greater, false, Assembler::pn, L_bad); twisti@1858: __ delayed()->nop(); twisti@1858: __ btst(-stack_move_unit() - 1, arg_slots.as_register()); twisti@1858: __ br(Assembler::zero, false, Assembler::pt, L_ok); twisti@1858: __ delayed()->nop(); twisti@1858: __ bind(L_bad); twisti@1858: __ stop("assert arg_slots <= 0 and clear low bits"); twisti@1858: __ bind(L_ok); twisti@1858: } else { twisti@1858: assert(arg_slots.as_constant() <= 0, ""); twisti@1858: assert(arg_slots.as_constant() % -stack_move_unit() == 0, ""); twisti@1858: } twisti@1858: #endif // ASSERT twisti@1858: twisti@1858: #ifdef _LP64 twisti@1858: if (arg_slots.is_register()) { twisti@1858: // Was arg_slots register loaded as signed int? twisti@1858: Label L_ok; twisti@1858: __ sll(arg_slots.as_register(), BitsPerInt, temp_reg); twisti@1858: __ sra(temp_reg, BitsPerInt, temp_reg); twisti@1858: __ cmp(arg_slots.as_register(), temp_reg); twisti@1858: __ br(Assembler::equal, false, Assembler::pt, L_ok); twisti@1858: __ delayed()->nop(); twisti@1858: __ stop("arg_slots register not loaded as signed int"); twisti@1858: __ bind(L_ok); twisti@1858: } twisti@1858: #endif twisti@1858: twisti@1858: // Make space on the stack for the inserted argument(s). twisti@1858: // Then pull down everything shallower than argslot_reg. twisti@1858: // The stacked return address gets pulled down with everything else. twisti@1858: // That is, copy [sp, argslot) downward by -size words. In pseudo-code: twisti@1858: // sp -= size; twisti@1858: // for (temp = sp + size; temp < argslot; temp++) twisti@1858: // temp[-size] = temp[0] twisti@1858: // argslot -= size; twisti@2204: BLOCK_COMMENT("insert_arg_slots {"); twisti@1858: RegisterOrConstant offset = __ regcon_sll_ptr(arg_slots, LogBytesPerWord, temp3_reg); twisti@1858: twisti@1858: // Keep the stack pointer 2*wordSize aligned. twisti@1858: const int TwoWordAlignmentMask = right_n_bits(LogBytesPerWord + 1); twisti@1858: RegisterOrConstant masked_offset = __ regcon_andn_ptr(offset, TwoWordAlignmentMask, temp_reg); twisti@1858: __ add(SP, masked_offset, SP); twisti@1858: twisti@1858: __ mov(Gargs, temp_reg); // source pointer for copy twisti@1858: __ add(Gargs, offset, Gargs); twisti@1858: twisti@1858: { twisti@1858: Label loop; twisti@2204: __ BIND(loop); twisti@1858: // pull one word down each time through the loop twisti@1858: __ ld_ptr(Address(temp_reg, 0), temp2_reg); twisti@1858: __ st_ptr(temp2_reg, Address(temp_reg, offset)); twisti@1858: __ add(temp_reg, wordSize, temp_reg); twisti@1858: __ cmp(temp_reg, argslot_reg); twisti@1858: __ brx(Assembler::less, false, Assembler::pt, loop); twisti@1858: __ delayed()->nop(); // FILLME twisti@1858: } twisti@1858: twisti@1858: // Now move the argslot down, to point to the opened-up space. twisti@1858: __ add(argslot_reg, offset, argslot_reg); twisti@2204: BLOCK_COMMENT("} insert_arg_slots"); twisti@1858: } twisti@1858: twisti@1858: twisti@1858: // Helper to remove argument slots from the stack. twisti@1858: // arg_slots must be a multiple of stack_move_unit() and >= 0 twisti@1858: void MethodHandles::remove_arg_slots(MacroAssembler* _masm, twisti@1858: RegisterOrConstant arg_slots, twisti@1858: Register argslot_reg, twisti@1858: Register temp_reg, Register temp2_reg, Register temp3_reg) { twisti@1858: assert(temp3_reg != noreg, "temp3 required"); twisti@1858: assert_different_registers(argslot_reg, temp_reg, temp2_reg, temp3_reg, twisti@1858: (!arg_slots.is_register() ? Gargs : arg_slots.as_register())); twisti@1858: twisti@1858: RegisterOrConstant offset = __ regcon_sll_ptr(arg_slots, LogBytesPerWord, temp3_reg); twisti@1858: twisti@1858: #ifdef ASSERT twisti@1858: // Verify that [argslot..argslot+size) lies within (Gargs, FP). twisti@1858: __ add(argslot_reg, offset, temp2_reg); twisti@1858: verify_argslot(_masm, temp2_reg, temp_reg, "deleted argument(s) must fall within current frame"); twisti@1858: if (arg_slots.is_register()) { twisti@1858: Label L_ok, L_bad; twisti@1858: __ cmp(arg_slots.as_register(), (int32_t) NULL_WORD); twisti@1858: __ br(Assembler::less, false, Assembler::pn, L_bad); twisti@1858: __ delayed()->nop(); twisti@1858: __ btst(-stack_move_unit() - 1, arg_slots.as_register()); twisti@1858: __ br(Assembler::zero, false, Assembler::pt, L_ok); twisti@1858: __ delayed()->nop(); twisti@1858: __ bind(L_bad); twisti@1858: __ stop("assert arg_slots >= 0 and clear low bits"); twisti@1858: __ bind(L_ok); twisti@1858: } else { twisti@1858: assert(arg_slots.as_constant() >= 0, ""); twisti@1858: assert(arg_slots.as_constant() % -stack_move_unit() == 0, ""); twisti@1858: } twisti@1858: #endif // ASSERT twisti@1858: twisti@2204: BLOCK_COMMENT("remove_arg_slots {"); twisti@1858: // Pull up everything shallower than argslot. twisti@1858: // Then remove the excess space on the stack. twisti@1858: // The stacked return address gets pulled up with everything else. twisti@1858: // That is, copy [sp, argslot) upward by size words. In pseudo-code: twisti@1858: // for (temp = argslot-1; temp >= sp; --temp) twisti@1858: // temp[size] = temp[0] twisti@1858: // argslot += size; twisti@1858: // sp += size; twisti@1858: __ sub(argslot_reg, wordSize, temp_reg); // source pointer for copy twisti@1858: { twisti@1858: Label loop; twisti@2204: __ BIND(loop); twisti@1858: // pull one word up each time through the loop twisti@1858: __ ld_ptr(Address(temp_reg, 0), temp2_reg); twisti@1858: __ st_ptr(temp2_reg, Address(temp_reg, offset)); twisti@1858: __ sub(temp_reg, wordSize, temp_reg); twisti@1858: __ cmp(temp_reg, Gargs); twisti@1858: __ brx(Assembler::greaterEqual, false, Assembler::pt, loop); twisti@1858: __ delayed()->nop(); // FILLME twisti@1858: } twisti@1858: twisti@1858: // Now move the argslot up, to point to the just-copied block. twisti@1858: __ add(Gargs, offset, Gargs); twisti@1858: // And adjust the argslot address to point at the deletion point. twisti@1858: __ add(argslot_reg, offset, argslot_reg); twisti@1858: twisti@1858: // Keep the stack pointer 2*wordSize aligned. twisti@1858: const int TwoWordAlignmentMask = right_n_bits(LogBytesPerWord + 1); twisti@1858: RegisterOrConstant masked_offset = __ regcon_andn_ptr(offset, TwoWordAlignmentMask, temp_reg); twisti@1858: __ add(SP, masked_offset, SP); twisti@2204: BLOCK_COMMENT("} remove_arg_slots"); twisti@1858: } twisti@1858: twisti@1858: twisti@1858: #ifndef PRODUCT twisti@1858: extern "C" void print_method_handle(oop mh); twisti@1858: void trace_method_handle_stub(const char* adaptername, twisti@2204: oopDesc* mh) { twisti@1858: printf("MH %s mh="INTPTR_FORMAT"\n", adaptername, (intptr_t) mh); twisti@1858: print_method_handle(mh); twisti@1858: } twisti@2204: void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) { twisti@2204: if (!TraceMethodHandles) return; twisti@2204: BLOCK_COMMENT("trace_method_handle {"); twisti@2204: // save: Gargs, O5_savedSP twisti@2204: __ save_frame(16); twisti@2204: __ set((intptr_t) adaptername, O0); twisti@2204: __ mov(G3_method_handle, O1); twisti@2204: __ mov(G3_method_handle, L3); twisti@2204: __ mov(Gargs, L4); twisti@2204: __ mov(G5_method_type, L5); twisti@2204: __ call_VM_leaf(L7, CAST_FROM_FN_PTR(address, trace_method_handle_stub)); twisti@2204: twisti@2204: __ mov(L3, G3_method_handle); twisti@2204: __ mov(L4, Gargs); twisti@2204: __ mov(L5, G5_method_type); twisti@2204: __ restore(); twisti@2204: BLOCK_COMMENT("} trace_method_handle"); twisti@2204: } twisti@1858: #endif // PRODUCT twisti@1858: jrose@1862: // which conversion op types are implemented here? jrose@1862: int MethodHandles::adapter_conversion_ops_supported_mask() { jrose@1862: return ((1<nop(); twisti@1858: twisti@1858: int jobject_oop_offset = 0; twisti@1858: __ ld_ptr(Address(G5_method, jobject_oop_offset), G5_method); twisti@1858: __ tst(G5_method); twisti@1858: __ brx(Assembler::zero, false, Assembler::pn, no_method); twisti@1858: __ delayed()->nop(); twisti@1858: twisti@1858: __ verify_oop(G5_method); twisti@1858: __ jump_indirect_to(G5_method_fie, O1_scratch); twisti@1858: __ delayed()->nop(); twisti@1858: twisti@1858: // If we get here, the Java runtime did not do its job of creating the exception. twisti@1858: // Do something that is at least causes a valid throw from the interpreter. twisti@1858: __ bind(no_method); twisti@1858: __ unimplemented("_raise_exception no method"); twisti@1858: } twisti@1858: break; twisti@1858: twisti@1858: case _invokestatic_mh: twisti@1858: case _invokespecial_mh: twisti@1858: { twisti@2201: __ load_heap_oop(G3_mh_vmtarget, G5_method); // target is a methodOop twisti@1858: __ verify_oop(G5_method); twisti@1858: // Same as TemplateTable::invokestatic or invokespecial, twisti@1858: // minus the CP setup and profiling: twisti@1858: if (ek == _invokespecial_mh) { twisti@1858: // Must load & check the first argument before entering the target method. twisti@1858: __ load_method_handle_vmslots(O0_argslot, G3_method_handle, O1_scratch); twisti@1858: __ ld_ptr(__ argument_address(O0_argslot), G3_method_handle); twisti@1858: __ null_check(G3_method_handle); twisti@1858: __ verify_oop(G3_method_handle); twisti@1858: } twisti@1858: __ jump_indirect_to(G5_method_fie, O1_scratch); twisti@1858: __ delayed()->nop(); twisti@1858: } twisti@1858: break; twisti@1858: twisti@1858: case _invokevirtual_mh: twisti@1858: { twisti@1858: // Same as TemplateTable::invokevirtual, twisti@1858: // minus the CP setup and profiling: twisti@1858: twisti@1858: // Pick out the vtable index and receiver offset from the MH, twisti@1858: // and then we can discard it: twisti@1858: __ load_method_handle_vmslots(O0_argslot, G3_method_handle, O1_scratch); twisti@1858: __ ldsw(G3_dmh_vmindex, G5_index); twisti@1858: // Note: The verifier allows us to ignore G3_mh_vmtarget. twisti@1858: __ ld_ptr(__ argument_address(O0_argslot, -1), G3_method_handle); twisti@1858: __ null_check(G3_method_handle, oopDesc::klass_offset_in_bytes()); twisti@1858: twisti@1858: // Get receiver klass: twisti@1858: Register O0_klass = O0_argslot; twisti@1858: __ load_klass(G3_method_handle, O0_klass); twisti@1858: __ verify_oop(O0_klass); twisti@1858: twisti@1858: // Get target methodOop & entry point: twisti@1858: const int base = instanceKlass::vtable_start_offset() * wordSize; twisti@1858: assert(vtableEntry::size() * wordSize == wordSize, "adjust the scaling in the code below"); twisti@1858: twisti@1858: __ sll_ptr(G5_index, LogBytesPerWord, G5_index); twisti@1858: __ add(O0_klass, G5_index, O0_klass); twisti@1858: Address vtable_entry_addr(O0_klass, base + vtableEntry::method_offset_in_bytes()); twisti@1858: __ ld_ptr(vtable_entry_addr, G5_method); twisti@1858: twisti@1858: __ verify_oop(G5_method); twisti@1858: __ jump_indirect_to(G5_method_fie, O1_scratch); twisti@1858: __ delayed()->nop(); twisti@1858: } twisti@1858: break; twisti@1858: twisti@1858: case _invokeinterface_mh: twisti@1858: { twisti@1858: // Same as TemplateTable::invokeinterface, twisti@1858: // minus the CP setup and profiling: twisti@1858: __ load_method_handle_vmslots(O0_argslot, G3_method_handle, O1_scratch); twisti@1858: Register O1_intf = O1_scratch; twisti@2201: __ load_heap_oop(G3_mh_vmtarget, O1_intf); twisti@1858: __ ldsw(G3_dmh_vmindex, G5_index); twisti@1858: __ ld_ptr(__ argument_address(O0_argslot, -1), G3_method_handle); twisti@1858: __ null_check(G3_method_handle, oopDesc::klass_offset_in_bytes()); twisti@1858: twisti@1858: // Get receiver klass: twisti@1858: Register O0_klass = O0_argslot; twisti@1858: __ load_klass(G3_method_handle, O0_klass); twisti@1858: __ verify_oop(O0_klass); twisti@1858: twisti@1858: // Get interface: twisti@1858: Label no_such_interface; twisti@1858: __ verify_oop(O1_intf); twisti@1858: __ lookup_interface_method(O0_klass, O1_intf, twisti@1858: // Note: next two args must be the same: twisti@1858: G5_index, G5_method, twisti@1858: O2_scratch, twisti@1858: O3_scratch, twisti@1858: no_such_interface); twisti@1858: twisti@1858: __ verify_oop(G5_method); twisti@1858: __ jump_indirect_to(G5_method_fie, O1_scratch); twisti@1858: __ delayed()->nop(); twisti@1858: twisti@1858: __ bind(no_such_interface); twisti@1858: // Throw an exception. twisti@1858: // For historical reasons, it will be IncompatibleClassChangeError. twisti@1858: __ unimplemented("not tested yet"); twisti@1858: __ ld_ptr(Address(O1_intf, java_mirror_offset), O3_scratch); // required interface twisti@1858: __ mov(O0_klass, O2_scratch); // bad receiver twisti@1858: __ jump_to(AddressLiteral(from_interpreted_entry(_raise_exception)), O0_argslot); twisti@1858: __ delayed()->mov(Bytecodes::_invokeinterface, O1_scratch); // who is complaining? twisti@1858: } twisti@1858: break; twisti@1858: twisti@1858: case _bound_ref_mh: twisti@1858: case _bound_int_mh: twisti@1858: case _bound_long_mh: twisti@1858: case _bound_ref_direct_mh: twisti@1858: case _bound_int_direct_mh: twisti@1858: case _bound_long_direct_mh: twisti@1858: { twisti@1858: const bool direct_to_method = (ek >= _bound_ref_direct_mh); twisti@1858: BasicType arg_type = T_ILLEGAL; twisti@1858: int arg_mask = _INSERT_NO_MASK; twisti@1858: int arg_slots = -1; twisti@1858: get_ek_bound_mh_info(ek, arg_type, arg_mask, arg_slots); twisti@1858: twisti@1858: // Make room for the new argument: twisti@1858: __ ldsw(G3_bmh_vmargslot, O0_argslot); twisti@1858: __ add(Gargs, __ argument_offset(O0_argslot), O0_argslot); twisti@1858: twisti@1858: insert_arg_slots(_masm, arg_slots * stack_move_unit(), arg_mask, O0_argslot, O1_scratch, O2_scratch, G5_index); twisti@1858: twisti@1858: // Store bound argument into the new stack slot: twisti@2201: __ load_heap_oop(G3_bmh_argument, O1_scratch); twisti@1858: if (arg_type == T_OBJECT) { twisti@1858: __ st_ptr(O1_scratch, Address(O0_argslot, 0)); twisti@1858: } else { twisti@1858: Address prim_value_addr(O1_scratch, java_lang_boxing_object::value_offset_in_bytes(arg_type)); twisti@1858: __ load_sized_value(prim_value_addr, O2_scratch, type2aelembytes(arg_type), is_signed_subword_type(arg_type)); twisti@1858: if (arg_slots == 2) { twisti@1858: __ unimplemented("not yet tested"); twisti@1858: #ifndef _LP64 twisti@1858: __ signx(O2_scratch, O3_scratch); // Sign extend twisti@1858: #endif twisti@1858: __ st_long(O2_scratch, Address(O0_argslot, 0)); // Uses O2/O3 on !_LP64 twisti@1858: } else { twisti@1858: __ st_ptr( O2_scratch, Address(O0_argslot, 0)); twisti@1858: } twisti@1858: } twisti@1858: twisti@1858: if (direct_to_method) { twisti@2201: __ load_heap_oop(G3_mh_vmtarget, G5_method); // target is a methodOop twisti@1858: __ verify_oop(G5_method); twisti@1858: __ jump_indirect_to(G5_method_fie, O1_scratch); twisti@1858: __ delayed()->nop(); twisti@1858: } else { twisti@2201: __ load_heap_oop(G3_mh_vmtarget, G3_method_handle); // target is a methodOop twisti@1858: __ verify_oop(G3_method_handle); twisti@1858: __ jump_to_method_handle_entry(G3_method_handle, O1_scratch); twisti@1858: } twisti@1858: } twisti@1858: break; twisti@1858: twisti@1858: case _adapter_retype_only: twisti@1858: case _adapter_retype_raw: twisti@1858: // Immediately jump to the next MH layer: twisti@2201: __ load_heap_oop(G3_mh_vmtarget, G3_method_handle); twisti@1858: __ jump_to_method_handle_entry(G3_method_handle, O1_scratch); twisti@1858: // This is OK when all parameter types widen. twisti@1858: // It is also OK when a return type narrows. twisti@1858: break; twisti@1858: twisti@1858: case _adapter_check_cast: twisti@1858: { twisti@1858: // Temps: twisti@1858: Register G5_klass = G5_index; // Interesting AMH data. twisti@1858: twisti@1858: // Check a reference argument before jumping to the next layer of MH: twisti@1858: __ ldsw(G3_amh_vmargslot, O0_argslot); twisti@1858: Address vmarg = __ argument_address(O0_argslot); twisti@1858: twisti@1858: // What class are we casting to? twisti@2201: __ load_heap_oop(G3_amh_argument, G5_klass); // This is a Class object! twisti@2201: __ load_heap_oop(Address(G5_klass, java_lang_Class::klass_offset_in_bytes()), G5_klass); twisti@1858: twisti@1858: Label done; twisti@1858: __ ld_ptr(vmarg, O1_scratch); twisti@1858: __ tst(O1_scratch); twisti@1858: __ brx(Assembler::zero, false, Assembler::pn, done); // No cast if null. twisti@1858: __ delayed()->nop(); twisti@1858: __ load_klass(O1_scratch, O1_scratch); twisti@1858: twisti@1858: // Live at this point: twisti@1858: // - G5_klass : klass required by the target method twisti@1858: // - O1_scratch : argument klass to test twisti@1858: // - G3_method_handle: adapter method handle twisti@1858: __ check_klass_subtype(O1_scratch, G5_klass, O0_argslot, O2_scratch, done); twisti@1858: twisti@1858: // If we get here, the type check failed! twisti@1858: __ ldsw(G3_amh_vmargslot, O0_argslot); // reload argslot field twisti@2201: __ load_heap_oop(G3_amh_argument, O3_scratch); // required class twisti@1858: __ ld_ptr(vmarg, O2_scratch); // bad object twisti@1858: __ jump_to(AddressLiteral(from_interpreted_entry(_raise_exception)), O0_argslot); twisti@1858: __ delayed()->mov(Bytecodes::_checkcast, O1_scratch); // who is complaining? twisti@1858: twisti@1858: __ bind(done); twisti@1858: // Get the new MH: twisti@2201: __ load_heap_oop(G3_mh_vmtarget, G3_method_handle); twisti@1858: __ jump_to_method_handle_entry(G3_method_handle, O1_scratch); twisti@1858: } twisti@1858: break; twisti@1858: twisti@1858: case _adapter_prim_to_prim: twisti@1858: case _adapter_ref_to_prim: twisti@1858: // Handled completely by optimized cases. twisti@1858: __ stop("init_AdapterMethodHandle should not issue this"); twisti@1858: break; twisti@1858: twisti@1858: case _adapter_opt_i2i: // optimized subcase of adapt_prim_to_prim twisti@1858: //case _adapter_opt_f2i: // optimized subcase of adapt_prim_to_prim twisti@1858: case _adapter_opt_l2i: // optimized subcase of adapt_prim_to_prim twisti@1858: case _adapter_opt_unboxi: // optimized subcase of adapt_ref_to_prim twisti@1858: { twisti@1858: // Perform an in-place conversion to int or an int subword. twisti@1858: __ ldsw(G3_amh_vmargslot, O0_argslot); twisti@1858: Address vmarg = __ argument_address(O0_argslot); twisti@1858: Address value; twisti@1858: bool value_left_justified = false; twisti@1858: twisti@1858: switch (ek) { twisti@1858: case _adapter_opt_i2i: twisti@2256: value = vmarg; twisti@2256: break; twisti@1858: case _adapter_opt_l2i: twisti@2256: { twisti@2256: // just delete the extra slot twisti@2256: __ add(Gargs, __ argument_offset(O0_argslot), O0_argslot); twisti@2256: remove_arg_slots(_masm, -stack_move_unit(), O0_argslot, O1_scratch, O2_scratch, O3_scratch); twisti@2256: value = vmarg = Address(O0_argslot, 0); twisti@2256: } twisti@1858: break; twisti@1858: case _adapter_opt_unboxi: twisti@1858: { twisti@1858: // Load the value up from the heap. twisti@1858: __ ld_ptr(vmarg, O1_scratch); twisti@1858: int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_INT); twisti@1858: #ifdef ASSERT twisti@1858: for (int bt = T_BOOLEAN; bt < T_INT; bt++) { twisti@1858: if (is_subword_type(BasicType(bt))) twisti@1858: assert(value_offset == java_lang_boxing_object::value_offset_in_bytes(BasicType(bt)), ""); twisti@1858: } twisti@1858: #endif twisti@1858: __ null_check(O1_scratch, value_offset); twisti@1858: value = Address(O1_scratch, value_offset); twisti@1858: #ifdef _BIG_ENDIAN twisti@1858: // Values stored in objects are packed. twisti@1858: value_left_justified = true; twisti@1858: #endif twisti@1858: } twisti@1858: break; twisti@1858: default: twisti@1858: ShouldNotReachHere(); twisti@1858: } twisti@1858: twisti@1858: // This check is required on _BIG_ENDIAN twisti@1858: Register G5_vminfo = G5_index; twisti@1858: __ ldsw(G3_amh_conversion, G5_vminfo); twisti@1858: assert(CONV_VMINFO_SHIFT == 0, "preshifted"); twisti@1858: twisti@1858: // Original 32-bit vmdata word must be of this form: twisti@1858: // | MBZ:6 | signBitCount:8 | srcDstTypes:8 | conversionOp:8 | twisti@1858: __ lduw(value, O1_scratch); twisti@1858: if (!value_left_justified) twisti@1858: __ sll(O1_scratch, G5_vminfo, O1_scratch); twisti@1858: Label zero_extend, done; twisti@1858: __ btst(CONV_VMINFO_SIGN_FLAG, G5_vminfo); twisti@1858: __ br(Assembler::zero, false, Assembler::pn, zero_extend); twisti@1858: __ delayed()->nop(); twisti@1858: twisti@1858: // this path is taken for int->byte, int->short twisti@1858: __ sra(O1_scratch, G5_vminfo, O1_scratch); twisti@1858: __ ba(false, done); twisti@1858: __ delayed()->nop(); twisti@1858: twisti@1858: __ bind(zero_extend); twisti@1858: // this is taken for int->char twisti@1858: __ srl(O1_scratch, G5_vminfo, O1_scratch); twisti@1858: twisti@1858: __ bind(done); twisti@1858: __ st(O1_scratch, vmarg); twisti@1858: twisti@1858: // Get the new MH: twisti@2201: __ load_heap_oop(G3_mh_vmtarget, G3_method_handle); twisti@1858: __ jump_to_method_handle_entry(G3_method_handle, O1_scratch); twisti@1858: } twisti@1858: break; twisti@1858: twisti@1858: case _adapter_opt_i2l: // optimized subcase of adapt_prim_to_prim twisti@1858: case _adapter_opt_unboxl: // optimized subcase of adapt_ref_to_prim twisti@1858: { twisti@1858: // Perform an in-place int-to-long or ref-to-long conversion. twisti@1858: __ ldsw(G3_amh_vmargslot, O0_argslot); twisti@1858: twisti@1858: // On big-endian machine we duplicate the slot and store the MSW twisti@1858: // in the first slot. twisti@1858: __ add(Gargs, __ argument_offset(O0_argslot, 1), O0_argslot); twisti@1858: twisti@1858: insert_arg_slots(_masm, stack_move_unit(), _INSERT_INT_MASK, O0_argslot, O1_scratch, O2_scratch, G5_index); twisti@1858: twisti@1858: Address arg_lsw(O0_argslot, 0); twisti@1861: Address arg_msw(O0_argslot, -Interpreter::stackElementSize); twisti@1858: twisti@1858: switch (ek) { twisti@1858: case _adapter_opt_i2l: twisti@1858: { twisti@1858: __ ldsw(arg_lsw, O2_scratch); // Load LSW twisti@1858: #ifndef _LP64 twisti@1858: __ signx(O2_scratch, O3_scratch); // Sign extend twisti@1858: #endif twisti@1858: __ st_long(O2_scratch, arg_msw); // Uses O2/O3 on !_LP64 twisti@1858: } twisti@1858: break; twisti@1858: case _adapter_opt_unboxl: twisti@1858: { twisti@1858: // Load the value up from the heap. twisti@1858: __ ld_ptr(arg_lsw, O1_scratch); twisti@1858: int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_LONG); twisti@1858: assert(value_offset == java_lang_boxing_object::value_offset_in_bytes(T_DOUBLE), ""); twisti@1858: __ null_check(O1_scratch, value_offset); twisti@1858: __ ld_long(Address(O1_scratch, value_offset), O2_scratch); // Uses O2/O3 on !_LP64 twisti@1858: __ st_long(O2_scratch, arg_msw); twisti@1858: } twisti@1858: break; twisti@1858: default: twisti@1858: ShouldNotReachHere(); twisti@1858: } twisti@1858: twisti@2201: __ load_heap_oop(G3_mh_vmtarget, G3_method_handle); twisti@1858: __ jump_to_method_handle_entry(G3_method_handle, O1_scratch); twisti@1858: } twisti@1858: break; twisti@1858: twisti@1858: case _adapter_opt_f2d: // optimized subcase of adapt_prim_to_prim twisti@1858: case _adapter_opt_d2f: // optimized subcase of adapt_prim_to_prim twisti@1858: { twisti@1858: // perform an in-place floating primitive conversion twisti@1858: __ unimplemented(entry_name(ek)); twisti@1858: } twisti@1858: break; twisti@1858: twisti@1858: case _adapter_prim_to_ref: twisti@1858: __ unimplemented(entry_name(ek)); // %%% FIXME: NYI twisti@1858: break; twisti@1858: twisti@1858: case _adapter_swap_args: twisti@1858: case _adapter_rot_args: twisti@1858: // handled completely by optimized cases twisti@1858: __ stop("init_AdapterMethodHandle should not issue this"); twisti@1858: break; twisti@1858: twisti@1858: case _adapter_opt_swap_1: twisti@1858: case _adapter_opt_swap_2: twisti@1858: case _adapter_opt_rot_1_up: twisti@1858: case _adapter_opt_rot_1_down: twisti@1858: case _adapter_opt_rot_2_up: twisti@1858: case _adapter_opt_rot_2_down: twisti@1858: { twisti@1858: int swap_bytes = 0, rotate = 0; twisti@1858: get_ek_adapter_opt_swap_rot_info(ek, swap_bytes, rotate); twisti@1858: twisti@1858: // 'argslot' is the position of the first argument to swap. twisti@1858: __ ldsw(G3_amh_vmargslot, O0_argslot); twisti@1858: __ add(Gargs, __ argument_offset(O0_argslot), O0_argslot); twisti@1858: twisti@1858: // 'vminfo' is the second. twisti@1858: Register O1_destslot = O1_scratch; twisti@1858: __ ldsw(G3_amh_conversion, O1_destslot); twisti@1858: assert(CONV_VMINFO_SHIFT == 0, "preshifted"); twisti@1858: __ and3(O1_destslot, CONV_VMINFO_MASK, O1_destslot); twisti@1858: __ add(Gargs, __ argument_offset(O1_destslot), O1_destslot); twisti@1858: twisti@1858: if (!rotate) { twisti@1858: for (int i = 0; i < swap_bytes; i += wordSize) { twisti@1858: __ ld_ptr(Address(O0_argslot, i), O2_scratch); twisti@1858: __ ld_ptr(Address(O1_destslot, i), O3_scratch); twisti@1858: __ st_ptr(O3_scratch, Address(O0_argslot, i)); twisti@1858: __ st_ptr(O2_scratch, Address(O1_destslot, i)); twisti@1858: } twisti@1858: } else { twisti@1858: // Save the first chunk, which is going to get overwritten. twisti@1858: switch (swap_bytes) { twisti@1858: case 4 : __ lduw(Address(O0_argslot, 0), O2_scratch); break; twisti@1858: case 16: __ ldx( Address(O0_argslot, 8), O3_scratch); //fall-thru twisti@1858: case 8 : __ ldx( Address(O0_argslot, 0), O2_scratch); break; twisti@1858: default: ShouldNotReachHere(); twisti@1858: } twisti@1858: twisti@1858: if (rotate > 0) { twisti@1858: // Rorate upward. twisti@1858: __ sub(O0_argslot, swap_bytes, O0_argslot); twisti@1858: #if ASSERT twisti@1858: { twisti@1858: // Verify that argslot > destslot, by at least swap_bytes. twisti@1858: Label L_ok; twisti@1858: __ cmp(O0_argslot, O1_destslot); twisti@1858: __ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, L_ok); twisti@1858: __ delayed()->nop(); twisti@1858: __ stop("source must be above destination (upward rotation)"); twisti@1858: __ bind(L_ok); twisti@1858: } twisti@1858: #endif twisti@1858: // Work argslot down to destslot, copying contiguous data upwards. twisti@1858: // Pseudo-code: twisti@1858: // argslot = src_addr - swap_bytes twisti@1858: // destslot = dest_addr twisti@1858: // while (argslot >= destslot) { twisti@1858: // *(argslot + swap_bytes) = *(argslot + 0); twisti@1858: // argslot--; twisti@1858: // } twisti@1858: Label loop; twisti@1858: __ bind(loop); twisti@1858: __ ld_ptr(Address(O0_argslot, 0), G5_index); twisti@1858: __ st_ptr(G5_index, Address(O0_argslot, swap_bytes)); twisti@1858: __ sub(O0_argslot, wordSize, O0_argslot); twisti@1858: __ cmp(O0_argslot, O1_destslot); twisti@1858: __ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, loop); twisti@1858: __ delayed()->nop(); // FILLME twisti@1858: } else { twisti@1858: __ add(O0_argslot, swap_bytes, O0_argslot); twisti@1858: #if ASSERT twisti@1858: { twisti@1858: // Verify that argslot < destslot, by at least swap_bytes. twisti@1858: Label L_ok; twisti@1858: __ cmp(O0_argslot, O1_destslot); twisti@1858: __ brx(Assembler::lessEqualUnsigned, false, Assembler::pt, L_ok); twisti@1858: __ delayed()->nop(); twisti@1858: __ stop("source must be above destination (upward rotation)"); twisti@1858: __ bind(L_ok); twisti@1858: } twisti@1858: #endif twisti@1858: // Work argslot up to destslot, copying contiguous data downwards. twisti@1858: // Pseudo-code: twisti@1858: // argslot = src_addr + swap_bytes twisti@1858: // destslot = dest_addr twisti@1858: // while (argslot >= destslot) { twisti@1858: // *(argslot - swap_bytes) = *(argslot + 0); twisti@1858: // argslot++; twisti@1858: // } twisti@1858: Label loop; twisti@1858: __ bind(loop); twisti@1858: __ ld_ptr(Address(O0_argslot, 0), G5_index); twisti@1858: __ st_ptr(G5_index, Address(O0_argslot, -swap_bytes)); twisti@1858: __ add(O0_argslot, wordSize, O0_argslot); twisti@1858: __ cmp(O0_argslot, O1_destslot); twisti@1858: __ brx(Assembler::lessEqualUnsigned, false, Assembler::pt, loop); twisti@1858: __ delayed()->nop(); // FILLME twisti@1858: } twisti@1858: twisti@1858: // Store the original first chunk into the destination slot, now free. twisti@1858: switch (swap_bytes) { twisti@1858: case 4 : __ stw(O2_scratch, Address(O1_destslot, 0)); break; twisti@1858: case 16: __ stx(O3_scratch, Address(O1_destslot, 8)); // fall-thru twisti@1858: case 8 : __ stx(O2_scratch, Address(O1_destslot, 0)); break; twisti@1858: default: ShouldNotReachHere(); twisti@1858: } twisti@1858: } twisti@1858: twisti@2201: __ load_heap_oop(G3_mh_vmtarget, G3_method_handle); twisti@1858: __ jump_to_method_handle_entry(G3_method_handle, O1_scratch); twisti@1858: } twisti@1858: break; twisti@1858: twisti@1858: case _adapter_dup_args: twisti@1858: { twisti@1858: // 'argslot' is the position of the first argument to duplicate. twisti@1858: __ ldsw(G3_amh_vmargslot, O0_argslot); twisti@1858: __ add(Gargs, __ argument_offset(O0_argslot), O0_argslot); twisti@1858: twisti@1858: // 'stack_move' is negative number of words to duplicate. twisti@1858: Register G5_stack_move = G5_index; twisti@1858: __ ldsw(G3_amh_conversion, G5_stack_move); twisti@1858: __ sra(G5_stack_move, CONV_STACK_MOVE_SHIFT, G5_stack_move); twisti@1858: twisti@1858: // Remember the old Gargs (argslot[0]). twisti@1858: Register O1_oldarg = O1_scratch; twisti@1858: __ mov(Gargs, O1_oldarg); twisti@1858: twisti@1858: // Move Gargs down to make room for dups. twisti@1858: __ sll_ptr(G5_stack_move, LogBytesPerWord, G5_stack_move); twisti@1858: __ add(Gargs, G5_stack_move, Gargs); twisti@1858: twisti@1858: // Compute the new Gargs (argslot[0]). twisti@1858: Register O2_newarg = O2_scratch; twisti@1858: __ mov(Gargs, O2_newarg); twisti@1858: twisti@1858: // Copy from oldarg[0...] down to newarg[0...] twisti@1858: // Pseude-code: twisti@1858: // O1_oldarg = old-Gargs twisti@1858: // O2_newarg = new-Gargs twisti@1858: // O0_argslot = argslot twisti@1858: // while (O2_newarg < O1_oldarg) *O2_newarg = *O0_argslot++ twisti@1858: Label loop; twisti@1858: __ bind(loop); twisti@1858: __ ld_ptr(Address(O0_argslot, 0), O3_scratch); twisti@1858: __ st_ptr(O3_scratch, Address(O2_newarg, 0)); twisti@1858: __ add(O0_argslot, wordSize, O0_argslot); twisti@1858: __ add(O2_newarg, wordSize, O2_newarg); twisti@1858: __ cmp(O2_newarg, O1_oldarg); twisti@1858: __ brx(Assembler::less, false, Assembler::pt, loop); twisti@1858: __ delayed()->nop(); // FILLME twisti@1858: twisti@2201: __ load_heap_oop(G3_mh_vmtarget, G3_method_handle); twisti@1858: __ jump_to_method_handle_entry(G3_method_handle, O1_scratch); twisti@1858: } twisti@1858: break; twisti@1858: twisti@1858: case _adapter_drop_args: twisti@1858: { twisti@1858: // 'argslot' is the position of the first argument to nuke. twisti@1858: __ ldsw(G3_amh_vmargslot, O0_argslot); twisti@1858: __ add(Gargs, __ argument_offset(O0_argslot), O0_argslot); twisti@1858: twisti@1858: // 'stack_move' is number of words to drop. twisti@1858: Register G5_stack_move = G5_index; twisti@1858: __ ldsw(G3_amh_conversion, G5_stack_move); twisti@1858: __ sra(G5_stack_move, CONV_STACK_MOVE_SHIFT, G5_stack_move); twisti@1858: twisti@1858: remove_arg_slots(_masm, G5_stack_move, O0_argslot, O1_scratch, O2_scratch, O3_scratch); twisti@1858: twisti@2201: __ load_heap_oop(G3_mh_vmtarget, G3_method_handle); twisti@1858: __ jump_to_method_handle_entry(G3_method_handle, O1_scratch); twisti@1858: } twisti@1858: break; twisti@1858: twisti@1858: case _adapter_collect_args: twisti@1858: __ unimplemented(entry_name(ek)); // %%% FIXME: NYI twisti@1858: break; twisti@1858: twisti@1858: case _adapter_spread_args: twisti@1858: // Handled completely by optimized cases. twisti@1858: __ stop("init_AdapterMethodHandle should not issue this"); twisti@1858: break; twisti@1858: twisti@1858: case _adapter_opt_spread_0: twisti@1858: case _adapter_opt_spread_1: twisti@1858: case _adapter_opt_spread_more: twisti@1858: { twisti@1858: // spread an array out into a group of arguments twisti@1858: __ unimplemented(entry_name(ek)); twisti@1858: } twisti@1858: break; twisti@1858: twisti@1858: case _adapter_flyby: twisti@1858: case _adapter_ricochet: twisti@1858: __ unimplemented(entry_name(ek)); // %%% FIXME: NYI twisti@1858: break; twisti@1858: twisti@1858: default: twisti@1858: ShouldNotReachHere(); twisti@1858: } twisti@1858: twisti@1858: address me_cookie = MethodHandleEntry::start_compiled_entry(_masm, interp_entry); twisti@1858: __ unimplemented(entry_name(ek)); // %%% FIXME: NYI twisti@1858: twisti@1858: init_entry(ek, MethodHandleEntry::finish_compiled_entry(_masm, me_cookie)); jrose@1145: }