changeset 12649:5d3ce4972641

Merge
author jprovino
date Mon, 27 Feb 2017 23:20:05 +0100
parents 86125753bf5b 138a5f5e37b7
children 676b576ca647
files src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java test/compiler/aot/cli/jaotc/ClasspathOptionTest.java test/compiler/aot/fingerprint/CDSDumper.java test/compiler/aot/fingerprint/CDSRunner.java test/compiler/aot/fingerprint/SelfChanged.java test/compiler/aot/fingerprint/SelfChangedCDS.java test/compiler/aot/fingerprint/SuperChanged.java test/compiler/c2/cr7200264/Test7200264.sh test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java
diffstat 442 files changed, 8005 insertions(+), 4428 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Mon Feb 27 12:41:41 2017 -0500
+++ b/.hgtags	Mon Feb 27 23:20:05 2017 +0100
@@ -557,3 +557,8 @@
 31f1d26c60df7b2e516a4f84160d76ba017d4e09 jdk-9+152
 217ba81b9a4ce8698200370175aa2db86a39f66c jdk-9+153
 fc7e94cb748507366b839e859f865f724467446a jdk-10+0
+a9fdfd55835ef9dccb7f317b07249bd66653b874 jdk-9+154
+f3b3d77a1751897413aae43ac340a130b6fa2ae1 jdk-9+155
+43139c588ea48b6504e52b6c3dec530b17b1fdb4 jdk-9+156
+b2d0a906afd73dcf27f572217eb1be0f196ec16c jdk-9+157
+4e78f30935229f13ce7c43089621cf7169f5abac jdk-9+158
--- a/make/ide/CreateVSProject.gmk	Mon Feb 27 12:41:41 2017 -0500
+++ b/make/ide/CreateVSProject.gmk	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2017, 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
@@ -121,7 +121,7 @@
       -buildBase $(call FixPath, $(IDE_OUTPUTDIR)/vs-output) \
       -buildSpace $(call FixPath, $(IDE_OUTPUTDIR)) \
       -makeBinary $(call FixPath, $(MAKE)) \
-      -makeOutput $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-%f/libjvm) \
+      -makeOutput $(call FixPath, $(JDK_OUTPUTDIR)/bin/server) \
       -absoluteInclude $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-server/gensrc) \
       -absoluteSrcInclude $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-server/gensrc) \
       $(EXTRACTED_DEFINES_client) \
--- a/make/lib/CompileJvm.gmk	Mon Feb 27 12:41:41 2017 -0500
+++ b/make/lib/CompileJvm.gmk	Mon Feb 27 23:20:05 2017 +0100
@@ -63,7 +63,7 @@
 # INCLUDE_SUFFIX_* is only meant for including the proper
 # platform files. Don't use it to guard code. Use the value of
 # HOTSPOT_TARGET_CPU_DEFINE etc. instead.
-# Remaining TARGET_ARCH_* is needed to select the cpu specific 
+# Remaining TARGET_ARCH_* is needed to select the cpu specific
 # sources for 64-bit ARM ports (arm versus aarch64).
 JVM_CFLAGS_TARGET_DEFINES += \
     -DTARGET_ARCH_$(HOTSPOT_TARGET_CPU_ARCH) \
@@ -132,7 +132,7 @@
     #
 
 # -DDONT_USE_PRECOMPILED_HEADER will exclude all includes in precompiled.hpp.
-ifeq ($(USE_PRECOMPILED_HEADER), 0)
+ifeq ($(USE_PRECOMPILED_HEADER), false)
   JVM_CFLAGS += -DDONT_USE_PRECOMPILED_HEADER
 endif
 
@@ -145,7 +145,7 @@
   JVM_EXCLUDE_PATTERNS += arm_64
 
 else ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU), linux-aarch64)
-  # For 64-bit arm builds, we use the 64 bit hotspot/src/cpu/arm 
+  # For 64-bit arm builds, we use the 64 bit hotspot/src/cpu/arm
   # hotspot sources if HOTSPOT_TARGET_CPU_ARCH is set to arm.
   # Exclude the aarch64 and 32 bit arm files for this build.
   ifeq ($(HOTSPOT_TARGET_CPU_ARCH), arm)
--- a/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2017, 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
@@ -114,8 +114,8 @@
             tag(cfg, "CodeAnalysisRuleAssemblies");
         }
         for (BuildConfig cfg : allConfigs) {
-            tagData(cfg, "NMakeBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile import-hotspot LOG=info");
-            tagData(cfg, "NMakeReBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot import-hotspot LOG=info");
+            tagData(cfg, "NMakeBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile hotspot LOG=info");
+            tagData(cfg, "NMakeReBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot hotspot LOG=info");
             tagData(cfg, "NMakeCleanCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot LOG=info");
             tagData(cfg, "NMakeOutput", cfg.get("MakeOutput") + Util.sep + "jvm.dll");
             tagData(cfg, "NMakePreprocessorDefinitions", Util.join(";", cfg.getDefines()));
--- a/make/symbols/symbols-unix	Mon Feb 27 12:41:41 2017 -0500
+++ b/make/symbols/symbols-unix	Mon Feb 27 23:20:05 2017 +0100
@@ -192,4 +192,3 @@
 JVM_AddReadsModule
 JVM_DefineModule
 JVM_SetBootLoaderUnnamedModule
-JVM_GetModuleByPackageName
--- a/src/cpu/aarch64/vm/aarch64.ad	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/aarch64/vm/aarch64.ad	Mon Feb 27 23:20:05 2017 +0100
@@ -1042,8 +1042,10 @@
   bool is_card_mark_membar(const MemBarNode *barrier);
   bool is_CAS(int opcode);
 
-  MemBarNode *leading_to_trailing(MemBarNode *leading);
-  MemBarNode *card_mark_to_leading(const MemBarNode *barrier);
+  MemBarNode *leading_to_normal(MemBarNode *leading);
+  MemBarNode *normal_to_leading(const MemBarNode *barrier);
+  MemBarNode *card_mark_to_trailing(const MemBarNode *barrier);
+  MemBarNode *trailing_to_card_mark(const MemBarNode *trailing);
   MemBarNode *trailing_to_leading(const MemBarNode *trailing);
 
   // predicates controlling emit of ldr<x>/ldar<x> and associated dmb
@@ -1420,28 +1422,23 @@
   // leading MemBarRelease and a trailing MemBarVolatile as follows
   //
   //   MemBarRelease
-  //  {    ||        } -- optional
+  //  {      ||      } -- optional
   //  {MemBarCPUOrder}
-  //       ||       \\
-  //       ||     StoreX[mo_release]
-  //       | \ Bot    / ???
-  //       | MergeMem
-  //       | /
+  //         ||     \\
+  //         ||     StoreX[mo_release]
+  //         | \     /
+  //         | MergeMem
+  //         | /
   //   MemBarVolatile
   //
   // where
   //  || and \\ represent Ctl and Mem feeds via Proj nodes
   //  | \ and / indicate further routing of the Ctl and Mem feeds
   //
-  // Note that the memory feed from the CPUOrder membar to the
-  // MergeMem node is an AliasIdxBot slice while the feed from the
-  // StoreX is for a slice determined by the type of value being
-  // written.
-  //
-  // the diagram above shows the graph we see for non-object stores.
-  // for a volatile Object store (StoreN/P) we may see other nodes
-  // below the leading membar because of the need for a GC pre- or
-  // post-write barrier.
+  // this is the graph we see for non-object stores. however, for a
+  // volatile Object store (StoreN/P) we may see other nodes below the
+  // leading membar because of the need for a GC pre- or post-write
+  // barrier.
   //
   // with most GC configurations we with see this simple variant which
   // includes a post-write barrier card mark.
@@ -1449,7 +1446,7 @@
   //   MemBarRelease______________________________
   //         ||    \\               Ctl \        \\
   //         ||    StoreN/P[mo_release] CastP2X  StoreB/CM
-  //         | \ Bot  / oop                 . . .  /
+  //         | \     /                       . . .  /
   //         | MergeMem
   //         | /
   //         ||      /
@@ -1459,142 +1456,152 @@
   // the object address to an int used to compute the card offset) and
   // Ctl+Mem to a StoreB node (which does the actual card mark).
   //
-  // n.b. a StoreCM node is only ever used when CMS (with or without
-  // CondCardMark) or G1 is configured. This abstract instruction
-  // differs from a normal card mark write (StoreB) because it implies
-  // a requirement to order visibility of the card mark (StoreCM)
-  // after that of the object put (StoreP/N) using a StoreStore memory
-  // barrier. Note that this is /not/ a requirement to order the
-  // instructions in the generated code (that is already guaranteed by
-  // the order of memory dependencies). Rather it is a requirement to
-  // ensure visibility order which only applies on architectures like
-  // AArch64 which do not implement TSO. This ordering is required for
-  // both non-volatile and volatile puts.
-  //
-  // That implies that we need to translate a StoreCM using the
-  // sequence
+  // n.b. a StoreCM node will only appear in this configuration when
+  // using CMS. StoreCM differs from a normal card mark write (StoreB)
+  // because it implies a requirement to order visibility of the card
+  // mark (StoreCM) relative to the object put (StoreP/N) using a
+  // StoreStore memory barrier (arguably this ought to be represented
+  // explicitly in the ideal graph but that is not how it works). This
+  // ordering is required for both non-volatile and volatile
+  // puts. Normally that means we need to translate a StoreCM using
+  // the sequence
   //
   //   dmb ishst
   //   stlrb
   //
-  // This dmb cannot be omitted even when the associated StoreX or
-  // CompareAndSwapX is implemented using stlr. However, as described
-  // below there are circumstances where a specific GC configuration
-  // requires a stronger barrier in which case it can be omitted.
-  // 
-  // With the Serial or Parallel GC using +CondCardMark the card mark
-  // is performed conditionally on it currently being unmarked in
-  // which case the volatile put graph looks slightly different
+  // However, in the case of a volatile put if we can recognise this
+  // configuration and plant an stlr for the object write then we can
+  // omit the dmb and just plant an strb since visibility of the stlr
+  // is ordered before visibility of subsequent stores. StoreCM nodes
+  // also arise when using G1 or using CMS with conditional card
+  // marking. In these cases (as we shall see) we don't need to insert
+  // the dmb when translating StoreCM because there is already an
+  // intervening StoreLoad barrier between it and the StoreP/N.
+  //
+  // It is also possible to perform the card mark conditionally on it
+  // currently being unmarked in which case the volatile put graph
+  // will look slightly different
   //
   //   MemBarRelease____________________________________________
   //         ||    \\               Ctl \     Ctl \     \\  Mem \
   //         ||    StoreN/P[mo_release] CastP2X   If   LoadB     |
-  //         | \ Bot / oop                          \            |
+  //         | \     /                              \            |
   //         | MergeMem                            . . .      StoreB
   //         | /                                                /
   //         ||     /
   //   MemBarVolatile
   //
-  // It is worth noting at this stage that all the above
+  // It is worth noting at this stage that both the above
   // configurations can be uniquely identified by checking that the
   // memory flow includes the following subgraph:
   //
   //   MemBarRelease
   //  {MemBarCPUOrder}
-  //      |  \      . . .
-  //      |  StoreX[mo_release]  . . .
-  //  Bot |   / oop
-  //     MergeMem
-  //      |
+  //          |  \      . . .
+  //          |  StoreX[mo_release]  . . .
+  //          |   /
+  //         MergeMem
+  //          |
   //   MemBarVolatile
   //
-  // This is referred to as a *normal* volatile store subgraph. It can
-  // easily be detected starting from any candidate MemBarRelease,
-  // StoreX[mo_release] or MemBarVolatile node.
-  //
-  // A small variation on this normal case occurs for an unsafe CAS
-  // operation. The basic memory flow subgraph for a non-object CAS is
-  // as follows
+  // This is referred to as a *normal* subgraph. It can easily be
+  // detected starting from any candidate MemBarRelease,
+  // StoreX[mo_release] or MemBarVolatile.
+  //
+  // A simple variation on this normal case occurs for an unsafe CAS
+  // operation. The basic graph for a non-object CAS is
   //
   //   MemBarRelease
   //         ||
   //   MemBarCPUOrder
-  //          |     \\   . . .
-  //          |     CompareAndSwapX
-  //          |       |
-  //      Bot |     SCMemProj
-  //           \     / Bot
-  //           MergeMem
-  //           /
+  //         ||     \\   . . .
+  //         ||     CompareAndSwapX
+  //         ||       |
+  //         ||     SCMemProj
+  //         | \     /
+  //         | MergeMem
+  //         | /
   //   MemBarCPUOrder
   //         ||
   //   MemBarAcquire
   //
   // The same basic variations on this arrangement (mutatis mutandis)
-  // occur when a card mark is introduced. i.e. the CPUOrder MemBar
-  // feeds the extra CastP2X, LoadB etc nodes but the above memory
-  // flow subgraph is still present.
-  // 
-  // This is referred to as a *normal* CAS subgraph. It can easily be
-  // detected starting from any candidate MemBarRelease,
-  // StoreX[mo_release] or MemBarAcquire node.
-  //
-  // The code below uses two helper predicates, leading_to_trailing
-  // and trailing_to_leading to identify these normal graphs, one
-  // validating the layout starting from the top membar and searching
-  // down and the other validating the layout starting from the lower
-  // membar and searching up.
-  //
-  // There are two special case GC configurations when the simple
-  // normal graphs above may not be generated: when using G1 (which
-  // always employs a conditional card mark); and when using CMS with
-  // conditional card marking (+CondCardMark) configured. These GCs
-  // are both concurrent rather than stop-the world GCs. So they
-  // introduce extra Ctl+Mem flow into the graph between the leading
-  // and trailing membar nodes, in particular enforcing stronger
-  // memory serialisation beween the object put and the corresponding
-  // conditional card mark. CMS employs a post-write GC barrier while
-  // G1 employs both a pre- and post-write GC barrier.
-  //
-  // The post-write barrier subgraph for these configurations includes
-  // a MemBarVolatile node -- referred to as a card mark membar --
-  // which is needed to order the card write (StoreCM) operation in
-  // the barrier, the preceding StoreX (or CompareAndSwapX) and Store
-  // operations performed by GC threads i.e. a card mark membar
-  // constitutes a StoreLoad barrier hence must be translated to a dmb
-  // ish (whether or not it sits inside a volatile store sequence).
-  //
-  // Of course, the use of the dmb ish for the card mark membar also
-  // implies theat the StoreCM which follows can omit the dmb ishst
-  // instruction. The necessary visibility ordering will already be
-  // guaranteed by the dmb ish. In sum, the dmb ishst instruction only
-  // needs to be generated for as part of the StoreCM sequence with GC
-  // configuration +CMS -CondCardMark.
-  // 
-  // Of course all these extra barrier nodes may well be absent --
-  // they are only inserted for object puts. Their potential presence
-  // significantly complicates the task of identifying whether a
-  // MemBarRelease, StoreX[mo_release], MemBarVolatile or
-  // MemBarAcquire forms part of a volatile put or CAS when using
-  // these GC configurations (see below) and also complicates the
-  // decision as to how to translate a MemBarVolatile and StoreCM.
-  //
-  // So, thjis means that a card mark MemBarVolatile occurring in the
-  // post-barrier graph it needs to be distinguished from a normal
-  // trailing MemBarVolatile. Resolving this is straightforward: a
-  // card mark MemBarVolatile always projects a Mem feed to a StoreCM
-  // node and that is a unique marker
+  // occur when a card mark is introduced. i.e. we se the same basic
+  // shape but the StoreP/N is replaced with CompareAndSawpP/N and the
+  // tail of the graph is a pair comprising a MemBarCPUOrder +
+  // MemBarAcquire.
+  //
+  // So, in the case of a CAS the normal graph has the variant form
+  //
+  //   MemBarRelease
+  //   MemBarCPUOrder
+  //          |   \      . . .
+  //          |  CompareAndSwapX  . . .
+  //          |    |
+  //          |   SCMemProj
+  //          |   /  . . .
+  //         MergeMem
+  //          |
+  //   MemBarCPUOrder
+  //   MemBarAcquire
+  //
+  // This graph can also easily be detected starting from any
+  // candidate MemBarRelease, CompareAndSwapX or MemBarAcquire.
+  //
+  // the code below uses two helper predicates, leading_to_normal and
+  // normal_to_leading to identify these normal graphs, one validating
+  // the layout starting from the top membar and searching down and
+  // the other validating the layout starting from the lower membar
+  // and searching up.
+  //
+  // There are two special case GC configurations when a normal graph
+  // may not be generated: when using G1 (which always employs a
+  // conditional card mark); and when using CMS with conditional card
+  // marking configured. These GCs are both concurrent rather than
+  // stop-the world GCs. So they introduce extra Ctl+Mem flow into the
+  // graph between the leading and trailing membar nodes, in
+  // particular enforcing stronger memory serialisation beween the
+  // object put and the corresponding conditional card mark. CMS
+  // employs a post-write GC barrier while G1 employs both a pre- and
+  // post-write GC barrier. Of course the extra nodes may be absent --
+  // they are only inserted for object puts. This significantly
+  // complicates the task of identifying whether a MemBarRelease,
+  // StoreX[mo_release] or MemBarVolatile forms part of a volatile put
+  // when using these GC configurations (see below). It adds similar
+  // complexity to the task of identifying whether a MemBarRelease,
+  // CompareAndSwapX or MemBarAcquire forms part of a CAS.
+  //
+  // In both cases the post-write subtree includes an auxiliary
+  // MemBarVolatile (StoreLoad barrier) separating the object put and
+  // the read of the corresponding card. This poses two additional
+  // problems.
+  //
+  // Firstly, a card mark MemBarVolatile needs to be distinguished
+  // from a normal trailing MemBarVolatile. Resolving this first
+  // problem is straightforward: a card mark MemBarVolatile always
+  // projects a Mem feed to a StoreCM node and that is a unique marker
   //
   //      MemBarVolatile (card mark)
   //       C |    \     . . .
   //         |   StoreCM   . . .
   //       . . .
   //
-  // Returning to the task of translating the object put and the
-  // leading/trailing membar nodes: what do the node graphs look like
-  // for these 2 special cases? and how can we determine the status of
-  // a MemBarRelease, StoreX[mo_release] or MemBarVolatile in both
-  // normal and non-normal cases?
+  // The second problem is how the code generator is to translate the
+  // card mark barrier? It always needs to be translated to a "dmb
+  // ish" instruction whether or not it occurs as part of a volatile
+  // put. A StoreLoad barrier is needed after the object put to ensure
+  // i) visibility to GC threads of the object put and ii) visibility
+  // to the mutator thread of any card clearing write by a GC
+  // thread. Clearly a normal store (str) will not guarantee this
+  // ordering but neither will a releasing store (stlr). The latter
+  // guarantees that the object put is visible but does not guarantee
+  // that writes by other threads have also been observed.
+  //
+  // So, returning to the task of translating the object put and the
+  // leading/trailing membar nodes: what do the non-normal node graph
+  // look like for these 2 special cases? and how can we determine the
+  // status of a MemBarRelease, StoreX[mo_release] or MemBarVolatile
+  // in both normal and non-normal cases?
   //
   // A CMS GC post-barrier wraps its card write (StoreCM) inside an If
   // which selects conditonal execution based on the value loaded
@@ -1605,117 +1612,91 @@
   // which looks like this
   //
   //   MemBarRelease
-  //   MemBarCPUOrder_(leading)____________________
-  //     C |  | M \       \\               M |   C \
-  //       |  |    \    StoreN/P[mo_release] |  CastP2X
-  //       |  | Bot \    / oop      \        |
-  //       |  |    MergeMem          \      / 
-  //       |  |      /                |    /
-  //     MemBarVolatile (card mark)   |   /
-  //     C |  ||    M |               |  /
-  //       | LoadB    | Bot       oop | / Bot
-  //       |   |      |              / /
-  //       | Cmp      |\            / /
-  //       | /        | \          / /
-  //       If         |  \        / /
-  //       | \        |   \      / /
-  // IfFalse  IfTrue  |    \    / /
-  //       \     / \  |    |   / /
-  //        \   / StoreCM  |  / /
-  //         \ /      \   /  / /
-  //        Region     Phi  / /
-  //          | \   Raw |  / /
-  //          |  . . .  | / /
+  //   MemBarCPUOrder_(leading)__________________
+  //     C |    M \       \\                   C \
+  //       |       \    StoreN/P[mo_release]  CastP2X
+  //       |    Bot \    /
+  //       |       MergeMem
+  //       |         /
+  //      MemBarVolatile (card mark)
+  //     C |  ||    M |
+  //       | LoadB    |
+  //       |   |      |
+  //       | Cmp      |\
+  //       | /        | \
+  //       If         |  \
+  //       | \        |   \
+  // IfFalse  IfTrue  |    \
+  //       \     / \  |     \
+  //        \   / StoreCM    |
+  //         \ /      |      |
+  //        Region   . . .   |
+  //          | \           /
+  //          |  . . .  \  / Bot
   //          |       MergeMem
-  //          |           |
+  //          |          |
   //        MemBarVolatile (trailing)
   //
-  // Notice that there are two MergeMem nodes below the leading
-  // membar. The first MergeMem merges the AliasIdxBot Mem slice from
-  // the leading membar and the oopptr Mem slice from the Store into
-  // the card mark membar. The trailing MergeMem merges the
-  // AliasIdxBot Mem slice from the leading membar, the AliasIdxRaw
-  // slice from the StoreCM and an oop slice from the StoreN/P node
-  // into the trailing membar (n.b. the raw slice proceeds via a Phi
-  // associated with the If region).
-  //
-  // So, in the case of CMS + CondCardMark the volatile object store
-  // graph still includes a normal volatile store subgraph from the
-  // leading membar to the trailing membar. However, it also contains
-  // the same shape memory flow to the card mark membar. The two flows
-  // can be distinguished by testing whether or not the downstream
-  // membar is a card mark membar.
-  //
-  // The graph for a CAS also varies with CMS + CondCardMark, in
-  // particular employing a control feed from the CompareAndSwapX node
-  // through a CmpI and If to the card mark membar and StoreCM which
-  // updates the associated card. This avoids executing the card mark
-  // if the CAS fails. However, it can be seen from the diagram below
-  // that the presence of the barrier does not alter the normal CAS
-  // memory subgraph where the leading membar feeds a CompareAndSwapX,
-  // an SCMemProj, a MergeMem then a final trailing MemBarCPUOrder and
-  // MemBarAcquire pair.
+  // The first MergeMem merges the AliasIdxBot Mem slice from the
+  // leading membar and the oopptr Mem slice from the Store into the
+  // card mark membar. The trailing MergeMem merges the AliasIdxBot
+  // Mem slice from the card mark membar and the AliasIdxRaw slice
+  // from the StoreCM into the trailing membar (n.b. the latter
+  // proceeds via a Phi associated with the If region).
+  //
+  // The graph for a CAS varies slightly, the obvious difference being
+  // that the StoreN/P node is replaced by a CompareAndSwapP/N node
+  // and the trailing MemBarVolatile by a MemBarCPUOrder +
+  // MemBarAcquire pair. The other important difference is that the
+  // CompareAndSwap node's SCMemProj is not merged into the card mark
+  // membar - it still feeds the trailing MergeMem. This also means
+  // that the card mark membar receives its Mem feed directly from the
+  // leading membar rather than via a MergeMem.
   //
   //   MemBarRelease
-  //   MemBarCPUOrder__(leading)_______________________
-  //   C /  M |                        \\            C \
-  //  . . .   | Bot                CompareAndSwapN/P   CastP2X
-  //          |                  C /  M |
-  //          |                 CmpI    |
-  //          |                  /      |
-  //          |               . . .     |
-  //          |              IfTrue     |
-  //          |              /          |
-  //       MemBarVolatile (card mark)   |
-  //        C |  ||    M |              |
-  //          | LoadB    | Bot   ______/|
-  //          |   |      |      /       |
-  //          | Cmp      |     /      SCMemProj
-  //          | /        |    /         |
-  //          If         |   /         /
-  //          | \        |  /         / Bot
-  //     IfFalse  IfTrue | /         /
-  //          |   / \   / / prec    /
-  //   . . .  |  /  StoreCM        /
-  //        \ | /      | raw      /
-  //        Region    . . .      /
-  //           | \              /
-  //           |   . . .   \    / Bot
-  //           |        MergeMem
-  //           |          /
-  //         MemBarCPUOrder
-  //         MemBarAcquire (trailing)
+  //   MemBarCPUOrder__(leading)_________________________
+  //       ||                       \\                 C \
+  //   MemBarVolatile (card mark)  CompareAndSwapN/P  CastP2X
+  //     C |  ||    M |              |
+  //       | LoadB    |       ______/|
+  //       |   |      |      /       |
+  //       | Cmp      |     /      SCMemProj
+  //       | /        |    /         |
+  //       If         |   /         /
+  //       | \        |  /         /
+  // IfFalse  IfTrue  | /         /
+  //       \     / \  |/ prec    /
+  //        \   / StoreCM       /
+  //         \ /      |        /
+  //        Region   . . .    /
+  //          | \            /
+  //          |  . . .  \   / Bot
+  //          |       MergeMem
+  //          |          |
+  //        MemBarCPUOrder
+  //        MemBarAcquire (trailing)
   //
   // This has a slightly different memory subgraph to the one seen
-  // previously but the core of it has a similar memory flow to the
-  // CAS normal subgraph:
+  // previously but the core of it is the same as for the CAS normal
+  // sungraph
   //
   //   MemBarRelease
   //   MemBarCPUOrder____
-  //         |          \      . . .
-  //         |       CompareAndSwapX  . . .
-  //         |       C /  M |
-  //         |      CmpI    |
-  //         |       /      |
-  //         |      . .    /
-  //     Bot |   IfTrue   /
-  //         |   /       /
-  //    MemBarVolatile  /
-  //         | ...     /
-  //      StoreCM ... /
-  //         |       / 
-  //       . . .  SCMemProj
-  //      Raw \    / Bot
-  //        MergeMem
-  //           |
+  //      ||             \      . . .
+  //   MemBarVolatile  CompareAndSwapX  . . .
+  //      |  \            |
+  //        . . .   SCMemProj
+  //          |     /  . . .
+  //         MergeMem
+  //          |
   //   MemBarCPUOrder
   //   MemBarAcquire
   //
-  // The G1 graph for a volatile object put is a lot more complicated.
-  // Nodes inserted on behalf of G1 may comprise: a pre-write graph
-  // which adds the old value to the SATB queue; the releasing store
-  // itself; and, finally, a post-write graph which performs a card
-  // mark.
+  //
+  // G1 is quite a lot more complicated. The nodes inserted on behalf
+  // of G1 may comprise: a pre-write graph which adds the old value to
+  // the SATB queue; the releasing store itself; and, finally, a
+  // post-write graph which performs a card mark.
   //
   // The pre-write graph may be omitted, but only when the put is
   // writing to a newly allocated (young gen) object and then only if
@@ -1753,60 +1734,25 @@
   //       | CastP2X | StoreN/P[mo_release] |
   //       |         |         |            |
   //     C |       M |       M |          M |
-  //        \        | Raw     | oop       / Bot
+  //        \        |         |           /
   //                  . . .
   //          (post write subtree elided)
   //                    . . .
   //             C \         M /
   //         MemBarVolatile (trailing)
   //
-  // Note that the three memory feeds into the post-write tree are an
-  // AliasRawIdx slice associated with the writes in the pre-write
-  // tree, an oop type slice from the StoreX specific to the type of
-  // the volatile field and the AliasBotIdx slice emanating from the
-  // leading membar.
-  //
   // n.b. the LoadB in this subgraph is not the card read -- it's a
   // read of the SATB queue active flag.
   //
-  // The CAS graph is once again a variant of the above with a
-  // CompareAndSwapX node and SCMemProj in place of the StoreX.  The
-  // value from the CompareAndSwapX node is fed into the post-write
-  // graph aling with the AliasIdxRaw feed from the pre-barrier and
-  // the AliasIdxBot feeds from the leading membar and the ScMemProj.
-  //
-  //  MemBarRelease (leading)____________
-  //     C |  ||  M \   M \    M \  M \ . . .
-  //       | LoadB   \  LoadL  LoadN   \
-  //       | /        \                 \
-  //       If         |\                 \
-  //       | \        | \                 \
-  //  IfFalse  IfTrue |  \                 \
-  //       |     |    |   \                 \
-  //       |     If   |    \                 |
-  //       |     |          \                |
-  //       |                 \               |
-  //       |    . . .         \              |
-  //       | /       | /       \             |
-  //      Region  Phi[M]        \            |
-  //       | \       |           \           |
-  //       |  \_____ |            |          |
-  //     C | C \     |            |          |
-  //       | CastP2X |     CompareAndSwapX   |
-  //       |         |   res |     |         |
-  //     C |       M |       |  SCMemProj  M |
-  //        \        | Raw   |     | Bot    / Bot
-  //                  . . .
-  //          (post write subtree elided)
-  //                    . . .
-  //             C \         M /
-  //         MemBarVolatile (trailing)
+  // Once again the CAS graph is a minor variant on the above with the
+  // expected substitutions of CompareAndSawpX for StoreN/P and
+  // MemBarCPUOrder + MemBarAcquire for trailing MemBarVolatile.
   //
   // The G1 post-write subtree is also optional, this time when the
   // new value being written is either null or can be identified as a
   // newly allocated (young gen) object with no intervening control
   // flow. The latter cannot happen but the former may, in which case
-  // the card mark membar is omitted and the memory feeds from the
+  // the card mark membar is omitted and the memory feeds form the
   // leading membar and the SToreN/P are merged direct into the
   // trailing membar as per the normal subgraph. So, the only special
   // case which arises is when the post-write subgraph is generated.
@@ -1828,106 +1774,94 @@
   //
   //                (pre-write subtree elided)
   //        . . .                  . . .    . . .  . . .
-  //        C |               M |    M |    M |
-  //       Region            Phi[M] StoreN    |
-  //          |            Raw  |  oop |  Bot |
-  //         / \_______         |\     |\     |\
-  //      C / C \      . . .    | \    | \    | \
-  //       If   CastP2X . . .   |  \   |  \   |  \
-  //       / \                  |   \  |   \  |   \
-  //      /   \                 |    \ |    \ |    \
-  // IfFalse IfTrue             |      |      |     \
-  //   |       |                 \     |     /       |
-  //   |       If                 \    | \  /   \    |
-  //   |      / \                  \   |   /     \   |
-  //   |     /   \                  \  |  / \     |  |
-  //   | IfFalse IfTrue           MergeMem   \    |  |
-  //   |  . . .    / \                 |      \   |  |
-  //   |          /   \                |       |  |  |
-  //   |     IfFalse IfTrue            |       |  |  |
-  //   |      . . .    |               |       |  |  |
-  //   |               If             /        |  |  |
-  //   |               / \           /         |  |  |
-  //   |              /   \         /          |  |  |
-  //   |         IfFalse IfTrue    /           |  |  |
-  //   |           . . .   |      /            |  |  |
-  //   |                    \    /             |  |  |
-  //   |                     \  /              |  |  |
-  //   |         MemBarVolatile__(card mark  ) |  |  |
-  //   |              ||   C |     \           |  |  |
-  //   |             LoadB   If     |         /   |  |
-  //   |                    / \ Raw |        /   /  /
-  //   |                   . . .    |       /   /  /
-  //   |                        \   |      /   /  /
-  //   |                        StoreCM   /   /  /
-  //   |                           |     /   /  /
-  //   |                            . . .   /  /
-  //   |                                   /  /
-  //   |   . . .                          /  /
-  //   |    |             | /            /  /
-  //   |    |           Phi[M] /        /  /
-  //   |    |             |   /        /  /
-  //   |    |             |  /        /  /
-  //   |  Region  . . .  Phi[M]      /  /
-  //   |    |             |         /  /
-  //    \   |             |        /  /
-  //     \  | . . .       |       /  /
-  //      \ |             |      /  /
-  //      Region         Phi[M] /  /
-  //        |               \  /  /
-  //         \             MergeMem
-  //          \            /
-  //          MemBarVolatile
-  //
-  // As with CMS + CondCardMark the first MergeMem merges the
-  // AliasIdxBot Mem slice from the leading membar and the oopptr Mem
-  // slice from the Store into the card mark membar. However, in this
-  // case it may also merge an AliasRawIdx mem slice from the pre
-  // barrier write.
-  //
-  // The trailing MergeMem merges an AliasIdxBot Mem slice from the
-  // leading membar with an oop slice from the StoreN and an
-  // AliasRawIdx slice from the post barrier writes. In this case the
-  // AliasIdxRaw Mem slice is merged through a series of Phi nodes
-  // which combine feeds from the If regions in the post barrier
-  // subgraph.
-  //
-  // So, for G1 the same characteristic subgraph arises as for CMS +
-  // CondCardMark. There is a normal subgraph feeding the card mark
-  // membar and a normal subgraph feeding the trailing membar.
-  //
-  // The CAS graph when using G1GC also includes an optional
-  // post-write subgraph. It is very similar to the above graph except
-  // for a few details.
-  // 
-  // - The control flow is gated by an additonal If which tests the
-  // result from the CompareAndSwapX node
-  // 
-  //  - The MergeMem which feeds the card mark membar only merges the
-  // AliasIdxBot slice from the leading membar and the AliasIdxRaw
-  // slice from the pre-barrier. It does not merge the SCMemProj
-  // AliasIdxBot slice. So, this subgraph does not look like the
-  // normal CAS subgraph.
-  //
-  // - The MergeMem which feeds the trailing membar merges the
-  // AliasIdxBot slice from the leading membar, the AliasIdxRaw slice
-  // from the post-barrier and the SCMemProj AliasIdxBot slice i.e. it
-  // has two AliasIdxBot input slices. However, this subgraph does
-  // still look like the normal CAS subgraph.
-  //
-  // So, the upshot is:
-  //
-  // In all cases a volatile put graph will include a *normal*
-  // volatile store subgraph betwen the leading membar and the
-  // trailing membar. It may also include a normal volatile store
-  // subgraph betwen the leading membar and the card mark membar.
-  //
-  // In all cases a CAS graph will contain a unique normal CAS graph
-  // feeding the trailing membar.
-  //
-  // In all cases where there is a card mark membar (either as part of
-  // a volatile object put or CAS) it will be fed by a MergeMem whose
-  // AliasIdxBot slice feed will be a leading membar.
+  //        C |                    M |     M |    M |
+  //       Region                  Phi[M] StoreN    |
+  //          |                     / \      |      |
+  //         / \_______            /   \     |      |
+  //      C / C \      . . .            \    |      |
+  //       If   CastP2X . . .            |   |      |
+  //       / \                           |   |      |
+  //      /   \                          |   |      |
+  // IfFalse IfTrue                      |   |      |
+  //   |       |                         |   |     /|
+  //   |       If                        |   |    / |
+  //   |      / \                        |   |   /  |
+  //   |     /   \                        \  |  /   |
+  //   | IfFalse IfTrue                   MergeMem  |
+  //   |  . . .    / \                       /      |
+  //   |          /   \                     /       |
+  //   |     IfFalse IfTrue                /        |
+  //   |      . . .    |                  /         |
+  //   |               If                /          |
+  //   |               / \              /           |
+  //   |              /   \            /            |
+  //   |         IfFalse IfTrue       /             |
+  //   |           . . .   |         /              |
+  //   |                    \       /               |
+  //   |                     \     /                |
+  //   |             MemBarVolatile__(card mark)    |
+  //   |                ||   C |  M \  M \          |
+  //   |               LoadB   If    |    |         |
+  //   |                      / \    |    |         |
+  //   |                     . . .   |    |         |
+  //   |                          \  |    |        /
+  //   |                        StoreCM   |       /
+  //   |                          . . .   |      /
+  //   |                        _________/      /
+  //   |                       /  _____________/
+  //   |   . . .       . . .  |  /            /
+  //   |    |                 | /   _________/
+  //   |    |               Phi[M] /        /
+  //   |    |                 |   /        /
+  //   |    |                 |  /        /
+  //   |  Region  . . .     Phi[M]  _____/
+  //   |    /                 |    /
+  //   |                      |   /
+  //   | . . .   . . .        |  /
+  //   | /                    | /
+  // Region           |  |  Phi[M]
+  //   |              |  |  / Bot
+  //    \            MergeMem
+  //     \            /
+  //     MemBarVolatile
+  //
+  // As with CMS the initial MergeMem merges the AliasIdxBot Mem slice
+  // from the leading membar and the oopptr Mem slice from the Store
+  // into the card mark membar i.e. the memory flow to the card mark
+  // membar still looks like a normal graph.
+  //
+  // The trailing MergeMem merges an AliasIdxBot Mem slice with other
+  // Mem slices (from the StoreCM and other card mark queue stores).
+  // However in this case the AliasIdxBot Mem slice does not come
+  // direct from the card mark membar. It is merged through a series
+  // of Phi nodes. These are needed to merge the AliasIdxBot Mem flow
+  // from the leading membar with the Mem feed from the card mark
+  // membar. Each Phi corresponds to one of the Ifs which may skip
+  // around the card mark membar. So when the If implementing the NULL
+  // value check has been elided the total number of Phis is 2
+  // otherwise it is 3.
+  //
+  // The CAS graph when using G1GC also includes a pre-write subgraph
+  // and an optional post-write subgraph. Teh sam evarioations are
+  // introduced as for CMS with conditional card marking i.e. the
+  // StoreP/N is swapped for a CompareAndSwapP/N, the tariling
+  // MemBarVolatile for a MemBarCPUOrder + MemBarAcquire pair and the
+  // Mem feed from the CompareAndSwapP/N includes a precedence
+  // dependency feed to the StoreCM and a feed via an SCMemProj to the
+  // trailing membar. So, as before the configuration includes the
+  // normal CAS graph as a subgraph of the memory flow.
+  //
+  // So, the upshot is that in all cases the volatile put graph will
+  // include a *normal* memory subgraph betwen the leading membar and
+  // its child membar, either a volatile put graph (including a
+  // releasing StoreX) or a CAS graph (including a CompareAndSwapX).
+  // When that child is not a card mark membar then it marks the end
+  // of the volatile put or CAS subgraph. If the child is a card mark
+  // membar then the normal subgraph will form part of a volatile put
+  // subgraph if and only if the child feeds an AliasIdxBot Mem feed
+  // to a trailing barrier via a MergeMem. That feed is either direct
+  // (for CMS) or via 2 or 3 Phi nodes merging the leading barrier
+  // memory flow (for G1).
   //
   // The predicates controlling generation of instructions for store
   // and barrier nodes employ a few simple helper functions (described
@@ -1971,24 +1905,24 @@
   }
 
 
