mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
8244997: Convert the JavaThread::_threadObj oop to use OopStorage
Move the oop and handle releasing it in the service thread. Remove Universe::oops_do from callers. Co-authored-by: Erik Osterlund <erik.osterlund@oracle.com> Co-authored-by: Tom Rodriguez <tom.rodriguez@oracle.com> Reviewed-by: dholmes, zgu, eosterlund, cjplummer
This commit is contained in:
parent
4d3baa2d37
commit
0c9e0c2e7f
46 changed files with 162 additions and 207 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. 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
|
||||
|
@ -48,7 +48,7 @@ LIR_Opr LIR_OprFact::double_fpu(int reg1, int reg2) {
|
|||
void LIR_Address::verify() const {
|
||||
assert(base()->is_cpu_register(), "wrong base operand");
|
||||
assert(index()->is_illegal() || index()->is_double_cpu() || index()->is_single_cpu(), "wrong index operand");
|
||||
assert(base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA,
|
||||
assert(base()->type() == T_ADDRESS || base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA,
|
||||
"wrong type for addresses");
|
||||
}
|
||||
#endif // PRODUCT
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 2020, Oracle and/or its affiliates. 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
|
||||
|
@ -52,12 +52,12 @@ void LIR_Address::verify() const {
|
|||
// be handled by the back-end or will be rejected if not.
|
||||
#ifdef _LP64
|
||||
assert(index()->is_illegal() || index()->is_double_cpu(), "wrong index operand");
|
||||
assert(base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA,
|
||||
assert(base()->type() == T_ADDRESS || base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA,
|
||||
"wrong type for addresses");
|
||||
#else
|
||||
assert(base()->is_single_cpu(), "wrong base operand");
|
||||
assert(index()->is_illegal() || index()->is_single_cpu(), "wrong index operand");
|
||||
assert(base()->type() == T_OBJECT || base()->type() == T_INT || base()->type() == T_METADATA,
|
||||
assert(base()->type() == T_ADDRESS || base()->type() == T_OBJECT || base()->type() == T_INT || base()->type() == T_METADATA,
|
||||
"wrong type for addresses");
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
|
@ -52,12 +52,12 @@ void LIR_Address::verify() const {
|
|||
#ifdef _LP64
|
||||
assert(base()->is_cpu_register(), "wrong base operand");
|
||||
assert(index()->is_illegal() || index()->is_double_cpu(), "wrong index operand");
|
||||
assert(base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA,
|
||||
assert(base()->type() == T_ADDRESS || base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA,
|
||||
"wrong type for addresses");
|
||||
#else
|
||||
assert(base()->is_single_cpu(), "wrong base operand");
|
||||
assert(index()->is_illegal() || index()->is_single_cpu(), "wrong index operand");
|
||||
assert(base()->type() == T_OBJECT || base()->type() == T_INT || base()->type() == T_METADATA,
|
||||
assert(base()->type() == T_ADDRESS || base()->type() == T_OBJECT || base()->type() == T_INT || base()->type() == T_METADATA,
|
||||
"wrong type for addresses");
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
|
@ -51,7 +51,7 @@ LIR_Opr LIR_OprFact::double_fpu(int reg1, int reg2) {
|
|||
void LIR_Address::verify() const {
|
||||
assert(base()->is_cpu_register(), "wrong base operand");
|
||||
assert(index()->is_illegal() || index()->is_double_cpu(), "wrong index operand");
|
||||
assert(base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA,
|
||||
assert(base()->type() == T_ADDRESS || base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA,
|
||||
"wrong type for addresses");
|
||||
}
|
||||
#endif // PRODUCT
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. 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
|
||||
|
@ -62,12 +62,12 @@ void LIR_Address::verify() const {
|
|||
#ifdef _LP64
|
||||
assert(base()->is_cpu_register(), "wrong base operand");
|
||||
assert(index()->is_illegal() || index()->is_double_cpu(), "wrong index operand");
|
||||
assert(base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA,
|
||||
assert(base()->type() == T_ADDRESS || base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA,
|
||||
"wrong type for addresses");
|
||||
#else
|
||||
assert(base()->is_single_cpu(), "wrong base operand");
|
||||
assert(index()->is_illegal() || index()->is_single_cpu(), "wrong index operand");
|
||||
assert(base()->type() == T_OBJECT || base()->type() == T_INT || base()->type() == T_METADATA,
|
||||
assert(base()->type() == T_ADDRESS || base()->type() == T_OBJECT || base()->type() == T_INT || base()->type() == T_METADATA,
|
||||
"wrong type for addresses");
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1315,8 +1315,12 @@ void LIRGenerator::do_isPrimitive(Intrinsic* x) {
|
|||
// Example: Thread.currentThread()
|
||||
void LIRGenerator::do_currentThread(Intrinsic* x) {
|
||||
assert(x->number_of_arguments() == 0, "wrong type");
|
||||
LIR_Opr temp = new_register(T_ADDRESS);
|
||||
LIR_Opr reg = rlock_result(x);
|
||||
__ move_wide(new LIR_Address(getThreadPointer(), in_bytes(JavaThread::threadObj_offset()), T_OBJECT), reg);
|
||||
__ move(new LIR_Address(getThreadPointer(), in_bytes(JavaThread::threadObj_offset()), T_ADDRESS), temp);
|
||||
// threadObj = ((OopHandle)_threadObj)->resolve();
|
||||
access_load(IN_NATIVE, T_OBJECT,
|
||||
LIR_OprFact::address(new LIR_Address(temp, T_OBJECT)), reg);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) :
|
|||
|
||||
// Root scanning phases
|
||||
_gc_par_phases[ThreadRoots] = new WorkerDataArray<double>("ThreadRoots", "Thread Roots (ms):", max_gc_threads);
|
||||
_gc_par_phases[UniverseRoots] = new WorkerDataArray<double>("UniverseRoots", "Universe Roots (ms):", max_gc_threads);
|
||||
_gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray<double>("ObjectSynchronizerRoots", "ObjectSynchronizer Roots (ms):", max_gc_threads);
|
||||
_gc_par_phases[CLDGRoots] = new WorkerDataArray<double>("CLDGRoots", "CLDG Roots (ms):", max_gc_threads);
|
||||
AOT_ONLY(_gc_par_phases[AOTCodeRoots] = new WorkerDataArray<double>("AOTCodeRoots", "AOT Root Scan (ms):", max_gc_threads);)
|
||||
|
|
|
@ -48,7 +48,6 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
|||
GCWorkerStart,
|
||||
ExtRootScan,
|
||||
ThreadRoots,
|
||||
UniverseRoots,
|
||||
ObjectSynchronizerRoots,
|
||||
CLDGRoots,
|
||||
AOT_ONLY(AOTCodeRoots COMMA)
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
#include "gc/shared/oopStorageSetParState.inline.hpp"
|
||||
#include "gc/shared/referenceProcessor.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "runtime/mutex.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
|
@ -181,13 +180,6 @@ void G1RootProcessor::process_vm_roots(G1RootClosures* closures,
|
|||
uint worker_id) {
|
||||
OopClosure* strong_roots = closures->strong_oops();
|
||||
|
||||
{
|
||||
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::UniverseRoots, worker_id);
|
||||
if (_process_strong_tasks.try_claim_task(G1RP_PS_Universe_oops_do)) {
|
||||
Universe::oops_do(strong_roots);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ObjectSynchronizerRoots, worker_id);
|
||||
if (_process_strong_tasks.try_claim_task(G1RP_PS_ObjectSynchronizer_oops_do)) {
|
||||
|
|
|
@ -2008,10 +2008,6 @@ static void mark_from_roots_work(ParallelRootType::Value root_type, uint worker_
|
|||
PCMarkAndPushClosure mark_and_push_closure(cm);
|
||||
|
||||
switch (root_type) {
|
||||
case ParallelRootType::universe:
|
||||
Universe::oops_do(&mark_and_push_closure);
|
||||
break;
|
||||
|
||||
case ParallelRootType::object_synchronizer:
|
||||
ObjectSynchronizer::oops_do(&mark_and_push_closure);
|
||||
break;
|
||||
|
@ -2225,7 +2221,6 @@ void PSParallelCompact::adjust_roots(ParCompactionManager* cm) {
|
|||
PCAdjustPointerClosure oop_closure(cm);
|
||||
|
||||
// General strong roots.
|
||||
Universe::oops_do(&oop_closure);
|
||||
Threads::oops_do(&oop_closure, NULL);
|
||||
ObjectSynchronizer::oops_do(&oop_closure);
|
||||
OopStorageSet::strong_oops_do(&oop_closure);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. 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
|
||||
|
@ -34,7 +34,6 @@ public:
|
|||
// The order reflects the order these roots are to be processed,
|
||||
// We do not want any holes in the enum as we enumerate these values by incrementing them.
|
||||
enum Value {
|
||||
universe,
|
||||
object_synchronizer,
|
||||
class_loader_data,
|
||||
code_cache,
|
||||
|
|
|
@ -92,10 +92,6 @@ static void scavenge_roots_work(ParallelRootType::Value root_type, uint worker_i
|
|||
PSPromoteRootsClosure roots_to_old_closure(pm);
|
||||
|
||||
switch (root_type) {
|
||||
case ParallelRootType::universe:
|
||||
Universe::oops_do(&roots_closure);
|
||||
break;
|
||||
|
||||
case ParallelRootType::object_synchronizer:
|
||||
ObjectSynchronizer::oops_do(&roots_closure);
|
||||
break;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. 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
|
||||
|
@ -141,6 +141,7 @@ Node* BarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) con
|
|||
bool control_dependent = (decorators & C2_CONTROL_DEPENDENT_LOAD) != 0;
|
||||
bool unknown_control = (decorators & C2_UNKNOWN_CONTROL_LOAD) != 0;
|
||||
bool unsafe = (decorators & C2_UNSAFE_ACCESS) != 0;
|
||||
bool immutable = (decorators & C2_IMMUTABLE_MEMORY) != 0;
|
||||
|
||||
bool in_native = (decorators & IN_NATIVE) != 0;
|
||||
|
||||
|
@ -153,10 +154,14 @@ Node* BarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) con
|
|||
GraphKit* kit = parse_access.kit();
|
||||
Node* control = control_dependent ? kit->control() : NULL;
|
||||
|
||||
if (in_native) {
|
||||
load = kit->make_load(control, adr, val_type, access.type(), mo, dep,
|
||||
requires_atomic_access, unaligned,
|
||||
if (immutable) {
|
||||
assert(!requires_atomic_access, "can't ensure atomicity");
|
||||
Compile* C = Compile::current();
|
||||
Node* mem = kit->immutable_memory();
|
||||
load = LoadNode::make(kit->gvn(), control, mem, adr,
|
||||
adr_type, val_type, access.type(), mo, dep, unaligned,
|
||||
mismatched, unsafe, access.barrier_data());
|
||||
load = kit->gvn().transform(load);
|
||||
} else {
|
||||
load = kit->make_load(control, adr, val_type, access.type(), adr_type, mo,
|
||||
dep, requires_atomic_access, unaligned, mismatched, unsafe,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. 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
|
||||
|
@ -54,6 +54,8 @@ const DecoratorSet C2_READ_ACCESS = DECORATOR_LAST << 8;
|
|||
const DecoratorSet C2_TIGHTLY_COUPLED_ALLOC = DECORATOR_LAST << 9;
|
||||
// Loads and stores from an arraycopy being optimized
|
||||
const DecoratorSet C2_ARRAY_COPY = DECORATOR_LAST << 10;
|
||||
// Loads from immutable memory
|
||||
const DecoratorSet C2_IMMUTABLE_MEMORY = DECORATOR_LAST << 11;
|
||||
|
||||
class Compile;
|
||||
class ConnectionGraph;
|
||||
|
|
|
@ -817,10 +817,6 @@ void GenCollectedHeap::process_roots(StrongRootsScope* scope,
|
|||
bool is_par = scope->n_threads() > 1;
|
||||
Threads::possibly_parallel_oops_do(is_par, strong_roots, roots_from_code_p);
|
||||
|
||||
if (_process_strong_tasks->try_claim_task(GCH_PS_Universe_oops_do)) {
|
||||
Universe::oops_do(strong_roots);
|
||||
}
|
||||
|
||||
if (_process_strong_tasks->try_claim_task(GCH_PS_ObjectSynchronizer_oops_do)) {
|
||||
ObjectSynchronizer::oops_do(strong_roots);
|
||||
}
|
||||
|
|
|
@ -105,7 +105,6 @@ protected:
|
|||
|
||||
// The set of potentially parallel tasks in root scanning.
|
||||
enum GCH_strong_roots_tasks {
|
||||
GCH_PS_Universe_oops_do,
|
||||
GCH_PS_ObjectSynchronizer_oops_do,
|
||||
GCH_PS_OopStorageSet_oops_do,
|
||||
GCH_PS_ClassLoaderDataGraph_oops_do,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. 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,7 +37,7 @@ class OopStorageSet : public AllStatic {
|
|||
|
||||
public:
|
||||
// Must be updated when new OopStorages are introduced
|
||||
static const uint strong_count = 2;
|
||||
static const uint strong_count = 3;
|
||||
static const uint weak_count = 4 JFR_ONLY(+ 1);
|
||||
static const uint all_count = strong_count + weak_count;
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ class outputStream;
|
|||
f(CNT_PREFIX ## TotalWork, DESC_PREFIX "<total>") \
|
||||
f(CNT_PREFIX ## ThreadRoots, DESC_PREFIX "Thread Roots") \
|
||||
f(CNT_PREFIX ## CodeCacheRoots, DESC_PREFIX "Code Cache Roots") \
|
||||
f(CNT_PREFIX ## UniverseRoots, DESC_PREFIX "Universe Roots") \
|
||||
f(CNT_PREFIX ## VMStrongRoots, DESC_PREFIX "VM Strong Roots") \
|
||||
f(CNT_PREFIX ## VMWeakRoots, DESC_PREFIX "VM Weak Roots") \
|
||||
f(CNT_PREFIX ## ObjectSynchronizerRoots, DESC_PREFIX "Synchronizer Roots") \
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
#include "gc/shenandoah/shenandoahVMOperations.hpp"
|
||||
#include "memory/iterator.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
|
||||
ShenandoahSerialRoot::ShenandoahSerialRoot(ShenandoahSerialRoot::OopsDo oops_do,
|
||||
|
@ -53,12 +52,10 @@ void ShenandoahSerialRoot::oops_do(OopClosure* cl, uint worker_id) {
|
|||
}
|
||||
|
||||
ShenandoahSerialRoots::ShenandoahSerialRoots(ShenandoahPhaseTimings::Phase phase) :
|
||||
_universe_root(&Universe::oops_do, phase, ShenandoahPhaseTimings::UniverseRoots),
|
||||
_object_synchronizer_root(&ObjectSynchronizer::oops_do, phase, ShenandoahPhaseTimings::ObjectSynchronizerRoots) {
|
||||
}
|
||||
|
||||
void ShenandoahSerialRoots::oops_do(OopClosure* cl, uint worker_id) {
|
||||
_universe_root.oops_do(cl, worker_id);
|
||||
_object_synchronizer_root.oops_do(cl, worker_id);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,6 @@ public:
|
|||
|
||||
class ShenandoahSerialRoots {
|
||||
private:
|
||||
ShenandoahSerialRoot _universe_root;
|
||||
ShenandoahSerialRoot _object_synchronizer_root;
|
||||
public:
|
||||
ShenandoahSerialRoots(ShenandoahPhaseTimings::Phase phase);
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
#include "gc/shared/oopStorage.inline.hpp"
|
||||
#include "gc/shared/oopStorageSet.hpp"
|
||||
#include "gc/shared/weakProcessor.inline.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
|
@ -75,7 +74,6 @@ void ShenandoahRootVerifier::oops_do(OopClosure* oops) {
|
|||
|
||||
if (verify(SerialRoots)) {
|
||||
shenandoah_assert_safepoint();
|
||||
Universe::oops_do(oops);
|
||||
ObjectSynchronizer::oops_do(oops);
|
||||
}
|
||||
|
||||
|
@ -119,7 +117,6 @@ void ShenandoahRootVerifier::roots_do(OopClosure* oops) {
|
|||
CLDToOopClosure clds(oops, ClassLoaderData::_claim_none);
|
||||
ClassLoaderDataGraph::cld_do(&clds);
|
||||
|
||||
Universe::oops_do(oops);
|
||||
JNIHandles::oops_do(oops);
|
||||
ObjectSynchronizer::oops_do(oops);
|
||||
Universe::vm_global()->oops_do(oops);
|
||||
|
@ -145,7 +142,6 @@ void ShenandoahRootVerifier::strong_roots_do(OopClosure* oops) {
|
|||
CLDToOopClosure clds(oops, ClassLoaderData::_claim_none);
|
||||
ClassLoaderDataGraph::roots_cld_do(&clds, NULL);
|
||||
|
||||
Universe::oops_do(oops);
|
||||
JNIHandles::oops_do(oops);
|
||||
ObjectSynchronizer::oops_do(oops);
|
||||
Universe::vm_global()->oops_do(oops);
|
||||
|
|
|
@ -54,7 +54,6 @@
|
|||
static const ZStatSubPhase ZSubPhasePauseRootsSetup("Pause Roots Setup");
|
||||
static const ZStatSubPhase ZSubPhasePauseRoots("Pause Roots");
|
||||
static const ZStatSubPhase ZSubPhasePauseRootsTeardown("Pause Roots Teardown");
|
||||
static const ZStatSubPhase ZSubPhasePauseRootsUniverse("Pause Roots Universe");
|
||||
static const ZStatSubPhase ZSubPhasePauseRootsObjectSynchronizer("Pause Roots ObjectSynchronizer");
|
||||
static const ZStatSubPhase ZSubPhasePauseRootsJVMTIWeakExport("Pause Roots JVMTIWeakExport");
|
||||
static const ZStatSubPhase ZSubPhasePauseRootsVMThread("Pause Roots VM Thread");
|
||||
|
@ -185,7 +184,6 @@ void ZJavaThreadsIterator::threads_do(ThreadClosure* cl) {
|
|||
ZRootsIterator::ZRootsIterator(bool visit_jvmti_weak_export) :
|
||||
_visit_jvmti_weak_export(visit_jvmti_weak_export),
|
||||
_java_threads_iter(),
|
||||
_universe(this),
|
||||
_object_synchronizer(this),
|
||||
_jvmti_weak_export(this),
|
||||
_vm_thread(this),
|
||||
|
@ -213,11 +211,6 @@ ZRootsIterator::~ZRootsIterator() {
|
|||
COMPILER2_OR_JVMCI_PRESENT(DerivedPointerTable::update_pointers());
|
||||
}
|
||||
|
||||
void ZRootsIterator::do_universe(ZRootsIteratorClosure* cl) {
|
||||
ZStatTimer timer(ZSubPhasePauseRootsUniverse);
|
||||
Universe::oops_do(cl);
|
||||
}
|
||||
|
||||
void ZRootsIterator::do_object_synchronizer(ZRootsIteratorClosure* cl) {
|
||||
ZStatTimer timer(ZSubPhasePauseRootsObjectSynchronizer);
|
||||
ObjectSynchronizer::oops_do(cl);
|
||||
|
@ -248,7 +241,6 @@ void ZRootsIterator::do_code_cache(ZRootsIteratorClosure* cl) {
|
|||
|
||||
void ZRootsIterator::oops_do(ZRootsIteratorClosure* cl) {
|
||||
ZStatTimer timer(ZSubPhasePauseRoots);
|
||||
_universe.oops_do(cl);
|
||||
_object_synchronizer.oops_do(cl);
|
||||
_vm_thread.oops_do(cl);
|
||||
_java_threads.oops_do(cl);
|
||||
|
|
|
@ -110,14 +110,12 @@ private:
|
|||
const bool _visit_jvmti_weak_export;
|
||||
ZJavaThreadsIterator _java_threads_iter;
|
||||
|
||||
void do_universe(ZRootsIteratorClosure* cl);
|
||||
void do_object_synchronizer(ZRootsIteratorClosure* cl);
|
||||
void do_jvmti_weak_export(ZRootsIteratorClosure* cl);
|
||||
void do_vm_thread(ZRootsIteratorClosure* cl);
|
||||
void do_java_threads(ZRootsIteratorClosure* cl);
|
||||
void do_code_cache(ZRootsIteratorClosure* cl);
|
||||
|
||||
ZSerialOopsDo<ZRootsIterator, &ZRootsIterator::do_universe> _universe;
|
||||
ZSerialOopsDo<ZRootsIterator, &ZRootsIterator::do_object_synchronizer> _object_synchronizer;
|
||||
ZSerialOopsDo<ZRootsIterator, &ZRootsIterator::do_jvmti_weak_export> _jvmti_weak_export;
|
||||
ZSerialOopsDo<ZRootsIterator, &ZRootsIterator::do_vm_thread> _vm_thread;
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#include "jfr/leakprofiler/chains/edgeQueue.hpp"
|
||||
#include "jfr/leakprofiler/chains/rootSetClosure.hpp"
|
||||
#include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "oops/access.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/synchronizer.hpp"
|
||||
|
@ -73,7 +72,6 @@ void RootSetClosure<Delegate>::process() {
|
|||
// We don't follow code blob oops, because they have misaligned oops.
|
||||
Threads::oops_do(this, NULL);
|
||||
ObjectSynchronizer::oops_do(this);
|
||||
Universe::oops_do(this);
|
||||
OopStorageSet::strong_oops_do(this);
|
||||
AOTLoader::oops_do(this);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#include "jfr/leakprofiler/checkpoint/rootResolver.hpp"
|
||||
#include "jfr/utilities/jfrThreadIterator.hpp"
|
||||
#include "memory/iterator.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "oops/klass.hpp"
|
||||
#include "oops/oop.hpp"
|
||||
#include "prims/jvmtiThreadState.hpp"
|
||||
|
@ -97,7 +96,6 @@ class ReferenceToRootClosure : public StackObj {
|
|||
|
||||
bool do_cldg_roots();
|
||||
bool do_object_synchronizer_roots();
|
||||
bool do_universe_roots();
|
||||
bool do_oop_storage_roots();
|
||||
bool do_string_table_roots();
|
||||
bool do_aot_loader_roots();
|
||||
|
@ -138,13 +136,6 @@ bool ReferenceToRootClosure::do_object_synchronizer_roots() {
|
|||
return rlc.complete();
|
||||
}
|
||||
|
||||
bool ReferenceToRootClosure::do_universe_roots() {
|
||||
assert(!complete(), "invariant");
|
||||
ReferenceLocateClosure rlc(_callback, OldObjectRoot::_universe, OldObjectRoot::_type_undetermined, NULL);
|
||||
Universe::oops_do(&rlc);
|
||||
return rlc.complete();
|
||||
}
|
||||
|
||||
bool ReferenceToRootClosure::do_oop_storage_roots() {
|
||||
int i = 0;
|
||||
for (OopStorageSet::Iterator it = OopStorageSet::strong_iterator(); !it.is_end(); ++it, ++i) {
|
||||
|
@ -185,11 +176,6 @@ bool ReferenceToRootClosure::do_roots() {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (do_universe_roots()) {
|
||||
_complete = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (do_oop_storage_roots()) {
|
||||
_complete = true;
|
||||
return true;
|
||||
|
|
|
@ -170,7 +170,7 @@
|
|||
nonstatic_field(JVMCICompileState, _jvmti_can_post_on_exceptions, jbyte) \
|
||||
nonstatic_field(JVMCICompileState, _jvmti_can_pop_frame, jbyte) \
|
||||
\
|
||||
nonstatic_field(JavaThread, _threadObj, oop) \
|
||||
nonstatic_field(JavaThread, _threadObj, OopHandle) \
|
||||
nonstatic_field(JavaThread, _anchor, JavaFrameAnchor) \
|
||||
nonstatic_field(JavaThread, _vm_result, oop) \
|
||||
volatile_nonstatic_field(JavaThread, _exception_oop, oop) \
|
||||
|
|
|
@ -223,11 +223,6 @@ void Universe::basic_type_classes_do(KlassClosure *closure) {
|
|||
}
|
||||
}
|
||||
|
||||
void Universe::oops_do(OopClosure* f) {
|
||||
|
||||
ThreadsSMRSupport::exiting_threads_oops_do(f);
|
||||
}
|
||||
|
||||
void LatestMethodCache::metaspace_pointers_do(MetaspaceClosure* it) {
|
||||
it->push(&_klass);
|
||||
}
|
||||
|
|
|
@ -328,12 +328,6 @@ class Universe: AllStatic {
|
|||
static bool should_fill_in_stack_trace(Handle throwable);
|
||||
static void check_alignment(uintx size, uintx alignment, const char* name);
|
||||
|
||||
// Iteration
|
||||
|
||||
// Apply "f" to the addresses of all the direct heap pointers maintained
|
||||
// as static fields of "Universe".
|
||||
static void oops_do(OopClosure* f);
|
||||
|
||||
// CDS support
|
||||
static void serialize(SerializeClosure* f);
|
||||
|
||||
|
|
|
@ -1614,7 +1614,7 @@ Node* GraphKit::access_load(Node* adr, // actual adress to load val at
|
|||
return top(); // Dead path ?
|
||||
}
|
||||
|
||||
C2AccessValuePtr addr(adr, NULL);
|
||||
C2AccessValuePtr addr(adr, adr->bottom_type()->is_ptr());
|
||||
C2ParseAccess access(this, decorators | C2_READ_ACCESS, bt, NULL, addr);
|
||||
if (access.is_raw()) {
|
||||
return _barrier_set->BarrierSetC2::load_at(access, val_type);
|
||||
|
|
|
@ -1096,9 +1096,10 @@ Node* LibraryCallKit::generate_current_thread(Node* &tls_output) {
|
|||
const Type* thread_type = TypeOopPtr::make_from_klass(thread_klass)->cast_to_ptr_type(TypePtr::NotNull);
|
||||
Node* thread = _gvn.transform(new ThreadLocalNode());
|
||||
Node* p = basic_plus_adr(top()/*!oop*/, thread, in_bytes(JavaThread::threadObj_offset()));
|
||||
Node* threadObj = _gvn.transform(LoadNode::make(_gvn, NULL, immutable_memory(), p, p->bottom_type()->is_ptr(), thread_type, T_OBJECT, MemNode::unordered));
|
||||
tls_output = thread;
|
||||
return threadObj;
|
||||
Node* thread_obj_handle = LoadNode::make(_gvn, NULL, immutable_memory(), p, p->bottom_type()->is_ptr(), TypeRawPtr::NOTNULL, T_ADDRESS, MemNode::unordered);
|
||||
thread_obj_handle = _gvn.transform(thread_obj_handle);
|
||||
return access_load(thread_obj_handle, thread_type, T_OBJECT, IN_NATIVE | C2_IMMUTABLE_MEMORY);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -811,7 +811,9 @@ bool LoadNode::is_immutable_value(Node* adr) {
|
|||
return (adr->is_AddP() && adr->in(AddPNode::Base)->is_top() &&
|
||||
adr->in(AddPNode::Address)->Opcode() == Op_ThreadLocal &&
|
||||
(adr->in(AddPNode::Offset)->find_intptr_t_con(-1) ==
|
||||
in_bytes(JavaThread::osthread_offset())));
|
||||
in_bytes(JavaThread::osthread_offset()) ||
|
||||
adr->in(AddPNode::Offset)->find_intptr_t_con(-1) ==
|
||||
in_bytes(JavaThread::threadObj_offset())));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -3030,7 +3030,7 @@ inline bool VM_HeapWalkOperation::collect_simple_roots() {
|
|||
// Many of these won't be visible but others (such as instances of important
|
||||
// exceptions) will be visible.
|
||||
blk.set_kind(JVMTI_HEAP_REFERENCE_OTHER);
|
||||
Universe::oops_do(&blk);
|
||||
Universe::vm_global()->oops_do(&blk);
|
||||
if (blk.stopped()) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "gc/shared/oopStorage.hpp"
|
||||
#include "gc/shared/oopStorageSet.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "oops/oopHandle.inline.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/interfaceSupport.inline.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
|
@ -53,6 +54,29 @@ JvmtiDeferredEvent* ServiceThread::_jvmti_event = NULL;
|
|||
// to add this field to the per-JavaThread event queue. TODO: fix this sometime later
|
||||
JvmtiDeferredEventQueue ServiceThread::_jvmti_service_queue;
|
||||
|
||||
// Defer releasing JavaThread OopHandle to the ServiceThread
|
||||
class OopHandleList : public CHeapObj<mtInternal> {
|
||||
OopHandle _handle;
|
||||
OopHandleList* _next;
|
||||
public:
|
||||
OopHandleList(OopHandle h, OopHandleList* next) : _handle(h), _next(next) {}
|
||||
~OopHandleList() {
|
||||
_handle.release(JavaThread::thread_oop_storage());
|
||||
}
|
||||
OopHandleList* next() const { return _next; }
|
||||
};
|
||||
|
||||
static OopHandleList* _oop_handle_list = NULL;
|
||||
|
||||
static void release_oop_handles() {
|
||||
assert_lock_strong(Service_lock);
|
||||
while (_oop_handle_list != NULL) {
|
||||
OopHandleList* l = _oop_handle_list;
|
||||
_oop_handle_list = l->next();
|
||||
delete l;
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceThread::initialize() {
|
||||
EXCEPTION_MARK;
|
||||
|
||||
|
@ -139,6 +163,7 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
|
|||
(thread_id_table_work = ThreadIdTable::has_work()) |
|
||||
(protection_domain_table_work = SystemDictionary::pd_cache_table()->has_work()) |
|
||||
(oopstorage_work = OopStorage::has_cleanup_work_and_reset()) |
|
||||
(_oop_handle_list != NULL) |
|
||||
(deflate_idle_monitors = ObjectSynchronizer::is_async_deflation_needed())
|
||||
) == 0) {
|
||||
// Wait until notified that there is some work to do.
|
||||
|
@ -152,6 +177,11 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
|
|||
jvmti_event = _jvmti_service_queue.dequeue();
|
||||
_jvmti_event = &jvmti_event;
|
||||
}
|
||||
|
||||
// Release thread OopHandles in lock
|
||||
if (_oop_handle_list != NULL) {
|
||||
release_oop_handles();
|
||||
}
|
||||
}
|
||||
|
||||
if (stringtable_work) {
|
||||
|
@ -238,3 +268,10 @@ void ServiceThread::nmethods_do(CodeBlobClosure* cf) {
|
|||
_jvmti_service_queue.nmethods_do(cf);
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceThread::add_oop_handle_release(OopHandle handle) {
|
||||
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||||
OopHandleList* new_head = new OopHandleList(handle, _oop_handle_list);
|
||||
_oop_handle_list = new_head;
|
||||
Service_lock->notify_all();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. 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
|
||||
|
@ -52,6 +52,7 @@ class ServiceThread : public JavaThread {
|
|||
|
||||
// Add event to the service thread event queue.
|
||||
static void enqueue_deferred_event(JvmtiDeferredEvent* event);
|
||||
static void add_oop_handle_release(OopHandle handle);
|
||||
|
||||
// GC support
|
||||
void oops_do(OopClosure* f, CodeBlobClosure* cf);
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/gcId.hpp"
|
||||
#include "gc/shared/gcLocker.inline.hpp"
|
||||
#include "gc/shared/oopStorage.hpp"
|
||||
#include "gc/shared/oopStorageSet.hpp"
|
||||
#include "gc/shared/workgroup.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "interpreter/linkResolver.hpp"
|
||||
|
@ -1055,12 +1057,12 @@ static Handle create_initial_thread_group(TRAPS) {
|
|||
return main_instance;
|
||||
}
|
||||
|
||||
// Creates the initial Thread
|
||||
static oop create_initial_thread(Handle thread_group, JavaThread* thread,
|
||||
// Creates the initial Thread, and sets it to running.
|
||||
static void create_initial_thread(Handle thread_group, JavaThread* thread,
|
||||
TRAPS) {
|
||||
InstanceKlass* ik = SystemDictionary::Thread_klass();
|
||||
assert(ik->is_initialized(), "must be");
|
||||
instanceHandle thread_oop = ik->allocate_instance_handle(CHECK_NULL);
|
||||
instanceHandle thread_oop = ik->allocate_instance_handle(CHECK);
|
||||
|
||||
// Cannot use JavaCalls::construct_new_instance because the java.lang.Thread
|
||||
// constructor calls Thread.current(), which must be set here for the
|
||||
|
@ -1069,7 +1071,7 @@ static oop create_initial_thread(Handle thread_group, JavaThread* thread,
|
|||
java_lang_Thread::set_priority(thread_oop(), NormPriority);
|
||||
thread->set_threadObj(thread_oop());
|
||||
|
||||
Handle string = java_lang_String::create_from_str("main", CHECK_NULL);
|
||||
Handle string = java_lang_String::create_from_str("main", CHECK);
|
||||
|
||||
JavaValue result(T_VOID);
|
||||
JavaCalls::call_special(&result, thread_oop,
|
||||
|
@ -1078,8 +1080,12 @@ static oop create_initial_thread(Handle thread_group, JavaThread* thread,
|
|||
vmSymbols::threadgroup_string_void_signature(),
|
||||
thread_group,
|
||||
string,
|
||||
CHECK_NULL);
|
||||
return thread_oop();
|
||||
CHECK);
|
||||
|
||||
// Set thread status to running since main thread has
|
||||
// been started and running.
|
||||
java_lang_Thread::set_thread_status(thread_oop(),
|
||||
java_lang_Thread::RUNNABLE);
|
||||
}
|
||||
|
||||
char java_runtime_name[128] = "";
|
||||
|
@ -1187,6 +1193,23 @@ static void call_postVMInitHook(TRAPS) {
|
|||
}
|
||||
}
|
||||
|
||||
// Initialized by VMThread at vm_global_init
|
||||
static OopStorage* _thread_oop_storage = NULL;
|
||||
|
||||
oop JavaThread::threadObj() const {
|
||||
return _threadObj.resolve();
|
||||
}
|
||||
|
||||
void JavaThread::set_threadObj(oop p) {
|
||||
assert(_thread_oop_storage != NULL, "not yet initialized");
|
||||
_threadObj = OopHandle(_thread_oop_storage, p);
|
||||
}
|
||||
|
||||
OopStorage* JavaThread::thread_oop_storage() {
|
||||
assert(_thread_oop_storage != NULL, "not yet initialized");
|
||||
return _thread_oop_storage;
|
||||
}
|
||||
|
||||
void JavaThread::allocate_threadObj(Handle thread_group, const char* thread_name,
|
||||
bool daemon, TRAPS) {
|
||||
assert(thread_group.not_null(), "thread group should be specified");
|
||||
|
@ -1653,7 +1676,6 @@ void JavaThread::initialize() {
|
|||
// Initialize fields
|
||||
|
||||
set_saved_exception_pc(NULL);
|
||||
set_threadObj(NULL);
|
||||
_anchor.clear();
|
||||
set_entry_point(NULL);
|
||||
set_jni_functions(jni_functions());
|
||||
|
@ -1758,7 +1780,7 @@ void JavaThread::interrupt() {
|
|||
bool JavaThread::is_interrupted(bool clear_interrupted) {
|
||||
debug_only(check_for_dangling_thread_pointer(this);)
|
||||
|
||||
if (threadObj() == NULL) {
|
||||
if (_threadObj.peek() == NULL) {
|
||||
// If there is no j.l.Thread then it is impossible to have
|
||||
// been interrupted. We can find NULL during VM initialization
|
||||
// or when a JNI thread is still in the process of attaching.
|
||||
|
@ -1871,6 +1893,9 @@ JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) :
|
|||
|
||||
JavaThread::~JavaThread() {
|
||||
|
||||
// Ask ServiceThread to release the threadObj OopHandle
|
||||
ServiceThread::add_oop_handle_release(_threadObj);
|
||||
|
||||
// JSR166 -- return the parker to the free list
|
||||
Parker::Release(_parker);
|
||||
_parker = NULL;
|
||||
|
@ -1971,7 +1996,7 @@ void JavaThread::run() {
|
|||
|
||||
void JavaThread::thread_main_inner() {
|
||||
assert(JavaThread::current() == this, "sanity check");
|
||||
assert(this->threadObj() != NULL, "just checking");
|
||||
assert(_threadObj.peek() != NULL, "just checking");
|
||||
|
||||
// Execute thread entry point unless this thread has a pending exception
|
||||
// or has been stopped before starting.
|
||||
|
@ -3015,7 +3040,6 @@ void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
|
|||
|
||||
// Traverse instance variables at the end since the GC may be moving things
|
||||
// around using this function
|
||||
f->do_oop((oop*) &_threadObj);
|
||||
f->do_oop((oop*) &_vm_result);
|
||||
f->do_oop((oop*) &_exception_oop);
|
||||
f->do_oop((oop*) &_pending_async_exception);
|
||||
|
@ -3717,13 +3741,7 @@ void Threads::initialize_java_lang_classes(JavaThread* main_thread, TRAPS) {
|
|||
Handle thread_group = create_initial_thread_group(CHECK);
|
||||
Universe::set_main_thread_group(thread_group());
|
||||
initialize_class(vmSymbols::java_lang_Thread(), CHECK);
|
||||
oop thread_object = create_initial_thread(thread_group, main_thread, CHECK);
|
||||
main_thread->set_threadObj(thread_object);
|
||||
|
||||
// Set thread status to running since main thread has
|
||||
// been started and running.
|
||||
java_lang_Thread::set_thread_status(thread_object,
|
||||
java_lang_Thread::RUNNABLE);
|
||||
create_initial_thread(thread_group, main_thread, CHECK);
|
||||
|
||||
// The VM creates objects of this class.
|
||||
initialize_class(vmSymbols::java_lang_Module(), CHECK);
|
||||
|
@ -3886,6 +3904,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
|
|||
}
|
||||
#endif // INCLUDE_JVMCI
|
||||
|
||||
// Initialize OopStorage for threadObj
|
||||
_thread_oop_storage = OopStorageSet::create_strong("Thread OopStorage");
|
||||
|
||||
// Attach the main thread to this os thread
|
||||
JavaThread* main_thread = new JavaThread();
|
||||
main_thread->set_thread_state(_thread_in_vm);
|
||||
|
|
|
@ -92,6 +92,8 @@ class JVMCIPrimitiveArray;
|
|||
class Metadata;
|
||||
class ResourceArea;
|
||||
|
||||
class OopStorage;
|
||||
|
||||
DEBUG_ONLY(class ResourceMark;)
|
||||
|
||||
class WorkerThread;
|
||||
|
@ -1017,7 +1019,7 @@ class JavaThread: public Thread {
|
|||
friend class ThreadsSMRSupport; // to access _threadObj for exiting_threads_oops_do
|
||||
private:
|
||||
bool _on_thread_list; // Is set when this JavaThread is added to the Threads list
|
||||
oop _threadObj; // The Java level thread object
|
||||
OopHandle _threadObj; // The Java level thread object
|
||||
|
||||
#ifdef ASSERT
|
||||
private:
|
||||
|
@ -1277,8 +1279,8 @@ class JavaThread: public Thread {
|
|||
|
||||
// Thread oop. threadObj() can be NULL for initial JavaThread
|
||||
// (or for threads attached via JNI)
|
||||
oop threadObj() const { return _threadObj; }
|
||||
void set_threadObj(oop p) { _threadObj = p; }
|
||||
oop threadObj() const;
|
||||
void set_threadObj(oop p);
|
||||
|
||||
// Prepare thread and add to priority queue. If a priority is
|
||||
// not specified, use the priority of the thread object. Threads_lock
|
||||
|
@ -2112,6 +2114,7 @@ public:
|
|||
void interrupt();
|
||||
bool is_interrupted(bool clear_interrupted);
|
||||
|
||||
static OopStorage* thread_oop_storage();
|
||||
};
|
||||
|
||||
// Inline implementation of JavaThread::current
|
||||
|
|
|
@ -41,9 +41,6 @@
|
|||
#include "utilities/resourceHash.hpp"
|
||||
#include "utilities/vmError.hpp"
|
||||
|
||||
// List of exiting threads
|
||||
ThreadsSMRSupport::Holder* ThreadsSMRSupport::_exiting_threads = NULL;
|
||||
|
||||
// The '_cnt', '_max' and '_times" fields are enabled via
|
||||
// -XX:+EnableThreadSMRStatistics:
|
||||
|
||||
|
@ -927,8 +924,6 @@ void ThreadsSMRSupport::release_stable_list_wake_up(bool is_nested) {
|
|||
|
||||
void ThreadsSMRSupport::remove_thread(JavaThread *thread) {
|
||||
|
||||
ThreadsSMRSupport::add_exiting_thread(thread);
|
||||
|
||||
if (ThreadIdTable::is_initialized()) {
|
||||
jlong tid = SharedRuntime::get_java_tid(thread);
|
||||
ThreadIdTable::remove_thread(tid);
|
||||
|
@ -998,7 +993,6 @@ void ThreadsSMRSupport::wait_until_not_protected(JavaThread *thread) {
|
|||
// This is the common case.
|
||||
ThreadsSMRSupport::clear_delete_notify();
|
||||
ThreadsSMRSupport::delete_lock()->unlock();
|
||||
ThreadsSMRSupport::remove_exiting_thread(thread);
|
||||
break;
|
||||
}
|
||||
if (!has_logged_once) {
|
||||
|
@ -1188,47 +1182,3 @@ void ThreadsSMRSupport::print_info_elements_on(outputStream* st, ThreadsList* t_
|
|||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadsSMRSupport::add_exiting_thread(JavaThread* thread) {
|
||||
assert(thread == JavaThread::current(), "invariant");
|
||||
assert(Threads_lock->owned_by_self(), "invariant");
|
||||
assert(!contains_exiting_thread(thread), "invariant");
|
||||
Holder* h = new Holder(thread, _exiting_threads);
|
||||
_exiting_threads = h;
|
||||
}
|
||||
|
||||
void ThreadsSMRSupport::remove_exiting_thread(JavaThread* thread) {
|
||||
assert(thread == JavaThread::current(), "invariant");
|
||||
assert(Threads_lock->owned_by_self(), "invariant");
|
||||
// If a thread fails to initialize fully it can be deleted immediately
|
||||
// so we won't remove it from the ThreadsList and so never add it to the
|
||||
// exiting thread list - so we can't assert(contains_exiting_thread(p)) here.
|
||||
|
||||
for (Holder* current = _exiting_threads, **prev_next = &_exiting_threads;
|
||||
current != NULL;
|
||||
prev_next = ¤t->_next, current = current->_next) {
|
||||
if (current->_thread == thread) {
|
||||
*prev_next = current->_next;
|
||||
delete current;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
bool ThreadsSMRSupport::contains_exiting_thread(JavaThread* thread) {
|
||||
for (Holder* current = _exiting_threads; current != NULL; current = current->_next) {
|
||||
if (current->_thread == thread) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void ThreadsSMRSupport::exiting_threads_oops_do(OopClosure* f) {
|
||||
assert_locked_or_safepoint(Threads_lock);
|
||||
for (Holder* current = _exiting_threads; current != NULL; current = current->_next) {
|
||||
f->do_oop((oop*) ¤t->_thread->_threadObj);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,33 +82,12 @@ class ThreadClosure;
|
|||
// but that target JavaThread * will not be deleted until it is no
|
||||
// longer protected by a ThreadsListHandle.
|
||||
//
|
||||
// Once a JavaThread has removed itself from the main ThreadsList it is
|
||||
// no longer visited by GC. To ensure that thread's threadObj() oop remains
|
||||
// valid while the thread is still accessible from a ThreadsListHandle we
|
||||
// maintain a special list of exiting threads:
|
||||
// - In remove() we add the exiting thread to the list (under the Threads_lock).
|
||||
// - In wait_until_not_protected() we remove it from the list (again under the
|
||||
// Threads_lock).
|
||||
// - Universe::oops_do walks the list (at a safepoint so VMThread holds
|
||||
// Threads_lock) and visits the _threadObj oop of each JavaThread.
|
||||
|
||||
// SMR Support for the Threads class.
|
||||
//
|
||||
class ThreadsSMRSupport : AllStatic {
|
||||
friend class VMStructs;
|
||||
friend class SafeThreadsListPtr; // for _nested_thread_list_max, delete_notify(), release_stable_list_wake_up() access
|
||||
|
||||
// Helper class for the exiting thread list
|
||||
class Holder : public CHeapObj<mtInternal> {
|
||||
public:
|
||||
JavaThread* _thread;
|
||||
Holder* _next;
|
||||
Holder(JavaThread* thread, Holder* next) : _thread(thread), _next(next) {}
|
||||
};
|
||||
|
||||
// The list of exiting threads
|
||||
static Holder* _exiting_threads;
|
||||
|
||||
// The coordination between ThreadsSMRSupport::release_stable_list() and
|
||||
// ThreadsSMRSupport::smr_delete() uses the delete_lock in order to
|
||||
// reduce the traffic on the Threads_lock.
|
||||
|
@ -170,12 +149,6 @@ class ThreadsSMRSupport : AllStatic {
|
|||
static void smr_delete(JavaThread *thread);
|
||||
static void update_tlh_stats(uint millis);
|
||||
|
||||
// Exiting thread list maintenance
|
||||
static void add_exiting_thread(JavaThread* thread);
|
||||
static void remove_exiting_thread(JavaThread* thread);
|
||||
DEBUG_ONLY(static bool contains_exiting_thread(JavaThread* thread);)
|
||||
static void exiting_threads_oops_do(OopClosure* f);
|
||||
|
||||
// Logging and printing support:
|
||||
static void log_statistics();
|
||||
static void print_info_elements_on(outputStream* st, ThreadsList* t_list);
|
||||
|
|
|
@ -740,7 +740,7 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
|
|||
nonstatic_field(Thread, _current_waiting_monitor, ObjectMonitor*) \
|
||||
nonstatic_field(NamedThread, _name, char*) \
|
||||
nonstatic_field(NamedThread, _processed_thread, JavaThread*) \
|
||||
nonstatic_field(JavaThread, _threadObj, oop) \
|
||||
nonstatic_field(JavaThread, _threadObj, OopHandle) \
|
||||
nonstatic_field(JavaThread, _anchor, JavaFrameAnchor) \
|
||||
nonstatic_field(JavaThread, _vm_result, oop) \
|
||||
nonstatic_field(JavaThread, _vm_result_2, Metadata*) \
|
||||
|
|
|
@ -1859,8 +1859,9 @@ void VM_HeapDumper::work(uint worker_id) {
|
|||
// HPROF_GC_ROOT_JNI_GLOBAL
|
||||
JNIGlobalsDumper jni_dumper(writer());
|
||||
JNIHandles::oops_do(&jni_dumper);
|
||||
Universe::oops_do(&jni_dumper); // technically not jni roots, but global roots
|
||||
// technically not jni roots, but global roots
|
||||
// for things like preallocated throwable backtraces
|
||||
Universe::vm_global()->oops_do(&jni_dumper);
|
||||
|
||||
// HPROF_GC_ROOT_STICKY_CLASS
|
||||
// These should be classes in the NULL class loader data, and not all classes
|
||||
|
|
|
@ -43,7 +43,7 @@ import sun.jvm.hotspot.utilities.Observer;
|
|||
public class JavaThread extends Thread {
|
||||
private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.runtime.JavaThread.DEBUG") != null;
|
||||
|
||||
private static sun.jvm.hotspot.types.OopField threadObjField;
|
||||
private static long threadObjFieldOffset;
|
||||
private static AddressField anchorField;
|
||||
private static AddressField lastJavaSPField;
|
||||
private static AddressField lastJavaPCField;
|
||||
|
@ -85,7 +85,8 @@ public class JavaThread extends Thread {
|
|||
Type type = db.lookupType("JavaThread");
|
||||
Type anchorType = db.lookupType("JavaFrameAnchor");
|
||||
|
||||
threadObjField = type.getOopField("_threadObj");
|
||||
threadObjFieldOffset = type.getField("_threadObj").getOffset();
|
||||
|
||||
anchorField = type.getAddressField("_anchor");
|
||||
lastJavaSPField = anchorType.getAddressField("_last_Java_sp");
|
||||
lastJavaPCField = anchorType.getAddressField("_last_Java_pc");
|
||||
|
@ -347,7 +348,9 @@ public class JavaThread extends Thread {
|
|||
public Oop getThreadObj() {
|
||||
Oop obj = null;
|
||||
try {
|
||||
obj = VM.getVM().getObjectHeap().newOop(threadObjField.getValue(addr));
|
||||
Address addr = getAddress().addOffsetTo(threadObjFieldOffset);
|
||||
VMOopHandle vmOopHandle = VMObjectFactory.newObject(VMOopHandle.class, addr);
|
||||
obj = vmOopHandle.resolve();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
|
@ -375,7 +375,19 @@ public class GraalHotSpotVMConfig extends GraalHotSpotVMConfigAccess {
|
|||
public final int threadTlabOffset = getFieldOffset("Thread::_tlab", Integer.class, "ThreadLocalAllocBuffer");
|
||||
public final int javaThreadAnchorOffset = getFieldOffset("JavaThread::_anchor", Integer.class, "JavaFrameAnchor");
|
||||
public final int javaThreadShouldPostOnExceptionsFlagOffset = getFieldOffset("JavaThread::_should_post_on_exceptions_flag", Integer.class, "int", Integer.MIN_VALUE, JVMCI || JDK >= 12);
|
||||
public final int threadObjectOffset = getFieldOffset("JavaThread::_threadObj", Integer.class, "oop");
|
||||
|
||||
public final boolean threadObjectFieldIsHandle;
|
||||
public final int threadObjectOffset;
|
||||
{
|
||||
if (JDK <= 15) {
|
||||
threadObjectFieldIsHandle = false;
|
||||
threadObjectOffset = getFieldOffset("JavaThread::_threadObj", Integer.class, "oop");
|
||||
} else {
|
||||
threadObjectFieldIsHandle = true;
|
||||
threadObjectOffset = getFieldOffset("JavaThread::_threadObj", Integer.class, "OopHandle");
|
||||
}
|
||||
}
|
||||
|
||||
public final int osThreadOffset = getFieldOffset("JavaThread::_osthread", Integer.class, "OSThread*");
|
||||
public final int threadIsMethodHandleReturnOffset = getFieldOffset("JavaThread::_is_method_handle_return", Integer.class, "int");
|
||||
public final int threadObjectResultOffset = getFieldOffset("JavaThread::_vm_result", Integer.class, "oop");
|
||||
|
|
|
@ -30,6 +30,7 @@ import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigAccess.JDK;
|
|||
import static org.graalvm.compiler.hotspot.HotSpotBackend.BASE64_ENCODE_BLOCK;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotBackend.GHASH_PROCESS_BLOCKS;
|
||||
import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
|
||||
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_HANDLE_LOCATION;
|
||||
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION;
|
||||
import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing;
|
||||
|
||||
|
@ -427,12 +428,21 @@ public class HotSpotGraphBuilderPlugins {
|
|||
AddressNode address = b.add(new OffsetAddressNode(thread, offset));
|
||||
// JavaThread::_threadObj is never compressed
|
||||
ObjectStamp stamp = StampFactory.objectNonNull(TypeReference.create(b.getAssumptions(), metaAccess.lookupJavaType(Thread.class)));
|
||||
b.addPush(JavaKind.Object, new ReadNode(address, JAVA_THREAD_THREAD_OBJECT_LOCATION, stamp, BarrierType.NONE));
|
||||
ReadNode value = b.add(new ReadNode(address, JAVA_THREAD_THREAD_OBJECT_LOCATION,
|
||||
config.threadObjectFieldIsHandle ? StampFactory.forKind(wordTypes.getWordKind()) : stamp, BarrierType.NONE));
|
||||
if (config.threadObjectFieldIsHandle) {
|
||||
ValueNode handleOffset = ConstantNode.forIntegerKind(wordTypes.getWordKind(), 0, b.getGraph());
|
||||
AddressNode handleAddress = b.add(new OffsetAddressNode(value, handleOffset));
|
||||
value = b.add(new ReadNode(handleAddress, JAVA_THREAD_THREAD_OBJECT_HANDLE_LOCATION, stamp, BarrierType.NONE));
|
||||
}
|
||||
b.push(JavaKind.Object, value);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if (config.osThreadInterruptedOffset != Integer.MAX_VALUE) {
|
||||
// This substitution is no longer in use when threadObj is a handle
|
||||
assert !config.threadObjectFieldIsHandle;
|
||||
r.registerMethodSubstitution(ThreadSubstitutions.class, "isInterrupted", Receiver.class, boolean.class);
|
||||
}
|
||||
|
||||
|
|
|
@ -308,6 +308,8 @@ public class HotSpotReplacementsUtil {
|
|||
*/
|
||||
public static final LocationIdentity JAVA_THREAD_THREAD_OBJECT_LOCATION = NamedLocationIdentity.immutable("JavaThread::_threadObj");
|
||||
|
||||
public static final LocationIdentity JAVA_THREAD_THREAD_OBJECT_HANDLE_LOCATION = NamedLocationIdentity.immutable("JavaThread::_threadObj handle");
|
||||
|
||||
@Fold
|
||||
public static int threadObjectOffset(@InjectedParameter GraalHotSpotVMConfig config) {
|
||||
return config.threadObjectOffset;
|
||||
|
|
|
@ -121,7 +121,6 @@ public class TestGCLogMessages {
|
|||
new LogMessageWithLevel("LAB Undo Waste", Level.DEBUG),
|
||||
// Ext Root Scan
|
||||
new LogMessageWithLevel("Thread Roots", Level.TRACE),
|
||||
new LogMessageWithLevel("Universe Roots", Level.TRACE),
|
||||
new LogMessageWithLevel("ObjectSynchronizer Roots", Level.TRACE),
|
||||
new LogMessageWithLevel("CLDG Roots", Level.TRACE),
|
||||
new LogMessageWithLevel("CM RefProcessor Roots", Level.TRACE),
|
||||
|
|
|
@ -91,10 +91,10 @@ public class TestG1ParallelPhases {
|
|||
Set<String> allPhases = of(
|
||||
"ExtRootScan",
|
||||
"ThreadRoots",
|
||||
"UniverseRoots",
|
||||
"ObjectSynchronizerRoots",
|
||||
"VM Global",
|
||||
"JNI Global",
|
||||
"Thread OopStorage",
|
||||
"CLDGRoots",
|
||||
"CMRefRoots",
|
||||
"MergeER",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue