Merge
This commit is contained in:
commit
82157115c2
@ -176,6 +176,11 @@ endif
|
||||
|
||||
JVM_OPTIMIZATION ?= HIGHEST_JVM
|
||||
|
||||
# Need to set JVM_STRIPFLAGS to the default value from SPEC since the STRIPFLAGS
|
||||
# parameter to SetupNativeCompilation allows an empty value to override the
|
||||
# default.
|
||||
JVM_STRIPFLAGS ?= $(STRIPFLAGS)
|
||||
|
||||
################################################################################
|
||||
# Now set up the actual compilation of the main hotspot native library
|
||||
|
||||
@ -204,6 +209,7 @@ $(eval $(call SetupNativeCompilation, BUILD_LIBJVM, \
|
||||
OBJECT_DIR := $(JVM_OUTPUTDIR)/objs, \
|
||||
MAPFILE := $(JVM_MAPFILE), \
|
||||
USE_MAPFILE_FOR_SYMBOLS := true, \
|
||||
STRIPFLAGS := $(JVM_STRIPFLAGS), \
|
||||
EMBED_MANIFEST := true, \
|
||||
RC_FLAGS := $(JVM_RCFLAGS), \
|
||||
VERSIONINFO_RESOURCE := $(HOTSPOT_TOPDIR)/src/os/windows/vm/version.rc, \
|
||||
|
@ -59,6 +59,10 @@ endif
|
||||
|
||||
ifeq ($(call check-jvm-feature, minimal), true)
|
||||
JVM_CFLAGS_FEATURES += -DMINIMAL_JVM -DVMTYPE=\"Minimal\"
|
||||
ifeq ($(OPENJDK_TARGET_OS), linux)
|
||||
# Override the default -g with a more liberal strip policy for the minimal JVM
|
||||
JVM_STRIPFLAGS := --strip-unneeded
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(call check-jvm-feature, dtrace), true)
|
||||
|
@ -45,6 +45,7 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \
|
||||
$(HOTSPOT_TOPDIR)/test/runtime/jni/8025979 \
|
||||
$(HOTSPOT_TOPDIR)/test/runtime/jni/8033445 \
|
||||
$(HOTSPOT_TOPDIR)/test/runtime/jni/checked \
|
||||
$(HOTSPOT_TOPDIR)/test/runtime/jni/PrivateInterfaceMethods \
|
||||
$(HOTSPOT_TOPDIR)/test/runtime/jni/ToStringInInterfaceTest \
|
||||
$(HOTSPOT_TOPDIR)/test/runtime/modules/getModuleJNI \
|
||||
$(HOTSPOT_TOPDIR)/test/runtime/SameObject \
|
||||
|
@ -3496,6 +3496,16 @@ bool Matcher::narrow_klass_use_complex_address() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Matcher::const_oop_prefer_decode() {
|
||||
// Prefer ConN+DecodeN over ConP in simple compressed oops mode.
|
||||
return Universe::narrow_oop_base() == NULL;
|
||||
}
|
||||
|
||||
bool Matcher::const_klass_prefer_decode() {
|
||||
// Prefer ConNKlass+DecodeNKlass over ConP in simple compressed klass mode.
|
||||
return Universe::narrow_klass_base() == NULL;
|
||||
}
|
||||
|
||||
// Is it better to copy float constants, or load them directly from
|
||||
// memory? Intel can load a float constant from a direct address,
|
||||
// requiring no extra registers. Most RISCs will have to materialize
|
||||
@ -15502,6 +15512,24 @@ instruct string_indexof_conLU(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2,
|
||||
ins_pipe(pipe_class_memory);
|
||||
%}
|
||||
|
||||
instruct string_indexofU_char(iRegP_R1 str1, iRegI_R2 cnt1, iRegI_R3 ch,
|
||||
iRegI_R0 result, iRegI tmp1, iRegI tmp2,
|
||||
iRegI tmp3, rFlagsReg cr)
|
||||
%{
|
||||
match(Set result (StrIndexOfChar (Binary str1 cnt1) ch));
|
||||
effect(USE_KILL str1, USE_KILL cnt1, USE_KILL ch,
|
||||
TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
|
||||
|
||||
format %{ "String IndexOf char[] $str1,$cnt1,$ch -> $result" %}
|
||||
|
||||
ins_encode %{
|
||||
__ string_indexof_char($str1$$Register, $cnt1$$Register, $ch$$Register,
|
||||
$result$$Register, $tmp1$$Register, $tmp2$$Register,
|
||||
$tmp3$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_class_memory);
|
||||
%}
|
||||
|
||||
instruct string_equalsL(iRegP_R1 str1, iRegP_R3 str2, iRegI_R4 cnt,
|
||||
iRegI_R0 result, rFlagsReg cr)
|
||||
%{
|
||||
|
@ -4508,6 +4508,67 @@ void MacroAssembler::string_indexof(Register str2, Register str1,
|
||||
typedef void (MacroAssembler::* chr_insn)(Register Rt, const Address &adr);
|
||||
typedef void (MacroAssembler::* uxt_insn)(Register Rd, Register Rn);
|
||||
|
||||
void MacroAssembler::string_indexof_char(Register str1, Register cnt1,
|
||||
Register ch, Register result,
|
||||
Register tmp1, Register tmp2, Register tmp3)
|
||||
{
|
||||
Label CH1_LOOP, HAS_ZERO, DO1_SHORT, DO1_LOOP, MATCH, NOMATCH, DONE;
|
||||
Register cnt1_neg = cnt1;
|
||||
Register ch1 = rscratch1;
|
||||
Register result_tmp = rscratch2;
|
||||
|
||||
cmp(cnt1, 4);
|
||||
br(LT, DO1_SHORT);
|
||||
|
||||
orr(ch, ch, ch, LSL, 16);
|
||||
orr(ch, ch, ch, LSL, 32);
|
||||
|
||||
sub(cnt1, cnt1, 4);
|
||||
mov(result_tmp, cnt1);
|
||||
lea(str1, Address(str1, cnt1, Address::uxtw(1)));
|
||||
sub(cnt1_neg, zr, cnt1, LSL, 1);
|
||||
|
||||
mov(tmp3, 0x0001000100010001);
|
||||
|
||||
BIND(CH1_LOOP);
|
||||
ldr(ch1, Address(str1, cnt1_neg));
|
||||
eor(ch1, ch, ch1);
|
||||
sub(tmp1, ch1, tmp3);
|
||||
orr(tmp2, ch1, 0x7fff7fff7fff7fff);
|
||||
bics(tmp1, tmp1, tmp2);
|
||||
br(NE, HAS_ZERO);
|
||||
adds(cnt1_neg, cnt1_neg, 8);
|
||||
br(LT, CH1_LOOP);
|
||||
|
||||
cmp(cnt1_neg, 8);
|
||||
mov(cnt1_neg, 0);
|
||||
br(LT, CH1_LOOP);
|
||||
b(NOMATCH);
|
||||
|
||||
BIND(HAS_ZERO);
|
||||
rev(tmp1, tmp1);
|
||||
clz(tmp1, tmp1);
|
||||
add(cnt1_neg, cnt1_neg, tmp1, LSR, 3);
|
||||
b(MATCH);
|
||||
|
||||
BIND(DO1_SHORT);
|
||||
mov(result_tmp, cnt1);
|
||||
lea(str1, Address(str1, cnt1, Address::uxtw(1)));
|
||||
sub(cnt1_neg, zr, cnt1, LSL, 1);
|
||||
BIND(DO1_LOOP);
|
||||
ldrh(ch1, Address(str1, cnt1_neg));
|
||||
cmpw(ch, ch1);
|
||||
br(EQ, MATCH);
|
||||
adds(cnt1_neg, cnt1_neg, 2);
|
||||
br(LT, DO1_LOOP);
|
||||
BIND(NOMATCH);
|
||||
mov(result, -1);
|
||||
b(DONE);
|
||||
BIND(MATCH);
|
||||
add(result, result_tmp, cnt1_neg, ASR, 1);
|
||||
BIND(DONE);
|
||||
}
|
||||
|
||||
// Compare strings.
|
||||
void MacroAssembler::string_compare(Register str1, Register str2,
|
||||
Register cnt1, Register cnt2, Register result,
|
||||
|
@ -1229,6 +1229,9 @@ public:
|
||||
Register tmp1, Register tmp2,
|
||||
Register tmp3, Register tmp4,
|
||||
int int_cnt1, Register result, int ae);
|
||||
void string_indexof_char(Register str1, Register cnt1,
|
||||
Register ch, Register result,
|
||||
Register tmp1, Register tmp2, Register tmp3);
|
||||
private:
|
||||
void add2_with_carry(Register final_dest_hi, Register dest_hi, Register dest_lo,
|
||||
Register src1, Register src2);
|
||||
|
@ -3717,19 +3717,15 @@ void TemplateTable::monitorenter()
|
||||
|
||||
// allocate one if there's no free slot
|
||||
{
|
||||
Label entry, loop, no_adjust;
|
||||
Label entry, loop;
|
||||
// 1. compute new pointers // rsp: old expression stack top
|
||||
__ ldr(c_rarg1, monitor_block_bot); // c_rarg1: old expression stack bottom
|
||||
__ sub(esp, esp, entry_size); // move expression stack top
|
||||
__ sub(esp, esp, entry_size); // move expression stack top
|
||||
__ sub(c_rarg1, c_rarg1, entry_size); // move expression stack bottom
|
||||
__ mov(c_rarg3, esp); // set start value for copy loop
|
||||
__ str(c_rarg1, monitor_block_bot); // set new monitor block bottom
|
||||
|
||||
__ cmp(sp, c_rarg3); // Check if we need to move sp
|
||||
__ br(Assembler::LO, no_adjust); // to allow more stack space
|
||||
// for our new esp
|
||||
__ sub(sp, sp, 2 * wordSize);
|
||||
__ bind(no_adjust);
|
||||
__ sub(sp, sp, entry_size); // make room for the monitor
|
||||
|
||||
__ b(entry);
|
||||
// 2. move expression stack contents
|
||||
|
@ -1097,21 +1097,19 @@ EmitCallOffsets emit_call_with_trampoline_stub(MacroAssembler &_masm, address en
|
||||
// No entry point given, use the current pc.
|
||||
if (entry_point == NULL) entry_point = __ pc();
|
||||
|
||||
if (!Compile::current()->in_scratch_emit_size()) {
|
||||
// Put the entry point as a constant into the constant pool.
|
||||
const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none);
|
||||
if (entry_point_toc_addr == NULL) {
|
||||
ciEnv::current()->record_out_of_memory_failure();
|
||||
return offsets;
|
||||
}
|
||||
const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr);
|
||||
|
||||
// Emit the trampoline stub which will be related to the branch-and-link below.
|
||||
CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, offsets.insts_call_instruction_offset);
|
||||
if (ciEnv::current()->failing()) { return offsets; } // Code cache may be full.
|
||||
__ relocate(rtype);
|
||||
// Put the entry point as a constant into the constant pool.
|
||||
const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none);
|
||||
if (entry_point_toc_addr == NULL) {
|
||||
ciEnv::current()->record_out_of_memory_failure();
|
||||
return offsets;
|
||||
}
|
||||
|
||||
const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr);
|
||||
|
||||
// Emit the trampoline stub which will be related to the branch-and-link below.
|
||||
CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, offsets.insts_call_instruction_offset);
|
||||
if (ciEnv::current()->failing()) { return offsets; } // Code cache may be full.
|
||||
__ relocate(rtype);
|
||||
|
||||
// Note: At this point we do not have the address of the trampoline
|
||||
// stub, and the entry point might be too far away for bl, so __ pc()
|
||||
// serves as dummy and the bl will be patched later.
|
||||
@ -2166,6 +2164,16 @@ bool Matcher::narrow_klass_use_complex_address() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Matcher::const_oop_prefer_decode() {
|
||||
// Prefer ConN+DecodeN over ConP in simple compressed oops mode.
|
||||
return Universe::narrow_oop_base() == NULL;
|
||||
}
|
||||
|
||||
bool Matcher::const_klass_prefer_decode() {
|
||||
// Prefer ConNKlass+DecodeNKlass over ConP in simple compressed klass mode.
|
||||
return Universe::narrow_klass_base() == NULL;
|
||||
}
|
||||
|
||||
// Is it better to copy float constants, or load them directly from memory?
|
||||
// Intel can load a float constant from a direct address, requiring no
|
||||
// extra registers. Most RISCs will have to materialize an address into a
|
||||
@ -2424,23 +2432,21 @@ encode %{
|
||||
MacroAssembler _masm(&cbuf);
|
||||
int toc_offset = 0;
|
||||
|
||||
if (!ra_->C->in_scratch_emit_size()) {
|
||||
address const_toc_addr;
|
||||
// Create a non-oop constant, no relocation needed.
|
||||
// If it is an IC, it has a virtual_call_Relocation.
|
||||
const_toc_addr = __ long_constant((jlong)$src$$constant);
|
||||
if (const_toc_addr == NULL) {
|
||||
ciEnv::current()->record_out_of_memory_failure();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the constant's TOC offset.
|
||||
toc_offset = __ offset_to_method_toc(const_toc_addr);
|
||||
|
||||
// Keep the current instruction offset in mind.
|
||||
((loadConLNode*)this)->_cbuf_insts_offset = __ offset();
|
||||
address const_toc_addr;
|
||||
// Create a non-oop constant, no relocation needed.
|
||||
// If it is an IC, it has a virtual_call_Relocation.
|
||||
const_toc_addr = __ long_constant((jlong)$src$$constant);
|
||||
if (const_toc_addr == NULL) {
|
||||
ciEnv::current()->record_out_of_memory_failure();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Get the constant's TOC offset.
|
||||
toc_offset = __ offset_to_method_toc(const_toc_addr);
|
||||
|
||||
// Keep the current instruction offset in mind.
|
||||
((loadConLNode*)this)->_cbuf_insts_offset = __ offset();
|
||||
|
||||
__ ld($dst$$Register, toc_offset, $toc$$Register);
|
||||
%}
|
||||
|
||||
@ -2576,32 +2582,30 @@ encode %{
|
||||
MacroAssembler _masm(&cbuf);
|
||||
int toc_offset = 0;
|
||||
|
||||
if (!ra_->C->in_scratch_emit_size()) {
|
||||
intptr_t val = $src$$constant;
|
||||
relocInfo::relocType constant_reloc = $src->constant_reloc(); // src
|
||||
address const_toc_addr;
|
||||
if (constant_reloc == relocInfo::oop_type) {
|
||||
// Create an oop constant and a corresponding relocation.
|
||||
AddressLiteral a = __ allocate_oop_address((jobject)val);
|
||||
const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none);
|
||||
__ relocate(a.rspec());
|
||||
} else if (constant_reloc == relocInfo::metadata_type) {
|
||||
AddressLiteral a = __ constant_metadata_address((Metadata *)val);
|
||||
const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none);
|
||||
__ relocate(a.rspec());
|
||||
} else {
|
||||
// Create a non-oop constant, no relocation needed.
|
||||
const_toc_addr = __ long_constant((jlong)$src$$constant);
|
||||
}
|
||||
|
||||
if (const_toc_addr == NULL) {
|
||||
ciEnv::current()->record_out_of_memory_failure();
|
||||
return;
|
||||
}
|
||||
// Get the constant's TOC offset.
|
||||
toc_offset = __ offset_to_method_toc(const_toc_addr);
|
||||
intptr_t val = $src$$constant;
|
||||
relocInfo::relocType constant_reloc = $src->constant_reloc(); // src
|
||||
address const_toc_addr;
|
||||
if (constant_reloc == relocInfo::oop_type) {
|
||||
// Create an oop constant and a corresponding relocation.
|
||||
AddressLiteral a = __ allocate_oop_address((jobject)val);
|
||||
const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none);
|
||||
__ relocate(a.rspec());
|
||||
} else if (constant_reloc == relocInfo::metadata_type) {
|
||||
AddressLiteral a = __ constant_metadata_address((Metadata *)val);
|
||||
const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none);
|
||||
__ relocate(a.rspec());
|
||||
} else {
|
||||
// Create a non-oop constant, no relocation needed.
|
||||
const_toc_addr = __ long_constant((jlong)$src$$constant);
|
||||
}
|
||||
|
||||
if (const_toc_addr == NULL) {
|
||||
ciEnv::current()->record_out_of_memory_failure();
|
||||
return;
|
||||
}
|
||||
// Get the constant's TOC offset.
|
||||
toc_offset = __ offset_to_method_toc(const_toc_addr);
|
||||
|
||||
__ ld($dst$$Register, toc_offset, $toc$$Register);
|
||||
%}
|
||||
|
||||
@ -3272,28 +3276,26 @@ encode %{
|
||||
} else {
|
||||
// Remember the offset not the address.
|
||||
const int start_offset = __ offset();
|
||||
|
||||
// The trampoline stub.
|
||||
if (!Compile::current()->in_scratch_emit_size()) {
|
||||
// No entry point given, use the current pc.
|
||||
// Make sure branch fits into
|
||||
if (entry_point == 0) entry_point = __ pc();
|
||||
// No entry point given, use the current pc.
|
||||
// Make sure branch fits into
|
||||
if (entry_point == 0) entry_point = __ pc();
|
||||
|
||||
// Put the entry point as a constant into the constant pool.
|
||||
const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none);
|
||||
if (entry_point_toc_addr == NULL) {
|
||||
ciEnv::current()->record_out_of_memory_failure();
|
||||
return;
|
||||
}
|
||||
const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr);
|
||||
|
||||
|
||||
// Emit the trampoline stub which will be related to the branch-and-link below.
|
||||
CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset);
|
||||
if (ciEnv::current()->failing()) { return; } // Code cache may be full.
|
||||
int method_index = resolved_method_index(cbuf);
|
||||
__ relocate(_optimized_virtual ? opt_virtual_call_Relocation::spec(method_index)
|
||||
: static_call_Relocation::spec(method_index));
|
||||
// Put the entry point as a constant into the constant pool.
|
||||
const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none);
|
||||
if (entry_point_toc_addr == NULL) {
|
||||
ciEnv::current()->record_out_of_memory_failure();
|
||||
return;
|
||||
}
|
||||
const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr);
|
||||
|
||||
// Emit the trampoline stub which will be related to the branch-and-link below.
|
||||
CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset);
|
||||
if (ciEnv::current()->failing()) { return; } // Code cache may be full.
|
||||
int method_index = resolved_method_index(cbuf);
|
||||
__ relocate(_optimized_virtual ? opt_virtual_call_Relocation::spec(method_index)
|
||||
: static_call_Relocation::spec(method_index));
|
||||
|
||||
// The real call.
|
||||
// Note: At this point we do not have the address of the trampoline
|
||||
|
@ -2003,6 +2003,20 @@ bool Matcher::narrow_klass_use_complex_address() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Matcher::const_oop_prefer_decode() {
|
||||
// TODO: Check if loading ConP from TOC in heap-based mode is better:
|
||||
// Prefer ConN+DecodeN over ConP in simple compressed oops mode.
|
||||
// return Universe::narrow_oop_base() == NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Matcher::const_klass_prefer_decode() {
|
||||
// TODO: Check if loading ConP from TOC in heap-based mode is better:
|
||||
// Prefer ConNKlass+DecodeNKlass over ConP in simple compressed klass mode.
|
||||
// return Universe::narrow_klass_base() == NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Is it better to copy float constants, or load them directly from memory?
|
||||
// Intel can load a float constant from a direct address, requiring no
|
||||
// extra registers. Most RISCs will have to materialize an address into a
|
||||
|
@ -1452,6 +1452,15 @@ bool Matcher::narrow_klass_use_complex_address() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Matcher::const_oop_prefer_decode() {
|
||||
ShouldNotCallThis();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Matcher::const_klass_prefer_decode() {
|
||||
ShouldNotCallThis();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Is it better to copy float constants, or load them directly from memory?
|
||||
// Intel can load a float constant from a direct address, requiring no
|
||||
|
@ -1660,6 +1660,19 @@ bool Matcher::narrow_klass_use_complex_address() {
|
||||
return (LogKlassAlignmentInBytes <= 3);
|
||||
}
|
||||
|
||||
bool Matcher::const_oop_prefer_decode() {
|
||||
// Prefer ConN+DecodeN over ConP.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Matcher::const_klass_prefer_decode() {
|
||||
// TODO: Either support matching DecodeNKlass (heap-based) in operand
|
||||
// or condisider the following:
|
||||
// Prefer ConNKlass+DecodeNKlass over ConP in simple compressed klass mode.
|
||||
//return Universe::narrow_klass_base() == NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Is it better to copy float constants, or load them directly from
|
||||
// memory? Intel can load a float constant from a direct address,
|
||||
// requiring no extra registers. Most RISCs will have to materialize
|
||||
|
@ -90,14 +90,17 @@ public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider {
|
||||
* A list of all supported JVMCI options.
|
||||
*/
|
||||
public enum Option {
|
||||
// @formatter:off
|
||||
Compiler(String.class, null, "Selects the system compiler."),
|
||||
// Note: The following one is not used (see InitTimer.ENABLED). It is added here
|
||||
// so that -Djvmci.PrintFlags=true shows the option.
|
||||
InitTimer(boolean.class, false, "Specifies if initialization timing is enabled."),
|
||||
PrintConfig(boolean.class, false, "Prints VM configuration available via JVMCI and exits."),
|
||||
PrintFlags(boolean.class, false, "Prints all JVMCI flags and exits."),
|
||||
ShowFlags(boolean.class, false, "Prints all JVMCI flags and continues."),
|
||||
TraceMethodDataFilter(String.class, null, "");
|
||||
// so that -XX:+JVMCIPrintProperties shows the option.
|
||||
InitTimer(Boolean.class, false, "Specifies if initialization timing is enabled."),
|
||||
PrintConfig(Boolean.class, false, "Prints VM configuration available via JVMCI."),
|
||||
TraceMethodDataFilter(String.class, null,
|
||||
"Enables tracing of profiling info when read by JVMCI.",
|
||||
"Empty value: trace all methods",
|
||||
"Non-empty value: trace methods whose fully qualified name contains the value.");
|
||||
// @formatter:on
|
||||
|
||||
/**
|
||||
* The prefix for system properties that are JVMCI options.
|
||||
@ -113,25 +116,25 @@ public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider {
|
||||
private Object value;
|
||||
private final Object defaultValue;
|
||||
private boolean isDefault;
|
||||
private final String help;
|
||||
private final String[] helpLines;
|
||||
|
||||
Option(Class<?> type, Object defaultValue, String help) {
|
||||
Option(Class<?> type, Object defaultValue, String... helpLines) {
|
||||
assert Character.isUpperCase(name().charAt(0)) : "Option name must start with upper-case letter: " + name();
|
||||
this.type = type;
|
||||
this.value = UNINITIALIZED;
|
||||
this.defaultValue = defaultValue;
|
||||
this.help = help;
|
||||
this.helpLines = helpLines;
|
||||
}
|
||||
|
||||
@SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "sentinel must be String since it's a static final in an enum")
|
||||
private Object getValue() {
|
||||
if (value == UNINITIALIZED) {
|
||||
String propertyValue = VM.getSavedProperty(JVMCI_OPTION_PROPERTY_PREFIX + name());
|
||||
String propertyValue = VM.getSavedProperty(getPropertyName());
|
||||
if (propertyValue == null) {
|
||||
this.value = defaultValue;
|
||||
this.isDefault = true;
|
||||
} else {
|
||||
if (type == boolean.class) {
|
||||
if (type == Boolean.class) {
|
||||
this.value = Boolean.parseBoolean(propertyValue);
|
||||
} else if (type == String.class) {
|
||||
this.value = propertyValue;
|
||||
@ -146,6 +149,13 @@ public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of system property from which this option gets its value.
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return JVMCI_OPTION_PROPERTY_PREFIX + name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the option's value as boolean.
|
||||
*
|
||||
@ -165,16 +175,31 @@ public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints all option flags to {@code out}.
|
||||
* Prints a description of the properties used to configure shared JVMCI code.
|
||||
*
|
||||
* @param out stream to print to
|
||||
*/
|
||||
public static void printFlags(PrintStream out) {
|
||||
out.println("[List of JVMCI options]");
|
||||
for (Option option : values()) {
|
||||
public static void printProperties(PrintStream out) {
|
||||
out.println("[JVMCI properties]");
|
||||
int typeWidth = 0;
|
||||
int nameWidth = 0;
|
||||
Option[] values = values();
|
||||
for (Option option : values) {
|
||||
typeWidth = Math.max(typeWidth, option.type.getSimpleName().length());
|
||||
nameWidth = Math.max(nameWidth, option.getPropertyName().length());
|
||||
}
|
||||
for (Option option : values) {
|
||||
Object value = option.getValue();
|
||||
String assign = option.isDefault ? ":=" : " =";
|
||||
out.printf("%9s %-40s %s %-14s %s%n", option.type.getSimpleName(), option, assign, value, option.help);
|
||||
if (value instanceof String) {
|
||||
value = '"' + String.valueOf(value) + '"';
|
||||
}
|
||||
String assign = option.isDefault ? " =" : ":=";
|
||||
String format = "%" + (typeWidth + 1) + "s %-" + (nameWidth + 1) + "s %s %s%n";
|
||||
out.printf(format, option.type.getSimpleName(), option.getPropertyName(), assign, value);
|
||||
String helpFormat = "%" + (typeWidth + 1) + "s %s%n";
|
||||
for (String line : option.helpLines) {
|
||||
out.printf(helpFormat, "", line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -239,7 +264,6 @@ public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider {
|
||||
@SuppressWarnings("unused") private final String[] trivialPrefixes;
|
||||
|
||||
@SuppressWarnings("try")
|
||||
@SuppressFBWarnings(value = "DM_EXIT", justification = "PrintFlags is meant to exit the VM")
|
||||
private HotSpotJVMCIRuntime() {
|
||||
compilerToVm = new CompilerToVM();
|
||||
|
||||
@ -261,20 +285,6 @@ public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider {
|
||||
|
||||
metaAccessContext = new HotSpotJVMCIMetaAccessContext();
|
||||
|
||||
boolean printFlags = Option.PrintFlags.getBoolean();
|
||||
boolean showFlags = Option.ShowFlags.getBoolean();
|
||||
if (printFlags || showFlags) {
|
||||
Option.printFlags(System.out);
|
||||
if (printFlags) {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (Option.PrintConfig.getBoolean()) {
|
||||
printConfig(configStore, compilerToVm);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
compilerFactory = HotSpotJVMCICompilerConfig.getCompilerFactory();
|
||||
if (compilerFactory instanceof HotSpotJVMCICompilerFactory) {
|
||||
hsCompilerFactory = (HotSpotJVMCICompilerFactory) compilerFactory;
|
||||
@ -298,6 +308,16 @@ public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider {
|
||||
trivialPrefixes = null;
|
||||
compilationLevelAdjustment = config.compLevelAdjustmentNone;
|
||||
}
|
||||
|
||||
if (config.getFlag("JVMCIPrintProperties", Boolean.class)) {
|
||||
PrintStream out = new PrintStream(getLogStream());
|
||||
Option.printProperties(out);
|
||||
compilerFactory.printProperties(out);
|
||||
}
|
||||
|
||||
if (Option.PrintConfig.getBoolean()) {
|
||||
printConfig(configStore, compilerToVm);
|
||||
}
|
||||
}
|
||||
|
||||
private JVMCIBackend registerBackend(JVMCIBackend backend) {
|
||||
|
@ -53,9 +53,9 @@ final class HotSpotMethodData {
|
||||
* Reference to the C++ MethodData object.
|
||||
*/
|
||||
final long metaspaceMethodData;
|
||||
@SuppressWarnings("unused") private final HotSpotResolvedJavaMethodImpl method;
|
||||
private final HotSpotResolvedJavaMethodImpl method;
|
||||
|
||||
public HotSpotMethodData(long metaspaceMethodData, HotSpotResolvedJavaMethodImpl method) {
|
||||
HotSpotMethodData(long metaspaceMethodData, HotSpotResolvedJavaMethodImpl method) {
|
||||
this.metaspaceMethodData = metaspaceMethodData;
|
||||
this.method = method;
|
||||
}
|
||||
@ -107,6 +107,18 @@ final class HotSpotMethodData {
|
||||
return UNSAFE.getByte(metaspaceMethodData + config.methodDataOopTrapHistoryOffset + config.deoptReasonOSROffset + reasonIndex) & 0xFF;
|
||||
}
|
||||
|
||||
public int getDecompileCount() {
|
||||
return UNSAFE.getInt(metaspaceMethodData + config.methodDataDecompiles);
|
||||
}
|
||||
|
||||
public int getOverflowRecompileCount() {
|
||||
return UNSAFE.getInt(metaspaceMethodData + config.methodDataOverflowRecompiles);
|
||||
}
|
||||
|
||||
public int getOverflowTrapCount() {
|
||||
return UNSAFE.getInt(metaspaceMethodData + config.methodDataOverflowTraps);
|
||||
}
|
||||
|
||||
public HotSpotMethodDataAccessor getNormalData(int position) {
|
||||
if (position >= normalDataSize()) {
|
||||
return null;
|
||||
@ -214,6 +226,12 @@ final class HotSpotMethodData {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String nl = String.format("%n");
|
||||
String nlIndent = String.format("%n%38s", "");
|
||||
sb.append("Raw method data for ");
|
||||
sb.append(method.format("%H.%n(%p)"));
|
||||
sb.append(":");
|
||||
sb.append(nl);
|
||||
sb.append(String.format("nof_decompiles(%d) nof_overflow_recompiles(%d) nof_overflow_traps(%d)%n",
|
||||
getDecompileCount(), getOverflowRecompileCount(), getOverflowTrapCount()));
|
||||
if (hasNormalData()) {
|
||||
int pos = 0;
|
||||
HotSpotMethodDataAccessor data;
|
||||
@ -427,6 +445,10 @@ final class HotSpotMethodData {
|
||||
|
||||
protected abstract long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position);
|
||||
|
||||
public int getNonprofiledCount(HotSpotMethodData data, int position) {
|
||||
return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET);
|
||||
}
|
||||
|
||||
private JavaTypeProfile createTypeProfile(TriState nullSeen, RawItemProfile<ResolvedJavaType> profile) {
|
||||
if (profile.entries <= 0 || profile.totalCount <= 0) {
|
||||
return null;
|
||||
@ -462,7 +484,7 @@ final class HotSpotMethodData {
|
||||
TriState nullSeen = getNullSeen(data, pos);
|
||||
TriState exceptionSeen = getExceptionSeen(data, pos);
|
||||
sb.append(format("count(%d) null_seen(%s) exception_seen(%s) nonprofiled_count(%d) entries(%d)", getCounterValue(data, pos), nullSeen, exceptionSeen,
|
||||
getTypesNotRecordedExecutionCount(data, pos), profile.entries));
|
||||
getNonprofiledCount(data, pos), profile.entries));
|
||||
for (int i = 0; i < profile.entries; i++) {
|
||||
long count = profile.counts[i];
|
||||
sb.append(format("%n %s (%d, %4.2f)", profile.items[i].toJavaName(), count, (double) count / profile.totalCount));
|
||||
@ -490,7 +512,7 @@ final class HotSpotMethodData {
|
||||
|
||||
@Override
|
||||
protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) {
|
||||
return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET);
|
||||
return getNonprofiledCount(data, position);
|
||||
}
|
||||
}
|
||||
|
||||
@ -788,7 +810,8 @@ final class HotSpotMethodData {
|
||||
|
||||
@Override
|
||||
public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
|
||||
return null;
|
||||
sb.append("unknown profile data with tag: " + tag);
|
||||
return sb;
|
||||
}
|
||||
}
|
||||
|
||||
@ -822,10 +845,10 @@ final class HotSpotMethodData {
|
||||
private static boolean checkAccessorTags() {
|
||||
int expectedTag = 0;
|
||||
for (HotSpotMethodDataAccessor accessor : PROFILE_DATA_ACCESSORS) {
|
||||
if (expectedTag ==0 ) {
|
||||
if (expectedTag == 0) {
|
||||
assert accessor == null;
|
||||
} else {
|
||||
assert accessor.tag == expectedTag: expectedTag + " != " + accessor.tag + " " + accessor;
|
||||
assert accessor.tag == expectedTag : expectedTag + " != " + accessor.tag + " " + accessor;
|
||||
}
|
||||
expectedTag++;
|
||||
}
|
||||
|
@ -57,6 +57,18 @@ public final class HotSpotProfilingInfo implements ProfilingInfo {
|
||||
return method.getCodeSize();
|
||||
}
|
||||
|
||||
public int getDecompileCount() {
|
||||
return methodData.getDecompileCount();
|
||||
}
|
||||
|
||||
public int getOverflowRecompileCount() {
|
||||
return methodData.getOverflowRecompileCount();
|
||||
}
|
||||
|
||||
public int getOverflowTrapCount() {
|
||||
return methodData.getOverflowTrapCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaTypeProfile getTypeProfile(int bci) {
|
||||
if (!isMature) {
|
||||
|
@ -434,7 +434,6 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp
|
||||
methodData = new HotSpotMethodData(metaspaceMethodData, this);
|
||||
String methodDataFilter = Option.TraceMethodDataFilter.getString();
|
||||
if (methodDataFilter != null && this.format("%H.%n").contains(methodDataFilter)) {
|
||||
System.out.println("Raw method data for " + this.format("%H.%n(%p)") + ":");
|
||||
System.out.println(methodData.toString());
|
||||
}
|
||||
}
|
||||
|
@ -160,6 +160,10 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess {
|
||||
final int methodDataOopTrapHistoryOffset = getFieldOffset("MethodData::_trap_hist._array[0]", Integer.class, "u1");
|
||||
final int methodDataIRSizeOffset = getFieldOffset("MethodData::_jvmci_ir_size", Integer.class, "int");
|
||||
|
||||
final int methodDataDecompiles = getFieldOffset("MethodData::_nof_decompiles", Integer.class, "uint");
|
||||
final int methodDataOverflowRecompiles = getFieldOffset("MethodData::_nof_overflow_recompiles", Integer.class, "uint");
|
||||
final int methodDataOverflowTraps = getFieldOffset("MethodData::_nof_overflow_traps", Integer.class, "uint");
|
||||
|
||||
final int nmethodCompLevelOffset = getFieldOffset("nmethod::_comp_level", Integer.class, "int");
|
||||
|
||||
final int compilationLevelNone = getConstant("CompLevel_none", Integer.class);
|
||||
|
@ -22,6 +22,8 @@
|
||||
*/
|
||||
package jdk.vm.ci.runtime.services;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
import jdk.vm.ci.runtime.JVMCICompiler;
|
||||
import jdk.vm.ci.runtime.JVMCIRuntime;
|
||||
import jdk.vm.ci.services.JVMCIPermission;
|
||||
@ -70,4 +72,12 @@ public abstract class JVMCICompilerFactory {
|
||||
* Create a new instance of a {@link JVMCICompiler}.
|
||||
*/
|
||||
public abstract JVMCICompiler createCompiler(JVMCIRuntime runtime);
|
||||
|
||||
/**
|
||||
* Prints a description of the properties used to configure this compiler.
|
||||
*
|
||||
* @param out where to print the message
|
||||
*/
|
||||
public void printProperties(PrintStream out) {
|
||||
}
|
||||
}
|
||||
|
@ -153,6 +153,8 @@ void AbstractAssembler::generate_stack_overflow_check(int frame_size_in_bytes) {
|
||||
|
||||
void Label::add_patch_at(CodeBuffer* cb, int branch_loc) {
|
||||
assert(_loc == -1, "Label is unbound");
|
||||
// Don't add patch locations during scratch emit.
|
||||
if (cb->insts()->scratch_emit()) { return; }
|
||||
if (_patch_index < PatchCacheSize) {
|
||||
_patches[_patch_index] = branch_loc;
|
||||
} else {
|
||||
|
@ -331,6 +331,8 @@ void CodeSection::relocate(address at, relocInfo::relocType rtype, int format, j
|
||||
}
|
||||
|
||||
void CodeSection::relocate(address at, RelocationHolder const& spec, int format) {
|
||||
// Do not relocate in scratch buffers.
|
||||
if (scratch_emit()) { return; }
|
||||
Relocation* reloc = spec.reloc();
|
||||
relocInfo::relocType rtype = (relocInfo::relocType) reloc->type();
|
||||
if (rtype == relocInfo::none) return;
|
||||
|
@ -92,6 +92,7 @@ class CodeSection VALUE_OBJ_CLASS_SPEC {
|
||||
address _locs_point; // last relocated position (grows upward)
|
||||
bool _locs_own; // did I allocate the locs myself?
|
||||
bool _frozen; // no more expansion of this section
|
||||
bool _scratch_emit; // Buffer is used for scratch emit, don't relocate.
|
||||
char _index; // my section number (SECT_INST, etc.)
|
||||
CodeBuffer* _outer; // enclosing CodeBuffer
|
||||
|
||||
@ -108,6 +109,7 @@ class CodeSection VALUE_OBJ_CLASS_SPEC {
|
||||
_locs_point = NULL;
|
||||
_locs_own = false;
|
||||
_frozen = false;
|
||||
_scratch_emit = false;
|
||||
debug_only(_index = (char)-1);
|
||||
debug_only(_outer = (CodeBuffer*)badAddress);
|
||||
}
|
||||
@ -166,6 +168,10 @@ class CodeSection VALUE_OBJ_CLASS_SPEC {
|
||||
bool is_frozen() const { return _frozen; }
|
||||
bool has_locs() const { return _locs_end != NULL; }
|
||||
|
||||
// Mark scratch buffer.
|
||||
void set_scratch_emit() { _scratch_emit = true; }
|
||||
bool scratch_emit() { return _scratch_emit; }
|
||||
|
||||
CodeBuffer* outer() const { return _outer; }
|
||||
|
||||
// is a given address in this section? (2nd version is end-inclusive)
|
||||
|
@ -1929,7 +1929,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
|
||||
// number of implementors for decl_interface is 0 or 1. If
|
||||
// it's 0 then no class implements decl_interface and there's
|
||||
// no point in inlining.
|
||||
if (!holder->is_loaded() || decl_interface->nof_implementors() != 1 || decl_interface->has_default_methods()) {
|
||||
if (!holder->is_loaded() || decl_interface->nof_implementors() != 1 || decl_interface->has_nonstatic_concrete_methods()) {
|
||||
singleton = NULL;
|
||||
}
|
||||
}
|
||||
@ -4308,7 +4308,7 @@ void GraphBuilder::print_stats() {
|
||||
void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* known_holder, Values* obj_args, bool inlined) {
|
||||
assert(known_holder == NULL || (known_holder->is_instance_klass() &&
|
||||
(!known_holder->is_interface() ||
|
||||
((ciInstanceKlass*)known_holder)->has_default_methods())), "should be default method");
|
||||
((ciInstanceKlass*)known_holder)->has_nonstatic_concrete_methods())), "should be non-static concrete method");
|
||||
if (known_holder != NULL) {
|
||||
if (known_holder->exact_klass() == NULL) {
|
||||
known_holder = compilation()->cha_exact_type(known_holder);
|
||||
|
@ -58,7 +58,7 @@ ciInstanceKlass::ciInstanceKlass(KlassHandle h_k) :
|
||||
_init_state = ik->init_state();
|
||||
_nonstatic_field_size = ik->nonstatic_field_size();
|
||||
_has_nonstatic_fields = ik->has_nonstatic_fields();
|
||||
_has_default_methods = ik->has_default_methods();
|
||||
_has_nonstatic_concrete_methods = ik->has_nonstatic_concrete_methods();
|
||||
_is_anonymous = ik->is_anonymous();
|
||||
_nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields:
|
||||
_has_injected_fields = -1;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2016, 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,7 +52,7 @@ private:
|
||||
bool _has_finalizer;
|
||||
bool _has_subklass;
|
||||
bool _has_nonstatic_fields;
|
||||
bool _has_default_methods;
|
||||
bool _has_nonstatic_concrete_methods;
|
||||
bool _is_anonymous;
|
||||
|
||||
ciFlags _flags;
|
||||
@ -174,9 +174,9 @@ public:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
bool has_default_methods() {
|
||||
bool has_nonstatic_concrete_methods() {
|
||||
assert(is_loaded(), "must be loaded");
|
||||
return _has_default_methods;
|
||||
return _has_nonstatic_concrete_methods;
|
||||
}
|
||||
|
||||
bool is_anonymous() {
|
||||
|
@ -798,11 +798,11 @@ static bool put_after_lookup(const Symbol* name, const Symbol* sig, NameSigHash*
|
||||
void ClassFileParser::parse_interfaces(const ClassFileStream* const stream,
|
||||
const int itfs_len,
|
||||
ConstantPool* const cp,
|
||||
bool* const has_default_methods,
|
||||
bool* const has_nonstatic_concrete_methods,
|
||||
TRAPS) {
|
||||
assert(stream != NULL, "invariant");
|
||||
assert(cp != NULL, "invariant");
|
||||
assert(has_default_methods != NULL, "invariant");
|
||||
assert(has_nonstatic_concrete_methods != NULL, "invariant");
|
||||
|
||||
if (itfs_len == 0) {
|
||||
_local_interfaces = Universe::the_empty_klass_array();
|
||||
@ -844,8 +844,8 @@ void ClassFileParser::parse_interfaces(const ClassFileStream* const stream,
|
||||
"Implementing class");
|
||||
}
|
||||
|
||||
if (InstanceKlass::cast(interf())->has_default_methods()) {
|
||||
*has_default_methods = true;
|
||||
if (InstanceKlass::cast(interf())->has_nonstatic_concrete_methods()) {
|
||||
*has_nonstatic_concrete_methods = true;
|
||||
}
|
||||
_local_interfaces->at_put(index, interf());
|
||||
}
|
||||
@ -2830,12 +2830,12 @@ void ClassFileParser::parse_methods(const ClassFileStream* const cfs,
|
||||
bool is_interface,
|
||||
AccessFlags* promoted_flags,
|
||||
bool* has_final_method,
|
||||
bool* declares_default_methods,
|
||||
bool* declares_nonstatic_concrete_methods,
|
||||
TRAPS) {
|
||||
assert(cfs != NULL, "invariant");
|
||||
assert(promoted_flags != NULL, "invariant");
|
||||
assert(has_final_method != NULL, "invariant");
|
||||
assert(declares_default_methods != NULL, "invariant");
|
||||
assert(declares_nonstatic_concrete_methods != NULL, "invariant");
|
||||
|
||||
assert(NULL == _methods, "invariant");
|
||||
|
||||
@ -2860,11 +2860,11 @@ void ClassFileParser::parse_methods(const ClassFileStream* const cfs,
|
||||
if (method->is_final()) {
|
||||
*has_final_method = true;
|
||||
}
|
||||
// declares_default_methods: declares concrete instance methods, any access flags
|
||||
// declares_nonstatic_concrete_methods: declares concrete instance methods, any access flags
|
||||
// used for interface initialization, and default method inheritance analysis
|
||||
if (is_interface && !(*declares_default_methods)
|
||||
if (is_interface && !(*declares_nonstatic_concrete_methods)
|
||||
&& !method->is_abstract() && !method->is_static()) {
|
||||
*declares_default_methods = true;
|
||||
*declares_nonstatic_concrete_methods = true;
|
||||
}
|
||||
_methods->at_put(index, method);
|
||||
}
|
||||
@ -5250,8 +5250,8 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
|
||||
|
||||
ik->set_minor_version(_minor_version);
|
||||
ik->set_major_version(_major_version);
|
||||
ik->set_has_default_methods(_has_default_methods);
|
||||
ik->set_declares_default_methods(_declares_default_methods);
|
||||
ik->set_has_nonstatic_concrete_methods(_has_nonstatic_concrete_methods);
|
||||
ik->set_declares_nonstatic_concrete_methods(_declares_nonstatic_concrete_methods);
|
||||
|
||||
if (_host_klass != NULL) {
|
||||
assert (ik->is_anonymous(), "should be the same");
|
||||
@ -5311,12 +5311,9 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
|
||||
// check if this class overrides any final method
|
||||
check_final_method_override(ik, CHECK);
|
||||
|
||||
// check that if this class is an interface then it doesn't have static methods
|
||||
if (ik->is_interface()) {
|
||||
/* An interface in a JAVA 8 classfile can be static */
|
||||
if (_major_version < JAVA_8_VERSION) {
|
||||
check_illegal_static_method(ik, CHECK);
|
||||
}
|
||||
// reject static interface methods prior to Java 8
|
||||
if (ik->is_interface() && _major_version < JAVA_8_VERSION) {
|
||||
check_illegal_static_method(ik, CHECK);
|
||||
}
|
||||
|
||||
// Obtain this_klass' module entry
|
||||
@ -5336,9 +5333,9 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
|
||||
|
||||
assert(_all_mirandas != NULL, "invariant");
|
||||
|
||||
// Generate any default methods - default methods are interface methods
|
||||
// that have a default implementation. This is new with Lambda project.
|
||||
if (_has_default_methods ) {
|
||||
// Generate any default methods - default methods are public interface methods
|
||||
// that have a default implementation. This is new with Java 8.
|
||||
if (_has_nonstatic_concrete_methods) {
|
||||
DefaultMethods::generate_default_methods(ik,
|
||||
_all_mirandas,
|
||||
CHECK);
|
||||
@ -5523,8 +5520,8 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
|
||||
_java_fields_count(0),
|
||||
_need_verify(false),
|
||||
_relax_verify(false),
|
||||
_has_default_methods(false),
|
||||
_declares_default_methods(false),
|
||||
_has_nonstatic_concrete_methods(false),
|
||||
_declares_nonstatic_concrete_methods(false),
|
||||
_has_final_method(false),
|
||||
_has_finalizer(false),
|
||||
_has_empty_finalizer(false),
|
||||
@ -5798,7 +5795,7 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
|
||||
parse_interfaces(stream,
|
||||
_itfs_len,
|
||||
cp,
|
||||
&_has_default_methods,
|
||||
&_has_nonstatic_concrete_methods,
|
||||
CHECK);
|
||||
|
||||
assert(_local_interfaces != NULL, "invariant");
|
||||
@ -5821,7 +5818,7 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
|
||||
_access_flags.is_interface(),
|
||||
&promoted_flags,
|
||||
&_has_final_method,
|
||||
&_declares_default_methods,
|
||||
&_declares_nonstatic_concrete_methods,
|
||||
CHECK);
|
||||
|
||||
assert(_methods != NULL, "invariant");
|
||||
@ -5829,8 +5826,8 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
|
||||
// promote flags from parse_methods() to the klass' flags
|
||||
_access_flags.add_promoted_flags(promoted_flags.as_int());
|
||||
|
||||
if (_declares_default_methods) {
|
||||
_has_default_methods = true;
|
||||
if (_declares_nonstatic_concrete_methods) {
|
||||
_has_nonstatic_concrete_methods = true;
|
||||
}
|
||||
|
||||
// Additional attributes/annotations
|
||||
@ -5879,8 +5876,8 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st
|
||||
}
|
||||
|
||||
if (_super_klass != NULL) {
|
||||
if (_super_klass->has_default_methods()) {
|
||||
_has_default_methods = true;
|
||||
if (_super_klass->has_nonstatic_concrete_methods()) {
|
||||
_has_nonstatic_concrete_methods = true;
|
||||
}
|
||||
|
||||
if (_super_klass->is_interface()) {
|
||||
|
@ -139,8 +139,8 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
bool _need_verify;
|
||||
bool _relax_verify;
|
||||
|
||||
bool _has_default_methods;
|
||||
bool _declares_default_methods;
|
||||
bool _has_nonstatic_concrete_methods;
|
||||
bool _declares_nonstatic_concrete_methods;
|
||||
bool _has_final_method;
|
||||
|
||||
// precomputed flags
|
||||
@ -186,7 +186,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
void parse_interfaces(const ClassFileStream* const stream,
|
||||
const int itfs_len,
|
||||
ConstantPool* const cp,
|
||||
bool* has_default_methods,
|
||||
bool* has_nonstatic_concrete_methods,
|
||||
TRAPS);
|
||||
|
||||
const InstanceKlass* parse_super_class(ConstantPool* const cp,
|
||||
@ -224,7 +224,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
bool is_interface,
|
||||
AccessFlags* const promoted_flags,
|
||||
bool* const has_final_method,
|
||||
bool* const declares_default_methods,
|
||||
bool* const declares_nonstatic_concrete_methods,
|
||||
TRAPS);
|
||||
|
||||
const u2* parse_exception_table(const ClassFileStream* const stream,
|
||||
|
@ -81,7 +81,6 @@ typedef void * * (JNICALL *ZipOpen_t)(const char *name, char **pmsg);
|
||||
typedef void (JNICALL *ZipClose_t)(jzfile *zip);
|
||||
typedef jzentry* (JNICALL *FindEntry_t)(jzfile *zip, const char *name, jint *sizeP, jint *nameLen);
|
||||
typedef jboolean (JNICALL *ReadEntry_t)(jzfile *zip, jzentry *entry, unsigned char *buf, char *namebuf);
|
||||
typedef jboolean (JNICALL *ReadMappedEntry_t)(jzfile *zip, jzentry *entry, unsigned char **buf, char *namebuf);
|
||||
typedef jzentry* (JNICALL *GetNextEntry_t)(jzfile *zip, jint n);
|
||||
typedef jboolean (JNICALL *ZipInflateFully_t)(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pmsg);
|
||||
typedef jint (JNICALL *Crc32_t)(jint crc, const jbyte *buf, jint len);
|
||||
@ -91,7 +90,6 @@ static ZipOpen_t ZipOpen = NULL;
|
||||
static ZipClose_t ZipClose = NULL;
|
||||
static FindEntry_t FindEntry = NULL;
|
||||
static ReadEntry_t ReadEntry = NULL;
|
||||
static ReadMappedEntry_t ReadMappedEntry = NULL;
|
||||
static GetNextEntry_t GetNextEntry = NULL;
|
||||
static canonicalize_fn_t CanonicalizeEntry = NULL;
|
||||
static ZipInflateFully_t ZipInflateFully = NULL;
|
||||
@ -353,15 +351,10 @@ u1* ClassPathZipEntry::open_entry(const char* name, jint* filesize, bool nul_ter
|
||||
filename = NEW_RESOURCE_ARRAY(char, name_len + 1);
|
||||
}
|
||||
|
||||
// file found, get pointer to the entry in mmapped jar file.
|
||||
if (ReadMappedEntry == NULL ||
|
||||
!(*ReadMappedEntry)(_zip, entry, &buffer, filename)) {
|
||||
// mmapped access not available, perhaps due to compression,
|
||||
// read contents into resource array
|
||||
int size = (*filesize) + ((nul_terminate) ? 1 : 0);
|
||||
buffer = NEW_RESOURCE_ARRAY(u1, size);
|
||||
if (!(*ReadEntry)(_zip, entry, buffer, filename)) return NULL;
|
||||
}
|
||||
// read contents into resource array
|
||||
int size = (*filesize) + ((nul_terminate) ? 1 : 0);
|
||||
buffer = NEW_RESOURCE_ARRAY(u1, size);
|
||||
if (!(*ReadEntry)(_zip, entry, buffer, filename)) return NULL;
|
||||
|
||||
// return result
|
||||
if (nul_terminate) {
|
||||
@ -1079,7 +1072,6 @@ void ClassLoader::load_zip_library() {
|
||||
ZipClose = CAST_TO_FN_PTR(ZipClose_t, os::dll_lookup(handle, "ZIP_Close"));
|
||||
FindEntry = CAST_TO_FN_PTR(FindEntry_t, os::dll_lookup(handle, "ZIP_FindEntry"));
|
||||
ReadEntry = CAST_TO_FN_PTR(ReadEntry_t, os::dll_lookup(handle, "ZIP_ReadEntry"));
|
||||
ReadMappedEntry = CAST_TO_FN_PTR(ReadMappedEntry_t, os::dll_lookup(handle, "ZIP_ReadMappedEntry"));
|
||||
GetNextEntry = CAST_TO_FN_PTR(GetNextEntry_t, os::dll_lookup(handle, "ZIP_GetNextEntry"));
|
||||
ZipInflateFully = CAST_TO_FN_PTR(ZipInflateFully_t, os::dll_lookup(handle, "ZIP_InflateFully"));
|
||||
Crc32 = CAST_TO_FN_PTR(Crc32_t, os::dll_lookup(handle, "ZIP_CRC32"));
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016, 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
|
||||
@ -914,7 +914,7 @@ static void create_defaults_and_exceptions(
|
||||
BytecodeBuffer buffer;
|
||||
|
||||
if (log_is_enabled(Debug, defaultmethods)) {
|
||||
ResourceMark rm;
|
||||
ResourceMark rm(THREAD);
|
||||
outputStream* logstream = Log(defaultmethods)::debug_stream();
|
||||
logstream->print("for slot: ");
|
||||
slot->print_on(logstream);
|
||||
@ -929,6 +929,7 @@ static void create_defaults_and_exceptions(
|
||||
if (method->has_target()) {
|
||||
Method* selected = method->get_selected_target();
|
||||
if (selected->method_holder()->is_interface()) {
|
||||
assert(!selected->is_private(), "pushing private interface method as default");
|
||||
defaults.push(selected);
|
||||
}
|
||||
} else if (method->throws_exception()) {
|
||||
|
@ -780,19 +780,26 @@ void java_lang_Class::set_mirror_module_field(KlassHandle k, Handle mirror, Hand
|
||||
// Put the class on the fixup_module_list to patch later when the java.lang.reflect.Module
|
||||
// for java.base is known.
|
||||
assert(!Universe::is_module_initialized(), "Incorrect java.lang.reflect.Module pre module system initialization");
|
||||
MutexLocker m1(Module_lock, THREAD);
|
||||
// Keep list of classes needing java.base module fixup
|
||||
if (!ModuleEntryTable::javabase_defined()) {
|
||||
if (fixup_module_field_list() == NULL) {
|
||||
GrowableArray<Klass*>* list =
|
||||
new (ResourceObj::C_HEAP, mtModule) GrowableArray<Klass*>(500, true);
|
||||
set_fixup_module_field_list(list);
|
||||
|
||||
bool javabase_was_defined = false;
|
||||
{
|
||||
MutexLocker m1(Module_lock, THREAD);
|
||||
// Keep list of classes needing java.base module fixup
|
||||
if (!ModuleEntryTable::javabase_defined()) {
|
||||
if (fixup_module_field_list() == NULL) {
|
||||
GrowableArray<Klass*>* list =
|
||||
new (ResourceObj::C_HEAP, mtModule) GrowableArray<Klass*>(500, true);
|
||||
set_fixup_module_field_list(list);
|
||||
}
|
||||
k->class_loader_data()->inc_keep_alive();
|
||||
fixup_module_field_list()->push(k());
|
||||
} else {
|
||||
javabase_was_defined = true;
|
||||
}
|
||||
k->class_loader_data()->inc_keep_alive();
|
||||
fixup_module_field_list()->push(k());
|
||||
} else {
|
||||
// java.base was defined at some point between calling create_mirror()
|
||||
// and obtaining the Module_lock, patch this particular class with java.base.
|
||||
}
|
||||
|
||||
// If java.base was already defined then patch this particular class with java.base.
|
||||
if (javabase_was_defined) {
|
||||
ModuleEntry *javabase_entry = ModuleEntryTable::javabase_moduleEntry();
|
||||
assert(javabase_entry != NULL && javabase_entry->module() != NULL,
|
||||
"Setting class module field, java.base should be defined");
|
||||
|
@ -368,9 +368,6 @@ void ModuleEntryTable::finalize_javabase(Handle module_handle, Symbol* version,
|
||||
|
||||
// Store pointer to the ModuleEntry for java.base in the java.lang.reflect.Module object.
|
||||
java_lang_reflect_Module::set_module_entry(module_handle(), jb_module);
|
||||
|
||||
// Patch any previously loaded classes' module field with java.base's java.lang.reflect.Module.
|
||||
patch_javabase_entries(module_handle);
|
||||
}
|
||||
|
||||
// Within java.lang.Class instances there is a java.lang.reflect.Module field
|
||||
@ -378,7 +375,6 @@ void ModuleEntryTable::finalize_javabase(Handle module_handle, Symbol* version,
|
||||
// definition, classes needing their module field set are added to the fixup_module_list.
|
||||
// Their module field is set once java.base's java.lang.reflect.Module is known to the VM.
|
||||
void ModuleEntryTable::patch_javabase_entries(Handle module_handle) {
|
||||
assert(Module_lock->owned_by_self(), "should have the Module_lock");
|
||||
if (module_handle.is_null()) {
|
||||
fatal("Unable to patch the module field of classes loaded prior to java.base's definition, invalid java.lang.reflect.Module");
|
||||
}
|
||||
|
@ -244,6 +244,12 @@ static void define_javabase_module(jobject module, jstring version,
|
||||
"Module java.base is already defined");
|
||||
}
|
||||
|
||||
// Only the thread that actually defined the base module will get here,
|
||||
// so no locking is needed.
|
||||
|
||||
// Patch any previously loaded class's module field with java.base's java.lang.reflect.Module.
|
||||
ModuleEntryTable::patch_javabase_entries(module_handle);
|
||||
|
||||
log_debug(modules)("define_javabase_module(): Definition of module: java.base,"
|
||||
" version: %s, location: %s, package #: %d",
|
||||
module_version != NULL ? module_version : "NULL",
|
||||
|
@ -226,7 +226,7 @@ class SystemDictionary : AllStatic {
|
||||
WKID_LIMIT,
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
FIRST_JVMCI_WKID = WK_KLASS_ENUM_NAME(HotSpotCompiledCode_klass),
|
||||
FIRST_JVMCI_WKID = WK_KLASS_ENUM_NAME(JVMCI_klass),
|
||||
LAST_JVMCI_WKID = WK_KLASS_ENUM_NAME(Value_klass),
|
||||
#endif
|
||||
|
||||
|
@ -2340,13 +2340,11 @@ void CMSCollector::verify_after_remark_work_1() {
|
||||
{
|
||||
StrongRootsScope srs(1);
|
||||
|
||||
gch->gen_process_roots(&srs,
|
||||
GenCollectedHeap::OldGen,
|
||||
gch->cms_process_roots(&srs,
|
||||
true, // young gen as roots
|
||||
GenCollectedHeap::ScanningOption(roots_scanning_options()),
|
||||
should_unload_classes(),
|
||||
¬Older,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
@ -2414,13 +2412,11 @@ void CMSCollector::verify_after_remark_work_2() {
|
||||
{
|
||||
StrongRootsScope srs(1);
|
||||
|
||||
gch->gen_process_roots(&srs,
|
||||
GenCollectedHeap::OldGen,
|
||||
gch->cms_process_roots(&srs,
|
||||
true, // young gen as roots
|
||||
GenCollectedHeap::ScanningOption(roots_scanning_options()),
|
||||
should_unload_classes(),
|
||||
¬Older,
|
||||
NULL,
|
||||
&cld_closure);
|
||||
}
|
||||
|
||||
@ -2903,13 +2899,11 @@ void CMSCollector::checkpointRootsInitialWork() {
|
||||
|
||||
StrongRootsScope srs(1);
|
||||
|
||||
gch->gen_process_roots(&srs,
|
||||
GenCollectedHeap::OldGen,
|
||||
gch->cms_process_roots(&srs,
|
||||
true, // young gen as roots
|
||||
GenCollectedHeap::ScanningOption(roots_scanning_options()),
|
||||
should_unload_classes(),
|
||||
¬Older,
|
||||
NULL,
|
||||
&cld_closure);
|
||||
}
|
||||
}
|
||||
@ -4290,13 +4284,11 @@ void CMSParInitialMarkTask::work(uint worker_id) {
|
||||
|
||||
CLDToOopClosure cld_closure(&par_mri_cl, true);
|
||||
|
||||
gch->gen_process_roots(_strong_roots_scope,
|
||||
GenCollectedHeap::OldGen,
|
||||
gch->cms_process_roots(_strong_roots_scope,
|
||||
false, // yg was scanned above
|
||||
GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
|
||||
_collector->should_unload_classes(),
|
||||
&par_mri_cl,
|
||||
NULL,
|
||||
&cld_closure);
|
||||
assert(_collector->should_unload_classes()
|
||||
|| (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache),
|
||||
@ -4421,13 +4413,11 @@ void CMSParRemarkTask::work(uint worker_id) {
|
||||
// ---------- remaining roots --------------
|
||||
_timer.reset();
|
||||
_timer.start();
|
||||
gch->gen_process_roots(_strong_roots_scope,
|
||||
GenCollectedHeap::OldGen,
|
||||
gch->cms_process_roots(_strong_roots_scope,
|
||||
false, // yg was scanned above
|
||||
GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
|
||||
_collector->should_unload_classes(),
|
||||
&par_mrias_cl,
|
||||
NULL,
|
||||
NULL); // The dirty klasses will be handled below
|
||||
|
||||
assert(_collector->should_unload_classes()
|
||||
@ -4970,13 +4960,11 @@ void CMSCollector::do_remark_non_parallel() {
|
||||
gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
|
||||
StrongRootsScope srs(1);
|
||||
|
||||
gch->gen_process_roots(&srs,
|
||||
GenCollectedHeap::OldGen,
|
||||
gch->cms_process_roots(&srs,
|
||||
true, // young gen as roots
|
||||
GenCollectedHeap::ScanningOption(roots_scanning_options()),
|
||||
should_unload_classes(),
|
||||
&mrias_cl,
|
||||
NULL,
|
||||
NULL); // The dirty klasses will be handled below
|
||||
|
||||
assert(should_unload_classes()
|
||||
|
@ -605,14 +605,10 @@ void ParNewGenTask::work(uint worker_id) {
|
||||
false);
|
||||
|
||||
par_scan_state.start_strong_roots();
|
||||
gch->gen_process_roots(_strong_roots_scope,
|
||||
GenCollectedHeap::YoungGen,
|
||||
true, // Process younger gens, if any, as strong roots.
|
||||
GenCollectedHeap::SO_ScavengeCodeCache,
|
||||
GenCollectedHeap::StrongAndWeakRoots,
|
||||
&par_scan_state.to_space_root_closure(),
|
||||
&par_scan_state.older_gen_closure(),
|
||||
&cld_scan_closure);
|
||||
gch->young_process_roots(_strong_roots_scope,
|
||||
&par_scan_state.to_space_root_closure(),
|
||||
&par_scan_state.older_gen_closure(),
|
||||
&cld_scan_closure);
|
||||
|
||||
par_scan_state.end_strong_roots();
|
||||
|
||||
|
@ -648,15 +648,10 @@ void DefNewGeneration::collect(bool full,
|
||||
// See: CardTableModRefBSForCTRS::non_clean_card_iterate_possibly_parallel.
|
||||
StrongRootsScope srs(0);
|
||||
|
||||
gch->gen_process_roots(&srs,
|
||||
GenCollectedHeap::YoungGen,
|
||||
true, // Process younger gens, if any,
|
||||
// as strong roots.
|
||||
GenCollectedHeap::SO_ScavengeCodeCache,
|
||||
GenCollectedHeap::StrongAndWeakRoots,
|
||||
&fsc_with_no_gc_barrier,
|
||||
&fsc_with_gc_barrier,
|
||||
&cld_scan_closure);
|
||||
gch->young_process_roots(&srs,
|
||||
&fsc_with_no_gc_barrier,
|
||||
&fsc_with_gc_barrier,
|
||||
&cld_scan_closure);
|
||||
}
|
||||
|
||||
// "evacuate followers".
|
||||
|
@ -196,14 +196,13 @@ void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
|
||||
{
|
||||
StrongRootsScope srs(1);
|
||||
|
||||
gch->gen_process_roots(&srs,
|
||||
GenCollectedHeap::OldGen,
|
||||
false, // Younger gens are not roots.
|
||||
GenCollectedHeap::SO_None,
|
||||
ClassUnloading,
|
||||
&follow_root_closure,
|
||||
&follow_root_closure,
|
||||
&follow_cld_closure);
|
||||
gch->full_process_roots(&srs,
|
||||
false, // not the adjust phase
|
||||
GenCollectedHeap::SO_None,
|
||||
ClassUnloading, // only strong roots if ClassUnloading
|
||||
// is enabled
|
||||
&follow_root_closure,
|
||||
&follow_cld_closure);
|
||||
}
|
||||
|
||||
// Process reference objects found during marking
|
||||
@ -295,14 +294,12 @@ void GenMarkSweep::mark_sweep_phase3() {
|
||||
{
|
||||
StrongRootsScope srs(1);
|
||||
|
||||
gch->gen_process_roots(&srs,
|
||||
GenCollectedHeap::OldGen,
|
||||
false, // Younger gens are not roots.
|
||||
GenCollectedHeap::SO_AllCodeCache,
|
||||
GenCollectedHeap::StrongAndWeakRoots,
|
||||
&adjust_pointer_closure,
|
||||
&adjust_pointer_closure,
|
||||
&adjust_cld_closure);
|
||||
gch->full_process_roots(&srs,
|
||||
true, // this is the adjust phase
|
||||
GenCollectedHeap::SO_AllCodeCache,
|
||||
false, // all roots
|
||||
&adjust_pointer_closure,
|
||||
&adjust_cld_closure);
|
||||
}
|
||||
|
||||
gch->gen_process_weak_roots(&adjust_pointer_closure);
|
||||
|
@ -613,16 +613,6 @@ void GenCollectedHeap::process_roots(StrongRootsScope* scope,
|
||||
SystemDictionary::roots_oops_do(strong_roots, weak_roots);
|
||||
}
|
||||
|
||||
// All threads execute the following. A specific chunk of buckets
|
||||
// from the StringTable are the individual tasks.
|
||||
if (weak_roots != NULL) {
|
||||
if (is_par) {
|
||||
StringTable::possibly_parallel_oops_do(weak_roots);
|
||||
} else {
|
||||
StringTable::oops_do(weak_roots);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_process_strong_tasks->is_task_claimed(GCH_PS_CodeCache_oops_do)) {
|
||||
if (so & SO_ScavengeCodeCache) {
|
||||
assert(code_roots != NULL, "must supply closure for code cache");
|
||||
@ -644,46 +634,82 @@ void GenCollectedHeap::process_roots(StrongRootsScope* scope,
|
||||
}
|
||||
}
|
||||
|
||||
void GenCollectedHeap::gen_process_roots(StrongRootsScope* scope,
|
||||
GenerationType type,
|
||||
void GenCollectedHeap::process_string_table_roots(StrongRootsScope* scope,
|
||||
OopClosure* root_closure) {
|
||||
assert(root_closure != NULL, "Must be set");
|
||||
// All threads execute the following. A specific chunk of buckets
|
||||
// from the StringTable are the individual tasks.
|
||||
if (scope->n_threads() > 1) {
|
||||
StringTable::possibly_parallel_oops_do(root_closure);
|
||||
} else {
|
||||
StringTable::oops_do(root_closure);
|
||||
}
|
||||
}
|
||||
|
||||
void GenCollectedHeap::young_process_roots(StrongRootsScope* scope,
|
||||
OopsInGenClosure* root_closure,
|
||||
OopsInGenClosure* old_gen_closure,
|
||||
CLDClosure* cld_closure) {
|
||||
MarkingCodeBlobClosure mark_code_closure(root_closure, CodeBlobToOopClosure::FixRelocations);
|
||||
|
||||
process_roots(scope, SO_ScavengeCodeCache, root_closure, root_closure,
|
||||
cld_closure, cld_closure, &mark_code_closure);
|
||||
process_string_table_roots(scope, root_closure);
|
||||
|
||||
if (!_process_strong_tasks->is_task_claimed(GCH_PS_younger_gens)) {
|
||||
root_closure->reset_generation();
|
||||
}
|
||||
|
||||
// When collection is parallel, all threads get to cooperate to do
|
||||
// old generation scanning.
|
||||
old_gen_closure->set_generation(_old_gen);
|
||||
rem_set()->younger_refs_iterate(_old_gen, old_gen_closure, scope->n_threads());
|
||||
old_gen_closure->reset_generation();
|
||||
|
||||
_process_strong_tasks->all_tasks_completed(scope->n_threads());
|
||||
}
|
||||
|
||||
void GenCollectedHeap::cms_process_roots(StrongRootsScope* scope,
|
||||
bool young_gen_as_roots,
|
||||
ScanningOption so,
|
||||
bool only_strong_roots,
|
||||
OopsInGenClosure* not_older_gens,
|
||||
OopsInGenClosure* older_gens,
|
||||
OopsInGenClosure* root_closure,
|
||||
CLDClosure* cld_closure) {
|
||||
const bool is_adjust_phase = !only_strong_roots && !young_gen_as_roots;
|
||||
|
||||
bool is_moving_collection = false;
|
||||
if (type == YoungGen || is_adjust_phase) {
|
||||
// young collections are always moving
|
||||
is_moving_collection = true;
|
||||
}
|
||||
|
||||
MarkingCodeBlobClosure mark_code_closure(not_older_gens, is_moving_collection);
|
||||
OopsInGenClosure* weak_roots = only_strong_roots ? NULL : not_older_gens;
|
||||
MarkingCodeBlobClosure mark_code_closure(root_closure, !CodeBlobToOopClosure::FixRelocations);
|
||||
OopsInGenClosure* weak_roots = only_strong_roots ? NULL : root_closure;
|
||||
CLDClosure* weak_cld_closure = only_strong_roots ? NULL : cld_closure;
|
||||
|
||||
process_roots(scope, so,
|
||||
not_older_gens, weak_roots,
|
||||
cld_closure, weak_cld_closure,
|
||||
&mark_code_closure);
|
||||
|
||||
if (young_gen_as_roots) {
|
||||
if (!_process_strong_tasks->is_task_claimed(GCH_PS_younger_gens)) {
|
||||
if (type == OldGen) {
|
||||
not_older_gens->set_generation(_young_gen);
|
||||
_young_gen->oop_iterate(not_older_gens);
|
||||
}
|
||||
not_older_gens->reset_generation();
|
||||
}
|
||||
process_roots(scope, so, root_closure, weak_roots, cld_closure, weak_cld_closure, &mark_code_closure);
|
||||
if (!only_strong_roots) {
|
||||
process_string_table_roots(scope, root_closure);
|
||||
}
|
||||
// When collection is parallel, all threads get to cooperate to do
|
||||
// old generation scanning.
|
||||
if (type == YoungGen) {
|
||||
older_gens->set_generation(_old_gen);
|
||||
rem_set()->younger_refs_iterate(_old_gen, older_gens, scope->n_threads());
|
||||
older_gens->reset_generation();
|
||||
|
||||
if (young_gen_as_roots &&
|
||||
!_process_strong_tasks->is_task_claimed(GCH_PS_younger_gens)) {
|
||||
root_closure->set_generation(_young_gen);
|
||||
_young_gen->oop_iterate(root_closure);
|
||||
root_closure->reset_generation();
|
||||
}
|
||||
|
||||
_process_strong_tasks->all_tasks_completed(scope->n_threads());
|
||||
}
|
||||
|
||||
void GenCollectedHeap::full_process_roots(StrongRootsScope* scope,
|
||||
bool is_adjust_phase,
|
||||
ScanningOption so,
|
||||
bool only_strong_roots,
|
||||
OopsInGenClosure* root_closure,
|
||||
CLDClosure* cld_closure) {
|
||||
MarkingCodeBlobClosure mark_code_closure(root_closure, is_adjust_phase);
|
||||
OopsInGenClosure* weak_roots = only_strong_roots ? NULL : root_closure;
|
||||
CLDClosure* weak_cld_closure = only_strong_roots ? NULL : cld_closure;
|
||||
|
||||
process_roots(scope, so, root_closure, weak_roots, cld_closure, weak_cld_closure, &mark_code_closure);
|
||||
if (is_adjust_phase) {
|
||||
// We never treat the string table as roots during marking
|
||||
// for the full gc, so we only need to process it during
|
||||
// the adjust phase.
|
||||
process_string_table_roots(scope, root_closure);
|
||||
}
|
||||
|
||||
_process_strong_tasks->all_tasks_completed(scope->n_threads());
|
||||
|
@ -374,16 +374,7 @@ public:
|
||||
// asserted to be this type.
|
||||
static GenCollectedHeap* heap();
|
||||
|
||||
// Invoke the "do_oop" method of one of the closures "not_older_gens"
|
||||
// or "older_gens" on root locations for the generations depending on
|
||||
// the type. (The "older_gens" closure is used for scanning references
|
||||
// from older generations; "not_older_gens" is used everywhere else.)
|
||||
// If "younger_gens_as_roots" is false, younger generations are
|
||||
// not scanned as roots; in this case, the caller must be arranging to
|
||||
// scan the younger generations itself. (For example, a generation might
|
||||
// explicitly mark reachable objects in younger generations, to avoid
|
||||
// excess storage retention.)
|
||||
// The "so" argument determines which of the roots
|
||||
// The ScanningOption determines which of the roots
|
||||
// the closure is applied to:
|
||||
// "SO_None" does none;
|
||||
enum ScanningOption {
|
||||
@ -401,19 +392,34 @@ public:
|
||||
CLDClosure* weak_cld_closure,
|
||||
CodeBlobToOopClosure* code_roots);
|
||||
|
||||
public:
|
||||
static const bool StrongAndWeakRoots = false;
|
||||
static const bool StrongRootsOnly = true;
|
||||
void process_string_table_roots(StrongRootsScope* scope,
|
||||
OopClosure* root_closure);
|
||||
|
||||
void gen_process_roots(StrongRootsScope* scope,
|
||||
GenerationType type,
|
||||
public:
|
||||
void young_process_roots(StrongRootsScope* scope,
|
||||
OopsInGenClosure* root_closure,
|
||||
OopsInGenClosure* old_gen_closure,
|
||||
CLDClosure* cld_closure);
|
||||
|
||||
// If "young_gen_as_roots" is false, younger generations are
|
||||
// not scanned as roots; in this case, the caller must be arranging to
|
||||
// scan the younger generations itself. (For example, a generation might
|
||||
// explicitly mark reachable objects in younger generations, to avoid
|
||||
// excess storage retention.)
|
||||
void cms_process_roots(StrongRootsScope* scope,
|
||||
bool young_gen_as_roots,
|
||||
ScanningOption so,
|
||||
bool only_strong_roots,
|
||||
OopsInGenClosure* not_older_gens,
|
||||
OopsInGenClosure* older_gens,
|
||||
OopsInGenClosure* root_closure,
|
||||
CLDClosure* cld_closure);
|
||||
|
||||
void full_process_roots(StrongRootsScope* scope,
|
||||
bool is_adjust_phase,
|
||||
ScanningOption so,
|
||||
bool only_strong_roots,
|
||||
OopsInGenClosure* root_closure,
|
||||
CLDClosure* cld_closure);
|
||||
|
||||
// Apply "root_closure" to all the weak roots of the system.
|
||||
// These include JNI weak roots, string table,
|
||||
// and referents of reachable weak refs.
|
||||
|
@ -40,6 +40,7 @@
|
||||
|
||||
class InvocationCounter VALUE_OBJ_CLASS_SPEC {
|
||||
friend class VMStructs;
|
||||
friend class JVMCIVMStructs;
|
||||
friend class ciReplay;
|
||||
private: // bit no: |31 3| 2 | 1 0 |
|
||||
unsigned int _counter; // format: [count|carry|state]
|
||||
|
@ -858,8 +858,10 @@ methodHandle LinkResolver::resolve_interface_method(const LinkInfo& link_info, B
|
||||
}
|
||||
|
||||
if (log_develop_is_enabled(Trace, itables)) {
|
||||
trace_method_resolution("invokeinterface resolved method: caller-class",
|
||||
link_info.current_klass(), resolved_klass,
|
||||
char buf[200];
|
||||
jio_snprintf(buf, sizeof(buf), "%s resolved interface method: caller-class:",
|
||||
Bytecodes::name(code));
|
||||
trace_method_resolution(buf, link_info.current_klass(), resolved_klass,
|
||||
resolved_method, true);
|
||||
}
|
||||
|
||||
@ -1424,7 +1426,7 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result,
|
||||
}
|
||||
|
||||
if (log_develop_is_enabled(Trace, itables)) {
|
||||
trace_method_resolution("invokeinterface selected method: receiver-class",
|
||||
trace_method_resolution("invokeinterface selected method: receiver-class:",
|
||||
recv_klass, resolved_klass, sel_method, true);
|
||||
}
|
||||
// setup result
|
||||
|
@ -640,8 +640,6 @@ JVM_ENTRY(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c))
|
||||
JVM_END
|
||||
|
||||
Handle JVMCIRuntime::callStatic(const char* className, const char* methodName, const char* signature, JavaCallArguments* args, TRAPS) {
|
||||
guarantee(!_HotSpotJVMCIRuntime_initialized, "cannot reinitialize HotSpotJVMCIRuntime");
|
||||
|
||||
TempNewSymbol name = SymbolTable::new_symbol(className, CHECK_(Handle()));
|
||||
KlassHandle klass = SystemDictionary::resolve_or_fail(name, true, CHECK_(Handle()));
|
||||
TempNewSymbol runtime = SymbolTable::new_symbol(methodName, CHECK_(Handle()));
|
||||
@ -656,42 +654,37 @@ Handle JVMCIRuntime::callStatic(const char* className, const char* methodName, c
|
||||
}
|
||||
|
||||
void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(TRAPS) {
|
||||
if (JNIHandles::resolve(_HotSpotJVMCIRuntime_instance) == NULL) {
|
||||
ResourceMark rm;
|
||||
#ifdef ASSERT
|
||||
// This should only be called in the context of the JVMCI class being initialized
|
||||
TempNewSymbol name = SymbolTable::new_symbol("jdk/vm/ci/runtime/JVMCI", CHECK);
|
||||
Klass* k = SystemDictionary::resolve_or_null(name, CHECK);
|
||||
instanceKlassHandle klass = InstanceKlass::cast(k);
|
||||
assert(klass->is_being_initialized() && klass->is_reentrant_initialization(THREAD),
|
||||
"HotSpotJVMCIRuntime initialization should only be triggered through JVMCI initialization");
|
||||
#endif
|
||||
guarantee(!_HotSpotJVMCIRuntime_initialized, "cannot reinitialize HotSpotJVMCIRuntime");
|
||||
JVMCIRuntime::initialize_well_known_classes(CHECK);
|
||||
// This should only be called in the context of the JVMCI class being initialized
|
||||
instanceKlassHandle klass = InstanceKlass::cast(SystemDictionary::JVMCI_klass());
|
||||
guarantee(klass->is_being_initialized() && klass->is_reentrant_initialization(THREAD),
|
||||
"HotSpotJVMCIRuntime initialization should only be triggered through JVMCI initialization");
|
||||
|
||||
Handle result = callStatic("jdk/vm/ci/hotspot/HotSpotJVMCIRuntime",
|
||||
"runtime",
|
||||
"()Ljdk/vm/ci/hotspot/HotSpotJVMCIRuntime;", NULL, CHECK);
|
||||
objArrayOop trivial_prefixes = HotSpotJVMCIRuntime::trivialPrefixes(result);
|
||||
if (trivial_prefixes != NULL) {
|
||||
char** prefixes = NEW_C_HEAP_ARRAY(char*, trivial_prefixes->length(), mtCompiler);
|
||||
for (int i = 0; i < trivial_prefixes->length(); i++) {
|
||||
oop str = trivial_prefixes->obj_at(i);
|
||||
if (str == NULL) {
|
||||
THROW(vmSymbols::java_lang_NullPointerException());
|
||||
} else {
|
||||
prefixes[i] = strdup(java_lang_String::as_utf8_string(str));
|
||||
}
|
||||
Handle result = callStatic("jdk/vm/ci/hotspot/HotSpotJVMCIRuntime",
|
||||
"runtime",
|
||||
"()Ljdk/vm/ci/hotspot/HotSpotJVMCIRuntime;", NULL, CHECK);
|
||||
objArrayOop trivial_prefixes = HotSpotJVMCIRuntime::trivialPrefixes(result);
|
||||
if (trivial_prefixes != NULL) {
|
||||
char** prefixes = NEW_C_HEAP_ARRAY(char*, trivial_prefixes->length(), mtCompiler);
|
||||
for (int i = 0; i < trivial_prefixes->length(); i++) {
|
||||
oop str = trivial_prefixes->obj_at(i);
|
||||
if (str == NULL) {
|
||||
THROW(vmSymbols::java_lang_NullPointerException());
|
||||
} else {
|
||||
prefixes[i] = strdup(java_lang_String::as_utf8_string(str));
|
||||
}
|
||||
_trivial_prefixes = prefixes;
|
||||
_trivial_prefixes_count = trivial_prefixes->length();
|
||||
}
|
||||
int adjustment = HotSpotJVMCIRuntime::compilationLevelAdjustment(result);
|
||||
assert(adjustment >= JVMCIRuntime::none &&
|
||||
adjustment <= JVMCIRuntime::by_full_signature,
|
||||
"compilation level adjustment out of bounds");
|
||||
_comp_level_adjustment = (CompLevelAdjustment) adjustment;
|
||||
_HotSpotJVMCIRuntime_initialized = true;
|
||||
_HotSpotJVMCIRuntime_instance = JNIHandles::make_global(result());
|
||||
_trivial_prefixes = prefixes;
|
||||
_trivial_prefixes_count = trivial_prefixes->length();
|
||||
}
|
||||
int adjustment = HotSpotJVMCIRuntime::compilationLevelAdjustment(result);
|
||||
assert(adjustment >= JVMCIRuntime::none &&
|
||||
adjustment <= JVMCIRuntime::by_full_signature,
|
||||
"compilation level adjustment out of bounds");
|
||||
_comp_level_adjustment = (CompLevelAdjustment) adjustment;
|
||||
_HotSpotJVMCIRuntime_initialized = true;
|
||||
_HotSpotJVMCIRuntime_instance = JNIHandles::make_global(result());
|
||||
}
|
||||
|
||||
void JVMCIRuntime::initialize_JVMCI(TRAPS) {
|
||||
|
@ -85,6 +85,7 @@ bool JVMCIGlobals::check_jvmci_flags_are_consistent() {
|
||||
CHECK_NOT_SET(JVMCIUseFastLocking, EnableJVMCI)
|
||||
CHECK_NOT_SET(JVMCINMethodSizeLimit, EnableJVMCI)
|
||||
CHECK_NOT_SET(MethodProfileWidth, EnableJVMCI)
|
||||
CHECK_NOT_SET(JVMCIPrintProperties, EnableJVMCI)
|
||||
CHECK_NOT_SET(TraceUncollectedSpeculations, EnableJVMCI)
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
@ -49,6 +49,9 @@
|
||||
experimental(bool, UseJVMCICompiler, false, \
|
||||
"Use JVMCI as the default compiler") \
|
||||
\
|
||||
experimental(bool, JVMCIPrintProperties, false, \
|
||||
"Prints properties used by the JVMCI compiler") \
|
||||
\
|
||||
experimental(bool, BootstrapJVMCI, false, \
|
||||
"Bootstrap JVMCI before running Java main method") \
|
||||
\
|
||||
|
@ -29,6 +29,7 @@
|
||||
#else
|
||||
#define JVMCI_WK_KLASSES_DO(do_klass) \
|
||||
/* JVMCI classes. These are loaded on-demand. */ \
|
||||
do_klass(JVMCI_klass, jdk_vm_ci_runtime_JVMCI, Jvmci) \
|
||||
do_klass(HotSpotCompiledCode_klass, jdk_vm_ci_hotspot_HotSpotCompiledCode, Jvmci) \
|
||||
do_klass(HotSpotCompiledCode_Comment_klass, jdk_vm_ci_hotspot_HotSpotCompiledCode_Comment, Jvmci) \
|
||||
do_klass(HotSpotCompiledNmethod_klass, jdk_vm_ci_hotspot_HotSpotCompiledNmethod, Jvmci) \
|
||||
|
@ -169,6 +169,8 @@
|
||||
nonstatic_field(JVMCIEnv, _task, CompileTask*) \
|
||||
nonstatic_field(JVMCIEnv, _jvmti_can_hotswap_or_post_breakpoint, bool) \
|
||||
\
|
||||
nonstatic_field(InvocationCounter, _counter, unsigned int) \
|
||||
\
|
||||
nonstatic_field(Klass, _secondary_super_cache, Klass*) \
|
||||
nonstatic_field(Klass, _secondary_supers, Array<Klass*>*) \
|
||||
nonstatic_field(Klass, _super, Klass*) \
|
||||
@ -199,13 +201,34 @@
|
||||
volatile_nonstatic_field(Method, _code, CompiledMethod*) \
|
||||
volatile_nonstatic_field(Method, _from_compiled_entry, address) \
|
||||
\
|
||||
nonstatic_field(MethodCounters, _nmethod_age, int) \
|
||||
nonstatic_field(MethodCounters, _interpreter_invocation_limit, int) \
|
||||
nonstatic_field(MethodCounters, _interpreter_backward_branch_limit, int) \
|
||||
nonstatic_field(MethodCounters, _interpreter_profile_limit, int) \
|
||||
nonstatic_field(MethodCounters, _invoke_mask, int) \
|
||||
nonstatic_field(MethodCounters, _backedge_mask, int) \
|
||||
nonstatic_field(MethodCounters, _interpreter_invocation_count, int) \
|
||||
nonstatic_field(MethodCounters, _interpreter_throwout_count, u2) \
|
||||
JVMTI_ONLY(nonstatic_field(MethodCounters, _number_of_breakpoints, u2)) \
|
||||
nonstatic_field(MethodCounters, _invocation_counter, InvocationCounter) \
|
||||
nonstatic_field(MethodCounters, _backedge_counter, InvocationCounter) \
|
||||
\
|
||||
nonstatic_field(MethodData, _size, int) \
|
||||
nonstatic_field(MethodData, _method, Method*) \
|
||||
nonstatic_field(MethodData, _data_size, int) \
|
||||
nonstatic_field(MethodData, _data[0], intptr_t) \
|
||||
nonstatic_field(MethodData, _parameters_type_data_di, int) \
|
||||
nonstatic_field(MethodData, _nof_decompiles, uint) \
|
||||
nonstatic_field(MethodData, _nof_overflow_recompiles, uint) \
|
||||
nonstatic_field(MethodData, _nof_overflow_traps, uint) \
|
||||
nonstatic_field(MethodData, _trap_hist._array[0], u1) \
|
||||
nonstatic_field(MethodData, _eflags, intx) \
|
||||
nonstatic_field(MethodData, _arg_local, intx) \
|
||||
nonstatic_field(MethodData, _arg_stack, intx) \
|
||||
nonstatic_field(MethodData, _arg_returned, intx) \
|
||||
nonstatic_field(MethodData, _tenure_traps, uint) \
|
||||
nonstatic_field(MethodData, _invoke_mask, int) \
|
||||
nonstatic_field(MethodData, _backedge_mask, int) \
|
||||
nonstatic_field(MethodData, _jvmci_ir_size, int) \
|
||||
\
|
||||
nonstatic_field(nmethod, _verified_entry_point, address) \
|
||||
@ -290,6 +313,7 @@
|
||||
declare_toplevel_type(ExceptionTableElement) \
|
||||
declare_toplevel_type(Flag) \
|
||||
declare_toplevel_type(Flag*) \
|
||||
declare_toplevel_type(InvocationCounter) \
|
||||
declare_toplevel_type(JVMCIEnv) \
|
||||
declare_toplevel_type(LocalVariableTableElement) \
|
||||
declare_toplevel_type(narrowKlass) \
|
||||
|
@ -29,6 +29,7 @@
|
||||
#define JVMCI_VM_SYMBOLS_DO(template, do_alias)
|
||||
#else
|
||||
#define JVMCI_VM_SYMBOLS_DO(template, do_alias) \
|
||||
template(jdk_vm_ci_runtime_JVMCI, "jdk/vm/ci/runtime/JVMCI") \
|
||||
template(jdk_vm_ci_hotspot_HotSpotCompiledCode, "jdk/vm/ci/hotspot/HotSpotCompiledCode") \
|
||||
template(jdk_vm_ci_hotspot_HotSpotCompiledCode_Comment, "jdk/vm/ci/hotspot/HotSpotCompiledCode$Comment") \
|
||||
template(jdk_vm_ci_hotspot_HotSpotCompiledNmethod, "jdk/vm/ci/hotspot/HotSpotCompiledNmethod") \
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -97,11 +97,7 @@ static bool is_regular_file(const char* filename) {
|
||||
if (ret != 0) {
|
||||
return false;
|
||||
}
|
||||
#ifdef _WINDOWS
|
||||
return (st.st_mode & S_IFMT) == _S_IFREG;
|
||||
#else
|
||||
return S_ISREG(st.st_mode);
|
||||
#endif
|
||||
return (st.st_mode & S_IFMT) == S_IFREG;
|
||||
}
|
||||
|
||||
// Try to find the next number that should be used for file rotation.
|
||||
|
@ -105,6 +105,7 @@
|
||||
LOG_TAG(scavenge) \
|
||||
LOG_TAG(scrub) \
|
||||
LOG_TAG(stacktrace) \
|
||||
LOG_TAG(stackwalk) \
|
||||
LOG_TAG(start) \
|
||||
LOG_TAG(startuptime) \
|
||||
LOG_TAG(state) \
|
||||
|
@ -263,7 +263,7 @@ void FileMapInfo::allocate_classpath_entry_table() {
|
||||
} else {
|
||||
struct stat st;
|
||||
if (os::stat(name, &st) == 0) {
|
||||
if ((st.st_mode & S_IFDIR) == S_IFDIR) {
|
||||
if ((st.st_mode & S_IFMT) == S_IFDIR) {
|
||||
if (!os::dir_is_empty(name)) {
|
||||
ClassLoader::exit_with_path_failure(
|
||||
"Cannot have non-empty directory in archived classpaths", name);
|
||||
|
@ -674,20 +674,20 @@ void InstanceKlass::link_methods(TRAPS) {
|
||||
|
||||
// Eagerly initialize superinterfaces that declare default methods (concrete instance: any access)
|
||||
void InstanceKlass::initialize_super_interfaces(instanceKlassHandle this_k, TRAPS) {
|
||||
assert (this_k->has_default_methods(), "caller should have checked this");
|
||||
assert (this_k->has_nonstatic_concrete_methods(), "caller should have checked this");
|
||||
for (int i = 0; i < this_k->local_interfaces()->length(); ++i) {
|
||||
Klass* iface = this_k->local_interfaces()->at(i);
|
||||
InstanceKlass* ik = InstanceKlass::cast(iface);
|
||||
|
||||
// Initialization is depth first search ie. we start with top of the inheritance tree
|
||||
// has_default_methods drives searching superinterfaces since it
|
||||
// means has_default_methods in its superinterface hierarchy
|
||||
if (ik->has_default_methods()) {
|
||||
// has_nonstatic_concrete_methods drives searching superinterfaces since it
|
||||
// means has_nonstatic_concrete_methods in its superinterface hierarchy
|
||||
if (ik->has_nonstatic_concrete_methods()) {
|
||||
ik->initialize_super_interfaces(ik, CHECK);
|
||||
}
|
||||
|
||||
// Only initialize() interfaces that "declare" concrete methods.
|
||||
if (ik->should_be_initialized() && ik->declares_default_methods()) {
|
||||
if (ik->should_be_initialized() && ik->declares_nonstatic_concrete_methods()) {
|
||||
ik->initialize(CHECK);
|
||||
}
|
||||
}
|
||||
@ -761,11 +761,11 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_k, TRAPS) {
|
||||
if (super_klass != NULL && super_klass->should_be_initialized()) {
|
||||
super_klass->initialize(THREAD);
|
||||
}
|
||||
// If C implements any interfaces that declares a non-abstract, non-static method,
|
||||
// If C implements any interface that declares a non-static, concrete method,
|
||||
// the initialization of C triggers initialization of its super interfaces.
|
||||
// Only need to recurse if has_default_methods which includes declaring and
|
||||
// inheriting default methods
|
||||
if (!HAS_PENDING_EXCEPTION && this_k->has_default_methods()) {
|
||||
// Only need to recurse if has_nonstatic_concrete_methods which includes declaring and
|
||||
// having a superinterface that declares, non-static, concrete methods
|
||||
if (!HAS_PENDING_EXCEPTION && this_k->has_nonstatic_concrete_methods()) {
|
||||
this_k->initialize_super_interfaces(this_k, THREAD);
|
||||
}
|
||||
|
||||
|
@ -207,18 +207,18 @@ class InstanceKlass: public Klass {
|
||||
|
||||
// Start after _misc_kind field.
|
||||
enum {
|
||||
_misc_rewritten = 1 << 2, // methods rewritten.
|
||||
_misc_has_nonstatic_fields = 1 << 3, // for sizing with UseCompressedOops
|
||||
_misc_should_verify_class = 1 << 4, // allow caching of preverification
|
||||
_misc_is_anonymous = 1 << 5, // has embedded _host_klass field
|
||||
_misc_is_contended = 1 << 6, // marked with contended annotation
|
||||
_misc_has_default_methods = 1 << 7, // class/superclass/implemented interfaces has default methods
|
||||
_misc_declares_default_methods = 1 << 8, // directly declares default methods (any access)
|
||||
_misc_has_been_redefined = 1 << 9, // class has been redefined
|
||||
_misc_is_scratch_class = 1 << 10, // class is the redefined scratch class
|
||||
_misc_is_shared_boot_class = 1 << 11, // defining class loader is boot class loader
|
||||
_misc_is_shared_platform_class = 1 << 12, // defining class loader is platform class loader
|
||||
_misc_is_shared_app_class = 1 << 13 // defining class loader is app class loader
|
||||
_misc_rewritten = 1 << 2, // methods rewritten.
|
||||
_misc_has_nonstatic_fields = 1 << 3, // for sizing with UseCompressedOops
|
||||
_misc_should_verify_class = 1 << 4, // allow caching of preverification
|
||||
_misc_is_anonymous = 1 << 5, // has embedded _host_klass field
|
||||
_misc_is_contended = 1 << 6, // marked with contended annotation
|
||||
_misc_has_nonstatic_concrete_methods = 1 << 7, // class/superclass/implemented interfaces has non-static, concrete methods
|
||||
_misc_declares_nonstatic_concrete_methods = 1 << 8, // directly declares non-static, concrete methods
|
||||
_misc_has_been_redefined = 1 << 9, // class has been redefined
|
||||
_misc_is_scratch_class = 1 << 10, // class is the redefined scratch class
|
||||
_misc_is_shared_boot_class = 1 << 11, // defining class loader is boot class loader
|
||||
_misc_is_shared_platform_class = 1 << 12, // defining class loader is platform class loader
|
||||
_misc_is_shared_app_class = 1 << 13 // defining class loader is app class loader
|
||||
};
|
||||
u2 loader_type_bits() {
|
||||
return _misc_is_shared_boot_class|_misc_is_shared_platform_class|_misc_is_shared_app_class;
|
||||
@ -814,25 +814,25 @@ public:
|
||||
|
||||
#endif // INCLUDE_JVMTI
|
||||
|
||||
bool has_default_methods() const {
|
||||
return (_misc_flags & _misc_has_default_methods) != 0;
|
||||
bool has_nonstatic_concrete_methods() const {
|
||||
return (_misc_flags & _misc_has_nonstatic_concrete_methods) != 0;
|
||||
}
|
||||
void set_has_default_methods(bool b) {
|
||||
void set_has_nonstatic_concrete_methods(bool b) {
|
||||
if (b) {
|
||||
_misc_flags |= _misc_has_default_methods;
|
||||
_misc_flags |= _misc_has_nonstatic_concrete_methods;
|
||||
} else {
|
||||
_misc_flags &= ~_misc_has_default_methods;
|
||||
_misc_flags &= ~_misc_has_nonstatic_concrete_methods;
|
||||
}
|
||||
}
|
||||
|
||||
bool declares_default_methods() const {
|
||||
return (_misc_flags & _misc_declares_default_methods) != 0;
|
||||
bool declares_nonstatic_concrete_methods() const {
|
||||
return (_misc_flags & _misc_declares_nonstatic_concrete_methods) != 0;
|
||||
}
|
||||
void set_declares_default_methods(bool b) {
|
||||
void set_declares_nonstatic_concrete_methods(bool b) {
|
||||
if (b) {
|
||||
_misc_flags |= _misc_declares_default_methods;
|
||||
_misc_flags |= _misc_declares_nonstatic_concrete_methods;
|
||||
} else {
|
||||
_misc_flags &= ~_misc_declares_default_methods;
|
||||
_misc_flags &= ~_misc_declares_nonstatic_concrete_methods;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,7 +226,7 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
|
||||
HandleMark hm(THREAD);
|
||||
assert(default_methods->at(i)->is_method(), "must be a Method*");
|
||||
methodHandle mh(THREAD, default_methods->at(i));
|
||||
|
||||
assert(!mh->is_private(), "private interface method in the default method list");
|
||||
bool needs_new_entry = update_inherited_vtable(ik(), mh, super_vtable_len, i, checkconstraints, CHECK);
|
||||
|
||||
// needs new entry
|
||||
@ -362,14 +362,16 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
|
||||
|
||||
Array<int>* def_vtable_indices = NULL;
|
||||
bool is_default = false;
|
||||
// default methods are concrete methods in superinterfaces which are added to the vtable
|
||||
// with their real method_holder
|
||||
|
||||
// default methods are non-private concrete methods in superinterfaces which are added
|
||||
// to the vtable with their real method_holder.
|
||||
// Since vtable and itable indices share the same storage, don't touch
|
||||
// the default method's real vtable/itable index
|
||||
// the default method's real vtable/itable index.
|
||||
// default_vtable_indices stores the vtable value relative to this inheritor
|
||||
if (default_index >= 0 ) {
|
||||
is_default = true;
|
||||
def_vtable_indices = klass->default_vtable_indices();
|
||||
assert(!target_method()->is_private(), "private interface method flagged as default");
|
||||
assert(def_vtable_indices != NULL, "def vtable alloc?");
|
||||
assert(default_index <= def_vtable_indices->length(), "def vtable len?");
|
||||
} else {
|
||||
@ -395,12 +397,15 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
|
||||
// This method will either be assigned its own itable index later,
|
||||
// or be assigned an inherited vtable index in the loop below.
|
||||
// default methods inherited by classes store their vtable indices
|
||||
// in the inheritor's default_vtable_indices
|
||||
// in the inheritor's default_vtable_indices.
|
||||
// default methods inherited by interfaces may already have a
|
||||
// valid itable index, if so, don't change it
|
||||
// overpass methods in an interface will be assigned an itable index later
|
||||
// by an inheriting class
|
||||
if (!is_default || !target_method()->has_itable_index()) {
|
||||
// valid itable index, if so, don't change it.
|
||||
// Overpass methods in an interface will be assigned an itable index later
|
||||
// by an inheriting class.
|
||||
// Private interface methods have no itable index and are always invoked nonvirtually,
|
||||
// so they retain their nonvirtual_vtable_index value, and therefore can_be_statically_bound()
|
||||
// will return true.
|
||||
if ((!is_default || !target_method()->has_itable_index()) && !target_method()->is_private()) {
|
||||
target_method()->set_vtable_index(Method::pending_itable_index);
|
||||
}
|
||||
}
|
||||
@ -597,7 +602,9 @@ bool klassVtable::needs_new_vtable_entry(methodHandle target_method,
|
||||
// abstract method entries using default inheritance rules
|
||||
if (target_method()->method_holder() != NULL &&
|
||||
target_method()->method_holder()->is_interface() &&
|
||||
!target_method()->is_abstract() ) {
|
||||
!target_method()->is_abstract()) {
|
||||
assert(target_method()->is_default_method() || target_method()->is_private(),
|
||||
"unexpected interface method type");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -606,10 +613,8 @@ bool klassVtable::needs_new_vtable_entry(methodHandle target_method,
|
||||
return true;
|
||||
}
|
||||
|
||||
// private methods in classes always have a new entry in the vtable
|
||||
// specification interpretation since classic has
|
||||
// private methods not overriding
|
||||
// JDK8 adds private methods in interfaces which require invokespecial
|
||||
// private methods in classes always have a new entry in the vtable.
|
||||
// Specification interpretation since classic has private methods not overriding.
|
||||
if (target_method()->is_private()) {
|
||||
return true;
|
||||
}
|
||||
@ -1088,6 +1093,7 @@ void klassItable::initialize_itable(bool checkconstraints, TRAPS) {
|
||||
inline bool interface_method_needs_itable_index(Method* m) {
|
||||
if (m->is_static()) return false; // e.g., Stream.empty
|
||||
if (m->is_initializer()) return false; // <init> or <clinit>
|
||||
if (m->is_private()) return false; // requires invokeSpecial
|
||||
// If an interface redeclares a method from java.lang.Object,
|
||||
// it should already have a vtable index, don't touch it.
|
||||
// e.g., CharSequence.toString (from initialize_vtable)
|
||||
|
@ -277,7 +277,8 @@ int Method::validate_bci_from_bcp(address bcp) const {
|
||||
}
|
||||
|
||||
address Method::bcp_from(int bci) const {
|
||||
assert((is_native() && bci == 0) || (!is_native() && 0 <= bci && bci < code_size()), "illegal bci: %d", bci);
|
||||
assert((is_native() && bci == 0) || (!is_native() && 0 <= bci && bci < code_size()),
|
||||
"illegal bci: %d for %s method", bci, is_native() ? "native" : "non-native");
|
||||
address bcp = code_base() + bci;
|
||||
assert(is_native() && bcp == code_base() || contains(bcp), "bcp doesn't belong to this method");
|
||||
return bcp;
|
||||
@ -558,7 +559,7 @@ bool Method::compute_has_loops_flag() {
|
||||
bool Method::is_final_method(AccessFlags class_access_flags) const {
|
||||
// or "does_not_require_vtable_entry"
|
||||
// default method or overpass can occur, is not final (reuses vtable entry)
|
||||
// private methods get vtable entries for backward class compatibility.
|
||||
// private methods in classes get vtable entries for backward class compatibility.
|
||||
if (is_overpass() || is_default_method()) return false;
|
||||
return is_final() || class_access_flags.is_final();
|
||||
}
|
||||
@ -570,7 +571,7 @@ bool Method::is_final_method() const {
|
||||
bool Method::is_default_method() const {
|
||||
if (method_holder() != NULL &&
|
||||
method_holder()->is_interface() &&
|
||||
!is_abstract()) {
|
||||
!is_abstract() && !is_private()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@ -583,7 +584,9 @@ bool Method::can_be_statically_bound(AccessFlags class_access_flags) const {
|
||||
ResourceMark rm;
|
||||
bool is_nonv = (vtable_index() == nonvirtual_vtable_index);
|
||||
if (class_access_flags.is_interface()) {
|
||||
assert(is_nonv == is_static(), "is_nonv=%s", name_and_sig_as_C_string());
|
||||
assert(is_nonv == is_static() || is_nonv == is_private(),
|
||||
"nonvirtual unexpected for non-static, non-private: %s",
|
||||
name_and_sig_as_C_string());
|
||||
}
|
||||
#endif
|
||||
assert(valid_vtable_index() || valid_itable_index(), "method must be linked before we ask this question");
|
||||
|
@ -584,6 +584,7 @@ class Method : public Metadata {
|
||||
// checks method and its method holder
|
||||
bool is_final_method() const;
|
||||
bool is_final_method(AccessFlags class_access_flags) const;
|
||||
// interface method declared with 'default' - excludes private interface methods
|
||||
bool is_default_method() const;
|
||||
|
||||
// true if method needs no dynamic dispatch (final and/or no vtable entry)
|
||||
|
@ -574,6 +574,10 @@ uint Compile::scratch_emit_size(const Node* n) {
|
||||
buf.consts()->initialize_shared_locs(&locs_buf[lsize * 0], lsize);
|
||||
buf.insts()->initialize_shared_locs( &locs_buf[lsize * 1], lsize);
|
||||
buf.stubs()->initialize_shared_locs( &locs_buf[lsize * 2], lsize);
|
||||
// Mark as scratch buffer.
|
||||
buf.consts()->set_scratch_emit();
|
||||
buf.insts()->set_scratch_emit();
|
||||
buf.stubs()->set_scratch_emit();
|
||||
|
||||
// Do the emission.
|
||||
|
||||
@ -2867,15 +2871,20 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) {
|
||||
addp->Opcode() == Op_ConP &&
|
||||
addp == n->in(AddPNode::Base) &&
|
||||
n->in(AddPNode::Offset)->is_Con()) {
|
||||
// If the transformation of ConP to ConN+DecodeN is beneficial depends
|
||||
// on the platform and on the compressed oops mode.
|
||||
// Use addressing with narrow klass to load with offset on x86.
|
||||
// On sparc loading 32-bits constant and decoding it have less
|
||||
// instructions (4) then load 64-bits constant (7).
|
||||
// Some platforms can use the constant pool to load ConP.
|
||||
// Do this transformation here since IGVN will convert ConN back to ConP.
|
||||
const Type* t = addp->bottom_type();
|
||||
if (t->isa_oopptr() || t->isa_klassptr()) {
|
||||
bool is_oop = t->isa_oopptr() != NULL;
|
||||
bool is_klass = t->isa_klassptr() != NULL;
|
||||
|
||||
if ((is_oop && Matcher::const_oop_prefer_decode() ) ||
|
||||
(is_klass && Matcher::const_klass_prefer_decode())) {
|
||||
Node* nn = NULL;
|
||||
|
||||
int op = t->isa_oopptr() ? Op_ConN : Op_ConNKlass;
|
||||
int op = is_oop ? Op_ConN : Op_ConNKlass;
|
||||
|
||||
// Look for existing ConN node of the same exact type.
|
||||
Node* r = root();
|
||||
@ -2891,7 +2900,7 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) {
|
||||
if (nn != NULL) {
|
||||
// Decode a narrow oop to match address
|
||||
// [R12 + narrow_oop_reg<<3 + offset]
|
||||
if (t->isa_oopptr()) {
|
||||
if (is_oop) {
|
||||
nn = new DecodeNNode(nn, t);
|
||||
} else {
|
||||
nn = new DecodeNKlassNode(nn, t);
|
||||
|
@ -457,6 +457,9 @@ public:
|
||||
static bool narrow_oop_use_complex_address();
|
||||
static bool narrow_klass_use_complex_address();
|
||||
|
||||
static bool const_oop_prefer_decode();
|
||||
static bool const_klass_prefer_decode();
|
||||
|
||||
// Generate implicit null check for narrow oops if it can fold
|
||||
// into address expression (x64).
|
||||
//
|
||||
|
@ -1173,7 +1173,7 @@ static void jni_invoke_nonstatic(JNIEnv *env, JavaValue* result, jobject receive
|
||||
args->set_java_argument_object(&java_args);
|
||||
|
||||
// handle arguments
|
||||
assert(!method->is_static(), "method should not be static");
|
||||
assert(!method->is_static(), "method %s should not be static", method->name_and_sig_as_C_string());
|
||||
args->push_receiver(h_recv); // Push jobject handle
|
||||
|
||||
// Fill out JavaCallArguments object
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "classfile/javaClasses.inline.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/objArrayOop.inline.hpp"
|
||||
@ -105,10 +106,8 @@ int StackWalk::fill_in_frames(jlong mode, BaseFrameStream& stream,
|
||||
int max_nframes, int start_index,
|
||||
objArrayHandle frames_array,
|
||||
int& end_index, TRAPS) {
|
||||
if (TraceStackWalk) {
|
||||
tty->print_cr("fill_in_frames limit=%d start=%d frames length=%d",
|
||||
max_nframes, start_index, frames_array->length());
|
||||
}
|
||||
log_debug(stackwalk)("fill_in_frames limit=%d start=%d frames length=%d",
|
||||
max_nframes, start_index, frames_array->length());
|
||||
assert(max_nframes > 0, "invalid max_nframes");
|
||||
assert(start_index + max_nframes <= frames_array->length(), "oob");
|
||||
|
||||
@ -122,18 +121,24 @@ int StackWalk::fill_in_frames(jlong mode, BaseFrameStream& stream,
|
||||
// not set) and when StackWalker::getCallerClass is called
|
||||
if (!ShowHiddenFrames && (skip_hidden_frames(mode) || get_caller_class(mode))) {
|
||||
if (method->is_hidden()) {
|
||||
if (TraceStackWalk) {
|
||||
tty->print(" hidden method: "); method->print_short_name();
|
||||
tty->print("\n");
|
||||
if (log_is_enabled(Debug, stackwalk)) {
|
||||
ResourceMark rm(THREAD);
|
||||
outputStream* st = Log(stackwalk)::debug_stream();
|
||||
st->print(" hidden method: ");
|
||||
method->print_short_name(st);
|
||||
st->cr();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
int index = end_index++;
|
||||
if (TraceStackWalk) {
|
||||
tty->print(" %d: frame method: ", index); method->print_short_name();
|
||||
tty->print_cr(" bci=%d", stream.bci());
|
||||
if (log_is_enabled(Debug, stackwalk)) {
|
||||
ResourceMark rm(THREAD);
|
||||
outputStream* st = Log(stackwalk)::debug_stream();
|
||||
st->print(" %d: frame method: ", index);
|
||||
method->print_short_name(st);
|
||||
st->print_cr(" bci=%d", stream.bci());
|
||||
}
|
||||
|
||||
if (!need_method_info(mode) && get_caller_class(mode) &&
|
||||
@ -317,10 +322,8 @@ oop StackWalk::walk(Handle stackStream, jlong mode,
|
||||
TRAPS) {
|
||||
ResourceMark rm(THREAD);
|
||||
JavaThread* jt = (JavaThread*)THREAD;
|
||||
if (TraceStackWalk) {
|
||||
tty->print_cr("Start walking: mode " JLONG_FORMAT " skip %d frames batch size %d",
|
||||
mode, skip_frames, frame_count);
|
||||
}
|
||||
log_debug(stackwalk)("Start walking: mode " JLONG_FORMAT " skip %d frames batch size %d",
|
||||
mode, skip_frames, frame_count);
|
||||
|
||||
if (frames_array.is_null()) {
|
||||
THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", NULL);
|
||||
@ -355,8 +358,12 @@ oop StackWalk::fetchFirstBatch(BaseFrameStream& stream, Handle stackStream,
|
||||
break;
|
||||
}
|
||||
|
||||
if (TraceStackWalk) {
|
||||
tty->print(" skip "); stream.method()->print_short_name(); tty->print("\n");
|
||||
if (log_is_enabled(Debug, stackwalk)) {
|
||||
ResourceMark rm(THREAD);
|
||||
outputStream* st = Log(stackwalk)::debug_stream();
|
||||
st->print(" skip ");
|
||||
stream.method()->print_short_name(st);
|
||||
st->cr();
|
||||
}
|
||||
stream.next();
|
||||
}
|
||||
@ -364,8 +371,12 @@ oop StackWalk::fetchFirstBatch(BaseFrameStream& stream, Handle stackStream,
|
||||
// stack frame has been traversed individually and resume stack walk
|
||||
// from the stack frame at depth == skip_frames.
|
||||
for (int n=0; n < skip_frames && !stream.at_end(); stream.next(), n++) {
|
||||
if (TraceStackWalk) {
|
||||
tty->print(" skip "); stream.method()->print_short_name(); tty->cr();
|
||||
if (log_is_enabled(Debug, stackwalk)) {
|
||||
ResourceMark rm(THREAD);
|
||||
outputStream* st = Log(stackwalk)::debug_stream();
|
||||
st->print(" skip ");
|
||||
stream.method()->print_short_name(st);
|
||||
st->cr();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -438,10 +449,9 @@ jint StackWalk::fetchNextBatch(Handle stackStream, jlong mode, jlong magic,
|
||||
THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", 0L);
|
||||
}
|
||||
|
||||
if (TraceStackWalk) {
|
||||
tty->print_cr("StackWalk::fetchNextBatch frame_count %d existing_stream " PTR_FORMAT " start %d frames %d",
|
||||
frame_count, p2i(existing_stream), start_index, frames_array->length());
|
||||
}
|
||||
log_debug(stackwalk)("StackWalk::fetchNextBatch frame_count %d existing_stream "
|
||||
PTR_FORMAT " start %d frames %d",
|
||||
frame_count, p2i(existing_stream), start_index, frames_array->length());
|
||||
int end_index = start_index;
|
||||
if (frame_count <= 0) {
|
||||
return end_index; // No operation.
|
||||
|
@ -2887,9 +2887,6 @@ public:
|
||||
"exceptions (0 means all)") \
|
||||
range(0, max_jint/2) \
|
||||
\
|
||||
develop(bool, TraceStackWalk, false, \
|
||||
"Trace stack walking") \
|
||||
\
|
||||
/* notice: the max range value here is max_jint, not max_intx */ \
|
||||
/* because of overflow issue */ \
|
||||
diagnostic(intx, GuaranteedSafepointInterval, 1000, \
|
||||
|
@ -3768,10 +3768,21 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
|
||||
SystemDictionary::compute_java_system_loader(CHECK_(JNI_ERR));
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
if (EnableJVMCI && UseJVMCICompiler && (!UseInterpreter || !BackgroundCompilation)) {
|
||||
// 8145270: Force initialization of JVMCI runtime otherwise requests for blocking
|
||||
// compilations via JVMCI will not actually block until JVMCI is initialized.
|
||||
JVMCIRuntime::force_initialization(CHECK_JNI_ERR);
|
||||
if (EnableJVMCI) {
|
||||
// Initialize JVMCI eagerly if JVMCIPrintProperties is enabled.
|
||||
// The JVMCI Java initialization code will read this flag and
|
||||
// do the printing if it's set.
|
||||
bool init = JVMCIPrintProperties;
|
||||
|
||||
if (!init) {
|
||||
// 8145270: Force initialization of JVMCI runtime otherwise requests for blocking
|
||||
// compilations via JVMCI will not actually block until JVMCI is initialized.
|
||||
init = UseJVMCICompiler && (!UseInterpreter || !BackgroundCompilation);
|
||||
}
|
||||
|
||||
if (init) {
|
||||
JVMCIRuntime::force_initialization(CHECK_JNI_ERR);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -58,24 +58,7 @@ void InternalVMTests::run() {
|
||||
run_unit_test(TestNewSize_test);
|
||||
run_unit_test(TestOldSize_test);
|
||||
run_unit_test(TestBitMap_test);
|
||||
run_unit_test(TestResourcehash_test);
|
||||
run_unit_test(ObjectMonitor_test);
|
||||
run_unit_test(Test_log_tag_combinations_limit);
|
||||
run_unit_test(Test_logtarget);
|
||||
run_unit_test(Test_logstream);
|
||||
run_unit_test(Test_loghandle);
|
||||
run_unit_test(Test_logtargethandle);
|
||||
run_unit_test(Test_log_gctracetime);
|
||||
run_unit_test(Test_configure_stdout);
|
||||
run_unit_test(Test_logconfiguration_subscribe);
|
||||
run_unit_test(Test_log_prefix);
|
||||
run_unit_test(Test_log_big);
|
||||
run_unit_test(Test_logtagset_duplicates);
|
||||
run_unit_test(Test_logtagset_descriptions);
|
||||
run_unit_test(Test_log_file_startup_rotation);
|
||||
run_unit_test(Test_log_file_startup_truncation);
|
||||
run_unit_test(Test_invalid_log_file);
|
||||
run_unit_test(Test_multiline_logging);
|
||||
run_unit_test(DirectivesParser_test);
|
||||
#if INCLUDE_VM_STRUCTS
|
||||
run_unit_test(VMStructs_test);
|
||||
|
@ -1,182 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/resourceHash.hpp"
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
/////////////// Unit tests ///////////////
|
||||
|
||||
class TestResourceHashtable : public AllStatic {
|
||||
typedef void* K;
|
||||
typedef int V;
|
||||
|
||||
static unsigned identity_hash(const K& k) {
|
||||
return (unsigned)(uintptr_t)k;
|
||||
}
|
||||
|
||||
static unsigned bad_hash(const K& k) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
class EqualityTestIter {
|
||||
public:
|
||||
bool do_entry(K const& k, V const& v) {
|
||||
assert((uintptr_t)k == (uintptr_t)v, "");
|
||||
return true; // continue iteration
|
||||
}
|
||||
};
|
||||
|
||||
template<
|
||||
unsigned (*HASH) (K const&) = primitive_hash<K>,
|
||||
bool (*EQUALS)(K const&, K const&) = primitive_equals<K>,
|
||||
unsigned SIZE = 256,
|
||||
ResourceObj::allocation_type ALLOC_TYPE = ResourceObj::RESOURCE_AREA,
|
||||
MEMFLAGS MEM_TYPE = mtInternal
|
||||
>
|
||||
class Runner : public AllStatic {
|
||||
static void* as_K(uintptr_t val) { return (void*)val; }
|
||||
|
||||
public:
|
||||
static void test_small() {
|
||||
EqualityTestIter et;
|
||||
ResourceHashtable<K, V, HASH, EQUALS, SIZE, ALLOC_TYPE, MEM_TYPE> rh;
|
||||
|
||||
assert(!rh.contains(as_K(0x1)), "");
|
||||
|
||||
assert(rh.put(as_K(0x1), 0x1), "");
|
||||
assert(rh.contains(as_K(0x1)), "");
|
||||
|
||||
assert(!rh.put(as_K(0x1), 0x1), "");
|
||||
|
||||
assert(rh.put(as_K(0x2), 0x2), "");
|
||||
assert(rh.put(as_K(0x3), 0x3), "");
|
||||
assert(rh.put(as_K(0x4), 0x4), "");
|
||||
assert(rh.put(as_K(0x5), 0x5), "");
|
||||
|
||||
assert(!rh.remove(as_K(0x0)), "");
|
||||
rh.iterate(&et);
|
||||
|
||||
assert(rh.remove(as_K(0x1)), "");
|
||||
rh.iterate(&et);
|
||||
|
||||
}
|
||||
|
||||
// We use keys with the low bits cleared since the default hash will do some shifting
|
||||
static void test_small_shifted() {
|
||||
EqualityTestIter et;
|
||||
ResourceHashtable<K, V, HASH, EQUALS, SIZE, ALLOC_TYPE, MEM_TYPE> rh;
|
||||
|
||||
assert(!rh.contains(as_K(0x10)), "");
|
||||
|
||||
assert(rh.put(as_K(0x10), 0x10), "");
|
||||
assert(rh.contains(as_K(0x10)), "");
|
||||
|
||||
assert(!rh.put(as_K(0x10), 0x10), "");
|
||||
|
||||
assert(rh.put(as_K(0x20), 0x20), "");
|
||||
assert(rh.put(as_K(0x30), 0x30), "");
|
||||
assert(rh.put(as_K(0x40), 0x40), "");
|
||||
assert(rh.put(as_K(0x50), 0x50), "");
|
||||
|
||||
assert(!rh.remove(as_K(0x00)), "");
|
||||
|
||||
assert(rh.remove(as_K(0x10)), "");
|
||||
|
||||
rh.iterate(&et);
|
||||
}
|
||||
|
||||
static void test(unsigned num_elements = SIZE) {
|
||||
EqualityTestIter et;
|
||||
ResourceHashtable<K, V, HASH, EQUALS, SIZE, ALLOC_TYPE, MEM_TYPE> rh;
|
||||
|
||||
for (uintptr_t i = 0; i < num_elements; ++i) {
|
||||
assert(rh.put(as_K(i), i), "");
|
||||
}
|
||||
|
||||
rh.iterate(&et);
|
||||
|
||||
for (uintptr_t i = num_elements; i > 0; --i) {
|
||||
uintptr_t index = i - 1;
|
||||
assert(rh.remove(as_K(index)), "");
|
||||
}
|
||||
rh.iterate(&et);
|
||||
for (uintptr_t i = num_elements; i > 0; --i) {
|
||||
uintptr_t index = i - 1;
|
||||
assert(!rh.remove(as_K(index)), "");
|
||||
}
|
||||
rh.iterate(&et);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
static void run_tests() {
|
||||
{
|
||||
ResourceMark rm;
|
||||
Runner<>::test_small();
|
||||
Runner<>::test_small_shifted();
|
||||
Runner<>::test();
|
||||
}
|
||||
|
||||
{
|
||||
ResourceMark rm;
|
||||
Runner<identity_hash>::test_small();
|
||||
Runner<identity_hash>::test_small_shifted();
|
||||
Runner<identity_hash>::test();
|
||||
}
|
||||
|
||||
{
|
||||
ResourceMark rm;
|
||||
Runner<bad_hash>::test_small();
|
||||
Runner<bad_hash>::test_small_shifted();
|
||||
Runner<bad_hash>::test();
|
||||
}
|
||||
|
||||
|
||||
assert(Thread::current()->resource_area()->nesting() == 0, "this code depends on not having an active ResourceMark");
|
||||
// The following test calls will cause an assert if resource allocations occur since we don't have an active mark
|
||||
Runner<primitive_hash<K>, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test_small();
|
||||
Runner<primitive_hash<K>, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test_small_shifted();
|
||||
Runner<primitive_hash<K>, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test();
|
||||
|
||||
Runner<bad_hash, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test_small();
|
||||
Runner<bad_hash, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test_small_shifted();
|
||||
Runner<bad_hash, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test();
|
||||
|
||||
Runner<identity_hash, primitive_equals<K>, 1, ResourceObj::C_HEAP>::test_small();
|
||||
Runner<identity_hash, primitive_equals<K>, 1, ResourceObj::C_HEAP>::test_small_shifted();
|
||||
Runner<identity_hash, primitive_equals<K>, 1, ResourceObj::C_HEAP>::test(512);
|
||||
}
|
||||
};
|
||||
|
||||
void TestResourcehash_test() {
|
||||
TestResourceHashtable::run_tests();
|
||||
}
|
||||
|
||||
#endif // not PRODUCT
|
||||
|
50
hotspot/test/compiler/jvmci/TestJVMCIPrintProperties.java
Normal file
50
hotspot/test/compiler/jvmci/TestJVMCIPrintProperties.java
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, 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 TestBasicLogOutput
|
||||
* @summary Ensure -XX:-JVMCIPrintProperties can be enabled and successfully prints expected output to stdout.
|
||||
* @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
|
||||
* @library /test/lib
|
||||
*/
|
||||
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
public class TestJVMCIPrintProperties {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
||||
"-XX:+UnlockExperimentalVMOptions",
|
||||
"-XX:+EnableJVMCI",
|
||||
"-XX:+JVMCIPrintProperties",
|
||||
"-version");
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("[JVMCI properties]"); // expected message
|
||||
output.shouldContain("String jvmci.Compiler"); // expected message
|
||||
output.shouldContain("Boolean jvmci.InitTimer"); // expected message
|
||||
output.shouldContain("Boolean jvmci.PrintConfig"); // expected message
|
||||
output.shouldContain("String jvmci.TraceMethodDataFilter"); // expected message
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
TEST(SymbolTable, temp_new_symbol) {
|
||||
TEST_VM(SymbolTable, temp_new_symbol) {
|
||||
// Assert messages assume these symbols are unique, and the refcounts start at
|
||||
// one, but code does not rely on this.
|
||||
JavaThread* THREAD = JavaThread::current();
|
||||
|
@ -34,20 +34,34 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
static int init_jvm(int argc, char **argv, bool is_executing_death_test) {
|
||||
static bool is_prefix(const char* prefix, const char* str) {
|
||||
return strncmp(str, prefix, strlen(prefix)) == 0;
|
||||
}
|
||||
|
||||
static bool is_suffix(const char* suffix, const char* str) {
|
||||
size_t suffix_len = strlen(suffix);
|
||||
size_t str_len = strlen(str);
|
||||
if (str_len < suffix_len) {
|
||||
return false;
|
||||
}
|
||||
return strncmp(str + (str_len - suffix_len), suffix, suffix_len) == 0;
|
||||
}
|
||||
|
||||
|
||||
static int init_jvm(int argc, char **argv, bool disable_error_handling) {
|
||||
// don't care about the program name
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
int extra_jvm_args = is_executing_death_test ? 4 : 2;
|
||||
int extra_jvm_args = disable_error_handling ? 4 : 2;
|
||||
int num_jvm_options = argc + extra_jvm_args;
|
||||
|
||||
JavaVMOption* options = new JavaVMOption[num_jvm_options];
|
||||
options[0].optionString = (char*) "-Dsun.java.launcher.is_altjvm=true";
|
||||
options[1].optionString = (char*) "-XX:+ExecutingUnitTests";
|
||||
|
||||
if (is_executing_death_test) {
|
||||
// don't create core files or hs_err files when executing death tests
|
||||
if (disable_error_handling) {
|
||||
// don't create core files or hs_err files executing assert tests
|
||||
options[2].optionString = (char*) "-XX:+SuppressFatalErrorMessage";
|
||||
options[3].optionString = (char*) "-XX:-CreateCoredumpOnCrash";
|
||||
}
|
||||
@ -83,17 +97,14 @@ class JVMInitializerListener : public ::testing::EmptyTestEventListener {
|
||||
|
||||
virtual void OnTestStart(const ::testing::TestInfo& test_info) {
|
||||
const char* name = test_info.name();
|
||||
if (strstr(name, "_test_vm") != NULL && !_is_initialized) {
|
||||
ASSERT_EQ(init_jvm(_argc, _argv, false), 0) << "Could not initialize the JVM";
|
||||
if (!_is_initialized && is_suffix("_test_vm", name)) {
|
||||
// we want to have hs_err and core files when we execute regular tests
|
||||
ASSERT_EQ(0, init_jvm(_argc, _argv, false)) << "Could not initialize the JVM";
|
||||
_is_initialized = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static bool is_prefix(const char* prefix, const char* str) {
|
||||
return strncmp(str, prefix, strlen(prefix)) == 0;
|
||||
}
|
||||
|
||||
static char* get_java_home_arg(int argc, char** argv) {
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (strncmp(argv[i], "-jdk", strlen(argv[i])) == 0) {
|
||||
@ -144,19 +155,23 @@ static char** remove_test_runner_arguments(int* argcp, char **argv) {
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL runUnitTests(int argc, char** argv) {
|
||||
// Must look at googletest options before initializing googletest, since
|
||||
// InitGoogleTest removes googletest options from argv.
|
||||
bool is_executing_death_test = true;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
const char* death_test_flag = "--gtest_internal_run_death_test";
|
||||
if (is_prefix(death_test_flag, argv[i])) {
|
||||
is_executing_death_test = true;
|
||||
}
|
||||
}
|
||||
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
::testing::GTEST_FLAG(death_test_style) = "threadsafe";
|
||||
// ::testing::GTEST_FLAG(death_test_output_prefix) = "Other VM";
|
||||
|
||||
bool is_vmassert_test = false;
|
||||
bool is_othervm_test = false;
|
||||
// death tests facility is used for both regular death tests, other vm and vmassert tests
|
||||
if (::testing::internal::GTEST_FLAG(internal_run_death_test).length() > 0) {
|
||||
// when we execute death test, filter value equals to test name
|
||||
const char* test_name = ::testing::GTEST_FLAG(filter).c_str();
|
||||
const char* const othervm_suffix = "_other_vm_test"; // TEST_OTHER_VM
|
||||
const char* const vmassert_suffix = "_vm_assert_test"; // TEST_VM_ASSERT(_MSG)
|
||||
if (is_suffix(othervm_suffix, test_name)) {
|
||||
is_othervm_test = true;
|
||||
} else if (is_suffix(vmassert_suffix, test_name)) {
|
||||
is_vmassert_test = true;
|
||||
}
|
||||
}
|
||||
|
||||
char* java_home = get_java_home_arg(argc, argv);
|
||||
if (java_home == NULL) {
|
||||
@ -184,8 +199,10 @@ JNIEXPORT void JNICALL runUnitTests(int argc, char** argv) {
|
||||
#endif // _WIN32
|
||||
argv = remove_test_runner_arguments(&argc, argv);
|
||||
|
||||
if (is_executing_death_test) {
|
||||
if (init_jvm(argc, argv, true) != 0) {
|
||||
if (is_vmassert_test || is_othervm_test) {
|
||||
// both vmassert and other vm tests require inited jvm
|
||||
// but only vmassert tests disable hs_err and core file generation
|
||||
if (init_jvm(argc, argv, is_vmassert_test) != 0) {
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
|
@ -21,6 +21,10 @@
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logConfiguration.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
@ -43,3 +47,74 @@ static inline void delete_file(const char* filename) {
|
||||
EXPECT_TRUE(ret == 0 || errno == ENOENT) << "failed to remove file '" << filename << "': "
|
||||
<< os::strerror(errno) << " (" << errno << ")";
|
||||
}
|
||||
|
||||
static inline void create_directory(const char* name) {
|
||||
assert(!file_exists(name), "can't create directory: %s already exists", name);
|
||||
bool failed;
|
||||
#ifdef _WINDOWS
|
||||
failed = !CreateDirectory(name, NULL);
|
||||
#else
|
||||
failed = mkdir(name, 0777);
|
||||
#endif
|
||||
assert(!failed, "failed to create directory %s", name);
|
||||
}
|
||||
|
||||
static inline void init_log_file(const char* filename, const char* options = "") {
|
||||
LogStreamHandle(Error, logging) stream;
|
||||
bool success = LogConfiguration::parse_log_arguments(filename, "logging=trace", "", options, &stream);
|
||||
guarantee(success, "Failed to initialize log file '%s' with options '%s'", filename, options);
|
||||
log_debug(logging)("%s", LOG_TEST_STRING_LITERAL);
|
||||
success = LogConfiguration::parse_log_arguments(filename, "all=off", "", "", &stream);
|
||||
guarantee(success, "Failed to disable logging to file '%s'", filename);
|
||||
}
|
||||
|
||||
// Read a complete line from fp and return it as a resource allocated string.
|
||||
// Returns NULL on EOF.
|
||||
static inline char* read_line(FILE* fp) {
|
||||
assert(fp != NULL, "invalid fp");
|
||||
int buflen = 512;
|
||||
char* buf = NEW_RESOURCE_ARRAY(char, buflen);
|
||||
long pos = ftell(fp);
|
||||
|
||||
char* ret = fgets(buf, buflen, fp);
|
||||
while (ret != NULL && buf[strlen(buf) - 1] != '\n' && !feof(fp)) {
|
||||
// retry with a larger buffer
|
||||
buf = REALLOC_RESOURCE_ARRAY(char, buf, buflen, buflen * 2);
|
||||
buflen *= 2;
|
||||
// rewind to beginning of line
|
||||
fseek(fp, pos, SEEK_SET);
|
||||
// retry read with new buffer
|
||||
ret = fgets(buf, buflen, fp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool file_contains_substrings_in_order(const char* filename, const char* substrs[]) {
|
||||
FILE* fp = fopen(filename, "r");
|
||||
assert(fp != NULL, "error opening file %s: %s", filename, strerror(errno));
|
||||
|
||||
size_t idx = 0;
|
||||
while (substrs[idx] != NULL) {
|
||||
ResourceMark rm;
|
||||
char* line = read_line(fp);
|
||||
if (line == NULL) {
|
||||
break;
|
||||
}
|
||||
for (char* match = strstr(line, substrs[idx]); match != NULL;) {
|
||||
size_t match_len = strlen(substrs[idx]);
|
||||
idx++;
|
||||
if (substrs[idx] == NULL) {
|
||||
break;
|
||||
}
|
||||
match = strstr(match + match_len, substrs[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return substrs[idx] == NULL;
|
||||
}
|
||||
|
||||
static inline bool file_contains_substring(const char* filename, const char* substr) {
|
||||
const char* strs[] = {substr, NULL};
|
||||
return file_contains_substrings_in_order(filename, strs);
|
||||
}
|
||||
|
162
hotspot/test/native/logging/test_gcTraceTime.cpp
Normal file
162
hotspot/test/native/logging/test_gcTraceTime.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "logTestFixture.hpp"
|
||||
#include "logTestUtils.inline.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "runtime/interfaceSupport.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
class GCTraceTimeTest : public LogTestFixture {
|
||||
};
|
||||
|
||||
TEST_VM_F(GCTraceTimeTest, full) {
|
||||
set_log_config(TestLogFileName, "gc=debug,gc+start=debug");
|
||||
|
||||
LogTarget(Debug, gc) gc_debug;
|
||||
LogTarget(Debug, gc, start) gc_start_debug;
|
||||
|
||||
EXPECT_TRUE(gc_debug.is_enabled());
|
||||
EXPECT_TRUE(gc_start_debug.is_enabled());
|
||||
|
||||
{
|
||||
ThreadInVMfromNative tvn(JavaThread::current());
|
||||
MutexLocker lock(Heap_lock); // Needed to read heap usage
|
||||
GCTraceTime(Debug, gc) timer("Test GC", NULL, GCCause::_allocation_failure, true);
|
||||
}
|
||||
|
||||
const char* expected[] = {
|
||||
"[gc,start", "] Test GC (Allocation Failure) (", "s)",
|
||||
"[gc", "] Test GC (Allocation Failure) ", "M) (", "s, ", "s) ", "ms",
|
||||
NULL
|
||||
};
|
||||
EXPECT_TRUE(file_contains_substrings_in_order(TestLogFileName, expected));
|
||||
}
|
||||
|
||||
TEST_VM_F(GCTraceTimeTest, full_multitag) {
|
||||
set_log_config(TestLogFileName, "gc+ref=debug,gc+ref+start=debug");
|
||||
|
||||
LogTarget(Debug, gc, ref) gc_debug;
|
||||
LogTarget(Debug, gc, ref, start) gc_start_debug;
|
||||
|
||||
EXPECT_TRUE(gc_debug.is_enabled());
|
||||
EXPECT_TRUE(gc_start_debug.is_enabled());
|
||||
|
||||
{
|
||||
ThreadInVMfromNative tvn(JavaThread::current());
|
||||
MutexLocker lock(Heap_lock); // Needed to read heap usage
|
||||
GCTraceTime(Debug, gc, ref) timer("Test GC", NULL, GCCause::_allocation_failure, true);
|
||||
}
|
||||
|
||||
const char* expected[] = {
|
||||
"[gc,ref,start", "] Test GC (Allocation Failure) (", "s)",
|
||||
"[gc,ref", "] Test GC (Allocation Failure) ", "M) (", "s, ", "s) ", "ms",
|
||||
NULL
|
||||
};
|
||||
EXPECT_TRUE(file_contains_substrings_in_order(TestLogFileName, expected));
|
||||
}
|
||||
|
||||
TEST_VM_F(GCTraceTimeTest, no_heap) {
|
||||
set_log_config(TestLogFileName, "gc=debug,gc+start=debug");
|
||||
|
||||
LogTarget(Debug, gc) gc_debug;
|
||||
LogTarget(Debug, gc, start) gc_start_debug;
|
||||
|
||||
EXPECT_TRUE(gc_debug.is_enabled());
|
||||
EXPECT_TRUE(gc_start_debug.is_enabled());
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc) timer("Test GC", NULL, GCCause::_allocation_failure, false);
|
||||
}
|
||||
|
||||
const char* expected[] = {
|
||||
// [2.975s][debug][gc,start] Test GC (Allocation Failure) (2.975s)
|
||||
"[gc,start", "] Test GC (Allocation Failure) (", "s)",
|
||||
// [2.975s][debug][gc ] Test GC (Allocation Failure) (2.975s, 2.975s) 0.026ms
|
||||
"[gc", "] Test GC (Allocation Failure) ", "(", "s, ", "s) ", "ms",
|
||||
NULL
|
||||
};
|
||||
EXPECT_TRUE(file_contains_substrings_in_order(TestLogFileName, expected));
|
||||
|
||||
const char* not_expected[] = {
|
||||
// [2.975s][debug][gc ] Test GC 59M->59M(502M) (2.975s, 2.975s) 0.026ms
|
||||
"[gc", "] Test GC ", "M) (", "s, ", "s) ", "ms",
|
||||
};
|
||||
EXPECT_FALSE(file_contains_substrings_in_order(TestLogFileName, not_expected));
|
||||
}
|
||||
|
||||
TEST_VM_F(GCTraceTimeTest, no_cause) {
|
||||
set_log_config(TestLogFileName, "gc=debug,gc+start=debug");
|
||||
|
||||
LogTarget(Debug, gc) gc_debug;
|
||||
LogTarget(Debug, gc, start) gc_start_debug;
|
||||
|
||||
EXPECT_TRUE(gc_debug.is_enabled());
|
||||
EXPECT_TRUE(gc_start_debug.is_enabled());
|
||||
|
||||
{
|
||||
ThreadInVMfromNative tvn(JavaThread::current());
|
||||
MutexLocker lock(Heap_lock); // Needed to read heap usage
|
||||
GCTraceTime(Debug, gc) timer("Test GC", NULL, GCCause::_no_gc, true);
|
||||
}
|
||||
|
||||
const char* expected[] = {
|
||||
// [2.975s][debug][gc,start] Test GC (2.975s)
|
||||
"[gc,start", "] Test GC ", "s)",
|
||||
// [2.975s][debug][gc ] Test GC 59M->59M(502M) (2.975s, 2.975s) 0.026ms
|
||||
"[gc", "] Test GC ", "M) (", "s, ", "s) ", "ms",
|
||||
NULL
|
||||
};
|
||||
EXPECT_TRUE(file_contains_substrings_in_order(TestLogFileName, expected));
|
||||
}
|
||||
|
||||
TEST_VM_F(GCTraceTimeTest, no_heap_no_cause) {
|
||||
set_log_config(TestLogFileName, "gc=debug,gc+start=debug");
|
||||
|
||||
LogTarget(Debug, gc) gc_debug;
|
||||
LogTarget(Debug, gc, start) gc_start_debug;
|
||||
|
||||
EXPECT_TRUE(gc_debug.is_enabled());
|
||||
EXPECT_TRUE(gc_start_debug.is_enabled());
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc) timer("Test GC", NULL, GCCause::_no_gc, false);
|
||||
}
|
||||
|
||||
const char* expected[] = {
|
||||
// [2.975s][debug][gc,start] Test GC (2.975s)
|
||||
"[gc,start", "] Test GC ", "s)",
|
||||
// [2.975s][debug][gc ] Test GC (2.975s, 2.975s) 0.026ms
|
||||
"[gc", "] Test GC ", "(", "s, ", "s) ", "ms",
|
||||
NULL
|
||||
};
|
||||
EXPECT_TRUE(file_contains_substrings_in_order(TestLogFileName, expected));
|
||||
|
||||
const char* not_expected[] = {
|
||||
// [2.975s][debug][gc ] Test GC 59M->59M(502M) (2.975s, 2.975s) 0.026ms
|
||||
"[gc", "] Test GC ", "M) (", "s, ", "s) ", "ms",
|
||||
};
|
||||
EXPECT_FALSE(file_contains_substrings_in_order(TestLogFileName, not_expected));
|
||||
}
|
158
hotspot/test/native/logging/test_log.cpp
Normal file
158
hotspot/test/native/logging/test_log.cpp
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "logTestFixture.hpp"
|
||||
#include "logTestUtils.inline.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
class LogTest : public LogTestFixture {
|
||||
};
|
||||
|
||||
#define LOG_PREFIX_STR "THE_PREFIX "
|
||||
#define LOG_LINE_STR "a log line"
|
||||
|
||||
size_t Test_log_prefix_prefixer(char* buf, size_t len) {
|
||||
int ret = jio_snprintf(buf, len, LOG_PREFIX_STR);
|
||||
assert(ret > 0, "Failed to print prefix. Log buffer too small?");
|
||||
return (size_t) ret;
|
||||
}
|
||||
|
||||
#ifdef ASSERT // 'test' tag is debug only
|
||||
TEST_F(LogTest, prefix) {
|
||||
set_log_config(TestLogFileName, "logging+test=trace");
|
||||
log_trace(logging, test)(LOG_LINE_STR);
|
||||
EXPECT_TRUE(file_contains_substring(TestLogFileName, LOG_PREFIX_STR LOG_LINE_STR));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(LogTest, large_message) {
|
||||
char big_msg[4096] = {0};
|
||||
char Xchar = '~';
|
||||
|
||||
set_log_config(TestLogFileName, "logging=trace");
|
||||
|
||||
memset(big_msg, Xchar, sizeof(big_msg) - 1);
|
||||
log_trace(logging)("%s", big_msg);
|
||||
|
||||
ResourceMark rm;
|
||||
FILE* fp = fopen(TestLogFileName, "r");
|
||||
ASSERT_NE((void*)NULL, fp);
|
||||
char* output = read_line(fp);
|
||||
fclose(fp);
|
||||
|
||||
size_t count = 0;
|
||||
for (size_t ps = 0 ; output[ps + count] != '\0'; output[ps + count] == Xchar ? count++ : ps++);
|
||||
EXPECT_EQ(sizeof(big_msg) - 1, count);
|
||||
}
|
||||
|
||||
TEST_F(LogTest, enabled_logtarget) {
|
||||
set_log_config(TestLogFileName, "gc=debug");
|
||||
|
||||
LogTarget(Debug, gc) log;
|
||||
EXPECT_TRUE(log.is_enabled());
|
||||
|
||||
// Log the line and expect it to be available in the output file.
|
||||
log.print(LOG_TEST_STRING_LITERAL);
|
||||
|
||||
EXPECT_TRUE(file_contains_substring(TestLogFileName, LOG_TEST_STRING_LITERAL));
|
||||
}
|
||||
|
||||
TEST_F(LogTest, disabled_logtarget) {
|
||||
set_log_config(TestLogFileName, "gc=info");
|
||||
|
||||
LogTarget(Debug, gc) log;
|
||||
EXPECT_FALSE(log.is_enabled());
|
||||
|
||||
// Try to log, but expect this to be filtered out.
|
||||
log.print(LOG_TEST_STRING_LITERAL);
|
||||
|
||||
// Log a dummy line so that fgets doesn't return NULL because the file is empty.
|
||||
log_info(gc)("Dummy line");
|
||||
|
||||
EXPECT_FALSE(file_contains_substring(TestLogFileName, LOG_TEST_STRING_LITERAL));
|
||||
}
|
||||
|
||||
TEST_F(LogTest, enabled_loghandle) {
|
||||
set_log_config(TestLogFileName, "gc=debug");
|
||||
|
||||
Log(gc) log;
|
||||
LogHandle log_handle(log);
|
||||
|
||||
EXPECT_TRUE(log_handle.is_debug());
|
||||
|
||||
// Try to log through a LogHandle.
|
||||
log_handle.debug("%d workers", 3);
|
||||
|
||||
EXPECT_TRUE(file_contains_substring(TestLogFileName, "3 workers"));
|
||||
}
|
||||
|
||||
TEST_F(LogTest, disabled_loghandle) {
|
||||
set_log_config(TestLogFileName, "gc=info");
|
||||
|
||||
Log(gc) log;
|
||||
LogHandle log_handle(log);
|
||||
|
||||
EXPECT_FALSE(log_handle.is_debug());
|
||||
|
||||
// Try to log through a LogHandle.
|
||||
log_handle.debug("%d workers", 3);
|
||||
|
||||
// Log a dummy line so that fgets doesn't return NULL because the file is empty.
|
||||
log_info(gc)("Dummy line");
|
||||
|
||||
EXPECT_FALSE(file_contains_substring(TestLogFileName, "3 workers"));
|
||||
}
|
||||
|
||||
TEST_F(LogTest, enabled_logtargethandle) {
|
||||
set_log_config(TestLogFileName, "gc=debug");
|
||||
|
||||
LogTarget(Debug, gc) log;
|
||||
LogTargetHandle log_handle(log);
|
||||
|
||||
EXPECT_TRUE(log_handle.is_enabled());
|
||||
|
||||
// Try to log through a LogHandle.
|
||||
log_handle.print("%d workers", 3);
|
||||
|
||||
EXPECT_TRUE(file_contains_substring(TestLogFileName, "3 workers"));
|
||||
}
|
||||
|
||||
TEST_F(LogTest, disabled_logtargethandle) {
|
||||
set_log_config(TestLogFileName, "gc=info");
|
||||
|
||||
LogTarget(Debug, gc) log;
|
||||
LogTargetHandle log_handle(log);
|
||||
|
||||
EXPECT_FALSE(log_handle.is_enabled());
|
||||
|
||||
// Try to log through a LogHandle.
|
||||
log_handle.print("%d workers", 3);
|
||||
|
||||
// Log a dummy line so that fgets doesn't return NULL because the file is empty.
|
||||
log_info(gc)("Dummy line");
|
||||
|
||||
EXPECT_FALSE(file_contains_substring(TestLogFileName, "3 workers"));
|
||||
}
|
@ -61,7 +61,7 @@ static bool is_described(const char* text) {
|
||||
return string_contains_substring(ss.as_string(), text);
|
||||
}
|
||||
|
||||
TEST_F(LogConfigurationTest, describe) {
|
||||
TEST_VM_F(LogConfigurationTest, describe) {
|
||||
ResourceMark rm;
|
||||
stringStream ss;
|
||||
LogConfiguration::describe(&ss);
|
||||
@ -115,7 +115,7 @@ TEST_F(LogConfigurationTest, describe) {
|
||||
}
|
||||
|
||||
// Test updating an existing log output
|
||||
TEST_F(LogConfigurationTest, update_output) {
|
||||
TEST_VM_F(LogConfigurationTest, update_output) {
|
||||
// Update stdout twice, first using it's name, and the second time its index #
|
||||
const char* test_outputs[] = { "stdout", "#0" };
|
||||
for (size_t i = 0; i < ARRAY_SIZE(test_outputs); i++) {
|
||||
@ -144,7 +144,7 @@ TEST_F(LogConfigurationTest, update_output) {
|
||||
}
|
||||
|
||||
// Test adding a new output to the configuration
|
||||
TEST_F(LogConfigurationTest, add_new_output) {
|
||||
TEST_VM_F(LogConfigurationTest, add_new_output) {
|
||||
const char* what = "all=trace";
|
||||
|
||||
ASSERT_FALSE(is_described(TestLogFileName));
|
||||
@ -160,7 +160,7 @@ TEST_F(LogConfigurationTest, add_new_output) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(LogConfigurationTest, disable_logging) {
|
||||
TEST_VM_F(LogConfigurationTest, disable_logging) {
|
||||
// Add TestLogFileName as an output
|
||||
set_log_config(TestLogFileName, "logging=info");
|
||||
|
||||
@ -185,7 +185,7 @@ TEST_F(LogConfigurationTest, disable_logging) {
|
||||
}
|
||||
|
||||
// Test disabling a particular output
|
||||
TEST_F(LogConfigurationTest, disable_output) {
|
||||
TEST_VM_F(LogConfigurationTest, disable_output) {
|
||||
// Disable the default configuration for stdout
|
||||
set_log_config("stdout", "all=off");
|
||||
|
||||
@ -213,7 +213,7 @@ TEST_F(LogConfigurationTest, disable_output) {
|
||||
}
|
||||
|
||||
// Test reconfiguration of the selected decorators for an output
|
||||
TEST_F(LogConfigurationTest, reconfigure_decorators) {
|
||||
TEST_VM_F(LogConfigurationTest, reconfigure_decorators) {
|
||||
// Configure stderr with all decorators
|
||||
set_log_config("stderr", "all=off", _all_decorators);
|
||||
char buf[256];
|
||||
@ -227,7 +227,7 @@ TEST_F(LogConfigurationTest, reconfigure_decorators) {
|
||||
}
|
||||
|
||||
// Test that invalid options cause configuration errors
|
||||
TEST_F(LogConfigurationTest, invalid_configure_options) {
|
||||
TEST_VM_F(LogConfigurationTest, invalid_configure_options) {
|
||||
LogConfiguration::disable_logging();
|
||||
const char* invalid_outputs[] = { "#2", "invalidtype=123", ":invalid/path}to*file?" };
|
||||
for (size_t i = 0; i < ARRAY_SIZE(invalid_outputs); i++) {
|
||||
@ -240,7 +240,7 @@ TEST_F(LogConfigurationTest, invalid_configure_options) {
|
||||
}
|
||||
|
||||
// Test empty configuration options
|
||||
TEST_F(LogConfigurationTest, parse_empty_command_line_arguments) {
|
||||
TEST_VM_F(LogConfigurationTest, parse_empty_command_line_arguments) {
|
||||
const char* empty_variations[] = { "", ":", "::", ":::", "::::" };
|
||||
for (size_t i = 0; i < ARRAY_SIZE(empty_variations); i++) {
|
||||
const char* cmdline = empty_variations[i];
|
||||
@ -253,7 +253,7 @@ TEST_F(LogConfigurationTest, parse_empty_command_line_arguments) {
|
||||
}
|
||||
|
||||
// Test basic command line parsing & configuration
|
||||
TEST_F(LogConfigurationTest, parse_command_line_arguments) {
|
||||
TEST_VM_F(LogConfigurationTest, parse_command_line_arguments) {
|
||||
// Prepare a command line for logging*=debug on stderr with all decorators
|
||||
int ret;
|
||||
char buf[256];
|
||||
@ -273,7 +273,7 @@ TEST_F(LogConfigurationTest, parse_command_line_arguments) {
|
||||
}
|
||||
|
||||
// Test split up log configuration arguments
|
||||
TEST_F(LogConfigurationTest, parse_log_arguments) {
|
||||
TEST_VM_F(LogConfigurationTest, parse_log_arguments) {
|
||||
ResourceMark rm;
|
||||
stringStream ss;
|
||||
// Verify that it's possible to configure each individual tag
|
||||
@ -296,7 +296,82 @@ TEST_F(LogConfigurationTest, parse_log_arguments) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(LogConfigurationTest, parse_invalid_tagset) {
|
||||
TEST_F(LogConfigurationTest, configure_stdout) {
|
||||
// Start out with all logging disabled
|
||||
LogConfiguration::disable_logging();
|
||||
|
||||
// Enable 'logging=info', verifying it has been set
|
||||
LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(logging));
|
||||
EXPECT_TRUE(log_is_enabled(Info, logging));
|
||||
EXPECT_FALSE(log_is_enabled(Debug, logging));
|
||||
EXPECT_FALSE(log_is_enabled(Info, gc));
|
||||
LogTagSet* logging_ts = &LogTagSetMapping<LOG_TAGS(logging)>::tagset();
|
||||
EXPECT_EQ(LogLevel::Info, logging_ts->level_for(LogOutput::Stdout));
|
||||
|
||||
// Enable 'gc=debug' (no wildcard), verifying no other tags are enabled
|
||||
LogConfiguration::configure_stdout(LogLevel::Debug, true, LOG_TAGS(gc));
|
||||
EXPECT_TRUE(log_is_enabled(Debug, gc));
|
||||
EXPECT_TRUE(log_is_enabled(Info, logging));
|
||||
EXPECT_FALSE(log_is_enabled(Debug, gc, heap));
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
if (ts->contains(PREFIX_LOG_TAG(gc))) {
|
||||
if (ts->ntags() == 1) {
|
||||
EXPECT_EQ(LogLevel::Debug, ts->level_for(LogOutput::Stdout));
|
||||
} else {
|
||||
EXPECT_EQ(LogLevel::Off, ts->level_for(LogOutput::Stdout));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enable 'gc*=trace' (with wildcard), verifying that all tag combinations with gc are enabled (gc+...)
|
||||
LogConfiguration::configure_stdout(LogLevel::Trace, false, LOG_TAGS(gc));
|
||||
EXPECT_TRUE(log_is_enabled(Trace, gc));
|
||||
EXPECT_TRUE(log_is_enabled(Trace, gc, heap));
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
if (ts->contains(PREFIX_LOG_TAG(gc))) {
|
||||
EXPECT_EQ(LogLevel::Trace, ts->level_for(LogOutput::Stdout));
|
||||
} else if (ts == logging_ts) {
|
||||
// Previous setting for 'logging' should remain
|
||||
EXPECT_EQ(LogLevel::Info, ts->level_for(LogOutput::Stdout));
|
||||
} else {
|
||||
EXPECT_EQ(LogLevel::Off, ts->level_for(LogOutput::Stdout));
|
||||
}
|
||||
}
|
||||
|
||||
// Disable 'gc*' and 'logging', verifying all logging is properly disabled
|
||||
LogConfiguration::configure_stdout(LogLevel::Off, true, LOG_TAGS(logging));
|
||||
EXPECT_FALSE(log_is_enabled(Error, logging));
|
||||
LogConfiguration::configure_stdout(LogLevel::Off, false, LOG_TAGS(gc));
|
||||
EXPECT_FALSE(log_is_enabled(Error, gc));
|
||||
EXPECT_FALSE(log_is_enabled(Error, gc, heap));
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
EXPECT_EQ(LogLevel::Off, ts->level_for(LogOutput::Stdout));
|
||||
}
|
||||
}
|
||||
|
||||
static int Test_logconfiguration_subscribe_triggered = 0;
|
||||
static void Test_logconfiguration_subscribe_helper() {
|
||||
Test_logconfiguration_subscribe_triggered++;
|
||||
}
|
||||
|
||||
TEST_F(LogConfigurationTest, subscribe) {
|
||||
ResourceMark rm;
|
||||
Log(logging) log;
|
||||
set_log_config("stdout", "logging*=trace");
|
||||
|
||||
LogConfiguration::register_update_listener(&Test_logconfiguration_subscribe_helper);
|
||||
|
||||
LogConfiguration::parse_log_arguments("stdout", "logging=trace", NULL, NULL, log.error_stream());
|
||||
ASSERT_EQ(1, Test_logconfiguration_subscribe_triggered);
|
||||
|
||||
LogConfiguration::configure_stdout(LogLevel::Debug, true, LOG_TAGS(gc));
|
||||
ASSERT_EQ(2, Test_logconfiguration_subscribe_triggered);
|
||||
|
||||
LogConfiguration::disable_logging();
|
||||
ASSERT_EQ(3, Test_logconfiguration_subscribe_triggered);
|
||||
}
|
||||
|
||||
TEST_VM_F(LogConfigurationTest, parse_invalid_tagset) {
|
||||
static const char* invalid_tagset = "logging+start+exit+safepoint+gc"; // Must not exist for test to function.
|
||||
|
||||
// Make sure warning is produced if one or more configured tagsets are invalid
|
||||
@ -309,7 +384,7 @@ TEST_F(LogConfigurationTest, parse_invalid_tagset) {
|
||||
EXPECT_TRUE(string_contains_substring(msg, invalid_tagset));
|
||||
}
|
||||
|
||||
TEST_F(LogConfigurationTest, output_name_normalization) {
|
||||
TEST_VM_F(LogConfigurationTest, output_name_normalization) {
|
||||
const char* patterns[] = { "%s", "file=%s", "\"%s\"", "file=\"%s\"" };
|
||||
char buf[1 * K];
|
||||
for (size_t i = 0; i < ARRAY_SIZE(patterns); i++) {
|
||||
|
@ -31,7 +31,7 @@
|
||||
static const LogTagSet& tagset = LogTagSetMapping<LOG_TAGS(logging, safepoint)>::tagset();
|
||||
static const LogDecorators default_decorators;
|
||||
|
||||
TEST(LogDecorations, level) {
|
||||
TEST_VM(LogDecorations, level) {
|
||||
for (uint l = LogLevel::First; l <= LogLevel::Last; l++) {
|
||||
LogLevelType level = static_cast<LogLevelType>(l);
|
||||
// Create a decorations object for the current level
|
||||
@ -52,7 +52,7 @@ TEST(LogDecorations, level) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LogDecorations, uptime) {
|
||||
TEST_VM(LogDecorations, uptime) {
|
||||
// Verify the format of the decoration
|
||||
int a, b;
|
||||
char decimal_point;
|
||||
@ -73,7 +73,7 @@ TEST(LogDecorations, uptime) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LogDecorations, tags) {
|
||||
TEST_VM(LogDecorations, tags) {
|
||||
char expected_tags[1 * K];
|
||||
tagset.label(expected_tags, sizeof(expected_tags));
|
||||
// Verify that the expected tags are included in the tags decoration
|
||||
@ -82,7 +82,7 @@ TEST(LogDecorations, tags) {
|
||||
}
|
||||
|
||||
// Test each variation of the different timestamp decorations (ms, ns, uptime ms, uptime ns)
|
||||
TEST(LogDecorations, timestamps) {
|
||||
TEST_VM(LogDecorations, timestamps) {
|
||||
struct {
|
||||
const LogDecorators::Decorator decorator;
|
||||
const char* suffix;
|
||||
|
@ -22,6 +22,7 @@
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "logTestUtils.inline.hpp"
|
||||
#include "logging/logFileOutput.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
@ -32,7 +33,7 @@
|
||||
static const char* name = "file=testlog.pid%p.%t.log";
|
||||
|
||||
// Test parsing a bunch of valid file output options
|
||||
TEST(LogFileOutput, parse_valid) {
|
||||
TEST_VM(LogFileOutput, parse_valid) {
|
||||
const char* valid_options[] = {
|
||||
"", "filecount=10", "filesize=512",
|
||||
"filecount=11,filesize=256",
|
||||
@ -64,7 +65,7 @@ TEST(LogFileOutput, parse_valid) {
|
||||
}
|
||||
|
||||
// Test parsing a bunch of invalid file output options
|
||||
TEST(LogFileOutput, parse_invalid) {
|
||||
TEST_VM(LogFileOutput, parse_invalid) {
|
||||
const char* invalid_options[] = {
|
||||
"invalidopt", "filecount=",
|
||||
"filesize=,filecount=10",
|
||||
@ -91,7 +92,7 @@ TEST(LogFileOutput, parse_invalid) {
|
||||
}
|
||||
|
||||
// Test for overflows with filesize
|
||||
TEST(LogFileOutput, filesize_overflow) {
|
||||
TEST_VM(LogFileOutput, filesize_overflow) {
|
||||
char buf[256];
|
||||
int ret = jio_snprintf(buf, sizeof(buf), "filesize=" SIZE_FORMAT "K", SIZE_MAX);
|
||||
ASSERT_GT(ret, 0) << "Buffer too small";
|
||||
@ -101,3 +102,82 @@ TEST(LogFileOutput, filesize_overflow) {
|
||||
LogFileOutput fo(name);
|
||||
EXPECT_FALSE(fo.initialize(buf, &ss)) << "Accepted filesize that overflows";
|
||||
}
|
||||
|
||||
TEST(LogFileOutput, startup_rotation) {
|
||||
const size_t rotations = 5;
|
||||
const char* filename = "start-rotate-test";
|
||||
char* rotated_file[rotations];
|
||||
|
||||
ResourceMark rm;
|
||||
for (size_t i = 0; i < rotations; i++) {
|
||||
size_t len = strlen(filename) + 3;
|
||||
rotated_file[i] = NEW_RESOURCE_ARRAY(char, len);
|
||||
int ret = jio_snprintf(rotated_file[i], len, "%s." SIZE_FORMAT, filename, i);
|
||||
ASSERT_NE(-1, ret);
|
||||
delete_file(rotated_file[i]);
|
||||
}
|
||||
|
||||
delete_file(filename);
|
||||
init_log_file(filename);
|
||||
ASSERT_TRUE(file_exists(filename))
|
||||
<< "configured logging to file '" << filename << "' but file was not found";
|
||||
|
||||
// Initialize the same file a bunch more times to trigger rotations
|
||||
for (size_t i = 0; i < rotations; i++) {
|
||||
init_log_file(filename);
|
||||
EXPECT_TRUE(file_exists(rotated_file[i]));
|
||||
}
|
||||
|
||||
// Remove a file and expect its slot to be re-used
|
||||
delete_file(rotated_file[1]);
|
||||
init_log_file(filename);
|
||||
EXPECT_TRUE(file_exists(rotated_file[1]));
|
||||
|
||||
// Clean up after test
|
||||
delete_file(filename);
|
||||
for (size_t i = 0; i < rotations; i++) {
|
||||
delete_file(rotated_file[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LogFileOutput, startup_truncation) {
|
||||
const char* filename = "start-truncate-test";
|
||||
const char* archived_filename = "start-truncate-test.0";
|
||||
|
||||
delete_file(filename);
|
||||
delete_file(archived_filename);
|
||||
|
||||
// Use the same log file twice and expect it to be overwritten/truncated
|
||||
init_log_file(filename, "filecount=0");
|
||||
ASSERT_TRUE(file_exists(filename))
|
||||
<< "configured logging to file '" << filename << "' but file was not found";
|
||||
|
||||
init_log_file(filename, "filecount=0");
|
||||
ASSERT_TRUE(file_exists(filename))
|
||||
<< "configured logging to file '" << filename << "' but file was not found";
|
||||
EXPECT_FALSE(file_exists(archived_filename))
|
||||
<< "existing log file was not properly truncated when filecount was 0";
|
||||
|
||||
// Verify that the file was really truncated and not just appended
|
||||
EXPECT_TRUE(file_contains_substring(filename, LOG_TEST_STRING_LITERAL));
|
||||
const char* repeated[] = { LOG_TEST_STRING_LITERAL, LOG_TEST_STRING_LITERAL };
|
||||
EXPECT_FALSE(file_contains_substrings_in_order(filename, repeated))
|
||||
<< "log file " << filename << " appended rather than truncated";
|
||||
|
||||
delete_file(filename);
|
||||
delete_file(archived_filename);
|
||||
}
|
||||
|
||||
TEST(LogFileOutput, invalid_file) {
|
||||
ResourceMark rm;
|
||||
stringStream ss;
|
||||
|
||||
// Attempt to log to a directory (existing log not a regular file)
|
||||
create_directory("tmplogdir");
|
||||
LogFileOutput bad_file("file=tmplogdir");
|
||||
EXPECT_FALSE(bad_file.initialize("", &ss))
|
||||
<< "file was initialized when there was an existing directory with the same name";
|
||||
EXPECT_TRUE(string_contains_substring(ss.as_string(), "tmplogdir is not a regular file"))
|
||||
<< "missing expected error message, received msg: %s" << ss.as_string();
|
||||
remove("tmplogdir");
|
||||
}
|
||||
|
252
hotspot/test/native/logging/test_logMessageTest.cpp
Normal file
252
hotspot/test/native/logging/test_logMessageTest.cpp
Normal file
@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, 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
|
||||
* ac_heapanied 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "logTestFixture.hpp"
|
||||
#include "logTestUtils.inline.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logMessage.hpp"
|
||||
#include "unittest.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class LogMessageTest : public LogTestFixture {
|
||||
protected:
|
||||
static Log(logging) _log;
|
||||
static const char* _level_filename[];
|
||||
LogMessageTest();
|
||||
~LogMessageTest();
|
||||
};
|
||||
|
||||
const char* LogMessageTest::_level_filename[] = {
|
||||
NULL, // LogLevel::Off
|
||||
#define LOG_LEVEL(name, printname) "multiline-" #printname ".log",
|
||||
LOG_LEVEL_LIST
|
||||
#undef LOG_LEVEL
|
||||
};
|
||||
|
||||
LogMessageTest::LogMessageTest() {
|
||||
for (int i = 0; i < LogLevel::Count; i++) {
|
||||
char buf[32];
|
||||
// Attempt to remove possibly pre-existing log files
|
||||
remove(_level_filename[i]);
|
||||
|
||||
jio_snprintf(buf, sizeof(buf), "logging=%s", LogLevel::name(static_cast<LogLevelType>(i)));
|
||||
set_log_config(_level_filename[i], buf);
|
||||
}
|
||||
}
|
||||
|
||||
LogMessageTest::~LogMessageTest() {
|
||||
// Stop logging to the files and remove them.
|
||||
for (int i = 0; i < LogLevel::Count; i++) {
|
||||
set_log_config(_level_filename[i], "all=off");
|
||||
remove(_level_filename[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that messages with multiple levels are written
|
||||
// to outputs configured for all the corresponding levels
|
||||
TEST_F(LogMessageTest, level_inclusion) {
|
||||
const size_t message_count = 10;
|
||||
LogMessageBuffer msg[message_count];
|
||||
|
||||
struct {
|
||||
int message_number;
|
||||
LogLevelType level;
|
||||
} lines[] = {
|
||||
{ 0, LogLevel::Error },
|
||||
{ 1, LogLevel::Info },
|
||||
{ 2, LogLevel::Info }, { 2, LogLevel::Debug },
|
||||
{ 3, LogLevel::Info }, { 3, LogLevel::Warning },
|
||||
{ 4, LogLevel::Debug }, { 4, LogLevel::Warning },
|
||||
{ 5, LogLevel::Trace }, { 5, LogLevel::Debug },
|
||||
{ 6, LogLevel::Warning }, { 6, LogLevel::Error },
|
||||
{ 7, LogLevel::Trace }, { 7, LogLevel::Info }, { 7, LogLevel::Debug },
|
||||
{ 8, LogLevel::Trace }, { 8, LogLevel::Debug }, { 8, LogLevel::Info },
|
||||
{ 8, LogLevel::Warning }, { 8, LogLevel::Error},
|
||||
{ 9, LogLevel::Trace }
|
||||
};
|
||||
|
||||
// Fill in messages with the above lines
|
||||
for (size_t i = 0; i < ARRAY_SIZE(lines); i++) {
|
||||
switch (lines[i].level) {
|
||||
#define LOG_LEVEL(name, printname) \
|
||||
case LogLevel::name: \
|
||||
msg[lines[i].message_number].printname("msg[%d]: " #printname, lines[i].message_number); \
|
||||
break;
|
||||
LOG_LEVEL_LIST
|
||||
#undef LOG_LEVEL
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < message_count; i++) {
|
||||
_log.write(msg[i]);
|
||||
}
|
||||
|
||||
// Verify that lines are written to the expected log files
|
||||
for (size_t i = 0; i < ARRAY_SIZE(lines); i++) {
|
||||
char expected[256];
|
||||
jio_snprintf(expected, sizeof(expected), "msg[%d]: %s",
|
||||
lines[i].message_number, LogLevel::name(lines[i].level));
|
||||
for (int level = lines[i].level; level > 0; level--) {
|
||||
EXPECT_TRUE(file_contains_substring(_level_filename[level], expected))
|
||||
<< "line #" << i << " missing from log file " << _level_filename[level];
|
||||
}
|
||||
for (int level = lines[i].level + 1; level < LogLevel::Count; level++) {
|
||||
EXPECT_FALSE(file_contains_substring(_level_filename[level], expected))
|
||||
<< "line #" << i << " erroneously included in log file " << _level_filename[level];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that messages are logged in the order they are added to the log message
|
||||
TEST_F(LogMessageTest, line_order) {
|
||||
LogMessageBuffer msg;
|
||||
msg.info("info line").error("error line").trace("trace line")
|
||||
.error("another error").warning("warning line").debug("debug line");
|
||||
_log.write(msg);
|
||||
|
||||
const char* expected[] = { "info line", "error line", "trace line",
|
||||
"another error", "warning line", "debug line", NULL };
|
||||
EXPECT_TRUE(file_contains_substrings_in_order(_level_filename[LogLevel::Trace], expected))
|
||||
<< "output missing or in incorrect order";
|
||||
}
|
||||
|
||||
TEST_F(LogMessageTest, long_message) {
|
||||
// Write 10K bytes worth of log data
|
||||
LogMessageBuffer msg;
|
||||
const size_t size = 10 * K;
|
||||
const char* start_marker = "#start#";
|
||||
const char* end_marker = "#the end#";
|
||||
char* data = NEW_C_HEAP_ARRAY(char, size, mtLogging);
|
||||
|
||||
// fill buffer with start_marker...some data...end_marker
|
||||
sprintf(data, "%s", start_marker);
|
||||
for (size_t i = strlen(start_marker); i < size; i++) {
|
||||
data[i] = '0' + (i % 10);
|
||||
}
|
||||
sprintf(data + size - strlen(end_marker) - 1, "%s", end_marker);
|
||||
|
||||
msg.trace("%s", data); // Adds a newline, making the message exactly 10K in length.
|
||||
_log.write(msg);
|
||||
|
||||
const char* expected[] = { start_marker, "0123456789", end_marker, NULL };
|
||||
EXPECT_TRUE(file_contains_substrings_in_order(_level_filename[LogLevel::Trace], expected))
|
||||
<< "unable to print long line";
|
||||
FREE_C_HEAP_ARRAY(char, data);
|
||||
}
|
||||
|
||||
TEST_F(LogMessageTest, message_with_many_lines) {
|
||||
const size_t lines = 100;
|
||||
const size_t line_length = 16;
|
||||
|
||||
LogMessageBuffer msg;
|
||||
for (size_t i = 0; i < lines; i++) {
|
||||
msg.info("Line #" SIZE_FORMAT, i);
|
||||
}
|
||||
_log.write(msg);
|
||||
|
||||
char expected_lines_data[lines][line_length];
|
||||
const char* expected_lines[lines + 1];
|
||||
for (size_t i = 0; i < lines; i++) {
|
||||
jio_snprintf(&expected_lines_data[i][0], line_length, "Line #" SIZE_FORMAT, i);
|
||||
expected_lines[i] = expected_lines_data[i];
|
||||
}
|
||||
expected_lines[lines] = NULL;
|
||||
|
||||
EXPECT_TRUE(file_contains_substrings_in_order(_level_filename[LogLevel::Trace], expected_lines))
|
||||
<< "couldn't find all lines in multiline message";
|
||||
}
|
||||
|
||||
static size_t dummy_prefixer(char* buf, size_t len) {
|
||||
static int i = 0;
|
||||
const char* prefix = "some prefix: ";
|
||||
const size_t prefix_len = strlen(prefix);
|
||||
if (len < prefix_len) {
|
||||
return prefix_len;
|
||||
}
|
||||
jio_snprintf(buf, len, "%s", prefix);
|
||||
return prefix_len;
|
||||
}
|
||||
|
||||
TEST_F(LogMessageTest, prefixing) {
|
||||
LogMessageBuffer msg;
|
||||
msg.set_prefix(dummy_prefixer);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
msg.info("test %d", i);
|
||||
}
|
||||
msg.set_prefix(NULL);
|
||||
msg.info("test 3");
|
||||
_log.write(msg);
|
||||
|
||||
const char* expected[] = {
|
||||
"] some prefix: test 0",
|
||||
"] some prefix: test 1",
|
||||
"] some prefix: test 2",
|
||||
"] test 3",
|
||||
NULL
|
||||
};
|
||||
EXPECT_TRUE(file_contains_substrings_in_order(_level_filename[LogLevel::Trace], expected))
|
||||
<< "error in prefixed output";
|
||||
}
|
||||
|
||||
TEST_F(LogMessageTest, scoped_messages) {
|
||||
{
|
||||
LogMessage(logging) msg;
|
||||
msg.info("scoped info");
|
||||
msg.warning("scoped warn");
|
||||
EXPECT_FALSE(file_contains_substring(_level_filename[LogLevel::Info], "scoped info"))
|
||||
<< "scoped log message written prematurely";
|
||||
}
|
||||
EXPECT_TRUE(file_contains_substring(_level_filename[LogLevel::Info], "scoped info"))
|
||||
<< "missing output from scoped log message";
|
||||
EXPECT_TRUE(file_contains_substring(_level_filename[LogLevel::Warning], "scoped warn"))
|
||||
<< "missing output from scoped log message";
|
||||
}
|
||||
|
||||
TEST_F(LogMessageTest, scoped_flushing) {
|
||||
{
|
||||
LogMessage(logging) msg;
|
||||
msg.info("manual flush info");
|
||||
msg.flush();
|
||||
EXPECT_TRUE(file_contains_substring(_level_filename[LogLevel::Info], "manual flush info"))
|
||||
<< "missing output from manually flushed scoped log message";
|
||||
}
|
||||
const char* tmp[] = {"manual flush info", "manual flush info", NULL};
|
||||
EXPECT_FALSE(file_contains_substrings_in_order(_level_filename[LogLevel::Info], tmp))
|
||||
<< "log file contains duplicate lines from single scoped log message";
|
||||
}
|
||||
|
||||
TEST_F(LogMessageTest, scoped_reset) {
|
||||
{
|
||||
LogMessage(logging) msg, partial;
|
||||
msg.info("%s", "info reset msg");
|
||||
msg.reset();
|
||||
partial.info("%s", "info reset msg");
|
||||
partial.reset();
|
||||
partial.trace("%s", "trace reset msg");
|
||||
}
|
||||
EXPECT_FALSE(file_contains_substring(_level_filename[LogLevel::Info], "info reset msg"))
|
||||
<< "reset message written anyway";
|
||||
EXPECT_TRUE(file_contains_substring(_level_filename[LogLevel::Trace], "trace reset msg"))
|
||||
<< "missing message from partially reset scoped log message";
|
||||
}
|
83
hotspot/test/native/logging/test_logStream.cpp
Normal file
83
hotspot/test/native/logging/test_logStream.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "logTestFixture.hpp"
|
||||
#include "logTestUtils.inline.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
class LogStreamTest : public LogTestFixture {
|
||||
protected:
|
||||
void verify_stream(outputStream* stream);
|
||||
};
|
||||
|
||||
void LogStreamTest::verify_stream(outputStream* stream) {
|
||||
set_log_config(TestLogFileName, "gc=debug");
|
||||
stream->print("%d ", 3);
|
||||
stream->print("workers");
|
||||
stream->cr();
|
||||
EXPECT_TRUE(file_contains_substring(TestLogFileName, "3 workers\n"));
|
||||
}
|
||||
|
||||
TEST_F(LogStreamTest, from_log) {
|
||||
Log(gc) log;
|
||||
LogStream stream(log.debug());
|
||||
|
||||
verify_stream(&stream);
|
||||
}
|
||||
|
||||
TEST_F(LogStreamTest, from_logtarget) {
|
||||
LogTarget(Debug, gc) log;
|
||||
LogStream stream(log);
|
||||
|
||||
verify_stream(&stream);
|
||||
}
|
||||
|
||||
TEST_F(LogStreamTest, handle) {
|
||||
LogStreamHandle(Debug, gc) stream;
|
||||
|
||||
verify_stream(&stream);
|
||||
}
|
||||
|
||||
TEST_F(LogStreamTest, no_rm) {
|
||||
ResourceMark rm;
|
||||
outputStream* stream = LogTarget(Debug, gc)::stream();
|
||||
|
||||
verify_stream(stream);
|
||||
}
|
||||
|
||||
TEST_F(LogStreamTest, c_heap_stream) {
|
||||
Log(gc) log;
|
||||
LogStreamCHeap stream(log.debug());
|
||||
|
||||
verify_stream(&stream);
|
||||
}
|
||||
|
||||
TEST_F(LogStreamTest, c_heap_stream_target) {
|
||||
LogTarget(Debug, gc) log;
|
||||
LogStreamCHeap stream(log);
|
||||
|
||||
verify_stream(&stream);
|
||||
}
|
@ -28,6 +28,12 @@
|
||||
#include "unittest.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
TEST(LogTagLevelExpression, combination_limit) {
|
||||
size_t max_combinations = LogTagLevelExpression::MaxCombinations;
|
||||
EXPECT_GT(max_combinations, LogTagSet::ntagsets())
|
||||
<< "Combination limit not sufficient for configuring all available tag sets";
|
||||
}
|
||||
|
||||
TEST(LogTagLevelExpression, parse) {
|
||||
char buf[256];
|
||||
const char* invalid_substr[] = {
|
||||
|
@ -128,3 +128,46 @@ TEST(LogTagSet, label) {
|
||||
ASSERT_NE(-1, ts2.label(buf, sizeof(buf)));
|
||||
EXPECT_STREQ("logging", buf);
|
||||
}
|
||||
|
||||
TEST(LogTagSet, duplicates) {
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
char ts_name[512];
|
||||
ts->label(ts_name, sizeof(ts_name), ",");
|
||||
|
||||
// verify that NO_TAG is never followed by a real tag
|
||||
for (size_t i = 0; i < LogTag::MaxTags; i++) {
|
||||
if (ts->tag(i) == LogTag::__NO_TAG) {
|
||||
for (i++; i < LogTag::MaxTags; i++) {
|
||||
EXPECT_EQ(LogTag::__NO_TAG, ts->tag(i))
|
||||
<< "NO_TAG was followed by a real tag (" << LogTag::name(ts->tag(i)) << ") in tagset " << ts_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// verify that there are no duplicate tagsets (same tags in different order)
|
||||
for (LogTagSet* other = ts->next(); other != NULL; other = other->next()) {
|
||||
if (ts->ntags() != other->ntags()) {
|
||||
continue;
|
||||
}
|
||||
bool equal = true;
|
||||
for (size_t i = 0; i < ts->ntags(); i++) {
|
||||
LogTagType tag = ts->tag(i);
|
||||
if (!other->contains(tag)) {
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Since tagsets are implemented using template arguments, using both of
|
||||
// the (logically equivalent) tagsets (t1, t2) and (t2, t1) somewhere will
|
||||
// instantiate two different LogTagSetMappings. This causes multiple
|
||||
// tagset instances to be created for the same logical set. We want to
|
||||
// avoid this to save time, memory and prevent any confusion around it.
|
||||
if (equal) {
|
||||
char other_name[512];
|
||||
other->label(other_name, sizeof(other_name), ",");
|
||||
FAIL() << "duplicate LogTagSets found: '" << ts_name << "' vs '" << other_name << "' "
|
||||
<< "(tags must always be specified in the same order for each tagset)";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
66
hotspot/test/native/logging/test_logTagSetDescriptions.cpp
Normal file
66
hotspot/test/native/logging/test_logTagSetDescriptions.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, 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
|
||||
* ac_heapanied 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "logTestUtils.inline.hpp"
|
||||
#include "logging/logConfiguration.hpp"
|
||||
#include "logging/logTagSet.hpp"
|
||||
#include "logging/logTagSetDescriptions.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "unittest.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
TEST(LogTagSetDescriptions, describe) {
|
||||
for (LogTagSetDescription* d = tagset_descriptions; d->tagset != NULL; d++) {
|
||||
char expected[1 * K];
|
||||
d->tagset->label(expected, sizeof(expected), "+");
|
||||
jio_snprintf(expected + strlen(expected),
|
||||
sizeof(expected) - strlen(expected),
|
||||
": %s", d->descr);
|
||||
|
||||
ResourceMark rm;
|
||||
stringStream stream;
|
||||
LogConfiguration::describe(&stream);
|
||||
EXPECT_PRED2(string_contains_substring, stream.as_string(), expected)
|
||||
<< "missing log tag set descriptions in LogConfiguration::describe";
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LogTagSetDescriptions, command_line_help) {
|
||||
const char* filename = "logtagset_descriptions";
|
||||
FILE* fp = fopen(filename, "w+");
|
||||
ASSERT_NE((void*)NULL, fp);
|
||||
LogConfiguration::print_command_line_help(fp);
|
||||
fclose(fp);
|
||||
|
||||
for (LogTagSetDescription* d = tagset_descriptions; d->tagset != NULL; d++) {
|
||||
char expected[1 * K];
|
||||
d->tagset->label(expected, sizeof(expected), "+");
|
||||
jio_snprintf(expected + strlen(expected),
|
||||
sizeof(expected) - strlen(expected),
|
||||
": %s", d->descr);
|
||||
|
||||
EXPECT_TRUE(file_contains_substring(filename, expected)) << "missing log tag set descriptions in -Xlog:help output";
|
||||
}
|
||||
delete_file(filename);
|
||||
}
|
@ -43,47 +43,47 @@ static bool check_max_length_overflow(BasicType type) {
|
||||
return (julong) (size_t) bytes == bytes;
|
||||
}
|
||||
|
||||
TEST(arrayOopDesc, boolean) {
|
||||
TEST_VM(arrayOopDesc, boolean) {
|
||||
ASSERT_PRED1(check_max_length_overflow, T_BOOLEAN);
|
||||
}
|
||||
|
||||
TEST(arrayOopDesc, char) {
|
||||
TEST_VM(arrayOopDesc, char) {
|
||||
ASSERT_PRED1(check_max_length_overflow, T_CHAR);
|
||||
}
|
||||
|
||||
TEST(arrayOopDesc, float) {
|
||||
TEST_VM(arrayOopDesc, float) {
|
||||
ASSERT_PRED1(check_max_length_overflow, T_FLOAT);
|
||||
}
|
||||
|
||||
TEST(arrayOopDesc, double) {
|
||||
TEST_VM(arrayOopDesc, double) {
|
||||
ASSERT_PRED1(check_max_length_overflow, T_DOUBLE);
|
||||
}
|
||||
|
||||
TEST(arrayOopDesc, byte) {
|
||||
TEST_VM(arrayOopDesc, byte) {
|
||||
ASSERT_PRED1(check_max_length_overflow, T_BYTE);
|
||||
}
|
||||
|
||||
TEST(arrayOopDesc, short) {
|
||||
TEST_VM(arrayOopDesc, short) {
|
||||
ASSERT_PRED1(check_max_length_overflow, T_SHORT);
|
||||
}
|
||||
|
||||
TEST(arrayOopDesc, int) {
|
||||
TEST_VM(arrayOopDesc, int) {
|
||||
ASSERT_PRED1(check_max_length_overflow, T_INT);
|
||||
}
|
||||
|
||||
TEST(arrayOopDesc, long) {
|
||||
TEST_VM(arrayOopDesc, long) {
|
||||
ASSERT_PRED1(check_max_length_overflow, T_LONG);
|
||||
}
|
||||
|
||||
TEST(arrayOopDesc, object) {
|
||||
TEST_VM(arrayOopDesc, object) {
|
||||
ASSERT_PRED1(check_max_length_overflow, T_OBJECT);
|
||||
}
|
||||
|
||||
TEST(arrayOopDesc, array) {
|
||||
TEST_VM(arrayOopDesc, array) {
|
||||
ASSERT_PRED1(check_max_length_overflow, T_ARRAY);
|
||||
}
|
||||
|
||||
TEST(arrayOopDesc, narrowOop) {
|
||||
TEST_VM(arrayOopDesc, narrowOop) {
|
||||
ASSERT_PRED1(check_max_length_overflow, T_NARROWOOP);
|
||||
}
|
||||
// T_VOID and T_ADDRESS are not supported by max_array_length()
|
||||
|
@ -54,322 +54,322 @@ JSON_GTest::JSON_GTest(const char* text) : JSON(text, false, tty) {
|
||||
parse();
|
||||
}
|
||||
|
||||
TEST(utilities, json_curly_braces) {
|
||||
TEST_VM(utilities, json_curly_braces) {
|
||||
JSON_GTest::test("{}", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_brackets) {
|
||||
TEST_VM(utilities, json_brackets) {
|
||||
JSON_GTest::test("[]", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_space_braces) {
|
||||
TEST_VM(utilities, json_space_braces) {
|
||||
JSON_GTest::test(" { } ", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_space_bracketes) {
|
||||
TEST_VM(utilities, json_space_bracketes) {
|
||||
JSON_GTest::test(" [ ] ", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_quoted_error) {
|
||||
TEST_VM(utilities, json_quoted_error) {
|
||||
JSON_GTest::test("\"error\"", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_error_string) {
|
||||
TEST_VM(utilities, json_error_string) {
|
||||
JSON_GTest::test("error", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_simple_integer) {
|
||||
TEST_VM(utilities, json_simple_integer) {
|
||||
JSON_GTest::test("1", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_siple_float) {
|
||||
TEST_VM(utilities, json_siple_float) {
|
||||
JSON_GTest::test("1.2", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_simple_boolean_true) {
|
||||
TEST_VM(utilities, json_simple_boolean_true) {
|
||||
JSON_GTest::test("true", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_simple_boolean_false) {
|
||||
TEST_VM(utilities, json_simple_boolean_false) {
|
||||
JSON_GTest::test("false", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_simple_null) {
|
||||
TEST_VM(utilities, json_simple_null) {
|
||||
JSON_GTest::test("null", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_one_element_int_array) {
|
||||
TEST_VM(utilities, json_one_element_int_array) {
|
||||
JSON_GTest::test("[ 1 ]", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_int_array) {
|
||||
TEST_VM(utilities, json_int_array) {
|
||||
JSON_GTest::test("[ 1, ]", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_one_element_bool_array) {
|
||||
TEST_VM(utilities, json_one_element_bool_array) {
|
||||
JSON_GTest::test("[ true ]", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_bool_array) {
|
||||
TEST_VM(utilities, json_bool_array) {
|
||||
JSON_GTest::test("[ true, ]", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_one_element_false_array) {
|
||||
TEST_VM(utilities, json_one_element_false_array) {
|
||||
JSON_GTest::test("[ false ]", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_false_bool_array) {
|
||||
TEST_VM(utilities, json_false_bool_array) {
|
||||
JSON_GTest::test("[ false, ]", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_one_null_array) {
|
||||
TEST_VM(utilities, json_one_null_array) {
|
||||
JSON_GTest::test("[ null ]", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_null_array) {
|
||||
TEST_VM(utilities, json_null_array) {
|
||||
JSON_GTest::test("[ null, ]", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_one_empty_string_array) {
|
||||
TEST_VM(utilities, json_one_empty_string_array) {
|
||||
JSON_GTest::test("[ \"\" ]", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_empty_string_array) {
|
||||
TEST_VM(utilities, json_empty_string_array) {
|
||||
JSON_GTest::test("[ \"\", ]", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_single_string_array) {
|
||||
TEST_VM(utilities, json_single_string_array) {
|
||||
JSON_GTest::test("[ \"elem1\" ]", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_string_comma_arrray) {
|
||||
TEST_VM(utilities, json_string_comma_arrray) {
|
||||
JSON_GTest::test("[ \"elem1\", ]", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_two_strings_array) {
|
||||
TEST_VM(utilities, json_two_strings_array) {
|
||||
JSON_GTest::test("[ \"elem1\", \"elem2\" ]", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_two_strings_comma_array) {
|
||||
TEST_VM(utilities, json_two_strings_comma_array) {
|
||||
JSON_GTest::test("[ \"elem1\", \"elem2\", ]", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_curly_braces_outside) {
|
||||
TEST_VM(utilities, json_curly_braces_outside) {
|
||||
JSON_GTest::test("[ \"elem1\" ] { }", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_element_in_array) {
|
||||
TEST_VM(utilities, json_element_in_array) {
|
||||
JSON_GTest::test("[ elem1, \"elem2\" ]", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_incorrect_end_array) {
|
||||
TEST_VM(utilities, json_incorrect_end_array) {
|
||||
JSON_GTest::test("[ \"elem1\"", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_incorrect_string_end) {
|
||||
TEST_VM(utilities, json_incorrect_string_end) {
|
||||
JSON_GTest::test("[ \"elem1 ]", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_incorrect_end_of_two_elements_array) {
|
||||
TEST_VM(utilities, json_incorrect_end_of_two_elements_array) {
|
||||
JSON_GTest::test("[ \"elem1\", \"elem2\"", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_incorrect_bool_true_array) {
|
||||
TEST_VM(utilities, json_incorrect_bool_true_array) {
|
||||
JSON_GTest::test("[ truefoo ]", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_incorrect_bool_false_array) {
|
||||
TEST_VM(utilities, json_incorrect_bool_false_array) {
|
||||
JSON_GTest::test("[ falsefoo ]", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_incorrect_null_array) {
|
||||
TEST_VM(utilities, json_incorrect_null_array) {
|
||||
JSON_GTest::test("[ nullfoo ]", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_key_pair) {
|
||||
TEST_VM(utilities, json_key_pair) {
|
||||
JSON_GTest::test("{ key : 1 }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_key_pair_comma) {
|
||||
TEST_VM(utilities, json_key_pair_comma) {
|
||||
JSON_GTest::test("{ key : 1, }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_bool_true_key) {
|
||||
TEST_VM(utilities, json_bool_true_key) {
|
||||
JSON_GTest::test("{ key : true }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_bool_true_key_comma) {
|
||||
TEST_VM(utilities, json_bool_true_key_comma) {
|
||||
JSON_GTest::test("{ key : true, }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_bool_false_key) {
|
||||
TEST_VM(utilities, json_bool_false_key) {
|
||||
JSON_GTest::test("{ key : false }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_bool_false_key_comma) {
|
||||
TEST_VM(utilities, json_bool_false_key_comma) {
|
||||
JSON_GTest::test("{ key : false, }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_null_key) {
|
||||
TEST_VM(utilities, json_null_key) {
|
||||
JSON_GTest::test("{ key : null }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_null_key_comma) {
|
||||
TEST_VM(utilities, json_null_key_comma) {
|
||||
JSON_GTest::test("{ key : null, }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_pair_of_empty_strings) {
|
||||
TEST_VM(utilities, json_pair_of_empty_strings) {
|
||||
JSON_GTest::test("{ \"\" : \"\" }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_pair_of_empty_strings_comma) {
|
||||
TEST_VM(utilities, json_pair_of_empty_strings_comma) {
|
||||
JSON_GTest::test("{ \"\" : \"\", }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_pair_of_strings) {
|
||||
TEST_VM(utilities, json_pair_of_strings) {
|
||||
JSON_GTest::test("{ \"key1\" : \"val1\" }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_pair_of_strings_comma) {
|
||||
TEST_VM(utilities, json_pair_of_strings_comma) {
|
||||
JSON_GTest::test("{ \"key1\" : \"val1\", }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_two_pairs_of_strings) {
|
||||
TEST_VM(utilities, json_two_pairs_of_strings) {
|
||||
JSON_GTest::test("{ \"key1\" : \"val1\", \"key2\" : \"val2\" }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_two_pairs_of_strings_comma) {
|
||||
TEST_VM(utilities, json_two_pairs_of_strings_comma) {
|
||||
JSON_GTest::test("{ \"key1\" : \"val1\", \"key2\" : \"val2\", }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_array_outside) {
|
||||
TEST_VM(utilities, json_array_outside) {
|
||||
JSON_GTest::test("{ \"key\" : \"val\" } [ \"error\" ]", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_incorrect_object_end) {
|
||||
TEST_VM(utilities, json_incorrect_object_end) {
|
||||
JSON_GTest::test("{ \"key\" : \"val\" ", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_empty_comment) {
|
||||
TEST_VM(utilities, json_empty_comment) {
|
||||
JSON_GTest::test("/**/ { }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_space_comment) {
|
||||
TEST_VM(utilities, json_space_comment) {
|
||||
JSON_GTest::test("/* */ { }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_comment) {
|
||||
TEST_VM(utilities, json_comment) {
|
||||
JSON_GTest::test("/*foo*/ { }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_star_comment) {
|
||||
TEST_VM(utilities, json_star_comment) {
|
||||
JSON_GTest::test("/* *foo */ { }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_stars_comment) {
|
||||
TEST_VM(utilities, json_stars_comment) {
|
||||
JSON_GTest::test("/* *foo* */ { }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_special_comment) {
|
||||
TEST_VM(utilities, json_special_comment) {
|
||||
JSON_GTest::test("/* /*foo */ { }", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_comment_after) {
|
||||
TEST_VM(utilities, json_comment_after) {
|
||||
JSON_GTest::test("{ } /* foo */", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_comment_after_and_space) {
|
||||
TEST_VM(utilities, json_comment_after_and_space) {
|
||||
JSON_GTest::test("{ } /* foo */ ", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_one_line_empty_comment_after) {
|
||||
TEST_VM(utilities, json_one_line_empty_comment_after) {
|
||||
JSON_GTest::test("{ } //", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_one_line_space_comment_after) {
|
||||
TEST_VM(utilities, json_one_line_space_comment_after) {
|
||||
JSON_GTest::test("{ } // ", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_one_line_comment_after) {
|
||||
TEST_VM(utilities, json_one_line_comment_after) {
|
||||
JSON_GTest::test("{ } // foo", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_incorrect_multiline_comment) {
|
||||
TEST_VM(utilities, json_incorrect_multiline_comment) {
|
||||
JSON_GTest::test("/* * / { }", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_incorrect_multiline_comment_begin) {
|
||||
TEST_VM(utilities, json_incorrect_multiline_comment_begin) {
|
||||
JSON_GTest::test("/ * */ { }", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_oneline_comment_only) {
|
||||
TEST_VM(utilities, json_oneline_comment_only) {
|
||||
JSON_GTest::test("// { }", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_multiline_comment_only) {
|
||||
TEST_VM(utilities, json_multiline_comment_only) {
|
||||
JSON_GTest::test("/* { } */", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_multiline_comment_2) {
|
||||
TEST_VM(utilities, json_multiline_comment_2) {
|
||||
JSON_GTest::test("/* { } */ ", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_incorrectly_commented_object) {
|
||||
TEST_VM(utilities, json_incorrectly_commented_object) {
|
||||
JSON_GTest::test("/* { } ", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_missing_multiline_end) {
|
||||
TEST_VM(utilities, json_missing_multiline_end) {
|
||||
JSON_GTest::test("{ } /* ", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_missing_multiline_slash) {
|
||||
TEST_VM(utilities, json_missing_multiline_slash) {
|
||||
JSON_GTest::test("/* { } *", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_commented_object_end) {
|
||||
TEST_VM(utilities, json_commented_object_end) {
|
||||
JSON_GTest::test("{ /* } */", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_commented_array_end) {
|
||||
TEST_VM(utilities, json_commented_array_end) {
|
||||
JSON_GTest::test("[ /* ] */", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_missing_object_end) {
|
||||
TEST_VM(utilities, json_missing_object_end) {
|
||||
JSON_GTest::test("{ key : \"val\", /* } */", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_missing_array_end) {
|
||||
TEST_VM(utilities, json_missing_array_end) {
|
||||
JSON_GTest::test("[ \"val\", /* ] */", false);
|
||||
}
|
||||
|
||||
TEST(utilities, json_key_values_1) {
|
||||
TEST_VM(utilities, json_key_values_1) {
|
||||
JSON_GTest::test("/* comment */{ key1 : { \"key2\" : { \"key3\" : [ \"elem1\", \"elem2\","
|
||||
"{ \"key4\" : null }, 3 , 2 , 1 , 0 , -1 , -2 , -3 , true, false, null, ] }, \"key5\""
|
||||
" : true }, \"key6\" : [ \"☃\" ], key7 : \"val\",}", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_key_values_2) {
|
||||
TEST_VM(utilities, json_key_values_2) {
|
||||
JSON_GTest::test("/* comment */ { \"key1\" : { \"key2\" : { \"key3\" : [ \"elem1\", \"elem2\","
|
||||
"{ \"key4\" : null }, 3 , 2 , 1 , 0 , -1 , -2 , -3 , true, false, null, ] }, \"key5\""
|
||||
" : true }, \"key6\" : [ \"☃\" ], key7 : \"val\",}", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_quoted_symbols) {
|
||||
TEST_VM(utilities, json_quoted_symbols) {
|
||||
JSON_GTest::test("/*comment*/{\"ff1 fsd\":{\"☃\":{\"☃\":[\"☃\",\"☃\"]},"
|
||||
"\"☃\":true},\"☃\":[\"☃\"],\"foo\":\"☃\",}", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_incorrect_key) {
|
||||
TEST_VM(utilities, json_incorrect_key) {
|
||||
JSON_GTest::test("/* comment */ { key1 error : { \"☃\" : { \"☃\" : [ \"☃\","
|
||||
" \"☃\" ] }, \"☃\" : true }, \"baz\" : [ \"☃\" ], foo : \"☃\",}",
|
||||
false); // first key needs to be quoted since it contains a space
|
||||
}
|
||||
|
||||
TEST(utilities, json_array_with_newline) {
|
||||
TEST_VM(utilities, json_array_with_newline) {
|
||||
JSON_GTest::test("[\n]", true);
|
||||
}
|
||||
|
||||
TEST(utilities, json_directives_file) {
|
||||
TEST_VM(utilities, json_directives_file) {
|
||||
JSON_GTest::test(
|
||||
"[" "\n"
|
||||
" {"
|
||||
|
226
hotspot/test/native/utilities/test_resourceHash.cpp
Normal file
226
hotspot/test/native/utilities/test_resourceHash.cpp
Normal file
@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, 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.
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "unittest.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/resourceHash.hpp"
|
||||
|
||||
class CommonResourceHashtableTest : public ::testing::Test {
|
||||
protected:
|
||||
typedef void* K;
|
||||
typedef int V;
|
||||
const static MEMFLAGS MEM_TYPE = mtInternal;
|
||||
|
||||
static unsigned identity_hash(const K& k) {
|
||||
return (unsigned) (uintptr_t) k;
|
||||
}
|
||||
|
||||
static unsigned bad_hash(const K& k) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void* as_K(uintptr_t val) {
|
||||
return (void*) val;
|
||||
}
|
||||
|
||||
class EqualityTestIter {
|
||||
public:
|
||||
|
||||
bool do_entry(K const& k, V const& v) {
|
||||
if ((uintptr_t) k != (uintptr_t) v) {
|
||||
EXPECT_EQ((uintptr_t) k, (uintptr_t) v);
|
||||
return false;
|
||||
} else {
|
||||
return true; // continue iteration
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class SmallResourceHashtableTest : public CommonResourceHashtableTest {
|
||||
protected:
|
||||
|
||||
template<
|
||||
unsigned (*HASH) (K const&) = primitive_hash<K>,
|
||||
bool (*EQUALS)(K const&, K const&) = primitive_equals<K>,
|
||||
unsigned SIZE = 256,
|
||||
ResourceObj::allocation_type ALLOC_TYPE = ResourceObj::RESOURCE_AREA
|
||||
>
|
||||
class Runner : public AllStatic {
|
||||
public:
|
||||
|
||||
static void test(V step) {
|
||||
EqualityTestIter et;
|
||||
ResourceHashtable<K, V, HASH, EQUALS, SIZE, ALLOC_TYPE, MEM_TYPE> rh;
|
||||
|
||||
ASSERT_FALSE(rh.contains(as_K(step)));
|
||||
|
||||
ASSERT_TRUE(rh.put(as_K(step), step));
|
||||
ASSERT_TRUE(rh.contains(as_K(step)));
|
||||
|
||||
ASSERT_FALSE(rh.put(as_K(step), step));
|
||||
|
||||
ASSERT_TRUE(rh.put(as_K(2 * step), 2 * step));
|
||||
ASSERT_TRUE(rh.put(as_K(3 * step), 3 * step));
|
||||
ASSERT_TRUE(rh.put(as_K(4 * step), 4 * step));
|
||||
ASSERT_TRUE(rh.put(as_K(5 * step), 5 * step));
|
||||
|
||||
ASSERT_FALSE(rh.remove(as_K(0x0)));
|
||||
|
||||
rh.iterate(&et);
|
||||
if (::testing::Test::HasFailure()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT_TRUE(rh.remove(as_K(step)));
|
||||
rh.iterate(&et);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
TEST_VM_F(SmallResourceHashtableTest, default) {
|
||||
ResourceMark rm;
|
||||
Runner<>::test(0x1);
|
||||
}
|
||||
|
||||
TEST_VM_F(SmallResourceHashtableTest, default_shifted) {
|
||||
ResourceMark rm;
|
||||
Runner<>::test(0x10);
|
||||
}
|
||||
|
||||
TEST_VM_F(SmallResourceHashtableTest, bad_hash) {
|
||||
ResourceMark rm;
|
||||
Runner<bad_hash>::test(0x1);
|
||||
}
|
||||
|
||||
TEST_VM_F(SmallResourceHashtableTest, bad_hash_shifted) {
|
||||
ResourceMark rm;
|
||||
Runner<bad_hash>::test(0x10);
|
||||
}
|
||||
|
||||
TEST_VM_F(SmallResourceHashtableTest, identity_hash) {
|
||||
ResourceMark rm;
|
||||
Runner<identity_hash>::test(0x1);
|
||||
}
|
||||
|
||||
TEST_VM_F(SmallResourceHashtableTest, identity_hash_shifted) {
|
||||
ResourceMark rm;
|
||||
Runner<identity_hash>::test(0x10);
|
||||
}
|
||||
|
||||
TEST_VM_F(SmallResourceHashtableTest, primitive_hash_no_rm) {
|
||||
Runner<primitive_hash<K>, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test(0x1);
|
||||
}
|
||||
|
||||
TEST_VM_F(SmallResourceHashtableTest, primitive_hash_no_rm_shifted) {
|
||||
Runner<primitive_hash<K>, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test(0x10);
|
||||
}
|
||||
|
||||
TEST_VM_F(SmallResourceHashtableTest, bad_hash_no_rm) {
|
||||
Runner<bad_hash, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test(0x1);
|
||||
}
|
||||
|
||||
TEST_VM_F(SmallResourceHashtableTest, bad_hash_no_rm_shifted) {
|
||||
Runner<bad_hash, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test(0x10);
|
||||
}
|
||||
|
||||
TEST_VM_F(SmallResourceHashtableTest, identity_hash_no_rm) {
|
||||
Runner<identity_hash, primitive_equals<K>, 1, ResourceObj::C_HEAP>::test(0x1);
|
||||
}
|
||||
|
||||
TEST_VM_F(SmallResourceHashtableTest, identity_hash_no_rm_shifted) {
|
||||
Runner<identity_hash, primitive_equals<K>, 1, ResourceObj::C_HEAP>::test(0x10);
|
||||
}
|
||||
|
||||
class GenericResourceHashtableTest : public CommonResourceHashtableTest {
|
||||
protected:
|
||||
|
||||
template<
|
||||
unsigned (*HASH) (K const&) = primitive_hash<K>,
|
||||
bool (*EQUALS)(K const&, K const&) = primitive_equals<K>,
|
||||
unsigned SIZE = 256,
|
||||
ResourceObj::allocation_type ALLOC_TYPE = ResourceObj::RESOURCE_AREA
|
||||
>
|
||||
class Runner : public AllStatic {
|
||||
public:
|
||||
|
||||
static void test(unsigned num_elements = SIZE) {
|
||||
EqualityTestIter et;
|
||||
ResourceHashtable<K, V, HASH, EQUALS, SIZE, ALLOC_TYPE, MEM_TYPE> rh;
|
||||
|
||||
for (uintptr_t i = 0; i < num_elements; ++i) {
|
||||
ASSERT_TRUE(rh.put(as_K(i), i));
|
||||
}
|
||||
|
||||
rh.iterate(&et);
|
||||
if (::testing::Test::HasFailure()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uintptr_t i = num_elements; i > 0; --i) {
|
||||
uintptr_t index = i - 1;
|
||||
ASSERT_TRUE((rh.remove(as_K(index))));
|
||||
}
|
||||
|
||||
rh.iterate(&et);
|
||||
if (::testing::Test::HasFailure()) {
|
||||
return;
|
||||
}
|
||||
for (uintptr_t i = num_elements; i > 0; --i) {
|
||||
uintptr_t index = i - 1;
|
||||
ASSERT_FALSE(rh.remove(as_K(index)));
|
||||
}
|
||||
rh.iterate(&et);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
TEST_VM_F(GenericResourceHashtableTest, default) {
|
||||
ResourceMark rm;
|
||||
Runner<>::test();
|
||||
}
|
||||
|
||||
TEST_VM_F(GenericResourceHashtableTest, bad_hash) {
|
||||
ResourceMark rm;
|
||||
Runner<bad_hash>::test();
|
||||
}
|
||||
|
||||
TEST_VM_F(GenericResourceHashtableTest, identity_hash) {
|
||||
ResourceMark rm;
|
||||
Runner<identity_hash>::test();
|
||||
}
|
||||
|
||||
TEST_VM_F(GenericResourceHashtableTest, primitive_hash_no_rm) {
|
||||
Runner<primitive_hash<K>, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test();
|
||||
}
|
||||
|
||||
TEST_VM_F(GenericResourceHashtableTest, bad_hash_no_rm) {
|
||||
Runner<bad_hash, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test();
|
||||
}
|
||||
|
||||
TEST_VM_F(GenericResourceHashtableTest, identity_hash_no_rm) {
|
||||
Runner<identity_hash, primitive_equals<K>, 1, ResourceObj::C_HEAP>::test(512);
|
||||
}
|
104
hotspot/test/runtime/RedefineTests/RedefineInterfaceMethods.java
Normal file
104
hotspot/test/runtime/RedefineTests/RedefineInterfaceMethods.java
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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
|
||||
* @bug 8081800
|
||||
* @summary Redefine private and default interface methods
|
||||
* @library /test/lib
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @modules java.compiler
|
||||
* java.instrument
|
||||
* jdk.jartool/sun.tools.jar
|
||||
* @run main RedefineClassHelper
|
||||
* @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class*=trace RedefineInterfaceMethods
|
||||
*/
|
||||
public class RedefineInterfaceMethods {
|
||||
|
||||
static final int RET = -2;
|
||||
|
||||
static interface B {
|
||||
int ORIGINAL_RETURN = 1;
|
||||
int NEW_RETURN = 2;
|
||||
private int privateMethod() {
|
||||
return ORIGINAL_RETURN;
|
||||
}
|
||||
public default int defaultMethod() {
|
||||
return privateMethod();
|
||||
}
|
||||
}
|
||||
|
||||
public static String redefinedPrivateMethod =
|
||||
"interface RedefineInterfaceMethods$B {" +
|
||||
" int ORIGINAL_RETURN = 1;" +
|
||||
" int NEW_RETURN = 2;" +
|
||||
" private int privateMethod() {" +
|
||||
" return NEW_RETURN;" +
|
||||
" }" +
|
||||
" public default int defaultMethod() {" +
|
||||
" return privateMethod();" +
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
public static String redefinedDefaultMethod =
|
||||
"interface RedefineInterfaceMethods$B {" +
|
||||
" int ORIGINAL_RETURN = 1;" +
|
||||
" int NEW_RETURN = 2;" +
|
||||
" private int privateMethod() {" +
|
||||
" return ORIGINAL_RETURN;" +
|
||||
" }" +
|
||||
" public default int defaultMethod() {" +
|
||||
" return RedefineInterfaceMethods.RET;" +
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
static class Impl implements B {
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
Impl impl = new Impl();
|
||||
|
||||
int res = impl.defaultMethod();
|
||||
if (res != B.ORIGINAL_RETURN)
|
||||
throw new Error("defaultMethod returned " + res +
|
||||
" expected " + B.ORIGINAL_RETURN);
|
||||
|
||||
RedefineClassHelper.redefineClass(B.class, redefinedPrivateMethod);
|
||||
|
||||
res = impl.defaultMethod();
|
||||
if (res != B.NEW_RETURN)
|
||||
throw new Error("defaultMethod returned " + res +
|
||||
" expected " + B.NEW_RETURN);
|
||||
|
||||
System.gc();
|
||||
|
||||
RedefineClassHelper.redefineClass(B.class, redefinedDefaultMethod);
|
||||
|
||||
res = impl.defaultMethod();
|
||||
if (res != RET)
|
||||
throw new Error("defaultMethod returned " + res +
|
||||
" expected " + RET);
|
||||
}
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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
|
||||
* @bug 8081800
|
||||
* @summary Add JNI invocation tests for private interface methods
|
||||
* @run main/native PrivateInterfaceMethods
|
||||
*/
|
||||
|
||||
public class PrivateInterfaceMethods {
|
||||
|
||||
static {
|
||||
System.loadLibrary("PrivateInterfaceMethods");
|
||||
}
|
||||
|
||||
static native int callIntVoid(Object target, String definingClassName, String methodName, boolean virtual);
|
||||
|
||||
static interface A {
|
||||
static final int AmResult = 1;
|
||||
private int m() { return AmResult; }
|
||||
}
|
||||
|
||||
static interface B extends A {
|
||||
// No m() here
|
||||
}
|
||||
|
||||
static interface C extends B {
|
||||
static final int CmResult = 2;
|
||||
private int m() { return CmResult; } // unrelated to A.m
|
||||
}
|
||||
|
||||
public static class Impl implements C {
|
||||
static final int ImplmResult = 3;
|
||||
private int m() { return ImplmResult; } // unrelated to A.m or C.m
|
||||
}
|
||||
|
||||
// We found that itable/vtable construction was affected by whether or not the
|
||||
// implementation class declared a method with the same signature as the
|
||||
// private interface method, so we test both variants.
|
||||
|
||||
public static class Impl2 implements C {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Impl impl = new Impl();
|
||||
|
||||
// Note: JNI doesn't enforce access control so we can make
|
||||
// private calls not possible in Java code.
|
||||
// Also it doesn't check that the receiver is a type that
|
||||
// defines the method!
|
||||
|
||||
// test: ((A)impl).m() - should succeed
|
||||
test(impl, A.class.getName(), "m", A.AmResult, true, null);
|
||||
test(impl, A.class.getName(), "m", A.AmResult, false, null);
|
||||
|
||||
// test: ((B)impl).m() - should fail: NoSuchMethodError
|
||||
test(impl, B.class.getName(), "m", -1, true, NoSuchMethodError.class);
|
||||
test(impl, B.class.getName(), "m", -1, false, NoSuchMethodError.class);
|
||||
|
||||
// test: ((C)impl).m() - should succeed
|
||||
test(impl, C.class.getName(), "m", C.CmResult, true, null);
|
||||
test(impl, C.class.getName(), "m", C.CmResult, false, null);
|
||||
|
||||
// test: impl.m() - should succeed
|
||||
test(impl, Impl.class.getName(), "m", Impl.ImplmResult, true, null);
|
||||
test(impl, Impl.class.getName(), "m", Impl.ImplmResult, false, null);
|
||||
|
||||
// ---
|
||||
|
||||
Impl2 impl2 = new Impl2();
|
||||
|
||||
// test: ((A)impl2).m() - should succeed
|
||||
test(impl2, A.class.getName(), "m", A.AmResult, true, null);
|
||||
test(impl2, A.class.getName(), "m", A.AmResult, false, null);
|
||||
|
||||
// test: ((B)impl2).m() - should fail: NoSuchMethodError
|
||||
test(impl2, B.class.getName(), "m", -1, true, NoSuchMethodError.class);
|
||||
test(impl2, B.class.getName(), "m", -1, false, NoSuchMethodError.class);
|
||||
|
||||
// test: ((C)impl2).m() - should succeed
|
||||
test(impl2, C.class.getName(), "m", C.CmResult, true, null);
|
||||
test(impl2, C.class.getName(), "m", C.CmResult, false, null);
|
||||
|
||||
// test: impl2.m() - should fail: NoSuchMethodError
|
||||
test(impl2, Impl2.class.getName(), "m", -1, true, NoSuchMethodError.class);
|
||||
test(impl2, Impl2.class.getName(), "m", -1, false, NoSuchMethodError.class);
|
||||
}
|
||||
|
||||
static void test(Object target, String definingClass, String method,
|
||||
int expected, boolean virtual, Class<?> expectedException) {
|
||||
|
||||
String desc = (virtual ? "Virtual" : "Nonvirtual") + " Invocation of " +
|
||||
definingClass + "." + method + " on instance of class " +
|
||||
target.getClass().getName();
|
||||
try {
|
||||
int res = callIntVoid(target, definingClass, method, virtual);
|
||||
if (expectedException != null)
|
||||
throw new Error(desc + " succeeded - but expected exception " + expectedException.getSimpleName());
|
||||
if (res != expected)
|
||||
throw new Error(desc + " got wrong result: " + res + " instead of " + expected);
|
||||
System.out.println(desc + " - passed");
|
||||
}
|
||||
catch (Throwable t) {
|
||||
if (t.getClass() != expectedException)
|
||||
throw new Error(desc + " failed", t);
|
||||
else
|
||||
System.out.println(desc + " threw " + expectedException.getSimpleName() + " as expected");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
// Private interface methods call test
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_PrivateInterfaceMethods_callIntVoid(JNIEnv *env, jclass unused, jobject impl, jstring defining_class_name,
|
||||
jstring method_name, jboolean virtual) {
|
||||
|
||||
// Lookup int method_name() in defining_class_name, and if it exists call impl.method_name()
|
||||
// using a virtual or non-virtual invocation as indicated
|
||||
|
||||
jmethodID m_id = NULL;
|
||||
jclass clazz = NULL;
|
||||
const char* name = NULL;
|
||||
|
||||
name = (*env)->GetStringUTFChars(env, defining_class_name, NULL);
|
||||
if (name == NULL) return -1;
|
||||
clazz = (*env)->FindClass(env, name);
|
||||
(*env)->ReleaseStringUTFChars(env, defining_class_name, name);
|
||||
if ((*env)->ExceptionCheck(env)) return -1;
|
||||
|
||||
name = (*env)->GetStringUTFChars(env, method_name, NULL);
|
||||
if (name == NULL) return -1;
|
||||
m_id = (*env)->GetMethodID(env, clazz, name, "()I");
|
||||
(*env)->ReleaseStringUTFChars(env, method_name, name);
|
||||
if ((*env)->ExceptionCheck(env)) return -1;
|
||||
|
||||
if (!virtual)
|
||||
return (*env)->CallNonvirtualIntMethod(env, impl, clazz, m_id);
|
||||
else
|
||||
return (*env)->CallIntMethod(env, impl, m_id);
|
||||
}
|
@ -47,7 +47,7 @@ public class ItablesTest {
|
||||
output.shouldContain(": Initializing itable indices for interface ");
|
||||
output.shouldContain("itable index ");
|
||||
output.shouldContain("target: ClassB.Method1()V, method_holder: ClassB target_method flags: public");
|
||||
output.shouldContain("invokeinterface resolved method: caller-class");
|
||||
output.shouldContain("invokeinterface resolved interface method: caller-class");
|
||||
output.shouldContain("invokespecial resolved method: caller-class:ClassB");
|
||||
output.shouldContain("invokespecial selected method: resolved-class:ClassB");
|
||||
output.shouldContain("invokeinterface selected method: receiver-class");
|
||||
|
67
hotspot/test/runtime/logging/StackWalkTest.java
Normal file
67
hotspot/test/runtime/logging/StackWalkTest.java
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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 StackWalkTest
|
||||
* @bug 8160064
|
||||
* @summary -Xlog:stackwalk should produce logging from the source code
|
||||
* @library /test/lib
|
||||
* @run driver StackWalkTest
|
||||
*/
|
||||
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
public class StackWalkTest {
|
||||
static void analyzeOutputOn(ProcessBuilder pb) throws Exception {
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("Start walking");
|
||||
output.shouldContain("fill_in_frames");
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
static void analyzeOutputOff(ProcessBuilder pb) throws Exception {
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldNotContain("[stackwalk]");
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:stackwalk=debug",
|
||||
InnerClass.class.getName());
|
||||
analyzeOutputOn(pb);
|
||||
|
||||
pb = ProcessTools.createJavaProcessBuilder("-Xlog:stackwalk=off",
|
||||
InnerClass.class.getName());
|
||||
analyzeOutputOff(pb);
|
||||
}
|
||||
|
||||
public static class InnerClass {
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("Testing stackwalk.");
|
||||
StackWalker sw = StackWalker.getInstance();
|
||||
sw.forEach(System.out::println);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user