-  // leading_to_trailing
+  // leading_to_normal
   //
   //graph traversal helper which detects the normal case Mem feed from
   // a release membar (or, optionally, its cpuorder child) to a
   // dependent volatile membar i.e. it ensures that one or other of
   // the following Mem flow subgraph is present.
   //
-  //   MemBarRelease {leading}
-  //   {MemBarCPUOrder} {optional}
-  //     Bot |  \      . . .
-  //         |  StoreN/P[mo_release]  . . .
-  //         |   /
-  //        MergeMem
-  //         |
-  //   MemBarVolatile {not card mark}
-  //
-  //   MemBarRelease {leading}
-  //   {MemBarCPUOrder} {optional}
+  //   MemBarRelease
+  //   MemBarCPUOrder {leading}
+  //          |  \      . . .
+  //          |  StoreN/P[mo_release]  . . .
+  //          |   /
+  //         MergeMem
+  //          |
+  //   MemBarVolatile {trailing or card mark}
+  //
+  //   MemBarRelease
+  //   MemBarCPUOrder {leading}
   //      |       \      . . .
   //      |     CompareAndSwapX  . . .
   //               |
@@ -1999,23 +1933,6 @@
   //    MemBarCPUOrder
   //    MemBarAcquire {trailing}
   //
-  // the predicate needs to be capable of distinguishing the following
-  // volatile put graph which may arises when a GC post barrier
-  // inserts a card mark membar
-  //
-  //   MemBarRelease {leading}
-  //   {MemBarCPUOrder}__
-  //     Bot |   \       \
-  //         |   StoreN/P \
-  //         |    / \     |
-  //        MergeMem \    |
-  //         |        \   |
-  //   MemBarVolatile  \  |
-  //    {card mark}     \ |
-  //                  MergeMem
-  //                      |
-  // {not card mark} MemBarVolatile
-  //
   // if the correct configuration is present returns the trailing
   // membar otherwise NULL.
   //
@@ -2026,7 +1943,7 @@
   // the returned value may be a card mark or trailing membar
   //
 
-  MemBarNode *leading_to_trailing(MemBarNode *leading)
+  MemBarNode *leading_to_normal(MemBarNode *leading)
   {
     assert((leading->Opcode() == Op_MemBarRelease ||
 	    leading->Opcode() == Op_MemBarCPUOrder),
@@ -2043,21 +1960,15 @@
     StoreNode * st = NULL;
     LoadStoreNode *cas = NULL;
     MergeMemNode *mm = NULL;
-    MergeMemNode *mm2 = NULL;
 
     for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) {
       x = mem->fast_out(i);
       if (x->is_MergeMem()) {
 	if (mm != NULL) {
-	  if (mm2 != NULL) {
-	  // should not see more than 2 merge mems
-	    return NULL;
-	  } else {
-	    mm2 = x->as_MergeMem();
-	  }
-	} else {
-	  mm = x->as_MergeMem();
+	  return NULL;
 	}
+	// two merge mems is one too many
+	mm = x->as_MergeMem();
       } else if (x->is_Store() && x->as_Store()->is_release() && x->Opcode() != Op_StoreCM) {
 	// two releasing stores/CAS nodes is one too many
 	if (st != NULL || cas != NULL) {
@@ -2077,13 +1988,13 @@
       return NULL;
     }
 
-    // must have at least one merge if we also have st
+    // must have a merge if we also have st
     if (st && !mm) {
       return NULL;
     }
 
+    Node *y = NULL;
     if (cas) {
-      Node *y = NULL;
       // look for an SCMemProj
       for (DUIterator_Fast imax, i = cas->fast_outs(imax); i < imax; i++) {
 	x = cas->fast_out(i);
@@ -2103,29 +2014,10 @@
 	  break;
 	}
       }
-      if (mm == NULL) {
+      if (mm == NULL)
 	return NULL;
-      }
-      MemBarNode *mbar = NULL;
-      // ensure the merge feeds a trailing membar cpuorder + acquire pair
-      for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) {
-	x = mm->fast_out(i);
-	if (x->is_MemBar()) {
-	  int opcode = x->Opcode();
-	  if (opcode == Op_MemBarCPUOrder) {
-	    MemBarNode *z =  x->as_MemBar();
-	    z = child_membar(z);
-	    if (z != NULL && z->Opcode() == Op_MemBarAcquire) {
-	      mbar = z;
-	    }
-	  }
-	  break;
-	}
-      }
-      return mbar;
     } else {
-      Node *y = NULL;
-      // ensure the store feeds the first mergemem;
+      // ensure the store feeds the existing mergemem;
       for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) {
 	if (st->fast_out(i) == mm) {
 	  y = st;
@@ -2135,89 +2027,55 @@
       if (y == NULL) {
 	return NULL;
       }
-      if (mm2 != NULL) {
-	// ensure the store feeds the second mergemem;
-	y = NULL;
-	for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) {
-	  if (st->fast_out(i) == mm2) {
-	    y = st;
+    }
+
+    MemBarNode *mbar = NULL;
+    // ensure the merge feeds to the expected type of membar
+    for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) {
+      x = mm->fast_out(i);
+      if (x->is_MemBar()) {
+	int opcode = x->Opcode();
+	if (opcode == Op_MemBarVolatile && st) {
+	  mbar = x->as_MemBar();
+	} else if (cas && opcode == Op_MemBarCPUOrder) {
+	  MemBarNode *y =  x->as_MemBar();
+	  y = child_membar(y);
+	  if (y != NULL && y->Opcode() == Op_MemBarAcquire) {
+	    mbar = y;
 	  }
 	}
-	if (y == NULL) {
-	  return NULL;
-	}
+	break;
       }
-
-      MemBarNode *mbar = NULL;
-      // ensure the first mergemem feeds a volatile membar
-      for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) {
-	x = mm->fast_out(i);
-	if (x->is_MemBar()) {
-	  int opcode = x->Opcode();
-	  if (opcode == Op_MemBarVolatile) {
-	    mbar = x->as_MemBar();
-	  }
-	  break;
-	}
-      }
-      if (mm2 == NULL) {
-	// this is our only option for a trailing membar
-	return mbar;
-      }
-      // ensure the second mergemem feeds a volatile membar
-      MemBarNode *mbar2 = NULL;
-      for (DUIterator_Fast imax, i = mm2->fast_outs(imax); i < imax; i++) {
-	x = mm2->fast_out(i);
-	if (x->is_MemBar()) {
-	  int opcode = x->Opcode();
-	  if (opcode == Op_MemBarVolatile) {
-	    mbar2 = x->as_MemBar();
-	  }
-	  break;
-	}
-      }
-      // if we have two merge mems we must have two volatile membars
-      if (mbar == NULL || mbar2 == NULL) {
-	return NULL;
-      }
-      // return the trailing membar
-      if (is_card_mark_membar(mbar2)) {
-	return mbar;
-      } else {
-	if (is_card_mark_membar(mbar)) {
-	  return mbar2;
-	} else {
-	  return NULL;
-	}
-      }
-    }
-  }
-
-  // trailing_to_leading
+    }
+
+    return mbar;
+  }
+
+  // normal_to_leading
   //
   // graph traversal helper which detects the normal case Mem feed
-  // from a trailing membar to a preceding release membar (optionally
-  // its cpuorder child) i.e. it ensures that one or other of the
-  // following Mem flow subgraphs is present.
-  //
-  //   MemBarRelease {leading}
-  //   MemBarCPUOrder {optional}
-  //    | Bot |  \      . . .
-  //    |     |  StoreN/P[mo_release]  . . .
-  //    |     |   /
-  //    |    MergeMem
-  //    |     |
-  //   MemBarVolatile {not card mark}
-  //
-  //   MemBarRelease {leading}
-  //   MemBarCPUOrder {optional}
+  // from either a card mark or a trailing membar to a preceding
+  // release membar (optionally its cpuorder child) i.e. it ensures
+  // that one or other of the following Mem flow subgraphs is present.
+  //
+  //   MemBarRelease
+  //   MemBarCPUOrder {leading}
+  //          |  \      . . .
+  //          |  StoreN/P[mo_release]  . . .
+  //          |   /
+  //         MergeMem
+  //          |
+  //   MemBarVolatile {card mark or trailing}
+  //
+  //   MemBarRelease
+  //   MemBarCPUOrder {leading}
   //      |       \      . . .
   //      |     CompareAndSwapX  . . .
   //               |
   //     . . .    SCMemProj
   //           \   |
   //      |    MergeMem
-  //      |       |
+  //      |        /
   //    MemBarCPUOrder
   //    MemBarAcquire {trailing}
   //
@@ -2227,20 +2085,15 @@
   // if the configuration is present returns the cpuorder member for
   // preference or when absent the release membar otherwise NULL.
   //
-  // n.b. the input membar is expected to be a MemBarVolatile or
-  // MemBarAcquire. if it is a MemBarVolatile it must *not* be a card
-  // mark membar.
-
-  MemBarNode *trailing_to_leading(const MemBarNode *barrier)
+  // n.b. the input membar is expected to be a MemBarVolatile but
+  // need not be a card mark membar.
+
+  MemBarNode *normal_to_leading(const MemBarNode *barrier)
   {
     // input must be a volatile membar
     assert((barrier->Opcode() == Op_MemBarVolatile ||
 	    barrier->Opcode() == Op_MemBarAcquire),
 	   "expecting a volatile or an acquire membar");
-
-    assert((barrier->Opcode() != Op_MemBarVolatile) ||
-	   !is_card_mark_membar(barrier),
-	   "not expecting a card mark membar");
     Node *x;
     bool is_cas = barrier->Opcode() == Op_MemBarAcquire;
 
@@ -2353,35 +2206,169 @@
     return NULL;
   }
 
-  // card_mark_to_leading
-  //
-  // graph traversal helper which traverses from a card mark volatile
-  // membar to a leading membar i.e. it ensures that the following Mem
-  // flow subgraph is present.
-  //
-  //    MemBarRelease {leading}
-  //   {MemBarCPUOrder} {optional}
-  //         |   . . .
+  // card_mark_to_trailing
+  //
+  // graph traversal helper which detects extra, non-normal Mem feed
+  // from a card mark volatile membar to a trailing membar i.e. it
+  // ensures that one of the following three GC post-write Mem flow
+  // subgraphs is present.
+  //
+  // 1)
+  //     . . .
+  //       |
+  //   MemBarVolatile (card mark)
+  //      |          |
+  //      |        StoreCM
+  //      |          |
+  //      |        . . .
+  //  Bot |  /
+  //   MergeMem
+  //      |
+  //      |
+  //    MemBarVolatile {trailing}
+  //
+  // 2)
+  //   MemBarRelease/CPUOrder (leading)
+  //    |
+  //    |
+  //    |\       . . .
+  //    | \        |
+  //    |  \  MemBarVolatile (card mark)
+  //    |   \   |     |
+  //     \   \  |   StoreCM    . . .
+  //      \   \ |
+  //       \  Phi
+  //        \ /
+  //        Phi  . . .
   //     Bot |   /
-  //      MergeMem
+  //       MergeMem
   //         |
-  //     MemBarVolatile (card mark)
-  //        |     \
-  //      . . .   StoreCM
-  //
-  // if the configuration is present returns the cpuorder member for
-  // preference or when absent the release membar otherwise NULL.
-  //
-  // n.b. the input membar is expected to be a MemBarVolatile amd must
-  // be a card mark membar.
-
-  MemBarNode *card_mark_to_leading(const MemBarNode *barrier)
+  //    MemBarVolatile {trailing}
+  //
+  //
+  // 3)
+  //   MemBarRelease/CPUOrder (leading)
+  //    |
+  //    |\
+  //    | \
+  //    |  \      . . .
+  //    |   \       |
+  //    |\   \  MemBarVolatile (card mark)
+  //    | \   \   |     |
+  //    |  \   \  |   StoreCM    . . .
+  //    |   \   \ |
+  //     \   \  Phi
+  //      \   \ /
+  //       \  Phi
+  //        \ /
+  //        Phi  . . .
+  //     Bot |   /
+  //       MergeMem
+  //         |
+  //         |
+  //    MemBarVolatile {trailing}
+  //
+  // configuration 1 is only valid if UseConcMarkSweepGC &&
+  // UseCondCardMark
+  //
+  // configurations 2 and 3 are only valid if UseG1GC.
+  //
+  // if a valid configuration is present returns the trailing membar
+  // otherwise NULL.
+  //
+  // n.b. the supplied membar is expected to be a card mark
+  // MemBarVolatile i.e. the caller must ensure the input node has the
+  // correct operand and feeds Mem to a StoreCM node
+
+  MemBarNode *card_mark_to_trailing(const MemBarNode *barrier)
   {
     // input must be a card mark volatile membar
     assert(is_card_mark_membar(barrier), "expecting a card mark membar");
 
+    Node *feed = barrier->proj_out(TypeFunc::Memory);
+    Node *x;
+    MergeMemNode *mm = NULL;
+
+    const int MAX_PHIS = 3;	// max phis we will search through
+    int phicount = 0; 		// current search count
+
+    bool retry_feed = true;
+    while (retry_feed) {
+      // see if we have a direct MergeMem feed
+      for (DUIterator_Fast imax, i = feed->fast_outs(imax); i < imax; i++) {
+	x = feed->fast_out(i);
+	// the correct Phi will be merging a Bot memory slice
+	if (x->is_MergeMem()) {
+	  mm = x->as_MergeMem();
+	  break;
+	}
+      }
+      if (mm) {
+	retry_feed = false;
+      } else if (UseG1GC & phicount++ < MAX_PHIS) {
+	// the barrier may feed indirectly via one or two Phi nodes
+	PhiNode *phi = NULL;
+	for (DUIterator_Fast imax, i = feed->fast_outs(imax); i < imax; i++) {
+	  x = feed->fast_out(i);
+	  // the correct Phi will be merging a Bot memory slice
+	  if (x->is_Phi() && x->adr_type() == TypePtr::BOTTOM) {
+	    phi = x->as_Phi();
+	    break;
+	  }
+	}
+	if (!phi) {
+	  return NULL;
+	}
+	// look for another merge below this phi
+	feed = phi;
+      } else {
+	// couldn't find a merge
+	return NULL;
+      }
+    }
+
+    // sanity check this feed turns up as the expected slice
+    assert(mm->as_MergeMem()->in(Compile::AliasIdxBot) == feed, "expecting membar to feed AliasIdxBot slice to Merge");
+
+    MemBarNode *trailing = NULL;
+    // be sure we have a trailing membar the merge
+    for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) {
+      x = mm->fast_out(i);
+      if (x->is_MemBar() && x->Opcode() == Op_MemBarVolatile) {
+	trailing = x->as_MemBar();
+	break;
+      }
+    }
+
+    return trailing;
+  }
+
+  // trailing_to_card_mark
+  //
+  // graph traversal helper which detects extra, non-normal Mem feed
+  // from a trailing volatile membar to a preceding card mark volatile
+  // membar i.e. it identifies whether one of the three possible extra
+  // GC post-write Mem flow subgraphs is present
+  //
+  // this predicate checks for the same flow as the previous predicate
+  // but starting from the bottom rather than the top.
+  //
+  // if the configuration is present returns the card mark membar
+  // otherwise NULL
+  //
+  // n.b. the supplied membar is expected to be a trailing
+  // MemBarVolatile i.e. the caller must ensure the input node has the
+  // correct opcode
+
+  MemBarNode *trailing_to_card_mark(const MemBarNode *trailing)
+  {
+    assert(trailing->Opcode() == Op_MemBarVolatile,
+	   "expecting a volatile membar");
+    assert(!is_card_mark_membar(trailing),
+	   "not expecting a card mark membar");
+
     // the Mem feed to the membar should be a merge
-    Node *x = barrier->in(TypeFunc::Memory);
+    Node *x = trailing->in(TypeFunc::Memory);
     if (!x->is_MergeMem()) {
       return NULL;
     }
@@ -2389,19 +2376,117 @@
     MergeMemNode *mm = x->as_MergeMem();
 
     x = mm->in(Compile::AliasIdxBot);
-
+    // with G1 we may possibly see a Phi or two before we see a Memory
+    // Proj from the card mark membar
+
+    const int MAX_PHIS = 3;	// max phis we will search through
+    int phicount = 0; 		// current search count
+
+    bool retry_feed = !x->is_Proj();
+
+    while (retry_feed) {
+      if (UseG1GC && x->is_Phi() && phicount++ < MAX_PHIS) {
+	PhiNode *phi = x->as_Phi();
+	ProjNode *proj = NULL;
+	PhiNode *nextphi = NULL;
+	bool found_leading = false;
+	for (uint i = 1; i < phi->req(); i++) {
+	  x = phi->in(i);
+	  if (x->is_Phi()) {
+	    nextphi = x->as_Phi();
+	  } else if (x->is_Proj()) {
+	    int opcode = x->in(0)->Opcode();
+	    if (opcode == Op_MemBarVolatile) {
+	      proj = x->as_Proj();
+	    } else if (opcode == Op_MemBarRelease ||
+		       opcode == Op_MemBarCPUOrder) {
+	      // probably a leading membar
+	      found_leading = true;
+	    }
+	  }
+	}
+	// if we found a correct looking proj then retry from there
+	// otherwise we must see a leading and a phi or this the
+	// wrong config
+	if (proj != NULL) {
+	  x = proj;
+	  retry_feed = false;
+	} else if (found_leading && nextphi != NULL) {
+	  // retry from this phi to check phi2
+	  x = nextphi;
+	} else {
+	  // not what we were looking for
+	  return NULL;
+	}
+      } else {
+	return NULL;
+      }
+    }
+    // the proj has to come from the card mark membar
+    x = x->in(0);
     if (!x->is_MemBar()) {
       return NULL;
     }
 
-    MemBarNode *leading = x->as_MemBar();
-
-    if (leading_membar(leading)) {
+    MemBarNode *card_mark_membar = x->as_MemBar();
+
+    if (!is_card_mark_membar(card_mark_membar)) {
+      return NULL;
+    }
+
+    return card_mark_membar;
+  }
+
+  // trailing_to_leading
+  //
+  // graph traversal helper which checks the Mem flow up the graph
+  // from a (non-card mark) trailing membar attempting to locate and
+  // return an associated leading membar. it first looks for a
+  // subgraph in the normal configuration (relying on helper
+  // normal_to_leading). failing that it then looks for one of the
+  // possible post-write card mark subgraphs linking the trailing node
+  // to a the card mark membar (relying on helper
+  // trailing_to_card_mark), and then checks that the card mark membar
+  // is fed by a leading membar (once again relying on auxiliary
+  // predicate normal_to_leading).
+  //
+  // if the configuration is valid returns the cpuorder member for
+  // preference or when absent the release membar otherwise NULL.
+  //
+  // n.b. the input membar is expected to be either a volatile or
+  // acquire membar but in the former case must *not* be a card mark
+  // membar.
+
+  MemBarNode *trailing_to_leading(const MemBarNode *trailing)
+  {
+    assert((trailing->Opcode() == Op_MemBarAcquire ||
+	    trailing->Opcode() == Op_MemBarVolatile),
+	   "expecting an acquire or volatile membar");
+    assert((trailing->Opcode() != Op_MemBarVolatile ||
+	    !is_card_mark_membar(trailing)),
+	   "not expecting a card mark membar");
+
+    MemBarNode *leading = normal_to_leading(trailing);
+
+    if (leading) {
       return leading;
     }
 
-    return NULL;
-  }
+    // nothing more to do if this is an acquire
+    if (trailing->Opcode() == Op_MemBarAcquire) {
+      return NULL;
+    }
+
+    MemBarNode *card_mark_membar = trailing_to_card_mark(trailing);
+
+    if (!card_mark_membar) {
+      return NULL;
+    }
+
+    return normal_to_leading(card_mark_membar);
+  }
+
+  // predicates controlling emit of ldr<x>/ldar<x> and associated dmb
 
 bool unnecessary_acquire(const Node *barrier)
 {
@@ -2617,8 +2702,19 @@
   }
 
   // must start with a normal feed
-  MemBarNode *trailing = leading_to_trailing(barrier);
-
+  MemBarNode *child_barrier = leading_to_normal(barrier);
+
+  if (!child_barrier) {
+    return false;
+  }
+
+  if (!is_card_mark_membar(child_barrier)) {
+    // this is the trailing membar and we are done
+    return true;
+  }
+
+  // must be sure this card mark feeds a trailing membar
+  MemBarNode *trailing = card_mark_to_trailing(child_barrier);
   return (trailing != NULL);
 }
 
@@ -2640,7 +2736,7 @@
   }
 
   // ok, if it's not a card mark then we still need to check if it is
-  // a trailing membar of a volatile put graph.
+  // a trailing membar of a volatile put hgraph.
 
   return (trailing_to_leading(mbvol) != NULL);
 }
@@ -2690,9 +2786,20 @@
   }
 
   // does this lead a normal subgraph?
-  MemBarNode *trailing = leading_to_trailing(barrier);
-
-  return (trailing != NULL);
+  MemBarNode *mbvol = leading_to_normal(barrier);
+
+  if (!mbvol) {
+    return false;
+  }
+
+  // all done unless this is a card mark
+  if (!is_card_mark_membar(mbvol)) {
+    return true;
+  }
+
+  // we found a card mark -- just make sure we have a trailing barrier
+
+  return (card_mark_to_trailing(mbvol) != NULL);
 }
 
 // predicate controlling translation of CAS
@@ -2734,7 +2841,7 @@
 	  "CAS not fed by cpuorder+release membar pair!");
 
   // does this lead a normal subgraph?
-  MemBarNode *mbar = leading_to_trailing(barrier);
+  MemBarNode *mbar = leading_to_normal(barrier);
 
   assert(mbar != NULL, "CAS not embedded in normal graph!");
 
@@ -2755,27 +2862,48 @@
 
   // we only ever need to generate a dmb ishst between an object put
   // and the associated card mark when we are using CMS without
-  // conditional card marking. Any other occurence will happen when
-  // performing a card mark using CMS with conditional card marking or
-  // G1. In those cases the preceding MamBarVolatile will be
-  // translated to a dmb ish which guarantes visibility of the
-  // preceding StoreN/P before this StoreCM
+  // conditional card marking
 
   if (!UseConcMarkSweepGC || UseCondCardMark) {
     return true;
   }
 
-  // if we are implementing volatile puts using barriers then we must
-  // insert the dmb ishst
+  // if we are implementing volatile puts using barriers then the
+  // object put as an str so we must insert the dmb ishst
 
   if (UseBarriersForVolatile) {
     return false;
   }
 
-  // we must be using CMS with conditional card marking so we ahve to
-  // generate the StoreStore
-
-  return false;
+  // we can omit the dmb ishst if this StoreCM is part of a volatile
+  // put because in thta case the put will be implemented by stlr
+  //
+  // we need to check for a normal subgraph feeding this StoreCM.
+  // that means the StoreCM must be fed Memory from a leading membar,
+  // either a MemBarRelease or its dependent MemBarCPUOrder, and the
+  // leading membar must be part of a normal subgraph
+
+  Node *x = storecm->in(StoreNode::Memory);
+
+  if (!x->is_Proj()) {
+    return false;
+  }
+
+  x = x->in(0);
+
+  if (!x->is_MemBar()) {
+    return false;
+  }
+
+  MemBarNode *leading = x->as_MemBar();
+
+  // reject invalid candidates
+  if (!leading_membar(leading)) {
+    return false;
+  }
+
+  // we can omit the StoreStore if it is the head of a normal subgraph
+  return (leading_to_normal(leading) != NULL);
 }
 
 
@@ -3008,6 +3136,10 @@
     __ notify(Assembler::method_reentry);
   }
 
+  if (StackReservedPages > 0 && C->has_reserved_stack_access()) {
+    __ reserved_stack_check();
+  }
+
   if (do_polling() && C->is_method_compilation()) {
     __ read_polling_page(rscratch1, os::get_polling_page(), relocInfo::poll_return_type);
   }
@@ -9862,7 +9994,7 @@
 // END This section of the file is automatically generated. Do not edit --------------
 // ---------------------------------------------------------------------
 
-instruct get_and_setI(indirect mem, iRegINoSp newv, iRegI prev) %{
+instruct get_and_setI(indirect mem, iRegI newv, iRegINoSp prev) %{
   match(Set prev (GetAndSetI mem newv));
   format %{ "atomic_xchgw  $prev, $newv, [$mem]" %}
   ins_encode %{
@@ -9871,7 +10003,7 @@
   ins_pipe(pipe_serial);
 %}
 
-instruct get_and_setL(indirect mem, iRegLNoSp newv, iRegL prev) %{
+instruct get_and_setL(indirect mem, iRegL newv, iRegLNoSp prev) %{
   match(Set prev (GetAndSetL mem newv));
   format %{ "atomic_xchg  $prev, $newv, [$mem]" %}
   ins_encode %{
@@ -9880,7 +10012,7 @@
   ins_pipe(pipe_serial);
 %}
 
-instruct get_and_setN(indirect mem, iRegNNoSp newv, iRegI prev) %{
+instruct get_and_setN(indirect mem, iRegN newv, iRegINoSp prev) %{
   match(Set prev (GetAndSetN mem newv));
   format %{ "atomic_xchgw $prev, $newv, [$mem]" %}
   ins_encode %{
@@ -9889,7 +10021,7 @@
   ins_pipe(pipe_serial);
 %}
 
-instruct get_and_setP(indirect mem, iRegPNoSp newv, iRegP prev) %{
+instruct get_and_setP(indirect mem, iRegP newv, iRegPNoSp prev) %{
   match(Set prev (GetAndSetP mem newv));
   format %{ "atomic_xchg  $prev, $newv, [$mem]" %}
   ins_encode %{
--- a/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -532,8 +532,14 @@
 
 void LIR_Assembler::return_op(LIR_Opr result) {
   assert(result->is_illegal() || !result->is_single_cpu() || result->as_register() == r0, "word returns are in r0,");
+
   // Pop the stack before the safepoint code
   __ remove_frame(initial_frame_size_in_bytes());
+
+  if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) {
+    __ reserved_stack_check();
+  }
+
   address polling_page(os::get_polling_page());
   __ read_polling_page(rscratch1, polling_page, relocInfo::poll_return_type);
   __ ret(lr);
@@ -1916,12 +1922,17 @@
     }
 
     if (opr2->is_constant()) {
+      bool is_32bit = false; // width of register operand
       jlong imm;
+
       switch(opr2->type()) {
+      case T_INT:
+        imm = opr2->as_constant_ptr()->as_jint();
+        is_32bit = true;
+        break;
       case T_LONG:
         imm = opr2->as_constant_ptr()->as_jlong();
         break;
-      case T_INT:
       case T_ADDRESS:
         imm = opr2->as_constant_ptr()->as_jint();
         break;
@@ -1936,14 +1947,14 @@
       }
 
       if (Assembler::operand_valid_for_add_sub_immediate(imm)) {
-        if (type2aelembytes(opr1->type()) <= 4)
+        if (is_32bit)
           __ cmpw(reg1, imm);
         else
           __ cmp(reg1, imm);
         return;
       } else {
         __ mov(rscratch1, imm);
-        if (type2aelembytes(opr1->type()) <= 4)
+        if (is_32bit)
           __ cmpw(reg1, rscratch1);
         else
           __ cmp(reg1, rscratch1);
--- a/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2014, Red Hat Inc. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -1179,6 +1179,15 @@
         Label done;
         Label runtime;
 
+        // Is marking still active?
+        if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+          __ ldrw(tmp, in_progress);
+        } else {
+          assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+          __ ldrb(tmp, in_progress);
+        }
+        __ cbzw(tmp, done);
+
         // Can we store original value in the thread's buffer?
         __ ldr(tmp, queue_index);
         __ cbz(tmp, runtime);
--- a/src/cpu/aarch64/vm/frame_aarch64.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/aarch64/vm/frame_aarch64.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -375,7 +375,8 @@
   fr._unextended_sp = unextended_sp;
 
   address original_pc = nm->get_original_pc(&fr);
-  assert(nm->insts_contains(original_pc), "original PC must be in nmethod");
+  assert(nm->insts_contains_inclusive(original_pc),
+         "original PC must be in the main code section of the the compiled method (or must be immediately following it)");
 }
 #endif
 
@@ -629,6 +630,7 @@
     DESCRIBE_FP_OFFSET(interpreter_frame_last_sp);
     DESCRIBE_FP_OFFSET(interpreter_frame_method);
     DESCRIBE_FP_OFFSET(interpreter_frame_mdp);
+    DESCRIBE_FP_OFFSET(interpreter_frame_mirror);
     DESCRIBE_FP_OFFSET(interpreter_frame_cache);
     DESCRIBE_FP_OFFSET(interpreter_frame_locals);
     DESCRIBE_FP_OFFSET(interpreter_frame_bcp);
--- a/src/cpu/aarch64/vm/frame_aarch64.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/aarch64/vm/frame_aarch64.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -46,6 +46,9 @@
 //    [pointer to locals     ]                   = locals()             locals_offset
 //    [constant pool cache   ]                   = cache()              cache_offset
 
+//    [klass of method       ]                   = mirror()             mirror_offset
+//    [padding               ]
+
 //    [methodData            ]                   = mdp()                mdx_offset
 //    [methodOop             ]                   = method()             method_offset
 
--- a/src/cpu/aarch64/vm/frame_aarch64.inline.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/aarch64/vm/frame_aarch64.inline.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -82,7 +82,8 @@
   address original_pc = CompiledMethod::get_deopt_original_pc(this);
   if (original_pc != NULL) {
     _pc = original_pc;
-    assert(((CompiledMethod*)_cb)->insts_contains(_pc), "original PC must be in CompiledMethod");
+    assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc),
+           "original PC must be in the main code section of the the compiled method (or must be immediately following it)");
     _deopt_state = is_deoptimized;
   } else {
     _deopt_state = not_deoptimized;
--- a/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -53,4 +53,6 @@
 // evidence that it's worth doing.
 #define DEOPTIMIZE_WHEN_PATCHING
 
+#define SUPPORT_RESERVED_STACK_AREA
+
 #endif // CPU_AARCH64_VM_GLOBALDEFINITIONS_AARCH64_HPP
--- a/src/cpu/aarch64/vm/globals_aarch64.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/aarch64/vm/globals_aarch64.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -46,8 +46,11 @@
 
 #define DEFAULT_STACK_YELLOW_PAGES (2)
 #define DEFAULT_STACK_RED_PAGES (1)
-#define DEFAULT_STACK_SHADOW_PAGES (4 DEBUG_ONLY(+5))
-#define DEFAULT_STACK_RESERVED_PAGES (0)
+// Java_java_net_SocketOutputStream_socketWrite0() uses a 64k buffer on the
+// stack if compiled for unix and LP64. To pass stack overflow tests we need
+// 20 shadow pages.
+#define DEFAULT_STACK_SHADOW_PAGES (20 DEBUG_ONLY(+5))
+#define DEFAULT_STACK_RESERVED_PAGES (1)
 
 #define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES
 #define MIN_STACK_RED_PAGES    DEFAULT_STACK_RED_PAGES
--- a/src/cpu/aarch64/vm/interp_masm_aarch64.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/aarch64/vm/interp_masm_aarch64.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -619,6 +619,22 @@
   // get sender esp
   ldr(esp,
       Address(rfp, frame::interpreter_frame_sender_sp_offset * wordSize));
+  if (StackReservedPages > 0) {
+    // testing if reserved zone needs to be re-enabled
+    Label no_reserved_zone_enabling;
+
+    ldr(rscratch1, Address(rthread, JavaThread::reserved_stack_activation_offset()));
+    cmp(esp, rscratch1);
+    br(Assembler::LS, no_reserved_zone_enabling);
+
+    call_VM_leaf(
+      CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), rthread);
+    call_VM(noreg, CAST_FROM_FN_PTR(address,
+                   InterpreterRuntime::throw_delayed_StackOverflowError));
+    should_not_reach_here();
+
+    bind(no_reserved_zone_enabling);
+  }
   // remove frame anchor
   leave();
   // If we're returning to interpreted code we will shortly be
--- a/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -402,6 +402,30 @@
   }
 }
 
+void MacroAssembler::reserved_stack_check() {
+    // testing if reserved zone needs to be enabled
+    Label no_reserved_zone_enabling;
+
+    ldr(rscratch1, Address(rthread, JavaThread::reserved_stack_activation_offset()));
+    cmp(sp, rscratch1);
+    br(Assembler::LO, no_reserved_zone_enabling);
+
+    enter();   // LR and FP are live.
+    lea(rscratch1, CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone));
+    mov(c_rarg0, rthread);
+    blr(rscratch1);
+    leave();
+
+    // We have already removed our own frame.
+    // throw_delayed_StackOverflowError will think that it's been
+    // called by our caller.
+    lea(rscratch1, RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry()));
+    br(rscratch1);
+    should_not_reach_here();
+
+    bind(no_reserved_zone_enabling);
+}
+
 int MacroAssembler::biased_locking_enter(Register lock_reg,
                                          Register obj_reg,
                                          Register swap_reg,
--- a/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -957,6 +957,9 @@
   // stack overflow + shadow pages.  Also, clobbers tmp
   void bang_stack_size(Register size, Register tmp);
 
+  // Check for reserved stack access in method being exited (for JIT)
+  void reserved_stack_check();
+
   virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr,
                                                 Register tmp,
                                                 int offset);
--- a/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -4676,8 +4676,11 @@
     StubRoutines::_throw_StackOverflowError_entry =
       generate_throw_exception("StackOverflowError throw_exception",
                                CAST_FROM_FN_PTR(address,
-                                                SharedRuntime::
-                                                throw_StackOverflowError));
+                                                SharedRuntime::throw_StackOverflowError));
+    StubRoutines::_throw_delayed_StackOverflowError_entry =
+      generate_throw_exception("delayed StackOverflowError throw_exception",
+                               CAST_FROM_FN_PTR(address,
+                                                SharedRuntime::throw_delayed_StackOverflowError));
     if (UseCRC32Intrinsics) {
       // set table address before stub generation which use it
       StubRoutines::_crc_table_adr = (address)StubRoutines::aarch64::_crc_table;
--- a/src/cpu/arm/vm/c1_Runtime1_arm.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/arm/vm/c1_Runtime1_arm.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, 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
@@ -551,6 +551,8 @@
         const Register r_index_1    = R1;
         const Register r_buffer_2   = R2;
 
+        Address queue_active(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
+                                               SATBMarkQueue::byte_offset_of_active()));
         Address queue_index(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
                                               SATBMarkQueue::byte_offset_of_index()));
         Address buffer(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
@@ -559,6 +561,11 @@
         Label done;
         Label runtime;
 
+        // Is marking still active?
+        assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+        __ ldrb(R1, queue_active);
+        __ cbz(R1, done);
+
         __ ldr(r_index_1, queue_index);
         __ ldr(r_pre_val_0, Address(SP, nb_saved_regs*wordSize));
         __ ldr(r_buffer_2, buffer);
--- a/src/cpu/arm/vm/frame_arm.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/arm/vm/frame_arm.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -364,7 +364,8 @@
   fr._unextended_sp = unextended_sp;
 
   address original_pc = nm->get_original_pc(&fr);
-  assert(nm->insts_contains(original_pc), "original PC must be in nmethod");
+  assert(nm->insts_contains_inclusive(original_pc),
+         "original PC must be in the main code section of the the compiled method (or must be immediately following it)");
   assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be");
 }
 #endif
--- a/src/cpu/arm/vm/frame_arm.inline.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/arm/vm/frame_arm.inline.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -75,7 +75,8 @@
   address original_pc = CompiledMethod::get_deopt_original_pc(this);
   if (original_pc != NULL) {
     _pc = original_pc;
-    assert(_cb->as_compiled_method()->insts_contains(_pc), "original PC must be in CompiledMethod");
+    assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc),
+           "original PC must be in the main code section of the the compiled method (or must be immediately following it)");
     _deopt_state = is_deoptimized;
   } else {
     _deopt_state = not_deoptimized;
--- a/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2012, 2015 SAP SE. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -741,7 +741,10 @@
         Register tmp  = R14;
         Register tmp2 = R15;
 
-        Label refill, restart;
+        Label refill, restart, marking_not_active;
+        int satb_q_active_byte_offset =
+          in_bytes(JavaThread::satb_mark_queue_offset() +
+                   SATBMarkQueue::byte_offset_of_active());
         int satb_q_index_byte_offset =
           in_bytes(JavaThread::satb_mark_queue_offset() +
                    SATBMarkQueue::byte_offset_of_index());
@@ -753,6 +756,16 @@
         __ std(tmp, -16, R1_SP);
         __ std(tmp2, -24, R1_SP);
 
+        // Is marking still active?
+        if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+          __ lwz(tmp, satb_q_active_byte_offset, R16_thread);
+        } else {
+          assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+          __ lbz(tmp, satb_q_active_byte_offset, R16_thread);
+        }
+        __ cmpdi(CCR0, tmp, 0);
+        __ beq(CCR0, marking_not_active);
+
         __ bind(restart);
         // Load the index into the SATB buffer. SATBMarkQueue::_index is a
         // size_t so ld_ptr is appropriate.
@@ -769,6 +782,7 @@
         __ std(tmp, satb_q_index_byte_offset, R16_thread);
         __ stdx(pre_val, tmp2, tmp); // [_buf + index] := <address_of_card>
 
+        __ bind(marking_not_active);
         // Restore temp registers and return-from-leaf.
         __ ld(tmp2, -24, R1_SP);
         __ ld(tmp, -16, R1_SP);
--- a/src/cpu/ppc/vm/macroAssembler_ppc.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/ppc/vm/macroAssembler_ppc.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -2569,7 +2569,7 @@
 }
 
 // Spin and retry if lock is busy.
