Skip to content

Commit f6f038a

Browse files
author
Tom Rodriguez
committed
8317368: [JVMCI] SIGSEGV in JVMCIEnv::initialize_installed_code on libgraal
Reviewed-by: dnsimon, kvn, eosterlund
1 parent fb4cf1c commit f6f038a

File tree

7 files changed

+88
-22
lines changed

7 files changed

+88
-22
lines changed

src/hotspot/share/jvmci/jvmciCodeInstaller.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,7 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler,
704704
JVMCIObject compiled_code,
705705
objArrayHandle object_pool,
706706
CodeBlob*& cb,
707+
JVMCINMethodHandle& nmethod_handle,
707708
JVMCIObject installed_code,
708709
FailedSpeculation** failed_speculations,
709710
char* speculations,
@@ -805,6 +806,8 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler,
805806
speculations_len,
806807
_nmethod_entry_patch_offset);
807808
if (result == JVMCI::ok) {
809+
guarantee(nm != nullptr, "successful compile must produce an nmethod");
810+
nmethod_handle.set_nmethod(nm);
808811
cb = nm;
809812
if (compile_state == nullptr) {
810813
// This compile didn't come through the CompileBroker so perform the printing here
@@ -813,14 +816,13 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler,
813816
DirectivesStack::release(directive);
814817
}
815818

816-
if (nm != nullptr) {
817-
if (_nmethod_entry_patch_offset != -1) {
818-
err_msg msg("");
819-
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
819+
if (_nmethod_entry_patch_offset != -1) {
820+
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
820821

821-
if (!bs_nm->verify_barrier(nm, msg)) {
822-
JVMCI_THROW_MSG_(IllegalArgumentException, err_msg("nmethod entry barrier is malformed: %s", msg.buffer()), JVMCI::ok);
823-
}
822+
// an empty error buffer for use by the verify_barrier code
823+
err_msg msg("");
824+
if (!bs_nm->verify_barrier(nm, msg)) {
825+
JVMCI_THROW_MSG_(IllegalArgumentException, err_msg("nmethod entry barrier is malformed: %s", msg.buffer()), JVMCI::ok);
824826
}
825827
}
826828
}

src/hotspot/share/jvmci/jvmciCodeInstaller.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ class CodeInstaller : public StackObj {
332332
JVMCIObject compiled_code,
333333
objArrayHandle object_pool,
334334
CodeBlob*& cb,
335+
JVMCINMethodHandle& nmethod_handle,
335336
JVMCIObject installed_code,
336337
FailedSpeculation** failed_speculations,
337338
char* speculations,

src/hotspot/share/jvmci/jvmciCompilerToVM.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
#include "runtime/globals_extension.hpp"
6262
#include "runtime/interfaceSupport.inline.hpp"
6363
#include "runtime/jniHandles.inline.hpp"
64+
#include "runtime/keepStackGCProcessed.hpp"
6465
#include "runtime/reflection.hpp"
6566
#include "runtime/stackFrameStream.inline.hpp"
6667
#include "runtime/timerTrace.hpp"
@@ -1106,13 +1107,15 @@ C2V_VMENTRY_0(jint, installCode0, (JNIEnv *env, jobject,
11061107
TraceTime install_time("installCode", timer);
11071108

11081109
CodeInstaller installer(JVMCIENV);
1110+
JVMCINMethodHandle nmethod_handle(THREAD);
11091111

11101112
JVMCI::CodeInstallResult result = installer.install(compiler,
11111113
compiled_code_buffer,
11121114
with_type_info,
11131115
compiled_code_handle,
11141116
object_pool_handle,
11151117
cb,
1118+
nmethod_handle,
11161119
installed_code_handle,
11171120
(FailedSpeculation**)(address) failed_speculations_address,
11181121
speculations,
@@ -1204,7 +1207,8 @@ C2V_VMENTRY_NULL(jobject, executeHotSpotNmethod, (JNIEnv* env, jobject, jobject
12041207
HandleMark hm(THREAD);
12051208

12061209
JVMCIObject nmethod_mirror = JVMCIENV->wrap(hs_nmethod);
1207-
nmethod* nm = JVMCIENV->get_nmethod(nmethod_mirror);
1210+
JVMCINMethodHandle nmethod_handle(THREAD);
1211+
nmethod* nm = JVMCIENV->get_nmethod(nmethod_mirror, nmethod_handle);
12081212
if (nm == nullptr || !nm->is_in_use()) {
12091213
JVMCI_THROW_NULL(InvalidInstalledCodeException);
12101214
}
@@ -1478,6 +1482,7 @@ C2V_VMENTRY_NULL(jobject, iterateFrames, (JNIEnv* env, jobject compilerToVM, job
14781482
return nullptr;
14791483
}
14801484
Handle visitor(THREAD, JNIHandles::resolve_non_null(visitor_handle));
1485+
KeepStackGCProcessedMark keep_stack(THREAD);
14811486

14821487
requireInHotSpot("iterateFrames", JVMCI_CHECK_NULL);
14831488

@@ -2762,7 +2767,8 @@ C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle, jbool
27622767
result = PEER_JVMCIENV->get_object_constant(constant());
27632768
} else if (thisEnv->isa_HotSpotNmethod(obj)) {
27642769
if (PEER_JVMCIENV->is_hotspot()) {
2765-
nmethod* nm = JVMCIENV->get_nmethod(obj);
2770+
JVMCINMethodHandle nmethod_handle(THREAD);
2771+
nmethod* nm = JVMCIENV->get_nmethod(obj, nmethod_handle);
27662772
if (nm != nullptr) {
27672773
JVMCINMethodData* data = nm->jvmci_nmethod_data();
27682774
if (data != nullptr) {
@@ -2785,7 +2791,8 @@ C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle, jbool
27852791
const char* cstring = name_string.is_null() ? nullptr : thisEnv->as_utf8_string(name_string);
27862792
// Create a new HotSpotNmethod instance in the peer runtime
27872793
result = PEER_JVMCIENV->new_HotSpotNmethod(mh, cstring, isDefault, compileIdSnapshot, JVMCI_CHECK_0);
2788-
nmethod* nm = JVMCIENV->get_nmethod(obj);
2794+
JVMCINMethodHandle nmethod_handle(THREAD);
2795+
nmethod* nm = JVMCIENV->get_nmethod(obj, nmethod_handle);
27892796
if (result.is_null()) {
27902797
// exception occurred (e.g. OOME) creating a new HotSpotNmethod
27912798
} else if (nm == nullptr) {
@@ -2837,7 +2844,8 @@ C2V_END
28372844
C2V_VMENTRY(void, updateHotSpotNmethod, (JNIEnv* env, jobject, jobject code_handle))
28382845
JVMCIObject code = JVMCIENV->wrap(code_handle);
28392846
// Execute this operation for the side effect of updating the InstalledCode state
2840-
JVMCIENV->get_nmethod(code);
2847+
JVMCINMethodHandle nmethod_handle(THREAD);
2848+
JVMCIENV->get_nmethod(code, nmethod_handle);
28412849
C2V_END
28422850

28432851
C2V_VMENTRY_NULL(jbyteArray, getCode, (JNIEnv* env, jobject, jobject code_handle))

src/hotspot/share/jvmci/jvmciEnv.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include "code/codeCache.hpp"
3030
#include "compiler/compilerOracle.hpp"
3131
#include "compiler/compileTask.hpp"
32+
#include "gc/shared/barrierSet.hpp"
33+
#include "gc/shared/barrierSetNMethod.hpp"
3234
#include "jvm_io.h"
3335
#include "memory/oopFactory.hpp"
3436
#include "memory/resourceArea.hpp"
@@ -1722,12 +1724,6 @@ void JVMCIEnv::invalidate_nmethod_mirror(JVMCIObject mirror, bool deoptimize, JV
17221724
JVMCI_THROW(NullPointerException);
17231725
}
17241726

1725-
nmethod* nm = JVMCIENV->get_nmethod(mirror);
1726-
if (nm == nullptr) {
1727-
// Nothing to do
1728-
return;
1729-
}
1730-
17311727
Thread* current = Thread::current();
17321728
if (!mirror.is_hotspot() && !current->is_Java_thread()) {
17331729
// Calling back into native might cause the execution to block, so only allow this when calling
@@ -1736,6 +1732,14 @@ void JVMCIEnv::invalidate_nmethod_mirror(JVMCIObject mirror, bool deoptimize, JV
17361732
"Cannot invalidate HotSpotNmethod object in shared library VM heap from non-JavaThread");
17371733
}
17381734

1735+
JavaThread* thread = JavaThread::cast(current);
1736+
JVMCINMethodHandle nmethod_handle(thread);
1737+
nmethod* nm = JVMCIENV->get_nmethod(mirror, nmethod_handle);
1738+
if (nm == nullptr) {
1739+
// Nothing to do
1740+
return;
1741+
}
1742+
17391743
if (!deoptimize) {
17401744
// Prevent future executions of the nmethod but let current executions complete.
17411745
nm->make_not_entrant();
@@ -1825,10 +1829,22 @@ CodeBlob* JVMCIEnv::get_code_blob(JVMCIObject obj) {
18251829
return cb;
18261830
}
18271831

1828-
nmethod* JVMCIEnv::get_nmethod(JVMCIObject obj) {
1832+
void JVMCINMethodHandle::set_nmethod(nmethod* nm) {
1833+
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
1834+
if (bs_nm != nullptr) {
1835+
bs_nm->nmethod_entry_barrier(nm);
1836+
}
1837+
_thread->set_live_nmethod(nm);
1838+
}
1839+
1840+
nmethod* JVMCIEnv::get_nmethod(JVMCIObject obj, JVMCINMethodHandle& nmethod_handle) {
18291841
CodeBlob* cb = get_code_blob(obj);
18301842
if (cb != nullptr) {
1831-
return cb->as_nmethod_or_null();
1843+
nmethod* nm = cb->as_nmethod_or_null();
1844+
if (nm != nullptr) {
1845+
nmethod_handle.set_nmethod(nm);
1846+
return nm;
1847+
}
18321848
}
18331849
return nullptr;
18341850
}

src/hotspot/share/jvmci/jvmciEnv.hpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,21 @@ class JVMCIKlassHandle : public StackObj {
8888
bool not_null() const { return _klass != nullptr; }
8989
};
9090

91+
// A helper class to main a strong link to an nmethod that might not otherwise be referenced. Only
92+
// one nmethod can be kept alive in this manner.
93+
class JVMCINMethodHandle : public StackObj {
94+
JavaThread* _thread;
95+
96+
public:
97+
JVMCINMethodHandle(JavaThread* thread): _thread(thread) {}
98+
99+
void set_nmethod(nmethod* nm);
100+
101+
~JVMCINMethodHandle() {
102+
_thread->clear_live_nmethod();
103+
}
104+
};
105+
91106
// A class that maintains the state needed for compilations requested
92107
// by the CompileBroker. It is created in the broker and passed through
93108
// into the code installation step.
@@ -370,11 +385,11 @@ class JVMCIEnv : public ResourceObj {
370385

371386
void fthrow_error(const char* file, int line, const char* format, ...) ATTRIBUTE_PRINTF(4, 5);
372387

373-
// Given an instance of HotSpotInstalledCode return the corresponding CodeBlob*.
388+
// Given an instance of HotSpotInstalledCode, return the corresponding CodeBlob*.
374389
CodeBlob* get_code_blob(JVMCIObject code);
375390

376-
// Given an instance of HotSpotInstalledCode return the corresponding nmethod.
377-
nmethod* get_nmethod(JVMCIObject code);
391+
// Given an instance of HotSpotInstalledCode, return the corresponding nmethod.
392+
nmethod* get_nmethod(JVMCIObject code, JVMCINMethodHandle& nmethod_handle);
378393

379394
const char* klass_name(JVMCIObject object);
380395

src/hotspot/share/runtime/javaThread.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ JavaThread::JavaThread() :
467467
_jvmci_reserved0(0),
468468
_jvmci_reserved1(0),
469469
_jvmci_reserved_oop0(nullptr),
470+
_live_nmethod(nullptr),
470471
#endif // INCLUDE_JVMCI
471472

472473
_exception_oop(oop()),
@@ -1429,6 +1430,10 @@ void JavaThread::oops_do_no_frames(OopClosure* f, NMethodClosure* cf) {
14291430
f->do_oop((oop*) &_exception_oop);
14301431
#if INCLUDE_JVMCI
14311432
f->do_oop((oop*) &_jvmci_reserved_oop0);
1433+
1434+
if (_live_nmethod != nullptr && cf != nullptr) {
1435+
cf->do_nmethod(_live_nmethod);
1436+
}
14321437
#endif
14331438

14341439
if (jvmti_thread_state() != nullptr) {
@@ -1484,6 +1489,12 @@ void JavaThread::nmethods_do(NMethodClosure* cf) {
14841489
if (jvmti_thread_state() != nullptr) {
14851490
jvmti_thread_state()->nmethods_do(cf);
14861491
}
1492+
1493+
#if INCLUDE_JVMCI
1494+
if (_live_nmethod != nullptr) {
1495+
cf->do_nmethod(_live_nmethod);
1496+
}
1497+
#endif
14871498
}
14881499

14891500
void JavaThread::metadata_do(MetadataClosure* f) {

src/hotspot/share/runtime/javaThread.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,10 @@ class JavaThread: public Thread {
379379
jlong _jvmci_reserved1;
380380
oop _jvmci_reserved_oop0;
381381

382+
// This field is used to keep an nmethod visible to the GC so that it and its contained oops can
383+
// be kept alive
384+
nmethod* _live_nmethod;
385+
382386
public:
383387
static jlong* _jvmci_old_thread_counters;
384388
static void collect_counters(jlong* array, int length);
@@ -411,6 +415,15 @@ class JavaThread: public Thread {
411415
return _jvmci_reserved1;
412416
}
413417

418+
void set_live_nmethod(nmethod* nm) {
419+
assert(_live_nmethod == nullptr, "only one");
420+
_live_nmethod = nm;
421+
}
422+
423+
void clear_live_nmethod() {
424+
_live_nmethod = nullptr;
425+
}
426+
414427
private:
415428
#endif // INCLUDE_JVMCI
416429

0 commit comments

Comments
 (0)