diff src/cpu/x86/vm/methodHandles_x86.cpp @ 1039:987e948ebbc8

6815692: method handle code needs some cleanup (post-6655638) Summary: correctly raise exceptions, support safe bitwise "raw" conversions, fix bugs revealed by VerifyMethodHandles, remove dead code, improve debugging support Reviewed-by: never, twisti
author jrose
date Sat, 17 Oct 2009 19:51:05 -0700
parents df6caf649ff7
children 85f13cdfbc1d
line wrap: on
line diff
--- a/src/cpu/x86/vm/methodHandles_x86.cpp	Fri Oct 16 16:14:12 2009 -0700
+++ b/src/cpu/x86/vm/methodHandles_x86.cpp	Sat Oct 17 19:51:05 2009 -0700
@@ -271,9 +271,15 @@
 void trace_method_handle_stub(const char* adaptername,
                               oopDesc* mh,
                               intptr_t* entry_sp,
-                              intptr_t* saved_sp) {
+                              intptr_t* saved_sp,
+                              intptr_t* saved_bp) {
   // called as a leaf from native code: do not block the JVM!
-  printf("MH %s "PTR_FORMAT" "PTR_FORMAT" "INTX_FORMAT"\n", adaptername, (void*)mh, entry_sp, entry_sp - saved_sp);
+  intptr_t* last_sp = (intptr_t*) saved_bp[frame::interpreter_frame_last_sp_offset];
+  intptr_t* base_sp = (intptr_t*) saved_bp[frame::interpreter_frame_monitor_block_top_offset];
+  printf("MH %s mh="INTPTR_FORMAT" sp=("INTPTR_FORMAT"+"INTX_FORMAT") stack_size="INTX_FORMAT" bp="INTPTR_FORMAT"\n",
+         adaptername, (intptr_t)mh, (intptr_t)entry_sp, (intptr_t)(saved_sp - entry_sp), (intptr_t)(base_sp - last_sp), (intptr_t)saved_bp);
+  if (last_sp != saved_sp)
+    printf("*** last_sp="INTPTR_FORMAT"\n", (intptr_t)last_sp);
 }
 #endif //PRODUCT
 
@@ -293,6 +299,10 @@
   Register rbx_temp    = rbx;
   Register rdx_temp    = rdx;
 
+  // This guy is set up by prepare_to_jump_from_interpreted (from interpreted calls)
+  // and gen_c2i_adapter (from compiled calls):
+  Register saved_last_sp = LP64_ONLY(r13) NOT_LP64(rsi);
+
   guarantee(java_dyn_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets");
 
   // some handy addresses
@@ -315,6 +325,8 @@
     assert(tag_offset = wordSize, "stack grows as expected");
   }
 
+  const int java_mirror_offset = klassOopDesc::klass_part_offset_in_bytes() + Klass::java_mirror_offset_in_bytes();
+
   if (have_entry(ek)) {
     __ nop();                   // empty stubs make SG sick
     return;
@@ -328,45 +340,65 @@
     __ push(rax); __ push(rbx); __ push(rcx); __ push(rdx); __ push(rsi); __ push(rdi);
     __ lea(rax, Address(rsp, wordSize*6)); // entry_sp
     // arguments:
+    __ push(rbp);               // interpreter frame pointer
     __ push(rsi);               // saved_sp
     __ push(rax);               // entry_sp
     __ push(rcx);               // mh
     __ push(rcx);
     __ movptr(Address(rsp, 0), (intptr_t)entry_name(ek));
-    __ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub), 4);
+    __ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub), 5);
     __ pop(rdi); __ pop(rsi); __ pop(rdx); __ pop(rcx); __ pop(rbx); __ pop(rax);
   }
 #endif //PRODUCT
 
   switch ((int) ek) {
-  case _check_mtype:
+  case _raise_exception:
     {
-      // this stub is special, because it requires a live mtype argument
-      Register rax_mtype = rax;
+      // Not a real MH entry, but rather shared code for raising an exception.
+      // Extra local arguments are pushed on stack, as required type at TOS+8,
+      // failing object (or NULL) at TOS+4, failing bytecode type at TOS.
+      // Beyond those local arguments are the PC, of course.
+      Register rdx_code = rdx_temp;
+      Register rcx_fail = rcx_recv;
+      Register rax_want = rax_argslot;
+      Register rdi_pc   = rdi;
+      __ pop(rdx_code);  // TOS+0
+      __ pop(rcx_fail);  // TOS+4
+      __ pop(rax_want);  // TOS+8
+      __ pop(rdi_pc);    // caller PC
 
-      // emit WrongMethodType path first, to enable jccb back-branch
-      Label wrong_method_type;
-      __ bind(wrong_method_type);
-      __ movptr(rdx_temp, ExternalAddress((address) &_entries[_wrong_method_type]));
-      __ jmp(Address(rdx_temp, MethodHandleEntry::from_interpreted_entry_offset_in_bytes()));
-      __ hlt();
+      __ mov(rsp, rsi);   // cut the stack back to where the caller started
 
-      interp_entry = __ pc();
-      __ check_method_handle_type(rax_mtype, rcx_recv, rdx_temp, wrong_method_type);
-      // now rax_mtype is dead; subsequent stubs will use it as a temp
-
-      __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
-    }
-    break;
+      // Repush the arguments as if coming from the interpreter.
+      if (TaggedStackInterpreter)  __ push(frame::tag_for_basic_type(T_INT));
+      __ push(rdx_code);
+      if (TaggedStackInterpreter)  __ push(frame::tag_for_basic_type(T_OBJECT));
+      __ push(rcx_fail);
+      if (TaggedStackInterpreter)  __ push(frame::tag_for_basic_type(T_OBJECT));
+      __ push(rax_want);
 
-  case _wrong_method_type:
-    {
-      // this stub is special, because it requires a live mtype argument
-      Register rax_mtype = rax;
+      Register rbx_method = rbx_temp;
+      Label no_method;
+      // FIXME: fill in _raise_exception_method with a suitable sun.dyn method
+      __ movptr(rbx_method, ExternalAddress((address) &_raise_exception_method));
+      __ testptr(rbx_method, rbx_method);
+      __ jcc(Assembler::zero, no_method);
+      int jobject_oop_offset = 0;
+      __ movptr(rbx_method, Address(rbx_method, jobject_oop_offset));  // dereference the jobject
+      __ testptr(rbx_method, rbx_method);
+      __ jcc(Assembler::zero, no_method);
+      __ verify_oop(rbx_method);
+      __ push(rdi_pc);          // and restore caller PC
+      __ jmp(rbx_method_fie);
 
-      interp_entry = __ pc();
-      __ push(rax_mtype);       // required mtype
-      __ push(rcx_recv);        // random mh (1st stacked argument)
+      // If we get here, the Java runtime did not do its job of creating the exception.
+      // Do something that is at least causes a valid throw from the interpreter.
+      __ bind(no_method);
+      __ pop(rax_want);
+      if (TaggedStackInterpreter)  __ pop(rcx_fail);
+      __ pop(rcx_fail);
+      __ push(rax_want);
+      __ push(rcx_fail);
       __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
     }
     break;
@@ -442,7 +474,7 @@
       __ load_klass(rax_klass, rcx_recv);
       __ verify_oop(rax_klass);
 
-      Register rcx_temp   = rcx_recv;
+      Register rdi_temp   = rdi;
       Register rbx_method = rbx_index;
 
       // get interface klass
@@ -451,7 +483,7 @@
       __ lookup_interface_method(rax_klass, rdx_intf,
                                  // note: next two args must be the same:
                                  rbx_index, rbx_method,
-                                 rcx_temp,
+                                 rdi_temp,
                                  no_such_interface);
 
       __ verify_oop(rbx_method);
@@ -461,7 +493,10 @@
       __ bind(no_such_interface);
       // Throw an exception.
       // For historical reasons, it will be IncompatibleClassChangeError.
-      __ should_not_reach_here(); // %%% FIXME NYI
+      __ pushptr(Address(rdx_intf, java_mirror_offset));  // required interface
+      __ push(rcx_recv);        // bad receiver
+      __ push((int)Bytecodes::_invokeinterface);  // who is complaining?
+      __ jump(ExternalAddress(from_interpreted_entry(_raise_exception)));
     }
     break;
 
