Merge
This commit is contained in:
commit
d348978bc1
hotspot
make
src
cpu
os_cpu
aix_ppc/vm
bsd_x86/vm
bsd_zero/vm
linux_ppc/vm
linux_sparc/vm
linux_x86/vm
linux_zero/vm
solaris_sparc/vm
solaris_x86/vm
windows_x86/vm
share/vm
c1
ci
classfile
code
compiler
oops
opto
runtime
services
test/serviceability/dcmd
@ -95,6 +95,7 @@ MINIMAL1_VM_TARGETS=productminimal1 fastdebugminimal1 debugminimal1
|
||||
COMMON_VM_PRODUCT_TARGETS=product product1 docs export_product
|
||||
COMMON_VM_FASTDEBUG_TARGETS=fastdebug fastdebug1 docs export_fastdebug
|
||||
COMMON_VM_DEBUG_TARGETS=debug debug1 docs export_debug
|
||||
COMMON_VM_OPTIMIZED_TARGETS=optimized optimized1 docs export_optimized
|
||||
|
||||
# JDK directory list
|
||||
JDK_DIRS=bin include jre lib demo
|
||||
@ -111,20 +112,21 @@ ifdef BUILD_CLIENT_ONLY
|
||||
all_product: product1 docs export_product
|
||||
all_fastdebug: fastdebug1 docs export_fastdebug
|
||||
all_debug: debug1 docs export_debug
|
||||
all_optimized: optimized1 docs export_optimized
|
||||
else
|
||||
ifeq ($(MACOSX_UNIVERSAL),true)
|
||||
all_product: universal_product
|
||||
all_fastdebug: universal_fastdebug
|
||||
all_debug: universal_debug
|
||||
all_optimized: universal_optimized
|
||||
else
|
||||
all_product: $(COMMON_VM_PRODUCT_TARGETS)
|
||||
all_fastdebug: $(COMMON_VM_FASTDEBUG_TARGETS)
|
||||
all_debug: $(COMMON_VM_DEBUG_TARGETS)
|
||||
all_optimized: $(COMMON_VM_OPTIMIZED_TARGETS)
|
||||
endif
|
||||
endif
|
||||
|
||||
all_optimized: optimized optimized1 docs export_optimized
|
||||
|
||||
allzero: all_productzero all_fastdebugzero
|
||||
all_productzero: productzero docs export_product
|
||||
all_fastdebugzero: fastdebugzero docs export_fastdebug
|
||||
|
@ -25,6 +25,8 @@
|
||||
# macosx universal builds
|
||||
universal_product:
|
||||
$(MAKE) MACOSX_UNIVERSAL=true all_product_universal
|
||||
universal_optimized:
|
||||
$(MAKE) MACOSX_UNIVERSAL=true all_optimized_universal
|
||||
universal_fastdebug:
|
||||
$(MAKE) MACOSX_UNIVERSAL=true all_fastdebug_universal
|
||||
universal_debug:
|
||||
@ -36,6 +38,10 @@ all_product_universal:
|
||||
# $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=32 $(COMMON_VM_PRODUCT_TARGETS)
|
||||
$(QUIETLY) $(MAKE) ARCH_DATA_MODEL=64 $(COMMON_VM_PRODUCT_TARGETS)
|
||||
$(QUIETLY) $(MAKE) BUILD_FLAVOR=product EXPORT_SUBDIR= universalize
|
||||
all_optimized_universal:
|
||||
# $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=32 $(COMMON_VM_OPTIMIZED_TARGETS)
|
||||
$(QUIETLY) $(MAKE) ARCH_DATA_MODEL=64 $(COMMON_VM_OPTIMIZED_TARGETS)
|
||||
$(QUIETLY) $(MAKE) BUILD_FLAVOR=optimized EXPORT_SUBDIR=/optimized universalize
|
||||
all_fastdebug_universal:
|
||||
# $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=32 $(COMMON_VM_FASTDEBUG_TARGETS)
|
||||
$(QUIETLY) $(MAKE) ARCH_DATA_MODEL=64 $(COMMON_VM_FASTDEBUG_TARGETS)
|
||||
@ -98,13 +104,15 @@ copy_universal:
|
||||
export_product_jdk::
|
||||
$(MAKE) EXPORT_SUBDIR= export_universal
|
||||
export_optimized_jdk::
|
||||
$(MAKE) EXPORT_SUBDIR= export_universal
|
||||
$(MAKE) EXPORT_SUBDIR=/optimized export_universal
|
||||
export_fastdebug_jdk::
|
||||
$(MAKE) EXPORT_SUBDIR=/fastdebug export_universal
|
||||
export_debug_jdk::
|
||||
$(MAKE) EXPORT_SUBDIR=/debug export_universal
|
||||
copy_product_jdk::
|
||||
$(MAKE) COPY_SUBDIR= copy_universal
|
||||
copy_optimized_jdk::
|
||||
$(MAKE) COPY_SUBDIR=/optimized copy_universal
|
||||
copy_fastdebug_jdk::
|
||||
$(MAKE) COPY_SUBDIR=/fastdebug copy_universal
|
||||
copy_debug_jdk::
|
||||
@ -112,5 +120,6 @@ copy_debug_jdk::
|
||||
|
||||
.PHONY: universal_product universal_fastdebug universal_debug \
|
||||
all_product_universal all_fastdebug_universal all_debug_universal \
|
||||
universal_optimized all_optimized_universal \
|
||||
universalize export_universal copy_universal \
|
||||
$(UNIVERSAL_LIPO_LIST) $(UNIVERSAL_COPY_LIST)
|
||||
|
@ -143,7 +143,7 @@ else
|
||||
LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc -ldemangle
|
||||
endif # sparcWorks
|
||||
|
||||
LIBS += -lkstat
|
||||
LIBS += -lkstat -lpicl
|
||||
|
||||
# By default, link the *.o into the library, not the executable.
|
||||
LINK_INTO$(LINK_INTO) = LIBJVM
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
int VM_Version::_features = VM_Version::unknown_m;
|
||||
const char* VM_Version::_features_str = "";
|
||||
unsigned int VM_Version::_L2_cache_line_size = 0;
|
||||
|
||||
void VM_Version::initialize() {
|
||||
_features = determine_features();
|
||||
@ -192,7 +193,7 @@ void VM_Version::initialize() {
|
||||
}
|
||||
|
||||
assert(BlockZeroingLowLimit > 0, "invalid value");
|
||||
if (has_block_zeroing()) {
|
||||
if (has_block_zeroing() && cache_line_size > 0) {
|
||||
if (FLAG_IS_DEFAULT(UseBlockZeroing)) {
|
||||
FLAG_SET_DEFAULT(UseBlockZeroing, true);
|
||||
}
|
||||
@ -202,7 +203,7 @@ void VM_Version::initialize() {
|
||||
}
|
||||
|
||||
assert(BlockCopyLowLimit > 0, "invalid value");
|
||||
if (has_block_zeroing()) { // has_blk_init() && is_T4(): core's local L2 cache
|
||||
if (has_block_zeroing() && cache_line_size > 0) { // has_blk_init() && is_T4(): core's local L2 cache
|
||||
if (FLAG_IS_DEFAULT(UseBlockCopy)) {
|
||||
FLAG_SET_DEFAULT(UseBlockCopy, true);
|
||||
}
|
||||
@ -252,49 +253,6 @@ void VM_Version::initialize() {
|
||||
// buf is started with ", " or is empty
|
||||
_features_str = os::strdup(strlen(buf) > 2 ? buf + 2 : buf);
|
||||
|
||||
// There are three 64-bit SPARC families that do not overlap, e.g.,
|
||||
// both is_ultra3() and is_sparc64() cannot be true at the same time.
|
||||
// Within these families, there can be more than one chip, e.g.,
|
||||
// is_T4() and is_T7() machines are also is_niagara().
|
||||
if (is_ultra3()) {
|
||||
assert(_L1_data_cache_line_size == 0, "overlap with Ultra3 family");
|
||||
// Ref: UltraSPARC III Cu Processor
|
||||
_L1_data_cache_line_size = 64;
|
||||
}
|
||||
if (is_niagara()) {
|
||||
assert(_L1_data_cache_line_size == 0, "overlap with niagara family");
|
||||
// All Niagara's are sun4v's, but not all sun4v's are Niagaras, e.g.,
|
||||
// Fujitsu SPARC64 is sun4v, but we don't want it in this block.
|
||||
//
|
||||
// Ref: UltraSPARC T1 Supplement to the UltraSPARC Architecture 2005
|
||||
// Appendix F.1.3.1 Cacheable Accesses
|
||||
// -> 16-byte L1 cache line size
|
||||
//
|
||||
// Ref: UltraSPARC T2: A Highly-Threaded, Power-Efficient, SPARC SOC
|
||||
// Section III: SPARC Processor Core
|
||||
// -> 16-byte L1 cache line size
|
||||
//
|
||||
// Ref: Oracle's SPARC T4-1, SPARC T4-2, SPARC T4-4, and SPARC T4-1B Server Architecture
|
||||
// Section SPARC T4 Processor Cache Architecture
|
||||
// -> 32-byte L1 cache line size (no longer see that info on this ref)
|
||||
//
|
||||
// XXX - still need a T7 reference here
|
||||
//
|
||||
if (is_T7()) { // T7 or newer
|
||||
_L1_data_cache_line_size = 64;
|
||||
} else if (is_T4()) { // T4 or newer (until T7)
|
||||
_L1_data_cache_line_size = 32;
|
||||
} else { // T1 or newer (until T4)
|
||||
_L1_data_cache_line_size = 16;
|
||||
}
|
||||
}
|
||||
if (is_sparc64()) {
|
||||
guarantee(_L1_data_cache_line_size == 0, "overlap with SPARC64 family");
|
||||
// Ref: Fujitsu SPARC64 VII Processor
|
||||
// Section 4 Cache System
|
||||
_L1_data_cache_line_size = 64;
|
||||
}
|
||||
|
||||
// UseVIS is set to the smallest of what hardware supports and what
|
||||
// the command line requires. I.e., you cannot set UseVIS to 3 on
|
||||
// older UltraSparc which do not support it.
|
||||
@ -401,6 +359,7 @@ void VM_Version::initialize() {
|
||||
#ifndef PRODUCT
|
||||
if (PrintMiscellaneous && Verbose) {
|
||||
tty->print_cr("L1 data cache line size: %u", L1_data_cache_line_size());
|
||||
tty->print_cr("L2 cache line size: %u", L2_cache_line_size());
|
||||
tty->print("Allocation");
|
||||
if (AllocatePrefetchStyle <= 0) {
|
||||
tty->print_cr(": no prefetching");
|
||||
|
@ -96,6 +96,9 @@ protected:
|
||||
static int _features;
|
||||
static const char* _features_str;
|
||||
|
||||
static unsigned int _L2_cache_line_size;
|
||||
static unsigned int L2_cache_line_size() { return _L2_cache_line_size; }
|
||||
|
||||
static void print_features();
|
||||
static int determine_features();
|
||||
static int platform_features(int features);
|
||||
@ -167,9 +170,8 @@ public:
|
||||
|
||||
static const char* cpu_features() { return _features_str; }
|
||||
|
||||
static intx prefetch_data_size() {
|
||||
return is_T4() && !is_T7() ? 32 : 64; // default prefetch block size on sparc
|
||||
}
|
||||
// default prefetch block size on sparc
|
||||
static intx prefetch_data_size() { return L2_cache_line_size(); }
|
||||
|
||||
// Prefetch
|
||||
static intx prefetch_copy_interval_in_bytes() {
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define CPU_X86_VM_ASSEMBLER_X86_HPP
|
||||
|
||||
#include "asm/register.hpp"
|
||||
#include "vm_version_x86.hpp"
|
||||
|
||||
class BiasedLockingCounters;
|
||||
|
||||
@ -1292,14 +1293,34 @@ private:
|
||||
if (order_constraint & StoreLoad) {
|
||||
// All usable chips support "locked" instructions which suffice
|
||||
// as barriers, and are much faster than the alternative of
|
||||
// using cpuid instruction. We use here a locked add [esp],0.
|
||||
// using cpuid instruction. We use here a locked add [esp-C],0.
|
||||
// This is conveniently otherwise a no-op except for blowing
|
||||
// flags.
|
||||
// flags, and introducing a false dependency on target memory
|
||||
// location. We can't do anything with flags, but we can avoid
|
||||
// memory dependencies in the current method by locked-adding
|
||||
// somewhere else on the stack. Doing [esp+C] will collide with
|
||||
// something on stack in current method, hence we go for [esp-C].
|
||||
// It is convenient since it is almost always in data cache, for
|
||||
// any small C. We need to step back from SP to avoid data
|
||||
// dependencies with other things on below SP (callee-saves, for
|
||||
// example). Without a clear way to figure out the minimal safe
|
||||
// distance from SP, it makes sense to step back the complete
|
||||
// cache line, as this will also avoid possible second-order effects
|
||||
// with locked ops against the cache line. Our choice of offset
|
||||
// is bounded by x86 operand encoding, which should stay within
|
||||
// [-128; +127] to have the 8-byte displacement encoding.
|
||||
//
|
||||
// Any change to this code may need to revisit other places in
|
||||
// the code where this idiom is used, in particular the
|
||||
// orderAccess code.
|
||||
|
||||
int offset = -VM_Version::L1_line_size();
|
||||
if (offset < -128) {
|
||||
offset = -128;
|
||||
}
|
||||
|
||||
lock();
|
||||
addl(Address(rsp, 0), 0);// Assert the lock# signal here
|
||||
addl(Address(rsp, offset), 0);// Assert the lock# signal here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -563,3 +563,8 @@ void os::verify_stack_alignment() {
|
||||
assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment");
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// PPC does not require the additional stack bang.
|
||||
return 0;
|
||||
}
|
||||
|
@ -1030,3 +1030,8 @@ void os::setup_fpu() {
|
||||
void os::verify_stack_alignment() {
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// JDK-8050147 requires the full cache line bang for x86.
|
||||
return VM_Version::L1_line_size();
|
||||
}
|
||||
|
@ -465,3 +465,8 @@ extern "C" {
|
||||
void os::verify_stack_alignment() {
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// Zero does not require an additional stack bang.
|
||||
return 0;
|
||||
}
|
||||
|
@ -612,3 +612,8 @@ void os::verify_stack_alignment() {
|
||||
assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment");
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// PPC does not require the additional stack bang.
|
||||
return 0;
|
||||
}
|
||||
|
@ -752,3 +752,8 @@ size_t os::Linux::default_guard_size(os::ThreadType thr_type) {
|
||||
void os::verify_stack_alignment() {
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// SPARC does not require the additional stack bang.
|
||||
return 0;
|
||||
}
|
||||
|
@ -930,3 +930,8 @@ void os::workaround_expand_exec_shield_cs_limit() {
|
||||
// keep the page mapped so CS limit isn't reduced.
|
||||
#endif
|
||||
}
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// JDK-8050147 requires the full cache line bang for x86.
|
||||
return VM_Version::L1_line_size();
|
||||
}
|
||||
|
@ -495,3 +495,8 @@ extern "C" {
|
||||
void os::verify_stack_alignment() {
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// Zero does not require an additional stack banging.
|
||||
return 0;
|
||||
}
|
||||
|
@ -774,3 +774,8 @@ add_func_t* os::atomic_add_func = os::atomic_add_bootstrap;
|
||||
void os::verify_stack_alignment() {
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// SPARC does not require an additional stack bang.
|
||||
return 0;
|
||||
}
|
||||
|
@ -28,10 +28,140 @@
|
||||
#include "runtime/os.hpp"
|
||||
#include "vm_version_sparc.hpp"
|
||||
|
||||
# include <sys/auxv.h>
|
||||
# include <sys/auxv_SPARC.h>
|
||||
# include <sys/systeminfo.h>
|
||||
# include <kstat.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/auxv_SPARC.h>
|
||||
#include <sys/systeminfo.h>
|
||||
#include <kstat.h>
|
||||
#include <picl.h>
|
||||
|
||||
extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result);
|
||||
extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result);
|
||||
|
||||
class PICL {
|
||||
// Get a value of the integer property. The value in the tree can be either 32 or 64 bit
|
||||
// depending on the platform. The result is converted to int.
|
||||
static int get_int_property(picl_nodehdl_t nodeh, const char* name, int* result) {
|
||||
picl_propinfo_t pinfo;
|
||||
picl_prophdl_t proph;
|
||||
if (picl_get_prop_by_name(nodeh, name, &proph) != PICL_SUCCESS ||
|
||||
picl_get_propinfo(proph, &pinfo) != PICL_SUCCESS) {
|
||||
return PICL_FAILURE;
|
||||
}
|
||||
|
||||
if (pinfo.type != PICL_PTYPE_INT && pinfo.type != PICL_PTYPE_UNSIGNED_INT) {
|
||||
assert(false, "Invalid property type");
|
||||
return PICL_FAILURE;
|
||||
}
|
||||
if (pinfo.size == sizeof(int64_t)) {
|
||||
int64_t val;
|
||||
if (picl_get_propval(proph, &val, sizeof(int64_t)) != PICL_SUCCESS) {
|
||||
return PICL_FAILURE;
|
||||
}
|
||||
*result = static_cast<int>(val);
|
||||
} else if (pinfo.size == sizeof(int32_t)) {
|
||||
int32_t val;
|
||||
if (picl_get_propval(proph, &val, sizeof(int32_t)) != PICL_SUCCESS) {
|
||||
return PICL_FAILURE;
|
||||
}
|
||||
*result = static_cast<int>(val);
|
||||
} else {
|
||||
assert(false, "Unexpected integer property size");
|
||||
return PICL_FAILURE;
|
||||
}
|
||||
return PICL_SUCCESS;
|
||||
}
|
||||
|
||||
// Visitor and a state machine that visits integer properties and verifies that the
|
||||
// values are the same. Stores the unique value observed.
|
||||
class UniqueValueVisitor {
|
||||
enum {
|
||||
INITIAL, // Start state, no assignments happened
|
||||
ASSIGNED, // Assigned a value
|
||||
INCONSISTENT // Inconsistent value seen
|
||||
} _state;
|
||||
int _value;
|
||||
public:
|
||||
UniqueValueVisitor() : _state(INITIAL) { }
|
||||
int value() {
|
||||
assert(_state == ASSIGNED, "Precondition");
|
||||
return _value;
|
||||
}
|
||||
void set_value(int value) {
|
||||
assert(_state == INITIAL, "Precondition");
|
||||
_value = value;
|
||||
_state = ASSIGNED;
|
||||
}
|
||||
bool is_initial() { return _state == INITIAL; }
|
||||
bool is_assigned() { return _state == ASSIGNED; }
|
||||
bool is_inconsistent() { return _state == INCONSISTENT; }
|
||||
void set_inconsistent() { _state = INCONSISTENT; }
|
||||
|
||||
static int visit(picl_nodehdl_t nodeh, const char* name, void *arg) {
|
||||
UniqueValueVisitor *state = static_cast<UniqueValueVisitor*>(arg);
|
||||
assert(!state->is_inconsistent(), "Precondition");
|
||||
int curr;
|
||||
if (PICL::get_int_property(nodeh, name, &curr) == PICL_SUCCESS) {
|
||||
if (!state->is_assigned()) { // first iteration
|
||||
state->set_value(curr);
|
||||
} else if (curr != state->value()) { // following iterations
|
||||
state->set_inconsistent();
|
||||
}
|
||||
}
|
||||
if (state->is_inconsistent()) {
|
||||
return PICL_WALK_TERMINATE;
|
||||
}
|
||||
return PICL_WALK_CONTINUE;
|
||||
}
|
||||
};
|
||||
|
||||
int _L1_data_cache_line_size;
|
||||
int _L2_cache_line_size;
|
||||
public:
|
||||
static int get_l1_data_cache_line_size(picl_nodehdl_t nodeh, void *state) {
|
||||
return UniqueValueVisitor::visit(nodeh, "l1-dcache-line-size", state);
|
||||
}
|
||||
static int get_l2_cache_line_size(picl_nodehdl_t nodeh, void *state) {
|
||||
return UniqueValueVisitor::visit(nodeh, "l2-cache-line-size", state);
|
||||
}
|
||||
|
||||
PICL() : _L1_data_cache_line_size(0), _L2_cache_line_size(0) {
|
||||
if (picl_initialize() == PICL_SUCCESS) {
|
||||
picl_nodehdl_t rooth;
|
||||
if (picl_get_root(&rooth) == PICL_SUCCESS) {
|
||||
UniqueValueVisitor L1_state;
|
||||
// Visit all "cpu" class instances
|
||||
picl_walk_tree_by_class(rooth, "cpu", &L1_state, PICL_get_l1_data_cache_line_size_helper);
|
||||
if (L1_state.is_initial()) { // Still initial, iteration found no values
|
||||
// Try walk all "core" class instances, it might be a Fujitsu machine
|
||||
picl_walk_tree_by_class(rooth, "core", &L1_state, PICL_get_l1_data_cache_line_size_helper);
|
||||
}
|
||||
if (L1_state.is_assigned()) { // Is there a value?
|
||||
_L1_data_cache_line_size = L1_state.value();
|
||||
}
|
||||
|
||||
UniqueValueVisitor L2_state;
|
||||
picl_walk_tree_by_class(rooth, "cpu", &L2_state, PICL_get_l2_cache_line_size_helper);
|
||||
if (L2_state.is_initial()) {
|
||||
picl_walk_tree_by_class(rooth, "core", &L2_state, PICL_get_l2_cache_line_size_helper);
|
||||
}
|
||||
if (L2_state.is_assigned()) {
|
||||
_L2_cache_line_size = L2_state.value();
|
||||
}
|
||||
}
|
||||
picl_shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; }
|
||||
unsigned int L2_cache_line_size() const { return _L2_cache_line_size; }
|
||||
};
|
||||
|
||||
extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) {
|
||||
return PICL::get_l1_data_cache_line_size(nodeh, result);
|
||||
}
|
||||
extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) {
|
||||
return PICL::get_l2_cache_line_size(nodeh, result);
|
||||
}
|
||||
|
||||
// We need to keep these here as long as we have to build on Solaris
|
||||
// versions before 10.
|
||||
@ -211,5 +341,10 @@ int VM_Version::platform_features(int features) {
|
||||
kstat_close(kc);
|
||||
}
|
||||
|
||||
// Figure out cache line sizes using PICL
|
||||
PICL picl;
|
||||
_L1_data_cache_line_size = picl.L1_data_cache_line_size();
|
||||
_L2_cache_line_size = picl.L2_cache_line_size();
|
||||
|
||||
return features;
|
||||
}
|
||||
|
@ -918,3 +918,8 @@ void os::verify_stack_alignment() {
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// JDK-8050147 requires the full cache line bang for x86.
|
||||
return VM_Version::L1_line_size();
|
||||
}
|
||||
|
@ -639,3 +639,8 @@ void os::verify_stack_alignment() {
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// JDK-8050147 requires the full cache line bang for x86.
|
||||
return VM_Version::L1_line_size();
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ address LIR_Assembler::pc() const {
|
||||
// removes the need to bang the stack in the deoptimization blob which
|
||||
// in turn simplifies stack overflow handling.
|
||||
int LIR_Assembler::bang_size_in_bytes() const {
|
||||
return MAX2(initial_frame_size_in_bytes(), _compilation->interpreter_frame_size());
|
||||
return MAX2(initial_frame_size_in_bytes() + os::extra_bang_size_in_bytes(), _compilation->interpreter_frame_size());
|
||||
}
|
||||
|
||||
void LIR_Assembler::emit_exception_entries(ExceptionInfoList* info_list) {
|
||||
|
@ -926,7 +926,7 @@ void ciEnv::validate_compile_task_dependencies(ciMethod* target) {
|
||||
#ifdef ASSERT
|
||||
if (!counter_changed && !PrintCompilation) {
|
||||
// Print out the compile task that failed
|
||||
_task->print_line();
|
||||
_task->print_tty();
|
||||
}
|
||||
#endif
|
||||
assert(counter_changed, "failed dependencies, but counter didn't change");
|
||||
|
@ -1528,7 +1528,7 @@ void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) {
|
||||
if (TieredCompilation && TieredStopAtLevel >= CompLevel_full_optimization) {
|
||||
// Clobber the first compile and force second tier compilation
|
||||
nmethod* nm = m->code();
|
||||
if (nm != NULL) {
|
||||
if (nm != NULL && !m->is_method_handle_intrinsic()) {
|
||||
// Throw out the code so that the code cache doesn't fill up
|
||||
nm->make_not_entrant();
|
||||
m->clear_code();
|
||||
@ -1547,7 +1547,7 @@ void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) {
|
||||
}
|
||||
|
||||
nmethod* nm = m->code();
|
||||
if (nm != NULL) {
|
||||
if (nm != NULL && !m->is_method_handle_intrinsic()) {
|
||||
// Throw out the code so that the code cache doesn't fill up
|
||||
nm->make_not_entrant();
|
||||
m->clear_code();
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "oops/typeArrayKlass.hpp"
|
||||
#include "prims/jvmtiEnvBase.hpp"
|
||||
#include "prims/methodHandles.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/biasedLocking.hpp"
|
||||
#include "runtime/fieldType.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
@ -2274,7 +2275,11 @@ methodHandle SystemDictionary::find_method_handle_intrinsic(vmIntrinsics::ID iid
|
||||
m = Method::make_method_handle_intrinsic(iid, signature, CHECK_(empty));
|
||||
CompileBroker::compile_method(m, InvocationEntryBci, CompLevel_highest_tier,
|
||||
methodHandle(), CompileThreshold, "MH", CHECK_(empty));
|
||||
|
||||
// Check if we need to have compiled code but we don't.
|
||||
if (!Arguments::is_interpreter_only() && !m->has_compiled_code()) {
|
||||
THROW_MSG_(vmSymbols::java_lang_VirtualMachineError(),
|
||||
"out of space in CodeCache for method handle intrinsic", empty);
|
||||
}
|
||||
// Now grab the lock. We might have to throw away the new method,
|
||||
// if a racing thread has managed to install one at the same time.
|
||||
{
|
||||
@ -2288,6 +2293,9 @@ methodHandle SystemDictionary::find_method_handle_intrinsic(vmIntrinsics::ID iid
|
||||
}
|
||||
|
||||
assert(spe != NULL && spe->method() != NULL, "");
|
||||
assert(Arguments::is_interpreter_only() || (spe->method()->has_compiled_code() &&
|
||||
spe->method()->code()->entry_point() == spe->method()->from_compiled_entry()),
|
||||
"MH intrinsic invariant");
|
||||
return spe->method();
|
||||
}
|
||||
|
||||
|
@ -249,6 +249,7 @@ void CodeCache::commit(CodeBlob* cb) {
|
||||
#define FOR_ALL_BLOBS(var) for (CodeBlob *var = first() ; var != NULL; var = next(var) )
|
||||
#define FOR_ALL_ALIVE_BLOBS(var) for (CodeBlob *var = alive(first()); var != NULL; var = alive(next(var)))
|
||||
#define FOR_ALL_ALIVE_NMETHODS(var) for (nmethod *var = alive_nmethod(first()); var != NULL; var = alive_nmethod(next(var)))
|
||||
#define FOR_ALL_NMETHODS(var) for (nmethod *var = first_nmethod(); var != NULL; var = next_nmethod(var))
|
||||
|
||||
|
||||
bool CodeCache::contains(void *p) {
|
||||
@ -687,7 +688,9 @@ int CodeCache::mark_for_evol_deoptimization(instanceKlassHandle dependee) {
|
||||
void CodeCache::mark_all_nmethods_for_deoptimization() {
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
FOR_ALL_ALIVE_NMETHODS(nm) {
|
||||
nm->mark_for_deoptimization();
|
||||
if (!nm->method()->is_method_handle_intrinsic()) {
|
||||
nm->mark_for_deoptimization();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -967,6 +970,25 @@ void CodeCache::print_summary(outputStream* st, bool detailed) {
|
||||
}
|
||||
}
|
||||
|
||||
void CodeCache::print_codelist(outputStream* st) {
|
||||
assert_locked_or_safepoint(CodeCache_lock);
|
||||
|
||||
FOR_ALL_NMETHODS(p) {
|
||||
ResourceMark rm;
|
||||
char *method_name = p->method()->name_and_sig_as_C_string();
|
||||
st->print_cr("%d %d %s ["INTPTR_FORMAT", "INTPTR_FORMAT" - "INTPTR_FORMAT"]",
|
||||
p->compile_id(), p->comp_level(), method_name, (intptr_t)p->header_begin(),
|
||||
(intptr_t)p->code_begin(), (intptr_t)p->code_end());
|
||||
}
|
||||
}
|
||||
|
||||
void CodeCache::print_layout(outputStream* st) {
|
||||
assert_locked_or_safepoint(CodeCache_lock);
|
||||
ResourceMark rm;
|
||||
|
||||
print_summary(st, true);
|
||||
}
|
||||
|
||||
void CodeCache::log_state(outputStream* st) {
|
||||
st->print(" total_blobs='" UINT32_FORMAT "' nmethods='" UINT32_FORMAT "'"
|
||||
" adapters='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
|
||||
|
@ -152,6 +152,10 @@ class CodeCache : AllStatic {
|
||||
static void print_summary(outputStream* st, bool detailed = true); // Prints a summary of the code cache usage
|
||||
static void log_state(outputStream* st);
|
||||
|
||||
// Dcmd (Diagnostic commands)
|
||||
static void print_codelist(outputStream* st);
|
||||
static void print_layout(outputStream* st);
|
||||
|
||||
// The full limits of the codeCache
|
||||
static address low_bound() { return (address) _heap->low_boundary(); }
|
||||
static address high_bound() { return (address) _heap->high_boundary(); }
|
||||
|
@ -595,6 +595,7 @@ void CompiledStaticCall::compute_entry(methodHandle m, StaticCallInfo& info) {
|
||||
} else {
|
||||
// Callee is interpreted code. In any case entering the interpreter
|
||||
// puts a converter-frame on the stack to save arguments.
|
||||
assert(!m->is_method_handle_intrinsic(), "Compiled code should never call interpreter MH intrinsics");
|
||||
info._to_interpreter = true;
|
||||
info._entry = m()->get_c2i_entry();
|
||||
}
|
||||
|
@ -448,7 +448,10 @@ class nmethod : public CodeBlob {
|
||||
// alive. It is used when an uncommon trap happens. Returns true
|
||||
// if this thread changed the state of the nmethod or false if
|
||||
// another thread performed the transition.
|
||||
bool make_not_entrant() { return make_not_entrant_or_zombie(not_entrant); }
|
||||
bool make_not_entrant() {
|
||||
assert(!method()->is_method_handle_intrinsic(), "Cannot make MH intrinsic not entrant");
|
||||
return make_not_entrant_or_zombie(not_entrant);
|
||||
}
|
||||
bool make_zombie() { return make_not_entrant_or_zombie(zombie); }
|
||||
|
||||
// used by jvmti to track if the unload event has been reported
|
||||
|
@ -166,7 +166,7 @@ class CompilationLog : public StringEventLog {
|
||||
StringLogMessage lm;
|
||||
stringStream sstr = lm.stream();
|
||||
// msg.time_stamp().update_to(tty->time_stamp().ticks());
|
||||
task->print_compilation(&sstr, NULL, true);
|
||||
task->print_compilation(&sstr, NULL, true, false);
|
||||
log(thread, "%s", (const char*)lm);
|
||||
}
|
||||
|
||||
@ -328,7 +328,6 @@ void CompileTask::set_code(nmethod* nm) {
|
||||
if (nm == NULL) _code_handle = NULL; // drop the handle also
|
||||
}
|
||||
|
||||
|
||||
void CompileTask::mark_on_stack() {
|
||||
// Mark these methods as something redefine classes cannot remove.
|
||||
_method->set_on_stack(true);
|
||||
@ -337,18 +336,6 @@ void CompileTask::mark_on_stack() {
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// CompileTask::print
|
||||
void CompileTask::print() {
|
||||
tty->print("<CompileTask compile_id=%d ", _compile_id);
|
||||
tty->print("method=");
|
||||
_method->print_name(tty);
|
||||
tty->print_cr(" osr_bci=%d is_blocking=%s is_complete=%s is_success=%s>",
|
||||
_osr_bci, bool_to_str(_is_blocking),
|
||||
bool_to_str(_is_complete), bool_to_str(_is_success));
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// CompileTask::print_line_on_error
|
||||
//
|
||||
@ -367,19 +354,18 @@ void CompileTask::print_line_on_error(outputStream* st, char* buf, int buflen) {
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// CompileTask::print_line
|
||||
void CompileTask::print_line() {
|
||||
void CompileTask::print_tty() {
|
||||
ttyLocker ttyl; // keep the following output all in one block
|
||||
// print compiler name if requested
|
||||
if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler_name(comp_level()));
|
||||
print_compilation();
|
||||
print_compilation(tty);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// CompileTask::print_compilation_impl
|
||||
void CompileTask::print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level,
|
||||
bool is_osr_method, int osr_bci, bool is_blocking,
|
||||
const char* msg, bool short_form) {
|
||||
const char* msg, bool short_form, bool cr) {
|
||||
if (!short_form) {
|
||||
st->print("%7d ", (int) st->time_stamp().milliseconds()); // print timestamp
|
||||
}
|
||||
@ -428,7 +414,7 @@ void CompileTask::print_compilation_impl(outputStream* st, Method* method, int c
|
||||
if (msg != NULL) {
|
||||
st->print(" %s", msg);
|
||||
}
|
||||
if (!short_form) {
|
||||
if (cr) {
|
||||
st->cr();
|
||||
}
|
||||
}
|
||||
@ -494,9 +480,9 @@ void CompileTask::print_inline_indent(int inline_level, outputStream* st) {
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// CompileTask::print_compilation
|
||||
void CompileTask::print_compilation(outputStream* st, const char* msg, bool short_form) {
|
||||
void CompileTask::print_compilation(outputStream* st, const char* msg, bool short_form, bool cr) {
|
||||
bool is_osr_method = osr_bci() != InvocationEntryBci;
|
||||
print_compilation_impl(st, method(), compile_id(), comp_level(), is_osr_method, osr_bci(), is_blocking(), msg, short_form);
|
||||
print_compilation_impl(st, method(), compile_id(), comp_level(), is_osr_method, osr_bci(), is_blocking(), msg, short_form, cr);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@ -621,7 +607,9 @@ void CompileQueue::add(CompileTask* task) {
|
||||
// Mark the method as being in the compile queue.
|
||||
task->method()->set_queued_for_compilation();
|
||||
|
||||
NOT_PRODUCT(print();)
|
||||
if (CIPrintCompileQueue) {
|
||||
print_tty();
|
||||
}
|
||||
|
||||
if (LogCompilation && xtty != NULL) {
|
||||
task->log_task_queued();
|
||||
@ -786,24 +774,40 @@ void CompileQueue::mark_on_stack() {
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
/**
|
||||
* Print entire compilation queue.
|
||||
*/
|
||||
void CompileQueue::print() {
|
||||
if (CIPrintCompileQueue) {
|
||||
ttyLocker ttyl;
|
||||
tty->print_cr("Contents of %s", name());
|
||||
tty->print_cr("----------------------");
|
||||
CompileTask* task = _first;
|
||||
|
||||
CompileQueue* CompileBroker::compile_queue(int comp_level) {
|
||||
if (is_c2_compile(comp_level)) return _c2_compile_queue;
|
||||
if (is_c1_compile(comp_level)) return _c1_compile_queue;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void CompileBroker::print_compile_queues(outputStream* st) {
|
||||
_c1_compile_queue->print(st);
|
||||
_c2_compile_queue->print(st);
|
||||
}
|
||||
|
||||
|
||||
void CompileQueue::print(outputStream* st) {
|
||||
assert_locked_or_safepoint(lock());
|
||||
st->print_cr("Contents of %s", name());
|
||||
st->print_cr("----------------------------");
|
||||
CompileTask* task = _first;
|
||||
if (task == NULL) {
|
||||
st->print_cr("Empty");;
|
||||
} else {
|
||||
while (task != NULL) {
|
||||
task->print_line();
|
||||
task->print_compilation(st, NULL, true, true);
|
||||
task = task->next();
|
||||
}
|
||||
tty->print_cr("----------------------");
|
||||
}
|
||||
st->print_cr("----------------------------");
|
||||
}
|
||||
|
||||
void CompileQueue::print_tty() {
|
||||
ttyLocker ttyl;
|
||||
print(tty);
|
||||
}
|
||||
#endif // PRODUCT
|
||||
|
||||
CompilerCounters::CompilerCounters(const char* thread_name, int instance, TRAPS) {
|
||||
|
||||
@ -1068,11 +1072,11 @@ void CompileBroker::init_compiler_threads(int c1_compiler_count, int c2_compiler
|
||||
#endif // !ZERO && !SHARK
|
||||
// Initialize the compilation queue
|
||||
if (c2_compiler_count > 0) {
|
||||
_c2_compile_queue = new CompileQueue("C2 CompileQueue", MethodCompileQueue_lock);
|
||||
_c2_compile_queue = new CompileQueue("C2 compile queue", MethodCompileQueue_lock);
|
||||
_compilers[1]->set_num_compiler_threads(c2_compiler_count);
|
||||
}
|
||||
if (c1_compiler_count > 0) {
|
||||
_c1_compile_queue = new CompileQueue("C1 CompileQueue", MethodCompileQueue_lock);
|
||||
_c1_compile_queue = new CompileQueue("C1 compile queue", MethodCompileQueue_lock);
|
||||
_compilers[0]->set_num_compiler_threads(c1_compiler_count);
|
||||
}
|
||||
|
||||
@ -1892,7 +1896,7 @@ static void codecache_print(bool detailed)
|
||||
void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
|
||||
if (PrintCompilation) {
|
||||
ResourceMark rm;
|
||||
task->print_line();
|
||||
task->print_tty();
|
||||
}
|
||||
elapsedTimer time;
|
||||
|
||||
|
@ -111,14 +111,14 @@ class CompileTask : public CHeapObj<mtCompiler> {
|
||||
private:
|
||||
static void print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level,
|
||||
bool is_osr_method = false, int osr_bci = -1, bool is_blocking = false,
|
||||
const char* msg = NULL, bool short_form = false);
|
||||
const char* msg = NULL, bool short_form = false, bool cr = true);
|
||||
|
||||
public:
|
||||
void print_compilation(outputStream* st = tty, const char* msg = NULL, bool short_form = false);
|
||||
static void print_compilation(outputStream* st, const nmethod* nm, const char* msg = NULL, bool short_form = false) {
|
||||
void print_compilation(outputStream* st = tty, const char* msg = NULL, bool short_form = false, bool cr = true);
|
||||
static void print_compilation(outputStream* st, const nmethod* nm, const char* msg = NULL, bool short_form = false, bool cr = true) {
|
||||
print_compilation_impl(st, nm->method(), nm->compile_id(), nm->comp_level(),
|
||||
nm->is_osr_method(), nm->is_osr_method() ? nm->osr_entry_bci() : -1, /*is_blocking*/ false,
|
||||
msg, short_form);
|
||||
msg, short_form, cr);
|
||||
}
|
||||
|
||||
static void print_inlining(outputStream* st, ciMethod* method, int inline_level, int bci, const char* msg = NULL);
|
||||
@ -131,8 +131,7 @@ public:
|
||||
|
||||
static void print_inline_indent(int inline_level, outputStream* st = tty);
|
||||
|
||||
void print();
|
||||
void print_line();
|
||||
void print_tty();
|
||||
void print_line_on_error(outputStream* st, char* buf, int buflen);
|
||||
|
||||
void log_task(xmlStream* log);
|
||||
@ -234,7 +233,8 @@ class CompileQueue : public CHeapObj<mtCompiler> {
|
||||
// Redefine Classes support
|
||||
void mark_on_stack();
|
||||
void free_all();
|
||||
NOT_PRODUCT (void print();)
|
||||
void print_tty();
|
||||
void print(outputStream* st = tty);
|
||||
|
||||
~CompileQueue() {
|
||||
assert (is_empty(), " Compile Queue must be empty");
|
||||
@ -341,7 +341,7 @@ class CompileBroker: AllStatic {
|
||||
static void init_compiler_threads(int c1_compiler_count, int c2_compiler_count);
|
||||
static bool compilation_is_complete (methodHandle method, int osr_bci, int comp_level);
|
||||
static bool compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level);
|
||||
static bool is_compile_blocking ();
|
||||
static bool is_compile_blocking();
|
||||
static void preload_classes (methodHandle method, TRAPS);
|
||||
|
||||
static CompileTask* create_compile_task(CompileQueue* queue,
|
||||
@ -369,11 +369,8 @@ class CompileBroker: AllStatic {
|
||||
int hot_count,
|
||||
const char* comment,
|
||||
Thread* thread);
|
||||
static CompileQueue* compile_queue(int comp_level) {
|
||||
if (is_c2_compile(comp_level)) return _c2_compile_queue;
|
||||
if (is_c1_compile(comp_level)) return _c1_compile_queue;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static CompileQueue* compile_queue(int comp_level);
|
||||
static bool init_compiler_runtime();
|
||||
static void shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread);
|
||||
|
||||
@ -390,6 +387,7 @@ class CompileBroker: AllStatic {
|
||||
}
|
||||
|
||||
static bool compilation_is_in_queue(methodHandle method);
|
||||
static void print_compile_queues(outputStream* st);
|
||||
static int queue_size(int comp_level) {
|
||||
CompileQueue *q = compile_queue(comp_level);
|
||||
return q != NULL ? q->size() : 0;
|
||||
|
@ -1635,34 +1635,34 @@ int Method::backedge_count() {
|
||||
}
|
||||
|
||||
int Method::highest_comp_level() const {
|
||||
const MethodData* mdo = method_data();
|
||||
if (mdo != NULL) {
|
||||
return mdo->highest_comp_level();
|
||||
const MethodCounters* mcs = method_counters();
|
||||
if (mcs != NULL) {
|
||||
return mcs->highest_comp_level();
|
||||
} else {
|
||||
return CompLevel_none;
|
||||
}
|
||||
}
|
||||
|
||||
int Method::highest_osr_comp_level() const {
|
||||
const MethodData* mdo = method_data();
|
||||
if (mdo != NULL) {
|
||||
return mdo->highest_osr_comp_level();
|
||||
const MethodCounters* mcs = method_counters();
|
||||
if (mcs != NULL) {
|
||||
return mcs->highest_osr_comp_level();
|
||||
} else {
|
||||
return CompLevel_none;
|
||||
}
|
||||
}
|
||||
|
||||
void Method::set_highest_comp_level(int level) {
|
||||
MethodData* mdo = method_data();
|
||||
if (mdo != NULL) {
|
||||
mdo->set_highest_comp_level(level);
|
||||
MethodCounters* mcs = method_counters();
|
||||
if (mcs != NULL) {
|
||||
mcs->set_highest_comp_level(level);
|
||||
}
|
||||
}
|
||||
|
||||
void Method::set_highest_osr_comp_level(int level) {
|
||||
MethodData* mdo = method_data();
|
||||
if (mdo != NULL) {
|
||||
mdo->set_highest_osr_comp_level(level);
|
||||
MethodCounters* mcs = method_counters();
|
||||
if (mcs != NULL) {
|
||||
mcs->set_highest_osr_comp_level(level);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,4 +35,40 @@ void MethodCounters::clear_counters() {
|
||||
set_interpreter_throwout_count(0);
|
||||
set_interpreter_invocation_count(0);
|
||||
set_nmethod_age(INT_MAX);
|
||||
#ifdef TIERED
|
||||
set_prev_time(0);
|
||||
set_rate(0);
|
||||
set_highest_comp_level(0);
|
||||
set_highest_osr_comp_level(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int MethodCounters::highest_comp_level() const {
|
||||
#ifdef TIERED
|
||||
return _highest_comp_level;
|
||||
#else
|
||||
return CompLevel_none;
|
||||
#endif
|
||||
}
|
||||
|
||||
void MethodCounters::set_highest_comp_level(int level) {
|
||||
#ifdef TIERED
|
||||
_highest_comp_level = level;
|
||||
#endif
|
||||
}
|
||||
|
||||
int MethodCounters::highest_osr_comp_level() const {
|
||||
#ifdef TIERED
|
||||
return _highest_osr_comp_level;
|
||||
#else
|
||||
return CompLevel_none;
|
||||
#endif
|
||||
}
|
||||
|
||||
void MethodCounters::set_highest_osr_comp_level(int level) {
|
||||
#ifdef TIERED
|
||||
_highest_osr_comp_level = level;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,8 @@ class MethodCounters: public MetaspaceObj {
|
||||
#ifdef TIERED
|
||||
float _rate; // Events (invocation and backedge counter increments) per millisecond
|
||||
jlong _prev_time; // Previous time the rate was acquired
|
||||
u1 _highest_comp_level; // Highest compile level this method has ever seen.
|
||||
u1 _highest_osr_comp_level; // Same for OSR level
|
||||
#endif
|
||||
|
||||
MethodCounters() : _interpreter_invocation_count(0),
|
||||
@ -57,7 +59,9 @@ class MethodCounters: public MetaspaceObj {
|
||||
_nmethod_age(INT_MAX)
|
||||
#ifdef TIERED
|
||||
, _rate(0),
|
||||
_prev_time(0)
|
||||
_prev_time(0),
|
||||
_highest_comp_level(0),
|
||||
_highest_osr_comp_level(0)
|
||||
#endif
|
||||
{
|
||||
invocation_counter()->init();
|
||||
@ -114,6 +118,11 @@ class MethodCounters: public MetaspaceObj {
|
||||
void set_rate(float rate) { _rate = rate; }
|
||||
#endif
|
||||
|
||||
int highest_comp_level() const;
|
||||
void set_highest_comp_level(int level);
|
||||
int highest_osr_comp_level() const;
|
||||
void set_highest_osr_comp_level(int level);
|
||||
|
||||
// invocation counter
|
||||
InvocationCounter* invocation_counter() { return &_invocation_counter; }
|
||||
InvocationCounter* backedge_counter() { return &_backedge_counter; }
|
||||
|
@ -1134,8 +1134,6 @@ void MethodData::init() {
|
||||
_tenure_traps = 0;
|
||||
_num_loops = 0;
|
||||
_num_blocks = 0;
|
||||
_highest_comp_level = 0;
|
||||
_highest_osr_comp_level = 0;
|
||||
_would_profile = true;
|
||||
|
||||
#if INCLUDE_RTM_OPT
|
||||
|
@ -2095,10 +2095,6 @@ private:
|
||||
// time with C1. It is used to determine if method is trivial.
|
||||
short _num_loops;
|
||||
short _num_blocks;
|
||||
// Highest compile level this method has ever seen.
|
||||
u1 _highest_comp_level;
|
||||
// Same for OSR level
|
||||
u1 _highest_osr_comp_level;
|
||||
// Does this method contain anything worth profiling?
|
||||
bool _would_profile;
|
||||
|
||||
@ -2277,11 +2273,6 @@ public:
|
||||
void set_would_profile(bool p) { _would_profile = p; }
|
||||
bool would_profile() const { return _would_profile; }
|
||||
|
||||
int highest_comp_level() const { return _highest_comp_level; }
|
||||
void set_highest_comp_level(int level) { _highest_comp_level = level; }
|
||||
int highest_osr_comp_level() const { return _highest_osr_comp_level; }
|
||||
void set_highest_osr_comp_level(int level) { _highest_osr_comp_level = level; }
|
||||
|
||||
int num_loops() const { return _num_loops; }
|
||||
void set_num_loops(int n) { _num_loops = n; }
|
||||
int num_blocks() const { return _num_blocks; }
|
||||
|
@ -430,7 +430,7 @@ int Compile::frame_size_in_words() const {
|
||||
// removes the need to bang the stack in the deoptimization blob which
|
||||
// in turn simplifies stack overflow handling.
|
||||
int Compile::bang_size_in_bytes() const {
|
||||
return MAX2(_interpreter_frame_size, frame_size_in_bytes());
|
||||
return MAX2(frame_size_in_bytes() + os::extra_bang_size_in_bytes(), _interpreter_frame_size);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
@ -4968,7 +4968,8 @@ bool LibraryCallKit::inline_multiplyToLen() {
|
||||
|
||||
// Allocate the result array
|
||||
Node* zlen = _gvn.transform(new AddINode(xlen, ylen));
|
||||
Node* klass_node = makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_INT)));
|
||||
ciKlass* klass = ciTypeArrayKlass::make(T_INT);
|
||||
Node* klass_node = makecon(TypeKlassPtr::make(klass));
|
||||
|
||||
IdealKit ideal(this);
|
||||
|
||||
@ -5002,7 +5003,8 @@ bool LibraryCallKit::inline_multiplyToLen() {
|
||||
|
||||
sync_kit(ideal);
|
||||
z = __ value(z_alloc);
|
||||
_gvn.set_type(z, TypeAryPtr::INTS);
|
||||
// Can't use TypeAryPtr::INTS which uses Bottom offset.
|
||||
_gvn.set_type(z, TypeOopPtr::make_from_klass(klass));
|
||||
// Final sync IdealKit and GraphKit.
|
||||
final_sync(ideal);
|
||||
#undef __
|
||||
|
@ -590,7 +590,9 @@ class Arguments : AllStatic {
|
||||
static void fix_appclasspath();
|
||||
|
||||
// Operation modi
|
||||
static Mode mode() { return _mode; }
|
||||
static Mode mode() { return _mode; }
|
||||
static bool is_interpreter_only() { return mode() == _int; }
|
||||
|
||||
|
||||
// Utility: copies src into buf, replacing "%%" with "%" and "%p" with pid.
|
||||
static bool copy_expand_pid(const char* src, size_t srclen, char* buf, size_t buflen);
|
||||
|
@ -2473,7 +2473,7 @@ class CommandLineFlags {
|
||||
develop(bool, CIPrintCompilerName, false, \
|
||||
"when CIPrint is active, print the name of the active compiler") \
|
||||
\
|
||||
develop(bool, CIPrintCompileQueue, false, \
|
||||
diagnostic(bool, CIPrintCompileQueue, false, \
|
||||
"display the contents of the compile queue whenever a " \
|
||||
"compilation is enqueued") \
|
||||
\
|
||||
|
@ -771,6 +771,9 @@ class os: AllStatic {
|
||||
// Hook for os specific jvm options that we don't want to abort on seeing
|
||||
static bool obsolete_option(const JavaVMOption *option);
|
||||
|
||||
// Amount beyond the callee frame size that we bang the stack.
|
||||
static int extra_bang_size_in_bytes();
|
||||
|
||||
// Extensions
|
||||
#include "runtime/os_ext.hpp"
|
||||
|
||||
|
@ -618,7 +618,7 @@ void NMethodSweeper::possibly_flush(nmethod* nm) {
|
||||
if (mc == NULL) {
|
||||
// Sometimes we can get here without MethodCounters. For example if we run with -Xcomp.
|
||||
// Try to allocate them.
|
||||
mc = Method::build_method_counters(nm->method(), Thread::current());
|
||||
mc = nm->method()->get_method_counters(Thread::current());
|
||||
}
|
||||
if (mc != NULL) {
|
||||
// Snapshot the value as it's changed concurrently
|
||||
|
@ -470,3 +470,15 @@ void VM_Exit::wait_if_vm_exited() {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
void VM_PrintCompileQueue::doit() {
|
||||
CompileBroker::print_compile_queues(_out);
|
||||
}
|
||||
|
||||
void VM_PrintCodeList::doit() {
|
||||
CodeCache::print_codelist(_out);
|
||||
}
|
||||
|
||||
void VM_PrintCodeCache::doit() {
|
||||
CodeCache::print_layout(_out);
|
||||
}
|
||||
|
@ -99,6 +99,9 @@
|
||||
template(RotateGCLog) \
|
||||
template(WhiteBoxOperation) \
|
||||
template(ClassLoaderStatsOperation) \
|
||||
template(PrintCompileQueue) \
|
||||
template(PrintCodeList) \
|
||||
template(PrintCodeCache) \
|
||||
|
||||
class VM_Operation: public CHeapObj<mtInternal> {
|
||||
public:
|
||||
@ -413,4 +416,35 @@ class VM_RotateGCLog: public VM_Operation {
|
||||
void doit() { gclog_or_tty->rotate_log(true, _out); }
|
||||
};
|
||||
|
||||
class VM_PrintCompileQueue: public VM_Operation {
|
||||
private:
|
||||
outputStream* _out;
|
||||
|
||||
public:
|
||||
VM_PrintCompileQueue(outputStream* st) : _out(st) {}
|
||||
VMOp_Type type() const { return VMOp_PrintCompileQueue; }
|
||||
void doit();
|
||||
};
|
||||
|
||||
class VM_PrintCodeList: public VM_Operation {
|
||||
private:
|
||||
outputStream* _out;
|
||||
|
||||
public:
|
||||
VM_PrintCodeList(outputStream* st) : _out(st) {}
|
||||
VMOp_Type type() const { return VMOp_PrintCodeList; }
|
||||
void doit();
|
||||
};
|
||||
|
||||
class VM_PrintCodeCache: public VM_Operation {
|
||||
private:
|
||||
outputStream* _out;
|
||||
|
||||
public:
|
||||
VM_PrintCodeCache(outputStream* st) : _out(st) {}
|
||||
VMOp_Type type() const { return VMOp_PrintCodeCache; }
|
||||
void doit();
|
||||
};
|
||||
|
||||
|
||||
#endif // SHARE_VM_RUNTIME_VM_OPERATIONS_HPP
|
||||
|
@ -60,6 +60,9 @@ void DCmdRegistrant::register_dcmds(){
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RotateGCLogDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderStatsDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompileQueueDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeListDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeCacheDCmd>(full_export, true, false));
|
||||
|
||||
// Enhanced JMX Agent Support
|
||||
// These commands won't be exported via the DiagnosticCommandMBean until an
|
||||
@ -674,3 +677,18 @@ void RotateGCLogDCmd::execute(DCmdSource source, TRAPS) {
|
||||
}
|
||||
}
|
||||
|
||||
void CompileQueueDCmd::execute(DCmdSource source, TRAPS) {
|
||||
VM_PrintCompileQueue printCompileQueueOp(output());
|
||||
VMThread::execute(&printCompileQueueOp);
|
||||
}
|
||||
|
||||
void CodeListDCmd::execute(DCmdSource source, TRAPS) {
|
||||
VM_PrintCodeList printCodeListOp(output());
|
||||
VMThread::execute(&printCodeListOp);
|
||||
}
|
||||
|
||||
void CodeCacheDCmd::execute(DCmdSource source, TRAPS) {
|
||||
VM_PrintCodeCache printCodeCacheOp(output());
|
||||
VMThread::execute(&printCodeCacheOp);
|
||||
}
|
||||
|
||||
|
@ -399,4 +399,68 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class CompileQueueDCmd : public DCmd {
|
||||
public:
|
||||
CompileQueueDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
|
||||
static const char* name() {
|
||||
return "Compiler.queue";
|
||||
}
|
||||
static const char* description() {
|
||||
return "Print methods queued for compilation.";
|
||||
}
|
||||
static const char* impact() {
|
||||
return "Low";
|
||||
}
|
||||
static const JavaPermission permission() {
|
||||
JavaPermission p = {"java.lang.management.ManagementPermission",
|
||||
"monitor", NULL};
|
||||
return p;
|
||||
}
|
||||
static int num_arguments() { return 0; }
|
||||
virtual void execute(DCmdSource source, TRAPS);
|
||||
};
|
||||
|
||||
class CodeListDCmd : public DCmd {
|
||||
public:
|
||||
CodeListDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
|
||||
static const char* name() {
|
||||
return "Compiler.codelist";
|
||||
}
|
||||
static const char* description() {
|
||||
return "Print all compiled methods in code cache.";
|
||||
}
|
||||
static const char* impact() {
|
||||
return "Medium";
|
||||
}
|
||||
static const JavaPermission permission() {
|
||||
JavaPermission p = {"java.lang.management.ManagementPermission",
|
||||
"monitor", NULL};
|
||||
return p;
|
||||
}
|
||||
static int num_arguments() { return 0; }
|
||||
virtual void execute(DCmdSource source, TRAPS);
|
||||
};
|
||||
|
||||
|
||||
class CodeCacheDCmd : public DCmd {
|
||||
public:
|
||||
CodeCacheDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
|
||||
static const char* name() {
|
||||
return "Compiler.codecache";
|
||||
}
|
||||
static const char* description() {
|
||||
return "Print code cache layout and bounds.";
|
||||
}
|
||||
static const char* impact() {
|
||||
return "Low";
|
||||
}
|
||||
static const JavaPermission permission() {
|
||||
JavaPermission p = {"java.lang.management.ManagementPermission",
|
||||
"monitor", NULL};
|
||||
return p;
|
||||
}
|
||||
static int num_arguments() { return 0; }
|
||||
virtual void execute(DCmdSource source, TRAPS);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
|
||||
|
139
hotspot/test/serviceability/dcmd/CodeCacheTest.java
Normal file
139
hotspot/test/serviceability/dcmd/CodeCacheTest.java
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test CodeCacheTest
|
||||
* @bug 8054889
|
||||
* @build DcmdUtil CodeCacheTest
|
||||
* @run main CodeCacheTest
|
||||
* @summary Test of diagnostic command Compiler.codecache
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class CodeCacheTest {
|
||||
|
||||
/**
|
||||
* This test calls Jcmd (diagnostic command tool) Compiler.codecache and then parses the output,
|
||||
* making sure that all number look ok
|
||||
*
|
||||
*
|
||||
* Expected output:
|
||||
*
|
||||
* CodeCache: size=245760Kb used=4680Kb max_used=4680Kb free=241079Kb
|
||||
* bounds [0x00007f5bd9000000, 0x00007f5bd94a0000, 0x00007f5be8000000]
|
||||
* total_blobs=575 nmethods=69 adapters=423
|
||||
* compilation: enabled
|
||||
*/
|
||||
|
||||
static Pattern line1 = Pattern.compile("CodeCache: size=(\\p{Digit}*)Kb used=(\\p{Digit}*)Kb max_used=(\\p{Digit}*)Kb free=(\\p{Digit}*)Kb");
|
||||
static Pattern line2 = Pattern.compile(" bounds \\[0x(\\p{XDigit}*), 0x(\\p{XDigit}*), 0x(\\p{XDigit}*)\\]");
|
||||
static Pattern line3 = Pattern.compile(" total_blobs=(\\p{Digit}*) nmethods=(\\p{Digit}*) adapters=(\\p{Digit}*)");
|
||||
static Pattern line4 = Pattern.compile(" compilation: (\\w*)");
|
||||
|
||||
public static void main(String arg[]) throws Exception {
|
||||
|
||||
// Get output from dcmd (diagnostic command)
|
||||
String result = DcmdUtil.executeDcmd("Compiler.codecache");
|
||||
BufferedReader r = new BufferedReader(new StringReader(result));
|
||||
|
||||
// Validate first line
|
||||
String line;
|
||||
line = r.readLine();
|
||||
Matcher m = line1.matcher(line);
|
||||
if (m.matches()) {
|
||||
for(int i = 1; i <= 4; i++) {
|
||||
int val = Integer.parseInt(m.group(i));
|
||||
if (val < 0) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Exception("Regexp 1 failed");
|
||||
}
|
||||
|
||||
// Validate second line
|
||||
line = r.readLine();
|
||||
m = line2.matcher(line);
|
||||
if (m.matches()) {
|
||||
long start = Long.parseLong(m.group(1), 16);
|
||||
if (start < 0) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
long mark = Long.parseLong(m.group(2), 16);
|
||||
if (mark < 0) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
long top = Long.parseLong(m.group(3), 16);
|
||||
if (top < 0) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
if (start > mark) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
if (mark > top) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
} else {
|
||||
throw new Exception("Regexp 2 failed line: " + line);
|
||||
}
|
||||
|
||||
// Validate third line
|
||||
line = r.readLine();
|
||||
m = line3.matcher(line);
|
||||
if (m.matches()) {
|
||||
int blobs = Integer.parseInt(m.group(1));
|
||||
if (blobs <= 0) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
int nmethods = Integer.parseInt(m.group(2));
|
||||
if (nmethods <= 0) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
int adapters = Integer.parseInt(m.group(3));
|
||||
if (adapters <= 0) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
if (blobs < (nmethods + adapters)) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
} else {
|
||||
throw new Exception("Regexp 3 failed");
|
||||
}
|
||||
|
||||
// Validate fourth line
|
||||
line = r.readLine();
|
||||
m = line4.matcher(line);
|
||||
if (m.matches()) {
|
||||
if (!m.group(1).equals("enabled")) {
|
||||
throw new Exception("Invalid message: '" + m.group(1) + "'");
|
||||
}
|
||||
} else {
|
||||
throw new Exception("Regexp 4 failed");
|
||||
}
|
||||
}
|
||||
}
|
97
hotspot/test/serviceability/dcmd/CodelistTest.java
Normal file
97
hotspot/test/serviceability/dcmd/CodelistTest.java
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test CodelistTest
|
||||
* @bug 8054889
|
||||
* @build DcmdUtil MethodIdentifierParser CodelistTest
|
||||
* @run main CodelistTest
|
||||
* @summary Test of diagnostic command Compiler.codelist
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class CodelistTest {
|
||||
|
||||
/**
|
||||
* This test calls Jcmd (diagnostic command tool) Compiler.codelist and then parses the output,
|
||||
* making sure that the first methods in the list is valid by reflection.
|
||||
*
|
||||
* Output example:
|
||||
*
|
||||
* 6 0 java.lang.System.arraycopy(Ljava/lang/Object;ILjava/lang/Object;II)V [0x00007f7b49200910, 0x00007f7b49200aa0 - 0x00007f7b49200d30]
|
||||
* 2 3 java.lang.String.indexOf(II)I [0x00007f7b49200d90, 0x00007f7b49200f60 - 0x00007f7b49201490]
|
||||
* 7 3 java.lang.Math.min(II)I [0x00007f7b4922f010, 0x00007f7b4922f180 - 0x00007f7b4922f338]
|
||||
* 8 3 java.lang.String.equals(Ljava/lang/Object;)Z [0x00007f7b4922fb10, 0x00007f7b4922fd40 - 0x00007f7b49230698]
|
||||
* 9 3 java.lang.AbstractStringBuilder.ensureCapacityInternal(I)V [0x00007f7b49232010, 0x00007f7b492321a0 - 0x00007f7b49232510]
|
||||
* 10 1 java.lang.Object.<init>()V [0x00007f7b49233e90, 0x00007f7b49233fe0 - 0x00007f7b49234118]
|
||||
*
|
||||
*/
|
||||
|
||||
public static void main(String arg[]) throws Exception {
|
||||
int ok = 0;
|
||||
int fail = 0;
|
||||
|
||||
// Get output from dcmd (diagnostic command)
|
||||
String result = DcmdUtil.executeDcmd("Compiler.codelist");
|
||||
BufferedReader r = new BufferedReader(new StringReader(result));
|
||||
|
||||
// Grab a method name from the output
|
||||
String line;
|
||||
int count = 0;
|
||||
|
||||
while((line = r.readLine()) != null) {
|
||||
count++;
|
||||
|
||||
String[] parts = line.split(" ");
|
||||
// int compileID = Integer.parseInt(parts[0]);
|
||||
// int compileLevel = Integer.parseInt(parts[1]);
|
||||
String methodPrintedInLogFormat = parts[2];
|
||||
|
||||
// skip inits and clinits - they can not be reflected
|
||||
if (methodPrintedInLogFormat.contains("<init>")) {
|
||||
continue;
|
||||
}
|
||||
if (methodPrintedInLogFormat.contains("<clinit>")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MethodIdentifierParser mf = new MethodIdentifierParser(methodPrintedInLogFormat);
|
||||
Method m;
|
||||
try {
|
||||
m = mf.getMethod();
|
||||
} catch (NoSuchMethodException e) {
|
||||
m = null;
|
||||
}
|
||||
if (m == null) {
|
||||
throw new Exception("Test failed");
|
||||
}
|
||||
if (count > 10) {
|
||||
// Testing 10 entries is enough. Lets not waste time.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
108
hotspot/test/serviceability/dcmd/CompilerQueueTest.java
Normal file
108
hotspot/test/serviceability/dcmd/CompilerQueueTest.java
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test CompilerQueueTest
|
||||
* @bug 8054889
|
||||
* @build DcmdUtil CompilerQueueTest
|
||||
* @run main CompilerQueueTest
|
||||
* @summary Test of diagnostic command Compiler.queue
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.StringReader;
|
||||
|
||||
public class CompilerQueueTest {
|
||||
|
||||
/**
|
||||
* This test calls Jcmd (diagnostic command tool) Compiler.queue and
|
||||
* then parses the output, making sure that the output look ok.
|
||||
*
|
||||
*
|
||||
* Output example:
|
||||
*
|
||||
* Contents of C1 compile queue
|
||||
* ----------------------------
|
||||
* 73 3 java.lang.AbstractStringBuilder::append (50 bytes)
|
||||
* 74 1 java.util.TreeMap::size (5 bytes)
|
||||
* 75 3 java.lang.StringBuilder::append (8 bytes)
|
||||
* 83 3 java.util.TreeMap$ValueIterator::next (8 bytes)
|
||||
* 84 1 javax.management.MBeanFeatureInfo::getName (5 bytes)
|
||||
* ----------------------------
|
||||
* Contents of C2 compile queue
|
||||
* ----------------------------
|
||||
* Empty
|
||||
* ----------------------------
|
||||
*
|
||||
**/
|
||||
|
||||
public static void main(String arg[]) throws Exception {
|
||||
|
||||
// Get output from dcmd (diagnostic command)
|
||||
String result = DcmdUtil.executeDcmd("Compiler.queue");
|
||||
BufferedReader r = new BufferedReader(new StringReader(result));
|
||||
|
||||
String line;
|
||||
match(r.readLine(), "Contents of C1 compile queue");
|
||||
match(r.readLine(), "----------------------------");
|
||||
String str = r.readLine();
|
||||
if (!str.equals("Empty")) {
|
||||
while (str.charAt(0) != '-') {
|
||||
validateMethodLine(str);
|
||||
str = r.readLine();
|
||||
}
|
||||
} else {
|
||||
str = r.readLine();
|
||||
}
|
||||
|
||||
match(str, "----------------------------");
|
||||
match(r.readLine(), "Contents of C2 compile queue");
|
||||
match(r.readLine(), "----------------------------");
|
||||
str = r.readLine();
|
||||
if (!str.equals("Empty")) {
|
||||
while (str.charAt(0) != '-') {
|
||||
validateMethodLine(str);
|
||||
str = r.readLine();
|
||||
}
|
||||
} else {
|
||||
str = r.readLine();
|
||||
}
|
||||
match(str, "----------------------------");
|
||||
}
|
||||
|
||||
private static void validateMethodLine(String str) throws Exception {
|
||||
String name = str.substring(19);
|
||||
int sep = name.indexOf("::");
|
||||
try {
|
||||
Class.forName(name.substring(0, sep));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new Exception("Failed parsing dcmd queue");
|
||||
}
|
||||
}
|
||||
|
||||
public static void match(String line, String str) throws Exception {
|
||||
if (!line.equals(str)) {
|
||||
throw new Exception("String equals: " + line + ", " + str);
|
||||
}
|
||||
}
|
||||
}
|
196
hotspot/test/serviceability/dcmd/MethodIdentifierParser.java
Normal file
196
hotspot/test/serviceability/dcmd/MethodIdentifierParser.java
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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
|
||||
* 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 java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MethodIdentifierParser {
|
||||
|
||||
private String logString;
|
||||
private String className;
|
||||
private String methodName;
|
||||
private String methodDescriptor;
|
||||
|
||||
/**
|
||||
* This is a utility class for parsing the log entries for a method. It supplies
|
||||
* a few select methods for reflecting the class and method from that information.
|
||||
*
|
||||
* Example log entries:
|
||||
* "java.util.TreeMap.successor(Ljava/util/TreeMap$Entry;)Ljava/util/TreeMap$Entry;"
|
||||
*/
|
||||
|
||||
public MethodIdentifierParser(String logString) {
|
||||
this.logString = logString;
|
||||
|
||||
int i = logString.lastIndexOf("."); // find start of method name
|
||||
className = logString.substring(0, i); // classname is everything before
|
||||
int i2 = logString.indexOf("("); // Signature starts with an '('
|
||||
methodName = logString.substring(i+1, i2);
|
||||
methodDescriptor = logString.substring(i2, logString.length());
|
||||
|
||||
// Add sanity check for extracted fields
|
||||
}
|
||||
|
||||
public Method getMethod() throws NoSuchMethodException, SecurityException, ClassNotFoundException, Exception {
|
||||
try {
|
||||
return Class.forName(className).getDeclaredMethod(methodName, getParamenterDescriptorArray());
|
||||
} catch (UnexpectedTokenException e) {
|
||||
throw new Exception("Parse failed");
|
||||
}
|
||||
}
|
||||
|
||||
public Class<?>[] getParamenterDescriptorArray() throws ClassNotFoundException, UnexpectedTokenException {
|
||||
ParameterDecriptorIterator s = new ParameterDecriptorIterator(methodDescriptor);
|
||||
Class<?> paramType;
|
||||
ArrayList<Class<?>> list = new ArrayList<Class<?>>();
|
||||
while ((paramType = s.nextParamType()) != null) {
|
||||
list.add(paramType);
|
||||
}
|
||||
if (list.size() > 0) {
|
||||
return list.toArray(new Class<?>[list.size()]);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class ParameterDecriptorIterator {
|
||||
|
||||
// This class uses charAt() indexing for startMark and i
|
||||
// That is when i points to the last char it can be retrieved with
|
||||
// charAt(i). Including the last char for a subString requires
|
||||
// substring(startMark, i+1);
|
||||
|
||||
private String methodDescriptor;
|
||||
private int startMark;
|
||||
|
||||
public ParameterDecriptorIterator(String signature) {
|
||||
this.methodDescriptor = signature;
|
||||
this.startMark = 0;
|
||||
if (signature.charAt(0) == '(') {
|
||||
this.startMark = 1;
|
||||
}
|
||||
}
|
||||
|
||||
public Class<?> nextParamType() throws UnexpectedTokenException {
|
||||
int i = startMark;
|
||||
while (methodDescriptor.length() > i) {
|
||||
switch (methodDescriptor.charAt(i)) {
|
||||
case 'C':
|
||||
case 'B':
|
||||
case 'I':
|
||||
case 'J':
|
||||
case 'Z':
|
||||
case 'F':
|
||||
case 'D':
|
||||
case 'S':
|
||||
// Primitive class case, but we may have gotten here with [ as first token
|
||||
break;
|
||||
case 'L':
|
||||
// Internal class name suffixed by ';'
|
||||
while (methodDescriptor.charAt(i) != ';') {
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
case '[':
|
||||
i++; // arrays -> do another pass
|
||||
continue;
|
||||
case ')':
|
||||
return null; // end found
|
||||
case 'V':
|
||||
case ';':
|
||||
default:
|
||||
throw new UnexpectedTokenException(methodDescriptor, i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (i == startMark) {
|
||||
// Single char -> primitive class case
|
||||
startMark++; // Update for next iteration
|
||||
switch (methodDescriptor.charAt(i)) {
|
||||
case 'C':
|
||||
return char.class;
|
||||
case 'B':
|
||||
return byte.class;
|
||||
case 'I':
|
||||
return int.class;
|
||||
case 'J':
|
||||
return long.class;
|
||||
case 'F':
|
||||
return float.class;
|
||||
case 'D':
|
||||
return double.class;
|
||||
case 'S':
|
||||
return short.class;
|
||||
case 'Z':
|
||||
return boolean.class;
|
||||
default:
|
||||
throw new UnexpectedTokenException(methodDescriptor, i);
|
||||
}
|
||||
} else {
|
||||
// Multi char case
|
||||
String nextParam;
|
||||
if (methodDescriptor.charAt(startMark) == 'L') {
|
||||
// When reflecting a class the leading 'L' and trailing';' must be removed.
|
||||
// (When reflecting an array of classes, they must remain...)
|
||||
nextParam = methodDescriptor.substring(startMark+1, i);
|
||||
} else {
|
||||
// Any kind of array - simple case, use whole descriptor when reflecting.
|
||||
nextParam = methodDescriptor.substring(startMark, i+1);
|
||||
}
|
||||
startMark = ++i; // Update for next iteration
|
||||
try {
|
||||
// The parameter descriptor uses JVM internal class identifier with '/' as
|
||||
// package separator, but Class.forName expects '.'.
|
||||
nextParam = nextParam.replace('/', '.');
|
||||
return Class.forName(nextParam);
|
||||
} catch (ClassNotFoundException e) {
|
||||
System.out.println("Class not Found: " + nextParam);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UnexpectedTokenException extends Exception {
|
||||
String descriptor;
|
||||
int i;
|
||||
public UnexpectedTokenException(String descriptor, int i) {
|
||||
this.descriptor = descriptor;
|
||||
this.i = i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Unexpected token at: " + i + " in signature: " + descriptor;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
|
||||
public void debugPrint() {
|
||||
System.out.println("mlf in: " + logString);
|
||||
System.out.println("mlf class: " + className);
|
||||
System.out.println("mlf method: " + methodName);
|
||||
System.out.println("mlf methodDescriptor: " + methodDescriptor);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user