This commit is contained in:
Andrew Haley 2016-10-06 09:36:23 +00:00
commit 810f5aada6
47 changed files with 1628 additions and 1578 deletions

View File

@ -190,6 +190,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
@ -219,6 +224,7 @@ $(eval $(call SetupNativeCompilation, BUILD_LIBJVM, \
MAPFILE := $(JVM_MAPFILE), \
USE_MAPFILE_FOR_SYMBOLS := true, \
STRIP_SYMBOLS := $(JVM_STRIP_SYMBOLS), \
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

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

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

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

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

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

File diff suppressed because it is too large Load Diff

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

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

@ -59,22 +59,6 @@ void InternalVMTests::run() {
run_unit_test(TestOldSize_test);
run_unit_test(TestBitMap_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

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