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

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

mercurial