changeset 27200:29bb6b64d111

Merge
author Tom Rodriguez <tom.rodriguez@oracle.com>
date Mon, 18 Jan 2016 23:08:39 -0800
parents 4ee0c12489ec 2a2916923394
children 2832fba00c33
files .hgtags src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/InitTimer.java src/share/vm/c1/c1_Compilation.cpp src/share/vm/c1/c1_Compilation.hpp src/share/vm/c1/c1_Runtime1.cpp src/share/vm/ci/ciEnv.cpp src/share/vm/ci/ciEnv.hpp src/share/vm/ci/ciInstanceKlass.hpp src/share/vm/compiler/compileBroker.cpp src/share/vm/opto/compile.cpp src/share/vm/opto/compile.hpp src/share/vm/opto/escape.cpp src/share/vm/opto/graphKit.cpp src/share/vm/opto/graphKit.hpp src/share/vm/opto/ifnode.cpp src/share/vm/opto/library_call.cpp src/share/vm/opto/loopTransform.cpp src/share/vm/opto/loopopts.cpp src/share/vm/opto/node.cpp src/share/vm/opto/node.hpp src/share/vm/opto/parse2.cpp src/share/vm/opto/phaseX.cpp src/share/vm/opto/stringopts.cpp src/share/vm/opto/superword.cpp src/share/vm/prims/jvm.cpp src/share/vm/prims/nativeLookup.cpp src/share/vm/prims/perf.cpp src/share/vm/prims/whitebox.cpp src/share/vm/utilities/vmError.cpp
diffstat 44 files changed, 695 insertions(+), 167 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Mon Jan 18 10:58:08 2016 -0800
+++ b/.hgtags	Mon Jan 18 23:08:39 2016 -0800
@@ -502,3 +502,5 @@
 de592ea5f7ba0f8a8c5afc03bd169f7690c72b6f jdk-9+97
 e5b1a23be1e105417ba1c4c576ab373eb3fa2c2b jdk-9+98
 f008e8cc10d5b3212fb22d58c96fa01d38654f19 jdk-9+99
+bdb0acafc63c42e84d9d8195bf2e2b25ee9c3306 jdk-9+100
+9f45d3d57d6948cf526fbc2e2891a9a74ac6941a jdk-9+101
--- a/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java	Mon Jan 18 23:08:39 2016 -0800
@@ -27,6 +27,7 @@
 
 import java.lang.reflect.Array;
 
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option;
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.JavaConstant;
@@ -42,11 +43,6 @@
  */
 public class HotSpotConstantReflectionProvider implements ConstantReflectionProvider, HotSpotProxified {
 
-    /**
-     * Determines whether to treat {@code final} fields with default values as constant.
-     */
-    private static final boolean TrustFinalDefaultFields = HotSpotJVMCIRuntime.getBooleanProperty("TrustFinalDefaultFields", true);
-
     protected final HotSpotJVMCIRuntimeProvider runtime;
     protected final HotSpotMethodHandleAccessProvider methodHandleAccess;
     protected final HotSpotMemoryAccessProviderImpl memoryAccess;
@@ -249,14 +245,14 @@
      * Determines if a value read from a {@code final} instance field is considered constant. The
      * implementation in {@link HotSpotConstantReflectionProvider} returns true if {@code value} is
      * not the {@link JavaConstant#isDefaultForKind default value} for its kind or if
-     * {@link #TrustFinalDefaultFields} is true.
+     * {@link Option#TrustFinalDefaultFields} is true.
      *
      * @param value a value read from a {@code final} instance field
      * @param receiverClass the {@link Object#getClass() class} of object from which the
      *            {@code value} was read
      */
     protected boolean isFinalInstanceFieldValueConstant(JavaConstant value, Class<?> receiverClass) {
-        return !value.isDefaultForKind() || TrustFinalDefaultFields;
+        return !value.isDefaultForKind() || Option.TrustFinalDefaultFields.getBoolean();
     }
 
     /**
--- a/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java	Mon Jan 18 23:08:39 2016 -0800
@@ -26,6 +26,7 @@
 
 import java.io.IOException;
 import java.io.OutputStream;
+import java.io.PrintStream;
 import java.lang.reflect.Array;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
@@ -50,7 +51,7 @@
 import jdk.vm.ci.runtime.JVMCIBackend;
 import jdk.vm.ci.runtime.JVMCICompiler;
 import jdk.vm.ci.services.Services;
-import sun.misc.VM;
+import jdk.internal.misc.VM;
 
 //JaCoCo Exclude
 
@@ -86,19 +87,95 @@
     }
 
     /**
-     * Gets a boolean value based on a system property {@linkplain VM#getSavedProperty(String)
-     * saved} at system initialization time. The property name is prefixed with "{@code jvmci.}".
-     *
-     * @param name the name of the system property to derive a boolean value from using
-     *            {@link Boolean#parseBoolean(String)}
-     * @param def the value to return if there is no system property corresponding to {@code name}
+     * A list of all supported JVMCI options.
      */
-    public static boolean getBooleanProperty(String name, boolean def) {
-        String value = VM.getSavedProperty("jvmci." + name);
-        if (value == null) {
-            return def;
+    public enum Option {
+        ImplicitStableValues(boolean.class, true, "Mark well-known stable fields as such."),
+        // Note: The following one is not used (see InitTimer.ENABLED).
+        InitTimer(boolean.class, false, "Specifies if initialization timing is enabled."),
+        PrintConfig(boolean.class, false, "Prints all HotSpotVMConfig fields."),
+        PrintFlags(boolean.class, false, "Prints all JVMCI flags and exits."),
+        ShowFlags(boolean.class, false, "Prints all JVMCI flags and continues."),
+        TraceMethodDataFilter(String.class, null, ""),
+        TrustFinalDefaultFields(boolean.class, true, "Determines whether to treat final fields with default values as constant.");
+
+        /**
+         * The prefix for system properties that are JVMCI options.
+         */
+        private static final String JVMCI_OPTION_PROPERTY_PREFIX = "jvmci.";
+
+        /**
+         * Marker for uninitialized flags.
+         */
+        private static final String UNINITIALIZED = "UNINITIALIZED";
+
+        private final Class<?> type;
+        private Object value;
+        private final Object defaultValue;
+        private boolean isDefault;
+        private final String help;
+
+        private Option(Class<?> type, Object defaultValue, String help) {
+            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;
         }
-        return Boolean.parseBoolean(value);
+
+        private Object getValue() {
+            if (value == UNINITIALIZED) {
+                String propertyValue = VM.getSavedProperty(JVMCI_OPTION_PROPERTY_PREFIX + name());
+                if (propertyValue == null) {
+                    this.value = defaultValue;
+                    this.isDefault = true;
+                } else {
+                    if (type == boolean.class) {
+                        this.value = Boolean.parseBoolean(propertyValue);
+                    } else if (type == String.class) {
+                        this.value = propertyValue;
+                    } else {
+                        throw new JVMCIError("Unexpected option type " + type);
+                    }
+                    this.isDefault = false;
+                }
+                // Saved properties should not be interned - let's be sure
+                assert value != UNINITIALIZED;
+            }
+            return value;
+        }
+
+        /**
+         * Returns the option's value as boolean.
+         *
+         * @return option's value
+         */
+        public boolean getBoolean() {
+            return (boolean) getValue();
+        }
+
+        /**
+         * Returns the option's value as String.
+         *
+         * @return option's value
+         */
+        public String getString() {
+            return (String) getValue();
+        }
+
+        /**
+         * Prints all option flags to {@code out}.
+         *
+         * @param out stream to print to
+         */
+        public static void printFlags(PrintStream out) {
+            out.println("[List of JVMCI options]");
+            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);
+            }
+        }
     }
 
     public static HotSpotJVMCIBackendFactory findFactory(String architecture) {
@@ -165,7 +242,16 @@
         }
         metaAccessContext = context;
 
-        if (Boolean.valueOf(System.getProperty("jvmci.printconfig"))) {
+        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(config, compilerToVm);
         }
 
--- a/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java	Mon Jan 18 23:08:39 2016 -0800
@@ -29,6 +29,7 @@
 import java.lang.reflect.Field;
 
 import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option;
 import jdk.vm.ci.meta.JavaType;
 import jdk.vm.ci.meta.LocationIdentity;
 import jdk.vm.ci.meta.MetaAccessProvider;
@@ -41,11 +42,6 @@
  */
 class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField, HotSpotProxified {
 
-    /**
-     * Mark well-known stable fields as such.
-     */
-    private static final boolean ImplicitStableValues = HotSpotJVMCIRuntime.getBooleanProperty("ImplicitStableValues", true);
-
     private final HotSpotResolvedObjectTypeImpl holder;
     private final String name;
     private JavaType type;
@@ -198,7 +194,7 @@
             return true;
         }
         assert getAnnotation(Stable.class) == null;
-        if (ImplicitStableValues && isImplicitStableField()) {
+        if (Option.ImplicitStableValues.getBoolean() && isImplicitStableField()) {
             return true;
         }
         return false;
--- a/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java	Mon Jan 18 23:08:39 2016 -0800
@@ -37,6 +37,7 @@
 import java.util.Map;
 
 import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option;
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.ConstantPool;
 import jdk.vm.ci.meta.DefaultProfilingInfo;
@@ -417,8 +418,6 @@
         return false;
     }
 
-    private static final String TraceMethodDataFilter = System.getProperty("jvmci.traceMethodDataFilter");
-
     @Override
     public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) {
         ProfilingInfo info;
@@ -427,7 +426,8 @@
             long metaspaceMethodData = UNSAFE.getAddress(metaspaceMethod + config().methodDataOffset);
             if (metaspaceMethodData != 0) {
                 methodData = new HotSpotMethodData(metaspaceMethodData, this);
-                if (TraceMethodDataFilter != null && this.format("%H.%n").contains(TraceMethodDataFilter)) {
+                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/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/InitTimer.java	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/InitTimer.java	Mon Jan 18 23:08:39 2016 -0800
@@ -65,9 +65,10 @@
     }
 
     /**
-     * Specifies if initialization timing is enabled.
+     * Specifies if initialization timing is enabled. Note: This property cannot use
+     * {@code HotSpotJVMCIRuntime.Option} since that class is not visible from this package.
      */
-    private static final boolean ENABLED = Boolean.getBoolean("jvmci.inittimer") || Boolean.getBoolean("jvmci.runtime.TimeInit");
+    private static final boolean ENABLED = Boolean.getBoolean("jvmci.InitTimer");
 
     public static final AtomicInteger nesting = ENABLED ? new AtomicInteger() : null;
     public static final String SPACES = "                                            ";
--- a/src/share/vm/c1/c1_Compilation.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/c1/c1_Compilation.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -420,8 +420,7 @@
     implicit_exception_table(),
     compiler(),
     has_unsafe_access(),
-    SharedRuntime::is_wide_vector(max_vector_size()),
-    directive()
+    SharedRuntime::is_wide_vector(max_vector_size())
   );
 }
 
--- a/src/share/vm/c1/c1_Compilation.hpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/c1/c1_Compilation.hpp	Mon Jan 18 23:08:39 2016 -0800
@@ -28,6 +28,7 @@
 #include "ci/ciEnv.hpp"
 #include "ci/ciMethodData.hpp"
 #include "code/exceptionHandlerTable.hpp"
+#include "compiler/compilerDirectives.hpp"
 #include "memory/resourceArea.hpp"
 #include "runtime/deoptimization.hpp"
 
--- a/src/share/vm/c1/c1_Runtime1.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/c1/c1_Runtime1.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -964,7 +964,7 @@
         assert(cache_index >= 0 && cache_index < pool->cache()->length(), "unexpected cache index");
         ConstantPoolCacheEntry* cpce = pool->cache()->entry_at(cache_index);
         cpce->set_method_handle(pool, info);
-        appendix = info.resolved_appendix();  // just in case somebody already resolved the entry
+        appendix = cpce->appendix_if_resolved(pool); // just in case somebody already resolved the entry
         break;
       }
       case Bytecodes::_invokedynamic: {
@@ -975,8 +975,6 @@
       }
       default: fatal("unexpected bytecode for load_appendix_patching_id");
     }
-    assert(appendix.not_null(), "%s @ %d (%s)",
-           caller_method->name_and_sig_as_C_string(), bci, Bytecodes::name(bc));
   } else {
     ShouldNotReachHere();
   }
--- a/src/share/vm/ci/ciEnv.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/ci/ciEnv.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -38,7 +38,6 @@
 #include "code/scopeDesc.hpp"
 #include "compiler/compileBroker.hpp"
 #include "compiler/compileLog.hpp"
-#include "compiler/compilerDirectives.hpp"
 #include "compiler/disassembler.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
 #include "interpreter/linkResolver.hpp"
@@ -959,7 +958,6 @@
                             AbstractCompiler* compiler,
                             bool has_unsafe_access,
                             bool has_wide_vectors,
-                            DirectiveSet* directives,
                             RTMState  rtm_state) {
   VM_ENTRY_MARK;
   nmethod* nm = NULL;
@@ -1041,11 +1039,6 @@
     code_buffer->free_blob();
 
     if (nm != NULL) {
-      bool printnmethods = directives->PrintAssemblyOption || directives->PrintNMethodsOption;
-      if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) {
-        nm->print_nmethod(printnmethods);
-      }
-
       nm->set_has_unsafe_access(has_unsafe_access);
       nm->set_has_wide_vectors(has_wide_vectors);
 #if INCLUDE_RTM_OPT
--- a/src/share/vm/ci/ciEnv.hpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/ci/ciEnv.hpp	Mon Jan 18 23:08:39 2016 -0800
@@ -32,11 +32,9 @@
 #include "code/dependencies.hpp"
 #include "code/exceptionHandlerTable.hpp"
 #include "compiler/oopMap.hpp"
-#include "compiler/compilerDirectives.hpp"
 #include "runtime/thread.hpp"
 
 class CompileTask;
-class DirectiveSet;
 
 // ciEnv
 //
@@ -372,7 +370,6 @@
                        AbstractCompiler*         compiler,
                        bool                      has_unsafe_access,
                        bool                      has_wide_vectors,
-                       DirectiveSet*             directives,
                        RTMState                  rtm_state = NoRTM);
 
 
