8259008: ArithmeticException was thrown at "Monitor Cache Dump" on HSDB

Reviewed-by: dcubed, gziemski, eosterlund, cjplummer, sspitsyn
This commit is contained in:
Yasumasa Suenaga 2021-01-30 03:46:23 +00:00
parent 69ee314b63
commit 6b24e98c42
5 changed files with 149 additions and 75 deletions
src
hotspot/share/runtime
jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime
test/hotspot/jtreg/serviceability/sa

@ -58,31 +58,6 @@
#include "utilities/events.hpp"
#include "utilities/preserveException.hpp"
class MonitorList {
ObjectMonitor* volatile _head;
volatile size_t _count;
volatile size_t _max;
public:
void add(ObjectMonitor* monitor);
size_t unlink_deflated(Thread* self, LogStream* ls, elapsedTimer* timer_p,
GrowableArray<ObjectMonitor*>* unlinked_list);
size_t count() const;
size_t max() const;
class Iterator;
Iterator iterator() const;
};
class MonitorList::Iterator {
ObjectMonitor* _current;
public:
Iterator(ObjectMonitor* head) : _current(head) {}
bool has_next() const { return _current != NULL; }
ObjectMonitor* next();
};
void MonitorList::add(ObjectMonitor* m) {
ObjectMonitor* head;
do {
@ -240,7 +215,7 @@ void ObjectSynchronizer::initialize() {
set_in_use_list_ceiling(AvgMonitorsPerThreadEstimate);
}
static MonitorList _in_use_list;
MonitorList ObjectSynchronizer::_in_use_list;
// monitors_used_above_threshold() policy is as follows:
//
// The ratio of the current _in_use_list count to the ceiling is used

@ -35,6 +35,34 @@ class LogStream;
class ObjectMonitor;
class ThreadsList;
class MonitorList {
friend class VMStructs;
private:
ObjectMonitor* volatile _head;
volatile size_t _count;
volatile size_t _max;
public:
void add(ObjectMonitor* monitor);
size_t unlink_deflated(Thread* self, LogStream* ls, elapsedTimer* timer_p,
GrowableArray<ObjectMonitor*>* unlinked_list);
size_t count() const;
size_t max() const;
class Iterator;
Iterator iterator() const;
};
class MonitorList::Iterator {
ObjectMonitor* _current;
public:
Iterator(ObjectMonitor* head) : _current(head) {}
bool has_next() const { return _current != NULL; }
ObjectMonitor* next();
};
class ObjectSynchronizer : AllStatic {
friend class VMStructs;
@ -144,6 +172,7 @@ class ObjectSynchronizer : AllStatic {
private:
friend class SynchronizerTest;
static MonitorList _in_use_list;
static volatile bool _is_async_deflation_requested;
static volatile bool _is_final_audit;
static jlong _last_async_deflation_time_ns;

@ -890,6 +890,8 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
volatile_nonstatic_field(ObjectMonitor, _recursions, intx) \
nonstatic_field(BasicObjectLock, _lock, BasicLock) \
nonstatic_field(BasicObjectLock, _obj, oop) \
static_field(ObjectSynchronizer, _in_use_list, MonitorList) \
volatile_nonstatic_field(MonitorList, _head, ObjectMonitor*) \
\
/*********************/ \
/* Matcher (C2 only) */ \
@ -1468,6 +1470,7 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
/************/ \
\
declare_toplevel_type(ObjectMonitor) \
declare_toplevel_type(MonitorList) \
declare_toplevel_type(ObjectSynchronizer) \
declare_toplevel_type(BasicLock) \
declare_toplevel_type(BasicObjectLock) \
@ -2420,12 +2423,6 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
declare_constant(Deoptimization::Action_make_not_compilable) \
declare_constant(Deoptimization::Action_LIMIT) \
\
/***************************************************/ \
/* DEFAULT_CACHE_LINE_SIZE (globalDefinitions.hpp) */ \
/***************************************************/ \
\
declare_preprocessor_constant("DEFAULT_CACHE_LINE_SIZE", DEFAULT_CACHE_LINE_SIZE) \
\
declare_constant(Deoptimization::Unpack_deopt) \
declare_constant(Deoptimization::Unpack_exception) \
declare_constant(Deoptimization::Unpack_uncommon_trap) \

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2021, 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
@ -43,22 +43,8 @@ public class ObjectSynchronizer {
}
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
Type type;
try {
type = db.lookupType("ObjectSynchronizer");
gBlockList = type.getAddressField("g_block_list").getValue();
blockSize = db.lookupIntConstant("ObjectSynchronizer::_BLOCKSIZE").intValue();
defaultCacheLineSize = db.lookupIntConstant("DEFAULT_CACHE_LINE_SIZE").intValue();
} catch (RuntimeException e) { }
type = db.lookupType("ObjectMonitor");
objectMonitorTypeSize = type.getSize();
if ((objectMonitorTypeSize % defaultCacheLineSize) != 0) {
// sizeof(ObjectMonitor) is not already a multiple of a cache line.
// The ObjectMonitor allocation code in ObjectSynchronizer pads each
// ObjectMonitor in a block to the next cache line boundary.
int needLines = ((int)objectMonitorTypeSize / defaultCacheLineSize) + 1;
objectMonitorTypeSize = needLines * defaultCacheLineSize;
}
Type type = db.lookupType("ObjectSynchronizer");
inUseList = type.getAddressField("_in_use_list").getValue();
}
public long identityHashValueFor(Oop obj) {
@ -84,7 +70,7 @@ public class ObjectSynchronizer {
}
public static Iterator objectMonitorIterator() {
if (gBlockList != null) {
if (inUseList != null) {
return new ObjectMonitorIterator();
} else {
return null;
@ -93,47 +79,34 @@ public class ObjectSynchronizer {
private static class ObjectMonitorIterator implements Iterator {
// JVMTI raw monitors are not pointed by gBlockList
// and are not included by this Iterator. May add them later.
// JVMTI raw monitors are not included in _in_use_list and
// are not returned by this Iterator.
ObjectMonitorIterator() {
blockAddr = gBlockList;
index = blockSize - 1;
block = new ObjectMonitor(blockAddr);
mon = new ObjectMonitor(inUseList);
}
public boolean hasNext() {
return (index > 0 || block.nextOM() != null);
return (mon.nextOM() != null);
}
public Object next() {
Address addr;
if (index == 0) {
// advance to next block
blockAddr = block.nextOM();
if (blockAddr == null) {
throw new NoSuchElementException();
}
block = new ObjectMonitor(blockAddr);
index = blockSize - 1;
// advance to next entry
Address monAddr = mon.nextOM();
if (monAddr == null) {
throw new NoSuchElementException();
}
addr = blockAddr.addOffsetTo(index*objectMonitorTypeSize);
index --;
return new ObjectMonitor(addr);
mon = new ObjectMonitor(monAddr);
return mon;
}
public void remove() {
throw new UnsupportedOperationException();
}
private ObjectMonitor block;
private int index;
private Address blockAddr;
private ObjectMonitor mon;
}
private static Address gBlockList;
private static int blockSize;
private static int defaultCacheLineSize;
private static long objectMonitorTypeSize;
private static Address inUseList;
}

@ -0,0 +1,100 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, NTT DATA.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import sun.jvm.hotspot.HotSpotAgent;
import sun.jvm.hotspot.oops.Oop;
import sun.jvm.hotspot.runtime.ObjectMonitor;
import sun.jvm.hotspot.runtime.ObjectSynchronizer;
import sun.jvm.hotspot.runtime.VM;
import jdk.test.lib.apps.LingeredApp;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.SA.SATestUtils;
/**
* @test
* @bug 8259008
* @library /test/lib
* @requires vm.hasSA
* @modules jdk.hotspot.agent/sun.jvm.hotspot
* jdk.hotspot.agent/sun.jvm.hotspot.oops
* jdk.hotspot.agent/sun.jvm.hotspot.runtime
* @run main TestObjectMonitorIterate
*/
public class TestObjectMonitorIterate {
private static void test(String pid) {
HotSpotAgent agent = new HotSpotAgent();
agent.attach(Integer.parseInt(pid));
try {
var heap = VM.getVM().getObjectHeap();
var itr = ObjectSynchronizer.objectMonitorIterator();
if (!itr.hasNext()) {
throw new RuntimeException("Monitor not found");
}
while (itr.hasNext()) {
ObjectMonitor mon = (ObjectMonitor)itr.next();
Oop oop = heap.newOop(mon.object());
System.out.println("Monitor found: " + oop.getKlass().getName().asString());
}
} finally {
agent.detach();
}
}
private static void createAnotherToAttach(long lingeredAppPid) throws Exception {
// Start a new process to attach to the lingered app
ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
"--add-modules=jdk.hotspot.agent",
"--add-exports=jdk.hotspot.agent/sun.jvm.hotspot=ALL-UNNAMED",
"--add-exports=jdk.hotspot.agent/sun.jvm.hotspot.oops=ALL-UNNAMED",
"--add-exports=jdk.hotspot.agent/sun.jvm.hotspot.runtime=ALL-UNNAMED",
"TestObjectMonitorIterate",
Long.toString(lingeredAppPid));
SATestUtils.addPrivilegesIfNeeded(processBuilder);
OutputAnalyzer SAOutput = ProcessTools.executeProcess(processBuilder);
SAOutput.shouldHaveExitValue(0);
System.out.println(SAOutput.getOutput());
}
public static void main (String... args) throws Exception {
SATestUtils.skipIfCannotAttach(); // throws SkippedException if attach not expected to work.
if (args == null || args.length == 0) {
LingeredApp app = new LingeredAppWithLock();
try {
LingeredApp.startApp(app, "-XX:+UsePerfData");
createAnotherToAttach(app.getPid());
} finally {
LingeredApp.stopApp(app);
}
} else {
test(args[0]);
}
}
}