-// inputs: box_Reg (monitor address)
+// inputs: owner_addr_Reg (monitor address)
 //       : retry_count_Reg
 // output: retry_count_Reg decremented by 1
 // CTR is killed
@@ -2577,15 +2577,22 @@
   Label SpinLoop, doneRetry;
   addic_(retry_count_Reg, retry_count_Reg, -1);
   blt(CCR0, doneRetry);
-  li(R0, RTMSpinLoopCount);
-  mtctr(R0);
+
+  if (RTMSpinLoopCount > 1) {
+    li(R0, RTMSpinLoopCount);
+    mtctr(R0);
+  }
 
   bind(SpinLoop);
   smt_yield(); // Can't use waitrsv(). No permission (SIGILL).
-  bdz(retryLabel);
-  ld(R0, 0, owner_addr_Reg);
-  cmpdi(CCR0, R0, 0);
-  bne(CCR0, SpinLoop);
+
+  if (RTMSpinLoopCount > 1) {
+    bdz(retryLabel);
+    ld(R0, 0, owner_addr_Reg);
+    cmpdi(CCR0, R0, 0);
+    bne(CCR0, SpinLoop);
+  }
+
   b(retryLabel);
 
   bind(doneRetry);
--- a/src/cpu/ppc/vm/vm_version_ppc.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/ppc/vm/vm_version_ppc.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -327,7 +327,10 @@
       warning("RTMAbortRatio must be in the range 0 to 100, resetting it to 50");
       FLAG_SET_DEFAULT(RTMAbortRatio, 50);
     }
-    guarantee(RTMSpinLoopCount > 0, "unsupported");
+    if (RTMSpinLoopCount < 0) {
+      warning("RTMSpinLoopCount must not be a negative value, resetting it to 0");
+      FLAG_SET_DEFAULT(RTMSpinLoopCount, 0);
+    }
 #else
     // Only C2 does RTM locking optimization.
     // Can't continue because UseRTMLocking affects UseBiasedLocking flag
--- a/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1105,16 +1105,16 @@
       }
     case T_FLOAT :
       if (short_disp) {
-                    __ z_ste(from->as_float_reg(),  disp_value, disp_reg, dest);
+        __ z_ste(from->as_float_reg(),  disp_value, disp_reg, dest);
       } else {
-                    __ z_stey(from->as_float_reg(), disp_value, disp_reg, dest);
+        __ z_stey(from->as_float_reg(), disp_value, disp_reg, dest);
       }
       break;
     case T_DOUBLE:
       if (short_disp) {
-                    __ z_std(from->as_double_reg(),  disp_value, disp_reg, dest);
+        __ z_std(from->as_double_reg(),  disp_value, disp_reg, dest);
       } else {
-                    __ z_stdy(from->as_double_reg(), disp_value, disp_reg, dest);
+        __ z_stdy(from->as_double_reg(), disp_value, disp_reg, dest);
       }
       break;
     default: ShouldNotReachHere();
@@ -1148,6 +1148,10 @@
     __ restore_return_pc();
   }
 
+  if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) {
+    __ reserved_stack_check(Z_R14);
+  }
+
   // We need to mark the code position where the load from the safepoint
   // polling page was emitted as relocInfo::poll_return_type here.
   __ relocate(relocInfo::poll_return_type);
--- a/src/cpu/s390/vm/c1_Runtime1_s390.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/s390/vm/c1_Runtime1_s390.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017 Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2016 SAP SE. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -784,7 +784,10 @@
         Register tmp  = Z_R6; // Must be non-volatile because it is used to save pre_val.
         Register tmp2 = Z_R7;
 
-        Label refill, restart;
+        Label refill, restart, marking_not_active;
+        int satb_q_active_byte_offset =
+          in_bytes(JavaThread::satb_mark_queue_offset() +
+                   SATBMarkQueue::byte_offset_of_active());
         int satb_q_index_byte_offset =
           in_bytes(JavaThread::satb_mark_queue_offset() +
                    SATBMarkQueue::byte_offset_of_index());
@@ -796,6 +799,15 @@
         __ z_stg(tmp,  0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
         __ z_stg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
 
+        // Is marking still active?
+        if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+          __ load_and_test_int(tmp, Address(Z_thread, satb_q_active_byte_offset));
+        } else {
+          assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+          __ load_and_test_byte(tmp, Address(Z_thread, satb_q_active_byte_offset));
+        }
+        __ z_bre(marking_not_active); // Activity indicator is zero, so there is no marking going on currently.
+
         __ bind(restart);
         // Load the index into the SATB buffer. SATBMarkQueue::_index is a
         // size_t so ld_ptr is appropriate.
@@ -810,6 +822,7 @@
         __ z_stg(pre_val, 0, tmp, tmp2); // [_buf + index] := <address_of_card>
         __ z_stg(tmp, satb_q_index_byte_offset, Z_thread);
 
+        __ bind(marking_not_active);
         // Restore tmp registers (see assertion in G1PreBarrierStub::emit_code()).
         __ z_lg(tmp,  0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
         __ z_lg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
--- a/src/cpu/s390/vm/globalDefinitions_s390.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/s390/vm/globalDefinitions_s390.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -52,4 +52,6 @@
 // The expected size in bytes of a cache line, used to pad data structures.
 #define DEFAULT_CACHE_LINE_SIZE 256
 
+#define SUPPORT_RESERVED_STACK_AREA
+
 #endif // CPU_S390_VM_GLOBALDEFINITIONS_S390_HPP
--- a/src/cpu/s390/vm/globals_s390.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/s390/vm/globals_s390.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -56,7 +56,7 @@
 // Java_java_net_SocketOutputStream_socketWrite0() uses a 64k buffer on the
 // stack. To pass stack overflow tests we need 20 shadow pages.
 #define DEFAULT_STACK_SHADOW_PAGES   (20 DEBUG_ONLY(+2))
-#define DEFAULT_STACK_RESERVED_PAGES (0)
+#define DEFAULT_STACK_RESERVED_PAGES (1)
 
 #define MIN_STACK_YELLOW_PAGES     DEFAULT_STACK_YELLOW_PAGES
 #define MIN_STACK_RED_PAGES        DEFAULT_STACK_RED_PAGES
--- a/src/cpu/s390/vm/interp_masm_s390.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/s390/vm/interp_masm_s390.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -860,16 +860,39 @@
                                                   bool throw_monitor_exception,
                                                   bool install_monitor_exception,
                                                   bool notify_jvmti) {
-
+  BLOCK_COMMENT("remove_activation {");
   unlock_if_synchronized_method(state, throw_monitor_exception, install_monitor_exception);
 
   // Save result (push state before jvmti call and pop it afterwards) and notify jvmti.
   notify_method_exit(false, state, notify_jvmti ? NotifyJVMTI : SkipNotifyJVMTI);
 
+  if (StackReservedPages > 0) {
+    BLOCK_COMMENT("reserved_stack_check:");
+    // Test if reserved zone needs to be enabled.
+    Label no_reserved_zone_enabling;
+
+    // Compare frame pointers. There is no good stack pointer, as with stack
+    // frame compression we can get different SPs when we do calls. A subsequent
+    // call could have a smaller SP, so that this compare succeeds for an
+    // inner call of the method annotated with ReservedStack.
+    z_lg(Z_R0, Address(Z_SP, (intptr_t)_z_abi(callers_sp)));
+    z_clg(Z_R0, Address(Z_thread, JavaThread::reserved_stack_activation_offset())); // Compare with frame pointer in memory.
+    z_brl(no_reserved_zone_enabling);
+
+    // Enable reserved zone again, throw stack overflow exception.
+    call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), Z_thread);
+    call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_delayed_StackOverflowError));
+
+    should_not_reach_here();
+
+    bind(no_reserved_zone_enabling);
+  }
+
   verify_oop(Z_tos, state);
   verify_thread();
 
   pop_interpreter_frame(return_pc, Z_ARG2, Z_ARG3);
+  BLOCK_COMMENT("} remove_activation");
 }
 
 // lock object
--- a/src/cpu/s390/vm/macroAssembler_s390.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/s390/vm/macroAssembler_s390.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -2677,6 +2677,32 @@
   }
 }
 
+void MacroAssembler::reserved_stack_check(Register return_pc) {
+  // Test if reserved zone needs to be enabled.
+  Label no_reserved_zone_enabling;
+  assert(return_pc == Z_R14, "Return pc must be in R14 before z_br() to StackOverflow stub.");
+  BLOCK_COMMENT("reserved_stack_check {");
+
+  z_clg(Z_SP, Address(Z_thread, JavaThread::reserved_stack_activation_offset()));
+  z_brl(no_reserved_zone_enabling);
+
+  // Enable reserved zone again, throw stack overflow exception.
+  save_return_pc();
+  push_frame_abi160(0);
+  call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), Z_thread);
+  pop_frame();
+  restore_return_pc();
+
+  load_const_optimized(Z_R1, StubRoutines::throw_delayed_StackOverflowError_entry());
+  // Don't use call() or z_basr(), they will invalidate Z_R14 which contains the return pc.
+  z_br(Z_R1);
+
+  should_not_reach_here();
+
+  bind(no_reserved_zone_enabling);
+  BLOCK_COMMENT("} reserved_stack_check");
+}
+
 // Defines obj, preserves var_size_in_bytes, okay for t2 == var_size_in_bytes.
 void MacroAssembler::tlab_allocate(Register obj,
                                    Register var_size_in_bytes,
@@ -2726,11 +2752,11 @@
   BLOCK_COMMENT("lookup_interface_method {");
 
   // Load start of itable entries into itable_entry_addr.
-  z_llgf(vtable_len, Address(recv_klass, InstanceKlass::vtable_length_offset()));
+  z_llgf(vtable_len, Address(recv_klass, Klass::vtable_length_offset()));
   z_sllg(vtable_len, vtable_len, exact_log2(vtableEntry::size_in_bytes()));
 
   // Loop over all itable entries until desired interfaceOop(Rinterface) found.
-  const int vtable_base_offset = in_bytes(InstanceKlass::vtable_start_offset());
+  const int vtable_base_offset = in_bytes(Klass::vtable_start_offset());
 
   add2reg_with_index(itable_entry_addr,
                      vtable_base_offset + itableOffsetEntry::interface_offset_in_bytes(),
--- a/src/cpu/s390/vm/macroAssembler_s390.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/s390/vm/macroAssembler_s390.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -627,6 +627,11 @@
   // Stack overflow checking
   void bang_stack_with_offset(int offset);
 
+  // Check for reserved stack access in method being exited. If the reserved
+  // stack area was accessed, protect it again and throw StackOverflowError.
+  // Uses Z_R1.
+  void reserved_stack_check(Register return_pc);
+
   // Atomics
   // -- none?
 
--- a/src/cpu/s390/vm/s390.ad	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/s390/vm/s390.ad	Mon Feb 27 23:20:05 2017 +0100
@@ -909,15 +909,8 @@
   // If this does safepoint polling, then do it here.
   bool need_polling = do_polling() && C->is_method_compilation();
 
-  // Touch the polling page.
-  // Part 1: get the page's address.
-  if (need_polling) {
-    AddressLiteral pp(os::get_polling_page());
-    __ load_const_optimized(Z_R1_scratch, pp);
-  }
-
   // Pop frame, restore return_pc, and all stuff needed by interpreter.
-  // Pop frame by add insted of load (a penny saved is a penny got :-).
+  // Pop frame by add instead of load (a penny saved is a penny got :-).
   int frame_size_in_bytes = Assembler::align((C->frame_slots() << LogBytesPerInt), frame::alignment_in_bytes);
   int retPC_offset        = frame_size_in_bytes + _z_abi16(return_pc);
   if (Displacement::is_validDisp(retPC_offset)) {
@@ -928,9 +921,14 @@
     __ restore_return_pc();
   }
 
-  // Touch the polling page,
-  // part 2: touch the page now.
+  if (StackReservedPages > 0 && C->has_reserved_stack_access()) {
+    __ reserved_stack_check(Z_R14);
+  }
+
+  // Touch the polling page.
   if (need_polling) {
+    AddressLiteral pp(os::get_polling_page());
+    __ load_const_optimized(Z_R1_scratch, pp);
     // We need to mark the code position where the load from the safepoint
     // polling page was emitted as relocInfo::poll_return_type here.
     __ relocate(relocInfo::poll_return_type);
@@ -939,7 +937,7 @@
 }
 
 uint MachEpilogNode::size(PhaseRegAlloc *ra_) const {
-  // variable size. determine dynamically.
+  // Variable size. determine dynamically.
   return MachNode::size(ra_);
 }
 
@@ -6770,6 +6768,7 @@
   format %{ "SLL     $dst,$src,$nbits\t# use RISC-like SLLG also for int" %}
   ins_encode %{
     int Nbit = $nbits$$constant;
+    assert((Nbit & (BitsPerJavaInteger - 1)) == Nbit, "Check shift mask in ideal graph");
     __ z_sllg($dst$$Register, $src$$Register, Nbit & (BitsPerJavaInteger - 1), Z_R0);
   %}
   ins_pipe(pipe_class_dummy);
@@ -6843,6 +6842,7 @@
   format %{ "SRA     $dst,$src" %}
   ins_encode %{
     int Nbit = $src$$constant;
+    assert((Nbit & (BitsPerJavaInteger - 1)) == Nbit, "Check shift mask in ideal graph");
     __ z_sra($dst$$Register, Nbit & (BitsPerJavaInteger - 1), Z_R0);
   %}
   ins_pipe(pipe_class_dummy);
@@ -6895,6 +6895,7 @@
   format %{ "SRL     $dst,$src" %}
   ins_encode %{
     int Nbit = $src$$constant;
+    assert((Nbit & (BitsPerJavaInteger - 1)) == Nbit, "Check shift mask in ideal graph");
     __ z_srl($dst$$Register, Nbit & (BitsPerJavaInteger - 1), Z_R0);
   %}
   ins_pipe(pipe_class_dummy);
--- a/src/cpu/s390/vm/stubGenerator_s390.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/s390/vm/stubGenerator_s390.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -623,26 +623,6 @@
 #define __ (Verbose ? (_masm->block_comment(FILE_AND_LINE),_masm):_masm)->
 #endif
 
-  //----------------------------------------------------------------------
-  // The following routine generates a subroutine to throw an asynchronous
-  // UnknownError when an unsafe access gets a fault that could not be
-  // reasonably prevented by the programmer. (Example: SIGBUS/OBJERR.)
-  //
-  // Arguments:
-  //   trapping PC: ??
-  //
-  // Results:
-  //   Posts an asynchronous exception, skips the trapping instruction.
-  //
-  address generate_handler_for_unsafe_access() {
-    StubCodeMark mark(this, "StubRoutines", "handler_for_unsafe_access");
-    {
-      address start = __ pc();
-      __ unimplemented("StubRoutines::handler_for_unsafe_access", 86);
-      return start;
-    }
-  }
-
   // Support for uint StubRoutine::zarch::partial_subtype_check(Klass
   // sub, Klass super);
   //
@@ -2433,13 +2413,12 @@
     StubRoutines::_throw_StackOverflowError_entry          =
       generate_throw_exception("StackOverflowError throw_exception",
                                CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false);
+    StubRoutines::_throw_delayed_StackOverflowError_entry  =
+      generate_throw_exception("delayed StackOverflowError throw_exception",
+                               CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError), false);
 
     //----------------------------------------------------------------------
     // Entry points that are platform specific.
-    // Build this early so it's available for the interpreter.
-    StubRoutines::_throw_StackOverflowError_entry          =
-      generate_throw_exception("StackOverflowError throw_exception",
-                               CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false);
 
     if (UseCRC32Intrinsics) {
       // We have no CRC32 table on z/Architecture.
@@ -2462,8 +2441,6 @@
     StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError),  false);
     StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call), false);
 
-    StubRoutines::zarch::_handler_for_unsafe_access_entry  =  generate_handler_for_unsafe_access();
-
     // Support for verify_oop (must happen after universe_init).
     StubRoutines::_verify_oop_subroutine_entry             = generate_verify_oop_subroutine();
 
--- a/src/cpu/s390/vm/stubRoutines_s390.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/s390/vm/stubRoutines_s390.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -33,8 +33,6 @@
 // Implementation of the platform-specific part of StubRoutines - for
 // a description of how to extend it, see the stubRoutines.hpp file.
 
-address StubRoutines::zarch::_handler_for_unsafe_access_entry = NULL;
-
 address StubRoutines::zarch::_partial_subtype_check = NULL;
 
 // Comapct string intrinsics: Translate table for string inflate intrinsic. Used by trot instruction.
--- a/src/cpu/s390/vm/stubRoutines_s390.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/s390/vm/stubRoutines_s390.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -68,8 +68,6 @@
   };
 
  private:
-  static address _handler_for_unsafe_access_entry;
-
   static int _atomic_memory_operation_lock;
 
   static address _partial_subtype_check;
@@ -91,8 +89,6 @@
   static int atomic_memory_operation_lock() { return _atomic_memory_operation_lock; }
   static void set_atomic_memory_operation_lock(int value) { _atomic_memory_operation_lock = value; }
 
-  static address handler_for_unsafe_access_entry()        { return _handler_for_unsafe_access_entry; }
-
   static address partial_subtype_check()                  { return _partial_subtype_check; }
 
   static void generate_load_crc_table_addr(MacroAssembler* masm, Register table);
--- a/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1105,16 +1105,21 @@
   // top_frame_size = TOP_IJAVA_FRAME_ABI + max_stack + size of interpreter state
   __ add2reg(top_frame_size,
              frame::z_top_ijava_frame_abi_size +
-               frame::z_ijava_state_size +
-               frame::interpreter_frame_monitor_size() * wordSize,
+             frame::z_ijava_state_size +
+             frame::interpreter_frame_monitor_size() * wordSize,
              max_stack);
 
-  // Check if there's room for the new frame...
-  Register frame_size = max_stack; // Reuse the regiser for max_stack.
-  __ z_lgr(frame_size, Z_SP);
-  __ z_sgr(frame_size, sp_after_resize);
-  __ z_agr(frame_size, top_frame_size);
-  generate_stack_overflow_check(frame_size, fp/*tmp1*/);
+  if (!native_call) {
+    // Stack overflow check.
+    // Native calls don't need the stack size check since they have no
+    // expression stack and the arguments are already on the stack and
+    // we only add a handful of words to the stack.
+    Register frame_size = max_stack; // Reuse the regiser for max_stack.
+    __ z_lgr(frame_size, Z_SP);
+    __ z_sgr(frame_size, sp_after_resize);
+    __ z_agr(frame_size, top_frame_size);
+    generate_stack_overflow_check(frame_size, fp/*tmp1*/);
+  }
 
   DEBUG_ONLY(__ z_cg(Z_R14, _z_abi16(return_pc), Z_SP));
   __ asm_assert_eq("killed Z_R14", 0);
--- a/src/cpu/s390/vm/templateTable_s390.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/s390/vm/templateTable_s390.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -3466,7 +3466,7 @@
   __ z_sllg(index, index, exact_log2(vtableEntry::size_in_bytes()));
   __ mem2reg_opt(method,
                  Address(Z_tmp_2, index,
-                         InstanceKlass::vtable_start_offset() + in_ByteSize(vtableEntry::method_offset_in_bytes())));
+                         Klass::vtable_start_offset() + in_ByteSize(vtableEntry::method_offset_in_bytes())));
   __ profile_arguments_type(Z_ARG4, method, Z_ARG5, true);
   __ jump_from_interpreted(method, Z_ARG4);
   BLOCK_COMMENT("} invokevirtual_helper");
--- a/src/cpu/s390/vm/vtableStubs_s390.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/s390/vm/vtableStubs_s390.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -83,7 +83,7 @@
   __ load_klass(rcvr_klass, Z_ARG1);
 
   // Set method (in case of interpreted method), and destination address.
-  int entry_offset = in_bytes(InstanceKlass::vtable_start_offset()) +
+  int entry_offset = in_bytes(Klass::vtable_start_offset()) +
                      vtable_index * vtableEntry::size_in_bytes();
 
 #ifndef PRODUCT
@@ -96,8 +96,8 @@
     //                  worst case             actual size
     padding_bytes += __ load_const_size() - __ load_const_optimized_rtn_len(vtable_idx, vtable_index*vtableEntry::size_in_bytes(), true);
 
-    assert(Immediate::is_uimm12(in_bytes(InstanceKlass::vtable_length_offset())), "disp to large");
-    __ z_cl(vtable_idx, in_bytes(InstanceKlass::vtable_length_offset()), rcvr_klass);
+    assert(Immediate::is_uimm12(in_bytes(Klass::vtable_length_offset())), "disp to large");
+    __ z_cl(vtable_idx, in_bytes(Klass::vtable_length_offset()), rcvr_klass);
     __ z_brl(L);
     __ z_lghi(Z_ARG3, vtable_index);  // Debug code, don't optimize.
     __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), Z_ARG1, Z_ARG3, false);
@@ -187,11 +187,11 @@
   __ load_klass(rcvr_klass, Z_ARG1);
 
   // Load start of itable entries into itable_entry.
-  __ z_llgf(vtable_len, Address(rcvr_klass, InstanceKlass::vtable_length_offset()));
+  __ z_llgf(vtable_len, Address(rcvr_klass, Klass::vtable_length_offset()));
   __ z_sllg(vtable_len, vtable_len, exact_log2(vtableEntry::size_in_bytes()));
 
   // Loop over all itable entries until desired interfaceOop(Rinterface) found.
-  const int vtable_base_offset = in_bytes(InstanceKlass::vtable_start_offset());
+  const int vtable_base_offset = in_bytes(Klass::vtable_start_offset());
   // Count unused bytes.
   start_pc = __ pc();
   __ add2reg_with_index(itable_entry_addr, vtable_base_offset + itableOffsetEntry::interface_offset_in_bytes(), rcvr_klass, vtable_len);
--- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, 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
@@ -694,6 +694,7 @@
 int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide, bool unaligned) {
   int store_offset;
   if (!Assembler::is_simm13(offset + (type == T_LONG) ? wordSize : 0)) {
+    assert(base != O7, "destroying register");
     assert(!unaligned, "can't handle this");
     // for offsets larger than a simm13 we setup the offset in O7
     __ set(offset, O7);
@@ -712,9 +713,12 @@
       case T_LONG  :
 #ifdef _LP64
         if (unaligned || PatchALot) {
-          __ srax(from_reg->as_register_lo(), 32, O7);
+          // Don't use O7 here because it may be equal to 'base' (see LIR_Assembler::reg2mem)
+          assert(G3_scratch != base, "can't handle this");
+          assert(G3_scratch != from_reg->as_register_lo(), "can't handle this");
+          __ srax(from_reg->as_register_lo(), 32, G3_scratch);
           __ stw(from_reg->as_register_lo(), base, offset + lo_word_offset_in_bytes);
-          __ stw(O7,                         base, offset + hi_word_offset_in_bytes);
+          __ stw(G3_scratch,                 base, offset + hi_word_offset_in_bytes);
         } else {
           __ stx(from_reg->as_register_lo(), base, offset);
         }
@@ -821,7 +825,7 @@
       case T_SHORT : __ ldsh(base, offset, to_reg->as_register()); break;
       case T_INT   : __ ld(base, offset, to_reg->as_register()); break;
       case T_LONG  :
-        if (!unaligned) {
+        if (!unaligned && !PatchALot) {
 #ifdef _LP64
           __ ldx(base, offset, to_reg->as_register_lo());
 #else
@@ -1297,7 +1301,7 @@
       disp_reg = O7;
     }
   } else if (unaligned || PatchALot) {
-    __ add(src, addr->index()->as_register(), O7);
+    __ add(src, addr->index()->as_pointer_register(), O7);
     src = O7;
   } else {
     disp_reg = addr->index()->as_pointer_register();
@@ -1424,7 +1428,7 @@
       disp_reg = O7;
     }
   } else if (unaligned || PatchALot) {
-    __ add(src, addr->index()->as_register(), O7);
+    __ add(src, addr->index()->as_pointer_register(), O7);
     src = O7;
   } else {
     disp_reg = addr->index()->as_pointer_register();
--- a/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, 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
@@ -856,7 +856,9 @@
         Register tmp2 = G3_scratch;
 
         Label refill, restart;
-        bool with_frame = false; // I don't know if we can do with-frame.
+        int satb_q_active_byte_offset =
+          in_bytes(JavaThread::satb_mark_queue_offset() +
+                   SATBMarkQueue::byte_offset_of_active());
         int satb_q_index_byte_offset =
           in_bytes(JavaThread::satb_mark_queue_offset() +
                    SATBMarkQueue::byte_offset_of_index());
@@ -864,6 +866,17 @@
           in_bytes(JavaThread::satb_mark_queue_offset() +
                    SATBMarkQueue::byte_offset_of_buf());
 
+        // Is marking still active?
+        if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+          __ ld(G2_thread, satb_q_active_byte_offset, tmp);
+        } else {
+          assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+          __ ldsb(G2_thread, satb_q_active_byte_offset, tmp);
+        }
+        __ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, restart);
+        __ retl();
+        __ delayed()->nop();
+
         __ bind(restart);
         // Load the index into the SATB buffer. SATBMarkQueue::_index is a
         // size_t so ld_ptr is appropriate
--- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, 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
@@ -1623,6 +1623,8 @@
 
         NOT_LP64(__ get_thread(thread);)
 
+        Address queue_active(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
+                                              SATBMarkQueue::byte_offset_of_active()));
         Address queue_index(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
                                              SATBMarkQueue::byte_offset_of_index()));
         Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
@@ -1631,6 +1633,15 @@
         Label done;
         Label runtime;
 
+        // Is marking still active?
+        if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+          __ cmpl(queue_active, 0);
+        } else {
+          assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+          __ cmpb(queue_active, 0);
+        }
+        __ jcc(Assembler::equal, done);
+
         // Can we store original value in the thread's buffer?
 
         __ movptr(tmp, queue_index);
--- a/src/cpu/x86/vm/frame_x86.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/x86/vm/frame_x86.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -376,7 +376,8 @@
   fr._unextended_sp = unextended_sp;
 
   address original_pc = nm->get_original_pc(&fr);
-  assert(nm->insts_contains(original_pc), "original PC must be in CompiledMethod");
+  assert(nm->insts_contains_inclusive(original_pc),
+         "original PC must be in the main code section of the the compiled method (or must be immediately following it)");
 }
 #endif
 
--- a/src/cpu/x86/vm/frame_x86.inline.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/x86/vm/frame_x86.inline.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -75,7 +75,8 @@
   address original_pc = CompiledMethod::get_deopt_original_pc(this);
   if (original_pc != NULL) {
     _pc = original_pc;
-    assert(((CompiledMethod*)_cb)->insts_contains(_pc), "original PC must be in CompiledMethod");
+    assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc),
+           "original PC must be in the main code section of the the compiled method (or must be immediately following it)");
     _deopt_state = is_deoptimized;
   } else {
     if (_cb->is_deoptimization_stub()) {
--- a/src/cpu/x86/vm/macroAssembler_x86.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/x86/vm/macroAssembler_x86.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -3499,12 +3499,12 @@
   }
 }
 
-void MacroAssembler::movdqu(XMMRegister dst, AddressLiteral src) {
+void MacroAssembler::movdqu(XMMRegister dst, AddressLiteral src, Register scratchReg) {
   if (reachable(src)) {
     movdqu(dst, as_Address(src));
   } else {
-    lea(rscratch1, src);
-    movdqu(dst, Address(rscratch1, 0));
+    lea(scratchReg, src);
+    movdqu(dst, Address(scratchReg, 0));
   }
 }
 
--- a/src/cpu/x86/vm/macroAssembler_x86.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/x86/vm/macroAssembler_x86.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1085,7 +1085,7 @@
   void movdqu(Address     dst, XMMRegister src);
   void movdqu(XMMRegister dst, Address src);
   void movdqu(XMMRegister dst, XMMRegister src);
-  void movdqu(XMMRegister dst, AddressLiteral src);
+  void movdqu(XMMRegister dst, AddressLiteral src, Register scratchReg = rscratch1);
   // AVX Unaligned forms
   void vmovdqu(Address     dst, XMMRegister src);
   void vmovdqu(XMMRegister dst, Address src);
--- a/src/cpu/x86/vm/macroAssembler_x86_sha.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/x86/vm/macroAssembler_x86_sha.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -817,7 +817,7 @@
   movl(d, Address(CTX, 4*3));
   movl(e, Address(CTX, 4*4));
   movl(f, Address(CTX, 4*5));
-  movl(g, Address(CTX, 4*6));
+  // load g - r10 after it is used as scratch
   movl(h, Address(CTX, 4*7));
 
   pshuffle_byte_flip_mask_addr = pshuffle_byte_flip_mask;
@@ -825,6 +825,8 @@
   vmovdqu(SHUF_00BA, ExternalAddress(pshuffle_byte_flip_mask_addr + 32));     //[_SHUF_00BA wrt rip]
   vmovdqu(SHUF_DC00, ExternalAddress(pshuffle_byte_flip_mask_addr + 64));     //[_SHUF_DC00 wrt rip]
 
+  movl(g, Address(CTX, 4*6));
+
   movq(Address(rsp, _CTX), CTX);           // store
 
 bind(loop0);
@@ -977,7 +979,7 @@
   movl(d, Address(CTX, 4*3));   // 0xa54ff53a
   movl(e, Address(CTX, 4*4));   // 0x510e527f
   movl(f, Address(CTX, 4*5));   // 0x9b05688c
-  movl(g, Address(CTX, 4*6));   // 0x1f83d9ab
+  // load g - r10 after use as scratch
   movl(h, Address(CTX, 4*7));   // 0x5be0cd19
 
 
@@ -986,6 +988,8 @@
   vmovdqu(SHUF_00BA, ExternalAddress(pshuffle_byte_flip_mask_addr + 32));     //[_SHUF_00BA wrt rip]
   vmovdqu(SHUF_DC00, ExternalAddress(pshuffle_byte_flip_mask_addr + 64));     //[_SHUF_DC00 wrt rip]
 
+  movl(g, Address(CTX, 4*6));   // 0x1f83d9ab
+
   movq(Address(rsp, _CTX), CTX);
   jmpb(do_last_block);
 
@@ -1154,9 +1158,8 @@
       // Move to appropriate lanes for calculating w[16] and w[17]
       vperm2f128(xmm4, xmm0, xmm0, 0); //xmm4 = W[-16] + W[-7] + s0{ BABA }
 
-      address MASK_YMM_LO = StubRoutines::x86::pshuffle_byte_flip_mask_addr_sha512();
       //Move to appropriate lanes for calculating w[18] and w[19]
-      vpand(xmm0, xmm0, ExternalAddress(MASK_YMM_LO + 32), AVX_256bit); //xmm0 = W[-16] + W[-7] + s0{ DC00 }
+      vpand(xmm0, xmm0, xmm10, AVX_256bit); //xmm0 = W[-16] + W[-7] + s0{ DC00 }
       //Calculate w[16] and w[17] in both 128 bit lanes
       //Calculate sigma1 for w[16] and w[17] on both 128 bit lanes
       vperm2f128(xmm2, xmm7, xmm7, 17); //xmm2 = W[-2] {BABA}
@@ -1250,6 +1253,7 @@
 
     const XMMRegister& XFER = xmm0; // YTMP0
     const XMMRegister& BYTE_FLIP_MASK = xmm9; // ymm9
+    const XMMRegister& YMM_MASK_LO = xmm10; // ymm10
 #ifdef _WIN64
     const Register& INP = rcx; //1st arg
     const Register& CTX = rdx; //2nd arg
@@ -1368,11 +1372,14 @@
     movq(d, Address(CTX, 8 * 3));
     movq(e, Address(CTX, 8 * 4));
     movq(f, Address(CTX, 8 * 5));
-    movq(g, Address(CTX, 8 * 6));
+    // load g - r10 after it is used as scratch
     movq(h, Address(CTX, 8 * 7));
 
     pshuffle_byte_flip_mask_addr = pshuffle_byte_flip_mask_sha512;
     vmovdqu(BYTE_FLIP_MASK, ExternalAddress(pshuffle_byte_flip_mask_addr + 0)); //PSHUFFLE_BYTE_FLIP_MASK wrt rip
+    vmovdqu(YMM_MASK_LO, ExternalAddress(pshuffle_byte_flip_mask_addr + 32));
+
+    movq(g, Address(CTX, 8 * 6));
 
     bind(loop0);
     lea(TBL, ExternalAddress(K512_W));
--- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -3207,7 +3207,7 @@
     const Register len_reg     = c_rarg4;  // src len (must be multiple of blocksize 16)
 #else
     const Address  len_mem(rbp, 6 * wordSize);  // length is on stack on Win64
-    const Register len_reg     = r10;      // pick the first volatile windows register
+    const Register len_reg     = r11;      // pick the volatile windows register
 #endif
     const Register pos         = rax;
 
@@ -3404,7 +3404,7 @@
     const Register len_reg     = c_rarg4;  // src len (must be multiple of blocksize 16)
 #else
     const Address  len_mem(rbp, 6 * wordSize);  // length is on stack on Win64
-    const Register len_reg     = r10;      // pick the first volatile windows register
+    const Register len_reg     = r11;      // pick the volatile windows register
 #endif
     const Register pos         = rax;
 
@@ -3930,7 +3930,7 @@
 
     __ push(rbx); // Save RBX
     __ movdqu(xmm_curr_counter, Address(counter, 0x00)); // initialize counter with initial counter
-    __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr()));
+    __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr()), pos); // pos as scratch
     __ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled
     __ movptr(pos, 0);
 
@@ -3953,7 +3953,7 @@
     __ movl(Address(used_addr, 0), used);
 
     // key length could be only {11, 13, 15} * 4 = {44, 52, 60}
-    __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()));
+    __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()), rbx); // rbx as scratch
     __ movl(rbx, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
     __ cmpl(rbx, 52);
     __ jcc(Assembler::equal, L_multiBlock_loopTop[1]);
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java	Mon Feb 27 23:20:05 2017 +0100
@@ -39,6 +39,7 @@
 import jdk.tools.jaotc.binformat.macho.JMachORelocObject;
 import jdk.tools.jaotc.binformat.pecoff.JPECoffRelocObject;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
 
 /**
  * A format-agnostic container class that holds various components of a binary.
@@ -259,9 +260,9 @@
      * prefix {@code prefix}. It also initializes internal code container, symbol table and
      * relocation tables.
      */
-    public BinaryContainer(GraalHotSpotVMConfig config, String jvmVersion) {
-        this.codeSegmentSize = config.codeSegmentSize;
-        this.codeEntryAlignment = config.codeEntryAlignment;
+    public BinaryContainer(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, String jvmVersion) {
+        this.codeSegmentSize = graalHotSpotVMConfig.codeSegmentSize;
+        this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment;
 
         // read only, code
         codeContainer = new CodeContainer(".text", this);
@@ -291,30 +292,31 @@
 
         addGlobalSymbols();
 
-        recordConfiguration(config);
+        recordConfiguration(graalHotSpotVMConfig, graphBuilderConfig);
     }
 
-    private void recordConfiguration(GraalHotSpotVMConfig config) {
+    private void recordConfiguration(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig) {
         // @formatter:off
-        boolean[] booleanFlags = { config.cAssertions, // Debug VM
-                                   config.useCompressedOops,
-                                   config.useCompressedClassPointers,
-                                   config.compactFields,
-                                   config.useG1GC,
-                                   config.useCMSGC,
-                                   config.useTLAB,
-                                   config.useBiasedLocking,
+        boolean[] booleanFlags = { graalHotSpotVMConfig.cAssertions, // Debug VM
+                                   graalHotSpotVMConfig.useCompressedOops,
+                                   graalHotSpotVMConfig.useCompressedClassPointers,
+                                   graalHotSpotVMConfig.compactFields,
+                                   graalHotSpotVMConfig.useG1GC,
+                                   graalHotSpotVMConfig.useCMSGC,
+                                   graalHotSpotVMConfig.useTLAB,
+                                   graalHotSpotVMConfig.useBiasedLocking,
                                    TieredAOT.getValue(),
-                                   config.enableContended,
-                                   config.restrictContended,
+                                   graalHotSpotVMConfig.enableContended,
+                                   graalHotSpotVMConfig.restrictContended,
+                                   graphBuilderConfig.omitAssertions()
         };
 
-        int[] intFlags         = { config.narrowOopShift,
-                                   config.narrowKlassShift,
-                                   config.contendedPaddingWidth,
-                                   config.fieldsAllocationStyle,
-                                   config.objectAlignment,
-                                   config.codeSegmentSize,
+        int[] intFlags         = { graalHotSpotVMConfig.getOopEncoding().shift,
+                                   graalHotSpotVMConfig.getKlassEncoding().shift,
+                                   graalHotSpotVMConfig.contendedPaddingWidth,
+                                   graalHotSpotVMConfig.fieldsAllocationStyle,
+                                   1 << graalHotSpotVMConfig.getOopEncoding().alignment,
+                                   graalHotSpotVMConfig.codeSegmentSize,
         };
         // @formatter:on
 
@@ -397,6 +399,10 @@
         return "_aot_narrow_klass_base_address";
     }
 
+    public String getNarrowOopBaseAddressSymbolName() {
+        return "_aot_narrow_oop_base_address";
+    }
+
     public String getLogOfHeapRegionGrainBytesSymbolName() {
         return "_aot_log_of_heap_region_grain_bytes";
     }
@@ -447,6 +453,7 @@
         createGotSymbol(getHeapTopAddressSymbolName());
         createGotSymbol(getHeapEndAddressSymbolName());
         createGotSymbol(getNarrowKlassBaseAddressSymbolName());
+        createGotSymbol(getNarrowOopBaseAddressSymbolName());
         createGotSymbol(getPollingPageSymbolName());
         createGotSymbol(getLogOfHeapRegionGrainBytesSymbolName());
         createGotSymbol(getInlineContiguousAllocationSupportedSymbolName());
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java	Mon Feb 27 23:20:05 2017 +0100
@@ -77,10 +77,14 @@
         this.filters = filters;
         providers = backend.getProviders();
         codeCache = providers.getCodeCache();
-        graphBuilderSuite = initGraphBuilderSuite(backend);
+        graphBuilderSuite = initGraphBuilderSuite(backend, main.options.compileWithAssertions);
         highTierContext = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.ALL);
     }
 
+    public PhaseSuite<HighTierContext> getGraphBuilderSuite() {
+        return graphBuilderSuite;
+    }
+
     private Suites getSuites() {
         // create suites every time, as we modify options for the compiler
         return backend.getSuites().getDefaultSuites();
@@ -146,14 +150,14 @@
         return backend.getRuntime().getVMConfig().cAssertions;
     }
 
-    private static PhaseSuite<HighTierContext> initGraphBuilderSuite(HotSpotBackend backend) {
+    private static PhaseSuite<HighTierContext> initGraphBuilderSuite(HotSpotBackend backend, boolean compileWithAssertions) {
         PhaseSuite<HighTierContext> graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
         ListIterator<BasePhase<? super HighTierContext>> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class);
         GraphBuilderConfiguration baseConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig();
 
         // Use all default plugins.
         Plugins plugins = baseConfig.getPlugins();
-        GraphBuilderConfiguration aotConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+        GraphBuilderConfiguration aotConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withOmitAssertions(!compileWithAssertions);
 
         iterator.next();
         iterator.remove();
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java	Mon Feb 27 23:20:05 2017 +0100
@@ -293,12 +293,18 @@
             // Record methods holder
             methodInfo.addDependentKlassData(binaryContainer, resolvedJavaType);
             // Record inlinee classes
-            for (ResolvedJavaMethod m : methodInfo.getCompilationResult().getMethods()) {
-                methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass());
+            ResolvedJavaMethod[] inlinees = methodInfo.getCompilationResult().getMethods();
+            if (inlinees != null) {
+                for (ResolvedJavaMethod m : inlinees) {
+                    methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass());
+                }
             }
             // Record classes of fields that were accessed
-            for (ResolvedJavaField f : methodInfo.getCompilationResult().getFields()) {
-                methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass());
+            ResolvedJavaField[] fields = methodInfo.getCompilationResult().getFields();
+            if (fields != null) {
+                for (ResolvedJavaField f : fields) {
+                    methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass());
+                }
             }
         }
     }
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java	Mon Feb 27 23:20:05 2017 +0100
@@ -25,6 +25,7 @@
 
 import org.graalvm.compiler.code.CompilationResult;
 import org.graalvm.compiler.core.target.Backend;
