changeset 50922:47ce05a9b63b condy-folding

manual merge with branch jep-334
author vromero
date Thu, 31 May 2018 13:09:04 -0700
parents 80c69f5cd21a 33e5cd5815b7
children 8702994c0314
files make/CompileJavaModules.gmk make/test/JtregNativeHotspot.gmk src/hotspot/share/interpreter/linkResolver.cpp src/java.base/share/classes/java/lang/invoke/MethodHandles.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugValueMap.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/aaa src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/META-INF/services/javax.annotation.processing.Processor src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/APHotSpotSignature.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/AbstractVerifier.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/ClassSubstitutionVerifier.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/FoldVerifier.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedFoldPlugin.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedNodeIntrinsicPlugin.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedPlugin.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/InjectedDependencies.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/MethodSubstitutionVerifier.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/NodeIntrinsicVerifier.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/PluginGenerator.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/VerifierAnnotationProcessor.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/D
diffstat 628 files changed, 78956 insertions(+), 4786 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Thu May 31 06:15:17 2018 -0700
+++ b/.hgtags	Thu May 31 13:09:04 2018 -0700
@@ -487,3 +487,4 @@
 758deedaae8406ae60147486107a54e9864aa7b0 jdk-11+13
 3595bd343b65f8c37818ebe6a4c343ddeb1a5f88 jdk-11+14
 a11c1cb542bbd1671d25b85efe7d09b983c48525 jdk-11+15
+02934b0d661b82b7fe1052a04998d2091352e08d jdk-11+16
--- a/make/CompileJavaModules.gmk	Thu May 31 06:15:17 2018 -0700
+++ b/make/CompileJavaModules.gmk	Thu May 31 13:09:04 2018 -0700
@@ -444,11 +444,13 @@
 
 jdk.internal.vm.compiler_EXCLUDES += \
     jdk.internal.vm.compiler.collections.test \
+    org.graalvm.compiler.processor \
     org.graalvm.compiler.core.match.processor \
     org.graalvm.compiler.nodeinfo.processor \
     org.graalvm.compiler.options.processor \
     org.graalvm.compiler.serviceprovider.processor \
-    org.graalvm.compiler.replacements.verifier \
+    org.graalvm.compiler.replacements.processor \
+    org.graalvm.compiler.replacements.jdk9.test \
     org.graalvm.compiler.api.directives.test \
     org.graalvm.compiler.api.test \
     org.graalvm.compiler.asm.aarch64.test \
--- a/make/CompileToolsHotspot.gmk	Thu May 31 06:15:17 2018 -0700
+++ b/make/CompileToolsHotspot.gmk	Thu May 31 13:09:04 2018 -0700
@@ -47,34 +47,8 @@
   $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_MATCH_PROCESSOR, \
       SETUP := GENERATE_OLDBYTECODE, \
       SRC := \
-          $(SRC_DIR)/jdk.internal.vm.compiler.word/src \
-          $(SRC_DIR)/jdk.internal.vm.compiler.collections/src \
-          $(SRC_DIR)/org.graalvm.compiler.core/src \
-          $(SRC_DIR)/org.graalvm.compiler.core.common/src \
+          $(SRC_DIR)/org.graalvm.compiler.processor/src \
           $(SRC_DIR)/org.graalvm.compiler.core.match.processor/src \