--- a/src/share/vm/ci/ciInstanceKlass.hpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/ci/ciInstanceKlass.hpp	Mon Jan 18 23:08:39 2016 -0800
@@ -174,7 +174,6 @@
       return 2;
     }
   }
-
   bool has_default_methods()  {
     assert(is_loaded(), "must be loaded");
     return _has_default_methods;
@@ -261,6 +260,11 @@
     return NULL;
   }
 
+  bool can_be_instantiated() {
+    assert(is_loaded(), "must be loaded");
+    return !is_interface() && !is_abstract();
+  }
+
   // Dump the current state of this klass for compilation replay.
   virtual void dump_replay_data(outputStream* out);
 };
--- a/src/share/vm/compiler/compileBroker.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/compiler/compileBroker.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -1900,12 +1900,25 @@
     }
   }
 
+    post_compile(thread, task, event, !ci_env.failing(), &ci_env);
+  }
+  pop_jni_handle_block();
+
   methodHandle method(thread, task->method());
 
   DTRACE_METHOD_COMPILE_END_PROBE(method, compiler_name(task_level), task->is_success());
 
   collect_statistics(thread, time, task);
 
+  bool printnmethods = directive->PrintAssemblyOption || directive->PrintNMethodsOption;
+  if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) {
+    nmethod* nm = task->code();
+    if (nm != NULL) {
+      nm->print_nmethod(printnmethods);
+    }
+  }
+  DirectivesStack::release(directive);
+
   if (PrintCompilation && PrintCompilation2) {
     tty->print("%7d ", (int) tty->time_stamp().milliseconds());  // print timestamp
     tty->print("%4d ", compile_id);    // print compilation number
--- a/src/share/vm/opto/arraycopynode.hpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/arraycopynode.hpp	Mon Jan 18 23:08:39 2016 -0800
@@ -89,7 +89,6 @@
   static const TypePtr* get_address_type(PhaseGVN *phase, Node* n);
 
   Node* try_clone_instance(PhaseGVN *phase, bool can_reshape, int count);
-  Node* conv_I2X_offset(PhaseGVN *phase, Node* offset, const TypeAryPtr* ary_t);
   bool prepare_array_copy(PhaseGVN *phase, bool can_reshape,
                           Node*& adr_src, Node*& base_src, Node*& adr_dest, Node*& base_dest,
                           BasicType& copy_type, const Type*& value_type, bool& disjoint_bases);
--- a/src/share/vm/opto/castnode.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/castnode.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -277,6 +277,23 @@
   return NULL;
 }
 
