src/cpu/sparc/vm/methodHandles_sparc.cpp

Thu, 07 Apr 2011 09:53:20 -0700

author
johnc
date
Thu, 07 Apr 2011 09:53:20 -0700
changeset 2781
e1162778c1c8
parent 2664
3ef1a1866a60
child 2809
d934e4b931e9
permissions
-rw-r--r--

7009266: G1: assert(obj->is_oop_or_null(true )) failed: Error
Summary: A referent object that is only weakly reachable at the start of concurrent marking but is re-attached to the strongly reachable object graph during marking may not be marked as live. This can cause the reference object to be processed prematurely and leave dangling pointers to the referent object. Implement a read barrier for the java.lang.ref.Reference::referent field by intrinsifying the Reference.get() method, and intercepting accesses though JNI, reflection, and Unsafe, so that when a non-null referent object is read it is also logged in an SATB buffer.
Reviewed-by: kvn, iveresov, never, tonyp, dholmes

jrose@1145 1 /*
twisti@2436 2 * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
jrose@1145 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jrose@1145 4 *
jrose@1145 5 * This code is free software; you can redistribute it and/or modify it
jrose@1145 6 * under the terms of the GNU General Public License version 2 only, as
jrose@1145 7 * published by the Free Software Foundation.
jrose@1145 8 *
jrose@1145 9 * This code is distributed in the hope that it will be useful, but WITHOUT
jrose@1145 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jrose@1145 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jrose@1145 12 * version 2 for more details (a copy is included in the LICENSE file that
jrose@1145 13 * accompanied this code).
jrose@1145 14 *
jrose@1145 15 * You should have received a copy of the GNU General Public License version
jrose@1145 16 * 2 along with this work; if not, write to the Free Software Foundation,
jrose@1145 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jrose@1145 18 *
trims@1907 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
trims@1907 20 * or visit www.oracle.com if you need additional information or have any
trims@1907 21 * questions.
jrose@1145 22 *
jrose@1145 23 */
jrose@1145 24
stefank@2314 25 #include "precompiled.hpp"
stefank@2314 26 #include "interpreter/interpreter.hpp"
stefank@2314 27 #include "memory/allocation.inline.hpp"
stefank@2314 28 #include "prims/methodHandles.hpp"
jrose@1145 29
jrose@1145 30 #define __ _masm->
jrose@1145 31
twisti@2204 32 #ifdef PRODUCT
twisti@2204 33 #define BLOCK_COMMENT(str) /* nothing */
twisti@2204 34 #else
twisti@2204 35 #define BLOCK_COMMENT(str) __ block_comment(str)
twisti@2204 36 #endif
twisti@2204 37
twisti@2204 38 #define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
twisti@2204 39
jrose@1145 40 address MethodHandleEntry::start_compiled_entry(MacroAssembler* _masm,
jrose@1145 41 address interpreted_entry) {
twisti@1858 42 // Just before the actual machine code entry point, allocate space
twisti@1858 43 // for a MethodHandleEntry::Data record, so that we can manage everything
twisti@1858 44 // from one base pointer.
jrose@1145 45 __ align(wordSize);
jrose@1145 46 address target = __ pc() + sizeof(Data);
jrose@1145 47 while (__ pc() < target) {
jrose@1145 48 __ nop();
jrose@1145 49 __ align(wordSize);
jrose@1145 50 }
jrose@1145 51
jrose@1145 52 MethodHandleEntry* me = (MethodHandleEntry*) __ pc();
jrose@1145 53 me->set_end_address(__ pc()); // set a temporary end_address
jrose@1145 54 me->set_from_interpreted_entry(interpreted_entry);
jrose@1145 55 me->set_type_checking_entry(NULL);
jrose@1145 56
jrose@1145 57 return (address) me;
jrose@1145 58 }
jrose@1145 59
jrose@1145 60 MethodHandleEntry* MethodHandleEntry::finish_compiled_entry(MacroAssembler* _masm,
jrose@1145 61 address start_addr) {
jrose@1145 62 MethodHandleEntry* me = (MethodHandleEntry*) start_addr;
jrose@1145 63 assert(me->end_address() == start_addr, "valid ME");
jrose@1145 64
jrose@1145 65 // Fill in the real end_address:
jrose@1145 66 __ align(wordSize);
jrose@1145 67 me->set_end_address(__ pc());
jrose@1145 68
jrose@1145 69 return me;
jrose@1145 70 }
jrose@1145 71
jrose@1145 72
jrose@1145 73 // Code generation
jrose@1145 74 address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) {
twisti@2271 75 // I5_savedSP/O5_savedSP: sender SP (must preserve)
twisti@1858 76 // G4 (Gargs): incoming argument list (must preserve)
twisti@2271 77 // G5_method: invoke methodOop
twisti@1858 78 // G3_method_handle: receiver method handle (must load from sp[MethodTypeForm.vmslots])
twisti@2271 79 // O0, O1, O2, O3, O4: garbage temps, blown away
twisti@2271 80 Register O0_mtype = O0;
twisti@1858 81 Register O1_scratch = O1;
jrose@2266 82 Register O2_scratch = O2;
jrose@2266 83 Register O3_scratch = O3;
twisti@2271 84 Register O4_argslot = O4;
jrose@2266 85 Register O4_argbase = O4;
twisti@1858 86
twisti@1858 87 // emit WrongMethodType path first, to enable back-branch from main path
twisti@1858 88 Label wrong_method_type;
twisti@1858 89 __ bind(wrong_method_type);
jrose@2266 90 Label invoke_generic_slow_path;
jrose@2266 91 assert(methodOopDesc::intrinsic_id_size_in_bytes() == sizeof(u1), "");;
jrose@2266 92 __ ldub(Address(G5_method, methodOopDesc::intrinsic_id_offset_in_bytes()), O1_scratch);
jrose@2266 93 __ cmp(O1_scratch, (int) vmIntrinsics::_invokeExact);
jrose@2266 94 __ brx(Assembler::notEqual, false, Assembler::pt, invoke_generic_slow_path);
jrose@2266 95 __ delayed()->nop();
twisti@2271 96 __ mov(O0_mtype, G5_method_type); // required by throw_WrongMethodType
jrose@2266 97 // mov(G3_method_handle, G3_method_handle); // already in this register
twisti@1858 98 __ jump_to(AddressLiteral(Interpreter::throw_WrongMethodType_entry()), O1_scratch);
twisti@1858 99 __ delayed()->nop();
twisti@1858 100
twisti@1858 101 // here's where control starts out:
twisti@1858 102 __ align(CodeEntryAlignment);
twisti@1858 103 address entry_point = __ pc();
twisti@1858 104
jrose@2266 105 // fetch the MethodType from the method handle
twisti@1858 106 {
twisti@1858 107 Register tem = G5_method;
twisti@1858 108 for (jint* pchase = methodOopDesc::method_type_offsets_chain(); (*pchase) != -1; pchase++) {
twisti@2271 109 __ ld_ptr(Address(tem, *pchase), O0_mtype);
twisti@2271 110 tem = O0_mtype; // in case there is another indirection
twisti@1858 111 }
twisti@1858 112 }
twisti@1858 113
twisti@1858 114 // given the MethodType, find out where the MH argument is buried
jrose@2639 115 __ load_heap_oop(Address(O0_mtype, __ delayed_value(java_lang_invoke_MethodType::form_offset_in_bytes, O1_scratch)), O4_argslot);
jrose@2639 116 __ ldsw( Address(O4_argslot, __ delayed_value(java_lang_invoke_MethodTypeForm::vmslots_offset_in_bytes, O1_scratch)), O4_argslot);
twisti@2271 117 __ add(Gargs, __ argument_offset(O4_argslot, 1), O4_argbase);
jrose@2266 118 // Note: argument_address uses its input as a scratch register!
jrose@2266 119 __ ld_ptr(Address(O4_argbase, -Interpreter::stackElementSize), G3_method_handle);
twisti@1858 120
jrose@2266 121 trace_method_handle(_masm, "invokeExact");
jrose@2266 122
twisti@2271 123 __ check_method_handle_type(O0_mtype, G3_method_handle, O1_scratch, wrong_method_type);
twisti@1858 124 __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
twisti@1858 125
jrose@2266 126 // for invokeGeneric (only), apply argument and result conversions on the fly
jrose@2266 127 __ bind(invoke_generic_slow_path);
jrose@2266 128 #ifdef ASSERT
jrose@2266 129 { Label L;
jrose@2266 130 __ ldub(Address(G5_method, methodOopDesc::intrinsic_id_offset_in_bytes()), O1_scratch);
jrose@2266 131 __ cmp(O1_scratch, (int) vmIntrinsics::_invokeGeneric);
jrose@2266 132 __ brx(Assembler::equal, false, Assembler::pt, L);
jrose@2266 133 __ delayed()->nop();
jrose@2266 134 __ stop("bad methodOop::intrinsic_id");
jrose@2266 135 __ bind(L);
jrose@2266 136 }
jrose@2266 137 #endif //ASSERT
jrose@2266 138
jrose@2266 139 // make room on the stack for another pointer:
twisti@2271 140 insert_arg_slots(_masm, 2 * stack_move_unit(), _INSERT_REF_MASK, O4_argbase, O1_scratch, O2_scratch, O3_scratch);
jrose@2266 141 // load up an adapter from the calling type (Java weaves this)
jrose@2266 142 Register O2_form = O2_scratch;
jrose@2266 143 Register O3_adapter = O3_scratch;
jrose@2639 144 __ load_heap_oop(Address(O0_mtype, __ delayed_value(java_lang_invoke_MethodType::form_offset_in_bytes, O1_scratch)), O2_form);
jrose@2639 145 // load_heap_oop(Address(O2_form, __ delayed_value(java_lang_invoke_MethodTypeForm::genericInvoker_offset_in_bytes, O1_scratch)), O3_adapter);
jrose@2266 146 // deal with old JDK versions:
jrose@2639 147 __ add( Address(O2_form, __ delayed_value(java_lang_invoke_MethodTypeForm::genericInvoker_offset_in_bytes, O1_scratch)), O3_adapter);
jrose@2266 148 __ cmp(O3_adapter, O2_form);
jrose@2266 149 Label sorry_no_invoke_generic;
jrose@2266 150 __ brx(Assembler::lessUnsigned, false, Assembler::pn, sorry_no_invoke_generic);
jrose@2266 151 __ delayed()->nop();
jrose@2266 152
jrose@2266 153 __ load_heap_oop(Address(O3_adapter, 0), O3_adapter);
jrose@2266 154 __ tst(O3_adapter);
jrose@2266 155 __ brx(Assembler::zero, false, Assembler::pn, sorry_no_invoke_generic);
jrose@2266 156 __ delayed()->nop();
jrose@2266 157 __ st_ptr(O3_adapter, Address(O4_argbase, 1 * Interpreter::stackElementSize));
jrose@2266 158 // As a trusted first argument, pass the type being called, so the adapter knows
jrose@2266 159 // the actual types of the arguments and return values.
jrose@2266 160 // (Generic invokers are shared among form-families of method-type.)
twisti@2271 161 __ st_ptr(O0_mtype, Address(O4_argbase, 0 * Interpreter::stackElementSize));
jrose@2266 162 // FIXME: assert that O3_adapter is of the right method-type.
jrose@2266 163 __ mov(O3_adapter, G3_method_handle);
jrose@2266 164 trace_method_handle(_masm, "invokeGeneric");
jrose@2266 165 __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
jrose@2266 166
jrose@2266 167 __ bind(sorry_no_invoke_generic); // no invokeGeneric implementation available!
twisti@2271 168 __ mov(O0_mtype, G5_method_type); // required by throw_WrongMethodType
jrose@2266 169 // mov(G3_method_handle, G3_method_handle); // already in this register
jrose@2266 170 __ jump_to(AddressLiteral(Interpreter::throw_WrongMethodType_entry()), O1_scratch);
jrose@2266 171 __ delayed()->nop();
jrose@2266 172
twisti@1858 173 return entry_point;
jrose@1145 174 }
jrose@1145 175
twisti@1858 176
twisti@1858 177 #ifdef ASSERT
twisti@1858 178 static void verify_argslot(MacroAssembler* _masm, Register argslot_reg, Register temp_reg, const char* error_message) {
twisti@1858 179 // Verify that argslot lies within (Gargs, FP].
twisti@1858 180 Label L_ok, L_bad;
twisti@2204 181 BLOCK_COMMENT("{ verify_argslot");
twisti@1858 182 #ifdef _LP64
twisti@1858 183 __ add(FP, STACK_BIAS, temp_reg);
twisti@1858 184 __ cmp(argslot_reg, temp_reg);
twisti@1858 185 #else
twisti@1858 186 __ cmp(argslot_reg, FP);
twisti@1858 187 #endif
twisti@1858 188 __ brx(Assembler::greaterUnsigned, false, Assembler::pn, L_bad);
twisti@1858 189 __ delayed()->nop();
twisti@1858 190 __ cmp(Gargs, argslot_reg);
twisti@1858 191 __ brx(Assembler::lessEqualUnsigned, false, Assembler::pt, L_ok);
twisti@1858 192 __ delayed()->nop();
twisti@1858 193 __ bind(L_bad);
twisti@1858 194 __ stop(error_message);
twisti@1858 195 __ bind(L_ok);
twisti@2204 196 BLOCK_COMMENT("} verify_argslot");
twisti@1858 197 }
twisti@1858 198 #endif
twisti@1858 199
twisti@1858 200
twisti@1858 201 // Helper to insert argument slots into the stack.
twisti@1858 202 // arg_slots must be a multiple of stack_move_unit() and <= 0
twisti@1858 203 void MethodHandles::insert_arg_slots(MacroAssembler* _masm,
twisti@1858 204 RegisterOrConstant arg_slots,
twisti@1858 205 int arg_mask,
twisti@1858 206 Register argslot_reg,
twisti@1858 207 Register temp_reg, Register temp2_reg, Register temp3_reg) {
twisti@1858 208 assert(temp3_reg != noreg, "temp3 required");
twisti@1858 209 assert_different_registers(argslot_reg, temp_reg, temp2_reg, temp3_reg,
twisti@1858 210 (!arg_slots.is_register() ? Gargs : arg_slots.as_register()));
twisti@1858 211
twisti@1858 212 #ifdef ASSERT
twisti@1858 213 verify_argslot(_masm, argslot_reg, temp_reg, "insertion point must fall within current frame");
twisti@1858 214 if (arg_slots.is_register()) {
twisti@1858 215 Label L_ok, L_bad;
twisti@1858 216 __ cmp(arg_slots.as_register(), (int32_t) NULL_WORD);
twisti@1858 217 __ br(Assembler::greater, false, Assembler::pn, L_bad);
twisti@1858 218 __ delayed()->nop();
twisti@1858 219 __ btst(-stack_move_unit() - 1, arg_slots.as_register());
twisti@1858 220 __ br(Assembler::zero, false, Assembler::pt, L_ok);
twisti@1858 221 __ delayed()->nop();
twisti@1858 222 __ bind(L_bad);
twisti@1858 223 __ stop("assert arg_slots <= 0 and clear low bits");
twisti@1858 224 __ bind(L_ok);
twisti@1858 225 } else {
twisti@1858 226 assert(arg_slots.as_constant() <= 0, "");
twisti@1858 227 assert(arg_slots.as_constant() % -stack_move_unit() == 0, "");
twisti@1858 228 }
twisti@1858 229 #endif // ASSERT
twisti@1858 230
twisti@1858 231 #ifdef _LP64
twisti@1858 232 if (arg_slots.is_register()) {
twisti@1858 233 // Was arg_slots register loaded as signed int?
twisti@1858 234 Label L_ok;
twisti@1858 235 __ sll(arg_slots.as_register(), BitsPerInt, temp_reg);
twisti@1858 236 __ sra(temp_reg, BitsPerInt, temp_reg);
twisti@1858 237 __ cmp(arg_slots.as_register(), temp_reg);
twisti@1858 238 __ br(Assembler::equal, false, Assembler::pt, L_ok);
twisti@1858 239 __ delayed()->nop();
twisti@1858 240 __ stop("arg_slots register not loaded as signed int");
twisti@1858 241 __ bind(L_ok);
twisti@1858 242 }
twisti@1858 243 #endif
twisti@1858 244
twisti@1858 245 // Make space on the stack for the inserted argument(s).
twisti@1858 246 // Then pull down everything shallower than argslot_reg.
twisti@1858 247 // The stacked return address gets pulled down with everything else.
twisti@1858 248 // That is, copy [sp, argslot) downward by -size words. In pseudo-code:
twisti@1858 249 // sp -= size;
twisti@1858 250 // for (temp = sp + size; temp < argslot; temp++)
twisti@1858 251 // temp[-size] = temp[0]
twisti@1858 252 // argslot -= size;
twisti@2204 253 BLOCK_COMMENT("insert_arg_slots {");
twisti@1858 254 RegisterOrConstant offset = __ regcon_sll_ptr(arg_slots, LogBytesPerWord, temp3_reg);
twisti@1858 255
twisti@1858 256 // Keep the stack pointer 2*wordSize aligned.
twisti@1858 257 const int TwoWordAlignmentMask = right_n_bits(LogBytesPerWord + 1);
twisti@1858 258 RegisterOrConstant masked_offset = __ regcon_andn_ptr(offset, TwoWordAlignmentMask, temp_reg);
twisti@1858 259 __ add(SP, masked_offset, SP);
twisti@1858 260
twisti@1858 261 __ mov(Gargs, temp_reg); // source pointer for copy
twisti@1858 262 __ add(Gargs, offset, Gargs);
twisti@1858 263
twisti@1858 264 {
twisti@1858 265 Label loop;
twisti@2204 266 __ BIND(loop);
twisti@1858 267 // pull one word down each time through the loop
twisti@1858 268 __ ld_ptr(Address(temp_reg, 0), temp2_reg);
twisti@1858 269 __ st_ptr(temp2_reg, Address(temp_reg, offset));
twisti@1858 270 __ add(temp_reg, wordSize, temp_reg);
twisti@1858 271 __ cmp(temp_reg, argslot_reg);
twisti@1858 272 __ brx(Assembler::less, false, Assembler::pt, loop);
twisti@1858 273 __ delayed()->nop(); // FILLME
twisti@1858 274 }
twisti@1858 275
twisti@1858 276 // Now move the argslot down, to point to the opened-up space.
twisti@1858 277 __ add(argslot_reg, offset, argslot_reg);
twisti@2204 278 BLOCK_COMMENT("} insert_arg_slots");
twisti@1858 279 }
twisti@1858 280
twisti@1858 281
twisti@1858 282 // Helper to remove argument slots from the stack.
twisti@1858 283 // arg_slots must be a multiple of stack_move_unit() and >= 0
twisti@1858 284 void MethodHandles::remove_arg_slots(MacroAssembler* _masm,
twisti@1858 285 RegisterOrConstant arg_slots,
twisti@1858 286 Register argslot_reg,
twisti@1858 287 Register temp_reg, Register temp2_reg, Register temp3_reg) {
twisti@1858 288 assert(temp3_reg != noreg, "temp3 required");
twisti@1858 289 assert_different_registers(argslot_reg, temp_reg, temp2_reg, temp3_reg,
twisti@1858 290 (!arg_slots.is_register() ? Gargs : arg_slots.as_register()));
twisti@1858 291
twisti@1858 292 RegisterOrConstant offset = __ regcon_sll_ptr(arg_slots, LogBytesPerWord, temp3_reg);
twisti@1858 293
twisti@1858 294 #ifdef ASSERT
twisti@1858 295 // Verify that [argslot..argslot+size) lies within (Gargs, FP).
twisti@1858 296 __ add(argslot_reg, offset, temp2_reg);
twisti@1858 297 verify_argslot(_masm, temp2_reg, temp_reg, "deleted argument(s) must fall within current frame");
twisti@1858 298 if (arg_slots.is_register()) {
twisti@1858 299 Label L_ok, L_bad;
twisti@1858 300 __ cmp(arg_slots.as_register(), (int32_t) NULL_WORD);
twisti@1858 301 __ br(Assembler::less, false, Assembler::pn, L_bad);
twisti@1858 302 __ delayed()->nop();
twisti@1858 303 __ btst(-stack_move_unit() - 1, arg_slots.as_register());
twisti@1858 304 __ br(Assembler::zero, false, Assembler::pt, L_ok);
twisti@1858 305 __ delayed()->nop();
twisti@1858 306 __ bind(L_bad);
twisti@1858 307 __ stop("assert arg_slots >= 0 and clear low bits");
twisti@1858 308 __ bind(L_ok);
twisti@1858 309 } else {
twisti@1858 310 assert(arg_slots.as_constant() >= 0, "");
twisti@1858 311 assert(arg_slots.as_constant() % -stack_move_unit() == 0, "");
twisti@1858 312 }
twisti@1858 313 #endif // ASSERT
twisti@1858 314
twisti@2204 315 BLOCK_COMMENT("remove_arg_slots {");
twisti@1858 316 // Pull up everything shallower than argslot.
twisti@1858 317 // Then remove the excess space on the stack.
twisti@1858 318 // The stacked return address gets pulled up with everything else.
twisti@1858 319 // That is, copy [sp, argslot) upward by size words. In pseudo-code:
twisti@1858 320 // for (temp = argslot-1; temp >= sp; --temp)
twisti@1858 321 // temp[size] = temp[0]
twisti@1858 322 // argslot += size;
twisti@1858 323 // sp += size;
twisti@1858 324 __ sub(argslot_reg, wordSize, temp_reg); // source pointer for copy
twisti@1858 325 {
twisti@1858 326 Label loop;
twisti@2204 327 __ BIND(loop);
twisti@1858 328 // pull one word up each time through the loop
twisti@1858 329 __ ld_ptr(Address(temp_reg, 0), temp2_reg);
twisti@1858 330 __ st_ptr(temp2_reg, Address(temp_reg, offset));
twisti@1858 331 __ sub(temp_reg, wordSize, temp_reg);
twisti@1858 332 __ cmp(temp_reg, Gargs);
twisti@1858 333 __ brx(Assembler::greaterEqual, false, Assembler::pt, loop);
twisti@1858 334 __ delayed()->nop(); // FILLME
twisti@1858 335 }
twisti@1858 336
twisti@1858 337 // Now move the argslot up, to point to the just-copied block.
twisti@1858 338 __ add(Gargs, offset, Gargs);
twisti@1858 339 // And adjust the argslot address to point at the deletion point.
twisti@1858 340 __ add(argslot_reg, offset, argslot_reg);
twisti@1858 341
twisti@1858 342 // Keep the stack pointer 2*wordSize aligned.
twisti@1858 343 const int TwoWordAlignmentMask = right_n_bits(LogBytesPerWord + 1);
twisti@1858 344 RegisterOrConstant masked_offset = __ regcon_andn_ptr(offset, TwoWordAlignmentMask, temp_reg);
twisti@1858 345 __ add(SP, masked_offset, SP);
twisti@2204 346 BLOCK_COMMENT("} remove_arg_slots");
twisti@1858 347 }
twisti@1858 348
twisti@1858 349
twisti@1858 350 #ifndef PRODUCT
twisti@1858 351 extern "C" void print_method_handle(oop mh);
twisti@1858 352 void trace_method_handle_stub(const char* adaptername,
twisti@2204 353 oopDesc* mh) {
twisti@1858 354 printf("MH %s mh="INTPTR_FORMAT"\n", adaptername, (intptr_t) mh);
twisti@1858 355 print_method_handle(mh);
twisti@1858 356 }
twisti@2204 357 void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) {
twisti@2204 358 if (!TraceMethodHandles) return;
twisti@2204 359 BLOCK_COMMENT("trace_method_handle {");
twisti@2204 360 // save: Gargs, O5_savedSP
twisti@2204 361 __ save_frame(16);
twisti@2204 362 __ set((intptr_t) adaptername, O0);
twisti@2204 363 __ mov(G3_method_handle, O1);
twisti@2204 364 __ mov(G3_method_handle, L3);
twisti@2204 365 __ mov(Gargs, L4);
twisti@2204 366 __ mov(G5_method_type, L5);
twisti@2204 367 __ call_VM_leaf(L7, CAST_FROM_FN_PTR(address, trace_method_handle_stub));
twisti@2204 368
twisti@2204 369 __ mov(L3, G3_method_handle);
twisti@2204 370 __ mov(L4, Gargs);
twisti@2204 371 __ mov(L5, G5_method_type);
twisti@2204 372 __ restore();
twisti@2204 373 BLOCK_COMMENT("} trace_method_handle");
twisti@2204 374 }
twisti@1858 375 #endif // PRODUCT
twisti@1858 376
jrose@1862 377 // which conversion op types are implemented here?
jrose@1862 378 int MethodHandles::adapter_conversion_ops_supported_mask() {
jrose@2639 379 return ((1<<java_lang_invoke_AdapterMethodHandle::OP_RETYPE_ONLY)
jrose@2639 380 |(1<<java_lang_invoke_AdapterMethodHandle::OP_RETYPE_RAW)
jrose@2639 381 |(1<<java_lang_invoke_AdapterMethodHandle::OP_CHECK_CAST)
jrose@2639 382 |(1<<java_lang_invoke_AdapterMethodHandle::OP_PRIM_TO_PRIM)
jrose@2639 383 |(1<<java_lang_invoke_AdapterMethodHandle::OP_REF_TO_PRIM)
jrose@2639 384 |(1<<java_lang_invoke_AdapterMethodHandle::OP_SWAP_ARGS)
jrose@2639 385 |(1<<java_lang_invoke_AdapterMethodHandle::OP_ROT_ARGS)
jrose@2639 386 |(1<<java_lang_invoke_AdapterMethodHandle::OP_DUP_ARGS)
jrose@2639 387 |(1<<java_lang_invoke_AdapterMethodHandle::OP_DROP_ARGS)
jrose@2639 388 //|(1<<java_lang_invoke_AdapterMethodHandle::OP_SPREAD_ARGS) //BUG!
jrose@1862 389 );
jrose@1862 390 // FIXME: MethodHandlesTest gets a crash if we enable OP_SPREAD_ARGS.
jrose@1862 391 }
twisti@1858 392
twisti@1858 393 //------------------------------------------------------------------------------
twisti@1858 394 // MethodHandles::generate_method_handle_stub
twisti@1858 395 //
jrose@1145 396 // Generate an "entry" field for a method handle.
jrose@1145 397 // This determines how the method handle will respond to calls.
twisti@2436 398 void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) {
twisti@1858 399 // Here is the register state during an interpreted call,
twisti@1858 400 // as set up by generate_method_handle_interpreter_entry():
twisti@1858 401 // - G5: garbage temp (was MethodHandle.invoke methodOop, unused)
twisti@1858 402 // - G3: receiver method handle
twisti@1858 403 // - O5_savedSP: sender SP (must preserve)
twisti@1858 404
twisti@2411 405 const Register O0_argslot = O0;
twisti@2411 406 const Register O1_scratch = O1;
twisti@2411 407 const Register O2_scratch = O2;
twisti@2411 408 const Register O3_scratch = O3;
twisti@2411 409 const Register G5_index = G5;
twisti@2411 410
twisti@2411 411 // Argument registers for _raise_exception.
twisti@2411 412 const Register O0_code = O0;
twisti@2411 413 const Register O1_actual = O1;
twisti@2411 414 const Register O2_required = O2;
twisti@1858 415
jrose@2639 416 guarantee(java_lang_invoke_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets");
twisti@1858 417
twisti@1858 418 // Some handy addresses:
twisti@1858 419 Address G5_method_fie( G5_method, in_bytes(methodOopDesc::from_interpreted_offset()));
twisti@2603 420 Address G5_method_fce( G5_method, in_bytes(methodOopDesc::from_compiled_offset()));
twisti@1858 421
jrose@2639 422 Address G3_mh_vmtarget( G3_method_handle, java_lang_invoke_MethodHandle::vmtarget_offset_in_bytes());
twisti@1858 423
jrose@2639 424 Address G3_dmh_vmindex( G3_method_handle, java_lang_invoke_DirectMethodHandle::vmindex_offset_in_bytes());
twisti@1858 425
jrose@2639 426 Address G3_bmh_vmargslot( G3_method_handle, java_lang_invoke_BoundMethodHandle::vmargslot_offset_in_bytes());
jrose@2639 427 Address G3_bmh_argument( G3_method_handle, java_lang_invoke_BoundMethodHandle::argument_offset_in_bytes());
twisti@1858 428
jrose@2639 429 Address G3_amh_vmargslot( G3_method_handle, java_lang_invoke_AdapterMethodHandle::vmargslot_offset_in_bytes());
jrose@2639 430 Address G3_amh_argument ( G3_method_handle, java_lang_invoke_AdapterMethodHandle::argument_offset_in_bytes());
jrose@2639 431 Address G3_amh_conversion(G3_method_handle, java_lang_invoke_AdapterMethodHandle::conversion_offset_in_bytes());
twisti@1858 432
twisti@1858 433 const int java_mirror_offset = klassOopDesc::klass_part_offset_in_bytes() + Klass::java_mirror_offset_in_bytes();
twisti@1858 434
twisti@1858 435 if (have_entry(ek)) {
twisti@1858 436 __ nop(); // empty stubs make SG sick
twisti@1858 437 return;
twisti@1858 438 }
twisti@1858 439
twisti@1858 440 address interp_entry = __ pc();
twisti@1858 441
twisti@2204 442 trace_method_handle(_masm, entry_name(ek));
twisti@1858 443
twisti@1858 444 switch ((int) ek) {
twisti@1858 445 case _raise_exception:
twisti@1858 446 {
twisti@1858 447 // Not a real MH entry, but rather shared code for raising an
twisti@2603 448 // exception. Since we use the compiled entry, arguments are
twisti@2603 449 // expected in compiler argument registers.
twisti@2436 450 assert(raise_exception_method(), "must be set");
twisti@2603 451 assert(raise_exception_method()->from_compiled_entry(), "method must be linked");
twisti@1858 452
twisti@1858 453 __ mov(O5_savedSP, SP); // Cut the stack back to where the caller started.
twisti@1858 454
twisti@2411 455 Label L_no_method;
jrose@2639 456 // FIXME: fill in _raise_exception_method with a suitable java.lang.invoke method
twisti@1858 457 __ set(AddressLiteral((address) &_raise_exception_method), G5_method);
twisti@1858 458 __ ld_ptr(Address(G5_method, 0), G5_method);
twisti@1858 459 __ tst(G5_method);
twisti@2411 460 __ brx(Assembler::zero, false, Assembler::pn, L_no_method);
twisti@1858 461 __ delayed()->nop();
twisti@1858 462
twisti@2411 463 const int jobject_oop_offset = 0;
twisti@1858 464 __ ld_ptr(Address(G5_method, jobject_oop_offset), G5_method);
twisti@1858 465 __ tst(G5_method);
twisti@2411 466 __ brx(Assembler::zero, false, Assembler::pn, L_no_method);
twisti@1858 467 __ delayed()->nop();
twisti@1858 468
twisti@1858 469 __ verify_oop(G5_method);
twisti@2603 470 __ jump_indirect_to(G5_method_fce, O3_scratch); // jump to compiled entry
twisti@1858 471 __ delayed()->nop();
twisti@1858 472
twisti@1858 473 // Do something that is at least causes a valid throw from the interpreter.
twisti@2411 474 __ bind(L_no_method);
twisti@2411 475 __ unimplemented("call throw_WrongMethodType_entry");
twisti@1858 476 }
twisti@1858 477 break;
twisti@1858 478
twisti@1858 479 case _invokestatic_mh:
twisti@1858 480 case _invokespecial_mh:
twisti@1858 481 {
twisti@2201 482 __ load_heap_oop(G3_mh_vmtarget, G5_method); // target is a methodOop
twisti@1858 483 __ verify_oop(G5_method);
twisti@1858 484 // Same as TemplateTable::invokestatic or invokespecial,
twisti@1858 485 // minus the CP setup and profiling:
twisti@1858 486 if (ek == _invokespecial_mh) {
twisti@1858 487 // Must load & check the first argument before entering the target method.
twisti@1858 488 __ load_method_handle_vmslots(O0_argslot, G3_method_handle, O1_scratch);
twisti@1858 489 __ ld_ptr(__ argument_address(O0_argslot), G3_method_handle);
twisti@1858 490 __ null_check(G3_method_handle);
twisti@1858 491 __ verify_oop(G3_method_handle);
twisti@1858 492 }
twisti@1858 493 __ jump_indirect_to(G5_method_fie, O1_scratch);
twisti@1858 494 __ delayed()->nop();
twisti@1858 495 }
twisti@1858 496 break;
twisti@1858 497
twisti@1858 498 case _invokevirtual_mh:
twisti@1858 499 {
twisti@1858 500 // Same as TemplateTable::invokevirtual,
twisti@1858 501 // minus the CP setup and profiling:
twisti@1858 502
twisti@1858 503 // Pick out the vtable index and receiver offset from the MH,
twisti@1858 504 // and then we can discard it:
twisti@1858 505 __ load_method_handle_vmslots(O0_argslot, G3_method_handle, O1_scratch);
twisti@1858 506 __ ldsw(G3_dmh_vmindex, G5_index);
twisti@1858 507 // Note: The verifier allows us to ignore G3_mh_vmtarget.
twisti@1858 508 __ ld_ptr(__ argument_address(O0_argslot, -1), G3_method_handle);
twisti@1858 509 __ null_check(G3_method_handle, oopDesc::klass_offset_in_bytes());
twisti@1858 510
twisti@1858 511 // Get receiver klass:
twisti@1858 512 Register O0_klass = O0_argslot;
twisti@1858 513 __ load_klass(G3_method_handle, O0_klass);
twisti@1858 514 __ verify_oop(O0_klass);
twisti@1858 515
twisti@1858 516 // Get target methodOop & entry point:
twisti@1858 517 const int base = instanceKlass::vtable_start_offset() * wordSize;
twisti@1858 518 assert(vtableEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
twisti@1858 519
twisti@1858 520 __ sll_ptr(G5_index, LogBytesPerWord, G5_index);
twisti@1858 521 __ add(O0_klass, G5_index, O0_klass);
twisti@1858 522 Address vtable_entry_addr(O0_klass, base + vtableEntry::method_offset_in_bytes());
twisti@1858 523 __ ld_ptr(vtable_entry_addr, G5_method);
twisti@1858 524
twisti@1858 525 __ verify_oop(G5_method);
twisti@1858 526 __ jump_indirect_to(G5_method_fie, O1_scratch);
twisti@1858 527 __ delayed()->nop();
twisti@1858 528 }
twisti@1858 529 break;
twisti@1858 530
twisti@1858 531 case _invokeinterface_mh:
twisti@1858 532 {
twisti@1858 533 // Same as TemplateTable::invokeinterface,
twisti@1858 534 // minus the CP setup and profiling:
twisti@1858 535 __ load_method_handle_vmslots(O0_argslot, G3_method_handle, O1_scratch);
twisti@1858 536 Register O1_intf = O1_scratch;
twisti@2201 537 __ load_heap_oop(G3_mh_vmtarget, O1_intf);
twisti@1858 538 __ ldsw(G3_dmh_vmindex, G5_index);
twisti@1858 539 __ ld_ptr(__ argument_address(O0_argslot, -1), G3_method_handle);
twisti@1858 540 __ null_check(G3_method_handle, oopDesc::klass_offset_in_bytes());
twisti@1858 541
twisti@1858 542 // Get receiver klass:
twisti@1858 543 Register O0_klass = O0_argslot;
twisti@1858 544 __ load_klass(G3_method_handle, O0_klass);
twisti@1858 545 __ verify_oop(O0_klass);
twisti@1858 546
twisti@1858 547 // Get interface:
twisti@1858 548 Label no_such_interface;
twisti@1858 549 __ verify_oop(O1_intf);
twisti@1858 550 __ lookup_interface_method(O0_klass, O1_intf,
twisti@1858 551 // Note: next two args must be the same:
twisti@1858 552 G5_index, G5_method,
twisti@1858 553 O2_scratch,
twisti@1858 554 O3_scratch,
twisti@1858 555 no_such_interface);
twisti@1858 556
twisti@1858 557 __ verify_oop(G5_method);
twisti@1858 558 __ jump_indirect_to(G5_method_fie, O1_scratch);
twisti@1858 559 __ delayed()->nop();
twisti@1858 560
twisti@1858 561 __ bind(no_such_interface);
twisti@1858 562 // Throw an exception.
twisti@1858 563 // For historical reasons, it will be IncompatibleClassChangeError.
twisti@1858 564 __ unimplemented("not tested yet");
twisti@2411 565 __ ld_ptr(Address(O1_intf, java_mirror_offset), O2_required); // required interface
twisti@2411 566 __ mov( O0_klass, O1_actual); // bad receiver
twisti@2411 567 __ jump_to(AddressLiteral(from_interpreted_entry(_raise_exception)), O3_scratch);
twisti@2411 568 __ delayed()->mov(Bytecodes::_invokeinterface, O0_code); // who is complaining?
twisti@1858 569 }
twisti@1858 570 break;
twisti@1858 571
twisti@1858 572 case _bound_ref_mh:
twisti@1858 573 case _bound_int_mh:
twisti@1858 574 case _bound_long_mh:
twisti@1858 575 case _bound_ref_direct_mh:
twisti@1858 576 case _bound_int_direct_mh:
twisti@1858 577 case _bound_long_direct_mh:
twisti@1858 578 {
twisti@1858 579 const bool direct_to_method = (ek >= _bound_ref_direct_mh);
twisti@1858 580 BasicType arg_type = T_ILLEGAL;
twisti@1858 581 int arg_mask = _INSERT_NO_MASK;
twisti@1858 582 int arg_slots = -1;
twisti@1858 583 get_ek_bound_mh_info(ek, arg_type, arg_mask, arg_slots);
twisti@1858 584
twisti@1858 585 // Make room for the new argument:
twisti@1858 586 __ ldsw(G3_bmh_vmargslot, O0_argslot);
twisti@1858 587 __ add(Gargs, __ argument_offset(O0_argslot), O0_argslot);
twisti@1858 588
twisti@1858 589 insert_arg_slots(_masm, arg_slots * stack_move_unit(), arg_mask, O0_argslot, O1_scratch, O2_scratch, G5_index);
twisti@1858 590
twisti@1858 591 // Store bound argument into the new stack slot:
twisti@2201 592 __ load_heap_oop(G3_bmh_argument, O1_scratch);
twisti@1858 593 if (arg_type == T_OBJECT) {
twisti@1858 594 __ st_ptr(O1_scratch, Address(O0_argslot, 0));
twisti@1858 595 } else {
twisti@1858 596 Address prim_value_addr(O1_scratch, java_lang_boxing_object::value_offset_in_bytes(arg_type));
twisti@2565 597 const int arg_size = type2aelembytes(arg_type);
twisti@2565 598 __ load_sized_value(prim_value_addr, O2_scratch, arg_size, is_signed_subword_type(arg_type));
twisti@2565 599 __ store_sized_value(O2_scratch, Address(O0_argslot, 0), arg_size); // long store uses O2/O3 on !_LP64
twisti@1858 600 }
twisti@1858 601
twisti@1858 602 if (direct_to_method) {
twisti@2201 603 __ load_heap_oop(G3_mh_vmtarget, G5_method); // target is a methodOop
twisti@1858 604 __ verify_oop(G5_method);
twisti@1858 605 __ jump_indirect_to(G5_method_fie, O1_scratch);
twisti@1858 606 __ delayed()->nop();
twisti@1858 607 } else {
twisti@2201 608 __ load_heap_oop(G3_mh_vmtarget, G3_method_handle); // target is a methodOop
twisti@1858 609 __ verify_oop(G3_method_handle);
twisti@1858 610 __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
twisti@1858 611 }
twisti@1858 612 }
twisti@1858 613 break;
twisti@1858 614
twisti@1858 615 case _adapter_retype_only:
twisti@1858 616 case _adapter_retype_raw:
twisti@1858 617 // Immediately jump to the next MH layer:
twisti@2201 618 __ load_heap_oop(G3_mh_vmtarget, G3_method_handle);
twisti@1858 619 __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
twisti@1858 620 // This is OK when all parameter types widen.
twisti@1858 621 // It is also OK when a return type narrows.
twisti@1858 622 break;
twisti@1858 623
twisti@1858 624 case _adapter_check_cast:
twisti@1858 625 {
twisti@1858 626 // Temps:
twisti@1858 627 Register G5_klass = G5_index; // Interesting AMH data.
twisti@1858 628
twisti@1858 629 // Check a reference argument before jumping to the next layer of MH:
twisti@1858 630 __ ldsw(G3_amh_vmargslot, O0_argslot);
twisti@1858 631 Address vmarg = __ argument_address(O0_argslot);
twisti@1858 632
twisti@1858 633 // What class are we casting to?
twisti@2201 634 __ load_heap_oop(G3_amh_argument, G5_klass); // This is a Class object!
twisti@2201 635 __ load_heap_oop(Address(G5_klass, java_lang_Class::klass_offset_in_bytes()), G5_klass);
twisti@1858 636
twisti@1858 637 Label done;
twisti@1858 638 __ ld_ptr(vmarg, O1_scratch);
twisti@1858 639 __ tst(O1_scratch);
twisti@1858 640 __ brx(Assembler::zero, false, Assembler::pn, done); // No cast if null.
twisti@1858 641 __ delayed()->nop();
twisti@1858 642 __ load_klass(O1_scratch, O1_scratch);
twisti@1858 643
twisti@1858 644 // Live at this point:
twisti@1858 645 // - G5_klass : klass required by the target method
twisti@1858 646 // - O1_scratch : argument klass to test
twisti@1858 647 // - G3_method_handle: adapter method handle
twisti@1858 648 __ check_klass_subtype(O1_scratch, G5_klass, O0_argslot, O2_scratch, done);
twisti@1858 649
twisti@1858 650 // If we get here, the type check failed!
twisti@2411 651 __ load_heap_oop(G3_amh_argument, O2_required); // required class
twisti@2411 652 __ ld_ptr( vmarg, O1_actual); // bad object
twisti@2411 653 __ jump_to(AddressLiteral(from_interpreted_entry(_raise_exception)), O3_scratch);
twisti@2411 654 __ delayed()->mov(Bytecodes::_checkcast, O0_code); // who is complaining?
twisti@1858 655
twisti@1858 656 __ bind(done);
twisti@1858 657 // Get the new MH:
twisti@2201 658 __ load_heap_oop(G3_mh_vmtarget, G3_method_handle);
twisti@1858 659 __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
twisti@1858 660 }
twisti@1858 661 break;
twisti@1858 662
twisti@1858 663 case _adapter_prim_to_prim:
twisti@1858 664 case _adapter_ref_to_prim:
twisti@1858 665 // Handled completely by optimized cases.
twisti@1858 666 __ stop("init_AdapterMethodHandle should not issue this");
twisti@1858 667 break;
twisti@1858 668
twisti@1858 669 case _adapter_opt_i2i: // optimized subcase of adapt_prim_to_prim
twisti@1858 670 //case _adapter_opt_f2i: // optimized subcase of adapt_prim_to_prim
twisti@1858 671 case _adapter_opt_l2i: // optimized subcase of adapt_prim_to_prim
twisti@1858 672 case _adapter_opt_unboxi: // optimized subcase of adapt_ref_to_prim
twisti@1858 673 {
twisti@1858 674 // Perform an in-place conversion to int or an int subword.
twisti@1858 675 __ ldsw(G3_amh_vmargslot, O0_argslot);
twisti@2351 676 Address value;
twisti@1858 677 Address vmarg = __ argument_address(O0_argslot);
twisti@1858 678 bool value_left_justified = false;
twisti@1858 679
twisti@1858 680 switch (ek) {
twisti@1858 681 case _adapter_opt_i2i:
twisti@2256 682 value = vmarg;
twisti@2256 683 break;
twisti@1858 684 case _adapter_opt_l2i:
twisti@2256 685 {
twisti@2256 686 // just delete the extra slot
twisti@2351 687 #ifdef _LP64
twisti@2351 688 // In V9, longs are given 2 64-bit slots in the interpreter, but the
twisti@2351 689 // data is passed in only 1 slot.
twisti@2351 690 // Keep the second slot.
twisti@2351 691 __ add(Gargs, __ argument_offset(O0_argslot, -1), O0_argslot);
twisti@2351 692 remove_arg_slots(_masm, -stack_move_unit(), O0_argslot, O1_scratch, O2_scratch, O3_scratch);
twisti@2351 693 value = Address(O0_argslot, 4); // Get least-significant 32-bit of 64-bit value.
twisti@2351 694 vmarg = Address(O0_argslot, Interpreter::stackElementSize);
twisti@2351 695 #else
twisti@2351 696 // Keep the first slot.
twisti@2256 697 __ add(Gargs, __ argument_offset(O0_argslot), O0_argslot);
twisti@2256 698 remove_arg_slots(_masm, -stack_move_unit(), O0_argslot, O1_scratch, O2_scratch, O3_scratch);
twisti@2351 699 value = Address(O0_argslot, 0);
twisti@2351 700 vmarg = value;
twisti@2351 701 #endif
twisti@2256 702 }
twisti@1858 703 break;
twisti@1858 704 case _adapter_opt_unboxi:
twisti@1858 705 {
twisti@1858 706 // Load the value up from the heap.
twisti@1858 707 __ ld_ptr(vmarg, O1_scratch);
twisti@1858 708 int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_INT);
twisti@1858 709 #ifdef ASSERT
twisti@1858 710 for (int bt = T_BOOLEAN; bt < T_INT; bt++) {
twisti@1858 711 if (is_subword_type(BasicType(bt)))
twisti@1858 712 assert(value_offset == java_lang_boxing_object::value_offset_in_bytes(BasicType(bt)), "");
twisti@1858 713 }
twisti@1858 714 #endif
twisti@1858 715 __ null_check(O1_scratch, value_offset);
twisti@1858 716 value = Address(O1_scratch, value_offset);
twisti@1858 717 #ifdef _BIG_ENDIAN
twisti@1858 718 // Values stored in objects are packed.
twisti@1858 719 value_left_justified = true;
twisti@1858 720 #endif
twisti@1858 721 }
twisti@1858 722 break;
twisti@1858 723 default:
twisti@1858 724 ShouldNotReachHere();
twisti@1858 725 }
twisti@1858 726
twisti@1858 727 // This check is required on _BIG_ENDIAN
twisti@1858 728 Register G5_vminfo = G5_index;
twisti@1858 729 __ ldsw(G3_amh_conversion, G5_vminfo);
twisti@1858 730 assert(CONV_VMINFO_SHIFT == 0, "preshifted");
twisti@1858 731
twisti@1858 732 // Original 32-bit vmdata word must be of this form:
twisti@1858 733 // | MBZ:6 | signBitCount:8 | srcDstTypes:8 | conversionOp:8 |
twisti@1858 734 __ lduw(value, O1_scratch);
twisti@1858 735 if (!value_left_justified)
twisti@1858 736 __ sll(O1_scratch, G5_vminfo, O1_scratch);
twisti@1858 737 Label zero_extend, done;
twisti@1858 738 __ btst(CONV_VMINFO_SIGN_FLAG, G5_vminfo);
twisti@1858 739 __ br(Assembler::zero, false, Assembler::pn, zero_extend);
twisti@1858 740 __ delayed()->nop();
twisti@1858 741
twisti@1858 742 // this path is taken for int->byte, int->short
twisti@1858 743 __ sra(O1_scratch, G5_vminfo, O1_scratch);
twisti@1858 744 __ ba(false, done);
twisti@1858 745 __ delayed()->nop();
twisti@1858 746
twisti@1858 747 __ bind(zero_extend);
twisti@1858 748 // this is taken for int->char
twisti@1858 749 __ srl(O1_scratch, G5_vminfo, O1_scratch);
twisti@1858 750
twisti@1858 751 __ bind(done);
twisti@1858 752 __ st(O1_scratch, vmarg);
twisti@1858 753
twisti@1858 754 // Get the new MH:
twisti@2201 755 __ load_heap_oop(G3_mh_vmtarget, G3_method_handle);
twisti@1858 756 __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
twisti@1858 757 }
twisti@1858 758 break;
twisti@1858 759
twisti@1858 760 case _adapter_opt_i2l: // optimized subcase of adapt_prim_to_prim
twisti@1858 761 case _adapter_opt_unboxl: // optimized subcase of adapt_ref_to_prim
twisti@1858 762 {
twisti@1858 763 // Perform an in-place int-to-long or ref-to-long conversion.
twisti@1858 764 __ ldsw(G3_amh_vmargslot, O0_argslot);
twisti@1858 765
twisti@1858 766 // On big-endian machine we duplicate the slot and store the MSW
twisti@1858 767 // in the first slot.
twisti@1858 768 __ add(Gargs, __ argument_offset(O0_argslot, 1), O0_argslot);
twisti@1858 769
twisti@1858 770 insert_arg_slots(_masm, stack_move_unit(), _INSERT_INT_MASK, O0_argslot, O1_scratch, O2_scratch, G5_index);
twisti@1858 771
twisti@1858 772 Address arg_lsw(O0_argslot, 0);
twisti@1861 773 Address arg_msw(O0_argslot, -Interpreter::stackElementSize);
twisti@1858 774
twisti@1858 775 switch (ek) {
twisti@1858 776 case _adapter_opt_i2l:
twisti@1858 777 {
twisti@2664 778 #ifdef _LP64
twisti@2664 779 __ ldsw(arg_lsw, O2_scratch); // Load LSW sign-extended
twisti@2664 780 #else
twisti@2664 781 __ ldsw(arg_lsw, O3_scratch); // Load LSW sign-extended
twisti@2664 782 __ srlx(O3_scratch, BitsPerInt, O2_scratch); // Move MSW value to lower 32-bits for std
twisti@2664 783 #endif
twisti@2664 784 __ st_long(O2_scratch, arg_msw); // Uses O2/O3 on !_LP64
twisti@1858 785 }
twisti@1858 786 break;
twisti@1858 787 case _adapter_opt_unboxl:
twisti@1858 788 {
twisti@1858 789 // Load the value up from the heap.
twisti@1858 790 __ ld_ptr(arg_lsw, O1_scratch);
twisti@1858 791 int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_LONG);
twisti@1858 792 assert(value_offset == java_lang_boxing_object::value_offset_in_bytes(T_DOUBLE), "");
twisti@1858 793 __ null_check(O1_scratch, value_offset);
twisti@1858 794 __ ld_long(Address(O1_scratch, value_offset), O2_scratch); // Uses O2/O3 on !_LP64
twisti@1858 795 __ st_long(O2_scratch, arg_msw);
twisti@1858 796 }
twisti@1858 797 break;
twisti@1858 798 default:
twisti@1858 799 ShouldNotReachHere();
twisti@1858 800 }
twisti@1858 801
twisti@2201 802 __ load_heap_oop(G3_mh_vmtarget, G3_method_handle);
twisti@1858 803 __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
twisti@1858 804 }
twisti@1858 805 break;
twisti@1858 806
twisti@1858 807 case _adapter_opt_f2d: // optimized subcase of adapt_prim_to_prim
twisti@1858 808 case _adapter_opt_d2f: // optimized subcase of adapt_prim_to_prim
twisti@1858 809 {
twisti@1858 810 // perform an in-place floating primitive conversion
twisti@1858 811 __ unimplemented(entry_name(ek));
twisti@1858 812 }
twisti@1858 813 break;
twisti@1858 814
twisti@1858 815 case _adapter_prim_to_ref:
twisti@1858 816 __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
twisti@1858 817 break;
twisti@1858 818
twisti@1858 819 case _adapter_swap_args:
twisti@1858 820 case _adapter_rot_args:
twisti@1858 821 // handled completely by optimized cases
twisti@1858 822 __ stop("init_AdapterMethodHandle should not issue this");
twisti@1858 823 break;
twisti@1858 824
twisti@1858 825 case _adapter_opt_swap_1:
twisti@1858 826 case _adapter_opt_swap_2:
twisti@1858 827 case _adapter_opt_rot_1_up:
twisti@1858 828 case _adapter_opt_rot_1_down:
twisti@1858 829 case _adapter_opt_rot_2_up:
twisti@1858 830 case _adapter_opt_rot_2_down:
twisti@1858 831 {
twisti@1858 832 int swap_bytes = 0, rotate = 0;
twisti@1858 833 get_ek_adapter_opt_swap_rot_info(ek, swap_bytes, rotate);
twisti@1858 834
twisti@1858 835 // 'argslot' is the position of the first argument to swap.
twisti@1858 836 __ ldsw(G3_amh_vmargslot, O0_argslot);
twisti@1858 837 __ add(Gargs, __ argument_offset(O0_argslot), O0_argslot);
twisti@1858 838
twisti@1858 839 // 'vminfo' is the second.
twisti@1858 840 Register O1_destslot = O1_scratch;
twisti@1858 841 __ ldsw(G3_amh_conversion, O1_destslot);
twisti@1858 842 assert(CONV_VMINFO_SHIFT == 0, "preshifted");
twisti@1858 843 __ and3(O1_destslot, CONV_VMINFO_MASK, O1_destslot);
twisti@1858 844 __ add(Gargs, __ argument_offset(O1_destslot), O1_destslot);
twisti@1858 845
twisti@1858 846 if (!rotate) {
twisti@1858 847 for (int i = 0; i < swap_bytes; i += wordSize) {
twisti@1858 848 __ ld_ptr(Address(O0_argslot, i), O2_scratch);
twisti@1858 849 __ ld_ptr(Address(O1_destslot, i), O3_scratch);
twisti@1858 850 __ st_ptr(O3_scratch, Address(O0_argslot, i));
twisti@1858 851 __ st_ptr(O2_scratch, Address(O1_destslot, i));
twisti@1858 852 }
twisti@1858 853 } else {
twisti@1858 854 // Save the first chunk, which is going to get overwritten.
twisti@1858 855 switch (swap_bytes) {
twisti@1858 856 case 4 : __ lduw(Address(O0_argslot, 0), O2_scratch); break;
twisti@1858 857 case 16: __ ldx( Address(O0_argslot, 8), O3_scratch); //fall-thru
twisti@1858 858 case 8 : __ ldx( Address(O0_argslot, 0), O2_scratch); break;
twisti@1858 859 default: ShouldNotReachHere();
twisti@1858 860 }
twisti@1858 861
twisti@1858 862 if (rotate > 0) {
twisti@1858 863 // Rorate upward.
twisti@1858 864 __ sub(O0_argslot, swap_bytes, O0_argslot);
twisti@1858 865 #if ASSERT
twisti@1858 866 {
twisti@1858 867 // Verify that argslot > destslot, by at least swap_bytes.
twisti@1858 868 Label L_ok;
twisti@1858 869 __ cmp(O0_argslot, O1_destslot);
twisti@1858 870 __ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, L_ok);
twisti@1858 871 __ delayed()->nop();
twisti@1858 872 __ stop("source must be above destination (upward rotation)");
twisti@1858 873 __ bind(L_ok);
twisti@1858 874 }
twisti@1858 875 #endif
twisti@1858 876 // Work argslot down to destslot, copying contiguous data upwards.
twisti@1858 877 // Pseudo-code:
twisti@1858 878 // argslot = src_addr - swap_bytes
twisti@1858 879 // destslot = dest_addr
twisti@1858 880 // while (argslot >= destslot) {
twisti@1858 881 // *(argslot + swap_bytes) = *(argslot + 0);
twisti@1858 882 // argslot--;
twisti@1858 883 // }
twisti@1858 884 Label loop;
twisti@1858 885 __ bind(loop);
twisti@1858 886 __ ld_ptr(Address(O0_argslot, 0), G5_index);
twisti@1858 887 __ st_ptr(G5_index, Address(O0_argslot, swap_bytes));
twisti@1858 888 __ sub(O0_argslot, wordSize, O0_argslot);
twisti@1858 889 __ cmp(O0_argslot, O1_destslot);
twisti@1858 890 __ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, loop);
twisti@1858 891 __ delayed()->nop(); // FILLME
twisti@1858 892 } else {
twisti@1858 893 __ add(O0_argslot, swap_bytes, O0_argslot);
twisti@1858 894 #if ASSERT
twisti@1858 895 {
twisti@1858 896 // Verify that argslot < destslot, by at least swap_bytes.
twisti@1858 897 Label L_ok;
twisti@1858 898 __ cmp(O0_argslot, O1_destslot);
twisti@1858 899 __ brx(Assembler::lessEqualUnsigned, false, Assembler::pt, L_ok);
twisti@1858 900 __ delayed()->nop();
twisti@1858 901 __ stop("source must be above destination (upward rotation)");
twisti@1858 902 __ bind(L_ok);
twisti@1858 903 }
twisti@1858 904 #endif
twisti@1858 905 // Work argslot up to destslot, copying contiguous data downwards.
twisti@1858 906 // Pseudo-code:
twisti@1858 907 // argslot = src_addr + swap_bytes
twisti@1858 908 // destslot = dest_addr
twisti@1858 909 // while (argslot >= destslot) {
twisti@1858 910 // *(argslot - swap_bytes) = *(argslot + 0);
twisti@1858 911 // argslot++;
twisti@1858 912 // }
twisti@1858 913 Label loop;
twisti@1858 914 __ bind(loop);
twisti@1858 915 __ ld_ptr(Address(O0_argslot, 0), G5_index);
twisti@1858 916 __ st_ptr(G5_index, Address(O0_argslot, -swap_bytes));
twisti@1858 917 __ add(O0_argslot, wordSize, O0_argslot);
twisti@1858 918 __ cmp(O0_argslot, O1_destslot);
twisti@1858 919 __ brx(Assembler::lessEqualUnsigned, false, Assembler::pt, loop);
twisti@1858 920 __ delayed()->nop(); // FILLME
twisti@1858 921 }
twisti@1858 922
twisti@1858 923 // Store the original first chunk into the destination slot, now free.
twisti@1858 924 switch (swap_bytes) {
twisti@1858 925 case 4 : __ stw(O2_scratch, Address(O1_destslot, 0)); break;
twisti@1858 926 case 16: __ stx(O3_scratch, Address(O1_destslot, 8)); // fall-thru
twisti@1858 927 case 8 : __ stx(O2_scratch, Address(O1_destslot, 0)); break;
twisti@1858 928 default: ShouldNotReachHere();
twisti@1858 929 }
twisti@1858 930 }
twisti@1858 931
twisti@2201 932 __ load_heap_oop(G3_mh_vmtarget, G3_method_handle);
twisti@1858 933 __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
twisti@1858 934 }
twisti@1858 935 break;
twisti@1858 936
twisti@1858 937 case _adapter_dup_args:
twisti@1858 938 {
twisti@1858 939 // 'argslot' is the position of the first argument to duplicate.
twisti@1858 940 __ ldsw(G3_amh_vmargslot, O0_argslot);
twisti@1858 941 __ add(Gargs, __ argument_offset(O0_argslot), O0_argslot);
twisti@1858 942
twisti@1858 943 // 'stack_move' is negative number of words to duplicate.
twisti@1858 944 Register G5_stack_move = G5_index;
twisti@1858 945 __ ldsw(G3_amh_conversion, G5_stack_move);
twisti@1858 946 __ sra(G5_stack_move, CONV_STACK_MOVE_SHIFT, G5_stack_move);
twisti@1858 947
twisti@1858 948 // Remember the old Gargs (argslot[0]).
twisti@1858 949 Register O1_oldarg = O1_scratch;
twisti@1858 950 __ mov(Gargs, O1_oldarg);
twisti@1858 951
twisti@1858 952 // Move Gargs down to make room for dups.
twisti@1858 953 __ sll_ptr(G5_stack_move, LogBytesPerWord, G5_stack_move);
twisti@1858 954 __ add(Gargs, G5_stack_move, Gargs);
twisti@1858 955
twisti@1858 956 // Compute the new Gargs (argslot[0]).
twisti@1858 957 Register O2_newarg = O2_scratch;
twisti@1858 958 __ mov(Gargs, O2_newarg);
twisti@1858 959
twisti@1858 960 // Copy from oldarg[0...] down to newarg[0...]
twisti@1858 961 // Pseude-code:
twisti@1858 962 // O1_oldarg = old-Gargs
twisti@1858 963 // O2_newarg = new-Gargs
twisti@1858 964 // O0_argslot = argslot
twisti@1858 965 // while (O2_newarg < O1_oldarg) *O2_newarg = *O0_argslot++
twisti@1858 966 Label loop;
twisti@1858 967 __ bind(loop);
twisti@1858 968 __ ld_ptr(Address(O0_argslot, 0), O3_scratch);
twisti@1858 969 __ st_ptr(O3_scratch, Address(O2_newarg, 0));
twisti@1858 970 __ add(O0_argslot, wordSize, O0_argslot);
twisti@1858 971 __ add(O2_newarg, wordSize, O2_newarg);
twisti@1858 972 __ cmp(O2_newarg, O1_oldarg);
twisti@1858 973 __ brx(Assembler::less, false, Assembler::pt, loop);
twisti@1858 974 __ delayed()->nop(); // FILLME
twisti@1858 975
twisti@2201 976 __ load_heap_oop(G3_mh_vmtarget, G3_method_handle);
twisti@1858 977 __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
twisti@1858 978 }
twisti@1858 979 break;
twisti@1858 980
twisti@1858 981 case _adapter_drop_args:
twisti@1858 982 {
twisti@1858 983 // 'argslot' is the position of the first argument to nuke.
twisti@1858 984 __ ldsw(G3_amh_vmargslot, O0_argslot);
twisti@1858 985 __ add(Gargs, __ argument_offset(O0_argslot), O0_argslot);
twisti@1858 986
twisti@1858 987 // 'stack_move' is number of words to drop.
twisti@1858 988 Register G5_stack_move = G5_index;
twisti@1858 989 __ ldsw(G3_amh_conversion, G5_stack_move);
twisti@1858 990 __ sra(G5_stack_move, CONV_STACK_MOVE_SHIFT, G5_stack_move);
twisti@1858 991
twisti@1858 992 remove_arg_slots(_masm, G5_stack_move, O0_argslot, O1_scratch, O2_scratch, O3_scratch);
twisti@1858 993
twisti@2201 994 __ load_heap_oop(G3_mh_vmtarget, G3_method_handle);
twisti@1858 995 __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
twisti@1858 996 }
twisti@1858 997 break;
twisti@1858 998
twisti@1858 999 case _adapter_collect_args:
twisti@1858 1000 __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
twisti@1858 1001 break;
twisti@1858 1002
twisti@1858 1003 case _adapter_spread_args:
twisti@1858 1004 // Handled completely by optimized cases.
twisti@1858 1005 __ stop("init_AdapterMethodHandle should not issue this");
twisti@1858 1006 break;
twisti@1858 1007
twisti@1858 1008 case _adapter_opt_spread_0:
twisti@1858 1009 case _adapter_opt_spread_1:
twisti@1858 1010 case _adapter_opt_spread_more:
twisti@1858 1011 {
twisti@1858 1012 // spread an array out into a group of arguments
twisti@1858 1013 __ unimplemented(entry_name(ek));
twisti@1858 1014 }
twisti@1858 1015 break;
twisti@1858 1016
twisti@1858 1017 case _adapter_flyby:
twisti@1858 1018 case _adapter_ricochet:
twisti@1858 1019 __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
twisti@1858 1020 break;
twisti@1858 1021
twisti@1858 1022 default:
twisti@1858 1023 ShouldNotReachHere();
twisti@1858 1024 }
twisti@1858 1025
twisti@1858 1026 address me_cookie = MethodHandleEntry::start_compiled_entry(_masm, interp_entry);
twisti@1858 1027 __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
twisti@1858 1028
twisti@1858 1029 init_entry(ek, MethodHandleEntry::finish_compiled_entry(_masm, me_cookie));
jrose@1145 1030 }

mercurial