--- a/hotspot/make/lib/CompileJvm.gmk Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/make/lib/CompileJvm.gmk Thu Oct 06 09:36:23 2016 +0000
@@ -190,6 +190,11 @@
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 @@
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, \
--- a/hotspot/make/lib/JvmFeatures.gmk Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/make/lib/JvmFeatures.gmk Thu Oct 06 09:36:23 2016 +0000
@@ -59,6 +59,10 @@
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)
--- a/hotspot/src/cpu/aarch64/vm/aarch64.ad Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad Thu Oct 06 09:36:23 2016 +0000
@@ -3496,6 +3496,16 @@
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
--- a/hotspot/src/cpu/ppc/vm/ppc.ad Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/cpu/ppc/vm/ppc.ad Thu Oct 06 09:36:23 2016 +0000
@@ -1097,21 +1097,19 @@
// 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 @@
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 @@
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,31 +2582,29 @@
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 @@
} 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();
-
- // 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));
+ // 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));
// The real call.
// Note: At this point we do not have the address of the trampoline
--- a/hotspot/src/cpu/sparc/vm/sparc.ad Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad Thu Oct 06 09:36:23 2016 +0000
@@ -2003,6 +2003,20 @@
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
--- a/hotspot/src/cpu/x86/vm/x86_32.ad Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/cpu/x86/vm/x86_32.ad Thu Oct 06 09:36:23 2016 +0000
@@ -1452,6 +1452,15 @@
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
--- a/hotspot/src/cpu/x86/vm/x86_64.ad Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/cpu/x86/vm/x86_64.ad Thu Oct 06 09:36:23 2016 +0000
@@ -1660,6 +1660,19 @@
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
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java Thu Oct 06 09:36:23 2016 +0000
@@ -90,14 +90,17 @@
* 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 @@
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;
@@ -147,6 +150,13 @@
}
/**
+ * 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.
*
* @return option's value
@@ -165,16 +175,31 @@
}
/**
- * 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 @@
@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 @@
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 @@
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) {
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java Thu Oct 06 09:36:23 2016 +0000
@@ -53,9 +53,9 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
@Override
protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) {
- return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET);
+ return getNonprofiledCount(data, position);
}
}
@@ -788,7 +810,8 @@
@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 @@
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++;
}
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java Thu Oct 06 09:36:23 2016 +0000
@@ -57,6 +57,18 @@
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) {
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java Thu Oct 06 09:36:23 2016 +0000
@@ -434,7 +434,6 @@
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());
}
}
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java Thu Oct 06 09:36:23 2016 +0000
@@ -160,6 +160,10 @@
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);
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/services/JVMCICompilerFactory.java Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/services/JVMCICompilerFactory.java Thu Oct 06 09:36:23 2016 +0000
@@ -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 @@
* 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) {
+ }
}
--- a/hotspot/src/share/vm/asm/assembler.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/asm/assembler.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -153,6 +153,8 @@
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 {
--- a/hotspot/src/share/vm/asm/codeBuffer.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/asm/codeBuffer.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -331,6 +331,8 @@
}
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;
--- a/hotspot/src/share/vm/asm/codeBuffer.hpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/asm/codeBuffer.hpp Thu Oct 06 09:36:23 2016 +0000
@@ -92,6 +92,7 @@
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 @@
_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 @@
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)
--- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -2340,13 +2340,11 @@
{
StrongRootsScope srs(1);
- gch->gen_process_roots(&srs,
- GenCollectedHeap::OldGen,
+ gch->cms_process_roots(&srs,
true, // young gen as roots
GenCollectedHeap::ScanningOption(roots_scanning_options()),
should_unload_classes(),
¬Older,
- NULL,
NULL);
}
@@ -2414,13 +2412,11 @@
{
StrongRootsScope srs(1);
- gch->gen_process_roots(&srs,
- GenCollectedHeap::OldGen,
+ gch->cms_process_roots(&srs,
true, // young gen as roots
GenCollectedHeap::ScanningOption(roots_scanning_options()),
should_unload_classes(),
¬Older,
- NULL,
&cld_closure);
}
@@ -2903,13 +2899,11 @@
StrongRootsScope srs(1);
- gch->gen_process_roots(&srs,
- GenCollectedHeap::OldGen,
+ gch->cms_process_roots(&srs,
true, // young gen as roots
GenCollectedHeap::ScanningOption(roots_scanning_options()),
should_unload_classes(),
¬Older,
- NULL,
&cld_closure);
}
}
@@ -4290,13 +4284,11 @@
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 @@
// ---------- 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 @@
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()
--- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -605,14 +605,10 @@
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();
--- a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -648,15 +648,10 @@
// 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".
--- a/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -196,14 +196,13 @@
{
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 @@
{
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);
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -613,16 +613,6 @@
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::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);
+ 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);
+ }
+
+ 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());
+}
- 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();
- }
- }
- // 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();
+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());
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp Thu Oct 06 09:36:23 2016 +0000
@@ -374,16 +374,7 @@
// 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 @@
CLDClosure* weak_cld_closure,
CodeBlobToOopClosure* code_roots);
+ void process_string_table_roots(StrongRootsScope* scope,
+ OopClosure* root_closure);
+
public:
- static const bool StrongAndWeakRoots = false;
- static const bool StrongRootsOnly = true;
+ void young_process_roots(StrongRootsScope* scope,
+ OopsInGenClosure* root_closure,
+ OopsInGenClosure* old_gen_closure,
+ CLDClosure* cld_closure);
- void gen_process_roots(StrongRootsScope* scope,
- GenerationType type,
+ // 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.
--- a/hotspot/src/share/vm/interpreter/invocationCounter.hpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/interpreter/invocationCounter.hpp Thu Oct 06 09:36:23 2016 +0000
@@ -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]
--- a/hotspot/src/share/vm/jvmci/jvmci_globals.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/jvmci/jvmci_globals.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -85,6 +85,7 @@
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
--- a/hotspot/src/share/vm/jvmci/jvmci_globals.hpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/jvmci/jvmci_globals.hpp Thu Oct 06 09:36:23 2016 +0000
@@ -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") \
\
--- a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -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) \
--- a/hotspot/src/share/vm/logging/log.cpp Thu Oct 06 09:25:21 2016 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1197 +0,0 @@
-/*
- * 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"
-
-/////////////// Unit tests ///////////////
-
-#ifndef PRODUCT
-
-#include "gc/shared/gcTraceTime.inline.hpp"
-#include "logging/log.hpp"
-#include "logging/logConfiguration.hpp"
-#include "logging/logFileOutput.hpp"
-#include "logging/logMessage.hpp"
-#include "logging/logMessageBuffer.hpp"
-#include "logging/logOutput.hpp"
-#include "logging/logTagLevelExpression.hpp"
-#include "logging/logTagSet.hpp"
-#include "logging/logTagSetDescriptions.hpp"
-#include "logging/logStream.inline.hpp"
-#include "memory/resourceArea.hpp"
-
-#define assert_str_eq(s1, s2) \
- assert(strcmp(s1, s2) == 0, "Expected '%s' to equal '%s'", s1, s2)
-
-#define assert_char_in(c, s) \
- assert(strchr(s, c) != NULL, "Expected '%s' to contain character '%c'", s, c)
-
-#define assert_char_not_in(c, s) \
- assert(strchr(s, c) == NULL, "Expected '%s' to *not* contain character '%c'", s, c)
-
-void Test_log_tag_combinations_limit() {
- assert(LogTagLevelExpression::MaxCombinations > LogTagSet::ntagsets(),
- "Combination limit (" SIZE_FORMAT ") not sufficient "
- "for configuring all available tag sets (" SIZE_FORMAT ")",
- LogTagLevelExpression::MaxCombinations, LogTagSet::ntagsets());
-}
-
-// Read a complete line from fp and return it as a resource allocated string.
-// Returns NULL on EOF.
-static char* read_line(FILE* fp) {
- assert(fp != NULL, "bad 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 bool file_contains_substring(const char* filename, const char* substr) {
- const char* strs[] = {substr, NULL};
- return file_contains_substrings_in_order(filename, strs);
-}
-
-static size_t number_of_lines_with_substring_in_file(const char* filename,
- const char* substr) {
- FILE* fp = fopen(filename, "r");
- assert(fp != NULL, "error opening file %s: %s", filename, strerror(errno));
-
- size_t ret = 0;
- for (;;) {
- ResourceMark rm;
- char* line = read_line(fp);
- if (line == NULL) {
- break;
- }
- if (strstr(line, substr) != NULL) {
- ret++;
- }
- }
-
- fclose(fp);
- return ret;
-}
-
-static bool file_exists(const char* filename) {
- struct stat st;
- return os::stat(filename, &st) == 0;
-}
-
-static void delete_file(const char* filename) {
- if (!file_exists(filename)) {
- return;
- }
- int ret = remove(filename);
- assert(ret == 0, "failed to remove file '%s': %s", filename, strerror(errno));
-}
-
-static 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);
-}
-
-class TestLogFile {
- private:
- char file_name[256];
-
- void set_name(const char* test_name) {
- const char* tmpdir = os::get_temp_directory();
- int pos = jio_snprintf(file_name, sizeof(file_name), "%s%svmtest.%s.%d.log", tmpdir, os::file_separator(), test_name, os::current_process_id());
- assert(pos > 0, "too small log file name buffer");
- assert((size_t)pos < sizeof(file_name), "too small log file name buffer");
- }
-
- public:
- TestLogFile(const char* test_name) {
- set_name(test_name);
- remove(name());
- }
-
- ~TestLogFile() {
- remove(name());
- }
-
- const char* name() {
- return file_name;
- }
-};
-
-class TestLogSavedConfig {
- private:
- char* _saved_config;
- char* _new_output;
- Log(logging) _log;
- public:
- TestLogSavedConfig(const char* apply_output = NULL, const char* apply_setting = NULL) : _new_output(0) {
- ResourceMark rm;
- _saved_config = os::strdup_check_oom(LogOutput::Stdout->config_string());
- bool success = LogConfiguration::parse_log_arguments("stdout", "all=off", NULL, NULL, _log.error_stream());
- assert(success, "test unable to turn all off");
-
- if (apply_output) {
- _new_output = os::strdup_check_oom(apply_output);
- bool success = LogConfiguration::parse_log_arguments(_new_output, apply_setting, NULL, NULL, _log.error_stream());
- assert(success, "test unable to apply test log configuration");
- }
- }
-
- ~TestLogSavedConfig() {
- ResourceMark rm;
- if (_new_output) {
- bool success = LogConfiguration::parse_log_arguments(_new_output, "all=off", NULL, NULL, _log.error_stream());
- assert(success, "test unable to turn all off");
- os::free(_new_output);
- }
-
- bool success = LogConfiguration::parse_log_arguments("stdout", _saved_config, NULL, NULL, _log.error_stream());
- assert(success, "test unable to restore log configuration");
- os::free(_saved_config);
- }
-};
-
-void Test_configure_stdout() {
- LogOutput* stdoutput = LogOutput::Stdout;
- TestLogSavedConfig tlsc;
-
- // Enable 'logging=info', verifying it has been set
- LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(logging));
- assert_str_eq("logging=info", stdoutput->config_string());
- assert(log_is_enabled(Info, logging), "logging was not properly enabled");
-
- // Enable 'gc=debug' (no wildcard), verifying no other tags are enabled
- LogConfiguration::configure_stdout(LogLevel::Debug, true, LOG_TAGS(gc));
- // No '+' character means only single tags are enabled, and no combinations
- assert_char_not_in('+', stdoutput->config_string());
- assert(log_is_enabled(Debug, gc), "logging was not properly enabled");
-
- // Enable 'gc*=trace' (with wildcard), verifying at least one tag combination is enabled (gc+...)
- LogConfiguration::configure_stdout(LogLevel::Trace, false, LOG_TAGS(gc));
- assert_char_in('+', stdoutput->config_string());
- assert(log_is_enabled(Trace, gc), "logging was not properly enabled");
-
- // Disable 'gc*' and 'logging', verifying all logging is properly disabled
- LogConfiguration::configure_stdout(LogLevel::Off, false, LOG_TAGS(gc));
- LogConfiguration::configure_stdout(LogLevel::Off, true, LOG_TAGS(logging));
- assert_str_eq("all=off", stdoutput->config_string());
-}
-
-static const char* ExpectedLine = "a (hopefully) unique log line for testing";
-
-static void init_file(const char* filename, const char* options = "") {
- LogConfiguration::parse_log_arguments(filename, "logging=trace", "", options,
- Log(logging)::error_stream());
- log_debug(logging)("%s", ExpectedLine);
- LogConfiguration::parse_log_arguments(filename, "all=off", "", "",
- Log(logging)::error_stream());
-}
-
-void Test_log_file_startup_rotation() {
- ResourceMark rm;
- const size_t rotations = 5;
- const char* filename = "start-rotate-test";
- char* rotated_file[rotations];
- for (size_t i = 0; i < rotations; i++) {
- size_t len = strlen(filename) + 3;
- rotated_file[i] = NEW_RESOURCE_ARRAY(char, len);
- jio_snprintf(rotated_file[i], len, "%s." SIZE_FORMAT, filename, i);
- delete_file(rotated_file[i]);
- };
-
- delete_file(filename);
- init_file(filename);
- assert(file_exists(filename),
- "configured logging to file '%s' but file was not found", filename);
-
- // Initialize the same file a bunch more times to trigger rotations
- for (size_t i = 0; i < rotations; i++) {
- init_file(filename);
- assert(file_exists(rotated_file[i]), "existing file was not rotated");
- }
-
- // Remove a file and expect its slot to be re-used
- delete_file(rotated_file[1]);
- init_file(filename);
- assert(file_exists(rotated_file[1]), "log file not properly rotated");
-
- // Clean up after test
- delete_file(filename);
- for (size_t i = 0; i < rotations; i++) {
- delete_file(rotated_file[i]);
- }
-}
-
-void Test_log_file_startup_truncation() {
- ResourceMark rm;
- 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_file(filename, "filecount=0");
- assert(file_exists(filename), "couldn't find log file: %s", filename);
-
- init_file(filename, "filecount=0");
- assert(file_exists(filename), "couldn't find log file: %s", filename);
- assert(!file_exists(archived_filename),
- "existing log file %s was not properly truncated when filecount was 0",
- filename);
-
- // Verify that the file was really truncated and not just appended
- assert(number_of_lines_with_substring_in_file(filename, ExpectedLine) == 1,
- "log file %s appended rather than truncated", filename);
-
- delete_file(filename);
- delete_file(archived_filename);
-}
-
-class LogMessageTest {
- private:
- static Log(logging) _log;
- static const char* _level_filename[];
-
- static void test_level_inclusion();
- static void test_long_message();
- static void test_message_with_many_lines();
- static void test_line_order();
- static void test_prefixing();
- static void test_scoped_messages();
- static void test_scoped_flushing();
- static void test_scoped_reset();
-
- public:
- static void test();
-};
-
-const char* LogMessageTest::_level_filename[] = {
- NULL, // LogLevel::Off
-#define LOG_LEVEL(name, printname) "multiline-" #printname ".log",
- LOG_LEVEL_LIST
-#undef LOG_LEVEL
-};
-
-void Test_multiline_logging() {
- LogMessageTest::test();
-}
-
-void LogMessageTest::test() {
- ResourceMark rm;
-
- 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)));
- bool success = LogConfiguration::parse_log_arguments(_level_filename[i], buf,
- NULL, NULL, _log.error_stream());
- assert(success, "unable to configure logging to file '%s'", _level_filename[i]);
- }
-
- test_level_inclusion();
- test_line_order();
- test_long_message();
- test_message_with_many_lines();
- test_prefixing();
- test_scoped_messages();
- test_scoped_flushing();
- test_scoped_reset();
-
- // Stop logging to the files and remove them.
- for (int i = 0; i < LogLevel::Count; i++) {
- LogConfiguration::parse_log_arguments(_level_filename[i], "all=off", NULL, NULL, _log.error_stream());
- remove(_level_filename[i]);
- }
-}
-
-// Verify that messages with multiple levels are written
-// to outputs configured for all the corresponding levels
-void LogMessageTest::test_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--) {
- assert(file_contains_substring(_level_filename[level], expected),
- "line #" SIZE_FORMAT " missing from log file '%s'", i, _level_filename[level]);
- }
- for (int level = lines[i].level + 1; level < LogLevel::Count; level++) {
- assert(!file_contains_substring(_level_filename[level], expected),
- "line #" SIZE_FORMAT " erroneously included in log file '%s'", i, _level_filename[level]);
- }
- }
-}
-
-// Verify that messages are logged in the order they are added to the log message
-void LogMessageTest::test_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 };
- assert(file_contains_substrings_in_order(_level_filename[LogLevel::Trace], expected),
- "output missing or in incorrect order");
-}
-
-void LogMessageTest::test_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 };
- assert(file_contains_substrings_in_order(_level_filename[LogLevel::Trace], expected),
- "unable to print long line");
- FREE_C_HEAP_ARRAY(char, data);
-}
-
-void LogMessageTest::test_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;
-
- assert(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;
-}
-
-void LogMessageTest::test_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
- };
- assert(file_contains_substrings_in_order(_level_filename[LogLevel::Trace], expected), "error in prefixed output");
-}
-
-void LogMessageTest::test_scoped_messages() {
- {
- LogMessage(logging) msg;
- msg.info("scoped info");
- msg.warning("scoped warn");
- assert(!file_contains_substring(_level_filename[LogLevel::Info], "scoped info"),
- "scoped log message written prematurely");
- }
- assert(file_contains_substring(_level_filename[LogLevel::Info], "scoped info"),
- "missing output from scoped log message");
- assert(file_contains_substring(_level_filename[LogLevel::Warning], "scoped warn"),
- "missing output from scoped log message");
-}
-
-void LogMessageTest::test_scoped_flushing() {
- {
- LogMessage(logging) msg;
- msg.info("manual flush info");
- msg.flush();
- assert(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};
- assert(!file_contains_substrings_in_order(_level_filename[LogLevel::Info], tmp),
- "log file contains duplicate lines from single scoped log message");
-}
-
-void LogMessageTest::test_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");
- }
- assert(!file_contains_substring(_level_filename[LogLevel::Info], "info reset msg"),
- "reset message written anyway");
- assert(file_contains_substring(_level_filename[LogLevel::Trace], "trace reset msg"),
- "missing message from partially reset scoped log message");
-}
-
-
-static int Test_logconfiguration_subscribe_triggered = 0;
-
-static void Test_logconfiguration_subscribe_helper() {
- Test_logconfiguration_subscribe_triggered++;
-}
-
-void Test_logconfiguration_subscribe() {
- ResourceMark rm;
- Log(logging) log;
-
- TestLogSavedConfig log_cfg("stdout", "logging*=trace");
-
- LogConfiguration::register_update_listener(&Test_logconfiguration_subscribe_helper);
-
- LogConfiguration::parse_log_arguments("stdout", "logging=trace", NULL, NULL, log.error_stream());
- assert(Test_logconfiguration_subscribe_triggered == 1, "subscription not triggered (1)");
-
- LogConfiguration::configure_stdout(LogLevel::Debug, true, LOG_TAGS(gc));
- assert(Test_logconfiguration_subscribe_triggered == 2, "subscription not triggered (2)");
-
- LogConfiguration::disable_logging();
- assert(Test_logconfiguration_subscribe_triggered == 3, "subscription not triggered (3)");
-}
-
-#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;
-}
-
-void Test_log_prefix() {
- TestLogFile log_file("log_prefix");
- TestLogSavedConfig log_cfg(log_file.name(), "logging+test=trace");
-
- log_trace(logging, test)(LOG_LINE_STR);
-
- FILE* fp = fopen(log_file.name(), "r");
- assert(fp, "File read error");
- char output[1024];
- if (fgets(output, 1024, fp) != NULL) {
- assert(strstr(output, LOG_PREFIX_STR LOG_LINE_STR), "logging prefix error");
- }
- fclose(fp);
-}
-
-void Test_log_big() {
- char big_msg[4096] = {0};
- char Xchar = '~';
-
- TestLogFile log_file("log_big");
- TestLogSavedConfig log_cfg(log_file.name(), "logging+test=trace");
-
- memset(big_msg, Xchar, sizeof(big_msg) - 1);
-
- log_trace(logging, test)("%s", big_msg);
-
- FILE* fp = fopen(log_file.name(), "r");
- assert(fp, "File read error");
- char output[sizeof(big_msg)+128 /*decorators*/ ];
- if (fgets(output, sizeof(output), fp) != NULL) {
- assert(strstr(output, LOG_PREFIX_STR), "logging prefix error");
- size_t count = 0;
- for (size_t ps = 0 ; output[ps + count] != '\0'; output[ps + count] == Xchar ? count++ : ps++);
- assert(count == (sizeof(big_msg) - 1) , "logging msg error");
- }
- fclose(fp);
-}
-
-void 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++) {
- assert(ts->tag(i) == LogTag::__NO_TAG,
- "NO_TAG was followed by a real tag (%s) in tagset %s",
- LogTag::name(ts->tag(i)), 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), ",");
- assert(false, "duplicate LogTagSets found: '%s' vs '%s' "
- "(tags must always be specified in the same order for each tagset)",
- ts_name, other_name);
- }
- }
- }
-}
-
-#define Test_logtarget_string_literal "First line"
-
-
-static void Test_logtarget_on() {
- TestLogFile log_file("log_target");
- TestLogSavedConfig tlsc(log_file.name(), "gc=debug");
-
- LogTarget(Debug, gc) log;
-
- assert(log.is_enabled(), "assert");
-
- // Log the line and expect it to be available in the output file.
- log.print(Test_logtarget_string_literal);
-
- FILE* fp = fopen(log_file.name(), "r");
- assert(fp != NULL, "File read error");
-
- char output[256 /* Large enough buffer */];
- char* res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- assert(strstr(output, Test_logtarget_string_literal) != NULL, "log line missing");
-
- fclose(fp);
-}
-
-static void Test_logtarget_off() {
- TestLogFile log_file("log_target");
- TestLogSavedConfig tlsc(log_file.name(), "gc=info");
-
- LogTarget(Debug, gc) log;
-
- if (log.is_enabled()) {
- // The log config could have been redirected gc=debug to a file. If gc=debug
- // is enabled, we can only test that the LogTarget returns the same value
- // as the log_is_enabled function. The rest of the test will be ignored.
- assert(log.is_enabled() == log_is_enabled(Debug, gc), "assert");
- log_warning(logging)("This test doesn't support runs with -Xlog");
- return;
- }
-
- // Try to log, but expect this to be filtered out.
- log.print(Test_logtarget_string_literal);
-
- // Log a dummy line so that fgets doesn't return NULL because the file is empty.
- log_info(gc)("Dummy line");
-
- FILE* fp = fopen(log_file.name(), "r");
- assert(fp != NULL, "File read error");
-
- char output[256 /* Large enough buffer */];
- char* res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- assert(strstr(output, Test_logtarget_string_literal) == NULL, "log line not missing");
-
- fclose(fp);
-}
-
-void Test_logtarget() {
- Test_logtarget_on();
- Test_logtarget_off();
-}
-
-
-static void Test_logstream_helper(outputStream* stream) {
- TestLogFile log_file("log_stream");
- TestLogSavedConfig tlsc(log_file.name(), "gc=debug");
-
- // Try to log, but expect this to be filtered out.
- stream->print("%d ", 3); stream->print("workers"); stream->cr();
-
- FILE* fp = fopen(log_file.name(), "r");
- assert(fp != NULL, "File read error");
-
- char output[256 /* Large enough buffer */];
- char* res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- assert(strstr(output, "3 workers") != NULL, "log line missing");
-
- fclose(fp);
-}
-
-static void Test_logstream_log() {
- Log(gc) log;
- LogStream stream(log.debug());
-
- Test_logstream_helper(&stream);
-}
-
-static void Test_logstream_logtarget() {
- LogTarget(Debug, gc) log;
- LogStream stream(log);
-
- Test_logstream_helper(&stream);
-}
-
-static void Test_logstream_logstreamhandle() {
- LogStreamHandle(Debug, gc) stream;
-
- Test_logstream_helper(&stream);
-}
-
-static void Test_logstream_no_rm() {
- ResourceMark rm;
- outputStream* stream = LogTarget(Debug, gc)::stream();
-
- Test_logstream_helper(stream);
-}
-
-static void Test_logstreamcheap_log() {
- Log(gc) log;
- LogStreamCHeap stream(log.debug());
-
- Test_logstream_helper(&stream);
-}
-
-static void Test_logstreamcheap_logtarget() {
- LogTarget(Debug, gc) log;
- LogStreamCHeap stream(log);
-
- Test_logstream_helper(&stream);
-}
-
-void Test_logstream() {
- // Test LogStreams with embedded ResourceMark.
- Test_logstream_log();
- Test_logstream_logtarget();
- Test_logstream_logstreamhandle();
-
- // Test LogStreams without embedded ResourceMark.
- Test_logstream_no_rm();
-
- // Test LogStreams backed by CHeap memory.
- Test_logstreamcheap_log();
- Test_logstreamcheap_logtarget();
-}
-
-void Test_loghandle_on() {
- TestLogFile log_file("log_handle");
- TestLogSavedConfig tlsc(log_file.name(), "gc=debug");
-
- Log(gc) log;
- LogHandle log_handle(log);
-
- assert(log_handle.is_debug(), "assert");
-
- // Try to log through a LogHandle.
- log_handle.debug("%d workers", 3);
-
- FILE* fp = fopen(log_file.name(), "r");
- assert(fp, "File read error");
-
- char output[256 /* Large enough buffer */];
- char* res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- assert(strstr(output, "3 workers") != NULL, "log line missing");
-
- fclose(fp);
-}
-
-void Test_loghandle_off() {
- TestLogFile log_file("log_handle");
- TestLogSavedConfig tlsc(log_file.name(), "gc=info");
-
- Log(gc) log;
- LogHandle log_handle(log);
-
- if (log_handle.is_debug()) {
- // The log config could have been redirected gc=debug to a file. If gc=debug
- // is enabled, we can only test that the LogTarget returns the same value
- // as the log_is_enabled function. The rest of the test will be ignored.
- assert(log_handle.is_debug() == log_is_enabled(Debug, gc), "assert");
- log_warning(logging)("This test doesn't support runs with -Xlog");
- return;
- }
-
- // Try to log through a LogHandle. Should fail, since only info is turned on.
- 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");
-
- FILE* fp = fopen(log_file.name(), "r");
- assert(fp, "File read error");
-
- char output[256 /* Large enough buffer */];
- char* res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- assert(strstr(output, "3 workers") == NULL, "log line missing");
-
- fclose(fp);
-}
-
-void Test_loghandle() {
- Test_loghandle_on();
- Test_loghandle_off();
-}
-
-static void Test_logtargethandle_on() {
- TestLogFile log_file("log_handle");
- TestLogSavedConfig tlsc(log_file.name(), "gc=debug");
-
- LogTarget(Debug, gc) log;
- LogTargetHandle log_handle(log);
-
- assert(log_handle.is_enabled(), "assert");
-
- // Try to log through a LogHandle.
- log_handle.print("%d workers", 3);
-
- FILE* fp = fopen(log_file.name(), "r");
- assert(fp, "File read error");
-
- char output[256 /* Large enough buffer */];
- char* res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- assert(strstr(output, "3 workers") != NULL, "log line missing");
-
- fclose(fp);
-}
-
-static void Test_logtargethandle_off() {
- TestLogFile log_file("log_handle");
- TestLogSavedConfig tlsc(log_file.name(), "gc=info");
-
- LogTarget(Debug, gc) log;
- LogTargetHandle log_handle(log);
-
- if (log_handle.is_enabled()) {
- // The log config could have been redirected gc=debug to a file. If gc=debug
- // is enabled, we can only test that the LogTarget returns the same value
- // as the log_is_enabled function. The rest of the test will be ignored.
- assert(log_handle.is_enabled() == log_is_enabled(Debug, gc), "assert");
- log_warning(logging)("This test doesn't support runs with -Xlog");
- return;
- }
-
- // Try to log through a LogHandle. Should fail, since only info is turned on.
- 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");
-
- FILE* fp = fopen(log_file.name(), "r");
- assert(fp, "File read error");
-
- char output[256 /* Large enough buffer */];
- char* res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- assert(strstr(output, "3 workers") == NULL, "log line missing");
-
- fclose(fp);
-}
-
-void Test_logtargethandle() {
- Test_logtargethandle_on();
- Test_logtargethandle_off();
-}
-
-static void Test_log_gctracetime_full() {
- TestLogFile log_file("log_gctracetime");
- TestLogSavedConfig tlsc(log_file.name(), "gc=debug,gc+start=debug");
-
- LogTarget(Debug, gc) gc_debug;
- LogTarget(Debug, gc, start) gc_start_debug;
-
- assert(gc_debug.is_enabled(), "assert");
- assert(gc_start_debug.is_enabled(), "assert");
-
- {
- MutexLocker lock(Heap_lock); // Needed to read heap usage
- GCTraceTime(Debug, gc) timer("Test GC", NULL, GCCause::_allocation_failure, true);
- }
-
- FILE* fp = fopen(log_file.name(), "r");
- assert(fp, "File read error");
-
- char output[256 /* Large enough buffer */];
-
- char* res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- // [2.975s][debug][gc,start] Test GC (Allocation Failure) (2.975s)
- assert(strstr(output, "[gc,start") != NULL, "Incorrect tag set");
- assert(strstr(output, "] Test GC (Allocation Failure) (") != NULL, "Incorrect log line");
- assert(strstr(output, "s)") != NULL, "Incorrect log line");
-
- res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- // [2.975s][debug][gc ] Test GC (Allocation Failure) 59M->59M(502M) (2.975s, 2.975s) 0.026ms
- assert(strstr(output, "[gc ") != NULL, "Incorrect tag set");
- assert(strstr(output, "] Test GC (Allocation Failure) ") != NULL, "Incorrect log line");
- assert(strstr(output, "M) (") != NULL, "Incorrect log line");
- assert(strstr(output, "s, ") != NULL, "Incorrect log line");
- assert(strstr(output, "s) ") != NULL, "Incorrect log line");
- assert(strstr(output, "ms") != NULL, "Incorrect log line");
-
- fclose(fp);
-}
-
-static void Test_log_gctracetime_full_multitag() {
- TestLogFile log_file("log_gctracetime");
- TestLogSavedConfig tlsc(log_file.name(), "gc+ref=debug,gc+ref+start=debug");
-
- LogTarget(Debug, gc, ref) gc_debug;
- LogTarget(Debug, gc, ref, start) gc_start_debug;
-
- assert(gc_debug.is_enabled(), "assert");
- assert(gc_start_debug.is_enabled(), "assert");
-
- {
- MutexLocker lock(Heap_lock); // Needed to read heap usage
- GCTraceTime(Debug, gc, ref) timer("Test GC", NULL, GCCause::_allocation_failure, true);
- }
-
- FILE* fp = fopen(log_file.name(), "r");
- assert(fp, "File read error");
-
- char output[256 /* Large enough buffer */];
-
- char* res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- // [2.975s][debug][gc,start] Test GC (Allocation Failure) (2.975s)
- assert(strstr(output, "[gc,ref,start") != NULL, "Incorrect tag set");
- assert(strstr(output, "] Test GC (Allocation Failure) (") != NULL, "Incorrect log line");
- assert(strstr(output, "s)") != NULL, "Incorrect log line");
-
- res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- // [2.975s][debug][gc ] Test GC (Allocation Failure) 59M->59M(502M) (2.975s, 2.975s) 0.026ms
- assert(strstr(output, "[gc,ref ") != NULL, "Incorrect tag set");
- assert(strstr(output, "] Test GC (Allocation Failure) ") != NULL, "Incorrect log line");
- assert(strstr(output, "M) (") != NULL, "Incorrect log line");
- assert(strstr(output, "s, ") != NULL, "Incorrect log line");
- assert(strstr(output, "s) ") != NULL, "Incorrect log line");
- assert(strstr(output, "ms") != NULL, "Incorrect log line");
-
- fclose(fp);
-}
-
-static void Test_log_gctracetime_no_heap() {
- TestLogFile log_file("log_gctracetime");
- TestLogSavedConfig tlsc(log_file.name(), "gc=debug,gc+start=debug");
-
- LogTarget(Debug, gc) gc_debug;
- LogTarget(Debug, gc, start) gc_start_debug;
-
- assert(gc_debug.is_enabled(), "assert");
- assert(gc_start_debug.is_enabled(), "assert");
-
- {
- GCTraceTime(Debug, gc) timer("Test GC", NULL, GCCause::_allocation_failure, false);
- }
-
- FILE* fp = fopen(log_file.name(), "r");
- assert(fp, "File read error");
-
- char output[256 /* Large enough buffer */];
-
- char* res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- // [2.975s][debug][gc,start] Test GC (Allocation Failure) (2.975s)
- assert(strstr(output, "[gc,start") != NULL, "Incorrect tag set");
- assert(strstr(output, "] Test GC (Allocation Failure) (") != NULL, "Incorrect log line");
- assert(strstr(output, "s)") != NULL, "Incorrect log line");
-
- res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- // [2.975s][debug][gc ] Test GC (Allocation Failure) (2.975s, 2.975s) 0.026ms
- assert(strstr(output, "[gc ") != NULL, "Incorrect tag set");
- assert(strstr(output, "] Test GC (Allocation Failure) (") != NULL, "Incorrect log line");
- assert(strstr(output, "M) (") == NULL, "Incorrect log line");
- assert(strstr(output, "s, ") != NULL, "Incorrect log line");
- assert(strstr(output, "s) ") != NULL, "Incorrect log line");
- assert(strstr(output, "ms") != NULL, "Incorrect log line");
-
- fclose(fp);
-}
-
-static void Test_log_gctracetime_no_cause() {
- TestLogFile log_file("log_gctracetime");
- TestLogSavedConfig tlsc(log_file.name(), "gc=debug,gc+start=debug");
-
- LogTarget(Debug, gc) gc_debug;
- LogTarget(Debug, gc, start) gc_start_debug;
-
- assert(gc_debug.is_enabled(), "assert");
- assert(gc_start_debug.is_enabled(), "assert");
-
- {
- MutexLocker lock(Heap_lock); // Needed to read heap usage
- GCTraceTime(Debug, gc) timer("Test GC", NULL, GCCause::_no_gc, true);
- }
-
- FILE* fp = fopen(log_file.name(), "r");
- assert(fp, "File read error");
-
- char output[256 /* Large enough buffer */];
-
- char* res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- // [2.975s][debug][gc,start] Test GC (2.975s)
- assert(strstr(output, "[gc,start") != NULL, "Incorrect tag set");
- assert(strstr(output, "] Test GC (") != NULL, "Incorrect log line");
- assert(strstr(output, "s)") != NULL, "Incorrect log line");
-
- res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- // [2.975s][debug][gc ] Test GC 59M->59M(502M) (2.975s, 2.975s) 0.026ms
- assert(strstr(output, "[gc ") != NULL, "Incorrect tag set");
- assert(strstr(output, "] Test GC ") != NULL, "Incorrect log line");
- assert(strstr(output, "M) (") != NULL, "Incorrect log line");
- assert(strstr(output, "s, ") != NULL, "Incorrect log line");
- assert(strstr(output, "s) ") != NULL, "Incorrect log line");
- assert(strstr(output, "ms") != NULL, "Incorrect log line");
-
- fclose(fp);
-}
-
-static void Test_log_gctracetime_no_heap_no_cause() {
- TestLogFile log_file("log_gctracetime");
- TestLogSavedConfig tlsc(log_file.name(), "gc=debug,gc+start=debug");
-
- LogTarget(Debug, gc) gc_debug;
- LogTarget(Debug, gc, start) gc_start_debug;
-
- assert(gc_debug.is_enabled(), "assert");
- assert(gc_start_debug.is_enabled(), "assert");
-
- {
- MutexLocker lock(Heap_lock); // Needed to read heap usage
- GCTraceTime(Debug, gc) timer("Test GC", NULL, GCCause::_no_gc, false);
- }
-
- FILE* fp = fopen(log_file.name(), "r");
- assert(fp, "File read error");
-
- char output[256 /* Large enough buffer */];
-
- char* res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- // [2.975s][debug][gc,start] Test GC (2.975s)
- assert(strstr(output, "[gc,start") != NULL, "Incorrect tag set");
- assert(strstr(output, "] Test GC (") != NULL, "Incorrect log line");
- assert(strstr(output, "s)") != NULL, "Incorrect log line");
-
- res = fgets(output, sizeof(output), fp);
- assert(res != NULL, "assert");
-
- // [2.975s][debug][gc ] Test GC (2.975s, 2.975s) 0.026ms
- assert(strstr(output, "[gc ") != NULL, "Incorrect tag set");
- assert(strstr(output, "] Test GC (") != NULL, "Incorrect log line");
- assert(strstr(output, "M) (") == NULL, "Incorrect log line");
- assert(strstr(output, "s, ") != NULL, "Incorrect log line");
- assert(strstr(output, "s) ") != NULL, "Incorrect log line");
- assert(strstr(output, "ms") != NULL, "Incorrect log line");
-
- fclose(fp);
-}
-
-void Test_log_gctracetime() {
- Test_log_gctracetime_full();
- Test_log_gctracetime_full_multitag();
- Test_log_gctracetime_no_heap();
- Test_log_gctracetime_no_cause();
- Test_log_gctracetime_no_heap_no_cause();
-}
-
-void Test_invalid_log_file() {
- ResourceMark rm;
- stringStream ss;
- const char* target_name = "tmplogdir";
-
- // Attempt to log to a directory (existing log not a regular file)
- create_directory(target_name);
- LogFileOutput bad_file("file=tmplogdir");
- assert(bad_file.initialize("", &ss) == false, "file was initialized "
- "when there was an existing directory with the same name");
- assert(strstr(ss.as_string(), "tmplogdir is not a regular file") != NULL,
- "missing expected error message, received msg: %s", ss.as_string());
- ss.reset();
- remove(target_name);
-}
-
-// Ensure -Xlog:help and LogConfiguration::describe contain tagset descriptions
-void Test_logtagset_descriptions() {
- for (LogTagSetDescription* d = tagset_descriptions; d->tagset != NULL; d++) {
- char expected[1024];
- d->tagset->label(expected, sizeof(expected), "+");
- jio_snprintf(expected + strlen(expected),
- sizeof(expected) - strlen(expected),
- ": %s", d->descr);
-
- ResourceMark rm;
- stringStream ss;
- LogConfiguration::describe(&ss);
- assert(strstr(ss.as_string(), expected) != NULL,
- "missing log tag set descriptions in LogConfiguration::describe");
-
- TestLogFile file("log_tagset_descriptions");
- FILE* fp = fopen(file.name(), "w+");
- assert(fp != NULL, "File open error");
- LogConfiguration::print_command_line_help(fp);
- fclose(fp);
- assert(number_of_lines_with_substring_in_file(file.name(), expected) > 0,
- "missing log tag set descriptions in -Xlog:help output");
- }
-}
-#endif // PRODUCT
--- a/hotspot/src/share/vm/opto/compile.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/opto/compile.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -574,6 +574,10 @@
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 @@
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 @@
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);
--- a/hotspot/src/share/vm/opto/matcher.hpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/opto/matcher.hpp Thu Oct 06 09:36:23 2016 +0000
@@ -457,6 +457,9 @@
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).
//
--- a/hotspot/src/share/vm/runtime/thread.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/runtime/thread.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -3768,10 +3768,21 @@
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
--- a/hotspot/src/share/vm/utilities/internalVMTests.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/src/share/vm/utilities/internalVMTests.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -59,22 +59,6 @@
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);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jvmci/TestJVMCIPrintProperties.java Thu Oct 06 09:36:23 2016 +0000
@@ -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);
+ }
+}
--- a/hotspot/test/native/classfile/test_symbolTable.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/test/native/classfile/test_symbolTable.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -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();
--- a/hotspot/test/native/gtestMain.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/test/native/gtestMain.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -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 @@
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,20 +155,24 @@
}
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";
+
+ 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;
}
}
- ::testing::InitGoogleTest(&argc, argv);
- ::testing::GTEST_FLAG(death_test_style) = "threadsafe";
-// ::testing::GTEST_FLAG(death_test_output_prefix) = "Other VM";
-
char* java_home = get_java_home_arg(argc, argv);
if (java_home == NULL) {
fprintf(stderr, "ERROR: You must specify a JDK to use for running the unit tests.\n");
@@ -184,8 +199,10 @@
#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 {
--- a/hotspot/test/native/logging/logTestUtils.inline.hpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/test/native/logging/logTestUtils.inline.hpp Thu Oct 06 09:36:23 2016 +0000
@@ -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 @@
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);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/test_gcTraceTime.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -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));
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/test_log.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -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"));
+}
--- a/hotspot/test/native/logging/test_logConfiguration.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/test/native/logging/test_logConfiguration.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -61,7 +61,7 @@
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 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 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, disable_logging) {
+TEST_VM_F(LogConfigurationTest, disable_logging) {
// Add TestLogFileName as an output
set_log_config(TestLogFileName, "logging=info");
@@ -185,7 +185,7 @@
}
// 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 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 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 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 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 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_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 @@
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++) {
--- a/hotspot/test/native/logging/test_logDecorations.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/test/native/logging/test_logDecorations.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -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, uptime) {
+TEST_VM(LogDecorations, uptime) {
// Verify the format of the decoration
int a, b;
char decimal_point;
@@ -73,7 +73,7 @@
}
}
-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 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;
--- a/hotspot/test/native/logging/test_logFileOutput.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/test/native/logging/test_logFileOutput.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -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 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 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 @@
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");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/test_logMessageTest.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -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";
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/test_logStream.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -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);
+}
--- a/hotspot/test/native/logging/test_logTagLevelExpression.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/test/native/logging/test_logTagLevelExpression.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -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[] = {
--- a/hotspot/test/native/logging/test_logTagSet.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/test/native/logging/test_logTagSet.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -128,3 +128,46 @@
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)";
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/logging/test_logTagSetDescriptions.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -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);
+}
--- a/hotspot/test/native/oops/test_arrayOop.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/test/native/oops/test_arrayOop.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -43,47 +43,47 @@
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()
--- a/hotspot/test/native/utilities/test_json.cpp Thu Oct 06 09:25:21 2016 +0000
+++ b/hotspot/test/native/utilities/test_json.cpp Thu Oct 06 09:36:23 2016 +0000
@@ -54,322 +54,322 @@
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"
" {"