@@ -524,6 +559,7 @@
     break;
 
   case _adapter_retype_only:
+  case _adapter_retype_raw:
     // immediately jump to the next MH layer:
     __ movptr(rcx_recv, rcx_mh_vmtarget);
     __ verify_oop(rcx_recv);
@@ -545,10 +581,6 @@
       __ movptr(rbx_klass, rcx_amh_argument); // this is a Class object!
       __ movptr(rbx_klass, Address(rbx_klass, java_lang_Class::klass_offset_in_bytes()));
 
-      // get the new MH:
-      __ movptr(rcx_recv, rcx_mh_vmtarget);
-      // (now we are done with the old MH)
-
       Label done;
       __ movptr(rdx_temp, vmarg);
       __ testl(rdx_temp, rdx_temp);
@@ -558,17 +590,23 @@
       // live at this point:
       // - rbx_klass:  klass required by the target method
       // - rdx_temp:   argument klass to test
-      // - rcx_recv:   method handle to invoke (after cast succeeds)
+      // - rcx_recv:   adapter method handle
       __ check_klass_subtype(rdx_temp, rbx_klass, rax_argslot, done);
 
       // If we get here, the type check failed!
       // Call the wrong_method_type stub, passing the failing argument type in rax.
       Register rax_mtype = rax_argslot;
-      __ push(rbx_klass);       // missed klass (required type)
-      __ push(rdx_temp);        // bad actual type (1st stacked argument)
-      __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
+      __ movl(rax_argslot, rcx_amh_vmargslot);  // reload argslot field
+      __ movptr(rdx_temp, vmarg);
+
+      __ pushptr(rcx_amh_argument); // required class
+      __ push(rdx_temp);            // bad object
+      __ push((int)Bytecodes::_checkcast);  // who is complaining?
+      __ jump(ExternalAddress(from_interpreted_entry(_raise_exception)));
 
       __ bind(done);
+      // get the new MH:
+      __ movptr(rcx_recv, rcx_mh_vmtarget);
       __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
     }
     break;
@@ -1107,11 +1145,17 @@
 
       __ bind(bad_array_klass);
       UNPUSH_RSI_RDI;
-      __ stop("bad array klass NYI");
+      __ pushptr(Address(rdx_array_klass, java_mirror_offset)); // required type
+      __ pushptr(vmarg);                // bad array
+      __ push((int)Bytecodes::_aaload); // who is complaining?
+      __ jump(ExternalAddress(from_interpreted_entry(_raise_exception)));
 
       __ bind(bad_array_length);
       UNPUSH_RSI_RDI;
-      __ stop("bad array length NYI");
+      __ push(rcx_recv);        // AMH requiring a certain length
+      __ pushptr(vmarg);        // bad array
+      __ push((int)Bytecodes::_arraylength); // who is complaining?
+      __ jump(ExternalAddress(from_interpreted_entry(_raise_exception)));
 
 #undef UNPUSH_RSI_RDI
     }