-          $(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
-          $(SRC_DIR)/org.graalvm.compiler.asm/src \
-          $(SRC_DIR)/org.graalvm.compiler.bytecode/src \
-          $(SRC_DIR)/org.graalvm.compiler.code/src \
-          $(SRC_DIR)/org.graalvm.compiler.debug/src \
-          $(SRC_DIR)/org.graalvm.compiler.graph/src \
-          $(SRC_DIR)/org.graalvm.compiler.lir/src \
-          $(SRC_DIR)/org.graalvm.compiler.loop/src \
-          $(SRC_DIR)/org.graalvm.compiler.loop.phases/src \
-          $(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
-          $(SRC_DIR)/org.graalvm.compiler.nodes/src \
-          $(SRC_DIR)/org.graalvm.compiler.options/src \
-          $(SRC_DIR)/org.graalvm.compiler.phases/src \
-          $(SRC_DIR)/org.graalvm.compiler.phases.common/src \
-          $(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
-          $(SRC_DIR)/org.graalvm.compiler.virtual/src \
-          $(SRC_DIR)/org.graalvm.graphio/src \
-          $(SRC_DIR)/org.graalvm.util/src \
-          $(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
-          $(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
-          $(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \
-          $(VM_CI_SRC_DIR)/jdk.vm.ci.runtime/src \
-          $(VM_CI_SRC_DIR)/jdk.vm.ci.services/src \
           , \
       EXCLUDE_FILES := $(EXCLUDE_FILES), \
       BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.match.processor, \
@@ -88,7 +62,7 @@
   $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_NODEINFO_PROCESSOR, \
       SETUP := GENERATE_OLDBYTECODE, \
       SRC := \
-          $(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
+          $(SRC_DIR)/org.graalvm.compiler.processor/src \
           $(SRC_DIR)/org.graalvm.compiler.nodeinfo.processor/src \
           , \
       BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.nodeinfo.processor, \
@@ -102,10 +76,8 @@
   $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_OPTIONS_PROCESSOR, \
       SETUP := GENERATE_OLDBYTECODE, \
       SRC := \
-          $(SRC_DIR)/jdk.internal.vm.compiler.collections/src \
-          $(SRC_DIR)/org.graalvm.compiler.options/src \
+          $(SRC_DIR)/org.graalvm.compiler.processor/src \
           $(SRC_DIR)/org.graalvm.compiler.options.processor/src \
-          $(SRC_DIR)/org.graalvm.util/src \
           , \
       BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor, \
       JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor.jar, \
@@ -115,44 +87,26 @@
 
   ##############################################################################
 
-  $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_REPLACEMENTS_VERIFIER, \
+  $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_REPLACEMENTS_PROCESSOR, \
       SETUP := GENERATE_OLDBYTECODE, \
       SRC := \
-          $(SRC_DIR)/jdk.internal.vm.compiler.word/src \
-          $(SRC_DIR)/jdk.internal.vm.compiler.collections/src \
-          $(SRC_DIR)/org.graalvm.compiler.bytecode/src \
-          $(SRC_DIR)/org.graalvm.compiler.replacements.verifier/src \
-          $(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
-          $(SRC_DIR)/org.graalvm.compiler.code/src \
-          $(SRC_DIR)/org.graalvm.compiler.core.common/src \
-          $(SRC_DIR)/org.graalvm.compiler.debug/src \
-          $(SRC_DIR)/org.graalvm.compiler.graph/src \
-          $(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
-          $(SRC_DIR)/org.graalvm.compiler.options/src \
-          $(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
-          $(SRC_DIR)/org.graalvm.graphio/src \
-          $(SRC_DIR)/org.graalvm.util/src \
-          $(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
-          $(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
-          $(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \
-          $(VM_CI_SRC_DIR)/jdk.vm.ci.runtime/src \
-          $(VM_CI_SRC_DIR)/jdk.vm.ci.services/src \
+          $(SRC_DIR)/org.graalvm.compiler.processor/src \
+          $(SRC_DIR)/org.graalvm.compiler.replacements.processor/src \
           , \
       EXCLUDE_FILES := $(EXCLUDE_FILES), \
       BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier, \
       JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier.jar, \
   ))
 
-  TARGETS += $(BUILD_VM_COMPILER_REPLACEMENTS_VERIFIER)
+  TARGETS += $(BUILD_VM_COMPILER_REPLACEMENTS_PROCESSOR)
 
   ##############################################################################
 
   $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_SERVICEPROVIDER_PROCESSOR, \
       SETUP := GENERATE_OLDBYTECODE, \
       SRC := \
-          $(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
+          $(SRC_DIR)/org.graalvm.compiler.processor/src \
           $(SRC_DIR)/org.graalvm.compiler.serviceprovider.processor/src \
-          $(VM_CI_SRC_DIR)/jdk.vm.ci.services/src \
           , \
       EXCLUDE_FILES := $(EXCLUDE_FILES), \
       BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.serviceprovider.processor, \
--- a/make/test/JtregNativeHotspot.gmk	Thu May 31 06:15:17 2018 -0700
+++ b/make/test/JtregNativeHotspot.gmk	Thu May 31 13:09:04 2018 -0700
@@ -134,6 +134,11 @@
     -I$(VM_TESTBASE_DIR)/nsk/share/jvmti \
     -I$(VM_TESTBASE_DIR)/nsk/share/jvmti/aod
 
+NSK_AOD_INCLUDES := \
+    -I$(VM_TESTBASE_DIR)/nsk/share/aod \
+    -I$(VM_TESTBASE_DIR)/nsk/share/native \
+    -I$(VM_TESTBASE_DIR)/nsk/share/jni
+
 BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libProcessUtils := $(VM_SHARE_INCLUDES)
 
 BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libThreadController := $(NSK_MONITORING_INCLUDES)
@@ -823,6 +828,12 @@
 BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libattach050Agent00 := $(NSK_JVMTI_AOD_INCLUDES)
 BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libattach002Agent00 := $(NSK_JVMTI_AOD_INCLUDES)
 
+BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libVirtualMachine07agent00 := $(NSK_AOD_INCLUDES)
+BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libVirtualMachine07agent01 := $(NSK_AOD_INCLUDES)
+BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libVirtualMachine07agent02 := $(NSK_AOD_INCLUDES)
+BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libVirtualMachine07agent03 := $(NSK_AOD_INCLUDES)
+BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libVirtualMachine09agent00 := $(NSK_AOD_INCLUDES)
+
 ################################################################################
 
 # Platform specific setup
--- a/src/hotspot/os/windows/os_perf_windows.cpp	Thu May 31 06:15:17 2018 -0700
+++ b/src/hotspot/os/windows/os_perf_windows.cpp	Thu May 31 13:09:04 2018 -0700
@@ -118,6 +118,11 @@
   bool               initialized;
 } MultiCounterQuerySetS, *MultiCounterQuerySetP;
 
+typedef struct {
+  MultiCounterQuerySetS set;
+  int                   process_index;
+} ProcessQueryS, *ProcessQueryP;
+
 static void pdh_cleanup(HQUERY* const query, HCOUNTER* const counter) {
   if (counter != NULL && *counter != NULL) {
     PdhDll::PdhRemoveCounter(*counter);
@@ -158,7 +163,7 @@
   }
 }
 
-static void destroy_counter_query(MultiCounterQuerySetP counter_query_set) {
+static void destroy_multi_counter_query(MultiCounterQuerySetP counter_query_set) {
   for (int i = 0; i < counter_query_set->size; i++) {
     for (int j = 0; j < counter_query_set->queries[i].noOfCounters; ++j) {
       pdh_cleanup(NULL, &counter_query_set->queries[i].counters[j]);
@@ -167,9 +172,18 @@
     pdh_cleanup(&counter_query_set->queries[i].query.query, NULL);
   }
   FREE_C_HEAP_ARRAY(MultiCounterQueryS, counter_query_set->queries);
+}
+
+static void destroy_counter_query(MultiCounterQuerySetP counter_query_set) {
+  destroy_multi_counter_query(counter_query_set);
   FREE_C_HEAP_ARRAY(MultiCounterQuerySetS, counter_query_set);
 }
 
+static void destroy_counter_query(ProcessQueryP process_query) {
+  destroy_multi_counter_query(&process_query->set);
+  FREE_C_HEAP_ARRAY(ProcessQueryS, process_query);
+}
+
 static int open_query(HQUERY* query) {
   return PdhDll::PdhOpenQuery(NULL, 0, query);
 }
@@ -204,6 +218,11 @@
   return OS_OK;
 }
 
+static int allocate_counters(ProcessQueryP process_query, size_t nofCounters) {
+  assert(process_query != NULL, "invariant");
+  return allocate_counters(&process_query->set, nofCounters);
+}
+
 static void deallocate_counters(MultiCounterQueryP query) {
   if (query->counters != NULL) {
     FREE_C_HEAP_ARRAY(char, query->counters);
@@ -262,7 +281,6 @@
 
 static OSReturn add_process_counter(MultiCounterQueryP query, int slot_index, const char* path, bool first_sample_on_init) {
   assert(query != NULL, "invariant");
-  assert(query != NULL, "invariant");
   assert(slot_index < query->noOfCounters, "invariant");
   assert(query->counters[slot_index] == NULL, "invariant");
   const OSReturn ret = add_counter(query, &query->counters[slot_index], path, first_sample_on_init);
@@ -326,13 +344,15 @@
 * (in order to keep this index valid when the list resets from underneath,
 * ensure to call current_query_index_for_process() before every query involving
 * Process object instance data).
+*
+* if unable to query, returns OS_ERR(-1)
 */
 static int current_query_index_for_process() {
   assert(process_image_name != NULL, "invariant");
   assert(pdh_IDProcess_counter_fmt != NULL, "invariant");
   HQUERY tmpQuery = NULL;
   if (open_query(&tmpQuery) != ERROR_SUCCESS) {
-    return 0;
+    return OS_ERR;
   }
   char counter[512];
   HCOUNTER handle_counter = NULL;
@@ -342,12 +362,12 @@
     assert(strlen(counter) < sizeof(counter), "invariant");
     if (PdhDll::PdhAddCounter(tmpQuery, counter, 0, &handle_counter) != ERROR_SUCCESS) {
       pdh_cleanup(&tmpQuery, &handle_counter);
-      return 0;
+      return OS_ERR;
     }
     const PDH_STATUS res = PdhDll::PdhCollectQueryData(tmpQuery);
     if (res == PDH_INVALID_HANDLE || res == PDH_NO_DATA) {
       pdh_cleanup(&tmpQuery, &handle_counter);
-      return 0;
+      return OS_ERR;
     } else {
       PDH_FMT_COUNTERVALUE counter_value;
       formatted_counter_value(handle_counter, PDH_FMT_LONG, &counter_value);
@@ -359,24 +379,28 @@
     }
   }
   pdh_cleanup(&tmpQuery, NULL);
-  return 0;
+  return OS_ERR;
 }
 
-static MultiCounterQuerySetP create_process_counter_query() {
-  MultiCounterQuerySetP const query = NEW_C_HEAP_ARRAY(MultiCounterQuerySetS, 1, mtInternal);
-  memset(query, 0, sizeof(MultiCounterQuerySetS));
+static ProcessQueryP create_process_query() {
   const int current_process_idx = current_query_index_for_process();
-  query->queries = NEW_C_HEAP_ARRAY(MultiCounterQueryS, current_process_idx + 1, mtInternal);
-  memset(query->queries, 0, sizeof(MultiCounterQueryS) * (current_process_idx + 1));
-  query->size = current_process_idx + 1;
-  return query;
+  if (OS_ERR == current_process_idx) {
+    return NULL;
+  }
+  ProcessQueryP const process_query = NEW_C_HEAP_ARRAY(ProcessQueryS, 1, mtInternal);
+  memset(process_query, 0, sizeof(ProcessQueryS));
+  process_query->set.queries = NEW_C_HEAP_ARRAY(MultiCounterQueryS, current_process_idx + 1, mtInternal);
+  memset(process_query->set.queries, 0, sizeof(MultiCounterQueryS) * (current_process_idx + 1));
+  process_query->process_index = current_process_idx;
+  process_query->set.size = current_process_idx + 1;
+  assert(process_query->set.size > process_query->process_index, "invariant");
+  return process_query;
 }
 
-static MultiCounterQueryP current_process_counter_query(MultiCounterQuerySetP process_query_set) {
-  assert(process_query_set != NULL, "invariant");
-  const int current_query_index = current_query_index_for_process();
-  assert(current_query_index < process_query_set->size, "invariant");
-  return &process_query_set->queries[current_query_index];
+static MultiCounterQueryP current_process_counter_query(ProcessQueryP process_query) {
+  assert(process_query != NULL, "invariant");
+  assert(process_query->process_index < process_query->set.size, "invariant");
+  return &process_query->set.queries[process_query->process_index];
 }
 
 static void clear_multi_counter(MultiCounterQueryP query) {
@@ -384,19 +408,46 @@
     pdh_cleanup(NULL, &query->counters[i]);
   }
   pdh_cleanup(&query->query.query, NULL);
+  query->initialized = false;
 }
 
-static int collect_process_query_data(MultiCounterQuerySetP counter_query_set) {
+static int ensure_valid_process_query_index(ProcessQueryP process_query) {
+  assert(process_query != NULL, "invariant");
+  const int previous_process_idx = process_query->process_index;
+  if (previous_process_idx == 0) {
+    return previous_process_idx;
+  }
   const int current_process_idx = current_query_index_for_process();
-  while (current_process_idx < counter_query_set->size - 1) {
-    const int new_size = --counter_query_set->size;
-    clear_multi_counter(&counter_query_set->queries[new_size]);
+  if (current_process_idx == previous_process_idx || OS_ERR == current_process_idx ||
+    current_process_idx >= process_query->set.size) {
+    return previous_process_idx;
   }
-  return collect_query_data(&counter_query_set->queries[current_process_idx]);
+
+  assert(current_process_idx >= 0 && current_process_idx < process_query->set.size, "out of bounds!");
+  while (current_process_idx < process_query->set.size - 1) {
+    const int new_size = --process_query->set.size;
+    clear_multi_counter(&process_query->set.queries[new_size]);
+  }
+  assert(current_process_idx < process_query->set.size, "invariant");
+  process_query->process_index = current_process_idx;
+  return current_process_idx;
 }
 
-static int query_process_counter(MultiCounterQuerySetP process_query_set, int slot_index, DWORD format, PDH_FMT_COUNTERVALUE* const value) {
-  MultiCounterQueryP const current_query = current_process_counter_query(process_query_set);
+static MultiCounterQueryP current_process_query(ProcessQueryP process_query) {
+  assert(process_query != NULL, "invariant");
+  const int current_process_idx = ensure_valid_process_query_index(process_query);
+  assert(current_process_idx == process_query->process_index, "invariant");
+  assert(current_process_idx < process_query->set.size, "invariant");
+  return &process_query->set.queries[current_process_idx];
+}
+
+static int collect_process_query_data(ProcessQueryP process_query) {
+  assert(process_query != NULL, "invariant");
+  return collect_query_data(current_process_query(process_query));
+}
+
+static int query_process_counter(ProcessQueryP process_query, int slot_index, DWORD format, PDH_FMT_COUNTERVALUE* const value) {
+  MultiCounterQueryP const current_query = current_process_counter_query(process_query);
   assert(current_query != NULL, "invariant");
   assert(slot_index < current_query->noOfCounters, "invariant");
   assert(current_query->counters[slot_index] != NULL, "invariant");
@@ -810,7 +861,7 @@
   return initialize_cpu_query_counters(cpu_query, pdh_counter_idx);
 }
 
-static int initialize_process_counter(MultiCounterQuerySetP query_set, int slot_index, DWORD pdh_counter_index) {
+static int initialize_process_counter(ProcessQueryP process_query, int slot_index, DWORD pdh_counter_index) {
   char* localized_process_object;
   if (lookup_name_by_index(PDH_PROCESS_IDX, &localized_process_object) != OS_OK) {
     return OS_ERR;
@@ -821,7 +872,7 @@
     return OS_ERR;
   }
   assert(localized_counter_name != NULL, "invariant");
-  for (int i = 0; i < query_set->size; ++i) {
+  for (int i = 0; i < process_query->set.size; ++i) {
     char instanceIndexBuffer[32];
     const char* counter_path = make_fully_qualified_counter_path(localized_process_object,
                                                                  localized_counter_name,
@@ -830,7 +881,7 @@
     if (counter_path == NULL) {
       return OS_ERR;
     }
-    MultiCounterQueryP const query = &query_set->queries[i];
+    MultiCounterQueryP const query = &process_query->set.queries[i];
     if (add_process_counter(query, slot_index, counter_path, true)) {
       return OS_ERR;
     }
@@ -839,8 +890,9 @@
 }
 
 static CounterQueryP create_counter_query(DWORD pdh_object_idx, DWORD pdh_counter_idx) {
-  assert(is_valid_pdh_index(pdh_object_idx), "invariant");
-  assert(is_valid_pdh_index(pdh_counter_idx), "invariant");
+  if (!((is_valid_pdh_index(pdh_object_idx) && is_valid_pdh_index(pdh_counter_idx)))) {
+    return NULL;
+  }
   CounterQueryP const query = create_counter_query();
   const char* object = pdh_localized_artifact(pdh_object_idx);
   assert(object != NULL, "invariant");
@@ -917,7 +969,7 @@
   friend class CPUPerformanceInterface;
  private:
   CounterQueryP _context_switches;
-  MultiCounterQuerySetP _process_cpu_load;
+  ProcessQueryP _process_cpu_load;
   MultiCounterQueryP _machine_cpu_load;
 
   int cpu_load(int which_logical_cpu, double* cpu_load);
@@ -963,34 +1015,28 @@
 
 bool CPUPerformanceInterface::CPUPerformance::initialize() {
   if (!pdh_acquire()) {
-    return false;
+    return true;
   }
   _context_switches = create_counter_query(PDH_SYSTEM_IDX, PDH_CONTEXT_SWITCH_RATE_IDX);
-  if (_context_switches == NULL) {
-    return false;
-  }
-  _process_cpu_load = create_process_counter_query();
+  _process_cpu_load = create_process_query();
   if (_process_cpu_load == NULL) {
-    return false;
+    return true;
   }
   if (allocate_counters(_process_cpu_load, 2) != OS_OK) {
-    return false;
+    return true;
   }
   if (initialize_process_counter(_process_cpu_load, 0, PDH_PROCESSOR_TIME_IDX) != OS_OK) {
-    return false;
+    return true;
   }
   if (initialize_process_counter(_process_cpu_load, 1, PDH_PRIV_PROCESSOR_TIME_IDX) != OS_OK) {
-    return false;
+    return true;
   }
-  _process_cpu_load->initialized = true;
-
+  _process_cpu_load->set.initialized = true;
   _machine_cpu_load = create_multi_counter_query();
   if (_machine_cpu_load == NULL) {
-    return false;
+    return true;
   }
-  if (initialize_cpu_query(_machine_cpu_load, PDH_PROCESSOR_TIME_IDX) != OS_OK) {
-    return false;
-  }
+  initialize_cpu_query(_machine_cpu_load, PDH_PROCESSOR_TIME_IDX);
   return true;
 }
 
@@ -1044,12 +1090,13 @@
 }
 
 int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
+  *cpu_load = .0;
+  if (_machine_cpu_load == NULL || !_machine_cpu_load->initialized) {
+    return OS_ERR;
+  }
   assert(_machine_cpu_load != NULL, "invariant");
   assert(which_logical_cpu < _machine_cpu_load->noOfCounters, "invariant");
-  *cpu_load = .0;
-  if (!_machine_cpu_load->initialized) {
-    return OS_ERR;
-  }
+
   if (collect_query_data(_machine_cpu_load)) {
     return OS_ERR;
   }
@@ -1062,11 +1109,11 @@
 }
 
 int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
-  assert(_process_cpu_load != NULL, "invariant");
   *cpu_load = .0;
-  if (!_process_cpu_load->initialized) {
+  if (_process_cpu_load == NULL || !_process_cpu_load->set.initialized) {
     return OS_ERR;
   }
+  assert(_process_cpu_load != NULL, "invariant");
   if (collect_process_query_data(_process_cpu_load)) {
     return OS_ERR;
   }
@@ -1090,9 +1137,11 @@
   *pjvmUserLoad = .0;
   *pjvmKernelLoad = .0;
   *psystemTotalLoad = .0;
-  if (!_process_cpu_load->initialized) {
+
+  if (_process_cpu_load == NULL || !_process_cpu_load->set.initialized) {
     return OS_ERR;
   }
+  assert(_process_cpu_load != NULL, "invariant");
   if (collect_process_query_data(_process_cpu_load)) {
     return OS_ERR;
   }
@@ -1138,9 +1187,10 @@
 int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
   assert(rate != NULL, "invariant");
   *rate = .0;
-  if (!_context_switches->initialized) {
+  if (_context_switches == NULL || !_context_switches->initialized) {
     return OS_ERR;
   }
+  assert(_context_switches != NULL, "invariant");
   if (collect_query_data(_context_switches) != OS_OK) {
     return OS_ERR;
   }
--- a/src/hotspot/share/classfile/classLoaderExt.cpp	Thu May 31 06:15:17 2018 -0700
+++ b/src/hotspot/share/classfile/classLoaderExt.cpp	Thu May 31 13:09:04 2018 -0700
@@ -55,8 +55,10 @@
 
 void ClassLoaderExt::append_boot_classpath(ClassPathEntry* new_entry) {
 #if INCLUDE_CDS
-  warning("Sharing is only supported for boot loader classes because bootstrap classpath has been appended");
-  FileMapInfo::current_info()->header()->set_has_platform_or_app_classes(false);
+  if (UseSharedSpaces) {
+    warning("Sharing is only supported for boot loader classes because bootstrap classpath has been appended");
+    FileMapInfo::current_info()->header()->set_has_platform_or_app_classes(false);
+  }
 #endif
   ClassLoader::add_to_boot_append_entries(new_entry);
 }
--- a/src/hotspot/share/gc/shared/oopStorage.cpp	Thu May 31 06:15:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/oopStorage.cpp	Thu May 31 13:09:04 2018 -0700
@@ -40,7 +40,6 @@
 #include "utilities/align.hpp"
 #include "utilities/count_trailing_zeros.hpp"
 #include "utilities/debug.hpp"
-#include "utilities/globalCounter.inline.hpp"
 #include "utilities/globalDefinitions.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/ostream.hpp"
@@ -502,6 +501,48 @@
   return true;
 }
 
+OopStorage::ProtectActive::ProtectActive() : _enter(0), _exit() {}
+
+// Begin read-side critical section.
+uint OopStorage::ProtectActive::read_enter() {
+  return Atomic::add(2u, &_enter);
+}
+
+// End read-side critical section.
+void OopStorage::ProtectActive::read_exit(uint enter_value) {
+  Atomic::add(2u, &_exit[enter_value & 1]);
+}
+
+// Wait until all readers that entered the critical section before
+// synchronization have exited that critical section.
+void OopStorage::ProtectActive::write_synchronize() {
+  SpinYield spinner;
+  // Determine old and new exit counters, based on bit0 of the
+  // on-entry _enter counter.
+  uint value = OrderAccess::load_acquire(&_enter);
+  volatile uint* new_ptr = &_exit[(value + 1) & 1];
+  // Atomically change the in-use exit counter to the new counter, by
+  // adding 1 to the _enter counter (flipping bit0 between 0 and 1)
+  // and initializing the new exit counter to that enter value.  Note:
+  // The new exit counter is not being used by read operations until
+  // this change succeeds.
+  uint old;
+  do {
+    old = value;
+    *new_ptr = ++value;
+    value = Atomic::cmpxchg(value, &_enter, old);
+  } while (old != value);
+  // Readers that entered the critical section before we changed the
+  // selected exit counter will use the old exit counter.  Readers
+  // entering after the change will use the new exit counter.  Wait
+  // for all the critical sections started before the change to
+  // complete, e.g. for the value of old_ptr to catch up with old.
+  volatile uint* old_ptr = &_exit[old & 1];
+  while (old != OrderAccess::load_acquire(old_ptr)) {
+    spinner.wait();
+  }
+}
+
 // Make new_array the _active_array.  Increments new_array's refcount
 // to account for the new reference.  The assignment is atomic wrto
 // obtain_active_array; once this function returns, it is safe for the
@@ -513,9 +554,9 @@
   // Install new_array, ensuring its initialization is complete first.
   OrderAccess::release_store(&_active_array, new_array);
   // Wait for any readers that could read the old array from _active_array.
-  GlobalCounter::write_synchronize();
-  // All obtain_active_array critical sections that could see the old array
-  // have completed, having incremented the refcount of the old array.  The
+  _protect_active.write_synchronize();
+  // All obtain critical sections that could see the old array have
+  // completed, having incremented the refcount of the old array.  The
   // caller can now safely relinquish the old array.
 }
 
@@ -525,9 +566,10 @@
 // _active_array.  The caller must relinquish the array when done
 // using it.
 OopStorage::ActiveArray* OopStorage::obtain_active_array() const {
-  GlobalCounter::CriticalSection cs(Thread::current());
+  uint enter_value = _protect_active.read_enter();
   ActiveArray* result = OrderAccess::load_acquire(&_active_array);
   result->increment_refcount();
+  _protect_active.read_exit(enter_value);
   return result;
 }
 
--- a/src/hotspot/share/gc/shared/oopStorage.hpp	Thu May 31 06:15:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/oopStorage.hpp	Thu May 31 13:09:04 2018 -0700
@@ -204,6 +204,19 @@
     void unlink(const Block& block);
   };
 
+  // RCU-inspired protection of access to _active_array.
+  class ProtectActive {
+    volatile uint _enter;
+    volatile uint _exit[2];
+
+  public:
+    ProtectActive();
+
+    uint read_enter();
+    void read_exit(uint enter_value);
+    void write_synchronize();
+  };
+
 private:
   const char* _name;
   ActiveArray* _active_array;
@@ -216,6 +229,9 @@
   // Volatile for racy unlocked accesses.
   volatile size_t _allocation_count;
 
+  // Protection for _active_array.
+  mutable ProtectActive _protect_active;
+
   // mutable because this gets set even for const iteration.
   mutable bool _concurrent_iteration_active;
 
--- a/src/hotspot/share/interpreter/bytecodeInterpreterProfiling.hpp	Thu May 31 06:15:17 2018 -0700
+++ b/src/hotspot/share/interpreter/bytecodeInterpreterProfiling.hpp	Thu May 31 13:09:04 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2012, 2014 SAP SE. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -30,25 +30,10 @@
 #ifndef SHARE_VM_INTERPRETER_BYTECODEINTERPRETERPROFILING_HPP
 #define SHARE_VM_INTERPRETER_BYTECODEINTERPRETERPROFILING_HPP
 
-
-// Global settings /////////////////////////////////////////////////////////////
-
-
-// Enables profiling support.
-#if defined(COMPILER2)
-#define CC_INTERP_PROFILE
-#endif
-
-// Enables assertions for profiling code (also works in product-builds).
-// #define CC_INTERP_PROFILE_WITH_ASSERTIONS
-
-
 #ifdef CC_INTERP
 
 // Empty dummy implementations if profiling code is switched off. //////////////
 
-#ifndef CC_INTERP_PROFILE
-
 #define SET_MDX(mdx)
 
 #define BI_PROFILE_GET_OR_CREATE_METHOD_DATA(exception_handler)                \
@@ -69,240 +54,6 @@
 #define BI_PROFILE_UPDATE_VIRTUALCALL(receiver)
 #define BI_PROFILE_UPDATE_SWITCH(switch_index)
 
-
-#else
-
-
-// Non-dummy implementations ///////////////////////////////////////////////////
-
-// Accessors for the current method data pointer 'mdx'.
-#define MDX()        (istate->mdx())
-#define SET_MDX(mdx)                                                           \
-  if (TraceProfileInterpreter) {                                               \
-    /* Let it look like TraceBytecodes' format. */                             \
-    tty->print_cr("[%d]           %4d  "                                       \
-                  "mdx " PTR_FORMAT "(%d)"                                     \
-                  "  "                                                         \
-                  " \t-> " PTR_FORMAT "(%d)",                                  \
-                (int) THREAD->osthread()->thread_id(),                         \
-                BCI(),                                                         \
-                p2i(MDX()),                                                    \
-                (MDX() == NULL                                                 \
-                 ? 0                                                           \
-                 : istate->method()->method_data()->dp_to_di((address)MDX())), \
-                p2i(mdx),                                                      \
-                istate->method()->method_data()->dp_to_di((address)mdx)        \
-                );                                                             \
-  };                                                                           \
-  istate->set_mdx(mdx);
-
-
-// Dumps the profiling method data for the current method.
-#ifdef PRODUCT
-#define BI_PROFILE_PRINT_METHOD_DATA()
-#else  // PRODUCT
-#define BI_PROFILE_PRINT_METHOD_DATA()                                         \
-  {                                                                            \
-    ttyLocker ttyl;                                                            \
-    MethodData *md = istate->method()->method_data();                          \
-    tty->cr();                                                                 \
-    tty->print("method data at mdx " PTR_FORMAT "(0) for",                     \
-               p2i(md->data_layout_at(md->bci_to_di(0))));                     \
-    istate->method()->print_short_name(tty);                                   \
-    tty->cr();                                                                 \
-    if (md != NULL) {                                                          \
-      md->print_data_on(tty);                                                  \
-      address mdx = (address) MDX();                                           \
-      if (mdx != NULL) {                                                       \
-        tty->print_cr("current mdx " PTR_FORMAT "(%d)",                        \
-                      p2i(mdx),                                                \
-                      istate->method()->method_data()->dp_to_di(mdx));         \
-      }                                                                        \
-    } else {                                                                   \
-      tty->print_cr("no method data");                                         \
-    }                                                                          \
-  }
-#endif // PRODUCT
-
-
-// Gets or creates the profiling method data and initializes mdx.
-#define BI_PROFILE_GET_OR_CREATE_METHOD_DATA(exception_handler)                \
-  if (ProfileInterpreter && MDX() == NULL) {                                   \
-    /* Mdx is not yet initialized for this activation. */                      \
-    MethodData *md = istate->method()->method_data();                          \
-    if (md == NULL) {                                                          \
-      MethodCounters* mcs;                                                     \
-      GET_METHOD_COUNTERS(mcs);                                                \
-      /* The profiling method data doesn't exist for this method, */           \
-      /* create it if the counters have overflowed. */                         \
-      if (mcs->invocation_counter()                                            \
-                         ->reached_ProfileLimit(mcs->backedge_counter())) {    \
-        /* Must use CALL_VM, because an async exception may be pending. */     \
-        CALL_VM((InterpreterRuntime::profile_method(THREAD)),                  \
-                exception_handler);                                            \
-        md = istate->method()->method_data();                                  \
-        if (md != NULL) {                                                      \
-          if (TraceProfileInterpreter) {                                       \
-            BI_PROFILE_PRINT_METHOD_DATA();                                    \
-          }                                                                    \
-          Method *m = istate->method();                                        \
-          int bci = m->bci_from(pc);                                           \
-          jint di = md->bci_to_di(bci);                                        \
-          SET_MDX(md->data_layout_at(di));                                     \
-        }                                                                      \
-      }                                                                        \
-    } else {                                                                   \
-      /* The profiling method data exists, align the method data pointer */    \
-      /* mdx to the current bytecode index. */                                 \
-      if (TraceProfileInterpreter) {                                           \
-        BI_PROFILE_PRINT_METHOD_DATA();                                        \
-      }                                                                        \
-      SET_MDX(md->data_layout_at(md->bci_to_di(BCI())));                       \
-    }                                                                          \
-  }
-
-
-// Asserts that the current method data pointer mdx corresponds
-// to the current bytecode.
-#if defined(CC_INTERP_PROFILE_WITH_ASSERTIONS)
-#define BI_PROFILE_CHECK_MDX()                                                 \
-  {                                                                            \
-    MethodData *md = istate->method()->method_data();                          \
-    address mdx  = (address) MDX();                                            \
-    address mdx2 = (address) md->data_layout_at(md->bci_to_di(BCI()));         \
-    guarantee(md   != NULL, "1");                                              \
-    guarantee(mdx  != NULL, "2");                                              \
-    guarantee(mdx2 != NULL, "3");                                              \
-    if (mdx != mdx2) {                                                         \
-      BI_PROFILE_PRINT_METHOD_DATA();                                          \
-      fatal3("invalid mdx at bci %d:"                                          \
-             " was " PTR_FORMAT                                                \
-             " but expected " PTR_FORMAT,                                      \
-             BCI(),                                                            \
-             mdx,                                                              \
-             mdx2);                                                            \
-    }                                                                          \
-  }
-#else
-#define BI_PROFILE_CHECK_MDX()
-#endif
-
-
-// Aligns the method data pointer mdx to the current bytecode index.
-#define BI_PROFILE_ALIGN_TO_CURRENT_BCI()                                      \
-  if (ProfileInterpreter && MDX() != NULL) {                                   \
-    MethodData *md = istate->method()->method_data();                          \
-    SET_MDX(md->data_layout_at(md->bci_to_di(BCI())));                         \
-  }
-
-
-// Updates profiling data for a jump.
-#define BI_PROFILE_UPDATE_JUMP()                                               \
-  if (ProfileInterpreter && MDX() != NULL) {                                   \
-    BI_PROFILE_CHECK_MDX();                                                    \
-    JumpData::increment_taken_count_no_overflow(MDX());                        \
-    /* Remember last branch taken count. */                                    \
-    mdo_last_branch_taken_count = JumpData::taken_count(MDX());                \
-    SET_MDX(JumpData::advance_taken(MDX()));                                   \
-  }
-
-
-// Updates profiling data for a taken/not taken branch.
-#define BI_PROFILE_UPDATE_BRANCH(is_taken)                                     \
-  if (ProfileInterpreter && MDX() != NULL) {                                   \
-    BI_PROFILE_CHECK_MDX();                                                    \
-    if (is_taken) {                                                            \
-      BranchData::increment_taken_count_no_overflow(MDX());                    \
-      /* Remember last branch taken count. */                                  \
-      mdo_last_branch_taken_count = BranchData::taken_count(MDX());            \
-      SET_MDX(BranchData::advance_taken(MDX()));                               \
-    } else {                                                                   \
-      BranchData::increment_not_taken_count_no_overflow(MDX());                \
-      SET_MDX(BranchData::advance_not_taken(MDX()));                           \
-    }                                                                          \
-  }
-
-
-// Updates profiling data for a ret with given bci.
-#define BI_PROFILE_UPDATE_RET(bci)                                             \
-  if (ProfileInterpreter && MDX() != NULL) {                                   \
-    BI_PROFILE_CHECK_MDX();                                                    \
-    MethodData *md = istate->method()->method_data();                          \
-/* FIXME: there is more to do here than increment and advance(mdx)! */         \
-    CounterData::increment_count_no_overflow(MDX());                           \
-    SET_MDX(RetData::advance(md, bci));                                        \
-  }
-
-// Decrement counter at checkcast if the subtype check fails (as template
-// interpreter does!).
-#define BI_PROFILE_SUBTYPECHECK_FAILED(receiver)                               \
-  if (ProfileInterpreter && MDX() != NULL) {                                   \
-    BI_PROFILE_CHECK_MDX();                                                    \
-    ReceiverTypeData::increment_receiver_count_no_overflow(MDX(), receiver);   \
-    ReceiverTypeData::decrement_count(MDX());                                  \
-  }
-
-// Updates profiling data for a checkcast (was a null seen? which receiver?).
-#define BI_PROFILE_UPDATE_CHECKCAST(null_seen, receiver)                       \
-  if (ProfileInterpreter && MDX() != NULL) {                                   \
-    BI_PROFILE_CHECK_MDX();                                                    \
-    if (null_seen) {                                                           \
-      ReceiverTypeData::set_null_seen(MDX());                                  \
-    } else {                                                                   \
-      /* Template interpreter doesn't increment count. */                      \
-      /* ReceiverTypeData::increment_count_no_overflow(MDX()); */              \
-      ReceiverTypeData::increment_receiver_count_no_overflow(MDX(), receiver); \
-    }                                                                          \
-    SET_MDX(ReceiverTypeData::advance(MDX()));                                 \
-  }
-
-
-// Updates profiling data for an instanceof (was a null seen? which receiver?).
-#define BI_PROFILE_UPDATE_INSTANCEOF(null_seen, receiver)                      \
-  BI_PROFILE_UPDATE_CHECKCAST(null_seen, receiver)
-
-
-// Updates profiling data for a call.
-#define BI_PROFILE_UPDATE_CALL()                                               \
-  if (ProfileInterpreter && MDX() != NULL) {                                   \
-    BI_PROFILE_CHECK_MDX();                                                    \
-    CounterData::increment_count_no_overflow(MDX());                           \
-    SET_MDX(CounterData::advance(MDX()));                                      \
-  }
-
-
-// Updates profiling data for a final call.
-#define BI_PROFILE_UPDATE_FINALCALL()                                          \
-  if (ProfileInterpreter && MDX() != NULL) {                                   \
-    BI_PROFILE_CHECK_MDX();                                                    \
-    VirtualCallData::increment_count_no_overflow(MDX());                       \
-    SET_MDX(VirtualCallData::advance(MDX()));                                  \
-  }
-
-
-// Updates profiling data for a virtual call with given receiver Klass.
-#define BI_PROFILE_UPDATE_VIRTUALCALL(receiver)                                \
-  if (ProfileInterpreter && MDX() != NULL) {                                   \
-    BI_PROFILE_CHECK_MDX();                                                    \
-    VirtualCallData::increment_receiver_count_no_overflow(MDX(), receiver);    \
-    SET_MDX(VirtualCallData::advance(MDX()));                                  \
-  }
-
-
-// Updates profiling data for a switch (tabelswitch or lookupswitch) with
-// given taken index (-1 means default case was taken).
-#define BI_PROFILE_UPDATE_SWITCH(switch_index)                                 \
-  if (ProfileInterpreter && MDX() != NULL) {                                   \
-    BI_PROFILE_CHECK_MDX();                                                    \
-    MultiBranchData::increment_count_no_overflow(MDX(), switch_index);         \
-    SET_MDX(MultiBranchData::advance(MDX(), switch_index));                    \
-  }
-
-
-// The end /////////////////////////////////////////////////////////////////////
-
-#endif // CC_INTERP_PROFILE
-
 #endif // CC_INTERP
 
 #endif // SHARE_VM_INTERPRETER_BYTECODECINTERPRETERPROFILING_HPP
--- a/src/hotspot/share/interpreter/linkResolver.cpp	Thu May 31 06:15:17 2018 -0700
+++ b/src/hotspot/share/interpreter/linkResolver.cpp	Thu May 31 13:09:04 2018 -0700
@@ -688,19 +688,21 @@
                                               CHECK);
   if (failed_type_symbol != NULL) {
     const char* msg = "loader constraint violation: when resolving field"
-      " \"%s\" the class loader %s of the referring class, "
-      "%s, and the class loader %s for the field's resolved "
-      "type, %s, have different Class objects for that type";
-    char* field_name = field->as_C_string();
+      " \"%s\" of type %s, the class loader %s of the current class, "
+      "%s, and the class loader %s for the field's defining "
+      "type, %s, have different Class objects for type %s";
+    const char* field_name = field->as_C_string();
     const char* loader1_name = java_lang_ClassLoader::describe_external(ref_loader());
-    char* sel = sel_klass->name()->as_C_string();
+    const char* sel = sel_klass->external_name();
     const char* loader2_name = java_lang_ClassLoader::describe_external(sel_loader());
-    char* failed_type_name = failed_type_symbol->as_C_string();
-    size_t buflen = strlen(msg) + strlen(field_name) + strlen(loader1_name) +
-                    strlen(sel) + strlen(loader2_name) + strlen(failed_type_name) + 1;
+    const char* failed_type_name = failed_type_symbol->as_klass_external_name();
+    const char* curr_klass_name = current_klass->external_name();
+    size_t buflen = strlen(msg) + strlen(field_name) + 2 * strlen(failed_type_name) +
+                    strlen(loader1_name) + strlen(curr_klass_name) +
+                    strlen(loader2_name) + strlen(sel) + 1;
     char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen);
-    jio_snprintf(buf, buflen, msg, field_name, loader1_name, sel, loader2_name,
-                     failed_type_name);
+    jio_snprintf(buf, buflen, msg, field_name, failed_type_name, loader1_name,
+                 curr_klass_name, loader2_name, sel, failed_type_name);
     THROW_MSG(vmSymbols::java_lang_LinkageError(), buf);
   }
 }
--- a/src/hotspot/share/oops/methodData.cpp	Thu May 31 06:15:17 2018 -0700
+++ b/src/hotspot/share/oops/methodData.cpp	Thu May 31 13:09:04 2018 -0700
@@ -541,12 +541,6 @@
   return mdp;
 }
 
-#ifdef CC_INTERP
-DataLayout* RetData::advance(MethodData *md, int bci) {
-  return (DataLayout*) md->bci_to_dp(bci);
-}
-#endif // CC_INTERP
-
 void RetData::print_data_on(outputStream* st, const char* extra) const {
   print_shared(st, "RetData", extra);
   uint row;
--- a/src/hotspot/share/oops/methodData.hpp	Thu May 31 06:15:17 2018 -0700
+++ b/src/hotspot/share/oops/methodData.hpp	Thu May 31 13:09:04 2018 -0700
@@ -232,11 +232,6 @@
   static ByteSize cell_offset(int index) {
     return byte_offset_of(DataLayout, _cells) + in_ByteSize(index * cell_size);
   }
-#ifdef CC_INTERP
-  static int cell_offset_in_bytes(int index) {
-    return (int)offset_of(DataLayout, _cells[index]);
-  }
-#endif // CC_INTERP
   // Return a value which, when or-ed as a byte into _flags, sets the flag.
   static int flag_number_to_byte_constant(int flag_number) {
     assert(0 <= flag_number && flag_number < flag_limit, "oob");
@@ -372,41 +367,6 @@
     _data = data;
   }
 
-#ifdef CC_INTERP
-  // Static low level accessors for DataLayout with ProfileData's semantics.
-
-  static int cell_offset_in_bytes(int index) {
-    return DataLayout::cell_offset_in_bytes(index);
-  }
-
-  static void increment_uint_at_no_overflow(DataLayout* layout, int index,
-                                            int inc = DataLayout::counter_increment) {
-    uint count = ((uint)layout->cell_at(index)) + inc;
-    if (count == 0) return;
-    layout->set_cell_at(index, (intptr_t) count);
-  }
-
-  static int int_at(DataLayout* layout, int index) {
-    return (int)layout->cell_at(index);
-  }
-
-  static int uint_at(DataLayout* layout, int index) {
-    return (uint)layout->cell_at(index);
-  }
-
-  static oop oop_at(DataLayout* layout, int index) {
-    return cast_to_oop(layout->cell_at(index));
-  }
-
-  static void set_intptr_at(DataLayout* layout, int index, intptr_t value) {
-    layout->set_cell_at(index, (intptr_t) value);
-  }
-
-  static void set_flag_at(DataLayout* layout, int flag_number) {
-    layout->set_flag_at(flag_number);
-  }
-#endif // CC_INTERP
-
 public:
   // Constructor for invalid ProfileData.
   ProfileData();
@@ -581,20 +541,6 @@
     return cell_offset(bit_cell_count);
   }
 
-#ifdef CC_INTERP
-  static int bit_data_size_in_bytes() {
-    return cell_offset_in_bytes(bit_cell_count);
-  }
-
-  static void set_null_seen(DataLayout* layout) {
-    set_flag_at(layout, null_seen_flag);
-  }
-
-  static DataLayout* advance(DataLayout* layout) {
-    return (DataLayout*) (((address)layout) + (ssize_t)BitData::bit_data_size_in_bytes());
-  }
-#endif // CC_INTERP
-
   void print_data_on(outputStream* st, const char* extra = NULL) const;
 };
 
@@ -639,25 +585,6 @@
     set_uint_at(count_off, count);
   }
 
-#ifdef CC_INTERP
-  static int counter_data_size_in_bytes() {
-    return cell_offset_in_bytes(counter_cell_count);
-  }
-
-  static void increment_count_no_overflow(DataLayout* layout) {
-    increment_uint_at_no_overflow(layout, count_off);
-  }
-
-  // Support counter decrementation at checkcast / subtype check failed.
-  static void decrement_count(DataLayout* layout) {
-    increment_uint_at_no_overflow(layout, count_off, -1);
-  }
-
-  static DataLayout* advance(DataLayout* layout) {
-    return (DataLayout*) (((address)layout) + (ssize_t)CounterData::counter_data_size_in_bytes());
-  }
-#endif // CC_INTERP
-
   void print_data_on(outputStream* st, const char* extra = NULL) const;
 };
 
@@ -728,20 +655,6 @@
     return cell_offset(displacement_off_set);
   }
 
-#ifdef CC_INTERP
-  static void increment_taken_count_no_overflow(DataLayout* layout) {
-    increment_uint_at_no_overflow(layout, taken_off_set);
-  }
-
-  static DataLayout* advance_taken(DataLayout* layout) {
-    return (DataLayout*) (((address)layout) + (ssize_t)int_at(layout, displacement_off_set));
-  }
-
-  static uint taken_count(DataLayout* layout) {
-    return (uint) uint_at(layout, taken_off_set);
-  }
-#endif // CC_INTERP
-
   // Specific initialization.
   void post_initialize(BytecodeStream* stream, MethodData* mdo);
 
@@ -1302,43 +1215,6 @@
   // GC support
   virtual void clean_weak_klass_links(bool always_clean);
 
-#ifdef CC_INTERP
-  static int receiver_type_data_size_in_bytes() {
-    return cell_offset_in_bytes(static_cell_count());
-  }
-
-  static Klass *receiver_unchecked(DataLayout* layout, uint row) {
-    Klass* recv = (Klass*)layout->cell_at(receiver_cell_index(row));
-    return recv;
-  }
-
-  static void increment_receiver_count_no_overflow(DataLayout* layout, Klass *rcvr) {
-    const int num_rows = row_limit();
-    // Receiver already exists?
-    for (int row = 0; row < num_rows; row++) {
-      if (receiver_unchecked(layout, row) == rcvr) {
-        increment_uint_at_no_overflow(layout, receiver_count_cell_index(row));
-        return;
-      }
-    }
-    // New receiver, find a free slot.
-    for (int row = 0; row < num_rows; row++) {
-      if (receiver_unchecked(layout, row) == NULL) {
-        set_intptr_at(layout, receiver_cell_index(row), (intptr_t)rcvr);
-        increment_uint_at_no_overflow(layout, receiver_count_cell_index(row));
-        return;
-      }
-    }
-    // Receiver did not match any saved receiver and there is no empty row for it.
-    // Increment total counter to indicate polymorphic case.
-    increment_count_no_overflow(layout);
-  }
-
-  static DataLayout* advance(DataLayout* layout) {
-    return (DataLayout*) (((address)layout) + (ssize_t)ReceiverTypeData::receiver_type_data_size_in_bytes());
-  }
-#endif // CC_INTERP
-
   void print_receiver_data_on(outputStream* st) const;
   void print_data_on(outputStream* st, const char* extra = NULL) const;
 };
@@ -1371,16 +1247,6 @@
     return cell_offset(static_cell_count());
   }
 
-#ifdef CC_INTERP
-  static int virtual_call_data_size_in_bytes() {
-    return cell_offset_in_bytes(static_cell_count());
-  }
-
-  static DataLayout* advance(DataLayout* layout) {
-    return (DataLayout*) (((address)layout) + (ssize_t)VirtualCallData::virtual_call_data_size_in_bytes());
-  }
-#endif // CC_INTERP
-
 #if INCLUDE_JVMCI
   static ByteSize method_offset(uint row) {
     return cell_offset(method_cell_index(row));
@@ -1658,10 +1524,6 @@
     return cell_offset(bci_displacement_cell_index(row));
   }
 
-#ifdef CC_INTERP
-  static DataLayout* advance(MethodData *md, int bci);
-#endif // CC_INTERP
-
   // Specific initialization.
   void post_initialize(BytecodeStream* stream, MethodData* mdo);
 
@@ -1726,20 +1588,6 @@
     return cell_offset(branch_cell_count);
   }
 
-#ifdef CC_INTERP
-  static int branch_data_size_in_bytes() {
-    return cell_offset_in_bytes(branch_cell_count);
-  }
-
-  static void increment_not_taken_count_no_overflow(DataLayout* layout) {
-    increment_uint_at_no_overflow(layout, not_taken_off_set);
-  }
-
-  static DataLayout* advance_not_taken(DataLayout* layout) {
-    return (DataLayout*) (((address)layout) + (ssize_t)BranchData::branch_data_size_in_bytes());
-  }
-#endif // CC_INTERP
-
   // Specific initialization.
   void post_initialize(BytecodeStream* stream, MethodData* mdo);
 
@@ -1779,20 +1627,6 @@
     set_int_at(aindex, value);
   }
 
-#ifdef CC_INTERP
-  // Static low level accessors for DataLayout with ArrayData's semantics.
-
-  static void increment_array_uint_at_no_overflow(DataLayout* layout, int index) {
-    int aindex = index + array_start_off_set;
-    increment_uint_at_no_overflow(layout, aindex);
-  }
-
-  static int array_int_at(DataLayout* layout, int index) {
-    int aindex = index + array_start_off_set;
-    return int_at(layout, aindex);
-  }
-#endif // CC_INTERP
-
   // Code generation support for subclasses.
   static ByteSize array_element_offset(int index) {
     return cell_offset(array_start_off_set + index);
@@ -1913,28 +1747,6 @@
     return in_ByteSize(relative_displacement_off_set) * cell_size;
   }
 
-#ifdef CC_INTERP
-  static void increment_count_no_overflow(DataLayout* layout, int index) {
-    if (index == -1) {
-      increment_array_uint_at_no_overflow(layout, default_count_off_set);
-    } else {
-      increment_array_uint_at_no_overflow(layout, case_array_start +
-                                                  index * per_case_cell_count +
-                                                  relative_count_off_set);
-    }
-  }
-
-  static DataLayout* advance(DataLayout* layout, int index) {
-    if (index == -1) {
-      return (DataLayout*) (((address)layout) + (ssize_t)array_int_at(layout, default_disaplacement_off_set));
-    } else {
-      return (DataLayout*) (((address)layout) + (ssize_t)array_int_at(layout, case_array_start +
-                                                                              index * per_case_cell_count +
-                                                                              relative_displacement_off_set));
-    }
-  }
-#endif // CC_INTERP
-
   // Specific initialization.
   void post_initialize(BytecodeStream* stream, MethodData* mdo);
 
@@ -2127,13 +1939,11 @@
 // adjusted in the event of a change in control flow.
 //
 
-CC_INTERP_ONLY(class BytecodeInterpreter;)
 class CleanExtraDataClosure;
 
 class MethodData : public Metadata {
   friend class VMStructs;
   friend class JVMCIVMStructs;
-  CC_INTERP_ONLY(friend class BytecodeInterpreter;)
 private:
   friend class ProfileData;
   friend class TypeEntriesAtCall;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java	Thu May 31 13:09:04 2018 -0700
@@ -0,0 +1,1389 @@
+/*
+ * Copyright (c) 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.  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 com.sun.crypto.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.security.*;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Arrays;
+import java.util.Objects;
+import javax.crypto.spec.ChaCha20ParameterSpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.crypto.*;
+import sun.security.util.DerValue;
+
+/**
+ * Implementation of the ChaCha20 cipher, as described in RFC 7539.
+ *
+ * @since 11
+ */
+abstract class ChaCha20Cipher extends CipherSpi {
+    // Mode constants
+    private static final int MODE_NONE = 0;
+    private static final int MODE_AEAD = 1;
+
+    // Constants used in setting up the initial state
+    private static final int STATE_CONST_0 = 0x61707865;
+    private static final int STATE_CONST_1 = 0x3320646e;
+    private static final int STATE_CONST_2 = 0x79622d32;
+    private static final int STATE_CONST_3 = 0x6b206574;
+
+    // The keystream block size in bytes and as integers
+    private static final int KEYSTREAM_SIZE = 64;
+    private static final int KS_SIZE_INTS = KEYSTREAM_SIZE / Integer.BYTES;
+    private static final int CIPHERBUF_BASE = 1024;
+
+    // The initialization state of the cipher
+    private boolean initialized;
+
+    // The mode of operation for this object
+    protected int mode;
+
+    // The direction (encrypt vs. decrypt) for the data flow
+    private int direction;
+
+    // Has all AAD data been provided (i.e. have we called our first update)
+    private boolean aadDone = false;
+
+    // The key's encoding in bytes for this object
+    private byte[] keyBytes;
+
+    // The nonce used for this object
+    private byte[] nonce;
+
+    // The counter
+    private static final long MAX_UINT32 = 0x00000000FFFFFFFFL;
+    private long finalCounterValue;
+    private long counter;
+
+    // Two arrays, both implemented as 16-element integer arrays:
+    // The base state, created at initialization time, and a working
+    // state which is a clone of the start state, and is then modified
+    // with the counter and the ChaCha20 block function.
+    private final int[] startState = new int[KS_SIZE_INTS];
+    private final byte[] keyStream = new byte[KEYSTREAM_SIZE];
+
+    // The offset into the current keystream
+    private int keyStrOffset;
+
+    // AEAD-related fields and constants
+    private static final int TAG_LENGTH = 16;
+    private long aadLen;
+    private long dataLen;
+
+    // Have a buffer of zero padding that can be read all or in part
+    // by the authenticator.
+    private static final byte[] padBuf = new byte[TAG_LENGTH];
+
+    // Create a buffer for holding the AAD and Ciphertext lengths
+    private final byte[] lenBuf = new byte[TAG_LENGTH];
+
+    // The authenticator (Poly1305) when running in AEAD mode
+    protected String authAlgName;
+    private Poly1305 authenticator;
+
+    // The underlying engine for doing the ChaCha20/Poly1305 work
+    private ChaChaEngine engine;
+
+    // Use this VarHandle for converting the state elements into little-endian
+    // integer values for the ChaCha20 block function.
+    private static final VarHandle asIntLittleEndian =
+            MethodHandles.byteArrayViewVarHandle(int[].class,
+                    ByteOrder.LITTLE_ENDIAN);
+
+    // Use this VarHandle for converting the AAD and data lengths into
+    // little-endian long values for AEAD tag computations.
+    private static final VarHandle asLongLittleEndian =
+            MethodHandles.byteArrayViewVarHandle(long[].class,
+                    ByteOrder.LITTLE_ENDIAN);
+
+    // Use this for pulling in 8 bytes at a time as longs for XOR operations
+    private static final VarHandle asLongView =
+            MethodHandles.byteArrayViewVarHandle(long[].class,
+                    ByteOrder.nativeOrder());
+
+    /**
+     * Default constructor.
+     */
+    protected ChaCha20Cipher() {
+    }
+
+    /**
+     * Set the mode of operation.  Since this is a stream cipher, there
+     * is no mode of operation in the block-cipher sense of things.  The
+     * protected {@code mode} field will only accept a value of {@code None}
+     * (case-insensitive).
+     *
+     * @param mode The mode value
+     *
+     * @throws NoSuchAlgorithmException if a mode of operation besides
+     *      {@code None} is provided.
+     */
+    @Override
+    protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
+        if (mode.equalsIgnoreCase("None") == false) {
+            throw new NoSuchAlgorithmException("Mode must be None");
+        }
+    }
+
+    /**
+     * Set the padding scheme.  Padding schemes do not make sense with stream
+     * ciphers, but allow {@code NoPadding}.  See JCE spec.
+     *
+     * @param padding The padding type.  The only allowed value is
+     *      {@code NoPadding} case insensitive).
+     *
+     * @throws NoSuchPaddingException if a padding scheme besides
+     *      {@code NoPadding} is provided.
+     */
+    @Override
+    protected void engineSetPadding(String padding)
+            throws NoSuchPaddingException {
+        if (padding.equalsIgnoreCase("NoPadding") == false) {
+            throw new NoSuchPaddingException("Padding must be NoPadding");
+        }
+    }
+
+    /**
+     * Returns the block size.  For a stream cipher like ChaCha20, this
+     * value will always be zero.
+     *
+     * @return This method always returns 0.  See the JCE Specification.
+     */
+    @Override
+    protected int engineGetBlockSize() {
+        return 0;
+    }
+
+    /**
+     * Get the output size based on an input length.  In simple stream-cipher
+     * mode, the output size will equal the input size.  For ChaCha20-Poly1305
+     * for encryption the output size will be the sum of the input length
+     * and tag length.  For decryption, the output size will be the input
+     * length less the tag length or zero, whichever is larger.
+     *
+     * @param inputLen the length in bytes of the input
+     *
+     * @return the output length in bytes.
+     */
+    @Override
+    protected int engineGetOutputSize(int inputLen) {
+        int outLen = 0;
+
+        if (mode == MODE_NONE) {
+            outLen = inputLen;
+        } else if (mode == MODE_AEAD) {
+            outLen = (direction == Cipher.ENCRYPT_MODE) ?
+                    Math.addExact(inputLen, TAG_LENGTH) :
+                    Integer.max(inputLen - TAG_LENGTH, 0);
+        }
+
+        return outLen;
+    }
+
+    /**
+     * Get the nonce value used.
+     *
+     * @return the nonce bytes.  For ChaCha20 this will be a 12-byte value.
+     */
+    @Override
+    protected byte[] engineGetIV() {
+        return nonce.clone();
+    }
+
+    /**
+     * Get the algorithm parameters for this cipher.  For the ChaCha20
+     * cipher, this will always return {@code null} as there currently is
+     * no {@code AlgorithmParameters} implementation for ChaCha20.  For
+     * ChaCha20-Poly1305, a {@code ChaCha20Poly1305Parameters} object will be
+     * created and initialized with the configured nonce value and returned
+     * to the caller.
+     *
+     * @return a {@code null} value if the ChaCha20 cipher is used (mode is
+     * MODE_NONE), or a {@code ChaCha20Poly1305Parameters} object containing
+     * the nonce if the mode is MODE_AEAD.
+     */
+    @Override
+    protected AlgorithmParameters engineGetParameters() {
+        AlgorithmParameters params = null;
+        if (mode == MODE_AEAD) {
+            try {
+                // Force the 12-byte nonce into a DER-encoded OCTET_STRING
+                byte[] derNonce = new byte[nonce.length + 2];
+                derNonce[0] = 0x04;                 // OCTET_STRING tag
+                derNonce[1] = (byte)nonce.length;   // 12-byte length;
+                System.arraycopy(nonce, 0, derNonce, 2, nonce.length);
+                params = AlgorithmParameters.getInstance("ChaCha20-Poly1305");
+                params.init(derNonce);
+            } catch (NoSuchAlgorithmException | IOException exc) {
+                throw new RuntimeException(exc);
+            }
+        }
+
+        return params;
+    }
+
+    /**
+     * Initialize the engine using a key and secure random implementation.  If
+     * a SecureRandom object is provided it will be used to create a random
+     * nonce value.  If the {@code random} parameter is null an internal
+     * secure random source will be used to create the random nonce.
+     * The counter value will be set to 1.
+     *
+     * @param opmode the type of operation to do.  This value may not be
+     *      {@code Cipher.DECRYPT_MODE} or {@code Cipher.UNWRAP_MODE} mode
+     *      because it must generate random parameters like the nonce.
+     * @param key a 256-bit key suitable for ChaCha20
+     * @param random a {@code SecureRandom} implementation used to create the
+     *      random nonce.  If {@code null} is used for the random object,
+     *      then an internal secure random source will be used to create the
+     *      nonce.
+     *
+     * @throws UnsupportedOperationException if the mode of operation
+     *      is {@code Cipher.WRAP_MODE} or {@code Cipher.UNWRAP_MODE}
+     *      (currently unsupported).
+     * @throws InvalidKeyException if the key is of the wrong type or is
+     *      not 256-bits in length.  This will also be thrown if the opmode
+     *      parameter is {@code Cipher.DECRYPT_MODE}.
+     *      {@code Cipher.UNWRAP_MODE} would normally be disallowed in this
+     *      context but it is preempted by the UOE case above.
+     */
+    @Override
+    protected void engineInit(int opmode, Key key, SecureRandom random)
+            throws InvalidKeyException {
+        if (opmode != Cipher.DECRYPT_MODE) {
+            byte[] newNonce = createRandomNonce(random);
+            counter = 1;
+            init(opmode, key, newNonce);
+        } else {
+            throw new InvalidKeyException("Default parameter generation " +
+                "disallowed in DECRYPT and UNWRAP modes");
+        }
+    }
+
+    /**
+     * Initialize the engine using a key and secure random implementation.
+     *
+     * @param opmode the type of operation to do.  This value must be either
+     *      {@code Cipher.ENCRYPT_MODE} or {@code Cipher.DECRYPT_MODE}
+     * @param key a 256-bit key suitable for ChaCha20
+     * @param params a {@code ChaCha20ParameterSpec} that will provide
+     *      the nonce and initial block counter value.
+     * @param random a {@code SecureRandom} implementation, this parameter
+     *      is not used in this form of the initializer.
+     *
+     * @throws UnsupportedOperationException if the mode of operation
+     *      is {@code Cipher.WRAP_MODE} or {@code Cipher.UNWRAP_MODE}
+     *      (currently unsupported).
+     * @throws InvalidKeyException if the key is of the wrong type or is
+     *      not 256-bits in length.  This will also be thrown if the opmode
+     *      parameter is not {@code Cipher.ENCRYPT_MODE} or
+     *      {@code Cipher.DECRYPT_MODE} (excepting the UOE case above).
+     * @throws InvalidAlgorithmParameterException if {@code params} is
+     *      not a {@code ChaCha20ParameterSpec}
+     * @throws NullPointerException if {@code params} is {@code null}
+     */
+    @Override
+    protected void engineInit(int opmode, Key key,
+            AlgorithmParameterSpec params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+
+        // If AlgorithmParameterSpec is null, then treat this like an init
+        // of the form (int, Key, SecureRandom)
+        if (params == null) {
+            engineInit(opmode, key, random);
+            return;
+        }
+
+        // We will ignore the secure random implementation and use the nonce
+        // from the AlgorithmParameterSpec instead.
+        byte[] newNonce = null;
+        switch (mode) {
+            case MODE_NONE:
+                if (!(params instanceof ChaCha20ParameterSpec)) {
+                    throw new InvalidAlgorithmParameterException(
+                        "ChaCha20 algorithm requires ChaCha20ParameterSpec");
+                }
+                ChaCha20ParameterSpec chaParams = (ChaCha20ParameterSpec)params;
+                newNonce = chaParams.getNonce();
+                counter = ((long)chaParams.getCounter()) & 0x00000000FFFFFFFFL;
+                break;
+            case MODE_AEAD:
+                if (!(params instanceof IvParameterSpec)) {
+                    throw new InvalidAlgorithmParameterException(
+                        "ChaCha20-Poly1305 requires IvParameterSpec");
+                }
+                IvParameterSpec ivParams = (IvParameterSpec)params;
+                newNonce = ivParams.getIV();
+                if (newNonce.length != 12) {
+                    throw new InvalidAlgorithmParameterException(
+                        "ChaCha20-Poly1305 nonce must be 12 bytes in length");
+                }
+                break;
+            default:
+                // Should never happen
+                throw new RuntimeException("ChaCha20 in unsupported mode");
+        }
+        init(opmode, key, newNonce);
+    }
+
+    /**
+     * Initialize the engine using the {@code AlgorithmParameter} initialization
+     * format.  This cipher does supports initialization with
+     * {@code AlgorithmParameter} objects for ChaCha20-Poly1305 but not for
+     * ChaCha20 as a simple stream cipher.  In the latter case, it will throw
+     * an {@code InvalidAlgorithmParameterException} if the value is non-null.
+     * If a null value is supplied for the {@code params} field
+     * the cipher will be initialized with the counter value set to 1 and
+     * a random nonce.  If {@code null} is used for the random object,
+     * then an internal secure random source will be used to create the
+     * nonce.
+     *
+     * @param opmode the type of operation to do.  This value must be either
+     *      {@code Cipher.ENCRYPT_MODE} or {@code Cipher.DECRYPT_MODE}
+     * @param key a 256-bit key suitable for ChaCha20
+     * @param params a {@code null} value if the algorithm is ChaCha20, or
+     *      the appropriate {@code AlgorithmParameters} object containing the
+     *      nonce information if the algorithm is ChaCha20-Poly1305.
+     * @param random a {@code SecureRandom} implementation, may be {@code null}.
+     *
+     * @throws UnsupportedOperationException if the mode of operation
+     *      is {@code Cipher.WRAP_MODE} or {@code Cipher.UNWRAP_MODE}
+     *      (currently unsupported).
+     * @throws InvalidKeyException if the key is of the wrong type or is
+     *      not 256-bits in length.  This will also be thrown if the opmode
+     *      parameter is not {@code Cipher.ENCRYPT_MODE} or
+     *      {@code Cipher.DECRYPT_MODE} (excepting the UOE case above).
+     * @throws InvalidAlgorithmParameterException if {@code params} is
+     *      non-null and the algorithm is ChaCha20.  This exception will be
+     *      also thrown if the algorithm is ChaCha20-Poly1305 and an incorrect
+     *      {@code AlgorithmParameters} object is supplied.
+     */
+    @Override
+    protected void engineInit(int opmode, Key key,
+            AlgorithmParameters params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+
+        // If AlgorithmParameters is null, then treat this like an init
+        // of the form (int, Key, SecureRandom)
+        if (params == null) {
+            engineInit(opmode, key, random);
+            return;
+        }
+
+        byte[] newNonce = null;
+        switch (mode) {
+            case MODE_NONE:
+                throw new InvalidAlgorithmParameterException(
+                        "AlgorithmParameters not supported");
+            case MODE_AEAD:
+                String paramAlg = params.getAlgorithm();
+                if (!paramAlg.equalsIgnoreCase("ChaCha20-Poly1305")) {
+                    throw new InvalidAlgorithmParameterException(
+                            "Invalid parameter type: " + paramAlg);
+                }
+                try {
+                    DerValue dv = new DerValue(params.getEncoded());
+                    newNonce = dv.getOctetString();
+                    if (newNonce.length != 12) {
+                        throw new InvalidAlgorithmParameterException(
+                                "ChaCha20-Poly1305 nonce must be " +
+                                "12 bytes in length");
+                    }
+                } catch (IOException ioe) {
+                    throw new InvalidAlgorithmParameterException(ioe);
+                }
+                break;
+            default:
+                throw new RuntimeException("Invalid mode: " + mode);
+        }
+
+        // If after all the above processing we still don't have a nonce value
+        // then supply a random one provided a random source has been given.
+        if (newNonce == null) {
+            newNonce = createRandomNonce(random);
+        }
+
+        // Continue with initialization
+        init(opmode, key, newNonce);
+    }
+
+    /**
+     * Update additional authenticated data (AAD).
+     *
+     * @param src the byte array containing the authentication data.
+     * @param offset the starting offset in the buffer to update.
+     * @param len the amount of authentication data to update.
+     *
+     * @throws IllegalStateException if the cipher has not been initialized,
+     *      {@code engineUpdate} has been called, or the cipher is running
+     *      in a non-AEAD mode of operation.  It will also throw this
+     *      exception if the submitted AAD would overflow a 64-bit length
+     *      counter.
+     */
+    @Override
+    protected void engineUpdateAAD(byte[] src, int offset, int len) {
+        if (!initialized) {
+            // We know that the cipher has not been initialized if the key
+            // is still null.
+            throw new IllegalStateException(
+                    "Attempted to update AAD on uninitialized Cipher");
+        } else if (aadDone) {
+            // No AAD updates allowed after the PT/CT update method is called
+            throw new IllegalStateException("Attempted to update AAD on " +
+                    "Cipher after plaintext/ciphertext update");
+        } else if (mode != MODE_AEAD) {
+            throw new IllegalStateException(
+                    "Cipher is running in non-AEAD mode");
+        } else {
+            try {
+                aadLen = Math.addExact(aadLen, len);
+                authUpdate(src, offset, len);
+            } catch (ArithmeticException ae) {
+                throw new IllegalStateException("AAD overflow", ae);
+            }
+        }
+    }
+
+    /**
+     * Update additional authenticated data (AAD).
+     *
+     * @param src the ByteBuffer containing the authentication data.
+     *
+     * @throws IllegalStateException if the cipher has not been initialized,
+     *      {@code engineUpdate} has been called, or the cipher is running
+     *      in a non-AEAD mode of operation.  It will also throw this
+     *      exception if the submitted AAD would overflow a 64-bit length
+     *      counter.
+     */
+    @Override
+    protected void engineUpdateAAD(ByteBuffer src) {
+        if (!initialized) {
+            // We know that the cipher has not been initialized if the key
+            // is still null.
+            throw new IllegalStateException(
+                    "Attempted to update AAD on uninitialized Cipher");
+        } else if (aadDone) {
+            // No AAD updates allowed after the PT/CT update method  is called
+            throw new IllegalStateException("Attempted to update AAD on " +
+                    "Cipher after plaintext/ciphertext update");
+        } else if (mode != MODE_AEAD) {
+            throw new IllegalStateException(
+                    "Cipher is running in non-AEAD mode");
+        } else {
+            try {
+                aadLen = Math.addExact(aadLen, (src.limit() - src.position()));
+                authenticator.engineUpdate(src);
+            } catch (ArithmeticException ae) {
+                throw new IllegalStateException("AAD overflow", ae);
+            }
+        }
+    }
+
+    /**
+     * Create a random 12-byte nonce.
+     *
+     * @param random a {@code SecureRandom} object.  If {@code null} is
+     * provided a new {@code SecureRandom} object will be instantiated.
+     *
+     * @return a 12-byte array containing the random nonce.
+     */
+    private byte[] createRandomNonce(SecureRandom random) {
+        byte[] newNonce = new byte[12];
+        SecureRandom rand = (random != null) ? random : new SecureRandom();
+        rand.nextBytes(newNonce);
+        return newNonce;
+    }
+
+    /**
+     * Perform additional initialization actions based on the key and operation
+     * type.
+     *
+     * @param opmode the type of operation to do.  This value must be either
+     *      {@code Cipher.ENCRYPT_MODE} or {@code Cipher.DECRYPT_MODE}
+     * @param key a 256-bit key suitable for ChaCha20
+     * @param newNonce the new nonce value for this initialization.
+     *
+     * @throws UnsupportedOperationException if the {@code opmode} parameter
+     *      is {@code Cipher.WRAP_MODE} or {@code Cipher.UNWRAP_MODE}
+     *      (currently unsupported).
+     * @throws InvalidKeyException if the {@code opmode} parameter is not
+     *      {@code Cipher.ENCRYPT_MODE} or {@code Cipher.DECRYPT_MODE}, or
+     *      if the key format is not {@code RAW}.
+     */
+    private void init(int opmode, Key key, byte[] newNonce)
+            throws InvalidKeyException {
+        if ((opmode == Cipher.WRAP_MODE) || (opmode == Cipher.UNWRAP_MODE)) {
+            throw new UnsupportedOperationException(
+                    "WRAP_MODE and UNWRAP_MODE are not currently supported");
+        } else if ((opmode != Cipher.ENCRYPT_MODE) &&
+                (opmode != Cipher.DECRYPT_MODE)) {
+            throw new InvalidKeyException("Unknown opmode: " + opmode);
+        }
+
+        // Make sure that the provided key and nonce are unique before
+        // assigning them to the object.
+        byte[] newKeyBytes = getEncodedKey(key);
+        checkKeyAndNonce(newKeyBytes, newNonce);
+        this.keyBytes = newKeyBytes;
+        nonce = newNonce;
+
+        // Now that we have the key and nonce, we can build the initial state
+        setInitialState();
+
+        if (mode == MODE_NONE) {
+            engine = new EngineStreamOnly();
+        } else if (mode == MODE_AEAD) {
+            if (opmode == Cipher.ENCRYPT_MODE) {
+                engine = new EngineAEADEnc();
+            } else if (opmode == Cipher.DECRYPT_MODE) {
+                engine = new EngineAEADDec();
+            } else {
+                throw new InvalidKeyException("Not encrypt or decrypt mode");
+            }
+        }
+
+        // We can also get one block's worth of keystream created
+        finalCounterValue = counter + MAX_UINT32;
+        generateKeystream();
+        direction = opmode;
+        aadDone = false;
+        this.keyStrOffset = 0;
+        initialized = true;
+    }
+
+    /**
+     * Check the key and nonce bytes to make sure that they do not repeat
+     * across reinitialization.
+     *
+     * @param newKeyBytes the byte encoding for the newly provided key
+     * @param newNonce the new nonce to be used with this initialization
+     *
+     * @throws InvalidKeyException if both the key and nonce match the
+     *      previous initialization.
+     *
+     */
+    private void checkKeyAndNonce(byte[] newKeyBytes, byte[] newNonce)
+            throws InvalidKeyException {
+        // A new initialization must have either a different key or nonce
+        // so the starting state for each block is not the same as the
+        // previous initialization.
+        if (MessageDigest.isEqual(newKeyBytes, keyBytes) &&
+                MessageDigest.isEqual(newNonce, nonce)) {
+            throw new InvalidKeyException(
+                    "Matching key and nonce from previous initialization");
+        }
+    }
+
+    /**
+     * Return the encoded key as a byte array
+     *
+     * @param key the {@code Key} object used for this {@code Cipher}
+     *
+     * @return the key bytes
+     *
+     * @throws InvalidKeyException if the key is of the wrong type or length,
+     *      or if the key encoding format is not {@code RAW}.
+     */
+    private static byte[] getEncodedKey(Key key) throws InvalidKeyException {
+        if ("RAW".equals(key.getFormat()) == false) {
+            throw new InvalidKeyException("Key encoding format must be RAW");
+        }
+        byte[] encodedKey = key.getEncoded();
+        if (encodedKey == null || encodedKey.length != 32) {
+            throw new InvalidKeyException("Key length must be 256 bits");
+        }
+        return encodedKey;
+    }
+
+    /**
+     * Update the currently running operation with additional data
+     *
+     * @param in the plaintext or ciphertext input bytes (depending on the
+     *      operation type).
+     * @param inOfs the offset into the input array
+     * @param inLen the length of the data to use for the update operation.
+     *
+     * @return the resulting plaintext or ciphertext bytes (depending on
+     *      the operation type)
+     */
+    @Override
+    protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
+        byte[] out = new byte[inLen];
+        try {
+            engine.doUpdate(in, inOfs, inLen, out, 0);
+        } catch (ShortBufferException | KeyException exc) {
+            throw new RuntimeException(exc);
+        }
+
+        return out;
+    }
+
+    /**
+     * Update the currently running operation with additional data
+     *
+     * @param in the plaintext or ciphertext input bytes (depending on the
+     *      operation type).
+     * @param inOfs the offset into the input array
+     * @param inLen the length of the data to use for the update operation.
+     * @param out the byte array that will hold the resulting data.  The array
+     *      must be large enough to hold the resulting data.
+     * @param outOfs the offset for the {@code out} buffer to begin writing
+     *      the resulting data.
+     *
+     * @return the length in bytes of the data written into the {@code out}
+     *      buffer.
+     *
+     * @throws ShortBufferException if the buffer {@code out} does not have
+     *      enough space to hold the resulting data.
+     */
+    @Override
+    protected int engineUpdate(byte[] in, int inOfs, int inLen,
+            byte[] out, int outOfs) throws ShortBufferException {
+        int bytesUpdated = 0;
+        try {
+            bytesUpdated = engine.doUpdate(in, inOfs, inLen, out, outOfs);
+        } catch (KeyException ke) {
+            throw new RuntimeException(ke);
+        }
+        return bytesUpdated;
+    }
+
+    /**
+     * Complete the currently running operation using any final
+     * data provided by the caller.
+     *
+     * @param in the plaintext or ciphertext input bytes (depending on the
+     *      operation type).
+     * @param inOfs the offset into the input array
+     * @param inLen the length of the data to use for the update operation.
+     *
+     * @return the resulting plaintext or ciphertext bytes (depending on
+     *      the operation type)
+     *
+     * @throws AEADBadTagException if, during decryption, the provided tag
+     *      does not match the calculated tag.
+     */
+    @Override
+    protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
+            throws AEADBadTagException {
+        byte[] output = new byte[engineGetOutputSize(inLen)];
+        try {
+            engine.doFinal(in, inOfs, inLen, output, 0);
+        } catch (ShortBufferException | KeyException exc) {
+            throw new RuntimeException(exc);
+        } finally {
+            // Regardless of what happens, the cipher cannot be used for
+            // further processing until it has been freshly initialized.
+            initialized = false;
+        }
+        return output;
+    }
+
+    /**
+     * Complete the currently running operation using any final
+     * data provided by the caller.
+     *
+     * @param in the plaintext or ciphertext input bytes (depending on the
+     *      operation type).
+     * @param inOfs the offset into the input array
+     * @param inLen the length of the data to use for the update operation.
+     * @param out the byte array that will hold the resulting data.  The array
+     *      must be large enough to hold the resulting data.
+     * @param outOfs the offset for the {@code out} buffer to begin writing
+     *      the resulting data.
+     *
+     * @return the length in bytes of the data written into the {@code out}
+     *      buffer.
+     *
+     * @throws ShortBufferException if the buffer {@code out} does not have
+     *      enough space to hold the resulting data.
+     * @throws AEADBadTagException if, during decryption, the provided tag
+     *      does not match the calculated tag.
+     */
+    @Override
+    protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
+            int outOfs) throws ShortBufferException, AEADBadTagException {
+
+        int bytesUpdated = 0;
+        try {
+            bytesUpdated = engine.doFinal(in, inOfs, inLen, out, outOfs);
+        } catch (KeyException ke) {
+            throw new RuntimeException(ke);
+        } finally {
+            // Regardless of what happens, the cipher cannot be used for
+            // further processing until it has been freshly initialized.
+            initialized = false;
+        }
+        return bytesUpdated;
+    }
+
+    /**
+     * Wrap a {@code Key} using this Cipher's current encryption parameters.
+     *
+     * @param key the key to wrap.  The data that will be encrypted will
+     *      be the provided {@code Key} in its encoded form.
+     *
+     * @return a byte array consisting of the wrapped key.
+     *
+     * @throws UnsupportedOperationException this will (currently) always
+     *      be thrown, as this method is not currently supported.
+     */
+    @Override
+    protected byte[] engineWrap(Key key) throws IllegalBlockSizeException,
+            InvalidKeyException {
+        throw new UnsupportedOperationException(
+                "Wrap operations are not supported");
+    }
+
+    /**
+     * Unwrap a {@code Key} using this Cipher's current encryption parameters.
+     *
+     * @param wrappedKey the key to unwrap.
+     * @param algorithm the algorithm associated with the wrapped key
+     * @param type the type of the wrapped key. This is one of
+     *      {@code SECRET_KEY}, {@code PRIVATE_KEY}, or {@code PUBLIC_KEY}.
+     *
+     * @return the unwrapped key as a {@code Key} object.
+     *
+     * @throws UnsupportedOperationException this will (currently) always
+     *      be thrown, as this method is not currently supported.
+     */
+    @Override
+    protected Key engineUnwrap(byte[] wrappedKey, String algorithm,
+            int type) throws InvalidKeyException, NoSuchAlgorithmException {
+        throw new UnsupportedOperationException(
+                "Unwrap operations are not supported");
+    }
+
+    /**
+     * Get the length of a provided key in bits.
+     *
+     * @param key the key to be evaluated
+     *
+     * @return the length of the key in bits
+     *
+     * @throws InvalidKeyException if the key is invalid or does not
+     *      have an encoded form.
+     */
+    @Override
+    protected int engineGetKeySize(Key key) throws InvalidKeyException {
+        byte[] encodedKey = getEncodedKey(key);
+        return encodedKey.length << 3;
+    }
+
+    /**
+     * Set the initial state.  This will populate the state array and put the
+     * key and nonce into their proper locations.  The counter field is not
+     * set here.
+     *
+     * @throws IllegalArgumentException if the key or nonce are not in
+     *      their proper lengths (32 bytes for the key, 12 bytes for the
+     *      nonce).
+     * @throws InvalidKeyException if the key does not support an encoded form.
+     */
+    private void setInitialState() throws InvalidKeyException {
+        // Apply constants to first 4 words
+        startState[0] = STATE_CONST_0;
+        startState[1] = STATE_CONST_1;
+        startState[2] = STATE_CONST_2;
+        startState[3] = STATE_CONST_3;
+
+        // Apply the key bytes as 8 32-bit little endian ints (4 through 11)
+        for (int i = 0; i < 32; i += 4) {
+            startState[(i / 4) + 4] = (keyBytes[i] & 0x000000FF) |
+                ((keyBytes[i + 1] << 8) & 0x0000FF00) |
+                ((keyBytes[i + 2] << 16) & 0x00FF0000) |
+                ((keyBytes[i + 3] << 24) & 0xFF000000);
+        }
+
+        startState[12] = 0;
+
+        // The final integers for the state are from the nonce
+        // interpreted as 3 little endian integers
+        for (int i = 0; i < 12; i += 4) {
+            startState[(i / 4) + 13] = (nonce[i] & 0x000000FF) |
+                ((nonce[i + 1] << 8) & 0x0000FF00) |
+                ((nonce[i + 2] << 16) & 0x00FF0000) |
+                ((nonce[i + 3] << 24) & 0xFF000000);
+        }
+    }
+
+    /**
+     * Using the current state and counter create the next set of keystream
+     * bytes.  This method will generate the next 512 bits of keystream and
+     * return it in the {@code keyStream} parameter.  Following the
+     * block function the counter will be incremented.
+     */
+    private void generateKeystream() {
+        chaCha20Block(startState, counter, keyStream);
+        counter++;
+    }
+
+    /**
+     * Perform a full 20-round ChaCha20 transform on the initial state.
+     *
+     * @param initState the starting state, not including the counter
+     *      value.
+     * @param counter the counter value to apply
+     * @param result  the array that will hold the result of the ChaCha20
+     *      block function.
+     *
+     * @note it is the caller's responsibility to ensure that the workState
+     * is sized the same as the initState, no checking is performed internally.
+     */
+    private static void chaCha20Block(int[] initState, long counter,
+                                      byte[] result) {
+        // Create an initial state and clone a working copy
+        int ws00 = STATE_CONST_0;
+        int ws01 = STATE_CONST_1;
+        int ws02 = STATE_CONST_2;
+        int ws03 = STATE_CONST_3;
+        int ws04 = initState[4];
+        int ws05 = initState[5];
+        int ws06 = initState[6];
+        int ws07 = initState[7];
+        int ws08 = initState[8];
+        int ws09 = initState[9];
+        int ws10 = initState[10];
+        int ws11 = initState[11];
+        int ws12 = (int)counter;
+        int ws13 = initState[13];
+        int ws14 = initState[14];
+        int ws15 = initState[15];
+
+        // Peform 10 iterations of the 8 quarter round set
+        for (int round = 0; round < 10; round++) {
+            ws00 += ws04;
+            ws12 = Integer.rotateLeft(ws12 ^ ws00, 16);
+
+            ws08 += ws12;
+            ws04 = Integer.rotateLeft(ws04 ^ ws08, 12);
+
+            ws00 += ws04;
+            ws12 = Integer.rotateLeft(ws12 ^ ws00, 8);
+
+            ws08 += ws12;
+            ws04 = Integer.rotateLeft(ws04 ^ ws08, 7);
+
+            ws01 += ws05;
+            ws13 = Integer.rotateLeft(ws13 ^ ws01, 16);
+
+            ws09 += ws13;
+            ws05 = Integer.rotateLeft(ws05 ^ ws09, 12);
+
+            ws01 += ws05;
+            ws13 = Integer.rotateLeft(ws13 ^ ws01, 8);
+
+            ws09 += ws13;
+            ws05 = Integer.rotateLeft(ws05 ^ ws09, 7);
+
+            ws02 += ws06;
+            ws14 = Integer.rotateLeft(ws14 ^ ws02, 16);
+
+            ws10 += ws14;
+            ws06 = Integer.rotateLeft(ws06 ^ ws10, 12);
+
+            ws02 += ws06;
+            ws14 = Integer.rotateLeft(ws14 ^ ws02, 8);
+
+            ws10 += ws14;
+            ws06 = Integer.rotateLeft(ws06 ^ ws10, 7);
+
+            ws03 += ws07;
+            ws15 = Integer.rotateLeft(ws15 ^ ws03, 16);
+
+            ws11 += ws15;
+            ws07 = Integer.rotateLeft(ws07 ^ ws11, 12);
+
+            ws03 += ws07;
+            ws15 = Integer.rotateLeft(ws15 ^ ws03, 8);
+
+            ws11 += ws15;
+            ws07 = Integer.rotateLeft(ws07 ^ ws11, 7);
+
+            ws00 += ws05;
+            ws15 = Integer.rotateLeft(ws15 ^ ws00, 16);
+
+            ws10 += ws15;
+            ws05 = Integer.rotateLeft(ws05 ^ ws10, 12);
+
+            ws00 += ws05;
+            ws15 = Integer.rotateLeft(ws15 ^ ws00, 8);
+
+            ws10 += ws15;
+            ws05 = Integer.rotateLeft(ws05 ^ ws10, 7);
+
+            ws01 += ws06;
+            ws12 = Integer.rotateLeft(ws12 ^ ws01, 16);
+
+            ws11 += ws12;
+            ws06 = Integer.rotateLeft(ws06 ^ ws11, 12);
+
+            ws01 += ws06;
+            ws12 = Integer.rotateLeft(ws12 ^ ws01, 8);
+
+            ws11 += ws12;
+            ws06 = Integer.rotateLeft(ws06 ^ ws11, 7);
+
+            ws02 += ws07;
+            ws13 = Integer.rotateLeft(ws13 ^ ws02, 16);
+
+            ws08 += ws13;
+            ws07 = Integer.rotateLeft(ws07 ^ ws08, 12);
+
+            ws02 += ws07;
+            ws13 = Integer.rotateLeft(ws13 ^ ws02, 8);
+
+            ws08 += ws13;
+            ws07 = Integer.rotateLeft(ws07 ^ ws08, 7);
+
+            ws03 += ws04;
+            ws14 = Integer.rotateLeft(ws14 ^ ws03, 16);
+
+            ws09 += ws14;
+            ws04 = Integer.rotateLeft(ws04 ^ ws09, 12);
+
+            ws03 += ws04;
+            ws14 = Integer.rotateLeft(ws14 ^ ws03, 8);
+
+            ws09 += ws14;
+            ws04 = Integer.rotateLeft(ws04 ^ ws09, 7);
+        }
+
+        // Add the end working state back into the original state
+        asIntLittleEndian.set(result, 0, ws00 + STATE_CONST_0);
+        asIntLittleEndian.set(result, 4, ws01 + STATE_CONST_1);
+        asIntLittleEndian.set(result, 8, ws02 + STATE_CONST_2);
+        asIntLittleEndian.set(result, 12, ws03 + STATE_CONST_3);
+        asIntLittleEndian.set(result, 16, ws04 + initState[4]);
+        asIntLittleEndian.set(result, 20, ws05 + initState[5]);
+        asIntLittleEndian.set(result, 24, ws06 + initState[6]);
+        asIntLittleEndian.set(result, 28, ws07 + initState[7]);
+        asIntLittleEndian.set(result, 32, ws08 + initState[8]);
+        asIntLittleEndian.set(result, 36, ws09 + initState[9]);
+        asIntLittleEndian.set(result, 40, ws10 + initState[10]);
+        asIntLittleEndian.set(result, 44, ws11 + initState[11]);
+        // Add the counter back into workState[12]
+        asIntLittleEndian.set(result, 48, ws12 + (int)counter);
+        asIntLittleEndian.set(result, 52, ws13 + initState[13]);
+        asIntLittleEndian.set(result, 56, ws14 + initState[14]);
+        asIntLittleEndian.set(result, 60, ws15 + initState[15]);
+    }
+
+    /**
+     * Perform the ChaCha20 transform.
+     *
+     * @param in the array of bytes for the input
+     * @param inOff the offset into the input array to start the transform
+     * @param inLen the length of the data to perform the transform on.
+     * @param out the output array.  It must be large enough to hold the
+     *      resulting data
+     * @param outOff the offset into the output array to place the resulting
+     *      data.
+     */
+    private void chaCha20Transform(byte[] in, int inOff, int inLen,
+            byte[] out, int outOff) throws KeyException {
+        int remainingData = inLen;
+
+        while (remainingData > 0) {
+            int ksRemain = keyStream.length - keyStrOffset;
+            if (ksRemain <= 0) {
+                if (counter <= finalCounterValue) {
+                    generateKeystream();
+                    keyStrOffset = 0;
+                    ksRemain = keyStream.length;
+                } else {
+                    throw new KeyException("Counter exhausted.  " +
+                            "Reinitialize with new key and/or nonce");
+                }
+            }
+
+            // XOR each byte in the keystream against the input
+            int xformLen = Math.min(remainingData, ksRemain);
+            xor(keyStream, keyStrOffset, in, inOff, out, outOff, xformLen);
+            outOff += xformLen;
+            inOff += xformLen;
+            keyStrOffset += xformLen;
+            remainingData -= xformLen;
+        }
+    }
+
+    private static void xor(byte[] in1, int off1, byte[] in2, int off2,
+            byte[] out, int outOff, int len) {
+        while (len >= 8) {
+            long v1 = (long) asLongView.get(in1, off1);
+            long v2 = (long) asLongView.get(in2, off2);
+            asLongView.set(out, outOff, v1 ^ v2);
+            off1 += 8;
+            off2 += 8;
+            outOff += 8;
+            len -= 8;
+        }
+        while (len > 0) {
+            out[outOff] = (byte) (in1[off1] ^ in2[off2]);
+            off1++;
+            off2++;
+            outOff++;
+            len--;
+        }
+    }
+
+    /**
+     * Perform initialization steps for the authenticator
+     *
+     * @throws InvalidKeyException if the key is unusable for some reason
+     *      (invalid length, etc.)
+     */
+    private void initAuthenticator() throws InvalidKeyException {
+        authenticator = new Poly1305();
+
+        // Derive the Poly1305 key from the starting state
+        byte[] serializedKey = new byte[KEYSTREAM_SIZE];
+        chaCha20Block(startState, 0, serializedKey);
+
+        authenticator.engineInit(new SecretKeySpec(serializedKey, 0, 32,
+                authAlgName), null);
+        aadLen = 0;
+        dataLen = 0;
+    }
+
+    /**
+     * Update the authenticator state with data.  This routine can be used
+     * to add data to the authenticator, whether AAD or application data.
+     *
+     * @param data the data to stir into the authenticator.
+     * @param offset the offset into the data.
+     * @param length the length of data to add to the authenticator.
+     *
+     * @return the number of bytes processed by this method.
+     */
+    private int authUpdate(byte[] data, int offset, int length) {
+        Objects.checkFromIndexSize(offset, length, data.length);
+        authenticator.engineUpdate(data, offset, length);
+        return length;
+    }
+
+    /**
+     * Finalize the data and return the tag.
+     *
+     * @param data an array containing any remaining data to process.
+     * @param dataOff the offset into the data.
+     * @param length the length of the data to process.
+     * @param out the array to write the resulting tag into
+     * @param outOff the offset to begin writing the data.
+     *
+     * @throws ShortBufferException if there is insufficient room to
+     *      write the tag.
+     */
+    private void authFinalizeData(byte[] data, int dataOff, int length,
+            byte[] out, int outOff) throws ShortBufferException {
+        // Update with the final chunk of ciphertext, then pad to a
+        // multiple of 16.
+        if (data != null) {
+            dataLen += authUpdate(data, dataOff, length);
+        }
+        authPad16(dataLen);
+
+        // Also write the AAD and ciphertext data lengths as little-endian
+        // 64-bit values.
+        authWriteLengths(aadLen, dataLen, lenBuf);
+        authenticator.engineUpdate(lenBuf, 0, lenBuf.length);
+        byte[] tag = authenticator.engineDoFinal();
+        Objects.checkFromIndexSize(outOff, tag.length, out.length);
+        System.arraycopy(tag, 0, out, outOff, tag.length);
+        aadLen = 0;
+        dataLen = 0;
+    }
+
+    /**
+     * Based on a given length of data, make the authenticator process
+     * zero bytes that will pad the length out to a multiple of 16.
+     *
+     * @param dataLen the starting length to be padded.
+     */
+    private void authPad16(long dataLen) {
+        // Pad out the AAD or data to a multiple of 16 bytes
+        authenticator.engineUpdate(padBuf, 0,
+                (TAG_LENGTH - ((int)dataLen & 15)) & 15);
+    }
+
+    /**
+     * Write the two 64-bit little-endian length fields into an array
+     * for processing by the poly1305 authenticator.
+     *
+     * @param aLen the length of the AAD.
+     * @param dLen the length of the application data.
+     * @param buf the buffer to write the two lengths into.
+     *
+     * @note it is the caller's responsibility to provide an array large
+     *      enough to hold the two longs.
+     */
+    private void authWriteLengths(long aLen, long dLen, byte[] buf) {
+        asLongLittleEndian.set(buf, 0, aLen);
+        asLongLittleEndian.set(buf, Long.BYTES, dLen);
+    }
+
+    /**
+     * Interface for the underlying processing engines for ChaCha20
+     */
+    interface ChaChaEngine {
+        /**
+         * Perform a multi-part update for ChaCha20.
+         *
+         * @param in the input data.
+         * @param inOff the offset into the input.
+         * @param inLen the length of the data to process.
+         * @param out the output buffer.
+         * @param outOff the offset at which to write the output data.
+         *
+         * @return the number of output bytes written.
+         *
+         * @throws ShortBufferException if the output buffer does not
+         *      provide enough space.
+         * @throws KeyException if the counter value has been exhausted.
+         */
+        int doUpdate(byte[] in, int inOff, int inLen, byte[] out, int outOff)
+                throws ShortBufferException, KeyException;
+
+        /**
+         * Finalize a multi-part or single-part ChaCha20 operation.
+         *
+         * @param in the input data.
+         * @param inOff the offset into the input.
+         * @param inLen the length of the data to process.
+         * @param out the output buffer.
+         * @param outOff the offset at which to write the output data.
+         *
+         * @return the number of output bytes written.
+         *
+         * @throws ShortBufferException if the output buffer does not
+         *      provide enough space.
+         * @throws AEADBadTagException if in decryption mode the provided
+         *      tag and calculated tag do not match.
+         * @throws KeyException if the counter value has been exhausted.
+         */
+        int doFinal(byte[] in, int inOff, int inLen, byte[] out, int outOff)
+                throws ShortBufferException, AEADBadTagException, KeyException;
+    }
+
+    private final class EngineStreamOnly implements ChaChaEngine {
+
+        private EngineStreamOnly () { }
+
+        @Override
+        public int doUpdate(byte[] in, int inOff, int inLen, byte[] out,
+                int outOff) throws ShortBufferException, KeyException {
+            if (initialized) {
+               try {
+                    if (out != null) {
+                        Objects.checkFromIndexSize(outOff, inLen, out.length);
+                    } else {
+                        throw new ShortBufferException(
+                                "Output buffer too small");
+                    }
+                } catch (IndexOutOfBoundsException iobe) {
+                    throw new ShortBufferException("Output buffer too small");
+                }
+                if (in != null) {
+                    Objects.checkFromIndexSize(inOff, inLen, in.length);
+                    chaCha20Transform(in, inOff, inLen, out, outOff);
+                }
+                return inLen;
+            } else {
+                throw new IllegalStateException(
+                        "Must use either a different key or iv.");
+            }
+        }
+
+        @Override
+        public int doFinal(byte[] in, int inOff, int inLen, byte[] out,
+                int outOff) throws ShortBufferException, KeyException {
+            return doUpdate(in, inOff, inLen, out, outOff);
+        }
+    }
+
+    private final class EngineAEADEnc implements ChaChaEngine {
+
+        private EngineAEADEnc() throws InvalidKeyException {
+            initAuthenticator();
+            counter = 1;
+        }
+
+        @Override
+        public int doUpdate(byte[] in, int inOff, int inLen, byte[] out,
+                int outOff) throws ShortBufferException, KeyException {
+            if (initialized) {
+                // If this is the first update since AAD updates, signal that
+                // we're done processing AAD info and pad the AAD to a multiple
+                // of 16 bytes.
+                if (!aadDone) {
+                    authPad16(aadLen);
+                    aadDone = true;
+                }
+                try {
+                    if (out != null) {
+                        Objects.checkFromIndexSize(outOff, inLen, out.length);
+                    } else {
+                        throw new ShortBufferException(
+                                "Output buffer too small");
+                    }
+                } catch (IndexOutOfBoundsException iobe) {
+                    throw new ShortBufferException("Output buffer too small");
+                }
+                if (in != null) {
+                    Objects.checkFromIndexSize(inOff, inLen, in.length);
+                    chaCha20Transform(in, inOff, inLen, out, outOff);
+                    dataLen += authUpdate(out, outOff, inLen);
+                }
+
+                return inLen;
+            } else {
+                throw new IllegalStateException(
+                        "Must use either a different key or iv.");
+            }
+        }
+
+        @Override
+        public int doFinal(byte[] in, int inOff, int inLen, byte[] out,
+                int outOff) throws ShortBufferException, KeyException {
+            // Make sure we have enough room for the remaining data (if any)
+            // and the tag.
+            if ((inLen + TAG_LENGTH) > (out.length - outOff)) {
+                throw new ShortBufferException("Output buffer too small");
+            }
+
+            doUpdate(in, inOff, inLen, out, outOff);
+            authFinalizeData(null, 0, 0, out, outOff + inLen);
+            aadDone = false;
+            return inLen + TAG_LENGTH;
+        }
+    }
+
+    private final class EngineAEADDec implements ChaChaEngine {
+
+        private final ByteArrayOutputStream cipherBuf;
+        private final byte[] tag;
+
+        private EngineAEADDec() throws InvalidKeyException {
+            initAuthenticator();
+            counter = 1;
+            cipherBuf = new ByteArrayOutputStream(CIPHERBUF_BASE);
+            tag = new byte[TAG_LENGTH];
+        }
+
+        @Override
+        public int doUpdate(byte[] in, int inOff, int inLen, byte[] out,
+                int outOff) {
+            if (initialized) {
+                // If this is the first update since AAD updates, signal that
+                // we're done processing AAD info and pad the AAD to a multiple
+                // of 16 bytes.
+                if (!aadDone) {
+                    authPad16(aadLen);
+                    aadDone = true;
+                }
+
+                if (in != null) {
+                    Objects.checkFromIndexSize(inOff, inLen, in.length);
+                    cipherBuf.write(in, inOff, inLen);
+                }
+            } else {
+                throw new IllegalStateException(
+                        "Must use either a different key or iv.");
+            }
+
+            return 0;
+        }
+
+        @Override
+        public int doFinal(byte[] in, int inOff, int inLen, byte[] out,
+                int outOff) throws ShortBufferException, AEADBadTagException,
+                KeyException {
+
+            byte[] ctPlusTag;
+            int ctPlusTagLen;
+            if (cipherBuf.size() == 0 && inOff == 0) {
+                // No previous data has been seen before doFinal, so we do
+                // not need to hold any ciphertext in a buffer.  We can
+                // process it directly from the "in" parameter.
+                doUpdate(null, inOff, inLen, out, outOff);
+                ctPlusTag = in;
+                ctPlusTagLen = inLen;
+            } else {
+                doUpdate(in, inOff, inLen, out, outOff);
+                ctPlusTag = cipherBuf.toByteArray();
+                ctPlusTagLen = ctPlusTag.length;
+            }
+            cipherBuf.reset();
+
+            // There must at least be a tag length's worth of ciphertext
+            // data in the buffered input.
+            if (ctPlusTagLen < TAG_LENGTH) {
+                throw new AEADBadTagException("Input too short - need tag");
+            }
+            int ctLen = ctPlusTagLen - TAG_LENGTH;
+
+            // Make sure we will have enough room for the output buffer
+            try {
+                Objects.checkFromIndexSize(outOff, ctLen, out.length);
+            } catch (IndexOutOfBoundsException ioobe) {
+                throw new ShortBufferException("Output buffer too small");
+            }
+
+            // Calculate and compare the tag.  Only do the decryption
+            // if and only if the tag matches.
+            authFinalizeData(ctPlusTag, 0, ctLen, tag, 0);
+            if (Arrays.compare(ctPlusTag, ctLen, ctPlusTagLen,
+                    tag, 0, tag.length) != 0) {
+                throw new AEADBadTagException("Tag mismatch");
+            }
+            chaCha20Transform(ctPlusTag, 0, ctLen, out, outOff);
+            aadDone = false;
+
+            return ctLen;
+        }
+    }
+
+    public static final class ChaCha20Only extends ChaCha20Cipher {
+        public ChaCha20Only() {
+            mode = MODE_NONE;
+        }
+    }
+
+    public static final class ChaCha20Poly1305 extends ChaCha20Cipher {
+        public ChaCha20Poly1305() {
+            mode = MODE_AEAD;
+            authAlgName = "Poly1305";
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Poly1305Parameters.java	Thu May 31 13:09:04 2018 -0700
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 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.  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 com.sun.crypto.provider;
+
+import java.io.IOException;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import javax.crypto.spec.IvParameterSpec;
+import sun.security.util.*;
+
+/**
+ * This class implements the parameter set used with the ChaCha20-Poly1305
+ * algorithm.  The parameter definition comes from
+ * <a href="https://tools.ietf.org/html/rfc8103"><i>RFC 8103</i></a>
+ * and is defined according to the following ASN.1:
+ *
+ * <pre>
+ * id-alg-AEADChaCha20Poly1305 OBJECT IDENTIFIER ::=
+          { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
+            pkcs9(9) smime(16) alg(3) 18 }
+
+ * AEADChaCha20Poly1305Nonce ::= OCTET STRING (SIZE(12))
+ * </pre>
+ *
+ * The AlgorithmParameters may be instantiated either by its name
+ * ("ChaCha20-Poly1305") or via its OID (1.2.840.113549.1.9.16.3.18)
+ */
+public final class ChaCha20Poly1305Parameters extends AlgorithmParametersSpi {
+
+    private static final String DEFAULT_FMT = "ASN.1";
+    private byte[] nonce;
+
+    public ChaCha20Poly1305Parameters() {}
+
+    /**
+     * Initialize the ChaCha20Poly1305Parameters using an IvParameterSpec.
+     *
+     * @param paramSpec the {@code IvParameterSpec} used to configure
+     *      this object.
+     *
+     * @throws InvalidParameterSpecException if an object of a type other
+     *      than {@code IvParameterSpec} is used.
+     */
+    @Override
+    protected void engineInit(AlgorithmParameterSpec paramSpec)
+        throws InvalidParameterSpecException {
+
+        if (!(paramSpec instanceof IvParameterSpec)) {
+            throw new InvalidParameterSpecException
+                ("Inappropriate parameter specification");
+        }
+        IvParameterSpec ivps = (IvParameterSpec)paramSpec;
+
+        // Obtain the nonce
+        nonce = ivps.getIV();
+        if (nonce.length != 12) {
+            throw new InvalidParameterSpecException("ChaCha20-Poly1305 nonce" +
+                    " must be 12 bytes in length");
+        }
+    }
+
+    /**
+     * Initialize the ChaCha20Poly1305Parameters from a DER encoded
+     * parameter block.
+
+     * @param encoded the DER encoding of the nonce as an OCTET STRING.
+     *
+     * @throws IOException if the encoded nonce is not 12 bytes long or a DER
+     *      decoding error occurs.
+     */
+    @Override
+    protected void engineInit(byte[] encoded) throws IOException {
+        DerValue val = new DerValue(encoded);
+
+        // Get the nonce value
+        nonce = val.getOctetString();
+        if (nonce.length != 12) {
+           throw new IOException(
+                   "ChaCha20-Poly1305 nonce must be 12 bytes in length");
+        }
+    }
+
+    /**
+     * Initialize the ChaCha20Poly1305Parameters from a DER encoded
+     * parameter block.
+     *
+     * @param encoded the DER encoding of the nonce and initial block counter.
+     * @param decodingMethod the decoding method.  The only currently accepted
+     *      value is "ASN.1"
+     *
+     * @throws IOException if the encoded nonce is not 12 bytes long, a DER
+     *      decoding error occurs, or an unsupported decoding method is
+     *      provided.
+     */
+    @Override
+    protected void engineInit(byte[] encoded, String decodingMethod)
+            throws IOException {
+        if (decodingMethod == null ||
+                decodingMethod.equalsIgnoreCase(DEFAULT_FMT)) {
+            engineInit(encoded);
+        } else {
+            throw new IOException("Unsupported parameter format: " +
+                    decodingMethod);
+        }
+    }
+
+    /**
+     * Return an IvParameterSpec with the same parameters as those
+     * held in this object.
+     *
+     * @param paramSpec the class name of the spec.  In this case it should
+     *      be {@code IvParameterSpec.class}.
+     *
+     * @return a {@code IvParameterSpec} object containing the nonce
+     *      value held in this object.
+     *
+     * @throws InvalidParameterSpecException if a class other than
+     *      {@code IvParameterSpec.class} was specified in the paramSpec
+     *      parameter.
+     */
+    @Override
+    protected <T extends AlgorithmParameterSpec>
+            T engineGetParameterSpec(Class<T> paramSpec)
+        throws InvalidParameterSpecException {
+
+        if (IvParameterSpec.class.isAssignableFrom(paramSpec)) {
+            return paramSpec.cast(new IvParameterSpec(nonce));
+        } else {
+            throw new InvalidParameterSpecException
+                ("Inappropriate parameter specification");
+        }
+    }
+
+    /**
+     * Return the encoded parameters in ASN.1 form.
+     *
+     * @return a byte array containing the DER-encoding for the
+     *      ChaCha20-Poly1305 parameters.  This will be the nonce
+     *      encoded as a DER OCTET STRING.
+     *
+     * @throws IOException if any DER encoding error occurs.
+     */
+    @Override
+    protected byte[] engineGetEncoded() throws IOException {
+        DerOutputStream out = new DerOutputStream();
+        out.write(DerValue.tag_OctetString, nonce);
+        return out.toByteArray();
+    }
+
+    /**
+     * Return the encoded parameters in ASN.1 form.
+     *
+     * @param encodingMethod the encoding method to be used.  This parameter
+     *      must be "ASN.1" as it is the only currently supported encoding
+     *      format.  If the parameter is {@code null} then the default
+     *      encoding format will be used.
+     *
+     * @return a byte array containing the DER-encoding for the
+     *      ChaCha20-Poly1305 parameters.
+     *
+     * @throws IOException if any DER encoding error occurs or an unsupported
+     *      encoding method is provided.
+     */
+    @Override
+    protected byte[] engineGetEncoded(String encodingMethod)
+        throws IOException {
+        if (encodingMethod == null ||
+                encodingMethod.equalsIgnoreCase(DEFAULT_FMT)) {
+            return engineGetEncoded();
+        } else {
+            throw new IOException("Unsupported encoding format: " +
+                    encodingMethod);
+        }
+    }
+
+    /**
+     * Creates a formatted string describing the parameters.
+     *
+     * @return a string representation of the ChaCha20 parameters.
+     */
+    @Override
+    protected String engineToString() {
+        String LINE_SEP = System.lineSeparator();
+        HexDumpEncoder encoder = new HexDumpEncoder();
+        StringBuilder sb = new StringBuilder(LINE_SEP + "nonce:" +
+                LINE_SEP + "[" + encoder.encodeBuffer(nonce) + "]");
+        return sb.toString();
+    }
+}
--- a/src/java.base/share/classes/com/sun/crypto/provider/KeyGeneratorCore.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/java.base/share/classes/com/sun/crypto/provider/KeyGeneratorCore.java	Thu May 31 13:09:04 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -111,16 +111,20 @@
         protected HmacSHA2KG(String algoName, int len) {
             core = new KeyGeneratorCore(algoName, len);
         }
+        @Override
         protected void engineInit(SecureRandom random) {
             core.implInit(random);
         }
+        @Override
         protected void engineInit(AlgorithmParameterSpec params,
                 SecureRandom random) throws InvalidAlgorithmParameterException {
             core.implInit(params, random);
         }
+        @Override
         protected void engineInit(int keySize, SecureRandom random) {
             core.implInit(keySize, random);
         }
+        @Override
         protected SecretKey engineGenerateKey() {
             return core.implGenerateKey();
         }
@@ -153,13 +157,16 @@
         public RC2KeyGenerator() {
             core = new KeyGeneratorCore("RC2", 128);
         }
+        @Override
         protected void engineInit(SecureRandom random) {
             core.implInit(random);
         }
+        @Override
         protected void engineInit(AlgorithmParameterSpec params,
                 SecureRandom random) throws InvalidAlgorithmParameterException {
             core.implInit(params, random);
         }
+        @Override
         protected void engineInit(int keySize, SecureRandom random) {
             if ((keySize < 40) || (keySize > 1024)) {
                 throw new InvalidParameterException("Key length for RC2"
@@ -167,6 +174,7 @@
             }
             core.implInit(keySize, random);
         }
+        @Override
         protected SecretKey engineGenerateKey() {
             return core.implGenerateKey();
         }
@@ -178,13 +186,16 @@
         public ARCFOURKeyGenerator() {
             core = new KeyGeneratorCore("ARCFOUR", 128);
         }
+        @Override
         protected void engineInit(SecureRandom random) {
             core.implInit(random);
         }
+        @Override
         protected void engineInit(AlgorithmParameterSpec params,
                 SecureRandom random) throws InvalidAlgorithmParameterException {
             core.implInit(params, random);
         }
+        @Override
         protected void engineInit(int keySize, SecureRandom random) {
             if ((keySize < 40) || (keySize > 1024)) {
                 throw new InvalidParameterException("Key length for ARCFOUR"
@@ -192,9 +203,38 @@
             }
             core.implInit(keySize, random);
         }
+        @Override
         protected SecretKey engineGenerateKey() {
             return core.implGenerateKey();
         }
     }
 
+    // nested static class for the ChaCha20 key generator
+    public static final class ChaCha20KeyGenerator extends KeyGeneratorSpi {
+        private final KeyGeneratorCore core;
+        public ChaCha20KeyGenerator() {
+            core = new KeyGeneratorCore("ChaCha20", 256);
+        }
+        @Override
+        protected void engineInit(SecureRandom random) {
+            core.implInit(random);
+        }
+        @Override
+        protected void engineInit(AlgorithmParameterSpec params,
+                SecureRandom random) throws InvalidAlgorithmParameterException {
+            core.implInit(params, random);
+        }
+        @Override
+        protected void engineInit(int keySize, SecureRandom random) {
+            if (keySize != 256) {
+                throw new InvalidParameterException(
+                        "Key length for ChaCha20 must be 256 bits");
+            }
+            core.implInit(keySize, random);
+        }
+        @Override
+        protected SecretKey engineGenerateKey() {
+            return core.implGenerateKey();
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/com/sun/crypto/provider/Poly1305.java	Thu May 31 13:09:04 2018 -0700
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 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.  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 com.sun.crypto.provider;
+
+import java.nio.ByteBuffer;
+import java.security.Key;
+import java.security.InvalidKeyException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Arrays;
+import java.util.Objects;
+
+import sun.security.util.math.*;
+import sun.security.util.math.intpoly.*;
+
+/**
+ * This class represents the Poly1305 function defined in RFC 7539.
+ *
+ * This function is used in the implementation of ChaCha20/Poly1305
+ * AEAD mode.
+ */
+final class Poly1305 {
+
+    private static final int KEY_LENGTH = 32;
+    private static final int RS_LENGTH = KEY_LENGTH / 2;
+    private static final int BLOCK_LENGTH = 16;
+    private static final int TAG_LENGTH = 16;
+
+    private static final IntegerFieldModuloP ipl1305 =
+            new IntegerPolynomial1305();
+
+    private byte[] keyBytes;
+    private final byte[] block = new byte[BLOCK_LENGTH];
+    private int blockOffset;
+
+    private IntegerModuloP r;
+    private IntegerModuloP s;
+    private MutableIntegerModuloP a;
+    private final MutableIntegerModuloP n = ipl1305.get1().mutable();
+
+    Poly1305() { }
+
+    /**
+     * Initialize the Poly1305 object
+     *
+     * @param newKey the {@code Key} which will be used for the authentication.
+     * @param params this parameter is unused.
+     *
+     * @throws InvalidKeyException if {@code newKey} is {@code null} or is
+     *      not 32 bytes in length.
+     */
+    void engineInit(Key newKey, AlgorithmParameterSpec params)
+            throws InvalidKeyException {
+        Objects.requireNonNull(newKey, "Null key provided during init");
+        keyBytes = newKey.getEncoded();
+        if (keyBytes == null) {
+            throw new InvalidKeyException("Key does not support encoding");
+        } else if (keyBytes.length != KEY_LENGTH) {
+            throw new InvalidKeyException("Incorrect length for key: " +
+                    keyBytes.length);
+        }
+
+        engineReset();
+        setRSVals();
+    }
+
+    /**
+     * Returns the length of the MAC (authentication tag).
+     *
+     * @return the length of the auth tag, which is always 16 bytes.
+     */
+    int engineGetMacLength() {
+        return TAG_LENGTH;
+    }
+
+    /**
+     * Reset the Poly1305 object, discarding any current operation but
+     *      maintaining the same key.
+     */
+    void engineReset() {
+        // Clear the block and reset the offset
+        Arrays.fill(block, (byte)0);
+        blockOffset = 0;
+        // Discard any previous accumulator and start at zero
+        a = ipl1305.get0().mutable();
+    }
+
+    /**
+     * Update the MAC with bytes from a {@code ByteBuffer}
+     *
+     * @param buf the {@code ByteBuffer} containing the data to be consumed.
+     *      Upon return the buffer's position will be equal to its limit.
+     */
+    void engineUpdate(ByteBuffer buf) {
+        int remaining = buf.remaining();
+        while (remaining > 0) {
+            int bytesToWrite = Integer.min(remaining,
+                    BLOCK_LENGTH - blockOffset);
+
+            if (bytesToWrite >= BLOCK_LENGTH) {
+                // If bytes to write == BLOCK_LENGTH, then we have no
+                // left-over data from previous updates and we can create
+                // the IntegerModuloP directly from the input buffer.
+                processBlock(buf, bytesToWrite);
+            } else {
+                // We have some left-over data from previous updates, so
+                // copy that into the holding block until we get a full block.
+                buf.get(block, blockOffset, bytesToWrite);
+                blockOffset += bytesToWrite;
+
+                if (blockOffset >= BLOCK_LENGTH) {
+                    processBlock(block, 0, BLOCK_LENGTH);
+                    blockOffset = 0;
+                }
+            }
+
+            remaining -= bytesToWrite;
+        }
+    }
+
+    /**
+     * Update the MAC with bytes from an array.
+     *
+     * @param input the input bytes.
+     * @param offset the starting index from which to update the MAC.
+     * @param len the number of bytes to process.
+     */
+    void engineUpdate(byte[] input, int offset, int len) {
+        Objects.checkFromIndexSize(offset, len, input.length);
+        if (blockOffset > 0) {
+            // We have some left-over data from previous updates
+            int blockSpaceLeft = BLOCK_LENGTH - blockOffset;
+            if (len < blockSpaceLeft) {
+                System.arraycopy(input, offset, block, blockOffset, len);
+                blockOffset += len;
+                return; // block wasn't filled
+            } else {
+                System.arraycopy(input, offset, block, blockOffset,
+                        blockSpaceLeft);
+                offset += blockSpaceLeft;
+                len -= blockSpaceLeft;
+                processBlock(block, 0, BLOCK_LENGTH);
+                blockOffset = 0;
+            }
+        }
+        while (len >= BLOCK_LENGTH) {
+            processBlock(input, offset, BLOCK_LENGTH);
+            offset += BLOCK_LENGTH;
+            len -= BLOCK_LENGTH;
+        }
+        if (len > 0) { // and len < BLOCK_LENGTH
+            System.arraycopy(input, offset, block, 0, len);
+            blockOffset = len;
+        }
+    }
+
+    /**
+     * Update the MAC with a single byte of input
+     *
+     * @param input the byte to update the MAC with.
+     */
+    void engineUpdate(byte input) {
+        assert (blockOffset < BLOCK_LENGTH);
+        // we can't hold fully filled unprocessed block
+        block[blockOffset++] = input;
+
+        if (blockOffset == BLOCK_LENGTH) {
+            processBlock(block, 0, BLOCK_LENGTH);
+            blockOffset = 0;
+        }
+    }
+
+
+    /**
+     * Finish the authentication operation and reset the MAC for a new
+     * authentication operation.
+     *
+     * @return the authentication tag as a byte array.
+     */
+    byte[] engineDoFinal() {
+        byte[] tag = new byte[BLOCK_LENGTH];
+
+        // Finish up: process any remaining data < BLOCK_SIZE, then
+        // create the tag from the resulting little-endian integer.
+        if (blockOffset > 0) {
+            processBlock(block, 0, blockOffset);
+            blockOffset = 0;
+        }
+
+        // Add in the s-half of the key to the accumulator
+        a.addModPowerTwo(s, tag);
+
+        // Reset for the next auth
+        engineReset();
+        return tag;
+    }
+
+    /**
+     * Process a single block of data.  This should only be called
+     * when the block array is complete.  That may not necessarily
+     * be a full 16 bytes if the last block has less than 16 bytes.
+     */
+    private void processBlock(ByteBuffer buf, int len) {
+        n.setValue(buf, len, (byte)0x01);
+        a.setSum(n);                    // a += (n | 0x01)
+        a.setProduct(r);                // a = (a * r) % p
+    }
+
+    private void processBlock(byte[] block, int offset, int length) {
+        Objects.checkFromIndexSize(offset, length, block.length);
+        n.setValue(block, offset, length, (byte)0x01);
+        a.setSum(n);                    // a += (n | 0x01)
+        a.setProduct(r);                // a = (a * r) % p
+    }
+
+    /**
+     * Partition the authentication key into the R and S components, clamp
+     * the R value, and instantiate IntegerModuloP objects to R and S's
+     * numeric values.
+     */
+    private void setRSVals() {
+        // Clamp the bytes in the "r" half of the key.
+        keyBytes[3] &= 15;
+        keyBytes[7] &= 15;
+        keyBytes[11] &= 15;
+        keyBytes[15] &= 15;
+        keyBytes[4] &= 252;
+        keyBytes[8] &= 252;
+        keyBytes[12] &= 252;
+
+        // Create IntegerModuloP elements from the r and s values
+        r = ipl1305.getElement(keyBytes, 0, RS_LENGTH, (byte)0);
+        s = ipl1305.getElement(keyBytes, RS_LENGTH, RS_LENGTH, (byte)0);
+    }
+}
--- a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java	Thu May 31 13:09:04 2018 -0700
@@ -57,6 +57,8 @@
  *
  * - ARCFOUR (RC4 compatible)
  *
+ * - ChaCha20 (Stream cipher only and in AEAD mode with Poly1305)
+ *
  * - Cipher modes ECB, CBC, CFB, OFB, PCBC, CTR, and CTS for all block ciphers
  *   and mode GCM for AES cipher
  *
@@ -77,7 +79,7 @@
 
     private static final String info = "SunJCE Provider " +
     "(implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, "
-    + "Diffie-Hellman, HMAC)";
+    + "Diffie-Hellman, HMAC, ChaCha20)";
 
     private static final String OID_PKCS12_RC4_128 = "1.2.840.113549.1.12.1.1";
     private static final String OID_PKCS12_RC4_40 = "1.2.840.113549.1.12.1.2";
@@ -336,6 +338,15 @@
                     put("Cipher.ARCFOUR SupportedPaddings", "NOPADDING");
                     put("Cipher.ARCFOUR SupportedKeyFormats", "RAW");
 
+                    put("Cipher.ChaCha20",
+                        "com.sun.crypto.provider.ChaCha20Cipher$ChaCha20Only");
+                    put("Cipher.ChaCha20 SupportedKeyFormats", "RAW");
+                    put("Cipher.ChaCha20-Poly1305",
+                        "com.sun.crypto.provider.ChaCha20Cipher$ChaCha20Poly1305");
+                    put("Cipher.ChaCha20-Poly1305 SupportedKeyFormats", "RAW");
+                    put("Alg.Alias.Cipher.1.2.840.113549.1.9.16.3.18", "ChaCha20-Poly1305");
+                    put("Alg.Alias.Cipher.OID.1.2.840.113549.1.9.16.3.18", "ChaCha20-Poly1305");
+
                     /*
                      * Key(pair) Generator engines
                      */
@@ -361,6 +372,10 @@
                         "ARCFOURKeyGenerator");
                     put("Alg.Alias.KeyGenerator.RC4", "ARCFOUR");
 
+                    put("KeyGenerator.ChaCha20",
+                        "com.sun.crypto.provider.KeyGeneratorCore$" +
+                        "ChaCha20KeyGenerator");
+
                     put("KeyGenerator.HmacMD5",
                         "com.sun.crypto.provider.HmacMD5KeyGenerator");
 
@@ -541,6 +556,9 @@
                     put("AlgorithmParameters.OAEP",
                         "com.sun.crypto.provider.OAEPParameters");
 
+                    put("AlgorithmParameters.ChaCha20-Poly1305",
+                        "com.sun.crypto.provider.ChaCha20Poly1305Parameters");
+
                     /*
                      * Key factories
                      */
--- a/src/java.base/share/classes/java/lang/Character.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/java.base/share/classes/java/lang/Character.java	Thu May 31 13:09:04 2018 -0700
@@ -1419,7 +1419,8 @@
                              "YIRADICALS");
 
         /**
-         * Constant for the "Cyrillic Supplementary" Unicode character block.
+         * Constant for the "Cyrillic Supplement" Unicode character block.
+         * This block was previously known as the "Cyrillic Supplementary" block.
          * @since 1.5
          */
         public static final UnicodeBlock CYRILLIC_SUPPLEMENTARY =
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Thu May 31 13:09:04 2018 -0700
@@ -3483,6 +3483,11 @@
      * @return a method handle which inserts an additional argument,
      *         before calling the original method handle
      * @throws NullPointerException if the target or the {@code values} array is null
+     * @throws IllegalArgumentException if (@code pos) is less than {@code 0} or greater than
+     *         {@code N - L} where {@code N} is the arity of the target method handle and {@code L}
+     *         is the length of the values array.
+     * @throws ClassCastException if an argument does not match the corresponding bound parameter
+     *         type.
      * @see MethodHandle#bindTo
      */
     public static
--- a/src/java.base/share/classes/javax/crypto/Cipher.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/java.base/share/classes/javax/crypto/Cipher.java	Thu May 31 13:09:04 2018 -0700
@@ -111,7 +111,7 @@
  * encryption with a given key. When IVs are repeated for GCM
  * encryption, such usages are subject to forgery attacks. Thus, after
  * each encryption operation using GCM mode, callers should re-initialize
- * the cipher objects with GCM parameters which has a different IV value.
+ * the cipher objects with GCM parameters which have a different IV value.
  * <pre>
  *     GCMParameterSpec s = ...;
  *     cipher.init(..., s);
@@ -131,6 +131,13 @@
  *     ...
  *
  * </pre>
+ * The ChaCha20 and ChaCha20-Poly1305 algorithms have a similar requirement
+ * for unique nonces with a given key.  After each encryption or decryption
+ * operation, callers should re-initialize their ChaCha20 or ChaCha20-Poly1305
+ * ciphers with parameters that specify a different nonce value.  Please
+ * see <a href="https://tools.ietf.org/html/rfc7539">RFC 7539</a> for more
+ * information on the ChaCha20 and ChaCha20-Poly1305 algorithms.
+ * <p>
  * Every implementation of the Java platform is required to support
  * the following standard {@code Cipher} transformations with the keysizes
  * in parentheses:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/javax/crypto/spec/ChaCha20ParameterSpec.java	Thu May 31 13:09:04 2018 -0700
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 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.  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 javax.crypto.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Objects;
+
+/**
+ * This class specifies the parameters used with the
+ * <a href="https://tools.ietf.org/html/rfc7539"><i>ChaCha20</i></a>
+ * algorithm.
+ *
+ * <p> The parameters consist of a 12-byte nonce and an initial
+ * counter value expressed as a 32-bit integer.
+ *
+ * <p> This class can be used to initialize a {@code Cipher} object that
+ * implements the <i>ChaCha20</i> algorithm.
+ *
+ * @since 11
+ */
+public final class ChaCha20ParameterSpec implements AlgorithmParameterSpec {
+
+    // The nonce length is defined by the spec as 96 bits (12 bytes) in length.
+    private static final int NONCE_LENGTH = 12;
+
+    private final byte[] nonce;
+    private final int counter;
+
+    /**
+     * Constructs a parameter set for ChaCha20 from the given nonce
+     * and counter.
+     *
+     * @param nonce a 12-byte nonce value
+     * @param counter the initial counter value
+     *
+     * @throws NullPointerException if {@code nonce} is {@code null}
+     * @throws IllegalArgumentException if {@code nonce} is not 12 bytes
+     *      in length
+     */
+    public ChaCha20ParameterSpec(byte[] nonce, int counter) {
+        this.counter = counter;
+
+        Objects.requireNonNull(nonce, "Nonce must be non-null");
+        this.nonce = nonce.clone();
+        if (this.nonce.length != NONCE_LENGTH) {
+            throw new IllegalArgumentException(
+                    "Nonce must be 12-bytes in length");
+        }
+    }
+
+    /**
+     * Returns the nonce value.
+     *
+     * @return the nonce value.  This method returns a new array each time
+     * this method is called.
+     */
+    public byte[] getNonce() {
+        return nonce.clone();
+    }
+
+    /**
+     * Returns the configured counter value.
+     *
+     * @return the counter value
+     */
+    public int getCounter() {
+        return counter;
+    }
+}
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java	Thu May 31 13:09:04 2018 -0700
@@ -139,7 +139,7 @@
             CompilationResult compilationResult = new CompilationResult(id, isImmutablePIC);
 
             return GraalCompiler.compileGraph(graph, resolvedMethod, providers, backend, graphBuilderSuite, OptimisticOptimizations.ALL, profilingInfo, getSuites(), getLirSuites(),
-                            compilationResult, CompilationResultBuilderFactory.Default);
+                            compilationResult, CompilationResultBuilderFactory.Default, true);
 
         } catch (Throwable e) {
             main.handleError(resolvedMethod, e, " (compiling graph)");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java	Thu May 31 13:09:04 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2018, Red Hat Inc. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -63,11 +63,15 @@
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMSUB;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMUL;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FNEG;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FRINTM;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FRINTN;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FRINTP;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FRINTZ;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FSQRT;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FSUB;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.HINT;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.HLT;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDADD;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDAR;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDAXR;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDP;
@@ -480,6 +484,9 @@
     private static final int CASAcquireOffset = 22;
     private static final int CASReleaseOffset = 15;
 
+    private static final int LDADDAcquireOffset = 23;
+    private static final int LDADDReleaseOffset = 22;
+
     /**
      * Encoding for all instructions.
      */
@@ -511,6 +518,7 @@
         STP(0b0 << 22),
 
         CAS(0x08A07C00),
+        LDADD(0x38200000),
 
         ADR(0x00000000),
         ADRP(0x80000000),
@@ -573,6 +581,9 @@
         FSQRT(0x00018000),
         FNEG(0x00010000),
 
+        FRINTM(0x00050000),
+        FRINTN(0x00040000),
+        FRINTP(0x00048000),
         FRINTZ(0x00058000),
 
         FADD(0x00002000),
@@ -1330,7 +1341,18 @@
         emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt));
     }
 
-    /* Compare And Swap */
+    /**
+     * Compare And Swap word or doubleword in memory. This reads a value from an address rn,
+     * compares it against a given value rs, and, if equal, stores the value rt to memory. The value
+     * read from address rn is stored in register rs.
+     *
+     * @param size size of bits read from memory. Must be 32 or 64.
+     * @param rs general purpose register to be compared and loaded. May not be null.
+     * @param rt general purpose register to be conditionally stored. May not be null.
+     * @param rn general purpose register containing the address from which to read.
+     * @param acquire boolean value signifying if the load should use acquire semantics.
+     * @param release boolean value signifying if the store should use release semantics.
+     */
     public void cas(int size, Register rs, Register rt, Register rn, boolean acquire, boolean release) {
         assert size == 32 || size == 64;
         int transferSize = NumUtil.log2Ceil(size / 8);
@@ -1344,17 +1366,42 @@
         emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt) | (acquire ? 1 : 0) << CASAcquireOffset | (release ? 1 : 0) << CASReleaseOffset);
     }
 
+    /**
+     * Atomic add. This reads a value from an address rn, stores the value in rt, and adds the value
+     * in rs to it, and stores the result back at address rn. The initial value read from memory is
+     * stored in rt.
+     *
+     * @param size size of operand to read from memory. Must be 8, 16, 32, or 64.
+     * @param rs general purpose register to be added to contents. May not be null.
+     * @param rt general purpose register to be loaded. May not be null.
+     * @param rn general purpose register or stack pointer holding an address from which to load.
+     * @param acquire boolean value signifying if the load should use acquire semantics.
+     * @param release boolean value signifying if the store should use release semantics.
+     */
+    public void ldadd(int size, Register rs, Register rt, Register rn, boolean acquire, boolean release) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        loadAndAddInstruction(LDADD, rs, rt, rn, transferSize, acquire, release);
+    }
+
+    private void loadAndAddInstruction(Instruction instr, Register rs, Register rt, Register rn, int log2TransferSize, boolean acquire, boolean release) {
+        assert log2TransferSize >= 0 && log2TransferSize < 4;
+        assert rt.getRegisterCategory().equals(CPU) && rs.getRegisterCategory().equals(CPU) && !rs.equals(rt);
+        int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset;
+        emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt) | (acquire ? 1 : 0) << LDADDAcquireOffset | (release ? 1 : 0) << LDADDReleaseOffset);
+    }
+
     /* PC-relative Address Calculation (5.4.4) */
 
     /**
      * Address of page: sign extends 21-bit offset, shifts if left by 12 and adds it to the value of
-     * the PC with its bottom 12-bits cleared, writing the result to dst.
-     * No offset is emiited; the instruction will be patched later.
+     * the PC with its bottom 12-bits cleared, writing the result to dst. No offset is emitted; the
+     * instruction will be patched later.
      *
      * @param dst general purpose register. May not be null, zero-register or stackpointer.
      */
     public void adrp(Register dst) {
-        emitInt(ADRP.encoding | PcRelImmOp | rd(dst) );
+        emitInt(ADRP.encoding | PcRelImmOp | rd(dst));
     }
 
     /**
@@ -1367,14 +1414,17 @@
         emitInt(ADR.encoding | PcRelImmOp | rd(dst) | getPcRelativeImmEncoding(imm21));
     }
 
+    /**
+     * Adds a 21-bit signed offset to the program counter and writes the result to dst.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param imm21 Signed 21-bit offset.
+     * @param pos the position in the code that the instruction is emitted.
+     */
     public void adr(Register dst, int imm21, int pos) {
         emitInt(ADR.encoding | PcRelImmOp | rd(dst) | getPcRelativeImmEncoding(imm21), pos);
     }
 
-    public void adrp(Register dst, int pageOffset) {
-        emitInt(ADRP.encoding | PcRelImmOp | rd(dst) | getPcRelativeImmEncoding(pageOffset));
-    }
-
     private static int getPcRelativeImmEncoding(int imm21) {
         assert NumUtil.isSignedNbit(21, imm21);
         int imm = imm21 & NumUtil.getNbitNumberInt(21);
@@ -2432,6 +2482,39 @@
         fpDataProcessing1Source(FRINTZ, dst, src, floatFromSize(size));
     }
 
+    /**
+     * Rounds floating-point to integral. Rounds towards nearest with ties to even.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    public void frintn(int size, Register dst, Register src) {
+        fpDataProcessing1Source(FRINTN, dst, src, floatFromSize(size));
+    }
+
+    /**
+     * Rounds floating-point to integral. Rounds towards minus infinity.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    public void frintm(int size, Register dst, Register src) {
+        fpDataProcessing1Source(FRINTM, dst, src, floatFromSize(size));
+    }
+
+    /**
+     * Rounds floating-point to integral. Rounds towards plus infinity.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    public void frintp(int size, Register dst, Register src) {
+        fpDataProcessing1Source(FRINTP, dst, src, floatFromSize(size));
+    }
+
     /* Floating-point Arithmetic (1 source) (5.7.6) */
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java	Thu May 31 13:09:04 2018 -0700
@@ -1,6 +1,5 @@
 /*
  * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2018, Red Hat Inc. 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
@@ -38,7 +37,6 @@
 import static jdk.vm.ci.aarch64.AArch64.sp;
 import static jdk.vm.ci.aarch64.AArch64.zr;
 
-import org.graalvm.compiler.asm.AbstractAddress;
 import org.graalvm.compiler.asm.Label;
 import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.debug.GraalError;
@@ -307,9 +305,10 @@
             case EXTENDED_REGISTER_OFFSET:
                 add(64, dst, address.getBase(), address.getOffset(), address.getExtendType(), address.isScaled() ? shiftAmt : 0);
                 break;
-            case PC_LITERAL:
-                super.adr(dst, address.getImmediateRaw());
+            case PC_LITERAL: {
+                addressOf(dst);
                 break;
+            }
             case BASE_REGISTER_ONLY:
                 movx(dst, address.getBase());
                 break;
@@ -1561,7 +1560,7 @@
     }
 
     @Override
-    public AbstractAddress getPlaceholder(int instructionStartPosition) {
+    public AArch64Address getPlaceholder(int instructionStartPosition) {
         return AArch64Address.PLACEHOLDER;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java	Thu May 31 13:09:04 2018 -0700
@@ -1853,9 +1853,36 @@
         CMP.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
     }
 
-    // The 32-bit cmpxchg compares the value at adr with the contents of X86.rax,
-    // and stores reg into adr if so; otherwise, the value at adr is loaded into X86.rax,.
-    // The ZF is set if the compared values were equal, and cleared otherwise.
+    /**
+     * The 8-bit cmpxchg compares the value at adr with the contents of X86.rax, and stores reg into
+     * adr if so; otherwise, the value at adr is loaded into X86.rax,. The ZF is set if the compared
+     * values were equal, and cleared otherwise.
+     */
+    public final void cmpxchgb(Register reg, AMD64Address adr) { // cmpxchg
+        prefix(adr, reg);
+        emitByte(0x0F);
+        emitByte(0xB0);
+        emitOperandHelper(reg, adr, 0);
+    }
+
+    /**
+     * The 16-bit cmpxchg compares the value at adr with the contents of X86.rax, and stores reg
+     * into adr if so; otherwise, the value at adr is loaded into X86.rax,. The ZF is set if the
+     * compared values were equal, and cleared otherwise.
+     */
+    public final void cmpxchgw(Register reg, AMD64Address adr) { // cmpxchg
+        emitByte(0x66); // Switch to 16-bit mode.
+        prefix(adr, reg);
+        emitByte(0x0F);
+        emitByte(0xB1);
+        emitOperandHelper(reg, adr, 0);
+    }
+
+    /**
+     * The 32-bit cmpxchg compares the value at adr with the contents of X86.rax, and stores reg
+     * into adr if so; otherwise, the value at adr is loaded into X86.rax,. The ZF is set if the
+     * compared values were equal, and cleared otherwise.
+     */
     public final void cmpxchgl(Register reg, AMD64Address adr) { // cmpxchg
         prefix(adr, reg);
         emitByte(0x0F);
@@ -3677,6 +3704,21 @@
         emitByte(imm8);
     }
 
+    public final void xaddb(AMD64Address dst, Register src) {
+        prefix(dst, src);
+        emitByte(0x0F);
+        emitByte(0xC0);
+        emitOperandHelper(src, dst, 0);
+    }
+
+    public final void xaddw(AMD64Address dst, Register src) {
+        emitByte(0x66); // Switch to 16-bit mode.
+        prefix(dst, src);
+        emitByte(0x0F);
+        emitByte(0xC1);
+        emitOperandHelper(src, dst, 0);
+    }
+
     public final void xaddl(AMD64Address dst, Register src) {
         prefix(dst, src);
         emitByte(0x0F);
@@ -3691,6 +3733,19 @@
         emitOperandHelper(src, dst, 0);
     }
 
+    public final void xchgb(Register dst, AMD64Address src) {
+        prefix(src, dst);
+        emitByte(0x86);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void xchgw(Register dst, AMD64Address src) {
+        emitByte(0x66);
+        prefix(src, dst);
+        emitByte(0x87);
+        emitOperandHelper(dst, src, 0);
+    }
+
     public final void xchgl(Register dst, AMD64Address src) {
         prefix(src, dst);
         emitByte(0x87);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytecodes.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytecodes.java	Thu May 31 13:09:04 2018 -0700
@@ -837,4 +837,27 @@
 
         assert !isConditionalBranch(opcode) || isBranch(opcode) : "a conditional branch must also be a branch";
     }
+
+    public static boolean isIfBytecode(int bytecode) {
+        switch (bytecode) {
+            case IFEQ:
+            case IFNE:
+            case IFLT:
+            case IFGE:
+            case IFGT:
+            case IFLE:
+            case IF_ICMPEQ:
+            case IF_ICMPNE:
+            case IF_ICMPLT:
+            case IF_ICMPGE:
+            case IF_ICMPGT:
+            case IF_ICMPLE:
+            case IF_ACMPEQ:
+            case IF_ACMPNE:
+            case IFNULL:
+            case IFNONNULL:
+                return true;
+        }
+        return false;
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java	Thu May 31 13:09:04 2018 -0700
@@ -32,9 +32,9 @@
 import static org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode.CLZ;
 import static org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode.CTZ;
 
-import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
 import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.core.common.calc.FloatConvert;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.lir.ConstantValue;
@@ -491,4 +491,23 @@
         throw GraalError.unimplemented();
     }
 
+    @Override
+    public Value emitRound(Value value, RoundingMode mode) {
+        AArch64ArithmeticOp op;
+        switch (mode) {
+            case NEAREST:
+                op = AArch64ArithmeticOp.FRINTN;
+                break;
+            case UP:
+                op = AArch64ArithmeticOp.FRINTP;
+                break;
+            case DOWN:
+                op = AArch64ArithmeticOp.FRINTM;
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+
+        return emitUnary(op, value);
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java	Thu May 31 13:09:04 2018 -0700
@@ -52,6 +52,7 @@
 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.StrategySwitchOp;
 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.TableSwitchOp;
 import org.graalvm.compiler.lir.aarch64.AArch64Move;
+import org.graalvm.compiler.lir.aarch64.AArch64AtomicMove.AtomicReadAndAddOp;
 import org.graalvm.compiler.lir.aarch64.AArch64AtomicMove.CompareAndSwapOp;
 import org.graalvm.compiler.lir.aarch64.AArch64Move.MembarOp;
 import org.graalvm.compiler.lir.aarch64.AArch64PauseOp;
@@ -127,7 +128,7 @@
     }
 
     @Override
-    public Variable emitLogicCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+    public Variable emitLogicCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
         Variable prevValue = newVariable(expectedValue.getValueKind());
         Variable scratch = newVariable(LIRKind.value(AArch64Kind.DWORD));
         append(new CompareAndSwapOp(prevValue, loadReg(expectedValue), loadReg(newValue), asAllocatable(address), scratch));
@@ -138,7 +139,7 @@
     }
 
     @Override
-    public Variable emitValueCompareAndSwap(Value address, Value expectedValue, Value newValue) {
+    public Variable emitValueCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue) {
         Variable result = newVariable(newValue.getValueKind());
         Variable scratch = newVariable(LIRKind.value(AArch64Kind.WORD));
         append(new CompareAndSwapOp(result, loadNonCompareConst(expectedValue), loadReg(newValue), asAllocatable(address), scratch));
@@ -146,6 +147,16 @@
     }
 
     @Override
+    public Value emitAtomicReadAndAdd(Value address, ValueKind<?> kind, Value delta) {
+        Variable result = newVariable(kind);
+        Variable scratch1 = newVariable(kind);
+        Variable scratch2 = newVariable(kind);
+
+        append(new AtomicReadAndAddOp((AArch64Kind) kind.getPlatformKind(), asAllocatable(result), asAllocatable(address), asAllocatable(delta), asAllocatable(scratch1), asAllocatable(scratch2)));
+        return result;
+    }
+
+    @Override
     public void emitMembar(int barriers) {
         int necessaryBarriers = target().arch.requiredBarriers(barriers);
         if (target().isMP && necessaryBarriers != 0) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java	Thu May 31 13:09:04 2018 -0700
@@ -23,13 +23,16 @@
 
 package org.graalvm.compiler.core.amd64;
 
+import static jdk.vm.ci.code.ValueUtil.asRegister;
 import static jdk.vm.ci.code.ValueUtil.isAllocatableValue;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.CMP;
 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD;
 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PD;
 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PS;
 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
 import static org.graalvm.compiler.lir.LIRValueUtil.asConstantValue;
 import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
@@ -190,36 +193,68 @@
         }
     }
 
-    @Override
-    public Variable emitLogicCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+    private AllocatableValue asAllocatable(Value value, ValueKind<?> kind) {
+        if (value.getValueKind().equals(kind)) {
+            return asAllocatable(value);
+        } else if (isRegister(value)) {
+            return asRegister(value).asValue(kind);
+        } else if (isConstantValue(value)) {
+            return emitLoadConstant(kind, asConstant(value));
+        } else {
+            Variable variable = newVariable(kind);
+            emitMove(variable, value);
+            return variable;
+        }
+    }
+
+    private Value emitCompareAndSwap(boolean isLogic, LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
         ValueKind<?> kind = newValue.getValueKind();
         assert kind.equals(expectedValue.getValueKind());
-        AMD64Kind memKind = (AMD64Kind) kind.getPlatformKind();
 
         AMD64AddressValue addressValue = asAddressValue(address);
-        RegisterValue raxRes = AMD64.rax.asValue(kind);
-        emitMove(raxRes, expectedValue);
-        append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue)));
+        LIRKind integralAccessKind = accessKind;
+        Value reinterpretedExpectedValue = expectedValue;
+        Value reinterpretedNewValue = newValue;
+        boolean isXmm = ((AMD64Kind) accessKind.getPlatformKind()).isXMM();
+        if (isXmm) {
+            if (accessKind.getPlatformKind().equals(AMD64Kind.SINGLE)) {
+                integralAccessKind = LIRKind.fromJavaKind(target().arch, JavaKind.Int);
+            } else {
+                integralAccessKind = LIRKind.fromJavaKind(target().arch, JavaKind.Long);
+            }
+            reinterpretedExpectedValue = arithmeticLIRGen.emitReinterpret(integralAccessKind, expectedValue);
+            reinterpretedNewValue = arithmeticLIRGen.emitReinterpret(integralAccessKind, newValue);
+        }
+        AMD64Kind memKind = (AMD64Kind) integralAccessKind.getPlatformKind();
+        RegisterValue aRes = AMD64.rax.asValue(integralAccessKind);
+        AllocatableValue allocatableNewValue = asAllocatable(reinterpretedNewValue, integralAccessKind);
+        emitMove(aRes, reinterpretedExpectedValue);
+        append(new CompareAndSwapOp(memKind, aRes, addressValue, aRes, allocatableNewValue));
 