+uint CastIINode::cmp(const Node &n) const {
+  return ConstraintCastNode::cmp(n) && ((CastIINode&)n)._range_check_dependency == _range_check_dependency;
+}
+
+uint CastIINode::size_of() const {
+  return sizeof(*this);
+}
+
+#ifndef PRODUCT
+void CastIINode::dump_spec(outputStream* st) const {
+  ConstraintCastNode::dump_spec(st);
+  if (_range_check_dependency) {
+    st->print(" range check dependency");
+  }
+}
+#endif
+
 //=============================================================================
 //------------------------------Identity---------------------------------------
 // If input is already higher or equal to cast type, then this is an identity.
--- a/src/share/vm/opto/castnode.hpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/castnode.hpp	Mon Jan 18 23:08:39 2016 -0800
@@ -62,13 +62,33 @@
 //------------------------------CastIINode-------------------------------------
 // cast integer to integer (different range)
 class CastIINode: public ConstraintCastNode {
+  protected:
+  // Is this node dependent on a range check?
+  const bool _range_check_dependency;
+  virtual uint cmp(const Node &n) const;
+  virtual uint size_of() const;
+
   public:
-  CastIINode(Node *n, const Type *t, bool carry_dependency = false)
-    : ConstraintCastNode(n, t, carry_dependency) {}
+  CastIINode(Node* n, const Type* t, bool carry_dependency = false, bool range_check_dependency = false)
+    : ConstraintCastNode(n, t, carry_dependency), _range_check_dependency(range_check_dependency) {
+    init_class_id(Class_CastII);
+  }
   virtual int Opcode() const;
   virtual uint ideal_reg() const { return Op_RegI; }
   virtual const Type* Value(PhaseGVN* phase) const;
   virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
+  const bool has_range_check() {
+#ifdef _LP64
+    return _range_check_dependency;
+#else
+    assert(!_range_check_dependency, "Should not have range check dependency");
+    return false;
+#endif
+  }
+
+#ifndef PRODUCT
+  virtual void dump_spec(outputStream* st) const;
+#endif
 };
 
 //------------------------------CastPPNode-------------------------------------
--- a/src/share/vm/opto/cfgnode.hpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/cfgnode.hpp	Mon Jan 18 23:08:39 2016 -0800
@@ -277,13 +277,6 @@
   virtual uint size_of() const { return sizeof(*this); }
 
 private:
-  ProjNode* range_check_trap_proj() {
-    int flip_test = 0;
-    Node* l = NULL;
-    Node* r = NULL;
-    return range_check_trap_proj(flip_test, l, r);
-  }
-
   // Helper methods for fold_compares
   bool cmpi_folds(PhaseIterGVN* igvn);
   bool is_ctrl_folds(Node* ctrl, PhaseIterGVN* igvn);
--- a/src/share/vm/opto/compile.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/compile.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -38,6 +38,7 @@
 #include "opto/c2compiler.hpp"
 #include "opto/callGenerator.hpp"
 #include "opto/callnode.hpp"
+#include "opto/castnode.hpp"
 #include "opto/cfgnode.hpp"
 #include "opto/chaitin.hpp"
 #include "opto/compile.hpp"
@@ -402,6 +403,13 @@
       remove_macro_node(n);
     }
   }
+  // Remove useless CastII nodes with range check dependency
+  for (int i = range_check_cast_count() - 1; i >= 0; i--) {
+    Node* cast = range_check_cast_node(i);
+    if (!useful.member(cast)) {
+      remove_range_check_cast(cast);
+    }
+  }
   // Remove useless expensive node
   for (int i = C->expensive_count()-1; i >= 0; i--) {
     Node* n = C->expensive_node(i);
@@ -926,7 +934,6 @@
                            compiler,
                            has_unsafe_access(),
                            SharedRuntime::is_wide_vector(max_vector_size()),
-                           _directive,
                            rtm_state()
                            );
 
@@ -1178,6 +1185,7 @@
   _macro_nodes = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8,  0, NULL);
   _predicate_opaqs = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8,  0, NULL);
   _expensive_nodes = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8,  0, NULL);
+  _range_check_casts = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8,  0, NULL);
   register_library_intrinsics();
 }
 
@@ -1924,6 +1932,22 @@
   assert(predicate_count()==0, "should be clean!");
 }
 
+void Compile::add_range_check_cast(Node* n) {
+  assert(n->isa_CastII()->has_range_check(), "CastII should have range check dependency");
+  assert(!_range_check_casts->contains(n), "duplicate entry in range check casts");
+  _range_check_casts->append(n);
+}
+
+// Remove all range check dependent CastIINodes.
+void Compile::remove_range_check_casts(PhaseIterGVN &igvn) {
+  for (int i = range_check_cast_count(); i > 0; i--) {
+    Node* cast = range_check_cast_node(i-1);
+    assert(cast->isa_CastII()->has_range_check(), "CastII should have range check dependency");
+    igvn.replace_node(cast, cast->in(1));
+  }
+  assert(range_check_cast_count() == 0, "should be empty");
+}
+
 // StringOpts and late inlining of string methods
 void Compile::inline_string_calls(bool parse_time) {
   {
@@ -2284,6 +2308,12 @@
     PhaseIdealLoop::verify(igvn);
   }
 
+  if (range_check_cast_count() > 0) {
+    // No more loop optimizations. Remove all range check dependent CastIINodes.
+    C->remove_range_check_casts(igvn);
+    igvn.optimize();
+  }
+
   {
     TracePhase tp("macroExpand", &timers[_t_macroExpand]);
     PhaseMacroExpand  mex(igvn);
@@ -3087,6 +3117,16 @@
 
 #endif
 
+#ifdef ASSERT
+  case Op_CastII:
+    // Verify that all range check dependent CastII nodes were removed.
+    if (n->isa_CastII()->has_range_check()) {
+      n->dump(3);
+      assert(false, "Range check dependent CastII node was not removed");
+    }
+    break;
+#endif
+
   case Op_ModI:
     if (UseDivMod) {
       // Check if a%b and a/b both exist
@@ -3962,7 +4002,7 @@
   return SSC_full_test;
 }
 
-Node* Compile::conv_I2X_index(PhaseGVN *phase, Node* idx, const TypeInt* sizetype) {
+Node* Compile::conv_I2X_index(PhaseGVN* phase, Node* idx, const TypeInt* sizetype, Node* ctrl) {
 #ifdef _LP64
   // The scaled index operand to AddP must be a clean 64-bit value.
   // Java allows a 32-bit int to be incremented to a negative
@@ -3975,13 +4015,31 @@
   // number.  (The prior range check has ensured this.)
   // This assertion is used by ConvI2LNode::Ideal.
   int index_max = max_jint - 1;  // array size is max_jint, index is one less
-  if (sizetype != NULL)  index_max = sizetype->_hi - 1;
-  const TypeLong* lidxtype = TypeLong::make(CONST64(0), index_max, Type::WidenMax);
-  idx = phase->transform(new ConvI2LNode(idx, lidxtype));
+  if (sizetype != NULL) index_max = sizetype->_hi - 1;
+  const TypeInt* iidxtype = TypeInt::make(0, index_max, Type::WidenMax);
+  idx = constrained_convI2L(phase, idx, iidxtype, ctrl);
 #endif
   return idx;
 }
 
+// Convert integer value to a narrowed long type dependent on ctrl (for example, a range check)
+Node* Compile::constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl) {
+  if (ctrl != NULL) {
+    // Express control dependency by a CastII node with a narrow type.
+    value = new CastIINode(value, itype, false, true /* range check dependency */);
+    // Make the CastII node dependent on the control input to prevent the narrowed ConvI2L
+    // node from floating above the range check during loop optimizations. Otherwise, the
+    // ConvI2L node may be eliminated independently of the range check, causing the data path
+    // to become TOP while the control path is still there (although it's unreachable).
+    value->set_req(0, ctrl);
+    // Save CastII node to remove it after loop optimizations.
+    phase->C->add_range_check_cast(value);
+    value = phase->transform(value);
+  }
+  const TypeLong* ltype = TypeLong::make(itype->_lo, itype->_hi, itype->_widen);
+  return phase->transform(new ConvI2LNode(value, ltype));
+}
+
 // The message about the current inlining is accumulated in
 // _print_inlining_stream and transfered into the _print_inlining_list
 // once we know whether inlining succeeds or not. For regular
--- a/src/share/vm/opto/compile.hpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/compile.hpp	Mon Jan 18 23:08:39 2016 -0800
@@ -400,6 +400,7 @@
   GrowableArray<Node*>* _macro_nodes;           // List of nodes which need to be expanded before matching.
   GrowableArray<Node*>* _predicate_opaqs;       // List of Opaque1 nodes for the loop predicates.
   GrowableArray<Node*>* _expensive_nodes;       // List of nodes that are expensive to compute and that we'd better not let the GVN freely common
+  GrowableArray<Node*>* _range_check_casts;     // List of CastII nodes with a range check dependency
   ConnectionGraph*      _congraph;
 #ifndef PRODUCT
   IdealGraphPrinter*    _printer;
@@ -753,7 +754,7 @@
   void set_congraph(ConnectionGraph* congraph)  { _congraph = congraph;}
   void add_macro_node(Node * n) {
     //assert(n->is_macro(), "must be a macro node");
-    assert(!_macro_nodes->contains(n), " duplicate entry in expand list");
+    assert(!_macro_nodes->contains(n), "duplicate entry in expand list");
     _macro_nodes->append(n);
   }
   void remove_macro_node(Node * n) {
@@ -773,10 +774,23 @@
     }
   }
   void add_predicate_opaq(Node * n) {
-    assert(!_predicate_opaqs->contains(n), " duplicate entry in predicate opaque1");
+    assert(!_predicate_opaqs->contains(n), "duplicate entry in predicate opaque1");
     assert(_macro_nodes->contains(n), "should have already been in macro list");
     _predicate_opaqs->append(n);
   }
+
+  // Range check dependent CastII nodes that can be removed after loop optimizations
+  void add_range_check_cast(Node* n);
+  void remove_range_check_cast(Node* n) {
+    if (_range_check_casts->contains(n)) {
+      _range_check_casts->remove(n);
+    }
+  }
+  Node* range_check_cast_node(int idx) const { return _range_check_casts->at(idx);  }
+  int   range_check_cast_count()       const { return _range_check_casts->length(); }
+  // Remove all range check dependent CastIINodes.
+  void  remove_range_check_casts(PhaseIterGVN &igvn);
+
   // remove the opaque nodes that protect the predicates so that the unused checks and
   // uncommon traps will be eliminated from the graph.
   void cleanup_loop_predicates(PhaseIterGVN &igvn);
@@ -1292,7 +1306,12 @@
   enum { SSC_always_false, SSC_always_true, SSC_easy_test, SSC_full_test };
   int static_subtype_check(ciKlass* superk, ciKlass* subk);
 
-  static Node* conv_I2X_index(PhaseGVN *phase, Node* offset, const TypeInt* sizetype);
+  static Node* conv_I2X_index(PhaseGVN* phase, Node* offset, const TypeInt* sizetype,
+                              // Optional control dependency (for example, on range check)
+                              Node* ctrl = NULL);
+
+  // Convert integer value to a narrowed long type dependent on ctrl (for example, a range check)
+  static Node* constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl);
 
   // Auxiliary method for randomized fuzzing/stressing
   static bool randomized_select(int count);