+import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
 import org.graalvm.compiler.hotspot.stubs.Stub;
 
 import jdk.vm.ci.hotspot.HotSpotCompiledCode;
@@ -48,7 +49,7 @@
     }
 
     public HotSpotCompiledCode compiledCode(CompilationResult result) {
-        return stub.getCompiledCode(backend);
+        return HotSpotCompiledCodeBuilder.createCompiledCode(null, null, result);
     }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,64 @@
+package jdk.tools.jaotc;/*
+ * Copyright (c) 2015, 2017, 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.
+ */
+
+public class LoadedClass {
+    private final String name;
+    private final Class<?> clz;
+
+    public LoadedClass(String name, Class<?> clz) {
+        this.name = name;
+        this.clz = clz;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Class<?> getLoadedClass() {
+        return clz;
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof LoadedClass)) return false;
+
+        LoadedClass that = (LoadedClass) o;
+
+        if (name != null ? !name.equals(that.name) : that.name != null) return false;
+        return clz != null ? clz.equals(that.clz) : that.clz == null;
+
+    }
+
+    @Override
+    public int hashCode() {
+        int result = name != null ? name.hashCode() : 0;
+        result = 31 * result + (clz != null ? clz.hashCode() : 0);
+        return result;
+    }
+}
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java	Mon Feb 27 23:20:05 2017 +0100
@@ -43,19 +43,31 @@
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Set;
 import java.util.stream.Stream;
 
 import jdk.tools.jaotc.binformat.BinaryContainer;
 import jdk.tools.jaotc.binformat.ByteContainer;
-import jdk.tools.jaotc.collect.ClassCollector;
+import jdk.tools.jaotc.collect.*;
+import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider;
+import jdk.tools.jaotc.collect.directory.DirectorySourceProvider;
+import jdk.tools.jaotc.collect.jar.JarSourceProvider;
+import jdk.tools.jaotc.collect.module.ModuleSourceProvider;
 import jdk.tools.jaotc.utils.Timer;
 
 import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
 import org.graalvm.compiler.hotspot.HotSpotHostBackend;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.runtime.RuntimeProvider;
 
 import jdk.vm.ci.meta.MetaAccessProvider;
@@ -120,38 +132,54 @@
         abstract void process(Main task, String opt, String arg) throws BadArgs;
     }
 
-    static Option[] recognizedOptions = {new Option("  --module <name>            Module to compile", true, "--module") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            task.options.module = arg;
-        }
-    }, new Option("  --module-path <path>       Specify where to find module to compile", true, "--module-path") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            task.options.modulepath = arg;
-        }
-    }, new Option("  --output <file>            Output file name", true, "--output") {
+    static Option[] recognizedOptions = { new Option("  --output <file>            Output file name", true, "--output") {
         @Override
         void process(Main task, String opt, String arg) {
             String name = arg;
             task.options.outputName = name;
         }
+    }, new Option("  --class-name <class names> List of classes to compile", true, "--class-name", "--classname") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.files.addAll(ClassSearch.makeList(ClassNameSourceProvider.TYPE, arg));
+        }
+    }, new Option("  --jar <jarfiles>           List of jar files to compile", true, "--jar") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.files.addAll(ClassSearch.makeList(JarSourceProvider.TYPE, arg));
+        }
+    }, new Option("  --module <modules>         List of modules to compile", true, "--module") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.files.addAll(ClassSearch.makeList(ModuleSourceProvider.TYPE, arg));
+        }
+    }, new Option("  --directory <dirs>         List of directories where to search for files to compile", true, "--directory") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.files.addAll(ClassSearch.makeList(DirectorySourceProvider.TYPE, arg));
+        }
+    }, new Option("  --search-path <dirs>       List of directories where to search for specified files", true, "--search-path") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            String[] elements = arg.split(":");
+            task.options.searchPath.add(elements);
+        }
     }, new Option("  --compile-commands <file>  Name of file with compile commands", true, "--compile-commands") {
         @Override
         void process(Main task, String opt, String arg) {
             task.options.methodList = arg;
         }
-    }, new Option("  --compile-for-tiered       Generated profiling code for tiered compilation", false, "--compile-for-tiered") {
+    }, new Option("  --compile-for-tiered       Generate profiling code for tiered compilation", false, "--compile-for-tiered") {
         @Override
         void process(Main task, String opt, String arg) {
             TieredAOT.setValue(true);
         }
-    }, new Option("  --classpath <path>         Specify where to find user class files", true, "--classpath", "--class-path") {
+    }, new Option("  --compile-with-assertions  Compile with java assertions", false, "--compile-with-assertions") {
         @Override
         void process(Main task, String opt, String arg) {
-            task.options.classpath = arg;
+            task.options.compileWithAssertions = true;
         }
-    }, new Option("  --threads <number>         Number of compilation threads to be used", true, "--threads") {
+    }, new Option("  --compile-threads <number> Number of compilation threads to be used", true, "--compile-threads", "--threads") {
         @Override
         void process(Main task, String opt, String arg) {
             int threads = Integer.parseInt(arg);
@@ -203,6 +231,11 @@
         void process(Main task, String opt, String arg) {
             task.options.version = true;
         }
+    }, new Option("  --linker-path              Full path to linker executable", true, "--linker-path") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.linkerpath = arg;
+        }
     }, new Option("  -J<flag>                   Pass <flag> directly to the runtime system", false, "-J") {
         @Override
         void process(Main task, String opt, String arg) {
@@ -210,27 +243,28 @@
     }};
 
     public static class Options {
-        public List<String> files = new LinkedList<>();
-        public String module = null;
-        public String modulepath = "modules";
+        public List<SearchFor> files = new LinkedList<>();
         public String outputName = "unnamed.so";
         public String methodList;
-        public String classpath = ".";
+        public List<ClassSource> sources = new ArrayList<>();
+        public String linkerpath = null;
+        public SearchPath searchPath = new SearchPath();
 
         /**
          * We don't see scaling beyond 16 threads.
          */
         private static final int COMPILER_THREADS = 16;
 
-        int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors());
+        public int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors());
 
         public boolean ignoreClassLoadingErrors;
         public boolean exitOnError;
-        boolean info;
-        boolean verbose;
-        boolean debug;
-        boolean help;
-        boolean version;
+        public boolean info;
+        public boolean verbose;
+        public boolean debug;
+        public boolean help;
+        public boolean version;
+        public boolean compileWithAssertions;
     }
 
     /* package */final Options options = new Options();
@@ -272,7 +306,9 @@
 
             printlnInfo("Compiling " + options.outputName + "...");
             final long start = System.currentTimeMillis();
-            run();
+            if (!run()) {
+              return EXIT_ABNORMAL;
+            }
             final long end = System.currentTimeMillis();
             printlnInfo("Total time: " + (end - start) + " ms");
 
@@ -371,17 +407,34 @@
     }
 
     @SuppressWarnings("try")
-    private void run() throws Exception {
+    private boolean run() throws Exception {
         openLog();
 
         try {
             CompilationSpec compilationRestrictions = collectSpecifiedMethods();
 
-            Set<Class<?>> classesToCompile;
+            Set<Class<?>> classesToCompile = new HashSet<>();
 
             try (Timer t = new Timer(this, "")) {
-                ClassCollector collector = new ClassCollector(this.options, this);
-                classesToCompile = collector.collectClassesToCompile();
+                FileSupport fileSupport = new FileSupport();
+                ClassSearch lookup = new ClassSearch();
+                lookup.addProvider(new ModuleSourceProvider());
+                lookup.addProvider(new ClassNameSourceProvider(fileSupport));
+                lookup.addProvider(new JarSourceProvider());
+                lookup.addProvider(new DirectorySourceProvider(fileSupport));
+
+                List<LoadedClass> found = null;
+                try {
+                    found = lookup.search(options.files, options.searchPath);
+                } catch (InternalError e) {
+                    reportError(e);
+                    return false;
+                }
+
+                for (LoadedClass loadedClass : found) {
+                    classesToCompile.add(loadedClass.getLoadedClass());
+                }
+
                 printInfo(classesToCompile.size() + " classes found");
             }
 
@@ -409,6 +462,11 @@
             AOTCompiler compiler = new AOTCompiler(this, aotBackend, options.threads);
             classes = compiler.compileClasses(classes);
 
+            GraalHotSpotVMConfig graalHotSpotVMConfig = runtime.getVMConfig();
+            PhaseSuite<HighTierContext> graphBuilderSuite = aotBackend.getGraphBuilderSuite();
+            ListIterator<BasePhase<? super HighTierContext>> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class);
+            GraphBuilderConfiguration graphBuilderConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig();
+
             // Free memory!
             try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
                 printMemoryUsage();
@@ -417,7 +475,7 @@
                 System.gc();
             }
 
-            BinaryContainer binaryContainer = new BinaryContainer(runtime.getVMConfig(), JVM_VERSION);
+            BinaryContainer binaryContainer = new BinaryContainer(graalHotSpotVMConfig, graphBuilderConfig, JVM_VERSION);
             DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer);
             dataBuilder.prepareData();
 
@@ -460,7 +518,8 @@
             // tests are fixed.
             String libraryFileName = name;
 
-            String ldCmd;
+            String linkerCmd;
+            String linkerPath;
             String osName = System.getProperty("os.name");
 
             if (name.endsWith(".so")) {
@@ -477,27 +536,31 @@
                 case "Linux":
                     // libraryFileName = options.outputName + ".so";
                     objectFileName = objectFileName + ".o";
-                    ldCmd = "ld -shared -z noexecstack -o " + libraryFileName + " " + objectFileName;
+                    linkerPath = (options.linkerpath != null) ?  options.linkerpath : "ld";
+                    linkerCmd = linkerPath + " -shared -z noexecstack -o " + libraryFileName + " " + objectFileName;
                     break;
                 case "SunOS":
                     // libraryFileName = options.outputName + ".so";
                     objectFileName = objectFileName + ".o";
-                    ldCmd = "ld -shared -o " + libraryFileName + " " + objectFileName;
+                    linkerPath = (options.linkerpath != null) ?  options.linkerpath : "ld";
+                    linkerCmd = linkerPath + " -shared -o " + libraryFileName + " " + objectFileName;
                     break;
                 case "Mac OS X":
                     // libraryFileName = options.outputName + ".dylib";
                     objectFileName = objectFileName + ".o";
-                    ldCmd = "ld -dylib -o " + libraryFileName + " " + objectFileName;
+                    linkerPath = (options.linkerpath != null) ?  options.linkerpath : "ld";
+                    linkerCmd = linkerPath + " -dylib -o " + libraryFileName + " " + objectFileName;
                     break;
                 default:
                     if (osName.startsWith("Windows")) {
                         // libraryFileName = options.outputName + ".dll";
                         objectFileName = objectFileName + ".obj";
-                        String linkpath = getWindowsLinkPath();
-                        if (linkpath == null) {
+                        linkerPath = (options.linkerpath != null) ?
+                            options.linkerpath : getWindowsLinkPath();
+                        if (linkerPath == null) {
                             throw new InternalError("Can't locate Microsoft Visual Studio amd64 link.exe");
                         }
-                        ldCmd = linkpath + " /DLL /OPT:NOREF /NOLOGO /NOENTRY" + " /OUT:" + libraryFileName + " " + objectFileName;
+                        linkerCmd = linkerPath + " /DLL /OPT:NOREF /NOLOGO /NOENTRY" + " /OUT:" + libraryFileName + " " + objectFileName;
                         break;
                     }
                     else
@@ -516,7 +579,7 @@
             }
 
             try (Timer t = new Timer(this, "Creating shared library: " + libraryFileName)) {
-                Process p = Runtime.getRuntime().exec(ldCmd);
+                Process p = Runtime.getRuntime().exec(linkerCmd);
                 final int exitCode = p.waitFor();
                 if (exitCode != 0) {
                     InputStream stderr = p.getErrorStream();
@@ -548,6 +611,7 @@
         } finally {
             closeLog();
         }
+        return true;
     }
 
     private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions, GraalFilters filters) {
@@ -611,7 +675,7 @@
                     break;
                 }
             } else {
-                options.files.add(arg);
+                options.files.add(new SearchFor(arg));
             }
         }
     }
@@ -672,6 +736,12 @@
         log.flush();
     }
 
+    private void reportError(Throwable e) {
+        log.println("Error: " + e.getMessage());
+        e.printStackTrace(log);
+        log.flush();
+    }
+
     private void reportError(String key, Object... args) {
         printError(MessageFormat.format(key, args));
     }
