This commit is contained in:
Alejandro Murillo 2016-10-13 08:57:54 -07:00
commit 82157115c2
84 changed files with 2494 additions and 1957 deletions

View File

@ -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, \

View File

@ -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)

View File

@ -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 \

View File

@ -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)
%{

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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++;
}

View File

@ -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) {

View File

@ -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());
}
}

View File

@ -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);

View File

@ -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) {
}
}

View File

@ -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 {

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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() {

View File

@ -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()) {

View File

@ -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,

View File

@ -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"));

View File

@ -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()) {

View File

@ -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");

View File

@ -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");
}

View File

@ -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",

View File

@ -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

View File

@ -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(),
&notOlder,
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(),
&notOlder,
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(),
&notOlder,
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()

View File

@ -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();

View File

@ -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".

View File

@ -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);

View File

@ -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());

View File

@ -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.

View File

@ -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]

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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") \
\

View File

@ -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) \

View File

@ -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) \

View File

@ -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

View File

@ -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.

View File

@ -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) \

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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");

View File

@ -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)

View File

@ -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);

View File

@ -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).
//

View File

@ -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

View File

@ -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.

View File

@ -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, \

View File

@ -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

View File

@ -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);

View File

@ -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

View 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);
}
}

View File

@ -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();

View File

@ -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 {

View File

@ -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);
}

View 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));
}

View 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"));
}

View File

@ -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++) {

View File

@ -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;

View File

@ -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");
}

View 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";
}

View 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);
}

View File

@ -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[] = {

View File

@ -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)";
}
}
}
}

View 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);
}

View File

@ -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()

View File

@ -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"
" {"

View 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);
}

View 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);
}
}

View File

@ -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");
}
}
}

View File

@ -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);
}

View File

@ -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");

View 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);
}
}
}