Merge
authoraph
Thu, 06 Oct 2016 09:36:23 +0000
changeset 41689 ec4a65c134b4
parent 41688 230f8c29f67b (current diff)
parent 41687 6b97c4598667 (diff)
child 41690 038f2064e729
child 41729 d852f04fa9df
Merge
hotspot/src/share/vm/logging/log.cpp
--- 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(),
                            &notOlder,
-                           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(),
                            &notOlder,
-                           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(),
                              &notOlder,
-                             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"
             "   {"