changeset 1597:9eba43136cb5

6934494: JSR 292 MethodHandles adapters should be generated into their own CodeBlob Summary: Passing a null pointer to an InvokeDynamic function call should lead to a NullPointerException. Reviewed-by: kvn, never
author twisti
date Tue, 16 Mar 2010 11:52:17 +0100
parents da06d1795d84
children 428a9c451986
files src/cpu/sparc/vm/stubRoutines_sparc.hpp src/cpu/x86/vm/stubGenerator_x86_32.cpp src/cpu/x86/vm/stubGenerator_x86_64.cpp src/cpu/x86/vm/stubRoutines_x86_32.hpp src/cpu/x86/vm/stubRoutines_x86_64.hpp src/share/vm/code/codeBlob.cpp src/share/vm/code/codeBlob.hpp src/share/vm/includeDB_core src/share/vm/prims/methodHandles.cpp src/share/vm/prims/methodHandles.hpp src/share/vm/runtime/init.cpp src/share/vm/runtime/sharedRuntime.cpp src/share/vm/runtime/sharedRuntime.hpp
diffstat 13 files changed, 182 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- a/src/cpu/sparc/vm/stubRoutines_sparc.hpp	Thu Mar 11 05:09:20 2010 -0800
+++ b/src/cpu/sparc/vm/stubRoutines_sparc.hpp	Tue Mar 16 11:52:17 2010 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,8 +37,13 @@
 
 enum /* platform_dependent_constants */ {
   // %%%%%%%% May be able to shrink this a lot
-  code_size1 = 20000,                                        // simply increase if too small (assembler will crash if too small)
-  code_size2 = 20000                                         // simply increase if too small (assembler will crash if too small)
+  code_size1 = 20000,           // simply increase if too small (assembler will crash if too small)
+  code_size2 = 20000            // simply increase if too small (assembler will crash if too small)
+};
+
+// MethodHandles adapters
+enum method_handles_platform_dependent_constants {
+  method_handles_adapters_code_size = 5000
 };
 
 class Sparc {
--- a/src/cpu/x86/vm/stubGenerator_x86_32.cpp	Thu Mar 11 05:09:20 2010 -0800
+++ b/src/cpu/x86/vm/stubGenerator_x86_32.cpp	Tue Mar 16 11:52:17 2010 +0100
@@ -2276,16 +2276,6 @@
     // arraycopy stubs used by compilers
     generate_arraycopy_stubs();
 
-    // generic method handle stubs
-    if (EnableMethodHandles && SystemDictionary::MethodHandle_klass() != NULL) {
-      for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST;
-           ek < MethodHandles::_EK_LIMIT;
-           ek = MethodHandles::EntryKind(1 + (int)ek)) {
-        StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
-        MethodHandles::generate_method_handle_stub(_masm, ek);
-      }
-    }
-
     generate_math_stubs();
   }
 
--- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp	Thu Mar 11 05:09:20 2010 -0800
+++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp	Tue Mar 16 11:52:17 2010 +0100
@@ -3009,16 +3009,6 @@
     // arraycopy stubs used by compilers
     generate_arraycopy_stubs();
 
-    // generic method handle stubs
-    if (EnableMethodHandles && SystemDictionary::MethodHandle_klass() != NULL) {
-      for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST;
-           ek < MethodHandles::_EK_LIMIT;
-           ek = MethodHandles::EntryKind(1 + (int)ek)) {
-        StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
-        MethodHandles::generate_method_handle_stub(_masm, ek);
-      }
-    }
-
     generate_math_stubs();
   }
 
--- a/src/cpu/x86/vm/stubRoutines_x86_32.hpp	Thu Mar 11 05:09:20 2010 -0800
+++ b/src/cpu/x86/vm/stubRoutines_x86_32.hpp	Tue Mar 16 11:52:17 2010 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,11 @@
   code_size2 = 22000            // simply increase if too small (assembler will crash if too small)
 };
 