--- a/src/share/vm/opto/convertnode.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/convertnode.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "opto/addnode.hpp"
+#include "opto/castnode.hpp"
 #include "opto/convertnode.hpp"
 #include "opto/matcher.hpp"
 #include "opto/phaseX.hpp"
@@ -293,7 +294,8 @@
   }
 
 #ifdef _LP64
-  // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) ,
+  // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) or
+  // ConvI2L(CastII(AddI(x, y))) to AddL(ConvI2L(CastII(x)), ConvI2L(CastII(y))),
   // but only if x and y have subranges that cannot cause 32-bit overflow,
   // under the assumption that x+y is in my own subrange this->type().
 
@@ -317,6 +319,13 @@
 
   Node* z = in(1);
   int op = z->Opcode();
+  Node* ctrl = NULL;
+  if (op == Op_CastII && z->as_CastII()->has_range_check()) {
+    // Skip CastII node but save control dependency
+    ctrl = z->in(0);
+    z = z->in(1);
+    op = z->Opcode();
+  }
   if (op == Op_AddI || op == Op_SubI) {
     Node* x = z->in(1);
     Node* y = z->in(2);
@@ -374,9 +383,10 @@
       rylo = -ryhi;
       ryhi = -rylo0;
     }
-
-    Node* cx = phase->transform( new ConvI2LNode(x, TypeLong::make(rxlo, rxhi, widen)) );
-    Node* cy = phase->transform( new ConvI2LNode(y, TypeLong::make(rylo, ryhi, widen)) );
+    assert(rxlo == (int)rxlo && rxhi == (int)rxhi, "x should not overflow");
+    assert(rylo == (int)rylo && ryhi == (int)ryhi, "y should not overflow");
+    Node* cx = phase->C->constrained_convI2L(phase, x, TypeInt::make(rxlo, rxhi, widen), ctrl);
+    Node* cy = phase->C->constrained_convI2L(phase, y, TypeInt::make(rylo, ryhi, widen), ctrl);
     switch (op) {
       case Op_AddI:  return new AddLNode(cx, cy);
       case Op_SubI:  return new SubLNode(cx, cy);
--- a/src/share/vm/opto/escape.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/escape.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -810,6 +810,7 @@
       if (cik->is_subclass_of(_compile->env()->Thread_klass()) ||
           cik->is_subclass_of(_compile->env()->Reference_klass()) ||
          !cik->is_instance_klass() || // StressReflectiveCode
+         !cik->as_instance_klass()->can_be_instantiated() ||
           cik->as_instance_klass()->has_finalizer()) {
         es = PointsToNode::GlobalEscape;
       }
--- a/src/share/vm/opto/graphKit.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/graphKit.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -1658,7 +1658,7 @@
 
 //-------------------------array_element_address-------------------------
 Node* GraphKit::array_element_address(Node* ary, Node* idx, BasicType elembt,
-                                      const TypeInt* sizetype) {
+                                      const TypeInt* sizetype, Node* ctrl) {
   uint shift  = exact_log2(type2aelembytes(elembt));
   uint header = arrayOopDesc::base_offset_in_bytes(elembt);
 
@@ -1671,7 +1671,7 @@
 
   // must be correct type for alignment purposes
   Node* base  = basic_plus_adr(ary, header);
-  idx = Compile::conv_I2X_index(&_gvn, idx, sizetype);
+  idx = Compile::conv_I2X_index(&_gvn, idx, sizetype, ctrl);
   Node* scale = _gvn.transform( new LShiftXNode(idx, intcon(shift)) );
   return basic_plus_adr(ary, base, scale);
 }
@@ -3407,8 +3407,7 @@
   if (layout_is_con) {
     assert(!StressReflectiveCode, "stress mode does not use these paths");
     bool must_go_slow = Klass::layout_helper_needs_slow_path(layout_con);
-    initial_slow_test = must_go_slow? intcon(1): extra_slow_test;
-
+    initial_slow_test = must_go_slow ? intcon(1) : extra_slow_test;
   } else {   // reflective case
     // This reflective path is used by Unsafe.allocateInstance.
     // (It may be stress-tested by specifying StressReflectiveCode.)
@@ -3507,10 +3506,6 @@
 
   Node* initial_slow_cmp  = _gvn.transform( new CmpUNode( length, intcon( fast_size_limit ) ) );
   Node* initial_slow_test = _gvn.transform( new BoolNode( initial_slow_cmp, BoolTest::gt ) );
-  if (initial_slow_test->is_Bool()) {
-    // Hide it behind a CMoveI, or else PhaseIdealLoop::split_up will get sick.
-    initial_slow_test = initial_slow_test->as_Bool()->as_int_value(&_gvn);
-  }
 
   // --- Size Computation ---
   // array_size = round_to_heap(array_header + (length << elem_shift));
@@ -3556,13 +3551,35 @@
   Node* lengthx = ConvI2X(length);
   Node* headerx = ConvI2X(header_size);
 #ifdef _LP64
-  { const TypeLong* tllen = _gvn.find_long_type(lengthx);
-    if (tllen != NULL && tllen->_lo < 0) {
+  { const TypeInt* tilen = _gvn.find_int_type(length);
+    if (tilen != NULL && tilen->_lo < 0) {
       // Add a manual constraint to a positive range.  Cf. array_element_address.
-      jlong size_max = arrayOopDesc::max_array_length(T_BYTE);
-      if (size_max > tllen->_hi)  size_max = tllen->_hi;
-      const TypeLong* tlcon = TypeLong::make(CONST64(0), size_max, Type::WidenMin);
-      lengthx = _gvn.transform( new ConvI2LNode(length, tlcon));
+      jint size_max = fast_size_limit;
+      if (size_max > tilen->_hi)  size_max = tilen->_hi;
+      const TypeInt* tlcon = TypeInt::make(0, size_max, Type::WidenMin);
+
+      // Only do a narrow I2L conversion if the range check passed.
+      IfNode* iff = new IfNode(control(), initial_slow_test, PROB_MIN, COUNT_UNKNOWN);
+      _gvn.transform(iff);
+      RegionNode* region = new RegionNode(3);
+      _gvn.set_type(region, Type::CONTROL);
+      lengthx = new PhiNode(region, TypeLong::LONG);
+      _gvn.set_type(lengthx, TypeLong::LONG);
+
+      // Range check passed. Use ConvI2L node with narrow type.
+      Node* passed = IfFalse(iff);
+      region->init_req(1, passed);
+      // Make I2L conversion control dependent to prevent it from
+      // floating above the range check during loop optimizations.
+      lengthx->init_req(1, C->constrained_convI2L(&_gvn, length, tlcon, passed));
+
+      // Range check failed. Use ConvI2L with wide type because length may be invalid.
+      region->init_req(2, IfTrue(iff));
+      lengthx->init_req(2, ConvI2X(length));
+
+      set_control(region);
+      record_for_igvn(region);
+      record_for_igvn(lengthx);
     }
   }
 #endif
@@ -3593,6 +3610,11 @@
   Node *mem = reset_memory();
   set_all_memory(mem); // Create new memory state
 
+  if (initial_slow_test->is_Bool()) {
+    // Hide it behind a CMoveI, or else PhaseIdealLoop::split_up will get sick.
+    initial_slow_test = initial_slow_test->as_Bool()->as_int_value(&_gvn);
+  }
+
   // Create the AllocateArrayNode and its result projections
   AllocateArrayNode* alloc
     = new AllocateArrayNode(C, AllocateArrayNode::alloc_type(TypeInt::INT),
@@ -4341,20 +4363,51 @@
                   value, T_BYTE, coder_field_idx, MemNode::unordered);
 }
 
-Node* GraphKit::compress_string(Node* src, Node* dst, Node* count) {
+// Capture src and dst memory state with a MergeMemNode
+Node* GraphKit::capture_memory(const TypePtr* src_type, const TypePtr* dst_type) {
+  if (src_type == dst_type) {
+    // Types are equal, we don't need a MergeMemNode
+    return memory(src_type);
+  }
+  MergeMemNode* merge = MergeMemNode::make(map()->memory());
+  record_for_igvn(merge); // fold it up later, if possible
+  int src_idx = C->get_alias_index(src_type);
+  int dst_idx = C->get_alias_index(dst_type);
+  merge->set_memory_at(src_idx, memory(src_idx));
+  merge->set_memory_at(dst_idx, memory(dst_idx));
+  return merge;
+}
+
+Node* GraphKit::compress_string(Node* src, const TypeAryPtr* src_type, Node* dst, Node* count) {
   assert(Matcher::match_rule_supported(Op_StrCompressedCopy), "Intrinsic not supported");
-  uint idx = C->get_alias_index(TypeAryPtr::BYTES);
-  StrCompressedCopyNode* str = new StrCompressedCopyNode(control(), memory(idx), src, dst, count);
+  assert(src_type == TypeAryPtr::BYTES || src_type == TypeAryPtr::CHARS, "invalid source type");
+  // If input and output memory types differ, capture both states to preserve
+  // the dependency between preceding and subsequent loads/stores.
+  // For example, the following program:
+  //  StoreB
+  //  compress_string
+  //  LoadB
+  // has this memory graph (use->def):
+  //  LoadB -> compress_string -> CharMem
+  //             ... -> StoreB -> ByteMem
+  // The intrinsic hides the dependency between LoadB and StoreB, causing
+  // the load to read from memory not containing the result of the StoreB.
+  // The correct memory graph should look like this:
+  //  LoadB -> compress_string -> MergeMem(CharMem, StoreB(ByteMem))
+  Node* mem = capture_memory(src_type, TypeAryPtr::BYTES);
+  StrCompressedCopyNode* str = new StrCompressedCopyNode(control(), mem, src, dst, count);
   Node* res_mem = _gvn.transform(new SCMemProjNode(str));
-  set_memory(res_mem, idx);
+  set_memory(res_mem, TypeAryPtr::BYTES);
   return str;
 }
 
-void GraphKit::inflate_string(Node* src, Node* dst, Node* count) {
+void GraphKit::inflate_string(Node* src, Node* dst, const TypeAryPtr* dst_type, Node* count) {
   assert(Matcher::match_rule_supported(Op_StrInflatedCopy), "Intrinsic not supported");
-  uint idx = C->get_alias_index(TypeAryPtr::BYTES);
-  StrInflatedCopyNode* str = new StrInflatedCopyNode(control(), memory(idx), src, dst, count);
-  set_memory(_gvn.transform(str), idx);
+  assert(dst_type == TypeAryPtr::BYTES || dst_type == TypeAryPtr::CHARS, "invalid dest type");
+  // Capture src and dst memory (see comment in 'compress_string').
+  Node* mem = capture_memory(TypeAryPtr::BYTES, dst_type);
+  StrInflatedCopyNode* str = new StrInflatedCopyNode(control(), mem, src, dst, count);
+  set_memory(_gvn.transform(str), dst_type);
 }
 
 void GraphKit::inflate_string_slow(Node* src, Node* dst, Node* start, Node* count) {
--- a/src/share/vm/opto/graphKit.hpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/graphKit.hpp	Mon Jan 18 23:08:39 2016 -0800
@@ -634,7 +634,9 @@
   // Return addressing for an array element.
   Node* array_element_address(Node* ary, Node* idx, BasicType elembt,
                               // Optional constraint on the array size:
-                              const TypeInt* sizetype = NULL);
+                              const TypeInt* sizetype = NULL,
+                              // Optional control dependency (for example, on range check)
+                              Node* ctrl = NULL);
 
   // Return a load of array element at idx.
   Node* load_array_element(Node* ctl, Node* ary, Node* idx, const TypeAryPtr* arytype);
@@ -881,8 +883,9 @@
   Node* load_String_coder(Node* ctrl, Node* str);
   void store_String_value(Node* ctrl, Node* str, Node* value);
   void store_String_coder(Node* ctrl, Node* str, Node* value);
-  Node* compress_string(Node* src, Node* dst, Node* count);
-  void inflate_string(Node* src, Node* dst, Node* count);
+  Node* capture_memory(const TypePtr* src_type, const TypePtr* dst_type);
+  Node* compress_string(Node* src, const TypeAryPtr* src_type, Node* dst, Node* count);
+  void inflate_string(Node* src, Node* dst, const TypeAryPtr* dst_type, Node* count);
   void inflate_string_slow(Node* src, Node* dst, Node* start, Node* count);
 
   // Handy for making control flow
--- a/src/share/vm/opto/ifnode.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/ifnode.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -1104,7 +1104,8 @@
         if (ctrl == fail) {
           Node* init_n = stack.node_at(1);
           assert(init_n->Opcode() == Op_ConvI2L, "unexpected first node");
-          Node* new_n = igvn->C->conv_I2X_index(igvn, l, array_size);
+          // Create a new narrow ConvI2L node that is dependent on the range check
+          Node* new_n = igvn->C->conv_I2X_index(igvn, l, array_size, fail);
 
           // The type of the ConvI2L may be widen and so the new
           // ConvI2L may not be better than an existing ConvI2L
--- a/src/share/vm/opto/library_call.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/library_call.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -1359,9 +1359,9 @@
   // 'dst_start' points to dst array + scaled offset
   Node* count = NULL;
   if (compress) {
-    count = compress_string(src_start, dst_start, length);
+    count = compress_string(src_start, TypeAryPtr::get_array_body_type(src_elem), dst_start, length);
   } else {
-    inflate_string(src_start, dst_start, length);
+    inflate_string(src_start, dst_start, TypeAryPtr::get_array_body_type(dst_elem), length);
   }
 
   if (alloc != NULL) {
@@ -1587,7 +1587,7 @@
     (void) store_to_memory(control(), adr, ch, T_CHAR, TypeAryPtr::BYTES, MemNode::unordered,
                            false, false, true /* mismatched */);
   } else {
-    ch = make_load(control(), adr, TypeInt::CHAR, T_CHAR, MemNode::unordered,
+    ch = make_load(control(), adr, TypeInt::CHAR, T_CHAR, TypeAryPtr::BYTES, MemNode::unordered,
                    LoadNode::DependsOnlyOnTest, false, false, true /* mismatched */);
     set_result(ch);
   }
--- a/src/share/vm/opto/loopTransform.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/loopTransform.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -2660,7 +2660,7 @@
 
 //=============================================================================
 // Process all the loops in the loop tree and replace any fill
-// patterns with an intrisc version.
+// patterns with an intrinsic version.
 bool PhaseIdealLoop::do_intrinsify_fill() {
   bool changed = false;
   for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) {
@@ -2758,8 +2758,9 @@
   }
 
   // Make sure the address expression can be handled.  It should be
-  // head->phi * elsize + con.  head->phi might have a ConvI2L.
+  // head->phi * elsize + con.  head->phi might have a ConvI2L(CastII()).
   Node* elements[4];
+  Node* cast = NULL;
   Node* conv = NULL;
   bool found_index = false;
   int count = store->in(MemNode::Address)->as_AddP()->unpack_offsets(elements, ARRAY_SIZE(elements));
@@ -2774,6 +2775,12 @@
         conv = value;
         value = value->in(1);
       }
+      if (value->Opcode() == Op_CastII &&
+          value->as_CastII()->has_range_check()) {
+        // Skip range check dependent CastII nodes
+        cast = value;
+        value = value->in(1);
+      }
 #endif
       if (value != head->phi()) {
         msg = "unhandled shift in address";
@@ -2786,9 +2793,16 @@
         }
       }
     } else if (n->Opcode() == Op_ConvI2L && conv == NULL) {
-      if (n->in(1) == head->phi()) {
+      conv = n;
+      n = n->in(1);
+      if (n->Opcode() == Op_CastII &&
+          n->as_CastII()->has_range_check()) {
+        // Skip range check dependent CastII nodes
+        cast = n;
+        n = n->in(1);
+      }
+      if (n == head->phi()) {
         found_index = true;
-        conv = n;
       } else {
         msg = "unhandled input to ConvI2L";
       }
@@ -2847,6 +2861,7 @@
   // Address elements are ok
   if (con)   ok.set(con->_idx);
   if (shift) ok.set(shift->_idx);
+  if (cast)  ok.set(cast->_idx);
   if (conv)  ok.set(conv->_idx);
 
   for (uint i = 0; msg == NULL && i < lpt->_body.size(); i++) {
--- a/src/share/vm/opto/loopopts.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/loopopts.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -25,6 +25,7 @@
 #include "precompiled.hpp"
 #include "memory/allocation.inline.hpp"
 #include "opto/addnode.hpp"
+#include "opto/castnode.hpp"
 #include "opto/connode.hpp"
 #include "opto/castnode.hpp"
 #include "opto/divnode.hpp"
@@ -997,6 +998,9 @@
 #ifdef _LP64
         if (m->Opcode() == Op_ConvI2L)
           return false;
+        if (m->is_CastII() && m->isa_CastII()->has_range_check()) {
+          return false;
+        }
 #endif
       }
     }
--- a/src/share/vm/opto/node.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/node.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -25,6 +25,7 @@
 #include "precompiled.hpp"
 #include "libadt/vectset.hpp"
 #include "memory/allocation.inline.hpp"
+#include "opto/castnode.hpp"
 #include "opto/cfgnode.hpp"
 #include "opto/connode.hpp"
 #include "opto/loopnode.hpp"
@@ -516,6 +517,11 @@
     C->add_macro_node(n);
   if (is_expensive())
     C->add_expensive_node(n);
+  // If the cloned node is a range check dependent CastII, add it to the list.
+  CastIINode* cast = n->isa_CastII();
+  if (cast != NULL && cast->has_range_check()) {
+    C->add_range_check_cast(cast);
+  }
 
   n->set_idx(C->next_unique()); // Get new unique index as well
   debug_only( n->verify_construction() );
@@ -644,6 +650,11 @@
   if (is_expensive()) {
     compile->remove_expensive_node(this);
   }
+  CastIINode* cast = isa_CastII();
+  if (cast != NULL && cast->has_range_check()) {
+    compile->remove_range_check_cast(cast);
+  }
+
   if (is_SafePoint()) {
     as_SafePoint()->delete_replaced_nodes();
   }
@@ -1379,6 +1390,10 @@
       if (dead->is_expensive()) {
         igvn->C->remove_expensive_node(dead);
       }
+      CastIINode* cast = dead->isa_CastII();
+      if (cast != NULL && cast->has_range_check()) {
+        igvn->C->remove_range_check_cast(cast);
+      }
       igvn->C->record_dead_node(dead->_idx);
       // Kill all inputs to the dead guy
       for (uint i=0; i < dead->req(); i++) {
--- a/src/share/vm/opto/node.hpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/node.hpp	Mon Jan 18 23:08:39 2016 -0800
@@ -51,6 +51,7 @@
 class CallNode;
 class CallRuntimeNode;
 class CallStaticJavaNode;
+class CastIINode;
 class CatchNode;
 class CatchProjNode;
 class CheckCastPPNode;
@@ -653,6 +654,7 @@
     DEFINE_CLASS_ID(Type,  Node, 2)
       DEFINE_CLASS_ID(Phi,   Type, 0)
       DEFINE_CLASS_ID(ConstraintCast, Type, 1)
+        DEFINE_CLASS_ID(CastII, ConstraintCast, 0)
       DEFINE_CLASS_ID(CheckCastPP, Type, 2)
       DEFINE_CLASS_ID(CMove, Type, 3)
       DEFINE_CLASS_ID(SafePointScalarObject, Type, 4)
@@ -784,6 +786,7 @@
   DEFINE_CLASS_QUERY(Catch)
   DEFINE_CLASS_QUERY(CatchProj)
   DEFINE_CLASS_QUERY(CheckCastPP)
+  DEFINE_CLASS_QUERY(CastII)
   DEFINE_CLASS_QUERY(ConstraintCast)
   DEFINE_CLASS_QUERY(ClearArray)
   DEFINE_CLASS_QUERY(CMove)
--- a/src/share/vm/opto/parse2.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/parse2.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -166,7 +166,9 @@
   // Check for always knowing you are throwing a range-check exception
   if (stopped())  return top();
 
-  Node* ptr = array_element_address(ary, idx, type, sizetype);
+  // Make array address computation control dependent to prevent it
+  // from floating above the range check during loop optimizations.
+  Node* ptr = array_element_address(ary, idx, type, sizetype, control());
 
   if (result2 != NULL)  *result2 = elemtype;
 
@@ -466,12 +468,14 @@
   // of all possible ranges for a switch statement
   // The key_val input must be converted to a pointer offset and scaled.
   // Compare Parse::array_addressing above.
-#ifdef _LP64
+
   // Clean the 32-bit int into a real 64-bit offset.
   // Otherwise, the jint value 0 might turn into an offset of 0x0800000000.
-  const TypeLong* lkeytype = TypeLong::make(CONST64(0), num_cases-1, Type::WidenMin);
-  key_val       = _gvn.transform( new ConvI2LNode(key_val, lkeytype) );
-#endif
+  const TypeInt* ikeytype = TypeInt::make(0, num_cases, Type::WidenMin);
+  // Make I2L conversion control dependent to prevent it from
+  // floating above the range check during loop optimizations.
+  key_val = C->conv_I2X_index(&_gvn, key_val, ikeytype, control());
+
   // Shift the value by wordsize so we have an index into the table, rather
   // than a switch value
   Node *shiftWord = _gvn.MakeConX(wordSize);
--- a/src/share/vm/opto/phaseX.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/phaseX.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -26,6 +26,7 @@
 #include "memory/allocation.inline.hpp"
 #include "opto/block.hpp"
 #include "opto/callnode.hpp"
+#include "opto/castnode.hpp"
 #include "opto/cfgnode.hpp"
 #include "opto/idealGraphPrinter.hpp"
 #include "opto/loopnode.hpp"
@@ -1412,6 +1413,10 @@
       if (dead->is_expensive()) {
         C->remove_expensive_node(dead);
       }
+      CastIINode* cast = dead->isa_CastII();
+      if (cast != NULL && cast->has_range_check()) {
+        C->remove_range_check_cast(cast);
+      }
     }
   } // while (_stack.is_nonempty())
 }
--- a/src/share/vm/opto/stringopts.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/stringopts.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -1466,7 +1466,7 @@
       // Use fast intrinsic
       Node* src = kit.array_element_address(src_array, kit.intcon(0), T_BYTE);
       Node* dst = kit.array_element_address(dst_array, start, T_BYTE);
-      kit.inflate_string(src, dst, __ value(count));
+      kit.inflate_string(src, dst, TypeAryPtr::BYTES, __ value(count));
     } else {
       // No intrinsic available, use slow method
       kit.inflate_string_slow(src_array, dst_array, start, __ value(count));
--- a/src/share/vm/opto/superword.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/opto/superword.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -3343,6 +3343,11 @@
       return true;
     }
   } else if (opc == Op_ConvI2L) {
+    if (n->in(1)->Opcode() == Op_CastII &&
+        n->in(1)->as_CastII()->has_range_check()) {
+      // Skip range check dependent CastII nodes
+      n = n->in(1);
+    }
     if (scaled_iv_plus_offset(n->in(1))) {
       NOT_PRODUCT(_tracer.scaled_iv_7(n);)
       return true;
@@ -3437,6 +3442,12 @@
   if (invariant(n)) {
     if (opc == Op_ConvI2L) {
       n = n->in(1);
+      if (n->Opcode() == Op_CastII &&
+          n->as_CastII()->has_range_check()) {
+        // Skip range check dependent CastII nodes
+        assert(invariant(n), "sanity");
+        n = n->in(1);
+      }
     }
     if (n->bottom_type()->isa_int()) {
       _negate_invar = negate;
--- a/src/share/vm/prims/jvm.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/prims/jvm.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -285,7 +285,7 @@
   return os::javaTimeNanos();
 JVM_END
 
-// The function below is actually exposed by sun.misc.VM and not
+// The function below is actually exposed by jdk.internal.misc.VM and not
 // java.lang.System, but we choose to keep it here so that it stays next
 // to JVM_CurrentTimeMillis and JVM_NanoTime
 
--- a/src/share/vm/prims/nativeLookup.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/prims/nativeLookup.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -125,7 +125,7 @@
   { CC"Java_jdk_internal_misc_Unsafe_registerNatives",             NULL, FN_PTR(JVM_RegisterJDKInternalMiscUnsafeMethods) },
   { CC"Java_sun_misc_Unsafe_registerNatives",                      NULL, FN_PTR(JVM_RegisterSunMiscUnsafeMethods)         },
   { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) },
-  { CC"Java_sun_misc_Perf_registerNatives",                        NULL, FN_PTR(JVM_RegisterPerfMethods)         },
+  { CC"Java_jdk_internal_perf_Perf_registerNatives",               NULL, FN_PTR(JVM_RegisterPerfMethods)         },
   { CC"Java_sun_hotspot_WhiteBox_registerNatives",                 NULL, FN_PTR(JVM_RegisterWhiteBoxMethods)     },
 #if INCLUDE_JVMCI
   { CC"Java_jdk_vm_ci_runtime_JVMCI_initializeRuntime",            NULL, FN_PTR(JVM_GetJVMCIRuntime)             },
--- a/src/share/vm/prims/perf.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/prims/perf.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -34,7 +34,7 @@
 #include "runtime/perfMemory.hpp"
 
 /*
- *      Implementation of class sun.misc.Perf
+ *      Implementation of class jdk.internal.perf.Perf
  */
 
 
--- a/src/share/vm/prims/whitebox.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/prims/whitebox.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -1096,6 +1096,7 @@
 
   CodeBlobStub stub(code);
   jobjectArray codeBlob = codeBlob2objectArray(thread, env, &stub);
+  CHECK_JNI_EXCEPTION_(env, NULL);
   env->SetObjectArrayElement(result, 0, codeBlob);
 
   jobject level = integerBox(thread, env, code->comp_level());
@@ -1181,6 +1182,7 @@
   for (GrowableArrayIterator<CodeBlobStub*> it = blobs.begin();
        it != blobs.end(); ++it) {
     jobjectArray obj = codeBlob2objectArray(thread, env, *it);
+    CHECK_JNI_EXCEPTION_(env, NULL);
     env->SetObjectArrayElement(result, i, obj);
     ++i;
   }
--- a/src/share/vm/utilities/vmError.cpp	Mon Jan 18 10:58:08 2016 -0800
+++ b/src/share/vm/utilities/vmError.cpp	Mon Jan 18 23:08:39 2016 -0800
@@ -1234,38 +1234,6 @@
     log_done = true;
   }
 
-
-  static bool skip_OnError = false;
-  if (!skip_OnError && OnError && OnError[0]) {
-    skip_OnError = true;
-
-    out.print_raw_cr("#");
-    out.print_raw   ("# -XX:OnError=\"");
-    out.print_raw   (OnError);
-    out.print_raw_cr("\"");
-
-    char* cmd;
-    const char* ptr = OnError;
-    while ((cmd = next_OnError_command(buffer, sizeof(buffer), &ptr)) != NULL){
-      out.print_raw   ("#   Executing ");
-#if defined(LINUX) || defined(_ALLBSD_SOURCE)
-      out.print_raw   ("/bin/sh -c ");
-#elif defined(SOLARIS)
-      out.print_raw   ("/usr/bin/sh -c ");
-#endif
-      out.print_raw   ("\"");
-      out.print_raw   (cmd);
-      out.print_raw_cr("\" ...");
-
-      if (os::fork_and_exec(cmd) < 0) {
-        out.print_cr("os::fork_and_exec failed: %s (%d)", strerror(errno), errno);
-      }
-    }
-
-    // done with OnError
-    OnError = NULL;
-  }
-
   static bool skip_replay = ReplayCompiles; // Do not overwrite file during replay
   if (DumpReplayDataOnError && _thread && _thread->is_Compiler_thread() && !skip_replay) {
     skip_replay = true;
@@ -1295,6 +1263,40 @@
     print_bug_submit_message(&out, _thread);
   }
 
+  static bool skip_OnError = false;
+  if (!skip_OnError && OnError && OnError[0]) {
+    skip_OnError = true;
+
+    // Flush output and finish logs before running OnError commands.
+    ostream_abort();
+
+    out.print_raw_cr("#");
+    out.print_raw   ("# -XX:OnError=\"");
+    out.print_raw   (OnError);
+    out.print_raw_cr("\"");
+
+    char* cmd;
+    const char* ptr = OnError;
+    while ((cmd = next_OnError_command(buffer, sizeof(buffer), &ptr)) != NULL){
+      out.print_raw   ("#   Executing ");
+#if defined(LINUX) || defined(_ALLBSD_SOURCE)
+      out.print_raw   ("/bin/sh -c ");
+#elif defined(SOLARIS)
+      out.print_raw   ("/usr/bin/sh -c ");
+#endif
+      out.print_raw   ("\"");
+      out.print_raw   (cmd);
+      out.print_raw_cr("\" ...");
+
+      if (os::fork_and_exec(cmd) < 0) {
+        out.print_cr("os::fork_and_exec failed: %s (%d)", strerror(errno), errno);
+      }
+    }
+
+    // done with OnError
+    OnError = NULL;
+  }
+
   if (!UseOSErrorReporting) {
     // os::abort() will call abort hooks, try it first.
     static bool skip_os_abort = false;
--- a/test/compiler/compilercontrol/share/scenario/AbstractCommandBuilder.java	Mon Jan 18 10:58:08 2016 -0800
+++ b/test/compiler/compilercontrol/share/scenario/AbstractCommandBuilder.java	Mon Jan 18 23:08:39 2016 -0800
@@ -105,15 +105,15 @@
             Map<Executable, State> states = new HashMap<>();
             for (Pair<Executable, Callable<?>> pair : METHODS) {
                 Executable exec = pair.first;
-                State state = getState(commandList, states, exec);
+                State state = getState(commandList, exec);
                 states.put(exec, state);
             }
             return states;
         }
 
         private State getState(List<CompileCommand> commandList,
-                Map<Executable, State> states, Executable exec) {
-            State state = states.getOrDefault(exec, new State());
+                               Executable exec) {
+            State state = new State();
             MethodDescriptor execDesc = new MethodDescriptor(exec);
             for (CompileCommand compileCommand : commandList) {
                 if (compileCommand.isValid()) {
@@ -149,7 +149,8 @@
                         && (compileCommand.command == Command.COMPILEONLY)) {
                     MethodDescriptor md = compileCommand.methodDescriptor;
                     if (!execDesc.getCanonicalString().matches(md.getRegexp())
-                            && (state.getCompilableOptional(
+                            // if compilation state wasn't set before
+                            && (!state.getCompilableOptional(
                                     // no matter C1, C2 or both
                                     Scenario.Compiler.C2).isPresent())) {
                         /* compileonly excludes only methods that haven't been
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/compiler/intrinsics/string/TestStringIntrinsicMemoryFlow.java	Mon Jan 18 23:08:39 2016 -0800
@@ -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.
+ */
+
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @bug 8144212
+ * @summary Check for correct memory flow with the String compress/inflate intrinsics.
+ * @library /testlibrary
+ * @run main TestStringIntrinsicMemoryFlow
+ */
+public class TestStringIntrinsicMemoryFlow {
+
+    public static void main(String[] args) {
+        for (int i = 0; i < 100_000; ++i) {
+            String s = "MyString";
+            char[] c = {'M'};
+            char res = testInflate1(s);
+            Asserts.assertEquals(res, 'M', "testInflate1 failed");
+            res = testInflate2(s);
+            Asserts.assertEquals(res, (char)42, "testInflate2 failed");
+            res = testCompress1(c);
+            Asserts.assertEquals(res, 'M', "testCompress1 failed");
+            byte resB = testCompress2(c);
+            Asserts.assertEquals(resB, (byte)42, "testCompress2 failed");
+        }
+    }
+
+    private static char testInflate1(String s) {
+        char c[] = new char[1];
+        // Inflate String from byte[] to char[]
+        s.getChars(0, 1, c, 0);
+        // Read char[] memory written by inflate intrinsic
+        return c[0];
+    }
+
+    private static char testInflate2(String s) {
+        char c1[] = new char[1];
+        char c2[] = new char[1];
+        c2[0] = 42;
+        // Inflate String from byte[] to char[]
+        s.getChars(0, 1, c1, 0);
+        // Read char[] memory written before inflation
+        return c2[0];
+    }
+
+    private static char testCompress1(char[] c) {
+        // Compress String from char[] to byte[]
+        String s = new String(c);
+        // Read the memory written by compress intrinsic
+        return s.charAt(0);
+    }
+
+    private static byte testCompress2(char[] c) {
+        byte b1[] = new byte[1];
+        b1[0] = 42;
+        // Compress String from char[] to byte[]
+        new String(c);
+        // Read byte[] memory written before compression
+        return b1[0];
+    }
+}
--- a/test/compiler/jsr292/NonInlinedCall/RedefineTest.java	Mon Jan 18 10:58:08 2016 -0800
+++ b/test/compiler/jsr292/NonInlinedCall/RedefineTest.java	Mon Jan 18 23:08:39 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -30,7 +30,6 @@
  *                              sun.hotspot.WhiteBox$WhiteBoxPermission
  *                              java.lang.invoke.RedefineTest
  *                              Agent
- *                              jdk.test.lib.Asserts
  * @run main Agent agent.jar java.lang.invoke.RedefineTest
  * @run main/othervm -Xbootclasspath/a:. -javaagent:agent.jar
  *                   -XX:+IgnoreUnrecognizedVMOptions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/compiler/loopopts/TestLoopPeeling.java	Mon Jan 18 23:08:39 2016 -0800
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8078262
+ * @summary Tests correct dominator information after loop peeling.
+ * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,TestLoopPeeling::test* TestLoopPeeling
+ */
+public class TestLoopPeeling {
+
+    public int[] array = new int[100];
+
+    public static void main(String args[]) {
+        TestLoopPeeling test = new TestLoopPeeling();
+        try {
+            test.testArrayAccess(0, 1);
+            test.testArrayAllocation(0, 1);
+        } catch (Exception e) {
+            // Ignore exceptions
+        }
+    }
+
+    public void testArrayAccess(int index, int inc) {
+        int storeIndex = -1;
+
+        for (; index < 10; index += inc) {
+            // This loop invariant check triggers loop peeling because it can
+            // be moved out of the loop (see 'IdealLoopTree::policy_peeling').
+            if (inc == 42) return;
+
+            // This loop variant usage of LShiftL( ConvI2L( Phi(storeIndex) ) )
+            // prevents the split if optimization that would otherwise clone the
+            // LShiftL and ConvI2L nodes and assign them to their corresponding array
+            // address computation (see 'PhaseIdealLoop::split_if_with_blocks_post').
+            if (storeIndex > 0 && array[storeIndex] == 42) return;
+
+            if (index == 42) {
+                // This store and the corresponding range check are moved out of the
+                // loop and both used after old loop and the peeled iteration exit.
+                // For the peeled iteration, storeIndex is always -1 and the ConvI2L
+                // is replaced by TOP. However, the range check is not folded because
+                // we don't do the split if optimization in PhaseIdealLoop2.
+                // As a result, we have a (dead) control path from the peeled iteration
+                // to the StoreI but the data path is removed.
+                array[storeIndex] = 1;
+                return;
+            }
+
+            storeIndex++;
+        }
+    }
+
+    public byte[] testArrayAllocation(int index, int inc) {
+        int allocationCount = -1;
+        byte[] result;
+
+        for (; index < 10; index += inc) {
+            // This loop invariant check triggers loop peeling because it can
+            // be moved out of the loop (see 'IdealLoopTree::policy_peeling').
+            if (inc == 42) return null;
+
+            if (index == 42) {
+                // This allocation and the corresponding size check are moved out of the
+                // loop and both used after old loop and the peeled iteration exit.
+                // For the peeled iteration, allocationCount is always -1 and the ConvI2L
+                // is replaced by TOP. However, the size check is not folded because
+                // we don't do the split if optimization in PhaseIdealLoop2.
+                // As a result, we have a (dead) control path from the peeled iteration
+                // to the allocation but the data path is removed.
+                result = new byte[allocationCount];
+                return result;
+            }
+
+            allocationCount++;
+        }
+        return null;
+    }
+}
+
--- a/test/runtime/Unsafe/AllocateInstance.java	Mon Jan 18 10:58:08 2016 -0800
+++ b/test/runtime/Unsafe/AllocateInstance.java	Mon Jan 18 23:08:39 2016 -0800
@@ -35,21 +35,7 @@
 import static jdk.test.lib.Asserts.*;
 
 public class AllocateInstance {
-    public static void main(String args[]) throws Exception {
-        Unsafe unsafe = Utils.getUnsafe();
-
-        // allocateInstance() should not result in a call to the constructor
-        TestClass tc = (TestClass)unsafe.allocateInstance(TestClass.class);
-        assertFalse(tc.calledConstructor);
-
-        // allocateInstance() on an abstract class should result in an InstantiationException
-        try {
-            AbstractClass ac = (AbstractClass)unsafe.allocateInstance(AbstractClass.class);
-            throw new RuntimeException("Did not get expected InstantiationException");
-        } catch (InstantiationException e) {
-            // Expected
-        }
-    }
+    static final Unsafe UNSAFE = Utils.getUnsafe();
 
     class TestClass {
         public boolean calledConstructor = false;
@@ -59,7 +45,41 @@
         }
     }
 
+    static void testConstructorCall() throws InstantiationException {
+        // allocateInstance() should not result in a call to the constructor
+        TestClass tc = (TestClass)UNSAFE.allocateInstance(TestClass.class);
+        assertFalse(tc.calledConstructor);
+    }
+
     abstract class AbstractClass {
         public AbstractClass() {}
     }
+
+    static void testAbstractClass() {
+        try {
+            AbstractClass ac = (AbstractClass) UNSAFE.allocateInstance(AbstractClass.class);
+            throw new AssertionError("Should throw InstantiationException for an abstract class");
+        } catch (InstantiationException e) {
+            // Expected
+        }
+    }
+
+    interface AnInterface {}
+
+    static void testInterface() {
+        try {
+            AnInterface ai = (AnInterface) UNSAFE.allocateInstance(AnInterface.class);
+            throw new AssertionError("Should throw InstantiationException for an interface");
+        } catch (InstantiationException e) {
+            // Expected
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+        for (int i = 0; i < 20_000; i++) {
+            testConstructorCall();
+            testAbstractClass();
+            testInterface();
+        }
+    }
 }
--- a/test/testlibrary/ClassFileInstaller.java	Mon Jan 18 10:58:08 2016 -0800
+++ b/test/testlibrary/ClassFileInstaller.java	Mon Jan 18 23:08:39 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -21,6 +21,7 @@
  * questions.
  */
 
+import java.io.FileNotFoundException;
 import java.io.InputStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -42,6 +43,9 @@
             // Convert dotted class name to a path to a class file
             String pathName = arg.replace('.', '/').concat(".class");
             InputStream is = cl.getResourceAsStream(pathName);
+            if (is == null) {
+                throw new FileNotFoundException(pathName);
+            }
 
             // Create the class file's package directory
             Path p = Paths.get(pathName);