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
--- a/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.hpp Thu Mar 11 05:09:20 2010 -0800
+++ b/hotspot/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/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp Thu Mar 11 05:09:20 2010 -0800
+++ b/hotspot/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/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp Thu Mar 11 05:09:20 2010 -0800
+++ b/hotspot/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/hotspot/src/cpu/x86/vm/stubRoutines_x86_32.hpp Thu Mar 11 05:09:20 2010 -0800
+++ b/hotspot/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/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp Thu Mar 11 05:09:20 2010 -0800
+++ b/hotspot/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/hotspot/src/share/vm/code/codeBlob.cpp Thu Mar 11 05:09:20 2010 -0800
+++ b/hotspot/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/hotspot/src/share/vm/code/codeBlob.hpp Thu Mar 11 05:09:20 2010 -0800
+++ b/hotspot/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/hotspot/src/share/vm/includeDB_core Thu Mar 11 05:09:20 2010 -0800
+++ b/hotspot/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/hotspot/src/share/vm/prims/methodHandles.cpp Thu Mar 11 05:09:20 2010 -0800
+++ b/hotspot/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/hotspot/src/share/vm/prims/methodHandles.hpp Thu Mar 11 05:09:20 2010 -0800
+++ b/hotspot/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/hotspot/src/share/vm/runtime/init.cpp Thu Mar 11 05:09:20 2010 -0800
+++ b/hotspot/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/hotspot/src/share/vm/runtime/sharedRuntime.cpp Thu Mar 11 05:09:20 2010 -0800
+++ b/hotspot/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/hotspot/src/share/vm/runtime/sharedRuntime.hpp Thu Mar 11 05:09:20 2010 -0800
+++ b/hotspot/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; }