-        assert trueValue.getValueKind().equals(falseValue.getValueKind());
-        Variable result = newVariable(trueValue.getValueKind());
-        append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue));
-        return result;
+        if (isLogic) {
+            assert trueValue.getValueKind().equals(falseValue.getValueKind());
+            Variable result = newVariable(trueValue.getValueKind());
+            append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue));
+            return result;
+        } else {
+            if (isXmm) {
+                return arithmeticLIRGen.emitReinterpret(accessKind, aRes);
+            } else {
+                Variable result = newVariable(kind);
+                emitMove(result, aRes);
+                return result;
+            }
+        }
     }
 
     @Override
-    public Value emitValueCompareAndSwap(Value address, Value expectedValue, Value newValue) {
-        ValueKind<?> kind = newValue.getValueKind();
-        assert kind.equals(expectedValue.getValueKind());
-        AMD64Kind memKind = (AMD64Kind) kind.getPlatformKind();
+    public Variable emitLogicCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+        return (Variable) emitCompareAndSwap(true, accessKind, address, expectedValue, newValue, trueValue, falseValue);
+    }
 
-        AMD64AddressValue addressValue = asAddressValue(address);
-        RegisterValue raxRes = AMD64.rax.asValue(kind);
-        emitMove(raxRes, expectedValue);
-        append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue)));
-        Variable result = newVariable(kind);
-        emitMove(result, raxRes);
-        return result;
+    @Override
+    public Value emitValueCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue) {
+        return emitCompareAndSwap(false, accessKind, address, expectedValue, newValue, null, null);
     }
 
     public void emitCompareAndSwapBranch(ValueKind<?> kind, AMD64AddressValue address, Value expectedValue, Value newValue, Condition condition, LabelRef trueLabel, LabelRef falseLabel,
@@ -235,8 +270,7 @@
     }
 
     @Override
