hotspot/src/share/vm/runtime/sharedRuntime.cpp
changeset 4764 d15bb22d4d39
parent 4761 bdb7375a1fee
parent 4755 eee57ea6d910
child 4898 b5bbb74def0b
--- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp	Tue Feb 02 11:08:17 2010 -0700
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp	Thu Feb 04 15:50:59 2010 -0800
@@ -1033,10 +1033,20 @@
   address   sender_pc = caller_frame.pc();
   CodeBlob* sender_cb = caller_frame.cb();
   nmethod*  sender_nm = sender_cb->as_nmethod_or_null();
+  bool is_mh_invoke_via_adapter = false;  // Direct c2c call or via adapter?
+  if (sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc)) {
+    // If the callee_target is set, then we have come here via an i2c
+    // adapter.
+    methodOop callee = thread->callee_target();
+    if (callee != NULL) {
+      assert(callee->is_method(), "sanity");
+      is_mh_invoke_via_adapter = true;
+    }
+  }
 
   if (caller_frame.is_interpreted_frame() ||
-      caller_frame.is_entry_frame() ||
-      (sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc))) {
+      caller_frame.is_entry_frame()       ||
+      is_mh_invoke_via_adapter) {
     methodOop callee = thread->callee_target();
     guarantee(callee != NULL && callee->is_method(), "bad handshake");
     thread->set_vm_result(callee);
@@ -1351,7 +1361,7 @@
 // We are calling the interpreter via a c2i. Normally this would mean that
 // we were called by a compiled method. However we could have lost a race
 // where we went int -> i2c -> c2i and so the caller could in fact be
-// interpreted. If the caller is compiled we attampt to patch the caller
+// interpreted. If the caller is compiled we attempt to patch the caller
 // so he no longer calls into the interpreter.
 IRT_LEAF(void, SharedRuntime::fixup_callers_callsite(methodOopDesc* method, address caller_pc))
   methodOop moop(method);
@@ -1367,10 +1377,19 @@
   // we did we'd leap into space because the callsite needs to use
   // "to interpreter" stub in order to load up the methodOop. Don't
   // ask me how I know this...
-  //
 
   CodeBlob* cb = CodeCache::find_blob(caller_pc);
-  if ( !cb->is_nmethod() || entry_point == moop->get_c2i_entry()) {
+  if (!cb->is_nmethod() || entry_point == moop->get_c2i_entry()) {
+    return;
+  }
+
+  // The check above makes sure this is a nmethod.
+  nmethod* nm = cb->as_nmethod_or_null();
+  assert(nm, "must be");
+
+  // Don't fixup MethodHandle call sites as c2i/i2c adapters are used
+  // to implement MethodHandle actions.
+  if (nm->is_method_handle_return(caller_pc)) {
     return;
   }
 
@@ -1385,7 +1404,7 @@
 
   if (moop->code() == NULL) return;
 
-  if (((nmethod*)cb)->is_in_use()) {
+  if (nm->is_in_use()) {
 
     // Expect to find a native call there (unless it was no-inline cache vtable dispatch)
     MutexLockerEx ml_patch(Patching_lock, Mutex::_no_safepoint_check_flag);
@@ -1417,7 +1436,7 @@
         if (callee == cb || callee->is_adapter_blob()) {
           // static call or optimized virtual
           if (TraceCallFixup) {
-            tty->print("fixup callsite at " INTPTR_FORMAT " to compiled code for", caller_pc);
+            tty->print("fixup callsite           at " INTPTR_FORMAT " to compiled code for", caller_pc);
             moop->print_short_name(tty);
             tty->print_cr(" to " INTPTR_FORMAT, entry_point);
           }
@@ -1433,7 +1452,7 @@
         }
       } else {
           if (TraceCallFixup) {
-            tty->print("already patched  callsite at " INTPTR_FORMAT " to compiled code for", caller_pc);
+            tty->print("already patched callsite at " INTPTR_FORMAT " to compiled code for", caller_pc);
             moop->print_short_name(tty);
             tty->print_cr(" to " INTPTR_FORMAT, entry_point);
           }
@@ -1787,55 +1806,78 @@
 class AdapterFingerPrint : public CHeapObj {
  private:
   union {
-    signed char  _compact[12];
-    int          _compact_int[3];
-    intptr_t*    _fingerprint;
+    int  _compact[3];
+    int* _fingerprint;
   } _value;
-  int _length; // A negative length indicates that _value._fingerprint is the array.
-               // Otherwise it's in the compact form.
+  int _length; // A negative length indicates the fingerprint is in the compact form,
+               // Otherwise _value._fingerprint is the array.
+
+  // Remap BasicTypes that are handled equivalently by the adapters.
+  // These are correct for the current system but someday it might be
+  // necessary to make this mapping platform dependent.
+  static BasicType adapter_encoding(BasicType in) {
+    assert((~0xf & in) == 0, "must fit in 4 bits");
+    switch(in) {
+      case T_BOOLEAN:
+      case T_BYTE:
+      case T_SHORT:
+      case T_CHAR:
+        // There are all promoted to T_INT in the calling convention
+        return T_INT;
 
- public:
-  AdapterFingerPrint(int total_args_passed, VMRegPair* regs) {
-    assert(sizeof(_value._compact) == sizeof(_value._compact_int), "must match");
-    _length = total_args_passed * 2;
-    if (_length < (int)sizeof(_value._compact)) {
-      _value._compact_int[0] = _value._compact_int[1] = _value._compact_int[2] = 0;
-      // Storing the signature encoded as signed chars hits about 98%
-      // of the time.
-      signed char* ptr = _value._compact;
-      int o = 0;
-      for (int i = 0; i < total_args_passed; i++) {
-        VMRegPair pair = regs[i];
-        intptr_t v1 = pair.first()->value();
-        intptr_t v2 = pair.second()->value();
-        if (v1 == (signed char) v1 &&
-            v2 == (signed char) v2) {
-          _value._compact[o++] = v1;
-          _value._compact[o++] = v2;
-        } else {
-          goto big;
+      case T_OBJECT:
+      case T_ARRAY:
+        if (!TaggedStackInterpreter) {
+#ifdef _LP64
+          return T_LONG;
+#else
+          return T_INT;
+#endif
         }
-      }
-      _length = -_length;
-      return;
-    }
-  big:
-    _value._fingerprint = NEW_C_HEAP_ARRAY(intptr_t, _length);
-    int o = 0;
-    for (int i = 0; i < total_args_passed; i++) {
-      VMRegPair pair = regs[i];
-      intptr_t v1 = pair.first()->value();
-      intptr_t v2 = pair.second()->value();
-      _value._fingerprint[o++] = v1;
-      _value._fingerprint[o++] = v2;
+        return T_OBJECT;
+
+      case T_INT:
+      case T_LONG:
+      case T_FLOAT:
+      case T_DOUBLE:
+      case T_VOID:
+        return in;
+
+      default:
+        ShouldNotReachHere();
+        return T_CONFLICT;
     }
   }
 
-  AdapterFingerPrint(AdapterFingerPrint* orig) {
-    _length = orig->_length;
-    _value = orig->_value;
-    // take ownership of any storage by destroying the length
-    orig->_length = 0;
+ public:
+  AdapterFingerPrint(int total_args_passed, BasicType* sig_bt) {
+    // The fingerprint is based on the BasicType signature encoded
+    // into an array of ints with four entries per int.
+    int* ptr;
+    int len = (total_args_passed + 3) >> 2;
+    if (len <= (int)(sizeof(_value._compact) / sizeof(int))) {
+      _value._compact[0] = _value._compact[1] = _value._compact[2] = 0;
+      // Storing the signature encoded as signed chars hits about 98%
+      // of the time.
+      _length = -len;
+      ptr = _value._compact;
+    } else {
+      _length = len;
+      _value._fingerprint = NEW_C_HEAP_ARRAY(int, _length);
+      ptr = _value._fingerprint;
+    }
+
+    // Now pack the BasicTypes with 4 per int
+    int sig_index = 0;
+    for (int index = 0; index < len; index++) {
+      int value = 0;
+      for (int byte = 0; byte < 4; byte++) {
+        if (sig_index < total_args_passed) {
+          value = (value << 4) | adapter_encoding(sig_bt[sig_index++]);
+        }
+      }
+      ptr[index] = value;
+    }
   }
 
   ~AdapterFingerPrint() {
@@ -1844,11 +1886,7 @@
     }
   }
 
-  AdapterFingerPrint* allocate() {
-    return new AdapterFingerPrint(this);
-  }
-
-  intptr_t value(int index) {
+  int value(int index) {
     if (_length < 0) {
       return _value._compact[index];
     }
@@ -1864,9 +1902,9 @@
   }
 
   unsigned int compute_hash() {
-    intptr_t hash = 0;
+    int hash = 0;
     for (int i = 0; i < length(); i++) {
-      intptr_t v = value(i);
+      int v = value(i);
       hash = (hash << 8) ^ v ^ (hash >> 5);
     }
     return (unsigned int)hash;
@@ -1885,9 +1923,9 @@
       return false;
     }
     if (_length < 0) {
-      return _value._compact_int[0] == other->_value._compact_int[0] &&
-             _value._compact_int[1] == other->_value._compact_int[1] &&
-             _value._compact_int[2] == other->_value._compact_int[2];
+      return _value._compact[0] == other->_value._compact[0] &&
+             _value._compact[1] == other->_value._compact[1] &&
+             _value._compact[2] == other->_value._compact[2];
     } else {
       for (int i = 0; i < _length; i++) {
         if (_value._fingerprint[i] != other->_value._fingerprint[i]) {
@@ -1935,10 +1973,15 @@
     add_entry(index, entry);
   }
 
+  void free_entry(AdapterHandlerEntry* entry) {
+    entry->deallocate();
+    BasicHashtable::free_entry(entry);
+  }
+
   // Find a entry with the same fingerprint if it exists
-  AdapterHandlerEntry* lookup(int total_args_passed, VMRegPair* regs) {
+  AdapterHandlerEntry* lookup(int total_args_passed, BasicType* sig_bt) {
     debug_only(_lookups++);
-    AdapterFingerPrint fp(total_args_passed, regs);
+    AdapterFingerPrint fp(total_args_passed, sig_bt);
     unsigned int hash = fp.compute_hash();
     int index = hash_to_index(hash);
     for (AdapterHandlerEntry* e = bucket(index); e != NULL; e = e->next()) {
@@ -2110,17 +2153,26 @@
     }
     assert(i == total_args_passed, "");
 
-    // Get a description of the compiled java calling convention and the largest used (VMReg) stack slot usage
-    int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false);
+    // Lookup method signature's fingerprint
+    entry = _adapters->lookup(total_args_passed, sig_bt);
 
-    // Lookup method signature's fingerprint
-    entry = _adapters->lookup(total_args_passed, regs);
+#ifdef ASSERT
+    AdapterHandlerEntry* shared_entry = NULL;
+    if (VerifyAdapterSharing && entry != NULL) {
+      shared_entry = entry;
+      entry = NULL;
+    }
+#endif
+
     if (entry != NULL) {
       return entry;
     }
 
+    // Get a description of the compiled java calling convention and the largest used (VMReg) stack slot usage
+    int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false);
+
     // Make a C heap allocated version of the fingerprint to store in the adapter
-    fingerprint = new AdapterFingerPrint(total_args_passed, regs);
+    fingerprint = new AdapterFingerPrint(total_args_passed, sig_bt);
 
     // Create I2C & C2I handlers
 
@@ -2139,6 +2191,20 @@
                                                      regs,
                                                      fingerprint);
 
+#ifdef ASSERT
+      if (VerifyAdapterSharing) {
+        if (shared_entry != NULL) {
+          assert(shared_entry->compare_code(buf->instructions_begin(), buffer.code_size(), total_args_passed, sig_bt),
+                 "code must match");
+          // Release the one just created and return the original
+          _adapters->free_entry(entry);
+          return shared_entry;
+        } else  {
+          entry->save_code(buf->instructions_begin(), buffer.code_size(), total_args_passed, sig_bt);
+        }
+      }
+#endif
+
       B = BufferBlob::create(AdapterHandlerEntry::name, &buffer);
       NOT_PRODUCT(code_size = buffer.code_size());
     }
@@ -2146,19 +2212,8 @@
       // CodeCache is full, disable compilation
       // Ought to log this but compile log is only per compile thread
       // and we're some non descript Java thread.
-      UseInterpreter = true;
-      if (UseCompiler || AlwaysCompileLoopMethods ) {
-#ifndef PRODUCT
-        warning("CodeCache is full. Compiler has been disabled");
-        if (CompileTheWorld || ExitOnFullCodeCache) {
-          before_exit(JavaThread::current());
-          exit_globals(); // will delete tty
-          vm_direct_exit(CompileTheWorld ? 0 : 1);
-        }
-#endif
-        UseCompiler               = false;
-        AlwaysCompileLoopMethods  = false;
-      }
+      MutexUnlocker mu(AdapterHandlerLibrary_lock);
+      CompileBroker::handle_full_code_cache();
       return NULL; // Out of CodeCache space
     }
     entry->relocate(B->instructions_begin());
@@ -2204,6 +2259,44 @@
     _c2i_unverified_entry += delta;
 }
 
+
+void AdapterHandlerEntry::deallocate() {
+  delete _fingerprint;
+#ifdef ASSERT
+  if (_saved_code) FREE_C_HEAP_ARRAY(unsigned char, _saved_code);
+  if (_saved_sig)  FREE_C_HEAP_ARRAY(Basictype, _saved_sig);
+#endif
+}
+
+
+#ifdef ASSERT
+// Capture the code before relocation so that it can be compared
+// against other versions.  If the code is captured after relocation
+// then relative instructions won't be equivalent.
+void AdapterHandlerEntry::save_code(unsigned char* buffer, int length, int total_args_passed, BasicType* sig_bt) {
+  _saved_code = NEW_C_HEAP_ARRAY(unsigned char, length);
+  _code_length = length;
+  memcpy(_saved_code, buffer, length);
+  _total_args_passed = total_args_passed;
+  _saved_sig = NEW_C_HEAP_ARRAY(BasicType, _total_args_passed);
+  memcpy(_saved_sig, sig_bt, _total_args_passed * sizeof(BasicType));
+}
+
+
+bool AdapterHandlerEntry::compare_code(unsigned char* buffer, int length, int total_args_passed, BasicType* sig_bt) {
+  if (length != _code_length) {
+    return false;
+  }
+  for (int i = 0; i < length; i++) {
+    if (buffer[i] != _saved_code[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+#endif
+
+
 // Create a native wrapper for this native method.  The wrapper converts the
 // java compiled calling convention to the native convention, handlizes
 // arguments, and transitions to native.  On return from the native we transition
@@ -2282,19 +2375,8 @@
     // CodeCache is full, disable compilation
     // Ought to log this but compile log is only per compile thread
     // and we're some non descript Java thread.
-    UseInterpreter = true;
-    if (UseCompiler || AlwaysCompileLoopMethods ) {
-#ifndef PRODUCT
-      warning("CodeCache is full. Compiler has been disabled");
-      if (CompileTheWorld || ExitOnFullCodeCache) {
-        before_exit(JavaThread::current());
-        exit_globals(); // will delete tty
-        vm_direct_exit(CompileTheWorld ? 0 : 1);
-      }
-#endif
-      UseCompiler               = false;
-      AlwaysCompileLoopMethods  = false;
-    }
+    MutexUnlocker mu(AdapterHandlerLibrary_lock);
+    CompileBroker::handle_full_code_cache();
   }
   return nm;
 }