@@ -682,17 +752,17 @@
     }
 
     private void showUsage() {
-        log.println("Usage: " + PROGNAME + " <options> list...");
+        log.println("Usage: " + PROGNAME + " <options> list");
         log.println("use --help for a list of possible options");
     }
 
     private void showHelp() {
-        log.println("Usage: " + PROGNAME + " <options> <--module name> | <list...>");
+        log.println("Usage: " + PROGNAME + " <options> list");
         log.println();
-        log.println("  list       A list of class files, jar files or directories which");
-        log.println("             contains class files.");
+        log.println("  list       A : separated list of class names, modules, jar files");
+        log.println("             or directories which contain class files.");
         log.println();
-        log.println("where possible options include:");
+        log.println("where options include:");
         for (Option o : recognizedOptions) {
             String name = o.aliases[0].substring(1); // there must always be at least one name
             name = name.charAt(0) == '-' ? name.substring(1) : name;
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java	Mon Feb 27 23:20:05 2017 +0100
@@ -48,6 +48,7 @@
     HEAP_TOP_ADDRESS("CodeInstaller::HEAP_TOP_ADDRESS"),
     HEAP_END_ADDRESS("CodeInstaller::HEAP_END_ADDRESS"),
     NARROW_KLASS_BASE_ADDRESS("CodeInstaller::NARROW_KLASS_BASE_ADDRESS"),
+    NARROW_OOP_BASE_ADDRESS("CodeInstaller::NARROW_OOP_BASE_ADDRESS"),
     CRC_TABLE_ADDRESS("CodeInstaller::CRC_TABLE_ADDRESS"),
     LOG_OF_HEAP_REGION_GRAIN_BYTES("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES"),
     INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED");
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java	Mon Feb 27 23:20:05 2017 +0100
@@ -57,6 +57,7 @@
             case HEAP_TOP_ADDRESS:
             case HEAP_END_ADDRESS:
             case NARROW_KLASS_BASE_ADDRESS:
+            case NARROW_OOP_BASE_ADDRESS:
             case CRC_TABLE_ADDRESS:
             case LOG_OF_HEAP_REGION_GRAIN_BYTES:
             case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED:
@@ -78,6 +79,9 @@
                     case NARROW_KLASS_BASE_ADDRESS:
                         vmSymbolName = binaryContainer.getNarrowKlassBaseAddressSymbolName();
                         break;
+                    case NARROW_OOP_BASE_ADDRESS:
+                        vmSymbolName = binaryContainer.getNarrowOopBaseAddressSymbolName();
+                        break;
                     case CRC_TABLE_ADDRESS:
                         vmSymbolName = binaryContainer.getCrcTableAddressSymbolName();
                         break;
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java	Mon Feb 27 12:41:41 2017 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,337 +0,0 @@
-/*
- * Copyright (c) 2017, 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.
- */
-
-package jdk.tools.jaotc.collect;
-
-import jdk.tools.jaotc.LogPrinter;
-import jdk.tools.jaotc.Main;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.*;
-import java.nio.file.*;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.*;
-
-import static java.nio.file.FileVisitResult.CONTINUE;
-
-public class ClassCollector {
-    private final Main.Options options;
-    private final LogPrinter log;
-
-    public ClassCollector(Main.Options options, LogPrinter log) {
-        this.options = options;
-        this.log = log;
-    }
-
-    /**
-     * Collect all class names passed by the user.
-     *
-     * @return array list of classes
-     */
-    public Set<Class<?>> collectClassesToCompile() {
-        Set<Class<?>> classes = new HashSet<>();
-        List<String> filesToScan = new LinkedList<>(options.files);
-
-        if (options.module != null) {
-            classes.addAll(scanModule(filesToScan));
-        }
-
-        classes.addAll(scanFiles(filesToScan));
-        return classes;
-    }
-
-    private Set<Class<?>> scanModule(List<String> filesToScan) {
-        String module = options.module;
-        // Search module in standard JDK installation.
-        Path dir = getModuleDirectory(options.modulepath, module);
-
-        if (Files.isDirectory(dir)) {
-            return loadFromModuleDirectory(dir);
-        } else {
-            findFilesToScan(filesToScan, module);
-            return new HashSet<>();
-        }
-    }
-
-    private Set<Class<?>> loadFromModuleDirectory(Path dir) {
-        log.printInfo("Scanning module: " + dir + " ...");
-        log.printlnVerbose(" "); // Break line
-
-        FileSystemFinder finder = new FileSystemFinder(dir, pathname -> entryIsClassFile(pathname.toString()));
-        Set<Class<?>> cls = loadWithClassLoader(() -> ClassLoader.getSystemClassLoader(), dir, finder);
-        log.printlnInfo(" " + cls.size() + " classes loaded.");
-        return cls;
-    }
-
-    private void findFilesToScan(List<String> filesToScan, String module) {
-        // Try to search regular directory, .jar or .class files
-        Path path = Paths.get(options.modulepath, module);
-
-        if (Files.isDirectory(path)) {
-            filesToScan.add(".");
-            options.classpath = path.toString();
-        } else if (path.endsWith(".jar") || path.endsWith(".class")) {
-            filesToScan.add(path.toString());
-        } else {
-            path = Paths.get(options.modulepath, module + ".jar");
-            if (Files.exists(path)) {
-                filesToScan.add(path.toString());
-            } else {
-                path = Paths.get(options.modulepath, module + ".class");
-                if (Files.exists(path)) {
-                    filesToScan.add(path.toString());
-                } else {
-                    throw new InternalError("Expecting a .class, .jar or directory: " + path);
-                }
-            }
-        }
-    }
-
-    private boolean entryIsClassFile(String entry) {
-        return entry.endsWith(".class") && !entry.endsWith("module-info.class");
-    }
-
-    private Set<Class<?>> scanFiles(List<String> filesToScan) {
-        Set<Class<?>> classes = new HashSet<>();
-        for (String fileName : filesToScan) {
-            Set<Class<?>> loaded = scanFile(fileName);
-            log.printlnInfo(" " + loaded.size() + " classes loaded.");
-            classes.addAll(loaded);
-        }
-        return classes;
-    }
-
-    interface ClassLoaderFactory {
-        ClassLoader create() throws IOException;
-    }
-
-    private Set<Class<?>> loadWithClassLoader(ClassLoaderFactory factory, Path root, FileSystemFinder finder) {
-        ClassLoader loader = null;
-        try {
-            loader = factory.create();
-            return loadClassFiles(root, finder, loader);
-        } catch (IOException e) {
-            throw new InternalError(e);
-        } finally {
-            if (loader instanceof AutoCloseable) {
-                try {
-                    ((AutoCloseable) loader).close();
-                } catch (Exception e) {
-                    throw new InternalError(e);
-                }
-            }
-        }
-    }
-
-    private Set<Class<?>> scanFile(String fileName) {
-        log.printInfo("Scanning: " + fileName + " ...");
-        log.printlnVerbose(" "); // Break line
-
-        if (fileName.endsWith(".jar")) {
-            return loadFromJarFile(fileName);
-        } else if (fileName.endsWith(".class")) {
-            Set<Class<?>> classes = new HashSet<>();
-            loadFromClassFile(fileName, classes);
-            return classes;
-        } else {
-            return scanClassPath(fileName);
-        }
-    }
-
-    private Set<Class<?>> loadFromJarFile(String fileName) {
-        FileSystem fs = makeFileSystem(fileName);
-        FileSystemFinder finder = new FileSystemFinder(fs.getPath("/"), pathname -> entryIsClassFile(pathname.toString()));
-        return loadWithClassLoader(() -> URLClassLoader.newInstance(buildUrls(fileName)), fs.getPath("/"), finder);
-    }
-
-    private void loadFromClassFile(String fileName, Set<Class<?>> classes) {
-        Class<?> result;
-        File file = new File(options.classpath);
-        try (URLClassLoader loader = URLClassLoader.newInstance(buildUrls(file))) {
-            result = loadClassFile(loader, fileName);
-        } catch (IOException e) {
-            throw new InternalError(e);
-        }
-        Class<?> c = result;
-        addClass(classes, fileName, c);
-    }
-
-    private Set<Class<?>> scanClassPath(String fileName) {
-        Path classPath = Paths.get(options.classpath);
-        if (!Files.exists(classPath)) {
-            throw new InternalError("Path does not exist: " + classPath);
-        }
-        if (!Files.isDirectory(classPath)) {
-            throw new InternalError("Path must be a directory: " + classPath);
-        }
-
-        // Combine class path and file name and see what it is.
-        Path combinedPath = Paths.get(options.classpath + File.separator + fileName);
-        if (combinedPath.endsWith(".class")) {
-            throw new InternalError("unimplemented");
-        } else if (Files.isDirectory(combinedPath)) {
-            return scanDirectory(classPath, combinedPath);
-        } else {
-            throw new InternalError("Expecting a .class, .jar or directory: " + fileName);
-        }
-    }
-
-    private FileSystem makeFileSystem(String fileName) {
-        try {
-            return FileSystems.newFileSystem(makeJarFileURI(fileName), new HashMap<>());
-        } catch (IOException e) {
-            throw new InternalError(e);
-        }
-    }
-
-    private URI makeJarFileURI(String fileName) {
-        String name = Paths.get(fileName).toAbsolutePath().toString();
-        name = name.replace('\\', '/');
-        try {
-            return new URI("jar:file:///" + name + "!/");
-        } catch (URISyntaxException e) {
-            throw new InternalError(e);
-        }
-    }
-
-    private PathMatcher combine(PathMatcher m1, PathMatcher m2) {
-        return path -> m1.matches(path) && m2.matches(path);
-    }
-
-    private Set<Class<?>> scanDirectory(Path classPath, Path combinedPath) {
-        String dir = options.classpath;
-
-        FileSystem fileSystem = FileSystems.getDefault();
-        PathMatcher matcher = fileSystem.getPathMatcher("glob:" + "*.class");
-        FileSystemFinder finder = new FileSystemFinder(combinedPath,
-            combine(matcher, pathname -> entryIsClassFile(pathname.toString())));
-
-        File file = new File(dir);
-        try (URLClassLoader loader = URLClassLoader.newInstance(buildUrls(file))) {
-            return loadClassFiles(classPath, finder, loader);
-        } catch (IOException e) {
-            throw new InternalError(e);
-        }
-    }
-
-    private Set<Class<?>> loadClassFiles(Path root, FileSystemFinder finder, ClassLoader loader) {
-        Set<Class<?>> classes = new HashSet<>();
-        for (Path name : finder.done()) {
-            // Now relativize to the class path so we get the actual class names.
-            String entry = root.relativize(name).normalize().toString();
-            Class<?> c = loadClassFile(loader, entry);
-            addClass(classes, entry, c);
-        }
-        return classes;
-    }
-
-    private void addClass(Set<Class<?>> classes, String name, Class<?> c) {
-        if (c != null) {
-            classes.add(c);
-            log.printlnVerbose(" loaded " + name);
-        }
-    }
-
-    private URL[] buildUrls(String fileName) throws MalformedURLException {
-        String name = Paths.get(fileName).toAbsolutePath().toString();
-        name = name.replace('\\', '/');
-        return new URL[]{ new URL("jar:file:///" + name + "!/") };
-    }
-
-    private URL[] buildUrls(File file) throws MalformedURLException {
-        return new URL[] {file.toURI().toURL() };
-    }
-
-    private Path getModuleDirectory(String modulepath, String module) {
-        FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
-        return fs.getPath(modulepath, module);
-    }
-
-    /**
-     * Loads a class with the given file name from the specified {@link URLClassLoader}.
-     */
-    private Class<?> loadClassFile(final ClassLoader loader, final String fileName) {
-        int start = 0;
-        if (fileName.startsWith("/")) {
-            start = 1;
-        }
-        String className = fileName.substring(start, fileName.length() - ".class".length());
-        className = className.replace('/', '.');
-        className = className.replace('\\', '.');
-        try {
-            return loader.loadClass(className);
-        } catch (Throwable e) {
-            // If we are running in JCK mode we ignore all exceptions.
-            if (options.ignoreClassLoadingErrors) {
-                log.printError(className + ": " + e);
-                return null;
-            }
-            throw new InternalError(e);
-        }
-    }
-
-    /**
-     * {@link FileVisitor} implementation to find class files recursively.
-     */
-    private static class FileSystemFinder extends SimpleFileVisitor<Path> {
-        private final ArrayList<Path> fileNames = new ArrayList<>();
-        private final PathMatcher filter;
-
-        FileSystemFinder(Path combinedPath, PathMatcher filter) {
-            this.filter = filter;
-            try {
-                Files.walkFileTree(combinedPath, this);
-            } catch (IOException e) {
-                throw new InternalError(e);
-            }
-        }
-
-        /**
-         * Compares the glob pattern against the file name.
-         */
-        void find(Path file) {
-            Path name = file.getFileName();
-            if (name != null && filter.matches(name)) {
-                fileNames.add(file);
-            }
-        }
-
-        List<Path> done() {
-            return fileNames;
-        }
-
-        @Override
-        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
-            find(file);
-            return CONTINUE;
-        }
-
-        @Override
-        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
-            find(dir);
-            return CONTINUE;
-        }
-
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+package jdk.tools.jaotc.collect;
+
+import jdk.tools.jaotc.LoadedClass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ClassSearch {
+    private List<SourceProvider> providers = new ArrayList<>();
+
+    public void addProvider(SourceProvider provider) {
+        providers.add(provider);
+    }
+
+    public List<LoadedClass> search(List<SearchFor> search, SearchPath searchPath) {
+        List<LoadedClass> loaded = new ArrayList<>();
+
+        List<ClassSource> sources = new ArrayList<>();
+
+        for (SearchFor entry : search) {
+            sources.add(findSource(entry, searchPath));
+        }
+
+        for (ClassSource source : sources) {
+            source.eachClass((name, loader) -> loaded.add(loadClass(name, loader)));
+        }
+
+        return loaded;
+    }
+
+    private LoadedClass loadClass(String name, ClassLoader loader) {
+        try {
+            Class<?> clzz = loader.loadClass(name);
+            return new LoadedClass(name, clzz);
+        } catch (ClassNotFoundException e) {
+            throw new InternalError("Failed to load with: " + loader, e);
+        }
+    }
+
+    private ClassSource findSource(SearchFor searchFor, SearchPath searchPath) {
+        ClassSource found = null;
+
+        for (SourceProvider provider : providers) {
+            if (!searchFor.isUnknown() && !provider.supports(searchFor.getType())) {
+                continue;
+            }
+
+            ClassSource source = provider.findSource(searchFor.getName(), searchPath);
+            if (source != null) {
+                if (found != null) {
+                    throw new InternalError("Multiple possible sources: " + source + " and: " + found);
+                }
+                found = source;
+            }
+        }
+
+        if (found == null) {
+            throw new InternalError("Failed to find: " + searchFor.toString());
+        }
+        return found;
+    }
+
+    public static List<SearchFor> makeList(String type, String argument) {
+        List<SearchFor> list = new ArrayList<>();
+        String[] elements = argument.split(":");
+        for (String element : elements) {
+            list.add(new SearchFor(element, type));
+        }
+        return list;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+package jdk.tools.jaotc.collect;
+
+import java.nio.file.Path;
+import java.util.function.BiConsumer;
+
+public interface ClassSource {
+    static boolean pathIsClassFile(Path entry) {
+        String fileName = entry.getFileName().toString();
+        return fileName.endsWith(".class") && !fileName.endsWith("module-info.class");
+    }
+
+    static String makeClassName(Path path) {
+        String fileName = path.toString();
+
+        if (!fileName.endsWith(".class")) {
+            throw new IllegalArgumentException("File doesn't end with .class: '" + fileName + "'");
+        }
+
+        int start = 0;
+        if (fileName.startsWith("/")) {
+            start = 1;
+        }
+
+        String className = fileName.substring(start, fileName.length() - ".class".length());
+        className = className.replace('/', '.');
+        return className;
+    }
+
+    void eachClass(BiConsumer<String, ClassLoader> consumer);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+package jdk.tools.jaotc.collect;
+
+import java.io.IOException;
+import java.net.*;
+import java.nio.file.*;
+import java.util.HashMap;
+
+public class FileSupport {
+    public boolean exists(Path path)  {
+        return Files.exists(path);
+    }
+
+    public boolean isDirectory(Path path) {
+        return Files.isDirectory(path);
+    }
+
+    private FileSystem makeJarFileSystem(Path path) {
+        try {
+            return FileSystems.newFileSystem(makeJarFileURI(path), new HashMap<>());
+        } catch (IOException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    private URI makeJarFileURI(Path path) {
+        try {
+            return new URI("jar:file:" + path.toAbsolutePath() + "!/");
+        } catch (URISyntaxException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    public ClassLoader createClassLoader(Path path, ClassLoader parent) {
+        try {
+            return URLClassLoader.newInstance(buildUrls(path), parent);
+        } catch (MalformedURLException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    public ClassLoader createClassLoader(Path path) throws MalformedURLException {
+        return URLClassLoader.newInstance(buildUrls(path));
+    }
+
+    private URL[] buildUrls(Path path) throws MalformedURLException {
+        return new URL[] { path.toUri().toURL() };
+    }
+
+    public Path getJarFileSystemRoot(Path jarFile) {
+        FileSystem fileSystem = makeJarFileSystem(jarFile);
+        return fileSystem.getPath("/");
+    }
+
+    public boolean isAbsolute(Path entry) {
+        return entry.isAbsolute();
+    }
+
+    public Path getSubDirectory(FileSystem fileSystem, Path root, Path path) throws IOException {
+        DirectoryStream<Path> paths = fileSystem.provider().newDirectoryStream(root,null);
+        for (Path entry : paths) {
+            Path relative = root.relativize(entry);
+            if (relative.equals(path)) {
+                return entry;
+            }
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+package jdk.tools.jaotc.collect;
+
+import java.io.IOException;
+import java.nio.file.*;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import static java.nio.file.FileVisitResult.CONTINUE;
+
+/**
+ * {@link FileVisitor} implementation to find class files recursively.
+ */
+public class FileSystemFinder extends SimpleFileVisitor<Path> implements Iterable<Path> {
+    private final ArrayList<Path> fileNames = new ArrayList<>();
+    private final PathMatcher filter;
+
+    public FileSystemFinder(Path combinedPath, PathMatcher filter) {
+        this.filter = filter;
+        try {
+            Files.walkFileTree(combinedPath, this);
+        } catch (IOException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Compares the glob pattern against the file name.
+     */
+    private void find(Path file) {
+        Path name = file.getFileName();
+        if (name != null && filter.matches(name)) {
+            fileNames.add(file);
+        }
+    }
+
+    @Override
+    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+        find(file);
+        return CONTINUE;
+    }
+
+    @Override
+    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
+        find(dir);
+        return CONTINUE;
+    }
+
+
+    @Override
+    public Iterator<Path> iterator() {
+        return fileNames.iterator();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+package jdk.tools.jaotc.collect;
+
+public class SearchFor {
+    private final String name;
+    private final String type;
+
+    public SearchFor(String name) {
+        this(name, "unknown");
+    }
+
+    public SearchFor(String name, String type) {
+        this.name = name;
+        this.type = type;
+    }
+
+    public boolean isUnknown() {
+        return "unknown".equals(type);
+    }
+
+    public String getType() {
+        return this.type;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    @Override
+    public String toString() {
+        return type + ":" + name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+package jdk.tools.jaotc.collect;
+
+import java.nio.file.FileSystem;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SearchPath {
+    private final List<Path> searchPaths = new ArrayList<>();
+    private final FileSupport fileSupport;
+
+    public SearchPath() {
+        this(new FileSupport());
+    }
+
+    public SearchPath(FileSupport fileSupport) {
+        this.fileSupport = fileSupport;
+    }
+
+    public Path find(FileSystem fileSystem, Path entry, String... defaults) {
+        if (isAbsolute(entry)) {
+            if (exists(entry)) {
+                return entry;
+            }
+            return null;
+        }
+
+        if (exists(entry)) {
+            return entry;
+        }
+
+        for (String searchPath : defaults) {
+            Path newPath = fileSystem.getPath(searchPath, entry.toString());
+            if (exists(newPath)) {
+                return newPath;
+            }
+        }
+
+        for (Path searchPath : searchPaths) {
+            Path newPath = fileSystem.getPath(searchPath.toString(), entry.toString());
+            if (exists(newPath)) {
+                return newPath;
+            }
+        }
+
+        return null;
+    }
+
+    private boolean isAbsolute(Path entry) {
+        return fileSupport.isAbsolute(entry);
+    }
+
+    private boolean exists(Path entry) {
+        return fileSupport.exists(entry);
+    }
+
+    public void add(String... paths) {
+        for (String name : paths) {
+            Path path = Paths.get(name);
+            searchPaths.add(path);
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+package jdk.tools.jaotc.collect;
+
+public interface SourceProvider {
+    ClassSource findSource(String name, SearchPath searchPath);
+
+    boolean supports(String type);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+package jdk.tools.jaotc.collect.classname;
+
+import jdk.tools.jaotc.collect.ClassSource;
+
+import java.util.function.BiConsumer;
+
+public class ClassNameSource implements ClassSource {
+    private final String name;
+    private final ClassLoader classLoader;
+
+    public ClassNameSource(String name, ClassLoader classLoader) {
+        this.name = name;
+        this.classLoader = classLoader;
+    }
+
+    @Override
+    public void eachClass(BiConsumer<String, ClassLoader> consumer) {
+        consumer.accept(name, classLoader);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+package jdk.tools.jaotc.collect.classname;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.SearchPath;
+import jdk.tools.jaotc.collect.SourceProvider;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class ClassNameSourceProvider implements SourceProvider {
+    public final static String TYPE = "classname";
+    private final ClassLoader classLoader;
+
+    public ClassNameSourceProvider(FileSupport fileSupport) {
+        String classPath = System.getProperty("java.class.path");
+        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
+        if (classPath != null && !classPath.isEmpty()) {
+            classLoader = systemClassLoader;
+        } else {
+            Path path = Paths.get(".").toAbsolutePath();
+            classLoader = fileSupport.createClassLoader(path, systemClassLoader);
+        }
+    }
+
+    @Override
+    public ClassSource findSource(String name, SearchPath searchPath) {
+        try {
+            classLoader.loadClass(name);
+            return new ClassNameSource(name, classLoader);
+        } catch (ClassNotFoundException e) {
+            return null;
+        }
+    }
+
+    @Override
+    public boolean supports(String type) {
+        return TYPE.equals(type);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+package jdk.tools.jaotc.collect.directory;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSystemFinder;
+
+import java.nio.file.Path;
+import java.util.function.BiConsumer;
+
+public class DirectorySource implements ClassSource {
+    private final Path directoryPath;
+    private final ClassLoader classLoader;
+
+    public DirectorySource(Path directoryPath, ClassLoader classLoader) {
+        this.directoryPath = directoryPath;
+        this.classLoader = classLoader;
+    }
+
+    @Override
+    public void eachClass(BiConsumer<String, ClassLoader> consumer) {
+        FileSystemFinder finder = new FileSystemFinder(directoryPath, ClassSource::pathIsClassFile);
+
+        for (Path path : finder) {
+            consumer.accept(ClassSource.makeClassName(directoryPath.relativize(path).normalize()), classLoader);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "directory:" + directoryPath.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+package jdk.tools.jaotc.collect.directory;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.SearchPath;
+import jdk.tools.jaotc.collect.SourceProvider;
+
+import java.net.MalformedURLException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+
+public class DirectorySourceProvider implements SourceProvider {
+    private final FileSupport fileSupport;
+    private final FileSystem fileSystem;
+    public final static String TYPE = "directory";
+
+    public DirectorySourceProvider(FileSupport fileSupport) {
+        this.fileSupport = fileSupport;
+        fileSystem = FileSystems.getDefault();
+    }
+
+    @Override
+    public ClassSource findSource(String name, SearchPath searchPath) {
+        Path directoryPath = fileSystem.getPath(name);
+
+        if (!fileSupport.exists(directoryPath)) {
+            return null;
+        }
+        if (!fileSupport.isDirectory(directoryPath)) {
+            return null;
+        }
+
+        try {
+            ClassLoader classLoader = fileSupport.createClassLoader(directoryPath);
+            return new DirectorySource(directoryPath, classLoader);
+        } catch (MalformedURLException e) {
+            return null;
+        }
+    }
+
+    @Override
+    public boolean supports(String type) {
+        return TYPE.equals(type);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+package jdk.tools.jaotc.collect.jar;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSystemFinder;
+
+import java.nio.file.Path;
+import java.util.function.BiConsumer;
+
+public class JarFileSource implements ClassSource {
+    private final Path jarFile;
+    private final Path jarRootPath;
+    private final ClassLoader classLoader;
+
+
+    public JarFileSource(Path jarFile, Path jarRootPath, ClassLoader classLoader) {
+        this.jarFile = jarFile;
+        this.jarRootPath = jarRootPath;
+        this.classLoader = classLoader;
+    }
+
+    public void eachClass(BiConsumer<String, ClassLoader> consumer) {
+        FileSystemFinder finder = new FileSystemFinder(jarRootPath, ClassSource::pathIsClassFile);
+
+        for (Path path : finder) {
+            consumer.accept(ClassSource.makeClassName(jarRootPath.relativize(path).normalize()), classLoader);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "jar:" + jarFile.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+package jdk.tools.jaotc.collect.jar;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.SearchPath;
+import jdk.tools.jaotc.collect.SourceProvider;
+
+import java.net.MalformedURLException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.ProviderNotFoundException;
+
+public class JarSourceProvider implements SourceProvider {
+    private final FileSystem fileSystem;
+    private final FileSupport fileSupport;
+    public final static String TYPE = "jar";
+
+    public JarSourceProvider() {
+        this(new FileSupport());
+    }
+
+    public JarSourceProvider(FileSupport fileSupport) {
+        this.fileSupport = fileSupport;
+        fileSystem = FileSystems.getDefault();
+    }
+
+    @Override
+    public ClassSource findSource(String name, SearchPath searchPath) {
+        Path fileName = fileSystem.getPath(name);
+        Path jarFile = searchPath.find(fileSystem, fileName);
+
+        if (!validPath(jarFile)) {
+            return null;
+        }
+
+        return createSource(jarFile);
+    }
+
+    private ClassSource createSource(Path jarFile) {
+        try {
+            Path jarRootPath = fileSupport.getJarFileSystemRoot(jarFile);
+            if (jarRootPath == null) {
+                return null;
+            }
+            ClassLoader classLoader = fileSupport.createClassLoader(jarFile);
+            return new JarFileSource(jarFile, jarRootPath, classLoader);
+        } catch (ProviderNotFoundException | MalformedURLException e) {
+        }
+        return null;
+    }
+
+    @Override
+    public boolean supports(String type) {
+        return TYPE.equals(type);
+    }
+
+    private boolean validPath(Path jarFile) {
+        return jarFile != null && !fileSupport.isDirectory(jarFile);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+package jdk.tools.jaotc.collect.module;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSystemFinder;
+
+import java.nio.file.Path;
+import java.util.function.BiConsumer;
+
+public class ModuleSource implements ClassSource {
+    private final Path modulePath;
+    private final ClassLoader classLoader;
+
+    public ModuleSource(Path modulePath, ClassLoader classLoader) {
+        this.modulePath = modulePath;
+        this.classLoader = classLoader;
+    }
+
+    @Override
+    public void eachClass(BiConsumer<String, ClassLoader> consumer) {
+        FileSystemFinder finder = new FileSystemFinder(modulePath, ClassSource::pathIsClassFile);
+
+        for (Path path : finder) {
+            consumer.accept(ClassSource.makeClassName(modulePath.relativize(path).normalize()), classLoader);
+        }
+    }
+
+    public Path getModulePath() {
+        return modulePath;
+    }
+
+    @Override
+    public String toString() {
+        return "module:" + modulePath.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+package jdk.tools.jaotc.collect.module;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.SearchPath;
+import jdk.tools.jaotc.collect.SourceProvider;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+
+public class ModuleSourceProvider implements SourceProvider {
+    private final FileSystem fileSystem;
+    private final ClassLoader classLoader;
+    private final FileSupport fileSupport;
+    public final static String TYPE = "module";
+
+    public ModuleSourceProvider() {
+        this(FileSystems.getFileSystem(URI.create("jrt:/")), ClassLoader.getSystemClassLoader(), new FileSupport());
+    }
+
+    public ModuleSourceProvider(FileSystem fileSystem, ClassLoader classLoader, FileSupport fileSupport) {
+        this.fileSystem = fileSystem;
+        this.classLoader = classLoader;
+        this.fileSupport = fileSupport;
+    }
+
+    @Override
+    public ClassSource findSource(String name, SearchPath searchPath) {
+        Path path = fileSystem.getPath(name);
+        Path dir = fileSystem.getPath("modules");
+
+        if (dir == null || !fileSupport.isDirectory(dir)) {
+            return null;
+        }
+
+        Path found = findModuleDirectory(dir, path);
+
+        if (found == null) {
+            return null;
+        }
+
+        return new ModuleSource(found, classLoader);
+    }
+
+    private Path findModuleDirectory(Path root, Path path) {
+        try {
+            return fileSupport.getSubDirectory(fileSystem, root, path);
+        } catch (IOException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    @Override
+    public boolean supports(String type) {
+        return TYPE.equals(type);
+    }
+}
--- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, 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
@@ -50,7 +50,7 @@
   }
 
 
-  if (strlen(alt_root) + strlen(name) < PATH_MAX) {
+  if (strlen(alt_root) + strlen(name) > PATH_MAX) {
     // Buffer too small.
     return -1;
   }
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2017, 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
@@ -114,6 +114,8 @@
                     }
                 });
 
+                writeHeapRecordPrologue();
+
                 // write JavaThreads
                 writeJavaThreads();
 
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2017, 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
@@ -45,8 +45,8 @@
  * WARNING: This format is still under development, and is subject to
  * change without notice.
  *
- * header    "JAVA PROFILE 1.0.1" or "JAVA PROFILE 1.0.2" (0-terminated)
- * u4        size of identifiers. Identifiers are used to represent
+ * header     "JAVA PROFILE 1.0.2" (0-terminated)
+ * u4         size of identifiers. Identifiers are used to represent
  *            UTF8 strings, objects, stack traces, etc. They usually
  *            have the same size as host pointers. For example, on
  *            Solaris and Win32, the size is 4.
@@ -294,10 +294,9 @@
  *                u2        stack trace depth
  *
  *
- * When the header is "JAVA PROFILE 1.0.2" a heap dump can optionally
- * be generated as a sequence of heap dump segments. This sequence is
- * terminated by an end record. The additional tags allowed by format
- * "JAVA PROFILE 1.0.2" are:
+ * A heap dump can optionally be generated as a sequence of heap dump
+ * segments. This sequence is terminated by an end record. The additional
+ * tags allowed by format "JAVA PROFILE 1.0.2" are:
  *
  * HPROF_HEAP_DUMP_SEGMENT  denote a heap dump segment
  *
@@ -310,8 +309,6 @@
 
 public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
 
-    // The heap size threshold used to determine if segmented format
-    // ("JAVA PROFILE 1.0.2") should be used.
     private static final long HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD = 2L * 0x40000000;
 
     // The approximate size of a heap segment. Used to calculate when to create
@@ -319,7 +316,6 @@
     private static final long HPROF_SEGMENTED_HEAP_DUMP_SEGMENT_SIZE = 1L * 0x40000000;
 
     // hprof binary file header
-    private static final String HPROF_HEADER_1_0_1 = "JAVA PROFILE 1.0.1";
     private static final String HPROF_HEADER_1_0_2 = "JAVA PROFILE 1.0.2";
 
     // constants in enum HprofTag
@@ -380,6 +376,7 @@
     private static final int JVM_SIGNATURE_ARRAY   = '[';
     private static final int JVM_SIGNATURE_CLASS   = 'L';
 
+    private static final long MAX_U4_VALUE = 0xFFFFFFFFL;
     int serialNum = 1;
 
     public synchronized void write(String fileName) throws IOException {
@@ -469,7 +466,6 @@
             // length later - hprof format requires length.
             out.flush();
             currentSegmentStart = fos.getChannel().position();
-
             // write dummy length of 0 and we'll fix it later.
             out.writeInt(0);
         }
@@ -479,7 +475,7 @@
     protected void writeHeapRecordEpilogue() throws IOException {
         if (useSegmentedHeapDump) {
             out.flush();
-            if ((fos.getChannel().position() - currentSegmentStart - 4) >= HPROF_SEGMENTED_HEAP_DUMP_SEGMENT_SIZE) {
+            if ((fos.getChannel().position() - currentSegmentStart - 4L) >= HPROF_SEGMENTED_HEAP_DUMP_SEGMENT_SIZE) {
                 fillInHeapRecordLength();
                 currentSegmentStart = 0;
             }
@@ -488,14 +484,14 @@
 
     private void fillInHeapRecordLength() throws IOException {
 
-        // now get current position to calculate length
+        // now get the current position to calculate length
         long dumpEnd = fos.getChannel().position();
 
-        // calculate length of heap data
+        // calculate the length of heap data
         long dumpLenLong = (dumpEnd - currentSegmentStart - 4L);
 
         // Check length boundary, overflow could happen but is _very_ unlikely
-        if(dumpLenLong >= (4L * 0x40000000)){
+        if (dumpLenLong >= (4L * 0x40000000)) {
             throw new RuntimeException("Heap segment size overflow.");
         }
 
@@ -517,6 +513,71 @@
         fos.getChannel().position(currentPosition);
     }
 
+    // get the size in bytes for the requested type
+    private long getSizeForType(int type) throws IOException {
+        switch (type) {
+            case TypeArrayKlass.T_BOOLEAN:
+                return BOOLEAN_SIZE;
+            case TypeArrayKlass.T_INT:
+                return INT_SIZE;
+            case TypeArrayKlass.T_CHAR:
+                return CHAR_SIZE;
+            case TypeArrayKlass.T_SHORT:
+                return SHORT_SIZE;
+            case TypeArrayKlass.T_BYTE:
+                return BYTE_SIZE;
+            case TypeArrayKlass.T_LONG:
+                return LONG_SIZE;
+            case TypeArrayKlass.T_FLOAT:
+                return FLOAT_SIZE;
+            case TypeArrayKlass.T_DOUBLE:
+                return DOUBLE_SIZE;
+            default:
+                throw new RuntimeException(
+                    "Should not reach here: Unknown type: " + type);
+         }
+    }
+
+    private int getArrayHeaderSize(boolean isObjectAarray) {
+        return isObjectAarray?
+            ((int) BYTE_SIZE + 2 * (int) INT_SIZE + 2 * (int) OBJ_ID_SIZE):
+            (2 * (int) BYTE_SIZE + 2 * (int) INT_SIZE + (int) OBJ_ID_SIZE);
+    }
+
+    // Check if we need to truncate an array
+    private int calculateArrayMaxLength(long originalArrayLength,
+                                        int headerSize,
+                                        long typeSize,
+                                        String typeName) throws IOException {
+
+        long length = originalArrayLength;
+
+        // now get the current position to calculate length
+        long dumpEnd = fos.getChannel().position();
+        long originalLengthInBytes = originalArrayLength * typeSize;
+
+        // calculate the length of heap data
+        long currentRecordLength = (dumpEnd - currentSegmentStart - 4L);
+        if (currentRecordLength > 0 &&
+            (currentRecordLength + headerSize + originalLengthInBytes) > MAX_U4_VALUE) {
+            fillInHeapRecordLength();
+            currentSegmentStart = 0;
+            writeHeapRecordPrologue();
+            currentRecordLength = 0;
+        }
+
+        // Calculate the max bytes we can use.
+        long maxBytes = (MAX_U4_VALUE - (headerSize + currentRecordLength));
+
+        if (originalLengthInBytes > maxBytes) {
+            length = maxBytes/typeSize;
+            System.err.println("WARNING: Cannot dump array of type " + typeName
+                               + " with length " + originalArrayLength
+                               + "; truncating to length " + length);
+        }
+        return (int) length;
+    }
+
     private void writeClassDumpRecords() throws IOException {
         SystemDictionary sysDict = VM.getVM().getSystemDictionary();
         ClassLoaderDataGraph cldGraph = VM.getVM().getClassLoaderDataGraph();
@@ -694,12 +755,16 @@
     }
 
     protected void writeObjectArray(ObjArray array) throws IOException {
+        int headerSize = getArrayHeaderSize(true);
+        final int length = calculateArrayMaxLength(array.getLength(),
+                                                   headerSize,
+                                                   OBJ_ID_SIZE,
+                                                   "Object");
         out.writeByte((byte) HPROF_GC_OBJ_ARRAY_DUMP);
         writeObjectID(array);
         out.writeInt(DUMMY_STACK_TRACE_ID);
-        out.writeInt((int) array.getLength());
+        out.writeInt(length);
         writeObjectID(array.getKlass().getJavaMirror());
-        final int length = (int) array.getLength();
         for (int index = 0; index < length; index++) {
             OopHandle handle = array.getOopHandleAt(index);
             writeObjectID(getAddressValue(handle));
@@ -707,101 +772,101 @@
     }
 
     protected void writePrimitiveArray(TypeArray array) throws IOException {
+        int headerSize = getArrayHeaderSize(false);
+        TypeArrayKlass tak = (TypeArrayKlass) array.getKlass();
+        final int type = (int) tak.getElementType();
+        final String typeName = tak.getElementTypeName();
+        final long typeSize = getSizeForType(type);
+        final int length = calculateArrayMaxLength(array.getLength(),
+                                                   headerSize,
+                                                   typeSize,
+                                                   typeName);
         out.writeByte((byte) HPROF_GC_PRIM_ARRAY_DUMP);
         writeObjectID(array);
         out.writeInt(DUMMY_STACK_TRACE_ID);
-        out.writeInt((int) array.getLength());
-        TypeArrayKlass tak = (TypeArrayKlass) array.getKlass();
-        final int type = (int) tak.getElementType();
+        out.writeInt(length);
         out.writeByte((byte) type);
         switch (type) {
             case TypeArrayKlass.T_BOOLEAN:
-                writeBooleanArray(array);
+                writeBooleanArray(array, length);
                 break;
             case TypeArrayKlass.T_CHAR:
-                writeCharArray(array);
+                writeCharArray(array, length);
                 break;
             case TypeArrayKlass.T_FLOAT:
-                writeFloatArray(array);
+                writeFloatArray(array, length);
                 break;
             case TypeArrayKlass.T_DOUBLE:
-                writeDoubleArray(array);
+                writeDoubleArray(array, length);
                 break;
             case TypeArrayKlass.T_BYTE:
-                writeByteArray(array);
+                writeByteArray(array, length);
                 break;
             case TypeArrayKlass.T_SHORT:
-                writeShortArray(array);
+                writeShortArray(array, length);
                 break;
             case TypeArrayKlass.T_INT:
-                writeIntArray(array);
+                writeIntArray(array, length);
                 break;
             case TypeArrayKlass.T_LONG:
-                writeLongArray(array);
+                writeLongArray(array, length);
                 break;
             default:
-                throw new RuntimeException("should not reach here");
+                throw new RuntimeException(
+                    "Should not reach here: Unknown type: " + type);
         }
     }
 
-    private void writeBooleanArray(TypeArray array) throws IOException {
-        final int length = (int) array.getLength();
+    private void writeBooleanArray(TypeArray array, int length) throws IOException {
         for (int index = 0; index < length; index++) {
              long offset = BOOLEAN_BASE_OFFSET + index * BOOLEAN_SIZE;
              out.writeBoolean(array.getHandle().getJBooleanAt(offset));
         }
     }
 
-    private void writeByteArray(TypeArray array) throws IOException {
-        final int length = (int) array.getLength();
+    private void writeByteArray(TypeArray array, int length) throws IOException {
         for (int index = 0; index < length; index++) {
              long offset = BYTE_BASE_OFFSET + index * BYTE_SIZE;
              out.writeByte(array.getHandle().getJByteAt(offset));
         }
     }
 
-    private void writeShortArray(TypeArray array) throws IOException {
-        final int length = (int) array.getLength();
+    private void writeShortArray(TypeArray array, int length) throws IOException {
         for (int index = 0; index < length; index++) {
              long offset = SHORT_BASE_OFFSET + index * SHORT_SIZE;
              out.writeShort(array.getHandle().getJShortAt(offset));
         }
     }
 
-    private void writeIntArray(TypeArray array) throws IOException {
-        final int length = (int) array.getLength();
+    private void writeIntArray(TypeArray array, int length) throws IOException {
         for (int index = 0; index < length; index++) {
              long offset = INT_BASE_OFFSET + index * INT_SIZE;
              out.writeInt(array.getHandle().getJIntAt(offset));
         }
     }
 
-    private void writeLongArray(TypeArray array) throws IOException {
-        final int length = (int) array.getLength();
+    private void writeLongArray(TypeArray array, int length) throws IOException {
         for (int index = 0; index < length; index++) {
              long offset = LONG_BASE_OFFSET + index * LONG_SIZE;
              out.writeLong(array.getHandle().getJLongAt(offset));
         }
     }
 
-    private void writeCharArray(TypeArray array) throws IOException {
-        final int length = (int) array.getLength();
+    private void writeCharArray(TypeArray array, int length) throws IOException {
         for (int index = 0; index < length; index++) {
              long offset = CHAR_BASE_OFFSET + index * CHAR_SIZE;
              out.writeChar(array.getHandle().getJCharAt(offset));
         }
     }
 
-    private void writeFloatArray(TypeArray array) throws IOException {
-        final int length = (int) array.getLength();
+    private void writeFloatArray(TypeArray array, int length) throws IOException {
         for (int index = 0; index < length; index++) {
              long offset = FLOAT_BASE_OFFSET + index * FLOAT_SIZE;
              out.writeFloat(array.getHandle().getJFloatAt(offset));
         }
     }
 
-    private void writeDoubleArray(TypeArray array) throws IOException {
-        final int length = (int) array.getLength();
+    private void writeDoubleArray(TypeArray array, int length) throws IOException {
         for (int index = 0; index < length; index++) {
              long offset = DOUBLE_BASE_OFFSET + index * DOUBLE_SIZE;
              out.writeDouble(array.getHandle().getJDoubleAt(offset));
@@ -996,12 +1061,7 @@
     // writes hprof binary file header
     private void writeFileHeader() throws IOException {
         // version string
-        if(useSegmentedHeapDump) {
-            out.writeBytes(HPROF_HEADER_1_0_2);
-        }
-        else {
-            out.writeBytes(HPROF_HEADER_1_0_1);
-        }
+        out.writeBytes(HPROF_HEADER_1_0_2);
         out.writeByte((byte)'\0');
 
         // write identifier size. we use pointers as identifiers.
--- a/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java	Mon Feb 27 23:20:05 2017 +0100
@@ -100,15 +100,19 @@
     native long getExceptionTableStart(HotSpotResolvedJavaMethodImpl method);
 
     /**
-     * Determines if {@code method} can be inlined. A method may not be inlinable for a number of
-     * reasons such as:
-     * <ul>
-     * <li>a CompileOracle directive may prevent inlining or compilation of methods</li>
-     * <li>the method may have a bytecode breakpoint set</li>
-     * <li>the method may have other bytecode features that require special handling by the VM</li>
-     * </ul>
+     * Determines whether {@code method} is currently compilable by the JVMCI compiler being used by
+     * the VM. This can return false if JVMCI compilation failed earlier for {@code method}, a
+     * breakpoint is currently set in {@code method} or {@code method} contains other bytecode
+     * features that require special handling by the VM.
      */
-    native boolean canInlineMethod(HotSpotResolvedJavaMethodImpl method);
+    native boolean isCompilable(HotSpotResolvedJavaMethodImpl method);
+
+    /**
+     * Determines if {@code method} is targeted by a VM directive (e.g.,
+     * {@code -XX:CompileCommand=dontinline,<pattern>}) or annotation (e.g.,
+     * {@code jdk.internal.vm.annotation.DontInline}) that specifies it should not be inlined.
+     */
+    native boolean hasNeverInlineDirective(HotSpotResolvedJavaMethodImpl method);
 
     /**
      * Determines if {@code method} should be inlined at any cost. This could be because:
--- a/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIMetaAccessContext.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIMetaAccessContext.java	Mon Feb 27 23:20:05 2017 +0100
@@ -27,8 +27,6 @@
 import java.lang.ref.WeakReference;
 import java.util.Arrays;
 import java.util.Iterator;
-import java.util.Map;
-import java.util.WeakHashMap;
 
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaType;
@@ -147,21 +145,34 @@
         }
     }
 
-    private final Map<Class<?>, WeakReference<ResolvedJavaType>> typeMap = new WeakHashMap<>();
+    private final ClassValue<WeakReference<ResolvedJavaType>> resolvedJavaType = new ClassValue<WeakReference<ResolvedJavaType>>() {
+        @Override
+        protected WeakReference<ResolvedJavaType> computeValue(Class<?> type) {
+            return new WeakReference<>(createClass(type));
+        }
+    };
 
     /**
      * Gets the JVMCI mirror for a {@link Class} object.
      *
      * @return the {@link ResolvedJavaType} corresponding to {@code javaClass}
      */
-    public synchronized ResolvedJavaType fromClass(Class<?> javaClass) {
-        WeakReference<ResolvedJavaType> typeRef = typeMap.get(javaClass);
-        ResolvedJavaType type = typeRef != null ? typeRef.get() : null;
-        if (type == null) {
-            type = createClass(javaClass);
-            typeMap.put(javaClass, new WeakReference<>(type));
+    public ResolvedJavaType fromClass(Class<?> javaClass) {
+        ResolvedJavaType javaType = null;
+        while (javaType == null) {
+            WeakReference<ResolvedJavaType> type = resolvedJavaType.get(javaClass);
+            javaType = type.get();
+            if (javaType == null) {
+                /*
+                 * If the referent has become null, clear out the current value
+                 * and let computeValue above create a new value.  Reload the
+                 * value in a loop because in theory the WeakReference referent
+                 * can be reclaimed at any point.
+                 */
+                resolvedJavaType.remove(javaClass);
+            }
         }
-        return type;
+        return javaType;
     }
 
     /**
--- a/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java	Mon Feb 27 23:20:05 2017 +0100
@@ -50,13 +50,6 @@
     boolean isForceInline();
 
     /**
-     * Returns true if this method has a {@code DontInline} annotation.
-     *
-     * @return true if DontInline annotation present, false otherwise
-     */
-    boolean isDontInline();
-
-    /**
      * Returns true if this method has a {@code ReservedStackAccess} annotation.
      *
      * @return true if ReservedStackAccess annotation present, false otherwise
--- a/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java	Mon Feb 27 23:20:05 2017 +0100
@@ -299,15 +299,6 @@
     }
 
     /**
-     * Returns true if this method has a {@code DontInline} annotation.
-     *
-     * @return true if DontInline annotation present, false otherwise
-     */
-    public boolean isDontInline() {
-        return (getFlags() & config().methodFlagsDontInline) != 0;
-    }
-
-    /**
      * Returns true if this method has a {@code ReservedStackAccess} annotation.
      *
      * @return true if ReservedStackAccess annotation present, false otherwise
@@ -582,10 +573,15 @@
 
     @Override
     public boolean canBeInlined() {
-        if (isDontInline()) {
+        if (hasNeverInlineDirective()) {
             return false;
         }
-        return compilerToVM().canInlineMethod(this);
+        return compilerToVM().isCompilable(this);
+    }
+
+    @Override
+    public boolean hasNeverInlineDirective() {
+        return compilerToVM().hasNeverInlineDirective(this);
     }
 
     @Override
--- a/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java	Mon Feb 27 23:20:05 2017 +0100
@@ -347,6 +347,13 @@
     boolean canBeInlined();
 
     /**
+     * Determines if this method is targeted by a VM directive (e.g.,
+     * {@code -XX:CompileCommand=dontinline,<pattern>}) or VM recognized annotation (e.g.,
+     * {@code jdk.internal.vm.annotation.DontInline}) that specifies it should not be inlined.
+     */
+    boolean hasNeverInlineDirective();
+
+    /**
      * Returns {@code true} if the inlining of this method should be forced.
      */
     boolean shouldBeInlined();
--- a/src/jdk.vm.compiler/.mx.graal/suite.py	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.compiler/.mx.graal/suite.py	Mon Feb 27 23:20:05 2017 +0100
@@ -638,6 +638,7 @@
       "annotationProcessors" : [
         "GRAAL_NODEINFO_PROCESSOR",
         "GRAAL_REPLACEMENTS_VERIFIER",
+        "GRAAL_OPTIONS_PROCESSOR",
       ],
       "workingSets" : "Graal,Graph",
     },
--- a/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java	Mon Feb 27 23:20:05 2017 +0100
@@ -116,6 +116,7 @@
     public static final int INFO_LOG_LEVEL = 2;
     public static final int VERBOSE_LOG_LEVEL = 3;
     public static final int DETAILED_LOG_LEVEL = 4;
+    public static final int VERY_DETAILED_LOG_LEVEL = 5;
 
     public static boolean isDumpEnabled(int dumpLevel) {
         return ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel);
--- a/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java	Mon Feb 27 23:20:05 2017 +0100
@@ -267,10 +267,15 @@
 
             if (config.useCompressedClassPointers) {
                 Register register = r10;
-                AMD64HotSpotMove.decodeKlassPointer(asm, register, providers.getRegisters().getHeapBaseRegister(), src, config.getKlassEncoding());
-                if (config.narrowKlassBase != 0) {
-                    // The heap base register was destroyed above, so restore it
-                    asm.movq(providers.getRegisters().getHeapBaseRegister(), config.narrowOopBase);
+                AMD64HotSpotMove.decodeKlassPointer(crb, asm, register, providers.getRegisters().getHeapBaseRegister(), src, config);
+                if (GeneratePIC.getValue()) {
+                    asm.movq(providers.getRegisters().getHeapBaseRegister(), asm.getPlaceholder(-1));
+                    crb.recordMark(config.MARKID_NARROW_OOP_BASE_ADDRESS);
+                } else {
+                    if (config.narrowKlassBase != 0) {
+                        // The heap base register was destroyed above, so restore it
+                        asm.movq(providers.getRegisters().getHeapBaseRegister(), config.narrowOopBase);
+                    }
                 }
                 asm.cmpq(inlineCacheKlass, register);
             } else {
--- a/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java	Mon Feb 27 23:20:05 2017 +0100
@@ -265,14 +265,21 @@
         }
     }
 
-    public static void decodeKlassPointer(AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, CompressEncoding encoding) {
+    public static void decodeKlassPointer(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, GraalHotSpotVMConfig config) {
+        CompressEncoding encoding = config.getKlassEncoding();
         masm.movl(register, address);
         if (encoding.shift != 0) {
             assert encoding.alignment == encoding.shift : "Decode algorithm is wrong";
             masm.shlq(register, encoding.alignment);
         }
-        if (encoding.base != 0) {
-            masm.movq(scratch, encoding.base);
+        if (GeneratePIC.getValue() || encoding.base != 0) {
+            if (GeneratePIC.getValue()) {
+                masm.movq(scratch, masm.getPlaceholder(-1));
+                crb.recordMark(config.MARKID_NARROW_KLASS_BASE_ADDRESS);
+            } else {
+                assert encoding.base != 0;
+                masm.movq(scratch, encoding.base);
+            }
             masm.addq(register, scratch);
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/AOTGraalHotSpotVMConfig.java	Mon Feb 27 23:20:05 2017 +0100
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+package org.graalvm.compiler.hotspot;
+
+import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
+
+public class AOTGraalHotSpotVMConfig extends GraalHotSpotVMConfig {
+    private final CompressEncoding aotOopEncoding;
+    private final CompressEncoding aotKlassEncoding;
+
+    public AOTGraalHotSpotVMConfig(HotSpotVMConfigStore store) {
+        super(store);
+        // In AOT, force the shift to be always equal to alignment therefore avoiding zero-shift.
+        CompressEncoding vmOopEncoding = super.getOopEncoding();
+        aotOopEncoding = new CompressEncoding(vmOopEncoding.base, vmOopEncoding.alignment, vmOopEncoding.alignment);
+        CompressEncoding vmKlassEncoding = super.getKlassEncoding();
+        aotKlassEncoding = new CompressEncoding(vmKlassEncoding.base, vmKlassEncoding.alignment, vmKlassEncoding.alignment);
+        assert check();
+    }
+
+    @Override
+    public CompressEncoding getOopEncoding() {
+        return aotOopEncoding;
+    }
+
+    @Override
+    public CompressEncoding getKlassEncoding() {
+        return aotKlassEncoding;
+    }
+}
--- a/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java	Mon Feb 27 23:20:05 2017 +0100
@@ -479,7 +479,6 @@
     public final int methodCompiledEntryOffset = getFieldOffset("Method::_from_compiled_entry", Integer.class, "address");
     public final int methodCodeOffset = getFieldOffset("Method::_code", Integer.class, isJDK8 ? "nmethod*" : "CompiledMethod*");
 
-    public final int methodFlagsJfrTowrite = getConstant("Method::_jfr_towrite", Integer.class);
     public final int methodFlagsCallerSensitive = getConstant("Method::_caller_sensitive", Integer.class);
     public final int methodFlagsForceInline = getConstant("Method::_force_inline", Integer.class);
     public final int methodFlagsDontInline = getConstant("Method::_dont_inline", Integer.class);
@@ -773,13 +772,14 @@
     public final int MARKID_HEAP_TOP_ADDRESS = getConstant("CodeInstaller::HEAP_TOP_ADDRESS", Integer.class, 17);
     public final int MARKID_HEAP_END_ADDRESS = getConstant("CodeInstaller::HEAP_END_ADDRESS", Integer.class, 18);
     public final int MARKID_NARROW_KLASS_BASE_ADDRESS = getConstant("CodeInstaller::NARROW_KLASS_BASE_ADDRESS", Integer.class, 19);
-    public final int MARKID_CRC_TABLE_ADDRESS = getConstant("CodeInstaller::CRC_TABLE_ADDRESS", Integer.class, 20);
-    public final int MARKID_LOG_OF_HEAP_REGION_GRAIN_BYTES = getConstant("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES", Integer.class, 21);
-    public final int MARKID_INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = getConstant("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED", Integer.class, 22);
+    public final int MARKID_NARROW_OOP_BASE_ADDRESS = getConstant("CodeInstaller::NARROW_OOP_BASE_ADDRESS", Integer.class, 20);
+    public final int MARKID_CRC_TABLE_ADDRESS = getConstant("CodeInstaller::CRC_TABLE_ADDRESS", Integer.class, 21);
+    public final int MARKID_LOG_OF_HEAP_REGION_GRAIN_BYTES = getConstant("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES", Integer.class, 22);
+    public final int MARKID_INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = getConstant("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED", Integer.class, 23);
 
     // Checkstyle: resume
 
-    private boolean check() {
+    protected boolean check() {
         for (Field f : getClass().getDeclaredFields()) {
             int modifiers = f.getModifiers();
             if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
--- a/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java	Mon Feb 27 23:20:05 2017 +0100
@@ -22,6 +22,7 @@
  */
 package org.graalvm.compiler.hotspot;
 
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.debug.GraalDebugConfig.areScopedGlobalMetricsEnabled;
 import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueSummary;
 import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Dump;
@@ -99,7 +100,7 @@
     HotSpotGraalRuntime(HotSpotJVMCIRuntime jvmciRuntime, CompilerConfigurationFactory compilerConfigurationFactory) {
 
         HotSpotVMConfigStore store = jvmciRuntime.getConfigStore();
-        config = new GraalHotSpotVMConfig(store);
+        config = GeneratePIC.getValue() ? new AOTGraalHotSpotVMConfig(store) : new GraalHotSpotVMConfig(store);
         CompileTheWorldOptions.overrideWithNativeOptions(config);
 
         // Only set HotSpotPrintInlining if it still has its default value (false).
--- a/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java	Mon Feb 27 23:20:05 2017 +0100
@@ -22,7 +22,6 @@
  */
 package org.graalvm.compiler.hotspot.meta;
 
-import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
 import static org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider.FieldReadEnabledInImmutableCode;
 
@@ -112,11 +111,6 @@
                 return true;
             }
         }
-        if (GeneratePIC.getValue()) {
-            if (field.isSynthetic() && field.getName().startsWith("$assertionsDisabled")) {
-                return tryReadField(b, field, null);
-            }
-        }
         if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadStaticField(b, field)) {
             return true;
         }
--- a/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java	Mon Feb 27 23:20:05 2017 +0100
@@ -90,17 +90,10 @@
     protected InstalledCode code;
 
     /**
-     * Compilation result from which {@link #code} was created.
-     */
-    protected CompilationResult compResult;
-
-    /**
      * The registers destroyed by this stub (from the caller's perspective).
      */
     private Set<Register> destroyedCallerRegisters;
 
-    private HotSpotCompiledCode compiledCode;
-
     public void initDestroyedCallerRegisters(Set<Register> registers) {
         assert registers != null;
         assert destroyedCallerRegisters == null || registers.equals(destroyedCallerRegisters) : "cannot redefine";
@@ -184,35 +177,13 @@
     public synchronized InstalledCode getCode(final Backend backend) {
         if (code == null) {
             try (Scope d = Debug.sandbox("CompilingStub", DebugScope.getConfig(), providers.getCodeCache(), debugScopeContext())) {
-                final StructuredGraph graph = getGraph(getStubCompilationId());
-
-                // Stubs cannot be recompiled so they cannot be compiled with assumptions
-                assert graph.getAssumptions() == null;
-
-                if (!(graph.start() instanceof StubStartNode)) {
-                    StubStartNode newStart = graph.add(new StubStartNode(Stub.this));
-                    newStart.setStateAfter(graph.start().stateAfter());
-                    graph.replaceFixed(graph.start(), newStart);
-                }
-
                 CodeCacheProvider codeCache = providers.getCodeCache();
-
-                compResult = new CompilationResult(toString(), GeneratePIC.getValue());
-                try (Scope s0 = Debug.scope("StubCompilation", graph, providers.getCodeCache())) {
-                    Suites suites = createSuites();
-                    emitFrontEnd(providers, backend, graph, providers.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, DefaultProfilingInfo.get(TriState.UNKNOWN), suites);
-                    LIRSuites lirSuites = createLIRSuites();
-                    emitBackEnd(graph, Stub.this, getInstalledCodeOwner(), backend, compResult, CompilationResultBuilderFactory.Default, getRegisterConfig(), lirSuites);
-                    assert checkStubInvariants();
-                } catch (Throwable e) {
-                    throw Debug.handle(e);
-                }
-
-                assert destroyedCallerRegisters != null;
+                CompilationResult compResult = buildCompilationResult(backend);
                 try (Scope s = Debug.scope("CodeInstall", compResult)) {
+                    assert destroyedCallerRegisters != null;
                     // Add a GeneratePIC check here later, we don't want to install
                     // code if we don't have a corresponding VM global symbol.
-                    compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(null, null, compResult);
+                    HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(null, null, compResult);
                     code = codeCache.installCode(null, compiledCode, null, null, false);
                 } catch (Throwable e) {
                     throw Debug.handle(e);
@@ -226,6 +197,44 @@
         return code;
     }
 
+    @SuppressWarnings("try")
+    private CompilationResult buildCompilationResult(final Backend backend) {
+        CompilationResult compResult = new CompilationResult(toString(), GeneratePIC.getValue());
+        final StructuredGraph graph = getGraph(getStubCompilationId());
+
+        // Stubs cannot be recompiled so they cannot be compiled with assumptions
+        assert graph.getAssumptions() == null;
+
+        if (!(graph.start() instanceof StubStartNode)) {
+            StubStartNode newStart = graph.add(new StubStartNode(Stub.this));
+            newStart.setStateAfter(graph.start().stateAfter());
+            graph.replaceFixed(graph.start(), newStart);
+        }
+
+        try (Scope s0 = Debug.scope("StubCompilation", graph, providers.getCodeCache())) {
+            Suites suites = createSuites();
+            emitFrontEnd(providers, backend, graph, providers.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, DefaultProfilingInfo.get(TriState.UNKNOWN), suites);
+            LIRSuites lirSuites = createLIRSuites();
+            emitBackEnd(graph, Stub.this, getInstalledCodeOwner(), backend, compResult, CompilationResultBuilderFactory.Default, getRegisterConfig(), lirSuites);
+            assert checkStubInvariants(compResult);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+        return compResult;
+    }
+
+    /**
+     * Gets a {@link CompilationResult} that can be used for code generation. Required for AOT.
+     */
+    @SuppressWarnings("try")
+    public CompilationResult getCompilationResult(final Backend backend) {
+        try (Scope d = Debug.sandbox("CompilingStub", DebugScope.getConfig(), providers.getCodeCache(), debugScopeContext())) {
+            return buildCompilationResult(backend);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
     public CompilationIdentifier getStubCompilationId() {
         return new StubCompilationIdentifier(this);
     }
@@ -233,7 +242,7 @@
     /**
      * Checks the conditions a compilation must satisfy to be installed as a RuntimeStub.
      */
-    private boolean checkStubInvariants() {
+    private boolean checkStubInvariants(CompilationResult compResult) {
         assert compResult.getExceptionHandlers().isEmpty() : this;
 
         // Stubs cannot be recompiled so they cannot be compiled with
@@ -278,24 +287,4 @@
         }
         return lirSuites;
     }
-
-    /**
-     * Gets the HotSpotCompiledCode that was created during installation.
-     */
-    public synchronized HotSpotCompiledCode getCompiledCode(final Backend backend) {
-        getCompilationResult(backend);
-        assert compiledCode != null;
-        return compiledCode;
-    }
-
-    /**
-     * Gets the compilation result for this stub, compiling it first if necessary, and installing it
-     * in code.
-     */
-    public synchronized CompilationResult getCompilationResult(final Backend backend) {
-        if (code == null) {
-            getCode(backend);
-        }
-        return compResult;
-    }
 }
--- a/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Mon Feb 27 23:20:05 2017 +0100
@@ -1738,9 +1738,8 @@
             } else {
                 // Intrinsic was not applied: remove intrinsic guard
                 // and restore the original receiver node in the arguments array
-                for (Node node : graph.getNewNodes(intrinsicGuard.mark)) {
-                    GraphUtil.killCFG(node);
-                }
+                intrinsicGuard.lastInstr.setNext(null);
+                GraphUtil.removeNewNodes(graph, intrinsicGuard.mark);
                 lastInstr = intrinsicGuard.lastInstr;
                 args[0] = intrinsicGuard.receiver;
             }
--- a/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java	Mon Feb 27 23:20:05 2017 +0100
@@ -153,9 +153,7 @@
         }
 
         for (Node node : methodScope.graph.getNewNodes(methodScope.methodStartMark)) {
-            if (!(node instanceof FixedNode) && node.hasNoUsages()) {
-                GraphUtil.killCFG(node);
-            }
+            GraphUtil.tryKillUnused(node);
         }
     }
 
--- a/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java	Mon Feb 27 23:20:05 2017 +0100
@@ -506,7 +506,7 @@
         for (Node successor : snapshot) {
             if (successor != null && successor.isAlive()) {
                 if (successor != survivingSuccessor) {
-                    GraphUtil.killCFG(successor, tool);
+                    GraphUtil.killCFG((FixedNode) successor, tool);
                 }
             }
         }
@@ -566,6 +566,9 @@
             reduceTrivialMerge(begin);
         } else { // convert to merge
             AbstractMergeNode merge = this.add(new MergeNode());
+            for (EndNode end : begin.forwardEnds()) {
+                merge.addForwardEnd(end);
+            }
             this.replaceFixedWithFixed(begin, merge);
         }
     }
@@ -576,7 +579,14 @@
         for (PhiNode phi : merge.phis().snapshot()) {
             assert phi.valueCount() == 1;
             ValueNode singleValue = phi.valueAt(0);
-            phi.replaceAtUsagesAndDelete(singleValue);
+            if (phi.hasUsages()) {
+                phi.replaceAtUsagesAndDelete(singleValue);
+            } else {
+                phi.safeDelete();
+                if (singleValue != null) {
+                    GraphUtil.tryKillUnused(singleValue);
+                }
+            }
         }
         // remove loop exits
         if (merge instanceof LoopBeginNode) {
--- a/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2017, 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
@@ -22,18 +22,30 @@
  */
 package org.graalvm.compiler.nodes.util;
 
+import static org.graalvm.compiler.graph.Graph.Options.VerifyGraalGraphEdges;
+import static org.graalvm.compiler.nodes.util.GraphUtil.Options.VerifyKillCFGUnusedNodes;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.Set;
 
 import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.code.SourceStackTraceBailoutException;
+import org.graalvm.compiler.core.common.CollectionsFactory;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.Graph;
 import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.NodeWorkList;
+import org.graalvm.compiler.graph.Position;
 import org.graalvm.compiler.graph.iterators.NodeIterable;
 import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.AbstractEndNode;
 import org.graalvm.compiler.nodes.AbstractMergeNode;
@@ -48,11 +60,15 @@
 import org.graalvm.compiler.nodes.StateSplit;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
 import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
 import org.graalvm.compiler.nodes.spi.LimitedValueProxy;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.nodes.spi.ValueProxy;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
 
 import jdk.vm.ci.code.BailoutException;
 import jdk.vm.ci.code.BytecodePosition;
@@ -64,22 +80,78 @@
 
 public class GraphUtil {
 
-    public static void killCFG(Node node, SimplifierTool tool) {
-        NodeWorkList worklist = killCFG(node, tool, null);
-        if (worklist != null) {
-            for (Node successor : worklist) {
-                killCFG(successor, tool, worklist);
+    public static class Options {
+        @Option(help = "Verify that there are no new unused nodes when performing killCFG", type = OptionType.Debug)//
+        public static final OptionValue<Boolean> VerifyKillCFGUnusedNodes = new OptionValue<>(false);
+    }
+
+    @SuppressWarnings("try")
+    public static void killCFG(FixedNode node, SimplifierTool tool) {
+        try (Debug.Scope scope = Debug.scope("KillCFG", node)) {
+            Set<Node> unusedNodes = null;
+            Set<Node> unsafeNodes = null;
+            Graph.NodeEventScope nodeEventScope = null;
+            if (VerifyGraalGraphEdges.getValue()) {
+                unsafeNodes = collectUnsafeNodes(node.graph());
+            }
+            if (VerifyKillCFGUnusedNodes.getValue()) {
+                Set<Node> collectedUnusedNodes = unusedNodes = CollectionsFactory.newSet();
+                nodeEventScope = node.graph().trackNodeEvents(new Graph.NodeEventListener() {
+                    @Override
+                    public void event(Graph.NodeEvent e, Node n) {
+                        if (e == Graph.NodeEvent.ZERO_USAGES && isFloatingNode(n)) {
+                            collectedUnusedNodes.add(n);
+                        }
+                    }
+                });
+            }
+            Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, node.graph(), "Before killCFG %s", node);
+            NodeWorkList worklist = killCFG(node, tool, null);
+            if (worklist != null) {
+                for (Node n : worklist) {
+                    killCFG(n, tool, worklist);
+                }
+            }
+            if (VerifyGraalGraphEdges.getValue()) {
+                Set<Node> newUnsafeNodes = collectUnsafeNodes(node.graph());
+                newUnsafeNodes.removeAll(unsafeNodes);
+                assert newUnsafeNodes.isEmpty() : "New unsafe nodes: " + newUnsafeNodes;
+            }
+            if (VerifyKillCFGUnusedNodes.getValue()) {
+                nodeEventScope.close();
+                unusedNodes.removeIf(n -> n.isDeleted());
+                assert unusedNodes.isEmpty() : "New unused nodes: " + unusedNodes;
+            }
+        } catch (Throwable t) {
+            throw Debug.handle(t);
+        }
+    }
+
+    /**
+     * Collects all node in the graph which have non-optional inputs that are null.
+     */
+    private static Set<Node> collectUnsafeNodes(Graph graph) {
+        Set<Node> unsafeNodes = CollectionsFactory.newSet();
+        for (Node n : graph.getNodes()) {
+            for (Position pos : n.inputPositions()) {
+                Node input = pos.get(n);
+                if (input == null) {
+                    if (!pos.isInputOptional()) {
+                        unsafeNodes.add(n);
+                    }
+                }
             }
         }
+        return unsafeNodes;
     }
 
     private static NodeWorkList killCFG(Node node, SimplifierTool tool, NodeWorkList worklist) {
         NodeWorkList newWorklist = worklist;
-        // DebugScope.forceDump(node.graph(), "kill CFG %s", node);
         if (node instanceof FixedNode) {
             newWorklist = killCFGLinear((FixedNode) node, newWorklist, tool);
         } else {
-            propagateKill(node);
+            newWorklist = propagateKill(node, newWorklist);
+            Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, node.graph(), "killCFG (Floating) %s", node);
         }
         return newWorklist;
     }
@@ -93,19 +165,20 @@
             if (current instanceof AbstractEndNode) {
                 // We reached a control flow end.
                 AbstractEndNode end = (AbstractEndNode) current;
-                killEnd(end, tool);
+                newWorklist = killEnd(end, newWorklist, tool);
             } else if (current instanceof FixedWithNextNode) {
-                next = ((FixedWithNextNode) current).next();
+                // Node guaranteed to have a single successor
+                FixedWithNextNode fixedWithNext = (FixedWithNextNode) current;
+                assert fixedWithNext.successors().count() == 1 || fixedWithNext.successors().count() == 0;
+                assert fixedWithNext.successors().first() == fixedWithNext.next();
+                next = fixedWithNext.next();
             } else {
-                // Normal control flow node.
                 /*
                  * We do not take a successor snapshot because this iterator supports concurrent
                  * modifications as long as they do not change the size of the successor list. Not
                  * taking a snapshot allows us to see modifications to other branches that may
                  * happen while processing one branch.
                  */
-                // assert node.successors().count() > 1 || node.successors().count() == 0 :
-                // node.getClass();
                 Iterator<Node> successors = current.successors().iterator();
                 if (successors.hasNext()) {
                     Node first = successors.next();
@@ -126,100 +199,158 @@
                 }
             }
             current.replaceAtPredecessor(null);
-            propagateKill(current);
+            newWorklist = propagateKill(current, newWorklist);
+            Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, current.graph(), "killCFGLinear %s", current);
             current = next;
         }
+        Debug.dump(Debug.DETAILED_LOG_LEVEL, in.graph(), "killCFGLinear %s", in);
         return newWorklist;
     }
 
-    public static void killCFG(Node node) {
+    public static void killCFG(FixedNode node) {
         killCFG(node, null);
     }
 
-    private static void killEnd(AbstractEndNode end, SimplifierTool tool) {
+    /**
+     * Node type used temporarily while deleting loops.
+     *
+     * It is used as replacement for the loop {@link PhiNode PhiNodes} in order to break data-flow
+     * cycles before deleting the loop. The control-flow of the whole loop is killed before killing
+     * the poison node if they are still alive.
+     */
+    @NodeInfo(allowedUsageTypes = InputType.Unchecked)
+    private static final class PoisonNode extends FloatingNode {
+        public static final NodeClass<PoisonNode> TYPE = NodeClass.create(PoisonNode.class);
+
+        protected PoisonNode() {
+            super(TYPE, StampFactory.forVoid());
+        }
+    }
+
+    private static NodeWorkList killEnd(AbstractEndNode end, NodeWorkList worklist, SimplifierTool tool) {
+        NodeWorkList newWorklist = worklist;
         AbstractMergeNode merge = end.merge();
         if (merge != null) {
             merge.removeEnd(end);
             StructuredGraph graph = end.graph();
             if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) {
                 // dead loop
-                for (PhiNode phi : merge.phis().snapshot()) {
-                    propagateKill(phi);
-                }
                 LoopBeginNode begin = (LoopBeginNode) merge;
                 // disconnect and delete loop ends & loop exits
                 for (LoopEndNode loopend : begin.loopEnds().snapshot()) {
                     loopend.predecessor().replaceFirstSuccessor(loopend, null);
                     loopend.safeDelete();
                 }
+                // clean unused proxies to avoid creating new unused nodes
+                for (LoopExitNode exit : begin.loopExits()) {
+                    for (ProxyNode vpn : exit.proxies().snapshot()) {
+                        tryKillUnused(vpn);
+                    }
+                }
                 begin.removeExits();
+                PoisonNode poison = null;
+                if (merge.phis().isNotEmpty()) {
+                    poison = graph.unique(new PoisonNode());
+                    for (PhiNode phi : merge.phis()) {
+                        phi.replaceAtUsages(poison);
+                    }
+                    for (PhiNode phi : merge.phis().snapshot()) {
+                        killWithUnusedFloatingInputs(phi);
+                    }
+                }
                 FixedNode loopBody = begin.next();
-                if (loopBody != null) { // for small infinite loops, the body may be killed while
-                                        // killing the loop ends
-                    killCFG(loopBody);
+                Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, end.graph(), "killEnd (Loop) %s after initial loop cleanup", end);
+                if (loopBody != null) {
+                    // for small infinite loops, the body may already be killed while killing the
+                    // LoopEnds
+                    newWorklist = killCFG(loopBody, tool, worklist);
                 }
+                FrameState frameState = begin.stateAfter();
                 begin.safeDelete();
+                if (frameState != null) {
+                    tryKillUnused(frameState);
+                }
+                if (poison != null && poison.isAlive()) {
+                    if (newWorklist == null) {
+                        newWorklist = graph.createNodeWorkList();
+                    }
+                    // drain the worklist to finish the loop before adding the poison
+                    for (Node n : newWorklist) {
+                        killCFG(n, tool, newWorklist);
+                    }
+                    if (poison.isAlive()) {
+                        newWorklist.add(poison);
+                    }
+                }
             } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) {
                 // not a loop anymore
                 if (tool != null) {
-                    merge.phis().forEach(phi -> tool.addToWorkList(phi.usages()));
+                    for (PhiNode phi : merge.phis()) {
+                        tool.addToWorkList(phi.usages());
+                    }
                 }
                 graph.reduceDegenerateLoopBegin((LoopBeginNode) merge);
             } else if (merge.phiPredecessorCount() == 1) {
                 // not a merge anymore
                 if (tool != null) {
-                    merge.phis().forEach(phi -> tool.addToWorkList(phi.usages()));
+                    for (PhiNode phi : merge.phis()) {
+                        tool.addToWorkList(phi.usages());
+                    }
                 }
                 graph.reduceTrivialMerge(merge);
             }
         }
+        return newWorklist;
     }
 
     public static boolean isFloatingNode(Node n) {
         return !(n instanceof FixedNode);
     }
 
-    private static void propagateKill(Node node) {
+    private static NodeWorkList propagateKill(Node node, NodeWorkList workList) {
+        NodeWorkList newWorkList = workList;
         if (node != null && node.isAlive()) {
-            node.markDeleted();
-
-            for (Node in : node.inputs()) {
-                if (in.isAlive()) {
-                    in.removeUsage(node);
-                    if (in.hasNoUsages() && !(in instanceof FixedNode)) {
-                        killWithUnusedFloatingInputs(in);
+            for (Node usage : node.usages().snapshot()) {
+                assert usage.isAlive();
+                if (isFloatingNode(usage)) {
+                    boolean addUsage = false;
+                    if (usage instanceof PhiNode) {
+                        PhiNode phi = (PhiNode) usage;
+                        assert phi.merge() != null;
+                        if (phi.merge() == node) {
+                            // we reach the phi directly through he merge, queue it.
+                            addUsage = true;
+                        } else {
+                            // we reach it though a value
+                            assert phi.values().contains(node);
+                            // let that be handled when we reach the corresponding End node
+                        }
+                    } else {
+                        addUsage = true;
+                    }
+                    if (addUsage) {
+                        if (newWorkList == null) {
+                            newWorkList = node.graph().createNodeWorkList();
+                        }
+                        newWorkList.add(usage);
                     }
                 }
+                usage.replaceFirstInput(node, null);
             }
+            killWithUnusedFloatingInputs(node);
+        }
+        return newWorkList;
+    }
 
-            ArrayList<Node> usageToKill = null;
-            for (Node usage : node.usages()) {
-                if (usage.isAlive() && !(usage instanceof FixedNode)) {
-                    if (usageToKill == null) {
-                        usageToKill = new ArrayList<>();
-                    }
-                    usageToKill.add(usage);
-                }
-            }
-            if (usageToKill != null) {
-                for (Node usage : usageToKill) {
-                    if (usage.isAlive()) {
-                        if (usage instanceof PhiNode) {
-                            PhiNode phiNode = (PhiNode) usage;
-                            usage.replaceFirstInput(node, null);
-                            if (phiNode.merge() == null || !phiNode.hasValidInput()) {
-                                propagateKill(usage);
-                            }
-                        } else {
-                            propagateKill(usage);
-                        }
-                    }
-                }
-            }
-        }
+    private static boolean checkKill(Node node) {
+        node.assertTrue(node.isAlive(), "must be alive");
+        node.assertTrue(node.hasNoUsages(), "cannot kill node %s because of usages: %s", node, node.usages());
+        node.assertTrue(node.predecessor() == null, "cannot kill node %s because of predecessor: %s", node, node.predecessor());
+        return true;
     }
 
     public static void killWithUnusedFloatingInputs(Node node) {
+        assert checkKill(node);
         node.markDeleted();
         outer: for (Node in : node.inputs()) {
             if (in.isAlive()) {
@@ -227,7 +358,7 @@
                 if (in.hasNoUsages()) {
                     node.maybeNotifyZeroUsages(in);
                 }
-                if (!(in instanceof FixedNode)) {
+                if (isFloatingNode(in)) {
                     if (in.hasNoUsages()) {
                         killWithUnusedFloatingInputs(in);
                     } else if (in instanceof PhiNode) {
@@ -244,6 +375,35 @@
         }
     }
 
+    /**
+     * Removes all nodes created after the {@code mark}, assuming no "old" nodes point to "new"
+     * nodes.
+     */
+    public static void removeNewNodes(Graph graph, Graph.Mark mark) {
+        assert checkNoOldToNewEdges(graph, mark);
+        for (Node n : graph.getNewNodes(mark)) {
+            n.markDeleted();
+            for (Node in : n.inputs()) {
+                in.removeUsage(n);
+            }
+        }
+    }
+
+    private static boolean checkNoOldToNewEdges(Graph graph, Graph.Mark mark) {
+        for (Node old : graph.getNodes()) {
+            if (graph.isNew(mark, old)) {
+                break;
+            }
+            for (Node n : old.successors()) {
+                assert !graph.isNew(mark, n) : old + " -> " + n;
+            }
+            for (Node n : old.inputs()) {
+                assert !graph.isNew(mark, n) : old + " -> " + n;
+            }
+        }
+        return true;
+    }
+
     public static void removeFixedWithUnusedInputs(FixedWithNextNode fixed) {
         if (fixed instanceof StateSplit) {
             FrameState stateAfter = ((StateSplit) fixed).stateAfter();
@@ -688,8 +848,9 @@
 
         @Override
         public void deleteBranch(Node branch) {
-            branch.predecessor().replaceFirstSuccessor(branch, null);
-            GraphUtil.killCFG(branch, this);
+            FixedNode fixedBranch = (FixedNode) branch;
+            fixedBranch.predecessor().replaceFirstSuccessor(fixedBranch, null);
+            GraphUtil.killCFG(fixedBranch, this);
         }
 
         @Override
--- a/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java	Mon Feb 27 23:20:05 2017 +0100
@@ -444,8 +444,9 @@
 
             @Override
             public void deleteBranch(Node branch) {
-                branch.predecessor().replaceFirstSuccessor(branch, null);
-                GraphUtil.killCFG(branch, this);
+                FixedNode fixedBranch = (FixedNode) branch;
+                fixedBranch.predecessor().replaceFirstSuccessor(fixedBranch, null);
+                GraphUtil.killCFG(fixedBranch, this);
             }
 
             @Override
--- a/src/os/aix/vm/os_aix.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/os/aix/vm/os_aix.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2016 SAP SE. All rights reserved.
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017 SAP SE. 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
@@ -632,7 +632,6 @@
   sigaddset(&unblocked_sigs, SIGBUS);
   sigaddset(&unblocked_sigs, SIGFPE);
   sigaddset(&unblocked_sigs, SIGTRAP);
-  sigaddset(&unblocked_sigs, SIGDANGER);
   sigaddset(&unblocked_sigs, SR_signum);
 
   if (!ReduceSignalUsage) {
@@ -1553,6 +1552,8 @@
   print_signal_handler(st, SHUTDOWN3_SIGNAL , buf, buflen);
   print_signal_handler(st, BREAK_SIGNAL, buf, buflen);
   print_signal_handler(st, SIGTRAP, buf, buflen);
+  // We also want to know if someone else adds a SIGDANGER handler because
+  // that will interfere with OOM killling.
   print_signal_handler(st, SIGDANGER, buf, buflen);
 }
 
@@ -3156,7 +3157,6 @@
     set_signal_handler(SIGFPE, true);
     set_signal_handler(SIGTRAP, true);
     set_signal_handler(SIGXFSZ, true);
-    set_signal_handler(SIGDANGER, true);
 
     if (libjsig_is_loaded) {
       // Tell libjsig jvm finishes setting signal handlers.
@@ -3273,7 +3273,6 @@
   if (UseSIGTRAP) {
     DO_SIGNAL_CHECK(SIGTRAP);
   }
-  DO_SIGNAL_CHECK(SIGDANGER);
 
   // ReduceSignalUsage allows the user to override these handlers
   // see comments at the very top and jvm_solaris.h
--- a/src/os/posix/vm/vmError_posix.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/os/posix/vm/vmError_posix.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, 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
@@ -59,6 +59,21 @@
 static int resettedSigflags[NUM_SIGNALS];
 static address resettedSighandler[NUM_SIGNALS];
 
+// Needed for cancelable steps.
+static volatile pthread_t reporter_thread_id;
+
+void VMError::reporting_started() {
+  // record pthread id of reporter thread.
+  reporter_thread_id = ::pthread_self();
+}
+
+void VMError::interrupt_reporting_thread() {
+  // We misuse SIGILL here, but it does not really matter. We need
+  //  a signal which is handled by crash_handler and not likely to
+  //  occurr during error reporting itself.
+  ::pthread_kill(reporter_thread_id, SIGILL);
+}
+
 static void save_signal(int idx, int sig)
 {
   struct sigaction sa;
--- a/src/os/windows/vm/os_windows.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/os/windows/vm/os_windows.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -778,6 +778,11 @@
   // is already attached to a debugger; debugger must observe
   // the exception below to show the correct name.
 
+  // If there is no debugger attached skip raising the exception
+  if (!IsDebuggerPresent()) {
+    return;
+  }
+
   const DWORD MS_VC_EXCEPTION = 0x406D1388;
   struct {
     DWORD dwType;     // must be 0x1000
--- a/src/os/windows/vm/vmError_windows.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/os/windows/vm/vmError_windows.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, 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
@@ -66,3 +66,10 @@
     }
   }
 }
+
+// Error reporting cancellation: there is no easy way to implement this on Windows, because we do
+// not have an easy way to send signals to threads (aka to cause a win32 Exception in another
+// thread). We would need something like "RaiseException(HANDLE thread)"...
+void VMError::reporting_started() {}
+void VMError::interrupt_reporting_thread() {}
+
--- a/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2016 SAP SE. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017 SAP SE. 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
@@ -258,13 +258,6 @@
     }
   }
 
-  // Handle SIGDANGER right away. AIX would raise SIGDANGER whenever available swap
-  // space falls below 30%. This is only a chance for the process to gracefully abort.
-  // We can't hope to proceed after SIGDANGER since SIGKILL tailgates.
-  if (sig == SIGDANGER) {
-    goto report_and_die;
-  }
-
   if (info == NULL || uc == NULL || thread == NULL && vmthread == NULL) {
     goto run_chained_handler;
   }
--- a/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -87,6 +87,7 @@
 #define SPELL_REG_FP "rbp"
 #else
 #define REG_FP 29
+#define REG_LR 30
 
 #define SPELL_REG_SP "sp"
 #define SPELL_REG_FP "x29"
@@ -182,6 +183,46 @@
   return frame(sp, fp, epc.pc());
 }
 
+bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) {
+  address pc = (address) os::Linux::ucontext_get_pc(uc);
+  if (Interpreter::contains(pc)) {
+    // interpreter performs stack banging after the fixed frame header has
+    // been generated while the compilers perform it before. To maintain
+    // semantic consistency between interpreted and compiled frames, the
+    // method returns the Java sender of the current frame.
+    *fr = os::fetch_frame_from_context(uc);
+    if (!fr->is_first_java_frame()) {
+      assert(fr->safe_for_sender(thread), "Safety check");
+      *fr = fr->java_sender();
+    }
+  } else {
+    // more complex code with compiled code
+    assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
+    CodeBlob* cb = CodeCache::find_blob(pc);
+    if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
+      // Not sure where the pc points to, fallback to default
+      // stack overflow handling
+      return false;
+    } else {
+      // In compiled code, the stack banging is performed before LR
+      // has been saved in the frame.  LR is live, and SP and FP
+      // belong to the caller.
+      intptr_t* fp = os::Linux::ucontext_get_fp(uc);
+      intptr_t* sp = os::Linux::ucontext_get_sp(uc);
+      address pc = (address)(uc->uc_mcontext.regs[REG_LR]
+                         - NativeInstruction::instruction_size);
+      *fr = frame(sp, fp, pc);
+      if (!fr->is_java_frame()) {
+        assert(fr->safe_for_sender(thread), "Safety check");
+        assert(!fr->is_first_frame(), "Safety check");
+        *fr = fr->java_sender();
+      }
+    }
+  }
+  assert(fr->is_java_frame(), "Safety check");
+  return true;
+}
+
 // By default, gcc always saves frame pointer rfp on this stack. This
 // may get turned off by -fomit-frame-pointer.
 frame os::get_sender_for_C_frame(frame* fr) {
@@ -313,6 +354,24 @@
         if (thread->in_stack_yellow_reserved_zone(addr)) {
           thread->disable_stack_yellow_reserved_zone();
           if (thread->thread_state() == _thread_in_Java) {
+            if (thread->in_stack_reserved_zone(addr)) {
+              frame fr;
+              if (os::Linux::get_frame_at_stack_banging_point(thread, uc, &fr)) {
+                assert(fr.is_java_frame(), "Must be a Java frame");
+                frame activation =
+                  SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
+                if (activation.sp() != NULL) {
+                  thread->disable_stack_reserved_zone();
+                  if (activation.is_interpreted_frame()) {
+                    thread->set_reserved_stack_activation((address)(
+                      activation.fp() + frame::interpreter_frame_initial_sp_offset));
+                  } else {
+                    thread->set_reserved_stack_activation((address)activation.unextended_sp());
+                  }
+                  return 1;
+                }
+              }
+            }
             // Throw a stack overflow exception.  Guard pages will be reenabled
             // while unwinding the stack.
             stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
@@ -475,9 +534,9 @@
 
 // Minimum usable stack sizes required to get to user code. Space for
 // HotSpot guard pages is added later.
-size_t os::Posix::_compiler_thread_min_stack_allowed = 32 * K;
-size_t os::Posix::_java_thread_min_stack_allowed = 32 * K;
-size_t os::Posix::_vm_internal_thread_min_stack_allowed = 64 * K;
+size_t os::Posix::_compiler_thread_min_stack_allowed = 72 * K;
+size_t os::Posix::_java_thread_min_stack_allowed = 72 * K;
+size_t os::Posix::_vm_internal_thread_min_stack_allowed = 72 * K;
 
 // return default stack size for thr_type
 size_t os::Posix::default_stack_size(os::ThreadType thr_type) {
--- a/src/os_cpu/linux_s390/vm/os_linux_s390.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/os_cpu/linux_s390/vm/os_linux_s390.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -144,6 +144,42 @@
   return frame(sp, epc.pc());
 }
 
+bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) {
+  address pc = (address) os::Linux::ucontext_get_pc(uc);
+  if (Interpreter::contains(pc)) {
+    // Interpreter performs stack banging after the fixed frame header has
+    // been generated while the compilers perform it before. To maintain
+    // semantic consistency between interpreted and compiled frames, the
+    // method returns the Java sender of the current frame.
+    *fr = os::fetch_frame_from_context(uc);
+    if (!fr->is_first_java_frame()) {
+      assert(fr->safe_for_sender(thread), "Safety check");
+      *fr = fr->java_sender();
+    }
+  } else {
+    // More complex code with compiled code.
+    assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
+    CodeBlob* cb = CodeCache::find_blob(pc);
+    if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
+      // Not sure where the pc points to, fallback to default
+      // stack overflow handling. In compiled code, we bang before
+      // the frame is complete.
+      return false;
+    } else {
+      intptr_t* fp = os::Linux::ucontext_get_fp(uc);
+      intptr_t* sp = os::Linux::ucontext_get_sp(uc);
+      *fr = frame(sp, (address)*sp);
+      if (!fr->is_java_frame()) {
+        assert(fr->safe_for_sender(thread), "Safety check");
+        assert(!fr->is_first_frame(), "Safety check");
+        *fr = fr->java_sender();
+      }
+    }
+  }
+  assert(fr->is_java_frame(), "Safety check");
+  return true;
+}
+
 frame os::get_sender_for_C_frame(frame* fr) {
   if (*fr->sp() == 0) {
     // fr is the last C frame.
@@ -279,13 +315,31 @@
       if (thread->on_local_stack(addr)) {
         // stack overflow
         if (thread->in_stack_yellow_reserved_zone(addr)) {
-          thread->disable_stack_yellow_reserved_zone();
           if (thread->thread_state() == _thread_in_Java) {
+            if (thread->in_stack_reserved_zone(addr)) {
+              frame fr;
+              if (os::Linux::get_frame_at_stack_banging_point(thread, uc, &fr)) {
+                assert(fr.is_java_frame(), "Must be a Javac frame");
+                frame activation =
+                  SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
+                if (activation.sp() != NULL) {
+                  thread->disable_stack_reserved_zone();
+                  if (activation.is_interpreted_frame()) {
+                    thread->set_reserved_stack_activation((address)activation.fp());
+                  } else {
+                    thread->set_reserved_stack_activation((address)activation.unextended_sp());
+                  }
+                  return 1;
+                }
+              }
+            }
             // Throw a stack overflow exception.
             // Guard pages will be reenabled while unwinding the stack.
+            thread->disable_stack_yellow_reserved_zone();
             stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
           } else {
             // Thread was in the vm or native code. Return and try to finish.
+            thread->disable_stack_yellow_reserved_zone();
             return 1;
           }
         } else if (thread->in_stack_red_zone(addr)) {
--- a/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -89,7 +89,10 @@
 // Minimum usable stack sizes required to get to user code. Space for
 // HotSpot guard pages is added later.
 #ifdef _LP64
-size_t os::Posix::_compiler_thread_min_stack_allowed = 202 * K;
+// The adlc generated method 'State::MachNodeGenerator(int)' used by the C2 compiler
+// threads requires a large stack with the Solaris Studio C++ compiler version 5.13
+// and product VM builds (debug builds require significantly less stack space).
+size_t os::Posix::_compiler_thread_min_stack_allowed = 325 * K;
 size_t os::Posix::_java_thread_min_stack_allowed = 48 * K;
 size_t os::Posix::_vm_internal_thread_min_stack_allowed = 224 * K;
 #else
--- a/src/share/vm/adlc/formssel.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/adlc/formssel.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -650,6 +650,7 @@
   if( strcmp(_matrule->_opType,"MemBarReleaseLock") == 0 ) return true;
   if( strcmp(_matrule->_opType,"MemBarAcquireLock") == 0 ) return true;
   if( strcmp(_matrule->_opType,"MemBarStoreStore") == 0 ) return true;
+  if( strcmp(_matrule->_opType,"MemBarVolatile") == 0 ) return true;
   if( strcmp(_matrule->_opType,"StoreFence") == 0 ) return true;
   if( strcmp(_matrule->_opType,"LoadFence") == 0 ) return true;
 
--- a/src/share/vm/aot/aotCodeHeap.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/aot/aotCodeHeap.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -25,6 +25,7 @@
 
 #include "aot/aotCodeHeap.hpp"
 #include "aot/aotLoader.hpp"
+#include "classfile/javaAssertions.hpp"
 #include "gc/g1/heapRegion.hpp"
 #include "gc/shared/gcLocker.hpp"
 #include "interpreter/abstractInterpreter.hpp"
@@ -293,6 +294,8 @@
     // When the AOT compiler compiles something big we fail to generate metadata
     // in CodeInstaller::gather_metadata. In that case the scopes_pcs_begin == scopes_pcs_end.
     // In all successful cases we always have 2 entries of scope pcs.
+    log_info(aot, class, resolve)("Failed to load %s (no metadata available)", mh->name_and_sig_as_C_string());
+    _code_to_aot[code_id]._state = invalid;
     return;
   }
 
@@ -531,6 +534,7 @@
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_heap_end_address", address, (heap->supports_inline_contig_alloc() ? heap->end_addr() : NULL));
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_polling_page", address, os::get_polling_page());
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_klass_base_address", address, Universe::narrow_klass_base());
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_oop_base_address", address, Universe::narrow_oop_base());
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_log_of_heap_region_grain_bytes", int, HeapRegion::LogOfHRGrainBytes);
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_inline_contiguous_allocation_supported", bool, heap->supports_inline_contig_alloc());
     link_shared_runtime_symbols();
@@ -701,6 +705,12 @@
     return false;
   }
 
+  if (_lib->config()->_omitAssertions && JavaAssertions::enabled(kh->name()->as_C_string(), kh->class_loader() == NULL)) {
+    log_trace(aot, class, load)("class  %s  in  %s does not have java assertions in compiled code, but assertions are enabled for this execution.", kh->internal_name(), _lib->name());
+    sweep_dependent_methods(klass_data);
+    return false;
+  }
+
   NOT_PRODUCT( aot_klasses_found++; )
 
   log_trace(aot, class, load)("found  %s  in  %s for classloader %p tid=" INTPTR_FORMAT, kh->internal_name(), _lib->name(), kh->class_loader_data(), p2i(thread));
@@ -709,7 +719,7 @@
   // Set klass's Resolve (second) got cell.
   _metaspace_got[klass_data->_got_index] = kh();
 
-  // Initialize global symbols of the DSO to the correspondingVM symbol values.
+  // Initialize global symbols of the DSO to the corresponding VM symbol values.
   link_global_lib_symbols();
 
   int methods_offset = klass_data->_compiled_methods_offset;
--- a/src/share/vm/aot/aotCodeHeap.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/aot/aotCodeHeap.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -88,7 +88,7 @@
 } AOTHeader;
 
 typedef struct {
-  enum { CONFIG_SIZE = 11 + 7 * 4 };
+  enum { CONFIG_SIZE = 12 + 7 * 4 };
   int _config_size;
   int _narrowOopShift;
   int _narrowKlassShift;
@@ -108,6 +108,7 @@
   bool _tieredAOT;
   bool _enableContended;
   bool _restrictContended;
+  bool _omitAssertions;
 } AOTConfiguration;
 
 class AOTLib : public CHeapObj<mtCode> {
--- a/src/share/vm/c1/c1_Canonicalizer.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/c1/c1_Canonicalizer.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -248,7 +248,9 @@
   } else if ((lf = x->array()->as_LoadField()) != NULL) {
     ciField* field = lf->field();
     if (field->is_static_constant()) {
-      assert(PatchALot || ScavengeRootsInCode < 2, "Constant field loads are folded during parsing");
+      // Constant field loads are usually folded during parsing.
+      // But it doesn't happen with PatchALot, ScavengeRootsInCode < 2, or when
+      // holder class is being initialized during parsing (for static fields).
       ciObject* c = field->constant_value().as_object();
       if (!c->is_null_object()) {
         set_constant(c->as_array()->length());
--- a/src/share/vm/c1/c1_GraphBuilder.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/c1/c1_GraphBuilder.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -3298,7 +3298,9 @@
   // for osr compile, bailout if some requirements are not fulfilled
   if (osr_bci != -1) {
     BlockBegin* osr_block = blm.bci2block()->at(osr_bci);
-    assert(osr_block->is_set(BlockBegin::was_visited_flag),"osr entry must have been visited for osr compile");
+    if (!osr_block->is_set(BlockBegin::was_visited_flag)) {
+      BAILOUT("osr entry must have been visited for osr compile");
+    }
 
     // check if osr entry point has empty stack - we cannot handle non-empty stacks at osr entry points
     if (!osr_block->state()->stack_is_empty()) {
--- a/src/share/vm/c1/c1_LIR.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/c1/c1_LIR.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1413,6 +1413,17 @@
   append(c);
 }
 
+void LIR_List::null_check(LIR_Opr opr, CodeEmitInfo* info, bool deoptimize_on_null) {
+  if (deoptimize_on_null) {
+    // Emit an explicit null check and deoptimize if opr is null
+    CodeStub* deopt = new DeoptimizeStub(info, Deoptimization::Reason_null_check, Deoptimization::Action_none);
+    cmp(lir_cond_equal, opr, LIR_OprFact::oopConst(NULL));
+    branch(lir_cond_equal, T_OBJECT, deopt);
+  } else {
+    // Emit an implicit null check
+    append(new LIR_Op1(lir_null_check, opr, info));
+  }
+}
 
 void LIR_List::cas_long(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value,
                         LIR_Opr t1, LIR_Opr t2, LIR_Opr result) {
--- a/src/share/vm/c1/c1_LIR.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/c1/c1_LIR.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -2113,7 +2113,7 @@
   void   pack64(LIR_Opr src, LIR_Opr dst) { append(new LIR_Op1(lir_pack64,   src, dst, T_LONG, lir_patch_none, NULL)); }
   void unpack64(LIR_Opr src, LIR_Opr dst) { append(new LIR_Op1(lir_unpack64, src, dst, T_LONG, lir_patch_none, NULL)); }
 
-  void null_check(LIR_Opr opr, CodeEmitInfo* info)         { append(new LIR_Op1(lir_null_check, opr, info)); }
+  void null_check(LIR_Opr opr, CodeEmitInfo* info, bool deoptimize_on_null = false);
   void throw_exception(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) {
     append(new LIR_Op2(lir_throw, exceptionPC, exceptionOop, LIR_OprFact::illegalOpr, info));
   }
--- a/src/share/vm/c1/c1_LIRGenerator.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/c1/c1_LIRGenerator.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1752,8 +1752,10 @@
   if (x->needs_null_check() &&
       (needs_patching ||
        MacroAssembler::needs_explicit_null_check(x->offset()))) {
-    // emit an explicit null check because the offset is too large
-    __ null_check(object.result(), new CodeEmitInfo(info));
+    // Emit an explicit null check because the offset is too large.
+    // If the class is not loaded and the object is NULL, we need to deoptimize to throw a
+    // NoClassDefFoundError in the interpreter instead of an implicit NPE from compiled code.
+    __ null_check(object.result(), new CodeEmitInfo(info), /* deoptimize */ needs_patching);
   }
 
   LIR_Address* address;
@@ -1838,8 +1840,10 @@
       obj = new_register(T_OBJECT);
       __ move(LIR_OprFact::oopConst(NULL), obj);
     }
-    // emit an explicit null check because the offset is too large
-    __ null_check(obj, new CodeEmitInfo(info));
+    // Emit an explicit null check because the offset is too large.
+    // If the class is not loaded and the object is NULL, we need to deoptimize to throw a
+    // NoClassDefFoundError in the interpreter instead of an implicit NPE from compiled code.
+    __ null_check(obj, new CodeEmitInfo(info), /* deoptimize */ needs_patching);
   }
 
   LIR_Opr reg = rlock_result(x, field_type);
--- a/src/share/vm/ci/bcEscapeAnalyzer.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/ci/bcEscapeAnalyzer.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -895,8 +895,32 @@
           ciMethod* target = s.get_method(ignored_will_link, &declared_signature);
           ciKlass*  holder = s.get_declared_method_holder();
           assert(declared_signature != NULL, "cannot be null");
-          // Push appendix argument, if one.
-          if (s.has_appendix()) {
+          // If the current bytecode has an attached appendix argument,
+          // push an unknown object to represent that argument. (Analysis
+          // of dynamic call sites, especially invokehandle calls, needs
+          // the appendix argument on the stack, in addition to "regular" arguments
+          // pushed onto the stack by bytecode instructions preceding the call.)
+          //
+          // The escape analyzer does _not_ use the ciBytecodeStream::has_appendix(s)
+          // method to determine whether the current bytecode has an appendix argument.
+          // The has_appendix() method obtains the appendix from the
+          // ConstantPoolCacheEntry::_f1 field, which can happen concurrently with
+          // resolution of dynamic call sites. Callees in the
+          // ciBytecodeStream::get_method() call above also access the _f1 field;
+          // interleaving the get_method() and has_appendix() calls in the current
+          // method with call site resolution can lead to an inconsistent view of
+          // the current method's argument count. In particular, some interleaving(s)
+          // can cause the method's argument count to not include the appendix, which
+          // then leads to stack over-/underflow in the escape analyzer.
+          //
+          // Instead of pushing the argument if has_appendix() is true, the escape analyzer
+          // pushes an appendix for all call sites targeted by invokedynamic and invokehandle
+          // instructions, except if the call site is the _invokeBasic intrinsic
+          // (that intrinsic is always targeted by an invokehandle instruction but does
+          // not have an appendix argument).
+          if (target->is_loaded() &&
+              Bytecodes::has_optional_appendix(s.cur_bc_raw()) &&
+              target->intrinsic_id() != vmIntrinsics::_invokeBasic) {
             state.apush(unknown_obj);
           }
           // Pass in raw bytecode because we need to see invokehandle instructions.
--- a/src/share/vm/ci/ciEnv.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/ci/ciEnv.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -101,6 +101,7 @@
   _debug_info = NULL;
   _dependencies = NULL;
   _failure_reason = NULL;
+  _inc_decompile_count_on_failure = true;
   _compilable = MethodCompilable;
   _break_at_compile = false;
   _compiler_data = NULL;
@@ -161,6 +162,7 @@
   _debug_info = NULL;
   _dependencies = NULL;
   _failure_reason = NULL;
+  _inc_decompile_count_on_failure = true;
   _compilable = MethodCompilable_never;
   _break_at_compile = false;
   _compiler_data = NULL;
@@ -902,7 +904,12 @@
     if (deps.is_klass_type())  continue;  // skip klass dependencies
     Klass* witness = deps.check_dependency();
     if (witness != NULL) {
-      record_failure("invalid non-klass dependency");
+      if (deps.type() == Dependencies::call_site_target_value) {
+        _inc_decompile_count_on_failure = false;
+        record_failure("call site target change");
+      } else {
+        record_failure("invalid non-klass dependency");
+      }
       return;
     }
   }
@@ -1017,7 +1024,7 @@
     if (failing()) {
       // While not a true deoptimization, it is a preemptive decompile.
       MethodData* mdo = method()->method_data();
-      if (mdo != NULL) {
+      if (mdo != NULL && _inc_decompile_count_on_failure) {
         mdo->inc_decompile_count();
       }
 
--- a/src/share/vm/ci/ciEnv.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/ci/ciEnv.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -55,6 +55,7 @@
   DebugInformationRecorder* _debug_info;
   Dependencies*    _dependencies;
   const char*      _failure_reason;
+  bool             _inc_decompile_count_on_failure;
   int              _compilable;
   bool             _break_at_compile;
   int              _num_inlined_bytecodes;
--- a/src/share/vm/ci/ciMethod.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/ci/ciMethod.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -136,15 +136,19 @@
     check_is_loaded();
     return _signature->size() + (_flags.is_static() ? 0 : 1);
   }
-  // Report the number of elements on stack when invoking this method.
-  // This is different than the regular arg_size because invokedynamic
-  // has an implicit receiver.
+  // Report the number of elements on stack when invoking the current method.
+  // If the method is loaded, arg_size() gives precise information about the
+  // number of stack elements (using the method's signature and its flags).
+  // However, if the method is not loaded, the number of stack elements must
+  // be determined differently, as the method's flags are not yet available.
+  // The invoke_arg_size() method assumes in that case that all bytecodes except
+  // invokestatic and invokedynamic have a receiver that is also pushed onto the
+  // stack by the caller of the current method.
   int invoke_arg_size(Bytecodes::Code code) const {
     if (is_loaded()) {
       return arg_size();
     } else {
       int arg_size = _signature->size();
-      // Add a receiver argument, maybe:
       if (code != Bytecodes::_invokestatic &&
           code != Bytecodes::_invokedynamic) {
         arg_size++;
--- a/src/share/vm/classfile/classFileParser.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/classFileParser.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1025,16 +1025,20 @@
 
 static int skip_annotation_value(const u1*, int, int); // fwd decl
 
+// Safely increment index by val if does not pass limit
+#define SAFE_ADD(index, limit, val) \
+if (index >= limit - val) return limit; \
+index += val;
+
 // Skip an annotation.  Return >=limit if there is any problem.
 static int skip_annotation(const u1* buffer, int limit, int index) {
   assert(buffer != NULL, "invariant");
   // annotation := atype:u2 do(nmem:u2) {member:u2 value}
   // value := switch (tag:u1) { ... }
-  index += 2;  // skip atype
-  if ((index += 2) >= limit)  return limit;  // read nmem
+  SAFE_ADD(index, limit, 4); // skip atype and read nmem
   int nmem = Bytes::get_Java_u2((address)buffer + index - 2);
   while (--nmem >= 0 && index < limit) {
-    index += 2; // skip member
+    SAFE_ADD(index, limit, 2); // skip member
     index = skip_annotation_value(buffer, limit, index);
   }
   return index;
@@ -1052,7 +1056,7 @@
   //   case @: annotation;
   //   case s: s_con:u2;
   // }
-  if ((index += 1) >= limit)  return limit;  // read tag
+  SAFE_ADD(index, limit, 1); // read tag
   const u1 tag = buffer[index - 1];
   switch (tag) {
     case 'B':
@@ -1065,14 +1069,14 @@
     case 'J':
     case 'c':
     case 's':
-      index += 2;  // skip con or s_con
+      SAFE_ADD(index, limit, 2);  // skip con or s_con
       break;
     case 'e':
-      index += 4;  // skip e_class, e_name
+      SAFE_ADD(index, limit, 4);  // skip e_class, e_name
       break;
     case '[':
     {
-      if ((index += 2) >= limit)  return limit;  // read nval
+      SAFE_ADD(index, limit, 2); // read nval
       int nval = Bytes::get_Java_u2((address)buffer + index - 2);
       while (--nval >= 0 && index < limit) {
         index = skip_annotation_value(buffer, limit, index);
@@ -1101,8 +1105,8 @@
   assert(loader_data != NULL, "invariant");
 
   // annotations := do(nann:u2) {annotation}
-  int index = 0;
-  if ((index += 2) >= limit)  return;  // read nann
+  int index = 2; // read nann
+  if (index >= limit)  return;
   int nann = Bytes::get_Java_u2((address)buffer + index - 2);
   enum {  // initial annotation layout
     atype_off = 0,      // utf8 such as 'Ljava/lang/annotation/Retention;'
@@ -1121,7 +1125,8 @@
     s_size = 9,
     min_size = 6        // smallest possible size (zero members)
   };
-  while ((--nann) >= 0 && (index - 2 + min_size <= limit)) {
+  // Cannot add min_size to index in case of overflow MAX_INT
+  while ((--nann) >= 0 && (index - 2 <= limit - min_size)) {
     int index0 = index;
     index = skip_annotation(buffer, limit, index);
     const u1* const abase = buffer + index0;
@@ -1253,13 +1258,14 @@
         runtime_visible_annotations_length = attribute_length;
         runtime_visible_annotations = cfs->get_u1_buffer();
         assert(runtime_visible_annotations != NULL, "null visible annotations");
+        cfs->guarantee_more(runtime_visible_annotations_length, CHECK);
         parse_annotations(cp,
                           runtime_visible_annotations,
                           runtime_visible_annotations_length,
                           parsed_annotations,
                           _loader_data,
                           CHECK);
-        cfs->skip_u1(runtime_visible_annotations_length, CHECK);
+        cfs->skip_u1_fast(runtime_visible_annotations_length);
       } else if (attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
         if (runtime_invisible_annotations_exists) {
           classfile_parse_error(
@@ -2574,13 +2580,14 @@
         runtime_visible_annotations_length = method_attribute_length;
         runtime_visible_annotations = cfs->get_u1_buffer();
         assert(runtime_visible_annotations != NULL, "null visible annotations");
+        cfs->guarantee_more(runtime_visible_annotations_length, CHECK_NULL);
         parse_annotations(cp,
                           runtime_visible_annotations,
                           runtime_visible_annotations_length,
                           &parsed_annotations,
                           _loader_data,
                           CHECK_NULL);
-        cfs->skip_u1(runtime_visible_annotations_length, CHECK_NULL);
+        cfs->skip_u1_fast(runtime_visible_annotations_length);
       } else if (method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
         if (runtime_invisible_annotations_exists) {
           classfile_parse_error(
@@ -3284,13 +3291,14 @@
         runtime_visible_annotations_length = attribute_length;
         runtime_visible_annotations = cfs->get_u1_buffer();
         assert(runtime_visible_annotations != NULL, "null visible annotations");
+        cfs->guarantee_more(runtime_visible_annotations_length, CHECK);
         parse_annotations(cp,
                           runtime_visible_annotations,
                           runtime_visible_annotations_length,
                           parsed_annotations,
                           _loader_data,
                           CHECK);
-        cfs->skip_u1(runtime_visible_annotations_length, CHECK);
+        cfs->skip_u1_fast(runtime_visible_annotations_length);
       } else if (tag == vmSymbols::tag_runtime_invisible_annotations()) {
         if (runtime_invisible_annotations_exists) {
           classfile_parse_error(
--- a/src/share/vm/classfile/classLoader.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/classLoader.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -364,7 +364,12 @@
     if (verstr != NULL) {
       version = atoi(verstr);
       if (version < base_version || version > cur_ver) {
-        is_multi_ver = false;
+        // If the specified version is lower than the base version, the base
+        // entry will be used; if the version is higher than the current
+        // jdk version, the highest versioned entry will be used.
+        if (version < base_version) {
+          is_multi_ver = false;
+        }
         // print out warning, do not use assertion here since it will continue to look
         // for proper version.
         warning("JDK%d is not supported in multiple version jars", version);
--- a/src/share/vm/classfile/classLoaderData.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/classLoaderData.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -94,7 +94,7 @@
   _metaspace(NULL), _unloading(false), _klasses(NULL),
   _modules(NULL), _packages(NULL),
   _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL),
-  _next(NULL), _dependencies(dependencies), _shared_class_loader_id(-1),
+  _next(NULL), _dependencies(dependencies),
   _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
                             Monitor::_safepoint_check_never)) {
   TRACE_INIT_ID(this);
--- a/src/share/vm/classfile/classLoaderData.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/classLoaderData.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -204,9 +204,6 @@
   // Support for walking class loader data objects
   ClassLoaderData* _next; /// Next loader_datas created
 
-  // CDS
-  int _shared_class_loader_id;
-
   // ReadOnly and ReadWrite metaspaces (static because only on the null
   // class loader for now).
   static Metaspace* _ro_metaspace;
@@ -338,15 +335,6 @@
   Metaspace* rw_metaspace();
   void initialize_shared_metaspaces();
 
-  int shared_class_loader_id() const {
-    return _shared_class_loader_id;
-  }
-  void set_shared_class_loader_id(int id) {
-    assert(id >= 0, "sanity");
-    assert(_shared_class_loader_id <0, "cannot be assigned more than once");
-    _shared_class_loader_id = id;
-  }
-
   TRACE_DEFINE_TRACE_ID_METHODS;
 };
 
--- a/src/share/vm/classfile/dictionary.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/dictionary.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -61,7 +61,7 @@
   _pd_cache_table = new ProtectionDomainCacheTable(defaultProtectionDomainCacheSize);
 };
 
-ProtectionDomainCacheEntry* Dictionary::cache_get(oop protection_domain) {
+ProtectionDomainCacheEntry* Dictionary::cache_get(Handle protection_domain) {
   return _pd_cache_table->get(protection_domain);
 }
 
@@ -123,9 +123,9 @@
 }
 
 
-void DictionaryEntry::add_protection_domain(Dictionary* dict, oop protection_domain) {
+void DictionaryEntry::add_protection_domain(Dictionary* dict, Handle protection_domain) {
   assert_locked_or_safepoint(SystemDictionary_lock);
-  if (!contains_protection_domain(protection_domain)) {
+  if (!contains_protection_domain(protection_domain())) {
     ProtectionDomainCacheEntry* entry = dict->cache_get(protection_domain);
     ProtectionDomainEntry* new_head =
                 new ProtectionDomainEntry(entry, _pd_set);
@@ -454,7 +454,7 @@
   assert(protection_domain() != NULL,
          "real protection domain should be present");
 
-  entry->add_protection_domain(this, protection_domain());
+  entry->add_protection_domain(this, protection_domain);
 
   assert(entry->contains_protection_domain(protection_domain()),
          "now protection domain should be present");
@@ -505,11 +505,12 @@
 }
 
 
-unsigned int ProtectionDomainCacheTable::compute_hash(oop protection_domain) {
+unsigned int ProtectionDomainCacheTable::compute_hash(Handle protection_domain) {
+  // Identity hash can safepoint, so keep protection domain in a Handle.
   return (unsigned int)(protection_domain->identity_hash());
 }
 
-int ProtectionDomainCacheTable::index_for(oop protection_domain) {
+int ProtectionDomainCacheTable::index_for(Handle protection_domain) {
   return hash_to_index(compute_hash(protection_domain));
 }
 
@@ -619,7 +620,7 @@
   }
 }
 
-ProtectionDomainCacheEntry* ProtectionDomainCacheTable::get(oop protection_domain) {
+ProtectionDomainCacheEntry* ProtectionDomainCacheTable::get(Handle protection_domain) {
   unsigned int hash = compute_hash(protection_domain);
   int index = hash_to_index(hash);
 
@@ -630,9 +631,9 @@
   return entry;
 }
 
-ProtectionDomainCacheEntry* ProtectionDomainCacheTable::find_entry(int index, oop protection_domain) {
+ProtectionDomainCacheEntry* ProtectionDomainCacheTable::find_entry(int index, Handle protection_domain) {
   for (ProtectionDomainCacheEntry* e = bucket(index); e != NULL; e = e->next()) {
-    if (e->protection_domain() == protection_domain) {
+    if (e->protection_domain() == protection_domain()) {
       return e;
     }
   }
@@ -640,7 +641,7 @@
   return NULL;
 }
 
-ProtectionDomainCacheEntry* ProtectionDomainCacheTable::add_entry(int index, unsigned int hash, oop protection_domain) {
+ProtectionDomainCacheEntry* ProtectionDomainCacheTable::add_entry(int index, unsigned int hash, Handle protection_domain) {
   assert_locked_or_safepoint(SystemDictionary_lock);
   assert(index == index_for(protection_domain), "incorrect index?");
   assert(find_entry(index, protection_domain) == NULL, "no double entry");
@@ -651,7 +652,7 @@
 }
 
 void ProtectionDomainCacheTable::free(ProtectionDomainCacheEntry* to_delete) {
-  unsigned int hash = compute_hash(to_delete->protection_domain());
+  unsigned int hash = compute_hash(Handle(Thread::current(), to_delete->protection_domain()));
   int index = hash_to_index(hash);
 
   ProtectionDomainCacheEntry** p = bucket_addr(index);
--- a/src/share/vm/classfile/dictionary.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/dictionary.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, 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
@@ -128,7 +128,7 @@
   // Sharing support
   void reorder_dictionary();
 
-  ProtectionDomainCacheEntry* cache_get(oop protection_domain);
+  ProtectionDomainCacheEntry* cache_get(Handle protection_domain);
 
   void print(bool details = true);
 #ifdef ASSERT
@@ -194,23 +194,23 @@
     return (ProtectionDomainCacheEntry**) Hashtable<oop, mtClass>::bucket_addr(i);
   }
 
-  ProtectionDomainCacheEntry* new_entry(unsigned int hash, oop protection_domain) {
-    ProtectionDomainCacheEntry* entry = (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::new_entry(hash, protection_domain);
+  ProtectionDomainCacheEntry* new_entry(unsigned int hash, Handle protection_domain) {
+    ProtectionDomainCacheEntry* entry = (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::new_entry(hash, protection_domain());
     entry->init();
     return entry;
   }
 
-  static unsigned int compute_hash(oop protection_domain);
+  static unsigned int compute_hash(Handle protection_domain);
 
-  int index_for(oop protection_domain);
-  ProtectionDomainCacheEntry* add_entry(int index, unsigned int hash, oop protection_domain);
-  ProtectionDomainCacheEntry* find_entry(int index, oop protection_domain);
+  int index_for(Handle protection_domain);
+  ProtectionDomainCacheEntry* add_entry(int index, unsigned int hash, Handle protection_domain);
+  ProtectionDomainCacheEntry* find_entry(int index, Handle protection_domain);
 
 public:
 
   ProtectionDomainCacheTable(int table_size);
 
-  ProtectionDomainCacheEntry* get(oop protection_domain);
+  ProtectionDomainCacheEntry* get(Handle protection_domain);
   void free(ProtectionDomainCacheEntry* entry);
 
   void unlink(BoolObjectClosure* cl);
@@ -275,7 +275,7 @@
   // Tells whether a protection is in the approved set.
   bool contains_protection_domain(oop protection_domain) const;
   // Adds a protection domain to the approved set.
-  void add_protection_domain(Dictionary* dict, oop protection_domain);
+  void add_protection_domain(Dictionary* dict, Handle protection_domain);
 
   Klass* klass() const { return (Klass*)literal(); }
   Klass** klass_addr() { return (Klass**)literal_addr(); }
--- a/src/share/vm/classfile/javaClasses.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/javaClasses.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -163,8 +163,8 @@
 
   Klass* k = SystemDictionary::String_klass();
   compute_offset(value_offset,           k, vmSymbols::value_name(),  vmSymbols::byte_array_signature());
-  compute_optional_offset(hash_offset,   k, vmSymbols::hash_name(),   vmSymbols::int_signature());
-  compute_optional_offset(coder_offset,  k, vmSymbols::coder_name(),  vmSymbols::byte_signature());
+  compute_offset(hash_offset,            k, vmSymbols::hash_name(),   vmSymbols::int_signature());
+  compute_offset(coder_offset,           k, vmSymbols::coder_name(),  vmSymbols::byte_signature());
 
   initialized = true;
 }
@@ -2268,6 +2268,7 @@
   compute_offset(_monitors_offset,   k, vmSymbols::monitors_name(),    vmSymbols::object_array_signature());
   compute_offset(_locals_offset,     k, vmSymbols::locals_name(),      vmSymbols::object_array_signature());
   compute_offset(_operands_offset,   k, vmSymbols::operands_name(),    vmSymbols::object_array_signature());
+  compute_offset(_mode_offset,       k, vmSymbols::mode_name(),        vmSymbols::int_signature());
 }
 
 void java_lang_reflect_AccessibleObject::compute_offsets() {
@@ -3657,6 +3658,7 @@
 int java_lang_LiveStackFrameInfo::_monitors_offset;
 int java_lang_LiveStackFrameInfo::_locals_offset;
 int java_lang_LiveStackFrameInfo::_operands_offset;
+int java_lang_LiveStackFrameInfo::_mode_offset;
 int java_lang_AssertionStatusDirectives::classes_offset;
 int java_lang_AssertionStatusDirectives::classEnabled_offset;
 int java_lang_AssertionStatusDirectives::packages_offset;
@@ -3727,6 +3729,10 @@
   element->obj_field_put(_operands_offset, value);
 }
 
+void java_lang_LiveStackFrameInfo::set_mode(oop element, int value) {
+  element->int_field_put(_mode_offset, value);
+}
+
 // Support for java Assertions - java_lang_AssertionStatusDirectives.
 
 void java_lang_AssertionStatusDirectives::set_classes(oop o, oop val) {
@@ -3975,12 +3981,8 @@
   // java.lang.String
 
   CHECK_OFFSET("java/lang/String", java_lang_String, value, "[B");
-  if (java_lang_String::has_hash_field()) {
-    CHECK_OFFSET("java/lang/String", java_lang_String, hash, "I");
-  }
-  if (java_lang_String::has_coder_field()) {
-    CHECK_OFFSET("java/lang/String", java_lang_String, coder, "B");
-  }
+  CHECK_OFFSET("java/lang/String", java_lang_String, hash, "I");
+  CHECK_OFFSET("java/lang/String", java_lang_String, coder, "B");
 
   // java.lang.Class
 
--- a/src/share/vm/classfile/javaClasses.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/javaClasses.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -81,15 +81,6 @@
   static Handle create_from_platform_dependent_str(const char* str, TRAPS);
   static Handle char_converter(Handle java_string, jchar from_char, jchar to_char, TRAPS);
 
-  static bool has_hash_field()  {
-    assert(initialized, "Must be initialized");
-    return (hash_offset > 0);
-  }
-  static bool has_coder_field()  {
-    assert(initialized, "Must be initialized");
-    return (coder_offset > 0);
-  }
-
   static void set_compact_strings(bool value);
 
   static int value_offset_in_bytes()  {
@@ -1389,11 +1380,13 @@
   static int _monitors_offset;
   static int _locals_offset;
   static int _operands_offset;
+  static int _mode_offset;
 
  public:
   static void set_monitors(oop info, oop value);
   static void set_locals(oop info, oop value);
   static void set_operands(oop info, oop value);
+  static void set_mode(oop info, int value);
 
   static void compute_offsets();
 
--- a/src/share/vm/classfile/javaClasses.inline.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/javaClasses.inline.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -30,10 +30,8 @@
 #include "oops/oopsHierarchy.hpp"
 
 void java_lang_String::set_coder(oop string, jbyte coder) {
-  assert(initialized, "Must be initialized");
-  if (coder_offset > 0) {
-    string->byte_field_put(coder_offset, coder);
-  }
+  assert(initialized && (coder_offset > 0), "Must be initialized");
+  string->byte_field_put(coder_offset, coder);
 }
 
 void java_lang_String::set_value_raw(oop string, typeArrayOop buffer) {
@@ -61,15 +59,11 @@
   return java_string->int_field(hash_offset);
 }
 bool java_lang_String::is_latin1(oop java_string) {
-  assert(initialized, "Must be initialized");
+  assert(initialized && (coder_offset > 0), "Must be initialized");
   assert(is_instance(java_string), "must be java_string");
-  if (coder_offset > 0) {
-    jbyte coder = java_string->byte_field(coder_offset);
-    assert(CompactStrings || coder == CODER_UTF16, "Must be UTF16 without CompactStrings");
-    return coder == CODER_LATIN1;
-  } else {
-    return false;
-  }
+  jbyte coder = java_string->byte_field(coder_offset);
+  assert(CompactStrings || coder == CODER_UTF16, "Must be UTF16 without CompactStrings");
+  return coder == CODER_LATIN1;
 }
 int java_lang_String::length(oop java_string) {
   assert(initialized, "Must be initialized");
--- a/src/share/vm/classfile/modules.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/modules.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -39,8 +39,6 @@
 #include "logging/log.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/instanceKlass.hpp"
-#include "oops/objArrayKlass.hpp"
-#include "oops/objArrayOop.inline.hpp"
 #include "runtime/arguments.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/javaCalls.hpp"
@@ -48,17 +46,17 @@
 #include "utilities/stringUtils.hpp"
 #include "utilities/utf8.hpp"
 
-static bool verify_module_name(char *module_name) {
+static bool verify_module_name(const char *module_name) {
   if (module_name == NULL) return false;
   int len = (int)strlen(module_name);
   return (len > 0 && len <= Symbol::max_length());
 }
 
-bool Modules::verify_package_name(char *package_name) {
+bool Modules::verify_package_name(const char* package_name) {
   if (package_name == NULL) return false;
   int len = (int)strlen(package_name);
   return (len > 0 && len <= Symbol::max_length() &&
-    UTF8::is_legal_utf8((unsigned char *)package_name, len, false) &&
+    UTF8::is_legal_utf8((const unsigned char *)package_name, len, false) &&
     ClassFileParser::verify_unqualified_name(package_name, len,
     ClassFileParser::LegalClass));
 }
@@ -107,10 +105,8 @@
   return java_lang_reflect_Module::module_entry(module_h(), CHECK_NULL);
 }
 
-static PackageEntry* get_package_entry(ModuleEntry* module_entry, jstring package, TRAPS) {
+static PackageEntry* get_package_entry(ModuleEntry* module_entry, const char* package_name, TRAPS) {
   ResourceMark rm(THREAD);
-  if (package == NULL) return NULL;
-  const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package));
   if (package_name == NULL) return NULL;
   TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK_NULL);
   PackageEntryTable* package_entry_table = module_entry->loader_data()->packages();
@@ -139,7 +135,8 @@
 }
 
 static void define_javabase_module(jobject module, jstring version,
-                                   jstring location, jobjectArray packages, TRAPS) {
+                                   jstring location, const char* const* packages,
+                                   jsize num_packages, TRAPS) {
   ResourceMark rm(THREAD);
 
   Handle module_handle(THREAD, JNIHandles::resolve(module));
@@ -164,21 +161,12 @@
     }
   }
 
-  objArrayOop packages_oop = objArrayOop(JNIHandles::resolve(packages));
-  objArrayHandle packages_h(THREAD, packages_oop);
-  int num_packages = (packages_h == NULL ? 0 : packages_h->length());
 
   // Check that the list of packages has no duplicates and that the
   // packages are syntactically ok.
   GrowableArray<Symbol*>* pkg_list = new GrowableArray<Symbol*>(num_packages);
   for (int x = 0; x < num_packages; x++) {
-    oop string_obj = packages_h->obj_at(x);
-
-    if (string_obj == NULL || !string_obj->is_a(SystemDictionary::String_klass())) {
-      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
-                "Bad package name for module: " JAVA_BASE_NAME);
-    }
-    char *package_name = java_lang_String::as_utf8_string(string_obj);
+    const char *package_name = packages[x];
     if (!Modules::verify_package_name(package_name)) {
       THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
                 err_msg("Invalid package name: %s for module: " JAVA_BASE_NAME, package_name));
@@ -239,7 +227,7 @@
     }
   }
   if (duplicate_javabase) {
-    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+    THROW_MSG(vmSymbols::java_lang_InternalError(),
               "Module " JAVA_BASE_NAME " is already defined");
   }
 
@@ -262,13 +250,39 @@
   }
 }
 
+// Caller needs ResourceMark.
+void throw_dup_pkg_exception(const char* module_name, PackageEntry* package, TRAPS) {
+  const char* package_name = package->name()->as_C_string();
+  if (package->module()->is_named()) {
+    THROW_MSG(vmSymbols::java_lang_IllegalStateException(),
+      err_msg("Package %s for module %s is already in another module, %s, defined to the class loader",
+              package_name, module_name, package->module()->name()->as_C_string()));
+  } else {
+    THROW_MSG(vmSymbols::java_lang_IllegalStateException(),
+      err_msg("Package %s for module %s is already in the unnamed module defined to the class loader",
+              package_name, module_name));
+  }
+}
+
 void Modules::define_module(jobject module, jstring version,
-                            jstring location, jobjectArray packages, TRAPS) {
+                            jstring location, const char* const* packages,
+                            jsize num_packages, TRAPS) {
   ResourceMark rm(THREAD);
 
   if (module == NULL) {
     THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Null module object");
   }
+
+  if (num_packages < 0) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "num_packages must be >= 0");
+  }
+
+  if (packages == NULL && num_packages > 0) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "num_packages should be zero if packages is null");
+  }
+
   Handle module_handle(THREAD, JNIHandles::resolve(module));
   if (!java_lang_reflect_Module::is_instance(module_handle())) {
     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
@@ -283,7 +297,7 @@
 
   // Special handling of java.base definition
   if (strcmp(module_name, JAVA_BASE_NAME) == 0) {
-    define_javabase_module(module, version, location, packages, CHECK);
+    define_javabase_module(module, version, location, packages, num_packages, CHECK);
     return;
   }
 
@@ -297,21 +311,11 @@
   }
   Handle h_loader = Handle(THREAD, loader);
 
-  objArrayOop packages_oop = objArrayOop(JNIHandles::resolve(packages));
-  objArrayHandle packages_h(THREAD, packages_oop);
-  int num_packages = (packages_h == NULL ? 0 : packages_h->length());
-
   // Check that the list of packages has no duplicates and that the
   // packages are syntactically ok.
   GrowableArray<Symbol*>* pkg_list = new GrowableArray<Symbol*>(num_packages);
   for (int x = 0; x < num_packages; x++) {
-    oop string_obj = packages_h->obj_at(x);
-
-    if (string_obj == NULL || !string_obj->is_a(SystemDictionary::String_klass())) {
-      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
-                err_msg("Bad package name for module: %s", module_name));
-    }
-    char *package_name = java_lang_String::as_utf8_string(string_obj);
+    const char* package_name = packages[x];
     if (!verify_package_name(package_name)) {
       THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
                 err_msg("Invalid package name: %s for module: %s",
@@ -323,12 +327,15 @@
         !SystemDictionary::is_platform_class_loader(h_loader()) &&
         strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0) {
       const char* class_loader_name = SystemDictionary::loader_name(h_loader());
-      StringUtils::replace_no_expand(package_name, "/", ".");
+      size_t pkg_len = strlen(package_name);
+      char* pkg_name = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, pkg_len);
+      strncpy(pkg_name, package_name, pkg_len);
+      StringUtils::replace_no_expand(pkg_name, "/", ".");
       const char* msg_text1 = "Class loader (instance of): ";
       const char* msg_text2 = " tried to define prohibited package name: ";
-      size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + strlen(package_name) + 1;
+      size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + pkg_len + 1;
       char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, len);
-      jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, package_name);
+      jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, pkg_name);
       THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), message);
     }
 
@@ -347,7 +354,6 @@
   // Create symbol* entry for module name.
   TempNewSymbol module_symbol = SymbolTable::new_symbol(module_name, CHECK);
 
-  int dupl_pkg_index = -1;
   bool dupl_modules = false;
 
   // Create symbol* entry for module version.
@@ -373,6 +379,7 @@
   assert(loader_data != NULL, "class loader data shouldn't be null");
 
   PackageEntryTable* package_table = NULL;
+  PackageEntry* existing_pkg = NULL;
   {
     MutexLocker ml(Module_lock, THREAD);
 
@@ -382,13 +389,12 @@
 
       // Check that none of the packages exist in the class loader's package table.
       for (int x = 0; x < pkg_list->length(); x++) {
-        if (package_table->lookup_only(pkg_list->at(x)) != NULL) {
+        existing_pkg = package_table->lookup_only(pkg_list->at(x));
+        if (existing_pkg != NULL) {
           // This could be because the module was already defined.  If so,
           // report that error instead of the package error.
           if (module_table->lookup_only(module_symbol) != NULL) {
             dupl_modules = true;
-          } else {
-            dupl_pkg_index = x;
           }
           break;
         }
@@ -396,9 +402,8 @@
     }  // if (num_packages > 0)...
 
     // Add the module and its packages.
-    if (!dupl_modules && dupl_pkg_index == -1) {
+    if (!dupl_modules && existing_pkg == NULL) {
       // Create the entry for this module in the class loader's module entry table.
-
       ModuleEntry* module_entry = module_table->locked_create_entry_or_null(module_handle, module_symbol,
                                     version_symbol, location_symbol, loader_data);
 
@@ -426,13 +431,10 @@
 
   // any errors ?
   if (dupl_modules) {
-     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+     THROW_MSG(vmSymbols::java_lang_IllegalStateException(),
                err_msg("Module %s is already defined", module_name));
-  }
-  if (dupl_pkg_index != -1) {
-    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
-              err_msg("Package %s for module %s already exists for class loader",
-                      pkg_list->at(dupl_pkg_index)->as_C_string(), module_name));
+  } else if (existing_pkg != NULL) {
+      throw_dup_pkg_exception(module_name, existing_pkg, CHECK);
   }
 
   if (log_is_enabled(Debug, modules)) {
@@ -497,8 +499,8 @@
   java_lang_reflect_Module::set_module_entry(module_handle(), unnamed_module);
 }
 
-void Modules::add_module_exports(jobject from_module, jstring package, jobject to_module, TRAPS) {
-  if (package == NULL) {
+void Modules::add_module_exports(jobject from_module, const char* package_name, jobject to_module, TRAPS) {
+  if (package_name == NULL) {
     THROW_MSG(vmSymbols::java_lang_NullPointerException(),
               "package is null");
   }
@@ -526,10 +528,9 @@
     }
   }
 
-  PackageEntry *package_entry = get_package_entry(from_module_entry, package, CHECK);
+  PackageEntry *package_entry = get_package_entry(from_module_entry, package_name, CHECK);
   ResourceMark rm(THREAD);
   if (package_entry == NULL) {
-    const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package));
     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
               err_msg("Package %s not found in from_module %s",
                       package_name != NULL ? package_name : "",
@@ -557,7 +558,7 @@
 }
 
 
-void Modules::add_module_exports_qualified(jobject from_module, jstring package,
+void Modules::add_module_exports_qualified(jobject from_module, const char* package,
                                            jobject to_module, TRAPS) {
   if (to_module == NULL) {
     THROW_MSG(vmSymbols::java_lang_NullPointerException(),
@@ -649,21 +650,15 @@
 }
 
 
-jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRAPS) {
+jobject Modules::get_module_by_package_name(jobject loader, const char* package_name, TRAPS) {
   ResourceMark rm(THREAD);
   assert(ModuleEntryTable::javabase_defined(),
          "Attempt to call get_module_from_pkg before " JAVA_BASE_NAME " is defined");
 
-  if (NULL == package) {
+  if (package_name == NULL) {
     THROW_MSG_(vmSymbols::java_lang_NullPointerException(),
                "package is null", JNI_FALSE);
   }
-  const char* package_str =
-    java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package));
-  if (NULL == package_str) {
-    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
-               "Invalid package", JNI_FALSE);
-  }
 
   Handle h_loader (THREAD, JNIHandles::resolve(loader));
   // Check that loader is a subclass of java.lang.ClassLoader.
@@ -672,7 +667,7 @@
                "Class loader is not a subclass of java.lang.ClassLoader", JNI_FALSE);
   }
 
-  if (strlen(package_str) == 0) {
+  if (strlen(package_name) == 0) {
     // Return the unnamed module
     ModuleEntryTable* module_table = get_module_entry_table(h_loader, CHECK_NULL);
     if (NULL == module_table) return NULL;
@@ -680,24 +675,24 @@
     return JNIHandles::make_local(THREAD, JNIHandles::resolve(unnamed_module->module()));
 
   } else {
-    TempNewSymbol package_sym = SymbolTable::new_symbol(package_str, CHECK_NULL);
+    TempNewSymbol package_sym = SymbolTable::new_symbol(package_name, CHECK_NULL);
     return get_module(package_sym, h_loader, CHECK_NULL);
   }
   return NULL;
 }
 
 
-jobject Modules::get_named_module(Handle h_loader, const char* package_str, TRAPS) {
+jobject Modules::get_named_module(Handle h_loader, const char* package_name, TRAPS) {
   assert(ModuleEntryTable::javabase_defined(),
          "Attempt to call get_named_module before " JAVA_BASE_NAME " is defined");
   assert(h_loader.is_null() || java_lang_ClassLoader::is_subclass(h_loader->klass()),
          "Class loader is not a subclass of java.lang.ClassLoader");
-  assert(package_str != NULL, "the package_str should not be NULL");
+  assert(package_name != NULL, "the package_name should not be NULL");
 
-  if (strlen(package_str) == 0) {
+  if (strlen(package_name) == 0) {
     return NULL;
   }
-  TempNewSymbol package_sym = SymbolTable::new_symbol(package_str, CHECK_NULL);
+  TempNewSymbol package_sym = SymbolTable::new_symbol(package_name, CHECK_NULL);
   const PackageEntry* const pkg_entry =
     get_package_entry_by_name(package_sym, h_loader, THREAD);
   const ModuleEntry* const module_entry = (pkg_entry != NULL ? pkg_entry->module() : NULL);
@@ -723,14 +718,14 @@
   return NULL;
 }
 
-void Modules::add_module_package(jobject module, jstring package, TRAPS) {
+void Modules::add_module_package(jobject module, const char* package_name, TRAPS) {
   ResourceMark rm(THREAD);
 
   if (module == NULL) {
     THROW_MSG(vmSymbols::java_lang_NullPointerException(),
               "module is null");
   }
-  if (package == NULL) {
+  if (package_name == NULL) {
     THROW_MSG(vmSymbols::java_lang_NullPointerException(),
               "package is null");
   }
@@ -743,11 +738,6 @@
     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
               "module cannot be an unnamed module");
   }
-  char *package_name = java_lang_String::as_utf8_string(
-    JNIHandles::resolve_non_null(package));
-  if (package_name == NULL) {
-    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Bad package");
-  }
   if (!verify_package_name(package_name)) {
     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
               err_msg("Invalid package name: %s", package_name));
@@ -760,12 +750,15 @@
       !loader_data->is_platform_class_loader_data() &&
       strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0) {
     const char* class_loader_name = SystemDictionary::loader_name(loader_data);
-    StringUtils::replace_no_expand(package_name, "/", ".");
+    size_t pkg_len = strlen(package_name);
+    char* pkg_name = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, pkg_len);
+    strncpy(pkg_name, package_name, pkg_len);
+    StringUtils::replace_no_expand(pkg_name, "/", ".");
     const char* msg_text1 = "Class loader (instance of): ";
     const char* msg_text2 = " tried to define prohibited package name: ";
-    size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + strlen(package_name) + 1;
+    size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + pkg_len + 1;
     char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, len);
-    jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, package_name);
+    jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, pkg_name);
     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), message);
   }
 
@@ -776,31 +769,29 @@
   PackageEntryTable* package_table = loader_data->packages();
   assert(package_table != NULL, "Missing package_table");
 
-  bool pkg_exists = false;
+  PackageEntry* existing_pkg = NULL;
   {
     MutexLocker ml(Module_lock, THREAD);
 
     // Check that the package does not exist in the class loader's package table.
-    if (!package_table->lookup_only(pkg_symbol)) {
+    existing_pkg = package_table->lookup_only(pkg_symbol);
+    if (existing_pkg == NULL) {
       PackageEntry* pkg = package_table->locked_create_entry_or_null(pkg_symbol, module_entry);
       assert(pkg != NULL, "Unable to create a module's package entry");
-    } else {
-      pkg_exists = true;
     }
   }
-  if (pkg_exists) {
-    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
-              err_msg("Package %s already exists for class loader", package_name));
+  if (existing_pkg != NULL) {
+    throw_dup_pkg_exception(module_entry->name()->as_C_string(), existing_pkg, CHECK);
   }
 }
 
 // Export package in module to all unnamed modules.
-void Modules::add_module_exports_to_all_unnamed(jobject module, jstring package, TRAPS) {
+void Modules::add_module_exports_to_all_unnamed(jobject module, const char* package_name, TRAPS) {
   if (module == NULL) {
     THROW_MSG(vmSymbols::java_lang_NullPointerException(),
               "module is null");
   }
-  if (package == NULL) {
+  if (package_name == NULL) {
     THROW_MSG(vmSymbols::java_lang_NullPointerException(),
               "package is null");
   }
@@ -811,10 +802,9 @@
   }
 
   if (module_entry->is_named()) { // No-op for unnamed module.
-    PackageEntry *package_entry = get_package_entry(module_entry, package, CHECK);
+    PackageEntry *package_entry = get_package_entry(module_entry, package_name, CHECK);
     ResourceMark rm(THREAD);
     if (package_entry == NULL) {
-      const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package));
       THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
                 err_msg("Package %s not found in module %s",
                         package_name != NULL ? package_name : "",
@@ -833,10 +823,7 @@
                        package_entry->name()->as_C_string(),
                        module_entry->name()->as_C_string());
 
-    // Mark package as exported to all unnamed modules, unless already
-    // unqualifiedly exported.
-    if (!package_entry->is_unqual_exported()) {
-      package_entry->set_is_exported_allUnnamed();
-    }
+    // Mark package as exported to all unnamed modules.
+    package_entry->set_is_exported_allUnnamed();
   }
 }
--- a/src/share/vm/classfile/modules.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/modules.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -48,9 +48,12 @@
   // * Packages contains a duplicate package name
   // * A package already exists in another module for this class loader
   // * Module is an unnamed module
+  // * num_packages is negative
+  // * num_packages is non-zero when packages is null
   //  NullPointerExceptions are thrown if module is null.
   static void define_module(jobject module, jstring version,
-                            jstring location, jobjectArray packages, TRAPS);
+                            jstring location, const char* const* packages,
+                            jsize num_packages, TRAPS);
 
   // Provides the java.lang.reflect.Module for the unnamed module defined
   // to the boot loader.
@@ -72,7 +75,7 @@
   // * Package is not syntactically correct
   // * Package is not defined for from_module's class loader
   // * Package is not in module from_module.
-  static void add_module_exports(jobject from_module, jstring package, jobject to_module, TRAPS);
+  static void add_module_exports(jobject from_module, const char* package, jobject to_module, TRAPS);
 
   // This does a qualified export of package in module from_module to module
   // to_module.  The format for the package name must use "/' not ".".
@@ -83,7 +86,7 @@
   // * Package is not syntactically correct
   // * Package is not defined for from_module's class loader
   // * Package is not in module from_module.
-  static void add_module_exports_qualified(jobject from_module, jstring package, jobject to_module, TRAPS);
+  static void add_module_exports_qualified(jobject from_module, const char* package, jobject to_module, TRAPS);
 
   // add_reads_module adds module to_module to the list of modules that from_module
   // can read.  If from_module is the same as to_module then this is a no-op.
@@ -102,7 +105,7 @@
   // NullPointerException is thrown if package is null.
   // IllegalArgumentException is thrown if loader is neither null nor a subtype of
   // java/lang/ClassLoader.
-  static jobject get_module_by_package_name(jobject loader, jstring package, TRAPS);
+  static jobject get_module_by_package_name(jobject loader, const char* package, TRAPS);
   static jobject get_named_module(Handle h_loader, const char* package, TRAPS);
 
   // If package is defined by loader, return the
@@ -116,16 +119,16 @@
   // * Module is unnamed
   // * Package is not syntactically correct
   // * Package is already defined for module's class loader.
-  static void add_module_package(jobject module, jstring package, TRAPS);
+  static void add_module_package(jobject module, const char* package, TRAPS);
 
   // Marks the specified package as exported to all unnamed modules.
   // If either module or package is null then NullPointerException is thrown.
   // If module or package is bad, or module is unnamed, or package is not in
   // module then IllegalArgumentException is thrown.
-  static void add_module_exports_to_all_unnamed(jobject module, jstring package, TRAPS);
+  static void add_module_exports_to_all_unnamed(jobject module, const char* package, TRAPS);
 
   // Return TRUE if package_name is syntactically valid, false otherwise.
-  static bool verify_package_name(char *package_name);
+  static bool verify_package_name(const char *package_name);
 
   // Return TRUE iff package is defined by loader
   static bool is_package_defined(Symbol* package_name, Handle h_loader, TRAPS);
--- a/src/share/vm/classfile/packageEntry.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/packageEntry.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, 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
@@ -37,8 +37,8 @@
 
 // Returns true if this package specifies m as a qualified export, including through an unnamed export
 bool PackageEntry::is_qexported_to(ModuleEntry* m) const {
+  assert(Module_lock->owned_by_self(), "should have the Module_lock");
   assert(m != NULL, "No module to lookup in this package's qualified exports list");
-  MutexLocker m1(Module_lock);
   if (is_exported_allUnnamed() && !m->is_named()) {
     return true;
   } else if (!has_qual_exports_list()) {
@@ -98,15 +98,8 @@
   }
 
   if (m == NULL) {
-    // NULL indicates the package is being unqualifiedly exported
-    if (has_qual_exports_list()) {
-      // Legit to transition a package from being qualifiedly exported
-      // to unqualified.  Clean up the qualified lists at the next
-      // safepoint.
-      _exported_pending_delete = _qualified_exports;
-    }
-
-    // Mark package as unqualifiedly exported
+    // NULL indicates the package is being unqualifiedly exported.  Clean up
+    // the qualified list at the next safepoint.
     set_unqual_exported();
 
   } else {
@@ -115,14 +108,19 @@
   }
 }
 
+// Set the package as exported to all unnamed modules unless the package is
+// already unqualifiedly exported.
 void PackageEntry::set_is_exported_allUnnamed() {
   MutexLocker m1(Module_lock);
   if (!is_unqual_exported()) {
-   _is_exported_allUnnamed = true;
+   _export_flags = PKG_EXP_ALLUNNAMED;
   }
 }
 
-// Remove dead module entries within the package's exported list.
+// Remove dead module entries within the package's exported list.  Note that
+// if all of the modules on the _qualified_exports get purged the list does not
+// get deleted.  This prevents the package from illegally transitioning from
+// exported to non-exported.
 void PackageEntry::purge_qualified_exports() {
   assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
   if (_must_walk_exports &&
@@ -160,18 +158,9 @@
 
 void PackageEntry::delete_qualified_exports() {
   assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
-  if (_exported_pending_delete != NULL) {
-    // If a transition occurred from qualified to unqualified, the _qualified_exports
-    // field should have been NULL'ed out.
-    assert(_qualified_exports == NULL, "Package's exported pending delete, exported list should not be active");
-    delete _exported_pending_delete;
-  }
-
   if (_qualified_exports != NULL) {
     delete _qualified_exports;
   }
-
-  _exported_pending_delete = NULL;
   _qualified_exports = NULL;
 }
 
@@ -314,6 +303,11 @@
   }
 }
 
+bool PackageEntry::exported_pending_delete() const {
+  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
+  return (is_unqual_exported() && _qualified_exports != NULL);
+}
+
 // Remove dead entries from all packages' exported list
 void PackageEntryTable::purge_all_package_exports() {
   assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
@@ -344,13 +338,17 @@
   }
 }
 
+// This function may be called from debuggers so access private fields directly
+// to prevent triggering locking-related asserts that could result from calling
+// getter methods.
 void PackageEntry::print(outputStream* st) {
   ResourceMark rm;
   st->print_cr("package entry " PTR_FORMAT " name %s module %s classpath_index "
                INT32_FORMAT " is_exported_unqualified %d is_exported_allUnnamed %d " "next " PTR_FORMAT,
                p2i(this), name()->as_C_string(),
                (module()->is_named() ? module()->name()->as_C_string() : UNNAMED_MODULE),
-               _classpath_index, _is_exported_unqualified, _is_exported_allUnnamed, p2i(next()));
+               _classpath_index, _export_flags == PKG_EXP_UNQUALIFIED,
+               _export_flags == PKG_EXP_ALLUNNAMED, p2i(next()));
 }
 
 void PackageEntryTable::verify() {
--- a/src/share/vm/classfile/packageEntry.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/packageEntry.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, 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,8 +34,8 @@
 // A PackageEntry basically represents a Java package.  It contains:
 //   - Symbol* containing the package's name.
 //   - ModuleEntry* for this package's containing module.
-//   - a flag indicating if package is exported unqualifiedly
-//   - a flag indicating if this package is exported to all unnamed modules.
+//   - a field indicating if the package is exported unqualifiedly or to all
+//     unnamed modules.
 //   - a growable array containing other module entries that this
 //     package is exported to.
 //
@@ -44,9 +44,9 @@
 //   - qualified exports:   the package has been explicitly qualified to at least
 //                            one particular module or has been qualifiedly exported
 //                            to all unnamed modules.
-//                            Note: _is_exported_allUnnamed is a form of a qualified
-//                            export. It is equivalent to the package being
-//                            explicitly exported to all current and future unnamed modules.
+//                            Note: being exported to all unnamed is a form of a qualified
+//                            export. It is equivalent to the package being explicitly
+//                            exported to all current and future unnamed modules.
 //   - unqualified exports: the package is exported to all modules.
 //
 // A package can transition from:
@@ -56,21 +56,53 @@
 // A package cannot transition from:
 //   - being unqualifiedly exported, to exported qualifiedly to a specific module.
 //       This transition attempt is silently ignored in set_exported.
+//   - being qualifiedly exported to not exported.
+//       Because transitions are only allowed from less exposure to greater exposure,
+//       the transition from qualifiedly exported to not exported would be considered
+//       a backward direction.  Therefore the implementation considers a package as
+//       qualifiedly exported even if its export-list exists but is empty.
 //
 // The Mutex Module_lock is shared between ModuleEntry and PackageEntry, to lock either
 // data structure.
+
+// PKG_EXP_UNQUALIFIED and PKG_EXP_ALLUNNAMED indicate whether the package is
+// exported unqualifiedly or exported to all unnamed modules.  They are used to
+// set the value of _export_flags.  Field _export_flags and the _qualified_exports
+// list are used to determine a package's export state.
+// Valid states are:
+//
+//   1. Package is not exported
+//      _export_flags is zero and _qualified_exports is null
+//   2. Package is unqualifiedly exported
+//      _export_flags is set to PKG_EXP_UNQUALIFIED
+//      _qualified_exports may or may not be null depending on whether the package
+//        transitioned from qualifiedly exported to unqualifiedly exported.
+//   3. Package is qualifiedly exported
+//      _export_flags may be set to PKG_EXP_ALLUNNAMED if the package is also
+//        exported to all unnamed modules
+//      _qualified_exports will be non-null
+//   4. Package is exported to all unnamed modules
+//      _export_flags is set to PKG_EXP_ALLUNNAMED
+//      _qualified_exports may or may not be null depending on whether the package
+//        is also qualifiedly exported to one or more named modules.
+#define PKG_EXP_UNQUALIFIED  0x0001
+#define PKG_EXP_ALLUNNAMED   0x0002
+#define PKG_EXP_UNQUALIFIED_OR_ALL_UNAMED (PKG_EXP_UNQUALIFIED | PKG_EXP_ALLUNNAMED)
+
 class PackageEntry : public HashtableEntry<Symbol*, mtModule> {
 private:
   ModuleEntry* _module;
+  // Indicates if package is exported unqualifiedly or to all unnamed. Access to
+  // this field is protected by the Module_lock.
+  int _export_flags;
   // Used to indicate for packages with classes loaded by the boot loader that
   // a class in that package has been loaded.  And, for packages with classes
   // loaded by the boot loader from -Xbootclasspath/a in an unnamed module, it
   // indicates from which class path entry.
   s2 _classpath_index;
-  bool _is_exported_unqualified;
-  bool _is_exported_allUnnamed;
   bool _must_walk_exports;
-  GrowableArray<ModuleEntry*>* _exported_pending_delete; // transitioned from qualified to unqualified, delete at safepoint
+  // Contains list of modules this package is qualifiedly exported to.  Access
+  // to this list is protected by the Module_lock.
   GrowableArray<ModuleEntry*>* _qualified_exports;
   TRACE_DEFINE_TRACE_ID_FIELD;
 
@@ -80,17 +112,14 @@
 public:
   void init() {
     _module = NULL;
+    _export_flags = 0;
     _classpath_index = -1;
-    _is_exported_unqualified = false;
-    _is_exported_allUnnamed = false;
     _must_walk_exports = false;
-    _exported_pending_delete = NULL;
     _qualified_exports = NULL;
   }
 
   // package name
   Symbol*            name() const               { return literal(); }
-  void               set_name(Symbol* n)        { set_literal(n); }
 
   // the module containing the package definition
   ModuleEntry*       module() const             { return _module; }
@@ -98,37 +127,39 @@
 
   // package's export state
   bool is_exported() const { // qualifiedly or unqualifiedly exported
-      return (is_unqual_exported() || has_qual_exports_list() || is_exported_allUnnamed());
+    assert_locked_or_safepoint(Module_lock);
+    return ((_export_flags & PKG_EXP_UNQUALIFIED_OR_ALL_UNAMED) != 0) || has_qual_exports_list();
   }
   // Returns true if the package has any explicit qualified exports or is exported to all unnamed
   bool is_qual_exported() const {
+    assert_locked_or_safepoint(Module_lock);
     return (has_qual_exports_list() || is_exported_allUnnamed());
   }
-  // Returns true if there are any explicit qualified exports
+  // Returns true if there are any explicit qualified exports.  Note that even
+  // if the _qualified_exports list is now empty (because the modules that were
+  // on the list got gc-ed and deleted from the list) this method may still
+  // return true.
   bool has_qual_exports_list() const {
-    assert(!(_qualified_exports != NULL && _is_exported_unqualified),
-           "_qualified_exports set at same time as _is_exported_unqualified");
-    return (_qualified_exports != NULL);
+    assert_locked_or_safepoint(Module_lock);
+    return (!is_unqual_exported() && _qualified_exports != NULL);
   }
   bool is_exported_allUnnamed() const {
-    assert(!(_is_exported_allUnnamed && _is_exported_unqualified),
-           "_is_exported_allUnnamed set at same time as _is_exported_unqualified");
-    return _is_exported_allUnnamed;
+    assert_locked_or_safepoint(Module_lock);
+    return (_export_flags == PKG_EXP_ALLUNNAMED);
   }
   bool is_unqual_exported() const {
-    assert(!(_qualified_exports != NULL && _is_exported_unqualified),
-           "_qualified_exports set at same time as _is_exported_unqualified");
-    assert(!(_is_exported_allUnnamed && _is_exported_unqualified),
-           "_is_exported_allUnnamed set at same time as _is_exported_unqualified");
-    return _is_exported_unqualified;
+    assert_locked_or_safepoint(Module_lock);
+    return (_export_flags == PKG_EXP_UNQUALIFIED);
   }
+
+  // Explicitly set _export_flags to PKG_EXP_UNQUALIFIED and clear
+  // PKG_EXP_ALLUNNAMED, if it was set.
   void set_unqual_exported() {
     assert(Module_lock->owned_by_self(), "should have the Module_lock");
-    _is_exported_unqualified = true;
-    _is_exported_allUnnamed = false;
-    _qualified_exports = NULL;
+    _export_flags = PKG_EXP_UNQUALIFIED;
   }
-  bool exported_pending_delete() const     { return (_exported_pending_delete != NULL); }
+
+  bool exported_pending_delete() const;
 
   void set_exported(ModuleEntry* m);
 
--- a/src/share/vm/classfile/stackMapFrame.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/stackMapFrame.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -155,47 +155,8 @@
   return i;
 }
 
-bool StackMapFrame::has_flag_match_exception(
-    const StackMapFrame* target) const {
-  // We allow flags of {UninitThis} to assign to {} if-and-only-if the
-  // target frame does not depend upon the current type.
-  // This is slightly too strict, as we need only enforce that the
-  // slots that were initialized by the <init> (the things that were
-  // UninitializedThis before initialize_object() converted them) are unused.
-  // However we didn't save that information so we'll enforce this upon
-  // anything that might have been initialized.  This is a rare situation
-  // and javac never generates code that would end up here, but some profilers
-  // (such as NetBeans) might, when adding exception handlers in <init>
-  // methods to cover the invokespecial instruction.  See 7020118.
-
-  assert(max_locals() == target->max_locals() &&
-         stack_size() == target->stack_size(), "StackMap sizes must match");
-
-  VerificationType top = VerificationType::top_type();
-  VerificationType this_type = verifier()->current_type();
-
-  if (!flag_this_uninit() || target->flags() != 0) {
-    return false;
-  }
-
-  for (int i = 0; i < target->locals_size(); ++i) {
-    if (locals()[i] == this_type && target->locals()[i] != top) {
-      return false;
-    }
-  }
-
-  for (int i = 0; i < target->stack_size(); ++i) {
-    if (stack()[i] == this_type && target->stack()[i] != top) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
 bool StackMapFrame::is_assignable_to(
-    const StackMapFrame* target, bool is_exception_handler,
-    ErrorContext* ctx, TRAPS) const {
+    const StackMapFrame* target, ErrorContext* ctx, TRAPS) const {
   if (_max_locals != target->max_locals()) {
     *ctx = ErrorContext::locals_size_mismatch(
         _offset, (StackMapFrame*)this, (StackMapFrame*)target);
@@ -226,8 +187,7 @@
     return false;
   }
 
-  bool match_flags = (_flags | target->flags()) == target->flags();
-  if (match_flags || is_exception_handler && has_flag_match_exception(target)) {
+  if ((_flags | target->flags()) == target->flags()) {
     return true;
   } else {
     *ctx = ErrorContext::bad_flags(target->offset(),
--- a/src/share/vm/classfile/stackMapFrame.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/stackMapFrame.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -167,8 +167,7 @@
 
   // Return true if this stack map frame is assignable to target.
   bool is_assignable_to(
-      const StackMapFrame* target, bool is_exception_handler,
-      ErrorContext* ctx, TRAPS) const;
+      const StackMapFrame* target, ErrorContext* ctx, TRAPS) const;
 
   inline void set_mark() {
 #ifdef ASSERT
@@ -290,8 +289,6 @@
   int is_assignable_to(
     VerificationType* src, VerificationType* target, int32_t len, TRAPS) const;
 
-  bool has_flag_match_exception(const StackMapFrame* target) const;
-
   TypeOrigin stack_top_ctx();
 
   void print_on(outputStream* str) const;
--- a/src/share/vm/classfile/stackMapTable.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/stackMapTable.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -70,26 +70,25 @@
 
 bool StackMapTable::match_stackmap(
     StackMapFrame* frame, int32_t target,
-    bool match, bool update, bool handler, ErrorContext* ctx, TRAPS) const {
+    bool match, bool update, ErrorContext* ctx, TRAPS) const {
   int index = get_index_from_offset(target);
-  return match_stackmap(frame, target, index, match, update, handler, ctx, THREAD);
+  return match_stackmap(frame, target, index, match, update, ctx, THREAD);
 }
 
 // Match and/or update current_frame to the frame in stackmap table with
 // specified offset and frame index. Return true if the two frames match.
-// handler is true if the frame in stackmap_table is for an exception handler.
 //
-// The values of match and update are:                  _match__update__handler
+// The values of match and update are:                  _match__update
 //
-// checking a branch target:                             true   false   false
-// checking an exception handler:                        true   false   true
+// checking a branch target:                             true   false
+// checking an exception handler:                        true   false
 // linear bytecode verification following an
-// unconditional branch:                                 false  true    false
+// unconditional branch:                                 false  true
 // linear bytecode verification not following an
-// unconditional branch:                                 true   true    false
+// unconditional branch:                                 true   true
 bool StackMapTable::match_stackmap(
     StackMapFrame* frame, int32_t target, int32_t frame_index,
-    bool match, bool update, bool handler, ErrorContext* ctx, TRAPS) const {
+    bool match, bool update, ErrorContext* ctx, TRAPS) const {
   if (frame_index < 0 || frame_index >= _frame_count) {
     *ctx = ErrorContext::missing_stackmap(frame->offset());
     frame->verifier()->verify_error(
@@ -102,7 +101,7 @@
   if (match) {
     // Has direct control flow from last instruction, need to match the two
     // frames.
-    result = frame->is_assignable_to(stackmap_frame, handler,
+    result = frame->is_assignable_to(stackmap_frame,
         ctx, CHECK_VERIFY_(frame->verifier(), result));
   }
   if (update) {
@@ -126,7 +125,7 @@
     StackMapFrame* frame, int32_t target, TRAPS) const {
   ErrorContext ctx;
   bool match = match_stackmap(
-    frame, target, true, false, false, &ctx, CHECK_VERIFY(frame->verifier()));
+    frame, target, true, false, &ctx, CHECK_VERIFY(frame->verifier()));
   if (!match || (target < 0 || target >= _code_length)) {
     frame->verifier()->verify_error(ctx,
         "Inconsistent stackmap frames at branch target %d", target);
--- a/src/share/vm/classfile/stackMapTable.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/stackMapTable.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -60,12 +60,12 @@
   // specified offset. Return true if the two frames match.
   bool match_stackmap(
     StackMapFrame* current_frame, int32_t offset,
-    bool match, bool update, bool handler, ErrorContext* ctx, TRAPS) const;
+    bool match, bool update, ErrorContext* ctx, TRAPS) const;
   // Match and/or update current_frame to the frame in stackmap table with
   // specified offset and frame index. Return true if the two frames match.
   bool match_stackmap(
     StackMapFrame* current_frame, int32_t offset, int32_t frame_index,
-    bool match, bool update, bool handler, ErrorContext* ctx, TRAPS) const;
+    bool match, bool update, ErrorContext* ctx, TRAPS) const;
 
   // Check jump instructions. Make sure there are no uninitialized
   // instances on backward branch.
--- a/src/share/vm/classfile/systemDictionaryShared.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/systemDictionaryShared.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -29,7 +29,6 @@
 #include "classfile/dictionary.hpp"
 
 class ClassFileStream;
-class SerializeClosure;
 
 class SystemDictionaryShared: public SystemDictionary {
 public:
@@ -79,8 +78,6 @@
     return NULL;
   }
 
-  static void serialize(SerializeClosure* soc) {}
-
   // The (non-application) CDS implementation supports only classes in the boot
   // class loader, which ensures that the verification constraints are the same
   // during archive creation time and runtime. Thus we can do the constraint checks
--- a/src/share/vm/classfile/verifier.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/verifier.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -541,19 +541,13 @@
     stack_map_frame* sm_frame = sm_table->entries();
     streamIndentor si2(ss);
     int current_offset = -1;
-    // Subtract two from StackMapAttribute length because the length includes
-    // two bytes for number of table entries.
-    size_t sm_table_space = method->stackmap_data()->length() - 2;
+    address end_of_sm_table = (address)sm_table + method->stackmap_data()->length();
     for (u2 i = 0; i < sm_table->number_of_entries(); ++i) {
       ss->indent();
-      size_t sm_frame_size = sm_frame->size();
-      // If the size of the next stackmap exceeds the length of the entire
-      // stackmap table then print a truncated message and return.
-      if (sm_frame_size > sm_table_space) {
+      if (!sm_frame->verify((address)sm_frame, end_of_sm_table)) {
         sm_frame->print_truncated(ss, current_offset);
         return;
       }
-      sm_table_space -= sm_frame_size;
       sm_frame->print_on(ss, current_offset);
       ss->cr();
       current_offset += sm_frame->offset_delta();
@@ -1863,7 +1857,7 @@
       // If matched, current_frame will be updated by this method.
       bool matches = stackmap_table->match_stackmap(
         current_frame, this_offset, stackmap_index,
-        !no_control_flow, true, false, &ctx, CHECK_VERIFY_(this, 0));
+        !no_control_flow, true, &ctx, CHECK_VERIFY_(this, 0));
       if (!matches) {
         // report type error
         verify_error(ctx, "Instruction type does not match stack map");
@@ -1913,7 +1907,7 @@
       }
       ErrorContext ctx;
       bool matches = stackmap_table->match_stackmap(
-        new_frame, handler_pc, true, false, true, &ctx, CHECK_VERIFY(this));
+        new_frame, handler_pc, true, false, &ctx, CHECK_VERIFY(this));
       if (!matches) {
         verify_error(ctx, "Stack map does not match the one at "
             "exception handler %d", handler_pc);
--- a/src/share/vm/classfile/vmSymbols.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/classfile/vmSymbols.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -325,14 +325,8 @@
   template(java_lang_StackStreamFactory_AbstractStackWalker, "java/lang/StackStreamFactory$AbstractStackWalker") \
   template(doStackWalk_signature,                     "(JIIII)Ljava/lang/Object;")                \
   template(asPrimitive_name,                          "asPrimitive")                              \
-  template(asPrimitive_int_signature,                 "(I)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
-  template(asPrimitive_long_signature,                "(J)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
-  template(asPrimitive_short_signature,               "(S)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
-  template(asPrimitive_byte_signature,                "(B)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
-  template(asPrimitive_char_signature,                "(C)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
-  template(asPrimitive_float_signature,               "(F)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
-  template(asPrimitive_double_signature,              "(D)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
-  template(asPrimitive_boolean_signature,             "(Z)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
+  template(asPrimitive_int_signature,                 "(I)Ljava/lang/LiveStackFrame$PrimitiveSlot;") \
+  template(asPrimitive_long_signature,                "(J)Ljava/lang/LiveStackFrame$PrimitiveSlot;") \
                                                                                                   \
   /* common method and field names */                                                             \
   template(object_initializer_name,                   "<init>")                                   \
@@ -444,6 +438,7 @@
   template(monitors_name,                             "monitors")                                 \
   template(locals_name,                               "locals")                                   \
   template(operands_name,                             "operands")                                 \
+  template(mode_name,                                 "mode")                                     \
   template(oop_size_name,                             "oop_size")                                 \
   template(static_oop_field_count_name,               "static_oop_field_count")                   \
   template(protection_domain_name,                    "protection_domain")                        \
@@ -590,11 +585,11 @@
   template(java_lang_management_ThreadState,           "java/lang/management/ThreadState")                        \
   template(java_lang_management_MemoryUsage,           "java/lang/management/MemoryUsage")                        \
   template(java_lang_management_ThreadInfo,            "java/lang/management/ThreadInfo")                         \
+  template(jdk_internal_agent_Agent,                   "jdk/internal/agent/Agent")                                \
   template(sun_management_Sensor,                      "sun/management/Sensor")                                   \
-  template(sun_management_Agent,                       "sun/management/Agent")                                    \
+  template(sun_management_ManagementFactoryHelper,     "sun/management/ManagementFactoryHelper")                  \
   template(com_sun_management_internal_DiagnosticCommandImpl,  "com/sun/management/internal/DiagnosticCommandImpl")     \
   template(com_sun_management_internal_GarbageCollectorExtImpl,"com/sun/management/internal/GarbageCollectorExtImpl")   \
-  template(sun_management_ManagementFactoryHelper,     "sun/management/ManagementFactoryHelper")                  \
   template(getDiagnosticCommandMBean_name,             "getDiagnosticCommandMBean")                               \
   template(getDiagnosticCommandMBean_signature,        "()Lcom/sun/management/DiagnosticCommandMBean;")           \
   template(getGcInfoBuilder_name,                      "getGcInfoBuilder")                                        \
--- a/src/share/vm/code/codeCache.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/code/codeCache.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -149,16 +149,17 @@
   size_t total_size = non_nmethod_size + profiled_size + non_profiled_size;
   // Prepare error message
   const char* error = "Invalid code heap sizes";
-  err_msg message("NonNMethodCodeHeapSize (%zuK) + ProfiledCodeHeapSize (%zuK) + NonProfiledCodeHeapSize (%zuK) = %zuK",
+  err_msg message("NonNMethodCodeHeapSize (" SIZE_FORMAT "K) + ProfiledCodeHeapSize (" SIZE_FORMAT "K)"
+                  " + NonProfiledCodeHeapSize (" SIZE_FORMAT "K) = " SIZE_FORMAT "K",
           non_nmethod_size/K, profiled_size/K, non_profiled_size/K, total_size/K);
 
   if (total_size > cache_size) {
     // Some code heap sizes were explicitly set: total_size must be <= cache_size
-    message.append(" is greater than ReservedCodeCacheSize (%zuK).", cache_size/K);
+    message.append(" is greater than ReservedCodeCacheSize (" SIZE_FORMAT "K).", cache_size/K);
     vm_exit_during_initialization(error, message);
   } else if (all_set && total_size != cache_size) {
     // All code heap sizes were explicitly set: total_size must equal cache_size
-    message.append(" is not equal to ReservedCodeCacheSize (%zuK).", cache_size/K);
+    message.append(" is not equal to ReservedCodeCacheSize (" SIZE_FORMAT "K).", cache_size/K);
     vm_exit_during_initialization(error, message);
   }
 }
@@ -267,7 +268,7 @@
   uint min_code_cache_size = CodeCacheMinimumUseSpace DEBUG_ONLY(* 3);
   if (non_nmethod_size < (min_code_cache_size + code_buffers_size)) {
     vm_exit_during_initialization(err_msg(
-        "Not enough space in non-nmethod code heap to run VM: %zuK < %zuK",
+        "Not enough space in non-nmethod code heap to run VM: " SIZE_FORMAT "K < " SIZE_FORMAT "K",
         non_nmethod_size/K, (min_code_cache_size + code_buffers_size)/K));
   }
 
@@ -1210,7 +1211,7 @@
   CompiledMethodIterator iter;
   while(iter.next_alive()) {
     CompiledMethod* nm = iter.method();
-    if (nm->is_marked_for_deoptimization()) {
+    if (nm->is_marked_for_deoptimization() && !nm->is_not_entrant()) {
       nm->make_not_entrant();
     }
   }
--- a/src/share/vm/code/compiledMethod.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/code/compiledMethod.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -250,7 +250,11 @@
 
   address insts_begin() const { return code_begin(); }
   address insts_end() const { return stub_begin(); }
+  // Returns true if a given address is in the 'insts' section. The method
+  // insts_contains_inclusive() is end-inclusive.
   bool insts_contains(address addr) const { return insts_begin() <= addr && addr < insts_end(); }
+  bool insts_contains_inclusive(address addr) const { return insts_begin() <= addr && addr <= insts_end(); }
+
   int insts_size() const { return insts_end() - insts_begin(); }
 
   virtual address consts_begin() const = 0;
--- a/src/share/vm/code/nmethod.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/code/nmethod.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -1149,6 +1149,14 @@
   assert(state == zombie || state == not_entrant, "must be zombie or not_entrant");
   assert(!is_zombie(), "should not already be a zombie");
 
+  if (_state == state) {
+    // Avoid taking the lock if already in required state.
+    // This is safe from races because the state is an end-state,
+    // which the nmethod cannot back out of once entered.
+    // No need for fencing either.
+    return false;
+  }
+
   // Make sure neither the nmethod nor the method is flushed in case of a safepoint in code below.
   nmethodLocker nml(this);
   methodHandle the_method(method());
--- a/src/share/vm/compiler/compilerDefinitions.cpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/compiler/compilerDefinitions.cpp	Mon Feb 27 23:20:05 2017 +0100
@@ -23,6 +23,8 @@
  */
 
 #include "precompiled.hpp"
+#include "runtime/globals.hpp"
+#include "runtime/globals_extension.hpp"
 #include "compiler/compilerDefinitions.hpp"
 
 const char* compilertype2name_tab[compiler_number_of_types] = {
@@ -32,3 +34,82 @@
   "jvmci",
   "shark"
 };
+
+#if defined(COMPILER2) || defined(SHARK)
+CompLevel  CompLevel_highest_tier      = CompLevel_full_optimization;  // pure C2 and tiered or JVMCI and tiered
+#elif defined(COMPILER1)
+CompLevel  CompLevel_highest_tier      = CompLevel_simple;             // pure C1 or JVMCI
+#else
+CompLevel  CompLevel_highest_tier      = CompLevel_none;
+#endif
+
+#if defined(TIERED)
+CompLevel  CompLevel_initial_compile   = CompLevel_full_profile;        // tiered
+#elif defined(COMPILER1) || INCLUDE_JVMCI
+CompLevel  CompLevel_initial_compile   = CompLevel_simple;              // pure C1 or JVMCI
+#elif defined(COMPILER2) || defined(SHARK)
+CompLevel  CompLevel_initial_compile   = CompLevel_full_optimization;   // pure C2
+#else
+CompLevel  CompLevel_initial_compile   = CompLevel_none;
+#endif
+
+#if defined(COMPILER2)
+CompMode  Compilation_mode             = CompMode_server;
+#elif defined(COMPILER1)
+CompMode  Compilation_mode             = CompMode_client;
+#else
+CompMode  Compilation_mode             = CompMode_none;
+#endif
+
+#ifdef TIERED
+void set_client_compilation_mode() {
+  Compilation_mode = CompMode_client;
+  CompLevel_highest_tier = CompLevel_simple;
+  CompLevel_initial_compile = CompLevel_simple;
+  FLAG_SET_ERGO(bool, TieredCompilation, false);
+  FLAG_SET_ERGO(bool, ProfileInterpreter, false);
+#if INCLUDE_JVMCI
+  FLAG_SET_ERGO(bool, EnableJVMCI, false);
+  FLAG_SET_ERGO(bool, UseJVMCICompiler, false);
+#endif
+#if INCLUDE_AOT
+  FLAG_SET_ERGO(bool, UseAOT, false);
+#endif
+  if (FLAG_IS_DEFAULT(NeverActAsServerClassMachine)) {
+    FLAG_SET_ERGO(bool, NeverActAsServerClassMachine, true);
+  }
+  if (FLAG_IS_DEFAULT(InitialCodeCacheSize)) {
+    FLAG_SET_ERGO(uintx, InitialCodeCacheSize, 160*K);
+  }
+  if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) {
+    FLAG_SET_ERGO(uintx, ReservedCodeCacheSize, 32*M);
+  }
+  if (FLAG_IS_DEFAULT(NonProfiledCodeHeapSize)) {
+    FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, 27*M);
+  }
+  if (FLAG_IS_DEFAULT(ProfiledCodeHeapSize)) {
+    FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, 0);
+  }
+  if (FLAG_IS_DEFAULT(NonNMethodCodeHeapSize)) {
+    FLAG_SET_ERGO(uintx, NonNMethodCodeHeapSize, 5*M);
+  }
+  if (FLAG_IS_DEFAULT(CodeCacheExpansionSize)) {
+    FLAG_SET_ERGO(uintx, CodeCacheExpansionSize, 32*K);
+  }
+  if (FLAG_IS_DEFAULT(MetaspaceSize)) {
+    FLAG_SET_ERGO(size_t, MetaspaceSize, 12*M);
+  }
+  if (FLAG_IS_DEFAULT(MaxRAM)) {
+    FLAG_SET_ERGO(uint64_t, MaxRAM, 1ULL*G);
+  }
+  if (FLAG_IS_DEFAULT(CompileThreshold)) {
+    FLAG_SET_ERGO(intx, CompileThreshold, 1500);
+  }
+  if (FLAG_IS_DEFAULT(OnStackReplacePercentage)) {
+    FLAG_SET_ERGO(intx, OnStackReplacePercentage, 933);
+  }
+  if (FLAG_IS_DEFAULT(CICompilerCount)) {
+    FLAG_SET_ERGO(intx, CICompilerCount, 1);
+  }
+}
+#endif // TIERED
--- a/src/share/vm/compiler/compilerDefinitions.hpp	Mon Feb 27 12:41:41 2017 -0500
+++ b/src/share/vm/compiler/compilerDefinitions.hpp	Mon Feb 27 23:20:05 2017 +0100
@@ -54,27 +54,30 @@
   CompLevel_simple            = 1,         // C1
   CompLevel_limited_profile   = 2,         // C1, invocation & backedge counters
   CompLevel_full_profile      = 3,         // C1, invocation & backedge counters + mdo
-  CompLevel_full_optimization = 4,         // C2, Shark or JVMCI
+  CompLevel_full_optimization = 4          // C2, Shark or JVMCI
+};
 
-#if defined(COMPILER2) || defined(SHARK)
-  CompLevel_highest_tier      = CompLevel_full_optimization,  // pure C2 and tiered or JVMCI and tiered
-#elif defined(COMPILER1)
-  CompLevel_highest_tier      = CompLevel_simple,             // pure C1 or JVMCI
-#else
-  CompLevel_highest_tier      = CompLevel_none,
-#endif
+extern CompLevel CompLevel_highest_tier;
+extern CompLevel CompLevel_initial_compile;
 
-#if defined(TIERED)
-  CompLevel_initial_compile   = CompLevel_full_profile        // tiered
-#elif defined(COMPILER1) || INCLUDE_JVMCI
-  CompLevel_initial_compile   = CompLevel_simple              // pure C1 or JVMCI
-#elif defined(COMPILER2) || defined(SHARK)
-  CompLevel_initial_compile   = CompLevel_full_optimization   // pure C2
-#else
-  CompLevel_i