-    public Value emitAtomicReadAndAdd(Value address, Value delta) {
-        ValueKind<?> kind = delta.getValueKind();
+    public Value emitAtomicReadAndAdd(Value address, ValueKind<?> kind, Value delta) {
         Variable result = newVariable(kind);
         AMD64AddressValue addressValue = asAddressValue(address);
         append(new AMD64Move.AtomicReadAndAddOp((AMD64Kind) kind.getPlatformKind(), result, addressValue, asAllocatable(delta)));
@@ -244,8 +278,7 @@
     }
 
     @Override
-    public Value emitAtomicReadAndWrite(Value address, Value newValue) {
-        ValueKind<?> kind = newValue.getValueKind();
+    public Value emitAtomicReadAndWrite(Value address, ValueKind<?> kind, Value newValue) {
         Variable result = newVariable(kind);
         AMD64AddressValue addressValue = asAddressValue(address);
         append(new AMD64Move.AtomicReadAndWriteOp((AMD64Kind) kind.getPlatformKind(), result, addressValue, asAllocatable(newValue)));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalBailoutException.java	Thu May 31 13:09:04 2018 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common;
+
+import jdk.vm.ci.code.BailoutException;
+import org.graalvm.compiler.debug.CausableByCompilerAssert;
+
+@SuppressWarnings("serial")
+public class GraalBailoutException extends BailoutException implements CausableByCompilerAssert {
+
+    public GraalBailoutException(String format, Object... args) {
+        super(format, args);
+    }
+
+    public GraalBailoutException(Throwable cause, String format, Object... args) {
+        super(cause, format, args);
+    }
+
+    public GraalBailoutException(boolean permanent, String format, Object... args) {
+        super(permanent, format, args);
+    }
+
+    @Override
+    public boolean isCausedByCompilerAssert() {
+        return false;
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/PermanentBailoutException.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/PermanentBailoutException.java	Thu May 31 13:09:04 2018 -0700
@@ -22,9 +22,7 @@
  */
 package org.graalvm.compiler.core.common;
 
-import jdk.vm.ci.code.BailoutException;
-
-public class PermanentBailoutException extends BailoutException {
+public class PermanentBailoutException extends GraalBailoutException {
 
     private static final long serialVersionUID = -2683649650135362549L;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/RetryableBailoutException.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/RetryableBailoutException.java	Thu May 31 13:09:04 2018 -0700
@@ -22,9 +22,7 @@
  */
 package org.graalvm.compiler.core.common;
 
-import jdk.vm.ci.code.BailoutException;
-
-public class RetryableBailoutException extends BailoutException {
+public class RetryableBailoutException extends GraalBailoutException {
 
     private static final long serialVersionUID = -7145365025679144525L;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java	Thu May 31 13:09:04 2018 -0700
@@ -1545,6 +1545,9 @@
 
                         @Override
                         public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) {
+                            if (outStamp.isEmpty()) {
+                                return StampFactory.forInteger(inputBits).empty();
+                            }
                             IntegerStamp stamp = (IntegerStamp) outStamp;
                             long mask = CodeUtil.mask(inputBits);
                             return StampFactory.forIntegerWithMask(inputBits, stamp.lowerBound(), stamp.upperBound(), stamp.downMask() & mask, stamp.upMask() & mask);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java	Thu May 31 13:09:04 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -27,19 +27,20 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import javax.annotation.processing.AbstractProcessor;
 import javax.annotation.processing.Filer;
 import javax.annotation.processing.RoundEnvironment;
 import javax.annotation.processing.SupportedAnnotationTypes;
 import javax.lang.model.SourceVersion;
 import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
@@ -48,9 +49,7 @@
 import javax.lang.model.element.PackageElement;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.MirroredTypeException;
 import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.AbstractAnnotationValueVisitor7;
 import javax.lang.model.util.ElementFilter;
 import javax.lang.model.util.Types;
 import javax.tools.Diagnostic.Kind;
@@ -58,24 +57,10 @@
 import javax.tools.JavaFileObject;
 import javax.tools.StandardLocation;
 
-import jdk.internal.vm.compiler.collections.EconomicMap;
-import jdk.internal.vm.compiler.collections.EconomicSet;
-import jdk.internal.vm.compiler.collections.Equivalence;
-import org.graalvm.compiler.core.gen.NodeMatchRules;
-import org.graalvm.compiler.core.match.ComplexMatchResult;
-import org.graalvm.compiler.core.match.MatchRule;
-import org.graalvm.compiler.core.match.MatchRules;
-import org.graalvm.compiler.core.match.MatchStatement;
-import org.graalvm.compiler.core.match.MatchStatementSet;
-import org.graalvm.compiler.core.match.MatchableNode;
-import org.graalvm.compiler.core.match.MatchableNodes;
-import org.graalvm.compiler.debug.GraalError;
-import org.graalvm.compiler.graph.Position;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.serviceprovider.ServiceProvider;
+import org.graalvm.compiler.processor.AbstractProcessor;
 
 /**
- * Processes classes annotated with {@link MatchRule}. A {@link MatchStatementSet} service is
+ * Processes classes annotated with {@code MatchRule}. A {@code MatchStatementSet} service is
  * generated for each top level class containing at least one such field. These service objects can
  * be retrieved as follows:
  *
@@ -90,6 +75,13 @@
                 "org.graalvm.compiler.core.match.MatchableNodes"})
 public class MatchProcessor extends AbstractProcessor {
 
+    private static final String VALUE_NODE_CLASS_NAME = "org.graalvm.compiler.nodes.ValueNode";
+    private static final String COMPLEX_MATCH_RESULT_CLASS_NAME = "org.graalvm.compiler.core.match.ComplexMatchResult";
+    private static final String MATCHABLE_NODES_CLASS_NAME = "org.graalvm.compiler.core.match.MatchableNodes";
+    private static final String MATCHABLE_NODE_CLASS_NAME = "org.graalvm.compiler.core.match.MatchableNode";
+    private static final String MATCH_RULE_CLASS_NAME = "org.graalvm.compiler.core.match.MatchRule";
+    private static final String MATCH_RULES_CLASS_NAME = "org.graalvm.compiler.core.match.MatchRules";
+
     public MatchProcessor() {
     }
 
@@ -98,8 +90,8 @@
         return SourceVersion.latest();
     }
 
-    private final Set<Element> processedMatchRule = new HashSet<>();
-    private final Set<Element> processedMatchableNode = new HashSet<>();
+    private final Set<Element> processedMatchRules = new HashSet<>();
+    private final Set<Element> processedMatchableNodes = new HashSet<>();
 
     private static class RuleParseError extends RuntimeException {
         private static final long serialVersionUID = 6456128283609257490L;
@@ -170,14 +162,14 @@
             if (peek("(").equals("(")) {
                 next();
                 MatchDescriptor descriptor = parseType(true);
-                for (int n = 0; n < descriptor.nodeType.inputs.length; n++) {
+                for (int n = 0; n < descriptor.nodeType.inputs.size(); n++) {
                     if (peek("(").equals("(")) {
                         descriptor.inputs[n] = parseExpression();
                     } else {
                         descriptor.inputs[n] = parseType(false);
                     }
                 }
-                for (int n = 0; n < descriptor.nodeType.inputs.length; n++) {
+                for (int n = 0; n < descriptor.nodeType.inputs.size(); n++) {
                     if (descriptor.inputs[n] == null) {
                         throw new RuleParseError("not enough inputs for " + descriptor.name);
                     }
@@ -233,7 +225,7 @@
         /**
          * Recursively accumulate any required Position declarations.
          */
-        void generatePositionDeclarations(EconomicSet<String> declarations) {
+        void generatePositionDeclarations(Set<String> declarations) {
             matchDescriptor.generatePositionDeclarations(declarations);
         }
 
@@ -251,9 +243,8 @@
     }
 
     /**
-     * Set to true to enable logging to a local file during annotation processing. There's no normal
-     * channel for any debug messages and debugging annotation processors requires some special
-     * setup.
+     * Set to true to enable logging during annotation processing. There's no normal channel for any
+     * debug messages and debugging annotation processors requires some special setup.
      */
     private static final boolean DEBUG = false;
 
@@ -265,14 +256,21 @@
 
     private PrintWriter getLog() {
         if (log == null) {
-            try {
-                // Create the log file within the generated source directory so it's easy to find.
-                // /tmp isn't platform independent and java.io.tmpdir can map anywhere, particularly
-                // on the mac.
-                FileObject file = processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT, "", getClass().getSimpleName() + "log");
-                log = new PrintWriter(new FileWriter(file.toUri().getPath(), true));
-            } catch (IOException e) {
-                // Do nothing
+            if (processingEnv.getClass().getName().contains(".javac.")) {
+                // For javac, just log to System.err
+                log = new PrintWriter(System.err);
+            } else {
+                try {
+                    // Create the log file within the generated source directory so it's easy to
+                    // find.
+                    // /tmp isn't platform independent and java.io.tmpdir can map anywhere,
+                    // particularly
+                    // on the mac.
+                    FileObject file = processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT, "", getClass().getSimpleName() + "log");
+                    log = new PrintWriter(new FileWriter(file.toUri().getPath(), true));
+                } catch (IOException e) {
+                    // Do nothing
+                }
             }
         }
         return log;
@@ -309,7 +307,7 @@
             logMessage("throw for %s:\n", element);
         }
         logException(t);
-        errorMessage(element, "Exception throw during processing: %s %s", t, Arrays.toString(Arrays.copyOf(t.getStackTrace(), 4)));
+        printError(element, "Exception throw during processing: %s %s", t, Arrays.toString(Arrays.copyOf(t.getStackTrace(), 4)));
     }
 
     static class TypeDescriptor {
@@ -321,19 +319,19 @@
         final String shortName;
 
         /**
-         * The simple name of the {@link ValueNode} class represented by this type.
+         * The simple name of the {@code ValueNode} class represented by this type.
          */
         final String nodeClass;
 
         /**
-         * The package of {@link ValueNode} class represented by this type.
+         * The package of {@code ValueNode} class represented by this type.
          */
         final String nodePackage;
 
         /**
          * The matchable inputs of the node.
          */
-        final String[] inputs;
+        final List<String> inputs;
 
         /**
          * Should swapped variants of this match be generated. The user of the match is expected to
@@ -350,7 +348,7 @@
 
         final Set<Element> originatingElements = new HashSet<>();
 
-        TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, String[] inputs, boolean commutative, boolean shareable) {
+        TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, List<String> inputs, boolean commutative, boolean shareable) {
             this.mirror = mirror;
             this.shortName = shortName;
             this.nodeClass = nodeClass;
@@ -358,26 +356,18 @@
             this.inputs = inputs;
             this.commutative = commutative;
             this.shareable = shareable;
-            assert !commutative || inputs.length == 2;
+            assert !commutative || inputs.size() == 2;
         }
     }
 
     /**
      * The types which are know for purpose of parsing MatchRule expressions.
      */
-    EconomicMap<String, TypeDescriptor> knownTypes = EconomicMap.create(Equivalence.DEFAULT);
+    Map<String, TypeDescriptor> knownTypes = new HashMap<>();
 
     private TypeDescriptor valueType;
 
-    private TypeMirror matchRulesTypeMirror;
-
-    private TypeMirror matchRuleTypeMirror;
-
-    private TypeMirror matchableNodeTypeMirror;
-
-    private TypeMirror matchableNodesTypeMirror;
-
-    private void declareType(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, String[] inputs, boolean commutative, boolean shareable, Element element) {
+    private void declareType(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, List<String> inputs, boolean commutative, boolean shareable, Element element) {
         TypeDescriptor descriptor = new TypeDescriptor(mirror, shortName, nodeClass, nodePackage, inputs, commutative, shareable);
         descriptor.originatingElements.add(element);
         knownTypes.put(shortName, descriptor);
@@ -388,7 +378,7 @@
         if (p != null) {
             return p.getQualifiedName().toString();
         }
-        throw new GraalError("can't find package for %s", type);
+        throw new InternalError("Can't find package for " + type);
     }
 
     class MatchDescriptor {
@@ -400,13 +390,13 @@
             this.nodeType = nodeType;
             this.name = name;
             if (forExpression) {
-                this.inputs = new MatchDescriptor[nodeType.inputs.length];
+                this.inputs = new MatchDescriptor[nodeType.inputs.size()];
             } else {
                 this.inputs = new MatchDescriptor[0];
             }
         }
 
-        public void generatePositionDeclarations(EconomicSet<String> declarations) {
+        public void generatePositionDeclarations(Set<String> declarations) {
             if (inputs.length == 0) {
                 return;
             }
@@ -469,10 +459,10 @@
 
         private String formatSuffix() {
             if (nodeType != null) {
-                if (inputs.length != nodeType.inputs.length) {
+                if (inputs.length != nodeType.inputs.size()) {
                     return ", true)";
                 } else {
-                    if (nodeType.inputs.length > 0) {
+                    if (nodeType.inputs.size() > 0) {
                         return ", " + nodeType.nodeClass + "_positions, " + !nodeType.shareable + ")";
                     }
                     if (nodeType.shareable) {
@@ -502,7 +492,7 @@
         String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString();
         Name topDeclaringClass = info.topDeclaringType.getSimpleName();
 
-        String matchStatementClassName = topDeclaringClass + "_" + MatchStatementSet.class.getSimpleName();
+        String matchStatementClassName = topDeclaringClass + "_MatchStatementSet";
         Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]);
 
         Types typeUtils = typeUtils();
@@ -516,22 +506,20 @@
             out.println("package " + pkg + ";");
             out.println("");
             out.println("import java.util.*;");
-            out.println("import " + MatchStatementSet.class.getPackage().getName() + ".*;");
-            out.println("import " + NodeMatchRules.class.getName() + ";");
-            out.println("import " + Position.class.getName() + ";");
-            out.println("import " + ServiceProvider.class.getName() + ";");
+            out.println("import org.graalvm.compiler.core.match.*;");
+            out.println("import org.graalvm.compiler.core.gen.NodeMatchRules;");
+            out.println("import org.graalvm.compiler.graph.Position;");
             for (String p : info.requiredPackages) {
                 out.println("import " + p + ".*;");
             }
             out.println("");
 
-            out.println("@" + ServiceProvider.class.getSimpleName() + "(" + MatchStatementSet.class.getSimpleName() + ".class)");
-            out.println("public class " + matchStatementClassName + " implements " + MatchStatementSet.class.getSimpleName() + " {");
+            out.println("public class " + matchStatementClassName + " implements MatchStatementSet {");
 
             out.println();
 
             // Generate declarations for the wrapper class to invoke the code generation methods.
-            for (MethodInvokerItem invoker : info.invokers.getValues()) {
+            for (MethodInvokerItem invoker : info.invokers.values()) {
                 StringBuilder args = new StringBuilder();
                 StringBuilder types = new StringBuilder();
                 int count = invoker.fields.size();
@@ -562,7 +550,7 @@
 
             }
 
-            String desc = MatchStatement.class.getSimpleName();
+            String desc = "MatchStatement";
 
             out.println("    @Override");
             out.println("    public Class<? extends NodeMatchRules> forClass() {");
@@ -595,6 +583,7 @@
 
             out.println("}");
         }
+        this.createProviderFile(pkg + "." + matchStatementClassName, "org.graalvm.compiler.core.match.MatchStatementSet", originatingElements);
     }
 
     protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) {
@@ -662,17 +651,17 @@
 
         final TypeElement topDeclaringType;
         final List<MatchRuleItem> matchRules = new ArrayList<>();
-        private final EconomicSet<Element> originatingElements = EconomicSet.create(Equivalence.DEFAULT);
-        public EconomicSet<String> positionDeclarations = EconomicSet.create(Equivalence.DEFAULT);
+        private final Set<Element> originatingElements = new HashSet<>();
+        public Set<String> positionDeclarations = new HashSet<>();
 
         /**
          * The mapping between elements with MatchRules and the wrapper class used invoke the code
          * generation after the match.
          */
-        EconomicMap<String, MethodInvokerItem> invokers = EconomicMap.create(Equivalence.DEFAULT);
+        Map<String, MethodInvokerItem> invokers = new HashMap<>();
 
         /**
-         * The set of packages which must be imported to refer the classes mention in matchRules.
+         * The set of packages which must be imported to refer the classes mentioned in matchRules.
          */
         Set<String> requiredPackages = new HashSet<>();
 
@@ -690,14 +679,15 @@
         return topDeclaringType(enclosing);
     }
 
-    private AnnotationMirror findAnnotationMirror(Element element, TypeMirror typeMirror) {
-        for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
-            if (typeUtils().isSameType(mirror.getAnnotationType(), typeMirror)) {
-                return mirror;
-            }
-        }
-        return null;
-    }
+    /**
+     * The element currently being processed.
+     */
+    private Element currentElement;
+
+    /**
+     * The current processing round.
+     */
+    private RoundEnvironment currentRound;
 
     @Override
     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
@@ -706,45 +696,58 @@
         }
 
         logMessage("Starting round %s\n", roundEnv);
-        matchRulesTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchRules.class.getCanonicalName()).asType();
-        matchRuleTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchRule.class.getCanonicalName()).asType();
 
-        matchableNodeTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchableNode.class.getCanonicalName()).asType();
-        matchableNodesTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchableNodes.class.getCanonicalName()).asType();
+        TypeElement matchRulesTypeElement = getTypeElement(MATCH_RULES_CLASS_NAME);
+        TypeElement matchRuleTypeElement = getTypeElement(MATCH_RULE_CLASS_NAME);
 
-        Element currentElement = null;
+        TypeMirror matchRulesTypeMirror = matchRulesTypeElement.asType();
+        TypeMirror matchRuleTypeMirror = matchRuleTypeElement.asType();
+
+        TypeElement matchableNodeTypeElement = getTypeElement(MATCHABLE_NODE_CLASS_NAME);
+        TypeElement matchableNodesTypeElement = getTypeElement(MATCHABLE_NODES_CLASS_NAME);
+
+        currentRound = roundEnv;
         try {
-            for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNode.class)) {
+            for (Element element : roundEnv.getElementsAnnotatedWith(matchableNodeTypeElement)) {
+                currentElement = element;
                 logMessage("%s\n", element);
-                processMatchableNode(element);
+                processMatchableNodes(element);
             }
-            for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNodes.class)) {
+            for (Element element : roundEnv.getElementsAnnotatedWith(matchableNodesTypeElement)) {
+                currentElement = element;
                 logMessage("%s\n", element);
-                processMatchableNode(element);
+                processMatchableNodes(element);
             }
             // Define a TypeDescriptor for the generic node but don't enter it into the nodeTypes
             // table since it shouldn't be mentioned in match rules.
-            TypeMirror valueTypeMirror = processingEnv.getElementUtils().getTypeElement(ValueNode.class.getName()).asType();
-            valueType = new TypeDescriptor(valueTypeMirror, "Value", ValueNode.class.getSimpleName(), ValueNode.class.getPackage().getName(), new String[0], false, false);
+            TypeMirror valueTypeMirror = getTypeElement(VALUE_NODE_CLASS_NAME).asType();
+            valueType = new TypeDescriptor(valueTypeMirror, "Value", "ValueNode", "org.graalvm.compiler.nodes", Collections.emptyList(), false, false);
 
-            EconomicMap<TypeElement, MatchRuleDescriptor> map = EconomicMap.create(Equivalence.DEFAULT);
+            Map<TypeElement, MatchRuleDescriptor> map = new HashMap<>();
 
-            for (Element element : roundEnv.getElementsAnnotatedWith(MatchRule.class)) {
+            for (Element element : roundEnv.getElementsAnnotatedWith(matchRuleTypeElement)) {
                 currentElement = element;
-                processMatchRule(map, element, findAnnotationMirror(element, matchRuleTypeMirror));
+                AnnotationMirror matchRule = getAnnotation(element, matchRuleTypeMirror);
+                List<AnnotationMirror> matchRuleAnnotations = Collections.singletonList(matchRule);
+                processMatchRules(map, element, matchRuleAnnotations);
             }
-            for (Element element : roundEnv.getElementsAnnotatedWith(MatchRules.class)) {
+            for (Element element : roundEnv.getElementsAnnotatedWith(matchRulesTypeElement)) {
                 currentElement = element;
-                processMatchRule(map, element, findAnnotationMirror(element, matchRulesTypeMirror));
+                AnnotationMirror matchRules = getAnnotation(element, matchRulesTypeMirror);
+                List<AnnotationMirror> matchRuleAnnotations = getAnnotationValueList(matchRules, "value", AnnotationMirror.class);
+                processMatchRules(map, element, matchRuleAnnotations);
             }
 
             currentElement = null;
-            for (MatchRuleDescriptor info : map.getValues()) {
+            for (MatchRuleDescriptor info : map.values()) {
                 createFiles(info);
             }
 
         } catch (Throwable t) {
             reportExceptionThrow(currentElement, t);
+        } finally {
+            currentElement = null;
+            currentRound = null;
         }
 
         return true;
@@ -753,27 +756,27 @@
     /**
      * Build up the type table to be used during parsing of the MatchRule.
      */
-    private void processMatchableNode(Element element) {
-        if (!processedMatchableNode.contains(element)) {
+    private void processMatchableNodes(Element element) {
+        if (!processedMatchableNodes.contains(element)) {
             try {
-                processedMatchableNode.add(element);
+                processedMatchableNodes.add(element);
 
-                AnnotationMirror mirror = findAnnotationMirror(element, matchableNodesTypeMirror);
-                if (mirror == null) {
-                    mirror = findAnnotationMirror(element, matchableNodeTypeMirror);
+                List<AnnotationMirror> matchableNodeAnnotations;
+                AnnotationMirror mirror = getAnnotation(element, getType(MATCHABLE_NODES_CLASS_NAME));
+                if (mirror != null) {
+                    matchableNodeAnnotations = getAnnotationValueList(mirror, "value", AnnotationMirror.class);
+                } else {
+                    mirror = getAnnotation(element, getType(MATCHABLE_NODES_CLASS_NAME));
+                    if (mirror != null) {
+                        matchableNodeAnnotations = Collections.singletonList(mirror);
+                    } else {
+                        return;
+                    }
                 }
-                if (mirror == null) {
-                    return;
-                }
+
                 TypeElement topDeclaringType = topDeclaringType(element);
-                List<AnnotationMirror> mirrors = null;
-                if (typeUtils().isSameType(mirror.getAnnotationType(), matchableNodesTypeMirror)) {
-                    // Unpack the mirrors for a repeatable annotation
-                    mirrors = getAnnotationValueList(AnnotationMirror.class, mirror, "value");
-                }
-                int i = 0;
-                for (MatchableNode matchableNode : element.getAnnotationsByType(MatchableNode.class)) {
-                    processMatchableNode(element, topDeclaringType, matchableNode, mirrors != null ? mirrors.get(i++) : mirror);
+                for (AnnotationMirror matchableNode : matchableNodeAnnotations) {
+                    processMatchableNode(element, topDeclaringType, matchableNode);
                 }
             } catch (Throwable t) {
                 reportExceptionThrow(element, t);
@@ -781,27 +784,22 @@
         }
     }
 
-    private void processMatchableNode(Element element, TypeElement topDeclaringType, MatchableNode matchable, AnnotationMirror mirror) throws GraalError {
+    private void processMatchableNode(Element element, TypeElement topDeclaringType, AnnotationMirror matchable) {
         logMessage("processMatchableNode %s %s %s\n", topDeclaringType, element, matchable);
         String nodeClass;
         String nodePackage;
-        TypeMirror nodeClassMirror = null;
-        try {
-            matchable.nodeClass();
-        } catch (MirroredTypeException e) {
-            nodeClassMirror = e.getTypeMirror();
+        TypeMirror nodeClassMirror = getAnnotationValue(matchable, "nodeClass", TypeMirror.class);
+        if (nodeClassMirror == null) {
+            throw new InternalError("Can't get mirror for node class " + element);
         }
-        if (nodeClassMirror == null) {
-            throw new GraalError("Can't get mirror for node class %s", element);
-        }
-        if (nodeClassMirror.toString().equals(MatchableNode.class.getName())) {
+        if (nodeClassMirror.toString().equals(MATCHABLE_NODE_CLASS_NAME)) {
             nodeClass = topDeclaringType.getQualifiedName().toString();
         } else {
             nodeClass = nodeClassMirror.toString();
         }
         TypeElement typeElement = processingEnv.getElementUtils().getTypeElement(nodeClass);
         if (typeElement == null) {
-            errorMessage(element, mirror, "Class \"%s\" cannot be resolved to a type", nodeClass);
+            printError(element, matchable, "Class \"%s\" cannot be resolved to a type", nodeClass);
             return;
         }
         nodePackage = findPackage(typeElement);
@@ -812,7 +810,8 @@
 
         Types typeUtils = processingEnv.getTypeUtils();
         TypeElement nodeClassElement = (TypeElement) typeUtils.asElement(nodeClassMirror);
-        for (String input : matchable.inputs()) {
+        List<String> inputs = getAnnotationValueList(matchable, "inputs", String.class);
+        for (String input : inputs) {
             boolean ok = false;
             TypeElement current = nodeClassElement;
             while (!ok && current != null) {
@@ -826,17 +825,19 @@
                 current = (TypeElement) typeUtils.asElement(theSuper);
             }
             if (!ok) {
-                errorMessage(element, mirror, "Input named \"%s\" doesn't exist in %s", input, nodeClassElement.getSimpleName());
+                printError(element, matchable, "Input named \"%s\" doesn't exist in %s", input, nodeClassElement.getSimpleName());
             }
         }
 
-        declareType(nodeClassMirror, shortName, nodeClass, nodePackage, matchable.inputs(), matchable.commutative(), matchable.shareable(), element);
+        boolean commutative = getAnnotationValue(matchable, "commutative", Boolean.class);
+        boolean shareable = getAnnotationValue(matchable, "shareable", Boolean.class);
+        declareType(nodeClassMirror, shortName, nodeClass, nodePackage, inputs, commutative, shareable, element);
     }
 
-    private void processMatchRule(EconomicMap<TypeElement, MatchRuleDescriptor> map, Element element, AnnotationMirror mirror) {
-        if (!processedMatchRule.contains(element)) {
+    private void processMatchRules(Map<TypeElement, MatchRuleDescriptor> map, Element element, List<AnnotationMirror> matchRules) {
+        if (!processedMatchRules.contains(element)) {
             try {
-                processedMatchRule.add(element);
+                processedMatchRules.add(element);
 
                 // The annotation element type should ensure this is true.
                 assert element instanceof ExecutableElement;
@@ -849,14 +850,8 @@
                     info = new MatchRuleDescriptor(topDeclaringType);
                     map.put(topDeclaringType, info);
                 }
-                List<AnnotationMirror> mirrors = null;
-                if (typeUtils().isSameType(mirror.getAnnotationType(), matchRulesTypeMirror)) {
-                    // Unpack the mirrors for a repeatable annotation
-                    mirrors = getAnnotationValueList(AnnotationMirror.class, mirror, "value");
-                }
-                int i = 0;
-                for (MatchRule matchRule : element.getAnnotationsByType(MatchRule.class)) {
-                    processMethodMatchRule((ExecutableElement) element, info, matchRule, mirrors != null ? mirrors.get(i++) : mirror);
+                for (AnnotationMirror matchRule : matchRules) {
+                    processMatchRule((ExecutableElement) element, info, matchRule);
                 }
             } catch (Throwable t) {
                 reportExceptionThrow(element, t);
@@ -871,16 +866,16 @@
      * @param element
      */
     private void findMatchableNodes(Element element) {
-        processMatchableNode(element);
+        processMatchableNodes(element);
         Element enclosing = element.getEnclosingElement();
         while (enclosing != null) {
             if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
                 TypeElement current = (TypeElement) enclosing;
                 while (current != null) {
-                    processMatchableNode(current);
+                    processMatchableNodes(current);
                     for (TypeMirror intf : current.getInterfaces()) {
                         Element interfaceElement = typeUtils().asElement(intf);
-                        processMatchableNode(interfaceElement);
+                        processMatchableNodes(interfaceElement);
                         // Recurse
                         findMatchableNodes(interfaceElement);
                     }
@@ -896,34 +891,34 @@
         return processingEnv.getTypeUtils();
     }
 
-    private void processMethodMatchRule(ExecutableElement method, MatchRuleDescriptor info, MatchRule matchRule, AnnotationMirror mirror) {
-        logMessage("processMethodMatchRule %s %s\n", method, mirror);
+    private void processMatchRule(ExecutableElement method, MatchRuleDescriptor info, AnnotationMirror matchRule) {
+        logMessage("processMatchRule %s\n", method);
 
         Types typeUtils = typeUtils();
 
         if (!method.getModifiers().contains(Modifier.PUBLIC)) {
-            errorMessage(method, "MatchRule method %s must be public", method.getSimpleName());
+            printError(method, "MatchRule method %s must be public", method.getSimpleName());
             return;
         }
         if (method.getModifiers().contains(Modifier.STATIC)) {
-            errorMessage(method, "MatchRule method %s must be non-static", method.getSimpleName());
+            printError(method, "MatchRule method %s must be non-static", method.getSimpleName());
             return;
         }
 
         try {
             TypeMirror returnType = method.getReturnType();
-            if (!typeUtils.isSameType(returnType, processingEnv.getElementUtils().getTypeElement(ComplexMatchResult.class.getName()).asType())) {
-                errorMessage(method, "MatchRule method return type must be %s", ComplexMatchResult.class.getName());
+            if (!typeUtils.isSameType(returnType, processingEnv.getElementUtils().getTypeElement(COMPLEX_MATCH_RESULT_CLASS_NAME).asType())) {
+                printError(method, "MatchRule method return type must be %s", COMPLEX_MATCH_RESULT_CLASS_NAME);
                 return;
             }
 
-            String rule = matchRule.value();
+            String rule = getAnnotationValue(matchRule, "value", String.class);
             RuleParser parser = new RuleParser(rule);
             ArrayList<TypeDescriptor> expectedTypes = parser.capturedTypes();
             ArrayList<String> expectedNames = parser.capturedNames();
             List<? extends VariableElement> actualParameters = method.getParameters();
             if (expectedTypes.size() + 1 < actualParameters.size()) {
-                errorMessage(method, "Too many arguments for match method %s != %s", expectedTypes.size() + 1, actualParameters.size());
+                printError(method, "Too many arguments for match method %s != %s", expectedTypes.size() + 1, actualParameters.size());
                 return;
             }
 
@@ -934,12 +929,12 @@
                 String name = parameter.getSimpleName().toString();
                 int nameIndex = expectedNames.indexOf(name);
                 if (nameIndex == -1) {
-                    errorMessage(method, "Argument \"%s\" isn't captured in the match rule", name);
+                    printError(method, "Argument \"%s\" isn't captured in the match rule", name);
                     return;
                 }
                 TypeMirror type = parameter.asType();
                 if (!typeUtils.isAssignable(expectedTypes.get(nameIndex).mirror, type)) {
-                    errorMessage(method, "Captured value \"%s\" of type %s is not assignable to argument of type %s", name, expectedTypes.get(nameIndex).mirror, type);
+                    printError(method, "Captured value \"%s\" of type %s is not assignable to argument of type %s", name, expectedTypes.get(nameIndex).mirror, type);
                     return;
                 }
             }
@@ -952,7 +947,7 @@
             } else if (invoker.method != method) {
                 // This could be supported but it's easier if they are unique since the names
                 // are used in log output and snippet counters.
-                errorMessage(method, "Use unique method names for match methods: %s.%s != %s.%s", method.getReceiverType(), method.getSimpleName(), invoker.method.getReceiverType(),
+                printError(method, "Use unique method names for match methods: %s.%s != %s.%s", method.getReceiverType(), method.getSimpleName(), invoker.method.getReceiverType(),
                                 invoker.method.getSimpleName());
                 return;
             }
@@ -960,12 +955,12 @@
             Element enclosing = method.getEnclosingElement();
             String declaringClass = "";
             String separator = "";
-            EconomicSet<Element> originatingElementsList = info.originatingElements;
+            Set<Element> originatingElementsList = info.originatingElements;
             originatingElementsList.add(method);
             while (enclosing != null) {
                 if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
                     if (enclosing.getModifiers().contains(Modifier.PRIVATE)) {
-                        errorMessage(method, "MatchRule cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing);
+                        printError(method, "MatchRule cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing);
                         return;
                     }
                     originatingElementsList.add(enclosing);
@@ -988,144 +983,26 @@
                 info.matchRules.add(new MatchRuleItem(match, invoker));
             }
         } catch (RuleParseError e) {
-            errorMessage(method, mirror, e.getMessage());
+            printError(method, matchRule, e.getMessage());
         }
     }
 
-    private void errorMessage(Element element, String format, Object... args) {
-        processingEnv.getMessager().printMessage(Kind.ERROR, String.format(format, args), element);
+    private Element elementForMessage(Element e) {
+        if (currentRound != null && !currentRound.getRootElements().contains(e) && currentElement != null) {
+            return currentElement;
+        }
+        return e;
     }
 
-    private void errorMessage(Element element, AnnotationMirror mirror, String format, Object... args) {
-        processingEnv.getMessager().printMessage(Kind.ERROR, String.format(format, args), element, mirror);
+    private void printError(Element annotatedElement, String format, Object... args) {
+        Element e = elementForMessage(annotatedElement);
+        String prefix = e == annotatedElement ? "" : annotatedElement + ": ";
+        processingEnv.getMessager().printMessage(Kind.ERROR, prefix + String.format(format, args), e);
     }
 
-    // TODO borrowed from com.oracle.truffle.dsl.processor.Utils
-    @SuppressWarnings("unchecked")
-    private static <T> List<T> getAnnotationValueList(Class<T> expectedListType, AnnotationMirror mirror, String name) {
-        List<? extends AnnotationValue> values = getAnnotationValue(List.class, mirror, name);
-        List<T> result = new ArrayList<>();
-
-        if (values != null) {
-            for (AnnotationValue value : values) {
-                T annotationValue = resolveAnnotationValue(expectedListType, value);
-                if (annotationValue != null) {
-                    result.add(annotationValue);
-                }
-            }
-        }
-        return result;
-    }
-
-    private static <T> T getAnnotationValue(Class<T> expectedType, AnnotationMirror mirror, String name) {
-        return resolveAnnotationValue(expectedType, getAnnotationValue(mirror, name));
-    }
-
-    @SuppressWarnings({"unchecked"})
-    private static <T> T resolveAnnotationValue(Class<T> expectedType, AnnotationValue value) {
-        if (value == null) {
-            return null;
-        }
-
-        Object unboxedValue = value.accept(new AnnotationValueVisitorImpl(), null);
-        if (unboxedValue != null) {
-            if (expectedType == TypeMirror.class && unboxedValue instanceof String) {
-                return null;
-            }
-            if (!expectedType.isAssignableFrom(unboxedValue.getClass())) {
-                throw new ClassCastException(unboxedValue.getClass().getName() + " not assignable from " + expectedType.getName());
-            }
-        }
-        return (T) unboxedValue;
-    }
-
-    private static AnnotationValue getAnnotationValue(AnnotationMirror mirror, String name) {
-        ExecutableElement valueMethod = null;
-        for (ExecutableElement method : ElementFilter.methodsIn(mirror.getAnnotationType().asElement().getEnclosedElements())) {
-            if (method.getSimpleName().toString().equals(name)) {
-                valueMethod = method;
-                break;
-            }
-        }
-
-        if (valueMethod == null) {
-            return null;
-        }
-
-        AnnotationValue value = mirror.getElementValues().get(valueMethod);
-        if (value == null) {
-            value = valueMethod.getDefaultValue();
-        }
-
-        return value;
-    }
-
-    private static class AnnotationValueVisitorImpl extends AbstractAnnotationValueVisitor7<Object, Void> {
-
-        @Override
-        public Object visitBoolean(boolean b, Void p) {
-            return Boolean.valueOf(b);
-        }
-
-        @Override
-        public Object visitByte(byte b, Void p) {
-            return Byte.valueOf(b);
-        }
-
-        @Override
-        public Object visitChar(char c, Void p) {
-            return c;
-        }
-
-        @Override
-        public Object visitDouble(double d, Void p) {
-            return d;
-        }
-
-        @Override
-        public Object visitFloat(float f, Void p) {
-            return f;
-        }
-
-        @Override
-        public Object visitInt(int i, Void p) {
-            return i;
-        }
-
-        @Override
-        public Object visitLong(long i, Void p) {
-            return i;
-        }
-
-        @Override
-        public Object visitShort(short s, Void p) {
-            return s;
-        }
-
-        @Override
-        public Object visitString(String s, Void p) {
-            return s;
-        }
-
-        @Override
-        public Object visitType(TypeMirror t, Void p) {
-            return t;
-        }
-
-        @Override
-        public Object visitEnumConstant(VariableElement c, Void p) {
-            return c;
-        }
-
-        @Override
-        public Object visitAnnotation(AnnotationMirror a, Void p) {
-            return a;
-        }
-
-        @Override
-        public Object visitArray(List<? extends AnnotationValue> vals, Void p) {
-            return vals;
-        }
-
+    private void printError(Element annotatedElement, AnnotationMirror annotation, String format, Object... args) {
+        Element e = elementForMessage(annotatedElement);
+        String prefix = e == annotatedElement ? "" : annotation + " on " + annotatedElement + ": ";
+        processingEnv.getMessager().printMessage(Kind.ERROR, prefix + String.format(format, args), e, annotation);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java	Thu May 31 13:09:04 2018 -0700
@@ -169,7 +169,7 @@
                 SPARCAddressValue address = (SPARCAddressValue) operand(cas.getAddress());
                 Condition condition = successIsTrue ? Condition.EQ : Condition.NE;
 
-                Value result = getLIRGeneratorTool().emitValueCompareAndSwap(address, expectedValue, newValue);
+                Value result = getLIRGeneratorTool().emitValueCompareAndSwap(kind, address, expectedValue, newValue);
                 getLIRGeneratorTool().emitCompareBranch(kind.getPlatformKind(), result, expectedValue, condition, false, trueLabel, falseLabel, trueLabelProbability);
                 return null;
             };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ArrayLengthProviderTest.java	Thu May 31 13:09:04 2018 -0700
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, 2015, 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 java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+public class ArrayLengthProviderTest extends GraalCompilerTest {
+
+    public static Object test0Snippet(ArrayList<?> list, boolean a) {
+        while (true) {
+            Object[] array = toArray(list);
+            if (array.length < 1) {
+                return null;
+            }
+            if (array[0] instanceof String || a) {
+                /*
+                 * This code is outside of the loop. Accessing the array reqires a ValueProxyNode.
+                 * When the simplification of the ArrayLengthNode replaces the length access with
+                 * the ArrayList.size used to create the array, then the value needs to have a
+                 * ValueProxyNode too. In addition, the two parts of the if-condition actually lead
+                 * to two separate loop exits, with two separate proxy nodes. A ValuePhiNode is
+                 * present originally for the array, and the array length simplification needs to
+                 * create a new ValuePhiNode for the two newly introduced ValueProxyNode.
+                 */
+                if (array.length < 1) {
+                    return null;
+                }
+                return array[0];
+            }
+        }
+    }
+
+    public static Object test1Snippet(ArrayList<?> list, boolean a, boolean b) {
+        while (true) {
+            Object[] array = toArray(list);
+            if (a || b) {
+                if (array.length < 1) {
+                    return null;
+                }
+                return array[0];
+            }
+        }
+    }
+
+    public static Object[] toArray(List<?> list) {
+        return new Object[list.size()];
+    }
+
+    @Test
+    public void test0() {
+        test("test0Snippet", new ArrayList<>(Arrays.asList("a", "b")), true);
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet", new ArrayList<>(Arrays.asList("a", "b")), true, true);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CanonicalizedConversionTest.java	Thu May 31 13:09:04 2018 -0700
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 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.core.test;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.FloatEqualsNode;
+import org.graalvm.compiler.nodes.calc.ReinterpretNode;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Tests that substitutions for {@link Double#doubleToLongBits(double)} and
+ * {@link Float#floatToIntBits(float)} produce graphs such that multiple calls to these methods with
+ * the same input are canonicalized.
+ */
+public class CanonicalizedConversionTest extends GraalCompilerTest {
+
+    @Override
+    protected boolean checkLowTierGraph(StructuredGraph graph) {
+        int reinterpretCount = 0;
+        int floatEqualsCount = 0;
+        int addCount = 0;
+        for (Node node : graph.getNodes()) {
+            if (node instanceof ReinterpretNode) {
+                reinterpretCount++;
+            } else if (node instanceof FloatEqualsNode) {
+                floatEqualsCount++;
+            } else if (node instanceof IfNode) {
+                Assert.fail("Unexpected node: " + node);
+            } else if (node instanceof AddNode) {
+                addCount++;
+            }
+        }
+        Assert.assertEquals(1, reinterpretCount);
+        Assert.assertEquals(1, floatEqualsCount);
+        Assert.assertEquals(2, addCount);
+        return true;
+    }
+
+    @Test
+    public void test4() {
+        test("snippet4", 567.890F);
+        test("snippet4", -567.890F);
+        test("snippet4", Float.NaN);
+    }
+
+    public static int snippet4(float value) {
+        return Float.floatToIntBits(value) + Float.floatToIntBits(value) + Float.floatToIntBits(value);
+    }
+
+    @Test
+    public void test5() {
+        test("snippet5", 567.890D);
+        test("snippet5", -567.890D);
+        test("snippet5", Double.NaN);
+    }
+
+    public static long snippet5(double value) {
+        return Double.doubleToLongBits(value) + Double.doubleToLongBits(value) + Double.doubleToLongBits(value);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest15.java	Thu May 31 13:09:04 2018 -0700
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 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.core.test;
+
+import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Collection of tests for {@link org.graalvm.compiler.phases.common.ConditionalEliminationPhase}
+ * including those that triggered bugs in this phase.
+ */
+public class ConditionalEliminationTest15 extends ConditionalEliminationTestBase {
+
+    private void checkNodeCount(String methodName, Class<? extends Node> nodeClass, int count) {
+        StructuredGraph graph = parseEager(methodName, AllowAssumptions.YES);
+
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        PhaseContext context = new PhaseContext(getProviders());
+
+        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        canonicalizer.apply(graph, context);
+
+        // Merge arr.length reads.
+        new EarlyReadEliminationPhase(canonicalizer).apply(graph, context);
+        new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context);
+
+        getDebugContext().dump(DebugContext.BASIC_LEVEL, graph, "After ConditionalEliminationPhase");
+
+        Assert.assertEquals(count, graph.getNodes().filter(nodeClass).count());
+    }
+
+    public static int testRedundantIntegerLessThanNode(int index, int[] arr) {
+        while (arr[index] != 42) {
+            if (index >= 0) { // redundant
+                return 1;
+            }
+        }
+        return 2;
+    }
+
+    public static int testRedundantIntegerLessThanNode2(int index, int[] arr) {
+        while (arr[index] != 42) {
+            if (index < arr.length) { // redundant
+                return 1;
+            }
+        }
+        return 2;
+    }
+
+    @Test
+    public void testRedundantSignedLessThanNode() {
+        checkNodeCount("testRedundantIntegerLessThanNode", IntegerLessThanNode.class, 0);
+        checkNodeCount("testRedundantIntegerLessThanNode2", IntegerLessThanNode.class, 0);
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest2.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest2.java	Thu May 31 13:09:04 2018 -0700
@@ -22,15 +22,18 @@
  */
 package org.graalvm.compiler.core.test;
 
+import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.nodes.GuardNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
 import org.graalvm.compiler.phases.common.FloatingReadPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
-import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.junit.Assert;
 import org.junit.Test;
 
 /**
@@ -60,6 +63,15 @@
         final Entry next;
     }
 
+    static class A {
+    }
+
+    static class B extends A {
+    }
+
+    static class C extends A {
+    }
+
     public static Entry search(Entry start, String name, Entry alternative) {
         Entry current = start;
         do {
@@ -129,4 +141,81 @@
         assertDeepEquals(0, graph.getNodes().filter(GuardNode.class).count());
     }
 
+    private void checkInstanceOfCount(String methodName, int count) {
+        StructuredGraph graph = parseEager(methodName, AllowAssumptions.YES);
+
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        PhaseContext context = new PhaseContext(getProviders());
+
+        canonicalizer.apply(graph, context);
+        new ConditionalEliminationPhase(true).apply(graph, context);
+        getDebugContext().dump(DebugContext.BASIC_LEVEL, graph, "After ConditionalEliminationPhase");
+        canonicalizer.apply(graph, context);
+
+        Assert.assertEquals(count, graph.getNodes().filter(InstanceOfNode.class).count());
+    }
+
+    public static A testRedundantInstanceOfClass(Object value) {
+        if (value != null && value.getClass() == A.class) {
+            return (A) value;
+        }
+        return null;
+    }
+
+    public static Object testRedundantInstanceOfArray(Object value) {
+        if (value != null && value.getClass() == Object[].class) {
+            return ((Object[]) value)[0];
+        }
+        return null;
+    }
+
+    public static boolean testRedundantInstanceOfPrecise(Object value) {
+        if (value != null && value.getClass() == A.class) {
+            return value instanceof A;
+        }
+        return false;
+    }
+
+    public static boolean testRedundantInstanceOfImplicitNonNull(Object value) {
+        if (value.getClass() == A.class) {
+            return value instanceof A;
+        }
+        return false;
+    }
+
+    @Test
+    public void testRedundantInstanceOf() {
+        checkInstanceOfCount("testRedundantInstanceOfClass", 1);
+        checkInstanceOfCount("testRedundantInstanceOfArray", 1);
+        checkInstanceOfCount("testRedundantInstanceOfPrecise", 1);
+        checkInstanceOfCount("testRedundantInstanceOfImplicitNonNull", 1);
+    }
+
+    public static boolean testNonRedundantInstanceOfClass(Object value) {
+        if (value instanceof A) {
+            return (value != null && value.getClass() == A.class);
+        }
+        return false;
+    }
+
+    public static boolean testNonRedundantInstanceOfArray(Object value) {
+        if (value instanceof Object[]) {
+            return (value != null && value.getClass() == Object[].class);
+        }
+        return false;
+    }
+
+    public static boolean testNonRedundantInstanceOfImplicitNonNull(Object value) {
+        if (value instanceof Object[]) {
+            return value.getClass() == Object[].class;
+        }
+        return false;
+    }
+
+    @Test
+    public void testNonRedundantInstanceOf() {
+        checkInstanceOfCount("testNonRedundantInstanceOfClass", 2);
+        checkInstanceOfCount("testNonRedundantInstanceOfArray", 2);
+        checkInstanceOfCount("testNonRedundantInstanceOfImplicitNonNull", 2);
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Thu May 31 13:09:04 2018 -0700
@@ -1054,7 +1054,7 @@
         try (DebugContext.Scope s = debug.scope("Compile", graphToCompile)) {
             assert options != null;
             Request<CompilationResult> request = new Request<>(graphToCompile, installedCodeOwner, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL,
-                            graphToCompile.getProfilingInfo(), createSuites(options), createLIRSuites(options), compilationResult, CompilationResultBuilderFactory.Default);
+                            graphToCompile.getProfilingInfo(), createSuites(options), createLIRSuites(options), compilationResult, CompilationResultBuilderFactory.Default, true);
             return GraalCompiler.compile(request);
         } catch (Throwable e) {
             throw debug.handle(e);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java	Thu May 31 13:09:04 2018 -0700
@@ -68,7 +68,7 @@
         final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
         final StructuredGraph graph = parseEager(method, AllowAssumptions.YES);
         final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, graph.getProfilingInfo(),
-                        createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
+                        createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default, true);
         for (Infopoint sp : cr.getInfopoints()) {
             assertNotNull(sp.reason);
             if (sp instanceof Call) {
@@ -90,7 +90,7 @@
         assertTrue(graphLineSPs > 0);
         PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true));
         final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), graphBuilderSuite, OptimisticOptimizations.ALL, graph.getProfilingInfo(),
-                        createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
+                        createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default, true);
         int lineSPs = 0;
         for (Infopoint sp : cr.getInfopoints()) {
             assertNotNull(sp.reason);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/InvokeGraal.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/InvokeGraal.java	Thu May 31 13:09:04 2018 -0700
@@ -127,7 +127,7 @@
             CompilationResultBuilderFactory factory = CompilationResultBuilderFactory.Default;
 
             /* Invoke the whole Graal compilation pipeline. */
-            GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory);
+            GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory, true);
 
             /*
              * Install the compilation result into the VM, i.e., copy the byte[] array that contains
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java	Thu May 31 13:09:04 2018 -0700
@@ -106,6 +106,7 @@
         public final LIRSuites lirSuites;
         public final T compilationResult;
         public final CompilationResultBuilderFactory factory;
+        public final boolean verifySourcePositions;
 
         /**
          * @param graph the graph to be compiled
@@ -122,7 +123,8 @@
          * @param factory
          */
         public Request(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, PhaseSuite<HighTierContext> graphBuilderSuite,
-                        OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory) {
+                        OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory,
+                        boolean verifySourcePositions) {
             this.graph = graph;
             this.installedCodeOwner = installedCodeOwner;
             this.providers = providers;
@@ -134,6 +136,7 @@
             this.lirSuites = lirSuites;
             this.compilationResult = compilationResult;
             this.factory = factory;
+            this.verifySourcePositions = verifySourcePositions;
         }
 
         /**
@@ -156,8 +159,9 @@
      */
     public static <T extends CompilationResult> T compileGraph(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend,
                     PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult,
-                    CompilationResultBuilderFactory factory) {
-        return compile(new Request<>(graph, installedCodeOwner, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory));
+                    CompilationResultBuilderFactory factory, boolean verifySourcePositions) {
+        return compile(new Request<>(graph, installedCodeOwner, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory,
+                        verifySourcePositions));
     }
 
     /**
@@ -173,6 +177,9 @@
             try (DebugContext.Scope s0 = debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache()); DebugCloseable a = CompilerTimer.start(debug)) {
                 emitFrontEnd(r.providers, r.backend, r.graph, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.suites);
                 emitBackEnd(r.graph, null, r.installedCodeOwner, r.backend, r.compilationResult, r.factory, null, r.lirSuites);
+                if (r.verifySourcePositions) {
+                    assert r.graph.verifySourcePositions(true);
+                }
             } catch (Throwable e) {
                 throw debug.handle(e);
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java	Thu May 31 13:09:04 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -22,8 +22,6 @@
  */
 package org.graalvm.compiler.core.gen;
 
-import jdk.vm.ci.meta.Value;
-
 import org.graalvm.compiler.core.match.MatchableNode;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.lir.LIRFrameState;
@@ -62,6 +60,8 @@
 import org.graalvm.compiler.nodes.memory.ReadNode;
 import org.graalvm.compiler.nodes.memory.WriteNode;
 
+import jdk.vm.ci.meta.Value;
+
 @MatchableNode(nodeClass = ConstantNode.class, shareable = true)
 @MatchableNode(nodeClass = FloatConvertNode.class, inputs = {"value"})
 @MatchableNode(nodeClass = FloatingReadNode.class, inputs = {"address"})
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java	Thu May 31 13:09:04 2018 -0700
@@ -167,6 +167,32 @@
     }
 
     @Test
+    public void testContextScope() {
+        OptionValues options = new OptionValues(EconomicMap.create());
+        options = new OptionValues(options, DebugOptions.Log, ":5");
+        DebugContextSetup setup = new DebugContextSetup();
+        try (DebugContext debug = setup.openDebugContext(options)) {
+            try (DebugContext.Scope s0 = debug.scope("TestLogging")) {
+                try (DebugContext.Scope s1 = debug.withContext("A")) {
+                    for (Object o : debug.context()) {
+                        Assert.assertEquals(o, "A");
+                    }
+                } catch (Throwable t) {
+                    throw debug.handle(t);
+                }
+                try (DebugContext.Scope s1 = debug.withContext("B")) {
+                    for (Object o : debug.context()) {
+                        Assert.assertEquals(o, "B");
+                    }
+                } catch (Throwable t) {
+                    throw debug.handle(t);
+                }
+            }
+        }
+
+    }
+
+    @Test
     public void testEnabledSandbox() {
         EconomicMap<OptionKey<?>, Object> map = EconomicMap.create();
         // Configure with an option that enables scopes
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/CausableByCompilerAssert.java	Thu May 31 13:09:04 2018 -0700
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+public interface CausableByCompilerAssert {
+    boolean isCausedByCompilerAssert();
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigImpl.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigImpl.java	Thu May 31 13:09:04 2018 -0700
@@ -239,8 +239,11 @@
 
     @Override
     public RuntimeException interceptException(DebugContext debug, Throwable e) {
-        if (e instanceof BailoutException && !DebugOptions.InterceptBailout.getValue(options)) {
-            return null;
+        if (e instanceof BailoutException) {
+            final boolean causedByCompilerAssert = e instanceof CausableByCompilerAssert && ((CausableByCompilerAssert) e).isCausedByCompilerAssert();
+            if (!DebugOptions.InterceptBailout.getValue(options) && !causedByCompilerAssert) {
+                return null;
+            }
         }
 
         OptionValues interceptOptions = new OptionValues(options,
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java	Thu May 31 13:09:04 2018 -0700
@@ -96,7 +96,7 @@
      */
     boolean metricsEnabled;
 
-    DebugConfig currentConfig;
+    DebugConfigImpl currentConfig;
     ScopeImpl currentScope;
     CloseableCounter currentTimer;
     CloseableCounter currentMemUseTracker;
@@ -739,6 +739,19 @@
     }
 
     /**
+     * Create an unnamed scope that appends some context to the current scope.
+     *
+     * @param context an object to be appended to the {@linkplain #context() current} debug context
+     */
+    public DebugContext.Scope withContext(Object context) throws Throwable {
+        if (currentScope != null) {
+            return enterScope("", null, context);
+        } else {
+            return null;
+        }
+    }
+
+    /**
      * Creates and enters a new debug scope which will be disjoint from the current debug scope.
      * <p>
      * It is recommended to use the try-with-resource statement for managing entering and leaving
@@ -787,7 +800,7 @@
     class DisabledScope implements DebugContext.Scope {
         final boolean savedMetricsEnabled;
         final ScopeImpl savedScope;
-        final DebugConfig savedConfig;
+        final DebugConfigImpl savedConfig;
 
         DisabledScope() {
             this.savedMetricsEnabled = metricsEnabled;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugValueMap.java	Thu May 31 06:15:17 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,194 +0,0 @@
-/*
- * Copyright (c) 2012, 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.debug;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A node in a tree of values.
- */
-public class DebugValueMap {
-
-    /**
-     * The top level maps for all threads.
-     */
-    private static final List<DebugValueMap> topLevelMaps = new ArrayList<>();
-
-    private long[] values;
-    private List<DebugValueMap> children;
-    private String name;
-
-    public DebugValueMap(String name) {
-        this.name = name;
-    }
-
-    public void setCurrentValue(int index, long l) {
-        ensureSize(index);
-        values[index] = l;
-    }
-
-    public long getCurrentValue(int index) {
-        ensureSize(index);
-        return values[index];
-    }
-
-    public void clearChildren() {
-        if (children != null) {
-            children.clear();
-        }
-    }
-
-    public void reset() {
-        if (values != null) {
-            Arrays.fill(values, 0L);
-        }
-        if (children != null) {
-            for (DebugValueMap child : children) {
-                child.reset();
-            }
-        }
-    }
-
-    private void ensureSize(int index) {
-        if (values == null) {
-            values = new long[index + 1];
-        }
-        if (values.length <= index) {
-            values = Arrays.copyOf(values, index + 1);
-        }
-    }
-
-    private int capacity() {
-        return (values == null) ? 0 : values.length;
-    }
-
-    public void addChild(DebugValueMap map) {
-        if (children == null) {
-            children = new ArrayList<>(4);
-        }
-        children.add(map);
-    }
-
-    public List<DebugValueMap> getChildren() {
-        if (children == null) {
-            return Collections.emptyList();
-        } else {
-            return Collections.unmodifiableList(children);
-        }
-    }
-
-    public boolean hasChildren() {
-        return children != null && !children.isEmpty();
-    }
-
-    public String getName() {
-        return this.name;
-    }
-
-    @Override
-    public String toString() {
-        return "DebugValueMap<" + getName() + ">";
-    }
-
-    public static synchronized void registerTopLevel(DebugValueMap map) {
-        topLevelMaps.add(map);
-    }
-
-    public static synchronized List<DebugValueMap> getTopLevelMaps() {
-        return topLevelMaps;
-    }
-
-    /**
-     * The top level map for the current thread.
-     */
-    private static final ThreadLocal<DebugValueMap> topLevelMap = new ThreadLocal<>();
-
-    static DebugValueMap getTopLevelMap() {
-        DebugValueMap map = topLevelMap.get();
-        if (map == null) {
-            map = new DebugValueMap(Thread.currentThread().getName());
-            topLevelMap.set(map);
-            registerTopLevel(map);
-        }
-        return map;
-    }
-
-    public void normalize() {
-        if (hasChildren()) {
-            Map<String, DebugValueMap> occurred = new HashMap<>();
-            for (DebugValueMap map : children) {
-                String mapName = map.getName();
-                if (!occurred.containsKey(mapName)) {
-                    occurred.put(mapName, map);
-                    map.normalize();
-                } else {
-                    occurred.get(mapName).mergeWith(map);
-                    occurred.get(mapName).normalize();
-                }
-            }
-
-            if (occurred.values().size() < children.size()) {
-                // At least one duplicate was found.
-                children.clear();
-                for (DebugValueMap map : occurred.values()) {
-                    addChild(map);
-                    map.normalize();
-                }
-            }
-        }
-    }
-
-    private void mergeWith(DebugValueMap map) {
-        if (map.hasChildren()) {
-            if (hasChildren()) {
-                children.addAll(map.children);
-            } else {
-                children = map.children;
-            }
-            map.children = null;
-        }
-
-        int size = Math.max(this.capacity(), map.capacity());
-        ensureSize(size);
-        for (int i = 0; i < size; ++i) {
-            long curValue = getCurrentValue(i);
-            long otherValue = map.getCurrentValue(i);
-            setCurrentValue(i, curValue + otherValue);
-        }
-    }
-
-    public void group() {
-        if (this.hasChildren()) {
-            List<DebugValueMap> oldChildren = new ArrayList<>(this.children);
-            this.children.clear();
-            for (DebugValueMap map : oldChildren) {
-                mergeWith(map);
-            }
-        }
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/PathUtilities.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/PathUtilities.java	Thu May 31 13:09:04 2018 -0700
@@ -72,9 +72,10 @@
 
     /**
      * A maximum file name length supported by most file systems. There is no platform independent
-     * way to get this in Java.
+     * way to get this in Java. Normally it is 255. But for AUFS it is 242. Refer AUFS_MAX_NAMELEN
+     * in http://aufs.sourceforge.net/aufs3/man.html.
      */
-    private static final int MAX_FILE_NAME_LENGTH = 255;
+    private static final int MAX_FILE_NAME_LENGTH = 242;
 
     private static final String ELLIPSIS = "...";
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/ScopeImpl.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/ScopeImpl.java	Thu May 31 13:09:04 2018 -0700
@@ -38,31 +38,35 @@
         final String indent;
         final IndentImpl parentIndent;
 
+        boolean isEmitted() {
+            return emitted;
+        }
+
+        private boolean emitted;
+
         IndentImpl(IndentImpl parentIndent) {
             this.parentIndent = parentIndent;
             this.indent = (parentIndent == null ? "" : parentIndent.indent + INDENTATION_INCREMENT);
         }
 
-        private boolean logScopeName() {
-            return logScopeName;
-        }
-
         private void printScopeName(StringBuilder str, boolean isCurrent) {
-            if (logScopeName) {
-                boolean parentPrinted = false;
+            if (!emitted) {
+                boolean mustPrint = true;
                 if (parentIndent != null) {
-                    parentPrinted = parentIndent.logScopeName();
-                    parentIndent.printScopeName(str, false);
+                    if (!parentIndent.isEmitted()) {
+                        parentIndent.printScopeName(str, false);
+                        mustPrint = false;
+                    }
                 }
                 /*
-                 * Always print the current scope, scopes with context and the any scope whose
-                 * parent didn't print. This ensure the first new scope always shows up.
+                 * Always print the current scope, scopes with context and any scope whose parent
+                 * didn't print. This ensure the first new scope always shows up.
                  */
-                if (isCurrent || printContext(null) != 0 || !parentPrinted) {
+                if (isCurrent || printContext(null) != 0 || mustPrint) {
                     str.append(indent).append("[thread:").append(Thread.currentThread().getId()).append("] scope: ").append(getQualifiedName()).append(System.lineSeparator());
                 }
                 printContext(str);
-                logScopeName = false;
+                emitted = true;
             }
         }
 
@@ -116,7 +120,12 @@
     private final ScopeImpl parent;
     private final boolean sandbox;
     private IndentImpl lastUsedIndent;
-    private boolean logScopeName;
+
+    private boolean isEmptyScope() {
+        return emptyScope;
+    }
+
+    private final boolean emptyScope;
 
     private final Object[] context;
 
@@ -136,23 +145,24 @@
     private PrintStream output;
     private boolean interceptDisabled;
 
-    static final Object[] EMPTY_CONTEXT = new Object[0];
-
     ScopeImpl(DebugContext owner, Thread thread) {
         this(owner, thread.getName(), null, false);
     }
 
-    ScopeImpl(DebugContext owner, String unqualifiedName, ScopeImpl parent, boolean sandbox, Object... context) {
+    private ScopeImpl(DebugContext owner, String unqualifiedName, ScopeImpl parent, boolean sandbox, Object... context) {
         this.owner = owner;
         this.parent = parent;
         this.sandbox = sandbox;
         this.context = context;
         this.unqualifiedName = unqualifiedName;
         if (parent != null) {
-            logScopeName = !unqualifiedName.equals("");
+            emptyScope = unqualifiedName.equals("");
             this.interceptDisabled = parent.interceptDisabled;
         } else {
-            logScopeName = true;
+            if (unqualifiedName.isEmpty()) {
+                throw new IllegalArgumentException("root scope name must be non-empty");
+            }
+            emptyScope = false;
         }
 
         this.output = TTY.out;
@@ -169,29 +179,29 @@
         return parent == null;
     }
 
-    public boolean isDumpEnabled(int dumpLevel) {
+    boolean isDumpEnabled(int dumpLevel) {
         assert dumpLevel >= 0;
         return currentDumpLevel >= dumpLevel;
     }
 
-    public boolean isVerifyEnabled() {
+    boolean isVerifyEnabled() {
         return verifyEnabled;
     }
 
-    public boolean isLogEnabled(int logLevel) {
+    boolean isLogEnabled(int logLevel) {
         assert logLevel > 0;
         return currentLogLevel >= logLevel;
     }
 
-    public boolean isCountEnabled() {
+    boolean isCountEnabled() {
         return countEnabled;
     }
 
-    public boolean isTimeEnabled() {
+    boolean isTimeEnabled() {
         return timeEnabled;
     }
 
-    public boolean isMemUseTrackingEnabled() {
+    boolean isMemUseTrackingEnabled() {
         return memUseTrackingEnabled;
     }
 
@@ -307,7 +317,7 @@
         throw silenceException(RuntimeException.class, e);
     }
 
-    void updateFlags(DebugConfig config) {
+    void updateFlags(DebugConfigImpl config) {
         if (config == null) {
             countEnabled = false;
             memUseTrackingEnabled = false;
@@ -317,6 +327,14 @@
             // Be pragmatic: provide a default log stream to prevent a crash if the stream is not
             // set while logging
             output = TTY.out;
+        } else if (isEmptyScope()) {
+            countEnabled = parent.countEnabled;
+            memUseTrackingEnabled = parent.memUseTrackingEnabled;
+            timeEnabled = parent.timeEnabled;
+            verifyEnabled = parent.verifyEnabled;
+            output = parent.output;
+            currentDumpLevel = parent.currentDumpLevel;
+            currentLogLevel = parent.currentLogLevel;
         } else {
             countEnabled = config.isCountEnabled(this);
             memUseTrackingEnabled = config.isMemUseTrackingEnabled(this);
@@ -404,18 +422,21 @@
             if (parent == null) {
                 qualifiedName = unqualifiedName;
             } else {
-                qualifiedName = parent.getQualifiedName() + SCOPE_SEP + unqualifiedName;
+                qualifiedName = parent.getQualifiedName();
+                if (!isEmptyScope()) {
+                    qualifiedName += SCOPE_SEP + unqualifiedName;
+                }
             }
         }
         return qualifiedName;
     }
 
-    public Indent pushIndentLogger() {
+    Indent pushIndentLogger() {
         lastUsedIndent = getLastUsedIndent().indent();
         return lastUsedIndent;
     }
 
-    public IndentImpl getLastUsedIndent() {
+    private IndentImpl getLastUsedIndent() {
         if (lastUsedIndent == null) {
             if (parent != null) {
                 lastUsedIndent = new IndentImpl(parent.getLastUsedIndent());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java	Thu May 31 13:09:04 2018 -0700
@@ -1199,7 +1199,7 @@
         return true;
     }
 
-    public boolean verifySourcePositions() {
+    public boolean verifySourcePositions(boolean performConsistencyCheck) {
         if (trackNodeSourcePosition()) {
             ResolvedJavaMethod root = null;
             for (Node node : getNodes()) {
@@ -1211,6 +1211,11 @@
                         assert pos.verifyRootMethod(root) : node;
                     }
                 }
+
+                // More strict node-type-specific check
+                if (performConsistencyCheck) {
+                    node.verifySourcePosition();
+                }
             }
         }
         return true;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java	Thu May 31 13:09:04 2018 -0700
@@ -263,7 +263,7 @@
     static class NodeCreationStackTrace extends NodeStackTrace {
     }
 
-    static class NodeInsertionStackTrace extends NodeStackTrace {
+    public static class NodeInsertionStackTrace extends NodeStackTrace {
     }
 
     public Node(NodeClass<? extends Node> c) {
@@ -1063,6 +1063,10 @@
         return true;
     }
 
+    public boolean verifySourcePosition() {
+        return true;
+    }
+
     /**
      * Perform expensive verification of inputs, usages, predecessors and successors.
      *
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java	Thu May 31 13:09:04 2018 -0700
@@ -51,6 +51,7 @@
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.TTY;
 import org.graalvm.compiler.debug.TimerKey;
 import org.graalvm.compiler.graph.Edges.Type;
 import org.graalvm.compiler.graph.Graph.DuplicationReplacement;
@@ -125,11 +126,33 @@
     }
 
     public static <T> NodeClass<T> get(Class<T> clazz) {
-        NodeClass<T> result = getUnchecked(clazz);
-        if (result == null && clazz != NODE_CLASS) {
-            throw GraalError.shouldNotReachHere("TYPE field not initialized for class " + clazz.getTypeName());
+        int numTries = 0;
+        while (true) {
+            boolean shouldBeInitializedBefore = UnsafeAccess.UNSAFE.shouldBeInitialized(clazz);
+
+            NodeClass<T> result = getUnchecked(clazz);
+            if (result != null || clazz == NODE_CLASS) {
+                return result;
+            }
+
+            /*
+             * GR-9537: We observed a transient problem with TYPE fields being null. Retry a couple
+             * of times and print something to the log so that we can gather more diagnostic
+             * information without failing gates.
+             */
+            numTries++;
+            boolean shouldBeInitializedAfter = UnsafeAccess.UNSAFE.shouldBeInitialized(clazz);
+            String msg = "GR-9537 Reflective field access of TYPE field returned null. This is probably a bug in HotSpot class initialization. " +
+                            " clazz: " + clazz.getTypeName() + ", numTries: " + numTries +
+                            ", shouldBeInitializedBefore: " + shouldBeInitializedBefore + ", shouldBeInitializedAfter: " + shouldBeInitializedAfter;
+            if (numTries <= 100) {
+                TTY.println(msg);
+                UnsafeAccess.UNSAFE.ensureClassInitialized(clazz);
+            } else {
+                throw GraalError.shouldNotReachHere(msg);
+            }
+            return result;
         }
-        return result;
     }
 
     private static final Class<?> NODE_CLASS = Node.class;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java	Thu May 31 13:09:04 2018 -0700
@@ -29,6 +29,7 @@
 import static jdk.vm.ci.aarch64.AArch64.zr;
 import static jdk.vm.ci.code.ValueUtil.asRegister;
 import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry;
 
 import jdk.internal.vm.compiler.collections.EconomicSet;
@@ -41,6 +42,7 @@
 import org.graalvm.compiler.code.CompilationResult;
 import org.graalvm.compiler.core.aarch64.AArch64NodeMatchRules;
 import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
@@ -48,6 +50,7 @@
 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
 import org.graalvm.compiler.hotspot.HotSpotHostBackend;
 import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
 import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
 import org.graalvm.compiler.hotspot.stubs.Stub;
@@ -66,12 +69,15 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 
+import jdk.vm.ci.aarch64.AArch64Kind;
 import jdk.vm.ci.code.CallingConvention;
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.RegisterConfig;
 import jdk.vm.ci.code.StackSlot;
 import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
+import jdk.vm.ci.hotspot.HotSpotSentinelConstant;
 import jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig;
+import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.JavaType;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
@@ -269,7 +275,7 @@
             Register klass = r10;
             if (config.useCompressedClassPointers) {
                 masm.ldr(32, klass, klassAddress);
-                AArch64HotSpotMove.decodeKlassPointer(masm, klass, klass, providers.getRegisters().getHeapBaseRegister(), config.getKlassEncoding());
+                AArch64HotSpotMove.decodeKlassPointer(crb, masm, klass, klass, config.getKlassEncoding(), config);
             } else {
                 masm.ldr(64, klass, klassAddress);
             }
@@ -285,6 +291,23 @@
         crb.recordMark(config.MARKID_OSR_ENTRY);
         masm.bind(verifiedStub);
         crb.recordMark(config.MARKID_VERIFIED_ENTRY);
+
+        if (GeneratePIC.getValue(crb.getOptions())) {
+            // Check for method state
+            HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
+            if (!frameContext.isStub) {
+                crb.recordInlineDataInCodeWithNote(new HotSpotSentinelConstant(LIRKind.value(AArch64Kind.QWORD), JavaKind.Long), HotSpotConstantLoadAction.MAKE_NOT_ENTRANT);
+                try (ScratchRegister sc = masm.getScratchRegister()) {
+                    Register scratch = sc.getRegister();
+                    masm.addressOf(scratch);
+                    masm.ldr(64, scratch, AArch64Address.createBaseRegisterOnlyAddress(scratch));
+                    Label noCall = new Label();
+                    masm.cbz(64, scratch, noCall);
+                    AArch64Call.directJmp(crb, masm, getForeignCalls().lookupForeignCall(WRONG_METHOD_HANDLER));
+                    masm.bind(noCall);
+                }
+            }
+        }
     }
 
     private static void emitCodeBody(CompilationResultBuilder crb, LIR lir, AArch64MacroAssembler masm) {
@@ -299,8 +322,10 @@
      * @see "http://mail.openjdk.java.net/pipermail/aarch64-port-dev/2013-September/000273.html"
      */
     public static void emitInvalidatePlaceholder(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
-        crb.blockComment("[nop for method invalidation]");
-        masm.nop();
+        if (!GeneratePIC.getValue(crb.getOptions())) {
+            crb.blockComment("[nop for method invalidation]");
+            masm.nop();
+        }
     }
 
     private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler masm, FrameMap frameMap) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java	Thu May 31 13:09:04 2018 -0700
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Red Hat Inc. 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
@@ -25,6 +26,10 @@
 import static jdk.vm.ci.aarch64.AArch64.sp;
 import static jdk.vm.ci.common.InitTimer.timer;
 
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.core.aarch64.AArch64AddressLoweringByUse;
@@ -64,10 +69,6 @@
 import org.graalvm.compiler.word.WordTypes;
 
 import jdk.vm.ci.aarch64.AArch64;
-import jdk.vm.ci.code.Architecture;
-import jdk.vm.ci.code.RegisterArray;
-import jdk.vm.ci.code.RegisterConfig;
-import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.common.InitTimer;
 import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
 import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
@@ -77,6 +78,9 @@
 import jdk.vm.ci.meta.Value;
 import jdk.vm.ci.runtime.JVMCIBackend;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @ServiceProvider(HotSpotBackendFactory.class)
 public class AArch64HotSpotBackendFactory implements HotSpotBackendFactory {
 
@@ -200,12 +204,20 @@
     }
 
     protected static Value[] createNativeABICallerSaveRegisters(@SuppressWarnings("unused") GraalHotSpotVMConfig config, RegisterConfig regConfig) {
-        AArch64HotSpotRegisterConfig conf = (AArch64HotSpotRegisterConfig) regConfig;
-        RegisterArray callerSavedRegisters = conf.getCallerSaveRegisters();
-        int size = callerSavedRegisters.size();
-        Value[] nativeABICallerSaveRegisters = new Value[size];
-        for (int i = 0; i < size; i++) {
-            nativeABICallerSaveRegisters[i] = callerSavedRegisters.get(i).asValue();
+        List<Register> callerSave = new ArrayList<>(regConfig.getAllocatableRegisters().asList());
+        callerSave.remove(AArch64.r19);
+        callerSave.remove(AArch64.r20);
+        callerSave.remove(AArch64.r21);
+        callerSave.remove(AArch64.r22);
+        callerSave.remove(AArch64.r23);
+        callerSave.remove(AArch64.r24);
+        callerSave.remove(AArch64.r25);
+        callerSave.remove(AArch64.r26);
+        callerSave.remove(AArch64.r27);
+        callerSave.remove(AArch64.r28);
+        Value[] nativeABICallerSaveRegisters = new Value[callerSave.size()];
+        for (int i = 0; i < callerSave.size(); i++) {
+            nativeABICallerSaveRegisters[i] = callerSave.get(i).asValue();
         }
         return nativeABICallerSaveRegisters;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotCRuntimeCallEpilogueOp.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotCRuntimeCallEpilogueOp.java	Thu May 31 13:09:04 2018 -0700
@@ -24,6 +24,7 @@
 
 import static jdk.vm.ci.aarch64.AArch64.zr;
 
+import org.graalvm.compiler.asm.Label;
 import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
 import org.graalvm.compiler.lir.LIRInstructionClass;
 import org.graalvm.compiler.lir.Opcode;
@@ -37,20 +38,22 @@
     public static final LIRInstructionClass<AArch64HotSpotCRuntimeCallEpilogueOp> TYPE = LIRInstructionClass.create(AArch64HotSpotCRuntimeCallEpilogueOp.class);
 
     private final int threadLastJavaSpOffset;
-    private final int threadLastJavaFpOffset;
+    private final int threadLastJavaPcOffset;
     private final Register thread;
+    @SuppressWarnings("unused") private final Label label;
 
-    public AArch64HotSpotCRuntimeCallEpilogueOp(int threadLastJavaSpOffset, int threadLastJavaFpOffset, Register thread) {
+    public AArch64HotSpotCRuntimeCallEpilogueOp(int threadLastJavaSpOffset, int threadLastJavaPcOffset, Register thread, Label label) {
         super(TYPE);
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
-        this.threadLastJavaFpOffset = threadLastJavaFpOffset;
+        this.threadLastJavaPcOffset = threadLastJavaPcOffset;
         this.thread = thread;
+        this.label = label;
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
         // Reset last Java frame:
         masm.str(64, zr, masm.makeAddress(thread, threadLastJavaSpOffset, 8));
-        masm.str(64, zr, masm.makeAddress(thread, threadLastJavaFpOffset, 8));
+        masm.str(64, zr, masm.makeAddress(thread, threadLastJavaPcOffset, 8));
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotCRuntimeCallPrologueOp.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotCRuntimeCallPrologueOp.java	Thu May 31 13:09:04 2018 -0700
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Red Hat Inc. 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
@@ -25,7 +26,6 @@
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
 import static jdk.vm.ci.aarch64.AArch64.sp;
 import static jdk.vm.ci.code.ValueUtil.asRegister;
-import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp;
 
 import org.graalvm.compiler.asm.Label;
 import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
@@ -43,16 +43,14 @@
 
     private final int threadLastJavaSpOffset;
     private final int threadLastJavaPcOffset;
-    private final int threadLastJavaFpOffset;
     private final Register thread;
     @Temp({REG}) protected AllocatableValue scratch;
     private final Label label;
 
-    public AArch64HotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, Register thread, AllocatableValue scratch, Label label) {
+    public AArch64HotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, int threadLastJavaPcOffset, Register thread, AllocatableValue scratch, Label label) {
         super(TYPE);
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
         this.threadLastJavaPcOffset = threadLastJavaPcOffset;
-        this.threadLastJavaFpOffset = threadLastJavaFpOffset;
         this.thread = thread;
         this.scratch = scratch;
         this.label = label;
@@ -69,7 +67,5 @@
         // Get the current PC. Use a label to patch the return address.
         masm.adr(scratchRegister, label);
         masm.str(64, scratchRegister, masm.makeAddress(thread, threadLastJavaPcOffset, 8));
-
-        masm.str(64, fp, masm.makeAddress(thread, threadLastJavaFpOffset, 8));
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotConstantRetrievalOp.java	Thu May 31 13:09:04 2018 -0700
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2015, 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.aarch64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.LIRValueUtil;
+import org.graalvm.compiler.lir.ValueProcedure;
+import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public final class AArch64HotSpotConstantRetrievalOp extends AArch64LIRInstruction {
+    public static final LIRInstructionClass<AArch64HotSpotConstantRetrievalOp> TYPE = LIRInstructionClass.create(AArch64HotSpotConstantRetrievalOp.class);
+
+    @Def protected AllocatableValue result;
+    protected final Constant[] constants;
+    @Alive protected AllocatableValue[] constantDescriptions;
+    @Temp protected AllocatableValue[] gotSlotOffsetParameters;
+    @Temp protected AllocatableValue[] descriptionParameters;
+    @Temp protected Value[] callTemps;
+    @State protected LIRFrameState frameState;
+    private final ForeignCallLinkage callLinkage;
+    private final Object[] notes;
+
+    private class CollectTemporaries implements ValueProcedure {
+        ArrayList<Value> values = new ArrayList<>();
+
+        CollectTemporaries() {
+            forEachTemp(this);
+        }
+
+        public Value[] asArray() {
+            Value[] copy = new Value[values.size()];
+            return values.toArray(copy);
+        }
+
+        @Override
+        public Value doValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+            values.add(value);
+            return value;
+        }
+    }
+
+    public AArch64HotSpotConstantRetrievalOp(Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState, ForeignCallLinkage callLinkage, Object[] notes) {
+        super(TYPE);
+        this.constantDescriptions = constantDescriptions;
+        this.constants = constants;
+        this.frameState = frameState;
+        this.notes = notes;
+        assert constants.length == notes.length;
+
+        // call arguments
+        CallingConvention callingConvention = callLinkage.getOutgoingCallingConvention();
+        this.gotSlotOffsetParameters = new AllocatableValue[constants.length];
+        int argIndex = 0;
+        for (int i = 0; i < constants.length; i++, argIndex++) {
+            this.gotSlotOffsetParameters[i] = callingConvention.getArgument(argIndex);
+        }
+        this.descriptionParameters = new AllocatableValue[constantDescriptions.length];
+        for (int i = 0; i < constantDescriptions.length; i++, argIndex++) {
+            this.descriptionParameters[i] = callingConvention.getArgument(argIndex);
+        }
+        this.result = callingConvention.getReturn();
+
+        this.callLinkage = callLinkage;
+
+        // compute registers that are killed by the stub, but are not used as other temps.
+        this.callTemps = new Value[0];
+        this.callTemps = LIRValueUtil.subtractRegisters(callLinkage.getTemporaries(), new CollectTemporaries().asArray());
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        // metadata_adr
+        for (int i = 0; i < constants.length; i++) {
+            crb.recordInlineDataInCodeWithNote(constants[i], notes[i]);
+            masm.addressOf(asRegister(gotSlotOffsetParameters[i]));
+        }
+
+        for (int i = 0; i < constantDescriptions.length; i++) {
+            masm.mov(64, asRegister(descriptionParameters[i]), asRegister(constantDescriptions[i]));
+        }
+
+        final int before = masm.position();
+        masm.bl(before);
+        final int after = masm.position();
+        crb.recordDirectCall(before, after, callLinkage, frameState);
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java	Thu May 31 13:09:04 2018 -0700
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Red Hat Inc. 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
@@ -23,11 +24,21 @@
 
 package org.graalvm.compiler.hotspot.aarch64;
 
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE;
+import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE;
+import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.INITIALIZE;
+import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS;
 import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
 
 import java.util.function.Function;
 
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
 import org.graalvm.compiler.asm.Label;
 import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode;
 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag;
@@ -38,6 +49,7 @@
 import org.graalvm.compiler.core.common.CompressEncoding;
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
 import org.graalvm.compiler.core.common.spi.LIRKindTool;
 import org.graalvm.compiler.debug.GraalError;
@@ -48,6 +60,7 @@
 import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
 import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
 import org.graalvm.compiler.hotspot.HotSpotLockStack;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
 import org.graalvm.compiler.hotspot.stubs.Stub;
@@ -66,6 +79,9 @@
 import org.graalvm.compiler.lir.aarch64.AArch64Move;
 import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp;
 import org.graalvm.compiler.lir.aarch64.AArch64PrefetchOp;
+import org.graalvm.compiler.lir.aarch64.AArch64SaveRegistersOp;
+import org.graalvm.compiler.lir.aarch64.AArch64RestoreRegistersOp;
+
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
 
 import jdk.vm.ci.aarch64.AArch64;
@@ -84,6 +100,7 @@
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.PlatformKind;
 import jdk.vm.ci.meta.Value;
+import org.graalvm.compiler.options.OptionValues;
 
 /**
  * LIR generator specialized for AArch64 HotSpot.
@@ -114,7 +131,7 @@
         return getResult().getStub() != null;
     }
 
-    @SuppressWarnings("unused") private LIRFrameState currentRuntimeCallInfo;
+    private LIRFrameState currentRuntimeCallInfo;
 
     @Override
     protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
@@ -145,8 +162,45 @@
         append(new AArch64CCall(nativeCallingConvention.getReturn(), ptr, argLocations));
     }
 
-    public SaveRegistersOp emitSaveAllRegisters() {
-        throw GraalError.unimplemented();
+    /**
+     * @param savedRegisters the registers saved by this operation which may be subject to pruning
+     * @param savedRegisterLocations the slots to which the registers are saved
+     * @param supportsRemove determines if registers can be pruned
+     */
+    protected AArch64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) {
+        AArch64SaveRegistersOp save = new AArch64SaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove);
+        append(save);
+        return save;
+    }
+
+    /**
+     * Allocate a stack slot for saving a register.
+     */
+    protected VirtualStackSlot allocateSaveRegisterLocation(Register register) {
+        PlatformKind kind = target().arch.getLargestStorableKind(register.getRegisterCategory());
+        if (kind.getVectorLength() > 1) {
+            // we don't use vector registers, so there is no need to save them
+            kind = AArch64Kind.QWORD;
+        }
+        return getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(kind));
+    }
+
+    /**
+     * Adds a node to the graph that saves all allocatable registers to the stack.
+     *
+     * @param supportsRemove determines if registers can be pruned
+     * @return the register save node
+     */
+    private AArch64SaveRegistersOp emitSaveAllRegisters(Register[] savedRegisters, boolean supportsRemove) {
+        AllocatableValue[] savedRegisterLocations = new AllocatableValue[savedRegisters.length];
+        for (int i = 0; i < savedRegisters.length; i++) {
+            savedRegisterLocations[i] = allocateSaveRegisterLocation(savedRegisters[i]);
+        }
+        return emitSaveRegisters(savedRegisters, savedRegisterLocations, supportsRemove);
+    }
+
+    protected void emitRestoreRegisters(AArch64SaveRegistersOp save) {
+        append(new AArch64RestoreRegistersOp(save.getSlots().clone(), save));
     }
 
     @Override
@@ -199,6 +253,7 @@
     @Override
     public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
         LIRKind inputKind = pointer.getValueKind(LIRKind.class);
+        LIRKindTool lirKindTool = getLIRKindTool();
         assert inputKind.getPlatformKind() == AArch64Kind.QWORD;
         if (inputKind.isReference(0)) {
             // oop
@@ -209,8 +264,16 @@
             // metaspace pointer
             Variable result = newVariable(LIRKind.value(AArch64Kind.DWORD));
             AllocatableValue base = Value.ILLEGAL;
-            if (encoding.hasBase()) {
-                base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
+            OptionValues options = getResult().getLIR().getOptions();
+            if (encoding.hasBase() || GeneratePIC.getValue(options)) {
+                if (GeneratePIC.getValue(options)) {
+                    Variable baseAddress = newVariable(lirKindTool.getWordKind());
+                    AArch64HotSpotMove.BaseMove move = new AArch64HotSpotMove.BaseMove(baseAddress, config);
+                    append(move);
+                    base = baseAddress;
+                } else {
+                    base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
+                }
             }
             append(new AArch64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
             return result;
@@ -230,8 +293,16 @@
             // metaspace pointer
             Variable result = newVariable(LIRKind.value(AArch64Kind.QWORD));
             AllocatableValue base = Value.ILLEGAL;
-            if (encoding.hasBase()) {
-                base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
+            OptionValues options = getResult().getLIR().getOptions();
+            if (encoding.hasBase() || GeneratePIC.getValue(options)) {
+                if (GeneratePIC.getValue(options)) {
+                    Variable baseAddress = newVariable(LIRKind.value(AArch64Kind.QWORD));
+                    AArch64HotSpotMove.BaseMove move = new AArch64HotSpotMove.BaseMove(baseAddress, config);
+                    append(move);
+                    base = baseAddress;
+                } else {
+                    base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
+                }
             }
             append(new AArch64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
             return result;
@@ -270,6 +341,17 @@
     @Override
     public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
         HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage;
+        boolean destroysRegisters = hotspotLinkage.destroysRegisters();
+
+        AArch64SaveRegistersOp save = null;
+        Stub stub = getStub();
+        if (destroysRegisters) {
+            if (stub != null && stub.preservesRegisters()) {
+                Register[] savedRegisters = getRegisterConfig().getAllocatableRegisters().toArray();
+                save = emitSaveAllRegisters(savedRegisters, true);
+            }
+        }
+
         Variable result;
         LIRFrameState debugInfo = null;
         if (hotspotLinkage.needsDebugInfo()) {
@@ -277,7 +359,7 @@
             assert debugInfo != null || getStub() != null;
         }
 
-        if (linkage.destroysRegisters() || hotspotLinkage.needsJavaFrameAnchor()) {
+        if (destroysRegisters || hotspotLinkage.needsJavaFrameAnchor()) {
             HotSpotRegistersProvider registers = getProviders().getRegisters();
             Register thread = registers.getThreadRegister();
             Variable scratch = newVariable(LIRKind.value(target().arch.getWordKind()));
@@ -285,9 +367,9 @@
             // We need a label for the return address.
             label = new Label();
 
-            append(new AArch64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), thread, scratch, label));
+            append(new AArch64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), thread, scratch, label));
             result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
-            append(new AArch64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread));
+            append(new AArch64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), thread, label));
 
             // Clear it out so it's not being reused later.
             label = null;
@@ -295,6 +377,21 @@
             result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
         }
 
+        if (destroysRegisters) {
+            if (stub != null) {
+                if (stub.preservesRegisters()) {
+                    HotSpotLIRGenerationResult generationResult = getResult();
+                    LIRFrameState key = currentRuntimeCallInfo;
+                    if (key == null) {
+                        key = LIRFrameState.NO_STATE;
+                    }
+                    assert !generationResult.getCalleeSaveInfo().containsKey(key);
+                    generationResult.getCalleeSaveInfo().put(key, save);
+                    emitRestoreRegisters(save);
+                }
+            }
+        }
+
         return result;
     }
 
@@ -336,6 +433,65 @@
     }
 
     @Override
+    public Value emitLoadObjectAddress(Constant constant) {
+        HotSpotObjectConstant objectConstant = (HotSpotObjectConstant) constant;
+        LIRKind kind = objectConstant.isCompressed() ? getLIRKindTool().getNarrowOopKind() : getLIRKindTool().getObjectKind();
+        Variable result = newVariable(kind);
+        append(new AArch64HotSpotLoadAddressOp(result, constant, HotSpotConstantLoadAction.RESOLVE));
+        return result;
+    }
+
+    @Override
+    public Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) {
+        HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) constant;
+        LIRKind kind = metaspaceConstant.isCompressed() ? getLIRKindTool().getNarrowPointerKind() : getLIRKindTool().getWordKind();
+        Variable result = newVariable(kind);
+        append(new AArch64HotSpotLoadAddressOp(result, constant, action));
+        return result;
+    }
+
+    private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, Object[] notes, Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(foreignCall);
+        append(new AArch64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
+        AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
+        return emitMove(result);
+    }
+
+    private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, AllocatableValue[] constantDescriptions, LIRFrameState frameState) {
+        Constant[] constants = new Constant[]{constant};
+        Object[] notes = new Object[]{action};
+        return emitConstantRetrieval(foreignCall, notes, constants, constantDescriptions, frameState);
+    }
+
+    @Override
+    public Value emitResolveDynamicInvoke(Constant appendix, LIRFrameState frameState) {
+        AllocatableValue[] constantDescriptions = new AllocatableValue[0];
+        return emitConstantRetrieval(RESOLVE_DYNAMIC_INVOKE, INITIALIZE, appendix, constantDescriptions, frameState);
+    }
+
+    @Override
+    public Value emitLoadConfigValue(int markId, LIRKind kind) {
+        Variable result = newVariable(kind);
+        append(new AArch64HotSpotLoadConfigValueOp(markId, result));
+        return result;
+    }
+
+    private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, Value constantDescription, LIRFrameState frameState) {
+        AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
+        return emitConstantRetrieval(foreignCall, action, constant, constantDescriptions, frameState);
+    }
+
+    @Override
+    public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
+        return emitConstantRetrieval(RESOLVE_STRING_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState);
+    }
+
+    @Override
+    public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
+        return emitConstantRetrieval(RESOLVE_KLASS_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState);
+    }
+
+    @Override
     public void emitReturn(JavaKind kind, Value input) {
         AllocatableValue operand = Value.ILLEGAL;
         if (input != null) {
@@ -346,6 +502,17 @@
         append(new AArch64HotSpotReturnOp(operand, getStub() != null, config, thread));
     }
 
+    @Override
+    public Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
+        return emitConstantRetrieval(INITIALIZE_KLASS_BY_SYMBOL, INITIALIZE, constant, constantDescription, frameState);
+    }
+
+    @Override
+    public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) {
+        AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)};
+        return emitConstantRetrieval(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, LOAD_COUNTERS, method, constantDescriptions, frameState);
+    }
+
     /**
      * Gets the {@link Stub} this generator is generating code for or {@code null} if a stub is not
      * being generated.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoadAddressOp.java	Thu May 31 13:09:04 2018 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015, 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.aarch64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public final class AArch64HotSpotLoadAddressOp extends AArch64LIRInstruction {
+
+    public static final LIRInstructionClass<AArch64HotSpotLoadAddressOp> TYPE = LIRInstructionClass.create(AArch64HotSpotLoadAddressOp.class);
+
+    @Def({OperandFlag.REG}) protected AllocatableValue result;
+    private final Constant constant;
+    private final Object note;
+
+    public AArch64HotSpotLoadAddressOp(AllocatableValue result, Constant constant, Object note) {
+        super(TYPE);
+        this.result = result;
+        this.constant = constant;
+        this.note = note;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        crb.recordInlineDataInCodeWithNote(constant, note);
+        AArch64Kind kind = (AArch64Kind) result.getPlatformKind();
+        int size = 0;
+        switch (kind) {
+            case DWORD:
+                size = 32;
+                break;
+            case QWORD:
+                size = 64;
+                break;
+            default:
+                throw GraalError.shouldNotReachHere("unexpected kind: " + kind);
+        }
+        if (crb.compilationResult.isImmutablePIC()) {
+            Register dst = asRegister(result);
+            masm.addressOf(dst);
+            masm.ldr(size, dst, AArch64Address.createBaseRegisterOnlyAddress(dst));
+        } else {
+            masm.ldr(size, asRegister(result), masm.getPlaceholder(-1));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoadConfigValueOp.java	Thu May 31 13:09:04 2018 -0700
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Red Hat Inc. 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.aarch64;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public final class AArch64HotSpotLoadConfigValueOp extends AArch64LIRInstruction {
+
+    public static final LIRInstructionClass<AArch64HotSpotLoadConfigValueOp> TYPE = LIRInstructionClass.create(AArch64HotSpotLoadConfigValueOp.class);
+
+    @Def({OperandFlag.REG}) protected AllocatableValue result;
+    private final int markId;
+
+    public AArch64HotSpotLoadConfigValueOp(int markId, AllocatableValue result) {
+        super(TYPE);
+        this.result = result;
+        this.markId = markId;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        if (GeneratePIC.getValue(crb.getOptions())) {
+            AArch64Kind kind = (AArch64Kind) result.getPlatformKind();
+            Register reg = asRegister(result);
+            masm.adrp(reg);
+            masm.add(64, reg, reg, 1);
+            switch (kind) {
+                case BYTE:
+                    masm.ldrs(8, 32, reg, AArch64Address.createBaseRegisterOnlyAddress(reg));
+                    break;
+                case WORD:
+                    masm.ldrs(16, 32, reg, AArch64Address.createBaseRegisterOnlyAddress(reg));
+                    break;
+                case DWORD:
+                    masm.ldr(32, reg, AArch64Address.createBaseRegisterOnlyAddress(reg));
+                    break;
+                case QWORD:
+                    masm.ldr(64, reg, AArch64Address.createBaseRegisterOnlyAddress(reg));
+                    break;
+                default:
+                    throw GraalError.unimplemented();
+            }
+            masm.nop();
+        } else {
+            throw GraalError.unimplemented();
+        }
+        crb.recordMark(markId);
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoweringProvider.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoweringProvider.java	Thu May 31 13:09:04 2018 -0700
@@ -26,13 +26,13 @@
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
 import org.graalvm.compiler.debug.DebugHandlersFactory;
 import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
-import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
-import org.graalvm.compiler.nodes.calc.FixedBinaryNode;
 import org.graalvm.compiler.nodes.calc.FloatConvertNode;
+import org.graalvm.compiler.nodes.calc.IntegerDivRemNode;
 import org.graalvm.compiler.nodes.calc.RemNode;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.options.OptionValues;
@@ -62,8 +62,8 @@
 
     @Override
     public void lower(Node n, LoweringTool tool) {
-        if (n instanceof FixedBinaryNode) {
-            integerArithmeticSnippets.lower((FixedBinaryNode) n, tool);
+        if (n instanceof IntegerDivRemNode) {
+            integerArithmeticSnippets.lower((IntegerDivRemNode) n, tool);
         } else if (n instanceof RemNode) {
             floatArithmeticSnippets.lower((RemNode) n, tool);
         } else if (n instanceof FloatConvertNode) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java	Thu May 31 13:09:04 2018 -0700
@@ -25,15 +25,19 @@
 import static jdk.vm.ci.aarch64.AArch64.zr;
 import static jdk.vm.ci.code.ValueUtil.asRegister;
 import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
 
 import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
 import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
 import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
 import org.graalvm.compiler.core.common.CompressEncoding;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRInstruction;
 import org.graalvm.compiler.lir.LIRInstructionClass;
 import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
 import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction;
@@ -80,6 +84,32 @@
         }
     }
 
+    public static final class BaseMove extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<BaseMove> TYPE = LIRInstructionClass.create(BaseMove.class);
+
+        @LIRInstruction.Def({REG, HINT}) protected AllocatableValue result;
+        private final GraalHotSpotVMConfig config;
+
+        public BaseMove(AllocatableValue result, GraalHotSpotVMConfig config) {
+            super(TYPE);
+            this.result = result;
+            this.config = config;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            try (AArch64MacroAssembler.ScratchRegister sc = masm.getScratchRegister()) {
+                Register scratch = sc.getRegister();
+                masm.adrp(scratch);
+                masm.add(64, scratch, scratch, 1);
+                masm.ldr(64, asRegister(result), AArch64Address.createBaseRegisterOnlyAddress(scratch));
+                masm.nop();
+                crb.recordMark(config.MARKID_NARROW_KLASS_BASE_ADDRESS);
+            }
+        }
+
+    }
+
     /**
      * Compresses a 8-byte pointer as a 4-byte int.
      */
@@ -117,7 +147,7 @@
             } else if (nonNull) {
                 masm.sub(64, resultRegister, ptr, base);
                 if (encoding.hasShift()) {
-                    masm.shl(64, resultRegister, resultRegister, encoding.getShift());
+                    masm.lshr(64, resultRegister, resultRegister, encoding.getShift());
                 }
             } else {
                 // if ptr is null it still has to be null after compression
@@ -192,11 +222,21 @@
     // masm.cmov(64, result, result, ARMv8.zr, ARMv8Assembler.ConditionFlag.NE);
     // }
 
-    public static void decodeKlassPointer(AArch64MacroAssembler masm, Register result, Register ptr, Register klassBase, CompressEncoding encoding) {
-        // result = klassBase + ptr << shift
-        if (encoding.hasShift() || encoding.hasBase()) {
-            masm.add(64, result, klassBase, ptr, AArch64Assembler.ExtendType.UXTX, encoding.getShift());
+    public static void decodeKlassPointer(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register result, Register ptr, CompressEncoding encoding, GraalHotSpotVMConfig config) {
+        try (AArch64MacroAssembler.ScratchRegister sc = masm.getScratchRegister()) {
+            Register scratch = sc.getRegister();
+            boolean pic = GeneratePIC.getValue(crb.getOptions());
+            if (pic || encoding.hasBase() || encoding.getShift() != 0) {
+                if (pic) {
+                    masm.addressOf(scratch);
+                    masm.ldr(64, scratch, AArch64Address.createBaseRegisterOnlyAddress(scratch));
+                    masm.add(64, result, scratch, ptr, AArch64Assembler.ExtendType.UXTX, encoding.getShift());
+                    crb.recordMark(config.MARKID_NARROW_KLASS_BASE_ADDRESS);
+                } else {
+                    masm.mov(scratch, encoding.getBase());
+                    masm.add(64, result, scratch, ptr, AArch64Assembler.ExtendType.UXTX, encoding.getShift());
+                }
+            }
         }
     }
-
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Thu May 31 13:09:04 2018 -0700
@@ -236,7 +236,7 @@
     }
 
     @Override
-    public Variable emitLogicCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+    public Variable emitLogicCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
         ValueKind<?> kind = newValue.getValueKind();
         assert kind.equals(expectedValue.getValueKind());
         SPARCKind memKind = (SPARCKind) kind.getPlatformKind();
@@ -246,7 +246,7 @@
     }
 
     @Override
-    public Variable emitValueCompareAndSwap(Value address, Value expectedValue, Value newValue) {
+    public Variable emitValueCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue) {
         ValueKind<?> kind = newValue.getValueKind();
         assert kind.equals(expectedValue.getValueKind());
         Variable result = newVariable(newValue.getValueKind());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java	Thu May 31 13:09:04 2018 -0700
@@ -422,6 +422,12 @@
                             "jdk/internal/util/ArraysSupport.vectorizedMismatch(Ljava/lang/Object;JLjava/lang/Object;JII)I");
         }
 
+        if (isJDK11OrHigher()) {
+            // Relevant for Java flight recorder
+            add(TO_BE_INVESTIGATED,
+                            "jdk/jfr/internal/JVM.getEventWriter()Ljava/lang/Object;");
+        }
+
         if (!getHostArchitectureName().equals("amd64")) {
             // Can we implement these on non-AMD64 platforms? C2 seems to.
             add(TO_BE_INVESTIGATED,
@@ -549,6 +555,10 @@
         return GraalServices.JAVA_SPECIFICATION_VERSION >= 10;
     }
 
+    private static boolean isJDK11OrHigher() {
+        return GraalServices.JAVA_SPECIFICATION_VERSION >= 11;
+    }
+
     private static String getHostArchitectureName() {
         String arch = System.getProperty("os.arch");
         if (arch.equals("x86_64")) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java	Thu May 31 13:09:04 2018 -0700
@@ -223,25 +223,19 @@
             Assert.assertTrue(zip.toString(), zip.exists());
             Assert.assertTrue(zip + " not in " + dumpPathEntries, dumpPathEntries.contains(zip.getName()));
             try {
-                int bgv = 0;
-                int cfg = 0;
+                int bgvOrCfgFiles = 0;
                 ZipFile dd = new ZipFile(diagnosticOutputZip);
                 List<String> entries = new ArrayList<>();
                 for (Enumeration<? extends ZipEntry> e = dd.entries(); e.hasMoreElements();) {
                     ZipEntry ze = e.nextElement();
                     String name = ze.getName();
                     entries.add(name);
-                    if (name.endsWith(".bgv")) {
-                        bgv++;
-                    } else if (name.endsWith(".cfg")) {
-                        cfg++;
+                    if (name.endsWith(".bgv") || name.endsWith(".cfg")) {
+                        bgvOrCfgFiles++;
                     }
                 }
-                if (bgv == 0) {
-                    Assert.fail(String.format("Expected at least one .bgv file in %s: %s%n%s", diagnosticOutputZip, entries, proc));
-                }
-                if (cfg == 0) {
-                    Assert.fail(String.format("Expected at least one .cfg file in %s: %s%n%s", diagnosticOutputZip, entries, proc));
+                if (bgvOrCfgFiles == 0) {
+                    Assert.fail(String.format("Expected at least one .bgv or .cfg file in %s: %s%n%s", diagnosticOutputZip, entries, proc));
                 }
             } finally {
                 zip.delete();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/aaa	Thu May 31 06:15:17 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 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.test;
-
-import org.graalvm.compiler.core.test.GraalCompilerTest;
-import org.graalvm.compiler.hotspot.meta.HotSpotClassInitializationPlugin;
-import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
-import org.graalvm.compiler.java.GraphBuilderPhase;
-import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import org.graalvm.compiler.phases.PhaseSuite;
-import org.graalvm.compiler.phases.tiers.HighTierContext;
-import org.junit.Assert;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.Test;
-
-import jdk.vm.ci.meta.ConstantPool;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-
-public class HotSpotLazyInitializationTest extends GraalCompilerTest {
-
-    HotSpotClassInitializationPlugin classInitPlugin = new HotSpotClassInitializationPlugin();
-
-    @Override
-    protected Plugins getDefaultGraphBuilderPlugins() {
-        Plugins plugins = super.getDefaultGraphBuilderPlugins();
-        plugins.setClassInitializationPlugin(classInitPlugin);
-        return plugins;
-    }
-
-    static boolean X_initialized = false;
-
-    static class X {
-        static {
-            X_initialized = true;
-        }
-        static void foo() {}
-    }
-
-    public static void invokeStatic() {
-        X.foo();
-    }
-
-    private void test(String name) {
-        ResolvedJavaMethod method = getResolvedJavaMethod(name);
-        Assume.assumeTrue("skipping for old JVMCI", classInitPlugin.supportsLazyInitialization(method.getConstantPool()));
-        StructuredGraph graph = parseEager(method, AllowAssumptions.NO);
-        Assert.assertFalse(X_initialized);
-    }
-
-    @Test
-    public void test1() {
-        test("invokeStatic");
-    }
-
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java	Thu May 31 13:09:04 2018 -0700
@@ -101,6 +101,13 @@
         return new DefaultBackendMap(name);
     }
 
+    /**
+     * Returns a name that should uniquely identify this compiler configuration.
+     */
+    public final String getName() {
+        return name;
+    }
+
     public interface BackendMap {
         HotSpotBackendFactory getBackendFactory(Architecture arch);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java	Thu May 31 13:09:04 2018 -0700
@@ -80,6 +80,9 @@
     public final boolean foldStableValues = getFlag("FoldStableValues", Boolean.class);
     public final int maxVectorSize = getFlag("MaxVectorSize", Integer.class);
 
+    public final boolean verifyBeforeGC = getFlag("VerifyBeforeGC", Boolean.class);
+    public final boolean verifyAfterGC = getFlag("VerifyAfterGC", Boolean.class);
+
     public final boolean useTLAB = getFlag("UseTLAB", Boolean.class);
     public final boolean useBiasedLocking = getFlag("UseBiasedLocking", Boolean.class);
     public final boolean usePopCountInstruction = getFlag("UsePopCountInstruction", Boolean.class);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigVersioned.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigVersioned.java	Thu May 31 13:09:04 2018 -0700
@@ -40,12 +40,12 @@
         super(store);
     }
 
+    // JSK-8132287
+    final boolean inlineNotify = !getFlag("SyncKnobs", String.class, "").contains("InlineNotify=0");
+
     // JDK-8073583
     final boolean useCRC32CIntrinsics = getFlag("UseCRC32CIntrinsics", Boolean.class);
 
-    // JDK-8075171
-    final boolean inlineNotify = getFlag("InlineNotify", Boolean.class, true);
-
     // JDK-8046936
     final int javaThreadReservedStackActivationOffset = getFieldOffset("JavaThread::_reserved_stack_activation", Integer.class, "address");
     final int methodFlagsOffset = getFieldOffset("Method::_flags", Integer.class, "u2");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java	Thu May 31 13:09:04 2018 -0700
@@ -185,7 +185,7 @@
         result.setEntryBCI(entryBCI);
         boolean shouldDebugNonSafepoints = providers.getCodeCache().shouldDebugNonSafepoints();
         PhaseSuite<HighTierContext> graphBuilderSuite = configGraphBuilderSuite(providers.getSuites().getDefaultGraphBuilderSuite(), shouldDebugNonSafepoints, isOSR);
-        GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, result, crbf);
+        GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, result, crbf, true);
 
         if (!isOSR && useProfilingInfo) {
             ProfilingInfo profile = profilingInfo;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java	Thu May 31 13:09:04 2018 -0700
@@ -105,6 +105,7 @@
     }
 
     private final String runtimeName;
+    private final String compilerConfigurationName;
     private final HotSpotBackend hostBackend;
     private final GlobalMetrics metricValues = new GlobalMetrics();
     private final List<SnippetCounter.Group> snippetCounterGroups;
@@ -155,6 +156,7 @@
         compilationProblemsPerAction = new EnumMap<>(ExceptionAction.class);
         snippetCounterGroups = GraalOptions.SnippetCounters.getValue(options) ? new ArrayList<>() : null;
         CompilerConfiguration compilerConfiguration = compilerConfigurationFactory.createCompilerConfiguration();
+        compilerConfigurationName = compilerConfigurationFactory.getName();
 
         compiler = new HotSpotGraalCompiler(jvmciRuntime, this, options);
         management = GraalServices.loadSingle(HotSpotGraalManagementRegistration.class, false);
@@ -296,6 +298,11 @@
         return backends.get(arch);
     }
 
+    @Override
+    public String getCompilerConfigurationName() {
+        return compilerConfigurationName;
+    }
+
     private long runtimeStartTime;
     private boolean shutdown;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java	Thu May 31 13:09:04 2018 -0700
@@ -94,4 +94,10 @@
      * Gets the map used to count compilation problems at each {@link ExceptionAction} level.
      */
     Map<ExceptionAction, Integer> getCompilationProblemsPerAction();
+
+    /**
+     * Returns the unique compiler configuration name that is in use. Useful for users to find out
+     * which configuration is in use.
+     */
+    String getCompilerConfigurationName();
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java	Thu May 31 06:15:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java	Thu May 31 13:09:04 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -39,6 +39,7 @@
 import static jdk.internal.vm.compiler.word.LocationIdentity.any;
 
 import java.lang.ref.Reference;
+import java.util.EnumMap;
 
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.core.common.CompressEncoding;
@@ -49,6 +50,7 @@
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugHandlersFactory;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Node;
@@ -91,8 +93,8 @@
 import org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets;
 import org.graalvm.compiler.hotspot.replacements.aot.ResolveConstantSnippets;
 import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyNode;
+import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopySnippets;
 import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyWithSlowPathNode;
-import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopySnippets;
 import org.graalvm.compiler.hotspot.replacements.profiling.ProfileSnippets;
 import org.graalvm.compiler.hotspot.word.KlassPointer;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
@@ -118,6 +120,7 @@
 import org.graalvm.compiler.nodes.debug.StringToBytesNode;
 import org.graalvm.compiler.nodes.debug.VerifyHeapNode;
 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;
@@ -207,7 +210,7 @@
         instanceofSnippets = new InstanceOfSnippets.Templates(options, factories, runtime, providers, target);
         newObjectSnippets = new NewObjectSnippets.Templates(options, factories, runtime, providers, target, config);
         monitorSnippets = new MonitorSnippets.Templates(options, factories, runtime, providers, target, config.useFastLocking);
-        writeBarrierSnippets = new WriteBarrierSnippets.Templates(options, factories, runtime, providers, target, config.useCompressedOops ? config.getOopEncoding() : null);
+        writeBarrierSnippets = new