From 59d75fd5762a82812a412d4adeae7e842337cf69 Mon Sep 17 00:00:00 2001
From: Erik Joelsson <erikj@openjdk.org>
Date: Thu, 12 Dec 2019 19:35:57 +0000
Subject: [PATCH 01/12] 8235687: Contents/MacOS/libjli.dylib cannot be a
 symlink

Reviewed-by: tbell
---
 make/MacBundles.gmk | 32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/make/MacBundles.gmk b/make/MacBundles.gmk
index f2b7bbe97f4..0c5af57ed66 100644
--- a/make/MacBundles.gmk
+++ b/make/MacBundles.gmk
@@ -61,17 +61,15 @@ ifeq ($(call isTargetOs, macosx), true)
       FILES := $(call FindFiles, $(JRE_IMAGE_DIR)), \
   ))
 
-  $(JDK_MACOSX_CONTENTS_DIR)/MacOS/libjli.dylib:
-	$(call LogInfo, Creating link $(patsubst $(OUTPUTDIR)/%,%,$@))
-	$(call MakeTargetDir)
-	$(RM) $@
-	$(LN) -s ../Home/lib/libjli.dylib $@
+  $(eval $(call SetupCopyFiles, COPY_LIBJLI_JDK, \
+      FILES := $(JDK_IMAGE_DIR)/lib/libjli.dylib, \
+      DEST := $(JDK_MACOSX_CONTENTS_DIR)/MacOS, \
+  ))
 
-  $(JRE_MACOSX_CONTENTS_DIR)/MacOS/libjli.dylib:
-	$(call LogInfo, Creating link $(patsubst $(OUTPUTDIR)/%,%,$@))
-	$(call MakeTargetDir)
-	$(RM) $@
-	$(LN) -s ../Home/lib/libjli.dylib $@
+  $(eval $(call SetupCopyFiles, COPY_LIBJLI_JRE, \
+      FILES := $(JRE_IMAGE_DIR)/lib/libjli.dylib, \
+      DEST := $(JRE_MACOSX_CONTENTS_DIR)/MacOS, \
+  ))
 
   $(eval $(call SetupTextFileProcessing, BUILD_JDK_PLIST, \
       SOURCE_FILES := $(MACOSX_PLIST_SRC)/JDK-Info.plist, \
@@ -97,13 +95,19 @@ ifeq ($(call isTargetOs, macosx), true)
           @@VENDOR@@ => $(BUNDLE_VENDOR) , \
   ))
 
-  jdk-bundle: $(COPY_JDK_IMAGE) $(JDK_MACOSX_CONTENTS_DIR)/MacOS/libjli.dylib \
-      $(BUILD_JDK_PLIST)
+  $(SUPPORT_OUTPUTDIR)/images/_jdk_bundle_attribute_set: $(COPY_JDK_IMAGE)
 	$(SETFILE) -a B $(dir $(JDK_MACOSX_CONTENTS_DIR))
+	$(TOUCH) $@
 
-  jre-bundle: $(COPY_JRE_IMAGE) $(JRE_MACOSX_CONTENTS_DIR)/MacOS/libjli.dylib \
-      $(BUILD_JRE_PLIST)
+  $(SUPPORT_OUTPUTDIR)/images/_jre_bundle_attribute_set: $(COPY_JRE_IMAGE)
 	$(SETFILE) -a B $(dir $(JRE_MACOSX_CONTENTS_DIR))
+	$(TOUCH) $@
+
+  jdk-bundle: $(COPY_JDK_IMAGE) $(COPY_LIBJLI_JDK) \
+      $(BUILD_JDK_PLIST) $(SUPPORT_OUTPUTDIR)/images/_jdk_bundle_attribute_set
+
+  jre-bundle: $(COPY_JRE_IMAGE) $(COPY_LIBJLI_JRE) \
+      $(BUILD_JRE_PLIST) $(SUPPORT_OUTPUTDIR)/images/_jre_bundle_attribute_set
 
 else # Not macosx
 

From b9f62457b98d631d73063e9a46bef7fa6ea87b58 Mon Sep 17 00:00:00 2001
From: Erik Joelsson <erikj@openjdk.org>
Date: Thu, 12 Dec 2019 19:37:38 +0000
Subject: [PATCH 02/12] 8235686: Add more custom hooks in Bundles.gmk

Reviewed-by: tbell
---
 make/Bundles.gmk | 50 ++++++++++++++++++++++++++++++++++++------------
 1 file changed, 38 insertions(+), 12 deletions(-)

diff --git a/make/Bundles.gmk b/make/Bundles.gmk
index 6101e2b3123..170f46a9a6c 100644
--- a/make/Bundles.gmk
+++ b/make/Bundles.gmk
@@ -156,6 +156,12 @@ ifeq ($(call isTargetOs, macosx)+$(DEBUG_LEVEL), true+release)
   JRE_IMAGE_HOMEDIR := $(JRE_MACOSX_CONTENTS_DIR)/Home
   JDK_BUNDLE_SUBDIR :=
   JRE_BUNDLE_SUBDIR :=
+  # In certain situations, the JDK_IMAGE_DIR points to an image without the
+  # the symbols and demos. If so, the symobls and demos can be found in a
+  # separate image. These variables allow for overriding from a custom makefile.
+  JDK_SYMBOLS_IMAGE_DIR ?= $(JDK_IMAGE_DIR)
+  JDK_DEMOS_IMAGE_DIR ?= $(JDK_IMAGE_DIR)
+  JDK_DEMOS_IMAGE_HOMEDIR ?= $(JDK_DEMOS_IMAGE_DIR)/$(JDK_MACOSX_CONTENTS_SUBDIR)/Home
 else
   JDK_IMAGE_HOMEDIR := $(JDK_IMAGE_DIR)
   JRE_IMAGE_HOMEDIR := $(JRE_IMAGE_DIR)
@@ -165,6 +171,12 @@ else
     JDK_BUNDLE_SUBDIR := $(JDK_BUNDLE_SUBDIR)/$(DEBUG_LEVEL)
     JRE_BUNDLE_SUBDIR := $(JRE_BUNDLE_SUBDIR)/$(DEBUG_LEVEL)
   endif
+  # In certain situations, the JDK_IMAGE_DIR points to an image without the
+  # the symbols and demos. If so, the symobls and demos can be found in a
+  # separate image. These variables allow for overriding from a custom makefile.
+  JDK_SYMBOLS_IMAGE_DIR ?= $(JDK_IMAGE_DIR)
+  JDK_DEMOS_IMAGE_DIR ?= $(JDK_IMAGE_DIR)
+  JDK_DEMOS_IMAGE_HOMEDIR ?= $(JDK_DEMOS_IMAGE_DIR)
 endif
 
 ################################################################################
@@ -176,13 +188,24 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), )
   # There may be files with spaces in the names, so use ShellFindFiles
   # explicitly.
   ALL_JDK_FILES := $(call ShellFindFiles, $(JDK_IMAGE_DIR))
+  ifneq ($(JDK_IMAGE_DIR), $(JDK_SYMBOLS_IMAGE_DIR))
+    ALL_JDK_SYMBOLS_FILES := $(call ShellFindFiles, $(JDK_SYMBOLS_IMAGE_DIR))
+  else
+    ALL_JDK_SYMBOLS_FILES := $(ALL_JDK_FILES)
+  endif
+  ifneq ($(JDK_IMAGE_DIR), $(JDK_DEMOS_IMAGE_DIR))
+    ALL_JDK_DEMOS_FILES := $(call ShellFindFiles, $(JDK_DEMOS_IMAGE_DIR))
+  else
+    ALL_JDK_DEMOS_FILES := $(ALL_JDK_FILES)
+  endif
 
   # Create special filter rules when dealing with unzipped .dSYM directories on
   # macosx
   ifeq ($(call isTargetOs, macosx), true)
     ifeq ($(ZIP_EXTERNAL_DEBUG_SYMBOLS), false)
       JDK_SYMBOLS_EXCLUDE_PATTERN := $(addprefix %, \
-          $(call containing, .dSYM/, $(patsubst $(JDK_IMAGE_DIR)/%, %, $(ALL_JDK_FILES))))
+          $(call containing, .dSYM/, $(patsubst $(JDK_IMAGE_DIR)/%, %, \
+          $(ALL_JDK_SYMBOLS_FILES))))
     endif
   endif
 
@@ -203,12 +226,13 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), )
           $(filter-out \
               $(JDK_IMAGE_HOMEDIR)/demo/% \
               , \
-              $(ALL_JDK_FILES) \
+              $(ALL_JDK_SYMBOLS_FILES) \
           ) \
       ) \
       $(call FindFiles, $(SYMBOLS_IMAGE_DIR))
 
-  TEST_DEMOS_BUNDLE_FILES := $(filter $(JDK_IMAGE_HOMEDIR)/demo/%, $(ALL_JDK_FILES))
+  TEST_DEMOS_BUNDLE_FILES := $(filter $(JDK_DEMOS_IMAGE_HOMEDIR)/demo/%, \
+      $(ALL_JDK_DEMOS_FILES))
 
   ALL_JRE_FILES := $(call ShellFindFiles, $(JRE_IMAGE_DIR))
 
@@ -245,15 +269,17 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), )
 
   LEGACY_TARGETS += $(BUILD_JRE_BUNDLE)
 
-  $(eval $(call SetupBundleFile, BUILD_JDK_SYMBOLS_BUNDLE, \
-      BUNDLE_NAME := $(JDK_SYMBOLS_BUNDLE_NAME), \
-      FILES := $(JDK_SYMBOLS_BUNDLE_FILES), \
-      BASE_DIRS := $(JDK_IMAGE_DIR) $(wildcard $(SYMBOLS_IMAGE_DIR)), \
-      SUBDIR := $(JDK_BUNDLE_SUBDIR), \
-      UNZIP_DEBUGINFO := true, \
-  ))
+  ifeq ($(COPY_DEBUG_SYMBOLS), true)
+    $(eval $(call SetupBundleFile, BUILD_JDK_SYMBOLS_BUNDLE, \
+        BUNDLE_NAME := $(JDK_SYMBOLS_BUNDLE_NAME), \
+        FILES := $(JDK_SYMBOLS_BUNDLE_FILES), \
+        BASE_DIRS := $(JDK_SYMBOLS_IMAGE_DIR) $(wildcard $(SYMBOLS_IMAGE_DIR)), \
+        SUBDIR := $(JDK_BUNDLE_SUBDIR), \
+        UNZIP_DEBUGINFO := true, \
+    ))
 
-  PRODUCT_TARGETS += $(BUILD_JDK_SYMBOLS_BUNDLE)
+    PRODUCT_TARGETS += $(BUILD_JDK_SYMBOLS_BUNDLE)
+  endif
 
   # The demo bundle is only created to support client tests. Ideally it should
   # be built with the main test bundle, but since the prerequisites match
@@ -261,7 +287,7 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), )
   $(eval $(call SetupBundleFile, BUILD_TEST_DEMOS_BUNDLE, \
       BUNDLE_NAME := $(TEST_DEMOS_BUNDLE_NAME), \
       FILES := $(TEST_DEMOS_BUNDLE_FILES), \
-      BASE_DIRS := $(JDK_IMAGE_DIR), \
+      BASE_DIRS := $(JDK_DEMOS_IMAGE_DIR), \
       SUBDIR := $(JDK_BUNDLE_SUBDIR), \
   ))
 

From dbd4134c044bb14ab9c7483669d2e4e5c104ec9b Mon Sep 17 00:00:00 2001
From: Mikael Vidstedt <mikael@openjdk.org>
Date: Thu, 12 Dec 2019 12:45:03 -0800
Subject: [PATCH 03/12] 8235814: Add --enable-deprecated-ports=yes to all
 solaris and SPARC build profiles

Reviewed-by: erikj
---
 make/conf/jib-profiles.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js
index 08dc9aac8dd..b1193df965c 100644
--- a/make/conf/jib-profiles.js
+++ b/make/conf/jib-profiles.js
@@ -434,7 +434,7 @@ var getJibProfilesProfiles = function (input, common, data) {
             target_cpu: "x64",
             dependencies: ["devkit", "cups"],
             configure_args: concat(common.configure_args_64bit,
-                "--with-zlib=system", "--enable-dtrace"),
+                "--with-zlib=system", "--enable-dtrace", "--enable-deprecated-ports=yes"),
         },
 
         "solaris-sparcv9": {
@@ -442,7 +442,7 @@ var getJibProfilesProfiles = function (input, common, data) {
             target_cpu: "sparcv9",
             dependencies: ["devkit", "cups"],
             configure_args: concat(common.configure_args_64bit,
-                "--with-zlib=system", "--enable-dtrace"),
+                "--with-zlib=system", "--enable-dtrace", "--enable-deprecated-ports=yes"),
         },
 
         "windows-x64": {

From 7cdecd898148350eb420654c3fa7beb161bbd1f1 Mon Sep 17 00:00:00 2001
From: Brian Burkhalter <bpb@openjdk.org>
Date: Thu, 12 Dec 2019 13:43:07 -0800
Subject: [PATCH 04/12] 8235668: LineNumberReader#getLineNumber() returns wrong
 line number (one fewer) in Lucene test

Reviewed-by: alanb, rriggs
---
 .../share/classes/java/io/BufferedReader.java |  8 +--
 .../classes/java/io/LineNumberReader.java     |  6 +-
 test/jdk/java/io/LineNumberReader/Read.java   | 59 +------------------
 3 files changed, 8 insertions(+), 65 deletions(-)

diff --git a/src/java.base/share/classes/java/io/BufferedReader.java b/src/java.base/share/classes/java/io/BufferedReader.java
index ac271d62d3c..6825dc530e9 100644
--- a/src/java.base/share/classes/java/io/BufferedReader.java
+++ b/src/java.base/share/classes/java/io/BufferedReader.java
@@ -302,8 +302,6 @@ public class BufferedReader extends Reader {
      * (EOF).
      *
      * @param      ignoreLF  If true, the next '\n' will be skipped
-     * @param      term      Output: Whether a line terminator was encountered
-     *                       while reading the line; may be {@code null}.
      *
      * @return     A String containing the contents of the line, not including
      *             any line-termination characters, or null if the end of the
@@ -313,14 +311,13 @@ public class BufferedReader extends Reader {
      *
      * @throws     IOException  If an I/O error occurs
      */
-    String readLine(boolean ignoreLF, boolean[] term) throws IOException {
+    String readLine(boolean ignoreLF) throws IOException {
         StringBuilder s = null;
         int startChar;
 
         synchronized (lock) {
             ensureOpen();
             boolean omitLF = ignoreLF || skipLF;
-            if (term != null) term[0] = false;
 
         bufferLoop:
             for (;;) {
@@ -347,7 +344,6 @@ public class BufferedReader extends Reader {
                 for (i = nextChar; i < nChars; i++) {
                     c = cb[i];
                     if ((c == '\n') || (c == '\r')) {
-                        if (term != null) term[0] = true;
                         eol = true;
                         break charLoop;
                     }
@@ -393,7 +389,7 @@ public class BufferedReader extends Reader {
      * @see java.nio.file.Files#readAllLines
      */
     public String readLine() throws IOException {
-        return readLine(false, null);
+        return readLine(false);
     }
 
     /**
diff --git a/src/java.base/share/classes/java/io/LineNumberReader.java b/src/java.base/share/classes/java/io/LineNumberReader.java
index 1cfb90de2c9..bffda6e1c2c 100644
--- a/src/java.base/share/classes/java/io/LineNumberReader.java
+++ b/src/java.base/share/classes/java/io/LineNumberReader.java
@@ -25,6 +25,7 @@
 
 package java.io;
 
+
 /**
  * A buffered character-input stream that keeps track of line numbers.  This
  * class defines methods {@link #setLineNumber(int)} and {@link
@@ -199,10 +200,9 @@ public class LineNumberReader extends BufferedReader {
      */
     public String readLine() throws IOException {
         synchronized (lock) {
-            boolean[] term = new boolean[1];
-            String l = super.readLine(skipLF, term);
+            String l = super.readLine(skipLF);
             skipLF = false;
-            if (l != null && term[0])
+            if (l != null)
                 lineNumber++;
             return l;
         }
diff --git a/test/jdk/java/io/LineNumberReader/Read.java b/test/jdk/java/io/LineNumberReader/Read.java
index 7f8b93db4e3..0e1968b372f 100644
--- a/test/jdk/java/io/LineNumberReader/Read.java
+++ b/test/jdk/java/io/LineNumberReader/Read.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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,24 +22,16 @@
  */
 
 /* @test
-   @bug 4074875 4063511 8230342
+   @bug 4074875 4063511
    @summary Make sure LineNumberReader.read(char, int , int) will increase
             the linenumber correctly.
    */
 
-import java.io.IOException;
-import java.io.LineNumberReader;
-import java.io.StringReader;
-import java.util.function.Consumer;
+import java.io.*;
 
 public class Read {
 
     public static void main(String[] args) throws Exception {
-        testReadChars();
-        testEofs();
-    }
-
-    private static void testReadChars() throws Exception {
         String s = "aaaa\nbbb\n";
         char[] buf = new char[5];
         int n = 0;
@@ -57,49 +49,4 @@ public class Read {
             throw new Exception("Failed test: Expected line number: 2, got "
                                 + line);
     }
-
-    private static void testEofs() throws Exception {
-        String string = "first \n second";
-
-        Consumer<LineNumberReader> c = (LineNumberReader r) -> {
-            try {
-                while (r.read() != -1)
-                    continue;
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-        };
-        testEof(c, string, 1);
-
-        c = (LineNumberReader r) -> {
-            try {
-                char[] buf = new char[128];
-                while (r.read(buf) != -1)
-                    continue;
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-        };
-        testEof(c, string, 1);
-
-        c = (LineNumberReader r) -> {
-            try {
-                while (r.readLine() != null)
-                    continue;
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-        };
-        testEof(c, string, 1);
-    }
-
-    private static void testEof(Consumer<LineNumberReader> c, String s, int n)
-        throws Exception {
-        LineNumberReader r = new LineNumberReader(new StringReader(s));
-        c.accept(r);
-        int line;
-        if ((line = r.getLineNumber()) != n)
-            throw new Exception("Failed test: Expected line number: " + n  +
-                " , got " + line);
-    }
 }

From 8f4f088a1293e1d3cb0264861574214db289dd61 Mon Sep 17 00:00:00 2001
From: Jorn Vernee <jorn.vernee@oracle.com>
Date: Thu, 12 Dec 2019 22:59:57 +0000
Subject: [PATCH 05/12] 8234049: Implementation of Memory Access API
 (Incubator)

Co-authored-by: Vlaidmir Ivanov <vladimir.x.ivanov@oracle.com>
Reviewed-by: alanb, psandoz, chegar, rriggs, plevart, briangoetz, jrose, adinn, vlivanov
---
 make/common/Modules.gmk                       |   2 +
 make/gensrc/GensrcVarHandles.gmk              | 107 ++++
 src/hotspot/share/ci/ciField.cpp              |   4 +-
 .../invoke/AddressVarHandleGenerator.java     | 494 ++++++++++++++++
 .../java/lang/invoke/MethodHandleImpl.java    |  39 ++
 .../invoke/VarHandleMemoryAddressBase.java    |  63 ++
 .../classes/java/lang/invoke/VarHandles.java  |  50 ++
 .../X-VarHandleByteArrayView.java.template    |   7 +-
 ...X-VarHandleMemoryAddressView.java.template | 512 ++++++++++++++++
 .../share/classes/java/nio/Buffer.java        |  49 +-
 .../nio/ByteBufferAs-X-Buffer.java.template   |  27 +-
 .../nio/Direct-X-Buffer-bin.java.template     |  10 +-
 .../java/nio/Direct-X-Buffer.java.template    |  40 +-
 .../java/nio/Heap-X-Buffer.java.template      |  88 ++-
 .../classes/java/nio/MappedByteBuffer.java    |  14 +-
 .../classes/java/nio/StringCharBuffer.java    |   4 +-
 .../classes/java/nio/X-Buffer.java.template   |  21 +-
 .../internal/access/JavaLangInvokeAccess.java |  39 ++
 .../jdk/internal/access/JavaNioAccess.java    |  32 +
 .../access/foreign/MemoryAddressProxy.java    |  42 ++
 .../access/foreign/MemorySegmentProxy.java    |  35 ++
 .../access/foreign/UnmapperProxy.java         |  36 ++
 src/java.base/share/classes/module-info.java  |  17 +-
 .../classes/sun/nio/ch/FileChannelImpl.java   | 167 ++++--
 .../share/classes/sun/nio/ch/Util.java        |   9 +-
 .../jdk/incubator/foreign/AbstractLayout.java | 178 ++++++
 .../jdk/incubator/foreign/GroupLayout.java    | 210 +++++++
 .../jdk/incubator/foreign/MemoryAddress.java  | 111 ++++
 .../jdk/incubator/foreign/MemoryHandles.java  | 268 +++++++++
 .../jdk/incubator/foreign/MemoryLayout.java   | 445 ++++++++++++++
 .../jdk/incubator/foreign/MemoryLayouts.java  | 138 +++++
 .../jdk/incubator/foreign/MemorySegment.java  | 430 ++++++++++++++
 .../jdk/incubator/foreign/PaddingLayout.java  | 111 ++++
 .../jdk/incubator/foreign/SequenceLayout.java | 161 +++++
 .../jdk/incubator/foreign/ValueLayout.java    | 140 +++++
 .../jdk/incubator/foreign/package-info.java   |  90 +++
 .../foreign/unsafe/ForeignUnsafe.java         |  68 +++
 .../jdk/internal/foreign/LayoutPath.java      | 216 +++++++
 .../internal/foreign/MemoryAddressImpl.java   | 117 ++++
 .../jdk/internal/foreign/MemoryScope.java     | 119 ++++
 .../internal/foreign/MemorySegmentImpl.java   | 209 +++++++
 .../classes/jdk/internal/foreign/Utils.java   | 157 +++++
 .../share/classes/module-info.java            |  35 ++
 test/jdk/TEST.groups                          |   4 +
 test/jdk/java/foreign/TEST.properties         |  25 +
 test/jdk/java/foreign/TestArrays.java         | 145 +++++
 test/jdk/java/foreign/TestByteBuffer.java     | 555 ++++++++++++++++++
 .../jdk/java/foreign/TestLayoutConstants.java |  96 +++
 test/jdk/java/foreign/TestLayoutPaths.java    | 137 +++++
 test/jdk/java/foreign/TestLayouts.java        | 289 +++++++++
 test/jdk/java/foreign/TestMemoryAccess.java   | 459 +++++++++++++++
 .../jdk/java/foreign/TestMemoryAlignment.java | 137 +++++
 test/jdk/java/foreign/TestMemoryCopy.java     | 127 ++++
 test/jdk/java/foreign/TestNative.java         | 232 ++++++++
 test/jdk/java/foreign/TestSegments.java       | 196 +++++++
 test/jdk/java/foreign/TestSharedAccess.java   |  82 +++
 test/jdk/java/foreign/TestSlices.java         |  97 +++
 .../foreign/TestVarHandleCombinators.java     | 189 ++++++
 test/jdk/java/foreign/libNativeAccess.c       | 115 ++++
 59 files changed, 7849 insertions(+), 147 deletions(-)
 create mode 100644 src/java.base/share/classes/java/lang/invoke/AddressVarHandleGenerator.java
 create mode 100644 src/java.base/share/classes/java/lang/invoke/VarHandleMemoryAddressBase.java
 create mode 100644 src/java.base/share/classes/java/lang/invoke/X-VarHandleMemoryAddressView.java.template
 create mode 100644 src/java.base/share/classes/jdk/internal/access/foreign/MemoryAddressProxy.java
 create mode 100644 src/java.base/share/classes/jdk/internal/access/foreign/MemorySegmentProxy.java
 create mode 100644 src/java.base/share/classes/jdk/internal/access/foreign/UnmapperProxy.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/AbstractLayout.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/GroupLayout.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryAddress.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryHandles.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryLayout.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryLayouts.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemorySegment.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/PaddingLayout.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/SequenceLayout.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/ValueLayout.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/package-info.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/unsafe/ForeignUnsafe.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/LayoutPath.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MemoryAddressImpl.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MemoryScope.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MemorySegmentImpl.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/Utils.java
 create mode 100644 src/jdk.incubator.foreign/share/classes/module-info.java
 create mode 100644 test/jdk/java/foreign/TEST.properties
 create mode 100644 test/jdk/java/foreign/TestArrays.java
 create mode 100644 test/jdk/java/foreign/TestByteBuffer.java
 create mode 100644 test/jdk/java/foreign/TestLayoutConstants.java
 create mode 100644 test/jdk/java/foreign/TestLayoutPaths.java
 create mode 100644 test/jdk/java/foreign/TestLayouts.java
 create mode 100644 test/jdk/java/foreign/TestMemoryAccess.java
 create mode 100644 test/jdk/java/foreign/TestMemoryAlignment.java
 create mode 100644 test/jdk/java/foreign/TestMemoryCopy.java
 create mode 100644 test/jdk/java/foreign/TestNative.java
 create mode 100644 test/jdk/java/foreign/TestSegments.java
 create mode 100644 test/jdk/java/foreign/TestSharedAccess.java
 create mode 100644 test/jdk/java/foreign/TestSlices.java
 create mode 100644 test/jdk/java/foreign/TestVarHandleCombinators.java
 create mode 100644 test/jdk/java/foreign/libNativeAccess.c

diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk
index 55fc6efb668..a267eb38571 100644
--- a/make/common/Modules.gmk
+++ b/make/common/Modules.gmk
@@ -58,6 +58,7 @@ BOOT_MODULES += \
     java.rmi \
     java.security.sasl \
     java.xml \
+    jdk.incubator.foreign \
     jdk.internal.vm.ci \
     jdk.jfr \
     jdk.management \
@@ -162,6 +163,7 @@ DOCS_MODULES += \
     jdk.jsobject \
     jdk.jshell \
     jdk.jstatd \
+    jdk.incubator.foreign \
     jdk.localedata \
     jdk.management \
     jdk.management.agent \
diff --git a/make/gensrc/GensrcVarHandles.gmk b/make/gensrc/GensrcVarHandles.gmk
index 3ac86e1c275..fa9804c6014 100644
--- a/make/gensrc/GensrcVarHandles.gmk
+++ b/make/gensrc/GensrcVarHandles.gmk
@@ -159,6 +159,108 @@ endef
 
 ################################################################################
 
+################################################################################
+# Setup a rule for generating a VarHandleMemoryAddress java class
+# Param 1 - Variable declaration prefix
+# Param 2 - Type with first letter capitalized
+define GenerateVarHandleMemoryAddress
+
+  $1_Type := $2
+
+  $1_FILENAME := $(VARHANDLES_GENSRC_DIR)/VarHandleMemoryAddressAs$$($1_Type)s.java
+
+  ifeq ($$($1_Type), Byte)
+    $1_type := byte
+    $1_BoxType := $$($1_Type)
+
+    $1_rawType := $$($1_type)
+    $1_RawType := $$($1_Type)
+    $1_RawBoxType := $$($1_BoxType)
+
+    $1_ARGS += -Kbyte
+  endif
+
+  ifeq ($$($1_Type), Short)
+    $1_type := short
+    $1_BoxType := $$($1_Type)
+
+    $1_rawType := $$($1_type)
+    $1_RawType := $$($1_Type)
+    $1_RawBoxType := $$($1_BoxType)
+  endif
+
+  ifeq ($$($1_Type), Char)
+    $1_type := char
+    $1_BoxType := Character
+
+    $1_rawType := $$($1_type)
+    $1_RawType := $$($1_Type)
+    $1_RawBoxType := $$($1_BoxType)
+  endif
+
+  ifeq ($$($1_Type), Int)
+    $1_type := int
+    $1_BoxType := Integer
+
+    $1_rawType := $$($1_type)
+    $1_RawType := $$($1_Type)
+    $1_RawBoxType := $$($1_BoxType)
+
+    $1_ARGS += -KCAS
+    $1_ARGS += -KAtomicAdd
+    $1_ARGS += -KBitwise
+  endif
+
+  ifeq ($$($1_Type), Long)
+    $1_type := long
+    $1_BoxType := $$($1_Type)
+
+    $1_rawType := $$($1_type)
+    $1_RawType := $$($1_Type)
+    $1_RawBoxType := $$($1_BoxType)
+
+    $1_ARGS += -KCAS
+    $1_ARGS += -KAtomicAdd
+    $1_ARGS += -KBitwise
+  endif
+
+  ifeq ($$($1_Type), Float)
+    $1_type := float
+    $1_BoxType := $$($1_Type)
+
+    $1_rawType := int
+    $1_RawType := Int
+    $1_RawBoxType := Integer
+
+    $1_ARGS += -KCAS
+    $1_ARGS += -KfloatingPoint
+  endif
+
+  ifeq ($$($1_Type), Double)
+    $1_type := double
+    $1_BoxType := $$($1_Type)
+
+    $1_rawType := long
+    $1_RawType := Long
+    $1_RawBoxType := Long
+
+    $1_ARGS += -KCAS
+    $1_ARGS += -KfloatingPoint
+  endif
+
+  $$($1_FILENAME): $(VARHANDLES_SRC_DIR)/X-VarHandleMemoryAddressView.java.template $(BUILD_TOOLS_JDK)
+	$$(call MakeDir, $$(@D))
+	$(RM) $$@
+	$(TOOL_SPP) -nel -K$$($1_type) \
+	    -Dtype=$$($1_type) -DType=$$($1_Type) -DBoxType=$$($1_BoxType) \
+	    -DrawType=$$($1_rawType) -DRawType=$$($1_RawType) -DRawBoxType=$$($1_RawBoxType) \
+	    $$($1_ARGS) -i$$< -o$$@
+
+  GENSRC_VARHANDLES += $$($1_FILENAME)
+endef
+
+################################################################################
+
 # List the types to generate source for, with capitalized first letter
 VARHANDLES_TYPES := Boolean Byte Short Char Int Long Float Double Reference
 $(foreach t, $(VARHANDLES_TYPES), \
@@ -169,6 +271,11 @@ VARHANDLES_BYTE_ARRAY_TYPES := Short Char Int Long Float Double
 $(foreach t, $(VARHANDLES_BYTE_ARRAY_TYPES), \
   $(eval $(call GenerateVarHandleByteArray,VAR_HANDLE_BYTE_ARRAY_$t,$t)))
 
+# List the types to generate source for, with capitalized first letter
+VARHANDLES_MEMORY_ADDRESS_TYPES := Byte Short Char Int Long Float Double
+$(foreach t, $(VARHANDLES_MEMORY_ADDRESS_TYPES), \
+  $(eval $(call GenerateVarHandleMemoryAddress,VAR_HANDLE_MEMORY_ADDRESS_$t,$t)))
+
 GENSRC_JAVA_BASE += $(GENSRC_VARHANDLES)
 
 # Include custom extension post hook
diff --git a/src/hotspot/share/ci/ciField.cpp b/src/hotspot/share/ci/ciField.cpp
index 42bee032620..41bbde92f7a 100644
--- a/src/hotspot/share/ci/ciField.cpp
+++ b/src/hotspot/share/ci/ciField.cpp
@@ -219,7 +219,9 @@ static bool trust_final_non_static_fields(ciInstanceKlass* holder) {
     // Never trust strangely unstable finals:  System.out, etc.
     return false;
   // Even if general trusting is disabled, trust system-built closures in these packages.
-  if (holder->is_in_package("java/lang/invoke") || holder->is_in_package("sun/invoke"))
+  if (holder->is_in_package("java/lang/invoke") || holder->is_in_package("sun/invoke") ||
+      holder->is_in_package("jdk/internal/foreign") || holder->is_in_package("jdk/incubator/foreign") ||
+      holder->is_in_package("java/lang"))
     return true;
   // Trust VM unsafe anonymous classes. They are private API (jdk.internal.misc.Unsafe)
   // and can't be serialized, so there is no hacking of finals going on with them.
diff --git a/src/java.base/share/classes/java/lang/invoke/AddressVarHandleGenerator.java b/src/java.base/share/classes/java/lang/invoke/AddressVarHandleGenerator.java
new file mode 100644
index 00000000000..ca22fea39eb
--- /dev/null
+++ b/src/java.base/share/classes/java/lang/invoke/AddressVarHandleGenerator.java
@@ -0,0 +1,494 @@
+/*
+ * Copyright (c) 2019, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 java.lang.invoke;
+
+import jdk.internal.access.foreign.MemoryAddressProxy;
+import jdk.internal.misc.Unsafe;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
+import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
+import jdk.internal.vm.annotation.ForceInline;
+import sun.security.action.GetBooleanAction;
+import sun.security.action.GetPropertyAction;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL;
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE;
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;
+import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN;
+import static jdk.internal.org.objectweb.asm.Opcodes.BIPUSH;
+import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST;
+import static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD;
+import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0;
+import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_1;
+import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_2;
+import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_3;
+import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_4;
+import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_5;
+import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_M1;
+import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
+import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
+import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
+import static jdk.internal.org.objectweb.asm.Opcodes.LADD;
+import static jdk.internal.org.objectweb.asm.Opcodes.LALOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE;
+import static jdk.internal.org.objectweb.asm.Opcodes.LLOAD;
+import static jdk.internal.org.objectweb.asm.Opcodes.LMUL;
+import static jdk.internal.org.objectweb.asm.Opcodes.NEWARRAY;
+import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
+import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
+import static jdk.internal.org.objectweb.asm.Opcodes.DUP;
+import static jdk.internal.org.objectweb.asm.Opcodes.SIPUSH;
+import static jdk.internal.org.objectweb.asm.Opcodes.T_LONG;
+
+class AddressVarHandleGenerator {
+    private static final String DEBUG_DUMP_CLASSES_DIR_PROPERTY = "jdk.internal.foreign.ClassGenerator.DEBUG_DUMP_CLASSES_DIR";
+
+    private static final boolean DEBUG =
+        GetBooleanAction.privilegedGetProperty("jdk.internal.foreign.ClassGenerator.DEBUG");
+
+    private static final Class<?> BASE_CLASS = VarHandleMemoryAddressBase.class;
+
+    private static final HashMap<Class<?>, Class<?>> helperClassCache;
+
+    static {
+        helperClassCache = new HashMap<>();
+        helperClassCache.put(byte.class, VarHandleMemoryAddressAsBytes.class);
+        helperClassCache.put(short.class, VarHandleMemoryAddressAsShorts.class);
+        helperClassCache.put(char.class, VarHandleMemoryAddressAsChars.class);
+        helperClassCache.put(int.class, VarHandleMemoryAddressAsInts.class);
+        helperClassCache.put(long.class, VarHandleMemoryAddressAsLongs.class);
+        helperClassCache.put(float.class, VarHandleMemoryAddressAsFloats.class);
+        helperClassCache.put(double.class, VarHandleMemoryAddressAsDoubles.class);
+    }
+
+    private static final File DEBUG_DUMP_CLASSES_DIR;
+
+    static {
+        String path = GetPropertyAction.privilegedGetProperty(DEBUG_DUMP_CLASSES_DIR_PROPERTY);
+        if (path == null) {
+            DEBUG_DUMP_CLASSES_DIR = null;
+        } else {
+            DEBUG_DUMP_CLASSES_DIR = new File(path);
+        }
+    }
+
+    private static final Unsafe U = Unsafe.getUnsafe();
+
+    private final String implClassName;
+    private final int dimensions;
+    private final Class<?> carrier;
+    private final Class<?> helperClass;
+    private final VarForm form;
+
+    AddressVarHandleGenerator(Class<?> carrier, int dims) {
+        this.dimensions = dims;
+        this.carrier = carrier;
+        Class<?>[] components = new Class<?>[dimensions];
+        Arrays.fill(components, long.class);
+        this.form = new VarForm(BASE_CLASS, MemoryAddressProxy.class, carrier, components);
+        this.helperClass = helperClassCache.get(carrier);
+        this.implClassName = helperClass.getName().replace('.', '/') + dimensions;
+    }
+
+    /*
+     * Generate a VarHandle memory access factory.
+     * The factory has type (ZJJ[J)VarHandle.
+     */
+    MethodHandle generateHandleFactory() {
+        Class<?> implCls = generateClass();
+        try {
+            Class<?>[] components = new Class<?>[dimensions];
+            Arrays.fill(components, long.class);
+
+            VarForm form = new VarForm(implCls, MemoryAddressProxy.class, carrier, components);
+
+            MethodType constrType = MethodType.methodType(void.class, VarForm.class, boolean.class, long.class, long.class, long.class, long[].class);
+            MethodHandle constr = MethodHandles.Lookup.IMPL_LOOKUP.findConstructor(implCls, constrType);
+            constr = MethodHandles.insertArguments(constr, 0, form);
+            return constr;
+        } catch (Throwable ex) {
+            throw new AssertionError(ex);
+        }
+    }
+
+    /*
+     * Generate a specialized VarHandle class for given carrier
+     * and access coordinates.
+     */
+    Class<?> generateClass() {
+        BinderClassWriter cw = new BinderClassWriter();
+
+        if (DEBUG) {
+            System.out.println("Generating header implementation class");
+        }
+
+        cw.visit(52, ACC_PUBLIC | ACC_SUPER, implClassName, null, Type.getInternalName(BASE_CLASS), null);
+
+        //add dimension fields
+        for (int i = 0; i < dimensions; i++) {
+            cw.visitField(ACC_PRIVATE | ACC_FINAL, "dim" + i, "J", null, null);
+        }
+
+        addConstructor(cw);
+
+        addAccessModeTypeMethod(cw);
+
+        addStridesAccessor(cw);
+
+        addCarrierAccessor(cw);
+
+        for (VarHandle.AccessMode mode : VarHandle.AccessMode.values()) {
+            addAccessModeMethodIfNeeded(mode, cw);
+        }
+
+
+        cw.visitEnd();
+        byte[] classBytes = cw.toByteArray();
+        return defineClass(cw, classBytes);
+    }
+
+    void addConstructor(BinderClassWriter cw) {
+        MethodType constrType = MethodType.methodType(void.class, VarForm.class, boolean.class, long.class, long.class, long.class, long[].class);
+        MethodVisitor mv = cw.visitMethod(0, "<init>", constrType.toMethodDescriptorString(), null, null);
+        mv.visitCode();
+        //super call
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitVarInsn(ALOAD, 1);
+        mv.visitTypeInsn(CHECKCAST, Type.getInternalName(VarForm.class));
+        mv.visitVarInsn(ILOAD, 2);
+        mv.visitVarInsn(LLOAD, 3);
+        mv.visitVarInsn(LLOAD, 5);
+        mv.visitVarInsn(LLOAD, 7);
+        mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(BASE_CLASS), "<init>",
+                MethodType.methodType(void.class, VarForm.class, boolean.class, long.class, long.class, long.class).toMethodDescriptorString(), false);
+        //init dimensions
+        for (int i = 0 ; i < dimensions ; i++) {
+            mv.visitVarInsn(ALOAD, 0);
+            mv.visitVarInsn(ALOAD, 9);
+            mv.visitLdcInsn(i);
+            mv.visitInsn(LALOAD);
+            mv.visitFieldInsn(PUTFIELD, implClassName, "dim" + i, "J");
+        }
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+    }
+
+    void addAccessModeTypeMethod(BinderClassWriter cw) {
+        MethodType modeMethType = MethodType.methodType(MethodType.class, VarHandle.AccessMode.class);
+        MethodVisitor mv = cw.visitMethod(ACC_FINAL, "accessModeTypeUncached", modeMethType.toMethodDescriptorString(), null, null);
+        mv.visitCode();
+        mv.visitVarInsn(ALOAD, 1);
+        mv.visitFieldInsn(GETFIELD, Type.getInternalName(VarHandle.AccessMode.class), "at", Type.getDescriptor(VarHandle.AccessType.class));
+        mv.visitLdcInsn(cw.makeConstantPoolPatch(MemoryAddressProxy.class));
+        mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Class.class));
+        mv.visitLdcInsn(cw.makeConstantPoolPatch(carrier));
+        mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Class.class));
+
+        Class<?>[] dims = new Class<?>[dimensions];
+        Arrays.fill(dims, long.class);
+        mv.visitLdcInsn(cw.makeConstantPoolPatch(dims));
+        mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Class[].class));
+
+        mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(VarHandle.AccessType.class),
+                "accessModeType", MethodType.methodType(MethodType.class, Class.class, Class.class, Class[].class).toMethodDescriptorString(), false);
+
+        mv.visitInsn(ARETURN);
+
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+    }
+
+    void addAccessModeMethodIfNeeded(VarHandle.AccessMode mode, BinderClassWriter cw) {
+        String methName = mode.methodName();
+        MethodType methType = form.getMethodType(mode.at.ordinal())
+                .insertParameterTypes(0, BASE_CLASS);
+
+        try {
+            MethodType helperType = methType.insertParameterTypes(2, long.class);
+            if (dimensions > 0) {
+                helperType = helperType.dropParameterTypes(3, 3 + dimensions);
+            }
+            //try to resolve...
+            String helperMethodName = methName + "0";
+            MethodHandles.Lookup.IMPL_LOOKUP
+                    .findStatic(helperClass,
+                            helperMethodName,
+                            helperType);
+
+
+            MethodVisitor mv = cw.visitMethod(ACC_STATIC, methName, methType.toMethodDescriptorString(), null, null);
+            mv.visitAnnotation(Type.getDescriptor(ForceInline.class), true);
+            mv.visitCode();
+
+            mv.visitVarInsn(ALOAD, 0); // handle impl
+            mv.visitVarInsn(ALOAD, 1); // receiver
+
+            // offset calculation
+            int slot = 2;
+            mv.visitVarInsn(ALOAD, 0); // load recv
+            mv.visitFieldInsn(GETFIELD, Type.getInternalName(BASE_CLASS), "offset", "J");
+            for (int i = 0 ; i < dimensions ; i++) {
+                mv.visitVarInsn(ALOAD, 0); // load recv
+                mv.visitTypeInsn(CHECKCAST, implClassName);
+                mv.visitFieldInsn(GETFIELD, implClassName, "dim" + i, "J");
+                mv.visitVarInsn(LLOAD, slot);
+                mv.visitInsn(LMUL);
+                mv.visitInsn(LADD);
+                slot += 2;
+            }
+
+            for (int i = 2 + dimensions; i < methType.parameterCount() ; i++) {
+                Class<?> param = methType.parameterType(i);
+                mv.visitVarInsn(loadInsn(param), slot); // load index
+                slot += getSlotsForType(param);
+            }
+
+            //call helper
+            mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(helperClass), helperMethodName,
+                    helperType.toMethodDescriptorString(), false);
+
+            mv.visitInsn(returnInsn(helperType.returnType()));
+
+            mv.visitMaxs(0, 0);
+            mv.visitEnd();
+        } catch (ReflectiveOperationException ex) {
+            //not found, skip
+        }
+    }
+
+    void addStridesAccessor(BinderClassWriter cw) {
+        MethodVisitor mv = cw.visitMethod(ACC_FINAL, "strides", "()[J", null, null);
+        mv.visitCode();
+        iConstInsn(mv, dimensions);
+        mv.visitIntInsn(NEWARRAY, T_LONG);
+
+        for (int i = 0 ; i < dimensions ; i++) {
+            mv.visitInsn(DUP);
+            iConstInsn(mv, i);
+            mv.visitVarInsn(ALOAD, 0);
+            mv.visitFieldInsn(GETFIELD, implClassName, "dim" + i, "J");
+            mv.visitInsn(LASTORE);
+        }
+
+        mv.visitInsn(ARETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+    }
+
+    void addCarrierAccessor(BinderClassWriter cw) {
+        MethodVisitor mv = cw.visitMethod(ACC_FINAL, "carrier", "()Ljava/lang/Class;", null, null);
+        mv.visitCode();
+        mv.visitLdcInsn(cw.makeConstantPoolPatch(carrier));
+        mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Class.class));
+        mv.visitInsn(ARETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+    }
+
+    //where
+    private Class<?> defineClass(BinderClassWriter cw, byte[] classBytes) {
+        try {
+            if (DEBUG_DUMP_CLASSES_DIR != null) {
+                debugWriteClassToFile(classBytes);
+            }
+            Object[] patches = cw.resolvePatches(classBytes);
+            Class<?> c = U.defineAnonymousClass(BASE_CLASS, classBytes, patches);
+            return c;
+        } catch (Throwable e) {
+            debugPrintClass(classBytes);
+            throw e;
+        }
+    }
+
+    // shared code generation helpers
+
+    private static int getSlotsForType(Class<?> c) {
+        if (c == long.class || c == double.class) {
+            return 2;
+        }
+        return 1;
+    }
+
+    /**
+     * Emits an actual return instruction conforming to the given return type.
+     */
+    private int returnInsn(Class<?> type) {
+        return switch (LambdaForm.BasicType.basicType(type)) {
+            case I_TYPE -> Opcodes.IRETURN;
+            case J_TYPE -> Opcodes.LRETURN;
+            case F_TYPE -> Opcodes.FRETURN;
+            case D_TYPE -> Opcodes.DRETURN;
+            case L_TYPE -> Opcodes.ARETURN;
+            case V_TYPE -> RETURN;
+        };
+    }
+
+    private int loadInsn(Class<?> type) {
+        return switch (LambdaForm.BasicType.basicType(type)) {
+            case I_TYPE -> Opcodes.ILOAD;
+            case J_TYPE -> LLOAD;
+            case F_TYPE -> Opcodes.FLOAD;
+            case D_TYPE -> Opcodes.DLOAD;
+            case L_TYPE -> Opcodes.ALOAD;
+            case V_TYPE -> throw new IllegalStateException("Cannot load void");
+        };
+    }
+
+    private static void iConstInsn(MethodVisitor mv, int i) {
+        switch (i) {
+            case -1, 0, 1, 2, 3, 4, 5:
+                mv.visitInsn(ICONST_0 + i);
+                break;
+            default:
+                if(i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) {
+                    mv.visitIntInsn(BIPUSH, i);
+                } else if (i >= Short.MIN_VALUE && i <= Short.MAX_VALUE) {
+                    mv.visitIntInsn(SIPUSH, i);
+                } else {
+                    mv.visitLdcInsn(i);
+                }
+        }
+    }
+
+    // debug helpers
+
+    private static String debugPrintClass(byte[] classFile) {
+        ClassReader cr = new ClassReader(classFile);
+        StringWriter sw = new StringWriter();
+        cr.accept(new TraceClassVisitor(new PrintWriter(sw)), 0);
+        return sw.toString();
+    }
+
+    private void debugWriteClassToFile(byte[] classFile) {
+        File file = new File(DEBUG_DUMP_CLASSES_DIR, implClassName + ".class");
+
+        if (DEBUG) {
+            System.err.println("Dumping class " + implClassName + " to " + file);
+        }
+
+        try {
+            debugWriteDataToFile(classFile, file);
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to write class " + implClassName + " to file " + file);
+        }
+    }
+
+    private void debugWriteDataToFile(byte[] data, File file) {
+        if (file.exists()) {
+            file.delete();
+        }
+        if (file.exists()) {
+            throw new RuntimeException("Failed to remove pre-existing file " + file);
+        }
+
+        File parent = file.getParentFile();
+        if (!parent.exists()) {
+            parent.mkdirs();
+        }
+        if (!parent.exists()) {
+            throw new RuntimeException("Failed to create " + parent);
+        }
+        if (!parent.isDirectory()) {
+            throw new RuntimeException(parent + " is not a directory");
+        }
+
+        try (FileOutputStream fos = new FileOutputStream(file)) {
+            fos.write(data);
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to write class " + implClassName + " to file " + file);
+        }
+    }
+
+    static class BinderClassWriter extends ClassWriter {
+
+        private final ArrayList<ConstantPoolPatch> cpPatches = new ArrayList<>();
+        private int curUniquePatchIndex = 0;
+
+        BinderClassWriter() {
+            super(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
+        }
+
+        public String makeConstantPoolPatch(Object o) {
+            int myUniqueIndex = curUniquePatchIndex++;
+            String cpPlaceholder = "CONSTANT_PLACEHOLDER_" + myUniqueIndex;
+            int index = newConst(cpPlaceholder);
+            cpPatches.add(new ConstantPoolPatch(index, cpPlaceholder, o));
+            return cpPlaceholder;
+        }
+
+        public Object[] resolvePatches(byte[] classFile) {
+            if (cpPatches.isEmpty()) {
+                return null;
+            }
+
+            int size = ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
+
+            Object[] patches = new Object[size];
+            for (ConstantPoolPatch p : cpPatches) {
+                if (p.index >= size) {
+                    throw new InternalError("Failed to resolve constant pool patch entries");
+                }
+                patches[p.index] = p.value;
+            }
+
+            return patches;
+        }
+
+        static class ConstantPoolPatch {
+            final int index;
+            final String placeholder;
+            final Object value;
+
+            ConstantPoolPatch(int index, String placeholder, Object value) {
+                this.index = index;
+                this.placeholder = placeholder;
+                this.value = value;
+            }
+
+            @Override
+            public String toString() {
+                return "CpPatch/index="+index+",placeholder="+placeholder+",value="+value;
+            }
+        }
+    }
+}
diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
index 94d4ff79e7b..c1ee66b58d5 100644
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
@@ -41,6 +41,7 @@ import sun.invoke.util.VerifyType;
 import sun.invoke.util.Wrapper;
 
 import java.lang.reflect.Array;
+import java.nio.ByteOrder;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
@@ -1790,6 +1791,44 @@ abstract class MethodHandleImpl {
                                 invokerMethodTypes, callSiteMethodTypes);
             }
 
+            @Override
+            public VarHandle memoryAddressViewVarHandle(Class<?> carrier, long alignmentMask,
+                                                        ByteOrder order, long offset, long[] strides) {
+                return VarHandles.makeMemoryAddressViewHandle(carrier, alignmentMask, order, offset, strides);
+            }
+
+            @Override
+            public Class<?> memoryAddressCarrier(VarHandle handle) {
+                return checkMemAccessHandle(handle).carrier();
+            }
+
+            @Override
+            public long memoryAddressAlignmentMask(VarHandle handle) {
+                return checkMemAccessHandle(handle).alignmentMask;
+            }
+
+            @Override
+            public ByteOrder memoryAddressByteOrder(VarHandle handle) {
+                return checkMemAccessHandle(handle).be ?
+                        ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
+            }
+
+            @Override
+            public long memoryAddressOffset(VarHandle handle) {
+                return checkMemAccessHandle(handle).offset;
+            }
+
+            @Override
+            public long[] memoryAddressStrides(VarHandle handle) {
+                return checkMemAccessHandle(handle).strides();
+            }
+
+            private VarHandleMemoryAddressBase checkMemAccessHandle(VarHandle handle) {
+                if (!(handle instanceof VarHandleMemoryAddressBase)) {
+                    throw new IllegalArgumentException("Not a memory access varhandle: " + handle);
+                }
+                return (VarHandleMemoryAddressBase) handle;
+            }
         });
     }
 
diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandleMemoryAddressBase.java b/src/java.base/share/classes/java/lang/invoke/VarHandleMemoryAddressBase.java
new file mode 100644
index 00000000000..fc8dc9f6bb8
--- /dev/null
+++ b/src/java.base/share/classes/java/lang/invoke/VarHandleMemoryAddressBase.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 java.lang.invoke;
+
+/**
+ * Base class for memory access var handle implementations.
+ */
+abstract class VarHandleMemoryAddressBase extends VarHandle {
+
+    /** endianness **/
+    final boolean be;
+
+    /** access size (in bytes, computed from var handle carrier type) **/
+    final long length;
+
+    /** access offset (in bytes); must be compatible with {@code alignmentMask} **/
+    final long offset;
+
+    /** alignment constraint (in bytes, expressed as a bit mask) **/
+    final long alignmentMask;
+
+    VarHandleMemoryAddressBase(VarForm form, boolean be, long length, long offset, long alignmentMask) {
+        super(form);
+        this.be = be;
+        this.length = length;
+        this.offset = offset;
+        this.alignmentMask = alignmentMask;
+    }
+
+    static IllegalStateException newIllegalStateExceptionForMisalignedAccess(long address) {
+        return new IllegalStateException("Misaligned access at address: " + address);
+    }
+
+    /**
+     * Strides used for multi-dimensional access; each stride must be compatible with {@code alignmentMask}.
+     */
+    abstract long[] strides();
+
+    abstract Class<?> carrier();
+}
diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandles.java b/src/java.base/share/classes/java/lang/invoke/VarHandles.java
index 232daf76fcc..2a9c2d8868e 100644
--- a/src/java.base/share/classes/java/lang/invoke/VarHandles.java
+++ b/src/java.base/share/classes/java/lang/invoke/VarHandles.java
@@ -25,13 +25,26 @@
 
 package java.lang.invoke;
 
+import sun.invoke.util.Wrapper;
+
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
+import java.nio.ByteOrder;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
 
 final class VarHandles {
 
+    static ClassValue<ConcurrentMap<Integer, MethodHandle>> ADDRESS_FACTORIES = new ClassValue<>() {
+        @Override
+        protected ConcurrentMap<Integer, MethodHandle> computeValue(Class<?> type) {
+            return new ConcurrentHashMap<>();
+        }
+    };
+
     static VarHandle makeFieldHandle(MemberName f, Class<?> refc, Class<?> type, boolean isWriteAllowedOnFinalFields) {
         if (!f.isStatic()) {
             long foffset = MethodHandleNatives.objectFieldOffset(f);
@@ -279,6 +292,43 @@ final class VarHandles {
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * Creates a memory access VarHandle.
+     *
+     * Resulting VarHandle will take a memory address as first argument,
+     * and a certain number of coordinate {@code long} parameters, depending on the length
+     * of the {@code strides} argument array.
+     *
+     * Coordinates are multiplied with corresponding scale factors ({@code strides}) and added
+     * to a single fixed offset to compute an effective offset from the given MemoryAddress for the access.
+     *
+     * @param carrier the Java carrier type.
+     * @param alignmentMask alignment requirement to be checked upon access. In bytes. Expressed as a mask.
+     * @param byteOrder the byte order.
+     * @param offset a constant offset for the access.
+     * @param strides the scale factors with which to multiply given access coordinates.
+     * @return the created VarHandle.
+     */
+    static VarHandle makeMemoryAddressViewHandle(Class<?> carrier, long alignmentMask,
+                                                 ByteOrder byteOrder, long offset, long[] strides) {
+        if (!carrier.isPrimitive() || carrier == void.class || carrier == boolean.class) {
+            throw new IllegalArgumentException("Invalid carrier: " + carrier.getName());
+        }
+        long size = Wrapper.forPrimitiveType(carrier).bitWidth() / 8;
+        boolean be = byteOrder == ByteOrder.BIG_ENDIAN;
+
+        Map<Integer, MethodHandle> carrierFactory = ADDRESS_FACTORIES.get(carrier);
+        MethodHandle fac = carrierFactory.computeIfAbsent(strides.length,
+                dims -> new AddressVarHandleGenerator(carrier, dims)
+                            .generateHandleFactory());
+
+        try {
+            return (VarHandle)fac.invoke(be, size, offset, alignmentMask, strides);
+        } catch (Throwable ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
+
 //    /**
 //     * A helper program to generate the VarHandleGuards class with a set of
 //     * static guard methods each of which corresponds to a particular shape and
diff --git a/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template b/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template
index 81c9fcd0d01..f8e5de90419 100644
--- a/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template
+++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template
@@ -24,6 +24,8 @@
  */
 package java.lang.invoke;
 
+import jdk.internal.access.JavaNioAccess;
+import jdk.internal.access.SharedSecrets;
 import jdk.internal.misc.Unsafe;
 import jdk.internal.util.Preconditions;
 import jdk.internal.vm.annotation.ForceInline;
@@ -38,6 +40,8 @@ import static java.lang.invoke.MethodHandleStatics.UNSAFE;
 
 final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
 
+    static JavaNioAccess nioAccess = SharedSecrets.getJavaNioAccess();
+
     static final int ALIGN = $BoxType$.BYTES - 1;
 
 #if[floatingPoint]
@@ -529,6 +533,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
 
         @ForceInline
         static int index(ByteBuffer bb, int index) {
+            nioAccess.checkSegment(bb);
             return Preconditions.checkIndex(index, UNSAFE.getInt(bb, BUFFER_LIMIT) - ALIGN, null);
         }
 
@@ -536,7 +541,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
         static int indexRO(ByteBuffer bb, int index) {
             if (UNSAFE.getBoolean(bb, BYTE_BUFFER_IS_READ_ONLY))
                 throw new ReadOnlyBufferException();
-            return Preconditions.checkIndex(index, UNSAFE.getInt(bb, BUFFER_LIMIT) - ALIGN, null);
+            return index(bb, index);
         }
 
         @ForceInline
diff --git a/src/java.base/share/classes/java/lang/invoke/X-VarHandleMemoryAddressView.java.template b/src/java.base/share/classes/java/lang/invoke/X-VarHandleMemoryAddressView.java.template
new file mode 100644
index 00000000000..0e537ac0633
--- /dev/null
+++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandleMemoryAddressView.java.template
@@ -0,0 +1,512 @@
+/*
+ * Copyright (c) 2019, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 java.lang.invoke;
+
+import jdk.internal.access.foreign.MemoryAddressProxy;
+import jdk.internal.vm.annotation.ForceInline;
+
+import java.util.Objects;
+
+import static java.lang.invoke.MethodHandleStatics.UNSAFE;
+
+#warn
+
+final class VarHandleMemoryAddressAs$Type$s {
+
+    static final boolean BE = UNSAFE.isBigEndian();
+
+    static final int VM_ALIGN = $BoxType$.BYTES - 1;
+
+#if[floatingPoint]
+    @ForceInline
+    static $rawType$ convEndian(boolean big, $type$ v) {
+        $rawType$ rv = $Type$.$type$ToRaw$RawType$Bits(v);
+        return big == BE ? rv : $RawBoxType$.reverseBytes(rv);
+    }
+
+    @ForceInline
+    static $type$ convEndian(boolean big, $rawType$ rv) {
+        rv = big == BE ? rv : $RawBoxType$.reverseBytes(rv);
+        return $Type$.$rawType$BitsTo$Type$(rv);
+    }
+#else[floatingPoint]
+#if[byte]
+    @ForceInline
+    static $type$ convEndian(boolean big, $type$ n) {
+        return n;
+    }
+#else[byte]
+    @ForceInline
+    static $type$ convEndian(boolean big, $type$ n) {
+        return big == BE ? n : $BoxType$.reverseBytes(n);
+    }
+#end[byte]
+#end[floatingPoint]
+
+    @ForceInline
+    static MemoryAddressProxy checkAddress(Object obb, long offset, long length, boolean ro) {
+        MemoryAddressProxy oo = (MemoryAddressProxy)Objects.requireNonNull(obb);
+        oo.checkAccess(offset, length, ro);
+        return oo;
+    }
+    
+    @ForceInline
+    static long offset(MemoryAddressProxy bb, long offset, long alignmentMask) {
+        long address = offsetNoVMAlignCheck(bb, offset, alignmentMask);
+        if ((address & VM_ALIGN) != 0) {
+            throw VarHandleMemoryAddressBase.newIllegalStateExceptionForMisalignedAccess(address);
+        }
+        return address;
+    }
+
+    @ForceInline
+    static long offsetNoVMAlignCheck(MemoryAddressProxy bb, long offset, long alignmentMask) {
+        long base = bb.unsafeGetOffset();
+        long address = base + offset;
+        //note: the offset portion has already been aligned-checked, by construction
+        if ((base & alignmentMask) != 0) {
+            throw VarHandleMemoryAddressBase.newIllegalStateExceptionForMisalignedAccess(address);
+        }
+        return address;
+    }
+    
+    @ForceInline
+    static $type$ get0(VarHandleMemoryAddressBase handle, Object obb, long base) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, true);
+#if[floatingPoint]
+        $rawType$ rawValue = UNSAFE.get$RawType$Unaligned(
+                bb.unsafeGetBase(),
+                offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
+                handle.be);
+        return $Type$.$rawType$BitsTo$Type$(rawValue);
+#else[floatingPoint]
+#if[byte]
+        return UNSAFE.get$Type$(
+                bb.unsafeGetBase(),
+                offsetNoVMAlignCheck(bb, base, handle.alignmentMask));
+#else[byte]
+        return UNSAFE.get$Type$Unaligned(
+                bb.unsafeGetBase(),
+                offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
+                handle.be);
+#end[byte]
+#end[floatingPoint]
+    }
+
+    @ForceInline
+    static void set0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+#if[floatingPoint]
+        UNSAFE.put$RawType$Unaligned(
+                bb.unsafeGetBase(),
+                offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
+                $Type$.$type$ToRaw$RawType$Bits(value),
+                handle.be);
+#else[floatingPoint]
+#if[byte]
+        UNSAFE.put$Type$(
+                bb.unsafeGetBase(),
+                offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
+                value);
+#else[byte]
+        UNSAFE.put$Type$Unaligned(
+                bb.unsafeGetBase(),
+                offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
+                value,
+                handle.be);
+#end[byte]
+#end[floatingPoint]
+    }
+
+    @ForceInline
+    static $type$ getVolatile0(VarHandleMemoryAddressBase handle, Object obb, long base) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, true);
+        return convEndian(handle.be,
+                          UNSAFE.get$RawType$Volatile(
+                                  bb.unsafeGetBase(),
+                                  offset(bb, base, handle.alignmentMask)));
+    }
+
+    @ForceInline
+    static void setVolatile0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        UNSAFE.put$RawType$Volatile(
+                bb.unsafeGetBase(),
+                offset(bb, base, handle.alignmentMask),
+                convEndian(handle.be, value));
+    }
+
+    @ForceInline
+    static $type$ getAcquire0(VarHandleMemoryAddressBase handle, Object obb, long base) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, true);
+        return convEndian(handle.be,
+                          UNSAFE.get$RawType$Acquire(
+                                  bb.unsafeGetBase(),
+                                  offset(bb, base, handle.alignmentMask)));
+    }
+
+    @ForceInline
+    static void setRelease0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        UNSAFE.put$RawType$Release(
+                bb.unsafeGetBase(),
+                offset(bb, base, handle.alignmentMask),
+                convEndian(handle.be, value));
+    }
+
+    @ForceInline
+    static $type$ getOpaque0(VarHandleMemoryAddressBase handle, Object obb, long base) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, true);
+        return convEndian(handle.be,
+                          UNSAFE.get$RawType$Opaque(
+                                  bb.unsafeGetBase(),
+                                  offset(bb, base, handle.alignmentMask)));
+    }
+
+    @ForceInline
+    static void setOpaque0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        UNSAFE.put$RawType$Opaque(
+                bb.unsafeGetBase(),
+                offset(bb, base, handle.alignmentMask),
+                convEndian(handle.be, value));
+    }
+#if[CAS]
+
+    @ForceInline
+    static boolean compareAndSet0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ expected, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        return UNSAFE.compareAndSet$RawType$(
+                bb.unsafeGetBase(),
+                offset(bb, base, handle.alignmentMask),
+                convEndian(handle.be, expected), convEndian(handle.be, value));
+    }
+
+    @ForceInline
+    static $type$ compareAndExchange0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ expected, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        return convEndian(handle.be,
+                          UNSAFE.compareAndExchange$RawType$(
+                                  bb.unsafeGetBase(),
+                                  offset(bb, base, handle.alignmentMask),
+                                  convEndian(handle.be, expected), convEndian(handle.be, value)));
+    }
+
+    @ForceInline
+    static $type$ compareAndExchangeAcquire0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ expected, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        return convEndian(handle.be,
+                          UNSAFE.compareAndExchange$RawType$Acquire(
+                                  bb.unsafeGetBase(),
+                                  offset(bb, base, handle.alignmentMask),
+                                  convEndian(handle.be, expected), convEndian(handle.be, value)));
+    }
+
+    @ForceInline
+    static $type$ compareAndExchangeRelease0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ expected, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        return convEndian(handle.be,
+                          UNSAFE.compareAndExchange$RawType$Release(
+                                  bb.unsafeGetBase(),
+                                  offset(bb, base, handle.alignmentMask),
+                                  convEndian(handle.be, expected), convEndian(handle.be, value)));
+    }
+
+    @ForceInline
+    static boolean weakCompareAndSetPlain0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ expected, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        return UNSAFE.weakCompareAndSet$RawType$Plain(
+                bb.unsafeGetBase(),
+                offset(bb, base, handle.alignmentMask),
+                convEndian(handle.be, expected), convEndian(handle.be, value));
+    }
+
+    @ForceInline
+    static boolean weakCompareAndSet0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ expected, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        return UNSAFE.weakCompareAndSet$RawType$(
+                bb.unsafeGetBase(),
+                offset(bb, base, handle.alignmentMask),
+                convEndian(handle.be, expected), convEndian(handle.be, value));
+    }
+
+    @ForceInline
+    static boolean weakCompareAndSetAcquire0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ expected, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        return UNSAFE.weakCompareAndSet$RawType$Acquire(
+                bb.unsafeGetBase(),
+                offset(bb, base, handle.alignmentMask),
+                convEndian(handle.be, expected), convEndian(handle.be, value));
+    }
+
+    @ForceInline
+    static boolean weakCompareAndSetRelease0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ expected, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        return UNSAFE.weakCompareAndSet$RawType$Release(
+                bb.unsafeGetBase(),
+                offset(bb, base, handle.alignmentMask),
+                convEndian(handle.be, expected), convEndian(handle.be, value));
+    }
+
+    @ForceInline
+    static $type$ getAndSet0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        return convEndian(handle.be,
+                          UNSAFE.getAndSet$RawType$(
+                                  bb.unsafeGetBase(),
+                                  offset(bb, base, handle.alignmentMask),
+                                  convEndian(handle.be, value)));
+    }
+
+    @ForceInline
+    static $type$ getAndSetAcquire0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        return convEndian(handle.be,
+                          UNSAFE.getAndSet$RawType$Acquire(
+                                  bb.unsafeGetBase(),
+                                  offset(bb, base, handle.alignmentMask),
+                                  convEndian(handle.be, value)));
+    }
+
+    @ForceInline
+    static $type$ getAndSetRelease0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        return convEndian(handle.be,
+                          UNSAFE.getAndSet$RawType$Release(
+                                  bb.unsafeGetBase(),
+                                  offset(bb, base, handle.alignmentMask),
+                                  convEndian(handle.be, value)));
+    }
+#end[CAS]
+#if[AtomicAdd]
+
+    @ForceInline
+    static $type$ getAndAdd0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ delta) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        if (handle.be == BE) {
+            return UNSAFE.getAndAdd$RawType$(
+                    bb.unsafeGetBase(),
+                    offset(bb, base, handle.alignmentMask),
+                    delta);
+        } else {
+            return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta);
+        }
+    }
+
+    @ForceInline
+    static $type$ getAndAddAcquire0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ delta) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        if (handle.be == BE) {
+            return UNSAFE.getAndAdd$RawType$Acquire(
+                    bb.unsafeGetBase(),
+                    offset(bb, base, handle.alignmentMask),
+                    delta);
+        } else {
+            return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta);
+        }
+    }
+
+    @ForceInline
+    static $type$ getAndAddRelease0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ delta) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        if (handle.be == BE) {
+            return UNSAFE.getAndAdd$RawType$Release(
+                    bb.unsafeGetBase(),
+                    offset(bb, base, handle.alignmentMask),
+                    delta);
+        } else {
+            return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta);
+        }
+    }
+
+    @ForceInline
+    static $type$ getAndAddConvEndianWithCAS(MemoryAddressProxy bb, long offset, $type$ delta) {
+        $type$ nativeExpectedValue, expectedValue;
+        Object base = bb.unsafeGetBase();
+        do {
+            nativeExpectedValue = UNSAFE.get$RawType$Volatile(base, offset);
+            expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
+        } while (!UNSAFE.weakCompareAndSet$RawType$(base, offset,
+                nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue + delta)));
+        return expectedValue;
+    }
+#end[AtomicAdd]
+#if[Bitwise]
+
+    @ForceInline
+    static $type$ getAndBitwiseOr0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        if (handle.be == BE) {
+            return UNSAFE.getAndBitwiseOr$RawType$(
+                    bb.unsafeGetBase(),
+                    offset(bb, base, handle.alignmentMask),
+                    value);
+        } else {
+            return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
+        }
+    }
+
+    @ForceInline
+    static $type$ getAndBitwiseOrRelease0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        if (handle.be == BE) {
+            return UNSAFE.getAndBitwiseOr$RawType$Release(
+                    bb.unsafeGetBase(),
+                    offset(bb, base, handle.alignmentMask),
+                    value);
+        } else {
+            return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
+        }
+    }
+
+    @ForceInline
+    static $type$ getAndBitwiseOrAcquire0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        if (handle.be == BE) {
+            return UNSAFE.getAndBitwiseOr$RawType$Acquire(
+                    bb.unsafeGetBase(),
+                    offset(bb, base, handle.alignmentMask),
+                    value);
+        } else {
+            return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
+        }
+    }
+
+    @ForceInline
+    static $type$ getAndBitwiseOrConvEndianWithCAS(MemoryAddressProxy bb, long offset, $type$ value) {
+        $type$ nativeExpectedValue, expectedValue;
+        Object base = bb.unsafeGetBase();
+        do {
+            nativeExpectedValue = UNSAFE.get$RawType$Volatile(base, offset);
+            expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
+        } while (!UNSAFE.weakCompareAndSet$RawType$(base, offset,
+                nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue | value)));
+        return expectedValue;
+    }
+
+    @ForceInline
+    static $type$ getAndBitwiseAnd0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        if (handle.be == BE) {
+            return UNSAFE.getAndBitwiseAnd$RawType$(
+                    bb.unsafeGetBase(),
+                    offset(bb, base, handle.alignmentMask),
+                    value);
+        } else {
+            return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
+        }
+    }
+
+    @ForceInline
+    static $type$ getAndBitwiseAndRelease0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        if (handle.be == BE) {
+            return UNSAFE.getAndBitwiseAnd$RawType$Release(
+                    bb.unsafeGetBase(),
+                    offset(bb, base, handle.alignmentMask),
+                    value);
+        } else {
+            return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
+        }
+    }
+
+    @ForceInline
+    static $type$ getAndBitwiseAndAcquire0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        if (handle.be == BE) {
+            return UNSAFE.getAndBitwiseAnd$RawType$Acquire(
+                    bb.unsafeGetBase(),
+                    offset(bb, base, handle.alignmentMask),
+                    value);
+        } else {
+            return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
+        }
+    }
+
+    @ForceInline
+    static $type$ getAndBitwiseAndConvEndianWithCAS(MemoryAddressProxy bb, long offset, $type$ value) {
+        $type$ nativeExpectedValue, expectedValue;
+        Object base = bb.unsafeGetBase();
+        do {
+            nativeExpectedValue = UNSAFE.get$RawType$Volatile(base, offset);
+            expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
+        } while (!UNSAFE.weakCompareAndSet$RawType$(base, offset,
+                nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue & value)));
+        return expectedValue;
+    }
+
+
+    @ForceInline
+    static $type$ getAndBitwiseXor0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        if (handle.be == BE) {
+            return UNSAFE.getAndBitwiseXor$RawType$(
+                    bb.unsafeGetBase(),
+                    offset(bb, base, handle.alignmentMask),
+                    value);
+        } else {
+            return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
+        }
+    }
+
+    @ForceInline
+    static $type$ getAndBitwiseXorRelease0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        if (handle.be == BE) {
+            return UNSAFE.getAndBitwiseXor$RawType$Release(
+                    bb.unsafeGetBase(),
+                    offset(bb, base, handle.alignmentMask),
+                    value);
+        } else {
+            return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
+        }
+    }
+
+    @ForceInline
+    static $type$ getAndBitwiseXorAcquire0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
+        MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
+        if (handle.be == BE) {
+            return UNSAFE.getAndBitwiseXor$RawType$Acquire(
+                    bb.unsafeGetBase(),
+                    offset(bb, base, handle.alignmentMask),
+                    value);
+        } else {
+            return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
+        }
+    }
+
+    @ForceInline
+    static $type$ getAndBitwiseXorConvEndianWithCAS(MemoryAddressProxy bb, long offset, $type$ value) {
+        $type$ nativeExpectedValue, expectedValue;
+        Object base = bb.unsafeGetBase();
+        do {
+            nativeExpectedValue = UNSAFE.get$RawType$Volatile(base, offset);
+            expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
+        } while (!UNSAFE.weakCompareAndSet$RawType$(base, offset,
+                nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue ^ value)));
+        return expectedValue;
+    }
+#end[Bitwise]
+}
diff --git a/src/java.base/share/classes/java/nio/Buffer.java b/src/java.base/share/classes/java/nio/Buffer.java
index bd903736d9d..45eebed4a4d 100644
--- a/src/java.base/share/classes/java/nio/Buffer.java
+++ b/src/java.base/share/classes/java/nio/Buffer.java
@@ -28,7 +28,9 @@ package java.nio;
 import jdk.internal.HotSpotIntrinsicCandidate;
 import jdk.internal.access.JavaNioAccess;
 import jdk.internal.access.SharedSecrets;
+import jdk.internal.access.foreign.MemorySegmentProxy;
 import jdk.internal.misc.Unsafe;
+import jdk.internal.vm.annotation.ForceInline;
 
 import java.util.Spliterator;
 
@@ -213,13 +215,26 @@ public abstract class Buffer {
     // NOTE: hoisted here for speed in JNI GetDirectBufferAddress
     long address;
 
+    // Used by buffers generated by the memory access API (JEP-370)
+    final MemorySegmentProxy segment;
+
+
+    // Creates a new buffer with given address and capacity.
+    //
+    Buffer(long addr, int cap, MemorySegmentProxy segment) {
+        this.address = addr;
+        this.capacity = cap;
+        this.segment = segment;
+    }
+
     // Creates a new buffer with the given mark, position, limit, and capacity,
     // after checking invariants.
     //
-    Buffer(int mark, int pos, int lim, int cap) {       // package-private
+    Buffer(int mark, int pos, int lim, int cap, MemorySegmentProxy segment) {       // package-private
         if (cap < 0)
             throw createCapacityException(cap);
         this.capacity = cap;
+        this.segment = segment;
         limit(lim);
         position(pos);
         if (mark >= 0) {
@@ -731,6 +746,13 @@ public abstract class Buffer {
         mark = -1;
     }
 
+    @ForceInline
+    final void checkSegment() {
+        if (segment != null) {
+            segment.checkValidState();
+        }
+    }
+
     static {
         // setup access to this package in SharedSecrets
         SharedSecrets.setJavaNioAccess(
@@ -739,6 +761,31 @@ public abstract class Buffer {
                 public JavaNioAccess.BufferPool getDirectBufferPool() {
                     return Bits.BUFFER_POOL;
                 }
+
+                @Override
+                public ByteBuffer newDirectByteBuffer(long addr, int cap, Object obj, MemorySegmentProxy segment) {
+                    return new DirectByteBuffer(addr, cap, obj, segment);
+                }
+
+                @Override
+                public ByteBuffer newHeapByteBuffer(byte[] hb, int offset, int capacity, MemorySegmentProxy segment) {
+                    return new HeapByteBuffer(hb, offset, capacity, segment);
+                }
+
+                @Override
+                public Object getBufferBase(ByteBuffer bb) {
+                    return bb.base();
+                }
+
+                @Override
+                public long getBufferAddress(ByteBuffer bb) {
+                    return bb.address;
+                }
+
+                @Override
+                public void checkSegment(Buffer buffer) {
+                    buffer.checkSegment();
+                }
             });
     }
 
diff --git a/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template b/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template
index 6278b466de5..55d356505d0 100644
--- a/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template
+++ b/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template
@@ -28,6 +28,7 @@
 package java.nio;
 
 import java.util.Objects;
+import jdk.internal.access.foreign.MemorySegmentProxy;
 import jdk.internal.misc.Unsafe;
 
 class ByteBufferAs$Type$Buffer$RW$$BO$                  // package-private
@@ -40,11 +41,11 @@ class ByteBufferAs$Type$Buffer$RW$$BO$                  // package-private
 
 #end[rw]
 
-    ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb) {   // package-private
+    ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb, MemorySegmentProxy segment) {   // package-private
 #if[rw]
         super(-1, 0,
               bb.remaining() >> $LG_BYTES_PER_VALUE$,
-              bb.remaining() >> $LG_BYTES_PER_VALUE$);
+              bb.remaining() >> $LG_BYTES_PER_VALUE$, segment);
         this.bb = bb;
         // enforce limit == capacity
         int cap = this.capacity();
@@ -53,21 +54,21 @@ class ByteBufferAs$Type$Buffer$RW$$BO$                  // package-private
         assert (pos <= cap);
         address = bb.address;
 #else[rw]
-        super(bb);
+        super(bb, segment);
 #end[rw]
     }
 
     ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb,
                                      int mark, int pos, int lim, int cap,
-                                     long addr)
+                                     long addr, MemorySegmentProxy segment)
     {
 #if[rw]
-        super(mark, pos, lim, cap);
+        super(mark, pos, lim, cap, segment);
         this.bb = bb;
         address = addr;
         assert address >= bb.address;
 #else[rw]
-        super(bb, mark, pos, lim, cap, addr);
+        super(bb, mark, pos, lim, cap, addr, segment);
 #end[rw]
     }
 
@@ -82,7 +83,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$                  // package-private
         assert (pos <= lim);
         int rem = (pos <= lim ? lim - pos : 0);
         long addr = byteOffset(pos);
-        return new ByteBufferAs$Type$Buffer$RW$$BO$(bb, -1, 0, rem, rem, addr);
+        return new ByteBufferAs$Type$Buffer$RW$$BO$(bb, -1, 0, rem, rem, addr, segment);
     }
 
     @Override
@@ -93,7 +94,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$                  // package-private
                                                     0,
                                                     length,
                                                     length,
-                                                    byteOffset(index));
+                                                    byteOffset(index), segment);
     }
 
     public $Type$Buffer duplicate() {
@@ -102,7 +103,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$                  // package-private
                                                     this.position(),
                                                     this.limit(),
                                                     this.capacity(),
-                                                    address);
+                                                    address, segment);
     }
 
     public $Type$Buffer asReadOnlyBuffer() {
@@ -112,7 +113,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$                  // package-private
                                                  this.position(),
                                                  this.limit(),
                                                  this.capacity(),
-                                                 address);
+                                                 address, segment);
 #else[rw]
         return duplicate();
 #end[rw]
@@ -130,12 +131,14 @@ class ByteBufferAs$Type$Buffer$RW$$BO$                  // package-private
     }
 
     public $type$ get() {
+        checkSegment();
         $memtype$ x = UNSAFE.get$Memtype$Unaligned(bb.hb, byteOffset(nextGetIndex()),
             {#if[boB]?true:false});
         return $fromBits$(x);
     }
 
     public $type$ get(int i) {
+        checkSegment();
         $memtype$ x = UNSAFE.get$Memtype$Unaligned(bb.hb, byteOffset(checkIndex(i)),
             {#if[boB]?true:false});
         return $fromBits$(x);
@@ -153,6 +156,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$                  // package-private
 
     public $Type$Buffer put($type$ x) {
 #if[rw]
+        checkSegment();
         $memtype$ y = $toBits$(x);
         UNSAFE.put$Memtype$Unaligned(bb.hb, byteOffset(nextPutIndex()), y,
             {#if[boB]?true:false});
@@ -164,6 +168,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$                  // package-private
 
     public $Type$Buffer put(int i, $type$ x) {
 #if[rw]
+        checkSegment();
         $memtype$ y = $toBits$(x);
         UNSAFE.put$Memtype$Unaligned(bb.hb, byteOffset(checkIndex(i)), y,
             {#if[boB]?true:false});
@@ -237,7 +242,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$                  // package-private
                                                   pos + start,
                                                   pos + end,
                                                   capacity(),
-                                                  address);
+                                                  address, segment);
     }
 
 #end[char]
diff --git a/src/java.base/share/classes/java/nio/Direct-X-Buffer-bin.java.template b/src/java.base/share/classes/java/nio/Direct-X-Buffer-bin.java.template
index a6fed522fa4..d6e0f58e0c3 100644
--- a/src/java.base/share/classes/java/nio/Direct-X-Buffer-bin.java.template
+++ b/src/java.base/share/classes/java/nio/Direct-X-Buffer-bin.java.template
@@ -33,6 +33,7 @@ class XXX {
 
     private $type$ get$Type$(long a) {
         try {
+            checkSegment();
             $memtype$ x = UNSAFE.get$Memtype$Unaligned(null, a, bigEndian);
             return $fromBits$(x);
         } finally {
@@ -61,6 +62,7 @@ class XXX {
     private ByteBuffer put$Type$(long a, $type$ x) {
 #if[rw]
         try {
+            checkSegment();
             $memtype$ y = $toBits$(x);
             UNSAFE.put$Memtype$Unaligned(null, a, y, bigEndian);
         } finally {
@@ -104,13 +106,13 @@ class XXX {
                                                                        0,
                                                                        size,
                                                                        size,
-                                                                       address + off))
+                                                                       address + off, segment))
                     : ($Type$Buffer)(new ByteBufferAs$Type$Buffer$RW$L(this,
                                                                        -1,
                                                                        0,
                                                                        size,
                                                                        size,
-                                                                       address + off)));
+                                                                       address + off, segment)));
         } else {
             return (nativeByteOrder
                     ? ($Type$Buffer)(new Direct$Type$Buffer$RW$U(this,
@@ -118,13 +120,13 @@ class XXX {
                                                                  0,
                                                                  size,
                                                                  size,
-                                                                 off))
+                                                                 off, segment))
                     : ($Type$Buffer)(new Direct$Type$Buffer$RW$S(this,
                                                                  -1,
                                                                  0,
                                                                  size,
                                                                  size,
-                                                                 off)));
+                                                                 off, segment)));
         }
     }
 
diff --git a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template
index cd68cc80f10..5ec4db04e5f 100644
--- a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template
+++ b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template
@@ -30,6 +30,7 @@ package java.nio;
 import java.io.FileDescriptor;
 import java.lang.ref.Reference;
 import java.util.Objects;
+import jdk.internal.access.foreign.MemorySegmentProxy;
 import jdk.internal.misc.VM;
 import jdk.internal.ref.Cleaner;
 import sun.nio.ch.DirectBuffer;
@@ -112,7 +113,7 @@ class Direct$Type$Buffer$RW$$BO$
     //
     Direct$Type$Buffer$RW$(int cap) {                   // package-private
 #if[rw]
-        super(-1, 0, cap, cap);
+        super(-1, 0, cap, cap, null);
         boolean pa = VM.isDirectMemoryPageAligned();
         int ps = Bits.pageSize();
         long size = Math.max(1L, (long)cap + (pa ? ps : 0));
@@ -145,8 +146,8 @@ class Direct$Type$Buffer$RW$$BO$
     // Invoked to construct a direct ByteBuffer referring to the block of
     // memory. A given arbitrary object may also be attached to the buffer.
     //
-    Direct$Type$Buffer(long addr, int cap, Object ob) {
-        super(-1, 0, cap, cap);
+    Direct$Type$Buffer(long addr, int cap, Object ob, MemorySegmentProxy segment) {
+        super(-1, 0, cap, cap, segment);
         address = addr;
         cleaner = null;
         att = ob;
@@ -156,7 +157,7 @@ class Direct$Type$Buffer$RW$$BO$
     // Invoked only by JNI: NewDirectByteBuffer(void*, long)
     //
     private Direct$Type$Buffer(long addr, int cap) {
-        super(-1, 0, cap, cap);
+        super(-1, 0, cap, cap, null);
         address = addr;
         cleaner = null;
         att = null;
@@ -169,15 +170,15 @@ class Direct$Type$Buffer$RW$$BO$
     protected Direct$Type$Buffer$RW$(int cap, long addr,
                                      FileDescriptor fd,
                                      Runnable unmapper,
-                                     boolean isSync)
+                                     boolean isSync, MemorySegmentProxy segment)
     {
 #if[rw]
-        super(-1, 0, cap, cap, fd, isSync);
+        super(-1, 0, cap, cap, fd, isSync, segment);
         address = addr;
         cleaner = Cleaner.create(this, unmapper);
         att = null;
 #else[rw]
-        super(cap, addr, fd, unmapper, isSync);
+        super(cap, addr, fd, unmapper, isSync, segment);
         this.isReadOnly = true;
 #end[rw]
     }
@@ -188,10 +189,10 @@ class Direct$Type$Buffer$RW$$BO$
     //
     Direct$Type$Buffer$RW$$BO$(DirectBuffer db,         // package-private
                                int mark, int pos, int lim, int cap,
-                               int off)
+                               int off, MemorySegmentProxy segment)
     {
 #if[rw]
-        super(mark, pos, lim, cap);
+        super(mark, pos, lim, cap, segment);
         address = db.address() + off;
 #if[byte]
         cleaner = null;
@@ -199,7 +200,7 @@ class Direct$Type$Buffer$RW$$BO$
         Object attachment = db.attachment();
         att = (attachment == null ? db : attachment);
 #else[rw]
-        super(db, mark, pos, lim, cap, off);
+        super(db, mark, pos, lim, cap, off, segment);
         this.isReadOnly = true;
 #end[rw]
     }
@@ -216,7 +217,7 @@ class Direct$Type$Buffer$RW$$BO$
         int rem = (pos <= lim ? lim - pos : 0);
         int off = (pos << $LG_BYTES_PER_VALUE$);
         assert (off >= 0);
-        return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, off);
+        return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, off, segment);
     }
 
     @Override
@@ -227,7 +228,7 @@ class Direct$Type$Buffer$RW$$BO$
                                               0,
                                               length,
                                               length,
-                                              index);
+                                              index, segment);
     }
 
     public $Type$Buffer duplicate() {
@@ -236,7 +237,7 @@ class Direct$Type$Buffer$RW$$BO$
                                               this.position(),
                                               this.limit(),
                                               this.capacity(),
-                                              0);
+                                              0, segment);
     }
 
     public $Type$Buffer asReadOnlyBuffer() {
@@ -246,7 +247,7 @@ class Direct$Type$Buffer$RW$$BO$
                                            this.position(),
                                            this.limit(),
                                            this.capacity(),
-                                           0);
+                                           0, segment);
 #else[rw]
         return duplicate();
 #end[rw]
@@ -264,6 +265,7 @@ class Direct$Type$Buffer$RW$$BO$
 
     public $type$ get() {
         try {
+            checkSegment();
             return $fromBits$($swap$(UNSAFE.get$Swaptype$(ix(nextGetIndex()))));
         } finally {
             Reference.reachabilityFence(this);
@@ -272,6 +274,7 @@ class Direct$Type$Buffer$RW$$BO$
 
     public $type$ get(int i) {
         try {
+            checkSegment();
             return $fromBits$($swap$(UNSAFE.get$Swaptype$(ix(checkIndex(i)))));
         } finally {
             Reference.reachabilityFence(this);
@@ -290,6 +293,7 @@ class Direct$Type$Buffer$RW$$BO$
 
     public $Type$Buffer get($type$[] dst, int offset, int length) {
 #if[rw]
+        checkSegment();
         if (((long)length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) {
             Objects.checkFromIndexSize(offset, length, dst.length);
             int pos = position();
@@ -331,6 +335,7 @@ class Direct$Type$Buffer$RW$$BO$
 
     public $Type$Buffer get(int index, $type$[] dst, int offset, int length) {
 #if[rw]
+        checkSegment();
         if (((long)length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) {
             Objects.checkFromIndexSize(index, length, limit());
             Objects.checkFromIndexSize(offset, length, dst.length);
@@ -368,6 +373,7 @@ class Direct$Type$Buffer$RW$$BO$
     public $Type$Buffer put($type$ x) {
 #if[rw]
         try {
+            checkSegment();
             UNSAFE.put$Swaptype$(ix(nextPutIndex()), $swap$($toBits$(x)));
         } finally {
             Reference.reachabilityFence(this);
@@ -381,6 +387,7 @@ class Direct$Type$Buffer$RW$$BO$
     public $Type$Buffer put(int i, $type$ x) {
 #if[rw]
         try {
+            checkSegment();
             UNSAFE.put$Swaptype$(ix(checkIndex(i)), $swap$($toBits$(x)));
         } finally {
             Reference.reachabilityFence(this);
@@ -393,6 +400,7 @@ class Direct$Type$Buffer$RW$$BO$
 
     public $Type$Buffer put($Type$Buffer src) {
 #if[rw]
+        checkSegment();
         if (src instanceof Direct$Type$Buffer$BO$) {
             if (src == this)
                 throw createSameBufferException();
@@ -439,6 +447,7 @@ class Direct$Type$Buffer$RW$$BO$
 
     public $Type$Buffer put($type$[] src, int offset, int length) {
 #if[rw]
+        checkSegment();
         if (((long)length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_FROM_ARRAY_THRESHOLD) {
             Objects.checkFromIndexSize(offset, length, src.length);
             int pos = position();
@@ -480,6 +489,7 @@ class Direct$Type$Buffer$RW$$BO$
 
     public $Type$Buffer put(int index, $type$[] src, int offset, int length) {
 #if[rw]
+        checkSegment();
         if (((long)length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_FROM_ARRAY_THRESHOLD) {
             Objects.checkFromIndexSize(index, length, limit());
             Objects.checkFromIndexSize(offset, length, src.length);
@@ -577,7 +587,7 @@ class Direct$Type$Buffer$RW$$BO$
                                             pos + start,
                                             pos + end,
                                             capacity(),
-                                            offset);
+                                            offset, segment);
     }
 
 #end[char]
diff --git a/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template b/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template
index 18247c23e97..f58dc76127f 100644
--- a/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template
+++ b/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template
@@ -28,6 +28,7 @@
 package java.nio;
 
 import java.util.Objects;
+import jdk.internal.access.foreign.MemorySegmentProxy;
 
 /**
 #if[rw]
@@ -58,47 +59,47 @@ class Heap$Type$Buffer$RW$
 #end[rw]
     */
 
-    Heap$Type$Buffer$RW$(int cap, int lim) {            // package-private
+    Heap$Type$Buffer$RW$(int cap, int lim, MemorySegmentProxy segment) {            // package-private
 #if[rw]
-        super(-1, 0, lim, cap, new $type$[cap], 0);
+        super(-1, 0, lim, cap, new $type$[cap], 0, segment);
         /*
         hb = new $type$[cap];
         offset = 0;
         */
         this.address = ARRAY_BASE_OFFSET;
 #else[rw]
-        super(cap, lim);
+        super(cap, lim, segment);
         this.isReadOnly = true;
 #end[rw]
     }
 
-    Heap$Type$Buffer$RW$($type$[] buf, int off, int len) { // package-private
+    Heap$Type$Buffer$RW$($type$[] buf, int off, int len, MemorySegmentProxy segment) { // package-private
 #if[rw]
-        super(-1, off, off + len, buf.length, buf, 0);
+        super(-1, off, off + len, buf.length, buf, 0, segment);
         /*
         hb = buf;
         offset = 0;
         */
         this.address = ARRAY_BASE_OFFSET;
 #else[rw]
-        super(buf, off, len);
+        super(buf, off, len, segment);
         this.isReadOnly = true;
 #end[rw]
     }
 
     protected Heap$Type$Buffer$RW$($type$[] buf,
                                    int mark, int pos, int lim, int cap,
-                                   int off)
+                                   int off, MemorySegmentProxy segment)
     {
 #if[rw]
-        super(mark, pos, lim, cap, buf, off);
+        super(mark, pos, lim, cap, buf, off, segment);
         /*
         hb = buf;
         offset = off;
         */
         this.address = ARRAY_BASE_OFFSET + off * ARRAY_INDEX_SCALE;
 #else[rw]
-        super(buf, mark, pos, lim, cap, off);
+        super(buf, mark, pos, lim, cap, off, segment);
         this.isReadOnly = true;
 #end[rw]
     }
@@ -110,7 +111,7 @@ class Heap$Type$Buffer$RW$
                                         0,
                                         rem,
                                         rem,
-                                        this.position() + offset);
+                                        this.position() + offset, segment);
     }
 
     @Override
@@ -121,7 +122,7 @@ class Heap$Type$Buffer$RW$
                                         0,
                                         length,
                                         length,
-                                        index + offset);
+                                        index + offset, segment);
     }
 
     public $Type$Buffer duplicate() {
@@ -130,7 +131,7 @@ class Heap$Type$Buffer$RW$
                                         this.position(),
                                         this.limit(),
                                         this.capacity(),
-                                        offset);
+                                        offset, segment);
     }
 
     public $Type$Buffer asReadOnlyBuffer() {
@@ -140,7 +141,7 @@ class Heap$Type$Buffer$RW$
                                      this.position(),
                                      this.limit(),
                                      this.capacity(),
-                                     offset);
+                                     offset, segment);
 #else[rw]
         return duplicate();
 #end[rw]
@@ -159,20 +160,23 @@ class Heap$Type$Buffer$RW$
 #end[byte]
 
     public $type$ get() {
+        checkSegment();
         return hb[ix(nextGetIndex())];
     }
 
     public $type$ get(int i) {
+        checkSegment();
         return hb[ix(checkIndex(i))];
     }
 
 #if[streamableType]
     $type$ getUnchecked(int i) {
-	return hb[ix(i)];
+    return hb[ix(i)];
     }
 #end[streamableType]
 
     public $Type$Buffer get($type$[] dst, int offset, int length) {
+        checkSegment();
         Objects.checkFromIndexSize(offset, length, dst.length);
         int pos = position();
         if (length > limit() - pos)
@@ -183,6 +187,7 @@ class Heap$Type$Buffer$RW$
     }
 
     public $Type$Buffer get(int index, $type$[] dst, int offset, int length) {
+        checkSegment();
         Objects.checkFromIndexSize(index, length, limit());
         Objects.checkFromIndexSize(offset, length, dst.length);
         System.arraycopy(hb, ix(index), dst, offset, length);
@@ -201,6 +206,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer put($type$ x) {
 #if[rw]
+        checkSegment();
         hb[ix(nextPutIndex())] = x;
         return this;
 #else[rw]
@@ -210,6 +216,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer put(int i, $type$ x) {
 #if[rw]
+        checkSegment();
         hb[ix(checkIndex(i))] = x;
         return this;
 #else[rw]
@@ -219,6 +226,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer put($type$[] src, int offset, int length) {
 #if[rw]
+        checkSegment();
         Objects.checkFromIndexSize(offset, length, src.length);
         int pos = position();
         if (length > limit() - pos)
@@ -233,6 +241,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer put($Type$Buffer src) {
 #if[rw]
+        checkSegment();
         if (src instanceof Heap$Type$Buffer) {
             if (src == this)
                 throw createSameBufferException();
@@ -264,6 +273,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer put(int index, $type$[] src, int offset, int length) {
 #if[rw]
+        checkSegment();
         Objects.checkFromIndexSize(index, length, limit());
         Objects.checkFromIndexSize(offset, length, src.length);
         System.arraycopy(src, offset, hb, ix(index), length);
@@ -276,6 +286,7 @@ class Heap$Type$Buffer$RW$
 #if[char]
 
     public $Type$Buffer put(String src, int start, int end) {
+        checkSegment();
         int length = end - start;
         Objects.checkFromIndexSize(start, length, src.length());
         if (isReadOnly())
@@ -327,6 +338,7 @@ class Heap$Type$Buffer$RW$
 #if[rw]
 
     public char getChar() {
+        checkSegment();
         return UNSAFE.getCharUnaligned(hb, byteOffset(nextGetIndex(2)), bigEndian);
     }
 
@@ -338,6 +350,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer putChar(char x) {
 #if[rw]
+        checkSegment();
         UNSAFE.putCharUnaligned(hb, byteOffset(nextPutIndex(2)), x, bigEndian);
         return this;
 #else[rw]
@@ -347,6 +360,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer putChar(int i, char x) {
 #if[rw]
+        checkSegment();
         UNSAFE.putCharUnaligned(hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
         return this;
 #else[rw]
@@ -364,13 +378,13 @@ class Heap$Type$Buffer$RW$
                                                                0,
                                                                size,
                                                                size,
-                                                               addr))
+                                                               addr, segment))
                 : (CharBuffer)(new ByteBufferAsCharBuffer$RW$L(this,
                                                                -1,
                                                                0,
                                                                size,
                                                                size,
-                                                               addr)));
+                                                               addr, segment)));
     }
 
 
@@ -379,10 +393,12 @@ class Heap$Type$Buffer$RW$
 #if[rw]
 
     public short getShort() {
+        checkSegment();
         return UNSAFE.getShortUnaligned(hb, byteOffset(nextGetIndex(2)), bigEndian);
     }
 
     public short getShort(int i) {
+        checkSegment();
         return UNSAFE.getShortUnaligned(hb, byteOffset(checkIndex(i, 2)), bigEndian);
     }
 
@@ -390,6 +406,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer putShort(short x) {
 #if[rw]
+        checkSegment();
         UNSAFE.putShortUnaligned(hb, byteOffset(nextPutIndex(2)), x, bigEndian);
         return this;
 #else[rw]
@@ -399,6 +416,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer putShort(int i, short x) {
 #if[rw]
+        checkSegment();
         UNSAFE.putShortUnaligned(hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
         return this;
 #else[rw]
@@ -416,13 +434,13 @@ class Heap$Type$Buffer$RW$
                                                                  0,
                                                                  size,
                                                                  size,
-                                                                 addr))
+                                                                 addr, segment))
                 : (ShortBuffer)(new ByteBufferAsShortBuffer$RW$L(this,
                                                                  -1,
                                                                  0,
                                                                  size,
                                                                  size,
-                                                                 addr)));
+                                                                 addr, segment)));
     }
 
 
@@ -431,10 +449,12 @@ class Heap$Type$Buffer$RW$
 #if[rw]
 
     public int getInt() {
+        checkSegment();
         return UNSAFE.getIntUnaligned(hb, byteOffset(nextGetIndex(4)), bigEndian);
     }
 
     public int getInt(int i) {
+        checkSegment();
         return UNSAFE.getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
     }
 
@@ -442,6 +462,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer putInt(int x) {
 #if[rw]
+        checkSegment();
         UNSAFE.putIntUnaligned(hb, byteOffset(nextPutIndex(4)), x, bigEndian);
         return this;
 #else[rw]
@@ -451,6 +472,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer putInt(int i, int x) {
 #if[rw]
+        checkSegment();
         UNSAFE.putIntUnaligned(hb, byteOffset(checkIndex(i, 4)), x, bigEndian);
         return this;
 #else[rw]
@@ -468,13 +490,13 @@ class Heap$Type$Buffer$RW$
                                                              0,
                                                              size,
                                                              size,
-                                                             addr))
+                                                             addr, segment))
                 : (IntBuffer)(new ByteBufferAsIntBuffer$RW$L(this,
                                                              -1,
                                                              0,
                                                              size,
                                                              size,
-                                                             addr)));
+                                                             addr, segment)));
     }
 
 
@@ -483,10 +505,12 @@ class Heap$Type$Buffer$RW$
 #if[rw]
 
     public long getLong() {
+        checkSegment();
         return UNSAFE.getLongUnaligned(hb, byteOffset(nextGetIndex(8)), bigEndian);
     }
 
     public long getLong(int i) {
+        checkSegment();
         return UNSAFE.getLongUnaligned(hb, byteOffset(checkIndex(i, 8)), bigEndian);
     }
 
@@ -494,6 +518,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer putLong(long x) {
 #if[rw]
+        checkSegment();
         UNSAFE.putLongUnaligned(hb, byteOffset(nextPutIndex(8)), x, bigEndian);
         return this;
 #else[rw]
@@ -503,6 +528,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer putLong(int i, long x) {
 #if[rw]
+        checkSegment();
         UNSAFE.putLongUnaligned(hb, byteOffset(checkIndex(i, 8)), x, bigEndian);
         return this;
 #else[rw]
@@ -520,13 +546,13 @@ class Heap$Type$Buffer$RW$
                                                                0,
                                                                size,
                                                                size,
-                                                               addr))
+                                                               addr, segment))
                 : (LongBuffer)(new ByteBufferAsLongBuffer$RW$L(this,
                                                                -1,
                                                                0,
                                                                size,
                                                                size,
-                                                               addr)));
+                                                               addr, segment)));
     }
 
 
@@ -535,11 +561,13 @@ class Heap$Type$Buffer$RW$
 #if[rw]
 
     public float getFloat() {
+        checkSegment();
         int x = UNSAFE.getIntUnaligned(hb, byteOffset(nextGetIndex(4)), bigEndian);
         return Float.intBitsToFloat(x);
     }
 
     public float getFloat(int i) {
+        checkSegment();
         int x = UNSAFE.getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
         return Float.intBitsToFloat(x);
     }
@@ -548,6 +576,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer putFloat(float x) {
 #if[rw]
+        checkSegment();
         int y = Float.floatToRawIntBits(x);
         UNSAFE.putIntUnaligned(hb, byteOffset(nextPutIndex(4)), y, bigEndian);
         return this;
@@ -558,6 +587,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer putFloat(int i, float x) {
 #if[rw]
+        checkSegment();
         int y = Float.floatToRawIntBits(x);
         UNSAFE.putIntUnaligned(hb, byteOffset(checkIndex(i, 4)), y, bigEndian);
         return this;
@@ -576,13 +606,13 @@ class Heap$Type$Buffer$RW$
                                                                  0,
                                                                  size,
                                                                  size,
-                                                                 addr))
+                                                                 addr, segment))
                 : (FloatBuffer)(new ByteBufferAsFloatBuffer$RW$L(this,
                                                                  -1,
                                                                  0,
                                                                  size,
                                                                  size,
-                                                                 addr)));
+                                                                 addr, segment)));
     }
 
 
@@ -591,11 +621,13 @@ class Heap$Type$Buffer$RW$
 #if[rw]
 
     public double getDouble() {
+        checkSegment();
         long x = UNSAFE.getLongUnaligned(hb, byteOffset(nextGetIndex(8)), bigEndian);
         return Double.longBitsToDouble(x);
     }
 
     public double getDouble(int i) {
+        checkSegment();
         long x = UNSAFE.getLongUnaligned(hb, byteOffset(checkIndex(i, 8)), bigEndian);
         return Double.longBitsToDouble(x);
     }
@@ -604,6 +636,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer putDouble(double x) {
 #if[rw]
+        checkSegment();
         long y = Double.doubleToRawLongBits(x);
         UNSAFE.putLongUnaligned(hb, byteOffset(nextPutIndex(8)), y, bigEndian);
         return this;
@@ -614,6 +647,7 @@ class Heap$Type$Buffer$RW$
 
     public $Type$Buffer putDouble(int i, double x) {
 #if[rw]
+        checkSegment();
         long y = Double.doubleToRawLongBits(x);
         UNSAFE.putLongUnaligned(hb, byteOffset(checkIndex(i, 8)), y, bigEndian);
         return this;
@@ -632,13 +666,13 @@ class Heap$Type$Buffer$RW$
                                                                    0,
                                                                    size,
                                                                    size,
-                                                                   addr))
+                                                                   addr, segment))
                 : (DoubleBuffer)(new ByteBufferAsDoubleBuffer$RW$L(this,
                                                                    -1,
                                                                    0,
                                                                    size,
                                                                    size,
-                                                                   addr)));
+                                                                   addr, segment)));
     }
 
 
@@ -666,7 +700,7 @@ class Heap$Type$Buffer$RW$
                                       pos + start,
                                       pos + end,
                                       capacity(),
-                                      offset);
+                                      offset, segment);
     }
 
 #end[char]
diff --git a/src/java.base/share/classes/java/nio/MappedByteBuffer.java b/src/java.base/share/classes/java/nio/MappedByteBuffer.java
index 22e1ad818ed..98848f3c85b 100644
--- a/src/java.base/share/classes/java/nio/MappedByteBuffer.java
+++ b/src/java.base/share/classes/java/nio/MappedByteBuffer.java
@@ -28,6 +28,8 @@ package java.nio;
 import java.io.FileDescriptor;
 import java.lang.ref.Reference;
 import java.util.Objects;
+
+import jdk.internal.access.foreign.MemorySegmentProxy;
 import jdk.internal.misc.Unsafe;
 
 
@@ -88,21 +90,21 @@ public abstract class MappedByteBuffer
     // This should only be invoked by the DirectByteBuffer constructors
     //
     MappedByteBuffer(int mark, int pos, int lim, int cap, // package-private
-                     FileDescriptor fd, boolean isSync) {
-        super(mark, pos, lim, cap);
+                     FileDescriptor fd, boolean isSync, MemorySegmentProxy segment) {
+        super(mark, pos, lim, cap, segment);
         this.fd = fd;
         this.isSync = isSync;
     }
 
     MappedByteBuffer(int mark, int pos, int lim, int cap, // package-private
-                     boolean isSync) {
-        super(mark, pos, lim, cap);
+                     boolean isSync, MemorySegmentProxy segment) {
+        super(mark, pos, lim, cap, segment);
         this.fd = null;
         this.isSync = isSync;
     }
 
-    MappedByteBuffer(int mark, int pos, int lim, int cap) { // package-private
-        super(mark, pos, lim, cap);
+    MappedByteBuffer(int mark, int pos, int lim, int cap, MemorySegmentProxy segment) { // package-private
+        super(mark, pos, lim, cap, segment);
         this.fd = null;
         this.isSync = false;
     }
diff --git a/src/java.base/share/classes/java/nio/StringCharBuffer.java b/src/java.base/share/classes/java/nio/StringCharBuffer.java
index 554c08466ad..aebc5083b39 100644
--- a/src/java.base/share/classes/java/nio/StringCharBuffer.java
+++ b/src/java.base/share/classes/java/nio/StringCharBuffer.java
@@ -35,7 +35,7 @@ class StringCharBuffer                                  // package-private
     CharSequence str;
 
     StringCharBuffer(CharSequence s, int start, int end) { // package-private
-        super(-1, start, end, s.length());
+        super(-1, start, end, s.length(), null);
         int n = s.length();
         Objects.checkFromToIndex(start, end, n);
         str = s;
@@ -68,7 +68,7 @@ class StringCharBuffer                                  // package-private
                              int limit,
                              int cap,
                              int offset) {
-        super(mark, pos, limit, cap, null, offset);
+        super(mark, pos, limit, cap, null, offset, null);
         str = s;
         this.isReadOnly = true;
     }
diff --git a/src/java.base/share/classes/java/nio/X-Buffer.java.template b/src/java.base/share/classes/java/nio/X-Buffer.java.template
index a0b76f5de67..4c7d723d0ea 100644
--- a/src/java.base/share/classes/java/nio/X-Buffer.java.template
+++ b/src/java.base/share/classes/java/nio/X-Buffer.java.template
@@ -37,6 +37,7 @@ import java.util.stream.$Streamtype$Stream;
 #end[streamableType]
 
 import java.util.Objects;
+import jdk.internal.access.foreign.MemorySegmentProxy;
 import jdk.internal.util.ArraysSupport;
 
 /**
@@ -279,17 +280,25 @@ public abstract class $Type$Buffer
     // backing array, and array offset
     //
     $Type$Buffer(int mark, int pos, int lim, int cap,   // package-private
-                 $type$[] hb, int offset)
+                 $type$[] hb, int offset, MemorySegmentProxy segment)
     {
-        super(mark, pos, lim, cap);
+        super(mark, pos, lim, cap, segment);
         this.hb = hb;
         this.offset = offset;
     }
 
     // Creates a new buffer with the given mark, position, limit, and capacity
     //
-    $Type$Buffer(int mark, int pos, int lim, int cap) { // package-private
-        this(mark, pos, lim, cap, null, 0);
+    $Type$Buffer(int mark, int pos, int lim, int cap, MemorySegmentProxy segment) { // package-private
+        this(mark, pos, lim, cap, null, 0, segment);
+    }
+
+    // Creates a new buffer with given base, address and capacity
+    //
+    $Type$Buffer($type$[] hb, long addr, int cap, MemorySegmentProxy segment) { // package-private
+        super(addr, cap, segment);
+        this.hb = hb;
+        this.offset = 0;
     }
 
     @Override
@@ -348,7 +357,7 @@ public abstract class $Type$Buffer
     public static $Type$Buffer allocate(int capacity) {
         if (capacity < 0)
             throw createCapacityException(capacity);
-        return new Heap$Type$Buffer(capacity, capacity);
+        return new Heap$Type$Buffer(capacity, capacity, null);
     }
 
     /**
@@ -393,7 +402,7 @@ public abstract class $Type$Buffer
                                     int offset, int length)
     {
         try {
-            return new Heap$Type$Buffer(array, offset, length);
+            return new Heap$Type$Buffer(array, offset, length, null);
         } catch (IllegalArgumentException x) {
             throw new IndexOutOfBoundsException();
         }
diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java
index 0eda491a319..1830408e9a1 100644
--- a/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java
+++ b/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java
@@ -26,6 +26,8 @@
 package jdk.internal.access;
 
 import java.lang.invoke.MethodType;
+import java.lang.invoke.VarHandle;
+import java.nio.ByteOrder;
 import java.util.Map;
 
 public interface JavaLangInvokeAccess {
@@ -106,4 +108,41 @@ public interface JavaLangInvokeAccess {
             MethodType[] invokerMethodTypes,
             MethodType[] callSiteMethodTypes);
 
+    /**
+     * Returns a var handle view of a given memory address.
+     * Used by {@code jdk.internal.foreign.LayoutPath} and
+     * {@code jdk.incubator.foreign.MemoryHandles}.
+     */
+    VarHandle memoryAddressViewVarHandle(Class<?> carrier, long alignmentMask,
+                                         ByteOrder order, long offset, long[] strides);
+
+    /**
+     * Returns the carrier associated with a memory access var handle.
+     * Used by {@code jdk.incubator.foreign.MemoryHandles}.
+     */
+    Class<?> memoryAddressCarrier(VarHandle handle);
+
+    /**
+     * Returns the alignment mask associated with a memory access var handle.
+     * Used by {@code jdk.incubator.foreign.MemoryHandles}.
+     */
+    long memoryAddressAlignmentMask(VarHandle handle);
+
+    /**
+     * Returns the byte order associated with a memory access var handle.
+     * Used by {@code jdk.incubator.foreign.MemoryHandles}.
+     */
+    ByteOrder memoryAddressByteOrder(VarHandle handle);
+
+    /**
+     * Returns the offset associated with a memory access var handle.
+     * Used by {@code jdk.incubator.foreign.MemoryHandles}.
+     */
+    long memoryAddressOffset(VarHandle handle);
+
+    /**
+     * Returns the strides associated with a memory access var handle.
+     * Used by {@code jdk.incubator.foreign.MemoryHandles}.
+     */
+    long[] memoryAddressStrides(VarHandle handle);
 }
diff --git a/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java
index 40a2c21da5c..022da7fe9f5 100644
--- a/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java
+++ b/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java
@@ -25,6 +25,8 @@
 
 package jdk.internal.access;
 
+import jdk.internal.access.foreign.MemorySegmentProxy;
+
 import java.nio.Buffer;
 import java.nio.ByteBuffer;
 
@@ -39,4 +41,34 @@ public interface JavaNioAccess {
         long getMemoryUsed();
     }
     BufferPool getDirectBufferPool();
+
+    /**
+     * Constructs a direct ByteBuffer referring to the block of memory starting
+     * at the given memory address and extending {@code cap} bytes.
+     * The {@code ob} parameter is an arbitrary object that is attached
+     * to the resulting buffer.
+     * Used by {@code jdk.internal.foreignMemorySegmentImpl}.
+     */
+    ByteBuffer newDirectByteBuffer(long addr, int cap, Object obj, MemorySegmentProxy segment);
+
+    /**
+     * Constructs an heap ByteBuffer with given backing array, offset, capacity and segment.
+     * Used by {@code jdk.internal.foreignMemorySegmentImpl}.
+     */
+    ByteBuffer newHeapByteBuffer(byte[] hb, int offset, int capacity, MemorySegmentProxy segment);
+
+    /**
+     * Used by {@code jdk.internal.foreign.Utils}.
+     */
+    Object getBufferBase(ByteBuffer bb);
+
+    /**
+     * Used by {@code jdk.internal.foreign.Utils}.
+     */
+    long getBufferAddress(ByteBuffer bb);
+
+    /**
+     * Used by byte buffer var handle views.
+     */
+    void checkSegment(Buffer buffer);
 }
diff --git a/src/java.base/share/classes/jdk/internal/access/foreign/MemoryAddressProxy.java b/src/java.base/share/classes/jdk/internal/access/foreign/MemoryAddressProxy.java
new file mode 100644
index 00000000000..7c6a7007e52
--- /dev/null
+++ b/src/java.base/share/classes/jdk/internal/access/foreign/MemoryAddressProxy.java
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.internal.access.foreign;
+
+/**
+ * This proxy interface is required to allow instances of the {@code MemoryAddress} interface (which is defined inside
+ * an incubating module) to be accessed from the memory access var handles.
+ */
+public interface MemoryAddressProxy {
+    /**
+     * Check that memory access is within spatial and temporal bounds.
+     * @throws IllegalStateException if underlying segment has been closed already.
+     * @throws IndexOutOfBoundsException if access is out-of-bounds.
+     */
+    void checkAccess(long offset, long length, boolean readOnly);
+    long unsafeGetOffset();
+    Object unsafeGetBase();
+}
diff --git a/src/java.base/share/classes/jdk/internal/access/foreign/MemorySegmentProxy.java b/src/java.base/share/classes/jdk/internal/access/foreign/MemorySegmentProxy.java
new file mode 100644
index 00000000000..6c6ec80987a
--- /dev/null
+++ b/src/java.base/share/classes/jdk/internal/access/foreign/MemorySegmentProxy.java
@@ -0,0 +1,35 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.internal.access.foreign;
+
+/**
+ * This proxy interface is required to allow instances of the {@code MemorySegment} interface (which is defined inside
+ * an incubating module) to be accessed from the memory access var handles.
+ */
+public interface MemorySegmentProxy {
+    void checkValidState();
+}
diff --git a/src/java.base/share/classes/jdk/internal/access/foreign/UnmapperProxy.java b/src/java.base/share/classes/jdk/internal/access/foreign/UnmapperProxy.java
new file mode 100644
index 00000000000..b411c922d58
--- /dev/null
+++ b/src/java.base/share/classes/jdk/internal/access/foreign/UnmapperProxy.java
@@ -0,0 +1,36 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.internal.access.foreign;
+
+/**
+ * This proxy interface is required to allow instances of the {@code FileChannelImpl.Unmapper} interface (which is a non-public class
+ * inside the {@code sun.nio.ch} package) to be accessed from the mapped memory segment factory.
+ */
+public interface UnmapperProxy {
+    long address();
+    void unmap();
+}
diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java
index 0aa48cebe22..b6f4c6b2103 100644
--- a/src/java.base/share/classes/module-info.java
+++ b/src/java.base/share/classes/module-info.java
@@ -134,7 +134,8 @@ module java.base {
     // see make/gensrc/GenModuleInfo.gmk
 
     exports sun.invoke.util to
-        jdk.compiler;
+        jdk.compiler,
+        jdk.incubator.foreign;
     exports com.sun.security.ntlm to
         java.security.sasl;
     exports jdk.internal to
@@ -149,7 +150,10 @@ module java.base {
         java.naming,
         java.rmi,
         jdk.jlink,
-        jdk.net;
+        jdk.net,
+        jdk.incubator.foreign;
+    exports jdk.internal.access.foreign to
+        jdk.incubator.foreign;
     exports jdk.internal.event to
         jdk.jfr;
     exports jdk.internal.jimage to
@@ -202,7 +206,8 @@ module java.base {
         jdk.scripting.nashorn,
         jdk.scripting.nashorn.shell,
         jdk.unsupported,
-        jdk.internal.vm.ci;
+        jdk.internal.vm.ci,
+        jdk.incubator.foreign;
     exports jdk.internal.module to
         java.instrument,
         java.management.rmi,
@@ -260,7 +265,8 @@ module java.base {
         java.management,
         jdk.crypto.cryptoki,
         jdk.net,
-        jdk.sctp;
+        jdk.sctp,
+        jdk.incubator.foreign;
     exports sun.nio.cs to
         jdk.charsets;
     exports sun.reflect.annotation to
@@ -276,7 +282,8 @@ module java.base {
         java.sql.rowset;
     exports sun.security.action to
         java.desktop,
-        java.security.jgss;
+        java.security.jgss,
+        jdk.incubator.foreign;
     exports sun.security.internal.interfaces to
         jdk.crypto.cryptoki;
     exports sun.security.internal.spec to
diff --git a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java
index 1157bcd3617..5f4137fa65b 100644
--- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java
+++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java
@@ -42,6 +42,7 @@ import java.nio.channels.NonWritableChannelException;
 import java.nio.channels.ReadableByteChannel;
 import java.nio.channels.SelectableChannel;
 import java.nio.channels.WritableByteChannel;
+import java.util.Objects;
 
 import jdk.internal.access.JavaIOFileDescriptorAccess;
 import jdk.internal.access.JavaNioAccess;
@@ -51,6 +52,8 @@ import jdk.internal.misc.Unsafe;
 import jdk.internal.ref.Cleaner;
 import jdk.internal.ref.CleanerFactory;
 
+import jdk.internal.access.foreign.UnmapperProxy;
+
 public class FileChannelImpl
     extends FileChannel
 {
@@ -863,27 +866,39 @@ public class FileChannelImpl
     // -- Memory-mapped buffers --
 
     private static abstract class Unmapper
-        implements Runnable
+        implements Runnable, UnmapperProxy
     {
         // may be required to close file
         private static final NativeDispatcher nd = new FileDispatcherImpl();
 
         private volatile long address;
         protected final long size;
-        protected final int cap;
+        protected final long cap;
         private final FileDescriptor fd;
+        private final int pagePosition;
 
-        private Unmapper(long address, long size, int cap,
-                         FileDescriptor fd)
+        private Unmapper(long address, long size, long cap,
+                         FileDescriptor fd, int pagePosition)
         {
             assert (address != 0);
             this.address = address;
             this.size = size;
             this.cap = cap;
             this.fd = fd;
+            this.pagePosition = pagePosition;
         }
 
+        @Override
+        public long address() {
+            return address;
+        }
+
+        @Override
         public void run() {
+            unmap();
+        }
+
+        public void unmap() {
             if (address == 0)
                 return;
             unmap0(address, size);
@@ -911,9 +926,9 @@ public class FileChannelImpl
         static volatile long totalSize;
         static volatile long totalCapacity;
 
-        public DefaultUnmapper(long address, long size, int cap,
-                                     FileDescriptor fd) {
-            super(address, size, cap, fd);
+        public DefaultUnmapper(long address, long size, long cap,
+                               FileDescriptor fd, int pagePosition) {
+            super(address, size, cap, fd, pagePosition);
             incrementStats();
         }
 
@@ -940,9 +955,9 @@ public class FileChannelImpl
         static volatile long totalSize;
         static volatile long totalCapacity;
 
-        public SyncUnmapper(long address, long size, int cap,
-                                  FileDescriptor fd) {
-            super(address, size, cap, fd);
+        public SyncUnmapper(long address, long size, long cap,
+                            FileDescriptor fd, int pagePosition) {
+            super(address, size, cap, fd, pagePosition);
             incrementStats();
         }
 
@@ -968,11 +983,44 @@ public class FileChannelImpl
             cl.clean();
     }
 
+    private static final int MAP_INVALID = -1;
     private static final int MAP_RO = 0;
     private static final int MAP_RW = 1;
     private static final int MAP_PV = 2;
 
-    public MappedByteBuffer map(MapMode mode, long position, long size)
+    public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException {
+        if (size > Integer.MAX_VALUE)
+            throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE");
+        boolean isSync = isSync(Objects.requireNonNull(mode, "Mode is null"));
+        int prot = toProt(mode);
+        Unmapper unmapper = mapInternal(mode, position, size, prot, isSync);
+        if (unmapper == null) {
+            // a valid file descriptor is not required
+            FileDescriptor dummy = new FileDescriptor();
+            if ((!writable) || (prot == MAP_RO))
+                return Util.newMappedByteBufferR(0, 0, dummy, null, isSync);
+            else
+                return Util.newMappedByteBuffer(0, 0, dummy, null, isSync);
+        } else if ((!writable) || (prot == MAP_RO)) {
+            return Util.newMappedByteBufferR((int)unmapper.cap,
+                    unmapper.address + unmapper.pagePosition,
+                    unmapper.fd,
+                    unmapper, isSync);
+        } else {
+            return Util.newMappedByteBuffer((int)unmapper.cap,
+                    unmapper.address + unmapper.pagePosition,
+                    unmapper.fd,
+                    unmapper, isSync);
+        }
+    }
+
+    public Unmapper mapInternal(MapMode mode, long position, long size) throws IOException {
+        boolean isSync = isSync(Objects.requireNonNull(mode, "Mode is null"));
+        int prot = toProt(mode);
+        return mapInternal(mode, position, size, prot, isSync);
+    }
+
+    private Unmapper mapInternal(MapMode mode, long position, long size, int prot, boolean isSync)
         throws IOException
     {
         ensureOpen();
@@ -984,35 +1032,8 @@ public class FileChannelImpl
             throw new IllegalArgumentException("Negative size");
         if (position + size < 0)
             throw new IllegalArgumentException("Position + size overflow");
-        if (size > Integer.MAX_VALUE)
-            throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE");
-
-        int imode;
-        boolean isSync = false;
-        if (mode == MapMode.READ_ONLY)
-            imode = MAP_RO;
-        else if (mode == MapMode.READ_WRITE)
-            imode = MAP_RW;
-        else if (mode == MapMode.PRIVATE)
-            imode = MAP_PV;
-        else if (mode == ExtendedMapMode.READ_ONLY_SYNC) {
-            imode = MAP_RO;
-            isSync = true;
-        } else if (mode == ExtendedMapMode.READ_WRITE_SYNC) {
-            imode = MAP_RW;
-            isSync = true;
-        } else {
-            throw new UnsupportedOperationException();
-        }
-        if ((mode != MapMode.READ_ONLY) && mode != ExtendedMapMode.READ_ONLY_SYNC && !writable)
-            throw new NonWritableChannelException();
-        if (!readable)
-            throw new NonReadableChannelException();
-        // reject SYNC request if writeback is not enabled for this platform
-        if (isSync && !Unsafe.isWritebackEnabled()) {
-            throw new UnsupportedOperationException();
-        }
 
+        checkMode(mode, prot, isSync);
         long addr = -1;
         int ti = -1;
         try {
@@ -1045,13 +1066,7 @@ public class FileChannelImpl
                 }
 
                 if (size == 0) {
-                    addr = 0;
-                    // a valid file descriptor is not required
-                    FileDescriptor dummy = new FileDescriptor();
-                    if ((!writable) || (imode == MAP_RO))
-                        return Util.newMappedByteBufferR(0, 0, dummy, null, isSync);
-                    else
-                        return Util.newMappedByteBuffer(0, 0, dummy, null, isSync);
+                    return null;
                 }
 
                 pagePosition = (int)(position % allocationGranularity);
@@ -1059,7 +1074,7 @@ public class FileChannelImpl
                 mapSize = size + pagePosition;
                 try {
                     // If map0 did not throw an exception, the address is valid
-                    addr = map0(imode, mapPosition, mapSize, isSync);
+                    addr = map0(prot, mapPosition, mapSize, isSync);
                 } catch (OutOfMemoryError x) {
                     // An OutOfMemoryError may indicate that we've exhausted
                     // memory so force gc and re-attempt map
@@ -1070,7 +1085,7 @@ public class FileChannelImpl
                         Thread.currentThread().interrupt();
                     }
                     try {
-                        addr = map0(imode, mapPosition, mapSize, isSync);
+                        addr = map0(prot, mapPosition, mapSize, isSync);
                     } catch (OutOfMemoryError y) {
                         // After a second OOME, fail
                         throw new IOException("Map failed", y);
@@ -1090,29 +1105,53 @@ public class FileChannelImpl
 
             assert (IOStatus.checkAll(addr));
             assert (addr % allocationGranularity == 0);
-            int isize = (int)size;
             Unmapper um = (isSync
-                           ? new SyncUnmapper(addr, mapSize, isize, mfd)
-                           : new DefaultUnmapper(addr, mapSize, isize, mfd));
-            if ((!writable) || (imode == MAP_RO)) {
-                return Util.newMappedByteBufferR(isize,
-                                                 addr + pagePosition,
-                                                 mfd,
-                                                 um,
-                                                 isSync);
-            } else {
-                return Util.newMappedByteBuffer(isize,
-                                                addr + pagePosition,
-                                                mfd,
-                                                um,
-                                                isSync);
-            }
+                           ? new SyncUnmapper(addr, mapSize, size, mfd, pagePosition)
+                           : new DefaultUnmapper(addr, mapSize, size, mfd, pagePosition));
+            return um;
         } finally {
             threads.remove(ti);
             endBlocking(IOStatus.checkAll(addr));
         }
     }
 
+    private boolean isSync(MapMode mode) {
+        return mode == ExtendedMapMode.READ_ONLY_SYNC ||
+                mode == ExtendedMapMode.READ_WRITE_SYNC;
+    }
+
+    private int toProt(MapMode mode) {
+        int prot;
+        if (mode == MapMode.READ_ONLY) {
+            prot = MAP_RO;
+        } else if (mode == MapMode.READ_WRITE) {
+            prot = MAP_RW;
+        } else if (mode == MapMode.PRIVATE) {
+            prot = MAP_PV;
+        } else if (mode == ExtendedMapMode.READ_ONLY_SYNC) {
+            prot = MAP_RO;
+        } else if (mode == ExtendedMapMode.READ_WRITE_SYNC) {
+            prot = MAP_RW;
+        } else {
+            prot = MAP_INVALID;
+        }
+        return prot;
+    }
+
+    private void checkMode(MapMode mode, int prot, boolean isSync) {
+        if (prot == MAP_INVALID) {
+            throw new UnsupportedOperationException();
+        }
+        if ((mode != MapMode.READ_ONLY) && mode != ExtendedMapMode.READ_ONLY_SYNC && !writable)
+            throw new NonWritableChannelException();
+        if (!readable)
+            throw new NonReadableChannelException();
+        // reject SYNC request if writeback is not enabled for this platform
+        if (isSync && !Unsafe.isWritebackEnabled()) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
     /**
      * Invoked by sun.management.ManagementFactoryHelper to create the management
      * interface for mapped buffers.
diff --git a/src/java.base/share/classes/sun/nio/ch/Util.java b/src/java.base/share/classes/sun/nio/ch/Util.java
index de8500881b6..d91a6927d05 100644
--- a/src/java.base/share/classes/sun/nio/ch/Util.java
+++ b/src/java.base/share/classes/sun/nio/ch/Util.java
@@ -37,6 +37,7 @@ import java.util.Collection;
 import java.util.Iterator;
 import java.util.Set;
 
+import jdk.internal.access.foreign.MemorySegmentProxy;
 import jdk.internal.misc.TerminatingThreadLocal;
 import jdk.internal.misc.Unsafe;
 import sun.security.action.GetPropertyAction;
@@ -416,7 +417,7 @@ public class Util {
                                              long.class,
                                              FileDescriptor.class,
                                              Runnable.class,
-                                             boolean.class });
+                                             boolean.class, MemorySegmentProxy.class});
                         ctor.setAccessible(true);
                         directByteBufferConstructor = ctor;
                     } catch (ClassNotFoundException   |
@@ -443,7 +444,7 @@ public class Util {
                              addr,
                              fd,
                              unmapper,
-                             isSync});
+                             isSync, null});
         } catch (InstantiationException |
                  IllegalAccessException |
                  InvocationTargetException e) {
@@ -464,7 +465,7 @@ public class Util {
                                              long.class,
                                              FileDescriptor.class,
                                              Runnable.class,
-                                             boolean.class });
+                                             boolean.class, MemorySegmentProxy.class });
                         ctor.setAccessible(true);
                         directByteBufferRConstructor = ctor;
                     } catch (ClassNotFoundException |
@@ -491,7 +492,7 @@ public class Util {
                              addr,
                              fd,
                              unmapper,
-                             isSync});
+                             isSync, null});
         } catch (InstantiationException |
                  IllegalAccessException |
                  InvocationTargetException e) {
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/AbstractLayout.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/AbstractLayout.java
new file mode 100644
index 00000000000..94ae1a462fc
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/AbstractLayout.java
@@ -0,0 +1,178 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.incubator.foreign;
+
+import java.lang.constant.ClassDesc;
+import java.lang.constant.ConstantDesc;
+import java.lang.constant.ConstantDescs;
+import java.lang.constant.DirectMethodHandleDesc;
+import java.lang.constant.DynamicConstantDesc;
+import java.lang.constant.MethodHandleDesc;
+import java.lang.constant.MethodTypeDesc;
+import java.nio.ByteOrder;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.OptionalLong;
+
+abstract class AbstractLayout implements MemoryLayout {
+    private final OptionalLong size;
+    final long alignment;
+    private final Optional<String> name;
+
+    public AbstractLayout(OptionalLong size, long alignment, Optional<String> name) {
+        this.size = size;
+        this.alignment = alignment;
+        this.name = name;
+    }
+
+    Optional<String> optName() {
+        return name;
+    }
+
+    @Override
+    public AbstractLayout withName(String name) {
+        return dup(alignment, Optional.of(name));
+    }
+
+    @Override
+    public final Optional<String> name() {
+        return name;
+    }
+
+    abstract AbstractLayout dup(long alignment, Optional<String> name);
+
+    @Override
+    public AbstractLayout withBitAlignment(long alignmentBits) {
+        checkAlignment(alignmentBits);
+        return dup(alignmentBits, name);
+    }
+
+    void checkAlignment(long alignmentBitCount) {
+        if (((alignmentBitCount & (alignmentBitCount - 1)) != 0L) || //alignment must be a power of two
+                (alignmentBitCount < 8)) { //alignment must be greater than 8
+            throw new IllegalArgumentException("Invalid alignment: " + alignmentBitCount);
+        }
+    }
+
+    static void checkSize(long size) {
+        checkSize(size, false);
+    }
+
+    static void checkSize(long size, boolean includeZero) {
+        if (size < 0 || (!includeZero && size == 0)) {
+            throw new IllegalArgumentException("Invalid size for layout: " + size);
+        }
+    }
+
+    @Override
+    public final long bitAlignment() {
+        return alignment;
+    }
+
+    @Override
+    public long bitSize() {
+        return size.orElseThrow(this::badSizeException);
+    }
+
+    static OptionalLong optSize(MemoryLayout layout) {
+        return ((AbstractLayout)layout).size;
+    }
+
+    private UnsupportedOperationException badSizeException() {
+        return new UnsupportedOperationException("Cannot compute size of a layout which is, or depends on a sequence layout with unspecified size");
+    }
+
+    String decorateLayoutString(String s) {
+        if (name.isPresent()) {
+            s = String.format("%s(%s)", s, name.get());
+        }
+        if (!hasNaturalAlignment()) {
+            s = alignment + "%" + s;
+        }
+        return s;
+    }
+
+    boolean hasNaturalAlignment() {
+        return size.isPresent() && size.getAsLong() == alignment;
+    }
+
+    @Override
+    public int hashCode() {
+        return name.hashCode() << Long.hashCode(alignment);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof AbstractLayout)) {
+            return false;
+        }
+
+        return Objects.equals(name, ((AbstractLayout)other).name) &&
+                Objects.equals(alignment, ((AbstractLayout)other).alignment);
+    }
+
+    /*** Helper constants for implementing Layout::describeConstable ***/
+
+    public static final DirectMethodHandleDesc BSM_GET_STATIC_FINAL
+            = ConstantDescs.ofConstantBootstrap(ConstantDescs.CD_ConstantBootstraps, "getStaticFinal",
+            ConstantDescs.CD_Object, ConstantDescs.CD_Class);
+
+    static final ClassDesc CD_LAYOUT = MemoryLayout.class.describeConstable().get();
+
+    static final ClassDesc CD_VALUE_LAYOUT = ValueLayout.class.describeConstable().get();
+
+    static final ClassDesc CD_SEQUENCE_LAYOUT = SequenceLayout.class.describeConstable().get();
+
+    static final ClassDesc CD_GROUP_LAYOUT = GroupLayout.class.describeConstable().get();
+
+    static final ClassDesc CD_BYTEORDER = ByteOrder.class.describeConstable().get();
+
+    static final ConstantDesc BIG_ENDIAN = DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL, "BIG_ENDIAN", CD_BYTEORDER, CD_BYTEORDER);
+
+    static final ConstantDesc LITTLE_ENDIAN = DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL, "LITTLE_ENDIAN", CD_BYTEORDER, CD_BYTEORDER);
+
+    static final MethodHandleDesc MH_PADDING = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofPaddingBits",
+                MethodTypeDesc.of(CD_LAYOUT, ConstantDescs.CD_long));
+
+    static final MethodHandleDesc MH_VALUE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofValueBits",
+                MethodTypeDesc.of(CD_VALUE_LAYOUT, ConstantDescs.CD_long, CD_BYTEORDER));
+
+    static final MethodHandleDesc MH_SIZED_SEQUENCE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofSequence",
+                MethodTypeDesc.of(CD_SEQUENCE_LAYOUT, ConstantDescs.CD_long, CD_LAYOUT));
+
+    static final MethodHandleDesc MH_UNSIZED_SEQUENCE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofSequence",
+                MethodTypeDesc.of(CD_SEQUENCE_LAYOUT, CD_LAYOUT));
+
+    static final MethodHandleDesc MH_STRUCT = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofStruct",
+                MethodTypeDesc.of(CD_GROUP_LAYOUT, CD_LAYOUT.arrayType()));
+
+    static final MethodHandleDesc MH_UNION = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofUnion",
+                MethodTypeDesc.of(CD_GROUP_LAYOUT, CD_LAYOUT.arrayType()));
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/GroupLayout.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/GroupLayout.java
new file mode 100644
index 00000000000..41923f34e65
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/GroupLayout.java
@@ -0,0 +1,210 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.incubator.foreign;
+
+import java.lang.constant.ConstantDesc;
+import java.lang.constant.ConstantDescs;
+import java.lang.constant.DynamicConstantDesc;
+import java.lang.constant.MethodHandleDesc;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.OptionalLong;
+import java.util.function.LongBinaryOperator;
+import java.util.stream.Collectors;
+
+/**
+ * A group layout is used to combine together multiple <em>member layouts</em>. There are two ways in which member layouts
+ * can be combined: if member layouts are laid out one after the other, the resulting group layout is said to be a <em>struct</em>
+ * (see {@link MemoryLayout#ofStruct(MemoryLayout...)}); conversely, if all member layouts are laid out at the same starting offset,
+ * the resulting group layout is said to be a <em>union</em> (see {@link MemoryLayout#ofUnion(MemoryLayout...)}).
+ *
+ * <p>
+ * This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
+ * class; use of identity-sensitive operations (including reference equality
+ * ({@code ==}), identity hash code, or synchronization) on instances of
+ * {@code GroupLayout} may have unpredictable results and should be avoided.
+ * The {@code equals} method should be used for comparisons.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ */
+public final class GroupLayout extends AbstractLayout {
+
+    /**
+     * The group kind.
+     */
+    enum Kind {
+        /**
+         * A 'struct' kind.
+         */
+        STRUCT("", MH_STRUCT, Long::sum),
+        /**
+         * A 'union' kind.
+         */
+        UNION("|", MH_UNION, Math::max);
+
+        final String delimTag;
+        final MethodHandleDesc mhDesc;
+        final LongBinaryOperator sizeOp;
+
+        Kind(String delimTag, MethodHandleDesc mhDesc, LongBinaryOperator sizeOp) {
+            this.delimTag = delimTag;
+            this.mhDesc = mhDesc;
+            this.sizeOp = sizeOp;
+        }
+
+        OptionalLong sizeof(List<MemoryLayout> elems) {
+            long size = 0;
+            for (MemoryLayout elem : elems) {
+                if (AbstractLayout.optSize(elem).isPresent()) {
+                    size = sizeOp.applyAsLong(size, elem.bitSize());
+                } else {
+                    return OptionalLong.empty();
+                }
+            }
+            return OptionalLong.of(size);
+        }
+
+        long alignof(List<MemoryLayout> elems) {
+            return elems.stream().mapToLong(MemoryLayout::bitAlignment).max() // max alignment in case we have member layouts
+                    .orElse(1); // or minimal alignment if no member layout is given
+        }
+    }
+
+    private final Kind kind;
+    private final List<MemoryLayout> elements;
+
+    GroupLayout(Kind kind, List<MemoryLayout> elements) {
+        this(kind, elements, kind.alignof(elements), Optional.empty());
+    }
+
+    GroupLayout(Kind kind, List<MemoryLayout> elements, long alignment, Optional<String> name) {
+        super(kind.sizeof(elements), alignment, name);
+        this.kind = kind;
+        this.elements = elements;
+    }
+
+    /**
+     * Returns the member layouts associated with this group.
+     *
+     * @apiNote the order in which member layouts are returned is the same order in which member layouts have
+     * been passed to one of the group layout factory methods (see {@link MemoryLayout#ofStruct(MemoryLayout...)},
+     * {@link MemoryLayout#ofUnion(MemoryLayout...)}).
+     *
+     * @return the member layouts associated with this group.
+     */
+    public List<MemoryLayout> memberLayouts() {
+        return Collections.unmodifiableList(elements);
+    }
+
+    @Override
+    public String toString() {
+        return decorateLayoutString(elements.stream()
+                .map(Object::toString)
+                .collect(Collectors.joining(kind.delimTag, "[", "]")));
+    }
+
+    /**
+     * Is this group layout a <em>struct</em>?
+     *
+     * @return true, if this group layout is a <em>struct</em>.
+     */
+    public boolean isStruct() {
+        return kind == Kind.STRUCT;
+    }
+
+    /**
+     * Is this group layout a <em>union</em>?
+     *
+     * @return true, if this group layout is a <em>union</em>.
+     */
+    public boolean isUnion() {
+        return kind == Kind.UNION;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!super.equals(other)) {
+            return false;
+        }
+        if (!(other instanceof GroupLayout)) {
+            return false;
+        }
+        GroupLayout g = (GroupLayout)other;
+        return kind.equals(g.kind) && elements.equals(g.elements);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), kind, elements);
+    }
+
+    @Override
+    GroupLayout dup(long alignment, Optional<String> name) {
+        return new GroupLayout(kind, elements, alignment, name);
+    }
+
+    @Override
+    boolean hasNaturalAlignment() {
+        return alignment == kind.alignof(elements);
+    }
+
+    @Override
+    public Optional<DynamicConstantDesc<GroupLayout>> describeConstable() {
+        ConstantDesc[] constants = new ConstantDesc[1 + elements.size()];
+        constants[0] = kind.mhDesc;
+        for (int i = 0 ; i < elements.size() ; i++) {
+            constants[i + 1] = elements.get(i).describeConstable().get();
+        }
+        return Optional.of(DynamicConstantDesc.ofNamed(
+                    ConstantDescs.BSM_INVOKE, kind.name().toLowerCase(),
+                CD_GROUP_LAYOUT, constants));
+    }
+
+    //hack: the declarations below are to make javadoc happy; we could have used generics in AbstractLayout
+    //but that causes issues with javadoc, see JDK-8224052
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public GroupLayout withName(String name) {
+        return (GroupLayout)super.withName(name);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public GroupLayout withBitAlignment(long alignmentBits) {
+        return (GroupLayout)super.withBitAlignment(alignmentBits);
+    }
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryAddress.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryAddress.java
new file mode 100644
index 00000000000..73c1c6a6957
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryAddress.java
@@ -0,0 +1,111 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.incubator.foreign;
+
+import jdk.internal.foreign.MemoryAddressImpl;
+
+/**
+ * A memory address encodes an offset within a given {@link MemorySegment}. Memory addresses are typically obtained
+ * using the {@link MemorySegment#baseAddress()} method; such addresses can then be adjusted as required,
+ * using {@link MemoryAddress#offset(long)}.
+ * <p>
+ * A memory address is typically used as the first argument in a memory access var handle call, to perform some operation
+ * on the underlying memory backing a given memory segment. Since a memory address is always associated with a memory segment,
+ * such access operations are always subject to spatial and temporal checks as enforced by the address' owning memory region.
+ * <p>
+ * All implementations of this interface must be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>;
+ * use of identity-sensitive operations (including reference equality ({@code ==}), identity hash code, or synchronization) on
+ * instances of {@code MemoryAddress} may have unpredictable results and should be avoided. The {@code equals} method should
+ * be used for comparisons.
+ * <p>
+ * Non-platform classes should not implement {@linkplain MemoryAddress} directly.
+ *
+ * @apiNote In the future, if the Java language permits, {@link MemoryAddress}
+ * may become a {@code sealed} interface, which would prohibit subclassing except by
+ * explicitly permitted types.
+ *
+ * @implSpec
+ * Implementations of this interface are immutable and thread-safe.
+ */
+public interface MemoryAddress {
+    /**
+     * Creates a new memory address with given offset (in bytes) from current one.
+     * @param l specified offset (in bytes), relative to this address, which should be used to create the new address.
+     * @return a new memory address with given offset from current one.
+     */
+    MemoryAddress offset(long l);
+
+    /**
+     * The offset of this memory address into the underlying segment.
+     *
+     * @return the offset
+     */
+    long offset();
+
+    /**
+     * The memory segment this address belongs to.
+     * @return The memory segment this address belongs to.
+     */
+    MemorySegment segment();
+
+    /**
+     * Compares the specified object with this address for equality. Returns {@code true} if and only if the specified
+     * object is also a address, and it is equal to this address.
+     *
+     * @param that the object to be compared for equality with this address.
+     * @return {@code true} if the specified object is equal to this address.
+     */
+    @Override
+    boolean equals(Object that);
+
+    /**
+     * Returns the hash code value for this address.
+     * @return the hash code value for this address.
+     */
+    @Override
+    int hashCode();
+
+    /**
+     * Perform bulk copy from source address to target address. More specifically, the bytes at addresses {@code src}
+     * through {@code src.offset(bytes - 1)} are copied into addresses {@code dst} through {@code dst.offset(bytes - 1)}.
+     * If the source and address ranges overlap, then the copying is performed as if the bytes at addresses {@code src}
+     * through {@code src.offset(bytes - 1)} were first copied into a temporary segment with size {@code bytes},
+     * and then the contents of the temporary segment were copied into the bytes at addresses {@code dst} through {@code dst.offset(bytes - 1)}.
+     * @param src the source address.
+     * @param dst the target address.
+     * @param bytes the number of bytes to be copied.
+     * @throws IndexOutOfBoundsException if {@code bytes < 0}, or if it is greater than the size of the segments
+     * associated with either {@code src} or {@code dst}.
+     * @throws IllegalStateException if either the source address or the target address belong to memory segments
+     * which have been already closed, or if access occurs from a thread other than the thread owning either segment.
+     * @throws UnsupportedOperationException if {@code dst} is associated with a read-only segment (see {@link MemorySegment#isReadOnly()}).
+     */
+    static void copy(MemoryAddress src, MemoryAddress dst, long bytes) {
+        MemoryAddressImpl.copy((MemoryAddressImpl)src, (MemoryAddressImpl)dst, bytes);
+    }
+
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryHandles.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryHandles.java
new file mode 100644
index 00000000000..c708ac5cc4c
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryHandles.java
@@ -0,0 +1,268 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.incubator.foreign;
+
+import jdk.internal.access.JavaLangInvokeAccess;
+import jdk.internal.access.SharedSecrets;
+import jdk.internal.foreign.Utils;
+import sun.invoke.util.Wrapper;
+
+import java.lang.invoke.VarHandle;
+import java.nio.ByteOrder;
+
+/**
+ * This class defines several factory methods for constructing and combining memory access var handles.
+ * To obtain a memory access var handle, clients must start from one of the <em>leaf</em> methods
+ * (see {@link MemoryHandles#varHandle(Class, ByteOrder)},
+ * {@link MemoryHandles#varHandle(Class, long, ByteOrder)}). This determines the variable type
+ * (all primitive types but {@code void} and {@code boolean} are supported), as well as the alignment constraint and the
+ * byte order associated to a memory access var handle. The resulting memory access var handle can then be combined in various ways
+ * to emulate different addressing modes. The var handles created by this class feature a <em>mandatory</em> coordinate type
+ * (of type {@link MemoryAddress}), and zero or more {@code long} coordinate types, which can be used to emulate
+ * multi-dimensional array indexing.
+ * <p>
+ * As an example, consider the memory layout expressed by a {@link SequenceLayout} instance constructed as follows:
+ * <blockquote><pre>{@code
+SequenceLayout seq = MemoryLayout.ofSequence(5,
+    MemoryLayout.ofStruct(
+        MemoryLayout.ofPaddingBits(32),
+        MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN).withName("value")
+    ));
+ * }</pre></blockquote>
+ * To access the member layout named {@code value}, we can construct a memory access var handle as follows:
+ * <blockquote><pre>{@code
+VarHandle handle = MemoryHandles.varHandle(int.class, ByteOrder.BIG_ENDIAN); //(MemoryAddress) -> int
+handle = MemoryHandles.withOffset(handle, 4); //(MemoryAddress) -> int
+handle = MemoryHandles.withStride(handle, 8); //(MemoryAddress, long) -> int
+ * }</pre></blockquote>
+ *
+ * <h2>Addressing mode</h2>
+ *
+ * The final memory location accessed by a memory access var handle can be computed as follows:
+ *
+ * <blockquote><pre>{@code
+address = base + offset
+ * }</pre></blockquote>
+ *
+ * where {@code base} denotes the address expressed by the {@link MemoryAddress} access coordinate, and {@code offset}
+ * can be expressed in the following form:
+ *
+ * <blockquote><pre>{@code
+offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
+ * }</pre></blockquote>
+ *
+ * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as optional {@code long}
+ * access coordinates, whereas {@code c_1}, {@code c_2}, ... {@code c_m} and {@code s_0}, {@code s_1}, ... {@code s_n} are
+ * <em>static</em> constants which are can be acquired through the {@link MemoryHandles#withOffset(VarHandle, long)}
+ * and the {@link MemoryHandles#withStride(VarHandle, long)} combinators, respectively.
+ *
+ * <h2><a id="memaccess-mode"></a>Alignment and access modes</h2>
+ *
+ * A memory access var handle is associated with an access size {@code S} and an alignment constraint {@code B}
+ * (both expressed in bytes). We say that a memory access operation is <em>fully aligned</em> if it occurs
+ * at a memory address {@code A} which is compatible with both alignment constraints {@code S} and {@code B}.
+ * If access is fully aligned then following access modes are supported and are
+ * guaranteed to support atomic access:
+ * <ul>
+ * <li>read write access modes for all {@code T}, with the exception of
+ *     access modes {@code get} and {@code set} for {@code long} and
+ *     {@code double} on 32-bit platforms.
+ * <li>atomic update access modes for {@code int}, {@code long},
+ *     {@code float} or {@code double}.
+ *     (Future major platform releases of the JDK may support additional
+ *     types for certain currently unsupported access modes.)
+ * <li>numeric atomic update access modes for {@code int} and {@code long}.
+ *     (Future major platform releases of the JDK may support additional
+ *     numeric types for certain currently unsupported access modes.)
+ * <li>bitwise atomic update access modes for {@code int} and {@code long}.
+ *     (Future major platform releases of the JDK may support additional
+ *     numeric types for certain currently unsupported access modes.)
+ * </ul>
+ *
+ * If {@code T} is {@code float} or {@code double} then atomic
+ * update access modes compare values using their bitwise representation
+ * (see {@link Float#floatToRawIntBits} and
+ * {@link Double#doubleToRawLongBits}, respectively).
+ * <p>
+ * Alternatively, a memory access operation is <em>partially aligned</em> if it occurs at a memory address {@code A}
+ * which is only compatible with the alignment constraint {@code B}; in such cases, access for anything other than the
+ * {@code get} and {@code set} access modes will result in an {@code IllegalStateException}. If access is partially aligned,
+ * atomic access is only guaranteed with respect to the largest power of two that divides the GCD of {@code A} and {@code S}.
+ * <p>
+ * Finally, in all other cases, we say that a memory access operation is <em>misaligned</em>; in such cases an
+ * {@code IllegalStateException} is thrown, irrespective of the access mode being used.
+ */
+public final class MemoryHandles {
+
+    private final static JavaLangInvokeAccess JLI = SharedSecrets.getJavaLangInvokeAccess();
+
+    private MemoryHandles() {
+        //sorry, just the one!
+    }
+
+    /**
+     * Creates a memory access var handle with the given carrier type and byte order.
+     *
+     * The resulting memory access var handle features a single {@link MemoryAddress} access coordinate,
+     * and its variable type is set by the given carrier type.
+     *
+     * The alignment constraint for the resulting memory access var handle is the same as the in memory size of the
+     * carrier type, and the accessed offset is set at zero.
+     *
+     * @apiNote the resulting var handle features certain <a href="#memaccess-mode">access mode restrictions</a>,
+     * which are common to all memory access var handles.
+     *
+     * @param carrier the carrier type. Valid carriers are {@code byte}, {@code short}, {@code char}, {@code int},
+     * {@code float}, {@code long}, and {@code double}.
+     * @param byteOrder the required byte order.
+     * @return the new memory access var handle.
+     * @throws IllegalArgumentException when an illegal carrier type is used
+     */
+    public static VarHandle varHandle(Class<?> carrier, ByteOrder byteOrder) {
+        checkCarrier(carrier);
+        return varHandle(carrier,
+                carrierSize(carrier),
+                byteOrder);
+    }
+
+    /**
+     * Creates a memory access var handle with the given carrier type, alignment constraint, and byte order.
+     *
+     * The resulting memory access var handle features a single {@link MemoryAddress} access coordinate,
+     * and its variable type is set by the given carrier type.
+     *
+     * The accessed offset is zero.
+     *
+     * @apiNote the resulting var handle features certain <a href="#memaccess-mode">access mode restrictions</a>,
+     * which are common to all memory access var handles.
+     *
+     * @param carrier the carrier type. Valid carriers are {@code byte}, {@code short}, {@code char}, {@code int},
+     * {@code float}, {@code long}, and {@code double}.
+     * @param alignmentBytes the alignment constraint (in bytes). Must be a power of two.
+     * @param byteOrder the required byte order.
+     * @return the new memory access var handle.
+     * @throws IllegalArgumentException if an illegal carrier type is used, or if {@code alignmentBytes} is not a power of two.
+     */
+    public static VarHandle varHandle(Class<?> carrier, long alignmentBytes, ByteOrder byteOrder) {
+        checkCarrier(carrier);
+
+        if (alignmentBytes <= 0
+                || (alignmentBytes & (alignmentBytes - 1)) != 0) { // is power of 2?
+            throw new IllegalArgumentException("Bad alignment: " + alignmentBytes);
+        }
+
+        return JLI.memoryAddressViewVarHandle(carrier, alignmentBytes - 1, byteOrder, 0, new long[]{});
+    }
+
+    /**
+     * Creates a memory access var handle with a fixed offset added to the accessed offset. That is,
+     * if the target memory access var handle accesses a memory location at offset <em>O</em>, the new memory access var
+     * handle will access a memory location at offset <em>O' + O</em>.
+     *
+     * The resulting memory access var handle will feature the same access coordinates as the ones in the target memory access var handle.
+     *
+     * @apiNote the resulting var handle features certain <a href="#memaccess-mode">access mode restrictions</a>,
+     * which are common to all memory access var handles.
+     *
+     * @param target the target memory access handle to access after the offset adjustment.
+     * @param bytesOffset the offset, in bytes. Must be positive or zero.
+     * @return the new memory access var handle.
+     * @throws IllegalArgumentException when the target var handle is not a memory access var handle,
+     * or when {@code bytesOffset < 0}, or otherwise incompatible with the alignment constraint.
+     */
+    public static VarHandle withOffset(VarHandle target, long bytesOffset) {
+        if (bytesOffset < 0) {
+            throw new IllegalArgumentException("Illegal offset: " + bytesOffset);
+        }
+
+        long alignMask = JLI.memoryAddressAlignmentMask(target);
+
+        if ((bytesOffset & alignMask) != 0) {
+            throw new IllegalArgumentException("Offset " + bytesOffset + " does not conform to alignment " + (alignMask + 1));
+        }
+
+        return JLI.memoryAddressViewVarHandle(
+                JLI.memoryAddressCarrier(target),
+                alignMask,
+                JLI.memoryAddressByteOrder(target),
+                JLI.memoryAddressOffset(target) + bytesOffset,
+                JLI.memoryAddressStrides(target));
+    }
+
+    /**
+     * Creates a memory access var handle with a <em>variable</em> offset added to the accessed offset.
+     * That is, if the target memory access var handle accesses a memory location at offset <em>O</em>,
+     * the new memory access var handle will access a memory location at offset <em>(S * X) + O</em>, where <em>S</em>
+     * is a constant <em>stride</em>, whereas <em>X</em> is a dynamic value that will be provided as an additional access
+     * coordinate (of type {@code long}). The new access coordinate will be <em>prepended</em> to the ones available
+     * in the target memory access var handles (if any).
+     *
+     * @apiNote the resulting var handle features certain <a href="#memaccess-mode">access mode restrictions</a>,
+     * which are common to all memory access var handles.
+     *
+     * @param target the target memory access handle to access after the scale adjustment.
+     * @param bytesStride the stride, in bytes, by which to multiply the coordinate value. Must be greater than zero.
+     * @return the new memory access var handle.
+     * @throws IllegalArgumentException when the target var handle is not a memory access var handle,
+     * or if {@code bytesStride <= 0}, or otherwise incompatible with the alignment constraint.
+     */
+    public static VarHandle withStride(VarHandle target, long bytesStride) {
+        if (bytesStride == 0) {
+            throw new IllegalArgumentException("Stride must be positive: " + bytesStride);
+        }
+
+        long alignMask = JLI.memoryAddressAlignmentMask(target);
+
+        if ((bytesStride & alignMask) != 0) {
+            throw new IllegalArgumentException("Stride " + bytesStride + " does not conform to alignment " + (alignMask + 1));
+        }
+
+        long offset = JLI.memoryAddressOffset(target);
+
+        long[] strides = JLI.memoryAddressStrides(target);
+        long[] newStrides = new long[strides.length + 1];
+        System.arraycopy(strides, 0, newStrides, 1, strides.length);
+        newStrides[0] = bytesStride;
+
+        return JLI.memoryAddressViewVarHandle(
+                JLI.memoryAddressCarrier(target),
+                alignMask,
+                JLI.memoryAddressByteOrder(target),
+                offset,
+                newStrides);
+    }
+
+    private static void checkCarrier(Class<?> carrier) {
+        if (!carrier.isPrimitive() || carrier == void.class || carrier == boolean.class) {
+            throw new IllegalArgumentException("Illegal carrier: " + carrier.getSimpleName());
+        }
+    }
+
+    private static long carrierSize(Class<?> carrier) {
+        long bitsAlignment = Math.max(8, Wrapper.forPrimitiveType(carrier).bitWidth());
+        return Utils.bitsToBytesOrThrow(bitsAlignment, IllegalStateException::new);
+    }
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryLayout.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryLayout.java
new file mode 100644
index 00000000000..bbb44e07594
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryLayout.java
@@ -0,0 +1,445 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.incubator.foreign;
+
+import jdk.internal.foreign.LayoutPath;
+import jdk.internal.foreign.Utils;
+
+import java.lang.constant.Constable;
+import java.lang.constant.DynamicConstantDesc;
+import java.lang.invoke.VarHandle;
+import java.nio.ByteOrder;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.OptionalLong;
+
+/**
+ * A memory layout can be used to describe the contents of a memory segment in a <em>language neutral</em> fashion.
+ * There are two leaves in the layout hierarchy, <em>value layouts</em>, which are used to represent values of given size and kind (see
+ * {@link ValueLayout}) and <em>padding layouts</em> which are used, as the name suggests, to represent a portion of a memory
+ * segment whose contents should be ignored, and which are primarily present for alignment reasons (see {@link MemoryLayout#ofPaddingBits(long)}).
+ * Some common value layout constants are defined in the {@link MemoryLayouts} class.
+ * <p>
+ * More complex layouts can be derived from simpler ones: a <em>sequence layout</em> denotes a repetition of one or more
+ * element layout (see {@link SequenceLayout}); a <em>group layout</em> denotes an aggregation of (typically) heterogeneous
+ * member layouts (see {@link GroupLayout}).
+ * <p>
+ * All implementations of this interface must be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>;
+ * use of identity-sensitive operations (including reference equality ({@code ==}), identity hash code, or synchronization) on
+ * instances of {@code MemoryLayout} may have unpredictable results and should be avoided. The {@code equals} method should
+ * be used for comparisons.
+ * <p>
+ * Non-platform classes should not implement {@linkplain MemoryLayout} directly.
+ *
+ * <h2>Size, alignment and byte order</h2>
+ *
+ * All layouts have a size; layout size for value and padding layouts is always explicitly denoted; this means that a layout description
+ * always has the same size in bits, regardless of the platform in which it is used. For derived layouts, the size is computed
+ * as follows:
+ * <ul>
+ *     <li>for a <em>finite</em> sequence layout <em>S</em> whose element layout is <em>E</em> and size is L,
+ *     the size of <em>S</em> is that of <em>E, multiplied by L</em></li>
+ *     <li>the size of an <em>unbounded</em> sequence layout is <em>unknown</em></li>
+ *     <li>for a group layout <em>G</em> with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose sizes are
+ *     <em>S1</em>, <em>S2</em>, ... <em>Sn</em>, respectively, the size of <em>G</em> is either <em>S1 + S2 + ... + Sn</em> or
+ *     <em>max(S1, S2, ... Sn)</em> depending on whether the group is a <em>struct</em> or an <em>union</em>, respectively</li>
+ * </ul>
+ * <p>
+ * Furthermore, all layouts feature a <em>natural alignment</em> which can be inferred as follows:
+ * <ul>
+ *     <li>for value and padding layout <em>L</em> whose size is <em>N</em>, the natural alignment of <em>L</em> is <em>N</em></li>
+ *     <li>for a sequence layout <em>S</em> whose element layout is <em>E</em>, the natural alignment of <em>S</em> is that of <em>E</em></li>
+ *     <li>for a group layout <em>G</em> with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose alignments are
+ *     <em>A1</em>, <em>A2</em>, ... <em>An</em>, respectively, the natural alignment of <em>G</em> is <em>max(A1, A2 ... An)</em></li>
+ * </ul>
+ * A layout's natural alignment can be overridden if needed (see {@link MemoryLayout#withBitAlignment(long)}), which can be useful to describe
+ * hyper-aligned layouts.
+ * <p>
+ * All value layouts have an <em>explicit</em> byte order (see {@link java.nio.ByteOrder}) which is set when the layout is created.
+ *
+ * <h2><a id = "layout-paths">Layout paths</a></h2>
+ *
+ * A <em>layout path</em> originates from a <em>root</em> layout (typically a group or a sequence layout) and terminates
+ * at a layout nested within the root layout - this is the layout <em>selected</em> by the layout path.
+ * Layout paths are typically expressed as a sequence of one or more {@link PathElement} instances.
+ * <p>
+ * Layout paths are useful in order to e.g. to obtain offset of leaf elements inside arbitrarily nested layouts
+ * (see {@link MemoryLayout#offset(PathElement...)}), or to quickly obtain a memory access handle corresponding to the selected
+ * layout (see {@link MemoryLayout#varHandle(Class, PathElement...)}).
+ * <p>
+ * Such <em>layout paths</em> can be constructed programmatically using the methods in this class.
+ * For instance, given a layout constructed as follows:
+ * <blockquote><pre>{@code
+SequenceLayout seq = MemoryLayout.ofSequence(5,
+    MemoryLayout.ofStruct(
+        MemoryLayout.ofPaddingBits(32),
+        MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN).withName("value")
+));
+ * }</pre></blockquote>
+ *
+ * We can obtain the offset of the member layout named <code>value</code> from <code>seq</code>, as follows:
+ * <blockquote><pre>{@code
+long valueOffset = seq.offset(PathElement.sequenceElement(), PathElement.groupElement("value"));
+ * }</pre></blockquote>
+ *
+ * Layout paths can feature one or more <em>free dimensions</em>. For instance, a layout path traversing
+ * an unspecified sequence element (that is, where one of the path component was obtained with the
+ * {@link PathElement#sequenceElement()} method) features an additional free dimension, which will have to be bound at runtime;
+ * that is, the memory access var handle associated with such a layout path expression will feature an extra {@code long}
+ * access coordinate. The layout path constructed in the above example features exactly one free dimension.
+ *
+ * @apiNote In the future, if the Java language permits, {@link MemoryLayout}
+ * may become a {@code sealed} interface, which would prohibit subclassing except by
+ * explicitly permitted types.
+ *
+ * @implSpec
+ * Implementations of this class are immutable and thread-safe.
+ */
+public interface MemoryLayout extends Constable {
+
+    /**
+     * Returns an {@link Optional} containing the nominal descriptor for this
+     * layout, if one can be constructed, or an empty {@link Optional}
+     * if one cannot be constructed.
+     *
+     * @return An {@link Optional} containing the resulting nominal descriptor,
+     * or an empty {@link Optional} if one cannot be constructed.
+     */
+    @Override
+    Optional<? extends DynamicConstantDesc<? extends MemoryLayout>> describeConstable();
+
+    /**
+     * Computes the layout size, in bits.
+     *
+     * @return the layout size, in bits.
+     * @throws UnsupportedOperationException if the layout is, or contains, a sequence layout with unspecified size (see {@link SequenceLayout}).
+     */
+    long bitSize();
+
+    /**
+     * Computes the layout size, in bytes.
+     *
+     * @return the layout size, in bytes.
+     * @throws UnsupportedOperationException if the layout is, or contains, a sequence layout with unspecified size (see {@link SequenceLayout}),
+     * or if {@code bitSize()} is not a multiple of 8.
+     */
+    default long byteSize() {
+        return Utils.bitsToBytesOrThrow(bitSize(),
+                () -> new UnsupportedOperationException("Cannot compute byte size; bit size is not a multiple of 8"));
+    }
+
+    /**
+     * Return the <em>name</em> (if any) associated with this layout.
+     *
+     * @return the layout <em>name</em> (if any).
+     * @see MemoryLayout#withName(String)
+     */
+    Optional<String> name();
+
+    /**
+     * Creates a new layout which features the desired layout <em>name</em>.
+     *
+     * @param name the layout name.
+     * @return a new layout which is the same as this layout, except for the <em>name</em> associated to it.
+     * @see MemoryLayout#name()
+     */
+    MemoryLayout withName(String name);
+
+    /**
+     * Returns the alignment constraint associated with this layout, expressed in bits. Layout alignment defines a power
+     * of two {@code A} which is the bit-wise alignment of the layout. If {@code A <= 8} then {@code A/8} is the number of
+     * bytes that must be aligned for any pointer that correctly points to this layout. Thus:
+     *
+     * <ul>
+     * <li>{@code A=8} means unaligned (in the usual sense), which is common in packets.</li>
+     * <li>{@code A=64} means word aligned (on LP64), {@code A=32} int aligned, {@code A=16} short aligned, etc.</li>
+     * <li>{@code A=512} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).</li>
+     * </ul>
+     *
+     * @return the layout alignment constraint, in bits.
+     */
+    long bitAlignment();
+
+    /**
+     * Returns the alignment constraint associated with this layout, expressed in bytes. Layout alignment defines a power
+     * of two {@code A} which is the byte-wise alignment of the layout, where {@code A} is the number of bytes that must be aligned
+     * for any pointer that correctly points to this layout. Thus:
+     *
+     * <ul>
+     * <li>{@code A=1} means unaligned (in the usual sense), which is common in packets.</li>
+     * <li>{@code A=8} means word aligned (on LP64), {@code A=4} int aligned, {@code A=2} short aligned, etc.</li>
+     * <li>{@code A=64} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).</li>
+     * </ul>
+     *
+     * @return the layout alignment constraint, in bytes.
+     * @throws UnsupportedOperationException if {@code bitAlignment()} is not a multiple of 8.
+     */
+    default long byteAlignment() {
+        return Utils.bitsToBytesOrThrow(bitAlignment(),
+                () -> new UnsupportedOperationException("Cannot compute byte alignment; bit alignment is not a multiple of 8"));
+    }
+
+    /**
+     * Creates a new layout which features the desired alignment constraint.
+     *
+     * @param bitAlignment the layout alignment constraint, expressed in bits.
+     * @return a new layout which is the same as this layout, except for the alignment constraint associated to it.
+     * @throws IllegalArgumentException if {@code bitAlignment} is not a power of two, or if it's less than than 8.
+     */
+    MemoryLayout withBitAlignment(long bitAlignment);
+
+    /**
+     * Computes the offset of the layout selected by a given layout path, where the path is considered rooted in this
+     * layout.
+     *
+     * @apiNote if the layout path has one (or more) free dimensions,
+     * the offset is computed as if all the indices corresponding to such dimensions were set to {@code 0}.
+     *
+     * @param elements the layout path elements.
+     * @return The offset of layout selected by a the layout path obtained by concatenating the path elements in {@code elements}.
+     * @throws IllegalArgumentException if the layout path obtained by concatenating the path elements in {@code elements}
+     * does not select a valid layout element.
+     */
+    default long offset(PathElement... elements) {
+        LayoutPath path = LayoutPath.rootPath(this);
+        for (PathElement e : elements) {
+            path = ((LayoutPath.PathElementImpl)e).apply(path);
+        }
+        return path.offset();
+    }
+
+    /**
+     * Creates a memory access var handle that can be used to dereference memory at the layout selected by a given layout path,
+     * where the path is considered rooted in this layout.
+     *
+     * @apiNote the resulting var handle will feature an additional {@code long} access coordinate for every
+     * unspecified sequence access component contained in this layout path. Moreover, the resulting var handle
+     * features certain <a href="MemoryHandles.html#memaccess-mode">access mode restrictions</a>, which are common to all memory access var handles.
+     *
+     * @param carrier the var handle carrier type.
+     * @param elements the layout path elements.
+     * @return a var handle which can be used to dereference memory at the layout denoted by given layout path.
+     * @throws UnsupportedOperationException if the layout path has one or more elements with incompatible alignment constraints.
+     * @throws IllegalArgumentException if the carrier does not represent a primitive type, if the carrier is {@code void},
+     * {@code boolean}, or if the layout path obtained by concatenating the path elements in {@code elements}
+     * does not select a value layout (see {@link ValueLayout}), or if the selected value layout has a size that
+     * that does not match that of the specified carrier type.
+     */
+    default VarHandle varHandle(Class<?> carrier, PathElement... elements) {
+        LayoutPath path = LayoutPath.rootPath(this);
+        for (PathElement e : elements) {
+            path = ((LayoutPath.PathElementImpl)e).apply(path);
+        }
+        return path.dereferenceHandle(carrier);
+    }
+
+    /**
+     * Instances of this class are used to form <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>. There
+     * are two kinds of path elements: <em>group path elements</em> and <em>sequence path elements</em>. Group
+     * path elements are used to select a given named member layout within a {@link GroupLayout}. Sequence
+     * path elements are used to select a sequence element layout within a {@link SequenceLayout}; selection
+     * of sequence element layout can be <em>explicit</em> (see {@link PathElement#sequenceElement(long)}) or
+     * <em>implicit</em> (see {@link PathElement#sequenceElement()}). When a path uses one or more implicit
+     * sequence path elements, it acquires additional <em>free dimensions</em>.
+     * <p>
+     * Non-platform classes should not implement {@linkplain PathElement} directly.
+     *
+     * @apiNote In the future, if the Java language permits, {@link PathElement}
+     * may become a {@code sealed} interface, which would prohibit subclassing except by
+     * explicitly permitted types.
+     *
+     * @implSpec
+     * Implementations of this interface are immutable and thread-safe.
+     */
+    interface PathElement {
+
+        /**
+         * Returns a path element which selects a member layout with given name from a given group layout.
+         * The path element returned by this method does not alter the number of free dimensions of any path
+         * that is combined with such element.
+         *
+         * @implSpec in case multiple group elements with a matching name exist, the path element returned by this
+         * method will select the first one; that is, the group element with lowest offset from current path is selected.
+         *
+         * @param name the name of the group element to be selected.
+         * @return a path element which selects the group element with given name.
+         * @throws NullPointerException if the specified group element name is {@code null}.
+         */
+        static PathElement groupElement(String name) {
+            Objects.requireNonNull(name);
+            return new LayoutPath.PathElementImpl(path -> path.groupElement(name));
+        }
+
+        /**
+         * Returns a path element which selects the element layout at the specified position in a given the sequence layout.
+         * The path element returned by this method does not alter the number of free dimensions of any path
+         * that is combined with such element.
+         *
+         * @param index the index of the sequence element to be selected.
+         * @return a path element which selects the sequence element layout with given index.
+         * @throws IllegalArgumentException if {@code index < 0}.
+         */
+        static PathElement sequenceElement(long index) {
+            if (index < 0) {
+                throw new IllegalArgumentException("Index must be positive: " + index);
+            }
+            return new LayoutPath.PathElementImpl(path -> path.sequenceElement(index));
+        }
+
+        /**
+         * Returns a path element which selects the element layout in a <em>range</em> of positions in a given the sequence layout,
+         * where the range is expressed as a pair of starting index (inclusive) {@code S} and step factor (which can also be negative)
+         * {@code F}.
+         * If a path with free dimensions {@code n} is combined with the path element returned by this method,
+         * the number of free dimensions of the resulting path will be {@code 1 + n}. If the free dimension associated
+         * with this path is bound by an index {@code I}, the resulting accessed offset can be obtained with the following
+         * formula:
+         * <blockquote><pre>{@code
+E * (S + I * F)
+         * }</pre></blockquote>
+         * where {@code E} is the size (in bytes) of the sequence element layout.
+         *
+         * @param start the index of the first sequence element to be selected.
+         * @param step the step factor at which subsequence sequence elements are to be selected.
+         * @return a path element which selects the sequence element layout with given index.
+         * @throws IllegalArgumentException if {@code start < 0}, or {@code step == 0}.
+         */
+        static PathElement sequenceElement(long start, long step) {
+            if (start < 0) {
+                throw new IllegalArgumentException("Start index must be positive: " + start);
+            }
+            if (step == 0) {
+                throw new IllegalArgumentException("Step must be != 0: " + step);
+            }
+            return new LayoutPath.PathElementImpl(path -> path.sequenceElement(start, step));
+        }
+
+        /**
+         * Returns a path element which selects an unspecified element layout from a given sequence layout.
+         * If a path with free dimensions {@code n} is combined with the path element returned by this method,
+         * the number of free dimensions of the resulting path will be {@code 1 + n}.
+         *
+         * @return a path element which selects an unspecified sequence element layout.
+         */
+        static PathElement sequenceElement() {
+            return new LayoutPath.PathElementImpl(LayoutPath::sequenceElement);
+        }
+    }
+
+    /**
+     * Compares the specified object with this layout for equality. Returns {@code true} if and only if the specified
+     * object is also a layout, and it is equal to this layout.
+     *
+     * @param that the object to be compared for equality with this layout.
+     * @return {@code true} if the specified object is equal to this layout.
+     */
+    boolean equals(Object that);
+
+    /**
+     * Returns the hash code value for this layout.
+     *
+     * @return the hash code value for this layout.
+     */
+    int hashCode();
+
+    /**
+     * Returns a string representation of this layout.
+     *
+     * @return a string representation of this layout.
+     */
+    @Override
+    String toString();
+
+    /**
+     * Create a new padding layout with given size.
+     *
+     * @param size the padding size in bits.
+     * @return the new selector layout.
+     * @throws IllegalArgumentException if {@code size <= 0}.
+     */
+    static MemoryLayout ofPaddingBits(long size) {
+        AbstractLayout.checkSize(size);
+        return new PaddingLayout(size);
+    }
+
+    /**
+     * Create a value layout of given byte order and size.
+     *
+     * @param size the value layout size.
+     * @param order the value layout's byte order.
+     * @return a new value layout.
+     * @throws IllegalArgumentException if {@code size <= 0}.
+     */
+    static ValueLayout ofValueBits(long size, ByteOrder order) {
+        AbstractLayout.checkSize(size);
+        return new ValueLayout(order, size);
+    }
+
+    /**
+     * Create a new sequence layout with given element layout and element count.
+     *
+     * @param elementCount the sequence element count.
+     * @param elementLayout the sequence element layout.
+     * @return the new sequence layout with given element layout and size.
+     * @throws IllegalArgumentException if {@code elementCount < 0}.
+     */
+    static SequenceLayout ofSequence(long elementCount, MemoryLayout elementLayout) {
+        AbstractLayout.checkSize(elementCount, true);
+        OptionalLong size = OptionalLong.of(elementCount);
+        return new SequenceLayout(size, elementLayout);
+    }
+
+    /**
+     * Create a new sequence layout, with unbounded element count and given element layout.
+     *
+     * @param elementLayout the element layout of the sequence layout.
+     * @return the new sequence layout with given element layout.
+     */
+    static SequenceLayout ofSequence(MemoryLayout elementLayout) {
+        return new SequenceLayout(OptionalLong.empty(), elementLayout);
+    }
+
+    /**
+     * Create a new <em>struct</em> group layout with given member layouts.
+     *
+     * @param elements The member layouts of the <em>struct</em> group layout.
+     * @return a new <em>struct</em> group layout with given member layouts.
+     */
+    static GroupLayout ofStruct(MemoryLayout... elements) {
+        return new GroupLayout(GroupLayout.Kind.STRUCT, List.of(elements));
+    }
+
+    /**
+     * Create a new <em>union</em> group layout with given member layouts.
+     *
+     * @param elements The member layouts of the <em>union</em> layout.
+     * @return a new <em>union</em> group layout with given member layouts.
+     */
+    static GroupLayout ofUnion(MemoryLayout... elements) {
+        return new GroupLayout(GroupLayout.Kind.UNION, List.of(elements));
+    }
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryLayouts.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryLayouts.java
new file mode 100644
index 00000000000..a2e5866266e
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryLayouts.java
@@ -0,0 +1,138 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.incubator.foreign;
+
+import java.nio.ByteOrder;
+
+/**
+ * This class defines useful layout constants. Some of the constants defined in this class are explicit in both
+ * size and byte order (see {@link #BITS_64_BE}), and can therefore be used to explicitly and unambiguously specify the
+ * contents of a memory segment. Other constants make implicit byte order assumptions (see
+ * {@link #JAVA_INT}); as such, these constants make it easy to interoperate with other serialization-centric APIs,
+ * such as {@link java.nio.ByteBuffer}.
+ */
+public final class MemoryLayouts {
+
+    private MemoryLayouts() {
+        //just the one, please
+    }
+
+    /**
+     * A value layout constant with size of one byte, and byte order set to {@link ByteOrder#LITTLE_ENDIAN}.
+     */
+    public static final ValueLayout BITS_8_LE = MemoryLayout.ofValueBits(8, ByteOrder.LITTLE_ENDIAN);
+
+    /**
+     * A value layout constant with size of two bytes, and byte order set to {@link ByteOrder#LITTLE_ENDIAN}.
+     */
+    public static final ValueLayout BITS_16_LE = MemoryLayout.ofValueBits(16, ByteOrder.LITTLE_ENDIAN);
+
+    /**
+     * A value layout constant with size of four bytes, and byte order set to {@link ByteOrder#LITTLE_ENDIAN}.
+     */
+    public static final ValueLayout BITS_32_LE = MemoryLayout.ofValueBits(32, ByteOrder.LITTLE_ENDIAN);
+
+    /**
+     * A value layout constant with size of eight bytes, and byte order set to {@link ByteOrder#LITTLE_ENDIAN}.
+     */
+    public static final ValueLayout BITS_64_LE = MemoryLayout.ofValueBits(64, ByteOrder.LITTLE_ENDIAN);
+
+    /**
+     * A value layout constant with size of one byte, and byte order set to {@link ByteOrder#BIG_ENDIAN}.
+     */
+    public static final ValueLayout BITS_8_BE = MemoryLayout.ofValueBits(8, ByteOrder.BIG_ENDIAN);
+
+    /**
+     * A value layout constant with size of two bytes, and byte order set to {@link ByteOrder#BIG_ENDIAN}.
+     */
+    public static final ValueLayout BITS_16_BE = MemoryLayout.ofValueBits(16, ByteOrder.BIG_ENDIAN);
+
+    /**
+     * A value layout constant with size of four bytes, and byte order set to {@link ByteOrder#BIG_ENDIAN}.
+     */
+    public static final ValueLayout BITS_32_BE = MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN);
+
+    /**
+     * A value layout constant with size of eight bytes, and byte order set to {@link ByteOrder#BIG_ENDIAN}.
+     */
+    public static final ValueLayout BITS_64_BE = MemoryLayout.ofValueBits(64, ByteOrder.BIG_ENDIAN);
+
+    /**
+     * A padding layout constant with size of one byte.
+     */
+    public static final MemoryLayout PAD_8 = MemoryLayout.ofPaddingBits(8);
+
+    /**
+     * A padding layout constant with size of two bytes.
+     */
+    public static final MemoryLayout PAD_16 = MemoryLayout.ofPaddingBits(16);
+
+    /**
+     * A padding layout constant with size of four bytes.
+     */
+    public static final MemoryLayout PAD_32 = MemoryLayout.ofPaddingBits(32);
+
+    /**
+     * A padding layout constant with size of eight bytes.
+     */
+    public static final MemoryLayout PAD_64 = MemoryLayout.ofPaddingBits(64);
+
+    /**
+     * A value layout constant whose size is the same as that of a Java {@code byte}, and byte order set to {@link ByteOrder#nativeOrder()}.
+     */
+    public static final ValueLayout JAVA_BYTE = MemoryLayout.ofValueBits(8, ByteOrder.nativeOrder());
+
+    /**
+     * A value layout constant whose size is the same as that of a Java {@code char}, and byte order set to {@link ByteOrder#nativeOrder()}.
+     */
+    public static final ValueLayout JAVA_CHAR = MemoryLayout.ofValueBits(16, ByteOrder.nativeOrder());
+
+    /**
+     * A value layout constant whose size is the same as that of a Java {@code short}, and byte order set to {@link ByteOrder#nativeOrder()}.
+     */
+    public static final ValueLayout JAVA_SHORT = MemoryLayout.ofValueBits(16, ByteOrder.nativeOrder());
+
+    /**
+     * A value layout constant whose size is the same as that of a Java {@code int}, and byte order set to {@link ByteOrder#nativeOrder()}.
+     */
+    public static final ValueLayout JAVA_INT = MemoryLayout.ofValueBits(32, ByteOrder.nativeOrder());
+
+    /**
+     * A value layout constant whose size is the same as that of a Java {@code long}, and byte order set to {@link ByteOrder#nativeOrder()}.
+     */
+    public static final ValueLayout JAVA_LONG = MemoryLayout.ofValueBits(64, ByteOrder.nativeOrder());
+
+    /**
+     * A value layout constant whose size is the same as that of a Java {@code float}, and byte order set to {@link ByteOrder#nativeOrder()}.
+     */
+    public static final ValueLayout JAVA_FLOAT = MemoryLayout.ofValueBits(32, ByteOrder.nativeOrder());
+
+    /**
+     * A value layout constant whose size is the same as that of a Java {@code double}, and byte order set to {@link ByteOrder#nativeOrder()}.
+     */
+    public static final ValueLayout JAVA_DOUBLE = MemoryLayout.ofValueBits(64, ByteOrder.nativeOrder());
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemorySegment.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemorySegment.java
new file mode 100644
index 00000000000..304a1bf19a0
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemorySegment.java
@@ -0,0 +1,430 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.incubator.foreign;
+
+import java.nio.ByteBuffer;
+
+import jdk.internal.foreign.Utils;
+
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.nio.file.Path;
+
+/**
+ * A memory segment models a contiguous region of memory. A memory segment is associated with both spatial
+ * and temporal bounds. Spatial bounds ensure that memory access operations on a memory segment cannot affect a memory location
+ * which falls <em>outside</em> the boundaries of the memory segment being accessed. Temporal checks ensure that memory access
+ * operations on a segment cannot occur after a memory segment has been closed (see {@link MemorySegment#close()}).
+ * <p>
+ * All implementations of this interface must be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>;
+ * use of identity-sensitive operations (including reference equality ({@code ==}), identity hash code, or synchronization) on
+ * instances of {@code MemorySegment} may have unpredictable results and should be avoided. The {@code equals} method should
+ * be used for comparisons.
+ * <p>
+ * Non-platform classes should not implement {@linkplain MemorySegment} directly.
+ *
+ * <h2>Constructing memory segments from different sources</h2>
+ *
+ * There are multiple ways to obtain a memory segment. First, memory segments backed by off-heap memory can
+ * be allocated using one of the many factory methods provided (see {@link MemorySegment#allocateNative(MemoryLayout)},
+ * {@link MemorySegment#allocateNative(long)} and {@link MemorySegment#allocateNative(long, long)}). Memory segments obtained
+ * in this way are called <em>native memory segments</em>.
+ * <p>
+ * It is also possible to obtain a memory segment backed by an existing heap-allocated Java array,
+ * using one of the provided factory methods (e.g. {@link MemorySegment#ofArray(int[])}). Memory segments obtained
+ * in this way are called <em>array memory segments</em>.
+ * <p>
+ * It is possible to obtain a memory segment backed by an existing Java byte buffer (see {@link ByteBuffer}),
+ * using the factory method {@link MemorySegment#ofByteBuffer(ByteBuffer)}.
+ * Memory segments obtained in this way are called <em>buffer memory segments</em>. Note that buffer memory segments might
+ * be backed by native memory (as in the case of native memory segments) or heap memory (as in the case of array memory segments),
+ * depending on the characteristics of the byte buffer instance the segment is associated with. For instance, a buffer memory
+ * segment obtained from a byte buffer created with the {@link ByteBuffer#allocateDirect(int)} method will be backed
+ * by native memory.
+ * <p>
+ * Finally, it is also possible to obtain a memory segment backed by a memory-mapped file using the factory method
+ * {@link MemorySegment#mapFromPath(Path, long, FileChannel.MapMode)}. Such memory segments are called <em>mapped memory segments</em>.
+ *
+ * <h2>Closing a memory segment</h2>
+ *
+ * Memory segments are closed explicitly (see {@link MemorySegment#close()}). In general when a segment is closed, all off-heap
+ * resources associated with it are released; this has different meanings depending on the kind of memory segment being
+ * considered:
+ * <ul>
+ *     <li>closing a native memory segment results in <em>freeing</em> the native memory associated with it</li>
+ *     <li>closing a mapped memory segment results in the backing memory-mapped file to be unmapped</li>
+ *     <li>closing an acquired memory segment <b>does not</b> result in the release of resources
+ *     (see the section on <a href="#thread-confinement">thread confinement</a> for more details)</li>
+ *     <li>closing a buffer, or a heap segment does not have any side-effect, other than marking the segment
+ *     as <em>not alive</em> (see {@link MemorySegment#isAlive()}). Also, since the buffer and heap segments might keep
+ *     strong references to the original buffer or array instance, it is the responsibility of clients to ensure that
+ *     these segments are discarded in a timely manner, so as not to prevent garbage collection to reclaim the underlying
+ *     objects.</li>
+ * </ul>
+ *
+ * <h2><a id = "thread-confinement">Thread confinement</a></h2>
+ *
+ * Memory segments support strong thread-confinement guarantees. Upon creation, they are assigned an <em>owner thread</em>,
+ * typically the thread which initiated the creation operation. After creation, only the owner thread will be allowed
+ * to directly manipulate the memory segment (e.g. close the memory segment) or access the underlying memory associated with
+ * the segment using a memory access var handle. Any attempt to perform such operations from a thread other than the
+ * owner thread will result in a runtime failure.
+ * <p>
+ * If a memory segment S owned by thread A needs to be used by thread B, B needs to explicitly <em>acquire</em> S,
+ * which will create a so called <em>acquired</em> memory segment owned by B (see {@link #acquire()}) backed by the same resources
+ * as S. A memory segment can be acquired multiple times by one or more threads; in that case, a memory segment S cannot
+ * be closed until all the acquired memory segments derived from S have been closed. Furthermore, closing an acquired
+ * memory segment does <em>not</em> trigger any deallocation action. It is therefore important that clients remember to
+ * explicitly close the original segment from which the acquired memory segments have been obtained in order to truly
+ * ensure that off-heap resources associated with the memory segment are released.
+ *
+ * <h2>Memory segment views</h2>
+ *
+ * Memory segments support <em>views</em>. It is possible to create an <em>immutable</em> view of a memory segment
+ * (see {@link MemorySegment#asReadOnly()}) which does not support write operations. It is also possible to create views
+ * whose spatial bounds are stricter than the ones of the original segment (see {@link MemorySegment#asSlice(long, long)}).
+ * <p>
+ * Temporal bounds of the original segment are inherited by the view; that is, closing a segment view, such as a sliced
+ * view, will cause the original segment to be closed; as such special care must be taken when sharing views
+ * between multiple clients. If a client want to protect itself against early closure of a segment by
+ * another actor, it is the responsibility of that client to take protective measures, such as calling
+ * {@link MemorySegment#acquire()} before sharing the view with another client.
+ * <p>
+ * To allow for interoperability with existing code, a byte buffer view can be obtained from a memory segment
+ * (see {@link #asByteBuffer()}). This can be useful, for instance, for those clients that want to keep using the
+ * {@link ByteBuffer} API, but need to operate on large memory segments. Byte buffers obtained in such a way support
+ * the same spatial and temporal access restrictions associated to the memory address from which they originated.
+ *
+ * @apiNote In the future, if the Java language permits, {@link MemorySegment}
+ * may become a {@code sealed} interface, which would prohibit subclassing except by
+ * explicitly permitted types.
+ *
+ * @implSpec
+ * Implementations of this interface are immutable and thread-safe.
+ */
+public interface MemorySegment extends AutoCloseable {
+
+    /**
+     * The base memory address associated with this memory segment.
+     * @return The base memory address.
+     */
+    MemoryAddress baseAddress();
+
+    /**
+     * Obtains an <a href="#thread-confinement">acquired</a> memory segment which can be used to access memory associated
+     * with this segment from the current thread. As a side-effect, this segment cannot be closed until the acquired
+     * view has been closed too (see {@link #close()}).
+     * @return an <a href="#thread-confinement">acquired</a> memory segment which can be used to access memory associated
+     * with this segment from the current thread.
+     * @throws IllegalStateException if this segment has been closed.
+     */
+    MemorySegment acquire();
+
+    /**
+     * Is this segment accessible from the current thread?
+     * @return true, if this segment is accessible from the current thread.
+     */
+    boolean isAccessible();
+
+    /**
+     * The size (in bytes) of this memory segment.
+     * @return The size (in bytes) of this memory segment.
+     */
+    long byteSize();
+
+    /**
+     * Obtains a read-only view of this segment. An attempt to write memory associated with a read-only memory segment
+     * will fail with {@link UnsupportedOperationException}.
+     * @return a read-only view of this segment.
+     * @throws IllegalStateException if this segment has been closed, or if access occurs from a thread other than the
+     * thread owning this segment.
+     */
+    MemorySegment asReadOnly();
+
+    /**
+     * Obtains a new memory segment view whose base address is the same as the base address of this segment plus a given offset,
+     * and whose new size is specified by the given argument.
+     * @param offset The new segment base offset (relative to the current segment base address), specified in bytes.
+     * @param newSize The new segment size, specified in bytes.
+     * @return a new memory segment view with updated base/limit addresses.
+     * @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}, {@code newSize < 0}, or {@code newSize > byteSize() - offset}
+     * @throws IllegalStateException if this segment has been closed, or if access occurs from a thread other than the
+     * thread owning this segment.
+     */
+    MemorySegment asSlice(long offset, long newSize);
+
+    /**
+     * Is this segment alive?
+     * @return true, if the segment is alive.
+     * @see MemorySegment#close()
+     */
+    boolean isAlive();
+
+    /**
+     * Is this segment read-only?
+     * @return true, if the segment is read-only.
+     * @see MemorySegment#asReadOnly()
+     */
+    boolean isReadOnly();
+
+    /**
+     * Closes this memory segment. Once a memory segment has been closed, any attempt to use the memory segment,
+     * or to access the memory associated with the segment will fail with {@link IllegalStateException}. Depending on
+     * the kind of memory segment being closed, calling this method further trigger deallocation of all the resources
+     * associated with the memory segment.
+     * @throws IllegalStateException if this segment has been closed, or if access occurs from a thread other than the
+     * thread owning this segment, or if existing acquired views of this segment are still in use (see {@link MemorySegment#acquire()}).
+     */
+    void close();
+
+    /**
+     * Wraps this segment in a {@link ByteBuffer}. Some of the properties of the returned buffer are linked to
+     * the properties of this segment. For instance, if this segment is <em>immutable</em>
+     * (see {@link MemorySegment#asReadOnly()}, then the resulting buffer is <em>read-only</em>
+     * (see {@link ByteBuffer#isReadOnly()}. Additionally, if this is a native memory segment, the resulting buffer is
+     * <em>direct</em> (see {@link ByteBuffer#isDirect()}).
+     * <p>
+     * The life-cycle of the returned buffer will be tied to that of this segment. That means that if the this segment
+     * is closed (see {@link MemorySegment#close()}, accessing the returned
+     * buffer will throw an {@link IllegalStateException}.
+     * <p>
+     * The resulting buffer's byte order is {@link java.nio.ByteOrder#BIG_ENDIAN}; this can be changed using
+     * {@link ByteBuffer#order(java.nio.ByteOrder)}.
+     *
+     * @return a {@link ByteBuffer} view of this memory segment.
+     * @throws UnsupportedOperationException if this segment cannot be mapped onto a {@link ByteBuffer} instance,
+     * e.g. because it models an heap-based segment that is not based on a {@code byte[]}), or if its size is greater
+     * than {@link Integer#MAX_VALUE}.
+     * @throws IllegalStateException if this segment has been closed, or if access occurs from a thread other than the
+     * thread owning this segment.
+     */
+    ByteBuffer asByteBuffer();
+
+    /**
+     * Copy the contents of this memory segment into a fresh byte array.
+     * @return a fresh byte array copy of this memory segment.
+     * @throws UnsupportedOperationException if this segment's contents cannot be copied into a {@link byte[]} instance,
+     * e.g. its size is greater than {@link Integer#MAX_VALUE}.
+     * @throws IllegalStateException if this segment has been closed, or if access occurs from a thread other than the
+     * thread owning this segment.
+     */
+    byte[] toByteArray();
+
+    /**
+     * Creates a new buffer memory segment that models the memory associated with the given byte
+     * buffer. The segment starts relative to the buffer's position (inclusive)
+     * and ends relative to the buffer's limit (exclusive).
+     * <p>
+     * The resulting memory segment keeps a reference to the backing buffer, to ensure it remains <em>reachable</em>
+     * for the life-time of the segment.
+     *
+     * @param bb the byte buffer backing the buffer memory segment.
+     * @return a new buffer memory segment.
+     */
+    static MemorySegment ofByteBuffer(ByteBuffer bb) {
+        return Utils.makeBufferSegment(bb);
+    }
+
+    /**
+     * Creates a new array memory segment that models the memory associated with a given heap-allocated byte array.
+     * <p>
+     * The resulting memory segment keeps a reference to the backing array, to ensure it remains <em>reachable</em>
+     * for the life-time of the segment.
+     *
+     * @param arr the primitive array backing the array memory segment.
+     * @return a new array memory segment.
+     */
+    static MemorySegment ofArray(byte[] arr) {
+        return Utils.makeArraySegment(arr);
+    }
+
+    /**
+     * Creates a new array memory segment that models the memory associated with a given heap-allocated char array.
+     * <p>
+     * The resulting memory segment keeps a reference to the backing array, to ensure it remains <em>reachable</em>
+     * for the life-time of the segment.
+     *
+     * @param arr the primitive array backing the array memory segment.
+     * @return a new array memory segment.
+     */
+    static MemorySegment ofArray(char[] arr) {
+        return Utils.makeArraySegment(arr);
+    }
+
+    /**
+     * Creates a new array memory segment that models the memory associated with a given heap-allocated short array.
+     * <p>
+     * The resulting memory segment keeps a reference to the backing array, to ensure it remains <em>reachable</em>
+     * for the life-time of the segment.
+     *
+     * @param arr the primitive array backing the array memory segment.
+     * @return a new array memory segment.
+     */
+    static MemorySegment ofArray(short[] arr) {
+        return Utils.makeArraySegment(arr);
+    }
+
+    /**
+     * Creates a new array memory segment that models the memory associated with a given heap-allocated int array.
+     * <p>
+     * The resulting memory segment keeps a reference to the backing array, to ensure it remains <em>reachable</em>
+     * for the life-time of the segment.
+     *
+     * @param arr the primitive array backing the array memory segment.
+     * @return a new array memory segment.
+     */
+    static MemorySegment ofArray(int[] arr) {
+        return Utils.makeArraySegment(arr);
+    }
+
+    /**
+     * Creates a new array memory segment that models the memory associated with a given heap-allocated float array.
+     * <p>
+     * The resulting memory segment keeps a reference to the backing array, to ensure it remains <em>reachable</em>
+     * for the life-time of the segment.
+     *
+     * @param arr the primitive array backing the array memory segment.
+     * @return a new array memory segment.
+     */
+    static MemorySegment ofArray(float[] arr) {
+        return Utils.makeArraySegment(arr);
+    }
+
+    /**
+     * Creates a new array memory segment that models the memory associated with a given heap-allocated long array.
+     * <p>
+     * The resulting memory segment keeps a reference to the backing array, to ensure it remains <em>reachable</em>
+     * for the life-time of the segment.
+     *
+     * @param arr the primitive array backing the array memory segment.
+     * @return a new array memory segment.
+     */
+    static MemorySegment ofArray(long[] arr) {
+        return Utils.makeArraySegment(arr);
+    }
+
+    /**
+     * Creates a new array memory segment that models the memory associated with a given heap-allocated double array.
+     * <p>
+     * The resulting memory segment keeps a reference to the backing array, to ensure it remains <em>reachable</em>
+     * for the life-time of the segment.
+     *
+     * @param arr the primitive array backing the array memory segment.
+     * @return a new array memory segment.
+     */
+    static MemorySegment ofArray(double[] arr) {
+        return Utils.makeArraySegment(arr);
+    }
+
+    /**
+     * Creates a new native memory segment that models a newly allocated block of off-heap memory with given layout.
+     * <p>
+     * This is equivalent to the following code:
+     * <blockquote><pre>{@code
+    allocateNative(layout.bytesSize(), layout.bytesAlignment());
+     * }</pre></blockquote>
+     *
+     * @implNote The initialization state of the contents of the block of off-heap memory associated with the returned native memory
+     * segment is unspecified and should not be relied upon. Moreover, a client is responsible to call the {@link MemorySegment#close()}
+     * on a native memory segment, to make sure the backing off-heap memory block is deallocated accordingly. Failure to do so
+     * will result in off-heap memory leaks.
+     *
+     * @param layout the layout of the off-heap memory block backing the native memory segment.
+     * @return a new native memory segment.
+     * @throws IllegalArgumentException if the specified layout has illegal size or alignment constraint.
+     */
+    static MemorySegment allocateNative(MemoryLayout layout) {
+        return allocateNative(layout.byteSize(), layout.byteAlignment());
+    }
+
+    /**
+     * Creates a new native memory segment that models a newly allocated block of off-heap memory with given size (in bytes).
+     * <p>
+     * This is equivalent to the following code:
+     * <blockquote><pre>{@code
+    allocateNative(bytesSize, 1);
+     * }</pre></blockquote>
+     *
+     * @implNote The initialization state of the contents of the block of off-heap memory associated with the returned native memory
+     * segment is unspecified and should not be relied upon. Moreover, a client is responsible to call the {@link MemorySegment#close()}
+     * on a native memory segment, to make sure the backing off-heap memory block is deallocated accordingly. Failure to do so
+     * will result in off-heap memory leaks.
+     *
+     * @param bytesSize the size (in bytes) of the off-heap memory block backing the native memory segment.
+     * @return a new native memory segment.
+     * @throws IllegalArgumentException if {@code bytesSize < 0}.
+     */
+    static MemorySegment allocateNative(long bytesSize) {
+        return allocateNative(bytesSize, 1);
+    }
+
+    /**
+     * Creates a new mapped memory segment that models a memory-mapped region of a file from a given path.
+     *
+     * @implNote When obtaining a mapped segment from a newly created file, the initialization state of the contents of the block
+     * of mapped memory associated with the returned mapped memory segment is unspecified and should not be relied upon.
+     *
+     * @param path the path to the file to memory map.
+     * @param bytesSize the size (in bytes) of the mapped memory backing the memory segment.
+     * @param mapMode a file mapping mode, see {@link FileChannel#map(FileChannel.MapMode, long, long)}.
+     * @return a new mapped memory segment.
+     * @throws IllegalArgumentException if {@code bytesSize < 0}.
+     * @throws UnsupportedOperationException if an unsupported map mode is specified.
+     * @throws IOException if the specified path does not point to an existing file, or if some other I/O error occurs.
+     */
+    static MemorySegment mapFromPath(Path path, long bytesSize, FileChannel.MapMode mapMode) throws IOException {
+        return Utils.makeMappedSegment(path, bytesSize, mapMode);
+    }
+
+    /**
+     * Creates a new native memory segment that models a newly allocated block of off-heap memory with given size and
+     * alignment constraint (in bytes).
+     *
+     * @implNote The initialization state of the contents of the block of off-heap memory associated with the returned native memory
+     * segment is unspecified and should not be relied upon. Moreover, a client is responsible to call the {@link MemorySegment#close()}
+     * on a native memory segment, to make sure the backing off-heap memory block is deallocated accordingly. Failure to do so
+     * will result in off-heap memory leaks.
+     *
+     * @param bytesSize the size (in bytes) of the off-heap memory block backing the native memory segment.
+     * @param alignmentBytes the alignment constraint (in bytes) of the off-heap memory block backing the native memory segment.
+     * @return a new native memory segment.
+     * @throws IllegalArgumentException if {@code bytesSize < 0}, {@code alignmentBytes < 0}, or if {@code alignmentBytes}
+     * is not a power of 2.
+     */
+    static MemorySegment allocateNative(long bytesSize, long alignmentBytes) {
+        if (bytesSize <= 0) {
+            throw new IllegalArgumentException("Invalid allocation size : " + bytesSize);
+        }
+
+        if (alignmentBytes < 0 ||
+                ((alignmentBytes & (alignmentBytes - 1)) != 0L)) {
+            throw new IllegalArgumentException("Invalid alignment constraint : " + alignmentBytes);
+        }
+
+        return Utils.makeNativeSegment(bytesSize, alignmentBytes);
+    }
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/PaddingLayout.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/PaddingLayout.java
new file mode 100644
index 00000000000..49be622d5af
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/PaddingLayout.java
@@ -0,0 +1,111 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.incubator.foreign;
+
+import java.lang.constant.ConstantDescs;
+import java.lang.constant.DynamicConstantDesc;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.OptionalLong;
+
+/**
+ * A padding layout. A padding layout specifies the size of extra space which is typically not accessed by applications,
+ * and is typically used for aligning member layouts around word boundaries.
+ * <p>
+ * This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
+ * class; use of identity-sensitive operations (including reference equality
+ * ({@code ==}), identity hash code, or synchronization) on instances of
+ * {@code PaddingLayout} may have unpredictable results and should be avoided.
+ * The {@code equals} method should be used for comparisons.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ */
+/* package-private */ final class PaddingLayout extends AbstractLayout implements MemoryLayout {
+
+    PaddingLayout(long size) {
+        this(size, size, Optional.empty());
+    }
+
+    PaddingLayout(long size, long alignment, Optional<String> name) {
+        super(OptionalLong.of(size), alignment, name);
+    }
+
+    @Override
+    public String toString() {
+        return decorateLayoutString("x" + bitSize());
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!super.equals(other)) {
+            return false;
+        }
+        if (!(other instanceof PaddingLayout)) {
+            return false;
+        }
+        PaddingLayout p = (PaddingLayout)other;
+        return bitSize() == p.bitSize();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), bitSize());
+    }
+
+    @Override
+    PaddingLayout dup(long alignment, Optional<String> name) {
+        return new PaddingLayout(bitSize(), alignment, name);
+    }
+
+    @Override
+    public Optional<DynamicConstantDesc<MemoryLayout>> describeConstable() {
+        return Optional.of(DynamicConstantDesc.ofNamed(ConstantDescs.BSM_INVOKE, "padding",
+                CD_LAYOUT, MH_PADDING, bitSize()));
+    }
+
+    //hack: the declarations below are to make javadoc happy; we could have used generics in AbstractLayout
+    //but that causes issues with javadoc, see JDK-8224052
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public PaddingLayout withName(String name) {
+        return (PaddingLayout)super.withName(name);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public PaddingLayout withBitAlignment(long alignmentBits) {
+        return (PaddingLayout)super.withBitAlignment(alignmentBits);
+    }
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/SequenceLayout.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/SequenceLayout.java
new file mode 100644
index 00000000000..e91bfa920aa
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/SequenceLayout.java
@@ -0,0 +1,161 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.incubator.foreign;
+
+import java.lang.constant.ConstantDescs;
+import java.lang.constant.DynamicConstantDesc;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.OptionalLong;
+
+/**
+ * A sequence layout. A sequence layout is used to denote a repetition of a given layout, also called the sequence layout's <em>element layout</em>.
+ * The repetition count, where it exists (e.g. for <em>finite</em> sequence layouts) is said to be the the sequence layout's <em>element count</em>.
+ * A finite sequence layout can be thought of as a group layout where the sequence layout's element layout is repeated a number of times
+ * that is equal to the sequence layout's element count. In other words this layout:
+ *
+ * <pre>{@code
+MemoryLayout.ofSequence(3, MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN));
+ * }</pre>
+ *
+ * is equivalent to the following layout:
+ *
+ * <pre>{@code
+MemoryLayout.ofStruct(
+    MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN),
+    MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN),
+    MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN));
+ * }</pre>
+ *
+ * <p>
+ * This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
+ * class; use of identity-sensitive operations (including reference equality
+ * ({@code ==}), identity hash code, or synchronization) on instances of
+ * {@code SequenceLayout} may have unpredictable results and should be avoided.
+ * The {@code equals} method should be used for comparisons.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ */
+public final class SequenceLayout extends AbstractLayout {
+
+    private final OptionalLong elemCount;
+    private final MemoryLayout elementLayout;
+
+    SequenceLayout(OptionalLong elemCount, MemoryLayout elementLayout) {
+        this(elemCount, elementLayout, elementLayout.bitAlignment(), Optional.empty());
+    }
+
+    SequenceLayout(OptionalLong elemCount, MemoryLayout elementLayout, long alignment, Optional<String> name) {
+        super(elemCount.isPresent() && AbstractLayout.optSize(elementLayout).isPresent() ?
+                OptionalLong.of(elemCount.getAsLong() * elementLayout.bitSize()) :
+                OptionalLong.empty(), alignment, name);
+        this.elemCount = elemCount;
+        this.elementLayout = elementLayout;
+    }
+
+    /**
+     * Returns the element layout associated with this sequence layout.
+     *
+     * @return The element layout associated with this sequence layout.
+     */
+    public MemoryLayout elementLayout() {
+        return elementLayout;
+    }
+
+    /**
+     * Returns the element count of this sequence layout (if any).
+     *
+     * @return the element count of this sequence layout (if any).
+     */
+    public OptionalLong elementCount() {
+        return elemCount;
+    }
+
+    @Override
+    public String toString() {
+        return decorateLayoutString(String.format("[%s:%s]",
+                elemCount.isPresent() ? elemCount.getAsLong() : "", elementLayout));
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!super.equals(other)) {
+            return false;
+        }
+        if (!(other instanceof SequenceLayout)) {
+            return false;
+        }
+        SequenceLayout s = (SequenceLayout)other;
+        return elemCount.equals(s.elemCount) && elementLayout.equals(s.elementLayout);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), elemCount, elementLayout);
+    }
+
+    @Override
+    SequenceLayout dup(long alignment, Optional<String> name) {
+        return new SequenceLayout(elementCount(), elementLayout, alignment, name);
+    }
+
+    @Override
+    boolean hasNaturalAlignment() {
+        return alignment == elementLayout.bitAlignment();
+    }
+
+    @Override
+    public Optional<DynamicConstantDesc<SequenceLayout>> describeConstable() {
+        return elemCount.isPresent() ?
+                Optional.of(DynamicConstantDesc.ofNamed(ConstantDescs.BSM_INVOKE, "value",
+                        CD_SEQUENCE_LAYOUT, MH_SIZED_SEQUENCE, elemCount.getAsLong(), elementLayout.describeConstable().get())) :
+                Optional.of(DynamicConstantDesc.ofNamed(ConstantDescs.BSM_INVOKE, "value",
+                        CD_SEQUENCE_LAYOUT, MH_UNSIZED_SEQUENCE, elementLayout.describeConstable().get()));
+    }
+
+    //hack: the declarations below are to make javadoc happy; we could have used generics in AbstractLayout
+    //but that causes issues with javadoc, see JDK-8224052
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public SequenceLayout withName(String name) {
+        return (SequenceLayout)super.withName(name);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public SequenceLayout withBitAlignment(long alignmentBits) {
+        return (SequenceLayout)super.withBitAlignment(alignmentBits);
+    }
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/ValueLayout.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/ValueLayout.java
new file mode 100644
index 00000000000..e0e45f68ffd
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/ValueLayout.java
@@ -0,0 +1,140 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.incubator.foreign;
+
+import java.lang.constant.ConstantDescs;
+import java.lang.constant.DynamicConstantDesc;
+import java.lang.constant.MethodHandleDesc;
+import java.nio.ByteOrder;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.OptionalLong;
+
+/**
+ * A value layout. A value layout is used to model the memory layout associated with values of basic data types, such as <em>integral</em> types
+ * (either signed or unsigned) and <em>floating-point</em> types. Each value layout has a size and a byte order (see {@link ByteOrder}).
+ *
+ * <p>
+ * This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
+ * class; use of identity-sensitive operations (including reference equality
+ * ({@code ==}), identity hash code, or synchronization) on instances of
+ * {@code ValueLayout} may have unpredictable results and should be avoided.
+ * The {@code equals} method should be used for comparisons.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ */
+public final class ValueLayout extends AbstractLayout implements MemoryLayout {
+
+    private final ByteOrder order;
+
+    ValueLayout(ByteOrder order, long size) {
+        this(order, size, size, Optional.empty());
+    }
+
+    ValueLayout(ByteOrder order, long size, long alignment, Optional<String> name) {
+        super(OptionalLong.of(size), alignment, name);
+        this.order = order;
+    }
+
+    /**
+     * Returns the value's byte order.
+     *
+     * @return the value's  byte order.
+     */
+    public ByteOrder order() {
+        return order;
+    }
+
+    /**
+     * Returns a new value layout with given byte order.
+     *
+     * @param order the desired byte order.
+     * @return a new value layout with given byte order.
+     */
+    public ValueLayout withOrder(ByteOrder order) {
+        return new ValueLayout(order, bitSize(), alignment, optName());
+    }
+
+    @Override
+    public String toString() {
+        return decorateLayoutString(String.format("%s%d",
+                order == ByteOrder.BIG_ENDIAN ? "B" : "b",
+                bitSize()));
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!super.equals(other)) {
+            return false;
+        }
+        if (!(other instanceof ValueLayout)) {
+            return false;
+        }
+        ValueLayout v = (ValueLayout)other;
+        return order.equals(v.order) &&
+            bitSize() == v.bitSize() &&
+            alignment == v.alignment;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), order, bitSize(), alignment);
+    }
+
+    @Override
+    ValueLayout dup(long alignment, Optional<String> name) {
+        return new ValueLayout(order, bitSize(), alignment, name);
+    }
+
+    @Override
+    public Optional<DynamicConstantDesc<ValueLayout>> describeConstable() {
+        return Optional.of(DynamicConstantDesc.ofNamed(ConstantDescs.BSM_INVOKE, "value",
+                CD_VALUE_LAYOUT, MH_VALUE, bitSize(), order == ByteOrder.BIG_ENDIAN ? BIG_ENDIAN : LITTLE_ENDIAN));
+    }
+
+    //hack: the declarations below are to make javadoc happy; we could have used generics in AbstractLayout
+    //but that causes issues with javadoc, see JDK-8224052
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ValueLayout withName(String name) {
+        return (ValueLayout)super.withName(name);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ValueLayout withBitAlignment(long alignmentBits) {
+        return (ValueLayout)super.withBitAlignment(alignmentBits);
+    }
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/package-info.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/package-info.java
new file mode 100644
index 00000000000..4f17619a02e
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/package-info.java
@@ -0,0 +1,90 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.
+ *
+ */
+
+/**
+ * <p> Classes to support low-level, safe and efficient memory access. For example:
+ *
+ * <pre>{@code
+static final VarHandle intHandle = MemoryHandles.varHandle(int.class, ByteOrder.BIG_ENDIAN);
+
+try (MemorySegment segment = MemorySegment.allocateNative(10 * 4)) {
+   MemoryAddress base = segment.baseAddress();
+   for (long i = 0 ; i < 10 ; i++) {
+     intHandle.set(base.offset(i * 4), (int)i);
+   }
+ }
+ * }</pre>
+ *
+ * Here we create a var handle, namely {@code intHandle}, to manipulate values of the primitive type {@code int}, at
+ * a given memory location. We then create a <em>native</em> memory segment, that is, a memory segment backed by
+ * off-heap memory; the size of the segment is 40 bytes, enough to store 10 values of the primitive type {@code int}.
+ * The segment is created inside a <em>try-with-resources</em> construct: this idiom ensures that all the memory resources
+ * associated with the segment will be released at the end of the block. Inside the try-with-resources block, we initialize
+ * the contents of the memory segment; more specifically, if we view the memory segment as a set of 10 adjacent slots,
+ * {@code s[i]}, where {@code 0 <= i < 10}, where the size of each slot is exactly 4 bytes, the initialization logic above will set each slot
+ * so that {@code s[i] = i}, again where {@code 0 <= i < 10}.
+ *
+ * <p>
+ * The key abstractions introduced by this package are {@link jdk.incubator.foreign.MemorySegment} and {@link jdk.incubator.foreign.MemoryAddress}.
+ * The first models a contiguous memory region, which can reside either inside or outside the Java heap; the latter models an address - that is,
+ * an offset inside a given segment. A memory address represents the main access coordinate of a memory access var handle, which can be obtained
+ * using the combinator methods defined in the {@link jdk.incubator.foreign.MemoryHandles} class. Finally, the {@link jdk.incubator.foreign.MemoryLayout} class
+ * hierarchy enables description of <em>memory layouts</em> and basic operations such as computing the size in bytes of a given
+ * layout, obtain its alignment requirements, and so on. Memory layouts also provide an alternate, more abstract way, to produce
+ * memory access var handles, e.g. using <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>.
+ *
+ * <h2><a id="deallocation"></a>Deterministic deallocation</h2>
+ *
+ * When writing code that manipulates memory segments, especially if backed by memory which resides outside the Java heap, it is
+ * crucial that the resources associated with a memory segment are released when the segment is no longer in use, by calling the {@link jdk.incubator.foreign.MemorySegment#close()}
+ * method either explicitly, or implicitly, by relying on try-with-resources construct (as demonstrated in the example above).
+ * Closing a given memory segment is an <em>atomic</em> operation which can either succeed - and result in the underlying
+ * memory associated with the segment to be released, or <em>fail</em> with an exception.
+ * <p>
+ * The deterministic deallocation model differs significantly from the implicit strategies adopted within other APIs, most
+ * notably the {@link java.nio.ByteBuffer} API: in that case, when a native byte buffer is created (see {@link java.nio.ByteBuffer#allocateDirect(int)}),
+ * the underlying memory is not released until the byte buffer reference becomes <em>unreachable</em>. While implicit deallocation
+ * models such as this can be very convenient - clients do not have to remember to <em>close</em> a direct buffer - such models can also make it
+ * hard for clients to ensure that the memory associated with a direct buffer has indeed been released.
+ *
+ * <h2><a id="safety"></a>Safety</h2>
+ *
+ * This API provides strong safety guarantees when it comes to memory access. First, when dereferencing a memory segment using
+ * a memory address, such an address is validated (upon access), to make sure that it does not point to a memory location
+ * which resides <em>outside</em> the boundaries of the memory segment it refers to. We call this guarantee <em>spatial safety</em>.
+ * <p>
+ * Since memory segments can be closed (see above), a memory address is also validated (upon access) to make sure that
+ * the segment it belongs to has not been closed prematurely. We call this guarantee <em>temporal safety</em>. Note that,
+ * in the general case, guaranteeing temporal safety can be hard, as multiple threads could attempt to access and/or close
+ * the same memory segment concurrently. The memory access API addresses this problem by imposing strong
+ * <a href="MemorySegment.html#thread-confinement"><em>thread-confinement</em></a> guarantees on memory segments: each
+ * memory segment is associated with an owner thread, which is the only thread that can either access or close the segment.
+ * A thread other than the owner thread will have to explicitly <em>acquire</em> a segment in order to be able to use it.
+ * <p>
+ * Together, spatial and temporal safety ensure that each memory access operation either succeeds - and accesses a valid
+ * memory location - or fails.
+ */
+package jdk.incubator.foreign;
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/unsafe/ForeignUnsafe.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/unsafe/ForeignUnsafe.java
new file mode 100644
index 00000000000..ab87d9322c0
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/unsafe/ForeignUnsafe.java
@@ -0,0 +1,68 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.incubator.foreign.unsafe;
+
+import jdk.incubator.foreign.MemoryAddress;
+import jdk.internal.foreign.MemoryAddressImpl;
+
+/**
+ * Unsafe methods to allow interop between sun.misc.unsafe and memory access API.
+ */
+public final class ForeignUnsafe {
+
+    private ForeignUnsafe() {
+        //just the one, please
+    }
+
+    // The following methods can be used in conjunction with the java.foreign API.
+
+    /**
+     * Obtain the base object (if any) associated with this address. This can be used in conjunction with
+     * {@link #getUnsafeOffset(MemoryAddress)} in order to obtain a base/offset addressing coordinate pair
+     * to be used with methods like {@link sun.misc.Unsafe#getInt(Object, long)} and the likes.
+     *
+     * @param address the address whose base object is to be obtained.
+     * @return the base object associated with the address, or {@code null}.
+     */
+    public static Object getUnsafeBase(MemoryAddress address) {
+        return ((MemoryAddressImpl)address).unsafeGetBase();
+    }
+
+    /**
+     * Obtain the offset associated with this address. If {@link #getUnsafeBase(MemoryAddress)} returns {@code null} on the passed
+     * address, then the offset is to be interpreted as the (absolute) numerical value associated said address.
+     * Alternatively, the offset represents the displacement of a field or an array element within the containing
+     * base object. This can be used in conjunction with {@link #getUnsafeBase(MemoryAddress)} in order to obtain a base/offset
+     * addressing coordinate pair to be used with methods like {@link sun.misc.Unsafe#getInt(Object, long)} and the likes.
+     *
+     * @param address the address whose offset is to be obtained.
+     * @return the offset associated with the address.
+     */
+    public static long getUnsafeOffset(MemoryAddress address) {
+        return ((MemoryAddressImpl)address).unsafeGetOffset();
+    }
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/LayoutPath.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/LayoutPath.java
new file mode 100644
index 00000000000..9055436f9cf
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/LayoutPath.java
@@ -0,0 +1,216 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.internal.foreign;
+
+import jdk.incubator.foreign.MemoryLayout;
+import jdk.internal.access.JavaLangInvokeAccess;
+import jdk.internal.access.SharedSecrets;
+import sun.invoke.util.Wrapper;
+
+import jdk.incubator.foreign.GroupLayout;
+import jdk.incubator.foreign.SequenceLayout;
+import jdk.incubator.foreign.ValueLayout;
+import java.lang.invoke.VarHandle;
+import java.util.function.UnaryOperator;
+import java.util.stream.LongStream;
+
+/**
+ * This class provide support for constructing layout paths; that is, starting from a root path (see {@link #rootPath(MemoryLayout)},
+ * a path can be constructed by selecting layout elements using the selector methods provided by this class
+ * (see {@link #sequenceElement()}, {@link #sequenceElement(long)}, {@link #sequenceElement(long, long)}, {@link #groupElement(String)}).
+ * Once a path has been fully constructed, clients can ask for the offset associated with the layout element selected
+ * by the path (see {@link #offset}), or obtain a memory access var handle to access the selected layout element
+ * given an address pointing to a segment associated with the root layout (see {@link #dereferenceHandle(Class)}).
+ */
+public class LayoutPath {
+
+    private static JavaLangInvokeAccess JLI = SharedSecrets.getJavaLangInvokeAccess();
+
+    private final MemoryLayout layout;
+    private final long offset;
+    private final LayoutPath enclosing;
+    private final long[] strides;
+
+    private LayoutPath(MemoryLayout layout, long offset, long[] strides, LayoutPath enclosing) {
+        this.layout = layout;
+        this.offset = offset;
+        this.strides = strides;
+        this.enclosing = enclosing;
+    }
+
+    // Layout path selector methods
+
+    public LayoutPath sequenceElement() {
+        check(SequenceLayout.class, "attempting to select a sequence element from a non-sequence layout");
+        SequenceLayout seq = (SequenceLayout)layout;
+        MemoryLayout elem = seq.elementLayout();
+        return LayoutPath.nestedPath(elem, offset, addStride(elem.bitSize()), this);
+    }
+
+    public LayoutPath sequenceElement(long start, long step) {
+        check(SequenceLayout.class, "attempting to select a sequence element from a non-sequence layout");
+        SequenceLayout seq = (SequenceLayout)layout;
+        checkSequenceBounds(seq, start);
+        MemoryLayout elem = seq.elementLayout();
+        long elemSize = elem.bitSize();
+        return LayoutPath.nestedPath(elem, offset + (start * elemSize), addStride(elemSize * step), this);
+    }
+
+    public LayoutPath sequenceElement(long index) {
+        check(SequenceLayout.class, "attempting to select a sequence element from a non-sequence layout");
+        SequenceLayout seq = (SequenceLayout)layout;
+        checkSequenceBounds(seq, index);
+        long elemOffset = 0;
+        if (index > 0) {
+            //if index == 0, we do not depend on sequence element size, so skip
+            long elemSize = seq.elementLayout().bitSize();
+            elemOffset = elemSize * index;
+        }
+        return LayoutPath.nestedPath(seq.elementLayout(), offset + elemOffset, strides, this);
+    }
+
+    public LayoutPath groupElement(String name) {
+        check(GroupLayout.class, "attempting to select a group element from a non-group layout");
+        GroupLayout g = (GroupLayout)layout;
+        long offset = 0;
+        MemoryLayout elem = null;
+        for (int i = 0; i < g.memberLayouts().size(); i++) {
+            MemoryLayout l = g.memberLayouts().get(i);
+            if (l.name().isPresent() &&
+                l.name().get().equals(name)) {
+                elem = l;
+                break;
+            } else {
+                offset += l.bitSize();
+            }
+        }
+        if (elem == null) {
+            throw badLayoutPath("cannot resolve '" + name + "' in layout " + layout);
+        }
+        return LayoutPath.nestedPath(elem, this.offset + offset, strides, this);
+    }
+
+    // Layout path projections
+
+    public long offset() {
+        return offset;
+    }
+
+    public VarHandle dereferenceHandle(Class<?> carrier) {
+        if (!(layout instanceof ValueLayout)) {
+            throw badLayoutPath("layout path does not select a value layout");
+        }
+
+        if (!carrier.isPrimitive() || carrier == void.class || carrier == boolean.class // illegal carrier?
+                || Wrapper.forPrimitiveType(carrier).bitWidth() != layout.bitSize()) { // carrier has the right size?
+            throw new IllegalArgumentException("Invalid carrier: " + carrier + ", for layout " + layout);
+        }
+
+        checkAlignment(this);
+
+        return JLI.memoryAddressViewVarHandle(
+                carrier,
+                layout.byteAlignment() - 1, //mask
+                ((ValueLayout) layout).order(),
+                Utils.bitsToBytesOrThrow(offset, IllegalStateException::new),
+                LongStream.of(strides).map(s -> Utils.bitsToBytesOrThrow(s, IllegalStateException::new)).toArray());
+    }
+
+    // Layout path construction
+
+    public static LayoutPath rootPath(MemoryLayout layout) {
+        return new LayoutPath(layout, 0L, EMPTY_STRIDES, null);
+    }
+
+    private static LayoutPath nestedPath(MemoryLayout layout, long offset, long[] strides, LayoutPath encl) {
+        return new LayoutPath(layout, offset, strides, encl);
+    }
+
+    // Helper methods
+
+    private void check(Class<?> layoutClass, String msg) {
+        if (!layoutClass.isAssignableFrom(layout.getClass())) {
+            throw badLayoutPath(msg);
+        }
+    }
+
+    private void checkSequenceBounds(SequenceLayout seq, long index) {
+        if (seq.elementCount().isPresent() && index >= seq.elementCount().getAsLong()) {
+            throw badLayoutPath(String.format("Sequence index out of bound; found: %d, size: %d", index, seq.elementCount().getAsLong()));
+        }
+    }
+
+    private static IllegalArgumentException badLayoutPath(String cause) {
+        return new IllegalArgumentException("Bad layout path: " + cause);
+    }
+
+    private static void checkAlignment(LayoutPath path) {
+        MemoryLayout layout = path.layout;
+        long alignment = layout.bitAlignment();
+        if (path.offset % alignment != 0) {
+            throw new UnsupportedOperationException("Invalid alignment requirements for layout " + layout);
+        }
+        for (long stride : path.strides) {
+            if (stride % alignment != 0) {
+                throw new UnsupportedOperationException("Alignment requirements for layout " + layout + " do not match stride " + stride);
+            }
+        }
+        LayoutPath encl = path.enclosing;
+        if (encl != null) {
+            if (encl.layout.bitAlignment() < alignment) {
+                throw new UnsupportedOperationException("Alignment requirements for layout " + layout + " do not match those for enclosing layout " + encl.layout);
+            }
+            checkAlignment(encl);
+        }
+    }
+
+    private long[] addStride(long stride) {
+        long[] newStrides = new long[strides.length + 1];
+        System.arraycopy(strides, 0, newStrides, 0, strides.length);
+        newStrides[strides.length] = stride;
+        return newStrides;
+    }
+
+    private static long[] EMPTY_STRIDES = new long[0];
+
+    /**
+     * This class provides an immutable implementation for the {@code PathElement} interface. A path element implementation
+     * is simply a pointer to one of the selector methods provided by the {@code LayoutPath} class.
+     */
+    public static class PathElementImpl implements MemoryLayout.PathElement, UnaryOperator<LayoutPath> {
+
+        final UnaryOperator<LayoutPath> pathOp;
+
+        public PathElementImpl(UnaryOperator<LayoutPath> pathOp) {
+            this.pathOp = pathOp;
+        }
+
+        @Override
+        public LayoutPath apply(LayoutPath layoutPath) {
+            return pathOp.apply(layoutPath);
+        }
+    }
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MemoryAddressImpl.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MemoryAddressImpl.java
new file mode 100644
index 00000000000..a5f0e3ce8f2
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MemoryAddressImpl.java
@@ -0,0 +1,117 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.internal.foreign;
+
+import jdk.internal.access.foreign.MemoryAddressProxy;
+import jdk.internal.misc.Unsafe;
+
+import jdk.incubator.foreign.MemoryAddress;
+import jdk.incubator.foreign.MemorySegment;
+
+import java.lang.ref.Reference;
+import java.util.Objects;
+
+/**
+ * This class provides an immutable implementation for the {@code MemoryAddress} interface. This class contains information
+ * about the segment this address is associated with, as well as an offset into such segment.
+ */
+public final class MemoryAddressImpl implements MemoryAddress, MemoryAddressProxy {
+
+    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
+    private final MemorySegmentImpl segment;
+    private final long offset;
+
+    public MemoryAddressImpl(MemorySegmentImpl segment, long offset) {
+        this.segment = Objects.requireNonNull(segment);
+        this.offset = offset;
+    }
+
+    public static void copy(MemoryAddressImpl src, MemoryAddressImpl dst, long size) {
+        src.checkAccess(0, size, true);
+        dst.checkAccess(0, size, false);
+        //check disjoint
+        long offsetSrc = src.unsafeGetOffset();
+        long offsetDst = dst.unsafeGetOffset();
+        Object baseSrc = src.unsafeGetBase();
+        Object baseDst = dst.unsafeGetBase();
+        UNSAFE.copyMemory(baseSrc, offsetSrc, baseDst, offsetDst, size);
+    }
+
+    // MemoryAddress methods
+
+    @Override
+    public long offset() {
+        return offset;
+    }
+
+    @Override
+    public MemorySegment segment() {
+        return segment;
+    }
+
+    @Override
+    public MemoryAddress offset(long bytes) {
+        return new MemoryAddressImpl(segment, offset + bytes);
+    }
+
+    // MemoryAddressProxy methods
+
+    public void checkAccess(long offset, long length, boolean readOnly) {
+        segment.checkRange(this.offset + offset, length, !readOnly);
+    }
+
+    public long unsafeGetOffset() {
+        return segment.min + offset;
+    }
+
+    public Object unsafeGetBase() {
+        return segment.base();
+    }
+
+    // Object methods
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(unsafeGetBase(), unsafeGetOffset());
+    }
+
+    @Override
+    public boolean equals(Object that) {
+        if (that instanceof MemoryAddressImpl) {
+            MemoryAddressImpl addr = (MemoryAddressImpl)that;
+            return Objects.equals(unsafeGetBase(), ((MemoryAddressImpl) that).unsafeGetBase()) &&
+                    unsafeGetOffset() == addr.unsafeGetOffset();
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "MemoryAddress{ region: " + segment + " offset=0x" + Long.toHexString(offset) + " }";
+    }
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MemoryScope.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MemoryScope.java
new file mode 100644
index 00000000000..969a3c02cda
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MemoryScope.java
@@ -0,0 +1,119 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.internal.foreign;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+/**
+ * This class manages the temporal bounds associated with a memory segment. A scope has a liveness bit, which is updated
+ * when the scope is closed (this operation is triggered by {@link MemorySegmentImpl#close()}). Furthermore, a scope is
+ * associated with an <em>atomic</em> counter which can be incremented (upon calling the {@link #acquire()} method),
+ * and is decremented (when a previously acquired segment is later closed).
+ */
+public final class MemoryScope {
+
+    //reference to keep hold onto
+    final Object ref;
+
+    int activeCount = UNACQUIRED;
+
+    final static VarHandle COUNT_HANDLE;
+
+    static {
+        try {
+            COUNT_HANDLE = MethodHandles.lookup().findVarHandle(MemoryScope.class, "activeCount", int.class);
+        } catch (Throwable ex) {
+            throw new ExceptionInInitializerError(ex);
+        }
+    }
+
+    final static int UNACQUIRED = 0;
+    final static int CLOSED = -1;
+    final static int MAX_ACQUIRE = Integer.MAX_VALUE;
+
+    final Runnable cleanupAction;
+
+    public MemoryScope(Object ref, Runnable cleanupAction) {
+        this.ref = ref;
+        this.cleanupAction = cleanupAction;
+    }
+
+    /**
+     * This method performs a full, thread-safe liveness check; can be used outside confinement thread.
+     */
+    final boolean isAliveThreadSafe() {
+        return ((int)COUNT_HANDLE.getVolatile(this)) != CLOSED;
+    }
+
+    /**
+     * This method performs a quick liveness check; must be called from the confinement thread.
+     */
+    final void checkAliveConfined() {
+        if (activeCount == CLOSED) {
+            throw new IllegalStateException("Segment is not alive");
+        }
+    }
+
+    MemoryScope acquire() {
+        int value;
+        do {
+            value = (int)COUNT_HANDLE.getVolatile(this);
+            if (value == CLOSED) {
+                //segment is not alive!
+                throw new IllegalStateException("Segment is not alive");
+            } else if (value == MAX_ACQUIRE) {
+                //overflow
+                throw new IllegalStateException("Segment acquire limit exceeded");
+            }
+        } while (!COUNT_HANDLE.compareAndSet(this, value, value + 1));
+        return new MemoryScope(ref, this::release);
+    }
+
+    private void release() {
+        int value;
+        do {
+            value = (int)COUNT_HANDLE.getVolatile(this);
+            if (value <= UNACQUIRED) {
+                //cannot get here - we can't close segment twice
+                throw new IllegalStateException();
+            }
+        } while (!COUNT_HANDLE.compareAndSet(this, value, value - 1));
+    }
+
+    void close() {
+        if (!COUNT_HANDLE.compareAndSet(this, UNACQUIRED, CLOSED)) {
+            //first check if already closed...
+            checkAliveConfined();
+            //...if not, then we have acquired views that are still active
+            throw new IllegalStateException("Cannot close a segment that has active acquired views");
+        }
+        if (cleanupAction != null) {
+            cleanupAction.run();
+        }
+    }
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MemorySegmentImpl.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MemorySegmentImpl.java
new file mode 100644
index 00000000000..25edc7b046b
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MemorySegmentImpl.java
@@ -0,0 +1,209 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.internal.foreign;
+
+import jdk.incubator.foreign.MemoryAddress;
+import jdk.incubator.foreign.MemorySegment;
+import jdk.internal.access.JavaNioAccess;
+import jdk.internal.access.SharedSecrets;
+import jdk.internal.access.foreign.MemorySegmentProxy;
+import jdk.internal.misc.Unsafe;
+
+import java.nio.ByteBuffer;
+import java.util.Objects;
+import java.util.Random;
+
+/**
+ * This class provides an immutable implementation for the {@code MemorySegment} interface. This class contains information
+ * about the segment's spatial and temporal bounds, as well as the addressing coordinates (base + offset) which allows
+ * unsafe access; each memory segment implementation is associated with an owner thread which is set at creation time.
+ * Access to certain sensitive operations on the memory segment will fail with {@code IllegalStateException} if the
+ * segment is either in an invalid state (e.g. it has already been closed) or if access occurs from a thread other
+ * than the owner thread. See {@link MemoryScope} for more details on management of temporal bounds.
+ */
+public final class MemorySegmentImpl implements MemorySegment, MemorySegmentProxy {
+
+    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+    private static final int BYTE_ARR_BASE = UNSAFE.arrayBaseOffset(byte[].class);
+
+    final long length;
+    final int mask;
+    final long min;
+    final Object base;
+    final Thread owner;
+    final MemoryScope scope;
+
+    final static int READ_ONLY = 1;
+    final static long NONCE = new Random().nextLong();
+
+    public MemorySegmentImpl(long min, Object base, long length, int mask, Thread owner, MemoryScope scope) {
+        this.length = length;
+        this.mask = mask;
+        this.min = min;
+        this.base = base;
+        this.owner = owner;
+        this.scope = scope;
+    }
+
+    // MemorySegment methods
+
+    @Override
+    public final MemorySegmentImpl asSlice(long offset, long newSize) {
+        checkValidState();
+        checkBounds(offset, newSize);
+        return new MemorySegmentImpl(min + offset, base, newSize, mask, owner, scope);
+    }
+
+    @Override
+    public MemorySegment acquire() {
+        return new MemorySegmentImpl(min, base, length, mask, Thread.currentThread(), scope.acquire());
+    }
+
+    @Override
+    public final MemoryAddress baseAddress() {
+        return new MemoryAddressImpl(this, 0);
+    }
+
+    @Override
+    public final long byteSize() {
+        return length;
+    }
+
+    @Override
+    public final MemorySegmentImpl asReadOnly() {
+        checkValidState();
+        return new MemorySegmentImpl(min, base, length, mask | READ_ONLY, owner, scope);
+    }
+
+    @Override
+    public final boolean isAlive() {
+        return scope.isAliveThreadSafe();
+    }
+
+    @Override
+    public final boolean isReadOnly() {
+        return isSet(READ_ONLY);
+    }
+
+    @Override
+    public boolean isAccessible() {
+        return owner == Thread.currentThread();
+    }
+
+    @Override
+    public final void close() {
+        checkValidState();
+        scope.close();
+    }
+
+    @Override
+    public ByteBuffer asByteBuffer() {
+        checkValidState();
+        checkIntSize("ByteBuffer");
+        JavaNioAccess nioAccess = SharedSecrets.getJavaNioAccess();
+        ByteBuffer _bb;
+        if (base() != null) {
+            if (!(base() instanceof byte[])) {
+                throw new UnsupportedOperationException("Not an address to an heap-allocated byte array");
+            }
+            _bb = nioAccess.newHeapByteBuffer((byte[]) base(), (int)min - BYTE_ARR_BASE, (int) length, this);
+        } else {
+            _bb = nioAccess.newDirectByteBuffer(min, (int) length, null, this);
+        }
+        if (isReadOnly()) {
+            //scope is IMMUTABLE - obtain a RO byte buffer
+            _bb = _bb.asReadOnlyBuffer();
+        }
+        return _bb;
+    }
+
+    @Override
+    public byte[] toByteArray() {
+        checkValidState();
+        checkIntSize("byte[]");
+        byte[] arr = new byte[(int)length];
+        MemorySegment arrSegment = MemorySegment.ofArray(arr);
+        MemoryAddress.copy(this.baseAddress(), arrSegment.baseAddress(), length);
+        return arr;
+    }
+
+    // MemorySegmentProxy methods
+
+    @Override
+    public final void checkValidState() {
+        if (owner != Thread.currentThread()) {
+            throw new IllegalStateException("Attempt to access segment outside owning thread");
+        }
+        scope.checkAliveConfined();
+    }
+
+    // Object methods
+
+    @Override
+    public String toString() {
+        return "MemorySegment{ id=0x" + Long.toHexString(id()) + " limit: " + byteSize() + " }";
+    }
+
+    // Helper methods
+
+    void checkRange(long offset, long length, boolean writeAccess) {
+        checkValidState();
+        if (isReadOnly() && writeAccess) {
+            throw new UnsupportedOperationException("Cannot write to read-only memory segment");
+        }
+        checkBounds(offset, length);
+    }
+
+    Object base() {
+        return base;
+    }
+
+    private boolean isSet(int mask) {
+        return (this.mask & mask) != 0;
+    }
+
+    private void checkIntSize(String typeName) {
+        if (length > (Integer.MAX_VALUE - 8)) { //conservative check
+            throw new UnsupportedOperationException(String.format("Segment is too large to wrap as %s. Size: %d", typeName, length));
+        }
+    }
+
+    private void checkBounds(long offset, long length) {
+        if (length < 0 ||
+                offset < 0 ||
+                offset > this.length - length) { // careful of overflow
+            throw new IndexOutOfBoundsException(String.format("Out of bound access on segment %s; new offset = %d; new length = %d",
+                this, offset, length));
+        }
+    }
+
+    private int id() {
+        //compute a stable and random id for this memory segment
+        return Math.abs(Objects.hash(base, min, NONCE));
+    }
+
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/Utils.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/Utils.java
new file mode 100644
index 00000000000..82debacab8b
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/Utils.java
@@ -0,0 +1,157 @@
+/*
+ *  Copyright (c) 2019, 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.  Oracle designates this
+ *  particular file as subject to the "Classpath" exception as provided
+ *  by Oracle in the LICENSE file that accompanied this code.
+ *
+ *  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.internal.foreign;
+
+import jdk.incubator.foreign.MemorySegment;
+import jdk.internal.access.JavaNioAccess;
+import jdk.internal.access.SharedSecrets;
+import jdk.internal.access.foreign.UnmapperProxy;
+import jdk.internal.misc.Unsafe;
+import sun.nio.ch.FileChannelImpl;
+import sun.security.action.GetBooleanAction;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.function.Supplier;
+
+/**
+ * This class contains misc helper functions to support creation of memory segments.
+ */
+public final class Utils {
+
+    private static Unsafe unsafe = Unsafe.getUnsafe();
+
+    // The maximum alignment supported by malloc - typically 16 on 64-bit platforms.
+    private final static long MAX_ALIGN = 16;
+
+    private static final JavaNioAccess javaNioAccess = SharedSecrets.getJavaNioAccess();
+
+    private static final boolean skipZeroMemory = GetBooleanAction.privilegedGetProperty("jdk.internal.foreign.skipZeroMemory");
+
+    public static long alignUp(long n, long alignment) {
+        return (n + alignment - 1) & -alignment;
+    }
+
+    public static long bitsToBytesOrThrow(long bits, Supplier<RuntimeException> exFactory) {
+        if (bits % 8 == 0) {
+            return bits / 8;
+        } else {
+            throw exFactory.get();
+        }
+    }
+
+    // segment factories
+
+    public static MemorySegment makeNativeSegment(long bytesSize, long alignmentBytes) {
+        long alignedSize = bytesSize;
+
+        if (alignmentBytes > MAX_ALIGN) {
+            alignedSize = bytesSize + (alignmentBytes - 1);
+        }
+
+        long buf = unsafe.allocateMemory(alignedSize);
+        if (!skipZeroMemory) {
+            unsafe.setMemory(buf, alignedSize, (byte)0);
+        }
+        long alignedBuf = Utils.alignUp(buf, alignmentBytes);
+        MemoryScope scope = new MemoryScope(null, () -> unsafe.freeMemory(buf));
+        MemorySegment segment = new MemorySegmentImpl(buf, null, alignedSize, 0, Thread.currentThread(), scope);
+        if (alignedBuf != buf) {
+            long delta = alignedBuf - buf;
+            segment = segment.asSlice(delta, bytesSize);
+        }
+        return segment;
+    }
+
+    public static MemorySegment makeArraySegment(byte[] arr) {
+        return makeArraySegment(arr, arr.length, Unsafe.ARRAY_BYTE_BASE_OFFSET, Unsafe.ARRAY_BYTE_INDEX_SCALE);
+    }
+
+    public static MemorySegment makeArraySegment(char[] arr) {
+        return makeArraySegment(arr, arr.length, Unsafe.ARRAY_CHAR_BASE_OFFSET, Unsafe.ARRAY_CHAR_INDEX_SCALE);
+    }
+
+    public static MemorySegment makeArraySegment(short[] arr) {
+        return makeArraySegment(arr, arr.length, Unsafe.ARRAY_SHORT_BASE_OFFSET, Unsafe.ARRAY_SHORT_INDEX_SCALE);
+    }
+
+    public static MemorySegment makeArraySegment(int[] arr) {
+        return makeArraySegment(arr, arr.length, Unsafe.ARRAY_INT_BASE_OFFSET, Unsafe.ARRAY_INT_INDEX_SCALE);
+    }
+
+    public static MemorySegment makeArraySegment(float[] arr) {
+        return makeArraySegment(arr, arr.length, Unsafe.ARRAY_FLOAT_BASE_OFFSET, Unsafe.ARRAY_FLOAT_INDEX_SCALE);
+    }
+
+    public static MemorySegment makeArraySegment(long[] arr) {
+        return makeArraySegment(arr, arr.length, Unsafe.ARRAY_LONG_BASE_OFFSET, Unsafe.ARRAY_LONG_INDEX_SCALE);
+    }
+
+    public static MemorySegment makeArraySegment(double[] arr) {
+        return makeArraySegment(arr, arr.length, Unsafe.ARRAY_DOUBLE_BASE_OFFSET, Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
+    }
+
+    private static MemorySegment makeArraySegment(Object arr, int size, int base, int scale) {
+        MemoryScope scope = new MemoryScope(null, null);
+        return new MemorySegmentImpl(base, arr, size * scale, 0, Thread.currentThread(), scope);
+    }
+
+    public static MemorySegment makeBufferSegment(ByteBuffer bb) {
+        long bbAddress = javaNioAccess.getBufferAddress(bb);
+        Object base = javaNioAccess.getBufferBase(bb);
+
+        int pos = bb.position();
+        int limit = bb.limit();
+
+        MemoryScope bufferScope = new MemoryScope(bb, null);
+        return new MemorySegmentImpl(bbAddress + pos, base, limit - pos, 0, Thread.currentThread(), bufferScope);
+    }
+
+    // create and map a file into a fresh segment
+    public static MemorySegment makeMappedSegment(Path path, long bytesSize, FileChannel.MapMode mapMode) throws IOException {
+        if (bytesSize <= 0) throw new IllegalArgumentException("Requested bytes size must be > 0.");
+        try (FileChannelImpl channelImpl = (FileChannelImpl)FileChannel.open(path, openOptions(mapMode))) {
+            UnmapperProxy unmapperProxy = channelImpl.mapInternal(mapMode, 0L, bytesSize);
+            MemoryScope scope = new MemoryScope(null, unmapperProxy::unmap);
+            return new MemorySegmentImpl(unmapperProxy.address(), null, bytesSize, 0, Thread.currentThread(), scope);
+        }
+    }
+
+    private static OpenOption[] openOptions(FileChannel.MapMode mapMode) {
+        if (mapMode == FileChannel.MapMode.READ_ONLY) {
+            return new OpenOption[] { StandardOpenOption.READ };
+        } else if (mapMode == FileChannel.MapMode.READ_WRITE || mapMode == FileChannel.MapMode.PRIVATE) {
+            return new OpenOption[] { StandardOpenOption.READ, StandardOpenOption.WRITE };
+        } else {
+            throw new UnsupportedOperationException("Unsupported map mode: " + mapMode);
+        }
+    }
+}
diff --git a/src/jdk.incubator.foreign/share/classes/module-info.java b/src/jdk.incubator.foreign/share/classes/module-info.java
new file mode 100644
index 00000000000..3c7c0ca74aa
--- /dev/null
+++ b/src/jdk.incubator.foreign/share/classes/module-info.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+/**
+ * Defines the experimental foreign memory access API.
+ *
+ * {@Incubating}
+ *
+ * @moduleGraph
+ */
+module jdk.incubator.foreign {
+    exports jdk.incubator.foreign;
+}
diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups
index 25484b673e6..56c41a3ad64 100644
--- a/test/jdk/TEST.groups
+++ b/test/jdk/TEST.groups
@@ -40,6 +40,7 @@ tier1_part2 = \
 tier1_part3 = \
     :jdk_math \
     :jdk_svc_sanity \
+    :jdk_foreign \
     java/nio/Buffer \
     com/sun/crypto/provider/Cipher \
     sun/nio/cs/ISO8859x.java
@@ -332,6 +333,9 @@ jdk_svc = \
     :jdk_jfr \
     :svc_tools
 
+jdk_foreign = \
+    java/foreign
+
 #############################
 
 #
diff --git a/test/jdk/java/foreign/TEST.properties b/test/jdk/java/foreign/TEST.properties
new file mode 100644
index 00000000000..c22c6512eff
--- /dev/null
+++ b/test/jdk/java/foreign/TEST.properties
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 2019, 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.
+#
+#
+
+modules = jdk.incubator.foreign
diff --git a/test/jdk/java/foreign/TestArrays.java b/test/jdk/java/foreign/TestArrays.java
new file mode 100644
index 00000000000..f9ec0da992a
--- /dev/null
+++ b/test/jdk/java/foreign/TestArrays.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ *
+ */
+
+/*
+ * @test
+ * @run testng TestArrays
+ */
+
+import jdk.incubator.foreign.MemoryAddress;
+import jdk.incubator.foreign.MemoryLayout;
+import jdk.incubator.foreign.MemoryLayout.PathElement;
+import jdk.incubator.foreign.MemoryLayouts;
+import jdk.incubator.foreign.MemorySegment;
+import jdk.incubator.foreign.SequenceLayout;
+
+import java.lang.invoke.VarHandle;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+import org.testng.annotations.*;
+import static org.testng.Assert.*;
+
+public class TestArrays {
+
+    static SequenceLayout bytes = MemoryLayout.ofSequence(100,
+            MemoryLayouts.JAVA_BYTE
+    );
+
+    static SequenceLayout chars = MemoryLayout.ofSequence(100,
+            MemoryLayouts.JAVA_CHAR
+    );
+
+    static SequenceLayout shorts = MemoryLayout.ofSequence(100,
+            MemoryLayouts.JAVA_SHORT
+    );
+
+    static SequenceLayout ints = MemoryLayout.ofSequence(100,
+            MemoryLayouts.JAVA_INT
+    );
+
+    static SequenceLayout floats = MemoryLayout.ofSequence(100,
+            MemoryLayouts.JAVA_FLOAT
+    );
+
+    static SequenceLayout longs = MemoryLayout.ofSequence(100,
+            MemoryLayouts.JAVA_LONG
+    );
+
+    static SequenceLayout doubles = MemoryLayout.ofSequence(100,
+            MemoryLayouts.JAVA_DOUBLE
+    );
+
+    static VarHandle byteHandle = bytes.varHandle(byte.class, PathElement.sequenceElement());
+    static VarHandle charHandle = chars.varHandle(char.class, PathElement.sequenceElement());
+    static VarHandle shortHandle = shorts.varHandle(short.class, PathElement.sequenceElement());
+    static VarHandle intHandle = ints.varHandle(int.class, PathElement.sequenceElement());
+    static VarHandle floatHandle = floats.varHandle(float.class, PathElement.sequenceElement());
+    static VarHandle longHandle = doubles.varHandle(long.class, PathElement.sequenceElement());
+    static VarHandle doubleHandle = longs.varHandle(double.class, PathElement.sequenceElement());
+
+    static void initBytes(MemoryAddress base, SequenceLayout seq, BiConsumer<MemoryAddress, Long> handleSetter) {
+        for (long i = 0; i < seq.elementCount().getAsLong() ; i++) {
+            handleSetter.accept(base, i);
+        }
+    }
+
+    static void checkBytes(MemoryAddress base, SequenceLayout layout) {
+        long nBytes = layout.elementCount().getAsLong() * layout.elementLayout().byteSize();
+        byte[] arr = base.segment().toByteArray();
+        for (long i = 0 ; i < nBytes ; i++) {
+            byte expected = (byte)byteHandle.get(base, i);
+            byte found = arr[(int)i];
+            assertEquals(expected, found);
+        }
+    }
+
+    @Test(dataProvider = "arrays")
+    public void testArrays(Consumer<MemoryAddress> init, SequenceLayout layout) {
+        try (MemorySegment segment = MemorySegment.allocateNative(layout)) {
+            init.accept(segment.baseAddress());
+            checkBytes(segment.baseAddress(), layout);
+        }
+    }
+
+    @Test(expectedExceptions = UnsupportedOperationException.class)
+    public void testTooBigForArray() {
+        MemorySegment.allocateNative((long) Integer.MAX_VALUE * 2).toByteArray();
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testArrayFromClosedSegment() {
+        MemorySegment segment = MemorySegment.allocateNative(8);
+        segment.close();
+        segment.toByteArray();
+    }
+
+    @DataProvider(name = "arrays")
+    public Object[][] nativeAccessOps() {
+        Consumer<MemoryAddress> byteInitializer =
+                (base) -> initBytes(base, bytes, (addr, pos) -> byteHandle.set(addr, pos, (byte)(long)pos));
+        Consumer<MemoryAddress> charInitializer =
+                (base) -> initBytes(base, chars, (addr, pos) -> charHandle.set(addr, pos, (char)(long)pos));
+        Consumer<MemoryAddress> shortInitializer =
+                (base) -> initBytes(base, shorts, (addr, pos) -> shortHandle.set(addr, pos, (short)(long)pos));
+        Consumer<MemoryAddress> intInitializer =
+                (base) -> initBytes(base, ints, (addr, pos) -> intHandle.set(addr, pos, (int)(long)pos));
+        Consumer<MemoryAddress> floatInitializer =
+                (base) -> initBytes(base, floats, (addr, pos) -> floatHandle.set(addr, pos, (float)(long)pos));
+        Consumer<MemoryAddress> longInitializer =
+                (base) -> initBytes(base, longs, (addr, pos) -> longHandle.set(addr, pos, (long)pos));
+        Consumer<MemoryAddress> doubleInitializer =
+                (base) -> initBytes(base, doubles, (addr, pos) -> doubleHandle.set(addr, pos, (double)(long)pos));
+
+        return new Object[][]{
+                {byteInitializer, bytes},
+                {charInitializer, chars},
+                {shortInitializer, shorts},
+                {intInitializer, ints},
+                {floatInitializer, floats},
+                {longInitializer, longs},
+                {doubleInitializer, doubles}
+        };
+    }
+}
diff --git a/test/jdk/java/foreign/TestByteBuffer.java b/test/jdk/java/foreign/TestByteBuffer.java
new file mode 100644
index 00000000000..43f9c4a535c
--- /dev/null
+++ b/test/jdk/java/foreign/TestByteBuffer.java
@@ -0,0 +1,555 @@
+/*
+ * Copyright (c) 2019, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @modules java.base/sun.nio.ch
+ *          jdk.incubator.foreign/jdk.internal.foreign
+ * @run testng TestByteBuffer
+ */
+
+
+import jdk.incubator.foreign.MemoryLayouts;
+import jdk.incubator.foreign.MemoryLayout;
+import jdk.incubator.foreign.MemoryAddress;
+import jdk.incubator.foreign.MemorySegment;
+import jdk.incubator.foreign.MemoryLayout.PathElement;
+import jdk.incubator.foreign.SequenceLayout;
+
+import java.io.File;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.InvalidMarkException;
+import java.nio.LongBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.ShortBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.StandardOpenOption;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+import jdk.internal.foreign.MemoryAddressImpl;
+import org.testng.annotations.*;
+import sun.nio.ch.DirectBuffer;
+
+import static org.testng.Assert.*;
+
+public class TestByteBuffer {
+
+    static SequenceLayout tuples = MemoryLayout.ofSequence(500,
+            MemoryLayout.ofStruct(
+                    MemoryLayouts.BITS_32_BE.withName("index"),
+                    MemoryLayouts.BITS_32_BE.withName("value")
+            ));
+
+    static SequenceLayout bytes = MemoryLayout.ofSequence(100,
+            MemoryLayouts.BITS_8_BE
+    );
+
+    static SequenceLayout chars = MemoryLayout.ofSequence(100,
+            MemoryLayouts.BITS_16_BE
+    );
+
+    static SequenceLayout shorts = MemoryLayout.ofSequence(100,
+            MemoryLayouts.BITS_16_BE
+    );
+
+    static SequenceLayout ints = MemoryLayout.ofSequence(100,
+            MemoryLayouts.BITS_32_BE
+    );
+
+    static SequenceLayout floats = MemoryLayout.ofSequence(100,
+            MemoryLayouts.BITS_32_BE
+    );
+
+    static SequenceLayout longs = MemoryLayout.ofSequence(100,
+            MemoryLayouts.BITS_64_BE
+    );
+
+    static SequenceLayout doubles = MemoryLayout.ofSequence(100,
+            MemoryLayouts.BITS_64_BE
+    );
+
+    static VarHandle indexHandle = tuples.varHandle(int.class, PathElement.sequenceElement(), PathElement.groupElement("index"));
+    static VarHandle valueHandle = tuples.varHandle(float.class, PathElement.sequenceElement(), PathElement.groupElement("value"));
+
+    static VarHandle byteHandle = bytes.varHandle(byte.class, PathElement.sequenceElement());
+    static VarHandle charHandle = chars.varHandle(char.class, PathElement.sequenceElement());
+    static VarHandle shortHandle = shorts.varHandle(short.class, PathElement.sequenceElement());
+    static VarHandle intHandle = ints.varHandle(int.class, PathElement.sequenceElement());
+    static VarHandle floatHandle = floats.varHandle(float.class, PathElement.sequenceElement());
+    static VarHandle longHandle = doubles.varHandle(long.class, PathElement.sequenceElement());
+    static VarHandle doubleHandle = longs.varHandle(double.class, PathElement.sequenceElement());
+
+
+    static void initTuples(MemoryAddress base) {
+        for (long i = 0; i < tuples.elementCount().getAsLong() ; i++) {
+            indexHandle.set(base, i, (int)i);
+            valueHandle.set(base, i, (float)(i / 500f));
+        }
+    }
+
+    static void checkTuples(MemoryAddress base, ByteBuffer bb) {
+        for (long i = 0; i < tuples.elementCount().getAsLong() ; i++) {
+            assertEquals(bb.getInt(), (int)indexHandle.get(base, i));
+            assertEquals(bb.getFloat(), (float)valueHandle.get(base, i));
+        }
+    }
+
+    static void initBytes(MemoryAddress base, SequenceLayout seq, BiConsumer<MemoryAddress, Long> handleSetter) {
+        for (long i = 0; i < seq.elementCount().getAsLong() ; i++) {
+            handleSetter.accept(base, i);
+        }
+    }
+
+    static <Z extends Buffer> void checkBytes(MemoryAddress base, SequenceLayout layout,
+                                              Function<ByteBuffer, Z> bufFactory,
+                                              BiFunction<MemoryAddress, Long, Object> handleExtractor,
+                                              Function<Z, Object> bufferExtractor) {
+        long nelems = layout.elementCount().getAsLong();
+        long elemSize = layout.elementLayout().byteSize();
+        for (long i = 0 ; i < nelems ; i++) {
+            long limit = nelems - i;
+            MemorySegment resizedSegment = base.segment().asSlice(i * elemSize, limit * elemSize);
+            ByteBuffer bb = resizedSegment.asByteBuffer();
+            Z z = bufFactory.apply(bb);
+            for (long j = i ; j < limit ; j++) {
+                Object handleValue = handleExtractor.apply(resizedSegment.baseAddress(), j - i);
+                Object bufferValue = bufferExtractor.apply(z);
+                if (handleValue instanceof Number) {
+                    assertEquals(((Number)handleValue).longValue(), j);
+                    assertEquals(((Number)bufferValue).longValue(), j);
+                } else {
+                    assertEquals((long)(char)handleValue, j);
+                    assertEquals((long)(char)bufferValue, j);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testOffheap() {
+        try (MemorySegment segment = MemorySegment.allocateNative(tuples)) {
+            MemoryAddress base = segment.baseAddress();
+            initTuples(base);
+
+            ByteBuffer bb = segment.asByteBuffer();
+            checkTuples(base, bb);
+        }
+    }
+
+    @Test
+    public void testHeap() {
+        byte[] arr = new byte[(int) tuples.byteSize()];
+        MemorySegment region = MemorySegment.ofArray(arr);
+        MemoryAddress base = region.baseAddress();
+        initTuples(base);
+
+        ByteBuffer bb = region.asByteBuffer();
+        checkTuples(base, bb);
+    }
+
+    @Test
+    public void testChannel() throws Throwable {
+        File f = new File("test.out");
+        assertTrue(f.createNewFile());
+        f.deleteOnExit();
+
+        //write to channel
+        try (FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
+            withMappedBuffer(channel, FileChannel.MapMode.READ_WRITE, 0, tuples.byteSize(), mbb -> {
+                MemorySegment segment = MemorySegment.ofByteBuffer(mbb);
+                MemoryAddress base = segment.baseAddress();
+                initTuples(base);
+                mbb.force();
+            });
+        }
+
+        //read from channel
+        try (FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.READ)) {
+            withMappedBuffer(channel, FileChannel.MapMode.READ_ONLY, 0, tuples.byteSize(), mbb -> {
+                MemorySegment segment = MemorySegment.ofByteBuffer(mbb);
+                MemoryAddress base = segment.baseAddress();
+                checkTuples(base, mbb);
+            });
+        }
+    }
+
+    @Test
+    public void testMappedSegment() throws Throwable {
+        File f = new File("test2.out");
+        f.createNewFile();
+        f.deleteOnExit();
+
+        //write to channel
+        try (MemorySegment segment = MemorySegment.mapFromPath(f.toPath(), tuples.byteSize(), FileChannel.MapMode.READ_WRITE)) {
+            MemoryAddress base = segment.baseAddress();
+            initTuples(base);
+        }
+
+        //read from channel
+        try (MemorySegment segment = MemorySegment.mapFromPath(f.toPath(), tuples.byteSize(), FileChannel.MapMode.READ_ONLY)) {
+            MemoryAddress base = segment.baseAddress();
+            checkTuples(base, segment.asByteBuffer());
+        }
+    }
+
+    static void withMappedBuffer(FileChannel channel, FileChannel.MapMode mode, long pos, long size, Consumer<MappedByteBuffer> action) throws Throwable {
+        MappedByteBuffer mbb = channel.map(mode, pos, size);
+        var ref = new WeakReference<>(mbb);
+        action.accept(mbb);
+        mbb = null;
+        //wait for it to be GCed
+        System.gc();
+        while (ref.get() != null) {
+            Thread.sleep(20);
+        }
+    }
+
+    @Test(dataProvider = "bufferOps")
+    public void testScopedBuffer(Function<ByteBuffer, Buffer> bufferFactory, Map<Method, Object[]> members) {
+        Buffer bb;
+        try (MemorySegment segment = MemorySegment.allocateNative(bytes)) {
+            MemoryAddress base = segment.baseAddress();
+            bb = bufferFactory.apply(segment.asByteBuffer());
+        }
+        //outside of scope!!
+        for (Map.Entry<Method, Object[]> e : members.entrySet()) {
+            if (!e.getKey().getName().contains("get") &&
+                            !e.getKey().getName().contains("put")) {
+                //skip
+                return;
+            }
+            try {
+                e.getKey().invoke(bb, e.getValue());
+                assertTrue(false);
+            } catch (InvocationTargetException ex) {
+                Throwable cause = ex.getCause();
+                if (cause instanceof IllegalStateException) {
+                    //all get/set buffer operation should fail because of the scope check
+                    assertTrue(ex.getCause().getMessage().contains("not alive"));
+                } else {
+                    //all other exceptions were unexpected - fail
+                    assertTrue(false);
+                }
+            } catch (Throwable ex) {
+                //unexpected exception - fail
+                assertTrue(false);
+            }
+        }
+    }
+
+    @Test(dataProvider = "bufferHandleOps")
+    public void testScopedBufferAndVarHandle(VarHandle bufferHandle) {
+        ByteBuffer bb;
+        try (MemorySegment segment = MemorySegment.allocateNative(bytes)) {
+            bb = segment.asByteBuffer();
+            for (Map.Entry<MethodHandle, Object[]> e : varHandleMembers(bb, bufferHandle).entrySet()) {
+                MethodHandle handle = e.getKey().bindTo(bufferHandle)
+                        .asSpreader(Object[].class, e.getValue().length);
+                try {
+                    handle.invoke(e.getValue());
+                } catch (UnsupportedOperationException ex) {
+                    //skip
+                } catch (Throwable ex) {
+                    //should not fail - segment is alive!
+                    fail();
+                }
+            }
+        }
+        for (Map.Entry<MethodHandle, Object[]> e : varHandleMembers(bb, bufferHandle).entrySet()) {
+            try {
+                MethodHandle handle = e.getKey().bindTo(bufferHandle)
+                        .asSpreader(Object[].class, e.getValue().length);
+                handle.invoke(e.getValue());
+                fail();
+            } catch (IllegalStateException ex) {
+                assertTrue(ex.getMessage().contains("not alive"));
+            } catch (UnsupportedOperationException ex) {
+                //skip
+            } catch (Throwable ex) {
+                fail();
+            }
+        }
+    }
+
+    @Test(dataProvider = "bufferOps")
+    public void testDirectBuffer(Function<ByteBuffer, Buffer> bufferFactory, Map<Method, Object[]> members) {
+        try (MemorySegment segment = MemorySegment.allocateNative(bytes)) {
+            MemoryAddress base = segment.baseAddress();
+            Buffer bb = bufferFactory.apply(segment.asByteBuffer());
+            assertTrue(bb.isDirect());
+            DirectBuffer directBuffer = ((DirectBuffer)bb);
+            assertEquals(directBuffer.address(), ((MemoryAddressImpl)base).unsafeGetOffset());
+            assertTrue((directBuffer.attachment() == null) == (bb instanceof ByteBuffer));
+            assertTrue(directBuffer.cleaner() == null);
+        }
+    }
+
+    @Test(dataProvider="resizeOps")
+    public void testResizeOffheap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
+        try (MemorySegment segment = MemorySegment.allocateNative(seq)) {
+            MemoryAddress base = segment.baseAddress();
+            initializer.accept(base);
+            checker.accept(base);
+        }
+    }
+
+    @Test(dataProvider="resizeOps")
+    public void testResizeHeap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
+        int capacity = (int)seq.byteSize();
+        MemoryAddress base = MemorySegment.ofArray(new byte[capacity]).baseAddress();
+        initializer.accept(base);
+        checker.accept(base);
+    }
+
+    @Test(dataProvider="resizeOps")
+    public void testResizeBuffer(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
+        int capacity = (int)seq.byteSize();
+        MemoryAddress base = MemorySegment.ofByteBuffer(ByteBuffer.wrap(new byte[capacity])).baseAddress();
+        initializer.accept(base);
+        checker.accept(base);
+    }
+
+    @Test(dataProvider="resizeOps")
+    public void testResizeRoundtripHeap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
+        int capacity = (int)seq.byteSize();
+        byte[] arr = new byte[capacity];
+        MemorySegment segment = MemorySegment.ofArray(arr);
+        MemoryAddress first = segment.baseAddress();
+        initializer.accept(first);
+        MemoryAddress second = MemorySegment.ofByteBuffer(segment.asByteBuffer()).baseAddress();
+        checker.accept(second);
+    }
+
+    @Test(dataProvider="resizeOps")
+    public void testResizeRoundtripNative(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
+        try (MemorySegment segment = MemorySegment.allocateNative(seq)) {
+            MemoryAddress first = segment.baseAddress();
+            initializer.accept(first);
+            MemoryAddress second = MemorySegment.ofByteBuffer(segment.asByteBuffer()).baseAddress();
+            checker.accept(second);
+        }
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testBufferOnClosedScope() {
+        MemorySegment leaked;
+        try (MemorySegment segment = MemorySegment.allocateNative(bytes)) {
+            leaked = segment;
+        }
+        leaked.asByteBuffer();
+    }
+
+    @Test(expectedExceptions = UnsupportedOperationException.class)
+    public void testTooBigForByteBuffer() {
+        MemorySegment.allocateNative((long) Integer.MAX_VALUE * 2).asByteBuffer();
+    }
+
+    @Test(dataProvider="resizeOps")
+    public void testCopyHeapToNative(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
+        int bytes = (int)seq.byteSize();
+        try (MemorySegment nativeArray = MemorySegment.allocateNative(bytes);
+             MemorySegment heapArray = MemorySegment.ofArray(new byte[bytes])) {
+            initializer.accept(heapArray.baseAddress());
+            MemoryAddress.copy(heapArray.baseAddress(), nativeArray.baseAddress(), bytes);
+            checker.accept(nativeArray.baseAddress());
+        }
+    }
+
+    @Test(dataProvider="resizeOps")
+    public void testCopyNativeToHeap(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
+        int bytes = (int)seq.byteSize();
+        try (MemorySegment nativeArray = MemorySegment.allocateNative(seq);
+             MemorySegment heapArray = MemorySegment.ofArray(new byte[bytes])) {
+            initializer.accept(nativeArray.baseAddress());
+            MemoryAddress.copy(nativeArray.baseAddress(), heapArray.baseAddress(), bytes);
+            checker.accept(heapArray.baseAddress());
+        }
+    }
+
+    @DataProvider(name = "bufferOps")
+    public static Object[][] bufferOps() throws Throwable {
+        return new Object[][]{
+                { (Function<ByteBuffer, Buffer>) bb -> bb, bufferMembers(ByteBuffer.class)},
+                { (Function<ByteBuffer, Buffer>) ByteBuffer::asCharBuffer, bufferMembers(CharBuffer.class)},
+                { (Function<ByteBuffer, Buffer>) ByteBuffer::asShortBuffer, bufferMembers(ShortBuffer.class)},
+                { (Function<ByteBuffer, Buffer>) ByteBuffer::asIntBuffer, bufferMembers(IntBuffer.class)},
+                { (Function<ByteBuffer, Buffer>) ByteBuffer::asFloatBuffer, bufferMembers(FloatBuffer.class)},
+                { (Function<ByteBuffer, Buffer>) ByteBuffer::asLongBuffer, bufferMembers(LongBuffer.class)},
+                { (Function<ByteBuffer, Buffer>) ByteBuffer::asDoubleBuffer, bufferMembers(DoubleBuffer.class)},
+        };
+    }
+
+    static Map<Method, Object[]> bufferMembers(Class<?> bufferClass) {
+        Map<Method, Object[]> members = new HashMap<>();
+        for (Method m : bufferClass.getMethods()) {
+            //skip statics and method declared in j.l.Object
+            if (m.getDeclaringClass().equals(Object.class) ||
+                    (m.getModifiers() & Modifier.STATIC) != 0) continue;
+            Object[] args = Stream.of(m.getParameterTypes())
+                    .map(TestByteBuffer::defaultValue)
+                    .toArray();
+            members.put(m, args);
+        }
+        return members;
+    }
+
+    @DataProvider(name = "bufferHandleOps")
+    public static Object[][] bufferHandleOps() throws Throwable {
+        return new Object[][]{
+                { MethodHandles.byteBufferViewVarHandle(char[].class, ByteOrder.nativeOrder()) },
+                { MethodHandles.byteBufferViewVarHandle(short[].class, ByteOrder.nativeOrder()) },
+                { MethodHandles.byteBufferViewVarHandle(int[].class, ByteOrder.nativeOrder()) },
+                { MethodHandles.byteBufferViewVarHandle(long[].class, ByteOrder.nativeOrder()) },
+                { MethodHandles.byteBufferViewVarHandle(float[].class, ByteOrder.nativeOrder()) },
+                { MethodHandles.byteBufferViewVarHandle(double[].class, ByteOrder.nativeOrder()) }
+        };
+    }
+
+    static Map<MethodHandle, Object[]> varHandleMembers(ByteBuffer bb, VarHandle handle) {
+        Map<MethodHandle, Object[]> members = new HashMap<>();
+        for (VarHandle.AccessMode mode : VarHandle.AccessMode.values()) {
+            Class<?>[] params = handle.accessModeType(mode).parameterArray();
+            Object[] args = Stream.concat(Stream.of(bb), Stream.of(params).skip(1)
+                    .map(TestByteBuffer::defaultValue))
+                    .toArray();
+            try {
+                members.put(MethodHandles.varHandleInvoker(mode, handle.accessModeType(mode)), args);
+            } catch (Throwable ex) {
+                throw new AssertionError(ex);
+            }
+        }
+        return members;
+    }
+
+    @DataProvider(name = "resizeOps")
+    public Object[][] resizeOps() {
+        Consumer<MemoryAddress> byteInitializer =
+                (base) -> initBytes(base, bytes, (addr, pos) -> byteHandle.set(addr, pos, (byte)(long)pos));
+        Consumer<MemoryAddress> charInitializer =
+                (base) -> initBytes(base, chars, (addr, pos) -> charHandle.set(addr, pos, (char)(long)pos));
+        Consumer<MemoryAddress> shortInitializer =
+                (base) -> initBytes(base, shorts, (addr, pos) -> shortHandle.set(addr, pos, (short)(long)pos));
+        Consumer<MemoryAddress> intInitializer =
+                (base) -> initBytes(base, ints, (addr, pos) -> intHandle.set(addr, pos, (int)(long)pos));
+        Consumer<MemoryAddress> floatInitializer =
+                (base) -> initBytes(base, floats, (addr, pos) -> floatHandle.set(addr, pos, (float)(long)pos));
+        Consumer<MemoryAddress> longInitializer =
+                (base) -> initBytes(base, longs, (addr, pos) -> longHandle.set(addr, pos, (long)pos));
+        Consumer<MemoryAddress> doubleInitializer =
+                (base) -> initBytes(base, doubles, (addr, pos) -> doubleHandle.set(addr, pos, (double)(long)pos));
+
+        Consumer<MemoryAddress> byteChecker =
+                (base) -> checkBytes(base, bytes, Function.identity(), byteHandle::get, ByteBuffer::get);
+        Consumer<MemoryAddress> charChecker =
+                (base) -> checkBytes(base, chars, ByteBuffer::asCharBuffer, charHandle::get, CharBuffer::get);
+        Consumer<MemoryAddress> shortChecker =
+                (base) -> checkBytes(base, shorts, ByteBuffer::asShortBuffer, shortHandle::get, ShortBuffer::get);
+        Consumer<MemoryAddress> intChecker =
+                (base) -> checkBytes(base, ints, ByteBuffer::asIntBuffer, intHandle::get, IntBuffer::get);
+        Consumer<MemoryAddress> floatChecker =
+                (base) -> checkBytes(base, floats, ByteBuffer::asFloatBuffer, floatHandle::get, FloatBuffer::get);
+        Consumer<MemoryAddress> longChecker =
+                (base) -> checkBytes(base, longs, ByteBuffer::asLongBuffer, longHandle::get, LongBuffer::get);
+        Consumer<MemoryAddress> doubleChecker =
+                (base) -> checkBytes(base, doubles, ByteBuffer::asDoubleBuffer, doubleHandle::get, DoubleBuffer::get);
+
+        return new Object[][]{
+                {byteChecker, byteInitializer, bytes},
+                {charChecker, charInitializer, chars},
+                {shortChecker, shortInitializer, shorts},
+                {intChecker, intInitializer, ints},
+                {floatChecker, floatInitializer, floats},
+                {longChecker, longInitializer, longs},
+                {doubleChecker, doubleInitializer, doubles}
+        };
+    }
+
+    static Object defaultValue(Class<?> c) {
+        if (c.isPrimitive()) {
+            if (c == char.class) {
+                return (char)0;
+            } else if (c == boolean.class) {
+                return false;
+            } else if (c == byte.class) {
+                return (byte)0;
+            } else if (c == short.class) {
+                return (short)0;
+            } else if (c == int.class) {
+                return 0;
+            } else if (c == long.class) {
+                return 0L;
+            } else if (c == float.class) {
+                return 0f;
+            } else if (c == double.class) {
+                return 0d;
+            } else {
+                throw new IllegalStateException();
+            }
+        } else if (c.isArray()) {
+            if (c == char[].class) {
+                return new char[1];
+            } else if (c == boolean[].class) {
+                return new boolean[1];
+            } else if (c == byte[].class) {
+                return new byte[1];
+            } else if (c == short[].class) {
+                return new short[1];
+            } else if (c == int[].class) {
+                return new int[1];
+            } else if (c == long[].class) {
+                return new long[1];
+            } else if (c == float[].class) {
+                return new float[1];
+            } else if (c == double[].class) {
+                return new double[1];
+            } else {
+                throw new IllegalStateException();
+            }
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/test/jdk/java/foreign/TestLayoutConstants.java b/test/jdk/java/foreign/TestLayoutConstants.java
new file mode 100644
index 00000000000..a0f73361abb
--- /dev/null
+++ b/test/jdk/java/foreign/TestLayoutConstants.java
@@ -0,0 +1,96 @@
+/*
+ *  Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *  Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ */
+
+/*
+ * @test
+ * @run testng TestLayoutConstants
+ */
+
+import jdk.incubator.foreign.MemoryLayouts;
+import jdk.incubator.foreign.MemoryLayout;
+
+import java.lang.invoke.MethodHandles;
+
+import org.testng.annotations.*;
+import static org.testng.Assert.*;
+
+public class TestLayoutConstants {
+
+    @Test(dataProvider = "layouts")
+    public void testDescribeResolve(MemoryLayout expected) {
+        try {
+            MemoryLayout actual = expected.describeConstable().get()
+                    .resolveConstantDesc(MethodHandles.lookup());
+            assertEquals(actual, expected);
+        } catch (ReflectiveOperationException ex) {
+            throw new AssertionError(ex);
+        }
+    }
+
+    @DataProvider(name = "layouts")
+    public Object[][] createLayouts() {
+        return new Object[][] {
+                //padding
+                { MemoryLayouts.PAD_32 },
+                { MemoryLayout.ofSequence(MemoryLayouts.PAD_32) },
+                { MemoryLayout.ofSequence(5, MemoryLayouts.PAD_32) },
+                { MemoryLayout.ofStruct(MemoryLayouts.PAD_32, MemoryLayouts.PAD_32) },
+                { MemoryLayout.ofUnion(MemoryLayouts.PAD_32, MemoryLayouts.PAD_32) },
+                //values, big endian
+                { MemoryLayouts.BITS_32_BE },
+                { MemoryLayout.ofStruct(
+                        MemoryLayouts.BITS_32_BE,
+                        MemoryLayouts.BITS_32_BE) },
+                { MemoryLayout.ofUnion(
+                        MemoryLayouts.BITS_32_BE,
+                        MemoryLayouts.BITS_32_BE) },
+                //values, little endian
+                { MemoryLayouts.BITS_32_LE },
+                { MemoryLayout.ofStruct(
+                        MemoryLayouts.BITS_32_LE,
+                        MemoryLayouts.BITS_32_LE) },
+                { MemoryLayout.ofUnion(
+                        MemoryLayouts.BITS_32_LE,
+                        MemoryLayouts.BITS_32_LE) },
+                //deeply nested
+                { MemoryLayout.ofStruct(
+                        MemoryLayouts.PAD_16,
+                        MemoryLayout.ofStruct(
+                                MemoryLayouts.PAD_8,
+                                MemoryLayouts.BITS_32_BE)) },
+                { MemoryLayout.ofUnion(
+                        MemoryLayouts.PAD_16,
+                        MemoryLayout.ofStruct(
+                                MemoryLayouts.PAD_8,
+                                MemoryLayouts.BITS_32_BE)) },
+                { MemoryLayout.ofSequence(
+                        MemoryLayout.ofStruct(
+                                MemoryLayouts.PAD_8,
+                                MemoryLayouts.BITS_32_BE)) },
+                { MemoryLayout.ofSequence(5,
+                        MemoryLayout.ofStruct(
+                                MemoryLayouts.PAD_8,
+                                MemoryLayouts.BITS_32_BE)) },
+        };
+    }
+}
diff --git a/test/jdk/java/foreign/TestLayoutPaths.java b/test/jdk/java/foreign/TestLayoutPaths.java
new file mode 100644
index 00000000000..588b008cce9
--- /dev/null
+++ b/test/jdk/java/foreign/TestLayoutPaths.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ *
+ */
+
+/*
+ * @test
+ * @run testng TestLayoutPaths
+ */
+
+import jdk.incubator.foreign.GroupLayout;
+import jdk.incubator.foreign.MemoryLayouts;
+import jdk.incubator.foreign.MemoryLayout;
+import jdk.incubator.foreign.MemoryLayout.PathElement;
+import jdk.incubator.foreign.SequenceLayout;
+
+import org.testng.annotations.*;
+import static org.testng.Assert.*;
+
+public class TestLayoutPaths {
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testBadSelectFromSeq() {
+        SequenceLayout seq = MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT);
+        seq.offset(PathElement.groupElement("foo"));
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testBadSelectFromStruct() {
+        GroupLayout g = MemoryLayout.ofStruct(MemoryLayouts.JAVA_INT);
+        g.offset(PathElement.sequenceElement());
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testBadSelectFromValue() {
+        SequenceLayout seq = MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT);
+        seq.offset(PathElement.sequenceElement(), PathElement.sequenceElement());
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testUnknownStructField() {
+        GroupLayout g = MemoryLayout.ofStruct(MemoryLayouts.JAVA_INT);
+        g.offset(PathElement.groupElement("foo"));
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testNullGroupElementName() {
+        GroupLayout g = MemoryLayout.ofStruct(MemoryLayouts.JAVA_INT);
+        g.offset(PathElement.groupElement(null));
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testOutOfBoundsSeqIndex() {
+        SequenceLayout seq = MemoryLayout.ofSequence(5, MemoryLayouts.JAVA_INT);
+        seq.offset(PathElement.sequenceElement(6));
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testNegativeSeqIndex() {
+        SequenceLayout seq = MemoryLayout.ofSequence(5, MemoryLayouts.JAVA_INT);
+        seq.offset(PathElement.sequenceElement(-2));
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testOutOfBoundsSeqRange() {
+        SequenceLayout seq = MemoryLayout.ofSequence(5, MemoryLayouts.JAVA_INT);
+        seq.offset(PathElement.sequenceElement(6, 2));
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testNegativeSeqRange() {
+        SequenceLayout seq = MemoryLayout.ofSequence(5, MemoryLayouts.JAVA_INT);
+        seq.offset(PathElement.sequenceElement(-2, 2));
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testIncompleteAccess() {
+        SequenceLayout seq = MemoryLayout.ofSequence(5, MemoryLayout.ofStruct(MemoryLayouts.JAVA_INT));
+        seq.varHandle(int.class, PathElement.sequenceElement());
+    }
+
+    @Test
+    public void testBadContainerAlign() {
+        GroupLayout g = MemoryLayout.ofStruct(MemoryLayouts.JAVA_INT.withBitAlignment(16).withName("foo")).withBitAlignment(8);
+        try {
+            g.offset(PathElement.groupElement("foo"));
+        } catch (Throwable ex) {
+            throw new AssertionError(ex); // should be ok!
+        }
+        try {
+            g.varHandle(int.class, PathElement.groupElement("foo")); //ok
+            assertTrue(false); //should fail!
+        } catch (UnsupportedOperationException ex) {
+            //ok
+        } catch (Throwable ex) {
+            throw new AssertionError(ex); //should fail!
+        }
+    }
+
+    @Test
+    public void testBadAlignOffset() {
+        GroupLayout g = MemoryLayout.ofStruct(MemoryLayouts.PAD_8, MemoryLayouts.JAVA_INT.withBitAlignment(16).withName("foo"));
+        try {
+            g.offset(PathElement.groupElement("foo"));
+        } catch (Throwable ex) {
+            throw new AssertionError(ex); // should be ok!
+        }
+        try {
+            g.varHandle(int.class, PathElement.groupElement("foo")); //ok
+            assertTrue(false); //should fail!
+        } catch (UnsupportedOperationException ex) {
+            //ok
+        } catch (Throwable ex) {
+            throw new AssertionError(ex); //should fail!
+        }
+    }
+}
+
diff --git a/test/jdk/java/foreign/TestLayouts.java b/test/jdk/java/foreign/TestLayouts.java
new file mode 100644
index 00000000000..fb076b75326
--- /dev/null
+++ b/test/jdk/java/foreign/TestLayouts.java
@@ -0,0 +1,289 @@
+/*
+ *  Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *  Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ */
+
+/*
+ * @test
+ * @run testng TestLayouts
+ */
+
+import jdk.incubator.foreign.MemoryLayouts;
+import jdk.incubator.foreign.MemoryLayout;
+
+import java.lang.invoke.VarHandle;
+import java.nio.ByteOrder;
+import java.util.function.LongFunction;
+
+import jdk.incubator.foreign.MemorySegment;
+import org.testng.annotations.*;
+import static org.testng.Assert.*;
+
+public class TestLayouts {
+
+    @Test(dataProvider = "badLayoutSizes", expectedExceptions = IllegalArgumentException.class)
+    public void testBadLayoutSize(SizedLayoutFactory factory, long size) {
+        factory.make(size);
+    }
+
+    @Test(dataProvider = "badAlignments", expectedExceptions = IllegalArgumentException.class)
+    public void testBadLayoutAlignment(MemoryLayout layout, long alignment) {
+        layout.withBitAlignment(alignment);
+    }
+
+    @Test
+    public void testVLAInStruct() {
+        MemoryLayout layout = MemoryLayout.ofStruct(
+                MemoryLayouts.JAVA_INT.withName("size"),
+                MemoryLayout.ofPaddingBits(32),
+                MemoryLayout.ofSequence(MemoryLayouts.JAVA_DOUBLE).withName("arr"));
+        VarHandle size_handle = layout.varHandle(int.class, MemoryLayout.PathElement.groupElement("size"));
+        VarHandle array_elem_handle = layout.varHandle(double.class,
+                MemoryLayout.PathElement.groupElement("arr"),
+                MemoryLayout.PathElement.sequenceElement());
+        try (MemorySegment segment = MemorySegment.allocateNative(8 + 8 * 4)) {
+            size_handle.set(segment.baseAddress(), 4);
+            for (int i = 0 ; i < 4 ; i++) {
+                array_elem_handle.set(segment.baseAddress(), i, (double)i);
+            }
+            //check
+            assertEquals(4, (int)size_handle.get(segment.baseAddress()));
+            for (int i = 0 ; i < 4 ; i++) {
+                assertEquals((double)i, (double)array_elem_handle.get(segment.baseAddress(), i));
+            }
+        }
+    }
+
+    @Test
+    public void testVLAInSequence() {
+        MemoryLayout layout = MemoryLayout.ofStruct(
+                MemoryLayouts.JAVA_INT.withName("size"),
+                MemoryLayout.ofPaddingBits(32),
+                MemoryLayout.ofSequence(1, MemoryLayout.ofSequence(MemoryLayouts.JAVA_DOUBLE)).withName("arr"));
+        VarHandle size_handle = layout.varHandle(int.class, MemoryLayout.PathElement.groupElement("size"));
+        VarHandle array_elem_handle = layout.varHandle(double.class,
+                MemoryLayout.PathElement.groupElement("arr"),
+                MemoryLayout.PathElement.sequenceElement(0),
+                MemoryLayout.PathElement.sequenceElement());
+        try (MemorySegment segment = MemorySegment.allocateNative(8 + 8 * 4)) {
+            size_handle.set(segment.baseAddress(), 4);
+            for (int i = 0 ; i < 4 ; i++) {
+                array_elem_handle.set(segment.baseAddress(), i, (double)i);
+            }
+            //check
+            assertEquals(4, (int)size_handle.get(segment.baseAddress()));
+            for (int i = 0 ; i < 4 ; i++) {
+                assertEquals((double)i, (double)array_elem_handle.get(segment.baseAddress(), i));
+            }
+        }
+    }
+
+    @Test
+    public void testIndexedSequencePath() {
+        MemoryLayout seq = MemoryLayout.ofSequence(10, MemoryLayouts.JAVA_INT);
+        try (MemorySegment segment = MemorySegment.allocateNative(seq)) {
+            VarHandle indexHandle = seq.varHandle(int.class, MemoryLayout.PathElement.sequenceElement());
+            // init segment
+            for (int i = 0 ; i < 10 ; i++) {
+                indexHandle.set(segment.baseAddress(), (long)i, i);
+            }
+            //check statically indexed handles
+            for (int i = 0 ; i < 10 ; i++) {
+                VarHandle preindexHandle = seq.varHandle(int.class, MemoryLayout.PathElement.sequenceElement(i));
+                int expected = (int)indexHandle.get(segment.baseAddress(), (long)i);
+                int found = (int)preindexHandle.get(segment.baseAddress());
+                assertEquals(expected, found);
+            }
+        }
+    }
+
+    @Test(dataProvider = "unboundLayouts", expectedExceptions = UnsupportedOperationException.class)
+    public void testUnboundSize(MemoryLayout layout, long align) {
+        layout.bitSize();
+    }
+
+    @Test(dataProvider = "unboundLayouts")
+    public void testUnboundAlignment(MemoryLayout layout, long align) {
+        assertEquals(align, layout.bitAlignment());
+    }
+
+    @Test(dataProvider = "unboundLayouts")
+    public void testUnboundEquals(MemoryLayout layout, long align) {
+        assertTrue(layout.equals(layout));
+    }
+
+    @Test(dataProvider = "unboundLayouts")
+    public void testUnboundHash(MemoryLayout layout, long align) {
+        layout.hashCode();
+    }
+
+    @Test
+    public void testEmptyGroup() {
+        MemoryLayout struct = MemoryLayout.ofStruct();
+        assertEquals(struct.bitSize(), 0);
+        assertEquals(struct.bitAlignment(), 1);
+
+        MemoryLayout union = MemoryLayout.ofUnion();
+        assertEquals(union.bitSize(), 0);
+        assertEquals(union.bitAlignment(), 1);
+    }
+
+    @Test
+    public void testStructSizeAndAlign() {
+        MemoryLayout struct = MemoryLayout.ofStruct(
+                MemoryLayout.ofPaddingBits(8),
+                MemoryLayouts.JAVA_BYTE,
+                MemoryLayouts.JAVA_CHAR,
+                MemoryLayouts.JAVA_INT,
+                MemoryLayouts.JAVA_LONG
+        );
+        assertEquals(struct.byteSize(), 1 + 1 + 2 + 4 + 8);
+        assertEquals(struct.byteAlignment(), 8);
+    }
+
+    @Test
+    public void testUnionSizeAndAlign() {
+        MemoryLayout struct = MemoryLayout.ofUnion(
+                MemoryLayouts.JAVA_BYTE,
+                MemoryLayouts.JAVA_CHAR,
+                MemoryLayouts.JAVA_INT,
+                MemoryLayouts.JAVA_LONG
+        );
+        assertEquals(struct.byteSize(), 8);
+        assertEquals(struct.byteAlignment(), 8);
+    }
+
+    @Test(dataProvider="layoutsAndAlignments")
+    public void testAlignmentString(MemoryLayout layout, long bitAlign) {
+        long[] alignments = { 8, 16, 32, 64, 128 };
+        for (long a : alignments) {
+            assertFalse(layout.toString().contains("%"));
+            assertEquals(layout.withBitAlignment(a).toString().contains("%"), a != bitAlign);
+        }
+    }
+
+    @DataProvider(name = "badLayoutSizes")
+    public Object[][] factoriesAndSizes() {
+        return new Object[][] {
+                { SizedLayoutFactory.VALUE_BE, 0 },
+                { SizedLayoutFactory.VALUE_BE, -1 },
+                { SizedLayoutFactory.VALUE_LE, 0 },
+                { SizedLayoutFactory.VALUE_LE, -1 },
+                { SizedLayoutFactory.PADDING, 0 },
+                { SizedLayoutFactory.PADDING, -1 },
+                { SizedLayoutFactory.SEQUENCE, -1 }
+        };
+    }
+
+    @DataProvider(name = "unboundLayouts")
+    public Object[][] unboundLayouts() {
+        return new Object[][] {
+                { MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT), 32 },
+                { MemoryLayout.ofSequence(MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT)), 32 },
+                { MemoryLayout.ofSequence(4, MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT)), 32 },
+                { MemoryLayout.ofStruct(MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT)), 32 },
+                { MemoryLayout.ofStruct(MemoryLayout.ofSequence(MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT))), 32 },
+                { MemoryLayout.ofStruct(MemoryLayout.ofSequence(4, MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT))), 32 },
+                { MemoryLayout.ofUnion(MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT)), 32 },
+                { MemoryLayout.ofUnion(MemoryLayout.ofSequence(MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT))), 32 },
+                { MemoryLayout.ofUnion(MemoryLayout.ofSequence(4, MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT))), 32 },
+        };
+    }
+
+    @DataProvider(name = "badAlignments")
+    public Object[][] layoutsAndBadAlignments() {
+        LayoutKind[] layoutKinds = LayoutKind.values();
+        Object[][] values = new Object[layoutKinds.length * 2][2];
+        for (int i = 0; i < layoutKinds.length ; i++) {
+            values[i * 2] = new Object[] { layoutKinds[i].layout, 3 }; // smaller than 8
+            values[(i * 2) + 1] = new Object[] { layoutKinds[i].layout, 18 }; // not a power of 2
+        }
+        return values;
+    }
+
+    enum SizedLayoutFactory {
+        VALUE_LE(size -> MemoryLayout.ofValueBits(size, ByteOrder.LITTLE_ENDIAN)),
+        VALUE_BE(size -> MemoryLayout.ofValueBits(size, ByteOrder.BIG_ENDIAN)),
+        PADDING(MemoryLayout::ofPaddingBits),
+        SEQUENCE(size -> MemoryLayout.ofSequence(size, MemoryLayouts.PAD_8));
+
+        private final LongFunction<MemoryLayout> factory;
+
+        SizedLayoutFactory(LongFunction<MemoryLayout> factory) {
+            this.factory = factory;
+        }
+
+        MemoryLayout make(long size) {
+            return factory.apply(size);
+        }
+    }
+
+    enum LayoutKind {
+        VALUE_LE(MemoryLayouts.BITS_8_LE),
+        VALUE_BE(MemoryLayouts.BITS_8_BE),
+        PADDING(MemoryLayouts.PAD_8),
+        SEQUENCE(MemoryLayout.ofSequence(1, MemoryLayouts.PAD_8)),
+        STRUCT(MemoryLayout.ofStruct(MemoryLayouts.PAD_8, MemoryLayouts.PAD_8)),
+        UNION(MemoryLayout.ofUnion(MemoryLayouts.PAD_8, MemoryLayouts.PAD_8));
+
+        final MemoryLayout layout;
+
+        LayoutKind(MemoryLayout layout) {
+            this.layout = layout;
+        }
+    }
+
+    @DataProvider(name = "layoutsAndAlignments")
+    public Object[][] layoutsAndAlignments() {
+        MemoryLayout[] basicLayouts = {
+                MemoryLayouts.JAVA_BYTE,
+                MemoryLayouts.JAVA_CHAR,
+                MemoryLayouts.JAVA_SHORT,
+                MemoryLayouts.JAVA_INT,
+                MemoryLayouts.JAVA_FLOAT,
+                MemoryLayouts.JAVA_LONG,
+                MemoryLayouts.JAVA_DOUBLE,
+        };
+        Object[][] layoutsAndAlignments = new Object[basicLayouts.length * 5][];
+        int i = 0;
+        //add basic layouts
+        for (MemoryLayout l : basicLayouts) {
+            layoutsAndAlignments[i++] = new Object[] { l, l.bitAlignment() };
+        }
+        //add basic layouts wrapped in a sequence with unspecified size
+        for (MemoryLayout l : basicLayouts) {
+            layoutsAndAlignments[i++] = new Object[] { MemoryLayout.ofSequence(l), l.bitAlignment() };
+        }
+        //add basic layouts wrapped in a sequence with given size
+        for (MemoryLayout l : basicLayouts) {
+            layoutsAndAlignments[i++] = new Object[] { MemoryLayout.ofSequence(4, l), l.bitAlignment() };
+        }
+        //add basic layouts wrapped in a struct
+        for (MemoryLayout l : basicLayouts) {
+            layoutsAndAlignments[i++] = new Object[] { MemoryLayout.ofStruct(l), l.bitAlignment() };
+        }
+        //add basic layouts wrapped in a union
+        for (MemoryLayout l : basicLayouts) {
+            layoutsAndAlignments[i++] = new Object[] { MemoryLayout.ofUnion(l), l.bitAlignment() };
+        }
+        return layoutsAndAlignments;
+    }
+}
diff --git a/test/jdk/java/foreign/TestMemoryAccess.java b/test/jdk/java/foreign/TestMemoryAccess.java
new file mode 100644
index 00000000000..edbfab230f1
--- /dev/null
+++ b/test/jdk/java/foreign/TestMemoryAccess.java
@@ -0,0 +1,459 @@
+/*
+ *  Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *  Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ */
+
+/*
+ * @test
+ * @run testng/othervm -Xverify:all TestMemoryAccess
+ */
+
+import jdk.incubator.foreign.GroupLayout;
+import jdk.incubator.foreign.MemoryLayouts;
+import jdk.incubator.foreign.MemoryLayout;
+import jdk.incubator.foreign.MemoryLayout.PathElement;
+import jdk.incubator.foreign.MemorySegment;
+import jdk.incubator.foreign.SequenceLayout;
+import jdk.incubator.foreign.ValueLayout;
+import jdk.incubator.foreign.MemoryAddress;
+import java.lang.invoke.VarHandle;
+import java.util.function.Function;
+
+import org.testng.annotations.*;
+import static org.testng.Assert.*;
+
+public class TestMemoryAccess {
+
+    @Test(dataProvider = "elements")
+    public void testAccess(Function<MemorySegment, MemorySegment> viewFactory, ValueLayout elemLayout, Class<?> carrier, Checker checker) {
+        ValueLayout layout = elemLayout.withName("elem");
+        testAccessInternal(viewFactory, layout, layout.varHandle(carrier), checker);
+    }
+
+    @Test(dataProvider = "elements")
+    public void testPaddedAccessByName(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, Checker checker) {
+        GroupLayout layout = MemoryLayout.ofStruct(MemoryLayout.ofPaddingBits(elemLayout.bitSize()), elemLayout.withName("elem"));
+        testAccessInternal(viewFactory, layout, layout.varHandle(carrier, PathElement.groupElement("elem")), checker);
+    }
+
+    @Test(dataProvider = "elements")
+    public void testPaddedAccessByIndexSeq(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, Checker checker) {
+        SequenceLayout layout = MemoryLayout.ofSequence(2, elemLayout);
+        testAccessInternal(viewFactory, layout, layout.varHandle(carrier, PathElement.sequenceElement(1)), checker);
+    }
+
+    @Test(dataProvider = "arrayElements")
+    public void testArrayAccess(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, ArrayChecker checker) {
+        SequenceLayout seq = MemoryLayout.ofSequence(10, elemLayout.withName("elem"));
+        testArrayAccessInternal(viewFactory, seq, seq.varHandle(carrier, PathElement.sequenceElement()), checker);
+    }
+
+    @Test(dataProvider = "arrayElements")
+    public void testPaddedArrayAccessByName(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, ArrayChecker checker) {
+        SequenceLayout seq = MemoryLayout.ofSequence(10, MemoryLayout.ofStruct(MemoryLayout.ofPaddingBits(elemLayout.bitSize()), elemLayout.withName("elem")));
+        testArrayAccessInternal(viewFactory, seq, seq.varHandle(carrier, MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.groupElement("elem")), checker);
+    }
+
+    @Test(dataProvider = "arrayElements")
+    public void testPaddedArrayAccessByIndexSeq(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, ArrayChecker checker) {
+        SequenceLayout seq = MemoryLayout.ofSequence(10, MemoryLayout.ofSequence(2, elemLayout));
+        testArrayAccessInternal(viewFactory, seq, seq.varHandle(carrier, PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement(1)), checker);
+    }
+
+    private void testAccessInternal(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout layout, VarHandle handle, Checker checker) {
+        MemoryAddress outer_address;
+        try (MemorySegment segment = viewFactory.apply(MemorySegment.allocateNative(layout))) {
+            MemoryAddress addr = segment.baseAddress();
+            try {
+                checker.check(handle, addr);
+                if (segment.isReadOnly()) {
+                    throw new AssertionError(); //not ok, memory should be immutable
+                }
+            } catch (UnsupportedOperationException ex) {
+                if (!segment.isReadOnly()) {
+                    throw new AssertionError(); //we should not have failed!
+                }
+                return;
+            }
+            try {
+                checker.check(handle, addr.offset(layout.byteSize()));
+                throw new AssertionError(); //not ok, out of bounds
+            } catch (IndexOutOfBoundsException ex) {
+                //ok, should fail (out of bounds)
+            }
+            outer_address = addr; //leak!
+        }
+        try {
+            checker.check(handle, outer_address);
+            throw new AssertionError(); //not ok, scope is closed
+        } catch (IllegalStateException ex) {
+            //ok, should fail (scope is closed)
+        }
+    }
+
+    private void testArrayAccessInternal(Function<MemorySegment, MemorySegment> viewFactory, SequenceLayout seq, VarHandle handle, ArrayChecker checker) {
+        MemoryAddress outer_address;
+        try (MemorySegment segment = viewFactory.apply(MemorySegment.allocateNative(seq))) {
+            MemoryAddress addr = segment.baseAddress();
+            try {
+                for (int i = 0; i < seq.elementCount().getAsLong(); i++) {
+                    checker.check(handle, addr, i);
+                }
+                if (segment.isReadOnly()) {
+                    throw new AssertionError(); //not ok, memory should be immutable
+                }
+            } catch (UnsupportedOperationException ex) {
+                if (!segment.isReadOnly()) {
+                    throw new AssertionError(); //we should not have failed!
+                }
+                return;
+            }
+            try {
+                checker.check(handle, addr, seq.elementCount().getAsLong());
+                throw new AssertionError(); //not ok, out of bounds
+            } catch (IndexOutOfBoundsException ex) {
+                //ok, should fail (out of bounds)
+            }
+            outer_address = addr; //leak!
+        }
+        try {
+            checker.check(handle, outer_address, 0);
+            throw new AssertionError(); //not ok, scope is closed
+        } catch (IllegalStateException ex) {
+            //ok, should fail (scope is closed)
+        }
+    }
+
+    @Test(dataProvider = "matrixElements")
+    public void testMatrixAccess(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, MatrixChecker checker) {
+        SequenceLayout seq = MemoryLayout.ofSequence(20,
+                MemoryLayout.ofSequence(10, elemLayout.withName("elem")));
+        testMatrixAccessInternal(viewFactory, seq, seq.varHandle(carrier,
+                PathElement.sequenceElement(), PathElement.sequenceElement()), checker);
+    }
+
+    @Test(dataProvider = "matrixElements")
+    public void testPaddedMatrixAccessByName(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, MatrixChecker checker) {
+        SequenceLayout seq = MemoryLayout.ofSequence(20,
+                MemoryLayout.ofSequence(10, MemoryLayout.ofStruct(MemoryLayout.ofPaddingBits(elemLayout.bitSize()), elemLayout.withName("elem"))));
+        testMatrixAccessInternal(viewFactory, seq,
+                seq.varHandle(carrier,
+                        PathElement.sequenceElement(), PathElement.sequenceElement(), PathElement.groupElement("elem")),
+                checker);
+    }
+
+    @Test(dataProvider = "matrixElements")
+    public void testPaddedMatrixAccessByIndexSeq(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, MatrixChecker checker) {
+        SequenceLayout seq = MemoryLayout.ofSequence(20,
+                MemoryLayout.ofSequence(10, MemoryLayout.ofSequence(2, elemLayout)));
+        testMatrixAccessInternal(viewFactory, seq,
+                seq.varHandle(carrier,
+                        PathElement.sequenceElement(), PathElement.sequenceElement(), PathElement.sequenceElement(1)),
+                checker);
+    }
+
+    @Test(dataProvider = "badCarriers",
+          expectedExceptions = IllegalArgumentException.class)
+    public void testBadCarriers(Class<?> carrier) {
+        ValueLayout l = MemoryLayouts.BITS_32_LE.withName("elem");
+        l.varHandle(carrier);
+    }
+
+    private void testMatrixAccessInternal(Function<MemorySegment, MemorySegment> viewFactory, SequenceLayout seq, VarHandle handle, MatrixChecker checker) {
+        MemoryAddress outer_address;
+        try (MemorySegment segment = viewFactory.apply(MemorySegment.allocateNative(seq))) {
+            MemoryAddress addr = segment.baseAddress();
+            try {
+                for (int i = 0; i < seq.elementCount().getAsLong(); i++) {
+                    for (int j = 0; j < ((SequenceLayout) seq.elementLayout()).elementCount().getAsLong(); j++) {
+                        checker.check(handle, addr, i, j);
+                    }
+                }
+                if (segment.isReadOnly()) {
+                    throw new AssertionError(); //not ok, memory should be immutable
+                }
+            } catch (UnsupportedOperationException ex) {
+                if (!segment.isReadOnly()) {
+                    throw new AssertionError(); //we should not have failed!
+                }
+                return;
+            }
+            try {
+                checker.check(handle, addr, seq.elementCount().getAsLong(),
+                        ((SequenceLayout)seq.elementLayout()).elementCount().getAsLong());
+                throw new AssertionError(); //not ok, out of bounds
+            } catch (IndexOutOfBoundsException ex) {
+                //ok, should fail (out of bounds)
+            }
+            outer_address = addr; //leak!
+        }
+        try {
+            checker.check(handle, outer_address, 0, 0);
+            throw new AssertionError(); //not ok, scope is closed
+        } catch (IllegalStateException ex) {
+            //ok, should fail (scope is closed)
+        }
+    }
+
+    static Function<MemorySegment, MemorySegment> ID = Function.identity();
+    static Function<MemorySegment, MemorySegment> IMMUTABLE = MemorySegment::asReadOnly;
+
+    @DataProvider(name = "elements")
+    public Object[][] createData() {
+        return new Object[][] {
+                //BE, RW
+                { ID, MemoryLayouts.BITS_8_BE, byte.class, Checker.BYTE },
+                { ID, MemoryLayouts.BITS_16_BE, short.class, Checker.SHORT },
+                { ID, MemoryLayouts.BITS_16_BE, char.class, Checker.CHAR },
+                { ID, MemoryLayouts.BITS_32_BE, int.class, Checker.INT },
+                { ID, MemoryLayouts.BITS_64_BE, long.class, Checker.LONG },
+                { ID, MemoryLayouts.BITS_32_BE, float.class, Checker.FLOAT },
+                { ID, MemoryLayouts.BITS_64_BE, double.class, Checker.DOUBLE },
+                //BE, RO
+                { IMMUTABLE, MemoryLayouts.BITS_8_BE, byte.class, Checker.BYTE },
+                { IMMUTABLE, MemoryLayouts.BITS_16_BE, short.class, Checker.SHORT },
+                { IMMUTABLE, MemoryLayouts.BITS_16_BE, char.class, Checker.CHAR },
+                { IMMUTABLE, MemoryLayouts.BITS_32_BE, int.class, Checker.INT },
+                { IMMUTABLE, MemoryLayouts.BITS_64_BE, long.class, Checker.LONG },
+                { IMMUTABLE, MemoryLayouts.BITS_32_BE, float.class, Checker.FLOAT },
+                { IMMUTABLE, MemoryLayouts.BITS_64_BE, double.class, Checker.DOUBLE },
+                //LE, RW
+                { ID, MemoryLayouts.BITS_8_LE, byte.class, Checker.BYTE },
+                { ID, MemoryLayouts.BITS_16_LE, short.class, Checker.SHORT },
+                { ID, MemoryLayouts.BITS_16_LE, char.class, Checker.CHAR },
+                { ID, MemoryLayouts.BITS_32_LE, int.class, Checker.INT },
+                { ID, MemoryLayouts.BITS_64_LE, long.class, Checker.LONG },
+                { ID, MemoryLayouts.BITS_32_LE, float.class, Checker.FLOAT },
+                { ID, MemoryLayouts.BITS_64_LE, double.class, Checker.DOUBLE },
+                //LE, RO
+                { IMMUTABLE, MemoryLayouts.BITS_8_LE, byte.class, Checker.BYTE },
+                { IMMUTABLE, MemoryLayouts.BITS_16_LE, short.class, Checker.SHORT },
+                { IMMUTABLE, MemoryLayouts.BITS_16_LE, char.class, Checker.CHAR },
+                { IMMUTABLE, MemoryLayouts.BITS_32_LE, int.class, Checker.INT },
+                { IMMUTABLE, MemoryLayouts.BITS_64_LE, long.class, Checker.LONG },
+                { IMMUTABLE, MemoryLayouts.BITS_32_LE, float.class, Checker.FLOAT },
+                { IMMUTABLE, MemoryLayouts.BITS_64_LE, double.class, Checker.DOUBLE },
+        };
+    }
+
+    interface Checker {
+        void check(VarHandle handle, MemoryAddress addr);
+
+        Checker BYTE = (handle, addr) -> {
+            handle.set(addr, (byte)42);
+            assertEquals(42, (byte)handle.get(addr));
+        };
+
+        Checker SHORT = (handle, addr) -> {
+            handle.set(addr, (short)42);
+            assertEquals(42, (short)handle.get(addr));
+        };
+
+        Checker CHAR = (handle, addr) -> {
+            handle.set(addr, (char)42);
+            assertEquals(42, (char)handle.get(addr));
+        };
+
+        Checker INT = (handle, addr) -> {
+            handle.set(addr, 42);
+            assertEquals(42, (int)handle.get(addr));
+        };
+
+        Checker LONG = (handle, addr) -> {
+            handle.set(addr, (long)42);
+            assertEquals(42, (long)handle.get(addr));
+        };
+
+        Checker FLOAT = (handle, addr) -> {
+            handle.set(addr, (float)42);
+            assertEquals((float)42, (float)handle.get(addr));
+        };
+
+        Checker DOUBLE = (handle, addr) -> {
+            handle.set(addr, (double)42);
+            assertEquals((double)42, (double)handle.get(addr));
+        };
+    }
+
+    @DataProvider(name = "arrayElements")
+    public Object[][] createArrayData() {
+        return new Object[][] {
+                //BE, RW
+                { ID, MemoryLayouts.BITS_8_BE, byte.class, ArrayChecker.BYTE },
+                { ID, MemoryLayouts.BITS_16_BE, short.class, ArrayChecker.SHORT },
+                { ID, MemoryLayouts.BITS_16_BE, char.class, ArrayChecker.CHAR },
+                { ID, MemoryLayouts.BITS_32_BE, int.class, ArrayChecker.INT },
+                { ID, MemoryLayouts.BITS_64_BE, long.class, ArrayChecker.LONG },
+                { ID, MemoryLayouts.BITS_32_BE, float.class, ArrayChecker.FLOAT },
+                { ID, MemoryLayouts.BITS_64_BE, double.class, ArrayChecker.DOUBLE },
+                //BE, RO
+                { IMMUTABLE, MemoryLayouts.BITS_8_BE, byte.class, ArrayChecker.BYTE },
+                { IMMUTABLE, MemoryLayouts.BITS_16_BE, short.class, ArrayChecker.SHORT },
+                { IMMUTABLE, MemoryLayouts.BITS_16_BE, char.class, ArrayChecker.CHAR },
+                { IMMUTABLE, MemoryLayouts.BITS_32_BE, int.class, ArrayChecker.INT },
+                { IMMUTABLE, MemoryLayouts.BITS_64_BE, long.class, ArrayChecker.LONG },
+                { IMMUTABLE, MemoryLayouts.BITS_32_BE, float.class, ArrayChecker.FLOAT },
+                { IMMUTABLE, MemoryLayouts.BITS_64_BE, double.class, ArrayChecker.DOUBLE },
+                //LE, RW
+                { ID, MemoryLayouts.BITS_8_LE, byte.class, ArrayChecker.BYTE },
+                { ID, MemoryLayouts.BITS_16_LE, short.class, ArrayChecker.SHORT },
+                { ID, MemoryLayouts.BITS_16_LE, char.class, ArrayChecker.CHAR },
+                { ID, MemoryLayouts.BITS_32_LE, int.class, ArrayChecker.INT },
+                { ID, MemoryLayouts.BITS_64_LE, long.class, ArrayChecker.LONG },
+                { ID, MemoryLayouts.BITS_32_LE, float.class, ArrayChecker.FLOAT },
+                { ID, MemoryLayouts.BITS_64_LE, double.class, ArrayChecker.DOUBLE },
+                //LE, RO
+                { IMMUTABLE, MemoryLayouts.BITS_8_LE, byte.class, ArrayChecker.BYTE },
+                { IMMUTABLE, MemoryLayouts.BITS_16_LE, short.class, ArrayChecker.SHORT },
+                { IMMUTABLE, MemoryLayouts.BITS_16_LE, char.class, ArrayChecker.CHAR },
+                { IMMUTABLE, MemoryLayouts.BITS_32_LE, int.class, ArrayChecker.INT },
+                { IMMUTABLE, MemoryLayouts.BITS_64_LE, long.class, ArrayChecker.LONG },
+                { IMMUTABLE, MemoryLayouts.BITS_32_LE, float.class, ArrayChecker.FLOAT },
+                { IMMUTABLE, MemoryLayouts.BITS_64_LE, double.class, ArrayChecker.DOUBLE },
+        };
+    }
+
+    interface ArrayChecker {
+        void check(VarHandle handle, MemoryAddress addr, long index);
+
+        ArrayChecker BYTE = (handle, addr, i) -> {
+            handle.set(addr, i, (byte)i);
+            assertEquals(i, (byte)handle.get(addr, i));
+        };
+
+        ArrayChecker SHORT = (handle, addr, i) -> {
+            handle.set(addr, i, (short)i);
+            assertEquals(i, (short)handle.get(addr, i));
+        };
+
+        ArrayChecker CHAR = (handle, addr, i) -> {
+            handle.set(addr, i, (char)i);
+            assertEquals(i, (char)handle.get(addr, i));
+        };
+
+        ArrayChecker INT = (handle, addr, i) -> {
+            handle.set(addr, i, (int)i);
+            assertEquals(i, (int)handle.get(addr, i));
+        };
+
+        ArrayChecker LONG = (handle, addr, i) -> {
+            handle.set(addr, i, (long)i);
+            assertEquals(i, (long)handle.get(addr, i));
+        };
+
+        ArrayChecker FLOAT = (handle, addr, i) -> {
+            handle.set(addr, i, (float)i);
+            assertEquals((float)i, (float)handle.get(addr, i));
+        };
+
+        ArrayChecker DOUBLE = (handle, addr, i) -> {
+            handle.set(addr, i, (double)i);
+            assertEquals((double)i, (double)handle.get(addr, i));
+        };
+    }
+
+    @DataProvider(name = "matrixElements")
+    public Object[][] createMatrixData() {
+        return new Object[][] {
+                //BE, RW
+                { ID, MemoryLayouts.BITS_8_BE, byte.class, MatrixChecker.BYTE },
+                { ID, MemoryLayouts.BITS_16_BE, short.class, MatrixChecker.SHORT },
+                { ID, MemoryLayouts.BITS_16_BE, char.class, MatrixChecker.CHAR },
+                { ID, MemoryLayouts.BITS_32_BE, int.class, MatrixChecker.INT },
+                { ID, MemoryLayouts.BITS_64_BE, long.class, MatrixChecker.LONG },
+                { ID, MemoryLayouts.BITS_32_BE, float.class, MatrixChecker.FLOAT },
+                { ID, MemoryLayouts.BITS_64_BE, double.class, MatrixChecker.DOUBLE },
+                //BE, RO
+                { IMMUTABLE, MemoryLayouts.BITS_8_BE, byte.class, MatrixChecker.BYTE },
+                { IMMUTABLE, MemoryLayouts.BITS_16_BE, short.class, MatrixChecker.SHORT },
+                { IMMUTABLE, MemoryLayouts.BITS_16_BE, char.class, MatrixChecker.CHAR },
+                { IMMUTABLE, MemoryLayouts.BITS_32_BE, int.class, MatrixChecker.INT },
+                { IMMUTABLE, MemoryLayouts.BITS_64_BE, long.class, MatrixChecker.LONG },
+                { IMMUTABLE, MemoryLayouts.BITS_32_BE, float.class, MatrixChecker.FLOAT },
+                { IMMUTABLE, MemoryLayouts.BITS_64_BE, double.class, MatrixChecker.DOUBLE },
+                //LE, RW
+                { ID, MemoryLayouts.BITS_8_LE, byte.class, MatrixChecker.BYTE },
+                { ID, MemoryLayouts.BITS_16_LE, short.class, MatrixChecker.SHORT },
+                { ID, MemoryLayouts.BITS_16_LE, char.class, MatrixChecker.CHAR },
+                { ID, MemoryLayouts.BITS_32_LE, int.class, MatrixChecker.INT },
+                { ID, MemoryLayouts.BITS_64_LE, long.class, MatrixChecker.LONG },
+                { ID, MemoryLayouts.BITS_32_LE, float.class, MatrixChecker.FLOAT },
+                { ID, MemoryLayouts.BITS_64_LE, double.class, MatrixChecker.DOUBLE },
+                //LE, RO
+                { IMMUTABLE, MemoryLayouts.BITS_8_LE, byte.class, MatrixChecker.BYTE },
+                { IMMUTABLE, MemoryLayouts.BITS_16_LE, short.class, MatrixChecker.SHORT },
+                { IMMUTABLE, MemoryLayouts.BITS_16_LE, char.class, MatrixChecker.CHAR },
+                { IMMUTABLE, MemoryLayouts.BITS_32_LE, int.class, MatrixChecker.INT },
+                { IMMUTABLE, MemoryLayouts.BITS_64_LE, long.class, MatrixChecker.LONG },
+                { IMMUTABLE, MemoryLayouts.BITS_32_LE, float.class, MatrixChecker.FLOAT },
+                { IMMUTABLE, MemoryLayouts.BITS_64_LE, double.class, MatrixChecker.DOUBLE },
+        };
+    }
+
+    interface MatrixChecker {
+        void check(VarHandle handle, MemoryAddress addr, long row, long col);
+
+        MatrixChecker BYTE = (handle, addr, r, c) -> {
+            handle.set(addr, r, c, (byte)(r + c));
+            assertEquals(r + c, (byte)handle.get(addr, r, c));
+        };
+
+        MatrixChecker SHORT = (handle, addr, r, c) -> {
+            handle.set(addr, r, c, (short)(r + c));
+            assertEquals(r + c, (short)handle.get(addr, r, c));
+        };
+
+        MatrixChecker CHAR = (handle, addr, r, c) -> {
+            handle.set(addr, r, c, (char)(r + c));
+            assertEquals(r + c, (char)handle.get(addr, r, c));
+        };
+
+        MatrixChecker INT = (handle, addr, r, c) -> {
+            handle.set(addr, r, c, (int)(r + c));
+            assertEquals(r + c, (int)handle.get(addr, r, c));
+        };
+
+        MatrixChecker LONG = (handle, addr, r, c) -> {
+            handle.set(addr, r, c, r + c);
+            assertEquals(r + c, (long)handle.get(addr, r, c));
+        };
+
+        MatrixChecker FLOAT = (handle, addr, r, c) -> {
+            handle.set(addr, r, c, (float)(r + c));
+            assertEquals((float)(r + c), (float)handle.get(addr, r, c));
+        };
+
+        MatrixChecker DOUBLE = (handle, addr, r, c) -> {
+            handle.set(addr, r, c, (double)(r + c));
+            assertEquals((double)(r + c), (double)handle.get(addr, r, c));
+        };
+    }
+
+    @DataProvider(name = "badCarriers")
+    public Object[][] createBadCarriers() {
+        return new Object[][] {
+                { void.class },
+                { boolean.class },
+                { Object.class },
+                { int[].class }
+        };
+    }
+}
diff --git a/test/jdk/java/foreign/TestMemoryAlignment.java b/test/jdk/java/foreign/TestMemoryAlignment.java
new file mode 100644
index 00000000000..f8330bcfd53
--- /dev/null
+++ b/test/jdk/java/foreign/TestMemoryAlignment.java
@@ -0,0 +1,137 @@
+/*
+ *  Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *  Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ */
+
+/*
+ * @test
+ * @run testng TestMemoryAlignment
+ */
+
+import jdk.incubator.foreign.MemoryLayouts;
+import jdk.incubator.foreign.MemoryLayout;
+
+import jdk.incubator.foreign.GroupLayout;
+import jdk.incubator.foreign.MemoryLayout.PathElement;
+import jdk.incubator.foreign.MemoryAddress;
+import jdk.incubator.foreign.MemorySegment;
+import jdk.incubator.foreign.SequenceLayout;
+import jdk.incubator.foreign.ValueLayout;
+import java.lang.invoke.VarHandle;
+import java.util.stream.LongStream;
+
+import org.testng.annotations.*;
+import static org.testng.Assert.*;
+
+public class TestMemoryAlignment {
+
+    @Test(dataProvider = "alignments")
+    public void testAlignedAccess(long align) {
+        ValueLayout layout = MemoryLayouts.BITS_32_BE;
+        assertEquals(layout.bitAlignment(), 32);
+        ValueLayout aligned = layout.withBitAlignment(align);
+        assertEquals(aligned.bitAlignment(), align); //unreasonable alignment here, to make sure access throws
+        VarHandle vh = aligned.varHandle(int.class);
+        try (MemorySegment segment = MemorySegment.allocateNative(aligned)) {
+            MemoryAddress addr = segment.baseAddress();
+            vh.set(addr, -42);
+            int val = (int)vh.get(addr);
+            assertEquals(val, -42);
+        }
+    }
+
+    @Test(dataProvider = "alignments")
+    public void testUnalignedAccess(long align) {
+        ValueLayout layout = MemoryLayouts.BITS_32_BE;
+        assertEquals(layout.bitAlignment(), 32);
+        ValueLayout aligned = layout.withBitAlignment(align);
+        MemoryLayout alignedGroup = MemoryLayout.ofStruct(MemoryLayouts.PAD_8, aligned);
+        assertEquals(alignedGroup.bitAlignment(), align);
+        VarHandle vh = aligned.varHandle(int.class);
+        try (MemorySegment segment = MemorySegment.allocateNative(alignedGroup)) {
+            MemoryAddress addr = segment.baseAddress();
+            vh.set(addr.offset(1L), -42);
+            assertEquals(align, 8); //this is the only case where access is aligned
+        } catch (IllegalStateException ex) {
+            assertNotEquals(align, 8); //if align != 8, access is always unaligned
+        }
+    }
+
+    @Test(dataProvider = "alignments")
+    public void testUnalignedPath(long align) {
+        MemoryLayout layout = MemoryLayouts.BITS_32_BE;
+        MemoryLayout aligned = layout.withBitAlignment(align).withName("value");
+        GroupLayout alignedGroup = MemoryLayout.ofStruct(MemoryLayouts.PAD_8, aligned);
+        try {
+            alignedGroup.varHandle(int.class, PathElement.groupElement("value"));
+            assertEquals(align, 8); //this is the only case where path is aligned
+        } catch (UnsupportedOperationException ex) {
+            assertNotEquals(align, 8); //if align != 8, path is always unaligned
+        }
+    }
+
+    @Test(dataProvider = "alignments")
+    public void testUnalignedSequence(long align) {
+        SequenceLayout layout = MemoryLayout.ofSequence(5, MemoryLayouts.BITS_32_BE.withBitAlignment(align));
+        try {
+            VarHandle vh = layout.varHandle(int.class, PathElement.sequenceElement());
+            try (MemorySegment segment = MemorySegment.allocateNative(layout)) {
+                MemoryAddress addr = segment.baseAddress();
+                for (long i = 0 ; i < 5 ; i++) {
+                    vh.set(addr, i, -42);
+                }
+            }
+        } catch (UnsupportedOperationException ex) {
+            assertTrue(align > 32); //if align > 32, access is always unaligned (for some elements)
+        }
+    }
+
+    @Test
+    public void testPackedAccess() {
+        ValueLayout vChar = MemoryLayouts.BITS_8_BE;
+        ValueLayout vShort = MemoryLayouts.BITS_16_BE;
+        ValueLayout vInt = MemoryLayouts.BITS_32_BE;
+        //mimic pragma pack(1)
+        GroupLayout g = MemoryLayout.ofStruct(vChar.withBitAlignment(8).withName("a"),
+                               vShort.withBitAlignment(8).withName("b"),
+                               vInt.withBitAlignment(8).withName("c"));
+        assertEquals(g.bitAlignment(), 8);
+        VarHandle vh_c = g.varHandle(byte.class, PathElement.groupElement("a"));
+        VarHandle vh_s = g.varHandle(short.class, PathElement.groupElement("b"));
+        VarHandle vh_i = g.varHandle(int.class, PathElement.groupElement("c"));
+        try (MemorySegment segment = MemorySegment.allocateNative(g)) {
+            MemoryAddress addr = segment.baseAddress();
+            vh_c.set(addr, Byte.MIN_VALUE);
+            assertEquals(vh_c.get(addr), Byte.MIN_VALUE);
+            vh_s.set(addr, Short.MIN_VALUE);
+            assertEquals(vh_s.get(addr), Short.MIN_VALUE);
+            vh_i.set(addr, Integer.MIN_VALUE);
+            assertEquals(vh_i.get(addr), Integer.MIN_VALUE);
+        }
+    }
+
+    @DataProvider(name = "alignments")
+    public Object[][] createAlignments() {
+        return LongStream.range(3, 32)
+                .mapToObj(v -> new Object[] { 1L << v })
+                .toArray(Object[][]::new);
+    }
+}
diff --git a/test/jdk/java/foreign/TestMemoryCopy.java b/test/jdk/java/foreign/TestMemoryCopy.java
new file mode 100644
index 00000000000..d532bd83de0
--- /dev/null
+++ b/test/jdk/java/foreign/TestMemoryCopy.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ *
+ */
+
+/*
+ * @test
+ * @run testng TestMemoryCopy
+ */
+
+import jdk.incubator.foreign.MemoryAddress;
+import jdk.incubator.foreign.MemoryHandles;
+import jdk.incubator.foreign.MemoryLayouts;
+import jdk.incubator.foreign.MemorySegment;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.lang.invoke.VarHandle;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.IntFunction;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static org.testng.Assert.*;
+
+public class TestMemoryCopy {
+
+    final static VarHandle BYTE_HANDLE = MemoryLayouts.JAVA_BYTE.varHandle(byte.class);
+
+    @Test(dataProvider = "slices")
+    public void testCopy(SegmentSlice s1, SegmentSlice s2) {
+        MemoryAddress addr1 = s1.segment.baseAddress();
+        MemoryAddress addr2 = s2.segment.baseAddress();
+        int size = Math.min(s1.size(), s2.size());
+        //prepare source and target segments
+        for (int i = 0 ; i < size ; i++) {
+            BYTE_HANDLE.set(addr2.offset(i), (byte)0);
+        }
+        for (int i = 0 ; i < size ; i++) {
+            BYTE_HANDLE.set(addr1.offset(i), (byte) i);
+        }
+        //perform copy
+        MemoryAddress.copy(addr1, addr2, size);
+        //check that copy actually worked
+        for (int i = 0 ; i < size ; i++) {
+            assertEquals((byte)i, BYTE_HANDLE.get(addr2.offset(i)));
+        }
+    }
+
+    static class SegmentSlice {
+
+        enum Kind {
+            NATIVE(MemorySegment::allocateNative),
+            ARRAY(i -> MemorySegment.ofArray(new byte[i]));
+
+            final IntFunction<MemorySegment> segmentFactory;
+
+            Kind(IntFunction<MemorySegment> segmentFactory) {
+                this.segmentFactory = segmentFactory;
+            }
+
+            MemorySegment makeSegment(int elems) {
+                return segmentFactory.apply(elems);
+            }
+        }
+
+        final Kind kind;
+        final int first;
+        final int last;
+        final MemorySegment segment;
+
+        public SegmentSlice(Kind kind, int first, int last, MemorySegment segment) {
+            this.kind = kind;
+            this.first = first;
+            this.last = last;
+            this.segment = segment;
+        }
+
+        int size() {
+            return last - first + 1;
+        }
+    }
+
+    @DataProvider(name = "slices")
+    static Object[][] slices() {
+        int[] sizes = { 16, 8, 4, 2, 1 };
+        List<SegmentSlice> slices = new ArrayList<>();
+        for (SegmentSlice.Kind kind : SegmentSlice.Kind.values()) {
+            MemorySegment segment = kind.makeSegment(16);
+            //compute all slices
+            for (int size : sizes) {
+                for (int index = 0 ; index < 16 ; index += size) {
+                    MemorySegment slice = segment.asSlice(index, size);
+                    slices.add(new SegmentSlice(kind, index, index + size - 1, slice));
+                }
+            }
+        }
+        Object[][] sliceArray = new Object[slices.size() * slices.size()][];
+        for (int i = 0 ; i < slices.size() ; i++) {
+            for (int j = 0 ; j < slices.size() ; j++) {
+                sliceArray[i * slices.size() + j] = new Object[] { slices.get(i), slices.get(j) };
+            }
+        }
+        return sliceArray;
+    }
+}
diff --git a/test/jdk/java/foreign/TestNative.java b/test/jdk/java/foreign/TestNative.java
new file mode 100644
index 00000000000..f4f448fbbd3
--- /dev/null
+++ b/test/jdk/java/foreign/TestNative.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ *
+ */
+
+/*
+ * @test
+ * @modules java.base/jdk.internal.misc
+ *          jdk.incubator.foreign/jdk.incubator.foreign.unsafe
+ * @run testng TestNative
+ */
+
+import jdk.incubator.foreign.MemoryLayouts;
+import jdk.incubator.foreign.MemoryLayout;
+import jdk.incubator.foreign.MemoryLayout.PathElement;
+import jdk.incubator.foreign.unsafe.ForeignUnsafe;
+import jdk.internal.misc.Unsafe;
+import org.testng.annotations.*;
+
+import jdk.incubator.foreign.MemoryAddress;
+import jdk.incubator.foreign.MemorySegment;
+import jdk.incubator.foreign.SequenceLayout;
+
+import java.lang.invoke.VarHandle;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.LongBuffer;
+import java.nio.ShortBuffer;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+import static org.testng.Assert.*;
+
+public class TestNative {
+
+    static Unsafe UNSAFE;
+
+    static {
+        UNSAFE = Unsafe.getUnsafe();
+    }
+
+    static SequenceLayout bytes = MemoryLayout.ofSequence(100,
+            MemoryLayouts.JAVA_BYTE.withOrder(ByteOrder.nativeOrder())
+    );
+
+    static SequenceLayout chars = MemoryLayout.ofSequence(100,
+            MemoryLayouts.JAVA_CHAR.withOrder(ByteOrder.nativeOrder())
+    );
+
+    static SequenceLayout shorts = MemoryLayout.ofSequence(100,
+            MemoryLayouts.JAVA_SHORT.withOrder(ByteOrder.nativeOrder())
+    );
+
+    static SequenceLayout ints = MemoryLayout.ofSequence(100,
+            MemoryLayouts.JAVA_INT.withOrder(ByteOrder.nativeOrder())
+    );
+
+    static SequenceLayout floats = MemoryLayout.ofSequence(100,
+            MemoryLayouts.JAVA_FLOAT.withOrder(ByteOrder.nativeOrder())
+    );
+
+    static SequenceLayout longs = MemoryLayout.ofSequence(100,
+            MemoryLayouts.JAVA_LONG.withOrder(ByteOrder.nativeOrder())
+    );
+
+    static SequenceLayout doubles = MemoryLayout.ofSequence(100,
+            MemoryLayouts.JAVA_DOUBLE.withOrder(ByteOrder.nativeOrder())
+    );
+
+    static VarHandle byteHandle = bytes.varHandle(byte.class, PathElement.sequenceElement());
+    static VarHandle charHandle = chars.varHandle(char.class, PathElement.sequenceElement());
+    static VarHandle shortHandle = shorts.varHandle(short.class, PathElement.sequenceElement());
+    static VarHandle intHandle = ints.varHandle(int.class, PathElement.sequenceElement());
+    static VarHandle floatHandle = floats.varHandle(float.class, PathElement.sequenceElement());
+    static VarHandle longHandle = doubles.varHandle(long.class, PathElement.sequenceElement());
+    static VarHandle doubleHandle = longs.varHandle(double.class, PathElement.sequenceElement());
+
+    static void initBytes(MemoryAddress base, SequenceLayout seq, BiConsumer<MemoryAddress, Long> handleSetter) {
+        for (long i = 0; i < seq.elementCount().getAsLong() ; i++) {
+            handleSetter.accept(base, i);
+        }
+    }
+
+    static <Z extends Buffer> void checkBytes(MemoryAddress base, SequenceLayout layout,
+                                              BiFunction<MemoryAddress, Long, Object> handleExtractor,
+                                              Function<ByteBuffer, Z> bufferFactory,
+                                              BiFunction<Z, Integer, Object> nativeBufferExtractor,
+                                              BiFunction<Long, Integer, Object> nativeRawExtractor) {
+        long nelems = layout.elementCount().getAsLong();
+        ByteBuffer bb = base.segment().asSlice(base.offset(), (int)layout.byteSize()).asByteBuffer();
+        Z z = bufferFactory.apply(bb);
+        for (long i = 0 ; i < nelems ; i++) {
+            Object handleValue = handleExtractor.apply(base, i);
+            Object bufferValue = nativeBufferExtractor.apply(z, (int)i);
+            Object rawValue = nativeRawExtractor.apply(ForeignUnsafe.getUnsafeOffset(base), (int)i);
+            if (handleValue instanceof Number) {
+                assertEquals(((Number)handleValue).longValue(), i);
+                assertEquals(((Number)bufferValue).longValue(), i);
+                assertEquals(((Number)rawValue).longValue(), i);
+            } else {
+                assertEquals((long)(char)handleValue, i);
+                assertEquals((long)(char)bufferValue, i);
+                assertEquals((long)(char)rawValue, i);
+            }
+        }
+    }
+
+    public static native byte getByteBuffer(ByteBuffer buf, int index);
+    public static native char getCharBuffer(CharBuffer buf, int index);
+    public static native short getShortBuffer(ShortBuffer buf, int index);
+    public static native int getIntBuffer(IntBuffer buf, int index);
+    public static native float getFloatBuffer(FloatBuffer buf, int index);
+    public static native long getLongBuffer(LongBuffer buf, int index);
+    public static native double getDoubleBuffer(DoubleBuffer buf, int index);
+
+    public static native byte getByteRaw(long addr, int index);
+    public static native char getCharRaw(long addr, int index);
+    public static native short getShortRaw(long addr, int index);
+    public static native int getIntRaw(long addr, int index);
+    public static native float getFloatRaw(long addr, int index);
+    public static native long getLongRaw(long addr, int index);
+    public static native double getDoubleRaw(long addr, int index);
+
+    public static native long getCapacity(Buffer buffer);
+
+    @Test(dataProvider="nativeAccessOps")
+    public void testNativeAccess(Consumer<MemoryAddress> checker, Consumer<MemoryAddress> initializer, SequenceLayout seq) {
+        try (MemorySegment segment = MemorySegment.allocateNative(seq)) {
+            MemoryAddress address = segment.baseAddress();
+            initializer.accept(address);
+            checker.accept(address);
+        }
+    }
+
+    @Test(dataProvider="buffers")
+    public void testNativeCapacity(Function<ByteBuffer, Buffer> bufferFunction, int elemSize) {
+        int capacity = (int)doubles.byteSize();
+        try (MemorySegment segment = MemorySegment.allocateNative(doubles)) {
+            ByteBuffer bb = segment.asByteBuffer();
+            Buffer buf = bufferFunction.apply(bb);
+            int expected = capacity / elemSize;
+            assertEquals(buf.capacity(), expected);
+            assertEquals(getCapacity(buf), expected);
+        }
+    }
+
+    static {
+        System.loadLibrary("NativeAccess");
+    }
+
+    @DataProvider(name = "nativeAccessOps")
+    public Object[][] nativeAccessOps() {
+        Consumer<MemoryAddress> byteInitializer =
+                (base) -> initBytes(base, bytes, (addr, pos) -> byteHandle.set(addr, pos, (byte)(long)pos));
+        Consumer<MemoryAddress> charInitializer =
+                (base) -> initBytes(base, chars, (addr, pos) -> charHandle.set(addr, pos, (char)(long)pos));
+        Consumer<MemoryAddress> shortInitializer =
+                (base) -> initBytes(base, shorts, (addr, pos) -> shortHandle.set(addr, pos, (short)(long)pos));
+        Consumer<MemoryAddress> intInitializer =
+                (base) -> initBytes(base, ints, (addr, pos) -> intHandle.set(addr, pos, (int)(long)pos));
+        Consumer<MemoryAddress> floatInitializer =
+                (base) -> initBytes(base, floats, (addr, pos) -> floatHandle.set(addr, pos, (float)(long)pos));
+        Consumer<MemoryAddress> longInitializer =
+                (base) -> initBytes(base, longs, (addr, pos) -> longHandle.set(addr, pos, (long)pos));
+        Consumer<MemoryAddress> doubleInitializer =
+                (base) -> initBytes(base, doubles, (addr, pos) -> doubleHandle.set(addr, pos, (double)(long)pos));
+
+        Consumer<MemoryAddress> byteChecker =
+                (base) -> checkBytes(base, bytes, byteHandle::get, bb -> bb, TestNative::getByteBuffer, TestNative::getByteRaw);
+        Consumer<MemoryAddress> charChecker =
+                (base) -> checkBytes(base, chars, charHandle::get, ByteBuffer::asCharBuffer, TestNative::getCharBuffer, TestNative::getCharRaw);
+        Consumer<MemoryAddress> shortChecker =
+                (base) -> checkBytes(base, shorts, shortHandle::get, ByteBuffer::asShortBuffer, TestNative::getShortBuffer, TestNative::getShortRaw);
+        Consumer<MemoryAddress> intChecker =
+                (base) -> checkBytes(base, ints, intHandle::get, ByteBuffer::asIntBuffer, TestNative::getIntBuffer, TestNative::getIntRaw);
+        Consumer<MemoryAddress> floatChecker =
+                (base) -> checkBytes(base, floats, floatHandle::get, ByteBuffer::asFloatBuffer, TestNative::getFloatBuffer, TestNative::getFloatRaw);
+        Consumer<MemoryAddress> longChecker =
+                (base) -> checkBytes(base, longs, longHandle::get, ByteBuffer::asLongBuffer, TestNative::getLongBuffer, TestNative::getLongRaw);
+        Consumer<MemoryAddress> doubleChecker =
+                (base) -> checkBytes(base, doubles, doubleHandle::get, ByteBuffer::asDoubleBuffer, TestNative::getDoubleBuffer, TestNative::getDoubleRaw);
+
+        return new Object[][]{
+                {byteChecker, byteInitializer, bytes},
+                {charChecker, charInitializer, chars},
+                {shortChecker, shortInitializer, shorts},
+                {intChecker, intInitializer, ints},
+                {floatChecker, floatInitializer, floats},
+                {longChecker, longInitializer, longs},
+                {doubleChecker, doubleInitializer, doubles}
+        };
+    }
+
+    @DataProvider(name = "buffers")
+    public Object[][] buffers() {
+        return new Object[][] {
+                { (Function<ByteBuffer, Buffer>)bb -> bb, 1 },
+                { (Function<ByteBuffer, Buffer>)ByteBuffer::asCharBuffer, 2 },
+                { (Function<ByteBuffer, Buffer>)ByteBuffer::asShortBuffer, 2 },
+                { (Function<ByteBuffer, Buffer>)ByteBuffer::asIntBuffer, 4 },
+                { (Function<ByteBuffer, Buffer>)ByteBuffer::asFloatBuffer, 4 },
+                { (Function<ByteBuffer, Buffer>)ByteBuffer::asLongBuffer, 8 },
+                { (Function<ByteBuffer, Buffer>)ByteBuffer::asDoubleBuffer, 8 },
+        };
+    }
+}
diff --git a/test/jdk/java/foreign/TestSegments.java b/test/jdk/java/foreign/TestSegments.java
new file mode 100644
index 00000000000..128e773b35a
--- /dev/null
+++ b/test/jdk/java/foreign/TestSegments.java
@@ -0,0 +1,196 @@
+/*
+ *  Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *  Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ */
+
+/*
+ * @test
+ * @run testng TestSegments
+ */
+
+import jdk.incubator.foreign.MemoryLayout;
+import jdk.incubator.foreign.MemoryLayouts;
+import jdk.incubator.foreign.MemorySegment;
+
+import java.awt.font.LayoutPath;
+import java.lang.invoke.VarHandle;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.LongFunction;
+import java.util.stream.Stream;
+
+import jdk.incubator.foreign.SequenceLayout;
+import org.testng.annotations.*;
+
+import static org.testng.Assert.*;
+
+public class TestSegments {
+
+    @Test(dataProvider = "badSizeAndAlignments", expectedExceptions = IllegalArgumentException.class)
+    public void testBadAllocateAlign(long size, long align) {
+        MemorySegment.allocateNative(size, align);
+    }
+
+    @Test(dataProvider = "badLayouts", expectedExceptions = UnsupportedOperationException.class)
+    public void testBadAllocateLayout(MemoryLayout layout) {
+        MemorySegment.allocateNative(layout);
+    }
+
+    @Test(expectedExceptions = OutOfMemoryError.class)
+    public void testAllocateTooBig() {
+        MemorySegment.allocateNative(Long.MAX_VALUE);
+    }
+
+    @Test(dataProvider = "segmentOperations")
+    public void testOpOutsideConfinement(SegmentMember member) throws Throwable {
+        try (MemorySegment segment = MemorySegment.allocateNative(4)) {
+            AtomicBoolean failed = new AtomicBoolean(false);
+            Thread t = new Thread(() -> {
+                try {
+                    Object o = member.method.invoke(segment, member.params);
+                    if (member.method.getName().equals("acquire")) {
+                        ((MemorySegment)o).close();
+                    }
+                } catch (ReflectiveOperationException ex) {
+                    throw new IllegalStateException(ex);
+                }
+            });
+            t.setUncaughtExceptionHandler((thread, ex) -> failed.set(true));
+            t.start();
+            t.join();
+            assertEquals(failed.get(), member.isConfined());
+        }
+    }
+
+    @Test
+    public void testNativeSegmentIsZeroed() {
+        VarHandle byteHandle = MemoryLayout.ofSequence(MemoryLayouts.JAVA_BYTE)
+                .varHandle(byte.class, MemoryLayout.PathElement.sequenceElement());
+        try (MemorySegment segment = MemorySegment.allocateNative(1000)) {
+            for (long i = 0 ; i < segment.byteSize() ; i++) {
+                assertEquals(0, (byte)byteHandle.get(segment.baseAddress(), i));
+            }
+        }
+    }
+
+    @DataProvider(name = "badSizeAndAlignments")
+    public Object[][] sizesAndAlignments() {
+        return new Object[][] {
+                { -1, 8 },
+                { 1, 15 },
+                { 1, -15 }
+        };
+    }
+
+    @DataProvider(name = "badLayouts")
+    public Object[][] layouts() {
+        SizedLayoutFactory[] layoutFactories = SizedLayoutFactory.values();
+        Object[][] values = new Object[layoutFactories.length * 2][2];
+        for (int i = 0; i < layoutFactories.length ; i++) {
+            values[i * 2] = new Object[] { MemoryLayout.ofStruct(layoutFactories[i].make(7), MemoryLayout.ofPaddingBits(9)) }; // good size, bad align
+            values[(i * 2) + 1] = new Object[] { layoutFactories[i].make(15).withBitAlignment(16) }; // bad size, good align
+        }
+        return values;
+    }
+
+    enum SizedLayoutFactory {
+        VALUE_BE(size -> MemoryLayout.ofValueBits(size, ByteOrder.BIG_ENDIAN)),
+        VALUE_LE(size -> MemoryLayout.ofValueBits(size, ByteOrder.LITTLE_ENDIAN)),
+        PADDING(MemoryLayout::ofPaddingBits);
+
+        private final LongFunction<MemoryLayout> factory;
+
+        SizedLayoutFactory(LongFunction<MemoryLayout> factory) {
+            this.factory = factory;
+        }
+
+        MemoryLayout make(long size) {
+            return factory.apply(size);
+        }
+    }
+
+    @DataProvider(name = "segmentOperations")
+    static Object[][] segmentMembers() {
+        List<SegmentMember> members = new ArrayList<>();
+        for (Method m : MemorySegment.class.getDeclaredMethods()) {
+            //skip statics and method declared in j.l.Object
+            if (m.getDeclaringClass().equals(Object.class) ||
+                    (m.getModifiers() & Modifier.STATIC) != 0) continue;
+            Object[] args = Stream.of(m.getParameterTypes())
+                    .map(TestSegments::defaultValue)
+                    .toArray();
+            members.add(new SegmentMember(m, args));
+        }
+        return members.stream().map(ms -> new Object[] { ms }).toArray(Object[][]::new);
+    }
+
+    static class SegmentMember {
+        final Method method;
+        final Object[] params;
+
+        public SegmentMember(Method method, Object[] params) {
+            this.method = method;
+            this.params = params;
+        }
+
+        boolean isConfined() {
+            return method.getName().startsWith("as") ||
+                    method.getName().startsWith("to") ||
+                    method.getName().equals("close") ||
+                    method.getName().equals("slice");
+        }
+
+        @Override
+        public String toString() {
+            return method.getName();
+        }
+    }
+
+    static Object defaultValue(Class<?> c) {
+        if (c.isPrimitive()) {
+            if (c == char.class) {
+                return (char)0;
+            } else if (c == boolean.class) {
+                return false;
+            } else if (c == byte.class) {
+                return (byte)0;
+            } else if (c == short.class) {
+                return (short)0;
+            } else if (c == int.class) {
+                return 0;
+            } else if (c == long.class) {
+                return 0L;
+            } else if (c == float.class) {
+                return 0f;
+            } else if (c == double.class) {
+                return 0d;
+            } else {
+                throw new IllegalStateException();
+            }
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/test/jdk/java/foreign/TestSharedAccess.java b/test/jdk/java/foreign/TestSharedAccess.java
new file mode 100644
index 00000000000..d78c5251236
--- /dev/null
+++ b/test/jdk/java/foreign/TestSharedAccess.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ *
+ */
+
+/*
+ * @test
+ * @run testng TestSharedAccess
+ */
+
+import jdk.incubator.foreign.MemorySegment;
+import jdk.incubator.foreign.MemoryLayouts;
+import org.testng.annotations.*;
+
+import java.lang.invoke.VarHandle;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.testng.Assert.*;
+
+public class TestSharedAccess {
+
+    static final VarHandle intHandle = MemoryLayouts.JAVA_INT.varHandle(int.class);
+
+    @Test
+    public void testShared() throws Throwable {
+        try (MemorySegment s = MemorySegment.allocateNative(4)) {
+            setInt(s, 42);
+            assertEquals(getInt(s), 42);
+            List<Thread> threads = new ArrayList<>();
+            for (int i = 0 ; i < 1000 ; i++) {
+                threads.add(new Thread(() -> {
+                    try (MemorySegment local = s.acquire()) {
+                        assertEquals(getInt(local), 42);
+                    }
+                }));
+            }
+            threads.forEach(Thread::start);
+            threads.forEach(t -> {
+                try {
+                    t.join();
+                } catch (Throwable e) {
+                    throw new IllegalStateException(e);
+                }
+            });
+        }
+    }
+
+    @Test(expectedExceptions=IllegalStateException.class)
+    public void testBadCloseWithPendingAcquire() {
+        try (MemorySegment segment = MemorySegment.allocateNative(8)) {
+            segment.acquire();
+        } //should fail here!
+    }
+
+    static int getInt(MemorySegment handle) {
+        return (int)intHandle.getVolatile(handle.baseAddress());
+    }
+
+    static void setInt(MemorySegment handle, int value) {
+        intHandle.setVolatile(handle.baseAddress(), value);
+    }
+}
diff --git a/test/jdk/java/foreign/TestSlices.java b/test/jdk/java/foreign/TestSlices.java
new file mode 100644
index 00000000000..7fe6436425b
--- /dev/null
+++ b/test/jdk/java/foreign/TestSlices.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ *
+ */
+
+import jdk.incubator.foreign.MemoryHandles;
+import jdk.incubator.foreign.MemoryLayout;
+import jdk.incubator.foreign.MemoryLayouts;
+import jdk.incubator.foreign.MemorySegment;
+
+import java.lang.invoke.VarHandle;
+
+import org.testng.annotations.*;
+import static org.testng.Assert.*;
+
+/*
+ * @test
+ * @run testng/othervm -Xverify:all TestSlices
+ */
+public class TestSlices {
+
+    static MemoryLayout LAYOUT = MemoryLayout.ofSequence(2,
+            MemoryLayout.ofSequence(5, MemoryLayouts.JAVA_INT));
+
+    static VarHandle VH_ALL = LAYOUT.varHandle(int.class,
+            MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement());
+
+    static VarHandle VH_INT = MemoryLayouts.JAVA_INT.varHandle(int.class);
+
+    @Test(dataProvider = "slices")
+    public void testSlices(VarHandle handle, int lo, int hi, int[] values) {
+        try (MemorySegment segment = MemorySegment.allocateNative(LAYOUT)) {
+            //init
+            for (long i = 0 ; i < 2 ; i++) {
+                for (long j = 0 ; j < 5 ; j++) {
+                    VH_ALL.set(segment.baseAddress(), i, j, (int)j + 1 + ((int)i * 5));
+                }
+            }
+
+            checkSlice(segment, handle, lo, hi, values);
+        }
+    }
+
+    static void checkSlice(MemorySegment segment, VarHandle handle, long i_max, long j_max, int... values) {
+        int index = 0;
+        for (long i = 0 ; i < i_max ; i++) {
+            for (long j = 0 ; j < j_max ; j++) {
+                int x = (int) handle.get(segment.baseAddress(), i, j);
+                assertEquals(x, values[index++]);
+            }
+        }
+        assertEquals(index, values.length);
+    }
+
+    @DataProvider(name = "slices")
+    static Object[][] slices() {
+        return new Object[][] {
+                // x
+                { VH_ALL, 2, 5, new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } },
+                // x[0::2]
+                { LAYOUT.varHandle(int.class, MemoryLayout.PathElement.sequenceElement(),
+                        MemoryLayout.PathElement.sequenceElement(0, 2)), 2, 3, new int[] { 1, 3, 5, 6, 8, 10 } },
+                { MemoryHandles.withStride(MemoryHandles.withStride(VH_INT, 8), 20), 2, 3, new int[] { 1, 3, 5, 6, 8, 10 } },
+                // x[1::2]
+                { LAYOUT.varHandle(int.class, MemoryLayout.PathElement.sequenceElement(),
+                        MemoryLayout.PathElement.sequenceElement(1, 2)), 2, 2, new int[] { 2, 4, 7, 9 } },
+                { MemoryHandles.withOffset(MemoryHandles.withStride(MemoryHandles.withStride(VH_INT, 8), 20), 4), 2, 2, new int[] { 2, 4, 7, 9 } },
+                // x[4::-2]
+                { LAYOUT.varHandle(int.class, MemoryLayout.PathElement.sequenceElement(),
+                        MemoryLayout.PathElement.sequenceElement(4, -2)), 2, 3, new int[] { 5, 3, 1, 10, 8, 6 } },
+                { MemoryHandles.withOffset(MemoryHandles.withStride(MemoryHandles.withStride(VH_INT, -8), 20), 16), 2, 3, new int[] { 5, 3, 1, 10, 8, 6 } },
+                // x[3::-2]
+                { LAYOUT.varHandle(int.class, MemoryLayout.PathElement.sequenceElement(),
+                        MemoryLayout.PathElement.sequenceElement(3, -2)), 2, 2, new int[] { 4, 2, 9, 7 } },
+                { MemoryHandles.withOffset(MemoryHandles.withStride(MemoryHandles.withStride(VH_INT, -8), 20), 12), 2, 2, new int[] { 4, 2, 9, 7 } },
+        };
+    }
+}
diff --git a/test/jdk/java/foreign/TestVarHandleCombinators.java b/test/jdk/java/foreign/TestVarHandleCombinators.java
new file mode 100644
index 00000000000..04fd987370d
--- /dev/null
+++ b/test/jdk/java/foreign/TestVarHandleCombinators.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ *
+ */
+
+/*
+ * @test
+ * @run testng TestVarHandleCombinators
+ */
+
+import jdk.incubator.foreign.MemoryHandles;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.MemoryAddress;
+import jdk.incubator.foreign.MemorySegment;
+
+import java.lang.invoke.VarHandle;
+import java.nio.ByteOrder;
+
+import static org.testng.Assert.assertEquals;
+
+public class TestVarHandleCombinators {
+
+    @Test
+    public void testElementAccess() {
+        VarHandle vh = MemoryHandles.varHandle(byte.class, ByteOrder.nativeOrder());
+        vh = MemoryHandles.withStride(vh, 1);
+
+        byte[] arr = { 0, 0, -1, 0 };
+        MemorySegment segment = MemorySegment.ofArray(arr);
+        MemoryAddress addr = segment.baseAddress();
+
+        assertEquals((byte) vh.get(addr, 2), (byte) -1);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testUnalignedElement() {
+        VarHandle vh = MemoryHandles.varHandle(byte.class, 4, ByteOrder.nativeOrder());
+        MemoryHandles.withStride(vh, 2);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testBadStrideElement() {
+        VarHandle vh = MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder());
+        MemoryHandles.withStride(vh, 0); //scale factor cant be zero
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testAlignNotPowerOf2() {
+        VarHandle vh = MemoryHandles.varHandle(byte.class, 3, ByteOrder.nativeOrder());
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testAlignNegative() {
+        VarHandle vh = MemoryHandles.varHandle(byte.class, -1, ByteOrder.nativeOrder());
+    }
+
+    @Test
+    public void testAlign() {
+        VarHandle vh = MemoryHandles.varHandle(byte.class, 2, ByteOrder.nativeOrder());
+
+        MemorySegment segment = MemorySegment.allocateNative(1, 2);
+        MemoryAddress address = segment.baseAddress();
+
+        vh.set(address, (byte) 10); // fine, memory region is aligned
+        assertEquals((byte) vh.get(address), (byte) 10);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testAlignBadAccess() {
+        VarHandle vh = MemoryHandles.varHandle(byte.class, 2, ByteOrder.nativeOrder());
+        vh = MemoryHandles.withOffset(vh, 1); // offset by 1 byte
+
+        MemorySegment segment = MemorySegment.allocateNative(2, 2);
+        MemoryAddress address = segment.baseAddress();
+
+        vh.set(address, (byte) 10); // should be bad align
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testOffsetNegative() {
+        VarHandle vh = MemoryHandles.varHandle(byte.class, ByteOrder.nativeOrder());
+        MemoryHandles.withOffset(vh, -1);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testUnalignedOffset() {
+        VarHandle vh = MemoryHandles.varHandle(byte.class, 4, ByteOrder.nativeOrder());
+        MemoryHandles.withOffset(vh, 2);
+    }
+
+    @Test
+    public void testOffset() {
+        VarHandle vh = MemoryHandles.varHandle(byte.class, ByteOrder.nativeOrder());
+        vh = MemoryHandles.withOffset(vh, 1);
+
+        MemorySegment segment = MemorySegment.ofArray(new byte[2]);
+        MemoryAddress address = segment.baseAddress();
+
+        vh.set(address, (byte) 10);
+        assertEquals((byte) vh.get(address), (byte) 10);
+    }
+
+    @Test
+    public void testByteOrderLE() {
+        VarHandle vh = MemoryHandles.varHandle(short.class, 2, ByteOrder.LITTLE_ENDIAN);
+        byte[] arr = new byte[2];
+        MemorySegment segment = MemorySegment.ofArray(arr);
+        MemoryAddress address = segment.baseAddress();
+
+        vh.set(address, (short) 0xFF);
+        assertEquals(arr[0], (byte) 0xFF);
+        assertEquals(arr[1], (byte) 0);
+    }
+
+    @Test
+    public void testByteOrderBE() {
+        VarHandle vh = MemoryHandles.varHandle(short.class, 2, ByteOrder.BIG_ENDIAN);
+        byte[] arr = new byte[2];
+        MemorySegment segment = MemorySegment.ofArray(arr);
+        MemoryAddress address = segment.baseAddress();
+
+        vh.set(address, (short) 0xFF);
+        assertEquals(arr[0], (byte) 0);
+        assertEquals(arr[1], (byte) 0xFF);
+    }
+
+    @Test
+    public void testNestedSequenceAccess() {
+        int outer_size = 10;
+        int inner_size = 5;
+
+        //[10 : [5 : [x32 i32]]]
+
+        VarHandle vh = MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder());
+        vh = MemoryHandles.withOffset(vh, 4);
+        VarHandle inner_vh = MemoryHandles.withStride(vh, 8);
+        VarHandle outer_vh = MemoryHandles.withStride(inner_vh, 5 * 8);
+        int count = 0;
+        try (MemorySegment segment = MemorySegment.allocateNative(inner_size * outer_size * 8)) {
+            for (long i = 0; i < outer_size; i++) {
+                for (long j = 0; j < inner_size; j++) {
+                    outer_vh.set(segment.baseAddress(), i, j, count);
+                    assertEquals(
+                            (int)inner_vh.get(segment.baseAddress().offset(i * inner_size * 8), j),
+                            count);
+                    count++;
+                }
+            }
+        }
+    }
+
+    @Test(dataProvider = "badCarriers", expectedExceptions = IllegalArgumentException.class)
+    public void testBadCarrier(Class<?> carrier) {
+        MemoryHandles.varHandle(carrier, ByteOrder.nativeOrder());
+    }
+
+    @DataProvider(name = "badCarriers")
+    public Object[][] createBadCarriers() {
+        return new Object[][] {
+                { void.class },
+                { boolean.class },
+                { Object.class },
+                { int[].class },
+                { MemoryAddress.class }
+        };
+    }
+
+}
diff --git a/test/jdk/java/foreign/libNativeAccess.c b/test/jdk/java/foreign/libNativeAccess.c
new file mode 100644
index 00000000000..edd47176b36
--- /dev/null
+++ b/test/jdk/java/foreign/libNativeAccess.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ *
+ */
+
+#include "jni.h"
+#include <stdio.h>
+
+JNIEXPORT jbyte JNICALL
+Java_TestNative_getByteRaw(JNIEnv *env, jclass cls, jlong addr, jint index) {
+    jbyte *arr = (jbyte*)addr;
+    return arr[index];
+}
+
+JNIEXPORT jbyte JNICALL
+Java_TestNative_getByteBuffer(JNIEnv *env, jclass cls, jobject buf, jint index) {
+    jlong addr = (jlong)(*env)->GetDirectBufferAddress(env, buf);
+    return Java_TestNative_getByteRaw(env, cls, addr, index);
+}
+
+JNIEXPORT jchar JNICALL
+Java_TestNative_getCharRaw(JNIEnv *env, jclass cls, jlong addr, jint index) {
+    jchar *arr = (jchar*)addr;
+    return arr[index];
+}
+
+JNIEXPORT jchar JNICALL
+Java_TestNative_getCharBuffer(JNIEnv *env, jclass cls, jobject buf, jint index) {
+    jlong addr = (jlong)(*env)->GetDirectBufferAddress(env, buf);
+    return Java_TestNative_getCharRaw(env, cls, addr, index);
+}
+
+JNIEXPORT jshort JNICALL
+Java_TestNative_getShortRaw(JNIEnv *env, jclass cls, jlong addr, jint index) {
+    jshort *arr = (jshort*)addr;
+    return arr[index];
+}
+
+JNIEXPORT jshort JNICALL
+Java_TestNative_getShortBuffer(JNIEnv *env, jclass cls, jobject buf, jint index) {
+    jlong addr = (jlong)(*env)->GetDirectBufferAddress(env, buf);
+    return Java_TestNative_getShortRaw(env, cls, addr, index);
+}
+
+JNIEXPORT jint JNICALL
+Java_TestNative_getIntRaw(JNIEnv *env, jclass cls, jlong addr, jint index) {
+    jint *arr = (jint*)addr;
+    return arr[index];
+}
+
+JNIEXPORT jint JNICALL
+Java_TestNative_getIntBuffer(JNIEnv *env, jclass cls, jobject buf, jint index) {
+    jlong addr = (jlong)(*env)->GetDirectBufferAddress(env, buf);
+    return Java_TestNative_getIntRaw(env, cls, addr, index);
+}
+
+JNIEXPORT jfloat JNICALL
+Java_TestNative_getFloatRaw(JNIEnv *env, jclass cls, jlong addr, jint index) {
+    jfloat *arr = (jfloat*)addr;
+    return arr[index];
+}
+
+JNIEXPORT jfloat JNICALL
+Java_TestNative_getFloatBuffer(JNIEnv *env, jclass cls, jobject buf, jint index) {
+    jlong addr = (jlong)(*env)->GetDirectBufferAddress(env, buf);
+    return Java_TestNative_getFloatRaw(env, cls, addr, index);
+}
+
+JNIEXPORT jlong JNICALL
+Java_TestNative_getLongRaw(JNIEnv *env, jclass cls, jlong addr, jint index) {
+    jlong *arr = (jlong*)addr;
+    return arr[index];
+}
+
+JNIEXPORT jlong JNICALL
+Java_TestNative_getLongBuffer(JNIEnv *env, jclass cls, jobject buf, jint index) {
+    jlong addr = (jlong)(*env)->GetDirectBufferAddress(env, buf);
+    return Java_TestNative_getLongRaw(env, cls, addr, index);
+}
+
+JNIEXPORT jdouble JNICALL
+Java_TestNative_getDoubleRaw(JNIEnv *env, jclass cls, jlong addr, jint index) {
+    jdouble *arr = (jdouble*)addr;
+    return arr[index];
+}
+
+JNIEXPORT jdouble JNICALL
+Java_TestNative_getDoubleBuffer(JNIEnv *env, jclass cls, jobject buf, jint index) {
+    jlong addr = (jlong)(*env)->GetDirectBufferAddress(env, buf);
+    return Java_TestNative_getDoubleRaw(env, cls, addr, index);
+}
+
+JNIEXPORT jlong JNICALL
+Java_TestNative_getCapacity(JNIEnv *env, jclass cls, jobject buf) {
+    return (*env)->GetDirectBufferCapacity(env, buf);
+}

From a5db02db72aeb3e02e63a916a6c803700b382f80 Mon Sep 17 00:00:00 2001
From: Jesper Wilhelmsson <jwilhelm@openjdk.org>
Date: Fri, 13 Dec 2019 02:45:28 +0100
Subject: [PATCH 06/12] Added tag jdk-14+27 for changeset 91a3f092682f

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index 87ac6618472..87f4de23368 100644
--- a/.hgtags
+++ b/.hgtags
@@ -599,3 +599,4 @@ c16ac7a2eba4e73cb4f7ee9294dd647860eebff0 jdk-14+21
 438337c846fb071900ddb6922bddf8b3e895a514 jdk-14+24
 17d242844fc9e7d18b3eac97426490a9c246119e jdk-14+25
 288777cf0702914e5266bc1e5d380eed9032ca41 jdk-14+26
+91a3f092682fc715d991a87eb6ec6f28886d2035 jdk-14+27

From e6b381faa2b516950ceb70b92c64d31962fcea8c Mon Sep 17 00:00:00 2001
From: Pankaj Bansal <pbansal@openjdk.org>
Date: Fri, 13 Dec 2019 12:08:10 +0530
Subject: [PATCH 07/12] 8235744: PIT:
 test/jdk/javax/swing/text/html/TestJLabelWithHTMLText.java times out in
 linux-x64

Reviewed-by: psadhukhan, prr
---
 test/jdk/javax/swing/text/html/TestJLabelWithHTMLText.java | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/jdk/javax/swing/text/html/TestJLabelWithHTMLText.java b/test/jdk/javax/swing/text/html/TestJLabelWithHTMLText.java
index eec9e6c932f..6fa70df83cc 100644
--- a/test/jdk/javax/swing/text/html/TestJLabelWithHTMLText.java
+++ b/test/jdk/javax/swing/text/html/TestJLabelWithHTMLText.java
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @bug 8230235
+ * @bug 8230235 8235744
  * @summary Tests if JLabel with HTML text having empty img tag and
  *      documentBaseKey set renders properly without NPE
  * @run main TestJLabelWithHTMLText
@@ -41,7 +41,7 @@ public class TestJLabelWithHTMLText {
             JLabel label = new JLabel();
             try {
                 label.putClientProperty(BasicHTML.documentBaseKey,
-                        new URL("https://www.google.com"));
+                        new URL("http://localhost"));
             } catch (MalformedURLException e) {
                 e.printStackTrace();
             }

From 58cce5fbf4eb64eb14588893d456bcfb006944bf Mon Sep 17 00:00:00 2001
From: Sibabrata Sahoo <ssahoo@openjdk.org>
Date: Fri, 13 Dec 2019 01:43:14 -0800
Subject: [PATCH 08/12] 8234728: Some security tests should support TLSv1.3

Tests were updated to support TLSv1.3 and cipher suite order

Reviewed-by: xuelei
---
 .../classes/sun/security/ssl/CipherSuite.java |  26 +-
 .../ciphersuites/CipherSuitesInOrder.java     | 294 ++++++++++--------
 .../SystemPropCipherSuitesOrder.java          | 143 +++++++++
 .../ciphersuites/TLSCipherSuitesOrder.java    | 185 +++++++++++
 .../HandshakeHashCloneExhaustion.java         |   6 +-
 .../HostnameMatcher/NullHostnameCheck.java    | 200 ++++++------
 6 files changed, 615 insertions(+), 239 deletions(-)
 create mode 100644 test/jdk/javax/net/ssl/sanity/ciphersuites/SystemPropCipherSuitesOrder.java
 create mode 100644 test/jdk/javax/net/ssl/sanity/ciphersuites/TLSCipherSuitesOrder.java

diff --git a/src/java.base/share/classes/sun/security/ssl/CipherSuite.java b/src/java.base/share/classes/sun/security/ssl/CipherSuite.java
index 971156cd7cf..24d7e1ded81 100644
--- a/src/java.base/share/classes/sun/security/ssl/CipherSuite.java
+++ b/src/java.base/share/classes/sun/security/ssl/CipherSuite.java
@@ -100,7 +100,7 @@ enum CipherSuite {
             K_ECDHE_ECDSA, B_CC20_P1305, M_NULL, H_SHA256),
 
     //
-    // Forward screcy cipher suites.
+    // Forward secrecy cipher suites.
     //
 
     // AES_256(GCM) - ECDHE
@@ -271,7 +271,7 @@ enum CipherSuite {
             ProtocolVersion.PROTOCOLS_TO_12,
             K_DHE_DSS, B_AES_128, M_SHA, H_SHA256),
 
-    // AES_256(CBC) - using SHA, not forward screcy
+    // AES_256(CBC) - using SHA, not forward secrecy
     TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA(
             0xC005, true, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", "",
             ProtocolVersion.PROTOCOLS_TO_12,
@@ -281,7 +281,7 @@ enum CipherSuite {
             ProtocolVersion.PROTOCOLS_TO_12,
             K_ECDH_RSA, B_AES_256, M_SHA, H_SHA256),
 
-    // AES_128(CBC) - using SHA, not forward screcy
+    // AES_128(CBC) - using SHA, not forward secrecy
     TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA(
             0xC004, true, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", "",
             ProtocolVersion.PROTOCOLS_TO_12,
@@ -319,13 +319,13 @@ enum CipherSuite {
             ProtocolVersion.PROTOCOLS_OF_12,
             K_RSA, B_AES_128, M_SHA256, H_SHA256),
 
-    // RSA, AES_256(CBC) - using SHA, not forward screcy
+    // RSA, AES_256(CBC) - using SHA, not forward secrecy
     TLS_RSA_WITH_AES_256_CBC_SHA(
             0x0035, true, "TLS_RSA_WITH_AES_256_CBC_SHA", "",
             ProtocolVersion.PROTOCOLS_TO_12,
             K_RSA, B_AES_256, M_SHA, H_SHA256),
 
-    // RSA, AES_128(CBC) - using SHA, not forward screcy
+    // RSA, AES_128(CBC) - using SHA, not forward secrecy
     TLS_RSA_WITH_AES_128_CBC_SHA(
             0x002F, true, "TLS_RSA_WITH_AES_128_CBC_SHA", "",
             ProtocolVersion.PROTOCOLS_TO_12,
@@ -464,7 +464,7 @@ enum CipherSuite {
             ProtocolVersion.PROTOCOLS_TO_TLS12,
             K_DH_ANON, B_RC4_128, M_MD5, H_SHA256),
 
-    // weak cipher suites obsoleted in TLS 1.2 [RFC 5246]
+    // Weak cipher suites obsoleted in TLS 1.2 [RFC 5246]
     SSL_RSA_WITH_DES_CBC_SHA(
             0x0009, false, "SSL_RSA_WITH_DES_CBC_SHA",
                            "TLS_RSA_WITH_DES_CBC_SHA",
@@ -486,7 +486,7 @@ enum CipherSuite {
             ProtocolVersion.PROTOCOLS_TO_11,
             K_DH_ANON, B_DES, M_SHA, H_NONE),
 
-    // weak cipher suites obsoleted in TLS 1.1  [RFC 4346]
+    // Weak cipher suites obsoleted in TLS 1.1  [RFC 4346]
     SSL_RSA_EXPORT_WITH_DES40_CBC_SHA(
             0x0008, false, "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
                            "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA",
@@ -518,7 +518,7 @@ enum CipherSuite {
             ProtocolVersion.PROTOCOLS_TO_10,
             K_DH_ANON, B_RC4_40, M_MD5, H_NONE),
 
-    // no traffic encryption cipher suites
+    // No traffic encryption cipher suites
     TLS_RSA_WITH_NULL_SHA256(
             0x003B, false, "TLS_RSA_WITH_NULL_SHA256", "",
             ProtocolVersion.PROTOCOLS_OF_12,
@@ -554,14 +554,14 @@ enum CipherSuite {
             ProtocolVersion.PROTOCOLS_TO_12,
             K_RSA, B_NULL, M_MD5, H_SHA256),
 
-    // Definition of the CipherSuites that are not supported but the names
+    // Definition of the cipher suites that are not supported but the names
     // are known.
     TLS_AES_128_CCM_SHA256(                          // TLS 1.3
             "TLS_AES_128_CCM_SHA256", 0x1304),
     TLS_AES_128_CCM_8_SHA256(                        // TLS 1.3
             "TLS_AES_128_CCM_8_SHA256", 0x1305),
 
-    // remaining unsupported ciphersuites defined in RFC2246.
+    // Remaining unsupported cipher suites defined in RFC2246.
     CS_0006("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5",           0x0006),
     CS_0007("SSL_RSA_WITH_IDEA_CBC_SHA",                    0x0007),
     CS_000B("SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",         0x000b),
@@ -571,18 +571,18 @@ enum CipherSuite {
     CS_000F("SSL_DH_RSA_WITH_DES_CBC_SHA",                  0x000f),
     CS_0010("SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA",             0x0010),
 
-    // SSL 3.0 Fortezza ciphersuites
+    // SSL 3.0 Fortezza cipher suites
     CS_001C("SSL_FORTEZZA_DMS_WITH_NULL_SHA",               0x001c),
     CS_001D("SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA",       0x001d),
 
-    // 1024/56 bit exportable ciphersuites from expired internet draft
+    // 1024/56 bit exportable cipher suites from expired internet draft
     CS_0062("SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA",          0x0062),
     CS_0063("SSL_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA",      0x0063),
     CS_0064("SSL_RSA_EXPORT1024_WITH_RC4_56_SHA",           0x0064),
     CS_0065("SSL_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA",       0x0065),
     CS_0066("SSL_DHE_DSS_WITH_RC4_128_SHA",                 0x0066),
 
-    // Netscape old and new SSL 3.0 FIPS ciphersuites
+    // Netscape old and new SSL 3.0 FIPS cipher suites
     // see http://www.mozilla.org/projects/security/pki/nss/ssl/fips-ssl-ciphersuites.html
     CS_FFE0("NETSCAPE_RSA_FIPS_WITH_3DES_EDE_CBC_SHA",      0xffe0),
     CS_FFE1("NETSCAPE_RSA_FIPS_WITH_DES_CBC_SHA",           0xffe1),
diff --git a/test/jdk/javax/net/ssl/sanity/ciphersuites/CipherSuitesInOrder.java b/test/jdk/javax/net/ssl/sanity/ciphersuites/CipherSuitesInOrder.java
index 4da5f555d18..1966eb25f03 100644
--- a/test/jdk/javax/net/ssl/sanity/ciphersuites/CipherSuitesInOrder.java
+++ b/test/jdk/javax/net/ssl/sanity/ciphersuites/CipherSuitesInOrder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -28,143 +28,179 @@
 
 /*
  * @test
- * @bug 7174244
- * @summary NPE in Krb5ProxyImpl.getServerKeys()
- * @ignore the dependent implementation details are changed
+ * @bug 7174244 8234728
+ * @summary Test for ciphersuites order
  * @run main/othervm CipherSuitesInOrder
  */
-
 import java.util.*;
 import javax.net.ssl.*;
-import java.security.Security;
 
 public class CipherSuitesInOrder {
 
-    // supported ciphersuites
-    private final static List<String> supportedCipherSuites =
-            Arrays.<String>asList(
-        "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
-        "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
-        "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
-        "TLS_RSA_WITH_AES_256_GCM_SHA384",
-        "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
-        "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
-        "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
-        "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
-        "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
-        "TLS_RSA_WITH_AES_128_GCM_SHA256",
-        "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
-        "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
-        "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
-        "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
-
-        "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
-        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
-        "TLS_RSA_WITH_AES_256_CBC_SHA256",
-        "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
-        "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",
-        "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
-        "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
-        "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
-        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
-        "TLS_RSA_WITH_AES_256_CBC_SHA",
-        "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
-        "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
-        "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
-        "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
-        "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
-        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
-        "TLS_RSA_WITH_AES_128_CBC_SHA256",
-        "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
-        "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
-        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
-        "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
-        "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
-        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
-        "TLS_RSA_WITH_AES_128_CBC_SHA",
-        "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
-        "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
-        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
-        "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
-
-        "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
-        "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
-        "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
-        "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
-        "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
-        "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
-        "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
-
-        "TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
-
-        "TLS_DH_anon_WITH_AES_256_GCM_SHA384",
-        "TLS_DH_anon_WITH_AES_128_GCM_SHA256",
-
-        "TLS_DH_anon_WITH_AES_256_CBC_SHA256",
-        "TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
-        "TLS_DH_anon_WITH_AES_256_CBC_SHA",
-        "TLS_DH_anon_WITH_AES_128_CBC_SHA256",
-        "TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
-        "TLS_DH_anon_WITH_AES_128_CBC_SHA",
-        "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
-        "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
-
-        "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
-        "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
-        "SSL_RSA_WITH_RC4_128_SHA",
-        "TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
-        "TLS_ECDH_RSA_WITH_RC4_128_SHA",
-        "SSL_RSA_WITH_RC4_128_MD5",
-        "TLS_ECDH_anon_WITH_RC4_128_SHA",
-        "SSL_DH_anon_WITH_RC4_128_MD5",
-
-        "SSL_RSA_WITH_DES_CBC_SHA",
-        "SSL_DHE_RSA_WITH_DES_CBC_SHA",
-        "SSL_DHE_DSS_WITH_DES_CBC_SHA",
-        "SSL_DH_anon_WITH_DES_CBC_SHA",
-        "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
-        "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
-        "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
-        "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
-
-        "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
-        "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
-
-        "TLS_RSA_WITH_NULL_SHA256",
-        "TLS_ECDHE_ECDSA_WITH_NULL_SHA",
-        "TLS_ECDHE_RSA_WITH_NULL_SHA",
-        "SSL_RSA_WITH_NULL_SHA",
-        "TLS_ECDH_ECDSA_WITH_NULL_SHA",
-        "TLS_ECDH_RSA_WITH_NULL_SHA",
-        "TLS_ECDH_anon_WITH_NULL_SHA",
-        "SSL_RSA_WITH_NULL_MD5",
-
-        "TLS_KRB5_WITH_3DES_EDE_CBC_SHA",
-        "TLS_KRB5_WITH_3DES_EDE_CBC_MD5",
-        "TLS_KRB5_WITH_RC4_128_SHA",
-        "TLS_KRB5_WITH_RC4_128_MD5",
-        "TLS_KRB5_WITH_DES_CBC_SHA",
-        "TLS_KRB5_WITH_DES_CBC_MD5",
-        "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA",
-        "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5",
-        "TLS_KRB5_EXPORT_WITH_RC4_40_SHA",
-        "TLS_KRB5_EXPORT_WITH_RC4_40_MD5"
-    );
+    // Supported ciphersuites
+    private final static List<String> supportedCipherSuites
+            = Arrays.<String>asList(
+                    // TLS 1.3 cipher suites.
+                    "TLS_AES_256_GCM_SHA384",
+                    "TLS_AES_128_GCM_SHA256",
+                    "TLS_CHACHA20_POLY1305_SHA256",
+                    // Suite B compliant cipher suites, see RFC 6460.
+                    "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+                    "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+                    // Not suite B, but we want it to position the suite early
+                    //in the list of 1.2 suites.
+                    "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
+                    //
+                    // Forward secrecy cipher suites.
+                    //
+                    // AES_256(GCM) - ECDHE
+                    "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
+                    "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
+                    // AES_128(GCM) - ECDHE
+                    "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+                    // AES_256(GCM) - DHE
+                    "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
+                    "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
+                    "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
+                    // AES_128(GCM) - DHE
+                    "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
+                    "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
+                    // AES_256(CBC) - ECDHE
+                    "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
+                    "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
+                    // AES_128(CBC) - ECDHE
+                    "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
+                    "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
+                    // AES_256(CBC) - DHE
+                    "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
+                    "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
+                    // AES_128(CBC) - DHE
+                    "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
+                    "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
+                    //
+                    // Not forward secret cipher suites.
+                    //
+                    // AES_256(GCM)
+                    "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
+                    "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
+                    // AES_128(GCM)
+                    "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
+                    "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
+                    // AES_256(CBC)
+                    "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
+                    "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",
+                    // AES_128(CBC)
+                    "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
+                    "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
+                    //
+                    // Legacy, used for compatibility
+                    //
+                    // AES_256(CBC) - ECDHE - Using SHA
+                    "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
+                    "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
+                    // AES_128(CBC) - ECDHE - using SHA
+                    "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+                    "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
+                    // AES_256(CBC) - DHE - Using SHA
+                    "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
+                    "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
+                    // AES_128(CBC) - DHE - using SHA
+                    "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+                    "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+                    // AES_256(CBC) - using SHA, not forward secrecy
+                    "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
+                    "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
+                    // AES_128(CBC) - using SHA, not forward secrecy
+                    "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
+                    "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
+                    //
+                    // Deprecated, used for compatibility
+                    //
+                    // RSA, AES_256(GCM)
+                    "TLS_RSA_WITH_AES_256_GCM_SHA384",
+                    // RSA, AES_128(GCM)
+                    "TLS_RSA_WITH_AES_128_GCM_SHA256",
+                    // RSA, AES_256(CBC)
+                    "TLS_RSA_WITH_AES_256_CBC_SHA256",
+                    // RSA, AES_128(CBC)
+                    "TLS_RSA_WITH_AES_128_CBC_SHA256",
+                    // RSA, AES_256(CBC) - using SHA, not forward secrecy
+                    "TLS_RSA_WITH_AES_256_CBC_SHA",
+                    // RSA, AES_128(CBC) - using SHA, not forward secrecy
+                    "TLS_RSA_WITH_AES_128_CBC_SHA",
+                    // 3DES_EDE, forward secrecy.
+                    "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
+                    "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
+                    "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+                    "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
+                    // 3DES_EDE, not forward secrecy.
+                    "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
+                    "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
+                    "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
+                    // Renegotiation protection request Signalling
+                    // Cipher Suite Value (SCSV).
+                    "TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
+                    // Definition of the Cipher Suites that are supported but not
+                    // enabled by default.
+                    "TLS_DH_anon_WITH_AES_256_GCM_SHA384",
+                    "TLS_DH_anon_WITH_AES_128_GCM_SHA256",
+                    "TLS_DH_anon_WITH_AES_256_CBC_SHA256",
+                    "TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
+                    "TLS_DH_anon_WITH_AES_256_CBC_SHA",
+                    "TLS_DH_anon_WITH_AES_128_CBC_SHA256",
+                    "TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
+                    "TLS_DH_anon_WITH_AES_128_CBC_SHA",
+                    "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
+                    "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
+                    // RC4
+                    "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
+                    "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
+                    "SSL_RSA_WITH_RC4_128_SHA",
+                    "TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
+                    "TLS_ECDH_RSA_WITH_RC4_128_SHA",
+                    "SSL_RSA_WITH_RC4_128_MD5",
+                    "TLS_ECDH_anon_WITH_RC4_128_SHA",
+                    "SSL_DH_anon_WITH_RC4_128_MD5",
+                    // Weak cipher suites obsoleted in TLS 1.2 [RFC 5246]
+                    "SSL_RSA_WITH_DES_CBC_SHA",
+                    "SSL_DHE_RSA_WITH_DES_CBC_SHA",
+                    "SSL_DHE_DSS_WITH_DES_CBC_SHA",
+                    "SSL_DH_anon_WITH_DES_CBC_SHA",
+                    // Weak cipher suites obsoleted in TLS 1.1  [RFC 4346]
+                    "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
+                    "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
+                    "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
+                    "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
+                    "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
+                    "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
+                    // No traffic encryption cipher suites
+                    "TLS_RSA_WITH_NULL_SHA256",
+                    "TLS_ECDHE_ECDSA_WITH_NULL_SHA",
+                    "TLS_ECDHE_RSA_WITH_NULL_SHA",
+                    "SSL_RSA_WITH_NULL_SHA",
+                    "TLS_ECDH_ECDSA_WITH_NULL_SHA",
+                    "TLS_ECDH_RSA_WITH_NULL_SHA",
+                    "TLS_ECDH_anon_WITH_NULL_SHA",
+                    "SSL_RSA_WITH_NULL_MD5",
+                    // Definition of the cipher suites that are not supported but the names
+                    // are known.
+                    "TLS_AES_128_CCM_SHA256",
+                    "TLS_AES_128_CCM_8_SHA256"
+            );
 
     private final static String[] protocols = {
-        "", "SSL", "TLS", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"
+        "", "SSL", "TLS", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"
     };
 
-
     public static void main(String[] args) throws Exception {
         // show all of the supported cipher suites
         showSuites(supportedCipherSuites.toArray(new String[0]),
-                                "All supported cipher suites");
+                "All supported cipher suites");
 
         for (String protocol : protocols) {
             System.out.println("//");
-            System.out.println("// " +
-                        "Testing for SSLContext of " + protocol);
+            System.out.println("// "
+                    + "Testing for SSLContext of " + protocol);
             System.out.println("//");
             checkForProtocols(protocol);
         }
@@ -189,7 +225,6 @@ public class CipherSuitesInOrder {
         checkSuites(parameters.getCipherSuites(),
                 "Supported cipher suites in SSLContext");
 
-
         //
         // Check the cipher suites order of SSLEngine
         //
@@ -209,34 +244,34 @@ public class CipherSuitesInOrder {
         // Check the cipher suites order of SSLSocket
         //
         SSLSocketFactory factory = context.getSocketFactory();
-        try (SSLSocket socket = (SSLSocket)factory.createSocket()) {
+        try (SSLSocket socket = (SSLSocket) factory.createSocket()) {
 
             // check the order of endabled cipher suites
             ciphers = socket.getEnabledCipherSuites();
             checkSuites(ciphers,
-                "Enabled cipher suites in SSLSocket");
+                    "Enabled cipher suites in SSLSocket");
 
             // check the order of supported cipher suites
             ciphers = socket.getSupportedCipherSuites();
             checkSuites(ciphers,
-                "Supported cipher suites in SSLSocket");
+                    "Supported cipher suites in SSLSocket");
         }
 
         //
         // Check the cipher suites order of SSLServerSocket
         //
         SSLServerSocketFactory serverFactory = context.getServerSocketFactory();
-        try (SSLServerSocket serverSocket =
-                (SSLServerSocket)serverFactory.createServerSocket()) {
+        try (SSLServerSocket serverSocket
+                = (SSLServerSocket) serverFactory.createServerSocket()) {
             // check the order of endabled cipher suites
             ciphers = serverSocket.getEnabledCipherSuites();
             checkSuites(ciphers,
-                "Enabled cipher suites in SSLServerSocket");
+                    "Enabled cipher suites in SSLServerSocket");
 
             // check the order of supported cipher suites
             ciphers = serverSocket.getSupportedCipherSuites();
             checkSuites(ciphers,
-                "Supported cipher suites in SSLServerSocket");
+                    "Supported cipher suites in SSLServerSocket");
         }
     }
 
@@ -250,7 +285,6 @@ public class CipherSuitesInOrder {
             if (index <= loc) {
                 throw new RuntimeException(suite + " is not in order");
             }
-
             loc = index;
         }
     }
diff --git a/test/jdk/javax/net/ssl/sanity/ciphersuites/SystemPropCipherSuitesOrder.java b/test/jdk/javax/net/ssl/sanity/ciphersuites/SystemPropCipherSuitesOrder.java
new file mode 100644
index 00000000000..bf808baf962
--- /dev/null
+++ b/test/jdk/javax/net/ssl/sanity/ciphersuites/SystemPropCipherSuitesOrder.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.util.Arrays;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSocket;
+
+/*
+ * @test
+ * @bug 8234728
+ * @library /javax/net/ssl/templates
+ *          /javax/net/ssl/TLSCommon
+ * @summary Test TLS ciphersuites order set through System properties
+ * @ignore Not applicable until the cipher order of system property maintained.
+ * @run main/othervm
+ *      -Djdk.tls.client.cipherSuites=TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384
+ *      -Djdk.tls.server.cipherSuites=TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_GCM_SHA256
+ *      SystemPropCipherSuitesOrder TLSv1.3
+ * @run main/othervm
+ *      -Djdk.tls.client.cipherSuites=TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384
+ *      SystemPropCipherSuitesOrder TLSv1.3
+ * @run main/othervm
+ *      -Djdk.tls.server.cipherSuites=TLS_AES_128_GCM_SHA256,TLS_CHACHA20_POLY1305_SHA256,TLS_AES_256_GCM_SHA384
+ *      SystemPropCipherSuitesOrder TLSv1.3
+ * @run main/othervm
+ *      -Djdk.tls.client.cipherSuites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+ *      -Djdk.tls.server.cipherSuites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+ *      SystemPropCipherSuitesOrder TLSv1.2
+ * @run main/othervm
+ *      -Djdk.tls.client.cipherSuites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+ *      SystemPropCipherSuitesOrder TLSv1.2
+ * @run main/othervm
+ *      -Djdk.tls.server.cipherSuites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+ *      SystemPropCipherSuitesOrder TLSv1.2
+ * @run main/othervm
+ *      -Djdk.tls.client.cipherSuites=TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA
+ *      -Djdk.tls.server.cipherSuites=TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA
+ *      SystemPropCipherSuitesOrder TLSv1.1
+ * @run main/othervm
+ *      -Djdk.tls.client.cipherSuites=TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA
+ *      SystemPropCipherSuitesOrder TLSv1.1
+ * @run main/othervm
+ *      -Djdk.tls.server.cipherSuites=TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA
+ *      SystemPropCipherSuitesOrder TLSv1.1
+ * @run main/othervm
+ *      -Djdk.tls.client.cipherSuites=TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA
+ *      -Djdk.tls.server.cipherSuites=TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA
+ *      SystemPropCipherSuitesOrder TLSv1
+ * @run main/othervm
+ *      -Djdk.tls.client.cipherSuites=TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA
+ *      SystemPropCipherSuitesOrder TLSv1
+ * @run main/othervm
+ *      -Djdk.tls.server.cipherSuites=TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA
+ *      SystemPropCipherSuitesOrder TLSv1
+ */
+public class SystemPropCipherSuitesOrder extends SSLSocketTemplate {
+
+    private final String protocol;
+    private static String[] servercipherSuites;
+    private static String[] clientcipherSuites;
+
+    public static void main(String[] args) {
+        servercipherSuites
+                = toArray(System.getProperty("jdk.tls.server.cipherSuites"));
+        clientcipherSuites
+                = toArray(System.getProperty("jdk.tls.client.cipherSuites"));
+        System.out.printf("SYSTEM PROPERTIES: ServerProp:%s - ClientProp:%s%n",
+                Arrays.deepToString(servercipherSuites),
+                Arrays.deepToString(clientcipherSuites));
+
+        try {
+            new SystemPropCipherSuitesOrder(args[0]).run();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private SystemPropCipherSuitesOrder(String protocol) {
+        this.protocol = protocol;
+    }
+
+    // Servers are configured before clients, increment test case after.
+    @Override
+    protected void configureClientSocket(SSLSocket socket) {
+        socket.setEnabledProtocols(new String[]{protocol});
+    }
+
+    @Override
+    protected void configureServerSocket(SSLServerSocket serverSocket) {
+        serverSocket.setEnabledProtocols(new String[]{protocol});
+    }
+
+    protected void runServerApplication(SSLSocket socket) throws Exception {
+        if (servercipherSuites != null) {
+            System.out.printf("SERVER: SystemProperty:%s - "
+                    + "getEnabledCipherSuites:%s%n",
+                    Arrays.deepToString(servercipherSuites),
+                    Arrays.deepToString(socket.getEnabledCipherSuites()));
+        }
+        if (servercipherSuites != null && !Arrays.equals(
+                servercipherSuites, socket.getEnabledCipherSuites())) {
+            throw new RuntimeException("Unmatched server side CipherSuite order");
+        }
+        super.runServerApplication(socket);
+    }
+
+    protected void runClientApplication(SSLSocket socket) throws Exception {
+        if (clientcipherSuites != null) {
+            System.out.printf("CLIENT: SystemProperty:%s - "
+                    + "getEnabledCipherSuites:%s%n",
+                    Arrays.deepToString(clientcipherSuites),
+                    Arrays.deepToString(socket.getEnabledCipherSuites()));
+        }
+        if (clientcipherSuites != null && !Arrays.equals(clientcipherSuites,
+                socket.getEnabledCipherSuites())) {
+            throw new RuntimeException("Unmatched client side CipherSuite order");
+        }
+        super.runClientApplication(socket);
+    }
+
+    private static String[] toArray(String prop) {
+        return (prop != null) ? prop.split(",") : null;
+    }
+}
diff --git a/test/jdk/javax/net/ssl/sanity/ciphersuites/TLSCipherSuitesOrder.java b/test/jdk/javax/net/ssl/sanity/ciphersuites/TLSCipherSuitesOrder.java
new file mode 100644
index 00000000000..23234d3fa10
--- /dev/null
+++ b/test/jdk/javax/net/ssl/sanity/ciphersuites/TLSCipherSuitesOrder.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.util.Arrays;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSocket;
+
+/*
+ * @test
+ * @bug 8234728
+ * @library /javax/net/ssl/templates
+ *          /javax/net/ssl/TLSCommon
+ * @summary Test TLS ciphersuites order.
+ *      Parameter order: <protocol> <client cipher order> <server cipher order>
+ * @run main/othervm TLSCipherSuitesOrder TLSv13 ORDERED default
+ * @run main/othervm TLSCipherSuitesOrder TLSv13 UNORDERED default
+ * @run main/othervm TLSCipherSuitesOrder TLSv13 UNORDERED UNORDERED
+ * @run main/othervm TLSCipherSuitesOrder TLSv13 ORDERED ORDERED
+ * @run main/othervm TLSCipherSuitesOrder TLSv12 ORDERED default
+ * @run main/othervm TLSCipherSuitesOrder TLSv12 UNORDERED default
+ * @run main/othervm TLSCipherSuitesOrder TLSv12 UNORDERED UNORDERED
+ * @run main/othervm TLSCipherSuitesOrder TLSv12 ORDERED ORDERED
+ * @run main/othervm TLSCipherSuitesOrder TLSv11 ORDERED default
+ * @run main/othervm TLSCipherSuitesOrder TLSv11 UNORDERED default
+ * @run main/othervm TLSCipherSuitesOrder TLSv11 UNORDERED UNORDERED
+ * @run main/othervm TLSCipherSuitesOrder TLSv11 ORDERED ORDERED
+ * @run main/othervm TLSCipherSuitesOrder TLSv1 ORDERED default
+ * @run main/othervm TLSCipherSuitesOrder TLSv1 UNORDERED default
+ * @run main/othervm TLSCipherSuitesOrder TLSv1 UNORDERED UNORDERED
+ * @run main/othervm TLSCipherSuitesOrder TLSv1 ORDERED ORDERED
+ */
+public class TLSCipherSuitesOrder extends SSLSocketTemplate {
+
+    private final String protocol;
+    private final String[] servercipherSuites;
+    private final String[] clientcipherSuites;
+
+    public static void main(String[] args) {
+        PROTOCOL protocol = PROTOCOL.valueOf(args[0]);
+        try {
+            new TLSCipherSuitesOrder(protocol.getProtocol(),
+                    protocol.getCipherSuite(args[1]),
+                    protocol.getCipherSuite(args[2])).run();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private TLSCipherSuitesOrder(String protocol, String[] clientcipherSuites,
+            String[] servercipherSuites) {
+        this.protocol = protocol;
+        this.clientcipherSuites = clientcipherSuites;
+        this.servercipherSuites = servercipherSuites;
+    }
+
+    // Servers are configured before clients, increment test case after.
+    @Override
+    protected void configureClientSocket(SSLSocket socket) {
+        socket.setEnabledProtocols(new String[]{protocol});
+        if (clientcipherSuites != null) {
+            socket.setEnabledCipherSuites(clientcipherSuites);
+        }
+    }
+
+    @Override
+    protected void configureServerSocket(SSLServerSocket serverSocket) {
+        serverSocket.setEnabledProtocols(new String[]{protocol});
+        if (servercipherSuites != null) {
+            serverSocket.setEnabledCipherSuites(servercipherSuites);
+        }
+    }
+
+    protected void runServerApplication(SSLSocket socket) throws Exception {
+        if (servercipherSuites != null) {
+            System.out.printf("SERVER: setEnabledCipherSuites:%s - "
+                    + "getEnabledCipherSuites:%s%n",
+                    Arrays.deepToString(servercipherSuites),
+                    Arrays.deepToString(socket.getEnabledCipherSuites()));
+        }
+        if (servercipherSuites != null && !Arrays.equals(servercipherSuites,
+                socket.getEnabledCipherSuites())) {
+            throw new RuntimeException("Unmatched server side CipherSuite order");
+        }
+        super.runServerApplication(socket);
+    }
+
+    protected void runClientApplication(SSLSocket socket) throws Exception {
+        if (clientcipherSuites != null) {
+            System.out.printf("CLIENT: setEnabledCipherSuites:%s - "
+                    + "getEnabledCipherSuites:%s%n",
+                    Arrays.deepToString(clientcipherSuites),
+                    Arrays.deepToString(socket.getEnabledCipherSuites()));
+        }
+        if (clientcipherSuites != null && !Arrays.equals(
+                clientcipherSuites, socket.getEnabledCipherSuites())) {
+            throw new RuntimeException("Unmatched client side CipherSuite order");
+        }
+        super.runClientApplication(socket);
+    }
+
+    enum PROTOCOL {
+        TLSv13("TLSv1.3",
+                new String[]{
+                    "TLS_AES_256_GCM_SHA384",
+                    "TLS_AES_128_GCM_SHA256",
+                    "TLS_CHACHA20_POLY1305_SHA256"},
+                new String[]{"TLS_CHACHA20_POLY1305_SHA256",
+                    "TLS_AES_128_GCM_SHA256",
+                    "TLS_AES_256_GCM_SHA384"}),
+        TLSv12("TLSv1.2",
+                new String[]{
+                    "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+                    "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"},
+                new String[]{
+                    "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+                    "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"}),
+        TLSv11("TLSv1.1",
+                new String[]{
+                    "TLS_RSA_WITH_AES_256_CBC_SHA",
+                    "TLS_RSA_WITH_AES_128_CBC_SHA"},
+                new String[]{
+                    "TLS_RSA_WITH_AES_128_CBC_SHA",
+                    "TLS_RSA_WITH_AES_256_CBC_SHA"}),
+        TLSv1("TLSv1",
+                new String[]{
+                    "TLS_RSA_WITH_AES_256_CBC_SHA",
+                    "TLS_RSA_WITH_AES_128_CBC_SHA"},
+                new String[]{
+                    "TLS_RSA_WITH_AES_128_CBC_SHA",
+                    "TLS_RSA_WITH_AES_256_CBC_SHA"});
+
+        String protocol;
+        String[] orderedCiphers;
+        String[] unOrderedCiphers;
+
+        private PROTOCOL(String protocol, String[] orderedCiphers,
+                String[] unOrderedCiphers) {
+            this.protocol = protocol;
+            this.orderedCiphers = orderedCiphers;
+            this.unOrderedCiphers = unOrderedCiphers;
+        }
+
+        public String getProtocol() {
+            return protocol;
+        }
+
+        public String[] getOrderedCiphers() {
+            return orderedCiphers;
+        }
+
+        public String[] getUnOrderedCiphers() {
+            return unOrderedCiphers;
+        }
+
+        public String[] getCipherSuite(String order) {
+            switch (order) {
+                case "ORDERED":
+                    return getOrderedCiphers();
+                case "UNORDERED":
+                    return getUnOrderedCiphers();
+                default:
+                    return null;
+            }
+        }
+    }
+}
diff --git a/test/jdk/sun/security/ssl/HandshakeHash/HandshakeHashCloneExhaustion.java b/test/jdk/sun/security/ssl/HandshakeHash/HandshakeHashCloneExhaustion.java
index 73e7c2a51c6..c565069babe 100644
--- a/test/jdk/sun/security/ssl/HandshakeHash/HandshakeHashCloneExhaustion.java
+++ b/test/jdk/sun/security/ssl/HandshakeHash/HandshakeHashCloneExhaustion.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, 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
@@ -28,13 +28,15 @@
 
 /*
  * @test
- * @bug 8148421 8193683
+ * @bug 8148421 8193683 8234728
  * @summary Transport Layer Security (TLS) Session Hash and Extended
  *     Master Secret Extension
  * @summary Increase the number of clones in the CloneableDigest
  * @library /javax/net/ssl/templates
  * @compile DigestBase.java
  * @run main/othervm HandshakeHashCloneExhaustion
+ *     TLSv1.3 TLS_AES_128_GCM_SHA256
+ * @run main/othervm HandshakeHashCloneExhaustion
  *     TLSv1.2 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  * @run main/othervm HandshakeHashCloneExhaustion
  *     TLSv1.1 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
diff --git a/test/jdk/sun/security/util/HostnameMatcher/NullHostnameCheck.java b/test/jdk/sun/security/util/HostnameMatcher/NullHostnameCheck.java
index 7be135900a1..2185b859dec 100644
--- a/test/jdk/sun/security/util/HostnameMatcher/NullHostnameCheck.java
+++ b/test/jdk/sun/security/util/HostnameMatcher/NullHostnameCheck.java
@@ -39,27 +39,31 @@ import jdk.test.lib.security.SSLContextBuilder;
 
 /*
  * @test
- * @bug 8211339
+ * @bug 8211339 8234728
  * @summary Verify hostname returns an exception instead of null pointer when
  * creating a new engine
  * @library /test/lib
- * @run main NullHostnameCheck
+ * @run main NullHostnameCheck TLSv1
+ * @run main NullHostnameCheck TLSv1.1
+ * @run main NullHostnameCheck TLSv1.2
+ * @run main NullHostnameCheck TLSv1.3
  */
 
 public final class NullHostnameCheck {
 
     public static void main(String[] args) throws Exception {
+        String protocol = args[0];
         String password = "123456";
         SSLContext serverCtx = SSLContextBuilder.builder()
                 .keyStore(KeyStoreUtils.loadKeyStoreBase64(
                         keystoreB64, password))
                 .kmfPassphrase(password)
-                .protocol("TLSv1.2")
+                .protocol(protocol)
                 .build();
         SSLEngine serverEngine = serverCtx.createSSLEngine("localhost", -1);
         serverEngine.setUseClientMode(false);
 
-        SSLContext clientCtx = SSLContext.getInstance("TLSv1.2");
+        SSLContext clientCtx = SSLContext.getInstance(protocol);
         clientCtx.init(null, new TrustManager[] {
                 new X509TrustManager() {
                     @Override
@@ -186,94 +190,102 @@ public final class NullHostnameCheck {
         }
     }
 
-// Base64 of PKCS12 Keystore
-static final String keystoreB64 =
-        "MIIQ6wIBAzCCEKQGCSqGSIb3DQEHAaCCEJUEghCRMIIQjTCCBgEGCSqGSIb3DQEHAa" +
-        "CCBfIEggXuMIIF6jCCAuwGCyqGSIb3DQEMCgECoIICmzCCApcwKQYKKoZIhvcNAQwB" +
-        "AzAbBBS7qnTOxJYV5At3migAiNAdPvKd7AIDAMNQBIICaMo0roH1TuZE1ARZtwCOXy" +
-        "F2sk4DmI6m1/CRdh6NeQzszJZH2701cEm0CES971IwobCNFo0+Er9tk1c+iXmMPJgM" +
-        "s1l/+7OpQCc/GRl2Nc7lQSj1Yvrq1CIQxC51hSrwNs0N9aCTavjKfJ7jk3k1+MNItU" +
-        "dMdwuIFK663NEH8Wm0D4njvIA9p3ehOLJWDi0ziFTcySyCbbWAL6HmJhzRlpakPpbp" +
-        "Ox68wfI2YgDpQwTq580TMEWz+9P1U07VmtfYlu9xjXQT/Ks1xzNrhbOyv+HLoE54qL" +
-        "RyhL36/fwCzlpCXCYokPUG2uziu8JiQyITYRpVhVcgR5m/rSMhVsj8HwUmIdlK2Irm" +
-        "kOqG2m6YPKRiq7eeCPskcf2Hh0H3pb6lxagSVQMb+qndIUhCvZoXL/oS2+1ngtMlXh" +
-        "ezjIEa5s2K+Kk8eV48Ydms5bW8Plqy20+0fgEClABF6QL4We4NaFJdl6DB0+KsxgUd" +
-        "ZHo4U7f3R6o971mAd/OACs4jzpA0/C3AKCbhBEh/nxnSPoxM0Ty3bLaK8LQnv+B2uo" +
-        "6TeypsxmGg4/kd6fymzrhWUJAFz7DjkO/32pDUXnUDa6CB+dZdUldPoOpviGl9ITfG" +
-        "apdnq8+B4y7lg/87OZbr99vyVBWtbATaNof3Y5PuNY5TTQ5y1u4gU+zO9qhRnjxSqb" +
-        "bXJYhKeOIJmXCgGerV1dFqcWfj163OtjTwwJ5VCrtgolTU+3eodARD86jkp1VRCtQ2" +
-        "M54zOND9mx9RM2ucOy41mgF2MyKIseN6+3665DtgDbN5H/pmmjR4/GSuuy4eJoGHvY" +
-        "OPy49P7o8xPjAZBgkqhkiG9w0BCRQxDB4KAG0AeQBrAGUAeTAhBgkqhkiG9w0BCRUx" +
-        "FAQSVGltZSAxNTQxMTg5MzQ5NTAxMIIC9gYLKoZIhvcNAQwKAQKgggKbMIIClzApBg" +
-        "oqhkiG9w0BDAEDMBsEFO1oLv/9BmQKRKpeUB/Q5FPzMZaPAgMAw1AEggJoxez71rvm" +
-        "pCMbF0MH3shCpy2LsHNnkyjQVTKBIqdHFmn1390gqRkUUlvaaLgpjNNFSVY/LMg+gK" +
-        "JEJW6kClerkFg1/fvMQDBr5ApGbACIWi7fN/qYjED0cY5eypnSKePUzR2uO254Qko4" +
-        "xc+Enx3+V0/O0eqwlzGq3Pmgq9vfyqPefG562tFQEmHyUMUTLg1m4rtUgG5bvtRIMl" +
-        "Vd6tgFA3JRb08USaJY3D+FQFb+zm/iIJ1KrHBgtBuJFLfaXqYo/fjjgIv0WiOIQmd1" +
-        "ygrfRp7AhCvqZu7IzKT3TWggfGHABfjgkRcVmCGsFCf1cXAJVzS1v4N2biY9tB9Q5Y" +
-        "iWZ0JglMHK+NfJu2+3UthyC3ugDeLTQTSbwfJv3ShcVFo7mVxJz2zPWJtDoXbORczm" +
-        "0tjMu8KztEpPhwH4nsoXJ60fMUDOAvYwr2t49CBRZ+b9rJB5QWWJ60ZrM5rsfNU5yJ" +
-        "RJYldqryD/T5UJEqRLK5X9N/DAszDFTDoTVFMwwuBv6yk/v9N999m4X77q75/d1y71" +
-        "sY9Aaj9gHKLSy1ZCsGoU2nt7A+Z+V9TNcmsM5aT+QpNdKvW99jI1T2XI7kHNJ+D0W3" +
-        "sD8dXlNA91na7/6HGM5dKQfZdk1zcUYg2lkDpyi3xzO2nzFvCaDfAqQqjuQtiXggWy" +
-        "RiNk+WC45GuUKP5F6fWWr871RjeVYezj5XoXWJ7x8J85SUMKiuQH3S2tRMcP2RtAS/" +
-        "D1aXdwuiVfLUMu9113dwpSwwmXcFASrt9VxXPNI8Aztu/YtqkONyQq50NChtYsykGA" +
-        "4ZUOuazkc1SLmIitNfBB9DFIMCMGCSqGSIb3DQEJFDEWHhQAcwBlAGwAZgBzAGkAZw" +
-        "BuAGUAZDAhBgkqhkiG9w0BCRUxFAQSVGltZSAxNTQxMTg5MzUzNjg4MIIKhAYJKoZI" +
-        "hvcNAQcGoIIKdTCCCnECAQAwggpqBgkqhkiG9w0BBwEwKQYKKoZIhvcNAQwBBjAbBB" +
-        "S3KnmddxJSpicU3Pxyg8+NUl6deAIDAMNQgIIKMA0HSR92DBEs74SvbSTUrLeitduz" +
-        "wzkxQ2D8jO+eP7dC7L9nVVvfHDcalUfwah7fvriDgPKg/ws7vaPO6c4Q7RdzB3epvK" +
-        "7LqJlqseW0NxRGJXF9hvDOWk6me+3NyAy791C0R8oF/llujojwoR2Tw6DzTdov9c0p" +
-        "pwCACNtgeAtz3SEFlc/F4MwZKai0jdpakINJkD5H7Za8nyKu6pIITs1roy3Oq2HA4M" +
-        "XAnlnWh+8R9mloDBTJJMJYUOsn1VaFrYNFq3kr4oOMNINJvUCZL2LZgl5rmzgWSVs0" +
-        "VSZa7JUWx49rsrBeCi/SFwW5ryleK5uEtjXjtqjQxCjvLvRYV5HmPfv/ZGCP/vitHX" +
-        "dQ9gzxO/7RVQoxgE0dSx90jiGOEsmG8N9sDnNyS+GCc7pxJeW6NKc1h5YameCsqUGz" +
-        "V9FTfz2JdDpaPsGmHtvMTs8n3ncK9FOWeWhoNKhPnoMGHmfJGZgz282aTosggSZgh7" +
-        "FSvf3KfAmhcCj9+frE90jPvB4W8tPF0YnOrNgvByw2+bj7NCkZ0WBT2WrOSOoS/o2H" +
-        "zmErCJmyt6Su5sPEeTz+dnU0std6qCjsHtjo8Is8VnVVec2nbpeT+nd3RTCV71dViW" +
-        "42L3rRYxl80UpsUs3Fh0J+01EZkWmExCSZpYTKgPhYcYSwUrIVx9ukcCdUSpvS07bq" +
-        "hLfqWOVLfLs00VBr/mFWOqDBfy+qJMXEFYyYDBa/TlrIjzEbF4qKwIJiIxRcqYy0Ta" +
-        "CnMVvn8HlMeIMPJQaqdfDspxIdSdJWWZVbk9FnEDcMuSg8saON26HwieH+AsdnsZDR" +
-        "cZ6kT+bMPibCfnKLTmJYM0dq7abhdYj7GYcfRjwCeeK/PSxklqpsJ/1T/FeVweuQXz" +
-        "bhHatL5z8UmTV3WUE1Ww23K3sR701xh/Tx3HoZPjluSHZFuQCvhkOU6Fj5o7dYjJZc" +
-        "3l3n8wD3SY04ObfCedHe56NytvbXGp79en8Q6kluThWvS5tuNgR5UhMf5oeVi8H1++" +
-        "MeuCOz9MJMwBGe0JUkxijdI1YVHvspqXcQhjAL9BBPT/Q+iaQITzqPSVj/fSUbY147" +
-        "XrAGKS8/9iOV5gTVw2TiW1MKp3ubLjqc1YmIB3TRz+SIlAXg3tD4hl/8DXs0zDFLN0" +
-        "OJLslwQJNaiV0S0mndsVQ/qXiS0gfZldQcn1NmUCJNiy04aUNWR/wKgyLAk5DNPCjx" +
-        "RlStSK7RjrgIcyUO+4cf/nfV2ymaaeDtBSwLLhAr2syXlio1fQILIrSlmT2X7i4/7X" +
-        "1vzN0h78g3+NcWpCs+WnOZ1bu/nzVY7zL8rmHJCeOD37UMgxgW5s3sBvONCpUzyOoe" +
-        "raTalqk843CE223ovLgh+KRm/JXUlDMtDSpk+02Ve7ZoyqgI8vr6UBwWk6CjUJx21M" +
-        "ldkh6QZcK+weQg0Ml9t3czrKXlfQl62VIG6aqSRehSEa52k5IWrcVY6yauRfERfi6a" +
-        "zGSmn5kXlQZSJ1mDuss22Fp12n5Kn0MAwo7XHmnzasaD3rB57A+s/3zkgC0j2t/qYC" +
-        "VpcTq/7Hh7CirbUzVBaXn9CI5MYcbtL40KEE7/DKsjR0VTUtLRi9PnEX1D4zxWl45Y" +
-        "WJ0QO4icHmUS+bvz3i/N91kI+XKDjZmktsqpF+JRaooQe2wZsasnsCSm6tEx8rN/Ya" +
-        "iE3nEUTxeUdHudzT4mldgYL9jlOoubC+DvXilRPRboNRuF9djrfq1p+j4egC4FcjeR" +
-        "kISHIuVXVwcg6Iz9q5j3IAGBfRhXuZ70qyLMtuts4RE+Xy4SmOPnw2rObNhMcTBs9T" +
-        "wYIhrzv426xid908L4v3bUunlsCoDP6LzzMdE4g1OhKzralRqoYZcsLN6Jt5f/W8UY" +
-        "RFauTV8YFV3dBUpp9xhKJlYH+OtJY1gLrT2aaX8b96ruv1JTq1fKCReiB2/0MCPvHd" +
-        "Yz8+/P7YQTysaoDlTC7prQFvDEcz11D0+SmVi2yxNQZETMaMcX5QdqfO8omTPMtuE5" +
-        "jKgtBtmjq6GeNNJBSKySWtjp0J7jKMqmk2n9+9/RCv3e4IVEcZDOo71g5omtB5592w" +
-        "XEQqydg1yH5HFD/B7bgcuFAbr36UMdp6o4M8vek9HsI9K/+Q+2clecOabzNDsS4S8y" +
-        "vr0Kna4rluHwGT0QUp0SbRQRIKzSm7xye5CTxUrZ8cizQ5hQFBUFMr8OWRm0N1GalY" +
-        "TfPaGwX0sWdvhX4rrrGXpToRbUUqeSk1suiRMT8s1iluaoCpiN1Kq4cehFdlSpWv9c" +
-        "74Dktfk+kS8X+vCdoU3voPHiGQbxql0mcdSIboOKdCdzs5krl7GbnJZoYLIYpK/y87" +
-        "YUbOb1CiivlTNe4+KiamuEg44Y0zZ/Z+yWLb7QkpjoIiDObU/0oJKqHUeYL4ZjReus" +
-        "U014itt5jBMmVCBlhUWtHTmznJotjl45H6bVAX7cimbdoWDcmzWlgHM5lFP6IH/q+Q" +
-        "Gsgw+kRfbzX0dnYF0a6d5j02ZgSjJJZpQ5Df+qB9ZKteywXxApcv3FRVuz7A5v7yXR" +
-        "xUE8TQnLwOZgvwDu/pL90drEf0KXef8G/CEHQPB4HVCDzaUnhfSIUflsjtaFfuFq1U" +
-        "DHmmt5WrrTkWo5RRMUzWYcYn2QzBvzCRDTWdVTlXAJcYJ+KHeJlyxhlrEDu3ej4WUe" +
-        "BmkbiTQStUEUpk3IcTbzVLLtfS/pe3m0EmaU6nRkmfLxMfYtnDUgdghMy0Cltc3TKn" +
-        "9qFrBtY41qf8D5LGSrrmLVC1tnQv+hJC7hwiIQZ/2a5b5Bv67tcdzlEGRNT7uv0ID0" +
-        "Ig5MyPjvJtppNQfxhPbNbJvxWtmI1NvH4359d0vR/4yzxYq+BpCLpOXw3BreGE55J7" +
-        "xIvxeRb+Pws7A0xdbKHAwSUsEyPglxAkZCzftZin+MoEw8UnhXYWOPKf+k49TVAq7S" +
-        "Yi1mJxxzwkSkSw9AdhbalYi1Y17VVfHHcb9Ioh1Jdtq8iNqtO2GG+Gd4yGKaRjnQ03" +
-        "6YRWyffrMx6Lv/aEecMR1DASDuX0vVjfafKHAp+13VKVGsB6zPbzR4njAXhJxTC9qj" +
-        "RbG2ISl4xrgAy/gBCKqN+UaVGVYe5DdA22XOOfNkgRrfoqcdgajzp4v6hqr3kPh997" +
-        "89Ayxcov6OopEUBuy6wuPO2ezXRMw8snABq6YDlf36l2jugHbqUUOiiQ4jIPgZAp/S" +
-        "r+4i6wyH+wOIjn1pBn9GgqypWCjyj/uTIMiXiMe5TDzp7U9pJ7e/hWUGzm6wWuDQWB" +
-        "zLwAJNRtaaGV0UraI4ubOJVsvGym0PJ8elxCUgKo6cePkhwrVPcNKA19HgVj/3g0pa" +
-        "ZwYt5Yw2Gdydm0zadva7K/oVgVKRDmkQbwlavySW0xqU8Pul/V/HUSd32/4cpOmmol" +
-        "OjMo1vyn/iSMylG0s2SzTjZ4LlcwhaxjoIVpXo6MwPMh/vdlgQyZ/bjO9PMr9TYW6J" +
-        "aF2PnIKsRkzYfcn6xcQwPjAhMAkGBSsOAwIaBQAEFLddLgmJBuufBBi+JoHCaLDeTK" +
-        "RvBBTQP0GN26PaNdjOaE/AzK7bbhZGNAIDAYag";
+    // Base64 of PKCS12 Keystore
+    /*
+     * Certificate
+     * "signature algorithm": "SHA384withRSA",
+     * "issuer"             : "CN=test, OU=test, O=test, L=test, ST=test, C=test",
+     * "not before"         : "2019-12-05 12:43:23.000 IST",
+     * "not  after"         : "2049-11-27 12:43:23.000 IST",
+     * "subject"            : "CN=test, OU=test, O=test, L=test, ST=test, C=test",
+     * "subject public key" : "RSA",
+     */
+    static final String keystoreB64 =
+        "MIIQZwIBAzCCECAGCSqGSIb3DQEHAaCCEBEEghANMIIQCTCCCeUGCSqGSIb3DQEHA"
+        + "aCCCdYEggnSMIIJzjCCCcoGCyqGSIb3DQEMCgECoIIJezCCCXcwKQYKKoZIhvcNAQ"
+        + "wBAzAbBBSaZBiYmowTxFT4KJxZhMHTVOC9OQIDAMNQBIIJSBnoVGtJKPsoiSU095y"
+        + "50x27NJQd727oJwMXqA8kdxCcE1tBowtO8P44ctSEvwJQlB7dR9PxHB6LcfCdMfpa"
+        + "GObVCH1/6jHzhRolI9JMAfXlvliAHKZSjuQd2USw1Y65/+0VYvKslXGU4hWhGQWh2"
+        + "ksUCBIIcC2A3sA3afF/JPrlfLCEbzYpcfAsv+Z7wEEr6YD11HIHfbOgu2/HU6phL2"
+        + "RMJDK9iLgP9mu6FzRFk+93BSguWXfbeJyPlzA8dcTzkXDyfVDx4Wd+UExWq0fx179"
+        + "b74MWkwEk76TowEkcGkrnugwOKnqBmyvmBkbl1827+ChZprZ3zGw69IkuRsdDSYGb"
+        + "IWVAB/psB0zX3TvsKHcraZm34oNJdSNpYrS0OWA8lSm5NdcfTzi6WLxWwxz55PvZg"
+        + "OP3pVyXmtAalyBujs6AOsLkJIMLGvWAYeD+72ook8fqpW7s5e/HA7MshXrlMMflpD"
+        + "m708kK5VnfdgzQsAGr6YfOYOKnyhoqskmzDYccuSz59owKiuGMgHpum0zVE8yyVwb"
+        + "esXfP3v7eiPuGvsxzq5DE6jaY4F+GoxdLbL4jDWocnWiZewnuYxQwd1vKIKTww/TG"
+        + "8RObPUEB38+/LNpgb7+5Oap45rujygiPFWD9+mTzKkLGkM6ItRo4qOwtKAqbjPIVk"
+        + "MDCovcr2TCrZfE8ZbQnU/q2LR5eC6ZpOMFNRZggm92n0+FmDuEKjR7lu2mQF4IDan"
+        + "SiYgS1+nBhfG9pcNP3yCpwoBHIImtZX5GObKqgvMqQ746KXhv40xwnNqXGypBNKYN"
+        + "jRJQmG2/m++2A6DUo+xCTNbD7g0pQbNOjKsGVMXUBTyDiyGqSUHH2EDxe37wcPVih"
+        + "ezcv5L1X48y3tSVD9czhjCDJ54sd0B3+LoEXs5/0xYmMvQ74zUx6iwE87FZ/duMbs"
+        + "N3dDWvIgqgjaoGnfRLy4lRRxYhn2/r1lesQtzNlZ3YkHZKmpgQkLm+yChFqxi7qm+"
+        + "ec/y+GSTm+ascK1ju1NG3f/SUdl7KqZ/J7DnDfQwyg7jiY+QOcr7UNRSeddQozxu7"
+        + "j07y/wiGX4z3+JSGBlnlWtOyLo5YERbheVHh1LfCSM4KQDcjxUnIlmsCqILwDYbVm"
+        + "aNJ3crkU22I5IVFcoF30v7gvMj4VFXcBYPCSJrkqNIIgZs6YPYwht3akquIz2ovXV"
+        + "CqD3TH527dBRAgpeZNs3/L8xCaYiHNUKXv9CRaHVQMTKk9zi3CTJoKo5TCsWR8l9h"
+        + "cJpcQnmNs5Jv9Jnq/zoet230r3iHkiGNAoXTlekqSER7vBVLHwPY7rogXP6WyAi67"
+        + "AYK/B5iVQcplEHs3n+MeZJgj9C7S0Zslxmym0mWw7l+4YjvyX+RGJVUvk+3TkWO8E"
+        + "WHKOX1+hQH9RBbcNqH4FeRZrh3P8wZQDMFfcr3vD0tLAnuqdMy+qAPA+kKWpu5K0D"
+        + "0W/ifEizq4Zf8VyzYU6UZaAQbloJadSkruXIwvUpHBZ+M8MHQ2AmRNd0vwyTBlhOI"
+        + "CzWU5E5OXtW/f5jA/ugl7PSqjwe5IYTsZaYstKqqZJMIPTzB/IxPtzVyoN15fG9GR"
+        + "kk43U6HPS9SdeVTGVmNLn6SM8keLo1yUh5BZ0J0b+K/7C1GfJeNxcv0lGpkrh5wWc"
+        + "ABzJ86+3daky6+aR6ldY2CF7mr/dcc3MnjgDNnx86wYIysC3HOkhgyIXD28+O1aTY"
+        + "oAvlmidNC9wb2/JJk7cHQatL02LG4/ql5GQ+dS1wOU7S1MVVGYDlZ7uiFmKPqC1Tv"
+        + "qVxQnBqPnggKSLWucVKFcjsvXKasMvRl99f4Y7qRAjgM6EHa7rNyWIflRe6ZLNBlj"
+        + "16mW293a4FL1jTosNlZoCN8xb1zDdb/NCISqkX6/sq7wDOn4t+m+78ckof4GNmTOM"
+        + "WSaRDJIuLM9c1stLHpcyif37oZum86FnB9Zw9qlQGdgLYnRPeZXV1rZuC1L9fugCN"
+        + "M4WcUQ20fmPOgyO4RGLsxCbZZJBJj0y7CAMthepMnzaEO9Z2O9BFaM4zpL2ng7GvO"
+        + "a26DQiHO5RFVjUpslUdmPuX7U5xkRfjJ025pqTvHVLfzWmsU53ZbkgiJ/0xxa1Emd"
+        + "5y0X2keTVfm7q5duNVVN1A6r50++RANI7NJaSLFTMm8Y5P79g4o7UmtCLSesUdTsF"
+        + "8swVR5slE3O7ErNr3drLfYVEF9FaB7vcuMDqxCNuahX8TCMJg0vqpO8+EXRNkieb9"
+        + "KSgcLD5WRjzGm7e/B5uACxWc50iY6lYvIVW5Itot95OHWZ5xdq3a3fIIb4MDQ2/nx"
+        + "lozhRHaHTBI9GAwy1/XcDJWMr+tI9rLGCB7hX8dVqNtYO93/oF3gvBiiNSw5qmUQ2"
+        + "qxepZEih5KfhHAVq44RbQMiBA5E2bVBisuNTPUAaA/Fzzsvky8vBq/M5usy8+RXj6"
+        + "m+mSZCUPpSTTunIUnu0bRLb2inccthEielCThk1FLKQCLSpsAo1h7kzuNJIeeJSCM"
+        + "cWXpZEURziXwE5KCl3jcY+dOLLMEI05F/UyRwZ/k1a2qW78Bc3DivIh2w/4ZBAS9q"
+        + "hERIY52y8VcnJ/+/7u45bnpIjkJShZTM1qmzgDCHQa/G5OpnqtI2nDPSNzOpTWA47"
+        + "6+AH0ZQoUKxHt6MJP3QLpnrw6xPSE2gR19KRvFZr0NtGJ+SPy418eFYMtJgPvOyI4"
+        + "XwYYCLrmMCkSGrqfbhwKK6rgYMVDg0fsBT1OAZGKD8QM51hXFt8p0HQS0UuddwCTA"
+        + "/KwyIt6Iw7Leb70yoTEJz3CVU4X4faohXV48gNtZhquawRDvqyBSFS5F8M4s/pJZK"
+        + "C5UY3MXifF1+LhSXjdQK7RwNs9XcCbIy+6Fi2wAKDX9MasXnzfzFVuQq1XtMoPVVS"
+        + "9gSqWXGbYuadDIto3gGIKUt3BT9nj/B0J/ENqlSsGsT0+fiya+p5thXOkI8r7X82P"
+        + "SxV0048QnP7cbuDG97AjOOAcEMsBdCrF3jWGYNd1nK7eKQ8DCrXEKoQhY0IY2sHpU"
+        + "5Cu24KW9M1RwIb/XtOEBun89edaKhfk1uDLlvgQ4huYDmfcu4Ebh6DRbHzwSNMK17"
+        + "qDgp8/mbAui0ATZBW7bTQNw3WMS0ltbdCj0ki28Udg1udYY6r6wwWkXE/mccgbXz0"
+        + "L3g72JfEIO/A56+rFubofZCHuf5AVkDE8MBcGCSqGSIb3DQEJFDEKHggAdABlAHMA"
+        + "dDAhBgkqhkiG9w0BCRUxFAQSVGltZSAxNTc1NTMwMDAzMjk3MIIGHAYJKoZIhvcNA"
+        + "QcGoIIGDTCCBgkCAQAwggYCBgkqhkiG9w0BBwEwKQYKKoZIhvcNAQwBBjAbBBRZLo"
+        + "kYmrJuiANzYxRFL9HmSVKYhQIDAMNQgIIFyPEfYqIJqAd13B5D4EFLs7VrUNaWoeO"
+        + "XNRVl5da6N7gMlG5gVpPRjRUCHyaBB066ZdGEquwkidgCdIAfIolcnyGv7a7PZvZM"
+        + "bJ8AUXjkf9q7zp0Uwc0k4zQ3Nmev5QxSx+f33J+AOQT4T1CRMxwpNOwrtzRoNVZFD"
+        + "oTCnxHBdTvmbCcuMsHYZQk+vLQpud4dI1AKccExjOc86ZAne2Df37LHB/2gxElSOn"
+        + "G9VkdIlKHLPbrk4JNcNSZs3VOOi3tEwAlBx9Xllg95aH3ziBPYKgk/u6M567tEnoH"
+        + "PDiss9+WeNJP9Tgsc6WPu33GTNxtxSLx4mffR3x0upSbFvhIP4t07aCtOZVwD/Hdw"
+        + "VmptatFvVSMiQSM1vf89zjAvdK3UFXTr/jDze4tF35y/UTlor8sbINQy3dZCEpCim"
+        + "G1MfDdSG+K5BZoHTny5bG2YM8a9EHtmZfq4i3GJE85M652UVlVDgDnk+PhgyIFWuJ"
+        + "6KFgWjUWio6RRhRvcTCJbk5soV+IFa4BppNMako9W8B2UvqIIV2XrxvFEh4QFkpsW"
+        + "13qEUGp33qUkAPhuz/NJ4InVh29CGSBnoWprIL/dKwdbTGudlrjnMs6pwURmlWVcJ"
+        + "FuPJFsBpyCQEeAtKS7TXaVJOTkfHdX4tYgN5SxEA0EGoddrKgWu48Dj1u2oC7ruZ9"
+        + "6J0zznFIr4FzBobv/woWx66EnCWyQLqjSCxipYeer+7ARDmHwgyj+CvgMsfkLa1VL"
+        + "LhFDDj0Efdt9IdKj4Nnhh+r9WkNsr+HGiwSgCDn/Hk1AWSvlxxsqFrUBCi6NMSG2l"
+        + "sM4MzCTrT47dJDPS0go0jIS5E4o3Hc/GMUlhaQaQX8iYaZQk4k1/OsRDoui+FuViU"
+        + "wIVuAne6AQhgy+9KMzmcgByFxAAoo5b0fDy/PgSG+C3wSs6brFmJIOw1exUIf2E/m"
+        + "9ATce4vT3CYKLvhk6dmHDK5jSvTrBU4njGVEW8DlW+GSf8jqABDW/PcAf0Y6T0hqv"
+        + "zTuWlpxv2O3QLeVbDTrIEe1bgRz8HaaiHznXe8oUbCC1xw5FaSAjXJLX0mlKtQ48z"
+        + "xdimSM7B4Pa6iz2q0m8PRzPaad+VyqD3xp53FaR3K9vNT0PXQwJIDZzxl3gYFisbN"
+        + "1KxUDtppnkrBwQx9iPH7zQvbNTQiyoUYnF4sAkECIduh/K+ZIAM8zGJH7NTNIrkK/"
+        + "piehq5/fVAXCr/tdSWeg88gsn0HjNRChuqYz1yFBaQvgMLQ7h/C7k0GP/l2pcUxr8"
+        + "/zDkFr1FFiUN9e2E0nlCO/FUxFZ3PO25D0ZrjAN7h4WLCybClC+Fdy+RhLAtK7Vuz"
+        + "zHwBMPNMMvlreXrSv/EE/37oN5OqA8YrDlPpiDuETS6xPkwkJti/ifrwzvakhBUbB"
+        + "dVd0De2QNctDQBnCFVb1lybbUtSF1Ol5Klcjt7UhFyq0ZkoVXhP2YqEJ7yLOaIKCk"
+        + "AdjOwCtb01L83/LhounfQLxIG8S2SQwMyxYua6k9BpQLJA36y2uu4+3OZIO4JRura"
+        + "drfjN6hGkGam8EvxM8UwrC//TDOHJUEy3IgNV4B4EJWs9lFTL9PO+kBlRFSeL5Son"
+        + "jLB/qZC+i8ssJ8oFkIrl+X7rRcooosbVaNvFIR2FpGCdx8bGoFV6pkfwpJ0hO4dOP"
+        + "nzFm24vBa6UrftojK/z234/h3W0yZScR5CvoSoU+tn1+3G3Q6a4+hdMwF6WjyO3Ne"
+        + "xfMRSvMkAqOqHiptdnz7QDQ7LgGIF6igtGEIpKo4urPAg+RnwqKG6NIYOA32QmU35"
+        + "B4+EJhhYZNINZm0NR5ZM0t9BpUiv6DGl8yZiRX1x4Nu35CLlAT8hWSqgMpb8mw5SQ"
+        + "rQ4dNggVaJ9lO1j1G4hV6umuyX6L1wtOyeQ9aNg3hIZGLPe4pkzahqI2KKlPWpksm"
+        + "MJVIi5WmlvEmFC/UkkUUICjo3KzKPHq7bYmdmDDNLwf9jOeAfq/UNxu4nO8wPjAhM"
+        + "AkGBSsOAwIaBQAEFJrJtKCo0WZ7ewFOiudk30HHA6e0BBRXe6IQoFcDFIzKAyXokh"
+        + "y3daZV4AIDAYag";
 }

From 0e6db16232fe69fe78270ff5b23a8208a778199c Mon Sep 17 00:00:00 2001
From: Igor Veresov <iveresov@openjdk.org>
Date: Fri, 13 Dec 2019 10:04:11 -0800
Subject: [PATCH 09/12] 8235634: Update Graal

Reviewed-by: kvn
---
 .../src/jdk/tools/jaotc/Main.java             |  11 +-
 .../api/directives/GraalDirectives.java       |  18 +-
 .../compiler/asm/amd64/AMD64Assembler.java    |  10 +-
 .../graalvm/compiler/asm/amd64/AVXKind.java   |  13 +-
 .../compiler/asm/sparc/SPARCAssembler.java    |  11 +-
 .../compiler/core/amd64/AMD64AddressNode.java |  19 +-
 .../amd64/AMD64ArithmeticLIRGenerator.java    |   2 +-
 .../core/amd64/AMD64LIRGenerator.java         |  17 +-
 .../graalvm/compiler/core/common/LIRKind.java |  16 +
 .../graalvm/compiler/core/common/NumUtil.java |   7 +-
 .../compiler/core/common/type/Stamp.java      |   7 +
 .../compiler/core/test/HashMapGetTest.java    |  22 +-
 .../core/test/ObjectSubstitutionsTest.java    |  57 +++
 .../graalvm/compiler/debug/DebugContext.java  |  31 +-
 .../org/graalvm/compiler/debug/ScopeImpl.java |   8 +-
 .../aarch64/AArch64HotSpotBackendFactory.java |   2 +-
 .../test/NumberOfTrailingZeroings003.java     |  76 +++
 .../amd64/AMD64HotSpotAddressLowering.java    |   3 +-
 .../amd64/AMD64HotSpotBackendFactory.java     |   2 +-
 .../sparc/SPARCHotSpotBackendFactory.java     |   2 +-
 .../hotspot/test/CompilationWrapperTest.java  |   2 +-
 .../hotspot/test/CompileTheWorld.java         |   3 +-
 .../test/MethodSubstitutionEffectTest.java    | 391 ++++++++++++++++
 .../MethodSubstitutionForeignCallTest.java    | 396 ++++++++++++++++
 .../test/WriteBarrierAdditionTest.java        | 343 ++++++++------
 .../hotspot/GraalHotSpotVMConfig.java         |   1 +
 .../hotspot/HotSpotBackendFactory.java        |   5 +-
 .../compiler/hotspot/HotSpotGraalRuntime.java |   3 +-
 .../hotspot/HotSpotGraalRuntimeProvider.java  |   4 +-
 .../hotspot/HotSpotReplacementsImpl.java      |   2 +-
 .../hotspot/SymbolicSnippetEncoder.java       |  21 +-
 .../meta/DefaultHotSpotLoweringProvider.java  |  43 +-
 .../hotspot/meta/HotSpotGCProvider.java       |  10 +-
 .../meta/HotSpotGraphBuilderPlugins.java      |  46 +-
 .../meta/HotSpotUnsafeSubstitutions.java      |  29 +-
 .../hotspot/replacements/FastNotifyNode.java  | 101 ++++
 .../HotSpotG1WriteBarrierSnippets.java        |  15 +-
 .../replacements/HotSpotReplacementsUtil.java |   7 +-
 .../hotspot/replacements/ObjectSnippets.java  | 126 +++++
 .../replacements/ObjectSubstitutions.java     |  64 ---
 .../replacements/UnsafeCopyMemoryNode.java    | 106 +++++
 .../hotspot/replacements/UnsafeSnippets.java  | 104 +++++
 .../compiler/java/BciBlockMapping.java        |  17 +-
 .../graalvm/compiler/java/BytecodeParser.java | 153 +++++-
 .../org/graalvm/compiler/java/JsrScope.java   |  25 +-
 .../compiler/lir/amd64/AMD64MathPowOp.java    |   2 +-
 .../compiler/lir/amd64/vector/AVXBlendOp.java |  72 +++
 .../compiler/lir/gen/LIRGeneratorTool.java    |   5 +-
 .../compiler/nodes/test/StampToolTest.java    |  58 +++
 .../graalvm/compiler/nodes/GraphDecoder.java  |  47 +-
 .../compiler/nodes/GuardedValueNode.java      |  11 +-
 .../compiler/nodes/calc/FloatEqualsNode.java  |  28 +-
 .../compiler/nodes/calc/IsNullNode.java       |   2 +-
 .../nodes/calc/PointerEqualsNode.java         |   8 +-
 .../compiler/nodes/debug/SideEffectNode.java  |  75 +++
 .../graalvm/compiler/nodes/gc/BarrierSet.java |   4 +
 .../nodes/gc/CardTableBarrierSet.java         |   6 +
 .../compiler/nodes/gc/G1BarrierSet.java       |  57 ++-
 .../nodes/gc/G1ReferentFieldReadBarrier.java  |  10 +-
 .../graphbuilderconf/IntrinsicContext.java    |  14 +-
 .../graphbuilderconf/LoopExplosionPlugin.java |  60 ++-
 .../compiler/nodes/memory/HeapAccess.java     |   7 +-
 .../compiler/nodes/type/StampTool.java        |   9 +-
 .../common/ConditionalEliminationPhase.java   | 391 ++--------------
 .../common/ConditionalEliminationUtil.java    | 441 ++++++++++++++++++
 .../DefaultJavaLoweringProvider.java          |  14 +-
 .../replacements/IntrinsicGraphBuilder.java   |  10 +-
 .../StandardGraphBuilderPlugins.java          |  34 +-
 .../gc/G1WriteBarrierSnippets.java            |  29 +-
 .../nodes/arithmetic/IntegerAddExactNode.java |   7 +-
 .../IntegerAddExactOverflowNode.java          |  12 +-
 71 files changed, 2967 insertions(+), 797 deletions(-)
 create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ObjectSubstitutionsTest.java
 create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/NumberOfTrailingZeroings003.java
 create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/MethodSubstitutionEffectTest.java
 create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/MethodSubstitutionForeignCallTest.java
 create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/FastNotifyNode.java
 create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectSnippets.java
 delete mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectSubstitutions.java
 create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeCopyMemoryNode.java
 create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeSnippets.java
 create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/vector/AVXBlendOp.java
 create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampToolTest.java
 create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/SideEffectNode.java
 create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationUtil.java

diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java
index 24ac51a285c..6970f430292 100644
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java
@@ -224,9 +224,14 @@ public final class Main {
                 System.gc();
             }
 
-            HotSpotGC graal_gc = runtime.getGarbageCollector();
-            int def = graal_gc.ordinal() + 1;
-            String name = "CollectedHeap::" + graal_gc.name();
+            HotSpotGC graalGC = runtime.getGarbageCollector();
+            // Prior to JDK 14, the Graal HotSpotGC enum order matched the JDK CollectedHeap enum
+            // order, so using the ordinal value worked fine. In JDK 14, CMS was removed on the
+            // JDK side, so we need a symbolic lookup of the JDK value.
+            int def = graalGC.ordinal() + 1;
+            // The GC names are spelled the same in both enums, so no clever remapping is needed
+            // here.
+            String name = "CollectedHeap::" + graalGC.name();
             int gc = graalHotSpotVMConfig.getConstant(name, Integer.class, def);
 
             BinaryContainer binaryContainer = new BinaryContainer(graalOptions, graalHotSpotVMConfig, graphBuilderConfig, gc, JVM_VERSION);
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives/src/org/graalvm/compiler/api/directives/GraalDirectives.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives/src/org/graalvm/compiler/api/directives/GraalDirectives.java
index f81ebf69c14..9814e4c36fd 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives/src/org/graalvm/compiler/api/directives/GraalDirectives.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives/src/org/graalvm/compiler/api/directives/GraalDirectives.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -71,6 +71,22 @@ public final class GraalDirectives {
     public static void controlFlowAnchor() {
     }
 
+    /**
+     * A call to this method will force the compiler to assume this instruction has a visible memory
+     * effect killing all memory locations.
+     */
+    public static void sideEffect() {
+
+    }
+
+    /**
+     * A call to this method will force the compiler to assume this instruction has a visible memory
+     * effect killing all memory locations.
+     */
+    public static int sideEffect(@SuppressWarnings("unused") int a) {
+        return 0;
+    }
+
     /**
      * Injects a probability for the given condition into the profiling information of a branch
      * instruction. The probability must be a value between 0.0 and 1.0 (inclusive).
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java
index 2f3bedf36fd..77cb7c9368d 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java
@@ -1298,9 +1298,9 @@ public class AMD64Assembler extends AMD64BaseAssembler {
      */
     public static class VexRVMROp extends VexOp {
         // @formatter:off
-        public static final VexRVMROp VPBLENDVB  = new VexRVMROp("VPBLENDVB",  P_66, M_0F3A, W0, 0x4C, VEXOpAssertion.AVX1_2);
-        public static final VexRVMROp VPBLENDVPS = new VexRVMROp("VPBLENDVPS", P_66, M_0F3A, W0, 0x4A, VEXOpAssertion.AVX1);
-        public static final VexRVMROp VPBLENDVPD = new VexRVMROp("VPBLENDVPD", P_66, M_0F3A, W0, 0x4B, VEXOpAssertion.AVX1);
+        public static final VexRVMROp VPBLENDVB = new VexRVMROp("VPBLENDVB", P_66, M_0F3A, W0, 0x4C, VEXOpAssertion.AVX1_2);
+        public static final VexRVMROp VBLENDVPS = new VexRVMROp("VBLENDVPS", P_66, M_0F3A, W0, 0x4A, VEXOpAssertion.AVX1);
+        public static final VexRVMROp VBLENDVPD = new VexRVMROp("VBLENDVPD", P_66, M_0F3A, W0, 0x4B, VEXOpAssertion.AVX1);
         // @formatter:on
 
         protected VexRVMROp(String opcode, int pp, int mmmmm, int w, int op, VEXOpAssertion assertion) {
@@ -3139,14 +3139,14 @@ public class AMD64Assembler extends AMD64BaseAssembler {
         SSEOp.XOR.emit(this, PS, dst, src);
     }
 
-    protected final void decl(Register dst) {
+    public final void decl(Register dst) {
         // Use two-byte form (one-byte form is a REX prefix in 64-bit mode)
         prefix(dst);
         emitByte(0xFF);
         emitModRM(1, dst);
     }
 
-    protected final void incl(Register dst) {
+    public final void incl(Register dst) {
         // Use two-byte form (one-byte from is a REX prefix in 64-bit mode)
         prefix(dst);
         emitByte(0xFF);
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AVXKind.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AVXKind.java
index bb16a48b882..6a1fe5a6954 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AVXKind.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AVXKind.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -111,6 +111,17 @@ public final class AVXKind {
         return getAVXKind(kind.getScalar(), newSize);
     }
 
+    public static AMD64Kind getMaskKind(AMD64Kind kind) {
+        switch (kind.getScalar()) {
+            case SINGLE:
+                return getAVXKind(AMD64Kind.DWORD, kind.getVectorLength());
+            case DOUBLE:
+                return getAVXKind(AMD64Kind.QWORD, kind.getVectorLength());
+            default:
+                return kind;
+        }
+    }
+
     public static AMD64Kind getAVXKind(AMD64Kind base, AVXSize size) {
         for (AMD64Kind ret : AMD64Kind.values()) {
             if (ret.getScalar() == base && ret.getSizeInBytes() == size.getBytes()) {
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAssembler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAssembler.java
index f67ceac99a0..4f2e5355701 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAssembler.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAssembler.java
@@ -628,6 +628,13 @@ public abstract class SPARCAssembler extends Assembler {
             return value;
         }
 
+        public int getOpfCCValue() {
+            /*
+             * In the opf_cc encoding for FMOVcc, the third bit is set to indicate icc/xcc.
+             */
+            return (isFloat ? value : (value | 0x4));
+        }
+
         public String getOperator() {
             return operator;
         }
@@ -1613,7 +1620,7 @@ public abstract class SPARCAssembler extends Assembler {
             inst = BitSpec.rd.setBits(inst, rd.encoding());
             inst = BitSpec.op3.setBits(inst, opfLow.op3.value);
             inst = BitSpec.opfCond.setBits(inst, condition.value);
-            inst = BitSpec.opfCC.setBits(inst, cc.value);
+            inst = BitSpec.opfCC.setBits(inst, cc.getOpfCCValue());
             inst = BitSpec.opfLow.setBits(inst, opfLow.value);
             inst = BitSpec.rs2.setBits(inst, rs2.encoding());
             masm.emitInt(inst);
@@ -2193,7 +2200,7 @@ public abstract class SPARCAssembler extends Assembler {
     }
 
     private void fmovcc(ConditionFlag cond, CC cc, Register rs2, Register rd, int opfLow) {
-        int opfCC = cc.value;
+        int opfCC = cc.getOpfCCValue();
         int a = opfCC << 11 | opfLow << 5 | rs2.encoding;
         fmt10(rd.encoding, Fpop2.value, cond.value, a);
     }
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressNode.java
index 3d759729305..ab1d06222ef 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressNode.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -63,6 +63,14 @@ public class AMD64AddressNode extends AddressNode implements Simplifiable, LIRLo
 
     private int displacement;
 
+    /*
+     * If this address has been improved by folding an uncompress operation into it, this is set by
+     * the address lowering to the uncompression scale used by the encoding strategy. It is null
+     * otherwise. This might be different from scale if we lowered an uncompression followed by
+     * further improvements that modify the scale.
+     */
+    private Scale uncompressionScale;
+
     public AMD64AddressNode(ValueNode base) {
         this(base, null);
     }
@@ -72,6 +80,7 @@ public class AMD64AddressNode extends AddressNode implements Simplifiable, LIRLo
         this.base = base;
         this.index = index;
         this.scale = Scale.Times1;
+        this.uncompressionScale = null;
     }
 
     public void canonicalizeIndex(SimplifierTool tool) {
@@ -103,12 +112,14 @@ public class AMD64AddressNode extends AddressNode implements Simplifiable, LIRLo
         AllocatableValue baseValue = base == null ? Value.ILLEGAL : tool.asAllocatable(gen.operand(base));
         AllocatableValue indexValue = index == null ? Value.ILLEGAL : tool.asAllocatable(gen.operand(index));
 
-        AllocatableValue baseReference = LIRKind.derivedBaseFromValue(baseValue);
+        AllocatableValue baseReference = base == null ? null : LIRKind.derivedBaseFromValue(baseValue);
         AllocatableValue indexReference;
         if (index == null) {
             indexReference = null;
         } else if (scale.equals(Scale.Times1)) {
             indexReference = LIRKind.derivedBaseFromValue(indexValue);
+        } else if (scale.equals(uncompressionScale) && LIRKind.isScalarCompressedReference(indexValue.getValueKind())) {
+            indexReference = LIRKind.derivedBaseFromValue(indexValue);
         } else {
             if (LIRKind.isValue(indexValue)) {
                 indexReference = null;
@@ -163,6 +174,10 @@ public class AMD64AddressNode extends AddressNode implements Simplifiable, LIRLo
         this.displacement = displacement;
     }
 
+    public void setUncompressionScale(Scale scale) {
+        this.uncompressionScale = scale;
+    }
+
     @Override
     public long getMaxConstantDisplacement() {
         return displacement;
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java
index 75d7f730722..6e1d026c5dd 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java
@@ -1305,7 +1305,7 @@ public class AMD64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implemen
                 return;
             } else if (c instanceof VMConstant) {
                 VMConstant vc = (VMConstant) c;
-                if (size == DWORD && !GeneratePIC.getValue(getOptions())) {
+                if (size == DWORD && !GeneratePIC.getValue(getOptions()) && getLIRGen().target().inlineObjects) {
                     getLIRGen().append(new AMD64BinaryConsumer.VMConstOp(CMP.getMIOpcode(DWORD, false), left, vc));
                 } else {
                     getLIRGen().append(new AMD64BinaryConsumer.DataOp(CMP.getRMOpcode(size), size, left, vc));
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java
index eff5bc3669b..72bc60336d1 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java
@@ -409,7 +409,7 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
         return result;
     }
 
-    private static AVXSize getRegisterSize(Value a) {
+    protected static AVXSize getRegisterSize(Value a) {
         AMD64Kind kind = (AMD64Kind) a.getPlatformKind();
         if (kind.isXMM()) {
             return AVXKind.getRegisterSize(kind);
@@ -479,18 +479,19 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
         if (JavaConstant.isNull(a.getConstant())) {
             append(new AMD64BinaryConsumer.MemoryConstOp(CMP, size, b, 0, state));
             return true;
-        } else if (a.getConstant() instanceof VMConstant && size == DWORD) {
+        } else if (a.getConstant() instanceof VMConstant && size == DWORD && target().inlineObjects) {
             VMConstant vc = (VMConstant) a.getConstant();
             append(new AMD64BinaryConsumer.MemoryVMConstOp(CMP.getMIOpcode(size, false), b, vc, state));
             return true;
         } else {
-            long value = a.getJavaConstant().asLong();
-            if (NumUtil.is32bit(value)) {
-                append(new AMD64BinaryConsumer.MemoryConstOp(CMP, size, b, (int) value, state));
-                return true;
-            } else {
-                return emitCompareRegMemoryOp(size, asAllocatable(a), b, state);
+            if (a.getConstant() instanceof JavaConstant && a.getJavaConstant().getJavaKind() != JavaKind.Object) {
+                long value = a.getJavaConstant().asLong();
+                if (NumUtil.is32bit(value)) {
+                    append(new AMD64BinaryConsumer.MemoryConstOp(CMP, size, b, (int) value, state));
+                    return true;
+                }
             }
+            return emitCompareRegMemoryOp(size, asAllocatable(a), b, state);
         }
     }
 
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LIRKind.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LIRKind.java
index 1f51ec64eef..6ed27d9d837 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LIRKind.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LIRKind.java
@@ -421,6 +421,22 @@ public final class LIRKind extends ValueKind<LIRKind> {
         return !isUnknownReference() && (referenceCompressionMask & (1 << idx)) != 0;
     }
 
+    /**
+     * Check whether the given kind is a scalar (i.e., vector length 1) <b>compressed</b> reference.
+     *
+     * @param kind The kind to be checked.
+     * @return true if the given kind is a scalar compressed reference
+     */
+    public static boolean isScalarCompressedReference(ValueKind<?> kind) {
+        if (kind instanceof LIRKind) {
+            LIRKind lirKind = (LIRKind) kind;
+            if (lirKind.getPlatformKind().getVectorLength() == 1 && lirKind.isCompressedReference(0)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Check whether this kind is a value type that doesn't need to be tracked at safepoints.
      */
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/NumUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/NumUtil.java
index 3258b13f42f..07a3a476913 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/NumUtil.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/NumUtil.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -105,6 +105,11 @@ public class NumUtil {
         return -0x80000000L <= x && x < 0x80000000L;
     }
 
+    public static byte safeToByte(int v) {
+        assert isByte(v);
+        return (byte) v;
+    }
+
     public static short safeToShort(int v) {
         assert isShort(v);
         return (short) v;
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java
index 3012ada2a1d..684b4d8203c 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java
@@ -135,6 +135,13 @@ public abstract class Stamp implements SpeculationContextObject {
         return this.equals(this.unrestricted());
     }
 
+    /**
+     * Tests whether this stamp represents a pointer value.
+     */
+    public boolean isPointerStamp() {
+        return this instanceof AbstractPointerStamp;
+    }
+
     /**
      * If this stamp represents a single value, the methods returns this single value. It returns
      * null otherwise.
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashMapGetTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashMapGetTest.java
index 374570b5677..43c0e9dac7e 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashMapGetTest.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashMapGetTest.java
@@ -25,25 +25,27 @@
 package org.graalvm.compiler.core.test;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
+import org.graalvm.compiler.nodes.FieldLocationIdentity;
 import org.graalvm.compiler.nodes.IfNode;
 import org.graalvm.compiler.nodes.LogicNode;
 import org.graalvm.compiler.nodes.ReturnNode;
 import org.graalvm.compiler.nodes.calc.ObjectEqualsNode;
+import org.graalvm.compiler.nodes.memory.ReadNode;
 import org.junit.Test;
 
+import java.io.IOException;
 import java.util.HashMap;
 
-public class HashMapGetTest extends GraalCompilerTest {
+public class HashMapGetTest extends SubprocessTest {
 
-    public static void mapGet(HashMap<Integer, Integer> map, Integer key) {
+    public static <K, V> void mapGet(HashMap<K, V> map, K key) {
         map.get(key);
     }
 
-    @Test
     public void hashMapTest() {
         HashMap<Integer, Integer> map = new HashMap<>();
         ResolvedJavaMethod get = getResolvedJavaMethod(HashMapGetTest.class, "mapGet");
-        for (int i = 0; i < 5000; i++) {
+        for (int i = 0; i < 10000; i++) {
             mapGet(map, i);
             map.put(i, i);
             mapGet(map, i);
@@ -51,10 +53,18 @@ public class HashMapGetTest extends GraalCompilerTest {
         test(get, null, map, 0);
         for (IfNode ifNode : lastCompiledGraph.getNodes(IfNode.TYPE)) {
             LogicNode condition = ifNode.condition();
-            if (ifNode.getTrueSuccessorProbability() < 0.4 && condition instanceof ObjectEqualsNode) {
-                assertTrue(ifNode.trueSuccessor().next() instanceof ReturnNode, "Expected return but got %s (trueSuccessor: %s)", ifNode.trueSuccessor().next(), ifNode.trueSuccessor());
+            if (ifNode.getTrueSuccessorProbability() < 0.4 && ifNode.predecessor() instanceof ReadNode && condition instanceof ObjectEqualsNode) {
+                ReadNode read = (ReadNode) ifNode.predecessor();
+                if (read.getLocationIdentity() instanceof FieldLocationIdentity && ((FieldLocationIdentity) read.getLocationIdentity()).getField().getName().contains("key")) {
+                    assertTrue(ifNode.trueSuccessor().next() instanceof ReturnNode, "Expected return after %s, got %s", ifNode.trueSuccessor(), ifNode.trueSuccessor().next());
+                }
             }
         }
     }
 
+    @Test
+    public void hashMapTestInSubprocess() throws IOException, InterruptedException {
+        launchSubprocess(this::hashMapTest);
+    }
+
 }
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ObjectSubstitutionsTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ObjectSubstitutionsTest.java
new file mode 100644
index 00000000000..f5828aae5f0
--- /dev/null
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ObjectSubstitutionsTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2019, 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.core.test;
+
+import org.junit.Test;
+
+public class ObjectSubstitutionsTest extends GraalCompilerTest {
+
+    public static int SideEffect;
+
+    public static final void notifySnippet() {
+        synchronized (ObjectSubstitutionsTest.class) {
+            SideEffect = System.identityHashCode(ObjectSubstitutionsTest.class);
+            ObjectSubstitutionsTest.class.notify();
+        }
+    }
+
+    public static final void notifyAllSnippet() {
+        synchronized (ObjectSubstitutionsTest.class) {
+            SideEffect = System.identityHashCode(ObjectSubstitutionsTest.class);
+            ObjectSubstitutionsTest.class.notifyAll();
+        }
+    }
+
+    @Test
+    public void testNotifyEmpty() {
+        test("notifySnippet");
+    }
+
+    @Test
+    public void testNotifyAllEmpty() {
+        test("notifyAllSnippet");
+    }
+
+}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java
index 655192be46a..f4df912b43c 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java
@@ -1841,6 +1841,25 @@ public final class DebugContext implements AutoCloseable {
         return createTimer(format, arg1, arg2);
     }
 
+    /**
+     * Gets the name to use for a class based on whether it appears to be an obfuscated name. The
+     * heuristic for an obfuscated name is that it is less than 6 characters in length and consists
+     * only of lower case letters.
+     */
+    private static String getBaseName(Class<?> c) {
+        String simpleName = c.getSimpleName();
+        if (simpleName.length() < 6) {
+            for (int i = 0; i < simpleName.length(); i++) {
+                if (!Character.isLowerCase(simpleName.charAt(0))) {
+                    return simpleName;
+                }
+            }
+            // Looks like an obfuscated simple class name so use qualified class name
+            return c.getName();
+        }
+        return simpleName;
+    }
+
     /**
      * There are paths where construction of formatted class names are common and the code below is
      * surprisingly expensive, so compute it once and cache it.
@@ -1848,17 +1867,21 @@ public final class DebugContext implements AutoCloseable {
     private static final ClassValue<String> formattedClassName = new ClassValue<String>() {
         @Override
         protected String computeValue(Class<?> c) {
-            final String simpleName = c.getSimpleName();
+            String baseName = getBaseName(c);
+            if (Character.isLowerCase(baseName.charAt(0))) {
+                // Looks like an obfuscated simple class name so use qualified class name
+                baseName = c.getName();
+            }
             Class<?> enclosingClass = c.getEnclosingClass();
             if (enclosingClass != null) {
                 String prefix = "";
                 while (enclosingClass != null) {
-                    prefix = enclosingClass.getSimpleName() + "_" + prefix;
+                    prefix = getBaseName(enclosingClass) + "_" + prefix;
                     enclosingClass = enclosingClass.getEnclosingClass();
                 }
-                return prefix + simpleName;
+                return prefix + baseName;
             } else {
-                return simpleName;
+                return baseName;
             }
         }
     };
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/ScopeImpl.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/ScopeImpl.java
index 885fdcdaf0c..397857877b4 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/ScopeImpl.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/ScopeImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -306,7 +306,11 @@ public final class ScopeImpl implements DebugContext.Scope {
                 assert owner.lastClosedScope instanceof DisabledScope : owner.lastClosedScope;
             }
         } catch (Throwable t) {
-            t.initCause(e);
+            if (t != e && t.getCause() == null) {
+                // This mitigates the chance of `e` being swallowed/lost in
+                // the case there's an error in the above handling of `e`.
+                t.initCause(e);
+            }
             throw t;
         }
 
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java
index df15af7b3e0..ced31a553be 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java
@@ -141,7 +141,7 @@ public class AArch64HotSpotBackendFactory extends HotSpotBackendFactory {
                 stampProvider = createStampProvider();
             }
             try (InitTimer rt = timer("create GC provider")) {
-                gc = createGCProvider(config);
+                gc = createGCProvider(config, metaAccess);
             }
 
             Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, gc);
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/NumberOfTrailingZeroings003.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/NumberOfTrailingZeroings003.java
new file mode 100644
index 00000000000..3398da274fd
--- /dev/null
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/NumberOfTrailingZeroings003.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2019, 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.amd64.test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.junit.Test;
+
+public class NumberOfTrailingZeroings003 extends GraalCompilerTest {
+
+    public static boolean numberOfTrailingZeros0() {
+        return Integer.numberOfTrailingZeros(0) == 32;
+    }
+
+    @Test
+    public void testNumberOfTrailingZeros0() {
+        test("numberOfTrailingZeros0");
+    }
+
+    public static boolean numberOfTrailingZeros1() {
+        return Integer.numberOfTrailingZeros(1) == 0;
+    }
+
+    @Test
+    public void testNumberOfTrailingZeros1() {
+        test("numberOfTrailingZeros1");
+    }
+
+    public static boolean numberOfTrailingZerosM1() {
+        return Integer.numberOfTrailingZeros(-1) == 0;
+    }
+
+    @Test
+    public void testNumberOfTrailingZerosM1() {
+        test("numberOfTrailingZerosM1");
+    }
+
+    public static boolean numberOfTrailingZerosMin() {
+        return Integer.numberOfTrailingZeros(Integer.MIN_VALUE) == 31;
+    }
+
+    @Test
+    public void testNumberOfTrailingZerosMin() {
+        test("numberOfTrailingZerosMin");
+    }
+
+    public static boolean numberOfTrailingZerosMax() {
+        return Integer.numberOfTrailingZeros(Integer.MAX_VALUE) == 0;
+    }
+
+    @Test
+    public void testNumberOfTrailingZerosMax() {
+        test("numberOfTrailingZerosMax");
+    }
+}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java
index ef4423ead18..a77861236cc 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -118,6 +118,7 @@ public class AMD64HotSpotAddressLowering extends AMD64CompressAddressLowering {
         }
 
         addr.setScale(scale);
+        addr.setUncompressionScale(scale);
         addr.setIndex(compression.getValue());
         return true;
     }
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java
index 288340ee223..41daaaf29a9 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java
@@ -133,7 +133,7 @@ public class AMD64HotSpotBackendFactory extends HotSpotBackendFactory {
                 stampProvider = createStampProvider();
             }
             try (InitTimer rt = timer("create GC provider")) {
-                gc = createGCProvider(config);
+                gc = createGCProvider(config, metaAccess);
             }
 
             Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, gc);
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java
index 63f355c662e..dce31c42e22 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java
@@ -101,7 +101,7 @@ public class SPARCHotSpotBackendFactory extends HotSpotBackendFactory {
         HotSpotForeignCallsProvider foreignCalls = new SPARCHotSpotForeignCallsProvider(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters);
         LoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
         HotSpotStampProvider stampProvider = createStampProvider();
-        HotSpotGCProvider gc = createGCProvider(config);
+        HotSpotGCProvider gc = createGCProvider(config, metaAccess);
         Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, gc);
         HotSpotSnippetReflectionProvider snippetReflection = createSnippetReflection(runtime, constantReflection, wordTypes);
         BytecodeProvider bytecodeProvider = createBytecodeProvider(metaAccess, snippetReflection);
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java
index 804cd9f2ff3..717c4bc1be8 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java
@@ -249,7 +249,7 @@ public class CompilationWrapperTest extends GraalCompilerTest {
             for (Probe probe : probes) {
                 String error = probe.test();
                 if (error != null) {
-                    Assert.fail(String.format("Did not find expected occurences of '%s' in output of command: %s%n%s", probe.substring, error, proc));
+                    Assert.fail(String.format("Did not find expected occurrences of '%s' in output of command: %s%n%s", probe.substring, error, proc));
                 }
             }
             String line = diagnosticProbe.lastMatchingLine;
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java
index de3bddff387..0015efa24d5 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java
@@ -1092,7 +1092,8 @@ public final class CompileTheWorld {
                                    "'PartialEscapeAnalysis=false PrintCompilation=true'. " +
                                    "Unless explicitly enabled with 'Inline=true' here, inlining is disabled.",
                   "MultiThreaded", "Run using multiple threads for compilation.",
-                        "Threads", "Number of threads to use for multithreaded execution. Defaults to Runtime.getRuntime().availableProcessors().");
+                        "Threads", "Number of threads to use for multithreaded execution. Defaults to Runtime.getRuntime().availableProcessors().",
+        "InvalidateInstalledCode", "Invalidate the generated code so the code cache doesn't fill up.");
         // @formatter:on
     }
 
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/MethodSubstitutionEffectTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/MethodSubstitutionEffectTest.java
new file mode 100644
index 00000000000..997f58617d7
--- /dev/null
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/MethodSubstitutionEffectTest.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2019, 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.test;
+
+import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+import static org.graalvm.compiler.debug.DebugOptions.DumpOnError;
+
+import java.util.ArrayList;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.java.BytecodeParserOptions;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.phases.tiers.Suites;
+import org.graalvm.compiler.replacements.ReplacementsImpl;
+import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class MethodSubstitutionEffectTest extends GraalCompilerTest {
+    public static int ValueFountain;
+
+    static class Substitutee {
+
+        public static int singleEffect(@SuppressWarnings("unused") int a) {
+            return 0;
+        }
+
+        public static int sequentialEffectInvalid(@SuppressWarnings("unused") int a) {
+            return 0;
+        }
+
+        public static void sequentialEffectInvalidVoid(@SuppressWarnings("unused") int a) {
+        }
+
+        public static int splitEffect(@SuppressWarnings("unused") int a) {
+            return 0;
+        }
+
+        public static void splitEffectVoid(@SuppressWarnings("unused") int a) {
+        }
+
+        public static int multiSplitEffectNoMerge(@SuppressWarnings("unused") int a) {
+            return 0;
+        }
+
+        public static int multiSplitEffectNoMergeInvalid(@SuppressWarnings("unused") int a) {
+            return 0;
+        }
+
+        public static int splitEffectWrong(@SuppressWarnings("unused") int a) {
+            return 0;
+        }
+
+        public static int splitParitalIntrinsicExit(@SuppressWarnings("unused") int a) {
+            return 0;
+        }
+    }
+
+    @ClassSubstitution(Substitutee.class)
+    public static class Substitutor {
+
+        @MethodSubstitution
+        public static int singleEffect(int a) {
+            return GraalDirectives.sideEffect(a);
+        }
+
+        @MethodSubstitution
+        public static int sequentialEffectInvalid(int a) {
+            GraalDirectives.sideEffect(a);
+            return GraalDirectives.sideEffect(a);
+        }
+
+        @MethodSubstitution
+        public static void sequentialEffectInvalidVoid(int a) {
+            GraalDirectives.sideEffect(a);
+            GraalDirectives.sideEffect(a);
+        }
+
+        @MethodSubstitution
+        public static int splitEffect(int a) {
+            int i;
+            if (a > 0) {
+                GraalDirectives.sideEffect(a);
+                i = a;
+            } else {
+                GraalDirectives.sideEffect(42);
+                i = 42;
+            }
+            return i;
+        }
+
+        @MethodSubstitution
+        public static void splitEffectVoid(int a) {
+            if (a > 0) {
+                GraalDirectives.sideEffect(a);
+            } else {
+                GraalDirectives.sideEffect(42);
+            }
+        }
+
+        @MethodSubstitution
+        public static int multiSplitEffectNoMerge(int a) {
+            switch (a) {
+                case 1:
+                    GraalDirectives.sideEffect(a);
+                    return 3;
+                case 2:
+                    GraalDirectives.sideEffect(a);
+                    return 2;
+                case 3:
+                    GraalDirectives.sideEffect(a);
+                    return 1;
+                default:
+                    GraalDirectives.sideEffect(a);
+                    return 0;
+            }
+        }
+
+        @MethodSubstitution
+        public static int multiSplitEffectNoMergeInvalid(int a) {
+            switch (a) {
+                case 1:
+                    GraalDirectives.sideEffect(a);
+                    return 3;
+                case 2:
+                    GraalDirectives.sideEffect(a);
+                    return 2;
+                case 3:
+                    GraalDirectives.sideEffect(a);
+                    return 1;
+                default:
+                    GraalDirectives.sideEffect(a);
+                    GraalDirectives.sideEffect(a);
+                    return 0;
+            }
+        }
+
+        @MethodSubstitution
+        public static int splitEffectWrong(int a) {
+            int i;
+            if (a > 0) {
+                GraalDirectives.sideEffect(a);
+                GraalDirectives.sideEffect(a);
+                i = a;
+            } else {
+                i = 42;
+                GraalDirectives.controlFlowAnchor();
+            }
+            return i;
+        }
+
+        @MethodSubstitution
+        public static int splitParitalIntrinsicExit(int a) {
+            int i;
+            if (a > 0) {
+                i = GraalDirectives.sideEffect(a);
+            } else {
+                i = splitParitalIntrinsicExit(a);
+            }
+            return i;
+        }
+    }
+
+    @Override
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
+        ClassfileBytecodeProvider bytecodeProvider = getSystemClassLoaderBytecodeProvider();
+        Registration r = new Registration(invocationPlugins, Substitutee.class, getReplacements(), bytecodeProvider);
+        r.registerMethodSubstitution(Substitutor.class, "singleEffect", int.class);
+        r.registerMethodSubstitution(Substitutor.class, "sequentialEffectInvalid", int.class);
+        r.registerMethodSubstitution(Substitutor.class, "sequentialEffectInvalidVoid", int.class);
+        r.registerMethodSubstitution(Substitutor.class, "splitEffect", int.class);
+        r.registerMethodSubstitution(Substitutor.class, "splitEffectVoid", int.class);
+        r.registerMethodSubstitution(Substitutor.class, "multiSplitEffectNoMerge", int.class);
+        r.registerMethodSubstitution(Substitutor.class, "multiSplitEffectNoMergeInvalid", int.class);
+        r.registerMethodSubstitution(Substitutor.class, "splitEffectWrong", int.class);
+        r.registerMethodSubstitution(Substitutor.class, "splitParitalIntrinsicExit", int.class);
+        super.registerInvocationPlugins(invocationPlugins);
+    }
+
+    private ClassfileBytecodeProvider getSystemClassLoaderBytecodeProvider() {
+        ReplacementsImpl d = (ReplacementsImpl) getReplacements();
+        MetaAccessProvider metaAccess = d.getProviders().getMetaAccess();
+        ClassfileBytecodeProvider bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, d.snippetReflection, ClassLoader.getSystemClassLoader());
+        return bytecodeProvider;
+    }
+
+    static void snippet01() {
+        Substitutee.singleEffect(42);
+        if (ValueFountain == 42) {
+            GraalDirectives.deoptimize();
+        }
+    }
+
+    static void snippet02() {
+        Substitutee.sequentialEffectInvalid(42);
+        if (ValueFountain == 42) {
+            GraalDirectives.deoptimize();
+        }
+    }
+
+    static void snippet03() {
+        Substitutee.sequentialEffectInvalidVoid(42);
+        if (ValueFountain == 42) {
+            GraalDirectives.deoptimize();
+        }
+    }
+
+    static void snippet04() {
+        Substitutee.splitEffect(ValueFountain);
+        if (ValueFountain == 42) {
+            GraalDirectives.deoptimize();
+        }
+    }
+
+    static void snippet05() {
+        Substitutee.splitEffectVoid(ValueFountain);
+        if (ValueFountain == 42) {
+            GraalDirectives.deoptimize();
+        }
+    }
+
+    static void snippet06() {
+        Substitutee.splitEffectWrong(ValueFountain);
+        if (ValueFountain == 42) {
+            GraalDirectives.deoptimize();
+        }
+    }
+
+    static void snippet07() {
+        if (Substitutee.splitParitalIntrinsicExit(ValueFountain) == 42) {
+            GraalDirectives.deoptimize();
+        }
+    }
+
+    static void snippet08() {
+        Substitutee.multiSplitEffectNoMerge(ValueFountain);
+    }
+
+    StructuredGraph getGraph(String snippet) {
+        OptionValues options = new OptionValues(getInitialOptions(), DumpOnError, false);
+        /*
+         * We do not want to inline partial intrinsic exits in this test to test the state of the
+         * self recursive call.
+         */
+        options = new OptionValues(getInitialOptions(), BytecodeParserOptions.InlinePartialIntrinsicExitDuringParsing, false);
+        StructuredGraph g = parseEager(getResolvedJavaMethod(snippet), AllowAssumptions.NO, options);
+        Suites s = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites().getDefaultSuites(getInitialOptions());
+        s.getHighTier().apply(g, getDefaultHighTierContext());
+        s.getMidTier().apply(g, getDefaultMidTierContext());
+        return g;
+    }
+
+    @Test
+    public void test1() {
+        getGraph("snippet01");
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void test2() {
+        try (AutoCloseable c = new TTY.Filter()) {
+            getGraph("snippet02");
+            Assert.fail("Compilation should not reach this point, must throw an exception before");
+        } catch (Throwable t) {
+            if (t.getCause() instanceof GraalError && t.getMessage().contains("unexpected node between return StateSplit and last instruction")) {
+                return;
+            }
+            throw new AssertionError(t);
+        }
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void test3() {
+        try (AutoCloseable c = new TTY.Filter()) {
+            getGraph("snippet03");
+            Assert.fail("Compilation should not reach this point, must throw an exception before");
+        } catch (Throwable t) {
+            if (t.getCause() instanceof GraalError && t.getMessage().contains(" produced invalid framestate")) {
+                return;
+            }
+            throw new AssertionError(t);
+        }
+    }
+
+    @Test
+    public void test4() {
+        getGraph("snippet04");
+    }
+
+    @Test
+    public void test5() {
+        getGraph("snippet05");
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void test6() {
+        try (AutoCloseable c = new TTY.Filter()) {
+            getGraph("snippet06");
+            Assert.fail("Compilation should not reach this point, must throw an exception before");
+        } catch (Throwable t) {
+            if (t.getCause() instanceof GraalError && t.getMessage().contains(" produced invalid framestate")) {
+                return;
+            }
+            throw new AssertionError(t);
+        }
+    }
+
+    @Test
+    public void test7() {
+        getGraph("snippet07");
+    }
+
+    @Test
+    public void test8() {
+        getGraph("snippet08");
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void testRootCompiles() {
+        ArrayList<ResolvedJavaMethod> intrinisicsWithoutErrors = new ArrayList<>();
+        ArrayList<ResolvedJavaMethod> intrinisicsErrors = new ArrayList<>();
+
+        intrinisicsWithoutErrors.add(getResolvedJavaMethod(Substitutee.class, "singleEffect"));
+        intrinisicsWithoutErrors.add(getResolvedJavaMethod(Substitutee.class, "splitEffect"));
+        intrinisicsWithoutErrors.add(getResolvedJavaMethod(Substitutee.class, "splitEffectVoid"));
+        intrinisicsWithoutErrors.add(getResolvedJavaMethod(Substitutee.class, "multiSplitEffectNoMerge"));
+        intrinisicsWithoutErrors.add(getResolvedJavaMethod(Substitutee.class, "splitParitalIntrinsicExit"));
+
+        intrinisicsErrors.add(getResolvedJavaMethod(Substitutee.class, "sequentialEffectInvalid"));
+        intrinisicsErrors.add(getResolvedJavaMethod(Substitutee.class, "sequentialEffectInvalidVoid"));
+        intrinisicsErrors.add(getResolvedJavaMethod(Substitutee.class, "splitEffectWrong"));
+        intrinisicsErrors.add(getResolvedJavaMethod(Substitutee.class, "multiSplitEffectNoMergeInvalid"));
+
+        for (ResolvedJavaMethod method : intrinisicsWithoutErrors) {
+            StructuredGraph graph = getProviders().getReplacements().getIntrinsicGraph(method, INVALID_COMPILATION_ID, getDebugContext(), null);
+            getCode(method, graph);
+        }
+        for (ResolvedJavaMethod method : intrinisicsErrors) {
+            try (AutoCloseable c = new TTY.Filter()) {
+                StructuredGraph graph = getProviders().getReplacements().getIntrinsicGraph(method, INVALID_COMPILATION_ID, getDebugContext(), null);
+                getCode(method, graph);
+                Assert.fail("Compilation should not reach this point, must throw an exception before");
+            } catch (Throwable t) {
+                if ((t.getCause() instanceof GraalError || t instanceof GraalError) && t.getMessage().contains("invalid state")) {
+                    continue;
+                }
+                throw new AssertionError(t);
+            }
+        }
+
+    }
+}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/MethodSubstitutionForeignCallTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/MethodSubstitutionForeignCallTest.java
new file mode 100644
index 00000000000..4b61a521ee3
--- /dev/null
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/MethodSubstitutionForeignCallTest.java
@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 2019, 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.test;
+
+import static org.graalvm.compiler.debug.DebugOptions.DumpOnError;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.phases.tiers.Suites;
+import org.graalvm.compiler.replacements.ReplacementsImpl;
+import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+import jdk.internal.vm.compiler.word.LocationIdentity;
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class MethodSubstitutionForeignCallTest extends GraalCompilerTest {
+    public static final ForeignCallDescriptor TEST_CALL = new ForeignCallDescriptor("test", int.class, int.class);
+
+    public static class A {
+        static void invalidConsecutiveForeignCall1(@SuppressWarnings("unused") int phi) {
+
+        }
+
+        static void invalidConsecutiveForeignCall2(@SuppressWarnings("unused") int phi) {
+
+        }
+
+        static void validConsecutiveForeignCallReexecutable(@SuppressWarnings("unused") int phi) {
+
+        }
+
+        static void splitForeignCallInvalid(@SuppressWarnings("unused") int phi) {
+
+        }
+    }
+
+    @ClassSubstitution(A.class)
+    public static class ASubstitutions {
+
+        /*
+         * Invalid: two consecutive states, deopt could float in between.
+         */
+        @MethodSubstitution
+        static void invalidConsecutiveForeignCall1(int phi) {
+            testDeopt(phi);
+            // invalid two consecutive calls
+            testDeopt(phi);
+        }
+
+        /*
+         * Invalid: two consecutive states, deopt could float in between. Same applies for
+         * non-deopting framestates if they are not re-executable. If they are, we are good.
+         */
+        @MethodSubstitution
+        static void invalidConsecutiveForeignCall2(int phi) {
+            testNonDeopting(phi);
+            testNonDeopting(phi);
+        }
+
+        /*
+         * Valid, the foreign calls are re-executable and non-deopting (thus completely side-effect
+         * free), they do not need a state.
+         */
+        @MethodSubstitution
+        static void validConsecutiveForeignCallReexecutable(int phi) {
+            testPureReexectuable(phi);
+            testPureReexectuable(phi);
+        }
+
+        /**
+         * Invalid: Splitting effect in a method substitution is allowed as long as it is just one
+         * effect per call. This is not the case here.
+         */
+        @MethodSubstitution
+        static void splitForeignCallInvalid(int phi) {
+            if (SideEffect == 0) {
+                testDeopt(phi);
+            } else {
+                CurrentJavaThreadNode.get().writeByte(0, (byte) 0);
+                testDeopt(phi);
+            }
+        }
+    }
+
+    @Override
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
+
+        invocationPlugins.register(new InvocationPlugin() {
+
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+                ForeignCallsProvider foreignCalls = new ForeignCallsProvider() {
+
+                    @Override
+                    public LIRKind getValueKind(JavaKind javaKind) {
+                        return LIRKind.fromJavaKind(getTarget().arch, javaKind);
+                    }
+
+                    @Override
+                    public ForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor) {
+                        throw GraalError.shouldNotReachHere("Test code must not need this method");
+                    }
+
+                    @Override
+                    public boolean isReexecutable(ForeignCallDescriptor descriptor) {
+                        return false;
+                    }
+
+                    @Override
+                    public boolean isGuaranteedSafepoint(ForeignCallDescriptor descriptor) {
+                        return true;
+                    }
+
+                    @Override
+                    public boolean isAvailable(ForeignCallDescriptor descriptor) {
+                        return true;
+                    }
+
+                    @Override
+                    public LocationIdentity[] getKilledLocations(ForeignCallDescriptor descriptor) {
+                        return new LocationIdentity[]{LocationIdentity.any()};
+                    }
+
+                    @Override
+                    public boolean canDeoptimize(ForeignCallDescriptor descriptor) {
+                        return true;
+                    }
+                };
+                ForeignCallNode node = new ForeignCallNode(foreignCalls, TEST_CALL, arg);
+                node.setBci(b.bci());
+                b.addPush(JavaKind.Int, node);
+                return true;
+            }
+        }, MethodSubstitutionForeignCallTest.class, "testDeopt", int.class);
+        invocationPlugins.register(new InvocationPlugin() {
+
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+                ForeignCallsProvider foreignCalls = new ForeignCallsProvider() {
+
+                    @Override
+                    public LIRKind getValueKind(JavaKind javaKind) {
+                        return LIRKind.fromJavaKind(getTarget().arch, javaKind);
+                    }
+
+                    @Override
+                    public ForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor) {
+                        throw GraalError.shouldNotReachHere("Test code must not need this method");
+                    }
+
+                    @Override
+                    public boolean isReexecutable(ForeignCallDescriptor descriptor) {
+                        return false;
+                    }
+
+                    @Override
+                    public boolean isGuaranteedSafepoint(ForeignCallDescriptor descriptor) {
+                        return false;
+                    }
+
+                    @Override
+                    public boolean isAvailable(ForeignCallDescriptor descriptor) {
+                        return true;
+                    }
+
+                    @Override
+                    public LocationIdentity[] getKilledLocations(ForeignCallDescriptor descriptor) {
+                        return new LocationIdentity[]{LocationIdentity.any()};
+                    }
+
+                    @Override
+                    public boolean canDeoptimize(ForeignCallDescriptor descriptor) {
+                        return false;
+                    }
+                };
+                ForeignCallNode node = new ForeignCallNode(foreignCalls, TEST_CALL, arg);
+                node.setBci(b.bci());
+                b.addPush(JavaKind.Int, node);
+                return true;
+            }
+        }, MethodSubstitutionForeignCallTest.class, "testNonDeopting", int.class);
+        invocationPlugins.register(new InvocationPlugin() {
+
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+                ForeignCallsProvider foreignCalls = new ForeignCallsProvider() {
+
+                    @Override
+                    public LIRKind getValueKind(JavaKind javaKind) {
+                        return LIRKind.fromJavaKind(getTarget().arch, javaKind);
+                    }
+
+                    @Override
+                    public ForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor) {
+                        throw GraalError.shouldNotReachHere("Test code must not need this method");
+                    }
+
+                    @Override
+                    public boolean isReexecutable(ForeignCallDescriptor descriptor) {
+                        return true;
+                    }
+
+                    @Override
+                    public boolean isGuaranteedSafepoint(ForeignCallDescriptor descriptor) {
+                        return false;
+                    }
+
+                    @Override
+                    public boolean isAvailable(ForeignCallDescriptor descriptor) {
+                        return true;
+                    }
+
+                    @Override
+                    public LocationIdentity[] getKilledLocations(ForeignCallDescriptor descriptor) {
+                        return new LocationIdentity[]{LocationIdentity.any()};
+                    }
+
+                    @Override
+                    public boolean canDeoptimize(ForeignCallDescriptor descriptor) {
+                        return false;
+                    }
+                };
+                ForeignCallNode node = new ForeignCallNode(foreignCalls, TEST_CALL, arg);
+                node.setBci(b.bci());
+                b.addPush(JavaKind.Int, node);
+                return true;
+            }
+        }, MethodSubstitutionForeignCallTest.class, "testPureReexectuable", int.class);
+        ClassfileBytecodeProvider bytecodeProvider = getSystemClassLoaderBytecodeProvider();
+        Registration r = new Registration(invocationPlugins, A.class, getReplacements(), bytecodeProvider);
+        r.registerMethodSubstitution(ASubstitutions.class, "invalidConsecutiveForeignCall1", int.class);
+        r.registerMethodSubstitution(ASubstitutions.class, "invalidConsecutiveForeignCall2", int.class);
+        r.registerMethodSubstitution(ASubstitutions.class, "validConsecutiveForeignCallReexecutable", int.class);
+        r.registerMethodSubstitution(ASubstitutions.class, "splitForeignCallInvalid", int.class);
+        super.registerInvocationPlugins(invocationPlugins);
+    }
+
+    private ClassfileBytecodeProvider getSystemClassLoaderBytecodeProvider() {
+        ReplacementsImpl d = (ReplacementsImpl) getReplacements();
+        MetaAccessProvider metaAccess = d.getProviders().getMetaAccess();
+        ClassfileBytecodeProvider bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, d.snippetReflection, ClassLoader.getSystemClassLoader());
+        return bytecodeProvider;
+    }
+
+    public static int SideEffect;
+
+    public static int testDeopt(int value) {
+        SideEffect = value;
+        return value;
+    }
+
+    public static int testNonDeopting(int value) {
+        return value;
+    }
+
+    public static int testPureReexectuable(int value) {
+        return value;
+    }
+
+    public static void testSnippetInvalidSequential() {
+        A.invalidConsecutiveForeignCall1(SideEffect);
+        if (SideEffect == 1) {
+            GraalDirectives.deoptimize();
+        }
+    }
+
+    public static void testNonDeoptingInvalid() {
+        A.invalidConsecutiveForeignCall2(SideEffect);
+        if (SideEffect == 1) {
+            GraalDirectives.deoptimize();
+        }
+    }
+
+    public static void testNonDeoptingSplit() {
+        A.splitForeignCallInvalid(SideEffect);
+        if (SideEffect == 1) {
+            GraalDirectives.deoptimize();
+        }
+    }
+
+    public static void testNonDeoptingReexectuable() {
+        A.validConsecutiveForeignCallReexecutable(SideEffect);
+        if (SideEffect == 1) {
+            GraalDirectives.deoptimize();
+        }
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void test1() {
+        try (AutoCloseable c = new TTY.Filter()) {
+            OptionValues options = new OptionValues(getInitialOptions(), DumpOnError, false);
+            StructuredGraph g = parseEager(getResolvedJavaMethod("testSnippetInvalidSequential"), AllowAssumptions.NO, options);
+            Suites s = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites().getDefaultSuites(getInitialOptions());
+            s.getHighTier().apply(g, getDefaultHighTierContext());
+            s.getMidTier().apply(g, getDefaultMidTierContext());
+            Assert.fail("Compilation should not reach this point, must throw an exception before");
+        } catch (Throwable t) {
+            if ((t.getCause() instanceof GraalError || t instanceof GraalError) && t.getMessage().contains("invalid framestate")) {
+                return;
+            }
+            throw new AssertionError(t);
+        }
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void test2() {
+        try (AutoCloseable c = new TTY.Filter()) {
+            OptionValues options = new OptionValues(getInitialOptions(), DumpOnError, false);
+            StructuredGraph g = parseEager(getResolvedJavaMethod("testSnippetInvalidSequential"), AllowAssumptions.NO, options);
+            Suites s = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites().getDefaultSuites(getInitialOptions());
+            s.getHighTier().apply(g, getDefaultHighTierContext());
+            s.getMidTier().apply(g, getDefaultMidTierContext());
+            Assert.fail("Compilation should not reach this point, must throw an exception before");
+        } catch (Throwable t) {
+            if ((t.getCause() instanceof GraalError || t instanceof GraalError) && t.getMessage().contains("invalid framestate")) {
+                return;
+            }
+            throw new AssertionError(t);
+        }
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void test3() {
+        try (AutoCloseable c = new TTY.Filter()) {
+            OptionValues options = new OptionValues(getInitialOptions(), DumpOnError, false);
+            StructuredGraph g = parseEager(getResolvedJavaMethod("testNonDeoptingSplit"), AllowAssumptions.NO, options);
+            Suites s = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites().getDefaultSuites(getInitialOptions());
+            s.getHighTier().apply(g, getDefaultHighTierContext());
+            s.getMidTier().apply(g, getDefaultMidTierContext());
+            Assert.fail("Compilation should not reach this point, must throw an exception before");
+        } catch (Throwable t) {
+            if ((t.getCause() instanceof GraalError || t instanceof GraalError) && t.getMessage().contains("invalid framestate")) {
+                return;
+            }
+            throw new AssertionError(t);
+        }
+    }
+
+    @Test
+    public void test4() {
+        StructuredGraph g = parseEager(getResolvedJavaMethod("testNonDeoptingReexectuable"), AllowAssumptions.NO);
+        Suites s = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites().getDefaultSuites(getInitialOptions());
+        s.getHighTier().apply(g, getDefaultHighTierContext());
+        s.getMidTier().apply(g, getDefaultMidTierContext());
+    }
+
+}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java
index 9779c6fe707..17470ad59cd 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java
@@ -24,83 +24,117 @@
 
 package org.graalvm.compiler.hotspot.test;
 
+import static org.graalvm.compiler.core.common.GraalOptions.FullUnroll;
+import static org.graalvm.compiler.core.common.GraalOptions.LoopPeeling;
+import static org.graalvm.compiler.core.common.GraalOptions.PartialEscapeAnalysis;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.referentOffset;
 
+import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
+import java.util.EnumSet;
+import java.util.ListIterator;
+import java.util.Objects;
 
 import org.graalvm.compiler.api.test.Graal;
-import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntime.HotSpotGC;
+import org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil;
+import org.graalvm.compiler.nodeinfo.NodeSize;
 import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.gc.G1PostWriteBarrier;
 import org.graalvm.compiler.nodes.gc.G1PreWriteBarrier;
 import org.graalvm.compiler.nodes.gc.G1ReferentFieldReadBarrier;
 import org.graalvm.compiler.nodes.gc.SerialWriteBarrier;
-import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.HeapAccess;
 import org.graalvm.compiler.nodes.memory.ReadNode;
 import org.graalvm.compiler.nodes.memory.WriteNode;
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
-import org.graalvm.compiler.nodes.spi.LoweringTool;
-import org.graalvm.compiler.phases.OptimisticOptimizations;
-import org.graalvm.compiler.phases.common.GuardLoweringPhase;
-import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.Phase;
 import org.graalvm.compiler.phases.common.WriteBarrierAdditionPhase;
-import org.graalvm.compiler.phases.common.inlining.InliningPhase;
-import org.graalvm.compiler.phases.common.inlining.policy.InlineEverythingPolicy;
-import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.phases.tiers.MidTierContext;
+import org.graalvm.compiler.phases.tiers.Suites;
 import org.graalvm.compiler.runtime.RuntimeProvider;
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 
-import jdk.vm.ci.hotspot.HotSpotInstalledCode;
 import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import sun.misc.Unsafe;
+import jdk.vm.ci.meta.MetaAccessProvider;
 
 /**
- * The following unit tests assert the presence of write barriers for both Serial and G1 GCs.
- * Normally, the tests check for compile time inserted barriers. However, there are the cases of
- * unsafe loads of the java.lang.ref.Reference.referent field where runtime checks have to be
- * performed also. For those cases, the unit tests check the presence of the compile-time inserted
- * barriers. Concerning the runtime checks, the results of variable inputs (object types and
- * offsets) passed as input parameters can be checked against printed output from the G1 write
- * barrier snippets. The runtime checks have been validated offline.
+ * The following unit tests assert the presence of write barriers for G1 and for the other GCs that
+ * use a simple card mark barrier, like Serial, CMS, ParallelGC and Pthe arNew/ParOld GCs. Normally,
+ * the tests check for compile time inserted barriers. However, there are the cases of unsafe loads
+ * of the java.lang.ref.Reference.referent field where runtime checks have to be performed also. For
+ * those cases, the unit tests check the presence of the compile-time inserted barriers. Concerning
+ * the runtime checks, the results of variable inputs (object types and offsets) passed as input
+ * parameters can be checked against printed output from the G1 write barrier snippets. The runtime
+ * checks have been validated offline.
  */
 public class WriteBarrierAdditionTest extends HotSpotGraalCompilerTest {
 
+    /**
+     * The set of GCs known at the time of writing of this test. The number of expected barrier
+     * might need to be adjusted for new GCs implementations.
+     */
+    private static EnumSet<HotSpotGC> knownSupport = EnumSet.of(HotSpotGC.G1, HotSpotGC.CMS, HotSpotGC.Parallel, HotSpotGC.Serial);
+
     private final GraalHotSpotVMConfig config = runtime().getVMConfig();
 
     public static class Container {
 
         public Container a;
         public Container b;
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            Container container = (Container) o;
+            return Objects.equals(a, container.a) && Objects.equals(b, container.b);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(a, b);
+        }
     }
 
+    private int expectedBarriers;
+
     /**
-     * Expected 2 barriers for the Serial GC and 4 for G1 (2 pre + 2 post).
+     * Expected 2 barriers for the card mark GCs and 4 for G1 (2 pre + 2 post).
      */
     @Test
-    public void test1() throws Exception {
-        testHelper("test1Snippet", (config.useG1GC) ? 4 : 2);
+    public void testAllocation() throws Exception {
+        this.expectedBarriers = (config.useG1GC) ? 4 : 2;
+        testWithoutPEA("testAllocationSnippet");
     }
 
-    public static void test1Snippet() {
+    public static Container testAllocationSnippet() {
         Container main = new Container();
         Container temp1 = new Container();
         Container temp2 = new Container();
         main.a = temp1;
         main.b = temp2;
+        return main;
     }
 
     /**
-     * Expected 4 barriers for the Serial GC and 8 for G1 (4 pre + 4 post).
+     * Expected 4 barriers for the card mark GCs and 8 for G1 (4 pre + 4 post).
      */
     @Test
-    public void test2() throws Exception {
-        testHelper("test2Snippet", config.useG1GC ? 8 : 4);
+    public void testLoopAllocation1() throws Exception {
+        this.expectedBarriers = config.useG1GC ? 8 : 4;
+        testWithoutPEA("test2Snippet", false);
+        testWithoutPEA("test2Snippet", true);
     }
 
     public static void test2Snippet(boolean test) {
@@ -119,11 +153,12 @@ public class WriteBarrierAdditionTest extends HotSpotGraalCompilerTest {
     }
 
     /**
-     * Expected 4 barriers for the Serial GC and 8 for G1 (4 pre + 4 post).
+     * Expected 4 barriers for the card mark GCs and 8 for G1 (4 pre + 4 post).
      */
     @Test
-    public void test3() throws Exception {
-        testHelper("test3Snippet", config.useG1GC ? 8 : 4);
+    public void testLoopAllocation2() throws Exception {
+        this.expectedBarriers = config.useG1GC ? 8 : 4;
+        testWithoutPEA("test3Snippet");
     }
 
     public static void test3Snippet() {
@@ -140,84 +175,109 @@ public class WriteBarrierAdditionTest extends HotSpotGraalCompilerTest {
     }
 
     /**
-     * Expected 2 barriers for the Serial GC and 5 for G1 (3 pre + 2 post) The (2 or 4) barriers are
-     * emitted while initializing the fields of the WeakReference instance. The extra pre barrier of
-     * G1 concerns the read of the referent field.
+     * Expected 2 barriers for the card mark GCs and 5 for G1 (3 pre + 2 post) The (2 or 4) barriers
+     * are emitted while initializing the fields of the WeakReference instance. The extra pre
+     * barrier of G1 concerns the read of the referent field.
      */
     @Test
-    public void test4() throws Exception {
-        testHelper("test4Snippet", config.useG1GC ? 5 : 2);
+    public void testReferenceGet() throws Exception {
+        this.expectedBarriers = config.useG1GC ? 1 : 0;
+        test("testReferenceGetSnippet");
     }
 
-    public static Object test4Snippet() {
-        WeakReference<Object> weakRef = new WeakReference<>(new Object());
-        return weakRef.get();
+    public static Object testReferenceGetSnippet() {
+        return weakReference.get();
     }
 
-    static WeakReference<Object> wr = new WeakReference<>(new Object());
-    static Container con = new Container();
+    static class DummyReference {
+        Object referent;
+    }
+
+    private static MetaAccessProvider getStaticMetaAccess() {
+        return ((HotSpotBackend) Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend()).getRuntime().getHostProviders().getMetaAccess();
+    }
+
+    private static final WeakReference<?> weakReference = new WeakReference<>(new Object());
+    private static final Object weakReferenceAsObject = new WeakReference<>(new Object());
+    private static final long referenceReferentFieldOffset = HotSpotReplacementsUtil.getFieldOffset(getStaticMetaAccess().lookupJavaType(Reference.class), "referent");
+    private static final long referenceQueueFieldOffset = HotSpotReplacementsUtil.getFieldOffset(getStaticMetaAccess().lookupJavaType(Reference.class), "queue");
+
+    private static final DummyReference dummyReference = new DummyReference();
+    private static final long dummyReferenceReferentFieldOffset = HotSpotReplacementsUtil.getFieldOffset(getStaticMetaAccess().lookupJavaType(DummyReference.class), "referent");
 
     /**
-     * Expected 0 barrier for the Serial GC and 1 for G1. In this test, we load the correct offset
-     * of the WeakReference object so naturally we assert the presence of the pre barrier.
+     * The type is known to be WeakReference and the offset is a constant, so the
+     * {@link org.graalvm.compiler.nodes.extended.RawLoadNode} is converted back into a normal
+     * LoadFieldNode and the lowering of the field node inserts the proper barrier.
      */
     @Test
-    public void test5() throws Exception {
-        testHelper("test5Snippet", config.useG1GC ? 1 : 0);
+    public void testReferenceReferent1() throws Exception {
+        this.expectedBarriers = config.useG1GC ? 1 : 0;
+        test("testReferenceReferentSnippet");
     }
 
-    private static final boolean useCompressedOops = ((HotSpotBackend) Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend()).getRuntime().getVMConfig().useCompressedOops;
-
-    public Object test5Snippet() {
-        return UNSAFE.getObject(wr, useCompressedOops ? 12L : 16L);
+    public Object testReferenceReferentSnippet() {
+        return UNSAFE.getObject(weakReference, referenceReferentFieldOffset);
     }
 
     /**
-     * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
-     * load the java.lang.ref.Reference.referent field so the pre barier has to be executed.
+     * The type is known to be WeakReference and the offset is non-constant, so the lowering of the
+     * {@link org.graalvm.compiler.nodes.extended.RawLoadNode} is guarded by a check that the offset
+     * is the same as {@link #referenceReferentFieldOffset} which does a barrier if requires it.
      */
     @Test
-    public void test6() throws Exception {
-        test2("testUnsafeLoad", UNSAFE, wr, Long.valueOf(referentOffset(getMetaAccess())), null);
+    public void testReferenceReferent2() throws Exception {
+        this.expectedBarriers = config.useG1GC ? 1 : 0;
+        test("testReferenceReferent2Snippet", referenceReferentFieldOffset);
+    }
+
+    public Object testReferenceReferent2Snippet(long offset) {
+        return UNSAFE.getObject(weakReference, offset);
     }
 
     /**
-     * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
-     * load a matching offset of a wrong object so the pre barier must not be executed.
+     * The type is known to be WeakReference and the offset is constant but not the referent field,
+     * so no barrier is required.
      */
     @Test
-    public void test7() throws Exception {
-        test2("testUnsafeLoad", UNSAFE, con, Long.valueOf(referentOffset(getMetaAccess())), null);
+    public void testReferenceReferent3() throws Exception {
+        this.expectedBarriers = 0;
+        test("testReferenceReferent3Snippet");
+    }
+
+    public Object testReferenceReferent3Snippet() {
+        return UNSAFE.getObject(weakReference, referenceQueueFieldOffset);
     }
 
     /**
-     * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
-     * load a non-matching offset field of the java.lang.ref.Reference object so the pre barier must
-     * not be executed.
+     * The type is a super class of WeakReference and the offset is non-constant, so the lowering of
+     * the {@link org.graalvm.compiler.nodes.extended.RawLoadNode} is guarded by a check that the
+     * offset is the same as {@link #referenceReferentFieldOffset} and the base object is a
+     * subclasses of {@link java.lang.ref.Reference} and does a barrier if requires it.
      */
     @Test
-    public void test8() throws Exception {
-        test2("testUnsafeLoad", UNSAFE, wr, Long.valueOf(config.useCompressedOops ? 20 : 32), null);
+    public void testReferenceReferent4() throws Exception {
+        this.expectedBarriers = config.useG1GC ? 1 : 0;
+        test("testReferenceReferent4Snippet");
+    }
+
+    public Object testReferenceReferent4Snippet() {
+        return UNSAFE.getObject(weakReferenceAsObject, referenceReferentFieldOffset);
     }
 
     /**
-     * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
-     * load a matching offset+disp field of the java.lang.ref.Reference object so the pre barier
-     * must be executed.
+     * The type is not related to Reference at all so no barrier check is required. This should be
+     * statically detectable.
      */
     @Test
-    public void test10() throws Exception {
-        test2("testUnsafeLoad", UNSAFE, wr, Long.valueOf(config.useCompressedOops ? 6 : 8), Integer.valueOf(config.useCompressedOops ? 6 : 8));
+    public void testReferenceReferent5() throws Exception {
+        this.expectedBarriers = 0;
+        Assert.assertEquals("expected fields to have the same offset", referenceReferentFieldOffset, dummyReferenceReferentFieldOffset);
+        test("testReferenceReferent5Snippet");
     }
 
-    /**
-     * The following test concerns the runtime checks of the unsafe loads. In this test, we unsafely
-     * load a non-matching offset+disp field of the java.lang.ref.Reference object so the pre barier
-     * must not be executed.
-     */
-    @Test
-    public void test9() throws Exception {
-        test2("testUnsafeLoad", UNSAFE, wr, Long.valueOf(config.useCompressedOops ? 10 : 16), Integer.valueOf(config.useCompressedOops ? 10 : 16));
+    public Object testReferenceReferent5Snippet() {
+        return UNSAFE.getObject(dummyReference, referenceReferentFieldOffset);
     }
 
     static Object[] src = new Object[1];
@@ -232,88 +292,93 @@ public class WriteBarrierAdditionTest extends HotSpotGraalCompilerTest {
         }
     }
 
-    public static void testArrayCopy(Object a, Object b, Object c) throws Exception {
+    public static void testArrayCopySnippet(Object a, Object b, Object c) throws Exception {
         System.arraycopy(a, 0, b, 0, (int) c);
     }
 
     @Test
-    public void test11() throws Exception {
-        test2("testArrayCopy", src, dst, dst.length);
+    public void testArrayCopy() throws Exception {
+        this.expectedBarriers = 0;
+        test("testArrayCopySnippet", src, dst, dst.length);
     }
 
-    public static Object testUnsafeLoad(Unsafe theUnsafe, Object a, Object b, Object c) throws Exception {
-        final int offset = (c == null ? 0 : ((Integer) c).intValue());
-        final long displacement = (b == null ? 0 : ((Long) b).longValue());
-        return theUnsafe.getObject(a, offset + displacement);
-    }
-
-    private HotSpotInstalledCode getInstalledCode(String name, boolean withUnsafePrefix) throws Exception {
-        final ResolvedJavaMethod javaMethod = withUnsafePrefix ? getResolvedJavaMethod(WriteBarrierAdditionTest.class, name, Unsafe.class, Object.class, Object.class, Object.class)
-                        : getResolvedJavaMethod(WriteBarrierAdditionTest.class, name, Object.class, Object.class, Object.class);
-        final HotSpotInstalledCode installedCode = (HotSpotInstalledCode) getCode(javaMethod);
-        return installedCode;
-    }
-
-    @SuppressWarnings("try")
-    private void testHelper(final String snippetName, final int expectedBarriers) throws Exception, SecurityException {
-        ResolvedJavaMethod snippet = getResolvedJavaMethod(snippetName);
-        DebugContext debug = getDebugContext();
-        try (DebugContext.Scope s = debug.scope("WriteBarrierAdditionTest", snippet)) {
-            StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO, debug);
-            HighTierContext highContext = getDefaultHighTierContext();
-            MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
-            new InliningPhase(new InlineEverythingPolicy(), createCanonicalizerPhase()).apply(graph, highContext);
-            this.createCanonicalizerPhase().apply(graph, highContext);
-            new LoweringPhase(this.createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highContext);
-            new GuardLoweringPhase().apply(graph, midContext);
-            new LoweringPhase(this.createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
-            new WriteBarrierAdditionPhase().apply(graph, midContext);
-            debug.dump(DebugContext.BASIC_LEVEL, graph, "After Write Barrier Addition");
-
-            int barriers = 0;
+    private void verifyBarriers(StructuredGraph graph) {
+        Assert.assertTrue("Unknown collector selected", knownSupport.contains(runtime().getGarbageCollector()));
+        Assert.assertNotEquals("test must set expected barrier count", expectedBarriers, -1);
+        int barriers = 0;
+        if (config.useG1GC) {
+            barriers = graph.getNodes().filter(G1ReferentFieldReadBarrier.class).count() + graph.getNodes().filter(G1PreWriteBarrier.class).count() +
+                            graph.getNodes().filter(G1PostWriteBarrier.class).count();
+        } else {
+            barriers = graph.getNodes().filter(SerialWriteBarrier.class).count();
+        }
+        if (expectedBarriers != barriers) {
+            Assert.assertEquals(expectedBarriers, barriers);
+        }
+        for (WriteNode write : graph.getNodes().filter(WriteNode.class)) {
             if (config.useG1GC) {
-                barriers = graph.getNodes().filter(G1ReferentFieldReadBarrier.class).count() + graph.getNodes().filter(G1PreWriteBarrier.class).count() +
-                                graph.getNodes().filter(G1PostWriteBarrier.class).count();
+                if (write.getBarrierType() != HeapAccess.BarrierType.NONE) {
+                    Assert.assertEquals(1, write.successors().count());
+                    Assert.assertTrue(write.next() instanceof G1PostWriteBarrier);
+                    Assert.assertTrue(write.predecessor() instanceof G1PreWriteBarrier || write.getLocationIdentity().isImmutable());
+                }
             } else {
-                barriers = graph.getNodes().filter(SerialWriteBarrier.class).count();
-            }
-            if (expectedBarriers != barriers) {
-                Assert.assertEquals(getScheduledGraphString(graph), expectedBarriers, barriers);
-            }
-            for (WriteNode write : graph.getNodes().filter(WriteNode.class)) {
-                if (config.useG1GC) {
-                    if (write.getBarrierType() != BarrierType.NONE) {
-                        Assert.assertEquals(1, write.successors().count());
-                        Assert.assertTrue(write.next() instanceof G1PostWriteBarrier);
-                        Assert.assertTrue(write.predecessor() instanceof G1PreWriteBarrier);
-                    }
-                } else {
-                    if (write.getBarrierType() != BarrierType.NONE) {
-                        Assert.assertEquals(1, write.successors().count());
-                        Assert.assertTrue(write.next() instanceof SerialWriteBarrier);
-                    }
+                if (write.getBarrierType() != HeapAccess.BarrierType.NONE) {
+                    Assert.assertEquals(1, write.successors().count());
+                    Assert.assertTrue(write.next() instanceof SerialWriteBarrier);
                 }
             }
+        }
 
-            for (ReadNode read : graph.getNodes().filter(ReadNode.class)) {
-                if (read.getBarrierType() != BarrierType.NONE) {
-                    Assert.assertTrue(read.getAddress() instanceof OffsetAddressNode);
+        for (ReadNode read : graph.getNodes().filter(ReadNode.class)) {
+            if (read.getBarrierType() != HeapAccess.BarrierType.NONE) {
+                if (read.getAddress() instanceof OffsetAddressNode) {
                     JavaConstant constDisp = ((OffsetAddressNode) read.getAddress()).getOffset().asJavaConstant();
-                    Assert.assertNotNull(constDisp);
-                    Assert.assertEquals(referentOffset(getMetaAccess()), constDisp.asLong());
-                    Assert.assertEquals(BarrierType.WEAK_FIELD, read.getBarrierType());
-                    if (config.useG1GC) {
-                        Assert.assertTrue(read.next() instanceof G1ReferentFieldReadBarrier);
+                    if (constDisp != null) {
+                        Assert.assertEquals(referentOffset(getMetaAccess()), constDisp.asLong());
                     }
                 }
+                Assert.assertTrue(HeapAccess.BarrierType.WEAK_FIELD == read.getBarrierType() || HeapAccess.BarrierType.MAYBE_WEAK_FIELD == read.getBarrierType());
+                if (config.useG1GC) {
+                    Assert.assertTrue(read.next() instanceof G1ReferentFieldReadBarrier);
+                }
             }
-        } catch (Throwable e) {
-            throw debug.handle(e);
         }
     }
 
-    private void test2(final String snippet, Object... args) throws Exception {
-        HotSpotInstalledCode code = getInstalledCode(snippet, args[0] instanceof Unsafe);
-        code.executeVarargs(args);
+    protected Result testWithoutPEA(String name, Object... args) {
+        return test(new OptionValues(getInitialOptions(), PartialEscapeAnalysis, false, FullUnroll, false, LoopPeeling, false), name, args);
+    }
+
+    @Before
+    public void before() {
+        expectedBarriers = -1;
+    }
+
+    /*
+     * Check the state of the barriers immediately after insertion.
+     */
+    @Override
+    protected Suites createSuites(OptionValues opts) {
+        Suites ret = getBackend().getSuites().getDefaultSuites(opts).copy();
+        ListIterator<BasePhase<? super MidTierContext>> iter = ret.getMidTier().findPhase(WriteBarrierAdditionPhase.class, true);
+        iter.add(new Phase() {
+
+            @Override
+            protected void run(StructuredGraph graph) {
+                verifyBarriers(graph);
+            }
+
+            @Override
+            public float codeSizeIncrease() {
+                return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR;
+            }
+
+            @Override
+            protected CharSequence getName() {
+                return "VerifyBarriersPhase";
+            }
+        });
+        return ret;
     }
 }
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java
index fb8a170f45e..3b0ce94c045 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java
@@ -165,6 +165,7 @@ public class GraalHotSpotVMConfig extends GraalHotSpotVMConfigBase {
     }
 
     public final boolean useG1GC = getFlag("UseG1GC", Boolean.class);
+    public final boolean useCMSGC = getFlag("UseConcMarkSweepGC", Boolean.class, false);
 
     public final int allocatePrefetchStyle = getFlag("AllocatePrefetchStyle", Integer.class);
     public final int allocatePrefetchInstr = getFlag("AllocatePrefetchInstr", Integer.class);
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackendFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackendFactory.java
index cf3cbd532f1..860b4b1d04f 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackendFactory.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackendFactory.java
@@ -39,6 +39,7 @@ import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
 import jdk.vm.ci.hotspot.HotSpotMetaAccessProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
 
 public abstract class HotSpotBackendFactory {
 
@@ -54,8 +55,8 @@ public abstract class HotSpotBackendFactory {
         return new HotSpotStampProvider();
     }
 
-    protected HotSpotGCProvider createGCProvider(GraalHotSpotVMConfig config) {
-        return new HotSpotGCProvider(config);
+    protected HotSpotGCProvider createGCProvider(GraalHotSpotVMConfig config, MetaAccessProvider metaAccess) {
+        return new HotSpotGCProvider(config, metaAccess);
     }
 
     protected HotSpotReplacementsImpl createReplacements(TargetDescription target, Providers p, HotSpotSnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider) {
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java
index a4fc53eae2a..fab3642f58e 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java
@@ -231,7 +231,7 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider {
     public enum HotSpotGC {
         // Supported GCs
         Serial(true, "UseSerialGC"),
-        Parallel(true, "UseParallelGC", "UseParallelOldGC"),
+        Parallel(true, "UseParallelGC", "UseParallelOldGC", "UseParNewGC"),
         CMS(true, "UseConcMarkSweepGC"),
         G1(true, "UseG1GC"),
 
@@ -355,6 +355,7 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider {
         return null;
     }
 
+    @Override
     public HotSpotGC getGarbageCollector() {
         return garbageCollector;
     }
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java
index c814d7b523e..f5c94e2f18f 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -58,6 +58,8 @@ public interface HotSpotGraalRuntimeProvider extends GraalRuntime, RuntimeProvid
         return getClass().getSimpleName();
     }
 
+    HotSpotGraalRuntime.HotSpotGC getGarbageCollector();
+
     @Override
     HotSpotBackend getHostBackend();
 
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReplacementsImpl.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReplacementsImpl.java
index fa003bdbb99..e2ce5078962 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReplacementsImpl.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReplacementsImpl.java
@@ -27,8 +27,8 @@ package org.graalvm.compiler.hotspot;
 import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE;
 import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
 import static org.graalvm.compiler.core.common.GraalOptions.UseEncodedGraphs;
-import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
+import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
 
 import java.util.Set;
 
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SymbolicSnippetEncoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SymbolicSnippetEncoder.java
index 92f9d6ac695..3496c1fb4fa 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SymbolicSnippetEncoder.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SymbolicSnippetEncoder.java
@@ -30,7 +30,7 @@ import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
 import static org.graalvm.compiler.core.common.GraalOptions.UseEncodedGraphs;
 import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.createIntrinsicInlineInfo;
 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
-import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
+import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION_ENCODING;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -306,13 +306,17 @@ public class SymbolicSnippetEncoder {
 
         StructuredGraph getMethodSubstitutionGraph(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, ReplacementsImpl replacements, IntrinsicContext.CompilationContext context,
                         StructuredGraph.AllowAssumptions allowAssumptions, Cancellable cancellable, OptionValues options) {
-            Integer startOffset = snippetStartOffsets.get(plugin.toString() + context);
+            IntrinsicContext.CompilationContext contextToUse = context;
+            if (context == IntrinsicContext.CompilationContext.ROOT_COMPILATION) {
+                contextToUse = IntrinsicContext.CompilationContext.ROOT_COMPILATION_ENCODING;
+            }
+            Integer startOffset = snippetStartOffsets.get(plugin.toString() + contextToUse);
             if (startOffset == null) {
-                throw GraalError.shouldNotReachHere("plugin graph not found: " + plugin + " with " + context);
+                throw GraalError.shouldNotReachHere("plugin graph not found: " + plugin + " with " + contextToUse);
             }
 
             ResolvedJavaType accessingClass = replacements.getProviders().getMetaAccess().lookupJavaType(plugin.getDeclaringClass());
-            return decodeGraph(original, accessingClass, startOffset, replacements, context, allowAssumptions, cancellable, options);
+            return decodeGraph(original, accessingClass, startOffset, replacements, contextToUse, allowAssumptions, cancellable, options);
         }
 
         @SuppressWarnings("try")
@@ -406,8 +410,13 @@ public class SymbolicSnippetEncoder {
         //
         // -J-Dgraal.Dump=SymbolicSnippetEncoder_:2 -J-Dgraal.PrintGraph=File
         // -J-Dgraal.DebugStubsAndSnippets=true
+        IntrinsicContext.CompilationContext contextToUse = context;
+        if (context == IntrinsicContext.CompilationContext.ROOT_COMPILATION) {
+            contextToUse = IntrinsicContext.CompilationContext.ROOT_COMPILATION_ENCODING;
+        }
         try (DebugContext debug = openDebugContext("SymbolicSnippetEncoder_", method, options)) {
-            StructuredGraph graph = snippetReplacements.makeGraph(debug, snippetReplacements.getDefaultReplacementBytecodeProvider(), method, args, original, trackNodeSourcePosition, null, context);
+            StructuredGraph graph = snippetReplacements.makeGraph(debug, snippetReplacements.getDefaultReplacementBytecodeProvider(), method, args, original, trackNodeSourcePosition, null,
+                            contextToUse);
 
             // Check if all methods which should be inlined are really inlined.
             for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.TYPE)) {
@@ -508,7 +517,7 @@ public class SymbolicSnippetEncoder {
                 ResolvedJavaMethod original = plugin.getOriginalMethod(originalReplacements.getProviders().getMetaAccess());
                 registerMethodSubstitution(plugin, original, INLINE_AFTER_PARSING, options);
                 if (!original.isNative()) {
-                    registerMethodSubstitution(plugin, original, ROOT_COMPILATION, options);
+                    registerMethodSubstitution(plugin, original, ROOT_COMPILATION_ENCODING, options);
                 }
             }
             preparedPlugins = plugins.size();
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java
index 2f69d10d8ea..cddc6d85528 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java
@@ -74,6 +74,7 @@ import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
 import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp;
 import org.graalvm.compiler.hotspot.replacements.AssertionSnippets;
 import org.graalvm.compiler.hotspot.replacements.ClassGetHubNode;
+import org.graalvm.compiler.hotspot.replacements.FastNotifyNode;
 import org.graalvm.compiler.hotspot.replacements.HashCodeSnippets;
 import org.graalvm.compiler.hotspot.replacements.HotSpotG1WriteBarrierSnippets;
 import org.graalvm.compiler.hotspot.replacements.HotSpotSerialWriteBarrierSnippets;
@@ -85,8 +86,11 @@ import org.graalvm.compiler.hotspot.replacements.LoadExceptionObjectSnippets;
 import org.graalvm.compiler.hotspot.replacements.MonitorSnippets;
 import org.graalvm.compiler.hotspot.replacements.NewObjectSnippets;
 import org.graalvm.compiler.hotspot.replacements.ObjectCloneSnippets;
+import org.graalvm.compiler.hotspot.replacements.ObjectSnippets;
 import org.graalvm.compiler.hotspot.replacements.StringToBytesSnippets;
+import org.graalvm.compiler.hotspot.replacements.UnsafeCopyMemoryNode;
 import org.graalvm.compiler.hotspot.replacements.UnsafeLoadSnippets;
+import org.graalvm.compiler.hotspot.replacements.UnsafeSnippets;
 import org.graalvm.compiler.hotspot.replacements.aot.ResolveConstantSnippets;
 import org.graalvm.compiler.hotspot.replacements.arraycopy.HotSpotArraycopySnippets;
 import org.graalvm.compiler.hotspot.replacements.profiling.ProfileSnippets;
@@ -107,6 +111,7 @@ import org.graalvm.compiler.nodes.ParameterNode;
 import org.graalvm.compiler.nodes.SafepointNode;
 import org.graalvm.compiler.nodes.StartNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
 import org.graalvm.compiler.nodes.UnwindNode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.AddNode;
@@ -120,14 +125,12 @@ import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode;
 import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
 import org.graalvm.compiler.nodes.extended.GetClassNode;
-import org.graalvm.compiler.nodes.extended.GuardedUnsafeLoadNode;
 import org.graalvm.compiler.nodes.extended.LoadHubNode;
 import org.graalvm.compiler.nodes.extended.LoadMethodNode;
 import org.graalvm.compiler.nodes.extended.OSRLocalNode;
 import org.graalvm.compiler.nodes.extended.OSRLockNode;
 import org.graalvm.compiler.nodes.extended.OSRMonitorEnterNode;
 import org.graalvm.compiler.nodes.extended.OSRStartNode;
-import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.extended.StoreHubNode;
 import org.graalvm.compiler.nodes.gc.G1ArrayRangePostWriteBarrier;
 import org.graalvm.compiler.nodes.gc.G1ArrayRangePreWriteBarrier;
@@ -202,7 +205,8 @@ public abstract class DefaultHotSpotLoweringProvider extends DefaultJavaLowering
     protected HashCodeSnippets.Templates hashCodeSnippets;
     protected ResolveConstantSnippets.Templates resolveConstantSnippets;
     protected ProfileSnippets.Templates profileSnippets;
-
+    protected ObjectSnippets.Templates objectSnippets;
+    protected UnsafeSnippets.Templates unsafeSnippets;
     protected ObjectCloneSnippets.Templates objectCloneSnippets;
     protected ForeignCallSnippets.Templates foreignCallSnippets;
 
@@ -212,6 +216,7 @@ public abstract class DefaultHotSpotLoweringProvider extends DefaultJavaLowering
         this.runtime = runtime;
         this.registers = registers;
         this.constantReflection = constantReflection;
+
     }
 
     @Override
@@ -233,6 +238,8 @@ public abstract class DefaultHotSpotLoweringProvider extends DefaultJavaLowering
         resolveConstantSnippets = new ResolveConstantSnippets.Templates(options, factories, providers, target);
         objectCloneSnippets = new ObjectCloneSnippets.Templates(options, factories, providers, target);
         foreignCallSnippets = new ForeignCallSnippets.Templates(options, factories, providers, target);
+        objectSnippets = new ObjectSnippets.Templates(options, factories, providers, target);
+        unsafeSnippets = new UnsafeSnippets.Templates(options, factories, providers, target);
         if (JavaVersionUtil.JAVA_SPEC <= 8) {
             // AOT only introduced in JDK 9
             profileSnippets = null;
@@ -408,10 +415,19 @@ public abstract class DefaultHotSpotLoweringProvider extends DefaultJavaLowering
                 profileSnippets.lower((ProfileNode) n, tool);
             } else if (n instanceof KlassBeingInitializedCheckNode) {
                 newObjectSnippets.lower((KlassBeingInitializedCheckNode) n, registers, tool);
+            } else if (n instanceof FastNotifyNode) {
+                if (graph.getGuardsStage() == GuardsStage.AFTER_FSA) {
+                    objectSnippets.lower(n, tool);
+                }
+            } else if (n instanceof UnsafeCopyMemoryNode) {
+                if (graph.getGuardsStage() == GuardsStage.AFTER_FSA) {
+                    unsafeSnippets.lower((UnsafeCopyMemoryNode) n, tool);
+                }
             } else {
                 super.lower(n, tool);
             }
         }
+
     }
 
     private static void lowerComputeObjectAddressNode(ComputeObjectAddressNode n) {
@@ -560,16 +576,6 @@ public abstract class DefaultHotSpotLoweringProvider extends DefaultJavaLowering
         return graph.unique(new FloatingReadNode(address, OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION, null, KlassPointerStamp.klassNonNull(), AbstractBeginNode.prevBegin(anchor)));
     }
 
-    @Override
-    protected void lowerUnsafeLoadNode(RawLoadNode load, LoweringTool tool) {
-        StructuredGraph graph = load.graph();
-        if (!(load instanceof GuardedUnsafeLoadNode) && !graph.getGuardsStage().allowsFloatingGuards() && addReadBarrier(load)) {
-            unsafeLoadSnippets.lower(load, tool);
-        } else {
-            super.lowerUnsafeLoadNode(load, tool);
-        }
-    }
-
     private void lowerLoadMethodNode(LoadMethodNode loadMethodNode) {
         StructuredGraph graph = loadMethodNode.graph();
         HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) loadMethodNode.getMethod();
@@ -720,17 +726,6 @@ public abstract class DefaultHotSpotLoweringProvider extends DefaultJavaLowering
         graph.replaceFixedWithFixed(node, foreignCallNode);
     }
 
-    private boolean addReadBarrier(RawLoadNode load) {
-        if (runtime.getVMConfig().useG1GC && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().getStackKind() == JavaKind.Object &&
-                        load.accessKind() == JavaKind.Object && !StampTool.isPointerAlwaysNull(load.object())) {
-            ResolvedJavaType type = StampTool.typeOrNull(load.object());
-            if (type != null && !type.isArray()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     private ReadNode createReadVirtualMethod(StructuredGraph graph, ValueNode hub, HotSpotResolvedJavaMethod method, ResolvedJavaType receiverType) {
         return createReadVirtualMethod(graph, hub, method.vtableEntryOffset(receiverType));
     }
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGCProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGCProvider.java
index f35a3d3eb9c..f0898fd53f7 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGCProvider.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGCProvider.java
@@ -35,11 +35,13 @@ import org.graalvm.compiler.nodes.java.AbstractNewObjectNode;
 import org.graalvm.compiler.nodes.memory.FixedAccessNode;
 import org.graalvm.compiler.nodes.spi.GCProvider;
 
+import jdk.vm.ci.meta.MetaAccessProvider;
+
 public class HotSpotGCProvider implements GCProvider {
     private final BarrierSet barrierSet;
 
-    public HotSpotGCProvider(GraalHotSpotVMConfig config) {
-        this.barrierSet = createBarrierSet(config);
+    public HotSpotGCProvider(GraalHotSpotVMConfig config, MetaAccessProvider metaAccess) {
+        this.barrierSet = createBarrierSet(config, metaAccess);
     }
 
     @Override
@@ -47,10 +49,10 @@ public class HotSpotGCProvider implements GCProvider {
         return barrierSet;
     }
 
-    private BarrierSet createBarrierSet(GraalHotSpotVMConfig config) {
+    private BarrierSet createBarrierSet(GraalHotSpotVMConfig config, MetaAccessProvider metaAccess) {
         boolean useDeferredInitBarriers = config.useDeferredInitBarriers;
         if (config.useG1GC) {
-            return new G1BarrierSet() {
+            return new G1BarrierSet(metaAccess) {
                 @Override
                 protected boolean writeRequiresPostBarrier(FixedAccessNode initializingWrite, ValueNode writtenValue) {
                     if (!super.writeRequiresPostBarrier(initializingWrite, writtenValue)) {
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java
index f674c8dded9..bd08a7e381d 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java
@@ -59,11 +59,11 @@ import org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitution
 import org.graalvm.compiler.hotspot.replacements.ClassGetHubNode;
 import org.graalvm.compiler.hotspot.replacements.CounterModeSubstitutions;
 import org.graalvm.compiler.hotspot.replacements.DigestBaseSubstitutions;
+import org.graalvm.compiler.hotspot.replacements.FastNotifyNode;
 import org.graalvm.compiler.hotspot.replacements.HotSpotArraySubstitutions;
 import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions;
 import org.graalvm.compiler.hotspot.replacements.IdentityHashCodeNode;
 import org.graalvm.compiler.hotspot.replacements.ObjectCloneNode;
-import org.graalvm.compiler.hotspot.replacements.ObjectSubstitutions;
 import org.graalvm.compiler.hotspot.replacements.ReflectionGetCallerClassNode;
 import org.graalvm.compiler.hotspot.replacements.ReflectionSubstitutions;
 import org.graalvm.compiler.hotspot.replacements.SHA2Substitutions;
@@ -194,7 +194,7 @@ public class HotSpotGraphBuilderPlugins {
                 registerCounterModePlugins(invocationPlugins, config, replacements);
                 registerBase64Plugins(invocationPlugins, config, metaAccess, foreignCalls);
                 registerUnsafePlugins(invocationPlugins, config, replacements);
-                StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacements, true, false);
+                StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacements, true, false, true);
                 registerArrayPlugins(invocationPlugins, replacements);
                 registerStringPlugins(invocationPlugins, replacements);
                 registerArraysSupportPlugins(invocationPlugins, config, replacements);
@@ -230,12 +230,48 @@ public class HotSpotGraphBuilderPlugins {
                 }
             });
         }
-        r.registerMethodSubstitution(ObjectSubstitutions.class, "hashCode", Receiver.class);
+        r.register1("hashCode", Receiver.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                ValueNode object = receiver.get();
+                b.addPush(JavaKind.Int, new IdentityHashCodeNode(object));
+                return true;
+            }
+
+            @Override
+            public boolean inlineOnly() {
+                return true;
+            }
+        });
         if (config.inlineNotify()) {
-            r.registerMethodSubstitution(ObjectSubstitutions.class, "notify", Receiver.class);
+            r.register1("notify", Receiver.class, new InvocationPlugin() {
+                @Override
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                    ValueNode object = receiver.get();
+                    b.add(new FastNotifyNode(object, false, b.bci()));
+                    return true;
+                }
+
+                @Override
+                public boolean inlineOnly() {
+                    return true;
+                }
+            });
         }
         if (config.inlineNotifyAll()) {
-            r.registerMethodSubstitution(ObjectSubstitutions.class, "notifyAll", Receiver.class);
+            r.register1("notifyAll", Receiver.class, new InvocationPlugin() {
+                @Override
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                    ValueNode object = receiver.get();
+                    b.add(new FastNotifyNode(object, true, b.bci()));
+                    return true;
+                }
+
+                @Override
+                public boolean inlineOnly() {
+                    return true;
+                }
+            });
         }
     }
 
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotUnsafeSubstitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotUnsafeSubstitutions.java
index 39b6125c779..f82340671ed 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotUnsafeSubstitutions.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotUnsafeSubstitutions.java
@@ -24,18 +24,10 @@
 
 package org.graalvm.compiler.hotspot.meta;
 
-import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.doingUnsafeAccessOffset;
-
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
-import org.graalvm.compiler.hotspot.HotSpotBackend;
-import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode;
-import org.graalvm.compiler.nodes.ComputeObjectAddressNode;
+import org.graalvm.compiler.hotspot.replacements.UnsafeCopyMemoryNode;
 import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
-import org.graalvm.compiler.word.Word;
-import jdk.internal.vm.compiler.word.LocationIdentity;
-import jdk.internal.vm.compiler.word.WordFactory;
 
 @ClassSubstitution(className = {"jdk.internal.misc.Unsafe", "sun.misc.Unsafe"})
 public class HotSpotUnsafeSubstitutions {
@@ -45,27 +37,12 @@ public class HotSpotUnsafeSubstitutions {
     @SuppressWarnings("unused")
     @MethodSubstitution(isStatic = false)
     static void copyMemory(Object receiver, Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes) {
-        Word srcAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(srcBase, srcOffset));
-        Word dstAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(destBase, destOffset));
-        Word size = WordFactory.signed(bytes);
-
-        HotSpotBackend.unsafeArraycopy(srcAddr, dstAddr, size);
+        UnsafeCopyMemoryNode.copyMemory(false, receiver, srcBase, srcOffset, destBase, destOffset, bytes);
     }
 
     @SuppressWarnings("unused")
     @MethodSubstitution(value = "copyMemory", isStatic = false)
     static void copyMemoryGuarded(Object receiver, Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes) {
-        Word srcAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(srcBase, srcOffset));
-        Word dstAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(destBase, destOffset));
-        Word size = WordFactory.signed(bytes);
-        Word javaThread = CurrentJavaThreadNode.get();
-        int offset = doingUnsafeAccessOffset(INJECTED_VMCONFIG);
-        LocationIdentity any = LocationIdentity.any();
-
-        /* Set doingUnsafeAccess to guard and handle unsafe memory access failures */
-        javaThread.writeByte(offset, (byte) 1, any);
-        HotSpotBackend.unsafeArraycopy(srcAddr, dstAddr, size);
-        /* Reset doingUnsafeAccess */
-        javaThread.writeByte(offset, (byte) 0, any);
+        UnsafeCopyMemoryNode.copyMemory(true, receiver, srcBase, srcOffset, destBase, destOffset, bytes);
     }
 }
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/FastNotifyNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/FastNotifyNode.java
new file mode 100644
index 00000000000..db9b4545726
--- /dev/null
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/FastNotifyNode.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019, 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.replacements;
+
+import static org.graalvm.compiler.nodeinfo.InputType.State;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import jdk.internal.vm.compiler.word.LocationIdentity;
+
+@NodeInfo(cycles = CYCLES_2, size = SIZE_0)
+public class FastNotifyNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single, DeoptimizingNode.DeoptDuring {
+
+    public static final NodeClass<FastNotifyNode> TYPE = NodeClass.create(FastNotifyNode.class);
+    private final boolean notifyAll;
+
+    private final int bci;
+
+    @Input ValueNode object;
+
+    @OptionalInput(State) FrameState stateDuring;
+
+    public FastNotifyNode(ValueNode object, boolean notifyAll, int bci) {
+        super(TYPE, StampFactory.forVoid());
+        this.object = object;
+        this.notifyAll = notifyAll;
+        this.bci = bci;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    public boolean isNotifyAll() {
+        return notifyAll;
+    }
+
+    @Override
+    public LocationIdentity getKilledLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    @Override
+    public FrameState stateDuring() {
+        return stateDuring;
+    }
+
+    @Override
+    public void setStateDuring(FrameState stateDuring) {
+        updateUsages(this.stateDuring, stateDuring);
+        this.stateDuring = stateDuring;
+    }
+
+    @Override
+    public void computeStateDuring(FrameState currentStateAfter) {
+        FrameState newStateDuring = currentStateAfter.duplicateModifiedDuringCall(bci, asNode().getStackKind());
+        setStateDuring(newStateDuring);
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    public int getBci() {
+        return bci;
+    }
+}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotG1WriteBarrierSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotG1WriteBarrierSnippets.java
index 9a2b9d913ed..ec37dcedef9 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotG1WriteBarrierSnippets.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotG1WriteBarrierSnippets.java
@@ -56,6 +56,7 @@ import jdk.internal.vm.compiler.word.WordFactory;
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaType;
 
 public final class HotSpotG1WriteBarrierSnippets extends G1WriteBarrierSnippets {
     public static final ForeignCallDescriptor G1WBPRECALL = new ForeignCallDescriptor("write_barrier_pre", void.class, Object.class);
@@ -175,6 +176,16 @@ public final class HotSpotG1WriteBarrierSnippets extends G1WriteBarrierSnippets
         return Log.LOG_PRINTF;
     }
 
+    @Override
+    protected ResolvedJavaType referenceType() {
+        return HotSpotReplacementsUtil.referenceType(INJECTED_METAACCESS);
+    }
+
+    @Override
+    protected long referentOffset() {
+        return HotSpotReplacementsUtil.referentOffset(INJECTED_METAACCESS);
+    }
+
     public static class Templates extends AbstractTemplates {
         private final SnippetInfo g1PreWriteBarrier;
         private final SnippetInfo g1ReferentReadBarrier;
@@ -191,7 +202,9 @@ public final class HotSpotG1WriteBarrierSnippets extends G1WriteBarrierSnippets
             HotSpotG1WriteBarrierSnippets receiver = new HotSpotG1WriteBarrierSnippets(config, providers.getRegisters());
             g1PreWriteBarrier = snippet(G1WriteBarrierSnippets.class, "g1PreWriteBarrier", null, receiver, GC_INDEX_LOCATION, GC_LOG_LOCATION, SATB_QUEUE_MARKING_LOCATION, SATB_QUEUE_INDEX_LOCATION,
                             SATB_QUEUE_BUFFER_LOCATION);
-            g1ReferentReadBarrier = g1PreWriteBarrier;
+            g1ReferentReadBarrier = snippet(G1WriteBarrierSnippets.class, "g1ReferentReadBarrier", null, receiver, GC_INDEX_LOCATION, GC_LOG_LOCATION, SATB_QUEUE_MARKING_LOCATION,
+                            SATB_QUEUE_INDEX_LOCATION,
+                            SATB_QUEUE_BUFFER_LOCATION);
             g1PostWriteBarrier = snippet(G1WriteBarrierSnippets.class, "g1PostWriteBarrier", null, receiver, GC_CARD_LOCATION, GC_INDEX_LOCATION, GC_LOG_LOCATION, CARD_QUEUE_INDEX_LOCATION,
                             CARD_QUEUE_BUFFER_LOCATION);
             g1ArrayRangePreWriteBarrier = snippet(G1WriteBarrierSnippets.class, "g1ArrayRangePreWriteBarrier", null, receiver, GC_INDEX_LOCATION, GC_LOG_LOCATION, SATB_QUEUE_MARKING_LOCATION,
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java
index c25cadc5cb3..e13328cbac1 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java
@@ -155,7 +155,7 @@ public class HotSpotReplacementsUtil {
     }
 
     @Fold
-    static int getFieldOffset(ResolvedJavaType type, String fieldName) {
+    public static int getFieldOffset(ResolvedJavaType type, String fieldName) {
         for (ResolvedJavaField field : type.getInstanceFields(true)) {
             if (field.getName().equals(fieldName)) {
                 return field.getOffset();
@@ -889,6 +889,11 @@ public class HotSpotReplacementsUtil {
         return getFieldOffset(metaAccessProvider.lookupJavaType(Reference.class), "referent");
     }
 
+    @Fold
+    public static ResolvedJavaType referenceType(@InjectedParameter MetaAccessProvider metaAccessProvider) {
+        return metaAccessProvider.lookupJavaType(Reference.class);
+    }
+
     public static final LocationIdentity OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION = new HotSpotOptimizingLocationIdentity("ObjArrayKlass::_element_klass") {
         @Override
         public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectSnippets.java
new file mode 100644
index 00000000000..be611c9efc6
--- /dev/null
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectSnippets.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2019, 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.replacements;
+
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+
+import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap;
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.debug.DebugHandlersFactory;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.SnippetAnchorNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class ObjectSnippets implements Snippets {
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native boolean fastNotifyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object o);
+
+    @Snippet
+    public static void fastNotify(Object thisObj) {
+        if (fastNotifyStub(HotSpotHostForeignCallsProvider.NOTIFY, thisObj)) {
+            return;
+        } else {
+            PiNode.piCastNonNull(thisObj, SnippetAnchorNode.anchor()).notify();
+        }
+    }
+
+    @Snippet
+    public static void fastNotifyAll(Object thisObj) {
+        if (fastNotifyStub(HotSpotHostForeignCallsProvider.NOTIFY_ALL, thisObj)) {
+            return;
+        } else {
+            PiNode.piCastNonNull(thisObj, SnippetAnchorNode.anchor()).notifyAll();
+        }
+    }
+
+    public static class Templates extends AbstractTemplates {
+        private final SnippetInfo notifySnippet = snippet(ObjectSnippets.class, "fastNotify", originalNotifyCall(false), null);
+        private final SnippetInfo notifyAllSnippet = snippet(ObjectSnippets.class, "fastNotifyAll", originalNotifyCall(true), null);
+
+        public Templates(OptionValues options, Iterable<DebugHandlersFactory> factories, HotSpotProviders providers, TargetDescription target) {
+            super(options, factories, providers, providers.getSnippetReflection(), target);
+        }
+
+        private ResolvedJavaMethod originalNotifyCall(boolean notifyAll) throws GraalError {
+            if (notifyAll) {
+                return findMethod(providers.getMetaAccess(), Object.class, "notifyAll");
+            } else {
+                return findMethod(providers.getMetaAccess(), Object.class, "notify");
+            }
+        }
+
+        public void lower(Node n, LoweringTool tool) {
+            if (n instanceof FastNotifyNode) {
+                FastNotifyNode fn = (FastNotifyNode) n;
+                StructuredGraph graph = (StructuredGraph) n.graph();
+                FrameState stateDuringCall = fn.stateDuring();
+                assert stateDuringCall != null : "Must have valid state for snippet recursive notify call";
+                Arguments args = new Arguments(fn.isNotifyAll() ? notifyAllSnippet : notifySnippet, graph.getGuardsStage(), tool.getLoweringStage());
+                args.add("thisObj", fn.object);
+                SnippetTemplate template = template(fn, args);
+                graph.getDebug().log("Lowering fast notify in %s: node=%s, template=%s, arguments=%s", graph, fn, template, args);
+                UnmodifiableEconomicMap<Node, Node> replacements = template.instantiate(providers.getMetaAccess(), fn, DEFAULT_REPLACER, args);
+                for (Node originalNode : replacements.getKeys()) {
+                    if (originalNode instanceof InvokeNode) {
+                        InvokeNode invoke = (InvokeNode) replacements.get(originalNode);
+                        assert invoke.asNode().graph() == graph;
+                        // Here we need to fix the bci of the invoke
+                        invoke.replaceBci(fn.getBci());
+                        invoke.setStateDuring(null);
+                        invoke.setStateAfter(null);
+                        invoke.setStateDuring(stateDuringCall);
+                    } else if (originalNode instanceof InvokeWithExceptionNode) {
+                        throw new GraalError("unexpected invoke with exception %s in snippet", originalNode);
+                    }
+                }
+            } else {
+                GraalError.shouldNotReachHere("Unknown object snippet lowered node");
+            }
+        }
+
+    }
+}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectSubstitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectSubstitutions.java
deleted file mode 100644
index d79a9392904..00000000000
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectSubstitutions.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2012, 2018, 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.replacements;
-
-import org.graalvm.compiler.api.replacements.ClassSubstitution;
-import org.graalvm.compiler.api.replacements.MethodSubstitution;
-import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
-import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
-import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
-import org.graalvm.compiler.graph.Node.NodeIntrinsic;
-import org.graalvm.compiler.nodes.extended.ForeignCallNode;
-
-// JaCoCo Exclude
-
-/**
- * Substitutions for {@link java.lang.Object} methods.
- */
-@ClassSubstitution(Object.class)
-public class ObjectSubstitutions {
-
-    @MethodSubstitution(isStatic = false)
-    public static int hashCode(final Object thisObj) {
-        return IdentityHashCodeNode.identityHashCode(thisObj);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void notify(final Object thisObj) {
-        if (!fastNotifyStub(HotSpotHostForeignCallsProvider.NOTIFY, thisObj)) {
-            notify(thisObj);
-        }
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void notifyAll(final Object thisObj) {
-        if (!fastNotifyStub(HotSpotHostForeignCallsProvider.NOTIFY_ALL, thisObj)) {
-            notifyAll(thisObj);
-        }
-    }
-
-    @NodeIntrinsic(ForeignCallNode.class)
-    public static native boolean fastNotifyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object o);
-}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeCopyMemoryNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeCopyMemoryNode.java
new file mode 100644
index 00000000000..cc02cc3a10d
--- /dev/null
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeCopyMemoryNode.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2019, 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.replacements;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractStateSplit;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValueNodeUtil;
+import org.graalvm.compiler.nodes.memory.MemoryAccess;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import jdk.internal.vm.compiler.word.LocationIdentity;
+
+@NodeInfo(cycles = CYCLES_64, size = SIZE_16, allowedUsageTypes = {Memory})
+public class UnsafeCopyMemoryNode extends AbstractStateSplit implements Lowerable, MemoryCheckpoint.Single, MemoryAccess {
+
+    public static final NodeClass<UnsafeCopyMemoryNode> TYPE = NodeClass.create(UnsafeCopyMemoryNode.class);
+
+    @Input ValueNode receiver;
+    @Input ValueNode srcBase;
+    @Input ValueNode srcOffset;
+    @Input ValueNode destBase;
+    @Input ValueNode desOffset;
+    @Input ValueNode bytes;
+
+    @OptionalInput(Memory) Node lastLocationAccess;
+
+    private final boolean guarded;
+
+    public UnsafeCopyMemoryNode(boolean guarded, ValueNode receiver, ValueNode srcBase, ValueNode srcOffset, ValueNode destBase, ValueNode desOffset,
+                    ValueNode bytes) {
+        super(TYPE, StampFactory.forVoid());
+        this.guarded = guarded;
+        this.receiver = receiver;
+        this.srcBase = srcBase;
+        this.srcOffset = srcOffset;
+        this.destBase = destBase;
+        this.desOffset = desOffset;
+        this.bytes = bytes;
+    }
+
+    public boolean isGuarded() {
+        return guarded;
+    }
+
+    @Override
+    public LocationIdentity getKilledLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return getKilledLocationIdentity();
+    }
+
+    @Override
+    public MemoryNode getLastLocationAccess() {
+        return (MemoryNode) lastLocationAccess;
+    }
+
+    @Override
+    public void setLastLocationAccess(MemoryNode lla) {
+        Node newLla = ValueNodeUtil.asNode(lla);
+        updateUsages(lastLocationAccess, newLla);
+        lastLocationAccess = newLla;
+    }
+
+    @NodeIntrinsic
+    public static native void copyMemory(@ConstantNodeParameter boolean guarded, Object receiver, Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes);
+}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeSnippets.java
new file mode 100644
index 00000000000..542e035e47d
--- /dev/null
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeSnippets.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2019, 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.replacements;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.doingUnsafeAccessOffset;
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.debug.DebugHandlersFactory;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode;
+import org.graalvm.compiler.nodes.ComputeObjectAddressNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
+import org.graalvm.compiler.word.Word;
+import jdk.internal.vm.compiler.word.LocationIdentity;
+import jdk.internal.vm.compiler.word.WordFactory;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public class UnsafeSnippets implements Snippets {
+
+    public static final String copyMemoryName = JavaVersionUtil.JAVA_SPEC <= 8 ? "copyMemory" : "copyMemory0";
+
+    @SuppressWarnings("unused")
+    @Snippet
+    static void copyMemory(Object receiver, Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes) {
+        Word srcAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(srcBase, srcOffset));
+        Word dstAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(destBase, destOffset));
+        Word size = WordFactory.signed(bytes);
+
+        HotSpotBackend.unsafeArraycopy(srcAddr, dstAddr, size);
+    }
+
+    @SuppressWarnings("unused")
+    @Snippet
+    static void copyMemoryGuarded(Object receiver, Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes) {
+        Word srcAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(srcBase, srcOffset));
+        Word dstAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(destBase, destOffset));
+        Word size = WordFactory.signed(bytes);
+        Word javaThread = CurrentJavaThreadNode.get();
+        int offset = doingUnsafeAccessOffset(INJECTED_VMCONFIG);
+        LocationIdentity any = LocationIdentity.any();
+
+        /* Set doingUnsafeAccess to guard and handle unsafe memory access failures */
+        javaThread.writeByte(offset, (byte) 1, any);
+        HotSpotBackend.unsafeArraycopy(srcAddr, dstAddr, size);
+        /* Reset doingUnsafeAccess */
+        javaThread.writeByte(offset, (byte) 0, any);
+    }
+
+    public static class Templates extends AbstractTemplates {
+        private final SnippetInfo copyMemory = snippet(UnsafeSnippets.class, "copyMemory");
+        private final SnippetInfo copyMemoryGuarded = snippet(UnsafeSnippets.class, "copyMemoryGuarded");
+
+        public Templates(OptionValues options, Iterable<DebugHandlersFactory> factories, HotSpotProviders providers, TargetDescription target) {
+            super(options, factories, providers, providers.getSnippetReflection(), target);
+        }
+
+        public void lower(UnsafeCopyMemoryNode copyMemoryNode, LoweringTool tool) {
+            StructuredGraph graph = copyMemoryNode.graph();
+            Arguments args = new Arguments(copyMemoryNode.isGuarded() ? copyMemoryGuarded : copyMemory, graph.getGuardsStage(), tool.getLoweringStage());
+            args.add("receiver", copyMemoryNode.receiver);
+            args.add("srcBase", copyMemoryNode.srcBase);
+            args.add("srcOffset", copyMemoryNode.srcOffset);
+            args.add("destBase", copyMemoryNode.destBase);
+            args.add("destOffset", copyMemoryNode.desOffset);
+            args.add("bytes", copyMemoryNode.bytes);
+            SnippetTemplate template = template(copyMemoryNode, args);
+            template.instantiate(providers.getMetaAccess(), copyMemoryNode, DEFAULT_REPLACER, args);
+        }
+    }
+}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java
index c9766b68c58..82a3e09ad32 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java
@@ -1079,7 +1079,7 @@ public final class BciBlockMapping {
                 BciBlock successor = block.getSuccessor(i);
                 JsrScope nextScope = scope;
                 if (successor == block.getJsrSuccessor()) {
-                    nextScope = scope.push(block.getJsrReturnBci());
+                    nextScope = scope.push(block.getJsrReturnBci(), successor);
                 }
                 if (successor == block.getRetSuccessor()) {
                     nextScope = scope.pop();
@@ -1109,12 +1109,25 @@ public final class BciBlockMapping {
             }
         }
         for (BciBlock successor : block.getSuccessors()) {
-            if (!jsrVisited.contains(successor)) {
+            if (!jsrVisited.contains(successor) && shouldFollowEdge(successor, scope)) {
                 createJsrAlternatives(blockMap, successor);
             }
         }
     }
 
+    private static boolean shouldFollowEdge(BciBlock successor, JsrScope scope) {
+        if (successor instanceof ExceptionDispatchBlock && scope.getJsrEntryBlock() != null) {
+            ExceptionDispatchBlock exceptionDispatchBlock = (ExceptionDispatchBlock) successor;
+            int bci = scope.getJsrEntryBlock().startBci;
+            if (exceptionDispatchBlock.handler.getStartBCI() < bci && bci < exceptionDispatchBlock.handler.getEndBCI()) {
+                // Handler covers start of JSR block and the bci before that => don't follow edge.
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     private ExceptionDispatchBlock handleExceptions(BciBlock[] blockMap, int bci) {
         ExceptionDispatchBlock lastHandler = null;
         int dispatchBlocks = 0;
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java
index fca890348da..40643c70b86 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java
@@ -32,7 +32,6 @@ import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateRecompile;
 import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
 import static jdk.vm.ci.meta.DeoptimizationAction.None;
 import static jdk.vm.ci.meta.DeoptimizationReason.ClassCastException;
-import static jdk.vm.ci.meta.DeoptimizationReason.JavaSubroutineMismatch;
 import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
 import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint;
 import static jdk.vm.ci.meta.DeoptimizationReason.UnreachedCode;
@@ -684,6 +683,114 @@ public class BytecodeParser implements GraphBuilderContext {
                 // Restore the original return value
                 parser.frameState.push(returnKind, returnValue);
             }
+            boolean inlinedIntrinsic = parser.getInvokeReturnType() != null;
+            if (inlinedIntrinsic) {
+                for (Node n : parser.graph.getNewNodes(mark)) {
+                    if (n instanceof FrameState) {
+                        GraalError.guarantee(((FrameState) n).bci != BytecodeFrame.INVALID_FRAMESTATE_BCI,
+                                        "Inlined call to intrinsic (callee %s) produced invalid framestate %s. " +
+                                                        "Such framestates must never be used as deoptimizing targets, thus they cannot be part of a high-tier graph, " +
+                                                        "and must only be used after framestate assignment. A common error is invalid usage of foreign call nodes in method " +
+                                                        "substitutions, which can be avoided by ensuring such calls are either replaced with nodes that are snippet " +
+                                                        "lowered after framestate assignment (see FastNotifyNode.java for example) or by ensuring all foreign use the state after of the " +
+                                                        "original call instruction.",
+                                        callee, n);
+                    }
+                }
+            } else {
+
+                /*
+                 * Special case root compiled method substitutions
+                 *
+                 * Root compiled intrinsics with self recursive calls (partial intrinsic exit) must
+                 * never produce more than one state except the start framestate since we do not
+                 * compile calls to the original method (or inline them) but deopt
+                 *
+                 * See ByteCodeParser::inline and search for compilationRoot
+                 */
+                assert intrinsic == null || intrinsic.isIntrinsicEncoding() || verifyIntrinsicRootCompileEffects();
+            }
+        }
+
+        private boolean verifyIntrinsicRootCompileEffects() {
+            int invalidBCIsInRootCompiledIntrinsic = 0;
+            for (Node n : parser.graph.getNewNodes(mark)) {
+                if (n instanceof FrameState) {
+                    if (((FrameState) n).bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
+                        invalidBCIsInRootCompiledIntrinsic++;
+                    }
+                }
+            }
+            if (invalidBCIsInRootCompiledIntrinsic > 1) {
+                int invalidBCIsToFind = invalidBCIsInRootCompiledIntrinsic;
+                List<ReturnNode> returns = parser.getGraph().getNodes(ReturnNode.TYPE).snapshot();
+                if (returns.size() > 1) {
+                    outer: for (ReturnNode ret : returns) {
+                        for (FixedNode f : GraphUtil.predecessorIterable(ret)) {
+                            if (f instanceof StateSplit) {
+                                StateSplit split = (StateSplit) f;
+                                if (split.hasSideEffect()) {
+                                    assert ((StateSplit) f).stateAfter() != null;
+                                    if (split.stateAfter().bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
+                                        invalidBCIsToFind--;
+                                        continue outer;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    GraalError.guarantee(invalidBCIsToFind == 0, "Root compiled intrinsic with invalid states has more than one return. " +
+                                    "This is allowed, however one path down a sink has more than one state, this is prohibited. " +
+                                    "Intrinsic %s", parser.method);
+                    return true;
+                }
+                ReturnNode ret = returns.get(0);
+                MergeNode merge = null;
+                int mergeCount = parser.graph.getNodes(MergeNode.TYPE).count();
+                if (mergeCount != 1) {
+                    throw new GraalError("Root compiled intrinsic with invalid states %s:Must have exactly one merge node. %d found", parser.method, mergeCount);
+                }
+                if (ret.predecessor() instanceof MergeNode) {
+                    merge = (MergeNode) ret.predecessor();
+                }
+                if (merge == null) {
+                    throw new GraalError("Root compiled intrinsic with invalid state: Unexpected node between return and merge.");
+                }
+                //@formatter:off
+                GraalError.guarantee(invalidBCIsInRootCompiledIntrinsic <= merge.phiPredecessorCount() + 1 /* merge itself */,
+                                "Root compiled intrinsic with invalid states %s must at maximum produce (0,1 or if the last instruction is a merge |merge.predCount|" +
+                                                " invalid BCI state, however %d where found.",
+                                parser.method, invalidBCIsInRootCompiledIntrinsic);
+                //@formatter:on
+                if (merge.stateAfter() != null && merge.stateAfter().bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
+                    invalidBCIsToFind--;
+                }
+                for (EndNode pred : merge.cfgPredecessors()) {
+                    Node lastPred = pred.predecessor();
+                    for (FixedNode f : GraphUtil.predecessorIterable((FixedNode) lastPred)) {
+                        if (f instanceof StateSplit) {
+                            StateSplit split = (StateSplit) f;
+                            if (split.hasSideEffect()) {
+                                assert ((StateSplit) f).stateAfter() != null;
+                                if (split.stateAfter().bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
+                                    invalidBCIsToFind--;
+                                }
+                            }
+                        }
+                    }
+                }
+                if (invalidBCIsToFind != 0) {
+                    throw new GraalError(
+                                    "Invalid BCI state missmatch: This root compiled method substitution %s " +
+                                                    "uses invalid side-effecting nodes resulting in invalid deoptimization information. " +
+                                                    "Method substitutions must never have more than one state (the after state) for deoptimization." +
+                                                    " Multiple states are only allowed if they are dominated by a control-flow split, there is only" +
+                                                    " a single effect per branch and a post dominating merge with the same invalid_bci state " +
+                                                    "(that must only be different in its return value).",
+                                    parser.method);
+                }
+            }
+            return true;
         }
 
         private void updateSplitFrameState(StateSplit split, JavaKind returnKind, ValueNode returnValue) {
@@ -1820,7 +1927,6 @@ public class BytecodeParser implements GraphBuilderContext {
         } finally {
             currentInvoke = null;
         }
-
         int invokeBci = bci();
         JavaTypeProfile profile = getProfileForInvoke(invokeKind);
         ExceptionEdgeAction edgeAction = getActionForInvokeExceptionEdge(inlineInfo);
@@ -2738,8 +2844,9 @@ public class BytecodeParser implements GraphBuilderContext {
         int retAddress = scope.nextReturnAddress();
         ConstantNode returnBciNode = getJsrConstant(retAddress);
         LogicNode guard = IntegerEqualsNode.create(getConstantReflection(), getMetaAccess(), options, null, local, returnBciNode, NodeView.DEFAULT);
-        guard = graph.addOrUniqueWithInputs(guard);
-        append(new FixedGuardNode(guard, JavaSubroutineMismatch, InvalidateReprofile));
+        if (!guard.isTautology()) {
+            throw new JsrNotSupportedBailout("cannot statically decide jsr return address " + local);
+        }
         if (!successor.getJsrScope().equals(scope.pop())) {
             throw new JsrNotSupportedBailout("unstructured control flow (ret leaves more than one scope)");
         }
@@ -3436,7 +3543,6 @@ public class BytecodeParser implements GraphBuilderContext {
             probability = getProfileProbability(canonicalizedCondition.mustNegate());
         }
 
-        probability = clampProbability(probability);
         genIf(condition, trueSuccessor, falseSuccessor, probability);
     }
 
@@ -3458,10 +3564,10 @@ public class BytecodeParser implements GraphBuilderContext {
             // the probability coming from profile is about the original condition
             probability = 1 - probability;
         }
-        return probability;
+        return clampProbability(probability);
     }
 
-    private static double extractInjectedProbability(IntegerEqualsNode condition) {
+    private double extractInjectedProbability(IntegerEqualsNode condition) {
         // Propagate injected branch probability if any.
         IntegerEqualsNode equalsNode = condition;
         BranchProbabilityNode probabilityNode = null;
@@ -3475,7 +3581,7 @@ public class BytecodeParser implements GraphBuilderContext {
         }
 
         if (probabilityNode != null && probabilityNode.getProbability().isConstant() && other != null && other.isConstant()) {
-            double probabilityValue = probabilityNode.getProbability().asJavaConstant().asDouble();
+            double probabilityValue = clampProbability(probabilityNode.getProbability().asJavaConstant().asDouble());
             return other.asJavaConstant().asInt() == 0 ? 1.0 - probabilityValue : probabilityValue;
         }
         return -1;
@@ -4166,11 +4272,15 @@ public class BytecodeParser implements GraphBuilderContext {
 
     private JavaMethod lookupMethod(int cpi, int opcode) {
         maybeEagerlyResolve(cpi, opcode);
-        JavaMethod result = constantPool.lookupMethod(cpi, opcode);
+        JavaMethod result = lookupMethodInPool(cpi, opcode);
         assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaMethod : unresolvedMethodAssertionMessage(result);
         return result;
     }
 
+    protected JavaMethod lookupMethodInPool(int cpi, int opcode) {
+        return constantPool.lookupMethod(cpi, opcode);
+    }
+
     protected JavaField lookupField(int cpi, int opcode) {
         maybeEagerlyResolve(cpi, opcode);
         JavaField result = constantPool.lookupField(cpi, method, opcode);
@@ -4319,6 +4429,7 @@ public class BytecodeParser implements GraphBuilderContext {
         }
     }
 
+    @SuppressWarnings("try")
     protected void genInstanceOf(ResolvedJavaType resolvedType, ValueNode objectIn) {
         ValueNode object = objectIn;
         TypeReference checkedType = TypeReference.createTrusted(graph.getAssumptions(), resolvedType);
@@ -4353,18 +4464,20 @@ public class BytecodeParser implements GraphBuilderContext {
         int value = getStream().readUByte(next);
         if (next <= currentBlock.endBci && (value == Bytecodes.IFEQ || value == Bytecodes.IFNE)) {
             getStream().next();
-            BciBlock firstSucc = currentBlock.getSuccessor(0);
-            BciBlock secondSucc = currentBlock.getSuccessor(1);
-            if (firstSucc != secondSucc) {
-                boolean negate = value != Bytecodes.IFNE;
-                if (negate) {
-                    BciBlock tmp = firstSucc;
-                    firstSucc = secondSucc;
-                    secondSucc = tmp;
+            try (DebugCloseable context = openNodeContext()) {
+                BciBlock firstSucc = currentBlock.getSuccessor(0);
+                BciBlock secondSucc = currentBlock.getSuccessor(1);
+                if (firstSucc != secondSucc) {
+                    boolean negate = value != Bytecodes.IFNE;
+                    if (negate) {
+                        BciBlock tmp = firstSucc;
+                        firstSucc = secondSucc;
+                        secondSucc = tmp;
+                    }
+                    genIf(instanceOfNode, firstSucc, secondSucc, getProfileProbability(negate));
+                } else {
+                    appendGoto(firstSucc);
                 }
-                genIf(instanceOfNode, firstSucc, secondSucc, getProfileProbability(negate));
-            } else {
-                appendGoto(firstSucc);
             }
         } else {
             // Most frequent for value is IRETURN, followed by ISTORE.
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/JsrScope.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/JsrScope.java
index f7ae4485907..e65fda92e8f 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/JsrScope.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/JsrScope.java
@@ -25,6 +25,7 @@
 package org.graalvm.compiler.java;
 
 import org.graalvm.compiler.bytecode.Bytecodes;
+import org.graalvm.compiler.java.BciBlockMapping.BciBlock;
 
 /**
  * Represents a subroutine entered via {@link Bytecodes#JSR} and exited via {@link Bytecodes#RET}.
@@ -40,34 +41,46 @@ public final class JsrScope {
 
     private final JsrScope parent;
 
-    private JsrScope(int returnBci, JsrScope parent) {
+    private final BciBlock jsrEntryBlock;
+
+    private JsrScope(int returnBci, BciBlock jsrEntryBlock, JsrScope parent) {
         this.returnAddress = (char) returnBci;
         this.parent = parent;
+        this.jsrEntryBlock = jsrEntryBlock;
     }
 
     private JsrScope() {
         this.returnAddress = 0;
         this.parent = null;
+        this.jsrEntryBlock = null;
     }
 
     public int nextReturnAddress() {
         return returnAddress;
     }
 
+    public BciBlock getJsrEntryBlock() {
+        return jsrEntryBlock;
+    }
+
     /**
      * Enters a new subroutine from the current scope represented by this object.
      *
      * @param returnBci the bytecode address returned to when leaving the new scope
      * @return an object representing the newly entered scope
      */
-    public JsrScope push(int returnBci) {
+    public JsrScope push(int returnBci, BciBlock newJsrEntryBlock) {
         if (returnBci == 0) {
             throw new IllegalArgumentException("A bytecode subroutine cannot have a return address of 0");
         }
         if (returnBci < 1 || returnBci > 0xFFFF) {
             throw new IllegalArgumentException("Bytecode subroutine return address cannot be encoded as a char: " + returnBci);
         }
-        return new JsrScope(returnBci, this);
+        return new JsrScope(returnBci, newJsrEntryBlock, this);
+    }
+
+    public JsrScope push(int returnBci) {
+        return push(returnBci, null);
     }
 
     /**
@@ -85,13 +98,13 @@ public final class JsrScope {
      *         {@code int[]} with {@code value.chars().toArray()}.
      */
     public String getAncestry() {
-        StringBuilder sb = new StringBuilder();
+        String result = "";
         for (JsrScope s = this; s != null; s = s.parent) {
             if (!s.isEmpty()) {
-                sb.append(s.returnAddress);
+                result = s.returnAddress + result;
             }
         }
-        return sb.reverse().toString();
+        return result;
     }
 
     /**
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathPowOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathPowOp.java
index ac5410e7a6f..b1184bf5fe5 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathPowOp.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathPowOp.java
@@ -113,7 +113,7 @@ public final class AMD64MathPowOp extends AMD64MathIntrinsicBinaryOp {
 
     public AMD64MathPowOp() {
         super(TYPE, /* GPR */ rax, rcx, rdx, r8, r9, r10, r11,
-                        /* XMM */ xmm2, xmm3, xmm4, xmm5, xmm6, xmm7);
+                        /* XMM */ xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7);
     }
 
     private ArrayDataPointerConstant highsigmask = pointerConstant(16, new int[]{
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/vector/AVXBlendOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/vector/AVXBlendOp.java
new file mode 100644
index 00000000000..0295dc6f2f9
--- /dev/null
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/vector/AVXBlendOp.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2019, 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.lir.amd64.vector;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.asm.amd64.AVXKind;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMROp;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.meta.AllocatableValue;
+
+public class AVXBlendOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AVXBlendOp> TYPE = LIRInstructionClass.create(AVXBlendOp.class);
+
+    @Opcode private final VexRVMROp opcode;
+    private final AVXKind.AVXSize size;
+
+    @Def({REG}) protected AllocatableValue result;
+    @Use({REG}) protected AllocatableValue x;
+    @Use({REG, STACK}) protected AllocatableValue y;
+    @Use({REG}) protected AllocatableValue mask;
+
+    public AVXBlendOp(VexRVMROp opcode, AVXKind.AVXSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y, AllocatableValue mask) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+        this.result = result;
+        this.x = x;
+        this.y = y;
+        this.mask = mask;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        if (isRegister(y)) {
+            opcode.emit(masm, size, asRegister(result), asRegister(mask), asRegister(x), asRegister(y));
+        } else {
+            opcode.emit(masm, size, asRegister(result), asRegister(mask), asRegister(x), (AMD64Address) crb.asAddress(y));
+        }
+    }
+}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java
index a3c252e09a5..4354730442f 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java
@@ -279,7 +279,10 @@ public interface LIRGeneratorTool extends DiagnosticLIRGeneratorTool, ValueKindF
         throw GraalError.unimplemented("String.compareTo substitution is not implemented on this architecture");
     }
 
-    Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length, boolean directPointers);
+    @SuppressWarnings("unused")
+    default Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length, boolean directPointers) {
+        throw GraalError.unimplemented("Array.equals substitution is not implemented on this architecture");
+    }
 
     @SuppressWarnings("unused")
     default Variable emitArrayEquals(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length, boolean directPointers) {
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampToolTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampToolTest.java
new file mode 100644
index 00000000000..85139105f57
--- /dev/null
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampToolTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019, 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.nodes.test;
+
+import static org.graalvm.compiler.nodes.type.StampTool.stampForTrailingZeros;
+import static org.graalvm.compiler.test.GraalTest.assertTrue;
+
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.test.GraphTest;
+import org.junit.Test;
+
+public class StampToolTest extends GraphTest {
+
+    @Test
+    public void testStampForTrailingZeros() {
+        assertIntegerStampEquals(stampForTrailingZeros(forInt(0)), 32);
+        assertIntegerStampEquals(stampForTrailingZeros(forInt(1)), 0);
+        assertIntegerStampEquals(stampForTrailingZeros(forInt(-1)), 0);
+        assertIntegerStampEquals(stampForTrailingZeros(forInt(Integer.MIN_VALUE)), 31);
+        assertIntegerStampEquals(stampForTrailingZeros(forInt(Integer.MAX_VALUE)), 0);
+    }
+
+    private static IntegerStamp forInt(int value) {
+        return StampFactory.forInteger(32, value, value);
+    }
+
+    private static void assertIntegerStampEquals(Stamp stamp, int value) {
+        assertTrue(stamp instanceof IntegerStamp);
+        IntegerStamp iStamp = (IntegerStamp) stamp;
+        assertTrue(iStamp.lowerBound() == value);
+        assertTrue(iStamp.upperBound() == value);
+    }
+
+}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java
index 840fccf188b..88f1a48e7bb 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java
@@ -139,7 +139,7 @@ public class GraphDecoder {
                 maxFixedNodeOrderId = 0;
             }
 
-            if (loopExplosion != LoopExplosionKind.NONE) {
+            if (loopExplosion.useExplosion()) {
                 loopExplosionMerges = EconomicSet.create(Equivalence.IDENTITY);
             } else {
                 loopExplosionMerges = null;
@@ -196,12 +196,11 @@ public class GraphDecoder {
         protected LoopScope(MethodScope methodScope) {
             this.methodScope = methodScope;
             this.outer = null;
-            this.nextIterations = methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN ? new ArrayDeque<>(2) : null;
+            this.nextIterations = methodScope.loopExplosion.duplicateLoopExits() ? new ArrayDeque<>(2) : null;
             this.loopDepth = 0;
             this.loopIteration = 0;
             this.iterationStates = null;
             this.loopBeginOrderId = -1;
-
             int nodeCount = methodScope.encodedGraph.nodeStartOffsets.length;
             this.nodesToProcess = new BitSet(methodScope.maxFixedNodeOrderId);
             this.createdNodes = new Node[nodeCount];
@@ -433,7 +432,7 @@ public class GraphDecoder {
             /*
              * Finished with an inlined method. Perform end-of-method cleanup tasks.
              */
-            if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
+            if (methodScope.loopExplosion.mergeLoops()) {
                 LoopDetector loopDetector = new LoopDetector(graph, methodScope);
                 loopDetector.run();
             }
@@ -472,8 +471,7 @@ public class GraphDecoder {
         }
 
         if ((node instanceof MergeNode ||
-                        (node instanceof LoopBeginNode && (methodScope.loopExplosion == LoopExplosionKind.FULL_UNROLL || methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE ||
-                                        methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN))) &&
+                        (node instanceof LoopBeginNode && (methodScope.loopExplosion.unrollLoops() && !methodScope.loopExplosion.mergeLoops()))) &&
                         ((AbstractMergeNode) node).forwardEndCount() == 1) {
             AbstractMergeNode merge = (AbstractMergeNode) node;
             EndNode singleEnd = merge.forwardEndAt(0);
@@ -492,7 +490,7 @@ public class GraphDecoder {
         LoopScope successorAddScope = loopScope;
         boolean updatePredecessors = true;
         if (node instanceof LoopExitNode) {
-            if (methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN || (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE && loopScope.loopDepth > 1)) {
+            if (methodScope.loopExplosion.duplicateLoopExits() || (methodScope.loopExplosion.mergeLoops() && loopScope.loopDepth > 1)) {
                 /*
                  * We do not want to merge loop exits of inner loops. Instead, we want to keep
                  * exploding the outer loop separately for every loop exit and then merge the outer
@@ -519,7 +517,7 @@ public class GraphDecoder {
             } else {
                 successorAddScope = loopScope.outer;
             }
-            updatePredecessors = methodScope.loopExplosion == LoopExplosionKind.NONE;
+            updatePredecessors = methodScope.loopExplosion.isNoExplosion();
         }
 
         methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]);
@@ -531,12 +529,12 @@ public class GraphDecoder {
 
         LoopScope resultScope = loopScope;
         if (node instanceof LoopBeginNode) {
-            if (methodScope.loopExplosion != LoopExplosionKind.NONE) {
+            if (methodScope.loopExplosion.useExplosion()) {
                 handleLoopExplosionBegin(methodScope, loopScope, (LoopBeginNode) node);
             }
 
         } else if (node instanceof LoopExitNode) {
-            if (methodScope.loopExplosion != LoopExplosionKind.NONE) {
+            if (methodScope.loopExplosion.useExplosion()) {
                 handleLoopExplosionProxyNodes(methodScope, loopScope, successorAddScope, (LoopExitNode) node, nodeOrderId);
             } else {
                 handleProxyNodes(methodScope, loopScope, (LoopExitNode) node);
@@ -549,7 +547,7 @@ public class GraphDecoder {
             LoopScope phiInputScope = loopScope;
             LoopScope phiNodeScope = loopScope;
 
-            if (methodScope.loopExplosion != LoopExplosionKind.NONE && node instanceof LoopEndNode) {
+            if (methodScope.loopExplosion.useExplosion() && node instanceof LoopEndNode) {
                 node = handleLoopExplosionEnd(methodScope, loopScope, (LoopEndNode) node);
                 phiNodeScope = loopScope.nextIterations.getLast();
             }
@@ -562,14 +560,14 @@ public class GraphDecoder {
                 if (merge instanceof LoopBeginNode) {
                     assert phiNodeScope == phiInputScope && phiNodeScope == loopScope;
                     resultScope = new LoopScope(methodScope, loopScope, loopScope.loopDepth + 1, 0, mergeOrderId,
-                                    methodScope.loopExplosion != LoopExplosionKind.NONE ? Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length) : null,
-                                    methodScope.loopExplosion != LoopExplosionKind.NONE ? Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length) : loopScope.createdNodes, //
-                                    methodScope.loopExplosion != LoopExplosionKind.NONE ? new ArrayDeque<>(2) : null, //
-                                    methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE ? EconomicMap.create(Equivalence.DEFAULT) : null);
+                                    methodScope.loopExplosion.useExplosion() ? Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length) : null,
+                                    methodScope.loopExplosion.useExplosion() ? Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length) : loopScope.createdNodes, //
+                                    methodScope.loopExplosion.useExplosion() ? new ArrayDeque<>(2) : null, //
+                                    methodScope.loopExplosion.mergeLoops() ? EconomicMap.create(Equivalence.DEFAULT) : null);
                     phiInputScope = resultScope;
                     phiNodeScope = resultScope;
 
-                    if (methodScope.loopExplosion != LoopExplosionKind.NONE) {
+                    if (methodScope.loopExplosion.useExplosion()) {
                         registerNode(loopScope, mergeOrderId, null, true, true);
                     }
                     loopScope.nodesToProcess.clear(mergeOrderId);
@@ -582,7 +580,6 @@ public class GraphDecoder {
         } else if (node instanceof Invoke) {
             InvokeData invokeData = readInvokeData(methodScope, nodeOrderId, (Invoke) node);
             resultScope = handleInvoke(methodScope, loopScope, invokeData);
-
         } else if (node instanceof ReturnNode || node instanceof UnwindNode) {
             methodScope.returnAndUnwindNodes.add((ControlSinkNode) node);
         } else {
@@ -658,7 +655,7 @@ public class GraphDecoder {
         FixedNode successor = loopBegin.next();
         FrameState frameState = loopBegin.stateAfter();
 
-        if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
+        if (methodScope.loopExplosion.mergeLoops()) {
             LoopExplosionState queryState = new LoopExplosionState(frameState, null);
             LoopExplosionState existingState = loopScope.iterationStates.get(queryState);
             if (existingState != null) {
@@ -674,7 +671,7 @@ public class GraphDecoder {
         MergeNode merge = graph.add(new MergeNode());
         methodScope.loopExplosionMerges.add(merge);
 
-        if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
+        if (methodScope.loopExplosion.mergeLoops()) {
             if (loopScope.iterationStates.size() == 0 && loopScope.loopDepth == 1) {
                 if (methodScope.loopExplosionHead != null) {
                     throw new PermanentBailoutException("Graal implementation restriction: Method with %s loop explosion must not have more than one top-level loop", LoopExplosionKind.MERGE_EXPLODE);
@@ -725,7 +722,7 @@ public class GraphDecoder {
             merge.addForwardEnd(predecessor);
         }
 
-        if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
+        if (methodScope.loopExplosion.mergeLoops()) {
             LoopExplosionState explosionState = new LoopExplosionState(frameState, merge);
             loopScope.iterationStates.put(explosionState, explosionState);
         }
@@ -746,8 +743,8 @@ public class GraphDecoder {
         loopEnd.replaceAtPredecessor(replacementNode);
         loopEnd.safeDelete();
 
-        assert methodScope.loopExplosion != LoopExplosionKind.NONE;
-        if (methodScope.loopExplosion != LoopExplosionKind.FULL_UNROLL || loopScope.nextIterations.isEmpty()) {
+        assert methodScope.loopExplosion.useExplosion();
+        if (methodScope.loopExplosion.duplicateLoopEnds() || loopScope.nextIterations.isEmpty()) {
             int nextIterationNumber = loopScope.nextIterations.isEmpty() ? loopScope.loopIteration + 1 : loopScope.nextIterations.getLast().loopIteration + 1;
             LoopScope nextIterationScope = new LoopScope(methodScope, loopScope.outer, loopScope.loopDepth, nextIterationNumber, loopScope.loopBeginOrderId,
                             Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length),
@@ -800,7 +797,7 @@ public class GraphDecoder {
         loopExit.replaceAtPredecessor(begin);
 
         MergeNode loopExitPlaceholder = null;
-        if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE && loopScope.loopDepth == 1) {
+        if (methodScope.loopExplosion.mergeLoops() && loopScope.loopDepth == 1) {
             /*
              * This exit might end up as a loop exit of a loop detected after partial evaluation. We
              * need to be able to create a FrameState and the necessary proxy nodes in this case.
@@ -955,7 +952,7 @@ public class GraphDecoder {
          * not processed yet when processing the loop body, we need to create all phi functions
          * upfront.
          */
-        boolean lazyPhi = allowLazyPhis() && (!(merge instanceof LoopBeginNode) || methodScope.loopExplosion != LoopExplosionKind.NONE);
+        boolean lazyPhi = allowLazyPhis() && (!(merge instanceof LoopBeginNode) || methodScope.loopExplosion.useExplosion());
         int numPhis = methodScope.reader.getUVInt();
         for (int i = 0; i < numPhis; i++) {
             int phiInputOrderId = readOrderId(methodScope);
@@ -974,7 +971,7 @@ public class GraphDecoder {
                  * the stale value because it will never be needed to be merged (we are exploding
                  * until we hit a return).
                  */
-                assert methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN && phiNodeScope.loopIteration > 0;
+                assert methodScope.loopExplosion.duplicateLoopExits() && phiNodeScope.loopIteration > 0;
                 existing = null;
             }
 
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardedValueNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardedValueNode.java
index 2de46431d4a..b7a4270ecb3 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardedValueNode.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardedValueNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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,13 @@ public final class GuardedValueNode extends FloatingGuardedNode implements LIRLo
         this.object = object;
     }
 
+    public static ValueNode create(ValueNode object, GuardingNode guard) {
+        if (guard == null) {
+            return object;
+        }
+        return new GuardedValueNode(object, guard);
+    }
+
     public ValueNode object() {
         return object;
     }
@@ -85,7 +92,7 @@ public final class GuardedValueNode extends FloatingGuardedNode implements LIRLo
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (getGuard() == null) {
+        if (guard == null) {
             if (stamp(NodeView.DEFAULT).equals(object().stamp(NodeView.DEFAULT))) {
                 return object();
             } else {
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java
index 0df61aa0660..42470e937eb 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -44,6 +44,7 @@ import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.OptionValues;
 
 import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.TriState;
 
@@ -54,7 +55,8 @@ public final class FloatEqualsNode extends CompareNode implements BinaryCommutat
 
     public FloatEqualsNode(ValueNode x, ValueNode y) {
         super(TYPE, CanonicalCondition.EQ, false, x, y);
-        assert x.stamp(NodeView.DEFAULT) instanceof FloatStamp && y.stamp(NodeView.DEFAULT) instanceof FloatStamp : x.stamp(NodeView.DEFAULT) + " " + y.stamp(NodeView.DEFAULT);
+        assert !x.getStackKind().isNumericInteger() && x.getStackKind() != JavaKind.Object;
+        assert !y.getStackKind().isNumericInteger() && y.getStackKind() != JavaKind.Object;
         assert x.stamp(NodeView.DEFAULT).isCompatible(y.stamp(NodeView.DEFAULT));
     }
 
@@ -78,15 +80,19 @@ public final class FloatEqualsNode extends CompareNode implements BinaryCommutat
 
     @Override
     public boolean isIdentityComparison() {
-        FloatStamp xStamp = (FloatStamp) x.stamp(NodeView.DEFAULT);
-        FloatStamp yStamp = (FloatStamp) y.stamp(NodeView.DEFAULT);
-        /*
-         * If both stamps have at most one 0.0 and it's the same 0.0 then this is an identity
-         * comparison. FloatStamp isn't careful about tracking the presence of -0.0 so assume that
-         * anything that includes 0.0 might include -0.0. So if either one is non-zero then it's an
-         * identity comparison.
-         */
-        return (!xStamp.contains(0.0) || !yStamp.contains(0.0));
+        Stamp xStamp = x.stamp(NodeView.DEFAULT);
+        Stamp yStamp = y.stamp(NodeView.DEFAULT);
+        if (xStamp instanceof FloatStamp && yStamp instanceof FloatStamp) {
+            /*
+             * If both stamps have at most one 0.0 and it's the same 0.0 then this is an identity
+             * comparison. FloatStamp isn't careful about tracking the presence of -0.0 so assume
+             * that anything that includes 0.0 might include -0.0. So if either one is non-zero then
+             * it's an identity comparison.
+             */
+            return (!((FloatStamp) xStamp).contains(0.0) || !((FloatStamp) yStamp).contains(0.0));
+        } else {
+            return false;
+        }
     }
 
     @Override
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IsNullNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IsNullNode.java
index 35cbb49bc12..11cf9c07adf 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IsNullNode.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IsNullNode.java
@@ -97,7 +97,7 @@ public final class IsNullNode extends UnaryOpLogicNode implements LIRLowerable,
     @Override
     public boolean verify() {
         assertTrue(getValue() != null, "is null input must not be null");
-        assertTrue(getValue().stamp(NodeView.DEFAULT) instanceof AbstractPointerStamp, "input must be a pointer not %s", getValue().stamp(NodeView.DEFAULT));
+        assertTrue(getValue().stamp(NodeView.DEFAULT).isPointerStamp(), "input must be a pointer not %s", getValue().stamp(NodeView.DEFAULT));
         return super.verify();
     }
 
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/PointerEqualsNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/PointerEqualsNode.java
index b620f84511f..d699b28e8e1 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/PointerEqualsNode.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/PointerEqualsNode.java
@@ -69,8 +69,8 @@ public class PointerEqualsNode extends CompareNode implements BinaryCommutative<
 
     protected PointerEqualsNode(NodeClass<? extends PointerEqualsNode> c, ValueNode x, ValueNode y) {
         super(c, CanonicalCondition.EQ, false, x, y);
-        assert x.stamp(NodeView.DEFAULT) instanceof AbstractPointerStamp;
-        assert y.stamp(NodeView.DEFAULT) instanceof AbstractPointerStamp;
+        assert x.stamp(NodeView.DEFAULT).isPointerStamp();
+        assert y.stamp(NodeView.DEFAULT).isPointerStamp();
     }
 
     @Override
@@ -137,9 +137,9 @@ public class PointerEqualsNode extends CompareNode implements BinaryCommutative<
             return LogicConstantNode.tautology();
         } else if (forX.stamp(view).alwaysDistinct(forY.stamp(view))) {
             return LogicConstantNode.contradiction();
-        } else if (((AbstractPointerStamp) forX.stamp(view)).alwaysNull()) {
+        } else if (forX.stamp(view) instanceof AbstractPointerStamp && ((AbstractPointerStamp) forX.stamp(view)).alwaysNull()) {
             return nullSynonym(forY, forX);
-        } else if (((AbstractPointerStamp) forY.stamp(view)).alwaysNull()) {
+        } else if (forY.stamp(view) instanceof AbstractPointerStamp && ((AbstractPointerStamp) forY.stamp(view)).alwaysNull()) {
             return nullSynonym(forX, forY);
         } else {
             return null;
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/SideEffectNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/SideEffectNode.java
new file mode 100644
index 00000000000..9b3ed6454a9
--- /dev/null
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/SideEffectNode.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019, 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.nodes.debug;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.NodeSize;
+import org.graalvm.compiler.nodes.NodeView;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import jdk.internal.vm.compiler.word.LocationIdentity;
+
+/**
+ * Debug node that can be used when an arbitrary side-effect and when a
+ * {@link LocationIdentity#ANY_LOCATION} kill is needed.
+ */
+@NodeInfo(cycles = NodeCycles.CYCLES_IGNORED, size = NodeSize.SIZE_IGNORED, allowedUsageTypes = {InputType.Memory})
+public class SideEffectNode extends AbstractMemoryCheckpoint implements LIRLowerable, MemoryCheckpoint.Single {
+    public static final NodeClass<SideEffectNode> TYPE = NodeClass.create(SideEffectNode.class);
+
+    @OptionalInput ValueNode value;
+
+    public SideEffectNode() {
+        super(TYPE, StampFactory.forVoid());
+    }
+
+    public SideEffectNode(ValueNode value) {
+        super(TYPE, value.stamp(NodeView.DEFAULT));
+        this.value = value;
+    }
+
+    @Override
+    public boolean hasSideEffect() {
+        return true;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        generator.setResult(this, generator.operand(value));
+    }
+
+    @Override
+    public LocationIdentity getKilledLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/BarrierSet.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/BarrierSet.java
index 4639cd6db68..12e1214949a 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/BarrierSet.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/BarrierSet.java
@@ -25,8 +25,12 @@
 
 package org.graalvm.compiler.nodes.gc;
 
+import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.memory.FixedAccessNode;
+import org.graalvm.compiler.nodes.memory.HeapAccess;
 
 public interface BarrierSet {
     void addBarriers(FixedAccessNode n);
+
+    HeapAccess.BarrierType readBarrierType(RawLoadNode load);
 }
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/CardTableBarrierSet.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/CardTableBarrierSet.java
index 0dad6707a57..55b88bd9910 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/CardTableBarrierSet.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/CardTableBarrierSet.java
@@ -31,6 +31,7 @@ import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.extended.ArrayRangeWrite;
+import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode;
 import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
 import org.graalvm.compiler.nodes.memory.FixedAccessNode;
@@ -47,6 +48,11 @@ public class CardTableBarrierSet implements BarrierSet {
     public CardTableBarrierSet() {
     }
 
+    @Override
+    public BarrierType readBarrierType(RawLoadNode load) {
+        return BarrierType.NONE;
+    }
+
     @Override
     public void addBarriers(FixedAccessNode n) {
         if (n instanceof ReadNode) {
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1BarrierSet.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1BarrierSet.java
index bbf04d8fed5..062675bc764 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1BarrierSet.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1BarrierSet.java
@@ -25,12 +25,15 @@
 
 package org.graalvm.compiler.nodes.gc;
 
+import java.lang.ref.Reference;
+
 import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.extended.ArrayRangeWrite;
+import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode;
 import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
 import org.graalvm.compiler.nodes.memory.FixedAccessNode;
@@ -41,8 +44,56 @@ import org.graalvm.compiler.nodes.memory.WriteNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.type.StampTool;
 
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
 public class G1BarrierSet implements BarrierSet {
-    public G1BarrierSet() {
+
+    private final long referentFieldOffset;
+    private final ResolvedJavaType referenceType;
+
+    public G1BarrierSet(MetaAccessProvider metaAccess) {
+        this.referenceType = metaAccess.lookupJavaType(Reference.class);
+        int offset = -1;
+        for (ResolvedJavaField field : referenceType.getInstanceFields(true)) {
+            if (field.getName().equals("referent")) {
+                offset = field.getOffset();
+            }
+        }
+        if (offset == 1) {
+            throw new GraalError("Can't find Reference.referent field");
+        }
+        this.referentFieldOffset = offset;
+    }
+
+    @Override
+    public BarrierType readBarrierType(RawLoadNode load) {
+        if (load.object().getStackKind() == JavaKind.Object &&
+                        load.accessKind() == JavaKind.Object &&
+                        !StampTool.isPointerAlwaysNull(load.object())) {
+            if (load.offset().isJavaConstant() && referentFieldOffset != load.offset().asJavaConstant().asLong()) {
+                // Reading at a constant offset which is different than the referent field.
+                return BarrierType.NONE;
+            }
+            ResolvedJavaType type = StampTool.typeOrNull(load.object());
+            if (type != null && referenceType.isAssignableFrom(type)) {
+                // It's definitely a field of a Reference type
+                if (load.offset().isJavaConstant() && referentFieldOffset == load.offset().asJavaConstant().asLong()) {
+                    // Exactly Reference.referent
+                    return BarrierType.WEAK_FIELD;
+                }
+                // An unknown offset into Reference
+                return BarrierType.MAYBE_WEAK_FIELD;
+            }
+            if (type == null || type.isAssignableFrom(referenceType)) {
+                // The object is a supertype of Reference with an unknown offset or a constant
+                // offset which is the same as Reference.referent.
+                return BarrierType.MAYBE_WEAK_FIELD;
+            }
+        }
+        return BarrierType.NONE;
     }
 
     @Override
@@ -66,9 +117,9 @@ public class G1BarrierSet implements BarrierSet {
     }
 
     private static void addReadNodeBarriers(ReadNode node) {
-        if (node.getBarrierType() == HeapAccess.BarrierType.WEAK_FIELD) {
+        if (node.getBarrierType() == HeapAccess.BarrierType.WEAK_FIELD || node.getBarrierType() == BarrierType.MAYBE_WEAK_FIELD) {
             StructuredGraph graph = node.graph();
-            G1ReferentFieldReadBarrier barrier = graph.add(new G1ReferentFieldReadBarrier(node.getAddress(), node, false));
+            G1ReferentFieldReadBarrier barrier = graph.add(new G1ReferentFieldReadBarrier(node.getAddress(), node, node.getBarrierType() == BarrierType.MAYBE_WEAK_FIELD));
             graph.addAfterFixed(node, barrier);
         }
     }
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1ReferentFieldReadBarrier.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1ReferentFieldReadBarrier.java
index 7a9c4b79ac4..22d1fa0f391 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1ReferentFieldReadBarrier.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1ReferentFieldReadBarrier.java
@@ -42,18 +42,18 @@ import org.graalvm.compiler.nodes.memory.address.AddressNode;
 public final class G1ReferentFieldReadBarrier extends ObjectWriteBarrier {
     public static final NodeClass<G1ReferentFieldReadBarrier> TYPE = NodeClass.create(G1ReferentFieldReadBarrier.class);
 
-    private final boolean doLoad;
+    private final boolean dynamicCheck;
 
-    public G1ReferentFieldReadBarrier(AddressNode address, ValueNode expectedObject, boolean doLoad) {
+    public G1ReferentFieldReadBarrier(AddressNode address, ValueNode expectedObject, boolean dynamicCheck) {
         super(TYPE, address, expectedObject, true);
-        this.doLoad = doLoad;
+        this.dynamicCheck = dynamicCheck;
     }
 
     public ValueNode getExpectedObject() {
         return getValue();
     }
 
-    public boolean doLoad() {
-        return doLoad;
+    public boolean isDynamicCheck() {
+        return dynamicCheck;
     }
 }
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java
index 871baeff0cb..4bf09d4136c 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java
@@ -28,6 +28,7 @@ import static jdk.vm.ci.code.BytecodeFrame.AFTER_BCI;
 import static jdk.vm.ci.code.BytecodeFrame.AFTER_EXCEPTION_BCI;
 import static jdk.vm.ci.code.BytecodeFrame.BEFORE_BCI;
 import static jdk.vm.ci.code.BytecodeFrame.INVALID_FRAMESTATE_BCI;
+import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION_ENCODING;
 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
 
@@ -136,7 +137,11 @@ public class IntrinsicContext {
     }
 
     public boolean isCompilationRoot() {
-        return compilationContext.equals(ROOT_COMPILATION);
+        return compilationContext.equals(ROOT_COMPILATION) || compilationContext.equals(ROOT_COMPILATION_ENCODING);
+    }
+
+    public boolean isIntrinsicEncoding() {
+        return compilationContext.equals(ROOT_COMPILATION_ENCODING);
     }
 
     public NodeSourcePosition getNodeSourcePosition() {
@@ -166,7 +171,12 @@ public class IntrinsicContext {
         /**
          * An intrinsic is the root of compilation.
          */
-        ROOT_COMPILATION
+        ROOT_COMPILATION,
+
+        /**
+         * An intrinsic is the root of a compilation done for graph encoding.
+         */
+        ROOT_COMPILATION_ENCODING
     }
 
     /**
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/LoopExplosionPlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/LoopExplosionPlugin.java
index 1874aa9fcbc..0ae22c13ca2 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/LoopExplosionPlugin.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/LoopExplosionPlugin.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -32,35 +32,83 @@ public interface LoopExplosionPlugin extends GraphBuilderPlugin {
         /**
          * No loop explosion.
          */
-        NONE,
+        NONE(false, false, false, false),
         /**
          * Fully unroll all loops. The loops must have a known finite number of iterations. If a
          * loop has multiple loop ends, they are merged so that the subsequent loop iteration is
          * processed only once. For example, a loop with 4 iterations and 2 loop ends leads to
          * 1+1+1+1 = 4 copies of the loop body.
          */
-        FULL_UNROLL,
+        FULL_UNROLL(true, false, false, false),
+        /**
+         * Like {@link #FULL_UNROLL}, but in addition loop unrolling duplicates loop exits in every
+         * iteration instead of merging them. Code after a loop exit is duplicated for every loop
+         * exit and every loop iteration. For example, a loop with 4 iterations and 2 loop exits
+         * (exit1 and exit2, where exit1 is an early return inside a loop) leads to 4 copies of the
+         * loop body and 4 copies of exit1 and 1 copy if exit2. After each exit all code until a
+         * return is duplicated per iteration. Beware of break statements inside loops since they
+         * cause additional loop exits leading to code duplication along exit2.
+         */
+        FULL_UNROLL_UNTIL_RETURN(true, false, true, false),
         /**
          * Fully explode all loops. The loops must have a known finite number of iterations. If a
          * loop has multiple loop ends, they are not merged so that subsequent loop iterations are
          * processed multiple times. For example, a loop with 4 iterations and 2 loop ends leads to
          * 1+2+4+8 = 15 copies of the loop body.
          */
-        FULL_EXPLODE,
+        FULL_EXPLODE(true, true, false, false),
         /**
          * Like {@link #FULL_EXPLODE}, but in addition explosion does not stop at loop exits. Code
          * after the loop is duplicated for every loop exit of every loop iteration. For example, a
          * loop with 4 iterations and 2 loop exits leads to 4 * 2 = 8 copies of the code after the
          * loop.
          */
-        FULL_EXPLODE_UNTIL_RETURN,
+        FULL_EXPLODE_UNTIL_RETURN(true, true, true, false),
         /**
          * like {@link #FULL_EXPLODE}, but copies of the loop body that have the exact same state
          * (all local variables have the same value) are merged. This reduces the number of copies
          * necessary, but can introduce loops again. This kind is useful for bytecode interpreter
          * loops.
          */
-        MERGE_EXPLODE
+        MERGE_EXPLODE(true, true, false, true);
+
+        private final boolean unrollLoops;
+        private final boolean duplicateLoopEnds;
+        private final boolean duplicateLoopExits;
+        private final boolean mergeLoops;
+
+        LoopExplosionKind(boolean unrollLoops, boolean duplicateLoopEnds, boolean duplicateLoopExits, boolean mergeLoops) {
+            this.unrollLoops = unrollLoops;
+            assert !duplicateLoopEnds || unrollLoops;
+            this.duplicateLoopEnds = duplicateLoopEnds;
+            assert !duplicateLoopExits || unrollLoops;
+            this.duplicateLoopExits = duplicateLoopExits;
+            this.mergeLoops = mergeLoops;
+        }
+
+        public boolean unrollLoops() {
+            return unrollLoops;
+        }
+
+        public boolean duplicateLoopExits() {
+            return duplicateLoopExits;
+        }
+
+        public boolean duplicateLoopEnds() {
+            return duplicateLoopEnds;
+        }
+
+        public boolean mergeLoops() {
+            return mergeLoops;
+        }
+
+        public boolean useExplosion() {
+            return this != NONE;
+        }
+
+        public boolean isNoExplosion() {
+            return this == NONE;
+        }
     }
 
     LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method);
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/HeapAccess.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/HeapAccess.java
index 0501c8b3252..906771753c0 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/HeapAccess.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/HeapAccess.java
@@ -52,7 +52,12 @@ public interface HeapAccess {
         /**
          * Weak field access (e.g. Hotspot's Reference.referent field).
          */
-        WEAK_FIELD
+        WEAK_FIELD,
+        /**
+         * An access which requires a dynamic check for Weak field access (e.g. Hotspot's
+         * Reference.referent field).
+         */
+        MAYBE_WEAK_FIELD
     }
 
     /**
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/StampTool.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/StampTool.java
index de83352378e..345c3891c53 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/StampTool.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/StampTool.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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,9 +121,10 @@ public class StampTool {
     }
 
     public static Stamp stampForTrailingZeros(IntegerStamp valueStamp) {
-        long mask = CodeUtil.mask(valueStamp.getBits());
-        int min = Long.numberOfTrailingZeros(valueStamp.upMask() & mask);
-        int max = Long.numberOfTrailingZeros(valueStamp.downMask() & mask);
+        int bits = valueStamp.getBits();
+        long mask = CodeUtil.mask(bits);
+        int min = Math.min(Long.numberOfTrailingZeros(valueStamp.upMask() & mask), bits);
+        int max = Math.min(Long.numberOfTrailingZeros(valueStamp.downMask() & mask), bits);
         return StampFactory.forInteger(JavaKind.Int, min, max);
     }
 
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java
index be8827c6f7a..0eaa88e6ab7 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java
@@ -25,6 +25,9 @@
 package org.graalvm.compiler.phases.common;
 
 import static org.graalvm.compiler.nodes.StaticDeoptimizingNode.mergeActions;
+import static org.graalvm.compiler.phases.common.ConditionalEliminationUtil.getOtherSafeStamp;
+import static org.graalvm.compiler.phases.common.ConditionalEliminationUtil.getSafeStamp;
+import static org.graalvm.compiler.phases.common.ConditionalEliminationUtil.rewireGuards;
 
 import java.util.ArrayDeque;
 import java.util.Deque;
@@ -69,20 +72,15 @@ import org.graalvm.compiler.nodes.LogicNode;
 import org.graalvm.compiler.nodes.LoopExitNode;
 import org.graalvm.compiler.nodes.MergeNode;
 import org.graalvm.compiler.nodes.NodeView;
-import org.graalvm.compiler.nodes.ParameterNode;
 import org.graalvm.compiler.nodes.PiNode;
 import org.graalvm.compiler.nodes.ProxyNode;
-import org.graalvm.compiler.nodes.ShortCircuitOrNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
 import org.graalvm.compiler.nodes.UnaryOpLogicNode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.ValuePhiNode;
 import org.graalvm.compiler.nodes.calc.AndNode;
-import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
-import org.graalvm.compiler.nodes.calc.BinaryNode;
 import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
-import org.graalvm.compiler.nodes.calc.UnaryNode;
 import org.graalvm.compiler.nodes.cfg.Block;
 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
 import org.graalvm.compiler.nodes.extended.GuardingNode;
@@ -96,18 +94,23 @@ import org.graalvm.compiler.nodes.spi.NodeWithState;
 import org.graalvm.compiler.nodes.spi.StampInverter;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.common.ConditionalEliminationUtil.GuardFolding;
+import org.graalvm.compiler.phases.common.ConditionalEliminationUtil.GuardRewirer;
+import org.graalvm.compiler.phases.common.ConditionalEliminationUtil.GuardedCondition;
+import org.graalvm.compiler.phases.common.ConditionalEliminationUtil.InfoElement;
+import org.graalvm.compiler.phases.common.ConditionalEliminationUtil.InfoElementProvider;
+import org.graalvm.compiler.phases.common.ConditionalEliminationUtil.InputFilter;
+import org.graalvm.compiler.phases.common.ConditionalEliminationUtil.Marks;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
 
 import jdk.vm.ci.meta.DeoptimizationAction;
-import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.SpeculationLog.Speculation;
 import jdk.vm.ci.meta.TriState;
 
 public class ConditionalEliminationPhase extends BasePhase<CoreProviders> {
 
     private static final CounterKey counterStampsRegistered = DebugContext.counter("StampsRegistered");
-    private static final CounterKey counterStampsFound = DebugContext.counter("StampsFound");
     private static final CounterKey counterIfsKilled = DebugContext.counter("CE_KilledIfs");
     private static final CounterKey counterPhiStampsImproved = DebugContext.counter("CE_ImprovedPhis");
     private final boolean fullSchedule;
@@ -257,40 +260,6 @@ public class ConditionalEliminationPhase extends BasePhase<CoreProviders> {
         }
     }
 
-    public static final class Marks {
-        final int infoElementOperations;
-        final int conditions;
-
-        public Marks(int infoElementOperations, int conditions) {
-            this.infoElementOperations = infoElementOperations;
-            this.conditions = conditions;
-        }
-    }
-
-    protected static final class GuardedCondition {
-        private final GuardingNode guard;
-        private final LogicNode condition;
-        private final boolean negated;
-
-        public GuardedCondition(GuardingNode guard, LogicNode condition, boolean negated) {
-            this.guard = guard;
-            this.condition = condition;
-            this.negated = negated;
-        }
-
-        public GuardingNode getGuard() {
-            return guard;
-        }
-
-        public LogicNode getCondition() {
-            return condition;
-        }
-
-        public boolean isNegated() {
-            return negated;
-        }
-    }
-
     public static class Instance implements ControlFlowGraph.RecursiveVisitor<Marks> {
         protected final NodeMap<InfoElement> map;
         protected final BlockMap<List<Node>> blockToNodes;
@@ -300,6 +269,8 @@ public class ConditionalEliminationPhase extends BasePhase<CoreProviders> {
         protected final StructuredGraph graph;
         protected final DebugContext debug;
         protected final EconomicMap<MergeNode, EconomicMap<ValuePhiNode, PhiInfoElement>> mergeMaps;
+        private final InfoElementProvider infoElementProvider;
+        private final GuardFolding guardFolding;
 
         protected final ArrayDeque<GuardedCondition> conditions;
 
@@ -320,10 +291,24 @@ public class ConditionalEliminationPhase extends BasePhase<CoreProviders> {
             tool = GraphUtil.getDefaultSimplifier(context.getMetaAccess(), context.getConstantReflection(), context.getConstantFieldProvider(), false, graph.getAssumptions(), graph.getOptions(),
                             context.getLowerer());
             mergeMaps = EconomicMap.create(Equivalence.IDENTITY);
+            infoElementProvider = new InfoElementProvider() {
+
+                @Override
+                public InfoElement infoElements(ValueNode value) {
+                    return getInfoElements(value);
+                }
+            };
+            guardFolding = new GuardFolding() {
+
+                @Override
+                public boolean foldGuard(DeoptimizingGuard thisGuard, ValueNode original, Stamp newStamp, GuardRewirer rewireGuardFunction) {
+                    return foldPendingTest(thisGuard, original, newStamp, rewireGuardFunction);
+                }
+            };
         }
 
         protected void processConditionAnchor(ConditionAnchorNode node) {
-            tryProveCondition(node.condition(), (guard, result, guardedValueStamp, newInput) -> {
+            tryProveGuardCondition(null, node.condition(), (guard, result, guardedValueStamp, newInput) -> {
                 if (result != node.isNegated()) {
                     node.replaceAtUsages(guard.asNode());
                     GraphUtil.unlinkFixedNode(node);
@@ -443,7 +428,7 @@ public class ConditionalEliminationPhase extends BasePhase<CoreProviders> {
         }
 
         protected void processIf(IfNode node) {
-            tryProveCondition(node.condition(), (guard, result, guardedValueStamp, newInput) -> {
+            tryProveGuardCondition(null, node.condition(), (guard, result, guardedValueStamp, newInput) -> {
                 node.setCondition(LogicConstantNode.forBoolean(result, node.graph()));
                 AbstractBeginNode survivingSuccessor = node.getSuccessor(result);
                 survivingSuccessor.replaceAtUsages(InputType.Guard, guard.asNode());
@@ -601,7 +586,7 @@ public class ConditionalEliminationPhase extends BasePhase<CoreProviders> {
                                     if (input == null) {
                                         input = valueAt;
                                     }
-                                    valueAt = graph.maybeAddOrUnique(PiNode.create(input, curBestStamp, (ValueNode) infoElement.guard));
+                                    valueAt = graph.maybeAddOrUnique(PiNode.create(input, curBestStamp, (ValueNode) infoElement.getGuard()));
                                 }
                                 newPhi.addInput(valueAt);
                             }
@@ -693,60 +678,6 @@ public class ConditionalEliminationPhase extends BasePhase<CoreProviders> {
             registerCondition(condition, negated, guard);
         }
 
-        Pair<InfoElement, Stamp> recursiveFoldStamp(Node node) {
-            if (node instanceof UnaryNode) {
-                UnaryNode unary = (UnaryNode) node;
-                ValueNode value = unary.getValue();
-                InfoElement infoElement = getInfoElements(value);
-                while (infoElement != null) {
-                    Stamp result = unary.foldStamp(infoElement.getStamp());
-                    if (result != null) {
-                        return Pair.create(infoElement, result);
-                    }
-                    infoElement = nextElement(infoElement);
-                }
-            } else if (node instanceof BinaryNode) {
-                BinaryNode binary = (BinaryNode) node;
-                ValueNode y = binary.getY();
-                ValueNode x = binary.getX();
-                if (y.isConstant()) {
-                    InfoElement infoElement = getInfoElements(x);
-                    while (infoElement != null) {
-                        Stamp result = binary.foldStamp(infoElement.stamp, y.stamp(NodeView.DEFAULT));
-                        if (result != null) {
-                            return Pair.create(infoElement, result);
-                        }
-                        infoElement = nextElement(infoElement);
-                    }
-                }
-            }
-            return null;
-        }
-
-        /**
-         * Get the stamp that may be used for the value for which we are registering the condition.
-         * We may directly use the stamp here without restriction, because any later lookup of the
-         * registered info elements is in the same chain of pi nodes.
-         */
-        private static Stamp getSafeStamp(ValueNode x) {
-            return x.stamp(NodeView.DEFAULT);
-        }
-
-        /**
-         * We can only use the stamp of a second value involved in the condition if we are sure that
-         * we are not implicitly creating a dependency on a pi node that is responsible for that
-         * stamp. For now, we are conservatively only using the stamps of constants. Under certain
-         * circumstances, we may also be able to use the stamp of the value after skipping pi nodes
-         * (e.g., the stamp of a parameter after inlining, or the stamp of a fixed node that can
-         * never be replaced with a pi node via canonicalization).
-         */
-        private static Stamp getOtherSafeStamp(ValueNode x) {
-            if (x.isConstant() || x.graph().isAfterFixedReadPhase()) {
-                return x.stamp(NodeView.DEFAULT);
-            }
-            return x.stamp(NodeView.DEFAULT).unrestricted();
-        }
-
         /**
          * Recursively try to fold stamps within this expression using information from
          * {@link #getInfoElements(ValueNode)}. It's only safe to use constants and one
@@ -757,7 +688,7 @@ public class ConditionalEliminationPhase extends BasePhase<CoreProviders> {
          *         expression
          */
         Pair<InfoElement, Stamp> recursiveFoldStampFromInfo(Node node) {
-            return recursiveFoldStamp(node);
+            return ConditionalEliminationUtil.recursiveFoldStamp(infoElementProvider, node);
         }
 
         /**
@@ -873,6 +804,10 @@ public class ConditionalEliminationPhase extends BasePhase<CoreProviders> {
             return false;
         }
 
+        protected boolean tryProveGuardCondition(DeoptimizingGuard thisGuard, LogicNode node, GuardRewirer rewireGuardFunction) {
+            return ConditionalEliminationUtil.tryProveGuardCondition(infoElementProvider, conditions, guardFolding, thisGuard, node, rewireGuardFunction);
+        }
+
         protected void registerCondition(LogicNode condition, boolean negated, GuardingNode guard) {
             if (condition.hasMoreThanOneUsage()) {
                 registerNewStamp(condition, negated ? StampFactory.contradiction() : StampFactory.tautology(), guard);
@@ -891,15 +826,6 @@ public class ConditionalEliminationPhase extends BasePhase<CoreProviders> {
             return infoElement;
         }
 
-        protected boolean rewireGuards(GuardingNode guard, boolean result, ValueNode proxifiedInput, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) {
-            counterStampsFound.increment(debug);
-            return rewireGuardFunction.rewire(guard, result, guardedValueStamp, proxifiedInput);
-        }
-
-        protected boolean tryProveCondition(LogicNode node, GuardRewirer rewireGuardFunction) {
-            return tryProveGuardCondition(null, node, rewireGuardFunction);
-        }
-
         private InfoElement nextElement(InfoElement current) {
             InfoElement parent = current.getParent();
             if (parent != null) {
@@ -914,166 +840,6 @@ public class ConditionalEliminationPhase extends BasePhase<CoreProviders> {
             return null;
         }
 
-        protected boolean tryProveGuardCondition(DeoptimizingGuard thisGuard, LogicNode node, GuardRewirer rewireGuardFunction) {
-            InfoElement infoElement = getInfoElements(node);
-            while (infoElement != null) {
-                Stamp stamp = infoElement.getStamp();
-                JavaConstant constant = (JavaConstant) stamp.asConstant();
-                if (constant != null) {
-                    // No proxified input and stamp required.
-                    return rewireGuards(infoElement.getGuard(), constant.asBoolean(), null, null, rewireGuardFunction);
-                }
-                infoElement = nextElement(infoElement);
-            }
-
-            for (GuardedCondition guardedCondition : this.conditions) {
-                TriState result = guardedCondition.getCondition().implies(guardedCondition.isNegated(), node);
-                if (result.isKnown()) {
-                    return rewireGuards(guardedCondition.guard, result.toBoolean(), null, null, rewireGuardFunction);
-                }
-            }
-
-            if (node instanceof UnaryOpLogicNode) {
-                UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) node;
-                ValueNode value = unaryLogicNode.getValue();
-                infoElement = getInfoElements(value);
-                while (infoElement != null) {
-                    Stamp stamp = infoElement.getStamp();
-                    TriState result = unaryLogicNode.tryFold(stamp);
-                    if (result.isKnown()) {
-                        return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), infoElement.getStamp(), rewireGuardFunction);
-                    }
-                    infoElement = nextElement(infoElement);
-                }
-                Pair<InfoElement, Stamp> foldResult = recursiveFoldStampFromInfo(value);
-                if (foldResult != null) {
-                    TriState result = unaryLogicNode.tryFold(foldResult.getRight());
-                    if (result.isKnown()) {
-                        return rewireGuards(foldResult.getLeft().getGuard(), result.toBoolean(), foldResult.getLeft().getProxifiedInput(), foldResult.getRight(), rewireGuardFunction);
-                    }
-                }
-                if (thisGuard != null) {
-                    Stamp newStamp = unaryLogicNode.getSucceedingStampForValue(thisGuard.isNegated());
-                    if (newStamp != null && foldPendingTest(thisGuard, value, newStamp, rewireGuardFunction)) {
-                        return true;
-                    }
-
-                }
-            } else if (node instanceof BinaryOpLogicNode) {
-                BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) node;
-                ValueNode x = binaryOpLogicNode.getX();
-                ValueNode y = binaryOpLogicNode.getY();
-                infoElement = getInfoElements(x);
-                while (infoElement != null) {
-                    TriState result = binaryOpLogicNode.tryFold(infoElement.getStamp(), y.stamp(NodeView.DEFAULT));
-                    if (result.isKnown()) {
-                        return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), infoElement.getStamp(), rewireGuardFunction);
-                    }
-                    infoElement = nextElement(infoElement);
-                }
-
-                if (y.isConstant()) {
-                    Pair<InfoElement, Stamp> foldResult = recursiveFoldStampFromInfo(x);
-                    if (foldResult != null) {
-                        TriState result = binaryOpLogicNode.tryFold(foldResult.getRight(), y.stamp(NodeView.DEFAULT));
-                        if (result.isKnown()) {
-                            return rewireGuards(foldResult.getLeft().getGuard(), result.toBoolean(), foldResult.getLeft().getProxifiedInput(), foldResult.getRight(), rewireGuardFunction);
-                        }
-                    }
-                } else {
-                    infoElement = getInfoElements(y);
-                    while (infoElement != null) {
-                        TriState result = binaryOpLogicNode.tryFold(x.stamp(NodeView.DEFAULT), infoElement.getStamp());
-                        if (result.isKnown()) {
-                            return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), infoElement.getStamp(), rewireGuardFunction);
-                        }
-                        infoElement = nextElement(infoElement);
-                    }
-                }
-
-                /*
-                 * For complex expressions involving constants, see if it's possible to fold the
-                 * tests by using stamps one level up in the expression. For instance, (x + n < y)
-                 * might fold if something is known about x and all other values are constants. The
-                 * reason for the constant restriction is that if more than 1 real value is involved
-                 * the code might need to adopt multiple guards to have proper dependences.
-                 */
-                if (x instanceof BinaryArithmeticNode<?> && y.isConstant()) {
-                    BinaryArithmeticNode<?> binary = (BinaryArithmeticNode<?>) x;
-                    if (binary.getY().isConstant()) {
-                        infoElement = getInfoElements(binary.getX());
-                        while (infoElement != null) {
-                            Stamp newStampX = binary.foldStamp(infoElement.getStamp(), binary.getY().stamp(NodeView.DEFAULT));
-                            TriState result = binaryOpLogicNode.tryFold(newStampX, y.stamp(NodeView.DEFAULT));
-                            if (result.isKnown()) {
-                                return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), newStampX, rewireGuardFunction);
-                            }
-                            infoElement = nextElement(infoElement);
-                        }
-                    }
-                }
-
-                if (thisGuard != null && binaryOpLogicNode instanceof IntegerEqualsNode && !thisGuard.isNegated()) {
-                    if (y.isConstant() && x instanceof AndNode) {
-                        AndNode and = (AndNode) x;
-                        if (and.getY() == y) {
-                            /*
-                             * This 'and' proves something about some of the bits in and.getX().
-                             * It's equivalent to or'ing in the mask value since those values are
-                             * known to be set.
-                             */
-                            BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp(NodeView.DEFAULT)).getOr();
-                            IntegerStamp newStampX = (IntegerStamp) op.foldStamp(getSafeStamp(and.getX()), getOtherSafeStamp(y));
-                            if (foldPendingTest(thisGuard, and.getX(), newStampX, rewireGuardFunction)) {
-                                return true;
-                            }
-                        }
-                    }
-                }
-
-                if (thisGuard != null) {
-                    if (!x.isConstant()) {
-                        Stamp newStampX = binaryOpLogicNode.getSucceedingStampForX(thisGuard.isNegated(), getSafeStamp(x), getOtherSafeStamp(y));
-                        if (newStampX != null && foldPendingTest(thisGuard, x, newStampX, rewireGuardFunction)) {
-                            return true;
-                        }
-                    }
-                    if (!y.isConstant()) {
-                        Stamp newStampY = binaryOpLogicNode.getSucceedingStampForY(thisGuard.isNegated(), getOtherSafeStamp(x), getSafeStamp(y));
-                        if (newStampY != null && foldPendingTest(thisGuard, y, newStampY, rewireGuardFunction)) {
-                            return true;
-                        }
-                    }
-                }
-            } else if (node instanceof ShortCircuitOrNode) {
-                final ShortCircuitOrNode shortCircuitOrNode = (ShortCircuitOrNode) node;
-                return tryProveCondition(shortCircuitOrNode.getX(), (guard, result, guardedValueStamp, newInput) -> {
-                    if (result == !shortCircuitOrNode.isXNegated()) {
-                        return rewireGuards(guard, true, newInput, guardedValueStamp, rewireGuardFunction);
-                    } else {
-                        return tryProveCondition(shortCircuitOrNode.getY(), (innerGuard, innerResult, innerGuardedValueStamp, innerNewInput) -> {
-                            ValueNode proxifiedInput = newInput;
-                            if (proxifiedInput == null) {
-                                proxifiedInput = innerNewInput;
-                            } else if (innerNewInput != null) {
-                                if (innerNewInput != newInput) {
-                                    // Cannot canonicalize due to different proxied inputs.
-                                    return false;
-                                }
-                            }
-                            // Can only canonicalize if the guards are equal.
-                            if (innerGuard == guard) {
-                                return rewireGuards(guard, innerResult ^ shortCircuitOrNode.isYNegated(), proxifiedInput, guardedValueStamp, rewireGuardFunction);
-                            }
-                            return false;
-                        });
-                    }
-                });
-            }
-
-            return false;
-        }
-
         protected void registerNewStamp(ValueNode maybeProxiedValue, Stamp newStamp, GuardingNode guard) {
             registerNewStamp(maybeProxiedValue, newStamp, guard, false);
         }
@@ -1179,95 +945,6 @@ public class ConditionalEliminationPhase extends BasePhase<CoreProviders> {
         }
     }
 
-    @FunctionalInterface
-    protected interface InfoElementProvider {
-        Iterable<InfoElement> getInfoElements(ValueNode value);
-    }
-
-    /**
-     * Checks for safe nodes when moving pending tests up.
-     */
-    static class InputFilter extends Node.EdgeVisitor {
-        boolean ok;
-        private ValueNode value;
-
-        InputFilter(ValueNode value) {
-            this.value = value;
-            this.ok = true;
-        }
-
-        @Override
-        public Node apply(Node node, Node curNode) {
-            if (!ok) {
-                // Abort the recursion
-                return curNode;
-            }
-            if (!(curNode instanceof ValueNode)) {
-                ok = false;
-                return curNode;
-            }
-            ValueNode curValue = (ValueNode) curNode;
-            if (curValue.isConstant() || curValue == value || curValue instanceof ParameterNode) {
-                return curNode;
-            }
-            if (curValue instanceof BinaryNode || curValue instanceof UnaryNode) {
-                curValue.applyInputs(this);
-            } else {
-                ok = false;
-            }
-            return curNode;
-        }
-    }
-
-    @FunctionalInterface
-    protected interface GuardRewirer {
-        /**
-         * Called if the condition could be proven to have a constant value ({@code result}) under
-         * {@code guard}.
-         *
-         * @param guard the guard whose result is proven
-         * @param result the known result of the guard
-         * @param newInput new input to pi nodes depending on the new guard
-         * @return whether the transformation could be applied
-         */
-        boolean rewire(GuardingNode guard, boolean result, Stamp guardedValueStamp, ValueNode newInput);
-    }
-
-    protected static final class InfoElement {
-        private final Stamp stamp;
-        private final GuardingNode guard;
-        private final ValueNode proxifiedInput;
-        private final InfoElement parent;
-
-        public InfoElement(Stamp stamp, GuardingNode guard, ValueNode proxifiedInput, InfoElement parent) {
-            this.stamp = stamp;
-            this.guard = guard;
-            this.proxifiedInput = proxifiedInput;
-            this.parent = parent;
-        }
-
-        public InfoElement getParent() {
-            return parent;
-        }
-
-        public Stamp getStamp() {
-            return stamp;
-        }
-
-        public GuardingNode getGuard() {
-            return guard;
-        }
-
-        public ValueNode getProxifiedInput() {
-            return proxifiedInput;
-        }
-
-        @Override
-        public String toString() {
-            return stamp + " -> " + guard;
-        }
-    }
-
     @Override
     public float codeSizeIncrease() {
         return 1.5f;
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationUtil.java
new file mode 100644
index 00000000000..529d45f670c
--- /dev/null
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationUtil.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2019, 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.phases.common;
+
+import java.util.ArrayDeque;
+
+import jdk.internal.vm.compiler.collections.Pair;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Or;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.BinaryOpLogicNode;
+import org.graalvm.compiler.nodes.DeoptimizingGuard;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.NodeView;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.ShortCircuitOrNode;
+import org.graalvm.compiler.nodes.UnaryOpLogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AndNode;
+import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
+import org.graalvm.compiler.nodes.calc.BinaryNode;
+import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
+import org.graalvm.compiler.nodes.calc.UnaryNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.TriState;
+
+public class ConditionalEliminationUtil {
+
+    public static final class Marks {
+
+        final int infoElementOperations;
+        final int conditions;
+
+        public Marks(int infoElementOperations, int conditions) {
+            this.infoElementOperations = infoElementOperations;
+            this.conditions = conditions;
+        }
+
+        public int getInfoElementOperations() {
+            return infoElementOperations;
+        }
+
+        public int getConditions() {
+            return conditions;
+        }
+    }
+
+    public static final class GuardedCondition {
+        private final GuardingNode guard;
+        private final LogicNode condition;
+        private final boolean negated;
+
+        public GuardedCondition(GuardingNode guard, LogicNode condition, boolean negated) {
+            this.guard = guard;
+            this.condition = condition;
+            this.negated = negated;
+        }
+
+        public GuardingNode getGuard() {
+            return guard;
+        }
+
+        public LogicNode getCondition() {
+            return condition;
+        }
+
+        public boolean isNegated() {
+            return negated;
+        }
+    }
+
+    @FunctionalInterface
+    public interface GuardRewirer {
+        /**
+         * Called if the condition could be proven to have a constant value ({@code result}) under
+         * {@code guard}.
+         *
+         * @param guard the guard whose result is proven
+         * @param result the known result of the guard
+         * @param newInput new input to pi nodes depending on the new guard
+         * @return whether the transformation could be applied
+         */
+        boolean rewire(GuardingNode guard, boolean result, Stamp guardedValueStamp, ValueNode newInput);
+    }
+
+    /**
+     * Checks for safe nodes when moving pending tests up.
+     */
+    public static class InputFilter extends Node.EdgeVisitor {
+        boolean ok;
+        private ValueNode value;
+
+        InputFilter(ValueNode value) {
+            this.value = value;
+            this.ok = true;
+        }
+
+        @Override
+        public Node apply(Node node, Node curNode) {
+            if (!ok) {
+                // Abort the recursion
+                return curNode;
+            }
+            if (!(curNode instanceof ValueNode)) {
+                ok = false;
+                return curNode;
+            }
+            ValueNode curValue = (ValueNode) curNode;
+            if (curValue.isConstant() || curValue == value || curValue instanceof ParameterNode) {
+                return curNode;
+            }
+            if (curValue instanceof BinaryNode || curValue instanceof UnaryNode) {
+                curValue.applyInputs(this);
+            } else {
+                ok = false;
+            }
+            return curNode;
+        }
+    }
+
+    public static final class InfoElement {
+        private final Stamp stamp;
+        private final GuardingNode guard;
+        private final ValueNode proxifiedInput;
+        private final InfoElement parent;
+
+        public InfoElement(Stamp stamp, GuardingNode guard, ValueNode proxifiedInput, InfoElement parent) {
+            this.stamp = stamp;
+            this.guard = guard;
+            this.proxifiedInput = proxifiedInput;
+            this.parent = parent;
+        }
+
+        public InfoElement getParent() {
+            return parent;
+        }
+
+        public Stamp getStamp() {
+            return stamp;
+        }
+
+        public GuardingNode getGuard() {
+            return guard;
+        }
+
+        public ValueNode getProxifiedInput() {
+            return proxifiedInput;
+        }
+
+        @Override
+        public String toString() {
+            return stamp + " -> " + guard;
+        }
+    }
+
+    /**
+     * Get the stamp that may be used for the value for which we are registering the condition. We
+     * may directly use the stamp here without restriction, because any later lookup of the
+     * registered info elements is in the same chain of pi nodes.
+     */
+    public static Stamp getSafeStamp(ValueNode x) {
+        return x.stamp(NodeView.DEFAULT);
+    }
+
+    /**
+     * We can only use the stamp of a second value involved in the condition if we are sure that we
+     * are not implicitly creating a dependency on a pi node that is responsible for that stamp. For
+     * now, we are conservatively only using the stamps of constants. Under certain circumstances,
+     * we may also be able to use the stamp of the value after skipping pi nodes (e.g., the stamp of
+     * a parameter after inlining, or the stamp of a fixed node that can never be replaced with a pi
+     * node via canonicalization).
+     */
+    public static Stamp getOtherSafeStamp(ValueNode x) {
+        if (x.isConstant() || x.graph().isAfterFixedReadPhase()) {
+            return x.stamp(NodeView.DEFAULT);
+        }
+        return x.stamp(NodeView.DEFAULT).unrestricted();
+    }
+
+    @FunctionalInterface
+    public interface InfoElementProvider {
+        InfoElement infoElements(ValueNode value);
+
+        default InfoElement nextElement(InfoElement current) {
+            InfoElement parent = current.getParent();
+            if (parent != null) {
+                return parent;
+            } else {
+                ValueNode proxifiedInput = current.getProxifiedInput();
+                if (proxifiedInput instanceof PiNode) {
+                    PiNode piNode = (PiNode) proxifiedInput;
+                    return infoElements(piNode.getOriginalNode());
+                }
+            }
+            return null;
+        }
+    }
+
+    public static Pair<InfoElement, Stamp> recursiveFoldStamp(InfoElementProvider infoElementProvider, Node node) {
+        if (node instanceof UnaryNode) {
+            UnaryNode unary = (UnaryNode) node;
+            ValueNode value = unary.getValue();
+            InfoElement infoElement = infoElementProvider.infoElements(value);
+            while (infoElement != null) {
+                Stamp result = unary.foldStamp(infoElement.getStamp());
+                if (result != null) {
+                    return Pair.create(infoElement, result);
+                }
+                infoElement = infoElementProvider.nextElement(infoElement);
+            }
+        } else if (node instanceof BinaryNode) {
+            BinaryNode binary = (BinaryNode) node;
+            ValueNode y = binary.getY();
+            ValueNode x = binary.getX();
+            if (y.isConstant()) {
+                InfoElement infoElement = infoElementProvider.infoElements(x);
+                while (infoElement != null) {
+                    Stamp result = binary.foldStamp(infoElement.getStamp(), y.stamp(NodeView.DEFAULT));
+                    if (result != null) {
+                        return Pair.create(infoElement, result);
+                    }
+                    infoElement = infoElementProvider.nextElement(infoElement);
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Recursively try to fold stamps within this expression using information from
+     * {@link InfoElementProvider#infoElements(ValueNode)}. It's only safe to use constants and one
+     * {@link InfoElement} otherwise more than one guard would be required.
+     *
+     * @param node
+     * @return the pair of the @{link InfoElement} used and the stamp produced for the whole
+     *         expression
+     */
+    public static Pair<InfoElement, Stamp> recursiveFoldStampFromInfo(InfoElementProvider infoElementProvider, Node node) {
+        return recursiveFoldStamp(infoElementProvider, node);
+    }
+
+    public static boolean rewireGuards(GuardingNode guard, boolean result, ValueNode proxifiedInput, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) {
+        return rewireGuardFunction.rewire(guard, result, guardedValueStamp, proxifiedInput);
+    }
+
+    @FunctionalInterface
+    public interface GuardFolding {
+        boolean foldGuard(DeoptimizingGuard thisGuard, ValueNode original, Stamp newStamp, GuardRewirer rewireGuardFunction);
+    }
+
+    public static boolean tryProveGuardCondition(InfoElementProvider infoElementProvider, ArrayDeque<GuardedCondition> conditions, GuardFolding guardFolding, DeoptimizingGuard thisGuard,
+                    LogicNode node,
+                    GuardRewirer rewireGuardFunction) {
+        InfoElement infoElement = infoElementProvider.infoElements(node);
+        while (infoElement != null) {
+            Stamp stamp = infoElement.getStamp();
+            JavaConstant constant = (JavaConstant) stamp.asConstant();
+            if (constant != null) {
+                // No proxified input and stamp required.
+                return rewireGuards(infoElement.getGuard(), constant.asBoolean(), null, null, rewireGuardFunction);
+            }
+            infoElement = infoElementProvider.nextElement(infoElement);
+        }
+
+        for (GuardedCondition guardedCondition : conditions) {
+            TriState result = guardedCondition.getCondition().implies(guardedCondition.isNegated(), node);
+            if (result.isKnown()) {
+                return rewireGuards(guardedCondition.getGuard(), result.toBoolean(), null, null, rewireGuardFunction);
+            }
+        }
+
+        if (node instanceof UnaryOpLogicNode) {
+            UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) node;
+            ValueNode value = unaryLogicNode.getValue();
+            infoElement = infoElementProvider.infoElements(value);
+            while (infoElement != null) {
+                Stamp stamp = infoElement.getStamp();
+                TriState result = unaryLogicNode.tryFold(stamp);
+                if (result.isKnown()) {
+                    return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), infoElement.getStamp(), rewireGuardFunction);
+                }
+                infoElement = infoElementProvider.nextElement(infoElement);
+            }
+            Pair<InfoElement, Stamp> foldResult = recursiveFoldStampFromInfo(infoElementProvider, value);
+            if (foldResult != null) {
+                TriState result = unaryLogicNode.tryFold(foldResult.getRight());
+                if (result.isKnown()) {
+                    return rewireGuards(foldResult.getLeft().getGuard(), result.toBoolean(), foldResult.getLeft().getProxifiedInput(), foldResult.getRight(), rewireGuardFunction);
+                }
+            }
+            if (thisGuard != null && guardFolding != null) {
+                Stamp newStamp = unaryLogicNode.getSucceedingStampForValue(thisGuard.isNegated());
+                if (newStamp != null && guardFolding.foldGuard(thisGuard, value, newStamp, rewireGuardFunction)) {
+                    return true;
+                }
+
+            }
+        } else if (node instanceof BinaryOpLogicNode) {
+            BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) node;
+            ValueNode x = binaryOpLogicNode.getX();
+            ValueNode y = binaryOpLogicNode.getY();
+            infoElement = infoElementProvider.infoElements(x);
+            while (infoElement != null) {
+                TriState result = binaryOpLogicNode.tryFold(infoElement.getStamp(), y.stamp(NodeView.DEFAULT));
+                if (result.isKnown()) {
+                    return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), infoElement.getStamp(), rewireGuardFunction);
+                }
+                infoElement = infoElementProvider.nextElement(infoElement);
+            }
+
+            if (y.isConstant()) {
+                Pair<InfoElement, Stamp> foldResult = recursiveFoldStampFromInfo(infoElementProvider, x);
+                if (foldResult != null) {
+                    TriState result = binaryOpLogicNode.tryFold(foldResult.getRight(), y.stamp(NodeView.DEFAULT));
+                    if (result.isKnown()) {
+                        return rewireGuards(foldResult.getLeft().getGuard(), result.toBoolean(), foldResult.getLeft().getProxifiedInput(), foldResult.getRight(), rewireGuardFunction);
+                    }
+                }
+            } else {
+                infoElement = infoElementProvider.infoElements(y);
+                while (infoElement != null) {
+                    TriState result = binaryOpLogicNode.tryFold(x.stamp(NodeView.DEFAULT), infoElement.getStamp());
+                    if (result.isKnown()) {
+                        return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), infoElement.getStamp(), rewireGuardFunction);
+                    }
+                    infoElement = infoElementProvider.nextElement(infoElement);
+                }
+            }
+
+            /*
+             * For complex expressions involving constants, see if it's possible to fold the tests
+             * by using stamps one level up in the expression. For instance, (x + n < y) might fold
+             * if something is known about x and all other values are constants. The reason for the
+             * constant restriction is that if more than 1 real value is involved the code might
+             * need to adopt multiple guards to have proper dependences.
+             */
+            if (x instanceof BinaryArithmeticNode<?> && y.isConstant()) {
+                BinaryArithmeticNode<?> binary = (BinaryArithmeticNode<?>) x;
+                if (binary.getY().isConstant()) {
+                    infoElement = infoElementProvider.infoElements(binary.getX());
+                    while (infoElement != null) {
+                        Stamp newStampX = binary.foldStamp(infoElement.getStamp(), binary.getY().stamp(NodeView.DEFAULT));
+                        TriState result = binaryOpLogicNode.tryFold(newStampX, y.stamp(NodeView.DEFAULT));
+                        if (result.isKnown()) {
+                            return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), newStampX, rewireGuardFunction);
+                        }
+                        infoElement = infoElementProvider.nextElement(infoElement);
+                    }
+                }
+            }
+
+            if (thisGuard != null && guardFolding != null && binaryOpLogicNode instanceof IntegerEqualsNode && !thisGuard.isNegated()) {
+                if (y.isConstant() && x instanceof AndNode) {
+                    AndNode and = (AndNode) x;
+                    if (and.getY() == y) {
+                        /*
+                         * This 'and' proves something about some of the bits in and.getX(). It's
+                         * equivalent to or'ing in the mask value since those values are known to be
+                         * set.
+                         */
+                        BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp(NodeView.DEFAULT)).getOr();
+                        IntegerStamp newStampX = (IntegerStamp) op.foldStamp(getSafeStamp(and.getX()), getOtherSafeStamp(y));
+                        if (guardFolding.foldGuard(thisGuard, and.getX(), newStampX, rewireGuardFunction)) {
+                            return true;
+                        }
+                    }
+                }
+            }
+
+            if (thisGuard != null && guardFolding != null) {
+                if (!x.isConstant()) {
+                    Stamp newStampX = binaryOpLogicNode.getSucceedingStampForX(thisGuard.isNegated(), getSafeStamp(x), getOtherSafeStamp(y));
+                    if (newStampX != null && guardFolding.foldGuard(thisGuard, x, newStampX, rewireGuardFunction)) {
+                        return true;
+                    }
+                }
+                if (!y.isConstant() && guardFolding != null) {
+                    Stamp newStampY = binaryOpLogicNode.getSucceedingStampForY(thisGuard.isNegated(), getOtherSafeStamp(x), getSafeStamp(y));
+                    if (newStampY != null && guardFolding.foldGuard(thisGuard, y, newStampY, rewireGuardFunction)) {
+                        return true;
+                    }
+                }
+            }
+        } else if (node instanceof ShortCircuitOrNode) {
+            final ShortCircuitOrNode shortCircuitOrNode = (ShortCircuitOrNode) node;
+            return tryProveGuardCondition(infoElementProvider, conditions, guardFolding, null, shortCircuitOrNode.getX(), (guard, result, guardedValueStamp, newInput) -> {
+                if (result == !shortCircuitOrNode.isXNegated()) {
+                    return rewireGuards(guard, true, newInput, guardedValueStamp, rewireGuardFunction);
+                } else {
+                    return tryProveGuardCondition(infoElementProvider, conditions, guardFolding, null, shortCircuitOrNode.getY(), (innerGuard, innerResult, innerGuardedValueStamp, innerNewInput) -> {
+                        ValueNode proxifiedInput = newInput;
+                        if (proxifiedInput == null) {
+                            proxifiedInput = innerNewInput;
+                        } else if (innerNewInput != null) {
+                            if (innerNewInput != newInput) {
+                                // Cannot canonicalize due to different proxied inputs.
+                                return false;
+                            }
+                        }
+                        // Can only canonicalize if the guards are equal.
+                        if (innerGuard == guard) {
+                            return rewireGuards(guard, innerResult ^ shortCircuitOrNode.isYNegated(), proxifiedInput, guardedValueStamp, rewireGuardFunction);
+                        }
+                        return false;
+                    });
+                }
+            });
+        }
+
+        return false;
+    }
+
+}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java
index cbd6cebe4ce..742f4e67b90 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java
@@ -43,7 +43,6 @@ import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.List;
 
-import jdk.vm.ci.meta.JavaConstant;
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
@@ -135,6 +134,7 @@ import org.graalvm.compiler.nodes.memory.WriteNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.memory.address.IndexAddressNode;
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.GCProvider;
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
@@ -157,6 +157,7 @@ import jdk.vm.ci.code.MemoryBarriers;
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.DeoptimizationAction;
 import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaField;
@@ -673,24 +674,25 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider {
      * @param tool utility for performing the lowering
      */
     protected void lowerUnsafeLoadNode(RawLoadNode load, LoweringTool tool) {
+        GCProvider gc = tool.getProviders().getGC();
         StructuredGraph graph = load.graph();
         if (load instanceof GuardedUnsafeLoadNode) {
             GuardedUnsafeLoadNode guardedLoad = (GuardedUnsafeLoadNode) load;
             GuardingNode guard = guardedLoad.getGuard();
             if (guard == null) {
                 // can float freely if the guard folded away
-                ReadNode memoryRead = createUnsafeRead(graph, load, null);
+                ReadNode memoryRead = createUnsafeRead(gc, graph, load, null);
                 memoryRead.setForceFixed(false);
                 graph.replaceFixedWithFixed(load, memoryRead);
             } else {
                 // must be guarded, but flows below the guard
-                ReadNode memoryRead = createUnsafeRead(graph, load, guard);
+                ReadNode memoryRead = createUnsafeRead(gc, graph, load, guard);
                 graph.replaceFixedWithFixed(load, memoryRead);
             }
         } else {
             // never had a guarding condition so it must be fixed, creation of the read will force
             // it to be fixed
-            ReadNode memoryRead = createUnsafeRead(graph, load, null);
+            ReadNode memoryRead = createUnsafeRead(gc, graph, load, null);
             graph.replaceFixedWithFixed(load, memoryRead);
         }
     }
@@ -703,12 +705,12 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider {
         }
     }
 
-    protected ReadNode createUnsafeRead(StructuredGraph graph, RawLoadNode load, GuardingNode guard) {
+    protected ReadNode createUnsafeRead(GCProvider gc, StructuredGraph graph, RawLoadNode load, GuardingNode guard) {
         boolean compressible = load.accessKind() == JavaKind.Object;
         JavaKind readKind = load.accessKind();
         Stamp loadStamp = loadStamp(load.stamp(NodeView.DEFAULT), readKind, compressible);
         AddressNode address = createUnsafeAddress(graph, load.object(), load.offset());
-        ReadNode memoryRead = graph.add(new ReadNode(address, load.getLocationIdentity(), loadStamp, BarrierType.NONE));
+        ReadNode memoryRead = graph.add(new ReadNode(address, load.getLocationIdentity(), loadStamp, gc.getBarrierSet().readBarrierType(load)));
         if (guard == null) {
             // An unsafe read must not float otherwise it may float above
             // a test guaranteeing the read is safe.
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java
index fbb546bb580..84d02103174 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java
@@ -155,10 +155,18 @@ public class IntrinsicGraphBuilder implements GraphBuilderContext, Receiver {
     @Override
     public void push(JavaKind kind, ValueNode value) {
         assert kind != JavaKind.Void;
-        assert returnValue == null;
+        GraalError.guarantee(returnValue == null, "can only push one value");
         returnValue = value;
     }
 
+    @Override
+    public ValueNode pop(JavaKind slotKind) {
+        GraalError.guarantee(returnValue != null, "no value pushed");
+        ValueNode result = returnValue;
+        returnValue = null;
+        return result;
+    }
+
     @Override
     public Invoke handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean forceInlineEverything) {
         throw GraalError.shouldNotReachHere();
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java
index 3588c071c8f..6526ccc03be 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java
@@ -84,6 +84,7 @@ import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
 import org.graalvm.compiler.nodes.debug.BindToRegisterNode;
 import org.graalvm.compiler.nodes.debug.BlackholeNode;
 import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode;
+import org.graalvm.compiler.nodes.debug.SideEffectNode;
 import org.graalvm.compiler.nodes.debug.SpillRegistersNode;
 import org.graalvm.compiler.nodes.extended.BoxNode;
 import org.graalvm.compiler.nodes.extended.BranchProbabilityNode;
@@ -155,20 +156,22 @@ import sun.misc.Unsafe;
 public class StandardGraphBuilderPlugins {
 
     public static void registerInvocationPlugins(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, InvocationPlugins plugins, Replacements replacements,
-                    boolean allowDeoptimization, boolean explicitUnsafeNullChecks) {
+                    boolean allowDeoptimization, boolean explicitUnsafeNullChecks, boolean arrayEqualsSubstitution) {
         registerObjectPlugins(plugins);
         registerClassPlugins(plugins);
         registerMathPlugins(plugins, allowDeoptimization);
         registerStrictMathPlugins(plugins);
         registerUnsignedMathPlugins(plugins);
-        registerStringPlugins(plugins, replacements, snippetReflection);
+        registerStringPlugins(plugins, replacements, snippetReflection, arrayEqualsSubstitution);
         registerCharacterPlugins(plugins);
         registerShortPlugins(plugins);
         registerIntegerLongPlugins(plugins, JavaKind.Int);
         registerIntegerLongPlugins(plugins, JavaKind.Long);
         registerFloatPlugins(plugins);
         registerDoublePlugins(plugins);
-        registerArraysPlugins(plugins, replacements);
+        if (arrayEqualsSubstitution) {
+            registerArraysPlugins(plugins, replacements);
+        }
         registerArrayPlugins(plugins, replacements);
         registerUnsafePlugins(plugins, replacements, explicitUnsafeNullChecks);
         registerEdgesPlugins(metaAccess, plugins);
@@ -196,7 +199,7 @@ public class StandardGraphBuilderPlugins {
         STRING_CODER_FIELD = coder;
     }
 
-    private static void registerStringPlugins(InvocationPlugins plugins, Replacements replacements, SnippetReflectionProvider snippetReflection) {
+    private static void registerStringPlugins(InvocationPlugins plugins, Replacements replacements, SnippetReflectionProvider snippetReflection, boolean arrayEqualsSubstitution) {
         final Registration r = new Registration(plugins, String.class, replacements);
         r.register1("hashCode", Receiver.class, new InvocationPlugin() {
             @Override
@@ -227,7 +230,9 @@ public class StandardGraphBuilderPlugins {
         });
 
         if (JavaVersionUtil.JAVA_SPEC <= 8) {
-            r.registerMethodSubstitution(StringSubstitutions.class, "equals", Receiver.class, Object.class);
+            if (arrayEqualsSubstitution) {
+                r.registerMethodSubstitution(StringSubstitutions.class, "equals", Receiver.class, Object.class);
+            }
 
             r.register7("indexOf", char[].class, int.class, int.class, char[].class, int.class, int.class, int.class, new StringIndexOfConstantPlugin());
 
@@ -242,7 +247,9 @@ public class StandardGraphBuilderPlugins {
                 }
             });
         } else {
-            r.registerMethodSubstitution(JDK9StringSubstitutions.class, "equals", Receiver.class, Object.class);
+            if (arrayEqualsSubstitution) {
+                r.registerMethodSubstitution(JDK9StringSubstitutions.class, "equals", Receiver.class, Object.class);
+            }
             Registration utf16sub = new Registration(plugins, StringUTF16Substitutions.class, replacements);
             utf16sub.register2("getCharDirect", byte[].class, int.class, new InvocationPlugin() {
                 @Override
@@ -1245,7 +1252,20 @@ public class StandardGraphBuilderPlugins {
                 return true;
             }
         });
-
+        r.register0("sideEffect", new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.add(new SideEffectNode());
+                return true;
+            }
+        });
+        r.register1("sideEffect", int.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode a) {
+                b.addPush(JavaKind.Int, new SideEffectNode(a));
+                return true;
+            }
+        });
         r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode probability, ValueNode condition) {
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/gc/G1WriteBarrierSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/gc/G1WriteBarrierSnippets.java
index f500b05ca99..83425b2bf34 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/gc/G1WriteBarrierSnippets.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/gc/G1WriteBarrierSnippets.java
@@ -48,6 +48,7 @@ import org.graalvm.compiler.nodes.gc.G1ArrayRangePreWriteBarrier;
 import org.graalvm.compiler.nodes.gc.G1PostWriteBarrier;
 import org.graalvm.compiler.nodes.gc.G1PreWriteBarrier;
 import org.graalvm.compiler.nodes.gc.G1ReferentFieldReadBarrier;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode.Address;
@@ -69,6 +70,8 @@ import jdk.internal.vm.compiler.word.Pointer;
 import jdk.internal.vm.compiler.word.UnsignedWord;
 import jdk.internal.vm.compiler.word.WordFactory;
 
+import jdk.vm.ci.meta.ResolvedJavaType;
+
 public abstract class G1WriteBarrierSnippets extends WriteBarrierSnippets implements Snippets {
 
     public static final LocationIdentity GC_LOG_LOCATION = NamedLocationIdentity.mutable("GC-Log");
@@ -164,6 +167,15 @@ public abstract class G1WriteBarrierSnippets extends WriteBarrierSnippets implem
         }
     }
 
+    @Snippet
+    public void g1ReferentReadBarrier(Address address, Object object, Object expectedObject, @ConstantParameter boolean isDynamicCheck, Word offset,
+                    @ConstantParameter int traceStartCycle, @ConstantParameter Counters counters) {
+        if (!isDynamicCheck ||
+                        (offset == WordFactory.unsigned(referentOffset()) && InstanceOfNode.doInstanceof(referenceType(), object))) {
+            g1PreWriteBarrier(address, object, expectedObject, false, false, traceStartCycle, counters);
+        }
+    }
+
     @Snippet
     public void g1PostWriteBarrier(Address address, Object object, Object value, @ConstantParameter boolean usePrecise, @ConstantParameter int traceStartCycle,
                     @ConstantParameter Counters counters) {
@@ -359,6 +371,10 @@ public abstract class G1WriteBarrierSnippets extends WriteBarrierSnippets implem
 
     protected abstract ForeignCallDescriptor printfCallDescriptor();
 
+    protected abstract ResolvedJavaType referenceType();
+
+    protected abstract long referentOffset();
+
     private boolean isTracingActive(int traceStartCycle) {
         return traceStartCycle > 0 && ((Pointer) WordFactory.pointer(gcTotalCollectionsAddress())).readLong(0) > traceStartCycle;
     }
@@ -446,13 +462,10 @@ public abstract class G1WriteBarrierSnippets extends WriteBarrierSnippets implem
 
         public void lower(AbstractTemplates templates, SnippetInfo snippet, G1ReferentFieldReadBarrier barrier, LoweringTool tool) {
             Arguments args = new Arguments(snippet, barrier.graph().getGuardsStage(), tool.getLoweringStage());
-            AddressNode address = barrier.getAddress();
+            // This is expected to be lowered before address lowering
+            OffsetAddressNode address = (OffsetAddressNode) barrier.getAddress();
             args.add("address", address);
-            if (address instanceof OffsetAddressNode) {
-                args.add("object", ((OffsetAddressNode) address).getBase());
-            } else {
-                args.add("object", null);
-            }
+            args.add("object", address.getBase());
 
             ValueNode expected = barrier.getExpectedObject();
             if (expected != null && expected.stamp(NodeView.DEFAULT) instanceof NarrowOopStamp) {
@@ -460,8 +473,8 @@ public abstract class G1WriteBarrierSnippets extends WriteBarrierSnippets implem
             }
 
             args.add("expectedObject", expected);
-            args.addConst("doLoad", barrier.doLoad());
-            args.addConst("nullCheck", false);
+            args.addConst("isDynamicCheck", barrier.isDynamicCheck());
+            args.add("offset", address.getOffset());
             args.addConst("traceStartCycle", traceStartCycle(barrier.graph()));
             args.addConst("counters", counters);
 
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerAddExactNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerAddExactNode.java
index 8c5f75f9ece..39038412abb 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerAddExactNode.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerAddExactNode.java
@@ -42,12 +42,12 @@ import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.extended.GuardedNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
 
 import jdk.vm.ci.code.CodeUtil;
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
-import org.graalvm.compiler.nodes.extended.GuardedNode;
-import org.graalvm.compiler.nodes.extended.GuardingNode;
 
 /**
  * Node representing an exact integer addition that will throw an {@link ArithmeticException} in
@@ -140,6 +140,9 @@ public final class IntegerAddExactNode extends AddNode implements GuardedNode, I
         if (!IntegerStamp.addCanOverflow((IntegerStamp) forX.stamp(NodeView.DEFAULT), (IntegerStamp) forY.stamp(NodeView.DEFAULT))) {
             return new AddNode(forX, forY).canonical(tool);
         }
+        if (getGuard() == null) {
+            return new AddNode(forX, forY).canonical(tool);
+        }
         return this;
     }
 
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerAddExactOverflowNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerAddExactOverflowNode.java
index 9bef4a01be6..a6490d7e701 100644
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerAddExactOverflowNode.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerAddExactOverflowNode.java
@@ -25,10 +25,12 @@
 
 package org.graalvm.compiler.replacements.nodes.arithmetic;
 
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.JavaKind;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.IterableNodeType;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
@@ -40,11 +42,11 @@ import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.BinaryNode;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
 
 @NodeInfo(cycles = CYCLES_2, size = SIZE_2)
-public final class IntegerAddExactOverflowNode extends IntegerExactOverflowNode implements Simplifiable, BinaryCommutative<ValueNode> {
+public final class IntegerAddExactOverflowNode extends IntegerExactOverflowNode implements Simplifiable, BinaryCommutative<ValueNode>, IterableNodeType {
     public static final NodeClass<IntegerAddExactOverflowNode> TYPE = NodeClass.create(IntegerAddExactOverflowNode.class);
 
     public IntegerAddExactOverflowNode(ValueNode x, ValueNode y) {

From abac8b17a9666ff49d088a68aeb909824ebbba21 Mon Sep 17 00:00:00 2001
From: John Jiang <jjiang@openjdk.org>
Date: Mon, 16 Dec 2019 16:19:10 +0800
Subject: [PATCH 10/12] 8235813: System property fullCipherSuites is not used
 by javax/net/ssl/compatibility/Compatibility.java

Reviewed-by: xuelei
---
 .../jdk/javax/net/ssl/compatibility/Cert.java | 30 ++++-----
 .../net/ssl/compatibility/JdkRelease.java     | 61 -------------------
 .../javax/net/ssl/compatibility/UseCase.java  |  2 +-
 3 files changed, 16 insertions(+), 77 deletions(-)
 delete mode 100644 test/jdk/javax/net/ssl/compatibility/JdkRelease.java

diff --git a/test/jdk/javax/net/ssl/compatibility/Cert.java b/test/jdk/javax/net/ssl/compatibility/Cert.java
index b72d0b32b5f..4ffcfc1db37 100644
--- a/test/jdk/javax/net/ssl/compatibility/Cert.java
+++ b/test/jdk/javax/net/ssl/compatibility/Cert.java
@@ -330,23 +330,23 @@ public enum Cert {
     EC_RSA_PRIME256V1_SHA256(
             KeyAlgorithm.EC,
             "-----BEGIN CERTIFICATE-----\n" +
-            "MIIB9TCB3gIUWuMp26pvpTFO08C+ev6W8ZRDwqAwDQYJKoZIhvcNAQELBQAwGjEY\n" +
-            "MBYGA1UEAwwPUlNBLTIwNDgtU0hBMjU2MB4XDTE5MDIyNzA3NTUwMFoXDTM5MDIy\n" +
-            "MjA3NTUwMFowIDEeMBwGA1UEAwwVRUMtUlNBLVNFQ1AyNTYtU0hBMjU2MFkwEwYH\n" +
-            "KoZIzj0CAQYIKoZIzj0DAQcDQgAEgCoIan3yAA4KVwAO4qrMFF1alcYFzywPHerI\n" +
-            "eje3eQVhFaTecnbm0rTJE66JF8HeNuefd61+v1FqWo95aJ1l9zANBgkqhkiG9w0B\n" +
-            "AQsFAAOCAQEAJIgHTHyPJ5X44JR5ee3N2sYA8C9KGf2YFq/yPQ+pYYIk2gNKqMTH\n" +
-            "IgHzEqpeb1KC8i+F57xD8qL76QZ7YGVueKoU0o2XYO8Fj4Kug9B48uYvw4J025Bf\n" +
-            "emxVzuDwgPNAeQwzfoR4NpMKV6TjA7c1VVNUwnse7jHyzqkQLlNors62U+O2MI/t\n" +
-            "4RM6PDLWuGm9eDZAtifxdjjME9efEXOVi2y/9YAr7hOJKn3r1ie1Txo1N3LXTsLg\n" +
-            "Y0GlCcOiDGD5So6jSn4hY2CyeeEtTOZkloT/2Slpz9MbLzlav8hqnNQDbuSCFnyn\n" +
-            "fQh6yysvdeRm6Yx8bNkA/pxz/Y21fXVWMg==\n" +
+            "MIIB9TCB3gIUeM/cp7ZB4C1Gi/elzfbpdCrNPtAwDQYJKoZIhvcNAQELBQAwGjEY\n" +
+            "MBYGA1UEAwwPUlNBLTIwNDgtU0hBMjU2MB4XDTE5MTIxNTEzMDQxMFoXDTM5MTIx\n" +
+            "MDEzMDQxMFowIDEeMBwGA1UEAwwVRUMtUlNBLVNFQ1AyNTYtU0hBMjU2MFkwEwYH\n" +
+            "KoZIzj0CAQYIKoZIzj0DAQcDQgAE/kcsoE9AIKIjGv0IlkSSQvSwRpoO97UJlUks\n" +
+            "F0+MLaw66yOxFvVT7182/oKdJ8HiwZfxmiGEswSumT8yDdMnFzANBgkqhkiG9w0B\n" +
+            "AQsFAAOCAQEAuBUW4HsZ0ICYW6KtKLr9LlZfQdhv9Bc/nU836ASd8cV+PQHH3NSM\n" +
+            "1sUFWqq7ivVxvlNTcXThOrTleK8QN6388K4NRUFEXzROZk9Qo3q6lLpnfWiCIqOF\n" +
+            "DzQerjcUH9L/TgEtAm83tDq0ZgO7G59X8thTE9GjhXJ6bITK7TMh/VtsGzE7cW8r\n" +
+            "kXBNwflorhsR7rywKsASz5snYPYoTM0NZL9T093sxtO86B5sMlfX2rR+/BDQPDsX\n" +
+            "bCnXQNvn3tPuFuUZV1IAmrxG+xLxEaH0vi8eU7N2xMvPQKHGrprk4TvxM/d1Z7xY\n" +
+            "lWJXWvlhmPI3hb2ngLHEFa/gElpcdWi8Tw==\n" +
             "-----END CERTIFICATE-----",
             "308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02" +
-            "0101042079433b715d94d8de6b423f55ef05c911613dc708339391339bef6ca3" +
-            "c14b419ca14403420004802a086a7df2000e0a57000ee2aacc145d5a95c605cf" +
-            "2c0f1deac87a37b779056115a4de7276e6d2b4c913ae8917c1de36e79f77ad7e" +
-            "bf516a5a8f79689d65"),
+            "010104207ce96cbc7fe72e987c6f194afab1b219d26eed446e6b462ed51a8f2a" +
+            "c0619c53a14403420004fe472ca04f4020a2231afd0896449242f4b0469a0ef7" +
+            "b50995492c174f8c2dac3aeb23b116f553ef5f36fe829d27c1e2c197f19a2184" +
+            "b304ae993f320dd32717"),
 
     // This certificate is generated by the below commands:
     // openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 \
diff --git a/test/jdk/javax/net/ssl/compatibility/JdkRelease.java b/test/jdk/javax/net/ssl/compatibility/JdkRelease.java
deleted file mode 100644
index 6ab5a28c896..00000000000
--- a/test/jdk/javax/net/ssl/compatibility/JdkRelease.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2017, 2018, 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.
- */
-
-/*
- * JDK major versions.
- */
-public enum JdkRelease {
-
-    JDK7(7, "1.7"),
-    JDK8(8, "1.8"),
-    JDK9(9, "9"),
-    JDK10(10, "10"),
-    JDK11(11, "11"),
-    JDK12(12, "12");
-
-    public final int sequence;
-    public final String release;
-
-    private JdkRelease(int sequence, String release) {
-        this.sequence = sequence;
-        this.release = release;
-    }
-
-    public static JdkRelease getRelease(String jdkVersion) {
-        if (jdkVersion.startsWith(JDK7.release)) {
-            return JDK7;
-        } else if (jdkVersion.startsWith(JDK8.release)) {
-            return JDK8;
-        } else if (jdkVersion.startsWith(JDK9.release)) {
-            return JDK9;
-        } else if (jdkVersion.startsWith(JDK10.release)) {
-            return JDK10;
-        } else if (jdkVersion.startsWith(JDK11.release)) {
-            return JDK11;
-        } else if (jdkVersion.startsWith(JDK12.release)) {
-            return JDK12;
-        }
-
-        return null;
-    }
-}
diff --git a/test/jdk/javax/net/ssl/compatibility/UseCase.java b/test/jdk/javax/net/ssl/compatibility/UseCase.java
index 7bb06128017..1eb16d636a1 100644
--- a/test/jdk/javax/net/ssl/compatibility/UseCase.java
+++ b/test/jdk/javax/net/ssl/compatibility/UseCase.java
@@ -130,7 +130,7 @@ public class UseCase {
 
     private static final Object[][] PARAMS = new Object[][] {
             PROTOCOLS,
-            FULL_CASES ? CIPHER_SUITES : MANDATORY_CIPHER_SUITES,
+            FULL_CASES || FULL_CIPHER_SUITES ? CIPHER_SUITES : MANDATORY_CIPHER_SUITES,
             FULL_CASES ? new Boolean[] { false, true } : new Boolean[] { true },
             FULL_CASES
                     ? new ServerName[] { ServerName.NONE, ServerName.EXAMPLE }

From fca342f7369a56d7c51f95a3f6607eb4b2d9438f Mon Sep 17 00:00:00 2001
From: Sibabrata Sahoo <ssahoo@openjdk.org>
Date: Mon, 16 Dec 2019 00:23:50 -0800
Subject: [PATCH 11/12] 8235874: The ordering of Cipher Suites is not
 maintained provided through jdk.tls.client.cipherSuites and
 jdk.tls.server.cipherSuites system property

Corrected Cipher Suites ordering through system properties

Reviewed-by: xuelei
---
 .../share/classes/sun/security/ssl/SSLContextImpl.java          | 2 +-
 .../ssl/sanity/ciphersuites/SystemPropCipherSuitesOrder.java    | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java
index d4361701dbf..90c4ec8b6fd 100644
--- a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java
+++ b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java
@@ -373,7 +373,7 @@ public abstract class SSLContextImpl extends SSLContextSpi {
     private static List<CipherSuite> getApplicableCipherSuites(
             Collection<CipherSuite> allowedCipherSuites,
             List<ProtocolVersion> protocols) {
-        TreeSet<CipherSuite> suites = new TreeSet<>();
+        LinkedHashSet<CipherSuite> suites = new LinkedHashSet<>();
         if (protocols != null && (!protocols.isEmpty())) {
             for (CipherSuite suite : allowedCipherSuites) {
                 if (!suite.isAvailable()) {
diff --git a/test/jdk/javax/net/ssl/sanity/ciphersuites/SystemPropCipherSuitesOrder.java b/test/jdk/javax/net/ssl/sanity/ciphersuites/SystemPropCipherSuitesOrder.java
index bf808baf962..84c24384eef 100644
--- a/test/jdk/javax/net/ssl/sanity/ciphersuites/SystemPropCipherSuitesOrder.java
+++ b/test/jdk/javax/net/ssl/sanity/ciphersuites/SystemPropCipherSuitesOrder.java
@@ -30,7 +30,6 @@ import javax.net.ssl.SSLSocket;
  * @library /javax/net/ssl/templates
  *          /javax/net/ssl/TLSCommon
  * @summary Test TLS ciphersuites order set through System properties
- * @ignore Not applicable until the cipher order of system property maintained.
  * @run main/othervm
  *      -Djdk.tls.client.cipherSuites=TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384
  *      -Djdk.tls.server.cipherSuites=TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_GCM_SHA256

From 49048adcf206034e8cfe2877029bfa5523c9eb4c Mon Sep 17 00:00:00 2001
From: Christian Hagedorn <chagedorn@openjdk.org>
Date: Mon, 16 Dec 2019 09:19:52 +0100
Subject: [PATCH 12/12] 8231501: VM crash in
 MethodData::clean_extra_data(CleanExtraDataClosure*): fatal error: unexpected
 tag 99

Snapshot MDO extra trap and argument data only after it is prepared.

Reviewed-by: roland, thartmann
---
 src/hotspot/share/ci/ciMethodData.cpp | 67 +++++++++++++++++++--------
 src/hotspot/share/ci/ciMethodData.hpp |  2 +-
 src/hotspot/share/oops/methodData.hpp |  9 ++--
 3 files changed, 53 insertions(+), 25 deletions(-)

diff --git a/src/hotspot/share/ci/ciMethodData.cpp b/src/hotspot/share/ci/ciMethodData.cpp
index e1f4af3ac64..fae10b58eb2 100644
--- a/src/hotspot/share/ci/ciMethodData.cpp
+++ b/src/hotspot/share/ci/ciMethodData.cpp
@@ -145,7 +145,7 @@ void ciMethodData::prepare_metadata() {
   }
 }
 
-void ciMethodData::load_extra_data() {
+void ciMethodData::load_remaining_extra_data() {
   MethodData* mdo = get_MethodData();
   MutexLocker ml(mdo->extra_data_lock());
   // Deferred metadata cleaning due to concurrent class unloading.
@@ -154,6 +154,14 @@ void ciMethodData::load_extra_data() {
   // and no safepoints can introduce more stale metadata.
   NoSafepointVerifier no_safepoint;
 
+  assert((mdo->data_size() == _data_size) && (mdo->extra_data_size() == _extra_data_size), "sanity, unchanged");
+  assert(extra_data_base() == (DataLayout*)((address) _data + _data_size), "sanity");
+
+  // Copy the extra data once it is prepared (i.e. cache populated, no release of extra data lock anymore)
+  Copy::disjoint_words_atomic((HeapWord*) mdo->extra_data_base(),
+                              (HeapWord*)((address) _data + _data_size),
+                              (_extra_data_size - mdo->parameters_size_in_bytes()) / HeapWordSize);
+
   // speculative trap entries also hold a pointer to a Method so need to be translated
   DataLayout* dp_src  = mdo->extra_data_base();
   DataLayout* end_src = mdo->args_data_limit();
@@ -162,19 +170,7 @@ void ciMethodData::load_extra_data() {
     assert(dp_src < end_src, "moved past end of extra data");
     assert(((intptr_t)dp_dst) - ((intptr_t)extra_data_base()) == ((intptr_t)dp_src) - ((intptr_t)mdo->extra_data_base()), "source and destination don't match");
 
-    // New traps in the MDO may have been added since we copied the
-    // data (concurrent deoptimizations before we acquired
-    // extra_data_lock above) or can be removed (a safepoint may occur
-    // in the prepare_metadata call above) as we translate the copy:
-    // update the copy as we go.
     int tag = dp_src->tag();
-    size_t entry_size = DataLayout::header_size_in_bytes();
-    if (tag != DataLayout::no_tag) {
-      ProfileData* src_data = dp_src->data_in();
-      entry_size = src_data->size_in_bytes();
-    }
-    memcpy(dp_dst, dp_src, entry_size);
-
     switch(tag) {
     case DataLayout::speculative_trap_data_tag: {
       ciSpeculativeTrapData data_dst(dp_dst);
@@ -205,9 +201,31 @@ void ciMethodData::load_data() {
   // To do: don't copy the data if it is not "ripe" -- require a minimum #
   // of invocations.
 
-  // Snapshot the data -- actually, take an approximate snapshot of
-  // the data.  Any concurrently executing threads may be changing the
-  // data as we copy it.
+  // Snapshot the data and extra parameter data first without the extra trap and arg info data.
+  // Those are copied in a second step. Actually, an approximate snapshot of the data is taken.
+  // Any concurrently executing threads may be changing the data as we copy it.
+  //
+  // The first snapshot step requires two copies (data entries and parameter data entries) since
+  // the MDO is laid out as follows:
+  //
+  //  data_base:        ---------------------------
+  //                    |       data entries      |
+  //                    |           ...           |
+  //  extra_data_base:  ---------------------------
+  //                    |    trap data entries    |
+  //                    |           ...           |
+  //                    | one arg info data entry |
+  //                    |    data for each arg    |
+  //                    |           ...           |
+  //  args_data_limit:  ---------------------------
+  //                    |  parameter data entries |
+  //                    |           ...           |
+  //  extra_data_limit: ---------------------------
+  //
+  // _data_size = extra_data_base - data_base
+  // _extra_data_size = extra_data_limit - extra_data_base
+  // total_size = _data_size + _extra_data_size
+  // args_data_limit = data_base + total_size - parameter_data_size
   Copy::disjoint_words_atomic((HeapWord*) mdo,
                               (HeapWord*) &_orig,
                               sizeof(_orig) / HeapWordSize);
@@ -218,8 +236,15 @@ void ciMethodData::load_data() {
   _data = (intptr_t *) arena->Amalloc(total_size);
   Copy::disjoint_words_atomic((HeapWord*) mdo->data_base(),
                               (HeapWord*) _data,
-                              total_size / HeapWordSize);
+                              _data_size / HeapWordSize);
 
+  int parameters_data_size = mdo->parameters_size_in_bytes();
+  if (parameters_data_size > 0) {
+    // Snapshot the parameter data
+    Copy::disjoint_words_atomic((HeapWord*) mdo->args_data_limit(),
+                                (HeapWord*) ((address)_data + total_size - parameters_data_size),
+                                parameters_data_size / HeapWordSize);
+  }
   // Traverse the profile data, translating any oops into their
   // ci equivalents.
   ResourceMark rm;
@@ -236,7 +261,9 @@ void ciMethodData::load_data() {
     parameters->translate_from(mdo->parameters_type_data());
   }
 
-  load_extra_data();
+  assert((DataLayout*) ((address)_data + total_size - parameters_data_size) == args_data_limit(),
+      "sanity - parameter data starts after the argument data of the single ArgInfoData entry");
+  load_remaining_extra_data();
 
   // Note:  Extra data are all BitData, and do not need translation.
   _current_mileage = MethodData::mileage_of(mdo->method());
@@ -360,7 +387,7 @@ ciProfileData* ciMethodData::bci_to_extra_data(int bci, ciMethod* m, bool& two_f
       two_free_slots = (MethodData::next_extra(dp)->tag() == DataLayout::no_tag);
       return NULL;
     case DataLayout::arg_info_data_tag:
-      return NULL; // ArgInfoData is at the end of extra data section.
+      return NULL; // ArgInfoData is after the trap data right before the parameter data.
     case DataLayout::bit_data_tag:
       if (m == NULL && dp->bci() == bci) {
         return new ciBitData(dp);
@@ -767,7 +794,7 @@ void ciMethodData::print_data_on(outputStream* st) {
       break;
     case DataLayout::arg_info_data_tag:
       data = new ciArgInfoData(dp);
-      dp = end; // ArgInfoData is at the end of extra data section.
+      dp = end; // ArgInfoData is after the trap data right before the parameter data.
       break;
     case DataLayout::speculative_trap_data_tag:
       data = new ciSpeculativeTrapData(dp);
diff --git a/src/hotspot/share/ci/ciMethodData.hpp b/src/hotspot/share/ci/ciMethodData.hpp
index 260f509aecd..09f692fd7a6 100644
--- a/src/hotspot/share/ci/ciMethodData.hpp
+++ b/src/hotspot/share/ci/ciMethodData.hpp
@@ -462,7 +462,7 @@ private:
   ciArgInfoData *arg_info() const;
 
   void prepare_metadata();
-  void load_extra_data();
+  void load_remaining_extra_data();
   ciProfileData* bci_to_extra_data(int bci, ciMethod* m, bool& two_free_slots);
 
   void dump_replay_data_type_helper(outputStream* out, int round, int& count, ProfileData* pdata, ByteSize offset, ciKlass* k);
diff --git a/src/hotspot/share/oops/methodData.hpp b/src/hotspot/share/oops/methodData.hpp
index 185bc1fceb4..fe7541a8ea3 100644
--- a/src/hotspot/share/oops/methodData.hpp
+++ b/src/hotspot/share/oops/methodData.hpp
@@ -2079,10 +2079,6 @@ private:
   // parameter profiling.
   enum { no_parameters = -2, parameters_uninitialized = -1 };
   int _parameters_type_data_di;
-  int parameters_size_in_bytes() const {
-    ParametersTypeData* param = parameters_type_data();
-    return param == NULL ? 0 : param->size_in_bytes();
-  }
 
   // Beginning of the data entries
   intptr_t _data[1];
@@ -2300,6 +2296,11 @@ public:
     return _data_size;
   }
 
+  int parameters_size_in_bytes() const {
+    ParametersTypeData* param = parameters_type_data();
+    return param == NULL ? 0 : param->size_in_bytes();
+  }
+
   // Accessors
   Method* method() const { return _method; }