+// MethodHandles adapters
+enum method_handles_platform_dependent_constants {
+  method_handles_adapters_code_size = 5000
+};
+
 class x86 {
  friend class StubGenerator;
  friend class VMStructs;
--- a/src/cpu/x86/vm/stubRoutines_x86_64.hpp	Thu Mar 11 05:09:20 2010 -0800
+++ b/src/cpu/x86/vm/stubRoutines_x86_64.hpp	Tue Mar 16 11:52:17 2010 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2003-2010 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,12 +28,14 @@
 
 static bool    returns_to_call_stub(address return_pc)   { return return_pc == _call_stub_return_address; }
 
-enum platform_dependent_constants
-{
-  code_size1 =  19000, // simply increase if too small (assembler will
-                      // crash if too small)
-  code_size2 = 22000  // simply increase if too small (assembler will
-                      // crash if too small)
+enum platform_dependent_constants {
+  code_size1 = 19000,          // simply increase if too small (assembler will crash if too small)
+  code_size2 = 22000           // simply increase if too small (assembler will crash if too small)
+};
+
+// MethodHandles adapters
+enum method_handles_platform_dependent_constants {
+  method_handles_adapters_code_size = 13000
 };
 
 class x86 {
--- a/src/share/vm/code/codeBlob.cpp	Thu Mar 11 05:09:20 2010 -0800
+++ b/src/share/vm/code/codeBlob.cpp	Tue Mar 16 11:52:17 2010 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright 1998-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1998-2010 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -249,7 +249,6 @@
   size += round_to(buffer_size, oopSize);
   assert(name != NULL, "must provide a name");
   {
-
     MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
     blob = new (size) BufferBlob(name, size);
   }
@@ -271,7 +270,6 @@
   unsigned int size = allocation_size(cb, sizeof(BufferBlob));
   assert(name != NULL, "must provide a name");
   {
-
     MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
     blob = new (size) BufferBlob(name, size, cb);
   }
@@ -298,10 +296,48 @@
   MemoryService::track_code_cache_memory_usage();
 }
 
-bool BufferBlob::is_adapter_blob() const {
-  return (strcmp(AdapterHandlerEntry::name, name()) == 0);
+
+//----------------------------------------------------------------------------------------------------
+// Implementation of AdapterBlob
+
+AdapterBlob* AdapterBlob::create(CodeBuffer* cb) {
+  ThreadInVMfromUnknown __tiv;  // get to VM state in case we block on CodeCache_lock
+
+  AdapterBlob* blob = NULL;
+  unsigned int size = allocation_size(cb, sizeof(AdapterBlob));
+  {
+    MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+    blob = new (size) AdapterBlob(size, cb);
+  }
+  // Track memory usage statistic after releasing CodeCache_lock
+  MemoryService::track_code_cache_memory_usage();
+
+  return blob;
 }
 
+
+//----------------------------------------------------------------------------------------------------
+// Implementation of MethodHandlesAdapterBlob
+
+MethodHandlesAdapterBlob* MethodHandlesAdapterBlob::create(int buffer_size) {
+  ThreadInVMfromUnknown __tiv;  // get to VM state in case we block on CodeCache_lock
+
+  MethodHandlesAdapterBlob* blob = NULL;
+  unsigned int size = sizeof(MethodHandlesAdapterBlob);
+  // align the size to CodeEntryAlignment
+  size = align_code_offset(size);
+  size += round_to(buffer_size, oopSize);
+  {
+    MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+    blob = new (size) MethodHandlesAdapterBlob(size);
+  }
+  // Track memory usage statistic after releasing CodeCache_lock
+  MemoryService::track_code_cache_memory_usage();
+
+  return blob;
+}
+
+
 //----------------------------------------------------------------------------------------------------
 // Implementation of RuntimeStub
 
--- a/src/share/vm/code/codeBlob.hpp	Thu Mar 11 05:09:20 2010 -0800
+++ b/src/share/vm/code/codeBlob.hpp	Tue Mar 16 11:52:17 2010 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright 1998-2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1998-2010 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -90,14 +90,15 @@
   void flush();
 
   // Typing
-  virtual bool is_buffer_blob() const            { return false; }
-  virtual bool is_nmethod() const                { return false; }
-  virtual bool is_runtime_stub() const           { return false; }
-  virtual bool is_deoptimization_stub() const    { return false; }
-  virtual bool is_uncommon_trap_stub() const     { return false; }
-  virtual bool is_exception_stub() const         { return false; }
-  virtual bool is_safepoint_stub() const         { return false; }
-  virtual bool is_adapter_blob() const           { return false; }
+  virtual bool is_buffer_blob() const                 { return false; }
+  virtual bool is_nmethod() const                     { return false; }
+  virtual bool is_runtime_stub() const                { return false; }
+  virtual bool is_deoptimization_stub() const         { return false; }
+  virtual bool is_uncommon_trap_stub() const          { return false; }
+  virtual bool is_exception_stub() const              { return false; }
+  virtual bool is_safepoint_stub() const              { return false; }
+  virtual bool is_adapter_blob() const                { return false; }
+  virtual bool is_method_handles_adapter_blob() const { return false; }
 
   virtual bool is_compiled_by_c2() const         { return false; }
   virtual bool is_compiled_by_c1() const         { return false; }
@@ -221,6 +222,9 @@
 
 class BufferBlob: public CodeBlob {
   friend class VMStructs;
+  friend class AdapterBlob;
+  friend class MethodHandlesAdapterBlob;
+
  private:
   // Creation support
   BufferBlob(const char* name, int size);
@@ -236,8 +240,7 @@
   static void free(BufferBlob* buf);
 
   // Typing
-  bool is_buffer_blob() const                    { return true; }
-  bool is_adapter_blob() const;
+  virtual bool is_buffer_blob() const            { return true; }
 
   // GC/Verification support
   void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f)  { /* nothing to do */ }
@@ -255,6 +258,40 @@
 
 
 //----------------------------------------------------------------------------------------------------
+// AdapterBlob: used to hold C2I/I2C adapters
+
+class AdapterBlob: public BufferBlob {
+private:
+  AdapterBlob(int size)                 : BufferBlob("I2C/C2I adapters", size) {}
+  AdapterBlob(int size, CodeBuffer* cb) : BufferBlob("I2C/C2I adapters", size, cb) {}
+
+public:
+  // Creation
+  static AdapterBlob* create(CodeBuffer* cb);
+
+  // Typing
+  virtual bool is_adapter_blob() const { return true; }
+};
+
+
+//----------------------------------------------------------------------------------------------------
+// MethodHandlesAdapterBlob: used to hold MethodHandles adapters
+
+class MethodHandlesAdapterBlob: public BufferBlob {
+private:
+  MethodHandlesAdapterBlob(int size)                 : BufferBlob("MethodHandles adapters", size) {}
+  MethodHandlesAdapterBlob(int size, CodeBuffer* cb) : BufferBlob("MethodHandles adapters", size, cb) {}
+
+public:
+  // Creation
+  static MethodHandlesAdapterBlob* create(int buffer_size);
+
+  // Typing
+  virtual bool is_method_handles_adapter_blob() const { return true; }
+};
+
+
+//----------------------------------------------------------------------------------------------------
 // RuntimeStub: describes stubs used by compiled code to call a (static) C++ runtime routine
 
 class RuntimeStub: public CodeBlob {
--- a/src/share/vm/includeDB_core	Thu Mar 11 05:09:20 2010 -0800
+++ b/src/share/vm/includeDB_core	Tue Mar 16 11:52:17 2010 +0100
@@ -2017,6 +2017,7 @@
 init.cpp                                icBuffer.hpp
 init.cpp                                icache.hpp
 init.cpp                                init.hpp
+init.cpp                                methodHandles.hpp
 init.cpp                                safepoint.hpp
 init.cpp                                sharedRuntime.hpp
 init.cpp                                universe.hpp
@@ -2871,6 +2872,7 @@
 methodHandles.cpp                       oopFactory.hpp
 methodHandles.cpp                       reflection.hpp
 methodHandles.cpp                       signature.hpp
+methodHandles.cpp                       stubRoutines.hpp
 methodHandles.cpp                       symbolTable.hpp
 
 methodHandles_<arch>.cpp                allocation.inline.hpp
--- a/src/share/vm/prims/methodHandles.cpp	Thu Mar 11 05:09:20 2010 -0800
+++ b/src/share/vm/prims/methodHandles.cpp	Tue Mar 16 11:52:17 2010 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2008-2010 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -82,6 +82,10 @@
   NULL
 };
 
+// Adapters.
+MethodHandlesAdapterBlob* MethodHandles::_adapter_code      = NULL;
+int                       MethodHandles::_adapter_code_size = StubRoutines::method_handles_adapters_code_size;
+
 jobject MethodHandles::_raise_exception_method;
 
 #ifdef ASSERT
@@ -95,6 +99,41 @@
 }
 #endif
 
+
+//------------------------------------------------------------------------------
+// MethodHandles::generate_adapters
+//
+void MethodHandles::generate_adapters() {
+  if (!EnableMethodHandles || SystemDictionary::MethodHandle_klass() == NULL)  return;
+
+  assert(_adapter_code == NULL, "generate only once");
+
+  ResourceMark rm;
+  TraceTime timer("MethodHandles adapters generation", TraceStartupTime);
+  _adapter_code = MethodHandlesAdapterBlob::create(_adapter_code_size);
+  if (_adapter_code == NULL)
+    vm_exit_out_of_memory(_adapter_code_size, "CodeCache: no room for MethodHandles adapters");
+  CodeBuffer code(_adapter_code->instructions_begin(), _adapter_code->instructions_size());
+
+  MethodHandlesAdapterGenerator g(&code);
+  g.generate();
+}
+
+
+//------------------------------------------------------------------------------
+// MethodHandlesAdapterGenerator::generate
+//
+void MethodHandlesAdapterGenerator::generate() {
+  // Generate generic method handle adapters.
+  for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST;
+       ek < MethodHandles::_EK_LIMIT;
+       ek = MethodHandles::EntryKind(1 + (int)ek)) {
+    StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
+    MethodHandles::generate_method_handle_stub(_masm, ek);
+  }
+}
+
+
 void MethodHandles::set_enabled(bool z) {
   if (_enabled != z) {
     guarantee(z && EnableMethodHandles, "can only enable once, and only if -XX:+EnableMethodHandles");
--- a/src/share/vm/prims/methodHandles.hpp	Thu Mar 11 05:09:20 2010 -0800
+++ b/src/share/vm/prims/methodHandles.hpp	Tue Mar 16 11:52:17 2010 +0100
@@ -115,6 +115,10 @@
   static const char*        _entry_names[_EK_LIMIT+1];
   static jobject            _raise_exception_method;
 
+  // Adapters.
+  static MethodHandlesAdapterBlob* _adapter_code;
+  static int                       _adapter_code_size;
+
   static bool ek_valid(EntryKind ek)            { return (uint)ek < (uint)_EK_LIMIT; }
   static bool conv_op_valid(int op)             { return (uint)op < (uint)CONV_OP_LIMIT; }
 
@@ -230,7 +234,10 @@
   // bit values for suppress argument to expand_MemberName:
   enum { _suppress_defc = 1, _suppress_name = 2, _suppress_type = 4 };
 
-  // called from InterpreterGenerator and StubGenerator
+  // Generate MethodHandles adapters.
+  static void generate_adapters();
+
+  // Called from InterpreterGenerator and MethodHandlesAdapterGenerator.
   static address generate_method_handle_interpreter_entry(MacroAssembler* _masm);
   static void generate_method_handle_stub(MacroAssembler* _masm, EntryKind ek);
 
@@ -447,3 +454,14 @@
 
 address MethodHandles::from_compiled_entry(EntryKind ek) { return entry(ek)->from_compiled_entry(); }
 address MethodHandles::from_interpreted_entry(EntryKind ek) { return entry(ek)->from_interpreted_entry(); }
+
+
+//------------------------------------------------------------------------------
+// MethodHandlesAdapterGenerator
+//
+class MethodHandlesAdapterGenerator : public StubCodeGenerator {
+public:
+  MethodHandlesAdapterGenerator(CodeBuffer* code) : StubCodeGenerator(code) {}
+
+  void generate();
+};
--- a/src/share/vm/runtime/init.cpp	Thu Mar 11 05:09:20 2010 -0800
+++ b/src/share/vm/runtime/init.cpp	Tue Mar 16 11:52:17 2010 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -118,6 +118,9 @@
   javaClasses_init();  // must happen after vtable initialization
   stubRoutines_init2(); // note: StubRoutines need 2-phase init
 
+  // Generate MethodHandles adapters.
+  MethodHandles::generate_adapters();
+
   // Although we'd like to, we can't easily do a heap verify
   // here because the main thread isn't yet a JavaThread, so
   // its TLAB may not be made parseable from the usual interfaces.
--- a/src/share/vm/runtime/sharedRuntime.cpp	Thu Mar 11 05:09:20 2010 -0800
+++ b/src/share/vm/runtime/sharedRuntime.cpp	Tue Mar 16 11:52:17 2010 +0100
@@ -582,7 +582,7 @@
           // 3. Implict null exception in nmethod
 
           if (!cb->is_nmethod()) {
-            guarantee(cb->is_adapter_blob(),
+            guarantee(cb->is_adapter_blob() || cb->is_method_handles_adapter_blob(),
                       "exception happened outside interpreter, nmethods and vtable stubs (1)");
             // There is no handler here, so we will simply unwind.
             return StubRoutines::throw_NullPointerException_at_call_entry();
@@ -2079,7 +2079,6 @@
 
 // ---------------------------------------------------------------------------
 // Implementation of AdapterHandlerLibrary
-const char* AdapterHandlerEntry::name = "I2C/C2I adapters";
 AdapterHandlerTable* AdapterHandlerLibrary::_adapters = NULL;
 AdapterHandlerEntry* AdapterHandlerLibrary::_abstract_method_handler = NULL;
 const int AdapterHandlerLibrary_size = 16*K;
@@ -2131,7 +2130,7 @@
   ResourceMark rm;
 
   NOT_PRODUCT(int code_size);
-  BufferBlob *B = NULL;
+  AdapterBlob* B = NULL;
   AdapterHandlerEntry* entry = NULL;
   AdapterFingerPrint* fingerprint = NULL;
   {
@@ -2181,7 +2180,7 @@
 
     // Create I2C & C2I handlers
 
-    BufferBlob*  buf = buffer_blob(); // the temporary code buffer in CodeCache
+    BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache
     if (buf != NULL) {
       CodeBuffer buffer(buf->instructions_begin(), buf->instructions_size());
       short buffer_locs[20];
@@ -2210,7 +2209,7 @@
       }
 #endif
 
-      B = BufferBlob::create(AdapterHandlerEntry::name, &buffer);
+      B = AdapterBlob::create(&buffer);
       NOT_PRODUCT(code_size = buffer.code_size());
     }
     if (B == NULL) {
@@ -2242,7 +2241,7 @@
     jio_snprintf(blob_id,
                  sizeof(blob_id),
                  "%s(%s)@" PTR_FORMAT,
-                 AdapterHandlerEntry::name,
+                 B->name(),
                  fingerprint->as_string(),
                  B->instructions_begin());
     VTune::register_stub(blob_id, B->instructions_begin(), B->instructions_end());
--- a/src/share/vm/runtime/sharedRuntime.hpp	Thu Mar 11 05:09:20 2010 -0800
+++ b/src/share/vm/runtime/sharedRuntime.hpp	Tue Mar 16 11:52:17 2010 +0100
@@ -567,9 +567,6 @@
   AdapterHandlerEntry();
 
  public:
-  // The name we give all buffer blobs
-  static const char* name;
-
   address get_i2c_entry()            { return _i2c_entry; }
   address get_c2i_entry()            { return _c2i_entry; }
   address get_c2i_unverified_entry() { return _c2i_unverified_entry; }