Merge
authorsspitsyn
Thu, 24 Aug 2017 21:06:33 +0000
changeset 46978 70d1bcee7340
parent 46977 9e8d0f0de00e (current diff)
parent 46975 59d4586da7bc (diff)
child 46979 054736045ae7
Merge
hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MiscUtils.java
hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/Timer.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/TestJMH.java
--- a/hotspot/.hgtags	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/.hgtags	Thu Aug 24 21:06:33 2017 +0000
@@ -604,3 +604,4 @@
 33b74e13c1457f36041addb8b850831f81ca6e9f jdk-10+19
 d7baadc223e790c08bc69bf7e553bce65b4e7e40 jdk-9+180
 4a443796f6f57842d6a0434ac27ca3d1033ccc20 jdk-9+181
+e93ed1a092409351c90b3a76d80b9aa8b44d5e6a jdk-10+20
--- a/hotspot/src/cpu/aarch64/vm/aarch64.ad	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad	Thu Aug 24 21:06:33 2017 +0000
@@ -3806,15 +3806,24 @@
       // Any use that can't embed the address computation?
       for (DUIterator_Fast imax, i = addp->fast_outs(imax); i < imax; i++) {
         Node* u = addp->fast_out(i);
-        if (!u->is_Mem() || u->is_LoadVector() || u->is_StoreVector() || u->Opcode() == Op_StoreCM) {
+        if (!u->is_Mem()) {
+          return;
+        }
+        if (u->is_LoadVector() || u->is_StoreVector() || u->Opcode() == Op_StoreCM) {
           return;
         }
+        if (addp2->in(AddPNode::Offset)->Opcode() != Op_ConvI2L) {
+          int scale = 1 << addp2->in(AddPNode::Offset)->in(2)->get_int();
+          if (VM_Version::expensive_load(u->as_Mem()->memory_size(), scale)) {
+            return;
+          }
+        }
       }
-      
+
       Node* off = addp->in(AddPNode::Offset);
       Node* addr2 = addp2->in(AddPNode::Address);
       Node* base = addp->in(AddPNode::Base);
-      
+
       Node* new_addr = NULL;
       // Check whether the graph already has the new AddP we need
       // before we create one (no GVN available here).
@@ -3828,7 +3837,7 @@
           break;
         }
       }
-      
+
       if (new_addr == NULL) {
         new_addr = new AddPNode(base, addr2, off);
       }
@@ -4415,6 +4424,22 @@
                /*weak*/ false, noreg);
   %}
 
+  enc_class aarch64_enc_cmpxchgs(memory mem, iRegINoSp oldval, iRegINoSp newval) %{
+    MacroAssembler _masm(&cbuf);
+    guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding");
+    __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register,
+               Assembler::halfword, /*acquire*/ false, /*release*/ true,
+               /*weak*/ false, noreg);
+  %}
+
+  enc_class aarch64_enc_cmpxchgb(memory mem, iRegINoSp oldval, iRegINoSp newval) %{
+    MacroAssembler _masm(&cbuf);
+    guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding");
+    __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register,
+               Assembler::byte, /*acquire*/ false, /*release*/ true,
+               /*weak*/ false, noreg);
+  %}  
+    
 
   // The only difference between aarch64_enc_cmpxchg and
   // aarch64_enc_cmpxchg_acq is that we use load-acquire in the
@@ -9637,6 +9662,42 @@
 // XXX No flag versions for CompareAndSwap{I,L,P,N} because matcher
 // can't match them
 
+instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{
+
+  match(Set res (CompareAndSwapB mem (Binary oldval newval)));
+  ins_cost(2 * VOLATILE_REF_COST);
+
+  effect(KILL cr);
+
+  format %{
+    "cmpxchgb $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval"
+    "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)"
+  %}
+
+  ins_encode(aarch64_enc_cmpxchgb(mem, oldval, newval),
+            aarch64_enc_cset_eq(res));
+
+  ins_pipe(pipe_slow);
+%}
+
+instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{
+
+  match(Set res (CompareAndSwapS mem (Binary oldval newval)));
+  ins_cost(2 * VOLATILE_REF_COST);
+
+  effect(KILL cr);
+
+  format %{
+    "cmpxchgs $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval"
+    "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)"
+  %}
+
+  ins_encode(aarch64_enc_cmpxchgs(mem, oldval, newval),
+            aarch64_enc_cset_eq(res));
+
+  ins_pipe(pipe_slow);
+%}
+
 instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{
 
   match(Set res (CompareAndSwapI mem (Binary oldval newval)));
--- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -272,8 +272,7 @@
   // load pointer for resolved_references[] objArray
   ldr(result, Address(result, ConstantPool::cache_offset_in_bytes()));
   ldr(result, Address(result, ConstantPoolCache::resolved_references_offset_in_bytes()));
-  // JNIHandles::resolve(obj);
-  ldr(result, Address(result, 0));
+  resolve_oop_handle(result);
   // Add in the index
   add(result, result, tmp);
   load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -3279,6 +3279,12 @@
   }
 }
 
+// ((OopHandle)result).resolve();
+void MacroAssembler::resolve_oop_handle(Register result) {
+  // OopHandle::resolve is an indirection.
+  ldr(result, Address(result, 0));
+}
+
 void MacroAssembler::load_mirror(Register dst, Register method) {
   const int mirror_offset = in_bytes(Klass::java_mirror_offset());
   ldr(dst, Address(rmethod, Method::const_offset()));
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -790,6 +790,7 @@
   void store_klass(Register dst, Register src);
   void cmp_klass(Register oop, Register trial_klass, Register tmp);
 
+  void resolve_oop_handle(Register result);
   void load_mirror(Register dst, Register method);
 
   void load_heap_oop(Register dst, Address src);
--- a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -56,6 +56,17 @@
   static void assert_is_initialized() {
   }
 
+  static bool expensive_load(int ld_size, int scale) {
+    if (cpu_family() == CPU_ARM) {
+      // Half-word load with index shift by 1 (aka scale is 2) has
+      // extra cycle latency, e.g. ldrsh w0, [x1,w2,sxtw #1].
+      if (ld_size == 2 && scale == 2) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   enum Family {
     CPU_ARM       = 'A',
     CPU_BROADCOM  = 'B',
--- a/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -300,8 +300,7 @@
   // load pointer for resolved_references[] objArray
   ldr(cache, Address(result, ConstantPool::cache_offset_in_bytes()));
   ldr(cache, Address(result, ConstantPoolCache::resolved_references_offset_in_bytes()));
-  // JNIHandles::resolve(result)
-  ldr(cache, Address(cache, 0));
+  resolve_oop_handle(cache);
   // Add in the index
   // convert from field index to resolved_references() index and from
   // word index to byte offset. Since this is a java object, it can be compressed
--- a/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -2887,6 +2887,11 @@
   return offset();
 }
 
+// ((OopHandle)result).resolve();
+void MacroAssembler::resolve_oop_handle(Register result) {
+  // OopHandle::resolve is an indirection.
+  ldr(result, Address(result, 0));
+}
 
 void MacroAssembler::load_mirror(Register mirror, Register method, Register tmp) {
   const int mirror_offset = in_bytes(Klass::java_mirror_offset());
@@ -2896,6 +2901,7 @@
   ldr(mirror, Address(tmp, mirror_offset));
 }
 
+
 ///////////////////////////////////////////////////////////////////////////////
 
 // Compressed pointers
--- a/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -687,6 +687,7 @@
     AbstractAssembler::emit_address((address)L.data());
   }
 
+  void resolve_oop_handle(Register result);
   void load_mirror(Register mirror, Register method, Register tmp);
 
   // Porting layer between 32-bit ARM and AArch64
--- a/hotspot/src/cpu/arm/vm/methodHandles_arm.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/arm/vm/methodHandles_arm.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -559,7 +559,7 @@
     values.print(p);
   }
   if (Verbose) {
-    if (has_mh && mh->is_oop()) {
+    if (has_mh && oopDesc::is_oop(mh)) {
       mh->print();
       if (java_lang_invoke_MethodHandle::is_instance(mh)) {
         if (java_lang_invoke_MethodHandle::form_offset_in_bytes() != 0)
--- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -464,8 +464,7 @@
   // Load pointer for resolved_references[] objArray.
   ld(result, ConstantPool::cache_offset_in_bytes(), result);
   ld(result, ConstantPoolCache::resolved_references_offset_in_bytes(), result);
-  // JNIHandles::resolve(result)
-  ld(result, 0, result);
+  resolve_oop_handle(result);
 #ifdef ASSERT
   Label index_ok;
   lwa(R0, arrayOopDesc::length_offset_in_bytes(), result);
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -3372,6 +3372,12 @@
   }
 }
 
+// ((OopHandle)result).resolve();
+void MacroAssembler::resolve_oop_handle(Register result) {
+  // OopHandle::resolve is an indirection.
+  ld(result, 0, result);
+}
+
 void MacroAssembler::load_mirror_from_const_method(Register mirror, Register const_method) {
   ld(mirror, in_bytes(ConstMethod::constants_offset()), const_method);
   ld(mirror, ConstantPool::pool_holder_offset_in_bytes(), mirror);
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -725,6 +725,7 @@
   void store_klass(Register dst_oop, Register klass, Register tmp = R0);
   void store_klass_gap(Register dst_oop, Register val = noreg); // Will store 0 if val not specified.
 
+  void resolve_oop_handle(Register result);
   void load_mirror_from_const_method(Register mirror, Register const_method);
 
   static int instr_size_for_decode_klass_not_null();
--- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -525,7 +525,7 @@
       values.print(p);
     }
 
-    if (has_mh && mh->is_oop()) {
+    if (has_mh && oopDesc::is_oop(mh)) {
       mh->print();
       if (java_lang_invoke_MethodHandle::is_instance(mh)) {
         if (java_lang_invoke_MethodHandle::form_offset_in_bytes() != 0)
--- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -830,7 +830,7 @@
   // Wrapper which calls oopDesc::is_oop_or_null()
   // Only called by MacroAssembler::verify_oop
   static void verify_oop_helper(const char* message, oop o) {
-    if (!o->is_oop_or_null()) {
+    if (!oopDesc::is_oop_or_null(o)) {
       fatal("%s", message);
     }
     ++ StubRoutines::_verify_oop_count;
--- a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -56,7 +56,7 @@
 // if too small.
 // Run with +PrintInterpreter to get the VM to print out the size.
 // Max size with JVMTI
-int TemplateInterpreter::InterpreterCodeSize = 230*K;
+int TemplateInterpreter::InterpreterCodeSize = 256*K;
 
 #ifdef PRODUCT
 #define BLOCK_COMMENT(str) /* nothing */
--- a/hotspot/src/cpu/s390/vm/assembler_s390.inline.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/s390/vm/assembler_s390.inline.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -246,8 +246,8 @@
 inline void Assembler::z_mvhhi( int64_t d1, Register b1, int64_t i2) { emit_48( MVHHI_ZOPC | uimm12( d1, 20, 48) | regz(b1, 16, 48) | simm16(i2, 32, 48)); }
 inline void Assembler::z_mvhi ( int64_t d1, Register b1, int64_t i2) { emit_48( MVHI_ZOPC  | uimm12( d1, 20, 48) | regz(b1, 16, 48) | simm16(i2, 32, 48)); }
 inline void Assembler::z_mvghi( int64_t d1, Register b1, int64_t i2) { emit_48( MVGHI_ZOPC | uimm12( d1, 20, 48) | regz(b1, 16, 48) | simm16(i2, 32, 48)); }
-inline void Assembler::z_mvhhi( const Address &d, int64_t i2) { assert(!d.has_index(), " no index reg allowed in MVHHI"); z_mvghi( d.disp(), d.baseOrR0(), i2); }
-inline void Assembler::z_mvhi ( const Address &d, int64_t i2) { assert(!d.has_index(), " no index reg allowed in MVHI");  z_mvghi( d.disp(), d.baseOrR0(), i2); }
+inline void Assembler::z_mvhhi( const Address &d, int64_t i2) { assert(!d.has_index(), " no index reg allowed in MVHHI"); z_mvhhi( d.disp(), d.baseOrR0(), i2); }
+inline void Assembler::z_mvhi ( const Address &d, int64_t i2) { assert(!d.has_index(), " no index reg allowed in MVHI");  z_mvhi(  d.disp(), d.baseOrR0(), i2); }
 inline void Assembler::z_mvghi( const Address &d, int64_t i2) { assert(!d.has_index(), " no index reg allowed in MVGHI"); z_mvghi( d.disp(), d.baseOrR0(), i2); }
 
 inline void Assembler::z_ex(Register r1, int64_t d2, Register x2, Register b2) { emit_32( EX_ZOPC | regz(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); }
--- a/hotspot/src/cpu/s390/vm/compiledIC_s390.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/s390/vm/compiledIC_s390.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -105,15 +105,18 @@
   NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + NativeCall::get_IC_pos_in_java_to_interp_stub());
   NativeJump*        jump          = nativeJump_at(method_holder->next_instruction_address());
 
+#ifdef ASSERT
   // A generated lambda form might be deleted from the Lambdaform
   // cache in MethodTypeForm.  If a jit compiled lambdaform method
   // becomes not entrant and the cache access returns null, the new
   // resolve will lead to a new generated LambdaForm.
-
-  assert(method_holder->data() == 0 || method_holder->data() == (intptr_t)callee() || callee->is_compiled_lambda_form(),
+  volatile intptr_t data = method_holder->data();
+  volatile address destination = jump->jump_destination();
+  assert(data == 0 || data == (intptr_t)callee() || callee->is_compiled_lambda_form(),
          "a) MT-unsafe modification of inline cache");
-  assert(jump->jump_destination() == (address)-1 || jump->jump_destination() == entry,
+  assert(destination == (address)-1 || destination == entry,
          "b) MT-unsafe modification of inline cache");
+#endif
 
   // Update stub.
   method_holder->set_data((intptr_t)callee());
--- a/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -364,8 +364,7 @@
   // Load pointer for resolved_references[] objArray.
   z_lg(result, ConstantPool::cache_offset_in_bytes(), result);
   z_lg(result, ConstantPoolCache::resolved_references_offset_in_bytes(), result);
-  // JNIHandles::resolve(result)
-  z_lg(result, 0, result); // Load resolved references array itself.
+  resolve_oop_handle(result); // Load resolved references array itself.
 #ifdef ASSERT
   NearLabel index_ok;
   z_lgf(Z_R0, Address(result, arrayOopDesc::length_offset_in_bytes()));
--- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -4660,6 +4660,12 @@
   }
 }
 
+// ((OopHandle)result).resolve();
+void MacroAssembler::resolve_oop_handle(Register result) {
+  // OopHandle::resolve is an indirection.
+  z_lg(result, 0, result);
+}
+
 void MacroAssembler::load_mirror(Register mirror, Register method) {
   mem2reg_opt(mirror, Address(method, Method::const_offset()));
   mem2reg_opt(mirror, Address(mirror, ConstMethod::constants_offset()));
--- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -832,6 +832,7 @@
   void oop_decoder(Register Rdst, Register Rsrc, bool maybeNULL,
                    Register Rbase = Z_R1, int pow2_offset = -1);
 
+  void resolve_oop_handle(Register result);
   void load_mirror(Register mirror, Register method);
 
   //--------------------------
--- a/hotspot/src/cpu/s390/vm/methodHandles_s390.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/s390/vm/methodHandles_s390.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -595,7 +595,7 @@
     // Note: the unextended_sp may not be correct.
     tty->print_cr("  stack layout:");
     values.print(p);
-    if (has_mh && mh->is_oop()) {
+    if (has_mh && oopDesc::is_oop(mh)) {
       mh->print();
       if (java_lang_invoke_MethodHandle::is_instance(mh)) {
         if (java_lang_invoke_MethodHandle::form_offset_in_bytes() != 0) {
--- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -730,8 +730,7 @@
   // load pointer for resolved_references[] objArray
   ld_ptr(result, ConstantPool::cache_offset_in_bytes(), result);
   ld_ptr(result, ConstantPoolCache::resolved_references_offset_in_bytes(), result);
-  // JNIHandles::resolve(result)
-  ld_ptr(result, 0, result);
+  resolve_oop_handle(result);
   // Add in the index
   add(result, tmp, result);
   load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result);
--- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -3822,6 +3822,12 @@
   card_table_write(bs->byte_map_base, tmp, store_addr);
 }
 
+// ((OopHandle)result).resolve();
+void MacroAssembler::resolve_oop_handle(Register result) {
+  // OopHandle::resolve is an indirection.
+  ld_ptr(result, 0, result);
+}
+
 void MacroAssembler::load_mirror(Register mirror, Register method) {
   const int mirror_offset = in_bytes(Klass::java_mirror_offset());
   ld_ptr(method, in_bytes(Method::const_offset()), mirror);
--- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -995,6 +995,7 @@
   inline void ldbool(const Address& a, Register d);
   inline void movbool( bool boolconst, Register d);
 
+  void resolve_oop_handle(Register result);
   void load_mirror(Register mirror, Register method);
 
   // klass oop manipulations if compressed
--- a/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -562,7 +562,7 @@
     // Note: the unextended_sp may not be correct
     tty->print_cr("  stack layout:");
     values.print(p);
-    if (has_mh && mh->is_oop()) {
+    if (has_mh && oopDesc::is_oop(mh)) {
       mh->print();
       if (java_lang_invoke_MethodHandle::is_instance(mh)) {
         if (java_lang_invoke_MethodHandle::form_offset_in_bytes() != 0)
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -511,8 +511,7 @@
   // load pointer for resolved_references[] objArray
   movptr(result, Address(result, ConstantPool::cache_offset_in_bytes()));
   movptr(result, Address(result, ConstantPoolCache::resolved_references_offset_in_bytes()));
-  // JNIHandles::resolve(obj);
-  movptr(result, Address(result, 0));
+  resolve_oop_handle(result);
   // Add in the index
   addptr(result, tmp);
   load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -6604,6 +6604,12 @@
 #endif // _LP64
 }
 
+// ((OopHandle)result).resolve();
+void MacroAssembler::resolve_oop_handle(Register result) {
+  // OopHandle::resolve is an indirection.
+  movptr(result, Address(result, 0));
+}
+
 void MacroAssembler::load_mirror(Register mirror, Register method) {
   // get mirror
   const int mirror_offset = in_bytes(Klass::java_mirror_offset());
@@ -7030,7 +7036,6 @@
 
 #endif // _LP64
 
-
 // C2 compiled method's prolog code.
 void MacroAssembler::verified_entry(int framesize, int stack_bang_size, bool fp_mode_24b) {
 
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -327,6 +327,7 @@
   void movbool(Address dst, Register src);
   void testbool(Register dst);
 
+  void resolve_oop_handle(Register result);
   void load_mirror(Register mirror, Register method);
 
   // oop manipulations
--- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -561,7 +561,7 @@
       tty->print_cr("Stack layout:");
       values.print(p);
     }
-    if (has_mh && mh->is_oop()) {
+    if (has_mh && oopDesc::is_oop(mh)) {
       mh->print();
       if (java_lang_invoke_MethodHandle::is_instance(mh)) {
         if (java_lang_invoke_MethodHandle::form_offset_in_bytes() != 0)
--- a/hotspot/src/cpu/x86/vm/x86_32.ad	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/x86/vm/x86_32.ad	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 //
-// Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
 // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 //
 // This code is free software; you can redistribute it and/or modify it
@@ -391,7 +391,7 @@
         int format) {
 #ifdef ASSERT
   if (rspec.reloc()->type() == relocInfo::oop_type && d32 != 0 && d32 != (int)Universe::non_oop_word()) {
-    assert(cast_to_oop(d32)->is_oop() && (ScavengeRootsInCode || !cast_to_oop(d32)->is_scavengable()), "cannot embed scavengable oops in code");
+    assert(oopDesc::is_oop(cast_to_oop(d32)) && (ScavengeRootsInCode || !cast_to_oop(d32)->is_scavengable()), "cannot embed scavengable oops in code");
   }
 #endif
   cbuf.relocate(cbuf.insts_mark(), rspec, format);
--- a/hotspot/src/cpu/x86/vm/x86_64.ad	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/cpu/x86/vm/x86_64.ad	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
 // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 //
 // This code is free software; you can redistribute it and/or modify it
@@ -653,7 +653,7 @@
   if (rspec.reloc()->type() == relocInfo::oop_type &&
       d32 != 0 && d32 != (intptr_t) Universe::non_oop_word()) {
     assert(Universe::heap()->is_in_reserved((address)(intptr_t)d32), "should be real oop");
-    assert(cast_to_oop((intptr_t)d32)->is_oop() && (ScavengeRootsInCode || !cast_to_oop((intptr_t)d32)->is_scavengable()), "cannot embed scavengable oops in code");
+    assert(oopDesc::is_oop(cast_to_oop((intptr_t)d32)) && (ScavengeRootsInCode || !cast_to_oop((intptr_t)d32)->is_scavengable()), "cannot embed scavengable oops in code");
   }
 #endif
   cbuf.relocate(cbuf.insts_mark(), rspec, format);
@@ -680,7 +680,7 @@
   if (rspec.reloc()->type() == relocInfo::oop_type &&
       d64 != 0 && d64 != (int64_t) Universe::non_oop_word()) {
     assert(Universe::heap()->is_in_reserved((address)d64), "should be real oop");
-    assert(cast_to_oop(d64)->is_oop() && (ScavengeRootsInCode || !cast_to_oop(d64)->is_scavengable()),
+    assert(oopDesc::is_oop(cast_to_oop(d64)) && (ScavengeRootsInCode || !cast_to_oop(d64)->is_scavengable()),
            "cannot embed scavengable oops in code");
   }
 #endif
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java	Thu Aug 24 21:06:33 2017 +0000
@@ -58,7 +58,7 @@
  * <p>
  * Methods to record and access code section contents, symbols and relocations are provided.
  */
-public class BinaryContainer implements SymbolTable {
+public final class BinaryContainer implements SymbolTable {
     private final OptionValues graalOptions;
 
     private final int codeSegmentSize;
@@ -71,19 +71,19 @@
     private final CodeContainer codeContainer;
 
     /**
-     * Container holding external hotspot linkage bits (PLT entries).
-     */
-    private final CodeContainer extLinkageContainer;
-
-    /**
      * Container holding global offset data for hotspot linkage.
      */
     private final ByteContainer extLinkageGOTContainer;
 
     /**
-     * Patched by HotSpot, contains metaspace pointers.
+     * Patched by HotSpot, contains Klass pointers.
      */
-    private final ByteContainer metaspaceGotContainer;
+    private final ByteContainer klassesGotContainer;
+
+    /**
+     * Patched by HotSpot, contains MethodCounters pointers.
+     */
+    private final ByteContainer countersGotContainer;
 
     /**
      * Patched lazily by hotspot, contains klass/method pointers.
@@ -268,33 +268,41 @@
         this.graalOptions = graalOptions;
 
         this.codeSegmentSize = graalHotSpotVMConfig.codeSegmentSize;
+        if (codeSegmentSize < 1 || codeSegmentSize > 1024) {
+            throw new InternalError("codeSegmentSize is not in range [1, 1024] bytes: (" + codeSegmentSize + "), update JPECoffRelocObject");
+        }
+        if ((codeSegmentSize & (codeSegmentSize - 1)) != 0) {
+            throw new InternalError("codeSegmentSize is not power of 2: (" + codeSegmentSize + "), update JPECoffRelocObject");
+        }
+
         this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment;
 
+        // Section unique name is limited to 8 characters due to limitation on Windows.
+        // Name could be longer but only first 8 characters are stored on Windows.
+
         // read only, code
         codeContainer = new CodeContainer(".text", this);
-        extLinkageContainer = new CodeContainer(".hs.plt.linkage", this);
 
         // read only, info
+        headerContainer = new HeaderContainer(jvmVersion, new ReadOnlyDataContainer(".header", this));
         configContainer = new ReadOnlyDataContainer(".config", this);
         metaspaceNamesContainer = new ReadOnlyDataContainer(".meta.names", this);
-        methodsOffsetsContainer = new ReadOnlyDataContainer(".methods.offsets", this);
+        methodsOffsetsContainer = new ReadOnlyDataContainer(".meth.offsets", this);
         klassesOffsetsContainer = new ReadOnlyDataContainer(".kls.offsets", this);
         klassesDependenciesContainer = new ReadOnlyDataContainer(".kls.dependencies", this);
 
-        headerContainer = new HeaderContainer(jvmVersion, new ReadOnlyDataContainer(".header", this));
         stubsOffsetsContainer = new ReadOnlyDataContainer(".stubs.offsets", this);
         codeSegmentsContainer = new ReadOnlyDataContainer(".code.segments", this);
         constantDataContainer = new ReadOnlyDataContainer(".meth.constdata", this);
-
-        // needs relocation patching at load time by the loader
         methodMetadataContainer = new ReadOnlyDataContainer(".meth.metadata", this);
 
         // writable sections
-        metaspaceGotContainer = new ByteContainer(".meta.got", this);
-        metadataGotContainer = new ByteContainer(".metadata.got", this);
+        oopGotContainer = new ByteContainer(".oop.got", this);
+        klassesGotContainer = new ByteContainer(".kls.got", this);
+        countersGotContainer = new ByteContainer(".cnt.got", this);
+        metadataGotContainer = new ByteContainer(".meta.got", this);
         methodStateContainer = new ByteContainer(".meth.state", this);
-        oopGotContainer = new ByteContainer(".oop.got", this);
-        extLinkageGOTContainer = new ByteContainer(".hs.got.linkage", this);
+        extLinkageGOTContainer = new ByteContainer(".got.linkage", this);
 
         addGlobalSymbols();
 
@@ -368,51 +376,51 @@
      * in the named GOT cell.
      */
 
-    public String getCardTableAddressSymbolName() {
+    public static String getCardTableAddressSymbolName() {
         return "_aot_card_table_address";
     }
 
-    public String getHeapTopAddressSymbolName() {
+    public static String getHeapTopAddressSymbolName() {
         return "_aot_heap_top_address";
     }
 
-    public String getHeapEndAddressSymbolName() {
+    public static String getHeapEndAddressSymbolName() {
         return "_aot_heap_end_address";
     }
 
-    public String getCrcTableAddressSymbolName() {
+    public static String getCrcTableAddressSymbolName() {
         return "_aot_stub_routines_crc_table_adr";
     }
 
-    public String getPollingPageSymbolName() {
+    public static String getPollingPageSymbolName() {
         return "_aot_polling_page";
     }
 
-    public String getResolveStaticEntrySymbolName() {
+    public static String getResolveStaticEntrySymbolName() {
         return "_resolve_static_entry";
     }
 
-    public String getResolveVirtualEntrySymbolName() {
+    public static String getResolveVirtualEntrySymbolName() {
         return "_resolve_virtual_entry";
     }
 
-    public String getResolveOptVirtualEntrySymbolName() {
+    public static String getResolveOptVirtualEntrySymbolName() {
         return "_resolve_opt_virtual_entry";
     }
 
-    public String getNarrowKlassBaseAddressSymbolName() {
+    public static String getNarrowKlassBaseAddressSymbolName() {
         return "_aot_narrow_klass_base_address";
     }
 
-    public String getNarrowOopBaseAddressSymbolName() {
+    public static String getNarrowOopBaseAddressSymbolName() {
         return "_aot_narrow_oop_base_address";
     }
 
-    public String getLogOfHeapRegionGrainBytesSymbolName() {
+    public static String getLogOfHeapRegionGrainBytesSymbolName() {
         return "_aot_log_of_heap_region_grain_bytes";
     }
 
-    public String getInlineContiguousAllocationSupportedSymbolName() {
+    public static String getInlineContiguousAllocationSupportedSymbolName() {
         return "_aot_inline_contiguous_allocation_supported";
     }
 
@@ -430,7 +438,7 @@
      * @param functionName function name
      * @return AOT symbol for the given function name, or null if there is no mapping.
      */
-    public String getAOTSymbolForVMFunctionName(String functionName) {
+    public static String getAOTSymbolForVMFunctionName(String functionName) {
         return functionNamesToAOTSymbols.get(functionName);
     }
 
@@ -441,7 +449,8 @@
         createContainerSymbol(methodsOffsetsContainer);
         createContainerSymbol(klassesOffsetsContainer);
         createContainerSymbol(klassesDependenciesContainer);
-        createContainerSymbol(metaspaceGotContainer);
+        createContainerSymbol(klassesGotContainer);
+        createContainerSymbol(countersGotContainer);
         createContainerSymbol(metadataGotContainer);
         createContainerSymbol(methodStateContainer);
         createContainerSymbol(oopGotContainer);
@@ -469,12 +478,13 @@
     }
 
     /**
-     * Creates a global symbol of the form {@code "JVM" + container name}.
+     * Creates a global symbol of the form {@code "A" + container name}.
+     * Note, linker on Windows does not allow names which start with '.'
      *
      * @param container container to create a symbol for
      */
     private static void createContainerSymbol(ByteContainer container) {
-        container.createSymbol(0, Kind.OBJECT, Binding.GLOBAL, 0, "JVM" + container.getContainerName());
+        container.createSymbol(0, Kind.OBJECT, Binding.GLOBAL, 0, "A" + container.getContainerName());
     }
 
     /**
@@ -499,12 +509,12 @@
      *
      * @throws IOException in case of file creation failure
      */
-    public void createBinary(String outputFileName, String aotVersion) throws IOException {
+    public void createBinary(String outputFileName) throws IOException {
         String osName = System.getProperty("os.name");
         switch (osName) {
             case "Linux":
             case "SunOS":
-                JELFRelocObject elfobj = new JELFRelocObject(this, outputFileName, aotVersion);
+                JELFRelocObject elfobj = new JELFRelocObject(this, outputFileName);
                 elfobj.createELFRelocObject(relocationTable, symbolTable.values());
                 break;
             case "Mac OS X":
@@ -513,7 +523,7 @@
                 break;
             default:
                 if (osName.startsWith("Windows")) {
-                    JPECoffRelocObject pecoffobj = new JPECoffRelocObject(this, outputFileName, aotVersion);
+                    JPECoffRelocObject pecoffobj = new JPECoffRelocObject(this, outputFileName);
                     pecoffobj.createPECoffRelocObject(relocationTable, symbolTable.values());
                     break;
                 } else
@@ -626,12 +636,6 @@
         return startOffset;
     }
 
-    public int appendMetaspaceGotBytes(byte[] bytes, int offset, int size) {
-        int startOffset = metaspaceGotContainer.getByteStreamSize();
-        appendBytes(metaspaceGotContainer, bytes, offset, size);
-        return startOffset;
-    }
-
     public void addMetadataGotEntry(int offset) {
         metadataGotContainer.appendLong(offset);
     }
@@ -681,8 +685,7 @@
     }
 
     /**
-     * Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to
-     * patch.
+     * Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to patch.
      *
      * @param oopName name of the oop symbol
      */
@@ -708,13 +711,13 @@
         return relocationSymbol.getOffset();
     }
 
-    public int addMetaspaceSymbol(String metaspaceName) {
+    public int addCountersSymbol(String metaspaceName) {
         String gotName = "got." + metaspaceName;
         Symbol relocationSymbol = getGotSymbol(gotName);
         int metaspaceOffset = -1;
         if (relocationSymbol == null) {
             // Add slots when asked in the .metaspace.got section:
-            metaspaceGotContainer.createGotSymbol(gotName);
+            countersGotContainer.createGotSymbol(gotName);
         }
         return metaspaceOffset;
     }
@@ -725,29 +728,30 @@
     }
 
     /**
-     * Add metaspace symbol by as follows. - Adding the symbol name to the metaspace.names section -
-     * Add the offset of the name in metaspace.names to metaspace.offsets - Extend the metaspace.got
-     * section with another slot for the VM to patch
+     * Add klass symbol by as follows.
+     *   - Adding the symbol name to the metaspace.names section
+     *   - Add the offset of the name in metaspace.names to metaspace.offsets
+     *   - Extend the klasses.got section with another slot for the VM to patch
      *
-     * @param metaspaceName name of the metaspace symbol
-     * @return the got offset in the metaspace.got of the metaspace symbol
+     * @param klassName name of the metaspace symbol
+     * @return the got offset in the klasses.got of the metaspace symbol
      */
-    public int addTwoSlotMetaspaceSymbol(String metaspaceName) {
-        String gotName = "got." + metaspaceName;
+    public int addTwoSlotKlassSymbol(String klassName) {
+        String gotName = "got." + klassName;
         Symbol previous = getGotSymbol(gotName);
-        assert previous == null : "should be called only once for: " + metaspaceName;
+        assert previous == null : "should be called only once for: " + klassName;
         // Add slots when asked in the .metaspace.got section:
         // First slot
-        String gotInitName = "got.init." + metaspaceName;
-        GotSymbol slot1Symbol = metaspaceGotContainer.createGotSymbol(gotInitName);
-        GotSymbol slot2Symbol = metaspaceGotContainer.createGotSymbol(gotName);
+        String gotInitName = "got.init." + klassName;
+        GotSymbol slot1Symbol = klassesGotContainer.createGotSymbol(gotInitName);
+        GotSymbol slot2Symbol = klassesGotContainer.createGotSymbol(gotName);
 
         slot1Symbol.getIndex(); // check alignment and ignore result
         // Get the index (offset/8) to the got in the .metaspace.got section
         return slot2Symbol.getIndex();
     }
 
-    public int addMethodsCount(int count, ReadOnlyDataContainer container) {
+    public static int addMethodsCount(int count, ReadOnlyDataContainer container) {
         return appendInt(count, container);
     }
 
@@ -772,7 +776,7 @@
         return constantDataOffset;
     }
 
-    public int alignUp(ByteContainer container, int alignment) {
+    public static int alignUp(ByteContainer container, int alignment) {
         if (Integer.bitCount(alignment) != 1) {
             throw new IllegalArgumentException("Must be a power of 2");
         }
@@ -814,15 +818,11 @@
         appendBytes(codeSegmentsContainer, segments, 0, segmentsCount);
     }
 
-    public CodeContainer getExtLinkageContainer() {
-        return extLinkageContainer;
-    }
-
     public ByteContainer getExtLinkageGOTContainer() {
         return extLinkageGOTContainer;
     }
 
-    public ByteContainer getMethodMetadataContainer() {
+    public ReadOnlyDataContainer getMethodMetadataContainer() {
         return methodMetadataContainer;
     }
 
@@ -854,8 +854,12 @@
         return constantDataContainer;
     }
 
-    public ByteContainer getMetaspaceGotContainer() {
-        return metaspaceGotContainer;
+    public ByteContainer getKlassesGotContainer() {
+        return klassesGotContainer;
+    }
+
+    public ByteContainer getCountersGotContainer() {
+        return countersGotContainer;
     }
 
     public ByteContainer getMetadataGotContainer() {
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/CodeContainer.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/CodeContainer.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,7 @@
 /**
  * A container that holds information about code section. This is simply a ByteContainer.
  */
-public class CodeContainer extends ByteContainer {
+public final class CodeContainer extends ByteContainer {
 
     public CodeContainer(String containerName, SymbolTable symbolTable) {
         super(containerName, symbolTable);
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Container.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Container.java	Thu Aug 24 21:06:33 2017 +0000
@@ -23,7 +23,7 @@
 
 package jdk.tools.jaotc.binformat;
 
-public interface Container {
+interface Container {
 
     String getContainerName();
 
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/GotSymbol.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/GotSymbol.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 
 package jdk.tools.jaotc.binformat;
 
-public class GotSymbol extends Symbol {
+public final class GotSymbol extends Symbol {
 
     private static final int GOT_SIZE = 8;
 
@@ -33,18 +33,27 @@
         return offset / GOT_SIZE;
     }
 
+    /**
+     * Create GOT symbol info.
+     *
+     * @param type type of the symbol (UNDEFINED, FUNC, etc)
+     * @param binding binding of the symbol (LOCAL, GLOBAL, ...)
+     * @param container section in which this symbol is "defined"
+     * @param name name of the symbol
+     */
     public GotSymbol(Kind type, Binding binding, ByteContainer container, String name) {
         this(container.getByteStreamSize(), type, binding, container, name);
         container.appendBytes(new byte[GOT_SIZE], 0, GOT_SIZE);
     }
 
     /**
-     * Create symbol info.
+     * Create GOT symbol info.
      *
      * @param offset section offset for the defined symbol
      * @param type type of the symbol (UNDEFINED, FUNC, etc)
      * @param binding binding of the symbol (LOCAL, GLOBAL, ...)
      * @param sec section in which this symbol is "defined"
+     * @param name name of the symbol
      */
     public GotSymbol(int offset, Kind type, Binding binding, ByteContainer sec, String name) {
         super(offset, type, binding, sec, GOT_SIZE, name);
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/HeaderContainer.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/HeaderContainer.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,14 +27,15 @@
 import java.io.DataOutputStream;
 import java.io.IOException;
 
-public class HeaderContainer {
+public final class HeaderContainer {
 
     private static final int CURRENT_VERSION = 1;
     private final ReadOnlyDataContainer container;
+
     // int _version;
     // int _class_count;
     // int _method_count;
-    // int _metaspace_got_size;
+    // int _klasses_got_size;
     // int _metadata_got_size;
     // int _oop_got_size;
     // int _jvm_version_offset;
@@ -76,7 +77,7 @@
         this.container.putIntAt(2 * 4, count);
     }
 
-    public void setMetaspaceGotSize(int size) {
+    public void setKlassesGotSize(int size) {
         this.container.putIntAt(3 * 4, size);
     }
 
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ReadOnlyDataContainer.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ReadOnlyDataContainer.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,9 +23,9 @@
 
 package jdk.tools.jaotc.binformat;
 
-public class ReadOnlyDataContainer extends ByteContainer {
+public final class ReadOnlyDataContainer extends ByteContainer {
 
-    public ReadOnlyDataContainer(String containerName, SymbolTable symbolTable) {
+    ReadOnlyDataContainer(String containerName, SymbolTable symbolTable) {
         super(containerName, symbolTable);
     }
 }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Relocation.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Relocation.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,25 +23,17 @@
 
 package jdk.tools.jaotc.binformat;
 
-public class Relocation {
+public final class Relocation {
 
     public enum RelocType {
         UNDEFINED,
         JAVA_CALL_INDIRECT,
         JAVA_CALL_DIRECT,
-        FOREIGN_CALL_INDIRECT,
         FOREIGN_CALL_INDIRECT_GOT, // Call to address in GOT cell
-        FOREIGN_CALL_DIRECT,
-        FOREIGN_CALL_DIRECT_FAR,
         STUB_CALL_DIRECT,
-        STUB_CALL_INDIRECT,
-        EXTERNAL_DATA_REFERENCE_FAR,
         METASPACE_GOT_REFERENCE,
         EXTERNAL_GOT_TO_PLT,
-        EXTERNAL_PLT_TO_GOT,
-        STATIC_STUB_TO_STATIC_METHOD,
-        STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT,
-        LOADTIME_ADDRESS
+        EXTERNAL_PLT_TO_GOT
     }
 
     private final RelocType type;
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Symbol.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Symbol.java	Thu Aug 24 21:06:33 2017 +0000
@@ -39,7 +39,6 @@
         UNDEFINED,
         NATIVE_FUNCTION,
         JAVA_FUNCTION,
-        STATIC_STUB_CALL, // static call stub inside the text section
         OBJECT,
         NOTYPE
     }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/Elf.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/Elf.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,17 +25,16 @@
 
 /**
  *
- * Support for the creation of Elf Object files.
- * Current support is limited to 64 bit x86_64.
+ * Support for the creation of Elf Object files. Current support is limited to 64 bit x86_64.
  *
  */
 
-public class Elf {
-
+final class Elf {
+    //@formatter:off
     /**
      * Elf64_Ehdr structure defines
      */
-    public enum Elf64_Ehdr {
+    enum Elf64_Ehdr {
                e_ident( 0,16),
                 e_type(16, 2),
              e_machine(18, 2),
@@ -51,15 +50,15 @@
                e_shnum(60, 2),
             e_shstrndx(62, 2);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         Elf64_Ehdr(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 64;
+        static int totalsize = 64;
 
         /**
          * Elf64_Ehdr defines
@@ -68,50 +67,44 @@
         /**
          * e_ident
          */
-        public static final int  EI_MAG0             = 0;
-        public static final byte ELFMAG0             = 0x7f;
-        public static final int  EI_MAG1             = 1;
-        public static final byte ELFMAG1             = 0x45;
-        public static final int  EI_MAG2             = 2;
-        public static final byte ELFMAG2             = 0x4c;
-        public static final int  EI_MAG3             = 3;
-        public static final byte ELFMAG3             = 0x46;
+        static final int  EI_MAG0        = 0;
+        static final byte ELFMAG0        = 0x7f;
+        static final int  EI_MAG1        = 1;
+        static final byte ELFMAG1        = 0x45;
+        static final int  EI_MAG2        = 2;
+        static final byte ELFMAG2        = 0x4c;
+        static final int  EI_MAG3        = 3;
+        static final byte ELFMAG3        = 0x46;
+        static final int  EI_CLASS       = 4;
+        static final byte ELFCLASS64     = 0x2;
 
-        public static final int  EI_CLASS            = 4;
-        public static final byte ELFCLASS64          = 0x2;
-
-        public static final int  EI_DATA             = 5;
-        public static final byte ELFDATA2LSB         = 0x1;
+        static final int  EI_DATA        = 5;
+        static final byte ELFDATA2LSB    = 0x1;
 
-        public static final int  EI_VERSION          = 6;
-        public static final byte EV_CURRENT          = 0x1;
+        static final int  EI_VERSION     = 6;
+        static final byte EV_CURRENT     = 0x1;
 
-        public static final int  EI_OSABI            = 7;
-        public static final byte ELFOSABI_NONE       = 0x0;
+        static final int  EI_OSABI       = 7;
+        static final byte ELFOSABI_NONE  = 0x0;
 
         /**
          * e_type
          */
-        public static final char ET_REL              = 0x1;
+        static final char ET_REL         = 0x1;
 
         /**
          * e_machine
          */
-        public static final char EM_NONE             = 0;
-        public static final char EM_X86_64           = 62;
-        public static final char EM_AARCH64          = 183;
-
-        /**
-         * e_version
-         */
-        // public static final int EV_CURRENT           = 1;
+        static final char EM_NONE        = 0;
+        static final char EM_X86_64      = 62;
+        static final char EM_AARCH64     = 183;
 
     }
 
     /**
      * Elf64_Shdr structure defines
      */
-    public enum Elf64_Shdr {
+    enum Elf64_Shdr {
                sh_name( 0, 4),
                sh_type( 4, 4),
               sh_flags( 8, 8),
@@ -123,15 +116,15 @@
           sh_addralign(48, 8),
             sh_entsize(56, 8);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         Elf64_Shdr(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 64;
+        static int totalsize = 64;
 
         /**
          * Elf64_Shdr defines
@@ -140,21 +133,21 @@
         /**
          * sh_type
          */
-        public static final int SHT_PROGBITS         = 0x1;
-        public static final int SHT_SYMTAB           = 0x2;
-        public static final int SHT_STRTAB           = 0x3;
-        public static final int SHT_RELA             = 0x4;
-        public static final int SHT_NOBITS           = 0x8;
-        public static final int SHT_REL              = 0x9;
+        static final int SHT_PROGBITS   = 0x1;
+        static final int SHT_SYMTAB     = 0x2;
+        static final int SHT_STRTAB     = 0x3;
+        static final int SHT_RELA       = 0x4;
+        static final int SHT_NOBITS     = 0x8;
+        static final int SHT_REL        = 0x9;
 
-        public static final byte SHN_UNDEF           = 0x0;
+        static final byte SHN_UNDEF     = 0x0;
 
         /**
          * sh_flag
          */
-        public static final int SHF_WRITE            = 0x1;
-        public static final int SHF_ALLOC            = 0x2;
-        public static final int SHF_EXECINSTR        = 0x4;
+        static final int SHF_WRITE      = 0x1;
+        static final int SHF_ALLOC      = 0x2;
+        static final int SHF_EXECINSTR  = 0x4;
 
     }
 
@@ -163,7 +156,7 @@
      *
      * Elf64_Sym structure defines
      */
-    public enum Elf64_Sym {
+    enum Elf64_Sym {
                st_name( 0, 4),
                st_info( 4, 1),
               st_other( 5, 1),
@@ -171,25 +164,25 @@
               st_value( 8, 8),
                st_size(16, 8);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         Elf64_Sym(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 24;
+        static int totalsize = 24;
 
         /* ST_BIND is in bits 4-7 of st_info.  ST_TYPE is in low 4 bits */
-        public static final byte STB_LOCAL           = 0x0;
-        public static final byte STB_GLOBAL          = 0x1;
+        static final byte STB_LOCAL   = 0x0;
+        static final byte STB_GLOBAL  = 0x1;
 
-        public static final byte STT_NOTYPE          = 0x0;
-        public static final byte STT_OBJECT          = 0x1;
-        public static final byte STT_FUNC            = 0x2;
+        static final byte STT_NOTYPE  = 0x0;
+        static final byte STT_OBJECT  = 0x1;
+        static final byte STT_FUNC    = 0x2;
 
-        public static byte ELF64_ST_INFO(byte bind, byte type) {
+        static byte ELF64_ST_INFO(byte bind, byte type) {
             return (byte)(((bind) << 4) + ((type) & 0xf));
         }
 
@@ -198,59 +191,59 @@
     /**
      * Elf64_Rel structure defines
      */
-    public enum Elf64_Rel {
+    enum Elf64_Rel {
               r_offset( 0, 8),
                 r_info( 8, 8);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         Elf64_Rel(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 16;
+        static int totalsize = 16;
 
         /**
          * Relocation types
          */
-        public static final int R_X86_64_NONE        = 0x0;
-        public static final int R_X86_64_64          = 0x1;
-        public static final int R_X86_64_PC32        = 0x2;
-        public static final int R_X86_64_PLT32       = 0x4;
-        public static final int R_X86_64_GOTPCREL    = 0x9;
+        static final int R_X86_64_NONE     = 0x0;
+        static final int R_X86_64_64       = 0x1;
+        static final int R_X86_64_PC32     = 0x2;
+        static final int R_X86_64_PLT32    = 0x4;
+        static final int R_X86_64_GOTPCREL = 0x9;
 
     }
 
     /**
      * Elf64_Rela structure defines
      */
-    public enum Elf64_Rela {
+    enum Elf64_Rela {
               r_offset( 0, 8),
                 r_info( 8, 8),
               r_addend(16, 8);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         Elf64_Rela(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 24;
+        static int totalsize = 24;
 
-        public static final int R_X86_64_NONE        = 0x0;
-        public static final int R_X86_64_64          = 0x1;
-        public static final int R_X86_64_PC32        = 0x2;
-        public static final int R_X86_64_PLT32       = 0x4;
-        public static final int R_X86_64_GOTPCREL    = 0x9;
+        static final int R_X86_64_NONE     = 0x0;
+        static final int R_X86_64_64       = 0x1;
+        static final int R_X86_64_PC32     = 0x2;
+        static final int R_X86_64_PLT32    = 0x4;
+        static final int R_X86_64_GOTPCREL = 0x9;
 
-        public static long ELF64_R_INFO(int symidx, int type) {
-            return (((long)symidx << 32) + ((long)type));
+        static long ELF64_R_INFO(int symidx, int type) {
+            return (((long)symidx << 32) + type);
         }
 
     }
-
+    //@formatter:on
 }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfByteBuffer.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfByteBuffer.java	Thu Aug 24 21:06:33 2017 +0000
@@ -23,20 +23,20 @@
 
 package jdk.tools.jaotc.binformat.elf;
 
-
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
 import jdk.tools.jaotc.binformat.elf.ElfTargetInfo;
 
-public class ElfByteBuffer {
+final class ElfByteBuffer {
 
-    public static ByteBuffer allocate(int size) {
+    static ByteBuffer allocate(int size) {
         ByteBuffer buf = ByteBuffer.allocate(size);
-        if (ElfTargetInfo.getElfEndian() == Elf64_Ehdr.ELFDATA2LSB)
+        if (ElfTargetInfo.getElfEndian() == Elf64_Ehdr.ELFDATA2LSB) {
             buf.order(ByteOrder.LITTLE_ENDIAN);
-        else
+        } else {
             buf.order(ByteOrder.BIG_ENDIAN);
+        }
         return (buf);
     }
 
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfContainer.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfContainer.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,14 +26,13 @@
 import java.io.File;
 import java.io.FileOutputStream;
 
-public class ElfContainer {
+final class ElfContainer {
 
-    File outputFile;
-    FileOutputStream outputStream;
-    long fileOffset;
+    private final File outputFile;
+    private FileOutputStream outputStream;
+    private long fileOffset;
 
-    public ElfContainer(String fileName, String aotVersion) {
-        String baseName;
+    ElfContainer(String fileName) {
 
         outputFile = new File(fileName);
         if (outputFile.exists()) {
@@ -48,7 +47,7 @@
         fileOffset = 0;
     }
 
-    public void close() {
+    void close() {
         try {
             outputStream.close();
         } catch (Exception e) {
@@ -56,8 +55,10 @@
         }
     }
 
-    public void writeBytes(byte [] bytes) {
-        if (bytes == null) return;
+    void writeBytes(byte[] bytes) {
+        if (bytes == null) {
+            return;
+        }
         try {
             outputStream.write(bytes);
         } catch (Exception e) {
@@ -67,11 +68,13 @@
     }
 
     // Write bytes to output file with up front alignment padding
-    public void writeBytes(byte [] bytes, int alignment) {
-        if (bytes == null) return;
+    void writeBytes(byte[] bytes, int alignment) {
+        if (bytes == null) {
+            return;
+        }
         try {
             // Pad to alignment
-            while ((fileOffset & (long)(alignment-1)) != 0) {
+            while ((fileOffset & (alignment - 1)) != 0) {
                 outputStream.write(0);
                 fileOffset++;
             }
@@ -82,4 +85,3 @@
         fileOffset += bytes.length;
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfHeader.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfHeader.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,55 +24,52 @@
 package jdk.tools.jaotc.binformat.elf;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
-import jdk.tools.jaotc.binformat.elf.Elf;
 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr;
 import jdk.tools.jaotc.binformat.elf.ElfTargetInfo;
 import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
 
-public class ElfHeader {
-    ByteBuffer header;
+final class ElfHeader {
+    private final ByteBuffer header;
 
-    public ElfHeader() {
+    ElfHeader() {
         header = ElfByteBuffer.allocate(Elf64_Ehdr.totalsize);
 
-        header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_MAG0, Elf64_Ehdr.ELFMAG0);
-        header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_MAG1, Elf64_Ehdr.ELFMAG1);
-        header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_MAG2, Elf64_Ehdr.ELFMAG2);
-        header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_MAG3, Elf64_Ehdr.ELFMAG3);
-        header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_CLASS, Elf64_Ehdr.ELFCLASS64);
-        header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_DATA, Elf64_Ehdr.ELFDATA2LSB);
-        header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_VERSION, Elf64_Ehdr.EV_CURRENT);
-        header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_OSABI, Elf64_Ehdr.ELFOSABI_NONE);
+        header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_MAG0, Elf64_Ehdr.ELFMAG0);
+        header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_MAG1, Elf64_Ehdr.ELFMAG1);
+        header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_MAG2, Elf64_Ehdr.ELFMAG2);
+        header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_MAG3, Elf64_Ehdr.ELFMAG3);
+        header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_CLASS, Elf64_Ehdr.ELFCLASS64);
+        header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_DATA, Elf64_Ehdr.ELFDATA2LSB);
+        header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_VERSION, Elf64_Ehdr.EV_CURRENT);
+        header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_OSABI, Elf64_Ehdr.ELFOSABI_NONE);
 
         header.putChar(Elf64_Ehdr.e_type.off, Elf64_Ehdr.ET_REL);
         header.putChar(Elf64_Ehdr.e_machine.off, ElfTargetInfo.getElfArch());
         header.putInt(Elf64_Ehdr.e_version.off, Elf64_Ehdr.EV_CURRENT);
-        header.putChar(Elf64_Ehdr.e_ehsize.off, (char)Elf64_Ehdr.totalsize);
-        header.putChar(Elf64_Ehdr.e_shentsize.off, (char)Elf64_Shdr.totalsize);
+        header.putChar(Elf64_Ehdr.e_ehsize.off, (char) Elf64_Ehdr.totalsize);
+        header.putChar(Elf64_Ehdr.e_shentsize.off, (char) Elf64_Shdr.totalsize);
 
     }
 
     // Update header with file offset of first section
-    public void setSectionOff(int offset) {
+    void setSectionOff(int offset) {
         header.putLong(Elf64_Ehdr.e_shoff.off, offset);
     }
 
     // Update header with the number of total sections
-    public void setSectionNum(int count) {
-        header.putChar(Elf64_Ehdr.e_shnum.off, (char)count);
+    void setSectionNum(int count) {
+        header.putChar(Elf64_Ehdr.e_shnum.off, (char) count);
     }
 
     // Update header with the section index containing the
     // string table for section names
-    public void setSectionStrNdx(int index) {
-        header.putChar(Elf64_Ehdr.e_shstrndx.off, (char)index);
+    void setSectionStrNdx(int index) {
+        header.putChar(Elf64_Ehdr.e_shstrndx.off, (char) index);
     }
 
-    public byte[] getArray() {
+    byte[] getArray() {
         return header.array();
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocEntry.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocEntry.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,28 +24,23 @@
 package jdk.tools.jaotc.binformat.elf;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
-import jdk.tools.jaotc.binformat.elf.Elf;
 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
-import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
-import jdk.tools.jaotc.binformat.elf.ElfTargetInfo;
 import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
 
-public class ElfRelocEntry {
-    ByteBuffer entry;
+final class ElfRelocEntry {
+    private final ByteBuffer entry;
 
-    public ElfRelocEntry(int offset, int symno, int type, int addend) {
+    ElfRelocEntry(int offset, int symno, int type, int addend) {
 
         entry = ElfByteBuffer.allocate(Elf64_Rela.totalsize);
 
         entry.putLong(Elf64_Rela.r_offset.off, offset);
-        entry.putLong(Elf64_Rela.r_info.off, Elf64_Rela.ELF64_R_INFO(symno,type));
+        entry.putLong(Elf64_Rela.r_info.off, Elf64_Rela.ELF64_R_INFO(symno, type));
         entry.putLong(Elf64_Rela.r_addend.off, addend);
     }
 
-    public byte[] getArray() {
+    byte[] getArray() {
         return entry.array();
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocTable.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocTable.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,48 +25,38 @@
 
 import java.util.ArrayList;
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
 import jdk.tools.jaotc.binformat.elf.ElfRelocEntry;
-import jdk.tools.jaotc.binformat.elf.ElfTargetInfo;
 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
-import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
 import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
 
-public class ElfRelocTable {
-    ArrayList<ArrayList<ElfRelocEntry>> relocEntries;
+final class ElfRelocTable {
+    private final ArrayList<ArrayList<ElfRelocEntry>> relocEntries;
 
-    public ElfRelocTable(int numsects) {
-        relocEntries = new ArrayList<ArrayList<ElfRelocEntry>>(numsects);
-        for (int i = 0; i < numsects; i++)
+    ElfRelocTable(int numsects) {
+        relocEntries = new ArrayList<>(numsects);
+        for (int i = 0; i < numsects; i++) {
             relocEntries.add(new ArrayList<ElfRelocEntry>());
+        }
     }
 
-    public void createRelocationEntry(int sectindex,
-                                      int offset,
-                                      int symno,
-                                      int type,
-                                      int addend) {
-
-        ElfRelocEntry entry = new ElfRelocEntry(offset,
-                                                symno,
-                                                type,
-                                                addend);
+    void createRelocationEntry(int sectindex, int offset, int symno, int type, int addend) {
+        ElfRelocEntry entry = new ElfRelocEntry(offset, symno, type, addend);
         relocEntries.get(sectindex).add(entry);
     }
 
-    public int getNumRelocs(int section_index) {
+    int getNumRelocs(int section_index) {
         return relocEntries.get(section_index).size();
     }
 
     // Return the relocation entries for a single section
-    //   or null if no entries added to section
-    public byte [] getRelocData(int section_index) {
+    // or null if no entries added to section
+    byte[] getRelocData(int section_index) {
         ArrayList<ElfRelocEntry> entryList = relocEntries.get(section_index);
 
-        if (entryList.size() == 0)
+        if (entryList.size() == 0) {
             return null;
-
+        }
         ByteBuffer relocData = ElfByteBuffer.allocate(entryList.size() * Elf64_Rela.totalsize);
 
         // Copy each entry to a single ByteBuffer
@@ -78,4 +68,3 @@
         return (relocData.array());
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSection.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSection.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,40 +24,36 @@
 package jdk.tools.jaotc.binformat.elf;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
-import jdk.tools.jaotc.binformat.elf.Elf;
-import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr;
 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rel;
 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym;
 import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
 
-public class ElfSection {
-    String name;
-    ByteBuffer section;
-    byte [] data;
-    boolean hasrelocations;
-    int sectionIndex;
+final class ElfSection {
+    private final String name;
+    private final ByteBuffer section;
+    private final byte[] data;
+    private final boolean hasrelocations;
+    private final int sectionIndex;
 
     /**
      * String holding section name strings
      */
-    private static StringBuilder sectNameTab = new StringBuilder();
+    private final static StringBuilder sectNameTab = new StringBuilder();
 
     /**
-     * Keeps track of bytes in section string table since strTabContent.length()
-     * is number of chars, not bytes.
+     * Keeps track of bytes in section string table since strTabContent.length() is number of chars,
+     * not bytes.
      */
     private static int shStrTabNrOfBytes = 0;
 
-    public ElfSection(String sectName, byte [] sectData, int sectFlags,
-                      int sectType, boolean hasRelocations, int align,
-                      int sectIndex) {
+    ElfSection(String sectName, byte[] sectData, int sectFlags, int sectType,
+               boolean hasRelocations, int align, int sectIndex) {
 
         section = ElfByteBuffer.allocate(Elf64_Shdr.totalsize);
-
+        name = sectName;
         // Return all 0's for NULL section
         if (sectIndex == 0) {
             sectNameTab.append('\0');
@@ -71,7 +67,6 @@
         section.putInt(Elf64_Shdr.sh_name.off, shStrTabNrOfBytes);
         sectNameTab.append(sectName).append('\0');
         shStrTabNrOfBytes += (sectName.getBytes().length + 1);
-        name = sectName;
 
         section.putInt(Elf64_Shdr.sh_type.off, sectType);
         section.putLong(Elf64_Shdr.sh_flags.off, sectFlags);
@@ -81,8 +76,7 @@
         if (sectName.equals(".shstrtab")) {
             section.putLong(Elf64_Shdr.sh_size.off, shStrTabNrOfBytes);
             data = sectNameTab.toString().getBytes();
-        }
-        else {
+        } else {
             data = sectData;
             section.putLong(Elf64_Shdr.sh_size.off, sectData.length);
         }
@@ -110,55 +104,53 @@
         sectionIndex = sectIndex;
     }
 
-    public String getName() {
+    String getName() {
         return name;
     }
 
-    public long getSize() {
+    long getSize() {
         return section.getLong(Elf64_Shdr.sh_size.off);
     }
 
-    public int getDataAlign() {
-        return ((int)section.getLong(Elf64_Shdr.sh_addralign.off));
+    int getDataAlign() {
+        return ((int) section.getLong(Elf64_Shdr.sh_addralign.off));
     }
 
     // Alignment requirements for the Elf64_Shdr structures
-    public static int getShdrAlign() {
+    static int getShdrAlign() {
         return (4);
     }
 
-    public byte[] getArray() {
+    byte[] getArray() {
         return section.array();
     }
 
-    public byte[] getDataArray() {
+    byte[] getDataArray() {
         return data;
     }
 
-    public void setOffset(long offset) {
+    void setOffset(long offset) {
         section.putLong(Elf64_Shdr.sh_offset.off, offset);
     }
 
-    public void setLink(int link) {
+    void setLink(int link) {
         section.putInt(Elf64_Shdr.sh_link.off, link);
     }
 
-    public void setInfo(int info) {
+    void setInfo(int info) {
         section.putInt(Elf64_Shdr.sh_info.off, info);
     }
 
-    public long getOffset() {
+    long getOffset() {
         return (section.getLong(Elf64_Shdr.sh_offset.off));
     }
 
-    public boolean hasRelocations() {
+    boolean hasRelocations() {
         return hasrelocations;
     }
 
-    public int getSectionId() {
+    int getSectionId() {
         return sectionIndex;
     }
 
 }
-
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymbol.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymbol.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,34 +24,29 @@
 package jdk.tools.jaotc.binformat.elf;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
 import jdk.tools.jaotc.binformat.NativeSymbol;
-import jdk.tools.jaotc.binformat.elf.Elf;
 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym;
-import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
 import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
 
-public class ElfSymbol extends NativeSymbol {
-    ByteBuffer sym;
+final class ElfSymbol extends NativeSymbol {
+    private final ByteBuffer sym;
 
-    public ElfSymbol(int symbolindex, int strindex, byte type, byte bind,
-                     byte sectindex, long offset, long size) {
+    ElfSymbol(int symbolindex, int strindex, byte type, byte bind, byte sectindex, long offset, long size) {
         super(symbolindex);
         sym = ElfByteBuffer.allocate(Elf64_Sym.totalsize);
 
         sym.putInt(Elf64_Sym.st_name.off, strindex);
         sym.put(Elf64_Sym.st_info.off, Elf64_Sym.ELF64_ST_INFO(bind, type));
-        sym.put(Elf64_Sym.st_other.off, (byte)0);
+        sym.put(Elf64_Sym.st_other.off, (byte) 0);
         // Section indexes start at 1 but we manage the index internally
         // as 0 relative
-        sym.putChar(Elf64_Sym.st_shndx.off, (char)(sectindex));
+        sym.putChar(Elf64_Sym.st_shndx.off, (char) (sectindex));
         sym.putLong(Elf64_Sym.st_value.off, offset);
         sym.putLong(Elf64_Sym.st_size.off, size);
     }
 
-    public byte[] getArray() {
+    byte[] getArray() {
         return sym.array();
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymtab.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymtab.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,41 +24,38 @@
 package jdk.tools.jaotc.binformat.elf;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 import java.util.ArrayList;
 
-import jdk.tools.jaotc.binformat.elf.Elf;
 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym;
 import jdk.tools.jaotc.binformat.elf.ElfSymbol;
 import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
 
-public class ElfSymtab {
+final class ElfSymtab {
 
-    ArrayList<ElfSymbol>localSymbols = new ArrayList<ElfSymbol>();
-    ArrayList<ElfSymbol>globalSymbols = new ArrayList<ElfSymbol>();
+    private final ArrayList<ElfSymbol> localSymbols = new ArrayList<>();
+    private final ArrayList<ElfSymbol> globalSymbols = new ArrayList<>();
 
     /**
      * number of symbols added
      */
-    int symbolCount;
+    private int symbolCount;
 
     /**
      * String holding symbol table strings
      */
-    private StringBuilder strTabContent = new StringBuilder();
+    private final StringBuilder strTabContent = new StringBuilder();
 
     /**
-     * Keeps track of bytes in string table since strTabContent.length()
-     * is number of chars, not bytes.
+     * Keeps track of bytes in string table since strTabContent.length() is number of chars, not
+     * bytes.
      */
     private int strTabNrOfBytes = 0;
 
-    public ElfSymtab() {
+    ElfSymtab() {
         symbolCount = 0;
     }
 
-    public ElfSymbol addSymbolEntry(String name, byte type, byte bind,
-                                    byte secHdrIndex, long offset, long size) {
+    ElfSymbol addSymbolEntry(String name, byte type, byte bind, byte secHdrIndex, long offset, long size) {
         // Get the current symbol index and append symbol name to string table.
         int index;
         ElfSymbol sym;
@@ -76,7 +73,7 @@
             // strTabContent.append("_").append(name).append('\0');
             strTabContent.append(name).append('\0');
             // + 1 for null, + 1 for "_"
-            //strTabNrOfBytes += (name.getBytes().length + 1 + 1);
+            // strTabNrOfBytes += (name.getBytes().length + 1 + 1);
             strTabNrOfBytes += (name.getBytes().length + 1);
 
             sym = new ElfSymbol(symbolCount, index, type, bind, secHdrIndex, offset, size);
@@ -92,44 +89,47 @@
     // Update the symbol indexes once all symbols have been added.
     // This is required since we'll be reordering the symbols in the
     // file to be in the order of Local then global.
-    public void updateIndexes() {
+    void updateIndexes() {
         int index = 0;
 
         // Update the local symbol indexes
-        for (int i = 0; i < localSymbols.size(); i++ ) {
+        for (int i = 0; i < localSymbols.size(); i++) {
             ElfSymbol sym = localSymbols.get(i);
             sym.setIndex(index++);
         }
 
         // Update the global symbol indexes
-        for (int i = 0; i < globalSymbols.size(); i++ ) {
+        for (int i = 0; i < globalSymbols.size(); i++) {
             ElfSymbol sym = globalSymbols.get(i);
             sym.setIndex(index++);
         }
     }
 
-    public int getNumLocalSyms()  { return localSymbols.size();  }
-    public int getNumGlobalSyms() { return globalSymbols.size(); }
+    int getNumLocalSyms() {
+        return localSymbols.size();
+    }
 
+    int getNumGlobalSyms() {
+        return globalSymbols.size();
+    }
 
     // Create a single byte array that contains the symbol table entries
-    public byte[] getSymtabArray() {
-        int index = 0;
-        ByteBuffer symtabData = ElfByteBuffer.allocate(symbolCount*Elf64_Sym.totalsize);
-        byte [] retarray;
+    byte[] getSymtabArray() {
+        ByteBuffer symtabData = ElfByteBuffer.allocate(symbolCount * Elf64_Sym.totalsize);
+        byte[] retarray;
 
         updateIndexes();
 
         // Add the local symbols
-        for (int i = 0; i < localSymbols.size(); i++ ) {
+        for (int i = 0; i < localSymbols.size(); i++) {
             ElfSymbol sym = localSymbols.get(i);
-            byte [] arr = sym.getArray();
+            byte[] arr = sym.getArray();
             symtabData.put(arr);
         }
         // Add the global symbols
-        for (int i = 0; i < globalSymbols.size(); i++ ) {
+        for (int i = 0; i < globalSymbols.size(); i++) {
             ElfSymbol sym = globalSymbols.get(i);
-            byte [] arr = sym.getArray();
+            byte[] arr = sym.getArray();
             symtabData.put(arr);
         }
         retarray = symtabData.array();
@@ -138,10 +138,8 @@
     }
 
     // Return the string table array
-    public byte[] getStrtabArray() {
-        byte [] strs = strTabContent.toString().getBytes();
+    byte[] getStrtabArray() {
+        byte[] strs = strTabContent.toString().getBytes();
         return (strs);
     }
 }
-
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfTargetInfo.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfTargetInfo.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,14 +24,13 @@
 package jdk.tools.jaotc.binformat.elf;
 
 import java.nio.ByteOrder;
-import jdk.tools.jaotc.binformat.elf.Elf;
 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
 
 /**
  * Class that abstracts MACH-O target details.
  *
  */
-public class ElfTargetInfo {
+final class ElfTargetInfo {
     /**
      * Target architecture.
      */
@@ -68,16 +67,15 @@
         }
     }
 
-    public static char getElfArch() {
+    static char getElfArch() {
         return arch;
     }
 
-    public static int getElfEndian() {
+    static int getElfEndian() {
         return endian;
     }
 
-    public static String getOsName() {
+    static String getOsName() {
         return osName;
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/JELFRelocObject.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/JELFRelocObject.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,13 +24,11 @@
 package jdk.tools.jaotc.binformat.elf;
 
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
-import jdk.tools.jaotc.binformat.Container;
 import jdk.tools.jaotc.binformat.BinaryContainer;
 import jdk.tools.jaotc.binformat.ByteContainer;
 import jdk.tools.jaotc.binformat.CodeContainer;
@@ -38,17 +36,14 @@
 import jdk.tools.jaotc.binformat.Relocation;
 import jdk.tools.jaotc.binformat.Relocation.RelocType;
 import jdk.tools.jaotc.binformat.Symbol;
-import jdk.tools.jaotc.binformat.NativeSymbol;
 import jdk.tools.jaotc.binformat.Symbol.Binding;
 import jdk.tools.jaotc.binformat.Symbol.Kind;
 
-import jdk.tools.jaotc.binformat.elf.Elf;
 import jdk.tools.jaotc.binformat.elf.ElfSymbol;
 import jdk.tools.jaotc.binformat.elf.ElfTargetInfo;
 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr;
 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym;
-import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rel;
 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
 
 public class JELFRelocObject {
@@ -59,34 +54,29 @@
 
     private final int segmentSize;
 
-    public JELFRelocObject(BinaryContainer binContainer, String outputFileName, String aotVersion) {
+    public JELFRelocObject(BinaryContainer binContainer, String outputFileName) {
         this.binContainer = binContainer;
-        this.elfContainer = new ElfContainer(outputFileName, aotVersion);
+        this.elfContainer = new ElfContainer(outputFileName);
         this.segmentSize = binContainer.getCodeSegmentSize();
     }
 
-    private ElfSection createByteSection(ArrayList<ElfSection>sections,
-                                         String sectName,
-                                         byte [] scnData,
-                                         boolean hasRelocs,
-                                         int align,
-                                         int scnFlags,
-                                         int scnType) {
+    private static ElfSection createByteSection(ArrayList<ElfSection> sections,
+                                                String sectName,
+                                                byte[] scnData,
+                                                boolean hasRelocs,
+                                                int align,
+                                                int scnFlags,
+                                                int scnType) {
 
-        ElfSection sect = new ElfSection(sectName,
-                                         scnData,
-                                         scnFlags,
-                                         scnType,
-                                         hasRelocs,
-                                         align,
-                                         sections.size());
+        ElfSection sect = new ElfSection(sectName, scnData, scnFlags, scnType,
+                                         hasRelocs, align, sections.size());
         // Add this section to our list
         sections.add(sect);
 
         return (sect);
     }
 
-    private void createByteSection(ArrayList<ElfSection>sections,
+    private void createByteSection(ArrayList<ElfSection> sections,
                                    ByteContainer c, int scnFlags) {
         ElfSection sect;
         boolean hasRelocs = c.hasRelocations();
@@ -112,15 +102,15 @@
         c.setSectionId(sect.getSectionId());
     }
 
-    private void createCodeSection(ArrayList<ElfSection>sections, CodeContainer c) {
+    private void createCodeSection(ArrayList<ElfSection> sections, CodeContainer c) {
         createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_EXECINSTR);
     }
 
-    private void createReadOnlySection(ArrayList<ElfSection>sections, ReadOnlyDataContainer c) {
+    private void createReadOnlySection(ArrayList<ElfSection> sections, ReadOnlyDataContainer c) {
         createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC);
     }
 
-    private void createReadWriteSection(ArrayList<ElfSection>sections, ByteContainer c) {
+    private void createReadWriteSection(ArrayList<ElfSection> sections, ByteContainer c) {
         createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_WRITE);
     }
 
@@ -135,7 +125,7 @@
         // Allocate ELF Header
         ElfHeader eh = new ElfHeader();
 
-        ArrayList<ElfSection> sections = new ArrayList<ElfSection>();
+        ArrayList<ElfSection> sections = new ArrayList<>();
 
         // Create the null section
         createByteSection(sections, null, null, false, 1, 0, 0);
@@ -146,63 +136,49 @@
         createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer());
         createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer());
         createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer());
-        createReadWriteSection(sections, binContainer.getMetaspaceGotContainer());
-        createReadWriteSection(sections, binContainer.getMetadataGotContainer());
-        createReadWriteSection(sections, binContainer.getMethodStateContainer());
-        createReadWriteSection(sections, binContainer.getOopGotContainer());
-        createReadWriteSection(sections, binContainer.getMethodMetadataContainer());
+        createReadOnlySection(sections, binContainer.getMethodMetadataContainer());
         createReadOnlySection(sections, binContainer.getStubsOffsetsContainer());
         createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer());
         createReadOnlySection(sections, binContainer.getCodeSegmentsContainer());
         createReadOnlySection(sections, binContainer.getConstantDataContainer());
         createReadOnlySection(sections, binContainer.getConfigContainer());
-
-        // createExternalLinkage();
-
-        createCodeSection(sections, binContainer.getExtLinkageContainer());
+        createReadWriteSection(sections, binContainer.getKlassesGotContainer());
+        createReadWriteSection(sections, binContainer.getCountersGotContainer());
+        createReadWriteSection(sections, binContainer.getMetadataGotContainer());
+        createReadWriteSection(sections, binContainer.getOopGotContainer());
+        createReadWriteSection(sections, binContainer.getMethodStateContainer());
         createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer());
 
         // Get ELF symbol data from BinaryContainer object's symbol tables
-        ElfSymtab symtab = createELFSymbolTables(sections, symbols);
+        ElfSymtab symtab = createELFSymbolTables(symbols);
 
         // Create string table section and symbol table sections in
         // that order since symtab section needs to set the index of
         // strtab in sh_link field
-        ElfSection strTabSection = createByteSection(sections,
-                                                     ".strtab",
+        ElfSection strTabSection = createByteSection(sections, ".strtab",
                                                      symtab.getStrtabArray(),
-                                                     false,
-                                                     1,
-                                                     0,
+                                                     false, 1, 0,
                                                      Elf64_Shdr.SHT_STRTAB);
 
         // Now create .symtab section with the symtab data constructed.
         // On Linux, sh_link of symtab contains the index of string table
         // its symbols reference and sh_info contains the index of first
         // non-local symbol
-        ElfSection symTabSection = createByteSection(sections,
-                                                    ".symtab",
-                                                    symtab.getSymtabArray(),
-                                                    false,
-                                                    8,
-                                                    0,
-                                                    Elf64_Shdr.SHT_SYMTAB);
+        ElfSection symTabSection = createByteSection(sections, ".symtab",
+                                                     symtab.getSymtabArray(),
+                                                     false, 8, 0,
+                                                     Elf64_Shdr.SHT_SYMTAB);
         symTabSection.setLink(strTabSection.getSectionId());
         symTabSection.setInfo(symtab.getNumLocalSyms());
 
-        ElfRelocTable elfRelocTable = createElfRelocTable(sections,
-                                                          relocationTable);
+        ElfRelocTable elfRelocTable = createElfRelocTable(sections, relocationTable);
 
         createElfRelocSections(sections, elfRelocTable, symTabSection.getSectionId());
 
         // Now, finally, after creating all sections, create shstrtab section
-        ElfSection shStrTabSection = createByteSection(sections,
-                                                    ".shstrtab",
-                                                    null,
-                                                    false,
-                                                    1,
-                                                    0,
-                                                    Elf64_Shdr.SHT_STRTAB);
+        ElfSection shStrTabSection = createByteSection(sections, ".shstrtab",
+                                                       null, false, 1, 0,
+                                                       Elf64_Shdr.SHT_STRTAB);
         eh.setSectionStrNdx(shStrTabSection.getSectionId());
 
         // Update all section offsets and the Elf header section offset
@@ -211,21 +187,21 @@
         int file_offset = Elf64_Ehdr.totalsize;
 
         // and round it up
-        file_offset = (file_offset + (sections.get(1).getDataAlign()-1)) &
-                      ~((sections.get(1).getDataAlign()-1));
+        file_offset = (file_offset + (sections.get(1).getDataAlign() - 1)) &
+                      ~((sections.get(1).getDataAlign() - 1));
 
         // Calc file offsets for section data skipping null section
         for (int i = 1; i < sections.size(); i++) {
             ElfSection sect = sections.get(i);
-            file_offset = (file_offset + (sect.getDataAlign()-1)) &
-                           ~((sect.getDataAlign()-1));
+            file_offset = (file_offset + (sect.getDataAlign() - 1)) &
+                          ~((sect.getDataAlign() - 1));
             sect.setOffset(file_offset);
             file_offset += sect.getSize();
         }
 
         // Align the section table
-        file_offset = (file_offset + (ElfSection.getShdrAlign()-1)) &
-                      ~((ElfSection.getShdrAlign()-1));
+        file_offset = (file_offset + (ElfSection.getShdrAlign() - 1)) &
+                      ~((ElfSection.getShdrAlign() - 1));
 
         // Update the Elf Header with the offset of the first Elf64_Shdr
         // and the number of sections.
@@ -249,24 +225,25 @@
 
         elfContainer.close();
     }
+
     /**
-     * Construct ELF symbol data from BinaryContainer object's symbol tables. Both dynamic ELF
-     * symbol table and ELF symbol table are created from BinaryContainer's symbol info.
+     * Construct ELF symbol data from BinaryContainer object's symbol tables. Both dynamic ELF symbol
+     * table and ELF symbol table are created from BinaryContainer's symbol info.
      *
      * @param symbols
      */
-    private ElfSymtab createELFSymbolTables(ArrayList<ElfSection> sections, Collection<Symbol> symbols) {
+    private static ElfSymtab createELFSymbolTables(Collection<Symbol> symbols) {
         ElfSymtab symtab = new ElfSymtab();
 
         // First, create the initial null symbol. This is a local symbol.
-        symtab.addSymbolEntry("", (byte)0, (byte)0, Elf64_Shdr.SHN_UNDEF, 0, 0);
+        symtab.addSymbolEntry("", (byte) 0, (byte) 0, Elf64_Shdr.SHN_UNDEF, 0, 0);
 
         // Now create ELF symbol entries for all symbols.
         for (Symbol symbol : symbols) {
             // Get the index of section this symbol is defined in.
             int secHdrIndex = symbol.getSection().getSectionId();
-            ElfSymbol elfSymbol = symtab.addSymbolEntry(symbol.getName(), getELFTypeOf(symbol), getELFBindOf(symbol), (byte)secHdrIndex, symbol.getOffset(), symbol.getSize());
-            symbol.setNativeSymbol((NativeSymbol)elfSymbol);
+            ElfSymbol elfSymbol = symtab.addSymbolEntry(symbol.getName(), getELFTypeOf(symbol), getELFBindOf(symbol), (byte) secHdrIndex, symbol.getOffset(), symbol.getSize());
+            symbol.setNativeSymbol(elfSymbol);
         }
         return (symtab);
     }
@@ -300,8 +277,7 @@
 
         ElfRelocTable elfRelocTable = new ElfRelocTable(sections.size());
         /*
-         * For each of the symbols with associated relocation records, create a Elf relocation
-         * entry.
+         * For each of the symbols with associated relocation records, create a Elf relocation entry.
          */
         for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) {
             List<Relocation> relocs = entry.getValue();
@@ -319,69 +295,39 @@
         return (elfRelocTable);
     }
 
-    private void createRelocation(Symbol symbol, Relocation reloc, ElfRelocTable elfRelocTable) {
+    private static void createRelocation(Symbol symbol, Relocation reloc, ElfRelocTable elfRelocTable) {
         RelocType relocType = reloc.getType();
 
         int elfRelocType = getELFRelocationType(relocType);
-        ElfSymbol sym = (ElfSymbol)symbol.getNativeSymbol();
+        ElfSymbol sym = (ElfSymbol) symbol.getNativeSymbol();
         int symno = sym.getIndex();
         int sectindex = reloc.getSection().getSectionId();
         int offset = reloc.getOffset();
         int addend = 0;
 
         switch (relocType) {
-            case FOREIGN_CALL_DIRECT:
             case JAVA_CALL_DIRECT:
             case STUB_CALL_DIRECT:
             case FOREIGN_CALL_INDIRECT_GOT: {
                 // Create relocation entry
-                // System.out.println("getELFRelocationType: PLT relocation type using X86_64_RELOC_BRANCH");
                 addend = -4; // Size in bytes of the patch location
                 // Relocation should be applied at the location after call operand
                 offset = offset + reloc.getSize() + addend;
                 break;
             }
-            case FOREIGN_CALL_DIRECT_FAR: {
-                // Create relocation entry
-                addend = -8; // Size in bytes of the patch location
-                // Relocation should be applied at the location after call operand
-                // 10 = 2 (jmp [r]) + 8 (imm64)
-                offset = offset + reloc.getSize() + addend - 2;
-                break;
-            }
-            case FOREIGN_CALL_INDIRECT:
             case JAVA_CALL_INDIRECT:
-            case STUB_CALL_INDIRECT: {
-                // Do nothing.
-                return;
-            }
-            case EXTERNAL_DATA_REFERENCE_FAR: {
-                // Create relocation entry
+            case METASPACE_GOT_REFERENCE:
+            case EXTERNAL_PLT_TO_GOT: {
                 addend = -4; // Size of 32-bit address of the GOT
                 /*
                  * Relocation should be applied before the test instruction to the move instruction.
-                 * offset points to the test instruction after the instruction that loads
-                 * the address of polling page. So set the offset appropriately.
+                 * reloc.getOffset() points to the test instruction after the instruction that loads the address of
+                 * polling page. So set the offset appropriately.
                  */
                 offset = offset + addend;
                 break;
             }
-            case METASPACE_GOT_REFERENCE:
-            case EXTERNAL_PLT_TO_GOT:
-            case STATIC_STUB_TO_STATIC_METHOD:
-            case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: {
-                addend = -4; // Size of 32-bit address of the GOT
-                /*
-                 * Relocation should be applied before the test instruction to
-                 * the move instruction. reloc.getOffset() points to the
-                 * test instruction after the instruction that loads the
-                 * address of polling page. So set the offset appropriately.
-                 */
-                offset = offset + addend;
-                break;
-            }
-            case EXTERNAL_GOT_TO_PLT:
-            case LOADTIME_ADDRESS: {
+            case EXTERNAL_GOT_TO_PLT: {
                 // this is load time relocations
                 break;
             }
@@ -396,27 +342,17 @@
         switch (ElfTargetInfo.getElfArch()) {
             case Elf64_Ehdr.EM_X86_64:
                 // Return R_X86_64_* entries based on relocType
-                if (relocType == RelocType.FOREIGN_CALL_DIRECT ||
-                    relocType == RelocType.JAVA_CALL_DIRECT ||
+                if (relocType == RelocType.JAVA_CALL_DIRECT ||
                     relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
                     elfRelocType = Elf64_Rela.R_X86_64_PLT32;
                 } else if (relocType == RelocType.STUB_CALL_DIRECT) {
                     elfRelocType = Elf64_Rela.R_X86_64_PC32;
-                } else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) {
-                    elfRelocType = Elf64_Rela.R_X86_64_64;
-                } else if (relocType == RelocType.FOREIGN_CALL_INDIRECT ||
-                           relocType == RelocType.JAVA_CALL_INDIRECT ||
-                           relocType == RelocType.STUB_CALL_INDIRECT) {
+                } else if (relocType == RelocType.JAVA_CALL_INDIRECT) {
                     elfRelocType = Elf64_Rela.R_X86_64_NONE;
-                } else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) {
-                    elfRelocType = Elf64_Rela.R_X86_64_GOTPCREL;
                 } else if (relocType == RelocType.METASPACE_GOT_REFERENCE ||
-                           relocType == RelocType.EXTERNAL_PLT_TO_GOT ||
-                           relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD ||
-                           relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) {
+                           relocType == RelocType.EXTERNAL_PLT_TO_GOT) {
                     elfRelocType = Elf64_Rela.R_X86_64_PC32;
-                } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT ||
-                           relocType == RelocType.LOADTIME_ADDRESS) {
+                } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT) {
                     elfRelocType = Elf64_Rela.R_X86_64_64;
                 } else {
                     assert false : "Unhandled relocation type: " + relocType;
@@ -428,9 +364,9 @@
         return elfRelocType;
     }
 
-    private void createElfRelocSections(ArrayList<ElfSection> sections,
-                                        ElfRelocTable elfRelocTable,
-                                        int symtabsectidx) {
+    private static void createElfRelocSections(ArrayList<ElfSection> sections,
+                                               ElfRelocTable elfRelocTable,
+                                               int symtabsectidx) {
 
         // Grab count before we create new sections
         int count = sections.size();
@@ -439,15 +375,11 @@
             if (elfRelocTable.getNumRelocs(i) > 0) {
                 ElfSection sect = sections.get(i);
                 String relname = ".rela" + sect.getName();
-                ElfSection relocSection = createByteSection(sections,
-                                                                    relname,
-                                                                    elfRelocTable.getRelocData(i),
-                                                                    false,
-                                                                    8,
-                                                                    0,
-                                                                    Elf64_Shdr.SHT_RELA);
-                        relocSection.setLink(symtabsectidx);
-                        relocSection.setInfo(sect.getSectionId());
+                ElfSection relocSection = createByteSection(sections, relname,
+                                                            elfRelocTable.getRelocData(i),
+                                                            false, 8, 0, Elf64_Shdr.SHT_RELA);
+                relocSection.setLink(symtabsectidx);
+                relocSection.setInfo(sect.getSectionId());
             }
         }
     }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/JMachORelocObject.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/JMachORelocObject.java	Thu Aug 24 21:06:33 2017 +0000
@@ -53,11 +53,8 @@
 import jdk.tools.jaotc.binformat.Relocation;
 import jdk.tools.jaotc.binformat.Relocation.RelocType;
 import jdk.tools.jaotc.binformat.Symbol;
-import jdk.tools.jaotc.binformat.NativeSymbol;
-import jdk.tools.jaotc.binformat.Symbol.Binding;
 import jdk.tools.jaotc.binformat.Symbol.Kind;
 
-import jdk.tools.jaotc.binformat.macho.MachO;
 import jdk.tools.jaotc.binformat.macho.MachO.section_64;
 import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64;
 import jdk.tools.jaotc.binformat.macho.MachO.segment_command_64;
@@ -85,7 +82,7 @@
         this.segmentSize = binContainer.getCodeSegmentSize();
     }
 
-    private void createByteSection(ArrayList<MachOSection>sections,
+    private void createByteSection(ArrayList<MachOSection> sections,
                                    ByteContainer c, String sectName, String segName, int scnFlags) {
 
         if (c.getByteArray().length == 0) {
@@ -102,24 +99,24 @@
         sections.add(sect);
 
         // Record the section Id (0 relative)
-        c.setSectionId(sections.size()-1);
+        c.setSectionId(sections.size() - 1);
 
         // TODO: Clear out code section data to allow for GC
         // c.clear();
     }
 
-    private void createCodeSection(ArrayList<MachOSection>sections, CodeContainer c) {
-        createByteSection(sections, c, /*c.getContainerName()*/ "__text", "__TEXT",
-                          section_64.S_ATTR_PURE_INSTRUCTIONS|
+    private void createCodeSection(ArrayList<MachOSection> sections, CodeContainer c) {
+        createByteSection(sections, c, /* c.getContainerName() */ "__text", "__TEXT",
+                          section_64.S_ATTR_PURE_INSTRUCTIONS |
                           section_64.S_ATTR_SOME_INSTRUCTIONS);
     }
 
-    private void createReadOnlySection(ArrayList<MachOSection>sections, ReadOnlyDataContainer c) {
+    private void createReadOnlySection(ArrayList<MachOSection> sections, ReadOnlyDataContainer c) {
         createByteSection(sections, c, c.getContainerName(), "__TEXT",
                           section_64.S_ATTR_SOME_INSTRUCTIONS);
     }
 
-    private void createReadWriteSection(ArrayList<MachOSection>sections, ByteContainer c) {
+    private void createReadWriteSection(ArrayList<MachOSection> sections, ByteContainer c) {
         createByteSection(sections, c, c.getContainerName(), "__DATA", section_64.S_REGULAR);
     }
 
@@ -140,7 +137,7 @@
 
         MachOHeader mh = new MachOHeader();
 
-        ArrayList<MachOSection> sections = new ArrayList<MachOSection>();
+        ArrayList<MachOSection> sections = new ArrayList<>();
 
         // Create Sections contained in the main Segment LC_SEGMENT_64
 
@@ -149,21 +146,19 @@
         createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer());
         createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer());
         createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer());
-        createReadWriteSection(sections, binContainer.getMetaspaceGotContainer());
-        createReadWriteSection(sections, binContainer.getMetadataGotContainer());
-        createReadWriteSection(sections, binContainer.getMethodStateContainer());
-        createReadWriteSection(sections, binContainer.getOopGotContainer());
-        createReadWriteSection(sections, binContainer.getMethodMetadataContainer());
+        createReadOnlySection(sections, binContainer.getMethodMetadataContainer());
         createReadOnlySection(sections, binContainer.getStubsOffsetsContainer());
         createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer());
         createReadOnlySection(sections, binContainer.getCodeSegmentsContainer());
         createReadOnlySection(sections, binContainer.getConstantDataContainer());
         createReadOnlySection(sections, binContainer.getConfigContainer());
-
-        // createExternalLinkage();
+        createReadWriteSection(sections, binContainer.getKlassesGotContainer());
+        createReadWriteSection(sections, binContainer.getCountersGotContainer());
+        createReadWriteSection(sections, binContainer.getMetadataGotContainer());
+        createReadWriteSection(sections, binContainer.getMethodStateContainer());
+        createReadWriteSection(sections, binContainer.getOopGotContainer());
+        createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer());
 
-        createCodeSection(sections, binContainer.getExtLinkageContainer());
-        createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer());
         // Update the Header sizeofcmds size.
         // This doesn't include the Header struct size
         mh.setCmdSizes(4, segment_command_64.totalsize +
@@ -175,14 +170,14 @@
         // Initialize file offset for data past commands
         int file_offset = mach_header_64.totalsize + mh.getCmdSize();
         // and round it up
-        file_offset = (file_offset + (sections.get(0).getAlign()-1)) & ~((sections.get(0).getAlign()-1));
+        file_offset = (file_offset + (sections.get(0).getAlign() - 1)) & ~((sections.get(0).getAlign() - 1));
         long address = 0;
         int segment_offset = file_offset;
 
         for (int i = 0; i < sections.size(); i++) {
             MachOSection sect = sections.get(i);
-            file_offset = (file_offset + (sect.getAlign()-1)) & ~((sect.getAlign()-1));
-            address = (address + (sect.getAlign()-1)) & ~((sect.getAlign()-1));
+            file_offset = (file_offset + (sect.getAlign() - 1)) & ~((sect.getAlign() - 1));
+            address = (address + (sect.getAlign() - 1)) & ~((sect.getAlign() - 1));
             sect.setOffset(file_offset);
             sect.setAddr(address);
             file_offset += sect.getSize();
@@ -199,7 +194,6 @@
                                             segment_size,
                                             sections.size());
 
-
         MachOVersion vers = new MachOVersion();
 
         // Get symbol data from BinaryContainer object's symbol tables
@@ -213,7 +207,7 @@
         // Create the Relocation Tables
         MachORelocTable machORelocs = createMachORelocTable(sections, relocationTable, symtab);
         // Calculate file offset for relocation data
-        file_offset = (file_offset + (machORelocs.getAlign()-1)) & ~((machORelocs.getAlign()-1));
+        file_offset = (file_offset + (MachORelocTable.getAlign() - 1)) & ~((MachORelocTable.getAlign() - 1));
 
         // Update relocation sizing information in each section
         for (int i = 0; i < sections.size(); i++) {
@@ -227,10 +221,9 @@
         }
 
         // Calculate and set file offset for symbol table data
-        file_offset = (file_offset + (symtab.getAlign()-1)) & ~((symtab.getAlign()-1));
+        file_offset = (file_offset + (MachOSymtab.getAlign() - 1)) & ~((MachOSymtab.getAlign() - 1));
         symtab.setOffset(file_offset);
 
-
         // Write Out Header
         machoContainer.writeBytes(mh.getArray());
         // Write out first Segment
@@ -259,12 +252,13 @@
 
         // Write out the relocation tables for all sections
         for (int i = 0; i < sections.size(); i++) {
-            if (machORelocs.getNumRelocs(i) > 0)
-                machoContainer.writeBytes(machORelocs.getRelocData(i), machORelocs.getAlign());
+            if (machORelocs.getNumRelocs(i) > 0) {
+                machoContainer.writeBytes(machORelocs.getRelocData(i), MachORelocTable.getAlign());
+            }
         }
 
         // Write out data associated with LC_SYMTAB
-        machoContainer.writeBytes(symtab.getDataArray(), symtab.getAlign());
+        machoContainer.writeBytes(symtab.getDataArray(), MachOSymtab.getAlign());
 
         machoContainer.close();
     }
@@ -273,14 +267,14 @@
      * Construct MachO symbol data from BinaryContainer object's symbol tables. Both dynamic MachO
      * symbol table and MachO symbol table are created from BinaryContainer's symbol info.
      *
+     * @param sections
      * @param symbols
-     * @param symtab
      */
-    private MachOSymtab createMachOSymbolTables(ArrayList<MachOSection>sections,
-                                         Collection<Symbol> symbols) {
+    private static MachOSymtab createMachOSymbolTables(ArrayList<MachOSection> sections,
+                                                       Collection<Symbol> symbols) {
         MachOSymtab symtab = new MachOSymtab();
         // First, create the initial null symbol. This is a local symbol.
-        symtab.addSymbolEntry("", (byte)nlist_64.N_UNDF, (byte)0, (long)0);
+        symtab.addSymbolEntry("", (byte) nlist_64.N_UNDF, (byte) 0, 0);
 
         // Now create MachO symbol entries for all symbols.
         for (Symbol symbol : symbols) {
@@ -290,14 +284,14 @@
             long sectionAddr = sections.get(sectionId).getAddr();
 
             MachOSymbol machoSymbol = symtab.addSymbolEntry(symbol.getName(),
-                                         getMachOTypeOf(symbol),
-                                         (byte)sectionId,
-                                         symbol.getOffset() + sectionAddr);
-            symbol.setNativeSymbol((NativeSymbol)machoSymbol);
+                                                            getMachOTypeOf(symbol),
+                                                            (byte) sectionId,
+                                                            symbol.getOffset() + sectionAddr);
+            symbol.setNativeSymbol(machoSymbol);
         }
 
         // Now that all symbols are enterred, update the
-        // symbol indexes.  This is necessary since they will
+        // symbol indexes. This is necessary since they will
         // be reordered based on local, global and undefined.
         symtab.updateIndexes();
 
@@ -309,9 +303,9 @@
         byte type = nlist_64.N_UNDF;
 
         // Global or Local
-        if (sym.getBinding() == Symbol.Binding.GLOBAL)
+        if (sym.getBinding() == Symbol.Binding.GLOBAL) {
             type = nlist_64.N_EXT;
-
+        }
         // If Function or Data, add section type
         if (kind == Symbol.Kind.NATIVE_FUNCTION ||
             kind == Symbol.Kind.JAVA_FUNCTION   ||
@@ -335,8 +329,7 @@
 
         MachORelocTable machORelocTable = new MachORelocTable(sections.size());
         /*
-         * For each of the symbols with associated relocation records, create a MachO relocation
-         * entry.
+         * For each of the symbols with associated relocation records, create a MachO relocation entry.
          */
         for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) {
             List<Relocation> relocs = entry.getValue();
@@ -354,11 +347,11 @@
         return (machORelocTable);
     }
 
-    private void createRelocation(Symbol symbol, Relocation reloc, MachORelocTable machORelocTable) {
+    private static void createRelocation(Symbol symbol, Relocation reloc, MachORelocTable machORelocTable) {
         RelocType relocType = reloc.getType();
 
         int machORelocType = getMachORelocationType(relocType);
-        MachOSymbol sym = (MachOSymbol)symbol.getNativeSymbol();
+        MachOSymbol sym = (MachOSymbol) symbol.getNativeSymbol();
         int symno = sym.getIndex();
         int sectindex = reloc.getSection().getSectionId();
         int offset = reloc.getOffset();
@@ -366,73 +359,39 @@
         int length = 0;
         int isextern = 1;
 
-/*
-        System.out.println("reloctype: " + relocType + " size is " +
-                            reloc.getSize() + " offset is " + offset +
-                            " Section Index is " + (sectindex) +
-                            " Symbol Index is " + symno +
-                            " Symbol Name is " + symbol.getName() + "\n");
-*/
-
         switch (relocType) {
-            case FOREIGN_CALL_DIRECT:
             case JAVA_CALL_DIRECT:
             case STUB_CALL_DIRECT:
             case FOREIGN_CALL_INDIRECT_GOT: {
                 // Create relocation entry
-                // System.out.println("getMachORelocationType: PLT relocation type using X86_64_RELOC_BRANCH");
                 int addend = -4; // Size in bytes of the patch location
                 // Relocation should be applied at the location after call operand
                 offset = offset + reloc.getSize() + addend;
-                pcrel = 1; length = 2;
+                pcrel = 1;
+                length = 2;
                 break;
             }
-            case FOREIGN_CALL_DIRECT_FAR: {
-                // Create relocation entry
-                int addend = -8; // Size in bytes of the patch location
-                // Relocation should be applied at the location after call operand
-                // 10 = 2 (jmp [r]) + 8 (imm64)
-                offset = offset + reloc.getSize() + addend - 2;
-                pcrel = 0; length = 3;
-                break;
-            }
-            case FOREIGN_CALL_INDIRECT:
-            case JAVA_CALL_INDIRECT:
-            case STUB_CALL_INDIRECT: {
+            case JAVA_CALL_INDIRECT: {
                 // Do nothing.
                 return;
             }
-            case EXTERNAL_DATA_REFERENCE_FAR: {
-                // Create relocation entry
+            case METASPACE_GOT_REFERENCE:
+            case EXTERNAL_PLT_TO_GOT: {
                 int addend = -4; // Size of 32-bit address of the GOT
                 /*
                  * Relocation should be applied before the test instruction to the move instruction.
-                 * offset points to the test instruction after the instruction that loads
-                 * the address of polling page. So set the offset appropriately.
+                 * reloc.getOffset() points to the test instruction after the instruction that loads the address of
+                 * polling page. So set the offset appropriately.
                  */
                 offset = offset + addend;
-                pcrel = 0; length = 2;
+                pcrel = 1;
+                length = 2;
                 break;
             }
-            case METASPACE_GOT_REFERENCE:
-            case EXTERNAL_PLT_TO_GOT:
-            case STATIC_STUB_TO_STATIC_METHOD:
-            case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: {
-                int addend = -4; // Size of 32-bit address of the GOT
-                /*
-                 * Relocation should be applied before the test instruction to
-                 * the move instruction. reloc.getOffset() points to the
-                 * test instruction after the instruction that loads the
-                 * address of polling page. So set the offset appropriately.
-                 */
-                offset = offset + addend;
-                pcrel = 1; length = 2;
-                break;
-            }
-            case EXTERNAL_GOT_TO_PLT:
-            case LOADTIME_ADDRESS: {
+            case EXTERNAL_GOT_TO_PLT: {
                 // this is load time relocations
-                pcrel = 0; length = 3;
+                pcrel = 0;
+                length = 3;
                 break;
             }
             default:
@@ -448,20 +407,17 @@
         switch (MachOTargetInfo.getMachOArch()) {
             case mach_header_64.CPU_TYPE_X86_64:
                 // Return X86_64_RELOC_* entries based on relocType
-                if (relocType == RelocType.FOREIGN_CALL_DIRECT || relocType == RelocType.JAVA_CALL_DIRECT || relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
+                if (relocType == RelocType.JAVA_CALL_DIRECT ||
+                    relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
                     machORelocType = reloc_info.X86_64_RELOC_BRANCH;
                 } else if (relocType == RelocType.STUB_CALL_DIRECT) {
                     machORelocType = reloc_info.X86_64_RELOC_BRANCH;
-                } else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) {
-                    machORelocType = reloc_info.X86_64_RELOC_UNSIGNED;
-                } else if (relocType == RelocType.FOREIGN_CALL_INDIRECT || relocType == RelocType.JAVA_CALL_INDIRECT || relocType == RelocType.STUB_CALL_INDIRECT) {
+                } else if (relocType == RelocType.JAVA_CALL_INDIRECT) {
                     machORelocType = reloc_info.X86_64_RELOC_NONE;
-                } else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) {
-                    machORelocType = reloc_info.X86_64_RELOC_GOT;
-                } else if (relocType == RelocType.METASPACE_GOT_REFERENCE || relocType == RelocType.EXTERNAL_PLT_TO_GOT || relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD ||
-                                relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) {
+                } else if (relocType == RelocType.METASPACE_GOT_REFERENCE ||
+                           relocType == RelocType.EXTERNAL_PLT_TO_GOT) {
                     machORelocType = reloc_info.X86_64_RELOC_BRANCH;
-                } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT || relocType == RelocType.LOADTIME_ADDRESS) {
+                } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT) {
                     machORelocType = reloc_info.X86_64_RELOC_UNSIGNED;
                 } else {
                     assert false : "Unhandled relocation type: " + relocType;
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachO.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachO.java	Thu Aug 24 21:06:33 2017 +0000
@@ -23,10 +23,10 @@
 
 package jdk.tools.jaotc.binformat.macho;
 
+//@formatter:off
 /**
  *
- * Support for the creation of Mach-o Object files.
- * Current support is limited to 64 bit x86_64.
+ * Support for the creation of Mach-o Object files. Current support is limited to 64 bit x86_64.
  *
  * File Format Overview:
  *
@@ -38,12 +38,12 @@
  *      (which each include multiple Sections)
  */
 
-public class MachO {
+final class MachO {
 
     /**
      * mach_header_64 structure defines
      */
-    public enum mach_header_64 {
+    enum mach_header_64 {
                  magic( 0, 4),
                cputype( 4, 4),
             cpusubtype( 8, 4),
@@ -53,49 +53,49 @@
                  flags(24, 4),
               reserved(28, 4);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         mach_header_64(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 32;
+        static int totalsize = 32;
 
         /**
          * mach_header_64 defines
          */
-        public static final int MH_MAGIC                   = 0xfeedface;
-        public static final int MH_MAGIC_64                = 0xfeedfacf;
-        public static final int MH_SUBSECTIONS_VIA_SYMBOLS = 0x2000;
+        static final int MH_MAGIC                   = 0xfeedface;
+        static final int MH_MAGIC_64                = 0xfeedfacf;
+        static final int MH_SUBSECTIONS_VIA_SYMBOLS = 0x2000;
 
         /**
          * filetype
          */
-        public static final int MH_OBJECT = 0x1;
+        static final int MH_OBJECT = 0x1;
 
         /**
          * cputype
          */
-        public static final int CPU_TYPE_ANY              = -1;
-        public static final int CPU_ARCH_ABI64            = 0x1000000;
-        public static final int CPU_TYPE_X86_64           = 0x1000007;
-        public static final int CPU_TYPE_ARM64            = 0x100000c;
+        static final int CPU_TYPE_ANY              = -1;
+        static final int CPU_ARCH_ABI64            = 0x1000000;
+        static final int CPU_TYPE_X86_64           = 0x1000007;
+        static final int CPU_TYPE_ARM64            = 0x100000c;
         /**
          * cpusubtype
          */
-        public static final int CPU_SUBTYPE_I386_ALL      = 3;
-        public static final int CPU_SUBTYPE_ARM64_ALL     = 0;
-        public static final int CPU_SUBTYPE_LITTLE_ENDIAN = 0;
-        public static final int CPU_SUBTYPE_BIG_ENDIAN    = 1;
+        static final int CPU_SUBTYPE_I386_ALL      = 3;
+        static final int CPU_SUBTYPE_ARM64_ALL     = 0;
+        static final int CPU_SUBTYPE_LITTLE_ENDIAN = 0;
+        static final int CPU_SUBTYPE_BIG_ENDIAN    = 1;
 
     }
 
     /**
      * segment_command_64 structure defines
      */
-    public enum segment_command_64 {
+    enum segment_command_64 {
                    cmd( 0, 4),
                cmdsize( 4, 4),
                segname( 8,16),
@@ -108,23 +108,23 @@
                 nsects(64, 4),
                  flags(68, 4);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         segment_command_64(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 72;
+        static int totalsize = 72;
 
-        public static final int LC_SEGMENT_64           = 0x19;
+        static final int LC_SEGMENT_64           = 0x19;
     }
 
     /**
      * section_64 structure defines
      */
-    public enum section_64 {
+    enum section_64 {
               sectname( 0,16),
                segname(16,16),
                   addr(32, 8),
@@ -138,49 +138,49 @@
              reserved2(72, 4),
              reserved3(76, 4);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         section_64(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 80;
+        static int totalsize = 80;
 
-        public static int S_REGULAR                = 0x0;
-        public static int S_CSTRING_LITERALS       = 0x2;
-        public static int S_ATTR_PURE_INSTRUCTIONS = 0x80000000;
-        public static int S_ATTR_SOME_INSTRUCTIONS = 0x400;
+        static int S_REGULAR                = 0x0;
+        static int S_CSTRING_LITERALS       = 0x2;
+        static int S_ATTR_PURE_INSTRUCTIONS = 0x80000000;
+        static int S_ATTR_SOME_INSTRUCTIONS = 0x400;
     }
 
     /**
      * version_min_command structure defines
      */
-    public enum version_min_command {
+    enum version_min_command {
                    cmd( 0, 4),
                cmdsize( 4, 4),
                version( 8, 4),
                    sdk(12, 4);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         version_min_command(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 16;
+        static int totalsize = 16;
 
-        public static final int LC_VERSION_MIN_MACOSX   = 0x24;
-        public static final int LC_VERSION_MIN_IPHONEOS = 0x25;
+        static final int LC_VERSION_MIN_MACOSX   = 0x24;
+        static final int LC_VERSION_MIN_IPHONEOS = 0x25;
     }
 
     /**
      * symtab_command structure defines
      */
-    public enum symtab_command {
+    enum symtab_command {
                    cmd( 0, 4),
                cmdsize( 4, 4),
                 symoff( 8, 4),
@@ -188,17 +188,17 @@
                 stroff(16, 4),
                strsize(20, 4);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         symtab_command(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 24;
+        static int totalsize = 24;
 
-        public static final int LC_SYMTAB               = 0x2;
+        static final int LC_SYMTAB               = 0x2;
     }
 
     /**
@@ -206,33 +206,33 @@
      *
      * nlist_64 structure defines
      */
-    public enum nlist_64 {
+    enum nlist_64 {
                 n_strx( 0, 4),
                 n_type( 4, 1),
                 n_sect( 5, 1),
                 n_desc( 6, 2),
                n_value( 8, 8);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         nlist_64(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 16;
+        static int totalsize = 16;
 
-        public static final int N_EXT                = 0x1;
-        public static final int N_TYPE               = 0xe;
-        public static final int N_UNDF               = 0x0;
-        public static final int N_SECT               = 0xe;
+        static final int N_EXT                = 0x1;
+        static final int N_TYPE               = 0xe;
+        static final int N_UNDF               = 0x0;
+        static final int N_SECT               = 0xe;
     }
 
     /**
      * dysymtab_command structure defines
      */
-    public enum dysymtab_command {
+    enum dysymtab_command {
                    cmd( 0, 4),
                cmdsize( 4, 4),
              ilocalsym( 8, 4),
@@ -254,54 +254,55 @@
              locreloff(72, 4),
                nlocrel(76, 4);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         dysymtab_command(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 80;
+        static int totalsize = 80;
 
-        public static final int LC_DYSYMTAB             = 0xb;
+        static final int LC_DYSYMTAB             = 0xb;
     }
 
     /**
      * relocation_info structure defines
      */
-    public enum reloc_info {
+    enum reloc_info {
              r_address( 0, 4),
            r_relocinfo( 4, 4);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         reloc_info(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 8;
+        static int totalsize = 8;
 
-        public static final int REL_SYMNUM_MASK         = 0xffffff;
-        public static final int REL_SYMNUM_SHIFT        = 0x0;
-        public static final int REL_PCREL_MASK          = 0x1;
-        public static final int REL_PCREL_SHIFT         = 0x18;
-        public static final int REL_LENGTH_MASK         = 0x3;
-        public static final int REL_LENGTH_SHIFT        = 0x19;
-        public static final int REL_EXTERN_MASK         = 0x1;
-        public static final int REL_EXTERN_SHIFT        = 0x1b;
-        public static final int REL_TYPE_MASK           = 0xf;
-        public static final int REL_TYPE_SHIFT          = 0x1c;
+        static final int REL_SYMNUM_MASK         = 0xffffff;
+        static final int REL_SYMNUM_SHIFT        = 0x0;
+        static final int REL_PCREL_MASK          = 0x1;
+        static final int REL_PCREL_SHIFT         = 0x18;
+        static final int REL_LENGTH_MASK         = 0x3;
+        static final int REL_LENGTH_SHIFT        = 0x19;
+        static final int REL_EXTERN_MASK         = 0x1;
+        static final int REL_EXTERN_SHIFT        = 0x1b;
+        static final int REL_TYPE_MASK           = 0xf;
+        static final int REL_TYPE_SHIFT          = 0x1c;
 
         /* reloc_type_x86_64 defines */
 
-        public static final int X86_64_RELOC_NONE      = 0x0;
-        public static final int X86_64_RELOC_BRANCH    = 0x2;
-        public static final int X86_64_RELOC_GOT       = 0x4;
-        public static final int X86_64_RELOC_GOT_LOAD  = 0x3;
-        public static final int X86_64_RELOC_SIGNED    = 0x1;
-        public static final int X86_64_RELOC_UNSIGNED  = 0x0;
+        static final int X86_64_RELOC_NONE      = 0x0;
+        static final int X86_64_RELOC_BRANCH    = 0x2;
+        static final int X86_64_RELOC_GOT       = 0x4;
+        static final int X86_64_RELOC_GOT_LOAD  = 0x3;
+        static final int X86_64_RELOC_SIGNED    = 0x1;
+        static final int X86_64_RELOC_UNSIGNED  = 0x0;
     }
 }
+//@formatter:on
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOByteBuffer.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOByteBuffer.java	Thu Aug 24 21:06:33 2017 +0000
@@ -23,21 +23,19 @@
 
 package jdk.tools.jaotc.binformat.macho;
 
-
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import jdk.tools.jaotc.binformat.macho.MachOTargetInfo;
-import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64;
 
-public class MachOByteBuffer {
+final class MachOByteBuffer {
 
-    public static ByteBuffer allocate(int size) {
+    static ByteBuffer allocate(int size) {
         ByteBuffer buf = ByteBuffer.allocate(size);
-        if (MachOTargetInfo.getMachOEndian() ==
-            MachO.mach_header_64.CPU_SUBTYPE_LITTLE_ENDIAN)
+        if (MachOTargetInfo.getMachOEndian() == MachO.mach_header_64.CPU_SUBTYPE_LITTLE_ENDIAN) {
             buf.order(ByteOrder.LITTLE_ENDIAN);
-        else
+        } else {
             buf.order(ByteOrder.BIG_ENDIAN);
+        }
         return (buf);
     }
 
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOContainer.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOContainer.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,14 +26,13 @@
 import java.io.File;
 import java.io.FileOutputStream;
 
-public class MachOContainer {
+final class MachOContainer {
 
-    File outputFile;
-    FileOutputStream outputStream;
-    long fileOffset;
+    private final File outputFile;
+    private FileOutputStream outputStream;
+    private long fileOffset;
 
-    public MachOContainer(String fileName) {
-        String baseName;
+    MachOContainer(String fileName) {
 
         outputFile = new File(fileName);
         if (outputFile.exists()) {
@@ -48,7 +47,7 @@
         fileOffset = 0;
     }
 
-    public void close() {
+    void close() {
         try {
             outputStream.close();
         } catch (Exception e) {
@@ -56,7 +55,7 @@
         }
     }
 
-    public void writeBytes(byte [] bytes) {
+    void writeBytes(byte[] bytes) {
         try {
             outputStream.write(bytes);
         } catch (Exception e) {
@@ -66,10 +65,10 @@
     }
 
     // Write bytes to output file with up front alignment padding
-    public void writeBytes(byte [] bytes, int alignment) {
+    void writeBytes(byte[] bytes, int alignment) {
         try {
             // Pad to alignment
-            while ((fileOffset & (long)(alignment-1)) != 0) {
+            while ((fileOffset & (alignment - 1)) != 0) {
                 outputStream.write(0);
                 fileOffset++;
             }
@@ -80,4 +79,3 @@
         fileOffset += bytes.length;
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachODySymtab.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachODySymtab.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,16 +24,14 @@
 package jdk.tools.jaotc.binformat.macho;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
-import jdk.tools.jaotc.binformat.macho.MachO;
 import jdk.tools.jaotc.binformat.macho.MachO.dysymtab_command;
 import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
 
-public class MachODySymtab {
-    ByteBuffer dysymtab;
+final class MachODySymtab {
+    private final ByteBuffer dysymtab;
 
-    public MachODySymtab(int nlocal, int nglobal, int nundef) {
+    MachODySymtab(int nlocal, int nglobal, int nundef) {
         dysymtab = MachOByteBuffer.allocate(dysymtab_command.totalsize);
 
         dysymtab.putInt(dysymtab_command.cmd.off, dysymtab_command.LC_DYSYMTAB);
@@ -42,13 +40,11 @@
         dysymtab.putInt(dysymtab_command.nlocalsym.off, nlocal);
         dysymtab.putInt(dysymtab_command.iextdefsym.off, nlocal);
         dysymtab.putInt(dysymtab_command.nextdefsym.off, nglobal);
-        dysymtab.putInt(dysymtab_command.iundefsym.off, nlocal+nglobal);
+        dysymtab.putInt(dysymtab_command.iundefsym.off, nlocal + nglobal);
         dysymtab.putInt(dysymtab_command.nundefsym.off, nundef);
     }
 
-    public byte[] getArray() {
+    byte[] getArray() {
         return dysymtab.array();
     }
 }
-
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOHeader.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOHeader.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,17 +24,15 @@
 package jdk.tools.jaotc.binformat.macho;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
-import jdk.tools.jaotc.binformat.macho.MachO;
 import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64;
 import jdk.tools.jaotc.binformat.macho.MachOTargetInfo;
 import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
 
-public class MachOHeader {
-    ByteBuffer header;
+final class MachOHeader {
+    private final ByteBuffer header;
 
-    public MachOHeader() {
+    MachOHeader() {
         header = MachOByteBuffer.allocate(mach_header_64.totalsize);
 
         header.putInt(mach_header_64.magic.off, mach_header_64.MH_MAGIC_64);
@@ -44,17 +42,16 @@
         header.putInt(mach_header_64.filetype.off, mach_header_64.MH_OBJECT);
     }
 
-    public void setCmdSizes(int ncmds, int sizeofcmds) {
+    void setCmdSizes(int ncmds, int sizeofcmds) {
         header.putInt(mach_header_64.ncmds.off, ncmds);
         header.putInt(mach_header_64.sizeofcmds.off, sizeofcmds);
     }
 
-    public int getCmdSize() {
+    int getCmdSize() {
         return (header.getInt(mach_header_64.sizeofcmds.off));
     }
 
-    public byte[] getArray() {
+    byte[] getArray() {
         return header.array();
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocEntry.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocEntry.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,42 +24,31 @@
 package jdk.tools.jaotc.binformat.macho;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
-import jdk.tools.jaotc.binformat.macho.MachO;
 import jdk.tools.jaotc.binformat.macho.MachO.reloc_info;
 import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
 
-public class MachORelocEntry {
-    ByteBuffer entry;
+final class MachORelocEntry {
+    private final ByteBuffer entry;
 
-    public MachORelocEntry(int offset,
-                           int symno,
-                           int pcrel,
-                           int length,
-                           int isextern,
-                           int type) {
+    MachORelocEntry(int offset, int symno, int pcrel, int length, int isextern, int type) {
 
         entry = MachOByteBuffer.allocate(reloc_info.totalsize);
 
         entry.putInt(reloc_info.r_address.off, offset);
 
         // Encode and store the relocation entry bitfields
+        // @formatter:off
         entry.putInt(reloc_info.r_relocinfo.off,
-            ((symno & reloc_info.REL_SYMNUM_MASK)
-             << reloc_info.REL_SYMNUM_SHIFT) |
-            ((pcrel & reloc_info.REL_PCREL_MASK)
-             << reloc_info.REL_PCREL_SHIFT) |
-            ((length & reloc_info.REL_LENGTH_MASK)
-             << reloc_info.REL_LENGTH_SHIFT) |
-            ((isextern & reloc_info.REL_EXTERN_MASK)
-             << reloc_info.REL_EXTERN_SHIFT) |
-            ((type & reloc_info.REL_TYPE_MASK)
-             << reloc_info.REL_TYPE_SHIFT));
+            ((symno    & reloc_info.REL_SYMNUM_MASK) << reloc_info.REL_SYMNUM_SHIFT) |
+            ((pcrel    & reloc_info.REL_PCREL_MASK)  << reloc_info.REL_PCREL_SHIFT)  |
+            ((length   & reloc_info.REL_LENGTH_MASK) << reloc_info.REL_LENGTH_SHIFT) |
+            ((isextern & reloc_info.REL_EXTERN_MASK) << reloc_info.REL_EXTERN_SHIFT) |
+            ((type     & reloc_info.REL_TYPE_MASK)   << reloc_info.REL_TYPE_SHIFT));
+        // @formatter:on
     }
 
-    public byte[] getArray() {
+    byte[] getArray() {
         return entry.array();
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocTable.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocTable.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,56 +25,43 @@
 
 import java.util.ArrayList;
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
 import jdk.tools.jaotc.binformat.macho.MachORelocEntry;
-import jdk.tools.jaotc.binformat.macho.MachOTargetInfo;
 import jdk.tools.jaotc.binformat.macho.MachO.reloc_info;
 import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
 
-public class MachORelocTable {
-    ArrayList<ArrayList<MachORelocEntry>> relocEntries;
+final class MachORelocTable {
+    private final ArrayList<ArrayList<MachORelocEntry>> relocEntries;
     int fileOffset;
 
-    public MachORelocTable(int numsects) {
-        relocEntries = new ArrayList<ArrayList<MachORelocEntry>>(numsects);
-        for (int i = 0; i < numsects; i++)
+    MachORelocTable(int numsects) {
+        relocEntries = new ArrayList<>(numsects);
+        for (int i = 0; i < numsects; i++) {
             relocEntries.add(new ArrayList<MachORelocEntry>());
+        }
     }
 
-    public void createRelocationEntry(int sectindex,
-                                 int offset,
-                                 int symno,
-                                 int pcrel,
-                                 int length,
-                                 int isextern,
-                                 int type) {
-
-        MachORelocEntry entry = new MachORelocEntry(offset,
-                                                    symno,
-                                                    pcrel,
-                                                    length,
-                                                    isextern,
-                                                    type);
+    void createRelocationEntry(int sectindex, int offset, int symno, int pcrel, int length, int isextern, int type) {
+        MachORelocEntry entry = new MachORelocEntry(offset, symno, pcrel, length, isextern, type);
         relocEntries.get(sectindex).add(entry);
     }
 
-    public int getAlign() {
+    static int getAlign() {
         return (4);
     }
 
-    public int getNumRelocs(int section_index) {
+    int getNumRelocs(int section_index) {
         return relocEntries.get(section_index).size();
     }
 
     // Return the relocation entries for a single section
-    //   or null if no entries added to section
-    public byte [] getRelocData(int section_index) {
+    // or null if no entries added to section
+    byte[] getRelocData(int section_index) {
         ArrayList<MachORelocEntry> entryList = relocEntries.get(section_index);
 
-        if (entryList.size() == 0)
+        if (entryList.size() == 0) {
             return null;
-
+        }
         ByteBuffer relocData = MachOByteBuffer.allocate(entryList.size() * reloc_info.totalsize);
 
         // Copy each entry to a single ByteBuffer
@@ -86,4 +73,3 @@
         return (relocData.array());
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSection.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSection.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,41 +24,36 @@
 package jdk.tools.jaotc.binformat.macho;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
-import jdk.tools.jaotc.binformat.macho.MachO;
 import jdk.tools.jaotc.binformat.macho.MachO.section_64;
 import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
 
-public class MachOSection {
-    ByteBuffer section;
-    byte [] data;
-    boolean hasrelocations;
+final class MachOSection {
+    private final ByteBuffer section;
+    private final byte[] data;
+    private final boolean hasrelocations;
 
-    public MachOSection(String sectName, String segName, byte [] sectData, int sectFlags, boolean hasRelocations, int align) {
+    MachOSection(String sectName, String segName, byte[] sectData, int sectFlags, boolean hasRelocations, int align) {
         section = MachOByteBuffer.allocate(section_64.totalsize);
 
         // TODO: Hotspot uses long section names.
-        //       They are getting truncated.
-        //       Is this a problem??
+        // They are getting truncated.
+        // Is this a problem??
         byte[] sectNameBytes = sectName.getBytes();
-        int sectNameMax = section_64.sectname.sz < sectNameBytes.length ?
-                         section_64.sectname.sz : sectNameBytes.length;
+        int sectNameMax = section_64.sectname.sz < sectNameBytes.length ? section_64.sectname.sz : sectNameBytes.length;
 
-        for (int i = 0; i < sectNameMax; i++)
-            section.put(section_64.sectname.off+i, sectNameBytes[i]);
-
+        for (int i = 0; i < sectNameMax; i++) {
+            section.put(section_64.sectname.off + i, sectNameBytes[i]);
+        }
         byte[] segNameBytes = segName.getBytes();
-        int segNameMax = section_64.segname.sz < segNameBytes.length ?
-                         section_64.segname.sz : segNameBytes.length;
+        int segNameMax = section_64.segname.sz < segNameBytes.length ? section_64.segname.sz : segNameBytes.length;
 
-        for (int i = 0; i < segNameMax; i++)
-            section.put(section_64.segname.off+i, segNameBytes[i]);
-
+        for (int i = 0; i < segNameMax; i++) {
+            section.put(section_64.segname.off + i, segNameBytes[i]);
+        }
         section.putLong(section_64.size.off, sectData.length);
 
-        section.putInt(section_64.align.off,
-                       31 - Integer.numberOfLeadingZeros(align));
+        section.putInt(section_64.align.off, 31 - Integer.numberOfLeadingZeros(align));
 
         section.putInt(section_64.flags.off, sectFlags);
 
@@ -67,49 +62,47 @@
         hasrelocations = hasRelocations;
     }
 
-    public long getSize() {
+    long getSize() {
         return section.getLong(section_64.size.off);
     }
 
-    public int getAlign() {
+    int getAlign() {
         return (1 << section.getInt(section_64.align.off));
     }
 
-    public byte[] getArray() {
+    byte[] getArray() {
         return section.array();
     }
 
-    public byte[] getDataArray() {
+    byte[] getDataArray() {
         return data;
     }
 
-    public void setAddr(long addr) {
+    void setAddr(long addr) {
         section.putLong(section_64.addr.off, addr);
     }
 
-    public long getAddr() {
+    long getAddr() {
         return (section.getLong(section_64.addr.off));
     }
 
-    public void setOffset(int offset) {
+    void setOffset(int offset) {
         section.putInt(section_64.offset.off, offset);
     }
 
-    public int getOffset() {
+    int getOffset() {
         return (section.getInt(section_64.offset.off));
     }
 
-    public void setReloff(int offset) {
+    void setReloff(int offset) {
         section.putInt(section_64.reloff.off, offset);
     }
 
-    public void setRelcount(int count) {
+    void setRelcount(int count) {
         section.putInt(section_64.nreloc.off, count);
     }
 
-    public boolean hasRelocations() {
+    boolean hasRelocations() {
         return hasrelocations;
     }
 }
-
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSegment.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSegment.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,9 +24,7 @@
 package jdk.tools.jaotc.binformat.macho;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
-import jdk.tools.jaotc.binformat.macho.MachO;
 import jdk.tools.jaotc.binformat.macho.MachO.segment_command_64;
 import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
 
@@ -52,5 +50,3 @@
         return segment.array();
     }
 }
-
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymbol.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymbol.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,17 +24,15 @@
 package jdk.tools.jaotc.binformat.macho;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
 import jdk.tools.jaotc.binformat.NativeSymbol;
-import jdk.tools.jaotc.binformat.macho.MachO;
 import jdk.tools.jaotc.binformat.macho.MachO.nlist_64;
 import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
 
-public class MachOSymbol extends NativeSymbol {
-    ByteBuffer sym;
+final class MachOSymbol extends NativeSymbol {
+    private final ByteBuffer sym;
 
-    public MachOSymbol(int symbolindex, int strindex, byte type, byte sectindex, long offset) {
+    MachOSymbol(int symbolindex, int strindex, byte type, byte sectindex, long offset) {
         super(symbolindex);
         sym = MachOByteBuffer.allocate(nlist_64.totalsize);
 
@@ -42,13 +40,12 @@
         sym.put(nlist_64.n_type.off, type);
         // Section indexes start at 1 but we manage the index internally
         // as 0 relative
-        sym.put(nlist_64.n_sect.off, (byte)(sectindex+1));
-        sym.putChar(nlist_64.n_desc.off, (char )0);
+        sym.put(nlist_64.n_sect.off, (byte) (sectindex + 1));
+        sym.putChar(nlist_64.n_desc.off, (char) 0);
         sym.putLong(nlist_64.n_value.off, offset);
     }
 
-    public byte[] getArray() {
+    byte[] getArray() {
         return sym.array();
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymtab.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymtab.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,50 +24,42 @@
 package jdk.tools.jaotc.binformat.macho;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 import java.util.ArrayList;
 
-import jdk.tools.jaotc.binformat.macho.MachO;
 import jdk.tools.jaotc.binformat.macho.MachO.symtab_command;
 import jdk.tools.jaotc.binformat.macho.MachO.nlist_64;
 import jdk.tools.jaotc.binformat.macho.MachOSymbol;
 import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
 
-public class MachOSymtab {
+final class MachOSymtab {
 
     /**
      * ByteBuffer holding the LC_SYMTAB command contents
      */
-    ByteBuffer symtabCmd;
+    private final ByteBuffer symtabCmd;
+
+    private int symtabDataSize;
 
-    /**
-     * ByteBuffer holding the symbol table entries and strings
-     */
-    ByteBuffer symtabData;
-
-    int symtabDataSize;
-
-    ArrayList<MachOSymbol>localSymbols = new ArrayList<MachOSymbol>();
-    ArrayList<MachOSymbol>globalSymbols = new ArrayList<MachOSymbol>();
-    ArrayList<MachOSymbol>undefSymbols = new ArrayList<MachOSymbol>();
+    private final ArrayList<MachOSymbol> localSymbols = new ArrayList<>();
+    private final ArrayList<MachOSymbol> globalSymbols = new ArrayList<>();
+    private final ArrayList<MachOSymbol> undefSymbols = new ArrayList<>();
 
     /**
      * number of symbols added
      */
-    int symbolCount;
+    private int symbolCount;
 
     /**
      * String holding symbol table strings
      */
-    private StringBuilder strTabContent = new StringBuilder();
+    private final StringBuilder strTabContent = new StringBuilder();
 
     /**
-     * Keeps track of bytes in string table since strTabContent.length()
-     * is number of chars, not bytes.
+     * Keeps track of bytes in string table since strTabContent.length() is number of chars, not bytes.
      */
     private int strTabNrOfBytes = 0;
 
-    public MachOSymtab() {
+    MachOSymtab() {
         symtabCmd = MachOByteBuffer.allocate(symtab_command.totalsize);
 
         symtabCmd.putInt(symtab_command.cmd.off, symtab_command.LC_SYMTAB);
@@ -77,11 +69,11 @@
 
     }
 
-    public int getAlign() {
+    static int getAlign() {
         return (4);
     }
 
-    public MachOSymbol addSymbolEntry(String name, byte type, byte secHdrIndex, long offset) {
+    MachOSymbol addSymbolEntry(String name, byte type, byte secHdrIndex, long offset) {
         // Get the current symbol index and append symbol name to string table.
         int index;
         MachOSymbol sym;
@@ -109,7 +101,7 @@
                 case nlist_64.N_UNDF:  // null symbol
                     localSymbols.add(sym);
                     break;
-                case nlist_64.N_SECT|nlist_64.N_EXT:
+                case nlist_64.N_SECT | nlist_64.N_EXT:
                     globalSymbols.add(sym);
                     break;
                 default:
@@ -121,30 +113,30 @@
         return (sym);
     }
 
-    public void setOffset(int symoff) {
+    void setOffset(int symoff) {
         symtabCmd.putInt(symtab_command.symoff.off, symoff);
     }
 
     // Update the symbol indexes once all symbols have been added.
     // This is required since we'll be reordering the symbols in the
     // file to be in the order of Local, global and Undefined.
-    public void updateIndexes() {
+    void updateIndexes() {
         int index = 0;
 
         // Update the local symbol indexes
-        for (int i = 0; i < localSymbols.size(); i++ ) {
+        for (int i = 0; i < localSymbols.size(); i++) {
             MachOSymbol sym = localSymbols.get(i);
             sym.setIndex(index++);
         }
 
         // Update the global symbol indexes
-        for (int i = 0; i < globalSymbols.size(); i++ ) {
+        for (int i = 0; i < globalSymbols.size(); i++) {
             MachOSymbol sym = globalSymbols.get(i);
             sym.setIndex(index++);
         }
 
         // Update the undefined symbol indexes
-        for (int i = index; i < undefSymbols.size(); i++ ) {
+        for (int i = index; i < undefSymbols.size(); i++) {
             MachOSymbol sym = undefSymbols.get(i);
             sym.setIndex(index++);
         }
@@ -152,7 +144,7 @@
 
     // Update LC_SYMTAB command fields based on the number of symbols added
     // return the file size taken up by symbol table entries and strings
-    public int calcSizes() {
+    int calcSizes() {
         int stroff;
 
         stroff = symtabCmd.getInt(symtab_command.symoff.off) + (nlist_64.totalsize * symbolCount);
@@ -164,42 +156,49 @@
         return (symtabDataSize);
     }
 
-    public int getNumLocalSyms()  { return localSymbols.size();  }
-    public int getNumGlobalSyms() { return globalSymbols.size(); }
-    public int getNumUndefSyms()  { return undefSymbols.size();  }
+    int getNumLocalSyms() {
+        return localSymbols.size();
+    }
 
-    public byte[] getCmdArray() {
+    int getNumGlobalSyms() {
+        return globalSymbols.size();
+    }
+
+    int getNumUndefSyms() {
+        return undefSymbols.size();
+    }
+
+    byte[] getCmdArray() {
         return symtabCmd.array();
     }
 
     // Create a single byte array that contains the symbol table entries
     // and string table
-    public byte[] getDataArray() {
-        int index = 0;
-        symtabData = MachOByteBuffer.allocate(symtabDataSize);
-        byte [] retarray;
+    byte[] getDataArray() {
+        ByteBuffer symtabData = MachOByteBuffer.allocate(symtabDataSize);
+        byte[] retarray;
 
         // Add the local symbols
-        for (int i = 0; i < localSymbols.size(); i++ ) {
+        for (int i = 0; i < localSymbols.size(); i++) {
             MachOSymbol sym = localSymbols.get(i);
-            byte [] arr = sym.getArray();
+            byte[] arr = sym.getArray();
             symtabData.put(arr);
         }
         // Add the global symbols
-        for (int i = 0; i < globalSymbols.size(); i++ ) {
+        for (int i = 0; i < globalSymbols.size(); i++) {
             MachOSymbol sym = globalSymbols.get(i);
-            byte [] arr = sym.getArray();
+            byte[] arr = sym.getArray();
             symtabData.put(arr);
         }
         // Add the undefined symbols
-        for (int i = 0; i < undefSymbols.size(); i++ ) {
+        for (int i = 0; i < undefSymbols.size(); i++) {
             MachOSymbol sym = undefSymbols.get(i);
-            byte [] arr = sym.getArray();
+            byte[] arr = sym.getArray();
             symtabData.put(arr);
         }
 
         // Add the stringtable
-        byte [] strs = strTabContent.toString().getBytes();
+        byte[] strs = strTabContent.toString().getBytes();
         symtabData.put(strs);
 
         retarray = symtabData.array();
@@ -207,5 +206,3 @@
         return (retarray);
     }
 }
-
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOTargetInfo.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOTargetInfo.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,14 +24,13 @@
 package jdk.tools.jaotc.binformat.macho;
 
 import java.nio.ByteOrder;
-import jdk.tools.jaotc.binformat.macho.MachO;
 import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64;
 
 /**
  * Class that abstracts MACH-O target details.
  *
  */
-public class MachOTargetInfo {
+final class MachOTargetInfo {
     /**
      * Target architecture and subtype.
      */
@@ -68,20 +67,19 @@
         osName = System.getProperty("os.name").toLowerCase();
     }
 
-    public static int getMachOArch() {
+    static int getMachOArch() {
         return arch;
     }
 
-    public static int getMachOSubArch() {
+    static int getMachOSubArch() {
         return subarch;
     }
 
-    public static int getMachOEndian() {
+    static int getMachOEndian() {
         return endian;
     }
 
-    public static String getOsName() {
+    static String getOsName() {
         return osName;
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOVersion.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOVersion.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,16 +24,14 @@
 package jdk.tools.jaotc.binformat.macho;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
-import jdk.tools.jaotc.binformat.macho.MachO;
 import jdk.tools.jaotc.binformat.macho.MachO.version_min_command;
 import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
 
-public class MachOVersion {
-    ByteBuffer version;
+final class MachOVersion {
+    private final ByteBuffer version;
 
-    public MachOVersion() {
+    MachOVersion() {
         version = MachOByteBuffer.allocate(version_min_command.totalsize);
 
         version.putInt(version_min_command.cmd.off, version_min_command.LC_VERSION_MIN_MACOSX);
@@ -42,8 +40,7 @@
         version.putInt(version_min_command.sdk.off, 0); /* N/A SDK */
     }
 
-    public byte[] getArray() {
+    byte[] getArray() {
         return version.array();
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/JPECoffRelocObject.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/JPECoffRelocObject.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,13 +24,11 @@
 package jdk.tools.jaotc.binformat.pecoff;
 
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
-import jdk.tools.jaotc.binformat.Container;
 import jdk.tools.jaotc.binformat.BinaryContainer;
 import jdk.tools.jaotc.binformat.ByteContainer;
 import jdk.tools.jaotc.binformat.CodeContainer;
@@ -38,11 +36,9 @@
 import jdk.tools.jaotc.binformat.Relocation;
 import jdk.tools.jaotc.binformat.Relocation.RelocType;
 import jdk.tools.jaotc.binformat.Symbol;
-import jdk.tools.jaotc.binformat.NativeSymbol;
 import jdk.tools.jaotc.binformat.Symbol.Binding;
 import jdk.tools.jaotc.binformat.Symbol.Kind;
 
-import jdk.tools.jaotc.binformat.pecoff.PECoff;
 import jdk.tools.jaotc.binformat.pecoff.PECoffSymbol;
 import jdk.tools.jaotc.binformat.pecoff.PECoffTargetInfo;
 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_FILE_HEADER;
@@ -56,71 +52,53 @@
 
     private final PECoffContainer pecoffContainer;
 
-    private final int segmentSize;
+    private final int sectionAlignment;
 
-    public JPECoffRelocObject(BinaryContainer binContainer, String outputFileName, String aotVersion) {
+    public JPECoffRelocObject(BinaryContainer binContainer, String outputFileName) {
         this.binContainer = binContainer;
-        this.pecoffContainer = new PECoffContainer(outputFileName, aotVersion);
-        this.segmentSize = binContainer.getCodeSegmentSize();
-        if (segmentSize != 64) {
-            System.out.println("binContainer alignment size not 64 bytes, update JPECoffRelocObject");
-        }
+        this.pecoffContainer = new PECoffContainer(outputFileName);
+        this.sectionAlignment = binContainer.getCodeSegmentSize();
     }
 
-    private PECoffSection createByteSection(ArrayList<PECoffSection>sections,
-                                         String sectName,
-                                         byte [] scnData,
-                                         boolean hasRelocs,
-                                         int scnFlags) {
+    private static PECoffSection createByteSection(ArrayList<PECoffSection> sections, String sectName, byte[] scnData,
+                    boolean hasRelocs, int scnFlags, int sectAlign) {
 
-        PECoffSection sect = new PECoffSection(sectName,
-                                         scnData,
-                                         scnFlags,
-                                         hasRelocs,
-                                         sections.size());
+        PECoffSection sect = new PECoffSection(sectName, scnData, scnFlags, sectAlign, hasRelocs, sections.size());
         // Add this section to our list
         sections.add(sect);
 
         return (sect);
     }
 
-    private void createByteSection(ArrayList<PECoffSection>sections,
-                                   ByteContainer c, int scnFlags) {
+    private static void createByteSection(ArrayList<PECoffSection> sections, ByteContainer c, int scnFlags, int sectAlign) {
         PECoffSection sect;
         boolean hasRelocs = c.hasRelocations();
         byte[] scnData = c.getByteArray();
 
-        sect = createByteSection(sections, c.getContainerName(),
-                                 scnData, hasRelocs,
-                                 scnFlags);
+        sect = createByteSection(sections, c.getContainerName(), scnData, hasRelocs, scnFlags, sectAlign);
 
         c.setSectionId(sect.getSectionId());
     }
 
-    private void createCodeSection(ArrayList<PECoffSection>sections, CodeContainer c) {
-        createByteSection(sections, c, IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ |
-                                       IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_EXECUTE |
-                                       IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_64BYTES |
-                                       IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_CODE);
+    private void createCodeSection(ArrayList<PECoffSection> sections, CodeContainer c) {
+        int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_EXECUTE | IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_CODE;
+        createByteSection(sections, c, scnFlags, sectionAlignment);
+    }
+
+    private void createReadOnlySection(ArrayList<PECoffSection> sections, ReadOnlyDataContainer c) {
+        int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA;
+        createByteSection(sections, c, scnFlags, sectionAlignment);
     }
 
-    private void createReadOnlySection(ArrayList<PECoffSection>sections, ReadOnlyDataContainer c) {
-        createByteSection(sections, c, IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ |
-                                       IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_64BYTES |
-                                       IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA);
-    }
+    private void createReadWriteSection(ArrayList<PECoffSection> sections, ByteContainer c) {
+        int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_WRITE;
 
-    private void createReadWriteSection(ArrayList<PECoffSection>sections, ByteContainer c) {
-        int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ |
-                       IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_WRITE |
-                       IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_64BYTES;
-
-        if (c.getByteArray().length > 0)
+        if (c.getByteArray().length > 0) {
             scnFlags |= IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA;
-        else
+        } else {
             scnFlags |= IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_UNINITIALIZED_DATA;
-
-        createByteSection(sections, c, scnFlags);
+        }
+        createByteSection(sections, c, scnFlags, sectionAlignment);
     }
 
     /**
@@ -131,7 +109,7 @@
      * @throws IOException throws {@code IOException} as a result of file system access failures.
      */
     public void createPECoffRelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException {
-        ArrayList<PECoffSection> sections = new ArrayList<PECoffSection>();
+        ArrayList<PECoffSection> sections = new ArrayList<>();
 
         // Create text section
         createCodeSection(sections, binContainer.getCodeContainer());
@@ -139,51 +117,45 @@
         createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer());
         createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer());
         createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer());
-        createReadWriteSection(sections, binContainer.getMetaspaceGotContainer());
-        createReadWriteSection(sections, binContainer.getMetadataGotContainer());
-        createReadWriteSection(sections, binContainer.getMethodStateContainer());
-        createReadWriteSection(sections, binContainer.getOopGotContainer());
-        createReadWriteSection(sections, binContainer.getMethodMetadataContainer());
+        createReadOnlySection(sections, binContainer.getMethodMetadataContainer());
         createReadOnlySection(sections, binContainer.getStubsOffsetsContainer());
         createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer());
         createReadOnlySection(sections, binContainer.getCodeSegmentsContainer());
         createReadOnlySection(sections, binContainer.getConstantDataContainer());
         createReadOnlySection(sections, binContainer.getConfigContainer());
-
-        // createExternalLinkage();
-
-        createCodeSection(sections, binContainer.getExtLinkageContainer());
+        createReadWriteSection(sections, binContainer.getKlassesGotContainer());
+        createReadWriteSection(sections, binContainer.getCountersGotContainer());
+        createReadWriteSection(sections, binContainer.getMetadataGotContainer());
+        createReadWriteSection(sections, binContainer.getMethodStateContainer());
+        createReadWriteSection(sections, binContainer.getOopGotContainer());
         createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer());
 
         // Allocate PECoff Header
         PECoffHeader header = new PECoffHeader();
 
         // Get PECoff symbol data from BinaryContainer object's symbol tables
-        PECoffSymtab symtab = createPECoffSymbolTables(sections, symbols);
+        PECoffSymtab symtab = createPECoffSymbolTables(symbols);
 
         // Add Linker Directives Section
-        createByteSection(sections, ".drectve",
-                          symtab.getDirectiveArray(), false,
-                          IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_INFO |
-                          IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_REMOVE |
-                          IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_1BYTES);
+        int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_INFO | IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_REMOVE;
+        createByteSection(sections, ".drectve", symtab.getDirectiveArray(), false, scnFlags, 1 /* 1 byte alignment */);
 
         // Create the Relocation Tables
         PECoffRelocTable pecoffRelocs = createPECoffRelocTable(sections, relocationTable);
 
         // File Output Order
         //
-        //   HEADER           (Need address of Symbol Table + symbol count)
-        //   SECTIONS         (Need pointer to Section Data, Relocation Table)
-        //   DIRECTIVES
-        //   SYMBOL TABLE
-        //   SYMBOLS
-        //   SECTION DATA
-        //   RELOCATION TABLE
+        // HEADER (Need address of Symbol Table + symbol count)
+        // SECTIONS (Need pointer to Section Data, Relocation Table)
+        // DIRECTIVES
+        // SYMBOL TABLE
+        // SYMBOLS
+        // SECTION DATA
+        // RELOCATION TABLE
 
         // Calculate Offset for Symbol table
         int file_offset = IMAGE_FILE_HEADER.totalsize +
-                          (IMAGE_SECTION_HEADER.totalsize*sections.size());
+                        (IMAGE_SECTION_HEADER.totalsize * sections.size());
 
         // Update Header fields
         header.setSectionCount(sections.size());
@@ -194,14 +166,14 @@
         file_offset += ((symtab.getSymtabCount() * IMAGE_SYMBOL.totalsize) +
                         symtab.getStrtabSize());
         // And round it up
-        file_offset = (file_offset + (sections.get(0).getDataAlign()-1)) &
-                      ~((sections.get(0).getDataAlign()-1));
+        file_offset = (file_offset + (sections.get(0).getDataAlign() - 1)) &
+                        ~((sections.get(0).getDataAlign() - 1));
 
         // Calc file offsets for section data
         for (int i = 0; i < sections.size(); i++) {
             PECoffSection sect = sections.get(i);
-            file_offset = (file_offset + (sect.getDataAlign()-1)) &
-                           ~((sect.getDataAlign()-1));
+            file_offset = (file_offset + (sect.getDataAlign() - 1)) &
+                            ~((sect.getDataAlign() - 1));
             sect.setOffset(file_offset);
             file_offset += sect.getSize();
         }
@@ -214,7 +186,9 @@
                 sect.setReloff(file_offset);
                 sect.setRelcount(nreloc);
                 // extended relocations add an addition entry
-                if (nreloc > 0xFFFF) nreloc++;
+                if (nreloc > 0xFFFF) {
+                    nreloc++;
+                }
                 file_offset += (nreloc * IMAGE_RELOCATION.totalsize);
             }
         }
@@ -253,7 +227,7 @@
      *
      * @param symbols
      */
-    private PECoffSymtab createPECoffSymbolTables(ArrayList<PECoffSection> sections, Collection<Symbol> symbols) {
+    private static PECoffSymtab createPECoffSymbolTables(Collection<Symbol> symbols) {
         PECoffSymtab symtab = new PECoffSymtab();
 
         // First, create the initial null symbol. This is a local symbol.
@@ -263,8 +237,8 @@
         for (Symbol symbol : symbols) {
             // Get the index of section this symbol is defined in.
             int secHdrIndex = symbol.getSection().getSectionId();
-            PECoffSymbol pecoffSymbol = symtab.addSymbolEntry(symbol.getName(), getPECoffTypeOf(symbol), getPECoffClassOf(symbol), (byte)secHdrIndex, symbol.getOffset(), symbol.getSize());
-            symbol.setNativeSymbol((NativeSymbol)pecoffSymbol);
+            PECoffSymbol pecoffSymbol = symtab.addSymbolEntry(symbol.getName(), getPECoffTypeOf(symbol), getPECoffClassOf(symbol), (byte) secHdrIndex, symbol.getOffset());
+            symbol.setNativeSymbol(pecoffSymbol);
         }
         return (symtab);
     }
@@ -291,13 +265,11 @@
      * @param sections
      * @param relocationTable
      */
-    private PECoffRelocTable createPECoffRelocTable(ArrayList<PECoffSection> sections,
-                                              Map<Symbol, List<Relocation>> relocationTable) {
+    private PECoffRelocTable createPECoffRelocTable(ArrayList<PECoffSection> sections, Map<Symbol, List<Relocation>> relocationTable) {
 
         PECoffRelocTable pecoffRelocTable = new PECoffRelocTable(sections.size());
         /*
-         * For each of the symbols with associated relocation records, create a PECoff relocation
-         * entry.
+         * For each of the symbols with associated relocation records, create a PECoff relocation entry.
          */
         for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) {
             List<Relocation> relocs = entry.getValue();
@@ -315,18 +287,17 @@
         return (pecoffRelocTable);
     }
 
-    private void createRelocation(Symbol symbol, Relocation reloc, PECoffRelocTable pecoffRelocTable) {
+    private static void createRelocation(Symbol symbol, Relocation reloc, PECoffRelocTable pecoffRelocTable) {
         RelocType relocType = reloc.getType();
 
         int pecoffRelocType = getPECoffRelocationType(relocType);
-        PECoffSymbol sym = (PECoffSymbol)symbol.getNativeSymbol();
+        PECoffSymbol sym = (PECoffSymbol) symbol.getNativeSymbol();
         int symno = sym.getIndex();
         int sectindex = reloc.getSection().getSectionId();
         int offset = reloc.getOffset();
         int addend = 0;
 
         switch (relocType) {
-            case FOREIGN_CALL_DIRECT:
             case JAVA_CALL_DIRECT:
             case STUB_CALL_DIRECT:
             case FOREIGN_CALL_INDIRECT_GOT: {
@@ -336,47 +307,22 @@
                 offset = offset + reloc.getSize() + addend;
                 break;
             }
-            case FOREIGN_CALL_DIRECT_FAR: {
-                // Create relocation entry
-                addend = -8; // Size in bytes of the patch location
-                // Relocation should be applied at the location after call operand
-                // 10 = 2 (jmp [r]) + 8 (imm64)
-                offset = offset + reloc.getSize() + addend - 2;
-                break;
-            }
-            case FOREIGN_CALL_INDIRECT:
-            case JAVA_CALL_INDIRECT:
-            case STUB_CALL_INDIRECT: {
+            case JAVA_CALL_INDIRECT: {
                 // Do nothing.
                 return;
             }
-            case EXTERNAL_DATA_REFERENCE_FAR: {
-                // Create relocation entry
+            case METASPACE_GOT_REFERENCE:
+            case EXTERNAL_PLT_TO_GOT: {
                 addend = -4; // Size of 32-bit address of the GOT
                 /*
                  * Relocation should be applied before the test instruction to the move instruction.
-                 * offset points to the test instruction after the instruction that loads
-                 * the address of polling page. So set the offset appropriately.
+                 * reloc.getOffset() points to the test instruction after the instruction that loads the address of
+                 * polling page. So set the offset appropriately.
                  */
                 offset = offset + addend;
                 break;
             }
-            case METASPACE_GOT_REFERENCE:
-            case EXTERNAL_PLT_TO_GOT:
-            case STATIC_STUB_TO_STATIC_METHOD:
-            case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: {
-                addend = -4; // Size of 32-bit address of the GOT
-                /*
-                 * Relocation should be applied before the test instruction to
-                 * the move instruction. reloc.getOffset() points to the
-                 * test instruction after the instruction that loads the
-                 * address of polling page. So set the offset appropriately.
-                 */
-                offset = offset + addend;
-                break;
-            }
-            case EXTERNAL_GOT_TO_PLT:
-            case LOADTIME_ADDRESS: {
+            case EXTERNAL_GOT_TO_PLT: {
                 // this is load time relocations
                 break;
             }
@@ -391,27 +337,17 @@
         int pecoffRelocType = 0; // R_<ARCH>_NONE if #define'd to 0 for all values of ARCH
         switch (PECoffTargetInfo.getPECoffArch()) {
             case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64:
-                if (relocType == RelocType.FOREIGN_CALL_DIRECT ||
-                    relocType == RelocType.JAVA_CALL_DIRECT ||
+                if (relocType == RelocType.JAVA_CALL_DIRECT ||
                     relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
                     pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
                 } else if (relocType == RelocType.STUB_CALL_DIRECT) {
                     pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
-                } else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) {
-                    pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ADDR64;
-                } else if (relocType == RelocType.FOREIGN_CALL_INDIRECT ||
-                           relocType == RelocType.JAVA_CALL_INDIRECT ||
-                           relocType == RelocType.STUB_CALL_INDIRECT) {
+                } else if (relocType == RelocType.JAVA_CALL_INDIRECT) {
                     pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ABSOLUTE;
-                } else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) {
+                } else if (relocType == RelocType.METASPACE_GOT_REFERENCE ||
+                           relocType == RelocType.EXTERNAL_PLT_TO_GOT) {
                     pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
-                } else if (relocType == RelocType.METASPACE_GOT_REFERENCE ||
-                           relocType == RelocType.EXTERNAL_PLT_TO_GOT ||
-                           relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD ||
-                           relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) {
-                    pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
-                } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT ||
-                           relocType == RelocType.LOADTIME_ADDRESS) {
+                } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT) {
                     pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ADDR64;
                 } else {
                     assert false : "Unhandled relocation type: " + relocType;
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoff.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoff.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,17 +25,16 @@
 
 /**
  *
- * Support for the creation of Coff files.
- * Current support is limited to 64 bit x86_64.
+ * Support for the creation of Coff files. Current support is limited to 64 bit x86_64.
  *
  */
 
-public class PECoff {
-
+final class PECoff {
+    //@formatter:off
     /**
      * IMAGE_FILE_HEADER structure defines
      */
-    public enum IMAGE_FILE_HEADER {
+    enum IMAGE_FILE_HEADER {
                      Machine( 0, 2),
             NumberOfSections( 2, 2),
                TimeDateStamp( 4, 4),
@@ -44,15 +43,15 @@
         SizeOfOptionalHeader(16, 2),
              Characteristics(18, 2);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         IMAGE_FILE_HEADER(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 20;
+        static int totalsize = 20;
 
         /**
          * IMAGE_FILE_HEADER defines
@@ -61,15 +60,15 @@
         /**
          * Machine
          */
-        public static final char IMAGE_FILE_MACHINE_UNKNOWN = 0x0;
-        public static final char IMAGE_FILE_MACHINE_AMD64   = 0x8664;
+        static final char IMAGE_FILE_MACHINE_UNKNOWN = 0x0;
+        static final char IMAGE_FILE_MACHINE_AMD64   = 0x8664;
 
     }
 
     /**
      * IMAGE_SECTION_HEADER structure defines
      */
-    public enum IMAGE_SECTION_HEADER {
+    enum IMAGE_SECTION_HEADER {
                         Name( 0, 8),
              PhysicalAddress( 8, 4),
                  VirtualSize( 8, 4),
@@ -82,15 +81,15 @@
          NumberOfLinenumbers(34, 2),
              Characteristics(36, 4);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         IMAGE_SECTION_HEADER(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 40;
+        static int totalsize = 40;
 
         /**
          * IMAGE_SECTION_HEADER defines
@@ -99,29 +98,33 @@
         /**
          * Characteristics
          */
-        public static final int IMAGE_SCN_CNT_CODE               = 0x20;
-        public static final int IMAGE_SCN_CNT_INITIALIZED_DATA   = 0x40;
-        public static final int IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x80;
-        public static final int IMAGE_SCN_LNK_COMDAT             = 0x1000;
-        public static final int IMAGE_SCN_LNK_INFO               = 0x200;
-        public static final int IMAGE_SCN_LNK_REMOVE             = 0x800;
+        static final int IMAGE_SCN_CNT_CODE               = 0x20;
+        static final int IMAGE_SCN_CNT_INITIALIZED_DATA   = 0x40;
+        static final int IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x80;
+        static final int IMAGE_SCN_LNK_COMDAT             = 0x1000;
+        static final int IMAGE_SCN_LNK_INFO               = 0x200;
+        static final int IMAGE_SCN_LNK_REMOVE             = 0x800;
 
-        public static final int IMAGE_SCN_ALIGN_1BYTES           = 0x100000;
-        public static final int IMAGE_SCN_ALIGN_2BYTES           = 0x200000;
-        public static final int IMAGE_SCN_ALIGN_4BYTES           = 0x300000;
-        public static final int IMAGE_SCN_ALIGN_8BYTES           = 0x400000;
-        public static final int IMAGE_SCN_ALIGN_16BYTES          = 0x500000;
-        public static final int IMAGE_SCN_ALIGN_32BYTES          = 0x600000;
-        public static final int IMAGE_SCN_ALIGN_64BYTES          = 0x700000;
-        public static final int IMAGE_SCN_ALIGN_MASK             = 0xf00000;
-        public static final int IMAGE_SCN_ALIGN_SHIFT            = 20;
+        static final int IMAGE_SCN_ALIGN_1BYTES           = 0x100000;
+        static final int IMAGE_SCN_ALIGN_2BYTES           = 0x200000;
+        static final int IMAGE_SCN_ALIGN_4BYTES           = 0x300000;
+        static final int IMAGE_SCN_ALIGN_8BYTES           = 0x400000;
+        static final int IMAGE_SCN_ALIGN_16BYTES          = 0x500000;
+        static final int IMAGE_SCN_ALIGN_32BYTES          = 0x600000;
+        static final int IMAGE_SCN_ALIGN_64BYTES          = 0x700000;
+        static final int IMAGE_SCN_ALIGN_128BYTES         = 0x800000;
+        static final int IMAGE_SCN_ALIGN_256BYTES         = 0x900000;
+        static final int IMAGE_SCN_ALIGN_512BYTES         = 0xa00000;
+        static final int IMAGE_SCN_ALIGN_1024BYTES        = 0xb00000;
+        static final int IMAGE_SCN_ALIGN_MASK             = 0xf00000;
+        static final int IMAGE_SCN_ALIGN_SHIFT            = 20;
 
-        public static final int IMAGE_SCN_LNK_NRELOC_OVFL        = 0x01000000;
+        static final int IMAGE_SCN_LNK_NRELOC_OVFL        = 0x01000000;
 
-        public static final int IMAGE_SCN_MEM_SHARED             = 0x10000000;
-        public static final int IMAGE_SCN_MEM_EXECUTE            = 0x20000000;
-        public static final int IMAGE_SCN_MEM_READ               = 0x40000000;
-        public static final int IMAGE_SCN_MEM_WRITE              = 0x80000000;
+        static final int IMAGE_SCN_MEM_SHARED             = 0x10000000;
+        static final int IMAGE_SCN_MEM_EXECUTE            = 0x20000000;
+        static final int IMAGE_SCN_MEM_READ               = 0x40000000;
+        static final int IMAGE_SCN_MEM_WRITE              = 0x80000000;
 
     }
 
@@ -130,7 +133,7 @@
      *
      * IMAGE_SYMBOL structure defines
      */
-    public enum IMAGE_SYMBOL {
+    enum IMAGE_SYMBOL {
                    ShortName( 0, 8),
                        Short( 0, 4),
                         Long( 4, 4),
@@ -140,63 +143,63 @@
                 StorageClass(16, 1),
           NumberOfAuxSymbols(17, 1);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         IMAGE_SYMBOL(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 18;
+        static int totalsize = 18;
 
         /**
          * Type
          */
-        public static final int IMAGE_SYM_DTYPE_NONE     = 0x0;
-        public static final int IMAGE_SYM_DTYPE_FUNCTION = 0x20;
+        static final int IMAGE_SYM_DTYPE_NONE     = 0x0;
+        static final int IMAGE_SYM_DTYPE_FUNCTION = 0x20;
 
         /**
          * StorageClass
          */
-        public static final int IMAGE_SYM_CLASS_NULL     = 0x0;
-        public static final int IMAGE_SYM_CLASS_EXTERNAL = 0x2;
-        public static final int IMAGE_SYM_CLASS_STATIC   = 0x3;
-        public static final int IMAGE_SYM_CLASS_LABEL    = 0x6;
+        static final int IMAGE_SYM_CLASS_NULL     = 0x0;
+        static final int IMAGE_SYM_CLASS_EXTERNAL = 0x2;
+        static final int IMAGE_SYM_CLASS_STATIC   = 0x3;
+        static final int IMAGE_SYM_CLASS_LABEL    = 0x6;
 
     }
 
     /**
      * IMAGE_RELOCATION structure defines
      */
-    public enum IMAGE_RELOCATION {
+    enum IMAGE_RELOCATION {
               VirtualAddress( 0, 4),
             SymbolTableIndex( 4, 4),
                         Type( 8, 2);
 
-        public final int off;
-        public final int sz;
+        final int off;
+        final int sz;
 
         IMAGE_RELOCATION(int offset, int size) {
             this.off = offset;
             this.sz = size;
         }
 
-        public static int totalsize = 10;
+        static int totalsize = 10;
 
         /**
          * Relocation types
          */
-        public static final int IMAGE_REL_AMD64_ABSOLUTE = 0x0;
-        public static final int IMAGE_REL_AMD64_ADDR32   = 0x2;
-        public static final int IMAGE_REL_AMD64_ADDR64   = 0x1;
-        public static final int IMAGE_REL_AMD64_REL32    = 0x4;
-        public static final int IMAGE_REL_AMD64_REL32_1  = 0x5;
-        public static final int IMAGE_REL_AMD64_REL32_2  = 0x6;
-        public static final int IMAGE_REL_AMD64_REL32_3  = 0x7;
-        public static final int IMAGE_REL_AMD64_REL32_4  = 0x8;
-        public static final int IMAGE_REL_AMD64_REL32_5  = 0x9;
+        static final int IMAGE_REL_AMD64_ABSOLUTE = 0x0;
+        static final int IMAGE_REL_AMD64_ADDR32   = 0x2;
+        static final int IMAGE_REL_AMD64_ADDR64   = 0x1;
+        static final int IMAGE_REL_AMD64_REL32    = 0x4;
+        static final int IMAGE_REL_AMD64_REL32_1  = 0x5;
+        static final int IMAGE_REL_AMD64_REL32_2  = 0x6;
+        static final int IMAGE_REL_AMD64_REL32_3  = 0x7;
+        static final int IMAGE_REL_AMD64_REL32_4  = 0x8;
+        static final int IMAGE_REL_AMD64_REL32_5  = 0x9;
 
     }
-
+    //@formatter:on
 }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffByteBuffer.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffByteBuffer.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,9 +26,9 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 
-public class PECoffByteBuffer {
+final class PECoffByteBuffer {
 
-    public static ByteBuffer allocate(int size) {
+    static ByteBuffer allocate(int size) {
         ByteBuffer buf = ByteBuffer.allocate(size);
         // Only support Little Endian on Windows
         buf.order(ByteOrder.LITTLE_ENDIAN);
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffContainer.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffContainer.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,14 +26,13 @@
 import java.io.File;
 import java.io.FileOutputStream;
 
-public class PECoffContainer {
+final class PECoffContainer {
 
-    File outputFile;
-    FileOutputStream outputStream;
-    long fileOffset;
+    private final File outputFile;
+    private FileOutputStream outputStream;
+    private long fileOffset;
 
-    public PECoffContainer(String fileName, String aotVersion) {
-        String baseName;
+    PECoffContainer(String fileName) {
 
         outputFile = new File(fileName);
         if (outputFile.exists()) {
@@ -48,7 +47,7 @@
         fileOffset = 0;
     }
 
-    public void close() {
+    void close() {
         try {
             outputStream.close();
         } catch (Exception e) {
@@ -56,8 +55,10 @@
         }
     }
 
-    public void writeBytes(byte [] bytes) {
-        if (bytes == null) return;
+    void writeBytes(byte[] bytes) {
+        if (bytes == null) {
+            return;
+        }
         try {
             outputStream.write(bytes);
         } catch (Exception e) {
@@ -67,11 +68,13 @@
     }
 
     // Write bytes to output file with up front alignment padding
-    public void writeBytes(byte [] bytes, int alignment) {
-        if (bytes == null) return;
+    void writeBytes(byte[] bytes, int alignment) {
+        if (bytes == null) {
+            return;
+        }
         try {
             // Pad to alignment
-            while ((fileOffset & (long)(alignment-1)) != 0) {
+            while ((fileOffset & (alignment - 1)) != 0) {
                 outputStream.write(0);
                 fileOffset++;
             }
@@ -82,4 +85,3 @@
         fileOffset += bytes.length;
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffHeader.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffHeader.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,45 +24,41 @@
 package jdk.tools.jaotc.binformat.pecoff;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
-import jdk.tools.jaotc.binformat.pecoff.PECoff;
 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_FILE_HEADER;
-import jdk.tools.jaotc.binformat.pecoff.PECoffTargetInfo;
 import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
 
-public class PECoffHeader {
-    ByteBuffer header;
+final class PECoffHeader {
+    private final ByteBuffer header;
 
-    public PECoffHeader() {
+    PECoffHeader() {
         header = PECoffByteBuffer.allocate(IMAGE_FILE_HEADER.totalsize);
 
         header.putChar(IMAGE_FILE_HEADER.Machine.off, IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64);
-        header.putInt(IMAGE_FILE_HEADER.TimeDateStamp.off, (int)(System.currentTimeMillis()/1000));
+        header.putInt(IMAGE_FILE_HEADER.TimeDateStamp.off, (int) (System.currentTimeMillis() / 1000));
         header.putInt(IMAGE_FILE_HEADER.PointerToSymbolTable.off, 0);
         header.putInt(IMAGE_FILE_HEADER.NumberOfSymbols.off, 0);
-        header.putChar(IMAGE_FILE_HEADER.SizeOfOptionalHeader.off, (char)0);
-        header.putChar(IMAGE_FILE_HEADER.Characteristics.off, (char)0);
+        header.putChar(IMAGE_FILE_HEADER.SizeOfOptionalHeader.off, (char) 0);
+        header.putChar(IMAGE_FILE_HEADER.Characteristics.off, (char) 0);
 
     }
 
     // Update header with the number of total sections
-    public void setSectionCount(int count) {
-        header.putChar(IMAGE_FILE_HEADER.NumberOfSections.off, (char)count);
+    void setSectionCount(int count) {
+        header.putChar(IMAGE_FILE_HEADER.NumberOfSections.off, (char) count);
     }
 
     // Update header with the number of total symbols
-    public void setSymbolCount(int count) {
+    void setSymbolCount(int count) {
         header.putInt(IMAGE_FILE_HEADER.NumberOfSymbols.off, count);
     }
 
     // Update header with the offset of symbol table
-    public void setSymbolOff(int offset) {
+    void setSymbolOff(int offset) {
         header.putInt(IMAGE_FILE_HEADER.PointerToSymbolTable.off, offset);
     }
 
-    public byte[] getArray() {
+    byte[] getArray() {
         return header.array();
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocEntry.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocEntry.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,26 +24,23 @@
 package jdk.tools.jaotc.binformat.pecoff;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
-import jdk.tools.jaotc.binformat.pecoff.PECoff;
 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_RELOCATION;
 import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
 
-public class PECoffRelocEntry {
-    ByteBuffer entry;
+final class PECoffRelocEntry {
+    private final ByteBuffer entry;
 
-    public PECoffRelocEntry(int offset, int symno, int type) {
+    PECoffRelocEntry(int offset, int symno, int type) {
 
         entry = PECoffByteBuffer.allocate(IMAGE_RELOCATION.totalsize);
 
         entry.putInt(IMAGE_RELOCATION.VirtualAddress.off, offset);
         entry.putInt(IMAGE_RELOCATION.SymbolTableIndex.off, symno);
-        entry.putChar(IMAGE_RELOCATION.Type.off, (char)type);
+        entry.putChar(IMAGE_RELOCATION.Type.off, (char) type);
     }
 
-    public byte[] getArray() {
+    byte[] getArray() {
         return entry.array();
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocTable.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocTable.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,52 +25,47 @@
 
 import java.util.ArrayList;
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
-import jdk.tools.jaotc.binformat.pecoff.PECoff;
 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_RELOCATION;
 import jdk.tools.jaotc.binformat.pecoff.PECoffRelocEntry;
 import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
 
-public class PECoffRelocTable {
+final class PECoffRelocTable {
     ArrayList<ArrayList<PECoffRelocEntry>> relocEntries;
 
-    public PECoffRelocTable(int numsects) {
-        relocEntries = new ArrayList<ArrayList<PECoffRelocEntry>>(numsects);
-        for (int i = 0; i < numsects; i++)
+    PECoffRelocTable(int numsects) {
+        relocEntries = new ArrayList<>(numsects);
+        for (int i = 0; i < numsects; i++) {
             relocEntries.add(new ArrayList<PECoffRelocEntry>());
+        }
     }
 
-    public void createRelocationEntry(int sectindex,
-                                      int offset,
-                                      int symno,
-                                      int type) {
-
-        PECoffRelocEntry entry = new PECoffRelocEntry(offset,
-                                                symno,
-                                                type);
+    void createRelocationEntry(int sectindex, int offset, int symno, int type) {
+        PECoffRelocEntry entry = new PECoffRelocEntry(offset, symno, type);
         relocEntries.get(sectindex).add(entry);
     }
 
-    public int getAlign() { return (4); }
+    static int getAlign() {
+        return (4);
+    }
 
-    public int getNumRelocs(int section_index) {
+    int getNumRelocs(int section_index) {
         return relocEntries.get(section_index).size();
     }
 
     // Return the relocation entries for a single section
-    //   or null if no entries added to section
-    public byte [] getRelocData(int section_index) {
+    // or null if no entries added to section
+    byte[] getRelocData(int section_index) {
         ArrayList<PECoffRelocEntry> entryList = relocEntries.get(section_index);
         int entryCount = entryList.size();
         int allocCount = entryCount;
 
-        if (entryCount == 0)
+        if (entryCount == 0) {
             return null;
-
-        if (entryCount > 0xFFFF)
+        }
+        if (entryCount > 0xFFFF) {
             allocCount++;
-
+        }
         ByteBuffer relocData = PECoffByteBuffer.allocate(allocCount * IMAGE_RELOCATION.totalsize);
 
         // If number of relocs exceeds 65K, add the real size
@@ -89,4 +84,3 @@
         return (relocData.array());
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSection.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSection.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,32 +24,39 @@
 package jdk.tools.jaotc.binformat.pecoff;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
-import jdk.tools.jaotc.binformat.pecoff.PECoff;
 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SECTION_HEADER;
 import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
 
-public class PECoffSection {
-    ByteBuffer section;
-    byte [] data;
-    boolean hasrelocations;
-    int sectionIndex;
-    int align;
+final class PECoffSection {
+    private final ByteBuffer section;
+    private final byte[] data;
+    private final boolean hasrelocations;
+    private final int sectionIndex;
+    private final int align;
 
-    public PECoffSection(String sectName, byte [] sectData, int sectFlags,
-                         boolean hasRelocations, int sectIndex) {
+    PECoffSection(String sectName, byte[] sectData0, int sectFlags0, int sectAlign, boolean hasRelocations, int sectIndex) {
 
         section = PECoffByteBuffer.allocate(IMAGE_SECTION_HEADER.totalsize);
 
-        // bug: If JVM.oop.got section is empty, VM exits since JVM.oop.got
-        //      symbol ends up as external forwarded reference.
-        if (sectData.length == 0) sectData = new byte[8];
+        // If .oop.got section is empty, VM exits since .oop.got
+        // symbol ends up as external forwarded reference.
+        byte[] sectData = sectData0;
+        if (sectData0.length == 0) {
+            sectData = new byte[8];
+        }
 
         // Copy only Max allowed bytes to Section Entry
-        byte [] Name = sectName.getBytes();
-        int max = Name.length <= IMAGE_SECTION_HEADER.Name.sz ?
-                  Name.length : IMAGE_SECTION_HEADER.Name.sz;
+        byte[] Name = sectName.getBytes();
+        int max = Name.length <= IMAGE_SECTION_HEADER.Name.sz ? Name.length : IMAGE_SECTION_HEADER.Name.sz;
+
+        assert (sectAlign < 1 || sectAlign > 1024 || (sectAlign & (sectAlign - 1)) != 0) : "section alignment is not valid: " + sectAlign;
+        align = sectAlign;
+
+        // Using 32 because IMAGE_SCN_ALIGN_*BYTES is value + 1
+        int sectAlignBits = (32 - Integer.numberOfLeadingZeros(align)) << IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_SHIFT;
+        // Clear and set alignment bits
+        int sectFlags = (sectFlags0 & ~IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_MASK) | (sectAlignBits & IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_MASK);
 
         section.put(Name, IMAGE_SECTION_HEADER.Name.off, max);
 
@@ -57,84 +64,69 @@
         section.putInt(IMAGE_SECTION_HEADER.VirtualAddress.off, 0);
         section.putInt(IMAGE_SECTION_HEADER.SizeOfRawData.off, sectData.length);
         section.putInt(IMAGE_SECTION_HEADER.PointerToLinenumbers.off, 0);
-        section.putChar(IMAGE_SECTION_HEADER.NumberOfLinenumbers.off, (char)0);
+        section.putChar(IMAGE_SECTION_HEADER.NumberOfLinenumbers.off, (char) 0);
 
         section.putInt(IMAGE_SECTION_HEADER.Characteristics.off, sectFlags);
 
-        // Extract alignment from Characteristics field
-        int alignshift = (sectFlags & IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_MASK) >>
-                                       IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_SHIFT;
-
-        // Use 8 byte alignment if not specified
-        if (alignshift == 0)
-            alignshift = 3;
-        else
-            --alignshift;
-
-        align = 1 << alignshift;
-
         data = sectData;
         hasrelocations = hasRelocations;
         sectionIndex = sectIndex;
     }
 
-    public long getSize() {
+    long getSize() {
         return section.getInt(IMAGE_SECTION_HEADER.SizeOfRawData.off);
     }
 
-    public int getDataAlign() {
+    int getDataAlign() {
         return (align);
     }
 
     // Alignment requirements for the IMAGE_SECTION_HEADER structures
-    public static int getShdrAlign() {
+    static int getShdrAlign() {
         return (4);
     }
 
-    public byte[] getArray() {
+    byte[] getArray() {
         return section.array();
     }
 
-    public byte[] getDataArray() {
+    byte[] getDataArray() {
         return data;
     }
 
-    public void setOffset(long offset) {
-        section.putInt(IMAGE_SECTION_HEADER.PointerToRawData.off, (int)offset);
+    void setOffset(long offset) {
+        section.putInt(IMAGE_SECTION_HEADER.PointerToRawData.off, (int) offset);
     }
 
-    public long getOffset() {
+    long getOffset() {
         return (section.getInt(IMAGE_SECTION_HEADER.PointerToRawData.off));
     }
 
-    public void setReloff(int offset) {
+    void setReloff(int offset) {
         section.putInt(IMAGE_SECTION_HEADER.PointerToRelocations.off, offset);
     }
 
-    public void setRelcount(int count) {
+    void setRelcount(int count) {
         // If the number of relocs is larger than 65K, then set
-        // the overflow bit.  The real count will be written to
+        // the overflow bit. The real count will be written to
         // the first reloc entry for this section.
         if (count > 0xFFFF) {
             int flags;
-            section.putChar(IMAGE_SECTION_HEADER.NumberOfRelocations.off, (char)0xFFFF);
+            section.putChar(IMAGE_SECTION_HEADER.NumberOfRelocations.off, (char) 0xFFFF);
             flags = section.getInt(IMAGE_SECTION_HEADER.Characteristics.off);
             flags |= IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_NRELOC_OVFL;
             section.putInt(IMAGE_SECTION_HEADER.Characteristics.off, flags);
-        }
-        else {
-            section.putChar(IMAGE_SECTION_HEADER.NumberOfRelocations.off, (char)count);
+        } else {
+            section.putChar(IMAGE_SECTION_HEADER.NumberOfRelocations.off, (char) count);
         }
     }
 
-    public boolean hasRelocations() {
+    boolean hasRelocations() {
         return hasrelocations;
     }
 
-    public int getSectionId() {
+    int getSectionId() {
         return sectionIndex;
     }
 
 }
-
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymbol.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymbol.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,18 +24,15 @@
 package jdk.tools.jaotc.binformat.pecoff;
 
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
 import jdk.tools.jaotc.binformat.NativeSymbol;
-import jdk.tools.jaotc.binformat.pecoff.PECoff;
 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SYMBOL;
 import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
 
-public class PECoffSymbol extends NativeSymbol {
-    ByteBuffer sym;
+final class PECoffSymbol extends NativeSymbol {
+    private final ByteBuffer sym;
 
-    public PECoffSymbol(int symbolindex, int strindex, byte type, byte storageclass,
-                        byte sectindex, long offset, long size) {
+    PECoffSymbol(int symbolindex, int strindex, byte type, byte storageclass, byte sectindex, long offset) {
         super(symbolindex);
         sym = PECoffByteBuffer.allocate(IMAGE_SYMBOL.totalsize);
 
@@ -43,19 +40,18 @@
         sym.putInt(IMAGE_SYMBOL.Short.off, 0);
 
         sym.putInt(IMAGE_SYMBOL.Long.off, strindex);
-        sym.putInt(IMAGE_SYMBOL.Value.off, (int)offset);
+        sym.putInt(IMAGE_SYMBOL.Value.off, (int) offset);
 
         // Section indexes start at 1 but we manage the index internally
         // as 0 relative except in this structure
-        sym.putChar(IMAGE_SYMBOL.SectionNumber.off, (char)(sectindex+1));
+        sym.putChar(IMAGE_SYMBOL.SectionNumber.off, (char) (sectindex + 1));
 
-        sym.putChar(IMAGE_SYMBOL.Type.off, (char)type);
+        sym.putChar(IMAGE_SYMBOL.Type.off, (char) type);
         sym.put(IMAGE_SYMBOL.StorageClass.off, storageclass);
-        sym.put(IMAGE_SYMBOL.NumberOfAuxSymbols.off, (byte)0);
+        sym.put(IMAGE_SYMBOL.NumberOfAuxSymbols.off, (byte) 0);
     }
 
-    public byte[] getArray() {
+    byte[] getArray() {
         return sym.array();
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymtab.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymtab.java	Thu Aug 24 21:06:33 2017 +0000
@@ -27,36 +27,35 @@
 import java.nio.ByteOrder;
 import java.util.ArrayList;
 
-import jdk.tools.jaotc.binformat.pecoff.PECoff;
 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SYMBOL;
 import jdk.tools.jaotc.binformat.pecoff.PECoffSymbol;
 import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
 
-public class PECoffSymtab {
-    ArrayList<PECoffSymbol>symbols = new ArrayList<PECoffSymbol>();
+final class PECoffSymtab {
+    ArrayList<PECoffSymbol> symbols = new ArrayList<>();
 
     /**
      * number of symbols added
      */
-    int symbolCount;
+    private int symbolCount;
 
     /**
      * String holding symbol table strings
      */
-    private StringBuilder strTabContent;
+    private final StringBuilder strTabContent;
 
     /**
-     * Keeps track of bytes in string table since strTabContent.length()
-     * is number of chars, not bytes.
+     * Keeps track of bytes in string table since strTabContent.length() is number of chars, not
+     * bytes.
      */
     private int strTabNrOfBytes;
 
     /**
      * String holding Linker Directives
      */
-    private StringBuilder directives;
+    private final StringBuilder directives;
 
-    public PECoffSymtab() {
+    PECoffSymtab() {
         symbolCount = 0;
         strTabContent = new StringBuilder();
         directives = new StringBuilder();
@@ -72,8 +71,7 @@
         directives.append("   ");
     }
 
-    public PECoffSymbol addSymbolEntry(String name, byte type, byte storageclass,
-                                    byte secHdrIndex, long offset, long size) {
+    PECoffSymbol addSymbolEntry(String name, byte type, byte storageclass, byte secHdrIndex, long offset) {
         // Get the current symbol index and append symbol name to string table.
         int index;
         PECoffSymbol sym;
@@ -82,7 +80,7 @@
             index = 0;
             strTabContent.append('\0');
             strTabNrOfBytes += 1;
-            sym = new PECoffSymbol(symbolCount, index, type, storageclass, secHdrIndex, offset, size);
+            sym = new PECoffSymbol(symbolCount, index, type, storageclass, secHdrIndex, offset);
             symbols.add(sym);
         } else {
             int nameSize = name.getBytes().length;
@@ -94,10 +92,11 @@
             strTabContent.append(name).append('\0');
             strTabNrOfBytes += (nameSize + 1);
 
-            sym = new PECoffSymbol(symbolCount, index, type, storageclass, secHdrIndex, offset, size);
+            sym = new PECoffSymbol(symbolCount, index, type, storageclass, secHdrIndex, offset);
             symbols.add(sym);
-            if (storageclass == IMAGE_SYMBOL.IMAGE_SYM_CLASS_EXTERNAL)
+            if (storageclass == IMAGE_SYMBOL.IMAGE_SYM_CLASS_EXTERNAL) {
                 addDirective(name, type);
+            }
         }
         symbolCount++;
         return (sym);
@@ -105,37 +104,37 @@
 
     private void addDirective(String name, byte type) {
         directives.append("/EXPORT:" + name);
-        if(type != IMAGE_SYMBOL.IMAGE_SYM_DTYPE_FUNCTION) {
+        if (type != IMAGE_SYMBOL.IMAGE_SYM_DTYPE_FUNCTION) {
             directives.append(",DATA");
         }
         directives.append(" ");
     }
 
-    public int getSymtabCount() {
+    int getSymtabCount() {
         return symbolCount;
     }
 
-    public int getStrtabSize() {
+    int getStrtabSize() {
         return strTabNrOfBytes;
     }
 
     // Return a byte array that contains the symbol table entries
-    public byte[] getSymtabArray() {
-        ByteBuffer symtabData = PECoffByteBuffer.allocate(symbolCount*IMAGE_SYMBOL.totalsize);
+    byte[] getSymtabArray() {
+        ByteBuffer symtabData = PECoffByteBuffer.allocate(symbolCount * IMAGE_SYMBOL.totalsize);
         symtabData.order(ByteOrder.LITTLE_ENDIAN);
 
         // copy all symbols
-        for (int i = 0; i < symbolCount; i++ ) {
+        for (int i = 0; i < symbolCount; i++) {
             PECoffSymbol sym = symbols.get(i);
-            byte [] arr = sym.getArray();
+            byte[] arr = sym.getArray();
             symtabData.put(arr);
         }
         return (symtabData.array());
     }
 
     // Return the string table array
-    public byte[] getStrtabArray() {
-        byte [] strs = strTabContent.toString().getBytes();
+    byte[] getStrtabArray() {
+        byte[] strs = strTabContent.toString().getBytes();
 
         // Update the size of the string table
         ByteBuffer buff = ByteBuffer.wrap(strs);
@@ -145,7 +144,7 @@
         return (strs);
     }
 
-    public byte[] getDirectiveArray() {
+    byte[] getDirectiveArray() {
         return (directives.toString().getBytes());
     }
 }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffTargetInfo.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffTargetInfo.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,14 +24,13 @@
 package jdk.tools.jaotc.binformat.pecoff;
 
 import java.nio.ByteOrder;
-import jdk.tools.jaotc.binformat.pecoff.PECoff;
 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_FILE_HEADER;
 
 /**
  * Class that abstracts MACH-O target details.
  *
  */
-public class PECoffTargetInfo {
+final class PECoffTargetInfo {
     /**
      * Target architecture.
      */
@@ -63,12 +62,11 @@
         }
     }
 
-    public static char getPECoffArch() {
+    static char getPECoffArch() {
         return arch;
     }
 
-    public static String getOsName() {
+    static String getOsName() {
         return osName;
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,7 +52,7 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.TriState;
 
-public class AOTBackend {
+final class AOTBackend {
     private final Main main;
     private final OptionValues graalOptions;
     private final HotSpotBackend backend;
@@ -60,28 +60,26 @@
     private final HotSpotCodeCacheProvider codeCache;
     private final PhaseSuite<HighTierContext> graphBuilderSuite;
     private final HighTierContext highTierContext;
-    private final GraalFilters filters;
 
-    public AOTBackend(Main main, OptionValues graalOptions, HotSpotBackend backend, GraalFilters filters) {
+    AOTBackend(Main main, OptionValues graalOptions, HotSpotBackend backend) {
         this.main = main;
         this.graalOptions = graalOptions;
         this.backend = backend;
-        this.filters = filters;
         providers = backend.getProviders();
         codeCache = providers.getCodeCache();
         graphBuilderSuite = initGraphBuilderSuite(backend, main.options.compileWithAssertions);
         highTierContext = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.ALL);
     }
 
-    public PhaseSuite<HighTierContext> getGraphBuilderSuite() {
+    PhaseSuite<HighTierContext> getGraphBuilderSuite() {
         return graphBuilderSuite;
     }
 
-    public HotSpotBackend getBackend() {
+    HotSpotBackend getBackend() {
         return backend;
     }
 
-    public HotSpotProviders getProviders() {
+    HotSpotProviders getProviders() {
         return providers;
     }
 
@@ -96,7 +94,7 @@
     }
 
     @SuppressWarnings("try")
-    public CompilationResult compileMethod(ResolvedJavaMethod resolvedMethod, DebugContext debug) {
+    CompilationResult compileMethod(ResolvedJavaMethod resolvedMethod, DebugContext debug) {
         StructuredGraph graph = buildStructuredGraph(resolvedMethod, debug);
         if (graph != null) {
             return compileGraph(resolvedMethod, graph, debug);
@@ -118,7 +116,7 @@
             graphBuilderSuite.apply(graph, highTierContext);
             return graph;
         } catch (Throwable e) {
-            handleError(javaMethod, e, " (building graph)");
+            main.handleError(javaMethod, e, " (building graph)");
         }
         return null;
     }
@@ -135,20 +133,11 @@
                             compilationResult, CompilationResultBuilderFactory.Default);
 
         } catch (Throwable e) {
-            handleError(resolvedMethod, e, " (compiling graph)");
+            main.handleError(resolvedMethod, e, " (compiling graph)");
         }
         return null;
     }
 
-    /**
-     * Returns whether the VM is a debug build.
-     *
-     * @return true is debug VM, false otherwise
-     */
-    public boolean isDebugVM() {
-        return backend.getRuntime().getVMConfig().cAssertions;
-    }
-
     private static PhaseSuite<HighTierContext> initGraphBuilderSuite(HotSpotBackend backend, boolean compileWithAssertions) {
         PhaseSuite<HighTierContext> graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
         ListIterator<BasePhase<? super HighTierContext>> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class);
@@ -165,39 +154,12 @@
         return graphBuilderSuite;
     }
 
-    private void handleError(ResolvedJavaMethod resolvedMethod, Throwable e, String message) {
-        String methodName = MiscUtils.uniqueMethodName(resolvedMethod);
-
-        if (main.options.debug) {
-            main.printError("Failed compilation: " + methodName + ": " + e);
-        }
-
-        // Ignore some exceptions when meta-compiling Graal.
-        if (filters.shouldIgnoreException(e)) {
-            return;
-        }
-
-        Main.writeLog("Failed compilation of method " + methodName + message);
-
-        if (!main.options.debug) {
-            main.printError("Failed compilation: " + methodName + ": " + e);
-        }
-
-        if (main.options.verbose) {
-            e.printStackTrace(main.log);
-        }
-
-        if (main.options.exitOnError) {
-            System.exit(1);
-        }
-    }
-
-    public void printCompiledMethod(HotSpotResolvedJavaMethod resolvedMethod, CompilationResult compResult) {
+    void printCompiledMethod(HotSpotResolvedJavaMethod resolvedMethod, CompilationResult compResult) {
         // This is really not installing the method.
         InstalledCode installedCode = codeCache.addCode(resolvedMethod, HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, null, null, compResult), null, null);
         String disassembly = codeCache.disassemble(installedCode);
         if (disassembly != null) {
-            main.printlnDebug(disassembly);
+            main.printer.printlnDebug(disassembly);
         }
     }
 }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java	Thu Aug 24 21:06:33 2017 +0000
@@ -48,7 +48,7 @@
  * compilation of classes. It also defines methods that parse compilation result of Graal to create
  * target-independent representation {@code BinaryContainer} of the intended target binary.
  */
-public class AOTCompilationTask implements Runnable, Comparable<Object> {
+final class AOTCompilationTask implements Runnable, Comparable<Object> {
 
     private static final AtomicInteger ids = new AtomicInteger();
 
@@ -77,7 +77,7 @@
      */
     private CompiledMethodInfo result;
 
-    public AOTCompilationTask(Main main, OptionValues graalOptions, AOTCompiledClass holder, ResolvedJavaMethod method, AOTBackend aotBackend) {
+    AOTCompilationTask(Main main, OptionValues graalOptions, AOTCompiledClass holder, ResolvedJavaMethod method, AOTBackend aotBackend) {
         this.main = main;
         this.graalOptions = graalOptions;
         this.id = ids.incrementAndGet();
@@ -95,7 +95,7 @@
         // may include processing command line options used by the latter.
         HotSpotJVMCIRuntime.runtime();
 
-        AOTCompiler.logCompilation(MiscUtils.uniqueMethodName(method), "Compiling");
+        AOTCompiler.logCompilation(JavaMethodInfo.uniqueMethodName(method), "Compiling");
 
         final long threadId = Thread.currentThread().getId();
 
@@ -137,7 +137,7 @@
         }
 
         // For now precision to the nearest second is sufficient.
-        Main.writeLog("    Compile Time: " + TimeUnit.MILLISECONDS.toSeconds(endTime - startTime) + "secs");
+        LogPrinter.writeLog("    Compile Time: " + TimeUnit.MILLISECONDS.toSeconds(endTime - startTime) + "secs");
         if (main.options.debug) {
             aotBackend.printCompiledMethod((HotSpotResolvedJavaMethod) method, compResult);
         }
@@ -146,7 +146,7 @@
     }
 
     private String getMethodDescription() {
-        return String.format("%-6d aot %s %s", getId(), MiscUtils.uniqueMethodName(method),
+        return String.format("%-6d aot %s %s", getId(), JavaMethodInfo.uniqueMethodName(method),
                         getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + getEntryBCI() + ") ");
     }
 
@@ -154,11 +154,11 @@
         return id;
     }
 
-    public int getEntryBCI() {
+    private static int getEntryBCI() {
         return JVMCICompiler.INVOCATION_ENTRY_BCI;
     }
 
-    public ResolvedJavaMethod getMethod() {
+    ResolvedJavaMethod getMethod() {
         return method;
     }
 
@@ -167,7 +167,7 @@
      *
      * @return the holder of this method
      */
-    public AOTCompiledClass getHolder() {
+    AOTCompiledClass getHolder() {
         return holder;
     }
 
@@ -176,7 +176,7 @@
      *
      * @return result of this compilation task
      */
-    public CompiledMethodInfo getResult() {
+    CompiledMethodInfo getResult() {
         return result;
     }
 
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,16 +41,16 @@
  * Class encapsulating Graal-compiled output of a Java class. The compilation result of all methods
  * of a class {@code className} are maintained in an array list.
  */
-public class AOTCompiledClass {
+final class AOTCompiledClass {
 
-    public static class AOTKlassData {
-        int gotIndex; // Index (offset/8) to the got in the .metaspace.got section
-        int classId;  // Unique ID
+    static class AOTKlassData {
+        private int gotIndex; // Index (offset/8) to the got in the .metaspace.got section
+        private int classId;  // Unique ID
         // Offset to compiled methods data in the .methods.offsets section.
-        int compiledMethodsOffset;
+        private int compiledMethodsOffset;
         // Offset to dependent methods data.
-        int dependentMethodsOffset;
-        long fingerprint;           // Class fingerprint
+        private int dependentMethodsOffset;
+        private long fingerprint;           // Class fingerprint
 
         private final String name;
         private boolean isArray;
@@ -60,25 +60,25 @@
          */
         private ArrayList<CompiledMethodInfo> dependentMethods;
 
-        public AOTKlassData(BinaryContainer binaryContainer, String name, long fingerprint, int classId) {
+        AOTKlassData(BinaryContainer binaryContainer, String name, long fingerprint, int classId) {
             this.dependentMethods = new ArrayList<>();
             this.classId = classId;
             this.fingerprint = fingerprint;
-            this.gotIndex = binaryContainer.addTwoSlotMetaspaceSymbol(name);
+            this.gotIndex = binaryContainer.addTwoSlotKlassSymbol(name);
             this.compiledMethodsOffset = -1; // Not compiled classes do not have compiled methods.
             this.dependentMethodsOffset = -1;
             this.name = name;
             this.isArray = name.length() > 0 && name.charAt(0) == '[';
         }
 
-        public long getFingerprint() {
+        long getFingerprint() {
             return fingerprint;
         }
 
         /**
          * Add a method to the list of dependent methods.
          */
-        public synchronized boolean addDependentMethod(CompiledMethodInfo cm) {
+        synchronized boolean addDependentMethod(CompiledMethodInfo cm) {
             return dependentMethods.add(cm);
         }
 
@@ -87,7 +87,7 @@
          *
          * @return array list of dependent methods
          */
-        public ArrayList<CompiledMethodInfo> getDependentMethods() {
+        ArrayList<CompiledMethodInfo> getDependentMethods() {
             return dependentMethods;
         }
 
@@ -96,11 +96,11 @@
          *
          * @return true if dependent methods exist, false otherwise
          */
-        public boolean hasDependentMethods() {
+        boolean hasDependentMethods() {
             return !dependentMethods.isEmpty();
         }
 
-        public void setCompiledMethodsOffset(int offset) {
+        void setCompiledMethodsOffset(int offset) {
             compiledMethodsOffset = offset;
         }
 
@@ -108,7 +108,7 @@
             int cntDepMethods = dependentMethods.size();
             // Create array of dependent methods IDs. First word is count.
             ReadOnlyDataContainer dependenciesContainer = binaryContainer.getKlassesDependenciesContainer();
-            this.dependentMethodsOffset = binaryContainer.addMethodsCount(cntDepMethods, dependenciesContainer);
+            this.dependentMethodsOffset = BinaryContainer.addMethodsCount(cntDepMethods, dependenciesContainer);
             for (CompiledMethodInfo methodInfo : dependentMethods) {
                 dependenciesContainer.appendInt(methodInfo.getCodeId());
             }
@@ -176,7 +176,7 @@
      *
      * @param compiledMethods AOT compiled methods
      */
-    public AOTCompiledClass(ArrayList<CompiledMethodInfo> compiledMethods) {
+    AOTCompiledClass(ArrayList<CompiledMethodInfo> compiledMethods) {
         this.resolvedJavaType = null;
         this.compiledMethods = compiledMethods;
         this.representsStubs = true;
@@ -185,7 +185,7 @@
     /**
      * Construct an object with compiled versions of the named class.
      */
-    public AOTCompiledClass(ResolvedJavaType resolvedJavaType) {
+    AOTCompiledClass(ResolvedJavaType resolvedJavaType) {
         this.resolvedJavaType = (HotSpotResolvedObjectType) resolvedJavaType;
         this.compiledMethods = new ArrayList<>();
         this.representsStubs = false;
@@ -194,14 +194,14 @@
     /**
      * @return the ResolvedJavaType of this class
      */
-    public ResolvedJavaType getResolvedJavaType() {
+    ResolvedJavaType getResolvedJavaType() {
         return resolvedJavaType;
     }
 
     /**
      * Get the list of methods which should be compiled.
      */
-    public ArrayList<ResolvedJavaMethod> getMethods() {
+    ArrayList<ResolvedJavaMethod> getMethods() {
         ArrayList<ResolvedJavaMethod> m = methods;
         methods = null; // Free - it is not used after that.
         return m;
@@ -210,7 +210,7 @@
     /**
      * Get the number of all AOT classes.
      */
-    public static int getClassesCount() {
+    static int getClassesCount() {
         return classesCount;
     }
 
@@ -219,14 +219,14 @@
      *
      * @return number of methods which should be compiled
      */
-    public int getMethodCount() {
+    int getMethodCount() {
         return methods.size();
     }
 
     /**
      * Add a method to the list of methods to be compiled.
      */
-    public void addMethod(ResolvedJavaMethod method) {
+    void addMethod(ResolvedJavaMethod method) {
         methods.add(method);
     }
 
@@ -235,14 +235,14 @@
      *
      * @return true if this class contains methods which should be compiled, false otherwise
      */
-    public boolean hasMethods() {
+    boolean hasMethods() {
         return !methods.isEmpty();
     }
 
     /**
      * Add a method to the list of compiled methods. This method needs to be thread-safe.
      */
-    public synchronized boolean addCompiledMethod(CompiledMethodInfo cm) {
+    synchronized boolean addCompiledMethod(CompiledMethodInfo cm) {
         return compiledMethods.add(cm);
     }
 
@@ -251,7 +251,7 @@
      *
      * @return array list of compiled methods
      */
-    public ArrayList<CompiledMethodInfo> getCompiledMethods() {
+    ArrayList<CompiledMethodInfo> getCompiledMethods() {
         return compiledMethods;
     }
 
@@ -260,14 +260,14 @@
      *
      * @return true if methods were compiled, false otherwise
      */
-    public boolean hasCompiledMethods() {
+    boolean hasCompiledMethods() {
         return !compiledMethods.isEmpty();
     }
 
     /**
      * Add a klass data.
      */
-    public synchronized static AOTKlassData addAOTKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) {
+    synchronized static AOTKlassData addAOTKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) {
         String name = type.getName();
         long fingerprint = type.getFingerprint();
         AOTKlassData data = klassData.get(name);
@@ -280,15 +280,15 @@
         return data;
     }
 
-    public synchronized static AOTKlassData getAOTKlassData(String name) {
+    synchronized static AOTKlassData getAOTKlassData(String name) {
         return klassData.get(name);
     }
 
-    public synchronized static AOTKlassData getAOTKlassData(HotSpotResolvedObjectType type) {
+    synchronized static AOTKlassData getAOTKlassData(HotSpotResolvedObjectType type) {
         return getAOTKlassData(type.getName());
     }
 
-    public void addAOTKlassData(BinaryContainer binaryContainer) {
+    void addAOTKlassData(BinaryContainer binaryContainer) {
         for (CompiledMethodInfo methodInfo : compiledMethods) {
             // Record methods holder
             methodInfo.addDependentKlassData(binaryContainer, resolvedJavaType);
@@ -309,7 +309,7 @@
         }
     }
 
-    public synchronized static AOTKlassData addFingerprintKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) {
+    synchronized static AOTKlassData addFingerprintKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) {
         if (type.isArray()) {
             return addAOTKlassData(binaryContainer, type);
         }
@@ -317,14 +317,15 @@
         AOTKlassData old = getAOTKlassData(type);
         if (old != null) {
             boolean assertsEnabled = false;
+            // Next assignment will be executed when asserts are enabled.
             assert assertsEnabled = true;
             if (assertsEnabled) {
                 HotSpotResolvedObjectType s = type.getSuperclass();
                 if (s != null) {
-                    assert getAOTKlassData(s) != null : "fingerprint super " + s.getName() + " needed for " + type.getName();
+                    assert getAOTKlassData(s) != null : "fingerprint for super " + s.getName() + " needed for " + type.getName();
                 }
                 for (HotSpotResolvedObjectType i : type.getInterfaces()) {
-                    assert getAOTKlassData(i) != null : "fingerprint super " + i.getName() + " needed for " + type.getName();
+                    assert getAOTKlassData(i) != null : "fingerprint for interface " + i.getName() + " needed for " + type.getName();
                 }
             }
             return old;
@@ -345,10 +346,10 @@
     /*
      * Put methods data to contained.
      */
-    public void putMethodsData(BinaryContainer binaryContainer) {
+    void putMethodsData(BinaryContainer binaryContainer) {
         ReadOnlyDataContainer container = binaryContainer.getMethodsOffsetsContainer();
         int cntMethods = compiledMethods.size();
-        int startMethods = binaryContainer.addMethodsCount(cntMethods, container);
+        int startMethods = BinaryContainer.addMethodsCount(cntMethods, container);
         for (CompiledMethodInfo methodInfo : compiledMethods) {
             methodInfo.addMethodOffsets(binaryContainer, container);
         }
@@ -361,18 +362,18 @@
         data.setCompiledMethodsOffset(startMethods);
     }
 
-    public static void putAOTKlassData(BinaryContainer binaryContainer) {
+    static void putAOTKlassData(BinaryContainer binaryContainer) {
         ReadOnlyDataContainer container = binaryContainer.getKlassesOffsetsContainer();
         for (AOTKlassData data : klassData.values()) {
             data.putAOTKlassData(binaryContainer, container);
         }
     }
 
-    public boolean representsStubs() {
+    boolean representsStubs() {
         return representsStubs;
     }
 
-    public void clear() {
+    void clear() {
         for (CompiledMethodInfo c : compiledMethods) {
             c.clear();
         }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiler.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiler.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,7 @@
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
-public class AOTCompiler {
+final class AOTCompiler {
 
     private final Main main;
 
@@ -68,7 +68,7 @@
         /**
          * Create a compile queue with the given number of threads.
          */
-        public CompileQueue(final int threads) {
+        CompileQueue(final int threads) {
             super(threads, threads, 0L, TimeUnit.MILLISECONDS, new PriorityBlockingQueue<>());
             startTime = System.currentTimeMillis();
         }
@@ -79,7 +79,7 @@
             if (task.getResult() != null) {
                 final int count = successfulMethodCount.incrementAndGet();
                 if (count % 100 == 0) {
-                    main.printInfo(".");
+                    main.printer.printInfo(".");
                 }
                 CompiledMethodInfo result = task.getResult();
                 if (result != null) {
@@ -87,9 +87,9 @@
                 }
             } else {
                 failedMethodCount.incrementAndGet();
-                main.printlnVerbose("");
+                main.printer.printlnVerbose("");
                 ResolvedJavaMethod method = task.getMethod();
-                main.printlnVerbose(" failed " + method.getName() + method.getSignature().toMethodDescriptor());
+                main.printer.printlnVerbose(" failed " + method.getName() + method.getSignature().toMethodDescriptor());
             }
         }
 
@@ -98,8 +98,8 @@
             final long endTime = System.currentTimeMillis();
             final int success = successfulMethodCount.get();
             final int failed = failedMethodCount.get();
-            main.printlnInfo("");
-            main.printlnInfo(success + " methods compiled, " + failed + " methods failed (" + (endTime - startTime) + " ms)");
+            main.printer.printlnInfo("");
+            main.printer.printlnInfo(success + " methods compiled, " + failed + " methods failed (" + (endTime - startTime) + " ms)");
         }
 
     }
@@ -110,7 +110,7 @@
      * @param aotBackend
      * @param threads number of compilation threads
      */
-    public AOTCompiler(Main main, OptionValues graalOptions, AOTBackend aotBackend, final int threads) {
+    AOTCompiler(Main main, OptionValues graalOptions, AOTBackend aotBackend, final int threads) {
         this.main = main;
         this.graalOptions = graalOptions;
         this.compileQueue = new CompileQueue(threads);
@@ -123,9 +123,9 @@
      * @param classes a list of class to compile
      * @throws InterruptedException
      */
-    public List<AOTCompiledClass> compileClasses(List<AOTCompiledClass> classes) throws InterruptedException {
-        main.printlnInfo("Compiling with " + compileQueue.getCorePoolSize() + " threads");
-        main.printInfo("."); // Compilation progress indication.
+    List<AOTCompiledClass> compileClasses(List<AOTCompiledClass> classes) throws InterruptedException {
+        main.printer.printlnInfo("Compiling with " + compileQueue.getCorePoolSize() + " threads");
+        main.printer.printInfo("."); // Compilation progress indication.
 
         for (AOTCompiledClass c : classes) {
             for (ResolvedJavaMethod m : c.getMethods()) {
@@ -160,8 +160,8 @@
         }
     }
 
-    public static void logCompilation(String methodName, String message) {
-        Main.writeLog(message + " " + methodName);
+    static void logCompilation(String methodName, String message) {
+        LogPrinter.writeLog(message + " " + methodName);
     }
 
 }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,18 +29,18 @@
 import jdk.vm.ci.hotspot.HotSpotCompiledCode;
 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
 
-public class AOTHotSpotResolvedJavaMethod implements JavaMethodInfo {
+final class AOTHotSpotResolvedJavaMethod implements JavaMethodInfo {
 
     private final HotSpotResolvedJavaMethod method;
     private final Backend backend;
 
-    public AOTHotSpotResolvedJavaMethod(HotSpotResolvedJavaMethod method, Backend backend) {
+    AOTHotSpotResolvedJavaMethod(HotSpotResolvedJavaMethod method, Backend backend) {
         this.method = method;
         this.backend = backend;
     }
 
     public String getSymbolName() {
-        return MiscUtils.uniqueMethodName(method);
+        return JavaMethodInfo.uniqueMethodName(method);
     }
 
     public String getNameAndSignature() {
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,12 +30,12 @@
 
 import jdk.vm.ci.hotspot.HotSpotCompiledCode;
 
-public class AOTStub implements JavaMethodInfo {
+final class AOTStub implements JavaMethodInfo {
 
     private final Stub stub;
     private final Backend backend;
 
-    public AOTStub(Stub stub, Backend backend) {
+    AOTStub(Stub stub, Backend backend) {
         this.stub = stub;
         this.backend = backend;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallInfo.java	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import org.graalvm.compiler.bytecode.Bytecodes;
+
+import jdk.vm.ci.code.BytecodePosition;
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+final class CallInfo {
+
+    static boolean isStaticCall(Call call) {
+        if (isJavaCall(call)) {
+            return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKESTATIC);
+        }
+        return false;
+    }
+
+    static boolean isSpecialCall(Call call) {
+        if (isJavaCall(call)) {
+            return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKESPECIAL);
+        }
+        return false;
+    }
+
+    private static boolean isInvokeVirtual(Call call) {
+        if (isJavaCall(call)) {
+            return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKEVIRTUAL) || ((getByteCode(call) & 0xFF) == Bytecodes.INVOKEINTERFACE);
+        }
+        return false;
+    }
+
+    static boolean isVirtualCall(CompiledMethodInfo methodInfo, Call call) {
+        return isInvokeVirtual(call) && !methodInfo.hasMark(call, MarkId.INVOKESPECIAL);
+    }
+
+    static boolean isOptVirtualCall(CompiledMethodInfo methodInfo, Call call) {
+        return isInvokeVirtual(call) && methodInfo.hasMark(call, MarkId.INVOKESPECIAL);
+    }
+
+    private static boolean isJavaCall(Call call) {
+        // If there is no associated debug info return false
+        if (call.debugInfo == null) {
+            return false;
+        }
+        BytecodePosition bcpos = call.debugInfo.getBytecodePosition();
+        ResolvedJavaMethod method = bcpos.getMethod();
+        // If bytecode position indicates a special value (negative value) it is
+        // not a normal java call
+        if (bcpos.getBCI() < 0) {
+            return false;
+        }
+        // If there is no method associated with the debuginfo, return false
+        if (method == null) {
+            return false;
+        }
+        assert (method instanceof HotSpotResolvedJavaMethod) : "Not a resolved Java call";
+        return true;
+    }
+
+    private static byte getByteCode(Call call) {
+        ResolvedJavaMethod m = call.debugInfo.getBytecodePosition().getMethod();
+        int callPosition = call.debugInfo.getBytecodePosition().getBCI();
+        byte[] code = m.getCode();
+        return code[callPosition];
+    }
+
+}
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationInfo.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationInfo.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,10 +31,10 @@
  */
 abstract class CallSiteRelocationInfo {
 
-    public final String targetSymbol;
-    public final RelocType type;
+    final String targetSymbol;
+    final RelocType type;
 
-    public CallSiteRelocationInfo(String targetSymbol, RelocType type) {
+    CallSiteRelocationInfo(String targetSymbol, RelocType type) {
         this.targetSymbol = targetSymbol;
         this.type = type;
     }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,9 +37,9 @@
  */
 abstract class CallSiteRelocationSymbol {
 
-    public final Symbol symbol;
+    final Symbol symbol;
 
-    public CallSiteRelocationSymbol(Symbol symbol) {
+    CallSiteRelocationSymbol(Symbol symbol) {
         assert symbol != null;
         this.symbol = symbol;
     }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeOffsets.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeOffsets.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,7 @@
 
 import jdk.vm.ci.code.site.Mark;
 
-public final class CodeOffsets {
+final class CodeOffsets {
     private final int entry;
     private final int verifiedEntry;
     private final int exceptionHandler;
@@ -40,7 +40,7 @@
         this.deoptHandler = deoptHandler;
     }
 
-    public static CodeOffsets buildFrom(List<Mark> marks) {
+    static CodeOffsets buildFrom(List<Mark> marks) {
         int entry = 0;
         int verifiedEntry = 0;
         int exceptionHandler = -1;
@@ -73,19 +73,19 @@
         return new CodeOffsets(entry, verifiedEntry, exceptionHandler, deoptHandler);
     }
 
-    public int entry() {
+    int entry() {
         return entry;
     }
 
-    public int verifiedEntry() {
+    int verifiedEntry() {
         return verifiedEntry;
     }
 
-    public int exceptionHandler() {
+    int exceptionHandler() {
         return exceptionHandler;
     }
 
-    public int deoptHandler() {
+    int deoptHandler() {
         return deoptHandler;
     }
 }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeSectionProcessor.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeSectionProcessor.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,7 @@
 import jdk.tools.jaotc.binformat.BinaryContainer;
 import jdk.tools.jaotc.binformat.CodeContainer;
 import jdk.tools.jaotc.binformat.Symbol;
-import jdk.tools.jaotc.CompiledMethodInfo.StubInformation;
+import jdk.tools.jaotc.StubInformation;
 import org.graalvm.compiler.code.CompilationResult;
 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
 
@@ -38,7 +38,7 @@
 import jdk.vm.ci.code.site.InfopointReason;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
-class CodeSectionProcessor {
+final class CodeSectionProcessor {
 
     private final TargetDescription target;
 
@@ -89,11 +89,11 @@
 
             // Align and pad method entry
             CodeContainer codeSection = binaryContainer.getCodeContainer();
-            int codeIdOffset = binaryContainer.alignUp(codeSection, binaryContainer.getCodeSegmentSize());
+            int codeIdOffset = BinaryContainer.alignUp(codeSection, binaryContainer.getCodeSegmentSize());
             // Store CodeId into code. It will be use by find_aot() using code.segments
             methodInfo.setCodeId();
             binaryContainer.appendIntToCode(methodInfo.getCodeId());
-            int textBaseOffset = binaryContainer.alignUp(codeSection, binaryContainer.getCodeEntryAlignment());
+            int textBaseOffset = BinaryContainer.alignUp(codeSection, binaryContainer.getCodeEntryAlignment());
 
             codeSection.createSymbol(textBaseOffset, Symbol.Kind.JAVA_FUNCTION, Symbol.Binding.LOCAL, targetCodeSize, entry);
 
@@ -102,7 +102,7 @@
 
             // Write code bytes of the current method into byte stream
             binaryContainer.appendCodeBytes(targetCode, 0, targetCodeSize);
-            int currentStubOffset = binaryContainer.alignUp(codeSection, 8);
+            int currentStubOffset = BinaryContainer.alignUp(codeSection, 8);
             // Set the offset at which stubs of this method would be laid out
             methodInfo.setStubsOffset(currentStubOffset - textBaseOffset);
             // step through all calls, for every call, add a stub
@@ -111,10 +111,10 @@
                     final Call callInfopoint = (Call) infopoint;
                     if (callInfopoint.target instanceof ResolvedJavaMethod) {
                         ResolvedJavaMethod call = (ResolvedJavaMethod) callInfopoint.target;
-                        StubInformation stub = addCallStub(MiscUtils.isVirtualCall(methodInfo, callInfopoint));
+                        StubInformation stub = addCallStub(CallInfo.isVirtualCall(methodInfo, callInfopoint));
                         // Get the targetSymbol. A symbol for this will be created later during plt
                         // creation
-                        String targetSymbol = MiscUtils.uniqueMethodName(call) + ".at." + infopoint.pcOffset;
+                        String targetSymbol = JavaMethodInfo.uniqueMethodName(call) + ".at." + infopoint.pcOffset;
                         methodInfo.addStubCode(targetSymbol, stub);
                         currentStubOffset += stub.getSize();
                     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Collector.java	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import jdk.tools.jaotc.collect.ClassSearch;
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider;
+import jdk.tools.jaotc.collect.directory.DirectorySourceProvider;
+import jdk.tools.jaotc.collect.jar.JarSourceProvider;
+import jdk.tools.jaotc.collect.module.ModuleSourceProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+final class Collector {
+
+    private final Main main;
+
+    Collector(Main main) {
+        this.main = main;
+    }
+
+    Set<Class<?>> collectClassesToCompile() {
+        Set<Class<?>> classesToCompile = new HashSet<>();
+        FileSupport fileSupport = new FileSupport();
+        ClassSearch lookup = new ClassSearch();
+        lookup.addProvider(new ModuleSourceProvider());
+        lookup.addProvider(new ClassNameSourceProvider(fileSupport));
+        lookup.addProvider(new JarSourceProvider());
+        lookup.addProvider(new DirectorySourceProvider(fileSupport));
+
+        List<LoadedClass> foundClasses = null;
+        try {
+            foundClasses = lookup.search(main.options.files, main.options.searchPath);
+        } catch (InternalError e) {
+            main.printer.reportError(e);
+            return null;
+        }
+
+        for (LoadedClass loadedClass : foundClasses) {
+            classesToCompile.add(loadedClass.getLoadedClass());
+        }
+        return classesToCompile;
+    }
+
+    private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions) {
+        for (ResolvedJavaMethod m : methods) {
+            addMethod(aotClass, m, compilationRestrictions);
+        }
+    }
+
+    private void addMethod(AOTCompiledClass aotClass, ResolvedJavaMethod method, CompilationSpec compilationRestrictions) {
+        // Don't compile native or abstract methods.
+        if (!method.hasBytecodes()) {
+            return;
+        }
+        if (!compilationRestrictions.shouldCompileMethod(method)) {
+            return;
+        }
+        if (!main.filters.shouldCompileMethod(method)) {
+            return;
+        }
+
+        aotClass.addMethod(method);
+        main.printer.printlnVerbose("  added " + method.getName() + method.getSignature().toMethodDescriptor());
+    }
+
+    /**
+     * Collect all method we should compile.
+     *
+     * @return array list of AOT classes which have compiled methods.
+     */
+    List<AOTCompiledClass> collectMethodsToCompile(Set<Class<?>> classesToCompile, MetaAccessProvider metaAccess) {
+        int total = 0;
+        int count = 0;
+        List<AOTCompiledClass> classes = new ArrayList<>();
+        CompilationSpec compilationRestrictions = collectSpecifiedMethods();
+
+        for (Class<?> c : classesToCompile) {
+            ResolvedJavaType resolvedJavaType = metaAccess.lookupJavaType(c);
+            if (main.filters.shouldCompileAnyMethodInClass(resolvedJavaType)) {
+                AOTCompiledClass aotClass = new AOTCompiledClass(resolvedJavaType);
+                main.printer.printlnVerbose(" Scanning " + c.getName());
+
+                // Constructors
+                try {
+                    ResolvedJavaMethod[] ctors = resolvedJavaType.getDeclaredConstructors();
+                    addMethods(aotClass, ctors, compilationRestrictions);
+                    total += ctors.length;
+                } catch (Throwable e) {
+                    // If we are running in JCK mode we ignore all exceptions.
+                    if (main.options.ignoreClassLoadingErrors) {
+                        main.printer.printError(c.getName() + ": " + e);
+                    } else {
+                        throw new InternalError(e);
+                    }
+                }
+
+                // Methods
+                try {
+                    ResolvedJavaMethod[] methods = resolvedJavaType.getDeclaredMethods();
+                    addMethods(aotClass, methods, compilationRestrictions);
+                    total += methods.length;
+                } catch (Throwable e) {
+                    // If we are running in JCK mode we ignore all exceptions.
+                    if (main.options.ignoreClassLoadingErrors) {
+                        main.printer.printError(c.getName() + ": " + e);
+                    } else {
+                        throw new InternalError(e);
+                    }
+                }
+
+                // Class initializer
+                try {
+                    ResolvedJavaMethod clinit = resolvedJavaType.getClassInitializer();
+                    if (clinit != null) {
+                        addMethod(aotClass, clinit, compilationRestrictions);
+                        total++;
+                    }
+                } catch (Throwable e) {
+                    // If we are running in JCK mode we ignore all exceptions.
+                    if (main.options.ignoreClassLoadingErrors) {
+                        main.printer.printError(c.getName() + ": " + e);
+                    } else {
+                        throw new InternalError(e);
+                    }
+                }
+
+                // Found any methods to compile? Add the class.
+                if (aotClass.hasMethods()) {
+                    classes.add(aotClass);
+                    count += aotClass.getMethodCount();
+                }
+            }
+        }
+        main.printer.printInfo(total + " methods total, " + count + " methods to compile");
+        return classes;
+    }
+
+    /**
+     * If a file with compilation limitations is specified using flag --compile-commands, read the
+     * file's contents and collect the restrictions.
+     */
+    private CompilationSpec collectSpecifiedMethods() {
+        CompilationSpec compilationRestrictions = new CompilationSpec();
+        String methodListFileName = main.options.methodList;
+
+        if (methodListFileName != null && !methodListFileName.equals("")) {
+            try {
+                FileReader methListFile = new FileReader(methodListFileName);
+                BufferedReader readBuf = new BufferedReader(methListFile);
+                String line = null;
+                while ((line = readBuf.readLine()) != null) {
+                    String trimmedLine = line.trim();
+                    if (!trimmedLine.startsWith("#")) {
+                        String[] components = trimmedLine.split(" ");
+                        if (components.length == 2) {
+                            String directive = components[0];
+                            String pattern = components[1];
+                            switch (directive) {
+                                case "compileOnly":
+                                    compilationRestrictions.addCompileOnlyPattern(pattern);
+                                    break;
+                                case "exclude":
+                                    compilationRestrictions.addExcludePattern(pattern);
+                                    break;
+                                default:
+                                    System.out.println("Unrecognized command " + directive + ". Ignoring\n\t" + line + "\n encountered in " + methodListFileName);
+                            }
+                        } else {
+                            if (!trimmedLine.equals("")) {
+                                System.out.println("Ignoring malformed line:\n\t " + line + "\n");
+                            }
+                        }
+                    }
+                }
+                readBuf.close();
+            } catch (FileNotFoundException e) {
+                throw new InternalError("Unable to open method list file: " + methodListFileName, e);
+            } catch (IOException e) {
+                throw new InternalError("Unable to read method list file: " + methodListFileName, e);
+            }
+        }
+
+        return compilationRestrictions;
+    }
+
+}
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompilationSpec.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompilationSpec.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@
 /**
  * A class encapsulating any user-specified compilation restrictions.
  */
-public class CompilationSpec {
+final class CompilationSpec {
 
     /**
      * Set of method names to restrict compilation to.
@@ -51,7 +51,7 @@
      *
      * @param pattern regex or non-regex pattern string
      */
-    public void addCompileOnlyPattern(String pattern) {
+    void addCompileOnlyPattern(String pattern) {
         if (pattern.contains("*")) {
             compileOnlyPatterns.add(Pattern.compile(pattern));
         } else {
@@ -64,7 +64,7 @@
      *
      * @param pattern regex or non-regex pattern string
      */
-    public void addExcludePattern(String pattern) {
+    void addExcludePattern(String pattern) {
         if (pattern.contains("*")) {
             excludePatterns.add(Pattern.compile(pattern));
         } else {
@@ -78,14 +78,14 @@
      * @param method method to be checked
      * @return true or false
      */
-    public boolean shouldCompileMethod(ResolvedJavaMethod method) {
+    boolean shouldCompileMethod(ResolvedJavaMethod method) {
         if (compileWithRestrictions()) {
             // If there are user-specified compileOnly patterns, default action
             // is not to compile the method.
             boolean compileMethod = compileOnlyStrings.isEmpty() && compileOnlyPatterns.isEmpty();
 
             // Check if the method matches with any of the specified compileOnly patterns.
-            String methodName = MiscUtils.uniqueMethodName(method);
+            String methodName = JavaMethodInfo.uniqueMethodName(method);
 
             // compileOnly
             if (!compileMethod) {
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,104 +37,7 @@
 import jdk.vm.ci.hotspot.HotSpotCompiledCode;
 import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
 
-public class CompiledMethodInfo {
-
-    public static class StubInformation {
-        int stubOffset;         // the offset inside the code (text + stubOffset)
-        int stubSize;           // the stub size
-        int dispatchJumpOffset; // offset after main dispatch jump instruction
-        int resolveJumpOffset;  // offset after jump instruction to runtime call resolution
-                               // function.
-        int resolveJumpStart;   // offset of jump instruction to VM runtime call resolution
-                              // function.
-        int c2iJumpOffset;      // offset after jump instruction to c2i adapter for static calls.
-        int movOffset; // offset after move instruction which loads from got cell:
-                       // - Method* for static call
-                       // - Klass* for virtual call
-
-        boolean isVirtual;  // virtual call stub
-
-        // maybe add type of stub as well, right now we only have static stubs
-
-        public StubInformation(int stubOffset, boolean isVirtual) {
-            this.stubOffset = stubOffset;
-            this.isVirtual = isVirtual;
-            this.stubSize = -1;
-            this.movOffset = -1;
-            this.c2iJumpOffset = -1;
-            this.resolveJumpOffset = -1;
-            this.resolveJumpStart = -1;
-            this.dispatchJumpOffset = -1;
-        }
-
-        public int getOffset() {
-            return stubOffset;
-        }
-
-        public boolean isVirtual() {
-            return isVirtual;
-        }
-
-        public void setSize(int stubSize) {
-            this.stubSize = stubSize;
-        }
-
-        public int getSize() {
-            return stubSize;
-        }
-
-        public void setMovOffset(int movOffset) {
-            this.movOffset = movOffset + stubOffset;
-        }
-
-        public int getMovOffset() {
-            return movOffset;
-        }
-
-        public void setC2IJumpOffset(int c2iJumpOffset) {
-            this.c2iJumpOffset = c2iJumpOffset + stubOffset;
-        }
-
-        public int getC2IJumpOffset() {
-            return c2iJumpOffset;
-        }
-
-        public void setResolveJumpOffset(int resolveJumpOffset) {
-            this.resolveJumpOffset = resolveJumpOffset + stubOffset;
-        }
-
-        public int getResolveJumpOffset() {
-            return resolveJumpOffset;
-        }
-
-        public void setResolveJumpStart(int resolveJumpStart) {
-            this.resolveJumpStart = resolveJumpStart + stubOffset;
-        }
-
-        public int getResolveJumpStart() {
-            return resolveJumpStart;
-        }
-
-        public void setDispatchJumpOffset(int dispatchJumpOffset) {
-            this.dispatchJumpOffset = dispatchJumpOffset + stubOffset;
-        }
-
-        public int getDispatchJumpOffset() {
-            return dispatchJumpOffset;
-        }
-
-        public void verify() {
-            assert stubOffset > 0 : "incorrect stubOffset: " + stubOffset;
-            assert stubSize > 0 : "incorrect stubSize: " + stubSize;
-            assert movOffset > 0 : "incorrect movOffset: " + movOffset;
-            assert dispatchJumpOffset > 0 : "incorrect dispatchJumpOffset: " + dispatchJumpOffset;
-            assert resolveJumpStart > 0 : "incorrect resolveJumpStart: " + resolveJumpStart;
-            assert resolveJumpOffset > 0 : "incorrect resolveJumpOffset: " + resolveJumpOffset;
-            if (!isVirtual) {
-                assert c2iJumpOffset > 0 : "incorrect c2iJumpOffset: " + c2iJumpOffset;
-            }
-        }
-    }
+final class CompiledMethodInfo {
 
     private static final int UNINITIALIZED_OFFSET = -1;
 
@@ -169,7 +72,7 @@
          */
         private int codeId;
 
-        public AOTMethodOffsets() {
+        AOTMethodOffsets() {
             this.nameOffset = UNINITIALIZED_OFFSET;
             this.textSectionOffset = UNINITIALIZED_OFFSET;
             this.metadataOffset = UNINITIALIZED_OFFSET;
@@ -178,7 +81,7 @@
             this.codeId = -1;
         }
 
-        protected void addMethodOffsets(ReadOnlyDataContainer container, String name) {
+        void addMethodOffsets(ReadOnlyDataContainer container, String name) {
             verify(name);
             // @formatter:off
             /*
@@ -291,7 +194,7 @@
      */
     private static final AtomicInteger methodsCount = new AtomicInteger();
 
-    public CompiledMethodInfo(CompilationResult compilationResult, JavaMethodInfo methodInfo) {
+    CompiledMethodInfo(CompilationResult compilationResult, JavaMethodInfo methodInfo) {
         this.name = methodInfo.getNameAndSignature();
         this.compilationResult = compilationResult;
         this.methodInfo = methodInfo;
@@ -299,11 +202,11 @@
         this.methodOffsets = new AOTMethodOffsets();
     }
 
-    public String name() {
+    String name() {
         return name;
     }
 
-    public void addMethodOffsets(BinaryContainer binaryContainer, ReadOnlyDataContainer container) {
+    void addMethodOffsets(BinaryContainer binaryContainer, ReadOnlyDataContainer container) {
         this.methodOffsets.setNameOffset(binaryContainer.addMetaspaceName(name));
         this.methodOffsets.addMethodOffsets(container, name);
         for (AOTKlassData data : dependentKlasses.values()) {
@@ -311,15 +214,15 @@
         }
     }
 
-    public CompilationResult getCompilationResult() {
+    CompilationResult getCompilationResult() {
         return compilationResult;
     }
 
-    public JavaMethodInfo getMethodInfo() {
+    JavaMethodInfo getMethodInfo() {
         return methodInfo;
     }
 
-    public void setTextSectionOffset(int textSectionOffset) {
+    void setTextSectionOffset(int textSectionOffset) {
         methodOffsets.setTextSectionOffset(textSectionOffset);
     }
 
@@ -327,66 +230,66 @@
         return methodOffsets.getTextSectionOffset();
     }
 
-    public void setCodeId() {
+    void setCodeId() {
         methodOffsets.setCodeId(CompiledMethodInfo.getNextCodeId());
     }
 
-    public int getCodeId() {
+    int getCodeId() {
         return this.methodOffsets.getCodeId();
     }
 
-    public static int getMethodsCount() {
+    static int getMethodsCount() {
         return methodsCount.get();
     }
 
-    public static int getNextCodeId() {
+    static int getNextCodeId() {
         return methodsCount.getAndIncrement();
     }
 
-    public int getCodeSize() {
+    int getCodeSize() {
         return stubsOffset + getStubCodeSize();
     }
 
-    public int getStubCodeSize() {
+    int getStubCodeSize() {
         return totalStubSize;
     }
 
-    public void setMetadataOffset(int offset) {
+    void setMetadataOffset(int offset) {
         this.methodOffsets.setMetadataOffset(offset);
     }
 
     /**
      * Offset into the code of this method where the stub section starts.
      */
-    public void setStubsOffset(int offset) {
+    void setStubsOffset(int offset) {
         stubsOffset = offset;
     }
 
-    public int getStubsOffset() {
+    int getStubsOffset() {
         return stubsOffset;
     }
 
-    public void setMetadataGotOffset(int metadataGotOffset) {
+    void setMetadataGotOffset(int metadataGotOffset) {
         this.methodOffsets.setMetadataGotOffset(metadataGotOffset);
     }
 
-    public void setMetadataGotSize(int length) {
+    void setMetadataGotSize(int length) {
         this.methodOffsets.setMetadataGotSize(length);
     }
 
-    public void addStubCode(String call, StubInformation stub) {
+    void addStubCode(String call, StubInformation stub) {
         stubs.put(call, stub);
         totalStubSize += stub.getSize();
     }
 
-    public StubInformation getStubFor(String call) {
+    StubInformation getStubFor(String call) {
         StubInformation stub = stubs.get(call);
         assert stub != null : "missing stub for call " + call;
         stub.verify();
         return stub;
     }
 
-    public void addDependentKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) {
+    void addDependentKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) {
         AOTKlassData klassData = AOTCompiledClass.addFingerprintKlassData(binaryContainer, type);
         String klassName = type.getName();
 
@@ -397,11 +300,11 @@
         }
     }
 
-    public AOTKlassData getDependentKlassData(String klassName) {
+    AOTKlassData getDependentKlassData(String klassName) {
         return dependentKlasses.get(klassName);
     }
 
-    public boolean hasMark(Site call, MarkId id) {
+    boolean hasMark(Site call, MarkId id) {
         for (Mark m : compilationResult.getMarks()) {
             // TODO: X64-specific code.
             // Call instructions are aligned to 8
@@ -415,11 +318,11 @@
         return false;
     }
 
-    public String asTag() {
+    String asTag() {
         return "[" + methodInfo.getSymbolName() + "]";
     }
 
-    public HotSpotCompiledCode compiledCode() {
+    HotSpotCompiledCode compiledCode() {
         if (code == null) {
             code = methodInfo.compiledCode(compilationResult);
         }
@@ -427,12 +330,12 @@
     }
 
     // Free memory
-    public void clear() {
+    void clear() {
         this.dependentKlasses = null;
         this.name = null;
     }
 
-    public void clearCompileData() {
+    void clearCompileData() {
         this.code = null;
         this.stubs = null;
         this.compilationResult = null;
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,7 @@
 import jdk.tools.jaotc.binformat.BinaryContainer;
 import jdk.tools.jaotc.binformat.ByteContainer;
 import jdk.tools.jaotc.binformat.HeaderContainer;
-import jdk.tools.jaotc.utils.Timer;
+
 import org.graalvm.compiler.code.CompilationResult;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.hotspot.HotSpotHostBackend;
@@ -42,7 +42,7 @@
 import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
 import jdk.vm.ci.hotspot.VMField;
 
-class DataBuilder {
+final class DataBuilder {
 
     private final Main main;
 
@@ -55,9 +55,9 @@
      */
     private final BinaryContainer binaryContainer;
 
-    private final HashMap<Long, String> vmAddresses = new HashMap<>();
+    private static final HashMap<Long, String> vmAddresses = new HashMap<>();
 
-    public DataBuilder(Main main, HotSpotHostBackend backend, List<AOTCompiledClass> classes, BinaryContainer binaryContainer) {
+    DataBuilder(Main main, HotSpotHostBackend backend, List<AOTCompiledClass> classes, BinaryContainer binaryContainer) {
         this.main = main;
         this.backend = backend;
         this.classes = classes;
@@ -68,7 +68,7 @@
     /**
      * Returns a value-name map of all {@link VMField} fields.
      */
-    private void fillVMAddresses(HotSpotVMConfigStore config) {
+    private static void fillVMAddresses(HotSpotVMConfigStore config) {
         for (VMField vmField : config.getFields().values()) {
             if (vmField.value != null && vmField.value instanceof Long) {
                 final long address = (Long) vmField.value;
@@ -98,7 +98,7 @@
      * @param address native address
      * @return C/C++ functio name associated with the native address
      */
-    public String getVMFunctionNameForAddress(long address) {
+    static String getVMFunctionNameForAddress(long address) {
         return vmAddresses.get(address);
     }
 
@@ -107,7 +107,7 @@
      *
      * @return host backend
      */
-    public HotSpotHostBackend getBackend() {
+    HotSpotHostBackend getBackend() {
         return backend;
     }
 
@@ -116,7 +116,7 @@
      *
      * @return binary container
      */
-    public BinaryContainer getBinaryContainer() {
+    BinaryContainer getBinaryContainer() {
         return binaryContainer;
     }
 
@@ -128,7 +128,7 @@
      * @throws Exception
      */
     @SuppressWarnings("try")
-    public void prepareData(DebugContext debug) throws Exception {
+    void prepareData(DebugContext debug) throws Exception {
         try (Timer t = new Timer(main, "Parsing compiled code")) {
             /*
              * Copy compiled code into code section container and calls stubs (PLT trampoline).
@@ -147,7 +147,7 @@
 
         // Free memory!
         try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) {
-            main.printMemoryUsage();
+            main.printer.printMemoryUsage();
             System.gc();
         }
 
@@ -163,7 +163,7 @@
 
         // Free memory!
         try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) {
-            main.printMemoryUsage();
+            main.printer.printMemoryUsage();
             System.gc();
         }
 
@@ -172,7 +172,7 @@
         }
         try (Timer t = new Timer(main, "Preparing compiled binary")) {
             // Should be called after Stubs because they can set dependent klasses.
-            prepareCompiledBinary(metadataBuilder);
+            prepareCompiledBinary();
         }
     }
 
@@ -203,7 +203,7 @@
     /**
      * Prepare metaspace.offsets section.
      */
-    private void prepareCompiledBinary(MetadataBuilder metadataBuilder) {
+    private void prepareCompiledBinary() {
         for (AOTCompiledClass c : classes) {
             // Create records for compiled AOT methods.
             c.putMethodsData(binaryContainer);
@@ -216,8 +216,8 @@
         header.setClassesCount(AOTCompiledClass.getClassesCount());
         header.setMethodsCount(CompiledMethodInfo.getMethodsCount());
         // Record size of got sections
-        ByteContainer bc = binaryContainer.getMetaspaceGotContainer();
-        header.setMetaspaceGotSize((bc.getByteStreamSize() / 8));
+        ByteContainer bc = binaryContainer.getKlassesGotContainer();
+        header.setKlassesGotSize((bc.getByteStreamSize() / 8));
         bc = binaryContainer.getMetadataGotContainer();
         header.setMetadataGotSize((bc.getByteStreamSize() / 8));
         bc = binaryContainer.getOopGotContainer();
@@ -232,7 +232,7 @@
         // them.
         ArrayList<CompiledMethodInfo> compiledStubs = compiledClass.getCompiledMethods();
         int cntStubs = compiledStubs.size();
-        binaryContainer.addMethodsCount(cntStubs, binaryContainer.getStubsOffsetsContainer());
+        BinaryContainer.addMethodsCount(cntStubs, binaryContainer.getStubsOffsetsContainer());
         for (CompiledMethodInfo methodInfo : compiledStubs) {
             // Note, stubs have different offsets container.
             methodInfo.addMethodOffsets(binaryContainer, binaryContainer.getStubsOffsetsContainer());
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,6 @@
 import jdk.tools.jaotc.binformat.Symbol;
 import jdk.tools.jaotc.binformat.Symbol.Binding;
 import jdk.tools.jaotc.binformat.Symbol.Kind;
-import jdk.tools.jaotc.AOTCompiledClass.AOTKlassData;
 import org.graalvm.compiler.code.DataSection;
 import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
 
@@ -47,7 +46,7 @@
 import jdk.vm.ci.hotspot.HotSpotSentinelConstant;
 import jdk.vm.ci.meta.VMConstant;
 
-class DataPatchProcessor {
+final class DataPatchProcessor {
 
     private final TargetDescription target;
 
@@ -89,9 +88,9 @@
                 gotName = ((action == HotSpotConstantLoadAction.INITIALIZE) ? "got.init." : "got.") + targetSymbol;
                 methodInfo.addDependentKlassData(binaryContainer, type);
             } else if (metaspaceConstant.asResolvedJavaMethod() != null && action == HotSpotConstantLoadAction.LOAD_COUNTERS) {
-                targetSymbol = "counters." + MiscUtils.uniqueMethodName(metaspaceConstant.asResolvedJavaMethod());
+                targetSymbol = "counters." + JavaMethodInfo.uniqueMethodName(metaspaceConstant.asResolvedJavaMethod());
                 gotName = "got." + targetSymbol;
-                binaryContainer.addMetaspaceSymbol(targetSymbol);
+                binaryContainer.addCountersSymbol(targetSymbol);
             }
         } else if (constant instanceof HotSpotObjectConstant) {
             // String constant.
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ELFMacroAssembler.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ELFMacroAssembler.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 
 package jdk.tools.jaotc;
 
-import jdk.tools.jaotc.CompiledMethodInfo.StubInformation;
+import jdk.tools.jaotc.StubInformation;
 import jdk.tools.jaotc.amd64.AMD64ELFMacroAssembler;
 
 import jdk.vm.ci.amd64.AMD64;
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationInfo.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationInfo.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,21 +37,20 @@
  */
 final class ForeignCallSiteRelocationInfo extends CallSiteRelocationInfo {
 
-    ForeignCallSiteRelocationInfo(Call call, HotSpotForeignCallLinkage callTarget, DataBuilder dataBuilder) {
-        super(getTargetSymbol(call, callTarget, dataBuilder), getRelocType(callTarget));
+    ForeignCallSiteRelocationInfo(Call call, HotSpotForeignCallLinkage callTarget) {
+        super(getTargetSymbol(call, callTarget), getRelocType(callTarget));
     }
 
-    private static String getTargetSymbol(Call call, HotSpotForeignCallLinkage callTarget, DataBuilder dataBuilder) {
+    private static String getTargetSymbol(Call call, HotSpotForeignCallLinkage callTarget) {
         // If it specifies a foreign call linkage, find the symbol corresponding to the address in
         // HotSpotVMConfig's fields.
         final long foreignCallTargetAddress = callTarget.getAddress();
 
         // Get the C/C++ function name associated with the foreign call target address.
-        String functionName = dataBuilder.getVMFunctionNameForAddress(foreignCallTargetAddress);
+        String functionName = DataBuilder.getVMFunctionNameForAddress(foreignCallTargetAddress);
         if (functionName != null) {
             // Use the known global AOT symbol associated with function name, if one exists
-            BinaryContainer binaryContainer = dataBuilder.getBinaryContainer();
-            String aotSymbol = binaryContainer.getAOTSymbolForVMFunctionName(functionName);
+            String aotSymbol = BinaryContainer.getAOTSymbolForVMFunctionName(functionName);
             if (aotSymbol == null) {
                 throw new InternalError("no global symbol found for: " + functionName);
             }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationSymbol.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationSymbol.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@
  */
 final class ForeignCallSiteRelocationSymbol extends CallSiteRelocationSymbol {
 
-    public ForeignCallSiteRelocationSymbol(CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) {
+    ForeignCallSiteRelocationSymbol(CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) {
         super(binaryContainer.createSymbol(0, Kind.NATIVE_FUNCTION, Binding.GLOBAL, 0, callSiteRelocation.targetSymbol));
     }
 
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignGotCallSiteRelocationSymbol.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignGotCallSiteRelocationSymbol.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,7 @@
 
 final class ForeignGotCallSiteRelocationSymbol extends CallSiteRelocationSymbol {
 
-    public ForeignGotCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation, DataBuilder dataBuilder) {
+    ForeignGotCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation, DataBuilder dataBuilder) {
         super(createPltSymbol(dataBuilder, mi, call, callSiteRelocation));
     }
 
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,7 +45,7 @@
 import org.graalvm.compiler.replacements.Snippets;
 import org.graalvm.word.WordBase;
 
-public class GraalFilters {
+final class GraalFilters {
     private List<ResolvedJavaType> specialClasses;
     private List<ResolvedJavaType> specialArgumentAndReturnTypes;
 
@@ -57,7 +57,7 @@
         skipAnnotations.add(MethodSubstitution.class);
     }
 
-    public boolean shouldCompileMethod(ResolvedJavaMethod method) {
+    boolean shouldCompileMethod(ResolvedJavaMethod method) {
         // NodeIntrinsics cannot be compiled.
         if (hasExcludedAnnotation(method)) {
             return false;
@@ -83,7 +83,7 @@
         return false;
     }
 
-    public boolean shouldCompileAnyMethodInClass(ResolvedJavaType klass) {
+    boolean shouldCompileAnyMethodInClass(ResolvedJavaType klass) {
         if (specialClasses.stream().filter(s -> s.isAssignableFrom(klass)).findAny().isPresent()) {
             return false;
         }
@@ -113,7 +113,7 @@
         specialArgumentAndReturnTypes = getSpecialArgumentAndReturnTypes(metaAccess);
     }
 
-    public boolean shouldIgnoreException(Throwable e) {
+    static boolean shouldIgnoreException(Throwable e) {
         if (e instanceof GraalError) {
             String m = e.getMessage();
             if (m.contains("ArrayKlass::_component_mirror")) {
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InfopointProcessor.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InfopointProcessor.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,16 +28,14 @@
 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
 
 import jdk.vm.ci.code.BytecodePosition;
-import jdk.vm.ci.code.DebugInfo;
 import jdk.vm.ci.code.VirtualObject;
 import jdk.vm.ci.code.site.Call;
 import jdk.vm.ci.code.site.Infopoint;
 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
-import jdk.vm.ci.hotspot.HotSpotResolvedJavaType;
 import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
 import jdk.vm.ci.meta.InvokeTarget;
 
-class InfopointProcessor {
+final class InfopointProcessor {
 
     private final DataBuilder dataBuilder;
 
@@ -70,9 +68,13 @@
             default:
                 throw new InternalError("Unknown info point reason: " + info.reason);
         }
-        if (info.debugInfo == null) return;
+        if (info.debugInfo == null) {
+            return;
+        }
         BytecodePosition bcp = info.debugInfo.getBytecodePosition();
-        if (bcp == null) return;
+        if (bcp == null) {
+            return;
+        }
         recordScopeKlasses(methodInfo, bcp, info.debugInfo.getVirtualObjectMapping());
     }
 
@@ -82,14 +84,15 @@
             recordScopeKlasses(methodInfo, caller, vos);
         }
 
-        HotSpotResolvedJavaMethod m = (HotSpotResolvedJavaMethod)bcp.getMethod();
+        HotSpotResolvedJavaMethod m = (HotSpotResolvedJavaMethod) bcp.getMethod();
         HotSpotResolvedObjectType klass = m.getDeclaringClass();
         methodInfo.addDependentKlassData(binaryContainer, klass);
 
-        if (vos == null) return;
-
+        if (vos == null) {
+            return;
+        }
         for (VirtualObject vo : vos) {
-            HotSpotResolvedObjectType vk = (HotSpotResolvedObjectType)vo.getType();
+            HotSpotResolvedObjectType vk = (HotSpotResolvedObjectType) vo.getType();
             methodInfo.addDependentKlassData(binaryContainer, vk);
         }
 
@@ -116,12 +119,12 @@
     /**
      * Get information about the call site. Name of the callee and relocation call type.
      */
-    private CallSiteRelocationInfo getCallSiteRelocationInfo(Call call) {
+    private static CallSiteRelocationInfo getCallSiteRelocationInfo(Call call) {
         InvokeTarget callTarget = call.target;
         if (callTarget instanceof HotSpotResolvedJavaMethod) {
             return new JavaCallSiteRelocationInfo(call, (HotSpotResolvedJavaMethod) callTarget);
         } else if (callTarget instanceof HotSpotForeignCallLinkage) {
-            return new ForeignCallSiteRelocationInfo(call, (HotSpotForeignCallLinkage) callTarget, dataBuilder);
+            return new ForeignCallSiteRelocationInfo(call, (HotSpotForeignCallLinkage) callTarget);
         } else {
             throw new InternalError("Unhandled call type found in infopoint: " + callTarget);
         }
@@ -136,10 +139,6 @@
                 return new StubDirectCallSiteRelocationSymbol(callSiteRelocation, binaryContainer);
             case FOREIGN_CALL_INDIRECT_GOT:
                 return new ForeignGotCallSiteRelocationSymbol(mi, call, callSiteRelocation, dataBuilder);
-            case FOREIGN_CALL_DIRECT:
-            case FOREIGN_CALL_DIRECT_FAR:
-            case FOREIGN_CALL_INDIRECT:
-                return new ForeignCallSiteRelocationSymbol(callSiteRelocation, binaryContainer);
             default:
                 return new JavaCallSiteRelocationSymbol(mi, call, callSiteRelocation, binaryContainer);
         }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationInfo.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationInfo.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,8 +34,8 @@
  */
 final class JavaCallSiteRelocationInfo extends CallSiteRelocationInfo {
 
-    public JavaCallSiteRelocationInfo(Call call, HotSpotResolvedJavaMethod callTarget) {
-        super(MiscUtils.uniqueMethodName(callTarget), call.direct ? RelocType.JAVA_CALL_DIRECT : RelocType.JAVA_CALL_INDIRECT);
+    JavaCallSiteRelocationInfo(Call call, HotSpotResolvedJavaMethod callTarget) {
+        super(JavaMethodInfo.uniqueMethodName(callTarget), call.direct ? RelocType.JAVA_CALL_DIRECT : RelocType.JAVA_CALL_INDIRECT);
     }
 
 }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,7 @@
 
 import jdk.tools.jaotc.binformat.BinaryContainer;
 import jdk.tools.jaotc.binformat.Symbol;
-import jdk.tools.jaotc.CompiledMethodInfo.StubInformation;
+import jdk.tools.jaotc.StubInformation;
 
 import jdk.vm.ci.code.site.Call;
 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
@@ -40,7 +40,7 @@
     // -1 represents Universe::non_oop_word() value
     private static final byte[] minusOneSlot = {-1, -1, -1, -1, -1, -1, -1, -1};
 
-    public JavaCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) {
+    JavaCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) {
         super(createPltEntrySymbol(binaryContainer, mi, call, callSiteRelocation));
         StubInformation stub = getStub(mi, call);
         addRelocations(mi, stub, binaryContainer, call, callSiteRelocation);
@@ -61,7 +61,7 @@
 
     private static StubInformation getStub(CompiledMethodInfo mi, Call call) {
         HotSpotResolvedJavaMethod callTarget = (HotSpotResolvedJavaMethod) call.target;
-        String callTargetSymbol = MiscUtils.uniqueMethodName(callTarget) + ".at." + call.pcOffset;
+        String callTargetSymbol = JavaMethodInfo.uniqueMethodName(callTarget) + ".at." + call.pcOffset;
         return mi.getStubFor(callTargetSymbol);
     }
 
@@ -69,7 +69,7 @@
      * Add all the required relocations.
      */
     private static void addRelocations(CompiledMethodInfo mi, StubInformation stub, BinaryContainer binaryContainer, Call call, CallSiteRelocationInfo callSiteRelocation) {
-        final boolean isVirtualCall = MiscUtils.isVirtualCall(mi, call);
+        final boolean isVirtualCall = CallInfo.isVirtualCall(mi, call);
 
         final int gotStartOffset = binaryContainer.appendExtLinkageGotBytes(zeroSlot, 0, zeroSlot.length);
         if (isVirtualCall) {
@@ -82,7 +82,7 @@
         // Add relocation to GOT cell for call resolution jump.
         // This GOT cell will be initialized during JVM startup with address
         // of JVM runtime call resolution function.
-        String gotSymbolName = "got." + getResolveSymbolName(binaryContainer, mi, call);
+        String gotSymbolName = "got." + getResolveSymbolName(mi, call);
         Symbol gotSymbol = binaryContainer.getGotSymbol(gotSymbolName);
         addExternalPltToGotRelocation(binaryContainer, gotSymbol, stub.getResolveJumpOffset());
 
@@ -121,16 +121,16 @@
     /**
      * Returns the name of the resolve method for this particular call.
      */
-    private static String getResolveSymbolName(BinaryContainer binaryContainer, CompiledMethodInfo mi, Call call) {
+    private static String getResolveSymbolName(CompiledMethodInfo mi, Call call) {
         String resolveSymbolName;
-        if (MiscUtils.isStaticCall(call)) {
-            resolveSymbolName = binaryContainer.getResolveStaticEntrySymbolName();
-        } else if (MiscUtils.isSpecialCall(call)) {
-            resolveSymbolName = binaryContainer.getResolveOptVirtualEntrySymbolName();
-        } else if (MiscUtils.isOptVirtualCall(mi, call)) {
-            resolveSymbolName = binaryContainer.getResolveOptVirtualEntrySymbolName();
-        } else if (MiscUtils.isVirtualCall(mi, call)) {
-            resolveSymbolName = binaryContainer.getResolveVirtualEntrySymbolName();
+        if (CallInfo.isStaticCall(call)) {
+            resolveSymbolName = BinaryContainer.getResolveStaticEntrySymbolName();
+        } else if (CallInfo.isSpecialCall(call)) {
+            resolveSymbolName = BinaryContainer.getResolveOptVirtualEntrySymbolName();
+        } else if (CallInfo.isOptVirtualCall(mi, call)) {
+            resolveSymbolName = BinaryContainer.getResolveOptVirtualEntrySymbolName();
+        } else if (CallInfo.isVirtualCall(mi, call)) {
+            resolveSymbolName = BinaryContainer.getResolveVirtualEntrySymbolName();
         } else {
             throw new InternalError("Unknown call type in " + mi.asTag() + " @ " + call.pcOffset + " for call" + call.target);
         }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaMethodInfo.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaMethodInfo.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,9 +24,11 @@
 package jdk.tools.jaotc;
 
 import org.graalvm.compiler.code.CompilationResult;
-import jdk.vm.ci.hotspot.HotSpotCompiledCode;
 
-public interface JavaMethodInfo {
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+interface JavaMethodInfo {
 
     /**
      * @return unique symbol name for this method.
@@ -42,4 +44,16 @@
 
     HotSpotCompiledCode compiledCode(CompilationResult result);
 
+    /**
+     * Name a java method with class and signature to make it unique.
+     *
+     * @param method to generate unique identifier for
+     * @return Unique name for this method including class and signature
+     **/
+    static String uniqueMethodName(ResolvedJavaMethod method) {
+        String className = method.getDeclaringClass().toClassName();
+        String name = className + "." + method.getName() + method.getSignature().toMethodDescriptor();
+        return name;
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Linker.java	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.stream.Stream;
+
+final class Linker {
+
+    private final Options options;
+    private String objectFileName;
+    private String libraryFileName;
+    private String linkerCmd;
+
+    String objFile() {
+        return objectFileName;
+    }
+
+    String libFile() {
+        return libraryFileName;
+    }
+
+    Linker(Main main) throws Exception {
+        this.options = main.options;
+        String name = options.outputName;
+        objectFileName = name;
+        libraryFileName = name;
+
+        if (options.linkerpath != null && !(new File(options.linkerpath).exists())) {
+            throw new InternalError("Invalid linker path: " + options.linkerpath);
+        }
+        String linkerPath;
+        String linkerCheck;
+
+        switch (options.osName) {
+            case "Linux":
+                if (name.endsWith(".so")) {
+                    objectFileName = name.substring(0, name.length() - ".so".length());
+                }
+                linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
+                linkerCmd = linkerPath + " -shared -z noexecstack -o " + libraryFileName + " " + objectFileName;
+                linkerCheck = linkerPath + " -v";
+                break;
+            case "SunOS":
+                if (name.endsWith(".so")) {
+                    objectFileName = name.substring(0, name.length() - ".so".length());
+                }
+                objectFileName = objectFileName + ".o";
+                linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
+                linkerCmd = linkerPath + " -shared -o " + libraryFileName + " " + objectFileName;
+                linkerCheck = linkerPath + " -V";
+                break;
+            case "Mac OS X":
+                if (name.endsWith(".dylib")) {
+                    objectFileName = name.substring(0, name.length() - ".dylib".length());
+                }
+                objectFileName = objectFileName + ".o";
+                linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
+                linkerCmd = linkerPath + " -dylib -o " + libraryFileName + " " + objectFileName;
+                linkerCheck = linkerPath + " -v";
+                break;
+            default:
+                if (options.osName.startsWith("Windows")) {
+                    if (name.endsWith(".dll")) {
+                        objectFileName = name.substring(0, name.length() - ".dll".length());
+                    }
+                    objectFileName = objectFileName + ".obj";
+                    linkerPath = (options.linkerpath != null) ? options.linkerpath : getWindowsLinkPath();
+                    if (linkerPath == null) {
+                        throw new InternalError("Can't locate Microsoft Visual Studio amd64 link.exe");
+                    }
+                    linkerCmd = linkerPath + " /DLL /OPT:NOREF /NOLOGO /NOENTRY" + " /OUT:" + libraryFileName + " " + objectFileName;
+                    linkerCheck = null; // link.exe presence is verified already
+                    break;
+                } else {
+                    throw new InternalError("Unsupported platform: " + options.osName);
+                }
+        }
+
+        // Check linker presence on platforms by printing its version
+        if (linkerCheck != null) {
+            Process p = Runtime.getRuntime().exec(linkerCheck);
+            final int exitCode = p.waitFor();
+            if (exitCode != 0) {
+                InputStream stderr = p.getErrorStream();
+                BufferedReader br = new BufferedReader(new InputStreamReader(stderr));
+                Stream<String> lines = br.lines();
+                StringBuilder sb = new StringBuilder();
+                lines.iterator().forEachRemaining(e -> sb.append(e));
+                throw new InternalError(sb.toString());
+            }
+        }
+    }
+
+    void link() throws Exception {
+        Process p = Runtime.getRuntime().exec(linkerCmd);
+        final int exitCode = p.waitFor();
+        if (exitCode != 0) {
+            InputStream stderr = p.getErrorStream();
+            if (stderr.read() == -1) {
+                stderr = p.getInputStream();
+            }
+            BufferedReader br = new BufferedReader(new InputStreamReader(stderr));
+            Stream<String> lines = br.lines();
+            StringBuilder sb = new StringBuilder();
+            lines.iterator().forEachRemaining(e -> sb.append(e));
+            throw new InternalError(sb.toString());
+        }
+        File objFile = new File(objectFileName);
+        if (objFile.exists()) {
+            if (!objFile.delete()) {
+                throw new InternalError("Failed to delete " + objectFileName + " file");
+            }
+        }
+        // Make non-executable for all.
+        File libFile = new File(libraryFileName);
+        if (libFile.exists() && !options.osName.startsWith("Windows")) {
+            if (!libFile.setExecutable(false, false)) {
+                throw new InternalError("Failed to change attribute for " + libraryFileName + " file");
+            }
+        }
+
+    }
+
+    /**
+     * Visual Studio supported versions Search Order is: VS2013, VS2015, VS2012
+     */
+    public enum VSVERSIONS {
+        VS2013("VS120COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64\\link.exe"),
+        VS2015("VS140COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\bin\\amd64\\link.exe"),
+        VS2012("VS110COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC\\bin\\amd64\\link.exe");
+
+        private final String envvariable;
+        private final String wkp;
+
+        VSVERSIONS(String envvariable, String wellknownpath) {
+            this.envvariable = envvariable;
+            this.wkp = wellknownpath;
+        }
+
+        String EnvVariable() {
+            return envvariable;
+        }
+
+        String WellKnownPath() {
+            return wkp;
+        }
+    }
+
+    /**
+     * Search for Visual Studio link.exe Search Order is: VS2013, VS2015, VS2012
+     */
+    private static String getWindowsLinkPath() {
+        String link = "\\VC\\bin\\amd64\\link.exe";
+
+        /**
+         * First try searching the paths pointed to by the VS environment variables.
+         */
+        for (VSVERSIONS vs : VSVERSIONS.values()) {
+            String vspath = System.getenv(vs.EnvVariable());
+            if (vspath != null) {
+                File commonTools = new File(vspath);
+                File vsRoot = commonTools.getParentFile().getParentFile();
+                File linkPath = new File(vsRoot, link);
+                if (linkPath.exists()) {
+                    return linkPath.getPath();
+                }
+            }
+        }
+
+        /**
+         * If we didn't find via the VS environment variables, try the well known paths
+         */
+        for (VSVERSIONS vs : VSVERSIONS.values()) {
+            String wkp = vs.WellKnownPath();
+            if (new File(wkp).exists()) {
+                return wkp;
+            }
+        }
+
+        return null;
+    }
+
+}
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,4 +1,4 @@
-package jdk.tools.jaotc;/*
+/*
  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -21,6 +21,8 @@
  * questions.
  */
 
+package jdk.tools.jaotc;
+
 public class LoadedClass {
     private final String name;
     private final Class<?> clz;
@@ -45,12 +47,17 @@
 
     @Override
     public boolean equals(Object o) {
-        if (this == o) return true;
-        if (!(o instanceof LoadedClass)) return false;
-
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof LoadedClass)) {
+            return false;
+        }
         LoadedClass that = (LoadedClass) o;
 
-        if (name != null ? !name.equals(that.name) : that.name != null) return false;
+        if (name != null ? !name.equals(that.name) : that.name != null) {
+            return false;
+        }
         return clz != null ? clz.equals(that.clz) : that.clz == null;
 
     }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LogPrinter.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LogPrinter.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,12 +23,174 @@
 
 package jdk.tools.jaotc;
 
-public interface LogPrinter {
-    void printInfo(String s);
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryUsage;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.MessageFormat;
+import java.util.Date;
+
+import jdk.tools.jaotc.binformat.ByteContainer;
+import jdk.tools.jaotc.binformat.BinaryContainer;
+
+final class LogPrinter {
+
+    private static FileWriter logFile = null;
+    private final Options options;
+    private final PrintWriter log;
+
+    LogPrinter(Main main, PrintWriter log) {
+        this.options = main.options;
+        this.log = log;
+    }
+
+    void printInfo(String message) {
+        if (options.info) {
+            log.print(message);
+            log.flush();
+        }
+    }
+
+    void printlnInfo(String message) {
+        if (options.info) {
+            log.println(message);
+            log.flush();
+        }
+    }
 
-    void printlnVerbose(String s);
+    void printVerbose(String message) {
+        if (options.verbose) {
+            log.print(message);
+            log.flush();
+        }
+    }
+
+    void printlnVerbose(String message) {
+        if (options.verbose) {
+            log.println(message);
+            log.flush();
+        }
+    }
+
+    void printDebug(String message) {
+        if (options.debug) {
+            log.print(message);
+            log.flush();
+        }
+    }
+
+    void printlnDebug(String message) {
+        if (options.debug) {
+            log.println(message);
+            log.flush();
+        }
+    }
+
+    void printError(String message) {
+        log.println("Error: " + message);
+        log.flush();
+    }
+
+    void reportError(Throwable e) {
+        log.println("Error: " + e.getMessage());
+        if (options.info) {
+            e.printStackTrace(log);
+        }
+        log.flush();
+    }
+
+    void reportError(String key, Object... args) {
+        printError(MessageFormat.format(key, args));
+    }
+
+    private static String humanReadableByteCount(long bytes) {
+        int unit = 1024;
 
-    void printlnInfo(String s);
+        if (bytes < unit) {
+            return bytes + " B";
+        }
+
+        int exp = (int) (Math.log(bytes) / Math.log(unit));
+        char pre = "KMGTPE".charAt(exp - 1);
+        return String.format("%.1f %cB", bytes / Math.pow(unit, exp), pre);
+    }
+
+    void printMemoryUsage() {
+        if (options.verbose) {
+            MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
+            float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted();
+            log.format(" [used: %-7s, comm: %-7s, freeRatio ~= %.1f%%]",
+                            humanReadableByteCount(memusage.getUsed()),
+                            humanReadableByteCount(memusage.getCommitted()),
+                            freeratio * 100);
+        }
+    }
+
+    private void printContainerInfo(ByteContainer container) {
+        printlnVerbose(container.getContainerName() + ": " + container.getByteStreamSize() + " bytes");
+    }
+
+    void containersInfo(BinaryContainer binaryContainer) {
+        printContainerInfo(binaryContainer.getHeaderContainer().getContainer());
+        printContainerInfo(binaryContainer.getConfigContainer());
+        printContainerInfo(binaryContainer.getKlassesOffsetsContainer());
+        printContainerInfo(binaryContainer.getMethodsOffsetsContainer());
+        printContainerInfo(binaryContainer.getKlassesDependenciesContainer());
+        printContainerInfo(binaryContainer.getStubsOffsetsContainer());
+        printContainerInfo(binaryContainer.getMethodMetadataContainer());
+        printContainerInfo(binaryContainer.getCodeContainer());
+        printContainerInfo(binaryContainer.getCodeSegmentsContainer());
+        printContainerInfo(binaryContainer.getConstantDataContainer());
+        printContainerInfo(binaryContainer.getKlassesGotContainer());
+        printContainerInfo(binaryContainer.getCountersGotContainer());
+        printContainerInfo(binaryContainer.getMetadataGotContainer());
+        printContainerInfo(binaryContainer.getMethodStateContainer());
+        printContainerInfo(binaryContainer.getOopGotContainer());
+        printContainerInfo(binaryContainer.getMetaspaceNamesContainer());
+    }
 
-    void printError(String s);
+    static void openLog() {
+        int v = Integer.getInteger("jdk.tools.jaotc.logCompilation", 0);
+        if (v == 0) {
+            logFile = null;
+            return;
+        }
+        // Create log file in current directory
+        String fileName = "aot_compilation" + new Date().getTime() + ".log";
+        Path logFilePath = Paths.get("./", fileName);
+        String logFileName = logFilePath.toString();
+        try {
+            // Create file to which we do not append
+            logFile = new FileWriter(logFileName, false);
+        } catch (IOException e) {
+            System.out.println("Unable to open logfile :" + logFileName + "\nNo logs will be created");
+            logFile = null;
+        }
+    }
+
+    static void writeLog(String str) {
+        if (logFile != null) {
+            try {
+                logFile.write(str + "\n");
+                logFile.flush();
+            } catch (IOException e) {
+                // Print to console
+                System.out.println(str + "\n");
+            }
+        }
+    }
+
+    static void closeLog() {
+        if (logFile != null) {
+            try {
+                logFile.close();
+            } catch (IOException e) {
+                // Do nothing
+            }
+        }
+    }
+
 }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java	Thu Aug 24 21:06:33 2017 +0000
@@ -27,37 +27,14 @@
 import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
 import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
 
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.PrintWriter;
-import java.lang.management.ManagementFactory;
-import java.lang.management.MemoryUsage;
-import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Set;
-import java.util.stream.Stream;
 
 import jdk.tools.jaotc.binformat.BinaryContainer;
-import jdk.tools.jaotc.binformat.ByteContainer;
-import jdk.tools.jaotc.collect.*;
-import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider;
-import jdk.tools.jaotc.collect.directory.DirectorySourceProvider;
-import jdk.tools.jaotc.collect.jar.JarSourceProvider;
-import jdk.tools.jaotc.collect.module.ModuleSourceProvider;
-import jdk.tools.jaotc.utils.Timer;
+import jdk.tools.jaotc.Options.Option;
 
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
@@ -80,227 +57,14 @@
 
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.runtime.JVMCI;
 
-public class Main implements LogPrinter {
-    static class BadArgs extends Exception {
-        private static final long serialVersionUID = 1L;
-        final String key;
-        final Object[] args;
-        boolean showUsage;
-
-        BadArgs(String key, Object... args) {
-            super(MessageFormat.format(key, args));
-            this.key = key;
-            this.args = args;
-        }
-
-        BadArgs showUsage(boolean b) {
-            showUsage = b;
-            return this;
-        }
-    }
-
-    abstract static class Option {
-        final String help;
-        final boolean hasArg;
-        final String[] aliases;
-
-        Option(String help, boolean hasArg, String... aliases) {
-            this.help = help;
-            this.hasArg = hasArg;
-            this.aliases = aliases;
-        }
-
-        boolean isHidden() {
-            return false;
-        }
-
-        boolean matches(String opt) {
-            for (String a : aliases) {
-                if (a.equals(opt)) {
-                    return true;
-                } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        boolean ignoreRest() {
-            return false;
-        }
-
-        abstract void process(Main task, String opt, String arg) throws BadArgs;
-    }
+public final class Main {
 
-    static Option[] recognizedOptions = {new Option("  --output <file>            Output file name", true, "--output") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            String name = arg;
-            task.options.outputName = name;
-        }
-    }, new Option("  --class-name <class names> List of classes to compile", true, "--class-name", "--classname") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            task.options.files.addAll(ClassSearch.makeList(ClassNameSourceProvider.TYPE, arg));
-        }
-    }, new Option("  --jar <jarfiles>           List of jar files to compile", true, "--jar") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            task.options.files.addAll(ClassSearch.makeList(JarSourceProvider.TYPE, arg));
-        }
-    }, new Option("  --module <modules>         List of modules to compile", true, "--module") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            task.options.files.addAll(ClassSearch.makeList(ModuleSourceProvider.TYPE, arg));
-        }
-    }, new Option("  --directory <dirs>         List of directories where to search for files to compile", true, "--directory") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            task.options.files.addAll(ClassSearch.makeList(DirectorySourceProvider.TYPE, arg));
-        }
-    }, new Option("  --search-path <dirs>       List of directories where to search for specified files", true, "--search-path") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            String[] elements = arg.split(":");
-            task.options.searchPath.add(elements);
-        }
-    }, new Option("  --compile-commands <file>  Name of file with compile commands", true, "--compile-commands") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            task.options.methodList = arg;
-        }
-    }, new Option("  --compile-for-tiered       Generate profiling code for tiered compilation", false, "--compile-for-tiered") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            task.options.tiered = true;
-        }
-    }, new Option("  --compile-with-assertions  Compile with java assertions", false, "--compile-with-assertions") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            task.options.compileWithAssertions = true;
-        }
-    }, new Option("  --compile-threads <number> Number of compilation threads to be used", true, "--compile-threads", "--threads") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            int threads = Integer.parseInt(arg);
-            final int available = Runtime.getRuntime().availableProcessors();
-            if (threads <= 0) {
-                task.warning("invalid number of threads specified: {0}, using: {1}", threads, available);
-                threads = available;
-            }
-            if (threads > available) {
-                task.warning("too many threads specified: {0}, limiting to: {1}", threads, available);
-            }
-            task.options.threads = Integer.min(threads, available);
-        }
-    }, new Option("  --ignore-errors            Ignores all exceptions thrown during class loading", false, "--ignore-errors") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            task.options.ignoreClassLoadingErrors = true;
-        }
-    }, new Option("  --exit-on-error            Exit on compilation errors", false, "--exit-on-error") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            task.options.exitOnError = true;
-        }
-    }, new Option("  --info                     Print information during compilation", false, "--info") {
-        @Override
-        void process(Main task, String opt, String arg) throws BadArgs {
-            task.options.info = true;
-        }
-    }, new Option("  --verbose                  Print verbose information", false, "--verbose") {
-        @Override
-        void process(Main task, String opt, String arg) throws BadArgs {
-            task.options.info = true;
-            task.options.verbose = true;
-        }
-    }, new Option("  --debug                    Print debug information", false, "--debug") {
-        @Override
-        void process(Main task, String opt, String arg) throws BadArgs {
-            task.options.info = true;
-            task.options.verbose = true;
-            task.options.debug = true;
-        }
-    }, new Option("  --help                     Print this usage message", false, "--help") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            task.options.help = true;
-        }
-    }, new Option("  --version                  Version information", false, "--version") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            task.options.version = true;
-        }
-    }, new Option("  --linker-path              Full path to linker executable", true, "--linker-path") {
-        @Override
-        void process(Main task, String opt, String arg) {
-            task.options.linkerpath = arg;
-        }
-    }, new Option("  -J<flag>                   Pass <flag> directly to the runtime system", false, "-J") {
-        @Override
-        void process(Main task, String opt, String arg) {
-        }
-    }};
-
-    public static class Options {
-        public List<SearchFor> files = new LinkedList<>();
-        public String outputName = defaultOutputName();
-        public String methodList;
-        public List<ClassSource> sources = new ArrayList<>();
-        public String linkerpath = null;
-        public SearchPath searchPath = new SearchPath();
-
-        /**
-         * We don't see scaling beyond 16 threads.
-         */
-        private static final int COMPILER_THREADS = 16;
-
-        public int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors());
-
-        public boolean ignoreClassLoadingErrors;
-        public boolean exitOnError;
-        public boolean info;
-        public boolean verbose;
-        public boolean debug;
-        public boolean help;
-        public boolean version;
-        public boolean compileWithAssertions;
-        public boolean tiered;
-
-        private static String defaultOutputName() {
-            String osName = System.getProperty("os.name");
-            String name = "unnamed.";
-            String ext;
-
-            switch (osName) {
-                case "Linux":
-                case "SunOS":
-                    ext = "so";
-                    break;
-                case "Mac OS X":
-                    ext = "dylib";
-                    break;
-                default:
-                    if (osName.startsWith("Windows")) {
-                        ext = "dll";
-                    } else {
-                        ext = "so";
-                    }
-            }
-
-            return name + ext;
-        }
-    }
-
-    /* package */final Options options = new Options();
-
-    /**
-     * Logfile.
-     */
-    private static FileWriter logFile = null;
+    final Options options = new Options();
+    private PrintWriter log;
+    LogPrinter printer;
+    GraalFilters filters;
 
     private static final int EXIT_OK = 0;        // No errors.
     private static final int EXIT_CMDERR = 2;    // Bad command-line arguments and/or switches.
@@ -317,12 +81,11 @@
     }
 
     private int run(String[] args) {
-        if (log == null) {
-            log = new PrintWriter(System.out);
-        }
+        log = new PrintWriter(System.out);
+        printer = new LogPrinter(this, log);
 
         try {
-            handleOptions(args);
+            Options.handleOptions(this, args);
             if (options.help) {
                 showHelp();
                 return EXIT_OK;
@@ -332,17 +95,17 @@
                 return EXIT_OK;
             }
 
-            printlnInfo("Compiling " + options.outputName + "...");
+            printer.printlnInfo("Compiling " + options.outputName + "...");
             final long start = System.currentTimeMillis();
             if (!run()) {
                 return EXIT_ABNORMAL;
             }
             final long end = System.currentTimeMillis();
-            printlnInfo("Total time: " + (end - start) + " ms");
+            printer.printlnInfo("Total time: " + (end - start) + " ms");
 
             return EXIT_OK;
-        } catch (BadArgs e) {
-            reportError(e.key, e.args);
+        } catch (Options.BadArgs e) {
+            printer.reportError(e.key, e.args);
             if (e.showUsage) {
                 showUsage();
             }
@@ -355,117 +118,20 @@
         }
     }
 
-    private static String humanReadableByteCount(long bytes) {
-        int unit = 1024;
-
-        if (bytes < unit) {
-            return bytes + " B";
-        }
-
-        int exp = (int) (Math.log(bytes) / Math.log(unit));
-        char pre = "KMGTPE".charAt(exp - 1);
-        return String.format("%.1f %cB", bytes / Math.pow(unit, exp), pre);
-    }
-
-    void printMemoryUsage() {
-        if (options.verbose) {
-            MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
-            float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted();
-            log.format(" [used: %-7s, comm: %-7s, freeRatio ~= %.1f%%]",
-                            humanReadableByteCount(memusage.getUsed()),
-                            humanReadableByteCount(memusage.getCommitted()),
-                            freeratio * 100);
-        }
-    }
-
-    /**
-     * Visual Studio supported versions Search Order is: VS2013, VS2015, VS2012
-     */
-    public enum VSVERSIONS {
-        VS2013("VS120COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64\\link.exe"),
-        VS2015("VS140COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\bin\\amd64\\link.exe"),
-        VS2012("VS110COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC\\bin\\amd64\\link.exe");
-
-        private final String envvariable;
-        private final String wkp;
-
-        VSVERSIONS(String envvariable, String wellknownpath) {
-            this.envvariable = envvariable;
-            this.wkp = wellknownpath;
-        }
-
-        String EnvVariable() {
-            return envvariable;
-        }
-
-        String WellKnownPath() {
-            return wkp;
-        }
-    }
-
-    /**
-     * Search for Visual Studio link.exe Search Order is: VS2013, VS2015, VS2012
-     */
-    private static String getWindowsLinkPath() {
-        String link = "\\VC\\bin\\amd64\\link.exe";
-
-        /**
-         * First try searching the paths pointed to by the VS environment variables.
-         */
-        for (VSVERSIONS vs : VSVERSIONS.values()) {
-            String vspath = System.getenv(vs.EnvVariable());
-            if (vspath != null) {
-                File commonTools = new File(vspath);
-                File vsRoot = commonTools.getParentFile().getParentFile();
-                File linkPath = new File(vsRoot, link);
-                if (linkPath.exists())
-                    return linkPath.getPath();
-            }
-        }
-
-        /**
-         * If we didn't find via the VS environment variables, try the well known paths
-         */
-        for (VSVERSIONS vs : VSVERSIONS.values()) {
-            String wkp = vs.WellKnownPath();
-            if (new File(wkp).exists()) {
-                return wkp;
-            }
-        }
-
-        return null;
-    }
-
     @SuppressWarnings("try")
     private boolean run() throws Exception {
-        openLog();
+        LogPrinter.openLog();
 
         try {
-            CompilationSpec compilationRestrictions = collectSpecifiedMethods();
 
-            Set<Class<?>> classesToCompile = new HashSet<>();
+            final Linker linker = new Linker(this);
+            final String objectFileName = linker.objFile();
+            final Collector collector = new Collector(this);
+            Set<Class<?>> classesToCompile;
 
             try (Timer t = new Timer(this, "")) {
-                FileSupport fileSupport = new FileSupport();
-                ClassSearch lookup = new ClassSearch();
-                lookup.addProvider(new ModuleSourceProvider());
-                lookup.addProvider(new ClassNameSourceProvider(fileSupport));
-                lookup.addProvider(new JarSourceProvider());
-                lookup.addProvider(new DirectorySourceProvider(fileSupport));
-
-                List<LoadedClass> found = null;
-                try {
-                    found = lookup.search(options.files, options.searchPath);
-                } catch (InternalError e) {
-                    reportError(e);
-                    return false;
-                }
-
-                for (LoadedClass loadedClass : found) {
-                    classesToCompile.add(loadedClass.getLoadedClass());
-                }
-
-                printInfo(classesToCompile.size() + " classes found");
+                classesToCompile = collector.collectClassesToCompile();
+                printer.printInfo(classesToCompile.size() + " classes found");
             }
 
             OptionValues graalOptions = HotSpotGraalOptionValues.HOTSPOT_OPTIONS;
@@ -478,23 +144,22 @@
             HotSpotGraalRuntimeProvider runtime = (HotSpotGraalRuntimeProvider) graalCompiler.getGraalRuntime();
             HotSpotHostBackend backend = (HotSpotHostBackend) runtime.getCapability(RuntimeProvider.class).getHostBackend();
             MetaAccessProvider metaAccess = backend.getProviders().getMetaAccess();
-            GraalFilters filters = new GraalFilters(metaAccess);
+            filters = new GraalFilters(metaAccess);
 
             List<AOTCompiledClass> classes;
 
             try (Timer t = new Timer(this, "")) {
-                classes = collectMethodsToCompile(classesToCompile, compilationRestrictions, filters, metaAccess);
+                classes = collector.collectMethodsToCompile(classesToCompile, metaAccess);
             }
 
             // Free memory!
             try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
-                printMemoryUsage();
-                compilationRestrictions = null;
+                printer.printMemoryUsage();
                 classesToCompile = null;
                 System.gc();
             }
 
-            AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend, filters);
+            AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend);
             SnippetReflectionProvider snippetReflection = aotBackend.getProviders().getSnippetReflection();
             AOTCompiler compiler = new AOTCompiler(this, graalOptions, aotBackend, options.threads);
             classes = compiler.compileClasses(classes);
@@ -506,7 +171,7 @@
 
             // Free memory!
             try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
-                printMemoryUsage();
+                printer.printMemoryUsage();
                 aotBackend = null;
                 compiler = null;
                 System.gc();
@@ -520,25 +185,11 @@
             }
 
             // Print information about section sizes
-            printContainerInfo(binaryContainer.getHeaderContainer().getContainer());
-            printContainerInfo(binaryContainer.getConfigContainer());
-            printContainerInfo(binaryContainer.getKlassesOffsetsContainer());
-            printContainerInfo(binaryContainer.getMethodsOffsetsContainer());
-            printContainerInfo(binaryContainer.getKlassesDependenciesContainer());
-            printContainerInfo(binaryContainer.getStubsOffsetsContainer());
-            printContainerInfo(binaryContainer.getMethodMetadataContainer());
-            printContainerInfo(binaryContainer.getCodeContainer());
-            printContainerInfo(binaryContainer.getCodeSegmentsContainer());
-            printContainerInfo(binaryContainer.getConstantDataContainer());
-            printContainerInfo(binaryContainer.getMetaspaceGotContainer());
-            printContainerInfo(binaryContainer.getMetadataGotContainer());
-            printContainerInfo(binaryContainer.getMethodStateContainer());
-            printContainerInfo(binaryContainer.getOopGotContainer());
-            printContainerInfo(binaryContainer.getMetaspaceNamesContainer());
+            printer.containersInfo(binaryContainer);
 
             // Free memory!
             try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
-                printMemoryUsage();
+                printer.printMemoryUsage();
                 backend = null;
                 for (AOTCompiledClass aotCompClass : classes) {
                     aotCompClass.clear();
@@ -550,238 +201,59 @@
                 System.gc();
             }
 
-            String name = options.outputName;
-            String objectFileName = name;
-
-            String libraryFileName = name;
-
-            String linkerCmd;
-            String linkerPath;
-            String osName = System.getProperty("os.name");
-
-            switch (osName) {
-                case "Linux":
-                    if (name.endsWith(".so")) {
-                        objectFileName = name.substring(0, name.length() - ".so".length());
-                    }
-                    linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
-                    linkerCmd = linkerPath + " -shared -z noexecstack -o " + libraryFileName + " " + objectFileName;
-                    break;
-                case "SunOS":
-                    if (name.endsWith(".so")) {
-                        objectFileName = name.substring(0, name.length() - ".so".length());
-                    }
-                    objectFileName = objectFileName + ".o";
-                    linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
-                    linkerCmd = linkerPath + " -shared -o " + libraryFileName + " " + objectFileName;
-                    break;
-                case "Mac OS X":
-                    if (name.endsWith(".dylib")) {
-                        objectFileName = name.substring(0, name.length() - ".dylib".length());
-                    }
-                    objectFileName = objectFileName + ".o";
-                    linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
-                    linkerCmd = linkerPath + " -dylib -o " + libraryFileName + " " + objectFileName;
-                    break;
-                default:
-                    if (osName.startsWith("Windows")) {
-                        if (name.endsWith(".dll")) {
-                            objectFileName = name.substring(0, name.length() - ".dll".length());
-                        }
-                        objectFileName = objectFileName + ".obj";
-                        linkerPath = (options.linkerpath != null) ? options.linkerpath : getWindowsLinkPath();
-                        if (linkerPath == null) {
-                            throw new InternalError("Can't locate Microsoft Visual Studio amd64 link.exe");
-                        }
-                        linkerCmd = linkerPath + " /DLL /OPT:NOREF /NOLOGO /NOENTRY" + " /OUT:" + libraryFileName + " " + objectFileName;
-                        break;
-                    } else {
-                        throw new InternalError("Unsupported platform: " + osName);
-                    }
-            }
-
             try (Timer t = new Timer(this, "Creating binary: " + objectFileName)) {
-                binaryContainer.createBinary(objectFileName, JVM_VERSION);
+                binaryContainer.createBinary(objectFileName);
             }
 
             // Free memory!
             try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
-                printMemoryUsage();
+                printer.printMemoryUsage();
                 binaryContainer = null;
                 System.gc();
             }
 
-            try (Timer t = new Timer(this, "Creating shared library: " + libraryFileName)) {
-                Process p = Runtime.getRuntime().exec(linkerCmd);
-                final int exitCode = p.waitFor();
-                if (exitCode != 0) {
-                    InputStream stderr = p.getErrorStream();
-                    BufferedReader br = new BufferedReader(new InputStreamReader(stderr));
-                    Stream<String> lines = br.lines();
-                    StringBuilder sb = new StringBuilder();
-                    lines.iterator().forEachRemaining(e -> sb.append(e));
-                    throw new InternalError(sb.toString());
-                }
-                File objFile = new File(objectFileName);
-                if (objFile.exists()) {
-                    if (!objFile.delete()) {
-                        throw new InternalError("Failed to delete " + objectFileName + " file");
-                    }
-                }
-                // Make non-executable for all.
-                File libFile = new File(libraryFileName);
-                if (libFile.exists() && !osName.startsWith("Windows")) {
-                    if (!libFile.setExecutable(false, false)) {
-                        throw new InternalError("Failed to change attribute for " + libraryFileName + " file");
-                    }
-                }
+            try (Timer t = new Timer(this, "Creating shared library: " + linker.libFile())) {
+                linker.link();
             }
 
-            printVerbose("Final memory  ");
-            printMemoryUsage();
-            printlnVerbose("");
+            printer.printVerbose("Final memory  ");
+            printer.printMemoryUsage();
+            printer.printlnVerbose("");
 
         } finally {
-            closeLog();
+            LogPrinter.closeLog();
         }
         return true;
     }
 
-    private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions, GraalFilters filters) {
-        for (ResolvedJavaMethod m : methods) {
-            addMethod(aotClass, m, compilationRestrictions, filters);
-        }
-    }
+    void handleError(ResolvedJavaMethod resolvedMethod, Throwable e, String message) {
+        String methodName = JavaMethodInfo.uniqueMethodName(resolvedMethod);
 
-    private void addMethod(AOTCompiledClass aotClass, ResolvedJavaMethod method, CompilationSpec compilationRestrictions, GraalFilters filters) {
-        // Don't compile native or abstract methods.
-        if (!method.hasBytecodes()) {
-            return;
+        if (options.debug) {
+            printer.printError("Failed compilation: " + methodName + ": " + e);
         }
-        if (!compilationRestrictions.shouldCompileMethod(method)) {
-            return;
-        }
-        if (!filters.shouldCompileMethod(method)) {
+
+        // Ignore some exceptions when meta-compiling Graal.
+        if (GraalFilters.shouldIgnoreException(e)) {
             return;
         }
 
-        aotClass.addMethod(method);
-        printlnVerbose("  added " + method.getName() + method.getSignature().toMethodDescriptor());
-    }
+        LogPrinter.writeLog("Failed compilation of method " + methodName + message);
 
-    private void printContainerInfo(ByteContainer container) {
-        printlnVerbose(container.getContainerName() + ": " + container.getByteStreamSize() + " bytes");
-    }
-
-    PrintWriter log;
-
-    private void handleOptions(String[] args) throws BadArgs {
-        if (args.length == 0) {
-            options.help = true;
-            return;
+        if (!options.debug) {
+            printer.printError("Failed compilation: " + methodName + ": " + e);
         }
 
-        // Make checkstyle happy.
-        int i = 0;
-        for (; i < args.length; i++) {
-            String arg = args[i];
-
-            if (arg.charAt(0) == '-') {
-                Option option = getOption(arg);
-                String param = null;
+        if (options.verbose) {
+            e.printStackTrace(log);
+        }
 
-                if (option.hasArg) {
-                    if (arg.startsWith("--") && arg.indexOf('=') > 0) {
-                        param = arg.substring(arg.indexOf('=') + 1, arg.length());
-                    } else if (i + 1 < args.length) {
-                        param = args[++i];
-                    }
-
-                    if (param == null || param.isEmpty() || param.charAt(0) == '-') {
-                        throw new BadArgs("missing argument for option: {0}", arg).showUsage(true);
-                    }
-                }
-
-                option.process(this, arg, param);
-
-                if (option.ignoreRest()) {
-                    break;
-                }
-            } else {
-                options.files.add(new SearchFor(arg));
-            }
+        if (options.exitOnError) {
+            System.exit(1);
         }
     }
 
-    private static Option getOption(String name) throws BadArgs {
-        for (Option o : recognizedOptions) {
-            if (o.matches(name)) {
-                return o;
-            }
-        }
-        throw new BadArgs("unknown option: {0}", name).showUsage(true);
-    }
-
-    public void printInfo(String message) {
-        if (options.info) {
-            log.print(message);
-            log.flush();
-        }
-    }
-
-    public void printlnInfo(String message) {
-        if (options.info) {
-            log.println(message);
-            log.flush();
-        }
-    }
-
-    public void printVerbose(String message) {
-        if (options.verbose) {
-            log.print(message);
-            log.flush();
-        }
-    }
-
-    public void printlnVerbose(String message) {
-        if (options.verbose) {
-            log.println(message);
-            log.flush();
-        }
-    }
-
-    public void printDebug(String message) {
-        if (options.debug) {
-            log.print(message);
-            log.flush();
-        }
-    }
-
-    public void printlnDebug(String message) {
-        if (options.debug) {
-            log.println(message);
-            log.flush();
-        }
-    }
-
-    public void printError(String message) {
-        log.println("Error: " + message);
-        log.flush();
-    }
-
-    private void reportError(Throwable e) {
-        log.println("Error: " + e.getMessage());
-        if (options.info) {
-            e.printStackTrace(log);
-        }
-        log.flush();
-    }
-
-    private void reportError(String key, Object... args) {
-        printError(MessageFormat.format(key, args));
-    }
-
-    private void warning(String key, Object... args) {
+    void warning(String key, Object... args) {
         log.println("Warning: " + MessageFormat.format(key, args));
         log.flush();
     }
@@ -789,6 +261,7 @@
     private void showUsage() {
         log.println("Usage: " + PROGNAME + " <options> list");
         log.println("use --help for a list of possible options");
+        log.flush();
     }
 
     private void showHelp() {
@@ -798,7 +271,7 @@
         log.println("             or directories which contain class files.");
         log.println();
         log.println("where options include:");
-        for (Option o : recognizedOptions) {
+        for (Option o : Options.recognizedOptions) {
             String name = o.aliases[0].substring(1); // there must always be at least one name
             name = name.charAt(0) == '-' ? name.substring(1) : name;
             if (o.isHidden() || name.equals("h")) {
@@ -806,169 +279,10 @@
             }
             log.println(o.help);
         }
+        log.flush();
     }
 
     private void showVersion() {
         log.println(PROGNAME + " " + JVM_VERSION);
     }
-
-    /**
-     * Collect all method we should compile.
-     *
-     * @return array list of AOT classes which have compiled methods.
-     */
-    private List<AOTCompiledClass> collectMethodsToCompile(Set<Class<?>> classesToCompile, CompilationSpec compilationRestrictions, GraalFilters filters, MetaAccessProvider metaAccess) {
-        int total = 0;
-        int count = 0;
-        List<AOTCompiledClass> classes = new ArrayList<>();
-
-        for (Class<?> c : classesToCompile) {
-            ResolvedJavaType resolvedJavaType = metaAccess.lookupJavaType(c);
-            if (filters.shouldCompileAnyMethodInClass(resolvedJavaType)) {
-                AOTCompiledClass aotClass = new AOTCompiledClass(resolvedJavaType);
-                printlnVerbose(" Scanning " + c.getName());
-
-                // Constructors
-                try {
-                    ResolvedJavaMethod[] ctors = resolvedJavaType.getDeclaredConstructors();
-                    addMethods(aotClass, ctors, compilationRestrictions, filters);
-                    total += ctors.length;
-                } catch (Throwable e) {
-                    // If we are running in JCK mode we ignore all exceptions.
-                    if (options.ignoreClassLoadingErrors) {
-                        printError(c.getName() + ": " + e);
-                    } else {
-                        throw new InternalError(e);
-                    }
-                }
-
-                // Methods
-                try {
-                    ResolvedJavaMethod[] methods = resolvedJavaType.getDeclaredMethods();
-                    addMethods(aotClass, methods, compilationRestrictions, filters);
-                    total += methods.length;
-                } catch (Throwable e) {
-                    // If we are running in JCK mode we ignore all exceptions.
-                    if (options.ignoreClassLoadingErrors) {
-                        printError(c.getName() + ": " + e);
-                    } else {
-                        throw new InternalError(e);
-                    }
-                }
-
-                // Class initializer
-                try {
-                    ResolvedJavaMethod clinit = resolvedJavaType.getClassInitializer();
-                    if (clinit != null) {
-                        addMethod(aotClass, clinit, compilationRestrictions, filters);
-                        total++;
-                    }
-                } catch (Throwable e) {
-                    // If we are running in JCK mode we ignore all exceptions.
-                    if (options.ignoreClassLoadingErrors) {
-                        printError(c.getName() + ": " + e);
-                    } else {
-                        throw new InternalError(e);
-                    }
-                }
-
-                // Found any methods to compile? Add the class.
-                if (aotClass.hasMethods()) {
-                    classes.add(aotClass);
-                    count += aotClass.getMethodCount();
-                }
-            }
-        }
-        printInfo(total + " methods total, " + count + " methods to compile");
-        return classes;
-    }
-
-    /**
-     * If a file with compilation limitations is specified using the java property
-     * jdk.tools.jaotc.compile.method.list, read the file's contents and collect the restrictions.
-     */
-    private CompilationSpec collectSpecifiedMethods() {
-        CompilationSpec compilationRestrictions = new CompilationSpec();
-        String methodListFileName = options.methodList;
-
-        if (methodListFileName != null && !methodListFileName.equals("")) {
-            try {
-                FileReader methListFile = new FileReader(methodListFileName);
-                BufferedReader readBuf = new BufferedReader(methListFile);
-                String line = null;
-                while ((line = readBuf.readLine()) != null) {
-                    String trimmedLine = line.trim();
-                    if (!trimmedLine.startsWith("#")) {
-                        String[] components = trimmedLine.split(" ");
-                        if (components.length == 2) {
-                            String directive = components[0];
-                            String pattern = components[1];
-                            switch (directive) {
-                                case "compileOnly":
-                                    compilationRestrictions.addCompileOnlyPattern(pattern);
-                                    break;
-                                case "exclude":
-                                    compilationRestrictions.addExcludePattern(pattern);
-                                    break;
-                                default:
-                                    System.out.println("Unrecognized command " + directive + ". Ignoring\n\t" + line + "\n encountered in " + methodListFileName);
-                            }
-                        } else {
-                            if (!trimmedLine.equals("")) {
-                                System.out.println("Ignoring malformed line:\n\t " + line + "\n");
-                            }
-                        }
-                    }
-                }
-                readBuf.close();
-            } catch (FileNotFoundException e) {
-                throw new InternalError("Unable to open method list file: " + methodListFileName, e);
-            } catch (IOException e) {
-                throw new InternalError("Unable to read method list file: " + methodListFileName, e);
-            }
-        }
-
-        return compilationRestrictions;
-    }
-
-    private static void openLog() {
-        int v = Integer.getInteger("jdk.tools.jaotc.logCompilation", 0);
-        if (v == 0) {
-            logFile = null;
-            return;
-        }
-        // Create log file in current directory
-        String fileName = "aot_compilation" + new Date().getTime() + ".log";
-        Path logFilePath = Paths.get("./", fileName);
-        String logFileName = logFilePath.toString();
-        try {
-            // Create file to which we do not append
-            logFile = new FileWriter(logFileName, false);
-        } catch (IOException e) {
-            System.out.println("Unable to open logfile :" + logFileName + "\nNo logs will be created");
-            logFile = null;
-        }
-    }
-
-    public static void writeLog(String str) {
-        if (logFile != null) {
-            try {
-                logFile.write(str + "\n");
-                logFile.flush();
-            } catch (IOException e) {
-                // Print to console
-                System.out.println(str + "\n");
-            }
-        }
-    }
-
-    public static void closeLog() {
-        if (logFile != null) {
-            try {
-                logFile.close();
-            } catch (IOException e) {
-                // Do nothing
-            }
-        }
-    }
 }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -59,7 +59,7 @@
         this.value = (int) (long) HotSpotJVMCIRuntime.runtime().getConfigStore().getConstants().get(name);
     }
 
-    public static MarkId getEnum(int value) {
+    static MarkId getEnum(int value) {
         for (MarkId e : values()) {
             if (e.value == value) {
                 return e;
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,7 @@
 
 import jdk.vm.ci.code.site.Mark;
 
-class MarkProcessor {
+final class MarkProcessor {
 
     private final BinaryContainer binaryContainer;
 
@@ -65,31 +65,31 @@
                 switch (markId) {
                     case POLL_FAR:
                     case POLL_RETURN_FAR:
-                        vmSymbolName = binaryContainer.getPollingPageSymbolName();
+                        vmSymbolName = BinaryContainer.getPollingPageSymbolName();
                         break;
                     case CARD_TABLE_ADDRESS:
-                        vmSymbolName = binaryContainer.getCardTableAddressSymbolName();
+                        vmSymbolName = BinaryContainer.getCardTableAddressSymbolName();
                         break;
                     case HEAP_TOP_ADDRESS:
-                        vmSymbolName = binaryContainer.getHeapTopAddressSymbolName();
+                        vmSymbolName = BinaryContainer.getHeapTopAddressSymbolName();
                         break;
                     case HEAP_END_ADDRESS:
-                        vmSymbolName = binaryContainer.getHeapEndAddressSymbolName();
+                        vmSymbolName = BinaryContainer.getHeapEndAddressSymbolName();
                         break;
                     case NARROW_KLASS_BASE_ADDRESS:
-                        vmSymbolName = binaryContainer.getNarrowKlassBaseAddressSymbolName();
+                        vmSymbolName = BinaryContainer.getNarrowKlassBaseAddressSymbolName();
                         break;
                     case NARROW_OOP_BASE_ADDRESS:
-                        vmSymbolName = binaryContainer.getNarrowOopBaseAddressSymbolName();
+                        vmSymbolName = BinaryContainer.getNarrowOopBaseAddressSymbolName();
                         break;
                     case CRC_TABLE_ADDRESS:
-                        vmSymbolName = binaryContainer.getCrcTableAddressSymbolName();
+                        vmSymbolName = BinaryContainer.getCrcTableAddressSymbolName();
                         break;
                     case LOG_OF_HEAP_REGION_GRAIN_BYTES:
-                        vmSymbolName = binaryContainer.getLogOfHeapRegionGrainBytesSymbolName();
+                        vmSymbolName = BinaryContainer.getLogOfHeapRegionGrainBytesSymbolName();
                         break;
                     case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED:
-                        vmSymbolName = binaryContainer.getInlineContiguousAllocationSupportedSymbolName();
+                        vmSymbolName = BinaryContainer.getInlineContiguousAllocationSupportedSymbolName();
                         break;
                     default:
                         throw new InternalError("Unhandled mark: " + mark);
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,10 +28,7 @@
 
 import jdk.tools.jaotc.binformat.BinaryContainer;
 import jdk.tools.jaotc.binformat.ByteContainer;
-import jdk.tools.jaotc.binformat.Symbol.Binding;
-import jdk.tools.jaotc.binformat.Symbol.Kind;
 import jdk.tools.jaotc.binformat.GotSymbol;
-import jdk.tools.jaotc.AOTCompiledClass.AOTKlassData;
 import jdk.tools.jaotc.utils.NativeOrderOutputStream;
 import org.graalvm.compiler.code.CompilationResult;
 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
@@ -43,7 +40,7 @@
 import jdk.vm.ci.hotspot.HotSpotCompiledCode;
 import jdk.vm.ci.hotspot.HotSpotMetaData;
 
-class MetadataBuilder {
+final class MetadataBuilder {
 
     private final DataBuilder dataBuilder;
 
@@ -58,8 +55,6 @@
      * Process compiled methods and create method metadata.
      */
     void processMetadata(List<AOTCompiledClass> classes, AOTCompiledClass stubCompiledCode) {
-        binaryContainer.getMethodMetadataContainer().createSymbol(0, Kind.OBJECT, Binding.LOCAL, 0, "metaStart");
-
         for (AOTCompiledClass c : classes) {
             processMetadataClass(c);
         }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MiscUtils.java	Thu Aug 24 14:03:21 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * 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 jdk.tools.jaotc;
-
-import org.graalvm.compiler.bytecode.Bytecodes;
-
-import jdk.vm.ci.code.BytecodePosition;
-import jdk.vm.ci.code.site.Call;
-import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-
-public class MiscUtils {
-
-    /**
-     * Name a java method with class and signature to make it unique.
-     *
-     * @param method to generate unique identifier for
-     * @return Unique name for this method including class and signature
-     **/
-    public static String uniqueMethodName(ResolvedJavaMethod method) {
-        String className = method.getDeclaringClass().toClassName();
-        String name = className + "." + method.getName() + method.getSignature().toMethodDescriptor();
-        return name;
-    }
-
-    public static boolean isStaticCall(Call call) {
-        if (isJavaCall(call)) {
-            return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKESTATIC);
-        }
-        return false;
-    }
-
-    public static boolean isSpecialCall(Call call) {
-        if (isJavaCall(call)) {
-            return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKESPECIAL);
-        }
-        return false;
-    }
-
-    private static boolean isInvokeVirtual(Call call) {
-        if (isJavaCall(call)) {
-            return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKEVIRTUAL) || ((getByteCode(call) & 0xFF) == Bytecodes.INVOKEINTERFACE);
-        }
-        return false;
-    }
-
-    public static boolean isVirtualCall(CompiledMethodInfo methodInfo, Call call) {
-        return isInvokeVirtual(call) && !methodInfo.hasMark(call, MarkId.INVOKESPECIAL);
-    }
-
-    public static boolean isOptVirtualCall(CompiledMethodInfo methodInfo, Call call) {
-        return isInvokeVirtual(call) && methodInfo.hasMark(call, MarkId.INVOKESPECIAL);
-    }
-
-    private static boolean isJavaCall(Call call) {
-        // If there is no associated debug info return false
-        if (call.debugInfo == null) {
-            return false;
-        }
-        BytecodePosition bcpos = call.debugInfo.getBytecodePosition();
-        ResolvedJavaMethod method = bcpos.getMethod();
-        // If bytecode position indicates a special value (negative value) it is
-        // not a normal java call
-        if (bcpos.getBCI() < 0) {
-            return false;
-        }
-        // If there is no method associated with the debuginfo, return false
-        if (method == null) {
-            return false;
-        }
-        assert (method instanceof HotSpotResolvedJavaMethod) : "Not a resolved Java call";
-        return true;
-    }
-
-    private static byte getByteCode(Call call) {
-        ResolvedJavaMethod m = call.debugInfo.getBytecodePosition().getMethod();
-        int callPosition = call.debugInfo.getBytecodePosition().getBCI();
-        byte[] code = m.getCode();
-        return code[callPosition];
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Options.java	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import jdk.tools.jaotc.collect.ClassSearch;
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.SearchFor;
+import jdk.tools.jaotc.collect.SearchPath;
+import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider;
+import jdk.tools.jaotc.collect.directory.DirectorySourceProvider;
+import jdk.tools.jaotc.collect.jar.JarSourceProvider;
+import jdk.tools.jaotc.collect.module.ModuleSourceProvider;
+
+final class Options {
+    List<SearchFor> files = new LinkedList<>();
+    String osName;
+    String outputName = defaultOutputName();
+    String methodList;
+    List<ClassSource> sources = new ArrayList<>();
+    String linkerpath = null;
+    SearchPath searchPath = new SearchPath();
+
+    /**
+     * We don't see scaling beyond 16 threads.
+     */
+    private static final int COMPILER_THREADS = 16;
+
+    int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors());
+
+    boolean ignoreClassLoadingErrors;
+    boolean exitOnError;
+    boolean info;
+    boolean verbose;
+    boolean debug;
+    boolean help;
+    boolean version;
+    boolean compileWithAssertions;
+    boolean tiered;
+
+    private String defaultOutputName() {
+        osName = System.getProperty("os.name");
+        String name = "unnamed.";
+        String ext;
+
+        switch (osName) {
+            case "Linux":
+            case "SunOS":
+                ext = "so";
+                break;
+            case "Mac OS X":
+                ext = "dylib";
+                break;
+            default:
+                if (osName.startsWith("Windows")) {
+                    ext = "dll";
+                } else {
+                    ext = "so";
+                }
+        }
+
+        return name + ext;
+    }
+
+    static class BadArgs extends Exception {
+        private static final long serialVersionUID = 1L;
+        final String key;
+        final Object[] args;
+        boolean showUsage;
+
+        BadArgs(String key, Object... args) {
+            super(MessageFormat.format(key, args));
+            this.key = key;
+            this.args = args;
+        }
+
+        BadArgs showUsage(boolean b) {
+            showUsage = b;
+            return this;
+        }
+    }
+
+    abstract static class Option {
+        final String help;
+        final boolean hasArg;
+        final String[] aliases;
+
+        Option(String help, boolean hasArg, String... aliases) {
+            this.help = help;
+            this.hasArg = hasArg;
+            this.aliases = aliases;
+        }
+
+        boolean isHidden() {
+            return false;
+        }
+
+        boolean matches(String opt) {
+            for (String a : aliases) {
+                if (a.equals(opt)) {
+                    return true;
+                } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        boolean ignoreRest() {
+            return false;
+        }
+
+        abstract void process(Main task, String opt, String arg) throws BadArgs;
+    }
+
+    static Option[] recognizedOptions = {new Option("  --output <file>            Output file name", true, "--output") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            String name = arg;
+            task.options.outputName = name;
+        }
+    }, new Option("  --class-name <class names> List of classes to compile", true, "--class-name", "--classname") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.files.addAll(ClassSearch.makeList(ClassNameSourceProvider.TYPE, arg));
+        }
+    }, new Option("  --jar <jarfiles>           List of jar files to compile", true, "--jar") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.files.addAll(ClassSearch.makeList(JarSourceProvider.TYPE, arg));
+        }
+    }, new Option("  --module <modules>         List of modules to compile", true, "--module") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.files.addAll(ClassSearch.makeList(ModuleSourceProvider.TYPE, arg));
+        }
+    }, new Option("  --directory <dirs>         List of directories where to search for files to compile", true, "--directory") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.files.addAll(ClassSearch.makeList(DirectorySourceProvider.TYPE, arg));
+        }
+    }, new Option("  --search-path <dirs>       List of directories where to search for specified files", true, "--search-path") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            String[] elements = arg.split(":");
+            task.options.searchPath.add(elements);
+        }
+    }, new Option("  --compile-commands <file>  Name of file with compile commands", true, "--compile-commands") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.methodList = arg;
+        }
+    }, new Option("  --compile-for-tiered       Generate profiling code for tiered compilation", false, "--compile-for-tiered") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.tiered = true;
+        }
+    }, new Option("  --compile-with-assertions  Compile with java assertions", false, "--compile-with-assertions") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.compileWithAssertions = true;
+        }
+    }, new Option("  --compile-threads <number> Number of compilation threads to be used", true, "--compile-threads", "--threads") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            int threads = Integer.parseInt(arg);
+            final int available = Runtime.getRuntime().availableProcessors();
+            if (threads <= 0) {
+                task.warning("invalid number of threads specified: {0}, using: {1}", threads, available);
+                threads = available;
+            }
+            if (threads > available) {
+                task.warning("too many threads specified: {0}, limiting to: {1}", threads, available);
+            }
+            task.options.threads = Integer.min(threads, available);
+        }
+    }, new Option("  --ignore-errors            Ignores all exceptions thrown during class loading", false, "--ignore-errors") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.ignoreClassLoadingErrors = true;
+        }
+    }, new Option("  --exit-on-error            Exit on compilation errors", false, "--exit-on-error") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.exitOnError = true;
+        }
+    }, new Option("  --info                     Print information during compilation", false, "--info") {
+        @Override
+        void process(Main task, String opt, String arg) throws BadArgs {
+            task.options.info = true;
+        }
+    }, new Option("  --verbose                  Print verbose information", false, "--verbose") {
+        @Override
+        void process(Main task, String opt, String arg) throws BadArgs {
+            task.options.info = true;
+            task.options.verbose = true;
+        }
+    }, new Option("  --debug                    Print debug information", false, "--debug") {
+        @Override
+        void process(Main task, String opt, String arg) throws BadArgs {
+            task.options.info = true;
+            task.options.verbose = true;
+            task.options.debug = true;
+        }
+    }, new Option("  --help                     Print this usage message", false, "--help") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.help = true;
+        }
+    }, new Option("  --version                  Version information", false, "--version") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.version = true;
+        }
+    }, new Option("  --linker-path              Full path to linker executable", true, "--linker-path") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.linkerpath = arg;
+        }
+    }, new Option("  -J<flag>                   Pass <flag> directly to the runtime system", false, "-J") {
+        @Override
+        void process(Main task, String opt, String arg) {
+        }
+    }};
+
+    static void handleOptions(Main task, String[] args) throws BadArgs {
+        if (args.length == 0) {
+            task.options.help = true;
+            return;
+        }
+
+        // Make checkstyle happy.
+        for (int i = 0; i < args.length; i++) {
+            String arg = args[i];
+
+            if (arg.charAt(0) == '-') {
+                Option option = getOption(arg);
+                String param = null;
+
+                if (option.hasArg) {
+                    if (arg.startsWith("--") && arg.indexOf('=') > 0) {
+                        param = arg.substring(arg.indexOf('=') + 1, arg.length());
+                    } else if (i + 1 < args.length) {
+                        param = args[++i];
+                    }
+
+                    if (param == null || param.isEmpty() || param.charAt(0) == '-') {
+                        throw new BadArgs("missing argument for option: {0}", arg).showUsage(true);
+                    }
+                }
+
+                option.process(task, arg, param);
+
+                if (option.ignoreRest()) {
+                    break;
+                }
+            } else {
+                task.options.files.add(new SearchFor(arg));
+            }
+        }
+    }
+
+    static Option getOption(String name) throws BadArgs {
+        for (Option o : recognizedOptions) {
+            if (o.matches(name)) {
+                return o;
+            }
+        }
+        throw new BadArgs("unknown option: {0}", name).showUsage(true);
+    }
+
+}
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubDirectCallSiteRelocationSymbol.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubDirectCallSiteRelocationSymbol.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,7 @@
  */
 final class StubDirectCallSiteRelocationSymbol extends CallSiteRelocationSymbol {
 
-    public StubDirectCallSiteRelocationSymbol(CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) {
+    StubDirectCallSiteRelocationSymbol(CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) {
         super(binaryContainer.getSymbol(callSiteRelocation.targetSymbol));
         assert symbol != null && symbol.getBinding() == Binding.LOCAL : "Stub symbol must exist and must be LOCAL";
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubInformation.java	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+public final class StubInformation {
+    private int stubOffset;         // the offset inside the code (text + stubOffset)
+    private int stubSize;           // the stub size
+    private int dispatchJumpOffset; // offset after main dispatch jump instruction
+    private int resolveJumpOffset;  // offset after jump instruction to runtime call resolution function.
+    private int resolveJumpStart;   // offset of jump instruction to VM runtime call resolution function.
+    private int c2iJumpOffset;      // offset after jump instruction to c2i adapter for static calls.
+    private int movOffset;          // offset after move instruction which loads from got cell:
+                                    // - Method* for static call
+                                    // - Klass* for virtual call
+
+    private boolean isVirtual;  // virtual call stub
+
+    // maybe add type of stub as well, right now we only have static stubs
+
+    StubInformation(int stubOffset, boolean isVirtual) {
+        this.stubOffset = stubOffset;
+        this.isVirtual = isVirtual;
+        this.stubSize = -1;
+        this.movOffset = -1;
+        this.c2iJumpOffset = -1;
+        this.resolveJumpOffset = -1;
+        this.resolveJumpStart = -1;
+        this.dispatchJumpOffset = -1;
+    }
+
+    int getOffset() {
+        return stubOffset;
+    }
+
+    boolean isVirtual() {
+        return isVirtual;
+    }
+
+    public void setSize(int stubSize) {
+        this.stubSize = stubSize;
+    }
+
+    int getSize() {
+        return stubSize;
+    }
+
+    public void setMovOffset(int movOffset) {
+        this.movOffset = movOffset + stubOffset;
+    }
+
+    int getMovOffset() {
+        return movOffset;
+    }
+
+    public void setC2IJumpOffset(int c2iJumpOffset) {
+        this.c2iJumpOffset = c2iJumpOffset + stubOffset;
+    }
+
+    int getC2IJumpOffset() {
+        return c2iJumpOffset;
+    }
+
+    public void setResolveJumpOffset(int resolveJumpOffset) {
+        this.resolveJumpOffset = resolveJumpOffset + stubOffset;
+    }
+
+    int getResolveJumpOffset() {
+        return resolveJumpOffset;
+    }
+
+    public void setResolveJumpStart(int resolveJumpStart) {
+        this.resolveJumpStart = resolveJumpStart + stubOffset;
+    }
+
+    int getResolveJumpStart() {
+        return resolveJumpStart;
+    }
+
+    public void setDispatchJumpOffset(int dispatchJumpOffset) {
+        this.dispatchJumpOffset = dispatchJumpOffset + stubOffset;
+    }
+
+    int getDispatchJumpOffset() {
+        return dispatchJumpOffset;
+    }
+
+    void verify() {
+        assert stubOffset > 0 : "incorrect stubOffset: " + stubOffset;
+        assert stubSize > 0 : "incorrect stubSize: " + stubSize;
+        assert movOffset > 0 : "incorrect movOffset: " + movOffset;
+        assert dispatchJumpOffset > 0 : "incorrect dispatchJumpOffset: " + dispatchJumpOffset;
+        assert resolveJumpStart > 0 : "incorrect resolveJumpStart: " + resolveJumpStart;
+        assert resolveJumpOffset > 0 : "incorrect resolveJumpOffset: " + resolveJumpOffset;
+        if (!isVirtual) {
+            assert c2iJumpOffset > 0 : "incorrect c2iJumpOffset: " + c2iJumpOffset;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Timer.java	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+final class Timer implements AutoCloseable {
+
+    private final Main main;
+    private final long start;
+
+    Timer(Main main, String message) {
+        this.main = main;
+        start = System.currentTimeMillis();
+        main.printer.printInfo(message);
+    }
+
+    public void close() {
+        final long end = System.currentTimeMillis();
+        main.printer.printlnInfo(" (" + (end - start) + " ms)");
+    }
+
+}
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64ELFMacroAssembler.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64ELFMacroAssembler.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,7 @@
 import static jdk.vm.ci.amd64.AMD64.rbx;
 import static jdk.vm.ci.amd64.AMD64.rip;
 
-import jdk.tools.jaotc.CompiledMethodInfo.StubInformation;
+import jdk.tools.jaotc.StubInformation;
 import jdk.tools.jaotc.ELFMacroAssembler;
 import org.graalvm.compiler.asm.amd64.AMD64Address;
 import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64InstructionDecoder.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64InstructionDecoder.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,43 +35,43 @@
     private static class Prefix {
 
         // segment overrides
-        public static final int CSSegment = 0x2e;
-        public static final int SSSegment = 0x36;
-        public static final int DSSegment = 0x3e;
-        public static final int ESSegment = 0x26;
-        public static final int FSSegment = 0x64;
-        public static final int GSSegment = 0x65;
-        public static final int REX = 0x40;
-        public static final int REXB = 0x41;
-        public static final int REXX = 0x42;
-        public static final int REXXB = 0x43;
-        public static final int REXR = 0x44;
-        public static final int REXRB = 0x45;
-        public static final int REXRX = 0x46;
-        public static final int REXRXB = 0x47;
-        public static final int REXW = 0x48;
-        public static final int REXWB = 0x49;
-        public static final int REXWX = 0x4A;
-        public static final int REXWXB = 0x4B;
-        public static final int REXWR = 0x4C;
-        public static final int REXWRB = 0x4D;
-        public static final int REXWRX = 0x4E;
-        public static final int REXWRXB = 0x4F;
-        public static final int VEX_3BYTES = 0xC4;
-        public static final int VEX_2BYTES = 0xC5;
+        static final int CSSegment = 0x2e;
+        static final int SSSegment = 0x36;
+        static final int DSSegment = 0x3e;
+        static final int ESSegment = 0x26;
+        static final int FSSegment = 0x64;
+        static final int GSSegment = 0x65;
+        static final int REX = 0x40;
+        static final int REXB = 0x41;
+        static final int REXX = 0x42;
+        static final int REXXB = 0x43;
+        static final int REXR = 0x44;
+        static final int REXRB = 0x45;
+        static final int REXRX = 0x46;
+        static final int REXRXB = 0x47;
+        static final int REXW = 0x48;
+        static final int REXWB = 0x49;
+        static final int REXWX = 0x4A;
+        static final int REXWXB = 0x4B;
+        static final int REXWR = 0x4C;
+        static final int REXWRB = 0x4D;
+        static final int REXWRX = 0x4E;
+        static final int REXWRXB = 0x4F;
+        static final int VEX_3BYTES = 0xC4;
+        static final int VEX_2BYTES = 0xC5;
     }
 
-    public static class VexPrefix {
-        public static final int VEX_R = 0x80;
-        public static final int VEX_W = 0x80;
+    private static class VexPrefix {
+        static final int VEX_R = 0x80;
+        static final int VEX_W = 0x80;
     }
 
-    public static class VexOpcode {
-        public static final int VEX_OPCODE_NONE = 0x0;
-        public static final int VEX_OPCODE_0F = 0x1;
-        public static final int VEX_OPCODE_0F_38 = 0x2;
-        public static final int VEX_OPCODE_0F_3A = 0x3;
-        public static final int VEX_OPCODE_MASK = 0x1F;
+    private static class VexOpcode {
+        static final int VEX_OPCODE_NONE = 0x0;
+        static final int VEX_OPCODE_0F = 0x1;
+        static final int VEX_OPCODE_0F_38 = 0x2;
+        static final int VEX_OPCODE_0F_3A = 0x3;
+        static final int VEX_OPCODE_MASK = 0x1F;
     }
 
     public AMD64InstructionDecoder(TargetDescription target) {
@@ -112,7 +112,7 @@
             againAfterPrefix = false;
             switch (0xFF & code[ip++]) {
 
-                // These convenience macros generate groups of "case" labels for the switch.
+            // These convenience macros generate groups of "case" labels for the switch.
 
                 case Prefix.CSSegment:
                 case Prefix.SSSegment:
@@ -446,7 +446,7 @@
                                     tailSize = 1;  // the imm8
                                     break;
                                 default:
-                                    ; // no imm8
+                                    break; // no imm8
                             }
                             break;
                         case VexOpcode.VEX_OPCODE_0F_3A:
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java	Thu Aug 24 21:06:33 2017 +0000
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.tools.jaotc.collect;
 
 import jdk.tools.jaotc.LoadedClass;
@@ -27,8 +28,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
-public class ClassSearch {
-    private List<SourceProvider> providers = new ArrayList<>();
+public final class ClassSearch {
+    private final List<SourceProvider> providers = new ArrayList<>();
 
     public void addProvider(SourceProvider provider) {
         providers.add(provider);
@@ -50,7 +51,7 @@
         return loaded;
     }
 
-    private LoadedClass loadClass(String name, ClassLoader loader) {
+    private static LoadedClass loadClass(String name, ClassLoader loader) {
         try {
             Class<?> clzz = loader.loadClass(name);
             return new LoadedClass(name, clzz);
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java	Thu Aug 24 21:06:33 2017 +0000
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.tools.jaotc.collect;
 
 import java.nio.file.Path;
@@ -32,17 +33,17 @@
     }
 
     static String stripRoot(Path path) {
-      if (path.getRoot() != null) {
-        String root = path.getRoot().toString();
-        String filename = path.toString().substring(root.length());
-        String separator = path.getFileSystem().getSeparator();
-        while (filename.startsWith(separator)) {
-          filename = filename.substring(separator.length());
+        if (path.getRoot() != null) {
+            String root = path.getRoot().toString();
+            String filename = path.toString().substring(root.length());
+            String separator = path.getFileSystem().getSeparator();
+            while (filename.startsWith(separator)) {
+                filename = filename.substring(separator.length());
+            }
+            return filename;
         }
-        return filename;
-      }
 
-      return path.toString();
+        return path.toString();
     }
 
     static String makeClassName(Path path) {
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java	Thu Aug 24 21:06:33 2017 +0000
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.tools.jaotc.collect;
 
 import java.io.IOException;
@@ -28,7 +29,7 @@
 import java.util.HashMap;
 
 public class FileSupport {
-    public boolean exists(Path path)  {
+    public boolean exists(Path path) {
         return Files.exists(path);
     }
 
@@ -36,7 +37,7 @@
         return Files.isDirectory(path);
     }
 
-    private FileSystem makeJarFileSystem(Path path) {
+    private static FileSystem makeJarFileSystem(Path path) {
         try {
             return FileSystems.newFileSystem(makeJarFileURI(path), new HashMap<>());
         } catch (IOException e) {
@@ -44,10 +45,10 @@
         }
     }
 
-    private URI makeJarFileURI(Path path) {
+    private static URI makeJarFileURI(Path path) {
         try {
             String name = path.toAbsolutePath().toString();
-            name = name.replace('\\','/');
+            name = name.replace('\\', '/');
             return new URI("jar:file:///" + name + "!/");
         } catch (URISyntaxException e) {
             throw new InternalError(e);
@@ -66,8 +67,8 @@
         return URLClassLoader.newInstance(buildUrls(path));
     }
 
-    private URL[] buildUrls(Path path) throws MalformedURLException {
-        return new URL[] { path.toUri().toURL() };
+    private static URL[] buildUrls(Path path) throws MalformedURLException {
+        return new URL[]{path.toUri().toURL()};
     }
 
     public Path getJarFileSystemRoot(Path jarFile) {
@@ -80,7 +81,7 @@
     }
 
     public Path getSubDirectory(FileSystem fileSystem, Path root, Path path) throws IOException {
-        DirectoryStream<Path> paths = fileSystem.provider().newDirectoryStream(root,null);
+        DirectoryStream<Path> paths = fileSystem.provider().newDirectoryStream(root, null);
         for (Path entry : paths) {
             Path relative = root.relativize(entry);
             if (relative.equals(path)) {
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java	Thu Aug 24 21:06:33 2017 +0000
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.tools.jaotc.collect;
 
 import java.io.IOException;
@@ -33,7 +34,7 @@
 /**
  * {@link FileVisitor} implementation to find class files recursively.
  */
-public class FileSystemFinder extends SimpleFileVisitor<Path> implements Iterable<Path> {
+public final class FileSystemFinder extends SimpleFileVisitor<Path> implements Iterable<Path> {
     private final ArrayList<Path> fileNames = new ArrayList<>();
     private final PathMatcher filter;
 
@@ -68,7 +69,6 @@
         return CONTINUE;
     }
 
-
     @Override
     public Iterator<Path> iterator() {
         return fileNames.iterator();
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java	Thu Aug 24 21:06:33 2017 +0000
@@ -20,9 +20,10 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.tools.jaotc.collect;
 
-public class SearchFor {
+public final class SearchFor {
     private final String name;
     private final String type;
 
@@ -35,15 +36,15 @@
         this.type = type;
     }
 
-    public boolean isUnknown() {
+    boolean isUnknown() {
         return "".equals(type);
     }
 
-    public String getType() {
+    String getType() {
         return this.type;
     }
 
-    public String getName() {
+    String getName() {
         return this.name;
     }
 
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java	Thu Aug 24 21:06:33 2017 +0000
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.tools.jaotc.collect;
 
 import java.nio.file.FileSystem;
@@ -84,4 +85,3 @@
         }
     }
 }
-
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java	Thu Aug 24 21:06:33 2017 +0000
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.tools.jaotc.collect;
 
 public interface SourceProvider {
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java	Thu Aug 24 21:06:33 2017 +0000
@@ -20,17 +20,18 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.tools.jaotc.collect.classname;
 
 import jdk.tools.jaotc.collect.ClassSource;
 
 import java.util.function.BiConsumer;
 
-public class ClassNameSource implements ClassSource {
+public final class ClassNameSource implements ClassSource {
     private final String name;
     private final ClassLoader classLoader;
 
-    public ClassNameSource(String name, ClassLoader classLoader) {
+    ClassNameSource(String name, ClassLoader classLoader) {
         this.name = name;
         this.classLoader = classLoader;
     }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java	Thu Aug 24 21:06:33 2017 +0000
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.tools.jaotc.collect.classname;
 
 import jdk.tools.jaotc.collect.ClassSource;
@@ -30,7 +31,7 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 
-public class ClassNameSourceProvider implements SourceProvider {
+public final class ClassNameSourceProvider implements SourceProvider {
     public final static String TYPE = "class";
     private final ClassLoader classLoader;
 
@@ -46,7 +47,8 @@
     }
 
     @Override
-    public ClassSource findSource(String name, SearchPath searchPath) {
+    public ClassSource findSource(String name0, SearchPath searchPath) {
+        String name = name0;
         Path path = Paths.get(name);
         if (ClassSource.pathIsClassFile(path)) {
             name = ClassSource.makeClassName(path);
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java	Thu Aug 24 21:06:33 2017 +0000
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.tools.jaotc.collect.directory;
 
 import jdk.tools.jaotc.collect.ClassSource;
@@ -28,11 +29,11 @@
 import java.nio.file.Path;
 import java.util.function.BiConsumer;
 
-public class DirectorySource implements ClassSource {
+public final class DirectorySource implements ClassSource {
     private final Path directoryPath;
     private final ClassLoader classLoader;
 
-    public DirectorySource(Path directoryPath, ClassLoader classLoader) {
+    DirectorySource(Path directoryPath, ClassLoader classLoader) {
         this.directoryPath = directoryPath;
         this.classLoader = classLoader;
     }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java	Thu Aug 24 21:06:33 2017 +0000
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.tools.jaotc.collect.directory;
 
 import jdk.tools.jaotc.collect.ClassSource;
@@ -32,7 +33,7 @@
 import java.nio.file.FileSystems;
 import java.nio.file.Path;
 
-public class DirectorySourceProvider implements SourceProvider {
+public final class DirectorySourceProvider implements SourceProvider {
     private final FileSupport fileSupport;
     private final FileSystem fileSystem;
     public final static String TYPE = "directory";
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java	Thu Aug 24 21:06:33 2017 +0000
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.tools.jaotc.collect.jar;
 
 import jdk.tools.jaotc.collect.ClassSource;
@@ -28,18 +29,18 @@
 import java.nio.file.Path;
 import java.util.function.BiConsumer;
 
-public class JarFileSource implements ClassSource {
+public final class JarFileSource implements ClassSource {
     private final Path jarFile;
     private final Path jarRootPath;
     private final ClassLoader classLoader;
 
-
-    public JarFileSource(Path jarFile, Path jarRootPath, ClassLoader classLoader) {
+    JarFileSource(Path jarFile, Path jarRootPath, ClassLoader classLoader) {
         this.jarFile = jarFile;
         this.jarRootPath = jarRootPath;
         this.classLoader = classLoader;
     }
 
+    @Override
     public void eachClass(BiConsumer<String, ClassLoader> consumer) {
         FileSystemFinder finder = new FileSystemFinder(jarRootPath, ClassSource::pathIsClassFile);
 
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java	Thu Aug 24 21:06:33 2017 +0000
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.tools.jaotc.collect.jar;
 
 import jdk.tools.jaotc.collect.ClassSource;
@@ -33,7 +34,7 @@
 import java.nio.file.Path;
 import java.nio.file.ProviderNotFoundException;
 
-public class JarSourceProvider implements SourceProvider {
+public final class JarSourceProvider implements SourceProvider {
     private final FileSystem fileSystem;
     private final FileSupport fileSupport;
     public final static String TYPE = "jar";
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java	Thu Aug 24 21:06:33 2017 +0000
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.tools.jaotc.collect.module;
 
 import jdk.tools.jaotc.collect.ClassSource;
@@ -28,15 +29,19 @@
 import java.nio.file.Path;
 import java.util.function.BiConsumer;
 
-public class ModuleSource implements ClassSource {
+public final class ModuleSource implements ClassSource {
     private final Path modulePath;
     private final ClassLoader classLoader;
 
-    public ModuleSource(Path modulePath, ClassLoader classLoader) {
+    ModuleSource(Path modulePath, ClassLoader classLoader) {
         this.modulePath = modulePath;
         this.classLoader = classLoader;
     }
 
+    public Path getModulePath() {
+        return modulePath;
+    }
+
     @Override
     public void eachClass(BiConsumer<String, ClassLoader> consumer) {
         FileSystemFinder finder = new FileSystemFinder(modulePath, ClassSource::pathIsClassFile);
@@ -46,10 +51,6 @@
         }
     }
 
-    public Path getModulePath() {
-        return modulePath;
-    }
-
     @Override
     public String toString() {
         return "module:" + modulePath.toString();
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java	Thu Aug 24 21:06:33 2017 +0000
@@ -20,6 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.tools.jaotc.collect.module;
 
 import jdk.tools.jaotc.collect.ClassSource;
@@ -33,7 +34,7 @@
 import java.nio.file.FileSystems;
 import java.nio.file.Path;
 
-public class ModuleSourceProvider implements SourceProvider {
+public final class ModuleSourceProvider implements SourceProvider {
     private final FileSystem fileSystem;
     private final ClassLoader classLoader;
     private final FileSupport fileSupport;
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/NativeOrderOutputStream.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/NativeOrderOutputStream.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-public class NativeOrderOutputStream {
+public final class NativeOrderOutputStream {
     private final PatchableByteOutputStream os = new PatchableByteOutputStream();
     private final byte[] backingArray = new byte[8];
     private final ByteBuffer buffer;
@@ -181,7 +181,7 @@
     private static class PatchableByteOutputStream extends ByteArrayOutputStream {
 
         public void writeAt(byte[] data, int length, int position) {
-            long end = (long)position + (long)length;
+            long end = (long) position + (long) length;
             if (buf.length < end) {
                 throw new IllegalArgumentException("Array not properly sized");
             }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/Timer.java	Thu Aug 24 14:03:21 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * 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 jdk.tools.jaotc.utils;
-
-import jdk.tools.jaotc.Main;
-
-public class Timer implements AutoCloseable {
-
-    private final Main main;
-    private final long start;
-
-    public Timer(Main main, String message) {
-        this.main = main;
-        start = System.currentTimeMillis();
-        main.printInfo(message);
-    }
-
-    public void close() {
-        final long end = System.currentTimeMillis();
-        main.printlnInfo(" (" + (end - start) + " ms)");
-    }
-
-}
--- a/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java	Thu Aug 24 21:06:33 2017 +0000
@@ -153,9 +153,9 @@
      * @param resolve force resolution to a {@link ResolvedJavaType}. If true, this method will
      *            either return a {@link ResolvedJavaType} or throw an exception
      * @return the type for {@code name} or 0 if resolution failed and {@code resolve == false}
-     * @throws LinkageError if {@code resolve == true} and the resolution failed
+     * @throws ClassNotFoundException if {@code resolve == true} and the resolution failed
      */
-    native HotSpotResolvedObjectTypeImpl lookupType(String name, Class<?> accessingClass, boolean resolve);
+    native HotSpotResolvedObjectTypeImpl lookupType(String name, Class<?> accessingClass, boolean resolve) throws ClassNotFoundException;
 
     /**
      * Resolves the entry at index {@code cpi} in {@code constantPool} to an object.
--- a/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java	Thu Aug 24 21:06:33 2017 +0000
@@ -367,13 +367,17 @@
 
         // Resolve non-primitive types in the VM.
         HotSpotResolvedObjectTypeImpl hsAccessingType = (HotSpotResolvedObjectTypeImpl) accessingType;
-        final HotSpotResolvedObjectTypeImpl klass = compilerToVm.lookupType(name, hsAccessingType.mirror(), resolve);
+        try {
+            final HotSpotResolvedObjectTypeImpl klass = compilerToVm.lookupType(name, hsAccessingType.mirror(), resolve);
 
-        if (klass == null) {
-            assert resolve == false;
-            return HotSpotUnresolvedJavaType.create(this, name);
+            if (klass == null) {
+                assert resolve == false;
+                return HotSpotUnresolvedJavaType.create(this, name);
+            }
+            return klass;
+        } catch (ClassNotFoundException e) {
+            throw (NoClassDefFoundError) new NoClassDefFoundError().initCause(e);
         }
-        return klass;
     }
 
     public JVMCIBackend getHostJVMCIBackend() {
--- a/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSignature.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSignature.java	Thu Aug 24 21:06:33 2017 +0000
@@ -45,7 +45,9 @@
 
     public HotSpotSignature(HotSpotJVMCIRuntimeProvider runtime, String signature) {
         this.runtime = runtime;
-        assert signature.length() > 0;
+        if (signature.length() == 0) {
+            throw new IllegalArgumentException("Signature cannot be empty");
+        }
         this.originalString = signature;
 
         if (signature.charAt(0) == '(') {
@@ -59,9 +61,11 @@
             cur++;
             int nextCur = parseSignature(signature, cur);
             returnType = signature.substring(cur, nextCur);
-            assert nextCur == signature.length();
+            if (nextCur != signature.length()) {
+                throw new IllegalArgumentException("Extra characters at end of signature: " + signature);
+            }
         } else {
-            returnType = null;
+            throw new IllegalArgumentException("Signature must start with a '(': " + signature);
         }
     }
 
@@ -81,33 +85,41 @@
     }
 
     private static int parseSignature(String signature, int start) {
-        int cur = start;
-        char first;
-        do {
-            first = signature.charAt(cur++);
-        } while (first == '[');
-
-        switch (first) {
-            case 'L':
-                while (signature.charAt(cur) != ';') {
-                    cur++;
-                }
+        try {
+            int cur = start;
+            char first;
+            do {
+                first = signature.charAt(cur);
                 cur++;
-                break;
-            case 'V':
-            case 'I':
-            case 'B':
-            case 'C':
-            case 'D':
-            case 'F':
-            case 'J':
-            case 'S':
-            case 'Z':
-                break;
-            default:
-                throw new JVMCIError("Invalid character at index %d in signature: %s", cur, signature);
+            } while (first == '[');
+
+            switch (first) {
+                case 'L':
+                    while (signature.charAt(cur) != ';') {
+                        if (signature.charAt(cur) == '.') {
+                            throw new IllegalArgumentException("Class name in signature contains '.' at index " + cur + ": " + signature);
+                        }
+                        cur++;
+                    }
+                    cur++;
+                    break;
+                case 'V':
+                case 'I':
+                case 'B':
+                case 'C':
+                case 'D':
+                case 'F':
+                case 'J':
+                case 'S':
+                case 'Z':
+                    break;
+                default:
+                    throw new IllegalArgumentException("Invalid character '" + signature.charAt(cur - 1) + "' at index " + (cur - 1) + " in signature: " + signature);
+            }
+            return cur;
+        } catch (StringIndexOutOfBoundsException e) {
+            throw new IllegalArgumentException("Truncated signature: " + signature);
         }
-        return cur;
     }
 
     @Override
--- a/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java	Thu Aug 24 21:06:33 2017 +0000
@@ -83,8 +83,9 @@
     /**
      * Parses a
      * <a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3">method
-     * descriptor</a> into a {@link Signature}. The behavior of this method is undefined if the
-     * method descriptor is not well formed.
+     * descriptor</a> into a {@link Signature}.
+     *
+     * @throws IllegalArgumentException if the method descriptor is not well formed
      */
     Signature parseMethodDescriptor(String methodDescriptor);
 
--- a/hotspot/src/jdk.internal.vm.compiler/.mx.graal/suite.py	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/.mx.graal/suite.py	Thu Aug 24 21:06:33 2017 +0000
@@ -1106,34 +1106,12 @@
     "jdk.tools.jaotc.binformat" : {
       "subDir" : "../jdk.aot/share/classes",
       "sourceDirs" : ["src"],
-      "dependencies" : [
-        "jdk.tools.jaotc.jnilibelf",
-      ],
       "generatedDependencies" : [
         "org.graalvm.compiler.hotspot",
       ],
       "checkstyle" : "jdk.tools.jaotc",
       "javaCompliance" : "1.8",
     },
-
-    "jdk.tools.jaotc.jnilibelf" : {
-      "subDir" : "../jdk.aot/share/classes",
-      "sourceDirs" : ["src"],
-      "dependencies" : [],
-      "checkstyle" : "jdk.tools.jaotc",
-      "javaCompliance" : "1.8",
-    },
-
-    "jdk.tools.jaotc.jnilibelf.test" : {
-      "subDir" : "../../test/compiler/aot",
-      "sourceDirs" : ["src"],
-      "dependencies" : [
-        "jdk.tools.jaotc.jnilibelf",
-      ],
-      "checkstyle" : "jdk.tools.jaotc",
-      "javaCompliance" : "1.8",
-    },
-
   },
 
   "distributions" : {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java	Thu Aug 24 21:06:33 2017 +0000
@@ -158,7 +158,7 @@
                 }
                 break;
             default:
-                throw GraalError.shouldNotReachHere();
+                throw GraalError.shouldNotReachHere(input.getPlatformKind().toString());
         }
         return result;
     }
@@ -451,7 +451,7 @@
     protected Value emitZeroExtendMemory(AMD64Kind memoryKind, int resultBits, AMD64AddressValue address, LIRFrameState state) {
         // Issue a zero extending load of the proper bit size and set the result to
         // the proper kind.
-        Variable result = getLIRGen().newVariable(LIRKind.value(resultBits == 32 ? AMD64Kind.DWORD : AMD64Kind.QWORD));
+        Variable result = getLIRGen().newVariable(LIRKind.value(resultBits <= 32 ? AMD64Kind.DWORD : AMD64Kind.QWORD));
         switch (memoryKind) {
             case BYTE:
                 getLIRGen().append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, address, state));
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/FloatConvert.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/FloatConvert.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,16 +25,26 @@
 import org.graalvm.compiler.debug.GraalError;
 
 public enum FloatConvert {
-    F2I,
-    D2I,
-    F2L,
-    D2L,
-    I2F,
-    L2F,
-    D2F,
-    I2D,
-    L2D,
-    F2D;
+    F2I(FloatConvertCategory.FloatingPointToInteger),
+    D2I(FloatConvertCategory.FloatingPointToInteger),
+    F2L(FloatConvertCategory.FloatingPointToInteger),
+    D2L(FloatConvertCategory.FloatingPointToInteger),
+    I2F(FloatConvertCategory.IntegerToFloatingPoint),
+    L2F(FloatConvertCategory.IntegerToFloatingPoint),
+    D2F(FloatConvertCategory.FloatingPointToFloatingPoint),
+    I2D(FloatConvertCategory.IntegerToFloatingPoint),
+    L2D(FloatConvertCategory.IntegerToFloatingPoint),
+    F2D(FloatConvertCategory.FloatingPointToFloatingPoint);
+
+    private FloatConvertCategory category;
+
+    FloatConvert(FloatConvertCategory category) {
+        this.category = category;
+    }
+
+    public FloatConvertCategory getCategory() {
+        return category;
+    }
 
     public FloatConvert reverse() {
         switch (this) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/FloatConvertCategory.java	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.calc;
+
+public enum FloatConvertCategory {
+    FloatingPointToInteger,
+    IntegerToFloatingPoint,
+    FloatingPointToFloatingPoint;
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java	Thu Aug 24 21:06:33 2017 +0000
@@ -33,9 +33,11 @@
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.And;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Div;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Mul;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.MulHigh;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Or;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Rem;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Sub;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.UMulHigh;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Xor;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend;
@@ -62,6 +64,8 @@
     private final BinaryOp<Sub> sub;
 
     private final BinaryOp<Mul> mul;
+    private final BinaryOp<MulHigh> mulHigh;
+    private final BinaryOp<UMulHigh> umulHigh;
     private final BinaryOp<Div> div;
     private final BinaryOp<Rem> rem;
 
@@ -92,7 +96,7 @@
         }
     }
 
-    public static final ArithmeticOpTable EMPTY = new ArithmeticOpTable(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
+    public static final ArithmeticOpTable EMPTY = new ArithmeticOpTable(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
 
     public interface ArithmeticOpWrapper {
 
@@ -121,6 +125,8 @@
         BinaryOp<Sub> sub = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getSub());
 
         BinaryOp<Mul> mul = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getMul());
+        BinaryOp<MulHigh> mulHigh = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getMulHigh());
+        BinaryOp<UMulHigh> umulHigh = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getUMulHigh());
         BinaryOp<Div> div = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getDiv());
         BinaryOp<Rem> rem = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getRem());
 
@@ -141,16 +147,18 @@
         IntegerConvertOp<Narrow> narrow = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getNarrow());
 
         FloatConvertOp[] floatConvert = CollectionsUtil.filterAndMapToArray(inner.floatConvert, Objects::nonNull, wrapper::wrapFloatConvertOp, FloatConvertOp[]::new);
-        return new ArithmeticOpTable(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow, floatConvert);
+        return new ArithmeticOpTable(neg, add, sub, mul, mulHigh, umulHigh, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow, floatConvert);
     }
 
-    protected ArithmeticOpTable(UnaryOp<Neg> neg, BinaryOp<Add> add, BinaryOp<Sub> sub, BinaryOp<Mul> mul, BinaryOp<Div> div, BinaryOp<Rem> rem, UnaryOp<Not> not, BinaryOp<And> and, BinaryOp<Or> or,
-                    BinaryOp<Xor> xor, ShiftOp<Shl> shl, ShiftOp<Shr> shr, ShiftOp<UShr> ushr, UnaryOp<Abs> abs, UnaryOp<Sqrt> sqrt, IntegerConvertOp<ZeroExtend> zeroExtend,
-                    IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow, FloatConvertOp... floatConvert) {
+    protected ArithmeticOpTable(UnaryOp<Neg> neg, BinaryOp<Add> add, BinaryOp<Sub> sub, BinaryOp<Mul> mul, BinaryOp<MulHigh> mulHigh, BinaryOp<UMulHigh> umulHigh, BinaryOp<Div> div, BinaryOp<Rem> rem,
+                    UnaryOp<Not> not, BinaryOp<And> and, BinaryOp<Or> or, BinaryOp<Xor> xor, ShiftOp<Shl> shl, ShiftOp<Shr> shr, ShiftOp<UShr> ushr, UnaryOp<Abs> abs, UnaryOp<Sqrt> sqrt,
+                    IntegerConvertOp<ZeroExtend> zeroExtend, IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow, FloatConvertOp... floatConvert) {
         this.neg = neg;
         this.add = add;
         this.sub = sub;
         this.mul = mul;
+        this.mulHigh = mulHigh;
+        this.umulHigh = umulHigh;
         this.div = div;
         this.rem = rem;
         this.not = not;
@@ -207,6 +215,20 @@
     }
 
     /**
+     * Describes a signed operation that multiples the upper 32-bits of two long values.
+     */
+    public BinaryOp<MulHigh> getMulHigh() {
+        return mulHigh;
+    }
+
+    /**
+     * Describes an unsigned operation that multiples the upper 32-bits of two long values.
+     */
+    public BinaryOp<UMulHigh> getUMulHigh() {
+        return umulHigh;
+    }
+
+    /**
      * Describes the division operation.
      */
     public BinaryOp<Div> getDiv() {
@@ -321,6 +343,8 @@
                Objects.equals(add, that.add) &&
                Objects.equals(sub, that.sub) &&
                Objects.equals(mul, that.mul) &&
+               Objects.equals(mulHigh, that.mulHigh) &&
+               Objects.equals(umulHigh, that.umulHigh) &&
                Objects.equals(div, that.div) &&
                Objects.equals(rem, that.rem) &&
                Objects.equals(not, that.not) &&
@@ -360,8 +384,8 @@
 
     @Override
     public String toString() {
-        return getClass().getSimpleName() + "[" + toString(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow) + ",floatConvert[" +
-                        toString(floatConvert) + "]]";
+        return getClass().getSimpleName() + "[" + toString(neg, add, sub, mul, mulHigh, umulHigh, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow) +
+                        ",floatConvert[" + toString(floatConvert) + "]]";
     }
 
     public abstract static class Op {
@@ -479,6 +503,20 @@
             }
         }
 
+        public abstract static class MulHigh extends BinaryOp<MulHigh> {
+
+            protected MulHigh(boolean associative, boolean commutative) {
+                super("*H", associative, commutative);
+            }
+        }
+
+        public abstract static class UMulHigh extends BinaryOp<UMulHigh> {
+
+            protected UMulHigh(boolean associative, boolean commutative) {
+                super("|*H|", associative, commutative);
+            }
+        }
+
         public abstract static class Div extends BinaryOp<Div> {
 
             protected Div(boolean associative, boolean commutative) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java	Thu Aug 24 21:06:33 2017 +0000
@@ -302,7 +302,7 @@
         return null;
     }
 
-    private static final ArithmeticOpTable OPS = new ArithmeticOpTable(
+    public static final ArithmeticOpTable OPS = new ArithmeticOpTable(
 
                     new UnaryOp.Neg() {
 
@@ -437,6 +437,10 @@
                         }
                     },
 
+                    null,
+
+                    null,
+
                     new BinaryOp.Div(false, false) {
 
                         @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java	Thu Aug 24 21:06:33 2017 +0000
@@ -858,6 +858,164 @@
                         }
                     },
 
+                    new BinaryOp.MulHigh(true, true) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            return JavaConstant.forIntegerKind(a.getJavaKind(), multiplyHigh(a.asLong(), b.asLong(), a.getJavaKind()));
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            IntegerStamp a = (IntegerStamp) stamp1;
+                            IntegerStamp b = (IntegerStamp) stamp2;
+                            JavaKind javaKind = a.getStackKind();
+
+                            assert a.getBits() == b.getBits();
+                            assert javaKind == b.getStackKind();
+                            assert (javaKind == JavaKind.Int || javaKind == JavaKind.Long);
+
+                            if (a.isEmpty() || b.isEmpty()) {
+                                return a.empty();
+                            } else if (a.isUnrestricted() || b.isUnrestricted()) {
+                                return a.unrestricted();
+                            }
+
+                            long[] xExtremes = {a.lowerBound(), a.upperBound()};
+                            long[] yExtremes = {b.lowerBound(), b.upperBound()};
+                            long min = Long.MAX_VALUE;
+                            long max = Long.MIN_VALUE;
+                            for (long x : xExtremes) {
+                                for (long y : yExtremes) {
+                                    long result = multiplyHigh(x, y, javaKind);
+                                    min = Math.min(min, result);
+                                    max = Math.max(max, result);
+                                }
+                            }
+                            return StampFactory.forInteger(javaKind, min, max);
+                        }
+
+                        @Override
+                        public boolean isNeutral(Constant value) {
+                            return false;
+                        }
+
+                        private long multiplyHigh(long x, long y, JavaKind javaKind) {
+                            if (javaKind == JavaKind.Int) {
+                                return (x * y) >> 32;
+                            } else {
+                                assert javaKind == JavaKind.Long;
+                                long x0 = x & 0xFFFFFFFFL;
+                                long x1 = x >> 32;
+
+                                long y0 = y & 0xFFFFFFFFL;
+                                long y1 = y >> 32;
+
+                                long z0 = x0 * y0;
+                                long t = x1 * y0 + (z0 >>> 32);
+                                long z1 = t & 0xFFFFFFFFL;
+                                long z2 = t >> 32;
+                                z1 += x0 * y1;
+
+                                return x1 * y1 + z2 + (z1 >> 32);
+                            }
+                        }
+                    },
+
+                    new BinaryOp.UMulHigh(true, true) {
+
+                        @Override
+                        public Constant foldConstant(Constant const1, Constant const2) {
+                            PrimitiveConstant a = (PrimitiveConstant) const1;
+                            PrimitiveConstant b = (PrimitiveConstant) const2;
+                            assert a.getJavaKind() == b.getJavaKind();
+                            return JavaConstant.forIntegerKind(a.getJavaKind(), multiplyHighUnsigned(a.asLong(), b.asLong(), a.getJavaKind()));
+                        }
+
+                        @Override
+                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            IntegerStamp a = (IntegerStamp) stamp1;
+                            IntegerStamp b = (IntegerStamp) stamp2;
+                            JavaKind javaKind = a.getStackKind();
+
+                            assert a.getBits() == b.getBits();
+                            assert javaKind == b.getStackKind();
+                            assert (javaKind == JavaKind.Int || javaKind == JavaKind.Long);
+
+                            if (a.isEmpty() || b.isEmpty()) {
+                                return a.empty();
+                            } else if (a.isUnrestricted() || b.isUnrestricted()) {
+                                return a.unrestricted();
+                            }
+
+                            // Note that the minima and maxima are calculated using signed min/max
+                            // functions, while the values themselves are unsigned.
+                            long[] xExtremes = getUnsignedExtremes(a);
+                            long[] yExtremes = getUnsignedExtremes(b);
+                            long min = Long.MAX_VALUE;
+                            long max = Long.MIN_VALUE;
+                            for (long x : xExtremes) {
+                                for (long y : yExtremes) {
+                                    long result = multiplyHighUnsigned(x, y, javaKind);
+                                    min = Math.min(min, result);
+                                    max = Math.max(max, result);
+                                }
+                            }
+
+                            // if min is negative, then the value can reach into the unsigned range
+                            if (min == max || min >= 0) {
+                                return StampFactory.forInteger(javaKind, min, max);
+                            } else {
+                                return StampFactory.forKind(javaKind);
+                            }
+                        }
+
+                        @Override
+                        public boolean isNeutral(Constant value) {
+                            return false;
+                        }
+
+                        private long[] getUnsignedExtremes(IntegerStamp stamp) {
+                            if (stamp.lowerBound() < 0 && stamp.upperBound() >= 0) {
+                                /*
+                                 * If -1 and 0 are both in the signed range, then we can't say
+                                 * anything about the unsigned range, so we have to return [0,
+                                 * MAX_UNSIGNED].
+                                 */
+                                return new long[]{0, -1L};
+                            } else {
+                                return new long[]{stamp.lowerBound(), stamp.upperBound()};
+                            }
+                        }
+
+                        private long multiplyHighUnsigned(long x, long y, JavaKind javaKind) {
+                            if (javaKind == JavaKind.Int) {
+                                long xl = x & 0xFFFFFFFFL;
+                                long yl = y & 0xFFFFFFFFL;
+                                long r = xl * yl;
+                                return (int) (r >>> 32);
+                            } else {
+                                assert javaKind == JavaKind.Long;
+                                long x0 = x & 0xFFFFFFFFL;
+                                long x1 = x >>> 32;
+
+                                long y0 = y & 0xFFFFFFFFL;
+                                long y1 = y >>> 32;
+
+                                long z0 = x0 * y0;
+                                long t = x1 * y0 + (z0 >>> 32);
+                                long z1 = t & 0xFFFFFFFFL;
+                                long z2 = t >>> 32;
+                                z1 += x0 * y1;
+
+                                return x1 * y1 + z2 + (z1 >>> 32);
+                            }
+                        }
+                    },
+
                     new BinaryOp.Div(true, false) {
 
                         @Override
@@ -1046,10 +1204,14 @@
                         public Stamp foldStamp(Stamp stamp, IntegerStamp shift) {
                             IntegerStamp value = (IntegerStamp) stamp;
                             int bits = value.getBits();
-                            long defaultMask = CodeUtil.mask(bits);
-                            if (value.upMask() == 0) {
+                            if (value.isEmpty()) {
+                                return value;
+                            } else if (shift.isEmpty()) {
+                                return StampFactory.forInteger(bits).empty();
+                            } else if (value.upMask() == 0) {
                                 return value;
                             }
+
                             int shiftMask = getShiftAmountMask(stamp);
                             int shiftBits = Integer.bitCount(shiftMask);
                             if (shift.lowerBound() == shift.upperBound()) {
@@ -1068,6 +1230,7 @@
                                 }
                             }
                             if ((shift.lowerBound() >>> shiftBits) == (shift.upperBound() >>> shiftBits)) {
+                                long defaultMask = CodeUtil.mask(bits);
                                 long downMask = defaultMask;
                                 long upMask = 0;
                                 for (long i = shift.lowerBound(); i <= shift.upperBound(); i++) {
@@ -1109,7 +1272,11 @@
                         public Stamp foldStamp(Stamp stamp, IntegerStamp shift) {
                             IntegerStamp value = (IntegerStamp) stamp;
                             int bits = value.getBits();
-                            if (shift.lowerBound() == shift.upperBound()) {
+                            if (value.isEmpty()) {
+                                return value;
+                            } else if (shift.isEmpty()) {
+                                return StampFactory.forInteger(bits).empty();
+                            } else if (shift.lowerBound() == shift.upperBound()) {
                                 long shiftCount = shift.lowerBound() & getShiftAmountMask(stamp);
                                 if (shiftCount == 0) {
                                     return stamp;
@@ -1153,6 +1320,12 @@
                         public Stamp foldStamp(Stamp stamp, IntegerStamp shift) {
                             IntegerStamp value = (IntegerStamp) stamp;
                             int bits = value.getBits();
+                            if (value.isEmpty()) {
+                                return value;
+                            } else if (shift.isEmpty()) {
+                                return StampFactory.forInteger(bits).empty();
+                            }
+
                             if (shift.lowerBound() == shift.upperBound()) {
                                 long shiftCount = shift.lowerBound() & getShiftAmountMask(stamp);
                                 if (shiftCount == 0) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -46,6 +46,16 @@
     public static double SideEffectD;
     public static double SideEffectL;
 
+    private static final long byteArrayBaseOffset;
+    private static final long intArrayBaseOffset;
+    private static final long longArrayBaseOffset;
+
+    static {
+        byteArrayBaseOffset = UNSAFE.arrayBaseOffset(byte[].class);
+        intArrayBaseOffset = UNSAFE.arrayBaseOffset(int[].class);
+        longArrayBaseOffset = UNSAFE.arrayBaseOffset(long[].class);
+    }
+
     public static long test1Snippet(double a) {
         final Object m = Memory;
         if (a > 0) {
@@ -130,4 +140,76 @@
         Assert.assertEquals(writes, graph.getNodes().filter(WriteNode.class).count());
     }
 
+    public static int testWriteIntToByteArraySnippet() {
+        byte[] array = new byte[4];
+        UNSAFE.putInt(array, byteArrayBaseOffset, 0x01020304);
+        return array[0];
+    }
+
+    @Test
+    public void testWriteIntToByteArray() {
+        test("testWriteIntToByteArraySnippet");
+    }
+
+    public static byte testWriteSignedExtendedByteToByteArraySnippet(byte b) {
+        byte[] array = new byte[4];
+        array[0] = 0x01;
+        array[1] = 0x02;
+        array[2] = 0x03;
+        array[3] = 0x04;
+        UNSAFE.putInt(array, byteArrayBaseOffset, b);
+        return array[3];
+    }
+
+    @Test
+    public void testWriteSignedExtendedByteToByteArray() {
+        test("testWriteSignedExtendedByteToByteArraySnippet", (byte) 0);
+    }
+
+    public static int testWriteLongToIntArraySnippet() {
+        int[] array = new int[2];
+        UNSAFE.putLong(array, intArrayBaseOffset, 0x0102030405060708L);
+        return array[0];
+    }
+
+    @Test
+    public void testWriteLongToIntArray() {
+        test("testWriteLongToIntArraySnippet");
+    }
+
+    public static int testWriteByteToIntArraySnippet() {
+        int[] array = new int[1];
+        array[0] = 0x01020304;
+        UNSAFE.putByte(array, intArrayBaseOffset, (byte) 0x05);
+        return array[0];
+    }
+
+    @Test
+    public void testWriteByteToIntArray() {
+        test("testWriteByteToIntArraySnippet");
+    }
+
+    public static long testWriteIntToLongArraySnippet() {
+        long[] array = new long[1];
+        array[0] = 0x0102030405060708L;
+        UNSAFE.putInt(array, longArrayBaseOffset, 0x04030201);
+        return array[0];
+    }
+
+    @Test
+    public void testWriteIntToLongArray() {
+        test("testWriteIntToLongArraySnippet");
+    }
+
+    public static float testWriteFloatToIntArraySnippet() {
+        float[] array = new float[1];
+        UNSAFE.putInt(array, intArrayBaseOffset, Float.floatToRawIntBits(0.5f));
+        return array[0];
+    }
+
+    @Test
+    public void testWriteFloatToIntArray() {
+        test("testWriteFloatToIntArraySnippet");
+    }
+
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -38,10 +38,6 @@
     private static final long fieldOffset1;
     private static final long fieldOffset2;
 
-    private static final long byteArrayBaseOffset;
-    private static final long intArrayBaseOffset;
-    private static final long longArrayBaseOffset;
-
     static {
         try {
             long localFieldOffset1 = UNSAFE.objectFieldOffset(TestClassInt.class.getField("x"));
@@ -55,9 +51,6 @@
                 fieldOffset2 = UNSAFE.objectFieldOffset(TestClassInt.class.getField("z"));
             }
             assert fieldOffset2 == fieldOffset1 + 4;
-            byteArrayBaseOffset = UNSAFE.arrayBaseOffset(byte[].class);
-            intArrayBaseOffset = UNSAFE.arrayBaseOffset(int[].class);
-            longArrayBaseOffset = UNSAFE.arrayBaseOffset(long[].class);
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
@@ -203,76 +196,4 @@
         return x;
     }
 
-    public static int testWriteIntToByteArraySnippet() {
-        byte[] array = new byte[4];
-        UNSAFE.putInt(array, byteArrayBaseOffset, 0x01020304);
-        return array[0];
-    }
-
-    @Test
-    public void testWriteIntToByteArray() {
-        test("testWriteIntToByteArraySnippet");
-    }
-
-    public static byte testWriteSignedExtendedByteToByteArraySnippet(byte b) {
-        byte[] array = new byte[4];
-        array[0] = 0x01;
-        array[1] = 0x02;
-        array[2] = 0x03;
-        array[3] = 0x04;
-        UNSAFE.putInt(array, byteArrayBaseOffset, b);
-        return array[3];
-    }
-
-    @Test
-    public void testWriteSignedExtendedByteToByteArray() {
-        test("testWriteSignedExtendedByteToByteArraySnippet", (byte) 0);
-    }
-
-    public static int testWriteLongToIntArraySnippet() {
-        int[] array = new int[2];
-        UNSAFE.putLong(array, intArrayBaseOffset, 0x0102030405060708L);
-        return array[0];
-    }
-
-    @Test
-    public void testWriteLongToIntArray() {
-        test("testWriteLongToIntArraySnippet");
-    }
-
-    public static int testWriteByteToIntArraySnippet() {
-        int[] array = new int[1];
-        array[0] = 0x01020304;
-        UNSAFE.putByte(array, intArrayBaseOffset, (byte) 0x05);
-        return array[0];
-    }
-
-    @Test
-    public void testWriteByteToIntArray() {
-        test("testWriteByteToIntArraySnippet");
-    }
-
-    public static long testWriteIntToLongArraySnippet() {
-        long[] array = new long[1];
-        array[0] = 0x0102030405060708L;
-        UNSAFE.putInt(array, longArrayBaseOffset, 0x04030201);
-        return array[0];
-    }
-
-    @Test
-    public void testWriteIntToLongArray() {
-        test("testWriteIntToLongArraySnippet");
-    }
-
-    public static float testWriteFloatToIntArraySnippet() {
-        float[] array = new float[1];
-        UNSAFE.putInt(array, intArrayBaseOffset, Float.floatToRawIntBits(0.5f));
-        return array[0];
-    }
-
-    @Test
-    public void testWriteFloatToIntArray() {
-        test("testWriteFloatToIntArraySnippet");
-    }
-
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationPrinter.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationPrinter.java	Thu Aug 24 21:06:33 2017 +0000
@@ -58,6 +58,11 @@
      */
     public static CompilationPrinter begin(OptionValues options, CompilationIdentifier id, JavaMethod method, int entryBCI) {
         if (PrintCompilation.getValue(options) && !TTY.isSuppressed()) {
+            try {
+                Class.forName("java.lang.management.ManagementFactory");
+            } catch (ClassNotFoundException ex) {
+                throw new IllegalArgumentException("PrintCompilation option requires java.management module");
+            }
             return new CompilationPrinter(id, method, entryBCI);
         }
         return DISABLED;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java	Thu Aug 24 21:06:33 2017 +0000
@@ -82,26 +82,6 @@
          */
         ExitVM;
 
-        static ValueHelp HELP = new ValueHelp();
-
-        static class ValueHelp implements EnumOptionKey.ValueHelp<ExceptionAction> {
-            @Override
-            public String getHelp(Object value) {
-                ExceptionAction action = (ExceptionAction) value;
-                switch (action) {
-                    case Silent:
-                        return action + ": Print nothing to the console.";
-                    case Print:
-                        return action + ": Print a stack trace to the console.";
-                    case Diagnose:
-                        return action + ": Retry the compilation with extra diagnostics.";
-                    case ExitVM:
-                        return action + ": Same as " + Diagnose + " except that the VM process exits after retrying.";
-                }
-                return null;
-            }
-        }
-
         /**
          * Gets the action that is one level less verbose than this action, bottoming out at the
          * least verbose action.
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java	Thu Aug 24 21:06:33 2017 +0000
@@ -36,13 +36,15 @@
     // @formatter:off
     @Option(help = "Print an informational line to the console for each completed compilation.", type = OptionType.Debug)
     public static final OptionKey<Boolean> PrintCompilation = new OptionKey<>(false);
-    @Option(help = "Pattern (see MethodFilter for format) for method that will trigger an exception when compiled. " +
-                   "This option exists to test handling compilation crashes gracefully.", type = OptionType.Debug)
+    @Option(help = "Pattern for method(s) that will trigger an exception when compiled. " +
+                   "This option exists to test handling compilation crashes gracefully. " +
+                   "See the MethodFilter option for the pattern syntax. ", type = OptionType.Debug)
     public static final OptionKey<String> CrashAt = new OptionKey<>(null);
-    @Option(help = "The action to take when compilation fails with a non-bailout exception.", type = OptionType.User)
-    public static final EnumOptionKey<ExceptionAction> CompilationFailureAction = new EnumOptionKey<>(ExceptionAction.Diagnose, ExceptionAction.HELP);
-    @Option(help = "The action to take when compilation fails with a bailout exception.", type = OptionType.User)
-    public static final EnumOptionKey<ExceptionAction> CompilationBailoutAction = new EnumOptionKey<>(ExceptionAction.Silent, ExceptionAction.HELP);
+    @Option(help = "file:doc-files/CompilationBailoutActionHelp.txt", type = OptionType.User)
+    public static final EnumOptionKey<ExceptionAction> CompilationBailoutAction = new EnumOptionKey<>(ExceptionAction.Silent);
+    @Option(help = "Specifies the action to take when compilation fails with a bailout exception. " +
+                    "The accepted values are the same as for CompilationBailoutAction.", type = OptionType.User)
+     public static final EnumOptionKey<ExceptionAction> CompilationFailureAction = new EnumOptionKey<>(ExceptionAction.Diagnose);
     @Option(help = "The maximum number of compilation failures or bailouts to handle with the action specified " +
                    "by CompilationFailureAction or CompilationBailoutAction before changing to a less verbose action.", type = OptionType.User)
     public static final OptionKey<Integer> MaxCompilationProblemsPerAction = new OptionKey<>(5);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/doc-files/CompilationBailoutActionHelp.txt	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,6 @@
+Specifies the action to take when compilation fails with a bailout exception.
+The accepted values are:
+    Silent - Print nothing to the console.
+     Print - Print a stack trace to the console.
+  Diagnose - Retry the compilation with extra diagnostics.
+    ExitVM - Same as Diagnose except that the VM process exits after retrying.
\ No newline at end of file
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java	Thu Aug 24 21:06:33 2017 +0000
@@ -198,9 +198,22 @@
 
         private Immutable(OptionValues options) {
             this.options = options;
+            String timeValue = Time.getValue(options);
+            String trackMemUseValue = TrackMemUse.getValue(options);
             this.unscopedCounters = parseUnscopedMetricSpec(Counters.getValue(options), "".equals(Count.getValue(options)), false);
-            this.unscopedTimers = parseUnscopedMetricSpec(Timers.getValue(options), "".equals(Time.getValue(options)), true);
-            this.unscopedMemUseTrackers = parseUnscopedMetricSpec(MemUseTrackers.getValue(options), "".equals(TrackMemUse.getValue(options)), true);
+            this.unscopedTimers = parseUnscopedMetricSpec(Timers.getValue(options), "".equals(timeValue), true);
+            this.unscopedMemUseTrackers = parseUnscopedMetricSpec(MemUseTrackers.getValue(options), "".equals(trackMemUseValue), true);
+
+            if (unscopedTimers != null ||
+                            unscopedMemUseTrackers != null ||
+                            timeValue != null ||
+                            trackMemUseValue != null) {
+                try {
+                    Class.forName("java.lang.management.ManagementFactory");
+                } catch (ClassNotFoundException ex) {
+                    throw new IllegalArgumentException("Time, Timers, MemUseTrackers and TrackMemUse options require java.management module");
+                }
+            }
 
             this.scopesEnabled = DumpOnError.getValue(options) ||
                             Dump.getValue(options) != null ||
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugFilter.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugFilter.java	Thu Aug 24 21:06:33 2017 +0000
@@ -28,8 +28,11 @@
 import org.graalvm.compiler.debug.DebugContext.Scope;
 
 /**
- * Implements the filter specified by the {@link DebugOptions#Dump}, {@link DebugOptions#Log},
- * {@link DebugOptions#Count} and {@link DebugOptions#Time} options.
+ * Implements the filter specified by options such as {@link DebugOptions#Dump},
+ * {@link DebugOptions#Log}, {@link DebugOptions#Count} and {@link DebugOptions#Time}.
+ *
+ * See <a href="DumpHelp.txt">here</a> for a description of the filter syntax.
+ *
  * <p>
  * These options enable the associated debug facility if their filter matches the
  * {@linkplain Scope#getQualifiedName() name} of the current scope. For the
@@ -37,47 +40,7 @@
  * {@link DebugOptions#Count} and {@link DebugOptions#Time} options don't have a level, for them
  * {@code level = 0} means disabled and a {@code level > 0} means enabled.
  * <p>
- * A filter is a list of comma-separated terms of the form {@code <pattern>[:<level>]}. {@code
- * <pattern>} is interpreted as a glob pattern if it contains a "*" or "?" character. Otherwise, it
- * is interpreted as a substring. If {@code <pattern>} is empty, it matches every scope. If {@code :
- * <level>} is omitted, it defaults to {@link DebugContext#BASIC_LEVEL}. The term {@code ~<pattern>}
- * is a shorthand for {@code <pattern>:0} to disable a debug facility for a pattern.
- * <p>
- * The resulting log level of a scope is determined by the <em>last</em> matching term. If no term
- * matches, the log level is 0 (disabled). A filter with no terms matches every scope with a log
- * level of {@link DebugContext#BASIC_LEVEL}.
- *
- * <h2>Examples of filters</h2>
- *
- * <ul>
- * <li>(empty string)<br>
- * Matches any scope with log level {@link DebugContext#BASIC_LEVEL}.
- *
- * <li>{@code :1}<br>
- * Matches any scope with log level 1.
- *
- * <li>{@code *}<br>
- * Matches any scope with log level {@link DebugContext#BASIC_LEVEL}.
- *
- * <li>{@code CodeGen,CodeInstall}<br>
- * Matches scopes containing "CodeGen" or "CodeInstall", both with log level
- * {@link DebugContext#BASIC_LEVEL}.
- *
- * <li>{@code CodeGen:2,CodeInstall:1}<br>
- * Matches scopes containing "CodeGen" with log level 2, or "CodeInstall" with log level 1.
- *
- * <li>{@code :1,Dead:2}<br>
- * Matches scopes containing "Dead" with log level 2, and all other scopes with log level 1.
- *
- * <li>{@code :1,Dead:0}<br>
- * Matches all scopes with log level 1, except those containing "Dead".
- *
- * <li>{@code Code*}<br>
- * Matches scopes starting with "Code" with log level {@link DebugContext#BASIC_LEVEL}.
- *
- * <li>{@code Code,~Dead}<br>
- * Matches scopes containing "Code" but not "Dead", with log level {@link DebugContext#BASIC_LEVEL}.
- * </ul>
+ * The syntax for a filter is explained <a href="file:doc-files/DumpHelp.txt">here</a>.
  */
 final class DebugFilter {
 
@@ -148,13 +111,16 @@
         if (terms == null) {
             return DebugContext.BASIC_LEVEL;
         } else {
-            int level = 0;
+            int defaultLevel = 0;
+            int level = -1;
             for (Term t : terms) {
-                if (t.matches(input)) {
+                if (t.isMatchAny()) {
+                    defaultLevel = t.level;
+                } else if (t.matches(input)) {
                     level = t.level;
                 }
             }
-            return level;
+            return level == -1 ? defaultLevel : level;
         }
     }
 
@@ -176,7 +142,7 @@
 
         Term(String filter, int level) {
             this.level = level;
-            if (filter.isEmpty()) {
+            if (filter.isEmpty() || filter.equals("*")) {
                 this.pattern = null;
             } else if (filter.contains("*") || filter.contains("?")) {
                 this.pattern = Pattern.compile(MethodFilter.createGlobString(filter));
@@ -192,6 +158,10 @@
             return pattern == null || pattern.matcher(input).matches();
         }
 
+        public boolean isMatchAny() {
+            return pattern == null;
+        }
+
         @Override
         public String toString() {
             return (pattern == null ? ".*" : pattern.toString()) + ":" + level;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java	Thu Aug 24 21:06:33 2017 +0000
@@ -64,24 +64,28 @@
                    "An empty value enables all memory usage trackers unconditionally.", type = OptionType.Debug)
     public static final OptionKey<String> MemUseTrackers = new OptionKey<>(null);
 
-    @Option(help = "Pattern for scope(s) in which counting is enabled (see DebugFilter and Debug.counter). " +
+    @Option(help = "Pattern for specifying scopes in which counters are enabled. " +
+                   "See the Dump option for the pattern syntax. " +
                    "An empty value enables all counters unconditionally.", type = OptionType.Debug)
     public static final OptionKey<String> Count = new OptionKey<>(null);
-    @Option(help = "Pattern for scope(s) in which memory use tracking is enabled (see DebugFilter and Debug.counter). " +
+    @Option(help = "Pattern for specifying scopes in which memory use tracking is enabled. " +
+                   "See the Dump option for the pattern syntax. " +
                    "An empty value enables all memory use trackers unconditionally.", type = OptionType.Debug)
     public static final OptionKey<String> TrackMemUse = new OptionKey<>(null);
-    @Option(help = "Pattern for scope(s) in which timing is enabled (see DebugFilter and Debug.timer). " +
+    @Option(help = "Pattern for specifying scopes in which timing is enabled. " +
+                   "See the Dump option for the pattern syntax. " +
                    "An empty value enables all timers unconditionally.", type = OptionType.Debug)
     public static final OptionKey<String> Time = new OptionKey<>(null);
 
-    @Option(help = "Pattern for scope(s) in which verification is enabled (see DebugFilter and Debug.verify).", type = OptionType.Debug)
+    @Option(help = "Pattern for specifying scopes in which logging is enabled. " +
+                   "See the Dump option for the pattern syntax.", type = OptionType.Debug)
     public static final OptionKey<String> Verify = new OptionKey<>(null);
-    @Option(help = "Pattern for scope(s) in which dumping is enabled (see DebugFilter and Debug.dump)", type = OptionType.Debug)
+    @Option(help = "file:doc-files/DumpHelp.txt", type = OptionType.Debug)
     public static final OptionKey<String> Dump = new OptionKey<>(null);
-    @Option(help = "Pattern for scope(s) in which logging is enabled (see DebugFilter and Debug.log)", type = OptionType.Debug)
+    @Option(help = "Pattern for specifying scopes in which logging is enabled. " +
+                   "See the Dump option for the pattern syntax.", type = OptionType.Debug)
     public static final OptionKey<String> Log = new OptionKey<>(null);
-
-    @Option(help = "Pattern for filtering debug scope output based on method context (see MethodFilter)", type = OptionType.Debug)
+    @Option(help = "file:doc-files/MethodFilterHelp.txt")
     public static final OptionKey<String> MethodFilter = new OptionKey<>(null);
     @Option(help = "Only check MethodFilter against the root method in the context if true, otherwise check all methods", type = OptionType.Debug)
     public static final OptionKey<Boolean> MethodFilterRootOnly = new OptionKey<>(false);
@@ -89,13 +93,11 @@
                    "The argument is substring matched against the simple name of the phase class", type = OptionType.Debug)
     public static final OptionKey<String> DumpOnPhaseChange = new OptionKey<>(null);
 
-    @Option(help = "Listst the console at VM shutdown the metric names available to the Timers, Counters and MemUseTrackers option. " +
+    @Option(help = "Lists on the console at VM shutdown the metric names available to the Timers, Counters and MemUseTrackers options. " +
                    "Note that this only lists the metrics that were initialized during the VM execution and so " +
                    "will not include metrics for compiler code that is not executed.", type = OptionType.Debug)
     public static final OptionKey<Boolean> ListMetrics = new OptionKey<>(false);
-    @Option(help = "File to which metrics are dumped per compilation. A CSV format is used if the file ends with .csv " +
-                    "otherwise a more human readable format is used. The fields in the CSV format are: " +
-                    "compilable, compilable_identity, compilation_nr, compilation_id, metric_name, metric_value", type = OptionType.Debug)
+    @Option(help = "file:doc-files/MetricsFileHelp.txt", type = OptionType.Debug)
      public static final OptionKey<String> MetricsFile = new OptionKey<>(null);
     @Option(help = "File to which aggregated metrics are dumped at shutdown. A CSV format is used if the file ends with .csv " +
                     "otherwise a more human readable format is used. If not specified, metrics are dumped to the console.", type = OptionType.Debug)
@@ -149,7 +151,7 @@
     @Option(help = "Enable dumping canonical text from for graphs.", type = OptionType.Debug)
     public static final OptionKey<Boolean> PrintCanonicalGraphStrings = new OptionKey<>(false);
     @Option(help = "Choose format used when dumping canonical text for graphs: " +
-            "0 gives a scheduled graph (better for spotting changes involving the schedule)" +
+            "0 gives a scheduled graph (better for spotting changes involving the schedule) " +
             "while 1 gives a CFG containing expressions rooted at fixed nodes (better for spotting small structure differences)", type = OptionType.Debug)
     public static final OptionKey<Integer> PrintCanonicalGraphStringFlavor = new OptionKey<>(0);
     @Option(help = "Exclude virtual nodes when dumping canonical text for graphs.", type = OptionType.Debug)
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MethodFilter.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MethodFilter.java	Thu Aug 24 21:06:33 2017 +0000
@@ -31,66 +31,7 @@
 
 /**
  * This class implements a method filter that can filter based on class name, method name and
- * parameters. The syntax for the source pattern that is passed to the constructor is as follows:
- *
- * <pre>
- * SourcePatterns = SourcePattern ["," SourcePatterns] .
- * SourcePattern = [ Class "." ] method [ "(" [ Parameter { ";" Parameter } ] ")" ] .
- * Parameter = Class | "int" | "long" | "float" | "double" | "short" | "char" | "boolean" .
- * Class = { package "." } class .
- * </pre>
- *
- *
- * Glob pattern matching (*, ?) is allowed in all parts of the source pattern. Examples for valid
- * filters are:
- *
- * <ul>
- * <li>
- *
- * <pre>
- * visit(Argument;BlockScope)
- * </pre>
- *
- * Matches all methods named "visit", with the first parameter of type "Argument", and the second
- * parameter of type "BlockScope". The packages of the parameter types are irrelevant.</li>
- * <li>
- *
- * <pre>
- * arraycopy(Object;;;;)
- * </pre>
- *
- * Matches all methods named "arraycopy", with the first parameter of type "Object", and four more
- * parameters of any type. The packages of the parameter types are irrelevant.</li>
- * <li>
- *
- * <pre>
- * org.graalvm.compiler.core.graph.PostOrderNodeIterator.*
- * </pre>
- *
- * Matches all methods in the class "org.graalvm.compiler.core.graph.PostOrderNodeIterator".</li>
- * <li>
- *
- * <pre>
- * *
- * </pre>
- *
- * Matches all methods in all classes</li>
- * <li>
- *
- * <pre>
- * org.graalvm.compiler.core.graph.*.visit
- * </pre>
- *
- * Matches all methods named "visit" in classes in the package "org.graalvm.compiler.core.graph".
- * <li>
- *
- * <pre>
- * arraycopy,toString
- * </pre>
- *
- * Matches all methods named "arraycopy" or "toString", meaning that ',' acts as an <i>or</i>
- * operator.</li>
- * </ul>
+ * parameters. The syntax for a filter is explained <a href="MethodFilterHelp.txt">here</a>.
  */
 public class MethodFilter {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/doc-files/DumpHelp.txt	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,61 @@
+Filter pattern for specifying scopes in which dumping is enabled.
+
+A filter is a list of comma-separated terms of the form:
+ 
+  <pattern>[:<level>]
+ 
+If <pattern> contains a "*" or "?" character, it is interpreted as a glob pattern.
+Otherwise, it is interpreted as a substring. If <pattern> is empty, it
+matches every scope. If :<level> is omitted, it defaults to 1. The term
+~<pattern> is a shorthand for <pattern>:0 to disable a debug facility for a pattern.
+
+The default log level is 0 (disabled). Terms with an empty pattern set
+the default log level to the specified value. The last
+matching term with a non-empty pattern selects the level specified. If
+no term matches, the log level is the default level. A filter with no
+terms matches every scope with a log level of 1.
+
+Examples of debug filters:
+--------- 
+  (empty string)
+
+  Matches any scope with level 1.
+--------- 
+  :1
+
+  Matches any scope with level 1.
+--------- 
+  *
+
+  Matches any scope with level 1.
+--------- 
+  CodeGen,CodeInstall
+
+  Matches scopes containing "CodeGen" or "CodeInstall", both with level 1.
+--------- 
+  CodeGen:2,CodeInstall:1
+
+  Matches scopes containing "CodeGen" with level 2, or "CodeInstall" with level 1.
+---------
+  Outer:2,Inner:0}
+
+  Matches scopes containing "Outer" with log level 2, or "Inner" with log level 0. If the scope
+  name contains both patterns then the log level will be 0. This is useful for silencing subscopes.
+---------
+  :1,Dead:2
+
+  Matches scopes containing "Dead" with level 2, and all other scopes with level 1.
+--------- 
+  Dead:0,:1
+
+  Matches all scopes with level 1, except those containing "Dead".   Note that the location of
+  the :1 doesn't matter since it's specifying the default log level so it's the same as
+  specifying :1,Dead:0.
+--------- 
+  Code*
+
+  Matches scopes starting with "Code" with level 1.
+--------- 
+  Code,~Dead
+
+  Matches scopes containing "Code" but not "Dead", with level 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/doc-files/MethodFilterHelp.txt	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,40 @@
+Pattern for filtering debug scope output based on method context.
+The syntax for a pattern is:
+
+  SourcePatterns = SourcePattern ["," SourcePatterns] .
+  SourcePattern = [ Class "." ] method [ "(" [ Parameter { ";" Parameter } ] ")" ] .
+  Parameter = Class | "int" | "long" | "float" | "double" | "short" | "char" | "boolean" .
+  Class = { package "." } class .
+ 
+Glob pattern matching (*, ?) is allowed in all parts of the source pattern.
+
+Examples of method filters:
+--------- 
+  visit(Argument;BlockScope)  
+  
+  Matches all methods named "visit", with the first parameter of
+  type "Argument", and the second parameter of type "BlockScope".
+  The packages of the parameter types are irrelevant.
+---------
+  arraycopy(Object;;;;)
+ 
+  Matches all methods named "arraycopy", with the first parameter
+  of type "Object", and four more parameters of any type. The
+  packages of the parameter types are irrelevant.
+---------    
+  org.graalvm.compiler.core.graph.PostOrderNodeIterator.*
+ 
+  Matches all methods in the class "org.graalvm.compiler.core.graph.PostOrderNodeIterator".
+---------    
+  *
+ 
+  Matches all methods in all classes
+---------
+  org.graalvm.compiler.core.graph.*.visit
+ 
+  Matches all methods named "visit" in classes in the package
+  "org.graalvm.compiler.core.graph".
+---------
+  arraycopy,toString
+ 
+  Matches all methods named "arraycopy" or "toString", meaning that ',' acts as an or operator.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/doc-files/MetricsFileHelp.txt	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,11 @@
+File to which metrics are dumped per compilation.
+A CSV format is used if the file ends with .csv otherwise a more
+human readable format is used. The fields in the CSV format are:
+           compilable - method being compiled
+  compilable_identity - identity hash code of compilable
+       compilation_nr - where this compilation lies in the ordered
+                        sequence of all compilations identified by
+                        compilable_identity
+       compilation_id - runtime issued identifier for the compilation
+          metric_name - name of metric
+         metric_value - value of metric
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java	Thu Aug 24 21:06:33 2017 +0000
@@ -931,7 +931,7 @@
     }
 
     /**
-     * @returns true if the node has no inputs and no successors
+     * @return true if the node has no inputs and no successors
      */
     public boolean isLeafNode() {
         return isLeafNode;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -40,20 +40,12 @@
 import org.graalvm.compiler.test.SubprocessUtil;
 import org.graalvm.compiler.test.SubprocessUtil.Subprocess;
 import org.junit.Assert;
-import org.junit.Assume;
 import org.junit.Test;
 
 /**
  * Tests support for dumping graphs and other info useful for debugging a compiler crash.
  */
 public class CompilationWrapperTest extends GraalCompilerTest {
-    public CompilationWrapperTest() {
-        try {
-            Class.forName("java.lang.management.ManagementFactory");
-        } catch (ClassNotFoundException ex) {
-            Assume.assumeNoException("skip this test if there is no java.management JDK9 module around", ex);
-        }
-    }
 
     /**
      * Tests compilation requested by the VM.
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ObjectCloneTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ObjectCloneTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,6 +25,7 @@
 import java.util.ArrayList;
 
 import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import org.junit.Test;
 
 /**
@@ -84,4 +85,20 @@
         }
         test("cloneList", list);
     }
+
+    @Override
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        return super.editGraphBuilderConfiguration(conf.withNodeSourcePosition(true));
+    }
+
+    static final int[] ARRAY = new int[]{1, 2, 4, 3};
+
+    public static int[] cloneConstantArray() {
+        return ARRAY.clone();
+    }
+
+    @Test
+    public void testCloneConstantArray() {
+        test("cloneConstantArray");
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java	Thu Aug 24 21:06:33 2017 +0000
@@ -157,8 +157,8 @@
     /**
      * Selects and instantiates a {@link CompilerConfigurationFactory}. The selection algorithm is
      * as follows: if {@code name} is non-null, then select the factory with the same name else if
-     * {@link Options#CompilerConfiguration}{@code .getValue()} is non-null then select the factory
-     * whose name matches the value else select the factory with the highest
+     * {@code Options.CompilerConfiguration.getValue()} is non-null then select the factory whose
+     * name matches the value else select the factory with the highest
      * {@link #autoSelectionPriority} value.
      *
      * @param name the name of the compiler configuration to select (optional)
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java	Thu Aug 24 21:06:33 2017 +0000
@@ -23,7 +23,6 @@
 package org.graalvm.compiler.hotspot;
 
 import java.util.Formatter;
-import java.util.Objects;
 
 /**
  * Mechanism for checking that the current Java runtime environment supports the minimum JVMCI API
@@ -40,10 +39,6 @@
     private static final int JVMCI8_MIN_MAJOR_VERSION = 0;
     private static final int JVMCI8_MIN_MINOR_VERSION = 29;
 
-    // MAX_VALUE indicates that no current EA version is compatible with Graal.
-    // Note: Keep README.md in sync with the EA version support checked here.
-    private static final int JVMCI9_MIN_EA_BUILD = 176;
-
     private static void failVersionCheck(boolean exit, String reason, Object... args) {
         Formatter errorMessage = new Formatter().format(reason, args);
         String javaHome = System.getProperty("java.home");
@@ -55,7 +50,7 @@
         if (System.getProperty("java.specification.version").compareTo("1.9") < 0) {
             errorMessage.format("Download the latest JVMCI JDK 8 from http://www.oracle.com/technetwork/oracle-labs/program-languages/downloads/index.html");
         } else {
-            errorMessage.format("Download the latest JDK 9 EA from https://jdk9.java.net/download/");
+            errorMessage.format("Download the latest JDK 9 build from https://jdk9.java.net/download/");
         }
         String value = System.getenv("JVMCI_VERSION_CHECK");
         if ("warn".equals(value)) {
@@ -119,34 +114,11 @@
                 // Allow local builds
                 return;
             }
-            // http://openjdk.java.net/jeps/223
-            if (vmVersion.startsWith("9+")) {
-                int start = "9+".length();
-                int end = start;
-                end = start;
-                while (end < vmVersion.length() && Character.isDigit(vmVersion.charAt(end))) {
-                    end++;
-                }
-                int build;
-                try {
-                    build = Integer.parseInt(vmVersion.substring(start, end));
-                } catch (NumberFormatException e) {
-                    failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
-                                    "Cannot read JDK9 EA build number from java.vm.version property: %s.%n", vmVersion);
-                    return;
-                }
-                if (build >= JVMCI9_MIN_EA_BUILD) {
-                    return;
-                }
-                if (Objects.equals(JVMCI9_MIN_EA_BUILD, Integer.MAX_VALUE)) {
-                    failVersionCheck(exitOnFailure, "This version of Graal is not compatible with any JDK 9 Early Access build.%n");
-                } else {
-                    failVersionCheck(exitOnFailure, "The VM is an insufficiently recent EA JDK9 build for Graal: %d < %d.%n", build, JVMCI9_MIN_EA_BUILD);
-                }
+            if (vmVersion.startsWith("9-ea")) {
+                failVersionCheck(exitOnFailure, "This version of Graal is not compatible with JDK 9 Early Access builds.%n");
                 return;
             } else {
-                // Graal will be compatible with all JDK versions as of 9 GA
-                // until a JVMCI API change is made in a 9u or later release.
+                // Graal is compatible with all JDK versions as of 9 GA.
             }
         }
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java	Thu Aug 24 21:06:33 2017 +0000
@@ -41,7 +41,6 @@
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.debug.TTY;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
-import org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions;
 import org.graalvm.compiler.nodes.debug.DynamicCounterNode;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
@@ -69,20 +68,8 @@
  * Counters will be displayed as a rate (per second) if their group name starts with "~", otherwise
  * they will be displayed as a total number.
  *
- * <h1>Example</h1> In order to create statistics about allocations within the DaCapo pmd benchmark
- * the following steps are necessary:
- * <ul>
- * <li>Set {@code -XX:JVMCICounterSize=value}. The actual required value depends on the granularity
- * of the profiling, 10000 should be enough for most cases.</li>
- * <li>Also: {@code -XX:+/-JVMCICountersExcludeCompiler} specifies whether the numbers generated by
- * compiler threads should be excluded (default: true).</li>
- * <li>Start the DaCapo pmd benchmark with
- * {@code "-Dgraal.BenchmarkDynamicCounters=err, starting ====, PASSED in "} and
- * {@code -Dgraal.ProfileAllocations=true}.</li>
- * <li>The numbers will only include allocation from compiled code!</li>
- * <li>The counters can be further configured by modifying the
- * {@link HotspotSnippetsOptions#ProfileAllocationsContext} flag..</li>
- * </ul>
+ * See <a href="BenchmarkDynamicCountersHelp.txt">here</a> for a detailed example of how to use
+ * benchmark counters.
  */
 public class BenchmarkCounters {
 
@@ -94,11 +81,7 @@
         @Option(help = "Turn on the benchmark counters, and displays the results every n milliseconds", type = OptionType.Debug)
         public static final OptionKey<Integer> TimedDynamicCounters = new OptionKey<>(-1);
 
-        @Option(help = "Turn on the benchmark counters, and listen for specific patterns on System.out/System.err:%n" +
-                       "Format: (err|out),start pattern,end pattern (~ matches multiple digits)%n" +
-                       "Examples:%n" +
-                       "  dacapo = 'err, starting =====, PASSED in'%n" +
-                       "  specjvm2008 = 'out,Iteration ~ (~s) begins:,Iteration ~ (~s) ends:'", type = OptionType.Debug)
+        @Option(help = "file:doc-files/BenchmarkDynamicCountersHelp.txt", type = OptionType.Debug)
         public static final OptionKey<String> BenchmarkDynamicCounters = new OptionKey<>(null);
         @Option(help = "Use grouping separators for number printing", type = OptionType.Debug)
         public static final OptionKey<Boolean> DynamicCountersPrintGroupSeparator = new OptionKey<>(true);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/doc-files/BenchmarkDynamicCountersHelp.txt	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,24 @@
+Turn on the benchmark counters, and listen for specific patterns on System.out/System.err.
+The format of this option is:
+
+  (err|out),start pattern,end pattern
+  
+You can use "~" to match 1 or more digits.
+Examples:
+
+  err, starting =====, PASSED in
+  out,Iteration ~ (~s) begins:,Iteration ~ (~s) ends:
+  
+The first pattern matches DaCapo output and the second matches SPECjvm2008 output.
+
+As a more detailed example, here are the options to use for getting statistics
+about allocations within the DaCapo pmd benchmark:
+
+  -XX:JVMCICounterSize=<value> -XX:-JVMCICountersExcludeCompiler \
+  -Dgraal.BenchmarkDynamicCounters="err, starting ====, PASSED in " \
+  -Dgraal.ProfileAllocations=true
+  
+The JVMCICounterSize value depends on the granularity of the profiling -
+10000 should be sufficient. Omit JVMCICountersExcludeCompiler to exclude
+counting allocations on the compiler threads.
+The counters can be further configured by the ProfileAllocationsContext option.
\ No newline at end of file
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,6 +25,7 @@
 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
 import static org.graalvm.compiler.core.common.GraalOptions.VerifyPhases;
+import static org.graalvm.compiler.core.phases.HighTier.Options.Inline;
 
 import java.util.ListIterator;
 
@@ -98,10 +99,12 @@
                 midTierLowering.add(new ReplaceConstantNodesPhase());
 
                 // Replace inlining policy
-                ListIterator<BasePhase<? super HighTierContext>> iter = ret.getHighTier().findPhase(InliningPhase.class);
-                InliningPhase inlining = (InliningPhase) iter.previous();
-                CanonicalizerPhase canonicalizer = inlining.getCanonicalizer();
-                iter.set(new InliningPhase(new AOTInliningPolicy(null), canonicalizer));
+                if (Inline.getValue(options)) {
+                    ListIterator<BasePhase<? super HighTierContext>> iter = ret.getHighTier().findPhase(InliningPhase.class);
+                    InliningPhase inlining = (InliningPhase) iter.previous();
+                    CanonicalizerPhase canonicalizer = inlining.getCanonicalizer();
+                    iter.set(new InliningPhase(new AOTInliningPolicy(null), canonicalizer));
+                }
             }
         }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotspotSnippetsOptions.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotspotSnippetsOptions.java	Thu Aug 24 21:06:33 2017 +0000
@@ -51,7 +51,7 @@
     @Option(help = "Enable profiling of allocation sites.", type = OptionType.Debug)
     public static final OptionKey<Boolean> ProfileAllocations = new OptionKey<>(false);
 
-    @Option(help = "Control the naming of the counters when using ProfileAllocations.", type = OptionType.Debug)
+    @Option(help = "file:doc-files/ProfileAllocationsContextHelp.txt", type = OptionType.Debug)
     public static final EnumOptionKey<ProfileContext> ProfileAllocationsContext = new EnumOptionKey<>(ProfileContext.AllocatingMethod);
 
     @Option(help = "Enable profiling of monitor operations.", type = OptionType.Debug)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/doc-files/ProfileAllocationsContextHelp.txt	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,8 @@
+Control the naming and granularity of the counters when using ProfileAllocations.
+The accepted values are:
+        AllocatingMethod - a counter per method
+         InstanceOrArray - one counter for all instance allocations and
+                           one counter for all array allocations 
+           AllocatedType - one counter per allocated type
+  AllocatedTypesInMethod - one counter per allocated type, per method
+ 
\ No newline at end of file
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java	Thu Aug 24 21:06:33 2017 +0000
@@ -36,6 +36,8 @@
 import org.graalvm.compiler.phases.graph.ReentrantNodeIterator;
 import org.graalvm.util.EconomicMap;
 
+import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilities;
+
 public final class ComputeLoopFrequenciesClosure extends ReentrantNodeIterator.NodeIteratorClosure<Double> {
 
     private static final ComputeLoopFrequenciesClosure INSTANCE = new ComputeLoopFrequenciesClosure();
@@ -75,32 +77,18 @@
         for (double d : exitStates.getValues()) {
             exitProbability += d;
         }
-        exitProbability = Math.min(1D, exitProbability);
-        if (exitProbability < ControlFlowGraph.MIN_PROBABILITY) {
-            exitProbability = ControlFlowGraph.MIN_PROBABILITY;
-        }
-        assert exitProbability <= 1D && exitProbability >= 0D;
-        double loopFrequency = 1D / exitProbability;
+        exitProbability = Math.min(1.0, exitProbability);
+        exitProbability = Math.max(ControlFlowGraph.MIN_PROBABILITY, exitProbability);
+        double loopFrequency = 1.0 / exitProbability;
         loop.setLoopFrequency(loopFrequency);
 
         double adjustmentFactor = initialState * loopFrequency;
-        exitStates.replaceAll((exitNode, probability) -> multiplySaturate(probability, adjustmentFactor));
+        exitStates.replaceAll((exitNode, probability) -> multiplyProbabilities(probability, adjustmentFactor));
 
         return exitStates;
     }
 
     /**
-     * Multiplies a and b and saturates the result to {@link ControlFlowGraph#MAX_PROBABILITY}.
-     */
-    public static double multiplySaturate(double a, double b) {
-        double r = a * b;
-        if (r > ControlFlowGraph.MAX_PROBABILITY) {
-            return ControlFlowGraph.MAX_PROBABILITY;
-        }
-        return r;
-    }
-
-    /**
      * Computes the frequencies of all loops in the given graph. This is done by performing a
      * reverse postorder iteration and computing the probability of all fixed nodes. The combined
      * probability of all exits of a loop can be used to compute the loop's expected frequency.
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayEqualsOp.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayEqualsOp.java	Thu Aug 24 21:06:33 2017 +0000
@@ -68,6 +68,8 @@
 
     public AArch64ArrayEqualsOp(LIRGeneratorTool tool, JavaKind kind, Value result, Value array1, Value array2, Value length) {
         super(TYPE);
+
+        assert !kind.isNumericFloat() : "Float arrays comparison (bitwise_equal || both_NaN) isn't supported";
         this.kind = kind;
 
         Class<?> arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java	Thu Aug 24 21:06:33 2017 +0000
@@ -33,6 +33,8 @@
 import org.graalvm.compiler.asm.amd64.AMD64Address;
 import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
 import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.lir.LIRInstructionClass;
@@ -69,6 +71,10 @@
     @Temp({REG}) protected Value temp2;
     @Temp({REG}) protected Value temp3;
     @Temp({REG}) protected Value temp4;
+
+    @Temp({REG, ILLEGAL}) protected Value temp5;
+    @Temp({REG, ILLEGAL}) protected Value tempXMM;
+
     @Temp({REG, ILLEGAL}) protected Value vectorTemp1;
     @Temp({REG, ILLEGAL}) protected Value vectorTemp2;
 
@@ -91,6 +97,15 @@
         this.temp3 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind()));
         this.temp4 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind()));
 
+        this.temp5 = kind.isNumericFloat() ? tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())) : Value.ILLEGAL;
+        if (kind == JavaKind.Float) {
+            this.tempXMM = tool.newVariable(LIRKind.value(AMD64Kind.SINGLE));
+        } else if (kind == JavaKind.Double) {
+            this.tempXMM = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+        } else {
+            this.tempXMM = Value.ILLEGAL;
+        }
+
         // We only need the vector temporaries if we generate SSE code.
         if (supportsSSE41(tool.target())) {
             this.vectorTemp1 = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
@@ -170,10 +185,14 @@
         Label loop = new Label();
         Label compareTail = new Label();
 
+        boolean requiresNaNCheck = kind.isNumericFloat();
+        Label loopCheck = new Label();
+        Label nanCheck = new Label();
+
         // Compare 16-byte vectors
         masm.andl(result, SSE4_1_VECTOR_SIZE - 1); // tail count (in bytes)
         masm.andl(length, ~(SSE4_1_VECTOR_SIZE - 1)); // vector count (in bytes)
-        masm.jccb(ConditionFlag.Zero, compareTail);
+        masm.jcc(ConditionFlag.Zero, compareTail);
 
         masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0));
         masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0));
@@ -186,13 +205,24 @@
         masm.movdqu(vector2, new AMD64Address(array2, length, Scale.Times1, 0));
         masm.pxor(vector1, vector2);
         masm.ptest(vector1, vector1);
-        masm.jcc(ConditionFlag.NotZero, falseLabel);
+        masm.jcc(ConditionFlag.NotZero, requiresNaNCheck ? nanCheck : falseLabel);
+
+        masm.bind(loopCheck);
         masm.addq(length, SSE4_1_VECTOR_SIZE);
         masm.jcc(ConditionFlag.NotZero, loop);
 
         masm.testl(result, result);
         masm.jcc(ConditionFlag.Zero, trueLabel);
 
+        if (requiresNaNCheck) {
+            Label unalignedCheck = new Label();
+            masm.jmpb(unalignedCheck);
+            masm.bind(nanCheck);
+            emitFloatCompareWithinRange(crb, masm, array1, array2, length, 0, falseLabel, SSE4_1_VECTOR_SIZE);
+            masm.jmpb(loopCheck);
+            masm.bind(unalignedCheck);
+        }
+
         /*
          * Compare the remaining bytes with an unaligned memory load aligned to the end of the
          * array.
@@ -201,7 +231,12 @@
         masm.movdqu(vector2, new AMD64Address(array2, result, Scale.Times1, -SSE4_1_VECTOR_SIZE));
         masm.pxor(vector1, vector2);
         masm.ptest(vector1, vector1);
-        masm.jcc(ConditionFlag.NotZero, falseLabel);
+        if (requiresNaNCheck) {
+            masm.jcc(ConditionFlag.Zero, trueLabel);
+            emitFloatCompareWithinRange(crb, masm, array1, array2, result, -SSE4_1_VECTOR_SIZE, falseLabel, SSE4_1_VECTOR_SIZE);
+        } else {
+            masm.jcc(ConditionFlag.NotZero, falseLabel);
+        }
         masm.jmp(trueLabel);
 
         masm.bind(compareTail);
@@ -233,10 +268,14 @@
         Label loop = new Label();
         Label compareTail = new Label();
 
+        boolean requiresNaNCheck = kind.isNumericFloat();
+        Label loopCheck = new Label();
+        Label nanCheck = new Label();
+
         // Compare 16-byte vectors
         masm.andl(result, AVX_VECTOR_SIZE - 1); // tail count (in bytes)
         masm.andl(length, ~(AVX_VECTOR_SIZE - 1)); // vector count (in bytes)
-        masm.jccb(ConditionFlag.Zero, compareTail);
+        masm.jcc(ConditionFlag.Zero, compareTail);
 
         masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0));
         masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0));
@@ -249,13 +288,24 @@
         masm.vmovdqu(vector2, new AMD64Address(array2, length, Scale.Times1, 0));
         masm.vpxor(vector1, vector1, vector2);
         masm.vptest(vector1, vector1);
-        masm.jcc(ConditionFlag.NotZero, falseLabel);
+        masm.jcc(ConditionFlag.NotZero, requiresNaNCheck ? nanCheck : falseLabel);
+
+        masm.bind(loopCheck);
         masm.addq(length, AVX_VECTOR_SIZE);
         masm.jcc(ConditionFlag.NotZero, loop);
 
         masm.testl(result, result);
         masm.jcc(ConditionFlag.Zero, trueLabel);
 
+        if (requiresNaNCheck) {
+            Label unalignedCheck = new Label();
+            masm.jmpb(unalignedCheck);
+            masm.bind(nanCheck);
+            emitFloatCompareWithinRange(crb, masm, array1, array2, length, 0, falseLabel, AVX_VECTOR_SIZE);
+            masm.jmpb(loopCheck);
+            masm.bind(unalignedCheck);
+        }
+
         /*
          * Compare the remaining bytes with an unaligned memory load aligned to the end of the
          * array.
@@ -264,7 +314,12 @@
         masm.vmovdqu(vector2, new AMD64Address(array2, result, Scale.Times1, -AVX_VECTOR_SIZE));
         masm.vpxor(vector1, vector1, vector2);
         masm.vptest(vector1, vector1);
-        masm.jcc(ConditionFlag.NotZero, falseLabel);
+        if (requiresNaNCheck) {
+            masm.jcc(ConditionFlag.Zero, trueLabel);
+            emitFloatCompareWithinRange(crb, masm, array1, array2, result, -AVX_VECTOR_SIZE, falseLabel, AVX_VECTOR_SIZE);
+        } else {
+            masm.jcc(ConditionFlag.NotZero, falseLabel);
+        }
         masm.jmp(trueLabel);
 
         masm.bind(compareTail);
@@ -283,11 +338,15 @@
         Label loop = new Label();
         Label compareTail = new Label();
 
+        boolean requiresNaNCheck = kind.isNumericFloat();
+        Label loopCheck = new Label();
+        Label nanCheck = new Label();
+
         Register temp = asRegister(temp4);
 
         masm.andl(result, VECTOR_SIZE - 1); // tail count (in bytes)
         masm.andl(length, ~(VECTOR_SIZE - 1));  // vector count (in bytes)
-        masm.jccb(ConditionFlag.Zero, compareTail);
+        masm.jcc(ConditionFlag.Zero, compareTail);
 
         masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0));
         masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0));
@@ -298,12 +357,27 @@
         masm.bind(loop);
         masm.movq(temp, new AMD64Address(array1, length, Scale.Times1, 0));
         masm.cmpq(temp, new AMD64Address(array2, length, Scale.Times1, 0));
-        masm.jccb(ConditionFlag.NotEqual, falseLabel);
+        masm.jcc(ConditionFlag.NotEqual, requiresNaNCheck ? nanCheck : falseLabel);
+
+        masm.bind(loopCheck);
         masm.addq(length, VECTOR_SIZE);
         masm.jccb(ConditionFlag.NotZero, loop);
 
         masm.testl(result, result);
-        masm.jccb(ConditionFlag.Zero, trueLabel);
+        masm.jcc(ConditionFlag.Zero, trueLabel);
+
+        if (requiresNaNCheck) {
+            // NaN check is slow path and hence placed outside of the main loop.
+            Label unalignedCheck = new Label();
+            masm.jmpb(unalignedCheck);
+            masm.bind(nanCheck);
+            // At most two iterations, unroll in the emitted code.
+            for (int offset = 0; offset < VECTOR_SIZE; offset += kind.getByteCount()) {
+                emitFloatCompare(masm, array1, array2, length, offset, falseLabel, kind.getByteCount() == VECTOR_SIZE);
+            }
+            masm.jmpb(loopCheck);
+            masm.bind(unalignedCheck);
+        }
 
         /*
          * Compare the remaining bytes with an unaligned memory load aligned to the end of the
@@ -311,7 +385,15 @@
          */
         masm.movq(temp, new AMD64Address(array1, result, Scale.Times1, -VECTOR_SIZE));
         masm.cmpq(temp, new AMD64Address(array2, result, Scale.Times1, -VECTOR_SIZE));
-        masm.jccb(ConditionFlag.NotEqual, falseLabel);
+        if (requiresNaNCheck) {
+            masm.jcc(ConditionFlag.Equal, trueLabel);
+            // At most two iterations, unroll in the emitted code.
+            for (int offset = 0; offset < VECTOR_SIZE; offset += kind.getByteCount()) {
+                emitFloatCompare(masm, array1, array2, result, -VECTOR_SIZE + offset, falseLabel, kind.getByteCount() == VECTOR_SIZE);
+            }
+        } else {
+            masm.jccb(ConditionFlag.NotEqual, falseLabel);
+        }
         masm.jmpb(trueLabel);
 
         masm.bind(compareTail);
@@ -333,8 +415,13 @@
             masm.jccb(ConditionFlag.Zero, compare2Bytes);
             masm.movl(temp, new AMD64Address(array1, 0));
             masm.cmpl(temp, new AMD64Address(array2, 0));
-            masm.jccb(ConditionFlag.NotEqual, falseLabel);
-
+            if (kind == JavaKind.Float) {
+                masm.jccb(ConditionFlag.Equal, trueLabel);
+                emitFloatCompare(masm, array1, array2, Register.None, 0, falseLabel, true);
+                masm.jmpb(trueLabel);
+            } else {
+                masm.jccb(ConditionFlag.NotEqual, falseLabel);
+            }
             if (kind.getByteCount() <= 2) {
                 // Move array pointers forward.
                 masm.leaq(array1, new AMD64Address(array1, 4));
@@ -372,6 +459,71 @@
         }
     }
 
+    /**
+     * Emits code to fall through if {@code src} is NaN, otherwise jump to {@code branchOrdered}.
+     */
+    private void emitNaNCheck(AMD64MacroAssembler masm, AMD64Address src, Label branchIfNonNaN) {
+        assert kind.isNumericFloat();
+        Register tempXMMReg = asRegister(tempXMM);
+        if (kind == JavaKind.Float) {
+            masm.movflt(tempXMMReg, src);
+        } else {
+            masm.movdbl(tempXMMReg, src);
+        }
+        SSEOp.UCOMIS.emit(masm, kind == JavaKind.Float ? OperandSize.PS : OperandSize.PD, tempXMMReg, tempXMMReg);
+        masm.jcc(ConditionFlag.NoParity, branchIfNonNaN);
+    }
+
+    /**
+     * Emits code to compare if two floats are bitwise equal or both NaN.
+     */
+    private void emitFloatCompare(AMD64MacroAssembler masm, Register base1, Register base2, Register index, int offset, Label falseLabel, boolean skipBitwiseCompare) {
+        AMD64Address address1 = new AMD64Address(base1, index, Scale.Times1, offset);
+        AMD64Address address2 = new AMD64Address(base2, index, Scale.Times1, offset);
+
+        Label bitwiseEqual = new Label();
+
+        if (!skipBitwiseCompare) {
+            // Bitwise compare
+            Register temp = asRegister(temp4);
+
+            if (kind == JavaKind.Float) {
+                masm.movl(temp, address1);
+                masm.cmpl(temp, address2);
+            } else {
+                masm.movq(temp, address1);
+                masm.cmpq(temp, address2);
+            }
+            masm.jccb(ConditionFlag.Equal, bitwiseEqual);
+        }
+
+        emitNaNCheck(masm, address1, falseLabel);
+        emitNaNCheck(masm, address2, falseLabel);
+
+        masm.bind(bitwiseEqual);
+    }
+
+    /**
+     * Emits code to compare float equality within a range.
+     */
+    private void emitFloatCompareWithinRange(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register base1, Register base2, Register index, int offset, Label falseLabel, int range) {
+        assert kind.isNumericFloat();
+        Label loop = new Label();
+        Register i = asRegister(temp5);
+
+        masm.movq(i, range);
+        masm.negq(i);
+        // Align the main loop
+        masm.align(crb.target.wordSize * 2);
+        masm.bind(loop);
+        emitFloatCompare(masm, base1, base2, index, offset, falseLabel, kind.getByteCount() == range);
+        masm.addq(index, kind.getByteCount());
+        masm.addq(i, kind.getByteCount());
+        masm.jccb(ConditionFlag.NotZero, loop);
+        // Floats within the range are equal, revert change to the register index
+        masm.subq(index, range);
+    }
+
     private static final Unsafe UNSAFE = initUnsafe();
 
     private static Unsafe initUnsafe() {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java	Thu Aug 24 21:06:33 2017 +0000
@@ -78,6 +78,8 @@
 
     public SPARCArrayEqualsOp(LIRGeneratorTool tool, JavaKind kind, AllocatableValue result, AllocatableValue array1, AllocatableValue array2, AllocatableValue length) {
         super(TYPE, SIZE);
+
+        assert !kind.isNumericFloat() : "Float arrays comparison (bitwise_equal || both_NaN) isn't supported";
         this.kind = kind;
 
         Class<?> arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGenerator.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGenerator.java	Thu Aug 24 21:06:33 2017 +0000
@@ -59,7 +59,7 @@
         if (isNumericInteger(a.getPlatformKind())) {
             LIRKind aKind = a.getValueKind(LIRKind.class);
             LIRKind bKind = b.getValueKind(LIRKind.class);
-            assert a.getPlatformKind() == b.getPlatformKind();
+            assert a.getPlatformKind() == b.getPlatformKind() : a.getPlatformKind() + " vs. " + b.getPlatformKind();
 
             if (aKind.isUnknownReference()) {
                 resultKind = aKind;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java	Thu Aug 24 21:06:33 2017 +0000
@@ -51,6 +51,8 @@
                 try (Graph.NodeEventScope nes = graph.trackNodeEvents(listener)) {
                     LoopsData dataCounted = new LoopsData(graph);
                     dataCounted.detectedCountedLoops();
+                    Graph.Mark mark = graph.getMark();
+                    boolean prePostInserted = false;
                     for (LoopEx loop : dataCounted.countedLoops()) {
                         if (!LoopTransformations.isUnrollableLoop(loop)) {
                             continue;
@@ -59,9 +61,10 @@
                             if (loop.loopBegin().isSimpleLoop()) {
                                 // First perform the pre/post transformation and do the partial
                                 // unroll when we come around again.
-                                LoopTransformations.insertPrePostLoops(loop, graph);
+                                LoopTransformations.insertPrePostLoops(loop);
+                                prePostInserted = true;
                             } else {
-                                LoopTransformations.partialUnroll(loop, graph);
+                                LoopTransformations.partialUnroll(loop);
                             }
                             changed = true;
                         }
@@ -72,11 +75,25 @@
                         canonicalizer.applyIncremental(graph, context, listener.getNodes());
                         listener.getNodes().clear();
                     }
+
+                    assert !prePostInserted || checkCounted(graph, mark);
                 }
             }
         }
     }
 
+    private static boolean checkCounted(StructuredGraph graph, Graph.Mark mark) {
+        LoopsData dataCounted;
+        dataCounted = new LoopsData(graph);
+        dataCounted.detectedCountedLoops();
+        for (LoopEx anyLoop : dataCounted.loops()) {
+            if (graph.isNew(mark, anyLoop.loopBegin())) {
+                assert anyLoop.isCounted() : "pre/post transformation loses counted loop " + anyLoop.loopBegin();
+            }
+        }
+        return true;
+    }
+
     @Override
     public boolean checkContract() {
         return false;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java	Thu Aug 24 21:06:33 2017 +0000
@@ -31,6 +31,7 @@
 import java.util.List;
 
 import org.graalvm.compiler.core.common.RetryableBailoutException;
+import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Graph.Mark;
@@ -145,9 +146,9 @@
         // TODO (gd) probabilities need some amount of fixup.. (probably also in other transforms)
     }
 
-    public static void partialUnroll(LoopEx loop, StructuredGraph graph) {
+    public static void partialUnroll(LoopEx loop) {
         assert loop.loopBegin().isMainLoop();
-        graph.getDebug().log("LoopPartialUnroll %s", loop);
+        loop.loopBegin().graph().getDebug().log("LoopPartialUnroll %s", loop);
 
         LoopFragmentInside newSegment = loop.inside().duplicate();
         newSegment.insertWithinAfter(loop);
@@ -222,72 +223,73 @@
     // The pre loop is constrained to one iteration for now and will likely
     // be updated to produce vector alignment if applicable.
 
-    public static void insertPrePostLoops(LoopEx loop, StructuredGraph graph) {
+    public static LoopBeginNode insertPrePostLoops(LoopEx loop) {
+        StructuredGraph graph = loop.loopBegin().graph();
         graph.getDebug().log("LoopTransformations.insertPrePostLoops %s", loop);
         LoopFragmentWhole preLoop = loop.whole();
         CountedLoopInfo preCounted = loop.counted();
         IfNode preLimit = preCounted.getLimitTest();
-        if (preLimit != null) {
-            LoopBeginNode preLoopBegin = loop.loopBegin();
-            InductionVariable preIv = preCounted.getCounter();
-            LoopExitNode preLoopExitNode = preLoopBegin.getSingleLoopExit();
-            FixedNode continuationNode = preLoopExitNode.next();
+        assert preLimit != null;
+        LoopBeginNode preLoopBegin = loop.loopBegin();
+        InductionVariable preIv = preCounted.getCounter();
+        LoopExitNode preLoopExitNode = preLoopBegin.getSingleLoopExit();
+        FixedNode continuationNode = preLoopExitNode.next();
 
-            // Each duplication is inserted after the original, ergo create the post loop first
-            LoopFragmentWhole mainLoop = preLoop.duplicate();
-            LoopFragmentWhole postLoop = preLoop.duplicate();
-            preLoopBegin.incrementSplits();
-            preLoopBegin.incrementSplits();
-            preLoopBegin.setPreLoop();
-            graph.getDebug().dump(DebugContext.VERBOSE_LEVEL, graph, "After duplication");
-            LoopBeginNode mainLoopBegin = mainLoop.getDuplicatedNode(preLoopBegin);
-            mainLoopBegin.setMainLoop();
-            LoopBeginNode postLoopBegin = postLoop.getDuplicatedNode(preLoopBegin);
-            postLoopBegin.setPostLoop();
+        // Each duplication is inserted after the original, ergo create the post loop first
+        LoopFragmentWhole mainLoop = preLoop.duplicate();
+        LoopFragmentWhole postLoop = preLoop.duplicate();
+        preLoopBegin.incrementSplits();
+        preLoopBegin.incrementSplits();
+        preLoopBegin.setPreLoop();
+        graph.getDebug().dump(DebugContext.VERBOSE_LEVEL, graph, "After duplication");
+        LoopBeginNode mainLoopBegin = mainLoop.getDuplicatedNode(preLoopBegin);
+        mainLoopBegin.setMainLoop();
+        LoopBeginNode postLoopBegin = postLoop.getDuplicatedNode(preLoopBegin);
+        postLoopBegin.setPostLoop();
 
-            EndNode postEndNode = getBlockEndAfterLoopExit(postLoopBegin);
-            AbstractMergeNode postMergeNode = postEndNode.merge();
-            LoopExitNode postLoopExitNode = postLoopBegin.getSingleLoopExit();
+        EndNode postEndNode = getBlockEndAfterLoopExit(postLoopBegin);
+        AbstractMergeNode postMergeNode = postEndNode.merge();
+        LoopExitNode postLoopExitNode = postLoopBegin.getSingleLoopExit();
 
-            // Update the main loop phi initialization to carry from the pre loop
-            for (PhiNode prePhiNode : preLoopBegin.phis()) {
-                PhiNode mainPhiNode = mainLoop.getDuplicatedNode(prePhiNode);
-                mainPhiNode.setValueAt(0, prePhiNode);
-            }
+        // Update the main loop phi initialization to carry from the pre loop
+        for (PhiNode prePhiNode : preLoopBegin.phis()) {
+            PhiNode mainPhiNode = mainLoop.getDuplicatedNode(prePhiNode);
+            mainPhiNode.setValueAt(0, prePhiNode);
+        }
 
-            EndNode mainEndNode = getBlockEndAfterLoopExit(mainLoopBegin);
-            AbstractMergeNode mainMergeNode = mainEndNode.merge();
-            AbstractEndNode postEntryNode = postLoopBegin.forwardEnd();
+        EndNode mainEndNode = getBlockEndAfterLoopExit(mainLoopBegin);
+        AbstractMergeNode mainMergeNode = mainEndNode.merge();
+        AbstractEndNode postEntryNode = postLoopBegin.forwardEnd();
 
-            // In the case of no Bounds tests, we just flow right into the main loop
-            AbstractBeginNode mainLandingNode = BeginNode.begin(postEntryNode);
-            LoopExitNode mainLoopExitNode = mainLoopBegin.getSingleLoopExit();
-            mainLoopExitNode.setNext(mainLandingNode);
-            preLoopExitNode.setNext(mainLoopBegin.forwardEnd());
+        // In the case of no Bounds tests, we just flow right into the main loop
+        AbstractBeginNode mainLandingNode = BeginNode.begin(postEntryNode);
+        LoopExitNode mainLoopExitNode = mainLoopBegin.getSingleLoopExit();
+        mainLoopExitNode.setNext(mainLandingNode);
+        preLoopExitNode.setNext(mainLoopBegin.forwardEnd());
 
-            // Add and update any phi edges as per merge usage as needed and update usages
-            processPreLoopPhis(loop, mainLoop, postLoop);
-            continuationNode.predecessor().clearSuccessors();
-            postLoopExitNode.setNext(continuationNode);
-            cleanupMerge(postMergeNode, postLoopExitNode);
-            cleanupMerge(mainMergeNode, mainLandingNode);
+        // Add and update any phi edges as per merge usage as needed and update usages
+        processPreLoopPhis(loop, mainLoop, postLoop);
+        continuationNode.predecessor().clearSuccessors();
+        postLoopExitNode.setNext(continuationNode);
+        cleanupMerge(postMergeNode, postLoopExitNode);
+        cleanupMerge(mainMergeNode, mainLandingNode);
 
-            // Change the preLoop to execute one iteration for now
-            updateMainLoopLimit(preLimit, preIv, mainLoop);
-            updatePreLoopLimit(preLimit, preIv, preCounted);
-            preLoopBegin.setLoopFrequency(1);
-            mainLoopBegin.setLoopFrequency(Math.max(0.0, mainLoopBegin.loopFrequency() - 2));
-            postLoopBegin.setLoopFrequency(Math.max(0.0, postLoopBegin.loopFrequency() - 1));
+        // Change the preLoop to execute one iteration for now
+        updateMainLoopLimit(preLimit, preIv, mainLoop);
+        updatePreLoopLimit(preLimit, preIv, preCounted);
+        preLoopBegin.setLoopFrequency(1);
+        mainLoopBegin.setLoopFrequency(Math.max(0.0, mainLoopBegin.loopFrequency() - 2));
+        postLoopBegin.setLoopFrequency(Math.max(0.0, postLoopBegin.loopFrequency() - 1));
 
-            // The pre and post loops don't require safepoints at all
-            for (SafepointNode safepoint : preLoop.nodes().filter(SafepointNode.class)) {
-                graph.removeFixed(safepoint);
-            }
-            for (SafepointNode safepoint : postLoop.nodes().filter(SafepointNode.class)) {
-                graph.removeFixed(safepoint);
-            }
+        // The pre and post loops don't require safepoints at all
+        for (SafepointNode safepoint : preLoop.nodes().filter(SafepointNode.class)) {
+            graph.removeFixed(safepoint);
+        }
+        for (SafepointNode safepoint : postLoop.nodes().filter(SafepointNode.class)) {
+            graph.removeFixed(safepoint);
         }
         graph.getDebug().dump(DebugContext.DETAILED_LEVEL, graph, "InsertPrePostLoops %s", loop);
+        return mainLoopBegin;
     }
 
     /**
@@ -373,7 +375,7 @@
             throw GraalError.shouldNotReachHere();
         }
 
-        // Preloop always performs at least once iteration, so remove that from the main loop.
+        // Preloop always performs at least one iteration, so remove that from the main loop.
         ValueNode newLimit = sub(graph, ub, mainStride);
 
         // Re-wire the condition with the new limit
@@ -445,6 +447,14 @@
             return false;
         }
         LoopBeginNode loopBegin = loop.loopBegin();
+        LogicNode condition = loop.counted().getLimitTest().condition();
+        if (!(condition instanceof CompareNode)) {
+            return false;
+        }
+        if (((CompareNode) condition).condition() == Condition.EQ || ((CompareNode) condition).condition() == Condition.NE) {
+            condition.getDebug().log(DebugContext.VERBOSE_LEVEL, "isUnrollableLoop %s condition unsupported %s ", loopBegin, ((CompareNode) condition).condition());
+            return false;
+        }
         if (loopBegin.isMainLoop() || loopBegin.isSimpleLoop()) {
             // Flow-less loops to partial unroll for now. 3 blocks corresponds to an if that either
             // exits or continues the loop. There might be fixed and floating work within the loop
@@ -452,6 +462,7 @@
             if (loop.loop().getBlocks().size() < 3) {
                 return true;
             }
+            condition.getDebug().log(DebugContext.VERBOSE_LEVEL, "isUnrollableLoop %s too large to unroll %s ", loopBegin, loop.loop().getBlocks().size());
         }
         return false;
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -22,12 +22,41 @@
  */
 package org.graalvm.compiler.loop.test;
 
+import java.util.ListIterator;
+
+import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.java.ComputeLoopFrequenciesClosure;
+import org.graalvm.compiler.loop.DefaultLoopPolicies;
+import org.graalvm.compiler.loop.LoopEx;
+import org.graalvm.compiler.loop.LoopFragmentInside;
+import org.graalvm.compiler.loop.LoopsData;
+import org.graalvm.compiler.loop.phases.LoopPartialUnrollPhase;
 import org.graalvm.compiler.nodes.LoopBeginNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
+import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
+import org.graalvm.compiler.phases.common.DeoptimizationGroupingPhase;
+import org.graalvm.compiler.phases.common.FloatingReadPhase;
+import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase;
+import org.graalvm.compiler.phases.common.GuardLoweringPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+import org.graalvm.compiler.phases.tiers.Suites;
+import org.junit.Ignore;
 import org.junit.Test;
 
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
 public class LoopPartialUnrollTest extends GraalCompilerTest {
 
     @Override
@@ -41,100 +70,72 @@
         return false;
     }
 
-    public static long testMultiplySnippet(int arg) {
-        long r = 1;
-        for (int i = 0; branchProbability(0.99, i < arg); i++) {
-            r += r * i;
+    public static long sumWithEqualityLimit(int[] text) {
+        long sum = 0;
+        for (int i = 0; branchProbability(0.99, i != text.length); ++i) {
+            sum += volatileInt;
         }
-        return r;
-    }
-
-    @Test
-    public void testMultiply() {
-        test("testMultiplySnippet", 9);
-    }
-
-    public static int testNestedSumSnippet(int d) {
-        int c = 0;
-        for (int i = 0; i < d; i++) {
-            for (int j = 0; branchProbability(0.99, j < i); j++) {
-                c += c + j & 0x3;
-            }
-        }
-        return c;
-    }
-
-    @Test
-    public void testNestedSumBy2() {
-        for (int i = 0; i < 1000; i++) {
-            test("testNestedSumBy2Snippet", i);
-        }
+        return sum;
     }
 
-    public static int testNestedSumBy2Snippet(int d) {
-        int c = 0;
-        for (int i = 0; i < d; i++) {
-            for (int j = 0; branchProbability(0.99, j < i); j += 2) {
-                c += c + j & 0x3;
-            }
-        }
-        return c;
-    }
-
+    @Ignore("equality limits aren't working properly")
     @Test
-    public void testNestedSum() {
-        for (int i = 0; i < 1000; i++) {
-            test("testNestedSumSnippet", i);
-        }
-    }
-
-    public static int testSumDownSnippet(int d) {
-        int c = 0;
-        for (int j = d; branchProbability(0.99, j > -4); j--) {
-            c += c + j & 0x3;
-        }
-        return c;
-    }
-
-    @Test
-    public void testSumDown() {
-        test("testSumDownSnippet", 1);
-        for (int i = 0; i < 160; i++) {
-            test("testSumDownSnippet", i);
-        }
-    }
-
-    public static int testSumDownBy2Snippet(int d) {
-        int c = 0;
-        for (int j = d; branchProbability(0.99, j > -4); j -= 2) {
-            c += c + j & 0x3;
-        }
-        return c;
-    }
-
-    @Test
-    public void testSumDownBy2() {
-        test("testSumDownBy2Snippet", 1);
-        for (int i = 0; i < 160; i++) {
-            test("testSumDownBy2Snippet", i);
+    public void testSumWithEqualityLimit() {
+        for (int i = 0; i < 128; i++) {
+            int[] data = new int[i];
+            test("sumWithEqualityLimit", data);
         }
     }
 
     @Test
     public void testLoopCarried() {
-        test("testLoopCarriedSnippet", 1, 2);
-        test("testLoopCarriedSnippet", 0, 4);
-        test("testLoopCarriedSnippet", 4, 0);
+        for (int i = 0; i < 64; i++) {
+            test("testLoopCarriedSnippet", i);
+        }
+    }
+
+    @Test
+    public void testLoopCarriedDuplication() {
+        testDuplicateBody("testLoopCarriedReference", "testLoopCarriedSnippet");
     }
 
-    public static int testLoopCarriedSnippet(int a, int b) {
-        int c = a;
-        int d = b;
-        for (int j = 0; branchProbability(0.99, j < a); j++) {
-            d = c;
-            c += 1;
+    static volatile int volatileInt = 3;
+
+    public int testLoopCarriedSnippet(int iterations) {
+        int a = 0;
+        int b = 0;
+        int c = 0;
+
+        for (int i = 0; branchProbability(0.99, i < iterations); i++) {
+            int t1 = volatileInt;
+            int t2 = a + b;
+            c = b;
+            b = a;
+            a = t1 + t2;
         }
-        return c + d;
+
+        return c;
+    }
+
+    public int testLoopCarriedReference(int iterations) {
+        int a = 0;
+        int b = 0;
+        int c = 0;
+
+        for (int i = 0; branchProbability(0.99, i < iterations); i += 2) {
+            int t1 = volatileInt;
+            int t2 = a + b;
+            c = b;
+            b = a;
+            a = t1 + t2;
+            t1 = volatileInt;
+            t2 = a + b;
+            c = b;
+            b = a;
+            a = t1 + t2;
+        }
+
+        return c;
     }
 
     public static long init = Runtime.getRuntime().totalMemory();
@@ -181,4 +182,82 @@
     public void testSignExtension() {
         test("testSignExtensionSnippet", 9L);
     }
+
+    @Override
+    protected Suites createSuites(OptionValues opts) {
+        Suites suites = super.createSuites(opts).copy();
+        PhaseSuite<MidTierContext> mid = suites.getMidTier();
+        ListIterator<BasePhase<? super MidTierContext>> iter = mid.findPhase(LoopPartialUnrollPhase.class);
+        BasePhase<? super MidTierContext> partialUnoll = iter.previous();
+        if (iter.previous().getClass() != FrameStateAssignmentPhase.class) {
+            // Ensure LoopPartialUnrollPhase runs immediately after FrameStateAssignment, so it gets
+            // priority over other optimizations in these tests.
+            mid.findPhase(LoopPartialUnrollPhase.class).remove();
+            ListIterator<BasePhase<? super MidTierContext>> fsa = mid.findPhase(FrameStateAssignmentPhase.class);
+            fsa.add(partialUnoll);
+        }
+        return suites;
+    }
+
+    public void testGraph(String reference, String test) {
+        StructuredGraph referenceGraph = buildGraph(reference, false);
+        StructuredGraph testGraph = buildGraph(test, true);
+        assertEquals(referenceGraph, testGraph, false, false);
+    }
+
+    @SuppressWarnings("try")
+    public StructuredGraph buildGraph(String name, boolean partialUnroll) {
+        CompilationIdentifier id = new CompilationIdentifier() {
+            @Override
+            public String toString(Verbosity verbosity) {
+                return name;
+            }
+        };
+        ResolvedJavaMethod method = getResolvedJavaMethod(name);
+        OptionValues options = new OptionValues(getInitialOptions(), DefaultLoopPolicies.UnrollMaxIterations, 2);
+        StructuredGraph graph = parse(builder(method, StructuredGraph.AllowAssumptions.YES, id, options), getEagerGraphBuilderSuite());
+        try (DebugContext.Scope buildScope = graph.getDebug().scope(name, method, graph)) {
+            MidTierContext context = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, null);
+
+            CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+            canonicalizer.apply(graph, context);
+            new RemoveValueProxyPhase().apply(graph);
+            new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+            new FloatingReadPhase().apply(graph);
+            new DeadCodeEliminationPhase().apply(graph);
+            new ConditionalEliminationPhase(true).apply(graph, context);
+            ComputeLoopFrequenciesClosure.compute(graph);
+            new GuardLoweringPhase().apply(graph, context);
+            new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context);
+            new FrameStateAssignmentPhase().apply(graph);
+            new DeoptimizationGroupingPhase().apply(graph, context);
+            canonicalizer.apply(graph, context);
+            new ConditionalEliminationPhase(true).apply(graph, context);
+            if (partialUnroll) {
+                LoopsData dataCounted = new LoopsData(graph);
+                dataCounted.detectedCountedLoops();
+                for (LoopEx loop : dataCounted.countedLoops()) {
+                    LoopFragmentInside newSegment = loop.inside().duplicate();
+                    newSegment.insertWithinAfter(loop, false);
+                }
+                canonicalizer.apply(graph, getDefaultMidTierContext());
+            }
+            new DeadCodeEliminationPhase().apply(graph);
+            canonicalizer.apply(graph, context);
+            graph.getDebug().dump(DebugContext.BASIC_LEVEL, graph, "before compare");
+            return graph;
+        } catch (Throwable e) {
+            throw getDebugContext().handle(e);
+        }
+    }
+
+    public void testDuplicateBody(String reference, String test) {
+
+        StructuredGraph referenceGraph = buildGraph(reference, false);
+        StructuredGraph testGraph = buildGraph(test, true);
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        canonicalizer.apply(testGraph, getDefaultMidTierContext());
+        canonicalizer.apply(referenceGraph, getDefaultMidTierContext());
+        assertEquals(referenceGraph, testGraph);
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java	Thu Aug 24 21:06:33 2017 +0000
@@ -100,11 +100,12 @@
 
     @Override
     public boolean shouldPartiallyUnroll(LoopEx loop) {
+        LoopBeginNode loopBegin = loop.loopBegin();
         if (!loop.isCounted()) {
+            loopBegin.getDebug().log(DebugContext.VERBOSE_LEVEL, "shouldPartiallyUnroll %s isn't counted", loopBegin);
             return false;
         }
         OptionValues options = loop.entryPoint().getOptions();
-        LoopBeginNode loopBegin = loop.loopBegin();
         int maxNodes = ExactPartialUnrollMaxNodes.getValue(options);
         maxNodes = Math.min(maxNodes, Math.max(0, MaximumDesiredSize.getValue(options) - loop.loopBegin().graph().getNodeCount()));
         int size = Math.max(1, loop.size() - 1 - loop.loopBegin().phis().count());
@@ -112,6 +113,7 @@
         if (unrollFactor == 1) {
             double loopFrequency = loopBegin.loopFrequency();
             if (loopBegin.isSimpleLoop() && loopFrequency < 5.0) {
+                loopBegin.getDebug().log(DebugContext.VERBOSE_LEVEL, "shouldPartiallyUnroll %s frequency too low %s ", loopBegin, loopFrequency);
                 return false;
             }
             loopBegin.setLoopOrigFrequency(loopFrequency);
@@ -136,6 +138,7 @@
             }
             return true;
         } else {
+            loopBegin.getDebug().log(DebugContext.VERBOSE_LEVEL, "shouldPartiallyUnroll %s unrolled loop is too large %s ", loopBegin, size);
             return false;
         }
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java	Thu Aug 24 21:06:33 2017 +0000
@@ -22,6 +22,7 @@
  */
 package org.graalvm.compiler.loop;
 
+import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -142,18 +143,49 @@
         end.setNext(loop.entryPoint());
     }
 
+    /**
+     * Duplicate the body within the loop after the current copy copy of the body, updating the
+     * iteration limit to account for the duplication.
+     *
+     * @param loop
+     */
     public void insertWithinAfter(LoopEx loop) {
+        insertWithinAfter(loop, true);
+    }
+
+    /**
+     * Duplicate the body within the loop after the current copy copy of the body.
+     *
+     * @param loop
+     * @param updateLimit true if the iteration limit should be adjusted.
+     */
+    public void insertWithinAfter(LoopEx loop, boolean updateLimit) {
         assert isDuplicate() && original().loop() == loop;
 
         patchNodes(dataFixWithinAfter);
 
+        /*
+         * Collect any new back edges values before updating them since they might reference each
+         * other.
+         */
         LoopBeginNode mainLoopBegin = loop.loopBegin();
+        ArrayList<ValueNode> backedgeValues = new ArrayList<>();
         for (PhiNode mainPhiNode : mainLoopBegin.phis()) {
             ValueNode duplicatedNode = getDuplicatedNode(mainPhiNode.valueAt(1));
+            if (duplicatedNode == null) {
+                if (mainLoopBegin.isPhiAtMerge(mainPhiNode.valueAt(1))) {
+                    duplicatedNode = ((PhiNode) (mainPhiNode.valueAt(1))).valueAt(1);
+                } else {
+                    assert mainPhiNode.valueAt(1).isConstant() : mainPhiNode.valueAt(1);
+                }
+            }
+            backedgeValues.add(duplicatedNode);
+        }
+        int index = 0;
+        for (PhiNode mainPhiNode : mainLoopBegin.phis()) {
+            ValueNode duplicatedNode = backedgeValues.get(index++);
             if (duplicatedNode != null) {
                 mainPhiNode.setValueAt(1, duplicatedNode);
-            } else {
-                assert mainPhiNode.valueAt(1).isConstant() || mainLoopBegin.isPhiAtMerge(mainPhiNode.valueAt(1)) : mainPhiNode.valueAt(1);
             }
         }
 
@@ -166,27 +198,29 @@
         }
 
         int unrollFactor = mainLoopBegin.getUnrollFactor();
-
-        // Now use the previous unrollFactor to update the exit condition to power of two
         StructuredGraph graph = mainLoopBegin.graph();
-        InductionVariable iv = loop.counted().getCounter();
-        CompareNode compareNode = (CompareNode) loop.counted().getLimitTest().condition();
-        ValueNode compareBound;
-        if (compareNode.getX() == iv.valueNode()) {
-            compareBound = compareNode.getY();
-        } else if (compareNode.getY() == iv.valueNode()) {
-            compareBound = compareNode.getX();
-        } else {
-            throw GraalError.shouldNotReachHere();
-        }
-        if (iv.direction() == InductionVariable.Direction.Up) {
-            ConstantNode aboveVal = graph.unique(ConstantNode.forIntegerStamp(iv.initNode().stamp(), unrollFactor * iv.constantStride()));
-            ValueNode newLimit = graph.addWithoutUnique(new SubNode(compareBound, aboveVal));
-            compareNode.replaceFirstInput(compareBound, newLimit);
-        } else if (iv.direction() == InductionVariable.Direction.Down) {
-            ConstantNode aboveVal = graph.unique(ConstantNode.forIntegerStamp(iv.initNode().stamp(), unrollFactor * -iv.constantStride()));
-            ValueNode newLimit = graph.addWithoutUnique(new AddNode(compareBound, aboveVal));
-            compareNode.replaceFirstInput(compareBound, newLimit);
+        if (updateLimit) {
+            // Now use the previous unrollFactor to update the exit condition to power of two
+            InductionVariable iv = loop.counted().getCounter();
+            CompareNode compareNode = (CompareNode) loop.counted().getLimitTest().condition();
+            ValueNode compareBound;
+            if (compareNode.getX() == iv.valueNode()) {
+                compareBound = compareNode.getY();
+            } else if (compareNode.getY() == iv.valueNode()) {
+                compareBound = compareNode.getX();
+            } else {
+                throw GraalError.shouldNotReachHere();
+            }
+            long originalStride = unrollFactor == 1 ? iv.constantStride() : iv.constantStride() / unrollFactor;
+            if (iv.direction() == InductionVariable.Direction.Up) {
+                ConstantNode aboveVal = graph.unique(ConstantNode.forIntegerStamp(iv.initNode().stamp(), unrollFactor * originalStride));
+                ValueNode newLimit = graph.addWithoutUnique(new SubNode(compareBound, aboveVal));
+                compareNode.replaceFirstInput(compareBound, newLimit);
+            } else if (iv.direction() == InductionVariable.Direction.Down) {
+                ConstantNode aboveVal = graph.unique(ConstantNode.forIntegerStamp(iv.initNode().stamp(), unrollFactor * -originalStride));
+                ValueNode newLimit = graph.addWithoutUnique(new AddNode(compareBound, aboveVal));
+                compareNode.replaceFirstInput(compareBound, newLimit);
+            }
         }
         mainLoopBegin.setUnrollFactor(unrollFactor * 2);
         mainLoopBegin.setLoopFrequency(mainLoopBegin.loopFrequency() / 2);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/TestJMH.java	Thu Aug 24 14:03:21 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * 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.microbenchmarks.graal;
-
-import org.openjdk.jmh.annotations.Benchmark;
-import org.openjdk.jmh.annotations.Fork;
-import org.openjdk.jmh.annotations.Measurement;
-import org.openjdk.jmh.annotations.Warmup;
-
-@Warmup(iterations = 1)
-@Measurement(iterations = 1)
-@Fork(1)
-/**
- * This dummy class is used to verify that the JMH microbenchmarking environment is set up properly.
- */
-public class TestJMH {
-
-    @Benchmark
-    public void testJMH() {
-        // This method was intentionally left blank.
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/TestJMHWhitebox.java	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.microbenchmarks.graal;
+
+import org.graalvm.compiler.microbenchmarks.graal.util.GraalState;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Warmup;
+
+@Warmup(iterations = 1)
+@Measurement(iterations = 1)
+@Fork(1)
+/**
+ * This dummy class is used to verify that the JMH microbenchmarking environment is set up properly.
+ */
+public class TestJMHWhitebox {
+
+    @Benchmark
+    public void testJMH(@SuppressWarnings("unused") GraalState s) {
+        // This method was intentionally left blank.
+    }
+
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,12 +25,10 @@
 import static org.graalvm.compiler.core.test.GraalCompilerTest.getInitialOptions;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.JavaKind;
 
-import org.junit.Before;
-import org.junit.Test;
+import java.math.BigInteger;
 
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
@@ -42,6 +40,12 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.options.OptionValues;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
 
 /**
  * This class tests that integer stamps are created correctly for constants.
@@ -365,10 +369,187 @@
         assertEquals(IntegerStamp.create(32, 0, 0x1ff, 0, 0x1ff), shl.foldStamp(IntegerStamp.create(32, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 0, 1, 0, 1)));
         assertEquals(IntegerStamp.create(32, 0, 0x1fe0, 0, 0x1fe0), shl.foldStamp(IntegerStamp.create(32, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5)));
         assertEquals(IntegerStamp.create(32, 0x1e0, 0x1fe0, 0, 0x1fe0), shl.foldStamp(IntegerStamp.create(32, 0xf, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5)));
+        assertEquals(IntegerStamp.create(32, -4096, -4096, -4096, -4096), shl.foldStamp(IntegerStamp.create(32, -16, -16, -16, -16), IntegerStamp.create(32, 8, 8, 8, 8)));
+        assertEquals(StampFactory.empty(JavaKind.Int), shl.foldStamp(StampFactory.empty(JavaKind.Int), IntegerStamp.create(32, 5, 5, 5, 5)));
+        assertEquals(StampFactory.empty(JavaKind.Int), shl.foldStamp(IntegerStamp.create(32, 0xf, 0xff, 0, 0xff), (IntegerStamp) StampFactory.empty(JavaKind.Int)));
 
         assertEquals(IntegerStamp.create(64, 0, 0x1ff, 0, 0x1ff), shl.foldStamp(IntegerStamp.create(64, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 0, 1, 0, 1)));
         assertEquals(IntegerStamp.create(64, 0, 0x1fe0, 0, 0x1fe0), shl.foldStamp(IntegerStamp.create(64, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5)));
         assertEquals(IntegerStamp.create(64, 0x1e0, 0x1fe0, 0, 0x1fe0), shl.foldStamp(IntegerStamp.create(64, 0xf, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5)));
+        assertEquals(IntegerStamp.create(64, -4096, -4096, -4096, -4096), shl.foldStamp(IntegerStamp.create(64, -16, -16, -16, -16), IntegerStamp.create(32, 8, 8, 8, 8)));
+        assertEquals(StampFactory.empty(JavaKind.Long), shl.foldStamp(StampFactory.empty(JavaKind.Long), IntegerStamp.create(32, 5, 5, 5, 5)));
+        assertEquals(StampFactory.empty(JavaKind.Long), shl.foldStamp(IntegerStamp.create(64, 0xf, 0xff, 0, 0xff), (IntegerStamp) StampFactory.empty(JavaKind.Int)));
+    }
 
+    @Test
+    public void testUnsignedShiftRight() {
+        ShiftOp<?> ushr = IntegerStamp.OPS.getUShr();
+        assertEquals(IntegerStamp.create(32, 0, 0xff, 0, 0xff), ushr.foldStamp(IntegerStamp.create(32, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 0, 1, 0, 1)));
+        assertEquals(IntegerStamp.create(32, 0, 0x07, 0, 0x07), ushr.foldStamp(IntegerStamp.create(32, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5)));
+        assertEquals(IntegerStamp.create(32, 0x0, 0x07, 0, 0x07), ushr.foldStamp(IntegerStamp.create(32, 0xf, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5)));
+        assertEquals(IntegerStamp.create(32, 0xffffff, 0xffffff, 0xffffff, 0xffffff), ushr.foldStamp(IntegerStamp.create(32, -16, -16, -16, -16), IntegerStamp.create(32, 8, 8, 8, 8)));
+        assertEquals(StampFactory.empty(JavaKind.Int), ushr.foldStamp(StampFactory.empty(JavaKind.Int), IntegerStamp.create(32, 5, 5, 5, 5)));
+        assertEquals(StampFactory.empty(JavaKind.Int), ushr.foldStamp(IntegerStamp.create(32, 0xf, 0xff, 0, 0xff), (IntegerStamp) StampFactory.empty(JavaKind.Int)));
+
+        assertEquals(IntegerStamp.create(64, 0, 0xff, 0, 0xff), ushr.foldStamp(IntegerStamp.create(64, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 0, 1, 0, 1)));
+        assertEquals(IntegerStamp.create(64, 0, 0x07, 0, 0x07), ushr.foldStamp(IntegerStamp.create(64, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5)));
+        assertEquals(IntegerStamp.create(64, 0x0, 0x07, 0, 0x07), ushr.foldStamp(IntegerStamp.create(64, 0xf, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5)));
+        assertEquals(IntegerStamp.create(64, 0xffffffffffffffL, 0xffffffffffffffL, 0xffffffffffffffL, 0xffffffffffffffL),
+                        ushr.foldStamp(IntegerStamp.create(64, -16, -16, -16, -16), IntegerStamp.create(32, 8, 8, 8, 8)));
+        assertEquals(StampFactory.empty(JavaKind.Long), ushr.foldStamp(StampFactory.empty(JavaKind.Long), IntegerStamp.create(32, 5, 5, 5, 5)));
+        assertEquals(StampFactory.empty(JavaKind.Long), ushr.foldStamp(IntegerStamp.create(64, 0xf, 0xff, 0, 0xff), (IntegerStamp) StampFactory.empty(JavaKind.Int)));
+    }
+
+    @Test
+    public void testShiftRight() {
+        ShiftOp<?> shr = IntegerStamp.OPS.getShr();
+        assertEquals(IntegerStamp.create(32, 0, 0xff, 0, 0xff), shr.foldStamp(IntegerStamp.create(32, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 0, 1, 0, 1)));
+        assertEquals(IntegerStamp.create(32, 0, 0x07, 0, 0x07), shr.foldStamp(IntegerStamp.create(32, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5)));
+        assertEquals(IntegerStamp.create(32, 0x0, 0x07, 0, 0x07), shr.foldStamp(IntegerStamp.create(32, 0xf, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5)));
+        assertEquals(IntegerStamp.create(32, -1, -1, -1, -1), shr.foldStamp(IntegerStamp.create(32, -16, -16, -16, -16), IntegerStamp.create(32, 8, 8, 8, 8)));
+        assertEquals(StampFactory.empty(JavaKind.Int), shr.foldStamp(StampFactory.empty(JavaKind.Int), IntegerStamp.create(32, 5, 5, 5, 5)));
+        assertEquals(StampFactory.empty(JavaKind.Int), shr.foldStamp(IntegerStamp.create(32, 0xf, 0xff, 0, 0xff), (IntegerStamp) StampFactory.empty(JavaKind.Int)));
+
+        assertEquals(IntegerStamp.create(64, 0, 0xff, 0, 0xff), shr.foldStamp(IntegerStamp.create(64, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 0, 1, 0, 1)));
+        assertEquals(IntegerStamp.create(64, 0, 0x07, 0, 0x07), shr.foldStamp(IntegerStamp.create(64, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5)));
+        assertEquals(IntegerStamp.create(64, 0x0, 0x07, 0, 0x07), shr.foldStamp(IntegerStamp.create(64, 0xf, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5)));
+        assertEquals(IntegerStamp.create(64, -1, -1, -1, -1), shr.foldStamp(IntegerStamp.create(64, -16, -16, -16, -16), IntegerStamp.create(32, 8, 8, 8, 8)));
+        assertEquals(StampFactory.empty(JavaKind.Long), shr.foldStamp(StampFactory.empty(JavaKind.Long), IntegerStamp.create(32, 5, 5, 5, 5)));
+        assertEquals(StampFactory.empty(JavaKind.Long), shr.foldStamp(IntegerStamp.create(64, 0xf, 0xff, 0, 0xff), (IntegerStamp) StampFactory.empty(JavaKind.Int)));
+    }
+
+    @Test
+    public void testMulHigh() {
+        testSomeMulHigh(IntegerStamp.OPS.getMulHigh());
+    }
+
+    @Test
+    public void testUMulHigh() {
+        testSomeMulHigh(IntegerStamp.OPS.getUMulHigh());
+    }
+
+    private static void testSomeMulHigh(BinaryOp<?> someMulHigh) {
+        // 32 bits
+        testMulHigh(someMulHigh, 0, 0, 32);
+
+        testMulHigh(someMulHigh, 1, 1, 32);
+        testMulHigh(someMulHigh, 1, 5, 32);
+        testMulHigh(someMulHigh, 256, 256, 32);
+        testMulHigh(someMulHigh, 0xFFFFFFF, 0xFFFFFFA, 32);
+        testMulHigh(someMulHigh, Integer.MAX_VALUE, 2, 32);
+
+        testMulHigh(someMulHigh, -1, -1, 32);
+        testMulHigh(someMulHigh, -1, -5, 32);
+        testMulHigh(someMulHigh, -256, -256, 32);
+        testMulHigh(someMulHigh, -0xFFFFFFF, -0xFFFFFFA, 32);
+        testMulHigh(someMulHigh, Integer.MIN_VALUE, -2, 32);
+
+        testMulHigh(someMulHigh, -1, 1, 32);
+        testMulHigh(someMulHigh, -1, 5, 32);
+        testMulHigh(someMulHigh, -256, 256, 32);
+        testMulHigh(someMulHigh, -0xFFFFFFF, 0xFFFFFFA, 32);
+        testMulHigh(someMulHigh, Integer.MIN_VALUE, 2, 32);
+
+        testMulHigh(someMulHigh, Integer.MIN_VALUE, Integer.MIN_VALUE, 32);
+        testMulHigh(someMulHigh, Integer.MAX_VALUE, Integer.MAX_VALUE, 32);
+
+        assertEquals(StampFactory.forKind(JavaKind.Int).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).empty(), StampFactory.forKind(JavaKind.Int).empty()));
+        assertEquals(StampFactory.forKind(JavaKind.Int).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).empty(), StampFactory.forKind(JavaKind.Int).unrestricted()));
+        assertEquals(StampFactory.forKind(JavaKind.Int).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).empty(), IntegerStamp.create(32, 0, 0)));
+        assertEquals(StampFactory.forKind(JavaKind.Int).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).empty(), IntegerStamp.create(32, 1, 1)));
+        assertEquals(StampFactory.forKind(JavaKind.Int).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).empty(), IntegerStamp.create(32, -1, -1)));
+
+        assertEquals(StampFactory.forKind(JavaKind.Int).unrestricted(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).unrestricted(), StampFactory.forKind(JavaKind.Int).unrestricted()));
+        assertEquals(StampFactory.forKind(JavaKind.Int).unrestricted(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).unrestricted(), IntegerStamp.create(32, 0, 0)));
+        assertEquals(StampFactory.forKind(JavaKind.Int).unrestricted(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).unrestricted(), IntegerStamp.create(32, 1, 1)));
+        assertEquals(StampFactory.forKind(JavaKind.Int).unrestricted(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).unrestricted(), IntegerStamp.create(32, -1, -1)));
+
+        // 64 bits
+        testMulHigh(someMulHigh, 0, 0, 64);
+
+        testMulHigh(someMulHigh, 1, 1, 64);
+        testMulHigh(someMulHigh, 1, 5, 64);
+        testMulHigh(someMulHigh, 256, 256, 64);
+        testMulHigh(someMulHigh, 0xFFFFFFF, 0xFFFFFFA, 64);
+        testMulHigh(someMulHigh, 0xFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFAL, 64);
+        testMulHigh(someMulHigh, Integer.MAX_VALUE, 2, 64);
+        testMulHigh(someMulHigh, Long.MAX_VALUE, 2, 64);
+
+        testMulHigh(someMulHigh, -1, -1, 64);
+        testMulHigh(someMulHigh, -1, -5, 64);
+        testMulHigh(someMulHigh, -256, -256, 64);
+        testMulHigh(someMulHigh, -0xFFFFFFF, -0xFFFFFFA, 64);
+        testMulHigh(someMulHigh, -0xFFFFFFFFFFFFFFL, -0xFFFFFFFFFFFFFAL, 64);
+        testMulHigh(someMulHigh, Integer.MIN_VALUE, -2, 64);
+        testMulHigh(someMulHigh, Long.MIN_VALUE, -2, 64);
+
+        testMulHigh(someMulHigh, -1, 1, 64);
+        testMulHigh(someMulHigh, -1, 5, 64);
+        testMulHigh(someMulHigh, -256, 256, 64);
+        testMulHigh(someMulHigh, -0xFFFFFFF, 0xFFFFFFA, 64);
+        testMulHigh(someMulHigh, -0xFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFAL, 64);
+        testMulHigh(someMulHigh, Integer.MIN_VALUE, 2, 64);
+        testMulHigh(someMulHigh, Long.MIN_VALUE, 2, 64);
+
+        testMulHigh(someMulHigh, Integer.MIN_VALUE, Integer.MIN_VALUE, 64);
+        testMulHigh(someMulHigh, Long.MIN_VALUE, Long.MIN_VALUE, 64);
+        testMulHigh(someMulHigh, Integer.MAX_VALUE, Integer.MAX_VALUE, 64);
+        testMulHigh(someMulHigh, Long.MAX_VALUE, Long.MAX_VALUE, 64);
+
+        assertEquals(StampFactory.forKind(JavaKind.Long).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).empty(), StampFactory.forKind(JavaKind.Long).empty()));
+        assertEquals(StampFactory.forKind(JavaKind.Long).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).empty(), StampFactory.forKind(JavaKind.Long).unrestricted()));
+        assertEquals(StampFactory.forKind(JavaKind.Long).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).empty(), IntegerStamp.create(64, 0, 0)));
+        assertEquals(StampFactory.forKind(JavaKind.Long).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).empty(), IntegerStamp.create(64, 1, 1)));
+        assertEquals(StampFactory.forKind(JavaKind.Long).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).empty(), IntegerStamp.create(64, -1, -1)));
+
+        assertEquals(StampFactory.forKind(JavaKind.Long).unrestricted(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).unrestricted(), StampFactory.forKind(JavaKind.Long).unrestricted()));
+        assertEquals(StampFactory.forKind(JavaKind.Long).unrestricted(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).unrestricted(), IntegerStamp.create(64, 0, 0)));
+        assertEquals(StampFactory.forKind(JavaKind.Long).unrestricted(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).unrestricted(), IntegerStamp.create(64, 1, 1)));
+        assertEquals(StampFactory.forKind(JavaKind.Long).unrestricted(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).unrestricted(), IntegerStamp.create(64, -1, -1)));
+    }
+
+    private static void testMulHigh(BinaryOp<?> someMulHigh, long a, long b, int bits) {
+        long expectedResult = getExpectedValue(someMulHigh, a, b, bits);
+        assertEquals(IntegerStamp.create(bits, expectedResult, expectedResult), someMulHigh.foldStamp(IntegerStamp.create(bits, a, a), IntegerStamp.create(bits, b, b)));
+    }
+
+    private static long getExpectedValue(BinaryOp<?> someMulHigh, long a, long b, int bits) {
+        if (someMulHigh == IntegerStamp.OPS.getMulHigh()) {
+            return mulHigh(a, b, bits);
+        } else {
+            assertEquals(IntegerStamp.OPS.getUMulHigh(), someMulHigh);
+            return umulHigh(a, b, bits);
+        }
+    }
+
+    private static long mulHigh(long a, long b, int bits) {
+        BigInteger valA = BigInteger.valueOf(a);
+        BigInteger valB = BigInteger.valueOf(b);
+        BigInteger result = valA.multiply(valB).shiftRight(bits);
+        if (bits == 32) {
+            return result.intValue();
+        } else {
+            assertEquals(64, bits);
+            return result.longValue();
+        }
+    }
+
+    private static long umulHigh(long a, long b, int bits) {
+        Assert.assertTrue(bits == 32 || bits == 64);
+        BigInteger valA = BigInteger.valueOf(a);
+        if (valA.compareTo(BigInteger.valueOf(0)) < 0) {
+            valA = valA.add(BigInteger.ONE.shiftLeft(bits));
+        }
+        BigInteger valB = BigInteger.valueOf(b);
+        if (valB.compareTo(BigInteger.valueOf(0)) < 0) {
+            valB = valB.add(BigInteger.ONE.shiftLeft(bits));
+        }
+
+        BigInteger result = valA.multiply(valB).shiftRight(bits);
+        if (bits == 32) {
+            return result.intValue();
+        } else {
+            return result.longValue();
+        }
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java	Thu Aug 24 21:06:33 2017 +0000
@@ -466,6 +466,28 @@
             AbstractMergeNode merge = (AbstractMergeNode) node;
             EndNode singleEnd = merge.forwardEndAt(0);
 
+            /*
+             * In some corner cases, the MergeNode already has PhiNodes. Since there is a single
+             * EndNode, each PhiNode can only have one input, and we can replace the PhiNode with
+             * this single input.
+             */
+            for (PhiNode phi : merge.phis()) {
+                assert phi.inputs().count() == 1 : "input count must match end count";
+                Node singlePhiInput = phi.inputs().first();
+
+                /*
+                 * We do not have the orderID of the PhiNode anymore, so we need to search through
+                 * the complete list of nodes to find a match.
+                 */
+                for (int i = 0; i < loopScope.createdNodes.length; i++) {
+                    if (loopScope.createdNodes[i] == phi) {
+                        loopScope.createdNodes[i] = singlePhiInput;
+                    }
+                }
+
+                phi.replaceAndDelete(singlePhiInput);
+            }
+
             /* Nodes that would use this merge as the guard need to use the previous block. */
             registerNode(loopScope, nodeOrderId, AbstractBeginNode.prevBegin(singleEnd), true, false);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,6 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Mul;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -108,6 +109,27 @@
                         return AddNode.create(new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(i - 1))), forX);
                     } else if (CodeUtil.isPowerOf2(i + 1)) {
                         return SubNode.create(new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(i + 1))), forX);
+                    } else {
+                        int bitCount = Long.bitCount(i);
+                        long highestBitValue = Long.highestOneBit(i);
+                        if (bitCount == 2) {
+                            // e.g., 0b1000_0010
+                            long lowerBitValue = i - highestBitValue;
+                            assert highestBitValue > 0 && lowerBitValue > 0;
+                            ValueNode left = new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(highestBitValue)));
+                            ValueNode right = lowerBitValue == 1 ? forX : new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(lowerBitValue)));
+                            return AddNode.create(left, right);
+                        } else {
+                            // e.g., 0b1111_1101
+                            int shiftToRoundUpToPowerOf2 = CodeUtil.log2(highestBitValue) + 1;
+                            long subValue = (1 << shiftToRoundUpToPowerOf2) - i;
+                            if (CodeUtil.isPowerOf2(subValue) && shiftToRoundUpToPowerOf2 < ((IntegerStamp) stamp).getBits()) {
+                                assert CodeUtil.log2(subValue) >= 1;
+                                ValueNode left = new LeftShiftNode(forX, ConstantNode.forInt(shiftToRoundUpToPowerOf2));
+                                ValueNode right = new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(subValue)));
+                                return SubNode.create(left, right);
+                            }
+                        }
                     }
                 } else if (i < 0) {
                     if (CodeUtil.isPowerOf2(-i)) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java	Thu Aug 24 21:06:33 2017 +0000
@@ -562,7 +562,7 @@
                 if (pred.getSuccessorCount() > 1) {
                     assert pred.getEndNode() instanceof ControlSplitNode;
                     ControlSplitNode controlSplit = (ControlSplitNode) pred.getEndNode();
-                    probability *= controlSplit.probability(block.getBeginNode());
+                    probability = multiplyProbabilities(probability, controlSplit.probability(block.getBeginNode()));
                 }
             } else {
                 probability = predecessors[0].probability;
@@ -572,7 +572,7 @@
 
                 if (block.getBeginNode() instanceof LoopBeginNode) {
                     LoopBeginNode loopBegin = (LoopBeginNode) block.getBeginNode();
-                    probability *= loopBegin.loopFrequency();
+                    probability = multiplyProbabilities(probability, loopBegin.loopFrequency());
                 }
             }
             if (probability < MIN_PROBABILITY) {
@@ -755,4 +755,20 @@
     public void setNodeToBlock(NodeMap<Block> nodeMap) {
         this.nodeToBlock = nodeMap;
     }
+
+    /**
+     * Multiplies a and b and clamps the between {@link ControlFlowGraph#MIN_PROBABILITY} and
+     * {@link ControlFlowGraph#MAX_PROBABILITY}.
+     */
+    public static double multiplyProbabilities(double a, double b) {
+        assert !Double.isNaN(a) && !Double.isNaN(b) && Double.isFinite(a) && Double.isFinite(b) : a + " " + b;
+        double r = a * b;
+        if (r > MAX_PROBABILITY) {
+            return MAX_PROBABILITY;
+        }
+        if (r < MIN_PROBABILITY) {
+            return MIN_PROBABILITY;
+        }
+        return r;
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java	Thu Aug 24 21:06:33 2017 +0000
@@ -22,9 +22,12 @@
  */
 package org.graalvm.compiler.options.processor;
 
+import java.io.BufferedReader;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -50,7 +53,9 @@
 import javax.lang.model.util.Elements;
 import javax.lang.model.util.Types;
 import javax.tools.Diagnostic.Kind;
+import javax.tools.FileObject;
 import javax.tools.JavaFileObject;
+import javax.tools.StandardLocation;
 
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionDescriptor;
@@ -117,22 +122,13 @@
             return;
         }
 
-        String help = annotation.help();
-        if (help.length() != 0) {
-            char firstChar = help.charAt(0);
-            if (!Character.isUpperCase(firstChar)) {
-                processingEnv.getMessager().printMessage(Kind.ERROR, "Option help text must start with upper case letter", element);
-                return;
-            }
-        }
-
         String optionName = annotation.name();
         if (optionName.equals("")) {
             optionName = fieldName;
         }
 
         if (!Character.isUpperCase(optionName.charAt(0))) {
-            processingEnv.getMessager().printMessage(Kind.ERROR, "Option name must start with capital letter", element);
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Option name must start with an upper case letter", element);
             return;
         }
 
@@ -154,6 +150,7 @@
         String separator = "";
         Set<Element> originatingElementsList = info.originatingElements;
         originatingElementsList.add(field);
+        PackageElement enclosingPackage = null;
         while (enclosing != null) {
             if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
                 if (enclosing.getModifiers().contains(Modifier.PRIVATE)) {
@@ -164,13 +161,64 @@
                 originatingElementsList.add(enclosing);
                 declaringClass = enclosing.getSimpleName() + separator + declaringClass;
                 separator = ".";
-            } else {
-                assert enclosing.getKind() == ElementKind.PACKAGE;
+            } else if (enclosing.getKind() == ElementKind.PACKAGE) {
+                enclosingPackage = (PackageElement) enclosing;
             }
             enclosing = enclosing.getEnclosingElement();
         }
+        if (enclosingPackage == null) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Option field cannot be declared in the unnamed package", element);
+            return;
+        }
+        String[] helpValue = annotation.help();
+        String help = "";
+        String[] extraHelp = {};
 
-        info.options.add(new OptionInfo(optionName, help, optionType, declaringClass, field));
+        if (helpValue.length == 1) {
+            help = helpValue[0];
+            if (help.startsWith("file:")) {
+                String path = help.substring("file:".length());
+                Filer filer = processingEnv.getFiler();
+                try {
+                    FileObject file;
+                    try {
+                        file = filer.getResource(StandardLocation.SOURCE_PATH, enclosingPackage.getQualifiedName(), path);
+                    } catch (IllegalArgumentException | IOException e) {
+                        // Handle the case when a compiler doesn't support the SOURCE_PATH location
+                        file = filer.getResource(StandardLocation.CLASS_OUTPUT, enclosingPackage.getQualifiedName(), path);
+                    }
+                    try (BufferedReader br = new BufferedReader(new InputStreamReader(file.openInputStream()))) {
+                        help = br.readLine();
+                        if (help == null) {
+                            help = "";
+                        }
+                        String line = br.readLine();
+                        List<String> lines = new ArrayList<>();
+                        while (line != null) {
+                            lines.add(line);
+                            line = br.readLine();
+                        }
+                        extraHelp = lines.toArray(new String[lines.size()]);
+                    }
+                } catch (IOException e) {
+                    String msg = String.format("Error reading %s containing the help text for option field: %s", path, e);
+                    processingEnv.getMessager().printMessage(Kind.ERROR, msg, element);
+                    return;
+                }
+            }
+        } else if (helpValue.length > 1) {
+            help = helpValue[0];
+            extraHelp = Arrays.copyOfRange(helpValue, 1, helpValue.length);
+        }
+        if (help.length() != 0) {
+            char firstChar = help.charAt(0);
+            if (!Character.isUpperCase(firstChar)) {
+                processingEnv.getMessager().printMessage(Kind.ERROR, "Option help text must start with an upper case letter", element);
+                return;
+            }
+        }
+
+        info.options.add(new OptionInfo(optionName, help, extraHelp, optionType, declaringClass, field));
     }
 
     private void createFiles(OptionsInfo info) {
@@ -200,11 +248,11 @@
 
             String desc = OptionDescriptor.class.getSimpleName();
 
-            int i = 0;
             Collections.sort(info.options);
 
             out.println("    @Override");
             out.println("    public OptionDescriptor get(String value) {");
+            out.println("        switch (value) {");
             out.println("        // CheckStyle: stop line length check");
             for (OptionInfo option : info.options) {
                 String name = option.name;
@@ -214,41 +262,52 @@
                 } else {
                     optionField = option.declaringClass + "." + option.field.getSimpleName();
                 }
+                out.println("        case \"" + name + "\": {");
                 String type = option.type;
                 String help = option.help;
+                String[] extraHelp = option.extraHelp;
                 String declaringClass = option.declaringClass;
                 Name fieldName = option.field.getSimpleName();
-                out.println("        if (value.equals(\"" + name + "\")) {");
-                out.printf("            return %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s);\n", desc, name, type, help, declaringClass, fieldName, optionField);
+                out.printf("            return " + desc + ".create(\n");
+                out.printf("                /*name*/ \"%s\",\n", name);
+                out.printf("                /*type*/ %s.class,\n", type);
+                out.printf("                /*help*/ \"%s\",\n", help);
+                if (extraHelp.length != 0) {
+                    out.printf("                /*extraHelp*/ new String[] {\n");
+                    for (String line : extraHelp) {
+                        out.printf("                         \"%s\",\n", line.replace("\\", "\\\\").replace("\"", "\\\""));
+                    }
+                    out.printf("                              },\n");
+                }
+                out.printf("                /*declaringClass*/ %s.class,\n", declaringClass);
+                out.printf("                /*fieldName*/ \"%s\",\n", fieldName);
+                out.printf("                /*option*/ %s);\n", optionField);
                 out.println("        }");
             }
             out.println("        // CheckStyle: resume line length check");
+            out.println("        }");
             out.println("        return null;");
             out.println("    }");
             out.println();
             out.println("    @Override");
             out.println("    public Iterator<" + desc + "> iterator() {");
-            out.println("        // CheckStyle: stop line length check");
-            out.println("        List<" + desc + "> options = Arrays.asList(");
-            for (OptionInfo option : info.options) {
-                String optionField;
-                if (option.field.getModifiers().contains(Modifier.PRIVATE)) {
-                    throw new InternalError();
-                } else {
-                    optionField = option.declaringClass + "." + option.field.getSimpleName();
-                }
-                String name = option.name;
-                String type = option.type;
-                String help = option.help;
-                String declaringClass = option.declaringClass;
-                Name fieldName = option.field.getSimpleName();
-                String comma = i == info.options.size() - 1 ? "" : ",";
-                out.printf("            %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s)%s\n", desc, name, type, help, declaringClass, fieldName, optionField, comma);
-                i++;
+            out.println("        return new Iterator<OptionDescriptor>() {");
+            out.println("            int i = 0;");
+            out.println("            @Override");
+            out.println("            public boolean hasNext() {");
+            out.println("                return i < " + info.options.size() + ";");
+            out.println("            }");
+            out.println("            @Override");
+            out.println("            public OptionDescriptor next() {");
+            out.println("                switch (i++) {");
+            for (int i = 0; i < info.options.size(); i++) {
+                OptionInfo option = info.options.get(i);
+                out.println("                    case " + i + ": return get(\"" + option.name + "\");");
             }
-            out.println("        );");
-            out.println("        // CheckStyle: resume line length check");
-            out.println("        return options.iterator();");
+            out.println("                }");
+            out.println("                throw new NoSuchElementException();");
+            out.println("            }");
+            out.println("        };");
             out.println("    }");
             out.println("}");
         }
@@ -274,13 +333,15 @@
 
         final String name;
         final String help;
+        final String[] extraHelp;
         final String type;
         final String declaringClass;
         final VariableElement field;
 
-        OptionInfo(String name, String help, String type, String declaringClass, VariableElement field) {
+        OptionInfo(String name, String help, String[] extraHelp, String type, String declaringClass, VariableElement field) {
             this.name = name;
             this.help = help;
+            this.extraHelp = extraHelp;
             this.type = type;
             this.declaringClass = declaringClass;
             this.field = field;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionKey.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionKey.java	Thu Aug 24 21:06:33 2017 +0000
@@ -28,27 +28,10 @@
 
 public class EnumOptionKey<T extends Enum<T>> extends OptionKey<T> {
     final Class<T> enumClass;
-    final ValueHelp<T> valueHelp;
-
-    /**
-     * Provides help text for enum values.
-     */
-    public interface ValueHelp<T extends Enum<T>> {
-        /**
-         * Gets help text for the enum {@code value} that includes the name of the value. If
-         * {@code null} is returned, {@code value.toString()} is used.
-         */
-        String getHelp(Object value);
-    }
-
-    public EnumOptionKey(T value) {
-        this(value, null);
-    }
 
     @SuppressWarnings("unchecked")
-    public EnumOptionKey(T value, ValueHelp<T> help) {
+    public EnumOptionKey(T value) {
         super(value);
-        this.valueHelp = help;
         if (value == null) {
             throw new IllegalArgumentException("Value must not be null");
         }
@@ -62,10 +45,6 @@
         return EnumSet.allOf(enumClass);
     }
 
-    public ValueHelp<T> getValueHelp() {
-        return valueHelp;
-    }
-
     Object valueOf(String name) {
         try {
             return Enum.valueOf(enumClass, name);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/Option.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/Option.java	Thu Aug 24 21:06:33 2017 +0000
@@ -38,10 +38,20 @@
 public @interface Option {
 
     /**
-     * Gets a help message for the option. New lines can be embedded in the message with
-     * {@code "%n"}.
+     * Gets a help message for the option.
+     * <p>
+     * The first element of the array is the short help message. This part of the help message is
+     * subject to line wrapping when printed.
+     * <p>
+     * The remaining elements contain a more detailed expansion of the help message and will be
+     * printed as is in a left-aligned block (i.e. leading spaces will be preserved).
+     * <p>
+     * If there is only one element and it starts with {@code "file:"<path>}, then the help message
+     * is located in a file located by resolving {@code <path>} against the location of the package
+     * in which the option is declared. The first line in the file is the short help message as
+     * described above. The remaining lines are the help message expansion.
      */
-    String help();
+    String[] help();
 
     /**
      * The name of the option. By default, the name of the annotated field should be used.
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionDescriptor.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionDescriptor.java	Thu Aug 24 21:06:33 2017 +0000
@@ -22,6 +22,10 @@
  */
 package org.graalvm.compiler.options;
 
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
 /**
  * Describes the attributes of a static field {@linkplain Option option} and provides access to its
  * {@linkplain OptionKey value}.
@@ -31,25 +35,34 @@
     protected final String name;
     protected final Class<?> type;
     protected final String help;
+    protected final List<String> extraHelp;
     protected final OptionKey<?> optionKey;
     protected final Class<?> declaringClass;
     protected final String fieldName;
 
+    private static final String[] NO_EXTRA_HELP = {};
+
     public static OptionDescriptor create(String name, Class<?> type, String help, Class<?> declaringClass, String fieldName, OptionKey<?> option) {
+        return create(name, type, help, NO_EXTRA_HELP, declaringClass, fieldName, option);
+    }
+
+    public static OptionDescriptor create(String name, Class<?> type, String help, String[] extraHelp, Class<?> declaringClass, String fieldName, OptionKey<?> option) {
         assert option != null : declaringClass + "." + fieldName;
         OptionDescriptor result = option.getDescriptor();
         if (result == null) {
-            result = new OptionDescriptor(name, type, help, declaringClass, fieldName, option);
+            List<String> extraHelpList = extraHelp == null || extraHelp.length == 0 ? Collections.emptyList() : Collections.unmodifiableList(Arrays.asList(extraHelp));
+            result = new OptionDescriptor(name, type, help, extraHelpList, declaringClass, fieldName, option);
             option.setDescriptor(result);
         }
         assert result.name.equals(name) && result.type == type && result.declaringClass == declaringClass && result.fieldName.equals(fieldName) && result.optionKey == option;
         return result;
     }
 
-    private OptionDescriptor(String name, Class<?> type, String help, Class<?> declaringClass, String fieldName, OptionKey<?> optionKey) {
+    private OptionDescriptor(String name, Class<?> type, String help, List<String> extraHelp, Class<?> declaringClass, String fieldName, OptionKey<?> optionKey) {
         this.name = name;
         this.type = type;
         this.help = help;
+        this.extraHelp = extraHelp;
         this.optionKey = optionKey;
         this.declaringClass = declaringClass;
         this.fieldName = fieldName;
@@ -65,13 +78,24 @@
     }
 
     /**
-     * Gets a descriptive help message for the option.
+     * Gets a descriptive help message for the option. This message should be self contained without
+     * relying on {@link #getExtraHelp() extra help lines}.
+     *
+     * @see Option#help()
      */
     public String getHelp() {
         return help;
     }
 
     /**
+     * Gets extra lines of help text. These lines should not be subject to any line wrapping or
+     * formatting apart from indentation.
+     */
+    public List<String> getExtraHelp() {
+        return extraHelp;
+    }
+
+    /**
      * Gets the name of the option. It's up to the client of this object how to use the name to get
      * a user specified value for the option from the environment.
      */
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,15 +24,12 @@
 
 import java.io.PrintStream;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Comparator;
-import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
-import org.graalvm.compiler.options.EnumOptionKey.ValueHelp;
 import org.graalvm.util.EconomicMap;
 import org.graalvm.util.Equivalence;
 import org.graalvm.util.UnmodifiableEconomicMap;
@@ -165,10 +162,9 @@
      * @return {@code text} broken into lines
      */
     private static List<String> wrap(String text, int width) {
-        List<String> lines = Collections.singletonList(text);
+        List<String> lines = new ArrayList<>();
         if (text.length() > width) {
             String[] chunks = text.split("\\s+");
-            lines = new ArrayList<>();
             StringBuilder line = new StringBuilder();
             for (String chunk : chunks) {
                 if (line.length() + chunk.length() > width) {
@@ -178,22 +174,13 @@
                 if (line.length() != 0) {
                     line.append(' ');
                 }
-                String[] embeddedLines = chunk.split("%n", -2);
-                if (embeddedLines.length == 1) {
-                    line.append(chunk);
-                } else {
-                    for (int i = 0; i < embeddedLines.length; i++) {
-                        line.append(embeddedLines[i]);
-                        if (i < embeddedLines.length - 1) {
-                            lines.add(line.toString());
-                            line.setLength(0);
-                        }
-                    }
-                }
+                line.append(chunk);
             }
             if (line.length() != 0) {
                 lines.add(line.toString());
             }
+        } else {
+            lines.add(text);
         }
         return lines;
     }
@@ -222,24 +209,7 @@
             if (value instanceof String) {
                 value = '"' + String.valueOf(value) + '"';
             }
-            String help = desc.getHelp();
-            if (desc.getOptionKey() instanceof EnumOptionKey) {
-                EnumOptionKey<?> eoption = (EnumOptionKey<?>) desc.getOptionKey();
-                EnumSet<?> evalues = eoption.getAllValues();
-                String evaluesString = evalues.toString();
-                ValueHelp<?> valueHelp = eoption.getValueHelp();
-                if (help.length() > 0 && !help.endsWith(".")) {
-                    help += ".";
-                }
-                if (valueHelp == null) {
-                    help += " Valid values are: " + evaluesString.substring(1, evaluesString.length() - 1);
-                } else {
-                    for (Object o : evalues) {
-                        String vhelp = valueHelp.getHelp(o);
-                        help += "%n" + (vhelp == null ? o : vhelp);
-                    }
-                }
-            }
+
             String name = namePrefix + e.getKey();
             String assign = containsKey(desc.optionKey) ? ":=" : "=";
             String typeName = desc.getOptionKey() instanceof EnumOptionKey ? "String" : desc.getType().getSimpleName();
@@ -252,11 +222,16 @@
                 out.printf("%s[%s]%n", linePrefix, typeName);
             }
 
+            List<String> helpLines;
+            String help = desc.getHelp();
             if (help.length() != 0) {
-                List<String> helpLines = wrap(help, PROPERTY_LINE_WIDTH - PROPERTY_HELP_INDENT);
-                for (int i = 0; i < helpLines.size(); i++) {
-                    out.printf("%" + PROPERTY_HELP_INDENT + "s%s%n", "", helpLines.get(i));
-                }
+                helpLines = wrap(help, PROPERTY_LINE_WIDTH - PROPERTY_HELP_INDENT);
+                helpLines.addAll(desc.getExtraHelp());
+            } else {
+                helpLines = desc.getExtraHelp();
+            }
+            for (String line : helpLines) {
+                out.printf("%" + PROPERTY_HELP_INDENT + "s%s%n", "", line);
             }
         }
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java	Thu Aug 24 21:06:33 2017 +0000
@@ -30,6 +30,7 @@
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 import java.util.function.Consumer;
 
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
@@ -351,7 +352,7 @@
             }
         }
 
-        updateSourcePositions(invoke, inlineGraph, duplicates);
+        updateSourcePositions(invoke, inlineGraph, duplicates, !Objects.equals(inlineGraph.method(), inlineeMethod));
         if (stateAfter != null) {
             processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge, returnNodes.size() > 1);
             int callerLockDepth = stateAfter.nestedLockDepth();
@@ -569,14 +570,14 @@
     }
 
     @SuppressWarnings("try")
-    private static void updateSourcePositions(Invoke invoke, StructuredGraph inlineGraph, UnmodifiableEconomicMap<Node, Node> duplicates) {
+    private static void updateSourcePositions(Invoke invoke, StructuredGraph inlineGraph, UnmodifiableEconomicMap<Node, Node> duplicates, boolean isSubstitution) {
         if (inlineGraph.mayHaveNodeSourcePosition() && invoke.stateAfter() != null) {
             if (invoke.asNode().getNodeSourcePosition() == null) {
                 // Temporarily ignore the assert below.
                 return;
             }
 
-            JavaConstant constantReceiver = invoke.getInvokeKind().hasReceiver() ? invoke.getReceiver().asJavaConstant() : null;
+            JavaConstant constantReceiver = invoke.getInvokeKind().hasReceiver() && !isSubstitution ? invoke.getReceiver().asJavaConstant() : null;
             NodeSourcePosition invokePos = invoke.asNode().getNodeSourcePosition();
             assert invokePos != null : "missing source information";
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/AbstractInliningPolicy.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/AbstractInliningPolicy.java	Thu Aug 24 21:06:33 2017 +0000
@@ -75,10 +75,11 @@
     }
 
     private static boolean onlyForcedIntrinsics(Replacements replacements, InlineInfo info) {
-        for (int i = 0; i < info.numberOfMethods(); i++) {
-            if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i), info.invoke().bci())) {
-                return false;
-            }
+        if (!onlyIntrinsics(replacements, info)) {
+            return false;
+        }
+        if (!info.shouldInline()) {
+            return false;
         }
         return true;
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java	Thu Aug 24 21:06:33 2017 +0000
@@ -39,6 +39,8 @@
 import org.graalvm.util.EconomicMap;
 import org.graalvm.util.Equivalence;
 
+import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilities;
+
 /**
  * Compute probabilities for fixed nodes on the fly and cache them at {@link AbstractBeginNode}s.
  */
@@ -106,7 +108,7 @@
             }
         } else {
             ControlSplitNode split = (ControlSplitNode) current.predecessor();
-            probability = split.probability((AbstractBeginNode) current) * applyAsDouble(split);
+            probability = multiplyProbabilities(split.probability((AbstractBeginNode) current), applyAsDouble(split));
         }
         assert !Double.isNaN(probability) && !Double.isInfinite(probability) : current + " " + probability;
         cache.put(current, probability);
@@ -125,7 +127,7 @@
             result += applyAsDouble(endNode);
         }
         if (current instanceof LoopBeginNode) {
-            result *= ((LoopBeginNode) current).loopFrequency();
+            result = multiplyProbabilities(result, ((LoopBeginNode) current).loopFrequency());
         }
         return result;
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java	Thu Aug 24 21:06:33 2017 +0000
@@ -366,7 +366,7 @@
             return ((Class<?>) obj).getName();
         }
         if (obj instanceof ResolvedJavaType) {
-            return ((ResolvedJavaType) obj).getName();
+            return ((ResolvedJavaType) obj).toJavaName();
         }
         return null;
     }
@@ -403,7 +403,7 @@
 
     @Override
     public String fieldTypeName(ResolvedJavaField field) {
-        return field.getType().getName();
+        return field.getType().toJavaName();
     }
 
     @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java	Thu Aug 24 21:06:33 2017 +0000
@@ -31,6 +31,8 @@
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN;
 import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
 
+import java.util.Arrays;
+
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool.RoundingMode;
 import org.graalvm.compiler.nodes.ValueNode;
@@ -44,6 +46,7 @@
 import org.graalvm.compiler.nodes.java.AtomicReadAndWriteNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.replacements.ArraysSubstitutions;
 import org.graalvm.compiler.replacements.IntegerSubstitutions;
 import org.graalvm.compiler.replacements.LongSubstitutions;
 import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.UnsafeGetPlugin;
@@ -73,6 +76,7 @@
                 registerUnsafePlugins(invocationPlugins, replacementsBytecodeProvider);
                 registerStringPlugins(invocationPlugins, arch, replacementsBytecodeProvider);
                 registerMathPlugins(invocationPlugins, arch, arithmeticStubs, replacementsBytecodeProvider);
+                registerArraysEqualsPlugins(invocationPlugins, replacementsBytecodeProvider);
             }
         });
     }
@@ -229,4 +233,10 @@
             r.registerOptional4("put" + kind.name() + "Unaligned", Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, false));
         }
     }
+
+    private static void registerArraysEqualsPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
+        Registration r = new Registration(plugins, Arrays.class, bytecodeProvider);
+        r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", float[].class, float[].class);
+        r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", double[].class, double[].class);
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -232,68 +232,6 @@
     }
 
     @Test
-    public void testEqualsFloat() {
-        Object[] args1 = new Object[N];
-        Object[] args2 = new Object[N];
-        int n = 0;
-
-        // equal arrays
-        for (int i = 0; i < N / 2; i++, n++) {
-            args1[n] = new float[i];
-            args2[n] = new float[i];
-        }
-
-        // non-equal arrays
-        for (int i = 0; i < N / 2; i++, n++) {
-            float[] a2 = new float[i];
-            if (i > 0) {
-                a2[i - 1] = 1;
-            }
-            args1[n] = new float[i];
-            args2[n] = a2;
-        }
-
-        Class<?>[] parameterTypes = new Class<?>[]{float[].class, float[].class};
-        testSubstitution("arraysEqualsFloat", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
-    }
-
-    @SuppressWarnings("all")
-    public static boolean arraysEqualsFloat(float[] a, float[] b) {
-        return Arrays.equals(a, b);
-    }
-
-    @Test
-    public void testEqualsDouble() {
-        Object[] args1 = new Object[N];
-        Object[] args2 = new Object[N];
-        int n = 0;
-
-        // equal arrays
-        for (int i = 0; i < N / 2; i++, n++) {
-            args1[n] = new double[i];
-            args2[n] = new double[i];
-        }
-
-        // non-equal arrays
-        for (int i = 0; i < N / 2; i++, n++) {
-            double[] a2 = new double[i];
-            if (i > 0) {
-                a2[i - 1] = 1;
-            }
-            args1[n] = new double[i];
-            args2[n] = a2;
-        }
-
-        Class<?>[] parameterTypes = new Class<?>[]{double[].class, double[].class};
-        testSubstitution("arraysEqualsDouble", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2);
-    }
-
-    @SuppressWarnings("all")
-    public static boolean arraysEqualsDouble(double[] a, double[] b) {
-        return Arrays.equals(a, b);
-    }
-
-    @Test
     public void testEqualsNodeGVN() {
         test("testEqualsNodeGVNSnippet", true);
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DeoptimizeOnExceptionTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DeoptimizeOnExceptionTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,16 +24,25 @@
 
 import java.util.Random;
 
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.phases.HighTier;
 import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
+import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.common.AbstractInliningPhase;
 import org.graalvm.compiler.test.ExportingClassLoader;
 import org.junit.Assert;
+import org.junit.Assume;
 import org.junit.Test;
 import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
 
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.DeoptimizationReason;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /**
@@ -90,6 +99,61 @@
         return "SUCCESS";
     }
 
+    @Test
+    public void test3() {
+        Assume.assumeTrue("Only works on jdk8 right now", Java8OrEarlier);
+        ResolvedJavaMethod method = getResolvedJavaMethod("test3Snippet");
+
+        for (int i = 0; i < 2; i++) {
+            Result actual;
+            boolean expectedCompiledCode = (method.getProfilingInfo().getDeoptimizationCount(DeoptimizationReason.NotCompiledExceptionHandler) != 0);
+            InstalledCode code = getCode(method, null, false, true, new OptionValues(getInitialOptions(), HighTier.Options.Inline, false));
+            assertTrue(code.isValid());
+
+            try {
+                actual = new Result(code.executeVarargs(false), null);
+            } catch (Exception e) {
+                actual = new Result(null, e);
+            }
+
+            assertTrue(i > 0 == expectedCompiledCode, "expect compiled code to stay around after the first iteration");
+            assertEquals(new Result(expectedCompiledCode, null), actual);
+            assertTrue(expectedCompiledCode == code.isValid());
+        }
+    }
+
+    @Override
+    protected InlineInvokePlugin.InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        if (method.getName().equals("throwException")) {
+            if (b.getMethod().getProfilingInfo().getDeoptimizationCount(DeoptimizationReason.NotCompiledExceptionHandler) != 0) {
+                return InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION;
+            } else {
+                return InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_NO_EXCEPTION;
+            }
+        }
+        return super.bytecodeParserShouldInlineInvoke(b, method, args);
+    }
+
+    private static void throwException() throws Exception {
+        throw new Exception();
+    }
+
+    static int footprint;
+
+    public static boolean test3Snippet(boolean rethrowException) throws Exception {
+        try {
+            footprint = 1;
+            throwException();
+        } catch (Exception e) {
+            footprint = 2;
+            if (rethrowException) {
+                throw e;
+            }
+        }
+
+        return GraalDirectives.inCompiledCode();
+    }
+
     public static class MyClassLoader extends ExportingClassLoader {
         @Override
         protected Class<?> findClass(String className) throws ClassNotFoundException {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FloatArraysEqualsTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import java.util.Arrays;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.junit.Test;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class FloatArraysEqualsTest extends GraalCompilerTest {
+
+    public static boolean testFloatArraySnippet(float[] a, float[] b) {
+        return Arrays.equals(a, b);
+    }
+
+    private void testEqualInFloatArray(int arraySize, int index, float f1, float f2) {
+        if (arraySize > 0 && index >= 0 && index < arraySize) {
+            float[] a1 = new float[arraySize];
+            float[] a2 = new float[arraySize];
+            a1[index] = f1;
+            a2[index] = f2;
+            test("testFloatArraySnippet", a1, a2);
+        }
+    }
+
+    public static final int FLOAT_TAIL = 1;
+    public static final int FLOAT_8BYTE_ALIGNED = 2;
+    public static final int FLOAT_8BYTE_UNALIGNED = 3;
+    public static final int FLOAT_VECTOR_ALIGNED = 8;
+    public static final int FLOAT_VECTOR_UNALIGNED = 9;
+
+    @Test
+    public void testFloatArray() {
+        for (int size : new int[]{FLOAT_TAIL, FLOAT_8BYTE_ALIGNED, FLOAT_8BYTE_UNALIGNED, FLOAT_VECTOR_ALIGNED, FLOAT_VECTOR_UNALIGNED}) {
+            for (int index : new int[]{0, size - 1}) {
+                testEqualInFloatArray(size, index, 1024, 1024);
+                testEqualInFloatArray(size, index, 0.0f, -0.0f);
+                testEqualInFloatArray(size, index, Float.intBitsToFloat(0x7fc00000), Float.intBitsToFloat(0x7fc00000));
+                testEqualInFloatArray(size, index, Float.intBitsToFloat(0x7fc00000), Float.intBitsToFloat(0x7f800001));
+                testEqualInFloatArray(size, index, Float.intBitsToFloat(0x7fc00000), 1024);
+            }
+        }
+    }
+
+    public static boolean testDoubleArraySnippet(double[] a, double[] b) {
+        return Arrays.equals(a, b);
+    }
+
+    public static final int DOUBLE_8BYTE_ALIGNED = 1;
+    public static final int DOUBLE_VECTOR_ALIGNED = 4;
+    public static final int DOUBLE_VECTOR_UNALIGNED = 5;
+
+    private void testEqualInDoubleArray(int arraySize, int index, double d1, double d2) {
+        if (arraySize > 0 && index >= 0 && index < arraySize) {
+            double[] a1 = new double[arraySize];
+            double[] a2 = new double[arraySize];
+            a1[index] = d1;
+            a2[index] = d2;
+            test("testDoubleArraySnippet", a1, a2);
+        }
+    }
+
+    @Test
+    public void testDoubleArrayOrdinary() {
+        for (int size : new int[]{DOUBLE_8BYTE_ALIGNED, DOUBLE_VECTOR_ALIGNED, DOUBLE_VECTOR_UNALIGNED}) {
+            for (int index : new int[]{0, size - 1}) {
+                testEqualInDoubleArray(size, index, 1024, 1024);
+                testEqualInDoubleArray(size, index, 0.0d, -0.0d);
+                testEqualInDoubleArray(size, index, Double.longBitsToDouble(0x7ff8000000000000L), Double.longBitsToDouble(0x7ff8000000000000L));
+                testEqualInDoubleArray(size, index, Double.longBitsToDouble(0x7ff8000000000000L), Double.longBitsToDouble(0x7ff0000000000001L));
+                testEqualInDoubleArray(size, index, Double.longBitsToDouble(0x7ff8000000000000L), 1024);
+            }
+        }
+    }
+
+    public static boolean testFloatArrayWithPEASnippet0() {
+        return Arrays.equals(new float[]{0.0f}, new float[]{-0.0f});
+    }
+
+    public static boolean testFloatArrayWithPEASnippet1() {
+        return Arrays.equals(new float[]{Float.intBitsToFloat(0x7fc00000)}, new float[]{Float.intBitsToFloat(0x7fc00000)});
+    }
+
+    public static boolean testFloatArrayWithPEASnippet2() {
+        return Arrays.equals(new float[]{Float.intBitsToFloat(0x7fc00000)}, new float[]{Float.intBitsToFloat(0x7f800001)});
+
+    }
+
+    @Test
+    public void testFloatArrayWithPEA() {
+        test("testFloatArrayWithPEASnippet0");
+        test("testFloatArrayWithPEASnippet1");
+        test("testFloatArrayWithPEASnippet2");
+    }
+
+    public static boolean testDoubleArrayWithPEASnippet0() {
+        return Arrays.equals(new double[]{0.0d}, new double[]{-0.0d});
+    }
+
+    public static boolean testDoubleArrayWithPEASnippet1() {
+        return Arrays.equals(new double[]{Double.longBitsToDouble(0x7ff8000000000000L)}, new double[]{Double.longBitsToDouble(0x7ff8000000000000L)});
+    }
+
+    public static boolean testDoubleArrayWithPEASnippet2() {
+        return Arrays.equals(new double[]{Double.longBitsToDouble(0x7ff8000000000000L)}, new double[]{Double.longBitsToDouble(0x7ff0000000000001L)});
+    }
+
+    @Test
+    public void testDoubleArrayWithPEA() {
+        test("testDoubleArrayWithPEASnippet0");
+        test("testDoubleArrayWithPEASnippet1");
+        test("testDoubleArrayWithPEASnippet2");
+    }
+
+    public static final float[] FLOAT_ARRAY1 = new float[]{0.0f};
+    public static final float[] FLOAT_ARRAY2 = new float[]{-0.0f};
+    public static final float[] FLOAT_ARRAY3 = new float[]{Float.intBitsToFloat(0x7fc00000)};
+    public static final float[] FLOAT_ARRAY4 = new float[]{Float.intBitsToFloat(0x7f800001)};
+
+    public static final double[] DOUBLE_ARRAY1 = new double[]{0.0d};
+    public static final double[] DOUBLE_ARRAY2 = new double[]{-0.0d};
+    public static final double[] DOUBLE_ARRAY3 = new double[]{Double.longBitsToDouble(0x7ff8000000000000L)};
+    public static final double[] DOUBLE_ARRAY4 = new double[]{Double.longBitsToDouble(0x7ff0000000000001L)};
+
+    public static boolean testStableFloatArraySnippet0() {
+        return Arrays.equals(FLOAT_ARRAY1, FLOAT_ARRAY2);
+    }
+
+    public static boolean testStableFloatArraySnippet1() {
+        return Arrays.equals(FLOAT_ARRAY1, FLOAT_ARRAY2);
+    }
+
+    public static boolean testStableDoubleArraySnippet0() {
+        return Arrays.equals(DOUBLE_ARRAY1, DOUBLE_ARRAY2);
+    }
+
+    public static boolean testStableDoubleArraySnippet1() {
+        return Arrays.equals(DOUBLE_ARRAY3, DOUBLE_ARRAY4);
+    }
+
+    public void testStableArray(String methodName) {
+        ResolvedJavaMethod method = getResolvedJavaMethod(methodName);
+        Result expected = executeExpected(method, null);
+
+        StructuredGraph graph = parseEager(method, AllowAssumptions.YES);
+
+        for (ConstantNode constantNode : graph.getNodes().filter(ConstantNode.class).snapshot()) {
+            if (getConstantReflection().readArrayLength(constantNode.asJavaConstant()) != null) {
+                ConstantNode newConstantNode = ConstantNode.forConstant(constantNode.asJavaConstant(), 1, true, getMetaAccess());
+                newConstantNode = graph.unique(newConstantNode);
+                constantNode.replaceAndDelete(newConstantNode);
+            }
+        }
+
+        CompilationResult result = compile(method, graph);
+        InstalledCode code = addMethod(graph.getDebug(), method, result);
+
+        Result actual;
+
+        try {
+            actual = new Result(code.executeVarargs(), null);
+        } catch (Exception e) {
+            actual = new Result(null, e);
+        }
+
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testStableArray() {
+        testStableArray("testStableFloatArraySnippet0");
+        testStableArray("testStableFloatArraySnippet1");
+        testStableArray("testStableDoubleArraySnippet0");
+        testStableArray("testStableDoubleArraySnippet1");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/UnsafeBooleanAccessTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import java.lang.reflect.Field;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.junit.Test;
+
+public class UnsafeBooleanAccessTest extends GraalCompilerTest {
+
+    private static short onHeapMemory;
+
+    private static final Object onHeapMemoryBase;
+    private static final long onHeapMemoryOffset;
+
+    static {
+        try {
+            Field staticField = UnsafeBooleanAccessTest.class.getDeclaredField("onHeapMemory");
+            onHeapMemoryBase = UNSAFE.staticFieldBase(staticField);
+            onHeapMemoryOffset = UNSAFE.staticFieldOffset(staticField);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static boolean testGetBooleanSnippet() {
+        UNSAFE.putShort(onHeapMemoryBase, onHeapMemoryOffset, (short) 0x0204);
+        return UNSAFE.getBoolean(onHeapMemoryBase, onHeapMemoryOffset);
+    }
+
+    @Test
+    public void testGetBoolean() {
+        test("testGetBooleanSnippet");
+    }
+
+    public static short testPutBooleanSnippet() {
+        UNSAFE.putShort(onHeapMemoryBase, onHeapMemoryOffset, (short) 0x0204);
+        boolean bool = UNSAFE.getBoolean(onHeapMemoryBase, onHeapMemoryOffset);
+        UNSAFE.putBoolean(onHeapMemoryBase, onHeapMemoryOffset, bool);
+        return onHeapMemory;
+    }
+
+    @Test
+    public void testPutBoolean() {
+        test("testPutBooleanSnippet");
+    }
+
+    public static boolean testAndBooleanSnippet() {
+        UNSAFE.putShort(onHeapMemoryBase, onHeapMemoryOffset, (short) 0x0204);
+        boolean bool0 = UNSAFE.getBoolean(onHeapMemoryBase, onHeapMemoryOffset);
+        boolean bool1 = UNSAFE.getBoolean(onHeapMemoryBase, onHeapMemoryOffset + 1);
+        return bool0 & bool1;
+    }
+
+    @Test
+    public void testAndBoolean() {
+        test("testAndBooleanSnippet");
+    }
+
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java	Thu Aug 24 21:06:33 2017 +0000
@@ -59,8 +59,10 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
 import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
 import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
+import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
 import org.graalvm.compiler.nodes.calc.IsNullNode;
 import org.graalvm.compiler.nodes.calc.LeftShiftNode;
 import org.graalvm.compiler.nodes.calc.NarrowNode;
@@ -577,7 +579,7 @@
         } else {
             memoryRead.setGuard(guard);
         }
-        ValueNode readValue = implicitLoadConvert(graph, readKind, memoryRead, compressible);
+        ValueNode readValue = performBooleanCoercionIfNecessary(implicitLoadConvert(graph, readKind, memoryRead, compressible), readKind);
         load.replaceAtUsages(readValue);
         return memoryRead;
     }
@@ -592,11 +594,20 @@
         // An unsafe read must not float otherwise it may float above
         // a test guaranteeing the read is safe.
         memoryRead.setForceFixed(true);
-        ValueNode readValue = implicitLoadConvert(graph, readKind, memoryRead, false);
+        ValueNode readValue = performBooleanCoercionIfNecessary(implicitLoadConvert(graph, readKind, memoryRead, false), readKind);
         load.replaceAtUsages(readValue);
         graph.replaceFixedWithFixed(load, memoryRead);
     }
 
+    private static ValueNode performBooleanCoercionIfNecessary(ValueNode readValue, JavaKind readKind) {
+        if (readKind == JavaKind.Boolean) {
+            StructuredGraph graph = readValue.graph();
+            IntegerEqualsNode eq = graph.addOrUnique(new IntegerEqualsNode(readValue, ConstantNode.forInt(0, graph)));
+            return graph.addOrUnique(new ConditionalNode(eq, ConstantNode.forBoolean(false, graph), ConstantNode.forBoolean(true, graph)));
+        }
+        return readValue;
+    }
+
     protected void lowerUnsafeStoreNode(RawStoreNode store) {
         StructuredGraph graph = store.graph();
         boolean compressible = store.value().getStackKind() == JavaKind.Object;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Thu Aug 24 21:06:33 2017 +0000
@@ -189,9 +189,7 @@
         r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", short[].class, short[].class);
         r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", char[].class, char[].class);
         r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", int[].class, int[].class);
-        r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", float[].class, float[].class);
         r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", long[].class, long[].class);
-        r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", double[].class, double[].class);
     }
 
     private static void registerArrayPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java	Thu Aug 24 21:06:33 2017 +0000
@@ -95,11 +95,16 @@
         return length;
     }
 
+    private static boolean isNaNFloat(JavaConstant constant) {
+        JavaKind kind = constant.getJavaKind();
+        return (kind == JavaKind.Float && Float.isNaN(constant.asFloat())) || (kind == JavaKind.Double && Double.isNaN(constant.asDouble()));
+    }
+
     private static boolean arrayEquals(ConstantReflectionProvider constantReflection, JavaConstant a, JavaConstant b, int len) {
         for (int i = 0; i < len; i++) {
             JavaConstant aElem = constantReflection.readArrayElement(a, i);
             JavaConstant bElem = constantReflection.readArrayElement(b, i);
-            if (!constantReflection.constantEquals(aElem, bElem)) {
+            if (!constantReflection.constantEquals(aElem, bElem) && !(isNaNFloat(aElem) && isNaNFloat(bElem))) {
                 return false;
             }
         }
@@ -145,8 +150,28 @@
                     ValueNode entry1 = tool.getEntry(virtual1, i);
                     ValueNode entry2 = tool.getEntry(virtual2, i);
                     if (entry1 != entry2) {
-                        // the contents might be different
-                        allEqual = false;
+                        if (entry1 instanceof ConstantNode && entry2 instanceof ConstantNode) {
+                            // Float NaN constants are different constant nodes but treated as
+                            // equal in Arrays.equals([F[F) or Arrays.equals([D[D).
+                            if (entry1.getStackKind() == JavaKind.Float && entry2.getStackKind() == JavaKind.Float) {
+                                float value1 = ((JavaConstant) ((ConstantNode) entry1).asConstant()).asFloat();
+                                float value2 = ((JavaConstant) ((ConstantNode) entry2).asConstant()).asFloat();
+                                if (Float.floatToIntBits(value1) != Float.floatToIntBits(value2)) {
+                                    allEqual = false;
+                                }
+                            } else if (entry1.getStackKind() == JavaKind.Double && entry2.getStackKind() == JavaKind.Double) {
+                                double value1 = ((JavaConstant) ((ConstantNode) entry1).asConstant()).asDouble();
+                                double value2 = ((JavaConstant) ((ConstantNode) entry2).asConstant()).asDouble();
+                                if (Double.doubleToLongBits(value1) != Double.doubleToLongBits(value2)) {
+                                    allEqual = false;
+                                }
+                            } else {
+                                allEqual = false;
+                            }
+                        } else {
+                            // the contents might be different
+                            allEqual = false;
+                        }
                     }
                     if (entry1.stamp().alwaysDistinct(entry2.stamp())) {
                         // the contents are different
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ExplodeLoopNode.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ExplodeLoopNode.java	Thu Aug 24 21:06:33 2017 +0000
@@ -57,7 +57,7 @@
             for (Node n : currentNext.cfgSuccessors()) {
                 succs.add(n);
             }
-            if (succs.size() == 1) {
+            if (succs.size() == 1 && succs.get(0) != currentNext) {
                 currentNext = succs.get(0);
             } else {
                 return null;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerMulHighNode.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerMulHighNode.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,69 +25,28 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
-import java.util.function.BiFunction;
-
-import org.graalvm.compiler.core.common.type.IntegerStamp;
-import org.graalvm.compiler.core.common.type.Stamp;
-import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.MulHigh;
 import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
 import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.calc.BinaryNode;
-import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 
-import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.PrimitiveConstant;
 import jdk.vm.ci.meta.Value;
 
 @NodeInfo(shortName = "*H", cycles = CYCLES_2, size = SIZE_2)
-public final class IntegerMulHighNode extends BinaryNode implements ArithmeticLIRLowerable {
+public final class IntegerMulHighNode extends BinaryArithmeticNode<MulHigh> implements Canonicalizable.BinaryCommutative<ValueNode> {
     public static final NodeClass<IntegerMulHighNode> TYPE = NodeClass.create(IntegerMulHighNode.class);
 
     public IntegerMulHighNode(ValueNode x, ValueNode y) {
-        this((IntegerStamp) x.stamp().unrestricted(), x, y);
-    }
-
-    public IntegerMulHighNode(IntegerStamp stamp, ValueNode x, ValueNode y) {
-        super(TYPE, stamp, x, y);
-    }
-
-    /**
-     * Determines the minimum and maximum result of this node for the given inputs and returns the
-     * result of the given BiFunction on the minimum and maximum values.
-     */
-    private <T> T processExtremes(Stamp forX, Stamp forY, BiFunction<Long, Long, T> op) {
-        IntegerStamp xStamp = (IntegerStamp) forX;
-        IntegerStamp yStamp = (IntegerStamp) forY;
-
-        JavaKind kind = getStackKind();
-        assert kind == JavaKind.Int || kind == JavaKind.Long;
-        long[] xExtremes = {xStamp.lowerBound(), xStamp.upperBound()};
-        long[] yExtremes = {yStamp.lowerBound(), yStamp.upperBound()};
-        long min = Long.MAX_VALUE;
-        long max = Long.MIN_VALUE;
-        for (long a : xExtremes) {
-            for (long b : yExtremes) {
-                long result = kind == JavaKind.Int ? multiplyHigh((int) a, (int) b) : multiplyHigh(a, b);
-                min = Math.min(min, result);
-                max = Math.max(max, result);
-            }
-        }
-        return op.apply(min, max);
-    }
-
-    @Override
-    public Stamp foldStamp(Stamp stampX, Stamp stampY) {
-        return processExtremes(stampX, stampY, (min, max) -> StampFactory.forInteger(getStackKind(), min, max));
-    }
-
-    @SuppressWarnings("cast")
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        return processExtremes(forX.stamp(), forY.stamp(), (min, max) -> min == (long) max ? ConstantNode.forIntegerKind(getStackKind(), min) : this);
+        super(TYPE, ArithmeticOpTable::getMulHigh, x, y);
     }
 
     @Override
@@ -97,29 +56,35 @@
         nodeValueMap.setResult(this, gen.emitMulHigh(a, b));
     }
 
-    public static int multiplyHigh(int x, int y) {
-        long r = (long) x * (long) y;
-        return (int) (r >> 32);
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forX.isConstant() && !forY.isConstant()) {
+            // we try to swap and canonicalize
+            ValueNode improvement = canonical(tool, forY, forX);
+            if (improvement != this) {
+                return improvement;
+            }
+            // if this fails we only swap
+            return new IntegerMulHighNode(forY, forX);
+        }
+        return canonical(this, forY);
     }
 
-    public static long multiplyHigh(long x, long y) {
-        // Checkstyle: stop
-        long x0, y0, z0;
-        long x1, y1, z1, z2, t;
-        // Checkstyle: resume
-
-        x0 = x & 0xFFFFFFFFL;
-        x1 = x >> 32;
-
-        y0 = y & 0xFFFFFFFFL;
-        y1 = y >> 32;
-
-        z0 = x0 * y0;
-        t = x1 * y0 + (z0 >>> 32);
-        z1 = t & 0xFFFFFFFFL;
-        z2 = t >> 32;
-        z1 += x0 * y1;
-
-        return x1 * y1 + z2 + (z1 >> 32);
+    private static ValueNode canonical(IntegerMulHighNode self, ValueNode forY) {
+        if (forY.isConstant()) {
+            Constant c = forY.asConstant();
+            if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) {
+                long i = ((PrimitiveConstant) c).asLong();
+                if (i == 0 || i == 1) {
+                    return ConstantNode.forIntegerStamp(self.stamp(), 0);
+                }
+            }
+        }
+        return self;
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/UnsignedMulHighNode.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/UnsignedMulHighNode.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,86 +25,28 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
-import java.util.function.BiFunction;
-
-import org.graalvm.compiler.core.common.type.IntegerStamp;
-import org.graalvm.compiler.core.common.type.Stamp;
-import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.UMulHigh;
 import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
 import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.calc.BinaryNode;
-import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 
-import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.PrimitiveConstant;
 import jdk.vm.ci.meta.Value;
 
 @NodeInfo(shortName = "|*H|", cycles = CYCLES_2, size = SIZE_2)
-public final class UnsignedMulHighNode extends BinaryNode implements ArithmeticLIRLowerable {
-
+public final class UnsignedMulHighNode extends BinaryArithmeticNode<UMulHigh> implements Canonicalizable.BinaryCommutative<ValueNode> {
     public static final NodeClass<UnsignedMulHighNode> TYPE = NodeClass.create(UnsignedMulHighNode.class);
 
     public UnsignedMulHighNode(ValueNode x, ValueNode y) {
-        this((IntegerStamp) x.stamp().unrestricted(), x, y);
-    }
-
-    public UnsignedMulHighNode(IntegerStamp stamp, ValueNode x, ValueNode y) {
-        super(TYPE, stamp, x, y);
-    }
-
-    private static long[] getUnsignedExtremes(IntegerStamp stamp) {
-        if (stamp.lowerBound() < 0 && stamp.upperBound() >= 0) {
-            /*
-             * If -1 and 0 are both in the signed range, then we can't say anything about the
-             * unsigned range, so we have to return [0, MAX_UNSIGNED].
-             */
-            return new long[]{0, -1L};
-        } else {
-            return new long[]{stamp.lowerBound(), stamp.upperBound()};
-        }
-    }
-
-    /**
-     * Determines the minimum and maximum result of this node for the given inputs and returns the
-     * result of the given BiFunction on the minimum and maximum values. Note that the minima and
-     * maxima are calculated using signed min/max functions, while the values themselves are
-     * unsigned.
-     */
-    private <T> T processExtremes(Stamp forX, Stamp forY, BiFunction<Long, Long, T> op) {
-        IntegerStamp xStamp = (IntegerStamp) forX;
-        IntegerStamp yStamp = (IntegerStamp) forY;
-
-        JavaKind kind = getStackKind();
-        assert kind == JavaKind.Int || kind == JavaKind.Long;
-        long[] xExtremes = getUnsignedExtremes(xStamp);
-        long[] yExtremes = getUnsignedExtremes(yStamp);
-        long min = Long.MAX_VALUE;
-        long max = Long.MIN_VALUE;
-        for (long a : xExtremes) {
-            for (long b : yExtremes) {
-                long result = kind == JavaKind.Int ? multiplyHighUnsigned((int) a, (int) b) : multiplyHighUnsigned(a, b);
-                min = Math.min(min, result);
-                max = Math.max(max, result);
-            }
-        }
-        return op.apply(min, max);
-    }
-
-    @SuppressWarnings("cast")
-    @Override
-    public Stamp foldStamp(Stamp stampX, Stamp stampY) {
-        // if min is negative, then the value can reach into the unsigned range
-        return processExtremes(stampX, stampY, (min, max) -> (min == (long) max || min >= 0) ? StampFactory.forInteger(getStackKind(), min, max) : StampFactory.forKind(getStackKind()));
-    }
-
-    @SuppressWarnings("cast")
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        return processExtremes(forX.stamp(), forY.stamp(), (min, max) -> min == (long) max ? ConstantNode.forIntegerKind(getStackKind(), min) : this);
+        super(TYPE, ArithmeticOpTable::getUMulHigh, x, y);
     }
 
     @Override
@@ -114,31 +56,35 @@
         nodeValueMap.setResult(this, gen.emitUMulHigh(a, b));
     }
 
-    public static int multiplyHighUnsigned(int x, int y) {
-        long xl = x & 0xFFFFFFFFL;
-        long yl = y & 0xFFFFFFFFL;
-        long r = xl * yl;
-        return (int) (r >> 32);
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forX.isConstant() && !forY.isConstant()) {
+            // we try to swap and canonicalize
+            ValueNode improvement = canonical(tool, forY, forX);
+            if (improvement != this) {
+                return improvement;
+            }
+            // if this fails we only swap
+            return new UnsignedMulHighNode(forY, forX);
+        }
+        return canonical(this, forY);
     }
 
-    public static long multiplyHighUnsigned(long x, long y) {
-        // Checkstyle: stop
-        long x0, y0, z0;
-        long x1, y1, z1, z2, t;
-        // Checkstyle: resume
-
-        x0 = x & 0xFFFFFFFFL;
-        x1 = x >>> 32;
-
-        y0 = y & 0xFFFFFFFFL;
-        y1 = y >>> 32;
-
-        z0 = x0 * y0;
-        t = x1 * y0 + (z0 >>> 32);
-        z1 = t & 0xFFFFFFFFL;
-        z2 = t >>> 32;
-        z1 += x0 * y1;
-
-        return x1 * y1 + z2 + (z1 >>> 32);
+    private static ValueNode canonical(UnsignedMulHighNode self, ValueNode forY) {
+        if (forY.isConstant()) {
+            Constant c = forY.asConstant();
+            if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) {
+                long i = ((PrimitiveConstant) c).asLong();
+                if (i == 0 || i == 1) {
+                    return ConstantNode.forIntegerStamp(self.stamp(), 0);
+                }
+            }
+        }
+        return self;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/TestJMHBlackbox.java	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package micro.benchmarks;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Warmup;
+
+@Warmup(iterations = 1)
+@Measurement(iterations = 1)
+@Fork(1)
+/**
+ * This dummy class is used to verify that the JMH microbenchmarking environment is set up properly.
+ */
+public class TestJMHBlackbox {
+
+    @Benchmark
+    public void testJMH() {
+        // This method was intentionally left blank.
+    }
+
+}
--- a/hotspot/src/os/aix/vm/os_aix.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os/aix/vm/os_aix.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -863,20 +863,31 @@
 
   // Calculate stack size if it's not specified by caller.
   size_t stack_size = os::Posix::get_initial_stack_size(thr_type, req_stack_size);
-  int status = pthread_attr_setstacksize(&attr, stack_size);
-  assert_status(status == 0, status, "pthread_attr_setstacksize");
+
+  // On Aix, pthread_attr_setstacksize fails with huge values and leaves the
+  // thread size in attr unchanged. If this is the minimal stack size as set
+  // by pthread_attr_init this leads to crashes after thread creation. E.g. the
+  // guard pages might not fit on the tiny stack created.
+  int ret = pthread_attr_setstacksize(&attr, stack_size);
+  if (ret != 0) {
+    log_warning(os, thread)("The thread stack size specified is invalid: " SIZE_FORMAT "k",
+                            stack_size / K);
+  }
 
   // Configure libc guard page.
-  pthread_attr_setguardsize(&attr, os::Aix::default_guard_size(thr_type));
-
-  pthread_t tid;
-  int ret = pthread_create(&tid, &attr, (void* (*)(void*)) thread_native_entry, thread);
-
-  char buf[64];
+  ret = pthread_attr_setguardsize(&attr, os::Aix::default_guard_size(thr_type));
+
+  pthread_t tid = 0;
   if (ret == 0) {
+    ret = pthread_create(&tid, &attr, (void* (*)(void*)) thread_native_entry, thread);
+  }
+
+  if (ret == 0) {
+    char buf[64];
     log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ",
       (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr));
   } else {
+    char buf[64];
     log_warning(os, thread)("Failed to start thread - pthread_create failed (%d=%s) for attributes: %s.",
       ret, os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr));
   }
--- a/hotspot/src/os/bsd/vm/os_bsd.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os/bsd/vm/os_bsd.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -952,7 +952,7 @@
   if (now <= prev) {
     return prev;   // same or retrograde time;
   }
-  const uint64_t obsv = Atomic::cmpxchg(now, (volatile jlong*)&Bsd::_max_abstime, prev);
+  const uint64_t obsv = Atomic::cmpxchg(now, &Bsd::_max_abstime, prev);
   assert(obsv >= prev, "invariant");   // Monotonicity
   // If the CAS succeeded then we're done and return "now".
   // If the CAS failed and the observed value "obsv" is >= now then
--- a/hotspot/src/os/linux/vm/os_linux.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os/linux/vm/os_linux.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1747,9 +1747,9 @@
     {EM_SPARCV9,     EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"},
     {EM_PPC,         EM_PPC,     ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"},
 #if defined(VM_LITTLE_ENDIAN)
-    {EM_PPC64,       EM_PPC64,   ELFCLASS64, ELFDATA2LSB, (char*)"Power PC 64"},
+    {EM_PPC64,       EM_PPC64,   ELFCLASS64, ELFDATA2LSB, (char*)"Power PC 64 LE"},
 #else
-    {EM_PPC64,       EM_PPC64,   ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64 LE"},
+    {EM_PPC64,       EM_PPC64,   ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"},
 #endif
     {EM_ARM,         EM_ARM,     ELFCLASS32,   ELFDATA2LSB, (char*)"ARM"},
     {EM_S390,        EM_S390,    ELFCLASSNONE, ELFDATA2MSB, (char*)"IBM System/390"},
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1197,7 +1197,7 @@
   if (now <= prev) {
     return prev;   // same or retrograde time;
   }
-  const hrtime_t obsv = Atomic::cmpxchg(now, (volatile jlong*)&max_hrtime, prev);
+  const hrtime_t obsv = Atomic::cmpxchg(now, &max_hrtime, prev);
   assert(obsv >= prev, "invariant");   // Monotonicity
   // If the CAS succeeded then we're done and return "now".
   // If the CAS failed and the observed value "obsv" is >= now then
--- a/hotspot/src/os_cpu/aix_ppc/vm/atomic_aix_ppc.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os_cpu/aix_ppc/vm/atomic_aix_ppc.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -30,6 +30,8 @@
 #error "Atomic currently only impleneted for PPC64"
 #endif
 
+#include "utilities/debug.hpp"
+
 // Implementation of class atomic
 
 inline void Atomic::store    (jbyte    store_value, jbyte*    dest) { *dest = store_value; }
@@ -306,8 +308,13 @@
   }
 }
 
-#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE
-inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) {
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(1 == sizeof(T));
 
   // Note that cmpxchg guarantees a two-way memory barrier across
   // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not
@@ -368,16 +375,22 @@
 
   cmpxchg_post_membar(order);
 
-  return (jbyte)(unsigned char)old_value;
+  return PrimitiveConversions::cast<T>((unsigned char)old_value);
 }
 
-inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) {
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(4 == sizeof(T));
 
   // Note that cmpxchg guarantees a two-way memory barrier across
   // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not
   // specified otherwise (see atomic.hpp).
 
-  unsigned int old_value;
+  T old_value;
   const uint64_t zero = 0;
 
   cmpxchg_pre_membar(order);
@@ -412,16 +425,22 @@
 
   cmpxchg_post_membar(order);
 
-  return (jint) old_value;
+  return old_value;
 }
 
-inline jlong Atomic::cmpxchg(jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) {
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(8 == sizeof(T));
 
   // Note that cmpxchg guarantees a two-way memory barrier across
   // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not
   // specified otherwise (see atomic.hpp).
 
-  long old_value;
+  T old_value;
   const uint64_t zero = 0;
 
   cmpxchg_pre_membar(order);
@@ -456,15 +475,7 @@
 
   cmpxchg_post_membar(order);
 
-  return (jlong) old_value;
-}
-
-inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) {
-  return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order);
-}
-
-inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) {
-  return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order);
+  return old_value;
 }
 
 #undef strasm_sync
--- a/hotspot/src/os_cpu/bsd_x86/vm/atomic_bsd_x86.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os_cpu/bsd_x86/vm/atomic_bsd_x86.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -25,8 +25,6 @@
 #ifndef OS_CPU_BSD_X86_VM_ATOMIC_BSD_X86_HPP
 #define OS_CPU_BSD_X86_VM_ATOMIC_BSD_X86_HPP
 
-#include "runtime/os.hpp"
-
 // Implementation of class atomic
 
 inline void Atomic::store    (jbyte    store_value, jbyte*    dest) { *dest = store_value; }
@@ -81,8 +79,13 @@
   return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
 }
 
-#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE
-inline jbyte    Atomic::cmpxchg    (jbyte    exchange_value, volatile jbyte*    dest, jbyte    compare_value, cmpxchg_memory_order order) {
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order /* order */) const {
+  STATIC_ASSERT(1 == sizeof(T));
   __asm__ volatile (  "lock cmpxchgb %1,(%3)"
                     : "=a" (exchange_value)
                     : "q" (exchange_value), "a" (compare_value), "r" (dest)
@@ -90,7 +93,13 @@
   return exchange_value;
 }
 
-inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value, cmpxchg_memory_order order) {
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order /* order */) const {
+  STATIC_ASSERT(4 == sizeof(T));
   __asm__ volatile (  "lock cmpxchgl %1,(%3)"
                     : "=a" (exchange_value)
                     : "r" (exchange_value), "a" (compare_value), "r" (dest)
@@ -137,7 +146,13 @@
   return exchange_value;
 }
 
-inline jlong    Atomic::cmpxchg    (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value, cmpxchg_memory_order order) {
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order /* order */) const {
+  STATIC_ASSERT(8 == sizeof(T));
   __asm__ __volatile__ (  "lock cmpxchgq %1,(%3)"
                         : "=a" (exchange_value)
                         : "r" (exchange_value), "a" (compare_value), "r" (dest)
@@ -145,14 +160,6 @@
   return exchange_value;
 }
 
-inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) {
-  return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order);
-}
-
-inline void*    Atomic::cmpxchg_ptr(void*    exchange_value, volatile void*     dest, void*    compare_value, cmpxchg_memory_order order) {
-  return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order);
-}
-
 inline jlong Atomic::load(const volatile jlong* src) { return *src; }
 
 #else // !AMD64
@@ -184,16 +191,14 @@
   void _Atomic_move_long(const volatile jlong* src, volatile jlong* dst);
 }
 
-inline jlong    Atomic::cmpxchg    (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value, cmpxchg_memory_order order) {
-  return _Atomic_cmpxchg_long(exchange_value, dest, compare_value, os::is_MP());
-}
-
-inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) {
-  return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order);
-}
-
-inline void*    Atomic::cmpxchg_ptr(void*    exchange_value, volatile void*     dest, void*    compare_value, cmpxchg_memory_order order) {
-  return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order);
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(8 == sizeof(T));
+  return cmpxchg_using_helper<jlong>(_Atomic_cmpxchg_long, exchange_value, dest, compare_value);
 }
 
 inline jlong Atomic::load(const volatile jlong* src) {
--- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -908,6 +908,12 @@
   // workaround for OS X 10.9.0 (Mavericks)
   // pthread_get_stacksize_np returns 128 pages even though the actual size is 2048 pages
   if (pthread_main_np() == 1) {
+    // At least on Mac OS 10.12 we have observed stack sizes not aligned
+    // to pages boundaries. This can be provoked by e.g. setrlimit() (ulimit -s xxxx in the
+    // shell). Apparently Mac OS actually rounds upwards to next multiple of page size,
+    // however, we round downwards here to be on the safe side.
+    *size = align_down(*size, getpagesize());
+
     if ((*size) < (DEFAULT_MAIN_THREAD_STACK_PAGES * (size_t)getpagesize())) {
       char kern_osrelease[256];
       size_t kern_osrelease_size = sizeof(kern_osrelease);
--- a/hotspot/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -57,9 +57,9 @@
 /* Perform an atomic compare and swap: if the current value of `*PTR'
    is OLDVAL, then write NEWVAL into `*PTR'.  Return the contents of
    `*PTR' before the operation.*/
-static inline int m68k_compare_and_swap(volatile int *ptr,
-                                        int oldval,
-                                        int newval) {
+static inline int m68k_compare_and_swap(int newval,
+                                        volatile int *ptr,
+                                        int oldval) {
   for (;;) {
       int prev = *ptr;
       if (prev != oldval)
@@ -118,9 +118,9 @@
 /* Perform an atomic compare and swap: if the current value of `*PTR'
    is OLDVAL, then write NEWVAL into `*PTR'.  Return the contents of
    `*PTR' before the operation.*/
-static inline int arm_compare_and_swap(volatile int *ptr,
-                                       int oldval,
-                                       int newval) {
+static inline int arm_compare_and_swap(int newval,
+                                       volatile int *ptr,
+                                       int oldval) {
   for (;;) {
       int prev = *ptr;
       if (prev != oldval)
@@ -267,55 +267,38 @@
                            (volatile intptr_t*) dest);
 }
 
-inline jint Atomic::cmpxchg(jint exchange_value,
-                            volatile jint* dest,
-                            jint compare_value,
-                            cmpxchg_memory_order order) {
+// No direct support for cmpxchg of bytes; emulate using int.
+template<>
+struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {};
+
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_CAST(4 == sizeof(T));
 #ifdef ARM
-  return arm_compare_and_swap(dest, compare_value, exchange_value);
+  return cmpxchg_using_helper<int>(arm_compare_and_swap, exchange_value, dest, compare_value);
 #else
 #ifdef M68K
-  return m68k_compare_and_swap(dest, compare_value, exchange_value);
+  return cmpxchg_using_helper<int>(m68k_compare_and_swap, exchange_value, dest, compare_value);
 #else
   return __sync_val_compare_and_swap(dest, compare_value, exchange_value);
 #endif // M68K
 #endif // ARM
 }
 
-inline jlong Atomic::cmpxchg(jlong exchange_value,
-                             volatile jlong* dest,
-                             jlong compare_value,
-                             cmpxchg_memory_order order) {
-
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_CAST(8 == sizeof(T));
   return __sync_val_compare_and_swap(dest, compare_value, exchange_value);
 }
 
-inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value,
-                                    volatile intptr_t* dest,
-                                    intptr_t compare_value,
-                                    cmpxchg_memory_order order) {
-#ifdef ARM
-  return arm_compare_and_swap(dest, compare_value, exchange_value);
-#else
-#ifdef M68K
-  return m68k_compare_and_swap(dest, compare_value, exchange_value);
-#else
-  return __sync_val_compare_and_swap(dest, compare_value, exchange_value);
-#endif // M68K
-#endif // ARM
-}
-
-inline void* Atomic::cmpxchg_ptr(void* exchange_value,
-                                 volatile void* dest,
-                                 void* compare_value,
-                                 cmpxchg_memory_order order) {
-
-  return (void *) cmpxchg_ptr((intptr_t) exchange_value,
-                              (volatile intptr_t*) dest,
-                              (intptr_t) compare_value,
-                              order);
-}
-
 inline jlong Atomic::load(const volatile jlong* src) {
   volatile jlong dest;
   os::atomic_copy64(src, &dest);
--- a/hotspot/src/os_cpu/linux_aarch64/vm/atomic_linux_aarch64.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os_cpu/linux_aarch64/vm/atomic_linux_aarch64.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -85,9 +85,13 @@
                            (volatile intptr_t*) dest);
 }
 
-template <typename T> T generic_cmpxchg(T exchange_value, volatile T* dest,
-                                        T compare_value, cmpxchg_memory_order order)
-{
+template<size_t byte_size>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<byte_size>::operator()(T exchange_value,
+                                                        T volatile* dest,
+                                                        T compare_value,
+                                                        cmpxchg_memory_order order) const {
+  STATIC_ASSERT(byte_size == sizeof(T));
   if (order == memory_order_relaxed) {
     T value = compare_value;
     __atomic_compare_exchange(dest, &value, &exchange_value, /*weak*/false,
@@ -98,17 +102,6 @@
   }
 }
 
-#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE
-inline jbyte Atomic::cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order)
-{
-  return generic_cmpxchg(exchange_value, dest, compare_value, order);
-}
-
-inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order)
-{
-  return generic_cmpxchg(exchange_value, dest, compare_value, order);
-}
-
 inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
 inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
 
@@ -139,24 +132,6 @@
   return res;
 }
 
-inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order)
-{
-  return generic_cmpxchg(exchange_value, dest, compare_value, order);
-}
-
-inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order)
-{
-  return generic_cmpxchg(exchange_value, dest, compare_value, order);
-}
-
-inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order)
-{
-  return (void *) cmpxchg_ptr((intptr_t) exchange_value,
-                              (volatile intptr_t*) dest,
-                              (intptr_t) compare_value,
-                              order);
-}
-
 inline jlong Atomic::load(const volatile jlong* src) { return *src; }
 
 #endif // OS_CPU_LINUX_AARCH64_VM_ATOMIC_LINUX_AARCH64_HPP
--- a/hotspot/src/os_cpu/linux_arm/vm/atomic_linux_arm.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os_cpu/linux_arm/vm/atomic_linux_arm.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -200,9 +200,38 @@
 
 // The memory_order parameter is ignored - we always provide the strongest/most-conservative ordering
 
-inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) {
+// No direct support for cmpxchg of bytes; emulate using int.
+template<>
+struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {};
+
+#ifndef AARCH64
+
+inline jint reorder_cmpxchg_func(jint exchange_value,
+                                 jint volatile* dest,
+                                 jint compare_value) {
+  // Warning:  Arguments are swapped to avoid moving them for kernel call
+  return (*os::atomic_cmpxchg_func)(compare_value, exchange_value, dest);
+}
+
+inline jlong reorder_cmpxchg_long_func(jlong exchange_value,
+                                       jlong volatile* dest,
+                                       jlong compare_value) {
+  assert(VM_Version::supports_cx8(), "Atomic compare and exchange jlong not supported on this architecture!");
+  // Warning:  Arguments are swapped to avoid moving them for kernel call
+  return (*os::atomic_cmpxchg_long_func)(compare_value, exchange_value, dest);
+}
+
+#endif // !AARCH64
+
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(4 == sizeof(T));
 #ifdef AARCH64
-  jint rv;
+  T rv;
   int tmp;
   __asm__ volatile(
     "1:\n\t"
@@ -220,14 +249,19 @@
     : "memory");
   return rv;
 #else
-  // Warning:  Arguments are swapped to avoid moving them for kernel call
-  return (*os::atomic_cmpxchg_func)(compare_value, exchange_value, dest);
+  return cmpxchg_using_helper<jint>(reorder_cmpxchg_func, exchange_value, dest, compare_value);
 #endif
 }
 
-inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) {
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(8 == sizeof(T));
 #ifdef AARCH64
-  jlong rv;
+  T rv;
   int tmp;
   __asm__ volatile(
     "1:\n\t"
@@ -245,21 +279,8 @@
     : "memory");
   return rv;
 #else
-  assert(VM_Version::supports_cx8(), "Atomic compare and exchange jlong not supported on this architecture!");
-  return (*os::atomic_cmpxchg_long_func)(compare_value, exchange_value, dest);
+  return cmpxchg_using_helper<jlong>(reorder_cmpxchg_long_func, exchange_value, dest, compare_value);
 #endif
 }
 
-inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) {
-#ifdef AARCH64
-  return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order);
-#else
-  return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order);
-#endif
-}
-
-inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) {
-  return (void*)cmpxchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest, (intptr_t)compare_value, order);
-}
-
 #endif // OS_CPU_LINUX_ARM_VM_ATOMIC_LINUX_ARM_HPP
--- a/hotspot/src/os_cpu/linux_ppc/vm/atomic_linux_ppc.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os_cpu/linux_ppc/vm/atomic_linux_ppc.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -306,8 +306,13 @@
   }
 }
 
-#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE
-inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) {
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(1 == sizeof(T));
 
   // Note that cmpxchg guarantees a two-way memory barrier across
   // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not
@@ -368,16 +373,22 @@
 
   cmpxchg_post_membar(order);
 
-  return (jbyte)(unsigned char)old_value;
+  return PrimitiveConversions::cast<T>((unsigned char)old_value);
 }
 
-inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) {
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(4 == sizeof(T));
 
   // Note that cmpxchg guarantees a two-way memory barrier across
   // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not
   // specified otherwise (see atomic.hpp).
 
-  unsigned int old_value;
+  T old_value;
   const uint64_t zero = 0;
 
   cmpxchg_pre_membar(order);
@@ -412,16 +423,22 @@
 
   cmpxchg_post_membar(order);
 
-  return (jint) old_value;
+  return old_value;
 }
 
-inline jlong Atomic::cmpxchg(jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) {
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(8 == sizeof(T));
 
   // Note that cmpxchg guarantees a two-way memory barrier across
   // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not
   // specified otherwise (see atomic.hpp).
 
-  long old_value;
+  T old_value;
   const uint64_t zero = 0;
 
   cmpxchg_pre_membar(order);
@@ -456,15 +473,7 @@
 
   cmpxchg_post_membar(order);
 
-  return (jlong) old_value;
-}
-
-inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) {
-  return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order);
-}
-
-inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) {
-  return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order);
+  return old_value;
 }
 
 #undef strasm_sync
--- a/hotspot/src/os_cpu/linux_s390/vm/atomic_linux_s390.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os_cpu/linux_s390/vm/atomic_linux_s390.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -105,7 +105,7 @@
       //---<  inputs  >---
       : [inc]  "a"   (inc)    // read-only.
       //---<  clobbered  >---
-      : "cc", "r0", "r2", "r3"
+      : "cc", "r0", "r2", "r3", "memory"
     );
   } else {
     __asm__ __volatile__ (
@@ -120,7 +120,7 @@
       //---<  inputs  >---
       : [inc] "a"   (inc)    // read-only.
       //---<  clobbered  >---
-      : "cc"
+      : "cc", "memory"
     );
   }
 
@@ -151,7 +151,7 @@
       //---<  inputs  >---
       : [inc]  "a"   (inc)    // read-only.
       //---<  clobbered  >---
-      : "cc", "r0", "r2", "r3"
+      : "cc", "r0", "r2", "r3", "memory"
     );
   } else {
     __asm__ __volatile__ (
@@ -166,7 +166,7 @@
       //---<  inputs  >---
       : [inc] "a"   (inc)    // read-only.
       //---<  clobbered  >---
-      : "cc"
+      : "cc", "memory"
     );
   }
 
@@ -214,7 +214,7 @@
       :
 //    : [inc]  "a"   (inc)    // read-only.
       //---<  clobbered  >---
-      : "cc", "r2", "r3"
+      : "cc", "r2", "r3", "memory"
     );
   } else {
     __asm__ __volatile__ (
@@ -229,7 +229,7 @@
       //---<  inputs  >---
       :
       //---<  clobbered  >---
-      : "cc"
+      : "cc", "memory"
     );
   }
 }
@@ -258,7 +258,7 @@
       :
 //    : [inc]  "a"   (inc)    // read-only.
       //---<  clobbered  >---
-      : "cc", "r2", "r3"
+      : "cc", "r2", "r3", "memory"
     );
   } else {
     __asm__ __volatile__ (
@@ -273,7 +273,7 @@
       //---<  inputs  >---
       :
       //---<  clobbered  >---
-      : "cc"
+      : "cc", "memory"
     );
   }
 }
@@ -317,7 +317,7 @@
       :
 //    : [inc]  "a"   (inc)    // read-only.
       //---<  clobbered  >---
-      : "cc", "r2", "r3"
+      : "cc", "r2", "r3", "memory"
     );
   } else {
     __asm__ __volatile__ (
@@ -335,7 +335,7 @@
       //---<  inputs  >---
       :
       //---<  clobbered  >---
-      : "cc"
+      : "cc", "memory"
     );
   }
 }
@@ -364,7 +364,7 @@
       :
 //    : [inc]  "a"   (inc)    // read-only.
       //---<  clobbered  >---
-      : "cc", "r2", "r3"
+      : "cc", "r2", "r3", "memory"
     );
   } else {
     __asm__ __volatile__ (
@@ -382,7 +382,7 @@
       //---<  inputs  >---
       :
       //---<  clobbered  >---
-      : "cc"
+      : "cc", "memory"
     );
   }
 }
@@ -420,7 +420,7 @@
     //---<  inputs  >---
     : [upd] "d"   (xchg_val) // read-only, value to be written to memory
     //---<  clobbered  >---
-    : "cc"
+    : "cc", "memory"
   );
 
   return (jint)old;
@@ -439,7 +439,7 @@
     //---<  inputs  >---
     : [upd] "d"   (xchg_val) // read-only, value to be written to memory
     //---<  clobbered  >---
-    : "cc"
+    : "cc", "memory"
   );
 
   return (intptr_t)old;
@@ -478,8 +478,18 @@
 // function is performed before the operand is fetched and again after the
 // operation is completed."
 
-jint Atomic::cmpxchg(jint xchg_val, volatile jint* dest, jint cmp_val, cmpxchg_memory_order unused) {
-  unsigned long old;
+// No direct support for cmpxchg of bytes; emulate using int.
+template<>
+struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {};
+
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<4>::operator()(T xchg_val,
+                                                T volatile* dest,
+                                                T cmp_val,
+                                                cmpxchg_memory_order unused) const {
+  STATIC_ASSERT(4 == sizeof(T));
+  T old;
 
   __asm__ __volatile__ (
     "   CS       %[old],%[upd],%[mem]    \n\t" // Try to xchg upd with mem.
@@ -490,14 +500,20 @@
     : [upd] "d"   (xchg_val)
     ,       "0"   (cmp_val)  // Read-only, initial value for [old] (operand #0).
     // clobbered
-    : "cc"
+    : "cc", "memory"
   );
 
-  return (jint)old;
+  return old;
 }
 
-jlong Atomic::cmpxchg(jlong xchg_val, volatile jlong* dest, jlong cmp_val, cmpxchg_memory_order unused) {
-  unsigned long old;
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<8>::operator()(T xchg_val,
+                                                T volatile* dest,
+                                                T cmp_val,
+                                                cmpxchg_memory_order unused) const {
+  STATIC_ASSERT(8 == sizeof(T));
+  T old;
 
   __asm__ __volatile__ (
     "   CSG      %[old],%[upd],%[mem]    \n\t" // Try to xchg upd with mem.
@@ -508,18 +524,10 @@
     : [upd] "d"   (xchg_val)
     ,       "0"   (cmp_val)  // Read-only, initial value for [old] (operand #0).
     // clobbered
-    : "cc"
+    : "cc", "memory"
   );
 
-  return (jlong)old;
-}
-
-void* Atomic::cmpxchg_ptr(void *xchg_val, volatile void* dest, void* cmp_val, cmpxchg_memory_order unused) {
-  return (void*)cmpxchg((jlong)xchg_val, (volatile jlong*)dest, (jlong)cmp_val, unused);
-}
-
-intptr_t Atomic::cmpxchg_ptr(intptr_t xchg_val, volatile intptr_t* dest, intptr_t cmp_val, cmpxchg_memory_order unused) {
-  return (intptr_t)cmpxchg((jlong)xchg_val, (volatile jlong*)dest, (jlong)cmp_val, unused);
+  return old;
 }
 
 inline jlong Atomic::load(const volatile jlong* src) { return *src; }
--- a/hotspot/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -121,9 +121,18 @@
   return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
 }
 
+// No direct support for cmpxchg of bytes; emulate using int.
+template<>
+struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {};
 
-inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value, cmpxchg_memory_order order) {
-  jint rv;
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(4 == sizeof(T));
+  T rv;
   __asm__ volatile(
     " cas    [%2], %3, %0"
     : "=r" (rv)
@@ -132,8 +141,14 @@
   return rv;
 }
 
-inline jlong    Atomic::cmpxchg    (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value, cmpxchg_memory_order order) {
-  jlong rv;
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(8 == sizeof(T));
+  T rv;
   __asm__ volatile(
     " casx   [%2], %3, %0"
     : "=r" (rv)
@@ -142,18 +157,4 @@
   return rv;
 }
 
-inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) {
-  intptr_t rv;
-  __asm__ volatile(
-    " casx    [%2], %3, %0"
-    : "=r" (rv)
-    : "0" (exchange_value), "r" (dest), "r" (compare_value)
-    : "memory");
-  return rv;
-}
-
-inline void*    Atomic::cmpxchg_ptr(void*    exchange_value, volatile void*     dest, void*    compare_value, cmpxchg_memory_order order) {
-  return (void*)cmpxchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest, (intptr_t)compare_value, order);
-}
-
 #endif // OS_CPU_LINUX_SPARC_VM_ATOMIC_LINUX_SPARC_INLINE_HPP
--- a/hotspot/src/os_cpu/linux_x86/vm/atomic_linux_x86.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os_cpu/linux_x86/vm/atomic_linux_x86.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -25,8 +25,6 @@
 #ifndef OS_CPU_LINUX_X86_VM_ATOMIC_LINUX_X86_HPP
 #define OS_CPU_LINUX_X86_VM_ATOMIC_LINUX_X86_HPP
 
-#include "runtime/os.hpp"
-
 // Implementation of class atomic
 
 inline void Atomic::store    (jbyte    store_value, jbyte*    dest) { *dest = store_value; }
@@ -81,8 +79,13 @@
   return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
 }
 
-#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE
-inline jbyte    Atomic::cmpxchg    (jbyte    exchange_value, volatile jbyte*    dest, jbyte    compare_value, cmpxchg_memory_order order) {
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order /* order */) const {
+  STATIC_ASSERT(1 == sizeof(T));
   __asm__ volatile ("lock cmpxchgb %1,(%3)"
                     : "=a" (exchange_value)
                     : "q" (exchange_value), "a" (compare_value), "r" (dest)
@@ -90,7 +93,13 @@
   return exchange_value;
 }
 
-inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value, cmpxchg_memory_order order) {
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order /* order */) const {
+  STATIC_ASSERT(4 == sizeof(T));
   __asm__ volatile ("lock cmpxchgl %1,(%3)"
                     : "=a" (exchange_value)
                     : "r" (exchange_value), "a" (compare_value), "r" (dest)
@@ -137,7 +146,13 @@
   return exchange_value;
 }
 
-inline jlong    Atomic::cmpxchg    (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value, cmpxchg_memory_order order) {
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order /* order */) const {
+  STATIC_ASSERT(8 == sizeof(T));
   __asm__ __volatile__ ("lock cmpxchgq %1,(%3)"
                         : "=a" (exchange_value)
                         : "r" (exchange_value), "a" (compare_value), "r" (dest)
@@ -145,14 +160,6 @@
   return exchange_value;
 }
 
-inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) {
-  return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order);
-}
-
-inline void*    Atomic::cmpxchg_ptr(void*    exchange_value, volatile void*     dest, void*    compare_value, cmpxchg_memory_order order) {
-  return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order);
-}
-
 inline jlong Atomic::load(const volatile jlong* src) { return *src; }
 
 #else // !AMD64
@@ -184,16 +191,14 @@
   void _Atomic_move_long(const volatile jlong* src, volatile jlong* dst);
 }
 
-inline jlong    Atomic::cmpxchg    (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value, cmpxchg_memory_order order) {
-  return _Atomic_cmpxchg_long(exchange_value, dest, compare_value);
-}
-
-inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) {
-  return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order);
-}
-
-inline void*    Atomic::cmpxchg_ptr(void*    exchange_value, volatile void*     dest, void*    compare_value, cmpxchg_memory_order order) {
-  return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order);
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(8 == sizeof(T));
+  return cmpxchg_using_helper<jlong>(_Atomic_cmpxchg_long, exchange_value, dest, compare_value);
 }
 
 inline jlong Atomic::load(const volatile jlong* src) {
--- a/hotspot/src/os_cpu/linux_zero/vm/atomic_linux_zero.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os_cpu/linux_zero/vm/atomic_linux_zero.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -57,9 +57,9 @@
 /* Perform an atomic compare and swap: if the current value of `*PTR'
    is OLDVAL, then write NEWVAL into `*PTR'.  Return the contents of
    `*PTR' before the operation.*/
-static inline int m68k_compare_and_swap(volatile int *ptr,
-                                        int oldval,
-                                        int newval) {
+static inline int m68k_compare_and_swap(int newval,
+                                        volatile int *ptr,
+                                        int oldval) {
   for (;;) {
       int prev = *ptr;
       if (prev != oldval)
@@ -118,9 +118,9 @@
 /* Perform an atomic compare and swap: if the current value of `*PTR'
    is OLDVAL, then write NEWVAL into `*PTR'.  Return the contents of
    `*PTR' before the operation.*/
-static inline int arm_compare_and_swap(volatile int *ptr,
-                                       int oldval,
-                                       int newval) {
+static inline int arm_compare_and_swap(int newval,
+                                       volatile int *ptr,
+                                       int oldval) {
   for (;;) {
       int prev = *ptr;
       if (prev != oldval)
@@ -261,55 +261,38 @@
                            (volatile intptr_t*) dest);
 }
 
-inline jint Atomic::cmpxchg(jint exchange_value,
-                            volatile jint* dest,
-                            jint compare_value,
-                            cmpxchg_memory_order order) {
+// No direct support for cmpxchg of bytes; emulate using int.
+template<>
+struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {};
+
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(4 == sizeof(T));
 #ifdef ARM
-  return arm_compare_and_swap(dest, compare_value, exchange_value);
+  return cmpxchg_using_helper<int>(arm_compare_and_swap, exchange_value, dest, compare_value);
 #else
 #ifdef M68K
-  return m68k_compare_and_swap(dest, compare_value, exchange_value);
+  return cmpxchg_using_helper<int>(m68k_compare_and_swap, exchange_value, dest, compare_value);
 #else
   return __sync_val_compare_and_swap(dest, compare_value, exchange_value);
 #endif // M68K
 #endif // ARM
 }
 
-inline jlong Atomic::cmpxchg(jlong exchange_value,
-                             volatile jlong* dest,
-                             jlong compare_value,
-                             cmpxchg_memory_order order) {
-
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(8 == sizeof(T));
   return __sync_val_compare_and_swap(dest, compare_value, exchange_value);
 }
 
-inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value,
-                                    volatile intptr_t* dest,
-                                    intptr_t compare_value,
-                                    cmpxchg_memory_order order) {
-#ifdef ARM
-  return arm_compare_and_swap(dest, compare_value, exchange_value);
-#else
-#ifdef M68K
-  return m68k_compare_and_swap(dest, compare_value, exchange_value);
-#else
-  return __sync_val_compare_and_swap(dest, compare_value, exchange_value);
-#endif // M68K
-#endif // ARM
-}
-
-inline void* Atomic::cmpxchg_ptr(void* exchange_value,
-                                 volatile void* dest,
-                                 void* compare_value,
-                                 cmpxchg_memory_order order) {
-
-  return (void *) cmpxchg_ptr((intptr_t) exchange_value,
-                              (volatile intptr_t*) dest,
-                              (intptr_t) compare_value,
-                              order);
-}
-
 inline jlong Atomic::load(const volatile jlong* src) {
   volatile jlong dest;
   os::atomic_copy64(src, &dest);
--- a/hotspot/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -25,8 +25,6 @@
 #ifndef OS_CPU_SOLARIS_SPARC_VM_ATOMIC_SOLARIS_SPARC_HPP
 #define OS_CPU_SOLARIS_SPARC_VM_ATOMIC_SOLARIS_SPARC_HPP
 
-#include "runtime/os.hpp"
-
 // Implementation of class atomic
 
 inline void Atomic::store    (jbyte    store_value, jbyte*    dest) { *dest = store_value; }
@@ -64,10 +62,6 @@
 extern "C" jint     _Atomic_swap32(jint     exchange_value, volatile jint*     dest);
 extern "C" intptr_t _Atomic_swap64(intptr_t exchange_value, volatile intptr_t* dest);
 
-extern "C" jint     _Atomic_cas32(jint     exchange_value, volatile jint*     dest, jint     compare_value);
-extern "C" intptr_t _Atomic_cas64(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value);
-extern "C" jlong    _Atomic_casl (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value);
-
 extern "C" jint     _Atomic_add32(jint     inc,       volatile jint*     dest);
 extern "C" intptr_t _Atomic_add64(intptr_t add_value, volatile intptr_t* dest);
 
@@ -97,22 +91,40 @@
   return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
 }
 
+// No direct support for cmpxchg of bytes; emulate using int.
+template<>
+struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {};
 
-inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value, cmpxchg_memory_order order) {
-  return _Atomic_cas32(exchange_value, dest, compare_value);
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(4 == sizeof(T));
+  T rv;
+  __asm__ volatile(
+    " cas    [%2], %3, %0"
+    : "=r" (rv)
+    : "0" (exchange_value), "r" (dest), "r" (compare_value)
+    : "memory");
+  return rv;
 }
 
-inline jlong    Atomic::cmpxchg    (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value, cmpxchg_memory_order order) {
-  // Return 64 bit value in %o0
-  return _Atomic_cas64((intptr_t)exchange_value, (intptr_t *)dest, (intptr_t)compare_value);
-}
-
-inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) {
-  return _Atomic_cas64(exchange_value, dest, compare_value);
-}
-
-inline void*    Atomic::cmpxchg_ptr(void*    exchange_value, volatile void*     dest, void*    compare_value, cmpxchg_memory_order order) {
-  return (void*)cmpxchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest, (intptr_t)compare_value, order);
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(8 == sizeof(T));
+  T rv;
+  __asm__ volatile(
+    " casx   [%2], %3, %0"
+    : "=r" (rv)
+    : "0" (exchange_value), "r" (dest), "r" (compare_value)
+    : "memory");
+  return rv;
 }
 
 #endif // OS_CPU_SOLARIS_SPARC_VM_ATOMIC_SOLARIS_SPARC_HPP
--- a/hotspot/src/os_cpu/solaris_sparc/vm/solaris_sparc.il	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/solaris_sparc.il	Thu Aug 24 21:06:33 2017 +0000
@@ -73,74 +73,6 @@
         .end
 
 
-  // Support for jint Atomic::cmpxchg(jint           exchange_value,
-  //                                  volatile jint* dest,
-  //                                  jint           compare_value)
-  //
-  // Arguments:
-  //      exchange_value: O0
-  //      dest:           O1
-  //      compare_value:  O2
-  //
-  // Results:
-  //     O0: the value previously stored in dest
-
-        .inline _Atomic_cas32, 3
-        .volatile
-        cas     [%o1], %o2, %o0
-        .nonvolatile
-        .end
-
-
-  // Support for intptr_t Atomic::cmpxchg_ptr(intptr_t           exchange_value,
-  //                                          volatile intptr_t* dest,
-  //                                          intptr_t           compare_value)
-  //
-  // 64-bit
-  //
-  // Arguments:
-  //      exchange_value: O0
-  //      dest:           O1
-  //      compare_value:  O2
-  //
-  // Results:
-  //     O0: the value previously stored in dest
-
-        .inline _Atomic_cas64, 3
-        .volatile
-        casx    [%o1], %o2, %o0
-        .nonvolatile
-        .end
-
-
-  // Support for jlong Atomic::cmpxchg(jlong           exchange_value,
-  //                                   volatile jlong* dest,
-  //                                   jlong           compare_value)
-  //
-  // 32-bit calling conventions
-  //
-  // Arguments:
-  //      exchange_value: O1:O0
-  //      dest:           O2
-  //      compare_value:  O4:O3
-  //
-  // Results:
-  //     O1:O0: the value previously stored in dest
-
-        .inline _Atomic_casl, 3
-        .volatile
-        sllx    %o0, 32, %o0
-        srl     %o1, 0, %o1
-        or      %o0,%o1,%o0
-        sllx    %o3, 32, %o3
-        srl     %o4, 0, %o4
-        or      %o3,%o4,%o3
-        casx    [%o2], %o3, %o0
-        srl     %o0, 0, %o1
-        srlx    %o0, 32, %o0
-        .nonvolatile
-        .end
-
   // Support for jlong Atomic::load and Atomic::store on v9.
   //
   // void _Atomic_move_long_v9(volatile jlong* src, volatile jlong* dst)
--- a/hotspot/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -25,8 +25,6 @@
 #ifndef OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP
 #define OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP
 
-#include "runtime/os.hpp"
-
 inline void Atomic::store    (jbyte    store_value, jbyte*    dest) { *dest = store_value; }
 inline void Atomic::store    (jshort   store_value, jshort*   dest) { *dest = store_value; }
 inline void Atomic::store    (jint     store_value, jint*     dest) { *dest = store_value; }
@@ -49,8 +47,7 @@
 inline void Atomic::dec_ptr(volatile intptr_t* dest) { (void)add_ptr(-1, dest); }
 inline void Atomic::dec_ptr(volatile void*     dest) { (void)add_ptr(-1, dest); }
 
-// For Sun Studio - implementation is in solaris_x86_[32/64].il.
-// For gcc - implementation is just below.
+// For Sun Studio - implementation is in solaris_x86_64.il.
 
 extern "C" {
   jint _Atomic_add(jint add_value, volatile jint* dest);
@@ -71,21 +68,51 @@
   return _Atomic_xchg(exchange_value, dest);
 }
 
-#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE
-inline jbyte    Atomic::cmpxchg    (jbyte    exchange_value, volatile jbyte*    dest, jbyte    compare_value, cmpxchg_memory_order order) {
-  return _Atomic_cmpxchg_byte(exchange_value, dest, compare_value);
+// Not using cmpxchg_using_helper here, because some configurations of
+// Solaris compiler don't deal well with passing a "defined in .il"
+// function as an argument.  We *should* switch to using gcc-style
+// inline assembly, but attempting to do so with Studio 12.4 ran into
+// segfaults.
+
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(1 == sizeof(T));
+  return PrimitiveConversions::cast<T>(
+    _Atomic_cmpxchg_byte(PrimitiveConversions::cast<jbyte>(exchange_value),
+                         reinterpret_cast<jbyte volatile*>(dest),
+                         PrimitiveConversions::cast<jbyte>(compare_value)));
 }
 
-inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value, cmpxchg_memory_order order) {
-  return _Atomic_cmpxchg(exchange_value, dest, compare_value);
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(4 == sizeof(T));
+  return PrimitiveConversions::cast<T>(
+    _Atomic_cmpxchg(PrimitiveConversions::cast<jint>(exchange_value),
+                    reinterpret_cast<jint volatile*>(dest),
+                    PrimitiveConversions::cast<jint>(compare_value)));
 }
 
-inline jlong    Atomic::cmpxchg    (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value, cmpxchg_memory_order order) {
-  return _Atomic_cmpxchg_long(exchange_value, dest, compare_value);
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(8 == sizeof(T));
+  return PrimitiveConversions::cast<T>(
+    _Atomic_cmpxchg_long(PrimitiveConversions::cast<jlong>(exchange_value),
+                         reinterpret_cast<jlong volatile*>(dest),
+                         PrimitiveConversions::cast<jlong>(compare_value)));
 }
 
-
-#ifdef AMD64
 inline void Atomic::store    (jlong    store_value, jlong*             dest) { *dest = store_value; }
 inline void Atomic::store    (jlong    store_value, volatile jlong*    dest) { *dest = store_value; }
 extern "C" jlong _Atomic_add_long(jlong add_value, volatile jlong* dest);
@@ -107,59 +134,6 @@
   return (void*)_Atomic_xchg_long((jlong)exchange_value, (volatile jlong*)dest);
 }
 
-inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) {
-  return (intptr_t)_Atomic_cmpxchg_long((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value);
-}
-
-inline void*    Atomic::cmpxchg_ptr(void*    exchange_value, volatile void*     dest, void*    compare_value, cmpxchg_memory_order order) {
-  return (void*)_Atomic_cmpxchg_long((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value);
-}
-
 inline jlong Atomic::load(const volatile jlong* src) { return *src; }
 
-#else // !AMD64
-
-inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) {
-  return (intptr_t)add((jint)add_value, (volatile jint*)dest);
-}
-
-inline void*    Atomic::add_ptr(intptr_t add_value, volatile void*     dest) {
-  return (void*)add((jint)add_value, (volatile jint*)dest);
-}
-
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
-  return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest);
-}
-
-inline void*    Atomic::xchg_ptr(void*    exchange_value, volatile void*     dest) {
-  return (void*)xchg((jint)exchange_value, (volatile jint*)dest);
-}
-
-inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) {
-  return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order);
-}
-
-inline void*    Atomic::cmpxchg_ptr(void*    exchange_value, volatile void*     dest, void*    compare_value, cmpxchg_memory_order order) {
-  return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order);
-}
-
-extern "C" void _Atomic_move_long(const volatile jlong* src, volatile jlong* dst);
-
-inline jlong Atomic::load(const volatile jlong* src) {
-  volatile jlong dest;
-  _Atomic_move_long(src, &dest);
-  return dest;
-}
-
-inline void Atomic::store(jlong store_value, jlong* dest) {
-  _Atomic_move_long((volatile jlong*)&store_value, (volatile jlong*)dest);
-}
-
-inline void Atomic::store(jlong store_value, volatile jlong* dest) {
-  _Atomic_move_long((volatile jlong*)&store_value, dest);
-}
-
-#endif // AMD64
-
-
 #endif // OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP
--- a/hotspot/src/os_cpu/windows_x86/vm/atomic_windows_x86.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/os_cpu/windows_x86/vm/atomic_windows_x86.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -109,26 +109,22 @@
   return (void *)(os::atomic_xchg_ptr_func)((intptr_t)exchange_value, (volatile intptr_t*)dest);
 }
 
-inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value, cmpxchg_memory_order order) {
-  return (*os::atomic_cmpxchg_func)(exchange_value, dest, compare_value);
-}
-
-#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE
-inline jbyte    Atomic::cmpxchg    (jbyte    exchange_value, volatile jbyte*    dest, jbyte    compare_value, cmpxchg_memory_order order) {
-    return (*os::atomic_cmpxchg_byte_func)(exchange_value, dest, compare_value);
-}
+#define DEFINE_STUB_CMPXCHG(ByteSize, StubType, StubName)               \
+  template<>                                                            \
+  template<typename T>                                                  \
+  inline T Atomic::PlatformCmpxchg<ByteSize>::operator()(T exchange_value, \
+                                                         T volatile* dest, \
+                                                         T compare_value, \
+                                                         cmpxchg_memory_order order) const { \
+    STATIC_ASSERT(ByteSize == sizeof(T));                               \
+    return cmpxchg_using_helper<StubType>(StubName, exchange_value, dest, compare_value); \
+  }
 
-inline jlong    Atomic::cmpxchg    (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value, cmpxchg_memory_order order) {
-  return (*os::atomic_cmpxchg_long_func)(exchange_value, dest, compare_value);
-}
+DEFINE_STUB_CMPXCHG(1, jbyte, os::atomic_cmpxchg_byte_func)
+DEFINE_STUB_CMPXCHG(4, jint,  os::atomic_cmpxchg_func)
+DEFINE_STUB_CMPXCHG(8, jlong, os::atomic_cmpxchg_long_func)
 
-inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) {
-  return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order);
-}
-
-inline void*    Atomic::cmpxchg_ptr(void*    exchange_value, volatile void*     dest, void*    compare_value, cmpxchg_memory_order order) {
-  return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order);
-}
+#undef DEFINE_STUB_CMPXCHG
 
 inline jlong Atomic::load(const volatile jlong* src) { return *src; }
 
@@ -201,8 +197,13 @@
   return (void*)xchg((jint)exchange_value, (volatile jint*)dest);
 }
 
-#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE
-inline jbyte    Atomic::cmpxchg    (jbyte    exchange_value, volatile jbyte*    dest, jbyte    compare_value, cmpxchg_memory_order order) {
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(1 == sizeof(T));
   // alternative for InterlockedCompareExchange
   __asm {
     mov edx, dest
@@ -212,7 +213,13 @@
   }
 }
 
-inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value, cmpxchg_memory_order order) {
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(4 == sizeof(T));
   // alternative for InterlockedCompareExchange
   __asm {
     mov edx, dest
@@ -222,7 +229,13 @@
   }
 }
 
-inline jlong    Atomic::cmpxchg    (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value, cmpxchg_memory_order order) {
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
+                                                T volatile* dest,
+                                                T compare_value,
+                                                cmpxchg_memory_order order) const {
+  STATIC_ASSERT(8 == sizeof(T));
   jint ex_lo  = (jint)exchange_value;
   jint ex_hi  = *( ((jint*)&exchange_value) + 1 );
   jint cmp_lo = (jint)compare_value;
@@ -241,14 +254,6 @@
   }
 }
 
-inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) {
-  return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order);
-}
-
-inline void*    Atomic::cmpxchg_ptr(void*    exchange_value, volatile void*     dest, void*    compare_value, cmpxchg_memory_order order) {
-  return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order);
-}
-
 inline jlong Atomic::load(const volatile jlong* src) {
   volatile jlong dest;
   volatile jlong* pdest = &dest;
--- a/hotspot/src/share/vm/aot/aotCodeHeap.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/aot/aotCodeHeap.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -51,7 +51,7 @@
 
 Klass* AOTCodeHeap::get_klass_from_got(const char* klass_name, int klass_len, const Method* method) {
   AOTKlassData* klass_data = (AOTKlassData*)_lib->load_symbol(klass_name);
-  Klass* k = (Klass*)_metaspace_got[klass_data->_got_index];
+  Klass* k = (Klass*)_klasses_got[klass_data->_got_index];
   if (k == NULL) {
     Thread* thread = Thread::current();
     k = lookup_klass(klass_name, klass_len, method, thread);
@@ -60,7 +60,7 @@
       fatal("Shared file %s error: klass %s should be resolved already", _lib->name(), klass_name);
       vm_exit(1);
     }
-    _metaspace_got[klass_data->_got_index] = k;
+    _klasses_got[klass_data->_got_index] = k;
   }
   return k;
 }
@@ -202,8 +202,8 @@
   _name = (const char*) strdup(name);
 
   // Verify that VM runs with the same parameters as AOT tool.
-  _config = (AOTConfiguration*) load_symbol("JVM.config");
-  _header = (AOTHeader*) load_symbol("JVM.header");
+  _config = (AOTConfiguration*) load_symbol("A.config");
+  _header = (AOTHeader*) load_symbol("A.header");
 
   verify_config();
 
@@ -224,31 +224,31 @@
   _method_count = _lib->header()->_method_count;
 
   // Collect metaspace info: names -> address in .got section
-  _metaspace_names = (const char*) _lib->load_symbol("JVM.meta.names");
-  _method_metadata =     (address) _lib->load_symbol("JVM.meth.metadata");
-  _methods_offsets =     (address) _lib->load_symbol("JVM.methods.offsets");
-  _klasses_offsets =     (address) _lib->load_symbol("JVM.kls.offsets");
-  _dependencies    =     (address) _lib->load_symbol("JVM.kls.dependencies");
-  _code_space      =     (address) _lib->load_symbol("JVM.text");
+  _metaspace_names = (const char*) _lib->load_symbol("A.meta.names");
+  _method_metadata =     (address) _lib->load_symbol("A.meth.metadata");
+  _methods_offsets =     (address) _lib->load_symbol("A.meth.offsets");
+  _klasses_offsets =     (address) _lib->load_symbol("A.kls.offsets");
+  _dependencies    =     (address) _lib->load_symbol("A.kls.dependencies");
+  _code_space      =     (address) _lib->load_symbol("A.text");
 
   // First cell is number of elements.
-  _metaspace_got      = (Metadata**) _lib->load_symbol("JVM.meta.got");
-  _metaspace_got_size = _lib->header()->_metaspace_got_size;
+  _klasses_got      = (Metadata**) _lib->load_symbol("A.kls.got");
+  _klasses_got_size = _lib->header()->_klasses_got_size;
 
-  _metadata_got      = (Metadata**) _lib->load_symbol("JVM.metadata.got");
+  _metadata_got      = (Metadata**) _lib->load_symbol("A.meta.got");
   _metadata_got_size = _lib->header()->_metadata_got_size;
 
-  _oop_got      = (oop*) _lib->load_symbol("JVM.oop.got");
+  _oop_got      = (oop*) _lib->load_symbol("A.oop.got");
   _oop_got_size = _lib->header()->_oop_got_size;
 
   // Collect stubs info
-  _stubs_offsets = (int*) _lib->load_symbol("JVM.stubs.offsets");
+  _stubs_offsets = (int*) _lib->load_symbol("A.stubs.offsets");
 
   // code segments table
-  _code_segments = (address) _lib->load_symbol("JVM.code.segments");
+  _code_segments = (address) _lib->load_symbol("A.code.segments");
 
   // method state
-  _method_state = (jlong*) _lib->load_symbol("JVM.meth.state");
+  _method_state = (jlong*) _lib->load_symbol("A.meth.state");
 
   // Create a table for mapping classes
   _classes = NEW_C_HEAP_ARRAY(AOTClass, _class_count, mtCode);
@@ -316,7 +316,7 @@
   AOTCompiledMethod *aot = new AOTCompiledMethod(code, mh(), meta, metadata_table, metadata_size, state_adr, this, name, code_id, _aot_id);
   assert(_code_to_aot[code_id]._aot == NULL, "should be not initialized");
   _code_to_aot[code_id]._aot = aot; // Should set this first
-  if (Atomic::cmpxchg(in_use, (jint*)&_code_to_aot[code_id]._state, not_set) != not_set) {
+  if (Atomic::cmpxchg(in_use, &_code_to_aot[code_id]._state, not_set) != not_set) {
     _code_to_aot[code_id]._aot = NULL; // Clean
   } else { // success
     // Publish method
@@ -342,8 +342,8 @@
       if (klass_data != NULL) {
         // Set both GOT cells, resolved and initialized klass pointers.
         // _got_index points to second cell - resolved klass pointer.
-        _metaspace_got[klass_data->_got_index-1] = (Metadata*)arr_klass; // Initialized
-        _metaspace_got[klass_data->_got_index  ] = (Metadata*)arr_klass; // Resolved
+        _klasses_got[klass_data->_got_index-1] = (Metadata*)arr_klass; // Initialized
+        _klasses_got[klass_data->_got_index  ] = (Metadata*)arr_klass; // Resolved
         if (PrintAOT) {
           tty->print_cr("[Found  %s  in  %s]", arr_klass->internal_name(), _lib->name());
         }
@@ -378,7 +378,7 @@
     AOTCompiledMethod* aot = new AOTCompiledMethod(entry, NULL, meta, metadata_table, metadata_size, state_adr, this, full_name, code_id, i);
     assert(_code_to_aot[code_id]._aot  == NULL, "should be not initialized");
     _code_to_aot[code_id]._aot  = aot;
-    if (Atomic::cmpxchg(in_use, (jint*)&_code_to_aot[code_id]._state, not_set) != not_set) {
+    if (Atomic::cmpxchg(in_use, &_code_to_aot[code_id]._state, not_set) != not_set) {
       fatal("stab '%s' code state is %d", full_name, _code_to_aot[code_id]._state);
     }
     // Adjust code buffer boundaries only for stubs because they are last in the buffer.
@@ -649,7 +649,7 @@
     for (int i = 0; i < methods_cnt; ++i) {
       int code_id = indexes[i];
       // Invalidate aot code.
-      if (Atomic::cmpxchg(invalid, (jint*)&_code_to_aot[code_id]._state, not_set) != not_set) {
+      if (Atomic::cmpxchg(invalid, &_code_to_aot[code_id]._state, not_set) != not_set) {
         if (_code_to_aot[code_id]._state == in_use) {
           AOTCompiledMethod* aot = _code_to_aot[code_id]._aot;
           assert(aot != NULL, "aot should be set");
@@ -680,16 +680,16 @@
   if (!ik->has_passed_fingerprint_check()) {
     NOT_PRODUCT( aot_klasses_fp_miss++; )
     log_trace(aot, class, fingerprint)("class  %s%s  has bad fingerprint in  %s tid=" INTPTR_FORMAT,
-                                   ik->internal_name(), ik->is_shared() ? " (shared)" : "",
-                                   _lib->name(), p2i(thread));
+                                       ik->internal_name(), ik->is_shared() ? " (shared)" : "",
+                                       _lib->name(), p2i(thread));
     sweep_dependent_methods(klass_data);
     return false;
   }
 
   if (ik->has_been_redefined()) {
     log_trace(aot, class, load)("class  %s%s in %s  has been redefined tid=" INTPTR_FORMAT,
-                                   ik->internal_name(), ik->is_shared() ? " (shared)" : "",
-                                   _lib->name(), p2i(thread));
+                                ik->internal_name(), ik->is_shared() ? " (shared)" : "",
+                                _lib->name(), p2i(thread));
     sweep_dependent_methods(klass_data);
     return false;
   }
@@ -698,7 +698,7 @@
   AOTClass* aot_class = &_classes[klass_data->_class_id];
   if (aot_class->_classloader != NULL && aot_class->_classloader != ik->class_loader_data()) {
     log_trace(aot, class, load)("class  %s  in  %s already loaded for classloader %p vs %p tid=" INTPTR_FORMAT,
-                             ik->internal_name(), _lib->name(), aot_class->_classloader, ik->class_loader_data(), p2i(thread));
+                                ik->internal_name(), _lib->name(), aot_class->_classloader, ik->class_loader_data(), p2i(thread));
     NOT_PRODUCT( aot_klasses_cl_miss++; )
     return false;
   }
@@ -715,7 +715,7 @@
 
   aot_class->_classloader = ik->class_loader_data();
   // Set klass's Resolve (second) got cell.
-  _metaspace_got[klass_data->_got_index] = ik;
+  _klasses_got[klass_data->_got_index] = ik;
 
   // Initialize global symbols of the DSO to the corresponding VM symbol values.
   link_global_lib_symbols();
@@ -823,12 +823,12 @@
   }
 }
 
-// Scan only metaspace_got cells which should have only Klass*,
+// Scan only klasses_got cells which should have only Klass*,
 // metadata_got cells are scanned only for alive AOT methods
 // by AOTCompiledMethod::metadata_do().
 void AOTCodeHeap::got_metadata_do(void f(Metadata*)) {
-  for (int i = 1; i < _metaspace_got_size; i++) {
-    Metadata** p = &_metaspace_got[i];
+  for (int i = 1; i < _klasses_got_size; i++) {
+    Metadata** p = &_klasses_got[i];
     Metadata* md = *p;
     if (md == NULL)  continue;  // skip non-oops
     if (Metaspace::contains(md)) {
--- a/hotspot/src/share/vm/aot/aotCodeHeap.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/aot/aotCodeHeap.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -26,6 +26,8 @@
 
 #include "aot/aotCompiledMethod.hpp"
 #include "classfile/symbolTable.hpp"
+#include "metaprogramming/integralConstant.hpp"
+#include "metaprogramming/isRegisteredEnum.hpp"
 #include "oops/metadata.hpp"
 #include "oops/method.hpp"
 
@@ -35,6 +37,8 @@
   invalid = 2  // AOT code is invalidated because dependencies failed
 };
 
+template<> struct IsRegisteredEnum<CodeState> : public TrueType {};
+
 typedef struct {
   AOTCompiledMethod* _aot;
   CodeState _state; // State change cases: not_set->in_use, not_set->invalid
@@ -77,7 +81,7 @@
   int _version;
   int _class_count;
   int _method_count;
-  int _metaspace_got_size;
+  int _klasses_got_size;
   int _metadata_got_size;
   int _oop_got_size;
   int _jvm_version_offset;
@@ -180,11 +184,11 @@
   address _klasses_offsets;
   address _dependencies;
 
-  Metadata** _metaspace_got;
+  Metadata** _klasses_got;
   Metadata** _metadata_got;
   oop*    _oop_got;
 
-  int _metaspace_got_size;
+  int _klasses_got_size;
   int _metadata_got_size;
   int _oop_got_size;
 
@@ -251,7 +255,7 @@
 #ifdef ASSERT
   bool got_contains(Metadata **p) {
     return (p >= &_metadata_got[0] && p < &_metadata_got[_metadata_got_size]) ||
-           (p >= &_metaspace_got[0] && p < &_metaspace_got[_metaspace_got_size]);
+           (p >= &_klasses_got[0] && p < &_klasses_got[_klasses_got_size]);
   }
 #endif
 
--- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -491,7 +491,6 @@
   }
 #ifdef ASSERT
   assert(exception.not_null(), "NULL exceptions should be handled by throw_exception");
-  assert(exception->is_oop(), "just checking");
   // Check that exception is a subclass of Throwable, otherwise we have a VerifyError
   if (!(exception->is_a(SystemDictionary::Throwable_klass()))) {
     if (ExitVMOnVerifyError) vm_exit(-1);
@@ -676,7 +675,6 @@
     Atomic::inc(BiasedLocking::slow_path_entry_count_addr());
   }
   Handle h_obj(thread, obj);
-  assert(h_obj()->is_oop(), "must be NULL or an object");
   if (UseBiasedLocking) {
     // Retry fast entry if bias is revoked to avoid unnecessary inflation
     ObjectSynchronizer::fast_enter(h_obj, lock->lock(), true, CHECK);
@@ -701,7 +699,7 @@
   EXCEPTION_MARK;
 
   oop obj = lock->obj();
-  assert(obj->is_oop(), "must be NULL or an object");
+  assert(oopDesc::is_oop(obj), "must be NULL or an object");
   if (UseFastLocking) {
     // When using fast locking, the compiled code has already tried the fast case
     ObjectSynchronizer::slow_exit(obj, lock->lock(), THREAD);
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -759,14 +759,18 @@
   return metaspace;
 }
 
-jobject ClassLoaderData::add_handle(Handle h) {
+OopHandle ClassLoaderData::add_handle(Handle h) {
   MutexLockerEx ml(metaspace_lock(),  Mutex::_no_safepoint_check_flag);
-  return (jobject) _handles.add(h());
+  return OopHandle(_handles.add(h()));
 }
 
-void ClassLoaderData::remove_handle_unsafe(jobject h) {
-  assert(_handles.contains((oop*) h), "Got unexpected handle " PTR_FORMAT, p2i((oop*) h));
-  *((oop*) h) = NULL;
+void ClassLoaderData::init_handle_locked(OopHandle& dest, Handle h) {
+  MutexLockerEx ml(metaspace_lock(),  Mutex::_no_safepoint_check_flag);
+  if (dest.resolve() != NULL) {
+    return;
+  } else {
+    dest = _handles.add(h());
+  }
 }
 
 // Add this metadata pointer to be freed when it's safe.  This is only during
--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -29,6 +29,7 @@
 #include "memory/memRegion.hpp"
 #include "memory/metaspace.hpp"
 #include "memory/metaspaceCounters.hpp"
+#include "oops/oopHandle.hpp"
 #include "runtime/mutex.hpp"
 #include "trace/traceMacros.hpp"
 #include "utilities/growableArray.hpp"
@@ -362,8 +363,8 @@
   void verify();
   const char* loader_name();
 
-  jobject add_handle(Handle h);
-  void remove_handle_unsafe(jobject h);
+  OopHandle add_handle(Handle h);
+  void init_handle_locked(OopHandle& pd, Handle h);  // used for concurrent access to ModuleEntry::_pd field
   void add_class(Klass* k, bool publicize = true);
   void remove_class(Klass* k);
   bool contains_klass(Klass* k);
--- a/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -41,7 +41,7 @@
 
 
 inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader, TRAPS) {
-  guarantee(loader() != NULL && loader()->is_oop(), "Loader must be oop");
+  guarantee(loader() != NULL && oopDesc::is_oop(loader()), "Loader must be oop");
   // Gets the class loader data out of the java/lang/ClassLoader object, if non-null
   // it's already in the loader_data, so no need to add
   ClassLoaderData* loader_data= java_lang_ClassLoader::loader_data(loader());
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -799,7 +799,7 @@
     // If java.base was already defined then patch this particular class with java.base.
     if (javabase_was_defined) {
       ModuleEntry *javabase_entry = ModuleEntryTable::javabase_moduleEntry();
-      assert(javabase_entry != NULL && javabase_entry->module_handle() != NULL,
+      assert(javabase_entry != NULL && javabase_entry->module() != NULL,
              "Setting class module field, " JAVA_BASE_NAME " should be defined");
       Handle javabase_handle(THREAD, javabase_entry->module());
       set_module(mirror(), javabase_handle());
@@ -1430,7 +1430,7 @@
 int java_lang_ThreadGroup::_ngroups_offset = 0;
 
 oop  java_lang_ThreadGroup::parent(oop java_thread_group) {
-  assert(java_thread_group->is_oop(), "thread group must be oop");
+  assert(oopDesc::is_oop(java_thread_group), "thread group must be oop");
   return java_thread_group->obj_field(_parent_offset);
 }
 
@@ -1446,7 +1446,7 @@
 }
 
 int java_lang_ThreadGroup::nthreads(oop java_thread_group) {
-  assert(java_thread_group->is_oop(), "thread group must be oop");
+  assert(oopDesc::is_oop(java_thread_group), "thread group must be oop");
   return java_thread_group->int_field(_nthreads_offset);
 }
 
@@ -1458,7 +1458,7 @@
 }
 
 int java_lang_ThreadGroup::ngroups(oop java_thread_group) {
-  assert(java_thread_group->is_oop(), "thread group must be oop");
+  assert(oopDesc::is_oop(java_thread_group), "thread group must be oop");
   return java_thread_group->int_field(_ngroups_offset);
 }
 
@@ -1469,17 +1469,17 @@
 }
 
 ThreadPriority java_lang_ThreadGroup::maxPriority(oop java_thread_group) {
-  assert(java_thread_group->is_oop(), "thread group must be oop");
+  assert(oopDesc::is_oop(java_thread_group), "thread group must be oop");
   return (ThreadPriority) java_thread_group->int_field(_maxPriority_offset);
 }
 
 bool java_lang_ThreadGroup::is_destroyed(oop java_thread_group) {
-  assert(java_thread_group->is_oop(), "thread group must be oop");
+  assert(oopDesc::is_oop(java_thread_group), "thread group must be oop");
   return java_thread_group->bool_field(_destroyed_offset) != 0;
 }
 
 bool java_lang_ThreadGroup::is_daemon(oop java_thread_group) {
-  assert(java_thread_group->is_oop(), "thread group must be oop");
+  assert(oopDesc::is_oop(java_thread_group), "thread group must be oop");
   return java_thread_group->bool_field(_daemon_offset) != 0;
 }
 
@@ -2868,7 +2868,7 @@
 ModuleEntry* java_lang_Module::module_entry(oop module, TRAPS) {
   assert(_module_entry_offset != -1, "Uninitialized module_entry_offset");
   assert(module != NULL, "module can't be null");
-  assert(module->is_oop(), "module must be oop");
+  assert(oopDesc::is_oop(module), "module must be oop");
 
   ModuleEntry* module_entry = (ModuleEntry*)module->address_field(_module_entry_offset);
   if (module_entry == NULL) {
@@ -2885,7 +2885,7 @@
 void java_lang_Module::set_module_entry(oop module, ModuleEntry* module_entry) {
   assert(_module_entry_offset != -1, "Uninitialized module_entry_offset");
   assert(module != NULL, "module can't be null");
-  assert(module->is_oop(), "module must be oop");
+  assert(oopDesc::is_oop(module), "module must be oop");
   module->address_field_put(_module_entry_offset, (address)module_entry);
 }
 
@@ -3088,12 +3088,9 @@
 
 oop java_lang_invoke_DirectMethodHandle::member(oop dmh) {
   oop member_name = NULL;
-  bool is_dmh = dmh->is_oop() && java_lang_invoke_DirectMethodHandle::is_instance(dmh);
-  assert(is_dmh, "a DirectMethodHandle oop is expected");
-  if (is_dmh) {
-    member_name = dmh->obj_field(member_offset_in_bytes());
-  }
-  return member_name;
+  assert(oopDesc::is_oop(dmh) && java_lang_invoke_DirectMethodHandle::is_instance(dmh),
+         "a DirectMethodHandle oop is expected");
+  return dmh->obj_field(member_offset_in_bytes());
 }
 
 void java_lang_invoke_DirectMethodHandle::compute_offsets() {
@@ -3476,7 +3473,7 @@
 int  java_lang_ClassLoader::unnamedModule_offset = -1;
 
 ClassLoaderData** java_lang_ClassLoader::loader_data_addr(oop loader) {
-    assert(loader != NULL && loader->is_oop(), "loader must be oop");
+    assert(loader != NULL && oopDesc::is_oop(loader), "loader must be oop");
     return (ClassLoaderData**) loader->address_field_addr(_loader_data_offset);
 }
 
--- a/hotspot/src/share/vm/classfile/moduleEntry.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/classfile/moduleEntry.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -80,19 +80,16 @@
 }
 
 // Returns the shared ProtectionDomain
-Handle ModuleEntry::shared_protection_domain() {
-  return Handle(Thread::current(), JNIHandles::resolve(_pd));
+oop ModuleEntry::shared_protection_domain() {
+  return _pd.resolve();
 }
 
 // Set the shared ProtectionDomain atomically
 void ModuleEntry::set_shared_protection_domain(ClassLoaderData *loader_data,
                                                Handle pd_h) {
   // Create a handle for the shared ProtectionDomain and save it atomically.
-  // If someone beats us setting the _pd cache, the created handle is destroyed.
-  jobject obj = loader_data->add_handle(pd_h);
-  if (Atomic::cmpxchg_ptr(obj, &_pd, NULL) != NULL) {
-    loader_data->remove_handle_unsafe(obj);
-  }
+  // init_handle_locked checks if someone beats us setting the _pd cache.
+  loader_data->init_handle_locked(_pd, pd_h);
 }
 
 // Returns true if this module can read module m
--- a/hotspot/src/share/vm/classfile/moduleEntry.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/classfile/moduleEntry.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -27,6 +27,7 @@
 
 #include "classfile/classLoaderData.hpp"
 #include "classfile/vmSymbols.hpp"
+#include "oops/oopHandle.hpp"
 #include "oops/symbol.hpp"
 #include "prims/jni.h"
 #include "runtime/jniHandles.hpp"
@@ -56,8 +57,8 @@
 // data structure.
 class ModuleEntry : public HashtableEntry<Symbol*, mtModule> {
 private:
-  jobject _module;                     // java.lang.Module
-  jobject _pd;                         // java.security.ProtectionDomain, cached
+  OopHandle _module;                   // java.lang.Module
+  OopHandle _pd;                       // java.security.ProtectionDomain, cached
                                        // for shared classes from this module
   ClassLoaderData* _loader_data;
   GrowableArray<ModuleEntry*>* _reads; // list of modules that are readable by this module
@@ -89,16 +90,16 @@
   Symbol*          name() const                        { return literal(); }
   void             set_name(Symbol* n)                 { set_literal(n); }
 
-  oop              module() const                      { return JNIHandles::resolve(_module); }
-  jobject          module_handle() const               { return _module; }
-  void             set_module(jobject j)               { _module = j; }
+  oop              module() const                      { return _module.resolve(); }
+  OopHandle        module_handle() const               { return _module; }
+  void             set_module(OopHandle j)             { _module = j; }
 
   // The shared ProtectionDomain reference is set once the VM loads a shared class
   // originated from the current Module. The referenced ProtectionDomain object is
   // created by the ClassLoader when loading a class (shared or non-shared) from the
   // Module for the first time. This ProtectionDomain object is used for all
   // classes from the Module loaded by the same ClassLoader.
-  Handle           shared_protection_domain();
+  oop              shared_protection_domain();
   void             set_shared_protection_domain(ClassLoaderData *loader_data, Handle pd);
 
   ClassLoaderData* loader_data() const                 { return _loader_data; }
@@ -246,7 +247,7 @@
   static void set_javabase_moduleEntry(ModuleEntry* java_base) { _javabase_module = java_base; }
 
   static bool javabase_defined() { return ((_javabase_module != NULL) &&
-                                           (_javabase_module->module_handle() != NULL)); }
+                                           (_javabase_module->module() != NULL)); }
   static void finalize_javabase(Handle module_handle, Symbol* version, Symbol* location);
   static void patch_javabase_entries(Handle module_handle);
 
--- a/hotspot/src/share/vm/classfile/protectionDomainCache.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/classfile/protectionDomainCache.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -97,7 +97,7 @@
 }
 
 void ProtectionDomainCacheEntry::verify() {
-  guarantee(literal()->is_oop(), "must be an oop");
+  guarantee(oopDesc::is_oop(literal()), "must be an oop");
 }
 
 ProtectionDomainCacheEntry* ProtectionDomainCacheTable::get(Handle protection_domain) {
--- a/hotspot/src/share/vm/code/debugInfo.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/code/debugInfo.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -48,7 +48,7 @@
 
 oop DebugInfoReadStream::read_oop() {
   oop o = code()->oop_at(read_int());
-  assert(o->is_oop_or_null(), "oop only");
+  assert(oopDesc::is_oop_or_null(o), "oop only");
   return o;
 }
 
--- a/hotspot/src/share/vm/code/dependencies.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/code/dependencies.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -940,7 +940,7 @@
 
 oop Dependencies::DepStream::argument_oop(int i) {
   oop result = recorded_oop_at(argument_index(i));
-  assert(result == NULL || result->is_oop(), "must be");
+  assert(oopDesc::is_oop_or_null(result), "must be");
   return result;
 }
 
--- a/hotspot/src/share/vm/code/nmethod.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/code/nmethod.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -2090,7 +2090,7 @@
   VerifyOopsClosure(nmethod* nm) : _nm(nm), _ok(true) { }
   bool ok() { return _ok; }
   virtual void do_oop(oop* p) {
-    if ((*p) == NULL || (*p)->is_oop())  return;
+    if (oopDesc::is_oop_or_null(*p)) return;
     if (_ok) {
       _nm->print_nmethod(true);
       _ok = false;
@@ -2112,7 +2112,7 @@
   // Make sure all the entry points are correctly aligned for patching.
   NativeJump::check_verified_entry_alignment(entry_point(), verified_entry_point());
 
-  // assert(method()->is_oop(), "must be valid");
+  // assert(oopDesc::is_oop(method()), "must be valid");
 
   ResourceMark rm;
 
--- a/hotspot/src/share/vm/code/relocInfo.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/code/relocInfo.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -867,7 +867,7 @@
       // work even during GC or other inconvenient times.
       if (WizardMode && oop_value != NULL) {
         tty->print("oop_value=" INTPTR_FORMAT ": ", p2i(oop_value));
-        if (oop_value->is_oop()) {
+        if (oopDesc::is_oop(oop_value)) {
           oop_value->print_value_on(tty);
         }
       }
--- a/hotspot/src/share/vm/gc/cms/cmsOopClosures.inline.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/cms/cmsOopClosures.inline.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -74,7 +74,7 @@
   while (_work_queue->size() > max) {
     oop newOop;
     if (_work_queue->pop_local(newOop)) {
-      assert(newOop->is_oop(), "Expected an oop");
+      assert(oopDesc::is_oop(newOop), "Expected an oop");
       assert(_bit_map->isMarked((HeapWord*)newOop),
              "only grey objects on this stack");
       // iterate over the oops in this oop, marking and pushing
--- a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -929,7 +929,7 @@
       if (k != NULL) {
         assert(k->is_klass(), "Should really be klass oop.");
         oop o = (oop)p;
-        assert(o->is_oop(true /* ignore mark word */), "Should be an oop.");
+        assert(oopDesc::is_oop(o, true /* ignore mark word */), "Should be an oop.");
 
         size_t res = o->size_given_klass(k);
         res = adjustObjectSize(res);
@@ -979,7 +979,7 @@
       if (k != NULL) {
         assert(k->is_klass(), "Should really be klass oop.");
         oop o = (oop)p;
-        assert(o->is_oop(), "Should be an oop");
+        assert(oopDesc::is_oop(o), "Should be an oop");
 
         size_t res = o->size_given_klass(k);
         res = adjustObjectSize(res);
@@ -1005,7 +1005,7 @@
     // Ignore mark word because this may be a recently promoted
     // object whose mark word is used to chain together grey
     // objects (the last one would have a null value).
-    assert(oop(p)->is_oop(true), "Should be an oop");
+    assert(oopDesc::is_oop(oop(p), true), "Should be an oop");
     return adjustObjectSize(oop(p)->size());
   }
 }
@@ -1022,7 +1022,7 @@
     // Ignore mark word because it may have been used to
     // chain together promoted objects (the last one
     // would have a null value).
-    assert(oop(p)->is_oop(true), "Should be an oop");
+    assert(oopDesc::is_oop(oop(p), true), "Should be an oop");
     return true;
   } else {
     return false;  // Was not an object at the start of collection.
@@ -1066,7 +1066,7 @@
     // Ignore mark word because it may have been used to
     // chain together promoted objects (the last one
     // would have a null value).
-    assert(oop(p)->is_oop(true), "Should be an oop");
+    assert(oopDesc::is_oop(oop(p), true), "Should be an oop");
     return true;
   }
   return false;
@@ -2174,7 +2174,7 @@
     if (_sp->block_is_obj(addr)) {
       was_obj = true;
       oop p = oop(addr);
-      guarantee(p->is_oop(), "Should be an oop");
+      guarantee(oopDesc::is_oop(p), "Should be an oop");
       res = _sp->adjustObjectSize(p->size());
       if (_sp->obj_is_alive(addr)) {
         was_live = true;
@@ -2226,7 +2226,7 @@
         guarantee(!_sp->is_in_reserved(obj) ||
                   _sp->block_is_obj((HeapWord*)obj),
                   "Should be an object");
-        guarantee(obj->is_oop(), "Should be an oop");
+        guarantee(oopDesc::is_oop(obj), "Should be an oop");
         obj->verify();
         if (_past_remark) {
           // Remark has been completed, the object should be marked
@@ -2243,7 +2243,7 @@
       }
     } else if (_sp->is_in_reserved(p)) {
       // the reference is from FLS, and points out of FLS
-      guarantee(obj->is_oop(), "Should be an oop");
+      guarantee(oopDesc::is_oop(obj), "Should be an oop");
       obj->verify();
     }
   }
--- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -940,7 +940,7 @@
   if (res != NULL) {
     // See comment in allocate() about when objects should
     // be allocated live.
-    assert(obj->is_oop(), "Will dereference klass pointer below");
+    assert(oopDesc::is_oop(obj), "Will dereference klass pointer below");
     collector()->promoted(false,           // Not parallel
                           (HeapWord*)res, obj->is_objArray(), obj_size);
     // promotion counters
@@ -1063,13 +1063,13 @@
   }
   assert(obj->klass_or_null() == NULL, "Object should be uninitialized here.");
   assert(!((FreeChunk*)obj_ptr)->is_free(), "Error, block will look free but show wrong size");
-  assert(old->is_oop(), "Will use and dereference old klass ptr below");
+  assert(oopDesc::is_oop(old), "Will use and dereference old klass ptr below");
 
   // Finally, install the klass pointer (this should be volatile).
   OrderAccess::storestore();
   obj->set_klass(old->klass());
   // We should now be able to calculate the right size for this object
-  assert(obj->is_oop() && obj->size() == (int)word_sz, "Error, incorrect size computed for promoted object");
+  assert(oopDesc::is_oop(obj) && obj->size() == (int)word_sz, "Error, incorrect size computed for promoted object");
 
   collector()->promoted(true,          // parallel
                         obj_ptr, old->is_objArray(), word_sz);
@@ -3348,7 +3348,7 @@
 // been published), so we do not need to check for
 // uninitialized objects before pushing here.
 void ParConcMarkingClosure::do_oop(oop obj) {
-  assert(obj->is_oop_or_null(true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj));
+  assert(oopDesc::is_oop_or_null(obj, true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj));
   HeapWord* addr = (HeapWord*)obj;
   // Check if oop points into the CMS generation
   // and is not marked
@@ -3390,7 +3390,7 @@
   while (_work_queue->size() > max) {
     oop new_oop;
     if (_work_queue->pop_local(new_oop)) {
-      assert(new_oop->is_oop(), "Should be an oop");
+      assert(oopDesc::is_oop(new_oop), "Should be an oop");
       assert(_bit_map->isMarked((HeapWord*)new_oop), "Grey object");
       assert(_span.contains((HeapWord*)new_oop), "Not in span");
       new_oop->oop_iterate(this);  // do_oop() above
@@ -3431,7 +3431,7 @@
       // assert(work_q->size() > 0, "Work from overflow stack");
       continue;
     } else if (task_queues()->steal(i, seed, /* reference */ obj_to_scan)) {
-      assert(obj_to_scan->is_oop(), "Should be an oop");
+      assert(oopDesc::is_oop(obj_to_scan), "Should be an oop");
       assert(bm->isMarked((HeapWord*)obj_to_scan), "Grey object");
       obj_to_scan->oop_iterate(&cl);
     } else if (terminator()->offer_termination(&_term_term)) {
@@ -4522,7 +4522,7 @@
       assert(mr.is_empty() || space->used_region().contains(mr),
              "Should be in space");
       // Verify that "start" is an object boundary
-      assert(mr.is_empty() || oop(mr.start())->is_oop(),
+      assert(mr.is_empty() || oopDesc::is_oop(oop(mr.start())),
              "Should be an oop");
       space->par_oop_iterate(mr, cl);
     }
@@ -4656,7 +4656,7 @@
     // Try to steal from other queues that have work
     if (task_queues()->steal(i, seed, /* reference */ obj_to_scan)) {
       NOT_PRODUCT(num_steals++;)
-      assert(obj_to_scan->is_oop(), "Oops, not an oop!");
+      assert(oopDesc::is_oop(obj_to_scan), "Oops, not an oop!");
       assert(bm->isMarked((HeapWord*)obj_to_scan), "Stole an unmarked oop?");
       // Do scanning work
       obj_to_scan->oop_iterate(cl);
@@ -5135,7 +5135,7 @@
     // Try to steal from other queues that have work
     if (task_queues()->steal(i, seed, /* reference */ obj_to_scan)) {
       NOT_PRODUCT(num_steals++;)
-      assert(obj_to_scan->is_oop(), "Oops, not an oop!");
+      assert(oopDesc::is_oop(obj_to_scan), "Oops, not an oop!");
       assert(_mark_bit_map->isMarked((HeapWord*)obj_to_scan), "Stole an unmarked oop?");
       // Do scanning work
       obj_to_scan->oop_iterate(keep_alive);
@@ -5825,7 +5825,7 @@
 
 void MarkRefsIntoClosure::do_oop(oop obj) {
   // if p points into _span, then mark corresponding bit in _markBitMap
-  assert(obj->is_oop(), "expected an oop");
+  assert(oopDesc::is_oop(obj), "expected an oop");
   HeapWord* addr = (HeapWord*)obj;
   if (_span.contains(addr)) {
     // this should be made more efficient
@@ -5847,7 +5847,7 @@
 
 void ParMarkRefsIntoClosure::do_oop(oop obj) {
   // if p points into _span, then mark corresponding bit in _markBitMap
-  assert(obj->is_oop(), "expected an oop");
+  assert(oopDesc::is_oop(obj), "expected an oop");
   HeapWord* addr = (HeapWord*)obj;
   if (_span.contains(addr)) {
     // this should be made more efficient
@@ -5871,7 +5871,7 @@
 
 void MarkRefsIntoVerifyClosure::do_oop(oop obj) {
   // if p points into _span, then mark corresponding bit in _markBitMap
-  assert(obj->is_oop(), "expected an oop");
+  assert(oopDesc::is_oop(obj), "expected an oop");
   HeapWord* addr = (HeapWord*)obj;
   if (_span.contains(addr)) {
     _verification_bm->mark(addr);
@@ -5925,7 +5925,7 @@
 // The parallel version (Par_...) appears further below.
 void MarkRefsIntoAndScanClosure::do_oop(oop obj) {
   if (obj != NULL) {
-    assert(obj->is_oop(), "expected an oop");
+    assert(oopDesc::is_oop(obj), "expected an oop");
     HeapWord* addr = (HeapWord*)obj;
     assert(_mark_stack->isEmpty(), "pre-condition (eager drainage)");
     assert(_collector->overflow_list_is_empty(),
@@ -5941,7 +5941,7 @@
       assert(res, "Should have space to push on empty stack");
       do {
         oop new_oop = _mark_stack->pop();
-        assert(new_oop != NULL && new_oop->is_oop(), "Expected an oop");
+        assert(new_oop != NULL && oopDesc::is_oop(new_oop), "Expected an oop");
         assert(_bit_map->isMarked((HeapWord*)new_oop),
                "only grey objects on this stack");
         // iterate over the oops in this oop, marking and pushing
@@ -6023,7 +6023,7 @@
   if (obj != NULL) {
     // Ignore mark word because this could be an already marked oop
     // that may be chained at the end of the overflow list.
-    assert(obj->is_oop(true), "expected an oop");
+    assert(oopDesc::is_oop(obj, true), "expected an oop");
     HeapWord* addr = (HeapWord*)obj;
     if (_span.contains(addr) &&
         !_bit_map->isMarked(addr)) {
@@ -6069,7 +6069,7 @@
     if (p->klass_or_null_acquire() != NULL) {
         // an initialized object; ignore mark word in verification below
         // since we are running concurrent with mutators
-        assert(p->is_oop(true), "should be an oop");
+        assert(oopDesc::is_oop(p, true), "should be an oop");
         if (p->is_objArray()) {
           // objArrays are precisely marked; restrict scanning
           // to dirty cards only.
@@ -6118,7 +6118,7 @@
     } else {
       // An object not (yet) reached by marking: we merely need to
       // compute its size so as to go look at the next block.
-      assert(p->is_oop(true), "should be an oop");
+      assert(oopDesc::is_oop(p, true), "should be an oop");
       size = CompactibleFreeListSpace::adjustObjectSize(p->size());
     }
   }
@@ -6165,7 +6165,7 @@
   assert(p->klass_or_null() != NULL, "object should be initialized");
   // an initialized object; ignore mark word in verification below
   // since we are running concurrent with mutators
-  assert(p->is_oop(true), "should be an oop");
+  assert(oopDesc::is_oop(p, true), "should be an oop");
   // Note that we do not yield while we iterate over
   // the interior oops of p, pushing the relevant ones
   // on our marking stack.
@@ -6179,7 +6179,7 @@
   // from the grey objects at a later time.
   while (!_mark_stack->isEmpty()) {
     oop new_oop = _mark_stack->pop();
-    assert(new_oop != NULL && new_oop->is_oop(), "Expected an oop");
+    assert(new_oop != NULL && oopDesc::is_oop(new_oop), "Expected an oop");
     assert(_bit_map->isMarked((HeapWord*)new_oop),
            "only grey objects on this stack");
     // iterate over the oops in this oop, marking and pushing
@@ -6223,7 +6223,7 @@
 // isMarked() query is "safe".
 bool ScanMarkedObjectsAgainClosure::do_object_bm(oop p, MemRegion mr) {
   // Ignore mark word because we are running concurrent with mutators
-  assert(p->is_oop_or_null(true), "Expected an oop or NULL at " PTR_FORMAT, p2i(p));
+  assert(oopDesc::is_oop_or_null(p, true), "Expected an oop or NULL at " PTR_FORMAT, p2i(p));
   HeapWord* addr = (HeapWord*)p;
   assert(_span.contains(addr), "we are scanning the CMS generation");
   bool is_obj_array = false;
@@ -6376,7 +6376,7 @@
   oop obj = oop(ptr);
   // Ignore mark word in verification below, since we
   // may be running concurrent with mutators.
-  assert(obj->is_oop(true), "should be an oop");
+  assert(oopDesc::is_oop(obj, true), "should be an oop");
   assert(_finger <= ptr, "_finger runneth ahead");
   // advance the finger to right end of this object
   _finger = ptr + obj->size();
@@ -6423,7 +6423,7 @@
     oop new_oop = _markStack->pop();
     // Skip verifying header mark word below because we are
     // running concurrent with mutators.
-    assert(new_oop->is_oop(true), "Oops! expected to pop an oop");
+    assert(oopDesc::is_oop(new_oop, true), "Oops! expected to pop an oop");
     // now scan this oop's oops
     new_oop->oop_iterate(&pushOrMarkClosure);
     do_yield_check();
@@ -6489,7 +6489,7 @@
   oop obj = oop(ptr);
   // Ignore mark word in verification below, since we
   // may be running concurrent with mutators.
-  assert(obj->is_oop(true), "should be an oop");
+  assert(oopDesc::is_oop(obj, true), "should be an oop");
   assert(_finger <= ptr, "_finger runneth ahead");
   // advance the finger to right end of this object
   _finger = ptr + obj->size();
@@ -6550,7 +6550,7 @@
     }
     // Skip verifying header mark word below because we are
     // running concurrent with mutators.
-    assert(new_oop->is_oop(true), "Oops! expected to pop an oop");
+    assert(oopDesc::is_oop(new_oop, true), "Oops! expected to pop an oop");
     // now scan this oop's oops
     new_oop->oop_iterate(&pushOrMarkClosure);
     do_yield_check();
@@ -6604,7 +6604,7 @@
          "should drain stack to limit stack usage");
   // convert addr to an oop preparatory to scanning
   oop obj = oop(addr);
-  assert(obj->is_oop(), "should be an oop");
+  assert(oopDesc::is_oop(obj), "should be an oop");
   assert(_finger <= addr, "_finger runneth ahead");
   // advance the finger to right end of this object
   _finger = addr + obj->size();
@@ -6615,7 +6615,7 @@
   assert(res, "Empty non-zero size stack should have space for single push");
   while (!_mark_stack->isEmpty()) {
     oop new_oop = _mark_stack->pop();
-    assert(new_oop->is_oop(), "Oops! expected to pop an oop");
+    assert(oopDesc::is_oop(new_oop), "Oops! expected to pop an oop");
     // now scan this oop's oops
     new_oop->oop_iterate(&_pam_verify_closure);
   }
@@ -6650,7 +6650,7 @@
 }
 
 void PushAndMarkVerifyClosure::do_oop(oop obj) {
-  assert(obj->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj));
+  assert(oopDesc::is_oop_or_null(obj), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj));
   HeapWord* addr = (HeapWord*)obj;
   if (_span.contains(addr) && !_verification_bm->isMarked(addr)) {
     // Oop lies in _span and isn't yet grey or black
@@ -6747,7 +6747,7 @@
 
 void PushOrMarkClosure::do_oop(oop obj) {
   // Ignore mark word because we are running concurrent with mutators.
-  assert(obj->is_oop_or_null(true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj));
+  assert(oopDesc::is_oop_or_null(obj, true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj));
   HeapWord* addr = (HeapWord*)obj;
   if (_span.contains(addr) && !_bitMap->isMarked(addr)) {
     // Oop lies in _span and isn't yet grey or black
@@ -6782,7 +6782,7 @@
 
 void ParPushOrMarkClosure::do_oop(oop obj) {
   // Ignore mark word because we are running concurrent with mutators.
-  assert(obj->is_oop_or_null(true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj));
+  assert(oopDesc::is_oop_or_null(obj, true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj));
   HeapWord* addr = (HeapWord*)obj;
   if (_whole_span.contains(addr) && !_bit_map->isMarked(addr)) {
     // Oop lies in _span and isn't yet grey or black
@@ -6855,7 +6855,7 @@
   // phases, the object may already have been reached by a  different
   // path and may be at the end of the global overflow list (so
   // the mark word may be NULL).
-  assert(obj->is_oop_or_null(true /* ignore mark word */),
+  assert(oopDesc::is_oop_or_null(obj, true /* ignore mark word */),
          "Expected an oop or NULL at " PTR_FORMAT, p2i(obj));
   HeapWord* addr = (HeapWord*)obj;
   // Check if oop points into the CMS generation
@@ -6934,7 +6934,7 @@
   // value, by the time we get to examined this failing assert in
   // the debugger, is_oop_or_null(false) may subsequently start
   // to hold.
-  assert(obj->is_oop_or_null(true),
+  assert(oopDesc::is_oop_or_null(obj, true),
          "Expected an oop or NULL at " PTR_FORMAT, p2i(obj));
   HeapWord* addr = (HeapWord*)obj;
   // Check if oop points into the CMS generation
@@ -7325,7 +7325,7 @@
 
   // This object is live: we'd normally expect this to be
   // an oop, and like to assert the following:
-  // assert(oop(addr)->is_oop(), "live block should be an oop");
+  // assert(oopDesc::is_oop(oop(addr)), "live block should be an oop");
   // However, as we commented above, this may be an object whose
   // header hasn't yet been initialized.
   size_t size;
@@ -7341,7 +7341,7 @@
 #ifdef ASSERT
       if (oop(addr)->klass_or_null_acquire() != NULL) {
         // Ignore mark word because we are running concurrent with mutators
-        assert(oop(addr)->is_oop(true), "live block should be an oop");
+        assert(oopDesc::is_oop(oop(addr), true), "live block should be an oop");
         assert(size ==
                CompactibleFreeListSpace::adjustObjectSize(oop(addr)->size()),
                "P-mark and computed size do not agree");
@@ -7353,7 +7353,7 @@
     assert(oop(addr)->klass_or_null_acquire() != NULL,
            "Should be an initialized object");
     // Ignore mark word because we are running concurrent with mutators
-    assert(oop(addr)->is_oop(true), "live block should be an oop");
+    assert(oopDesc::is_oop(oop(addr), true), "live block should be an oop");
     // Verify that the bit map has no bits marked between
     // addr and purported end of this block.
     size = CompactibleFreeListSpace::adjustObjectSize(oop(addr)->size());
@@ -7661,7 +7661,7 @@
   while (_work_queue->size() > max) {
     oop new_oop;
     if (_work_queue->pop_local(new_oop)) {
-      assert(new_oop != NULL && new_oop->is_oop(), "Expected an oop");
+      assert(new_oop != NULL && oopDesc::is_oop(new_oop), "Expected an oop");
       assert(_bit_map->isMarked((HeapWord*)new_oop),
              "no white objects on this stack!");
       assert(_span.contains((HeapWord*)new_oop), "Out of bounds oop");
@@ -7741,7 +7741,7 @@
     HeapWord* addr = (HeapWord*)obj;
     assert(_span.contains(addr), "Should be within span");
     assert(_bit_map->isMarked(addr), "Should be marked");
-    assert(obj->is_oop(), "Should be an oop");
+    assert(oopDesc::is_oop(obj), "Should be an oop");
     obj->oop_iterate(_keep_alive);
   }
 }
@@ -7756,7 +7756,7 @@
   while (_work_queue->size() > max) {
     oop new_oop;
     if (_work_queue->pop_local(new_oop)) {
-      assert(new_oop->is_oop(), "Expected an oop");
+      assert(oopDesc::is_oop(new_oop), "Expected an oop");
       assert(_bit_map->isMarked((HeapWord*)new_oop),
              "no white objects on this stack!");
       assert(_span.contains((HeapWord*)new_oop), "Out of bounds oop");
@@ -7807,7 +7807,7 @@
   for (oop next; i > 0 && cur != NULL; cur = next, i--) {
     next = oop(cur->mark());
     cur->set_mark(proto);   // until proven otherwise
-    assert(cur->is_oop(), "Should be an oop");
+    assert(oopDesc::is_oop(cur), "Should be an oop");
     bool res = stack->push(cur);
     assert(res, "Bit off more than can chew?");
     NOT_PRODUCT(n++;)
@@ -7951,7 +7951,7 @@
   for (cur = prefix; cur != NULL; cur = next) {
     next = oop(cur->mark());
     cur->set_mark(proto);   // until proven otherwise
-    assert(cur->is_oop(), "Should be an oop");
+    assert(oopDesc::is_oop(cur), "Should be an oop");
     bool res = work_q->push(cur);
     assert(res, "Bit off more than we can chew?");
     NOT_PRODUCT(n++;)
@@ -7966,7 +7966,7 @@
 // Single-threaded
 void CMSCollector::push_on_overflow_list(oop p) {
   NOT_PRODUCT(_num_par_pushes++;)
-  assert(p->is_oop(), "Not an oop");
+  assert(oopDesc::is_oop(p), "Not an oop");
   preserve_mark_if_necessary(p);
   p->set_mark((markOop)_overflow_list);
   _overflow_list = p;
@@ -7975,7 +7975,7 @@
 // Multi-threaded; use CAS to prepend to overflow list
 void CMSCollector::par_push_on_overflow_list(oop p) {
   NOT_PRODUCT(Atomic::inc_ptr(&_num_par_pushes);)
-  assert(p->is_oop(), "Not an oop");
+  assert(oopDesc::is_oop(p), "Not an oop");
   par_preserve_mark_if_necessary(p);
   oop observed_overflow_list = _overflow_list;
   oop cur_overflow_list;
@@ -8062,7 +8062,7 @@
 
   while (!_preserved_oop_stack.is_empty()) {
     oop p = _preserved_oop_stack.pop();
-    assert(p->is_oop(), "Should be an oop");
+    assert(oopDesc::is_oop(p), "Should be an oop");
     assert(_span.contains(p), "oop should be in _span");
     assert(p->mark() == markOopDesc::prototype(),
            "Set when taken from overflow list");
--- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -684,7 +684,7 @@
     oop obj = oopDesc::load_decode_heap_oop_not_null(p);
     // We never expect to see a null reference being processed
     // as a weak reference.
-    assert(obj->is_oop(), "expected an oop while scanning weak refs");
+    assert(oopDesc::is_oop(obj), "expected an oop while scanning weak refs");
   }
 #endif // ASSERT
 
@@ -711,7 +711,7 @@
     oop obj = oopDesc::load_decode_heap_oop_not_null(p);
     // We never expect to see a null reference being processed
     // as a weak reference.
-    assert(obj->is_oop(), "expected an oop while scanning weak refs");
+    assert(oopDesc::is_oop(obj), "expected an oop while scanning weak refs");
   }
 #endif // ASSERT
 
--- a/hotspot/src/share/vm/gc/cms/promotionInfo.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/cms/promotionInfo.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -43,7 +43,7 @@
   } else {
     res = (PromotedObject*)(_next & next_mask);
   }
-  assert(oop(res)->is_oop_or_null(true /* ignore mark word */), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(res)));
+  assert(oopDesc::is_oop_or_null(oop(res), true /* ignore mark word */), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(res)));
   return res;
 }
 
@@ -299,7 +299,7 @@
   for (PromotedObject* curObj = _promoHead; curObj != NULL; curObj = curObj->next()) {
     guarantee(space()->is_in_reserved((HeapWord*)curObj), "Containment");
     // the last promoted object may fail the mark() != NULL test of is_oop().
-    guarantee(curObj->next() == NULL || oop(curObj)->is_oop(), "must be an oop");
+    guarantee(curObj->next() == NULL || oopDesc::is_oop(oop(curObj)), "must be an oop");
     if (curObj->hasDisplacedMark()) {
       numObjsWithDisplacedHdrs++;
     }
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -38,12 +38,12 @@
 #include "gc/g1/g1CollectorPolicy.hpp"
 #include "gc/g1/g1CollectorState.hpp"
 #include "gc/g1/g1EvacStats.inline.hpp"
+#include "gc/g1/g1FullGCScope.hpp"
 #include "gc/g1/g1GCPhaseTimes.hpp"
 #include "gc/g1/g1HeapSizingPolicy.hpp"
 #include "gc/g1/g1HeapTransition.hpp"
 #include "gc/g1/g1HeapVerifier.hpp"
 #include "gc/g1/g1HotCardCache.hpp"
-#include "gc/g1/g1MarkSweep.hpp"
 #include "gc/g1/g1OopClosures.inline.hpp"
 #include "gc/g1/g1ParScanThreadState.inline.hpp"
 #include "gc/g1/g1Policy.hpp"
@@ -51,6 +51,7 @@
 #include "gc/g1/g1RemSet.inline.hpp"
 #include "gc/g1/g1RootClosures.hpp"
 #include "gc/g1/g1RootProcessor.hpp"
+#include "gc/g1/g1SerialFullCollector.hpp"
 #include "gc/g1/g1StringDedup.hpp"
 #include "gc/g1/g1YCTypes.hpp"
 #include "gc/g1/heapRegion.inline.hpp"
@@ -1062,73 +1063,6 @@
   ShouldNotReachHere();
 }
 
-class PostMCRemSetClearClosure: public HeapRegionClosure {
-  G1CollectedHeap* _g1h;
-  ModRefBarrierSet* _mr_bs;
-public:
-  PostMCRemSetClearClosure(G1CollectedHeap* g1h, ModRefBarrierSet* mr_bs) :
-    _g1h(g1h), _mr_bs(mr_bs) {}
-
-  bool doHeapRegion(HeapRegion* r) {
-    HeapRegionRemSet* hrrs = r->rem_set();
-
-    _g1h->reset_gc_time_stamps(r);
-
-    if (r->is_continues_humongous()) {
-      // We'll assert that the strong code root list and RSet is empty
-      assert(hrrs->strong_code_roots_list_length() == 0, "sanity");
-      assert(hrrs->occupied() == 0, "RSet should be empty");
-    } else {
-      hrrs->clear();
-    }
-    // You might think here that we could clear just the cards
-    // corresponding to the used region.  But no: if we leave a dirty card
-    // in a region we might allocate into, then it would prevent that card
-    // from being enqueued, and cause it to be missed.
-    // Re: the performance cost: we shouldn't be doing full GC anyway!
-    _mr_bs->clear(MemRegion(r->bottom(), r->end()));
-
-    return false;
-  }
-};
-
-void G1CollectedHeap::clear_rsets_post_compaction() {
-  PostMCRemSetClearClosure rs_clear(this, g1_barrier_set());
-  heap_region_iterate(&rs_clear);
-}
-
-class RebuildRSOutOfRegionClosure: public HeapRegionClosure {
-  G1CollectedHeap*   _g1h;
-  RebuildRSOopClosure _cl;
-public:
-  RebuildRSOutOfRegionClosure(G1CollectedHeap* g1, uint worker_i = 0) :
-    _cl(g1->g1_rem_set(), worker_i),
-    _g1h(g1)
-  { }
-
-  bool doHeapRegion(HeapRegion* r) {
-    if (!r->is_continues_humongous()) {
-      _cl.set_from(r);
-      r->oop_iterate(&_cl);
-    }
-    return false;
-  }
-};
-
-class ParRebuildRSTask: public AbstractGangTask {
-  G1CollectedHeap* _g1;
-  HeapRegionClaimer _hrclaimer;
-
-public:
-  ParRebuildRSTask(G1CollectedHeap* g1) :
-      AbstractGangTask("ParRebuildRSTask"), _g1(g1), _hrclaimer(g1->workers()->active_workers()) {}
-
-  void work(uint worker_id) {
-    RebuildRSOutOfRegionClosure rebuild_rs(_g1, worker_id);
-    _g1->heap_region_par_iterate(&rebuild_rs, worker_id, &_hrclaimer);
-  }
-};
-
 class PostCompactionPrinterClosure: public HeapRegionClosure {
 private:
   G1HRPrinter* _hr_printer;
@@ -1151,252 +1085,183 @@
 
 }
 
+void G1CollectedHeap::abort_concurrent_cycle() {
+  // Note: When we have a more flexible GC logging framework that
+  // allows us to add optional attributes to a GC log record we
+  // could consider timing and reporting how long we wait in the
+  // following two methods.
+  wait_while_free_regions_coming();
+  // If we start the compaction before the CM threads finish
+  // scanning the root regions we might trip them over as we'll
+  // be moving objects / updating references. So let's wait until
+  // they are done. By telling them to abort, they should complete
+  // early.
+  _cm->root_regions()->abort();
+  _cm->root_regions()->wait_until_scan_finished();
+  append_secondary_free_list_if_not_empty_with_lock();
+
+  // Disable discovery and empty the discovered lists
+  // for the CM ref processor.
+  ref_processor_cm()->disable_discovery();
+  ref_processor_cm()->abandon_partial_discovery();
+  ref_processor_cm()->verify_no_references_recorded();
+
+  // Abandon current iterations of concurrent marking and concurrent
+  // refinement, if any are in progress.
+  concurrent_mark()->abort();
+}
+
+void G1CollectedHeap::prepare_heap_for_full_collection() {
+  // Make sure we'll choose a new allocation region afterwards.
+  _allocator->release_mutator_alloc_region();
+  _allocator->abandon_gc_alloc_regions();
+  g1_rem_set()->cleanupHRRS();
+
+  // We may have added regions to the current incremental collection
+  // set between the last GC or pause and now. We need to clear the
+  // incremental collection set and then start rebuilding it afresh
+  // after this full GC.
+  abandon_collection_set(collection_set());
+
+  tear_down_region_sets(false /* free_list_only */);
+  collector_state()->set_gcs_are_young(true);
+}
+
+void G1CollectedHeap::verify_before_full_collection(bool explicit_gc) {
+  assert(!GCCause::is_user_requested_gc(gc_cause()) || explicit_gc, "invariant");
+  assert(used() == recalculate_used(), "Should be equal");
+  _verifier->verify_region_sets_optional();
+  _verifier->verify_before_gc();
+  _verifier->check_bitmaps("Full GC Start");
+}
+
+void G1CollectedHeap::prepare_heap_for_mutators() {
+  // Delete metaspaces for unloaded class loaders and clean up loader_data graph
+  ClassLoaderDataGraph::purge();
+  MetaspaceAux::verify_metrics();
+
+  // Prepare heap for normal collections.
+  assert(num_free_regions() == 0, "we should not have added any free regions");
+  rebuild_region_sets(false /* free_list_only */);
+  abort_refinement();
+  resize_if_necessary_after_full_collection();
+
+  // Rebuild the strong code root lists for each region
+  rebuild_strong_code_roots();
+
+  // Start a new incremental collection set for the next pause
+  start_new_collection_set();
+
+  _allocator->init_mutator_alloc_region();
+
+  // Post collection state updates.
+  MetaspaceGC::compute_new_size();
+}
+
+void G1CollectedHeap::abort_refinement() {
+  if (_hot_card_cache->use_cache()) {
+    _hot_card_cache->reset_card_counts();
+    _hot_card_cache->reset_hot_cache();
+  }
+
+  // Discard all remembered set updates.
+  JavaThread::dirty_card_queue_set().abandon_logs();
+  assert(dirty_card_queue_set().completed_buffers_num() == 0, "DCQS should be empty");
+}
+
+void G1CollectedHeap::verify_after_full_collection() {
+  check_gc_time_stamps();
+  _hrm.verify_optional();
+  _verifier->verify_region_sets_optional();
+  _verifier->verify_after_gc();
+  // Clear the previous marking bitmap, if needed for bitmap verification.
+  // Note we cannot do this when we clear the next marking bitmap in
+  // G1ConcurrentMark::abort() above since VerifyDuringGC verifies the
+  // objects marked during a full GC against the previous bitmap.
+  // But we need to clear it before calling check_bitmaps below since
+  // the full GC has compacted objects and updated TAMS but not updated
+  // the prev bitmap.
+  if (G1VerifyBitmaps) {
+    GCTraceTime(Debug, gc)("Clear Bitmap for Verification");
+    _cm->clear_prev_bitmap(workers());
+  }
+  _verifier->check_bitmaps("Full GC End");
+
+  // At this point there should be no regions in the
+  // entire heap tagged as young.
+  assert(check_young_list_empty(), "young list should be empty at this point");
+
+  // Note: since we've just done a full GC, concurrent
+  // marking is no longer active. Therefore we need not
+  // re-enable reference discovery for the CM ref processor.
+  // That will be done at the start of the next marking cycle.
+  // We also know that the STW processor should no longer
+  // discover any new references.
+  assert(!ref_processor_stw()->discovery_enabled(), "Postcondition");
+  assert(!ref_processor_cm()->discovery_enabled(), "Postcondition");
+  ref_processor_stw()->verify_no_references_recorded();
+  ref_processor_cm()->verify_no_references_recorded();
+}
+
+void G1CollectedHeap::print_heap_after_full_collection(G1HeapTransition* heap_transition) {
+  print_hrm_post_compaction();
+  heap_transition->print();
+  print_heap_after_gc();
+  print_heap_regions();
+#ifdef TRACESPINNING
+  ParallelTaskTerminator::print_termination_counts();
+#endif
+}
+
+void G1CollectedHeap::do_full_collection_inner(G1FullGCScope* scope) {
+  GCTraceTime(Info, gc) tm("Pause Full", NULL, gc_cause(), true);
+  g1_policy()->record_full_collection_start();
+
+  print_heap_before_gc();
+  print_heap_regions();
+
+  abort_concurrent_cycle();
+  verify_before_full_collection(scope->is_explicit_gc());
+
+  gc_prologue(true);
+  prepare_heap_for_full_collection();
+
+  G1SerialFullCollector serial(scope, ref_processor_stw());
+  serial.prepare_collection();
+  serial.collect();
+  serial.complete_collection();
+
+  prepare_heap_for_mutators();
+
+  g1_policy()->record_full_collection_end();
+  gc_epilogue(true);
+
+  // Post collection verification.
+  verify_after_full_collection();
+
+  // Post collection logging.
+  // We should do this after we potentially resize the heap so
+  // that all the COMMIT / UNCOMMIT events are generated before
+  // the compaction events.
+  print_heap_after_full_collection(scope->heap_transition());
+}
+
 bool G1CollectedHeap::do_full_collection(bool explicit_gc,
                                          bool clear_all_soft_refs) {
   assert_at_safepoint(true /* should_be_vm_thread */);
 
   if (GCLocker::check_active_before_gc()) {
+    // Full GC was not completed.
     return false;
   }
 
-  STWGCTimer* gc_timer = G1MarkSweep::gc_timer();
-  gc_timer->register_gc_start();
-
-  SerialOldTracer* gc_tracer = G1MarkSweep::gc_tracer();
-  GCIdMark gc_id_mark;
-  gc_tracer->report_gc_start(gc_cause(), gc_timer->gc_start());
-
-  SvcGCMarker sgcm(SvcGCMarker::FULL);
-  ResourceMark rm;
-
-  print_heap_before_gc();
-  print_heap_regions();
-  trace_heap_before_gc(gc_tracer);
-
-  size_t metadata_prev_used = MetaspaceAux::used_bytes();
-
-  _verifier->verify_region_sets_optional();
-
   const bool do_clear_all_soft_refs = clear_all_soft_refs ||
-                           collector_policy()->should_clear_all_soft_refs();
-
-  ClearedAllSoftRefs casr(do_clear_all_soft_refs, collector_policy());
-
-  {
-    IsGCActiveMark x;
-
-    // Timing
-    assert(!GCCause::is_user_requested_gc(gc_cause()) || explicit_gc, "invariant");
-    GCTraceCPUTime tcpu;
-
-    {
-      GCTraceTime(Info, gc) tm("Pause Full", NULL, gc_cause(), true);
-      TraceCollectorStats tcs(g1mm()->full_collection_counters());
-      TraceMemoryManagerStats tms(true /* fullGC */, gc_cause());
-
-      G1HeapTransition heap_transition(this);
-      g1_policy()->record_full_collection_start();
-
-      // Note: When we have a more flexible GC logging framework that
-      // allows us to add optional attributes to a GC log record we
-      // could consider timing and reporting how long we wait in the
-      // following two methods.
-      wait_while_free_regions_coming();
-      // If we start the compaction before the CM threads finish
-      // scanning the root regions we might trip them over as we'll
-      // be moving objects / updating references. So let's wait until
-      // they are done. By telling them to abort, they should complete
-      // early.
-      _cm->root_regions()->abort();
-      _cm->root_regions()->wait_until_scan_finished();
-      append_secondary_free_list_if_not_empty_with_lock();
-
-      gc_prologue(true);
-      increment_total_collections(true /* full gc */);
-      increment_old_marking_cycles_started();
-
-      assert(used() == recalculate_used(), "Should be equal");
-
-      _verifier->verify_before_gc();
-
-      _verifier->check_bitmaps("Full GC Start");
-      pre_full_gc_dump(gc_timer);
-
-#if defined(COMPILER2) || INCLUDE_JVMCI
-      DerivedPointerTable::clear();
-#endif
-
-      // Disable discovery and empty the discovered lists
-      // for the CM ref processor.
-      ref_processor_cm()->disable_discovery();
-      ref_processor_cm()->abandon_partial_discovery();
-      ref_processor_cm()->verify_no_references_recorded();
-
-      // Abandon current iterations of concurrent marking and concurrent
-      // refinement, if any are in progress.
-      concurrent_mark()->abort();
-
-      // Make sure we'll choose a new allocation region afterwards.
-      _allocator->release_mutator_alloc_region();
-      _allocator->abandon_gc_alloc_regions();
-      g1_rem_set()->cleanupHRRS();
-
-      // We may have added regions to the current incremental collection
-      // set between the last GC or pause and now. We need to clear the
-      // incremental collection set and then start rebuilding it afresh
-      // after this full GC.
-      abandon_collection_set(collection_set());
-
-      tear_down_region_sets(false /* free_list_only */);
-      collector_state()->set_gcs_are_young(true);
-
-      // See the comments in g1CollectedHeap.hpp and
-      // G1CollectedHeap::ref_processing_init() about
-      // how reference processing currently works in G1.
-
-      // Temporarily make discovery by the STW ref processor single threaded (non-MT).
-      ReferenceProcessorMTDiscoveryMutator stw_rp_disc_ser(ref_processor_stw(), false);
-
-      // Temporarily clear the STW ref processor's _is_alive_non_header field.
-      ReferenceProcessorIsAliveMutator stw_rp_is_alive_null(ref_processor_stw(), NULL);
-
-      ref_processor_stw()->enable_discovery();
-      ref_processor_stw()->setup_policy(do_clear_all_soft_refs);
-
-      // Do collection work
-      {
-        HandleMark hm;  // Discard invalid handles created during gc
-        G1MarkSweep::invoke_at_safepoint(ref_processor_stw(), do_clear_all_soft_refs);
-      }
-
-      assert(num_free_regions() == 0, "we should not have added any free regions");
-      rebuild_region_sets(false /* free_list_only */);
-
-      ReferenceProcessorPhaseTimes pt(NULL, ref_processor_stw()->num_q());
-
-      // Enqueue any discovered reference objects that have
-      // not been removed from the discovered lists.
-      ref_processor_stw()->enqueue_discovered_references(NULL, &pt);
-
-      pt.print_enqueue_phase();
-
-#if defined(COMPILER2) || INCLUDE_JVMCI
-      DerivedPointerTable::update_pointers();
-#endif
-
-      MemoryService::track_memory_usage();
-
-      assert(!ref_processor_stw()->discovery_enabled(), "Postcondition");
-      ref_processor_stw()->verify_no_references_recorded();
-
-      // Delete metaspaces for unloaded class loaders and clean up loader_data graph
-      ClassLoaderDataGraph::purge();
-      MetaspaceAux::verify_metrics();
-
-      // Note: since we've just done a full GC, concurrent
-      // marking is no longer active. Therefore we need not
-      // re-enable reference discovery for the CM ref processor.
-      // That will be done at the start of the next marking cycle.
-      assert(!ref_processor_cm()->discovery_enabled(), "Postcondition");
-      ref_processor_cm()->verify_no_references_recorded();
-
-      reset_gc_time_stamp();
-      // Since everything potentially moved, we will clear all remembered
-      // sets, and clear all cards.  Later we will rebuild remembered
-      // sets. We will also reset the GC time stamps of the regions.
-      clear_rsets_post_compaction();
-      check_gc_time_stamps();
-
-      resize_if_necessary_after_full_collection();
-
-      // We should do this after we potentially resize the heap so
-      // that all the COMMIT / UNCOMMIT events are generated before
-      // the compaction events.
-      print_hrm_post_compaction();
-
-      if (_hot_card_cache->use_cache()) {
-        _hot_card_cache->reset_card_counts();
-        _hot_card_cache->reset_hot_cache();
-      }
-
-      // Rebuild remembered sets of all regions.
-      uint n_workers =
-        AdaptiveSizePolicy::calc_active_workers(workers()->total_workers(),
-                                                workers()->active_workers(),
-                                                Threads::number_of_non_daemon_threads());
-      workers()->update_active_workers(n_workers);
-      log_info(gc,task)("Using %u workers of %u to rebuild remembered set", n_workers, workers()->total_workers());
-
-      ParRebuildRSTask rebuild_rs_task(this);
-      workers()->run_task(&rebuild_rs_task);
-
-      // Rebuild the strong code root lists for each region
-      rebuild_strong_code_roots();
-
-      if (true) { // FIXME
-        MetaspaceGC::compute_new_size();
-      }
-
-#ifdef TRACESPINNING
-      ParallelTaskTerminator::print_termination_counts();
-#endif
-
-      // Discard all rset updates
-      JavaThread::dirty_card_queue_set().abandon_logs();
-      assert(dirty_card_queue_set().completed_buffers_num() == 0, "DCQS should be empty");
-
-      // At this point there should be no regions in the
-      // entire heap tagged as young.
-      assert(check_young_list_empty(), "young list should be empty at this point");
-
-      // Update the number of full collections that have been completed.
-      increment_old_marking_cycles_completed(false /* concurrent */);
-
-      _hrm.verify_optional();
-      _verifier->verify_region_sets_optional();
-
-      _verifier->verify_after_gc();
-
-      // Clear the previous marking bitmap, if needed for bitmap verification.
-      // Note we cannot do this when we clear the next marking bitmap in
-      // G1ConcurrentMark::abort() above since VerifyDuringGC verifies the
-      // objects marked during a full GC against the previous bitmap.
-      // But we need to clear it before calling check_bitmaps below since
-      // the full GC has compacted objects and updated TAMS but not updated
-      // the prev bitmap.
-      if (G1VerifyBitmaps) {
-        GCTraceTime(Debug, gc)("Clear Bitmap for Verification");
-        _cm->clear_prev_bitmap(workers());
-      }
-      _verifier->check_bitmaps("Full GC End");
-
-      start_new_collection_set();
-
-      _allocator->init_mutator_alloc_region();
-
-      g1_policy()->record_full_collection_end();
-
-      // We must call G1MonitoringSupport::update_sizes() in the same scoping level
-      // as an active TraceMemoryManagerStats object (i.e. before the destructor for the
-      // TraceMemoryManagerStats is called) so that the G1 memory pools are updated
-      // before any GC notifications are raised.
-      g1mm()->update_sizes();
-
-      gc_epilogue(true);
-
-      heap_transition.print();
-
-      print_heap_after_gc();
-      print_heap_regions();
-      trace_heap_after_gc(gc_tracer);
-
-      post_full_gc_dump(gc_timer);
-    }
-
-    gc_timer->register_gc_end();
-    gc_tracer->report_gc_end(gc_timer->gc_end(), gc_timer->time_partitions());
-  }
-
+      collector_policy()->should_clear_all_soft_refs();
+
+  G1FullGCScope scope(explicit_gc, do_clear_all_soft_refs);
+  do_full_collection_inner(&scope);
+
+  // Full collection was successfully completed.
   return true;
 }
 
@@ -2677,21 +2542,37 @@
   return (G1CollectedHeap*)heap;
 }
 
-void G1CollectedHeap::gc_prologue(bool full /* Ignored */) {
+void G1CollectedHeap::gc_prologue(bool full) {
   // always_do_update_barrier = false;
   assert(InlineCacheBuffer::is_empty(), "should have cleaned up ICBuffer");
 
+  // This summary needs to be printed before incrementing total collections.
+  g1_rem_set()->print_periodic_summary_info("Before GC RS summary", total_collections());
+
+  // Update common counters.
+  increment_total_collections(full /* full gc */);
+  if (full) {
+    increment_old_marking_cycles_started();
+    reset_gc_time_stamp();
+  } else {
+    increment_gc_time_stamp();
+  }
+
+  // Fill TLAB's and such
   double start = os::elapsedTime();
-  // Fill TLAB's and such
   accumulate_statistics_all_tlabs();
   ensure_parsability(true);
   g1_policy()->phase_times()->record_prepare_tlab_time_ms((os::elapsedTime() - start) * 1000.0);
-
-  g1_rem_set()->print_periodic_summary_info("Before GC RS summary", total_collections());
 }
 
 void G1CollectedHeap::gc_epilogue(bool full) {
-  // we are at the end of the GC. Total collections has already been increased.
+  // Update common counters.
+  if (full) {
+    // Update the number of full collections that have been completed.
+    increment_old_marking_cycles_completed(false /* concurrent */);
+  }
+
+  // We are at the end of the GC. Total collections has already been increased.
   g1_rem_set()->print_periodic_summary_info("After GC RS summary", total_collections() - 1);
 
   // FIXME: what is this about?
@@ -2708,6 +2589,7 @@
 
   allocation_context_stats().update(full);
 
+  MemoryService::track_memory_usage();
   // We have just completed a GC. Update the soft reference
   // policy with the new heap occupancy
   Universe::update_heap_info_at_gc();
@@ -3098,8 +2980,6 @@
       IsGCActiveMark x;
 
       gc_prologue(false);
-      increment_total_collections(false /* full gc */);
-      increment_gc_time_stamp();
 
       if (VerifyRememberedSets) {
         log_info(gc, verify)("[Verifying RemSets before GC]");
@@ -3261,8 +3141,6 @@
         evacuation_info.set_collectionset_used_before(collection_set()->bytes_used_before());
         evacuation_info.set_bytes_copied(g1_policy()->bytes_copied_during_gc());
 
-        MemoryService::track_memory_usage();
-
         if (VerifyRememberedSets) {
           log_info(gc, verify)("[Verifying RemSets after GC]");
           VerifyRegionRemSetClosure v_cl;
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -34,6 +34,7 @@
 #include "gc/g1/g1EdenRegions.hpp"
 #include "gc/g1/g1EvacFailure.hpp"
 #include "gc/g1/g1EvacStats.hpp"
+#include "gc/g1/g1HeapTransition.hpp"
 #include "gc/g1/g1HeapVerifier.hpp"
 #include "gc/g1/g1HRPrinter.hpp"
 #include "gc/g1/g1InCSetState.hpp"
@@ -86,6 +87,7 @@
 class WorkGang;
 class G1Allocator;
 class G1ArchiveAllocator;
+class G1FullGCScope;
 class G1HeapVerifier;
 class G1HeapSizingPolicy;
 class G1HeapSummary;
@@ -513,6 +515,17 @@
                                       AllocationContext_t context,
                                       bool* succeeded);
 private:
+  // Internal helpers used during full GC to split it up to
+  // increase readability.
+  void do_full_collection_inner(G1FullGCScope* scope);
+  void abort_concurrent_cycle();
+  void verify_before_full_collection(bool explicit_gc);
+  void prepare_heap_for_full_collection();
+  void prepare_heap_for_mutators();
+  void abort_refinement();
+  void verify_after_full_collection();
+  void print_heap_after_full_collection(G1HeapTransition* heap_transition);
+
   // Helper method for satisfy_failed_allocation()
   HeapWord* satisfy_failed_allocation_helper(size_t word_size,
                                              AllocationContext_t context,
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1918,7 +1918,7 @@
       guarantee(_g1h->is_in_reserved(task_entry.slice()), "Slice " PTR_FORMAT " must be in heap.", p2i(task_entry.slice()));
       return;
     }
-    guarantee(task_entry.obj()->is_oop(),
+    guarantee(oopDesc::is_oop(task_entry.obj()),
               "Non-oop " PTR_FORMAT ", phase: %s, info: %d",
               p2i(task_entry.obj()), _phase, _info);
     guarantee(!_g1h->is_in_cset(task_entry.obj()),
@@ -2313,7 +2313,7 @@
     if (task_entry.is_null()) {
       break;
     }
-    assert(task_entry.is_array_slice() || task_entry.obj()->is_oop(), "Element " PTR_FORMAT " must be an array slice or oop", p2i(task_entry.obj()));
+    assert(task_entry.is_array_slice() || oopDesc::is_oop(task_entry.obj()), "Element " PTR_FORMAT " must be an array slice or oop", p2i(task_entry.obj()));
     bool success = _task_queue->push(task_entry);
     // We only call this when the local queue is empty or under a
     // given target limit. So, we do not expect this push to fail.
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -217,7 +217,7 @@
 }
 
 bool G1ConcurrentMark::isPrevMarked(oop p) const {
-  assert(p != NULL && p->is_oop(), "expected an oop");
+  assert(p != NULL && oopDesc::is_oop(p), "expected an oop");
   return _prevMarkBitMap->is_marked((HeapWord*)p);
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1FullGCScope.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/g1/g1FullGCScope.hpp"
+
+G1FullGCScope* G1FullGCScope::_instance = NULL;
+
+G1FullGCScope* G1FullGCScope::instance() {
+  assert(_instance != NULL, "Must be setup already");
+  return _instance;
+}
+
+G1FullGCScope::G1FullGCScope(bool explicit_gc, bool clear_soft) :
+    _rm(),
+    _explicit_gc(explicit_gc),
+    _g1h(G1CollectedHeap::heap()),
+    _gc_id(),
+    _svc_marker(SvcGCMarker::FULL),
+    _timer(),
+    _tracer(),
+    _active(),
+    _cpu_time(),
+    _soft_refs(clear_soft, _g1h->collector_policy()),
+    _memory_stats(true, _g1h->gc_cause()),
+    _collector_stats(_g1h->g1mm()->full_collection_counters()),
+    _heap_transition(_g1h) {
+  assert(_instance == NULL, "Only one scope at a time");
+  _timer.register_gc_start();
+  _tracer.report_gc_start(_g1h->gc_cause(), _timer.gc_start());
+  _g1h->pre_full_gc_dump(&_timer);
+  _g1h->trace_heap_before_gc(&_tracer);
+  _instance = this;
+}
+
+G1FullGCScope::~G1FullGCScope() {
+  // We must call G1MonitoringSupport::update_sizes() in the same scoping level
+  // as an active TraceMemoryManagerStats object (i.e. before the destructor for the
+  // TraceMemoryManagerStats is called) so that the G1 memory pools are updated
+  // before any GC notifications are raised.
+  _g1h->g1mm()->update_sizes();
+  _g1h->trace_heap_after_gc(&_tracer);
+  _g1h->post_full_gc_dump(&_timer);
+  _timer.register_gc_end();
+  _tracer.report_gc_end(_timer.gc_end(), _timer.time_partitions());
+  _instance = NULL;
+}
+
+bool G1FullGCScope::is_explicit_gc() {
+  return _explicit_gc;
+}
+
+bool G1FullGCScope::should_clear_soft_refs() {
+  return _soft_refs.should_clear();
+}
+
+STWGCTimer* G1FullGCScope::timer() {
+  return &_timer;
+}
+
+SerialOldTracer* G1FullGCScope::tracer() {
+  return &_tracer;
+}
+
+G1HeapTransition* G1FullGCScope::heap_transition() {
+  return &_heap_transition;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1FullGCScope.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_G1_G1FULLGCSCOPE_HPP
+#define SHARE_VM_GC_G1_G1FULLGCSCOPE_HPP
+
+#include "gc/g1/g1CollectedHeap.hpp"
+#include "gc/g1/g1HeapTransition.hpp"
+#include "gc/shared/collectorCounters.hpp"
+#include "gc/shared/gcId.hpp"
+#include "gc/shared/gcTrace.hpp"
+#include "gc/shared/gcTraceTime.hpp"
+#include "gc/shared/gcTimer.hpp"
+#include "gc/shared/isGCActiveMark.hpp"
+#include "gc/shared/vmGCOperations.hpp"
+#include "memory/allocation.hpp"
+#include "services/memoryService.hpp"
+
+// Class used to group scoped objects used in the Full GC together.
+class G1FullGCScope : public StackObj {
+  ResourceMark            _rm;
+  bool                    _explicit_gc;
+  G1CollectedHeap*        _g1h;
+  GCIdMark                _gc_id;
+  SvcGCMarker             _svc_marker;
+  STWGCTimer              _timer;
+  SerialOldTracer         _tracer;
+  IsGCActiveMark          _active;
+  GCTraceCPUTime          _cpu_time;
+  ClearedAllSoftRefs      _soft_refs;
+  TraceCollectorStats     _collector_stats;
+  TraceMemoryManagerStats _memory_stats;
+  G1HeapTransition        _heap_transition;
+
+  // Singleton instance.
+  static G1FullGCScope* _instance;
+public:
+  static G1FullGCScope* instance();
+
+  G1FullGCScope(bool explicit_gc, bool clear_soft);
+  ~G1FullGCScope();
+
+  bool is_explicit_gc();
+  bool should_clear_soft_refs();
+
+  STWGCTimer* timer();
+  SerialOldTracer* tracer();
+  G1HeapTransition* heap_transition();
+};
+
+#endif //SHARE_VM_GC_G1_G1FULLGCSCOPE_HPP
--- a/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -29,6 +29,7 @@
 #include "classfile/vmSymbols.hpp"
 #include "code/codeCache.hpp"
 #include "code/icBuffer.hpp"
+#include "gc/g1/g1FullGCScope.hpp"
 #include "gc/g1/g1MarkSweep.hpp"
 #include "gc/g1/g1RootProcessor.hpp"
 #include "gc/g1/g1StringDedup.hpp"
@@ -59,7 +60,11 @@
 void G1MarkSweep::invoke_at_safepoint(ReferenceProcessor* rp,
                                       bool clear_all_softrefs) {
   assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
+  HandleMark hm;  // Discard invalid handles created during gc
 
+#if defined(COMPILER2) || INCLUDE_JVMCI
+  DerivedPointerTable::clear();
+#endif
 #ifdef ASSERT
   if (G1CollectedHeap::heap()->collector_policy()->should_clear_all_soft_refs()) {
     assert(clear_all_softrefs, "Policy should have been checked earler");
@@ -85,8 +90,10 @@
   // The marking doesn't preserve the marks of biased objects.
   BiasedLocking::preserve_marks();
 
+  // Process roots and do the marking.
   mark_sweep_phase1(marked_for_unloading, clear_all_softrefs);
 
+  // Prepare compaction.
   mark_sweep_phase2();
 
 #if defined(COMPILER2) || INCLUDE_JVMCI
@@ -94,14 +101,21 @@
   DerivedPointerTable::set_active(false);
 #endif
 
+  // Adjust all pointers.
   mark_sweep_phase3();
 
+  // Do the actual compaction.
   mark_sweep_phase4();
 
   GenMarkSweep::restore_marks();
   BiasedLocking::restore_marks();
   GenMarkSweep::deallocate_stacks();
 
+#if defined(COMPILER2) || INCLUDE_JVMCI
+  // Now update the derived pointers.
+  DerivedPointerTable::update_pointers();
+#endif
+
   CodeCache::gc_epilogue();
   JvmtiExport::gc_epilogue();
 
@@ -109,6 +123,13 @@
   GenMarkSweep::set_ref_processor(NULL);
 }
 
+STWGCTimer* G1MarkSweep::gc_timer() {
+  return G1FullGCScope::instance()->timer();
+}
+
+SerialOldTracer* G1MarkSweep::gc_tracer() {
+  return G1FullGCScope::instance()->tracer();
+}
 
 void G1MarkSweep::allocate_stacks() {
   GenMarkSweep::_preserved_count_max = 0;
--- a/hotspot/src/share/vm/gc/g1/g1MarkSweep.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1MarkSweep.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -52,8 +52,8 @@
   static void invoke_at_safepoint(ReferenceProcessor* rp,
                                   bool clear_all_softrefs);
 
-  static STWGCTimer* gc_timer() { return GenMarkSweep::_gc_timer; }
-  static SerialOldTracer* gc_tracer() { return GenMarkSweep::_gc_tracer; }
+  static STWGCTimer* gc_timer();
+  static SerialOldTracer* gc_tracer();
 
 private:
   // Mark live objects
--- a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -107,7 +107,7 @@
 #ifdef ASSERT
   G1CollectedHeap* g1 = G1CollectedHeap::heap();
   // can't do because of races
-  // assert(obj == NULL || obj->is_oop(), "expected an oop");
+  // assert(oopDesc::is_oop_or_null(obj), "expected an oop");
   assert(check_obj_alignment(obj), "not oop aligned");
   assert(g1->is_in_reserved(obj), "must be in heap");
 
--- a/hotspot/src/share/vm/gc/g1/g1RemSet.inline.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1RemSet.inline.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -39,7 +39,7 @@
 
 #ifdef ASSERT
   // can't do because of races
-  // assert(obj == NULL || obj->is_oop(), "expected an oop");
+  // assert(oopDesc::is_oop_or_null(obj), "expected an oop");
   assert(check_obj_alignment(obj), "not oop aligned");
   assert(_g1->is_in_reserved(obj), "must be in heap");
 #endif // ASSERT
--- a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -43,7 +43,7 @@
 
 void G1SATBCardTableModRefBS::enqueue(oop pre_val) {
   // Nulls should have been already filtered.
-  assert(pre_val->is_oop(true), "Error");
+  assert(oopDesc::is_oop(pre_val, true), "Error");
 
   if (!JavaThread::satb_mark_queue_set().is_active()) return;
   Thread* thr = Thread::current();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1SerialFullCollector.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1FullGCScope.hpp"
+#include "gc/g1/g1MarkSweep.hpp"
+#include "gc/g1/g1RemSet.inline.hpp"
+#include "gc/g1/g1SerialFullCollector.hpp"
+#include "gc/g1/heapRegionRemSet.hpp"
+#include "gc/shared/referenceProcessor.hpp"
+
+G1SerialFullCollector::G1SerialFullCollector(G1FullGCScope* scope,
+                                             ReferenceProcessor* reference_processor) :
+    _scope(scope),
+    _reference_processor(reference_processor),
+    _is_alive_mutator(_reference_processor, NULL),
+    _mt_discovery_mutator(_reference_processor, false) {
+  // Temporarily make discovery by the STW ref processor single threaded (non-MT)
+  // and clear the STW ref processor's _is_alive_non_header field.
+}
+
+void G1SerialFullCollector::prepare_collection() {
+  _reference_processor->enable_discovery();
+  _reference_processor->setup_policy(_scope->should_clear_soft_refs());
+}
+
+void G1SerialFullCollector::complete_collection() {
+  // Enqueue any discovered reference objects that have
+  // not been removed from the discovered lists.
+  ReferenceProcessorPhaseTimes pt(NULL, _reference_processor->num_q());
+  _reference_processor->enqueue_discovered_references(NULL, &pt);
+  pt.print_enqueue_phase();
+
+  // Iterate the heap and rebuild the remembered sets.
+  rebuild_remembered_sets();
+}
+
+void G1SerialFullCollector::collect() {
+  // Do the actual collection work.
+  G1MarkSweep::invoke_at_safepoint(_reference_processor, _scope->should_clear_soft_refs());
+}
+
+class PostMCRemSetClearClosure: public HeapRegionClosure {
+  G1CollectedHeap* _g1h;
+  ModRefBarrierSet* _mr_bs;
+public:
+  PostMCRemSetClearClosure(G1CollectedHeap* g1h, ModRefBarrierSet* mr_bs) :
+    _g1h(g1h), _mr_bs(mr_bs) {}
+
+  bool doHeapRegion(HeapRegion* r) {
+    HeapRegionRemSet* hrrs = r->rem_set();
+
+    _g1h->reset_gc_time_stamps(r);
+
+    if (r->is_continues_humongous()) {
+      // We'll assert that the strong code root list and RSet is empty
+      assert(hrrs->strong_code_roots_list_length() == 0, "sanity");
+      assert(hrrs->occupied() == 0, "RSet should be empty");
+    } else {
+      hrrs->clear();
+    }
+    // You might think here that we could clear just the cards
+    // corresponding to the used region.  But no: if we leave a dirty card
+    // in a region we might allocate into, then it would prevent that card
+    // from being enqueued, and cause it to be missed.
+    // Re: the performance cost: we shouldn't be doing full GC anyway!
+    _mr_bs->clear(MemRegion(r->bottom(), r->end()));
+
+    return false;
+  }
+};
+
+
+class RebuildRSOutOfRegionClosure: public HeapRegionClosure {
+  G1CollectedHeap*   _g1h;
+  RebuildRSOopClosure _cl;
+public:
+  RebuildRSOutOfRegionClosure(G1CollectedHeap* g1, uint worker_i = 0) :
+    _cl(g1->g1_rem_set(), worker_i),
+    _g1h(g1)
+  { }
+
+  bool doHeapRegion(HeapRegion* r) {
+    if (!r->is_continues_humongous()) {
+      _cl.set_from(r);
+      r->oop_iterate(&_cl);
+    }
+    return false;
+  }
+};
+
+class ParRebuildRSTask: public AbstractGangTask {
+  G1CollectedHeap* _g1;
+  HeapRegionClaimer _hrclaimer;
+
+public:
+  ParRebuildRSTask(G1CollectedHeap* g1) :
+      AbstractGangTask("ParRebuildRSTask"), _g1(g1), _hrclaimer(g1->workers()->active_workers()) {}
+
+  void work(uint worker_id) {
+    RebuildRSOutOfRegionClosure rebuild_rs(_g1, worker_id);
+    _g1->heap_region_par_iterate(&rebuild_rs, worker_id, &_hrclaimer);
+  }
+};
+
+void G1SerialFullCollector::rebuild_remembered_sets() {
+  G1CollectedHeap* g1h = G1CollectedHeap::heap();
+  // First clear the stale remembered sets.
+  PostMCRemSetClearClosure rs_clear(g1h, g1h->g1_barrier_set());
+  g1h->heap_region_iterate(&rs_clear);
+
+  // Rebuild remembered sets of all regions.
+  uint n_workers = AdaptiveSizePolicy::calc_active_workers(g1h->workers()->total_workers(),
+                                                           g1h->workers()->active_workers(),
+                                                           Threads::number_of_non_daemon_threads());
+  g1h->workers()->update_active_workers(n_workers);
+  log_info(gc,task)("Using %u workers of %u to rebuild remembered set", n_workers, g1h->workers()->total_workers());
+
+  ParRebuildRSTask rebuild_rs_task(g1h);
+  g1h->workers()->run_task(&rebuild_rs_task);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1SerialFullCollector.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_G1_G1SERIALCOLLECTOR_HPP
+#define SHARE_VM_GC_G1_G1SERIALCOLLECTOR_HPP
+
+#include "memory/allocation.hpp"
+
+class G1FullGCScope;
+class ReferenceProcessor;
+
+class G1SerialFullCollector : StackObj {
+  G1FullGCScope*                       _scope;
+  ReferenceProcessor*                  _reference_processor;
+  ReferenceProcessorIsAliveMutator     _is_alive_mutator;
+  ReferenceProcessorMTDiscoveryMutator _mt_discovery_mutator;
+
+  void rebuild_remembered_sets();
+
+public:
+  G1SerialFullCollector(G1FullGCScope* scope, ReferenceProcessor* reference_processor);
+
+  void prepare_collection();
+  void collect();
+  void complete_collection();
+};
+
+#endif // SHARE_VM_GC_G1_G1SERIALCOLLECTOR_HPP
--- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -610,7 +610,7 @@
           LogStream ls(log.error());
           _containing_obj->print_on(&ls);
           log.error("points to obj " PTR_FORMAT " in region " HR_FORMAT, p2i(obj), HR_FORMAT_PARAMS(to));
-          if (obj->is_oop()) {
+          if (oopDesc::is_oop(obj)) {
             obj->print_on(&ls);
           }
           log.error("Obj head CTE = %d, field CTE = %d.", cv_obj, cv_field);
@@ -657,7 +657,7 @@
     object_num += 1;
 
     if (!g1->is_obj_dead_cond(obj, this, vo)) {
-      if (obj->is_oop()) {
+      if (oopDesc::is_oop(obj)) {
         Klass* klass = obj->klass();
         bool is_metaspace_object = Metaspace::contains(klass) ||
                                    (vo == VerifyOption_G1UsePrevMarking &&
@@ -803,7 +803,7 @@
     size_t obj_size = block_size(p);
 
     if (!g1->is_obj_dead_cond(obj, this, vo)) {
-      if (obj->is_oop()) {
+      if (oopDesc::is_oop(obj)) {
         vr_cl.set_containing_obj(obj);
         obj->oop_iterate_no_header(&vr_cl);
 
--- a/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -337,7 +337,7 @@
   const G1CMBitMap* const bitmap = g1h->concurrent_mark()->prevMarkBitMap();
   do {
     oop obj = oop(cur);
-    assert(obj->is_oop(true), "Not an oop at " PTR_FORMAT, p2i(cur));
+    assert(oopDesc::is_oop(obj, true), "Not an oop at " PTR_FORMAT, p2i(cur));
     assert(obj->klass_or_null() != NULL,
            "Unparsable heap at " PTR_FORMAT, p2i(cur));
 
--- a/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -95,7 +95,7 @@
     return false;
   }
 
-  assert(((oop)entry)->is_oop(true /* ignore mark word */),
+  assert(oopDesc::is_oop(oop(entry), true /* ignore mark word */),
          "Invalid oop in SATB buffer: " PTR_FORMAT, p2i(entry));
 
   return true;
--- a/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -287,7 +287,7 @@
           while (p < to) {
             Prefetch::write(p, interval);
             oop m = oop(p);
-            assert(m->is_oop_or_null(), "Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m));
+            assert(oopDesc::is_oop_or_null(m), "Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m));
             pm->push_contents(m);
             p += m->size();
           }
@@ -295,7 +295,7 @@
         } else {
           while (p < to) {
             oop m = oop(p);
-            assert(m->is_oop_or_null(), "Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m));
+            assert(oopDesc::is_oop_or_null(m), "Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m));
             pm->push_contents(m);
             p += m->size();
           }
--- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -2597,7 +2597,7 @@
         start_array->allocate_block(addr);
       }
       cm->update_contents(oop(addr));
-      assert(oop(addr)->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(addr)));
+      assert(oopDesc::is_oop_or_null(oop(addr)), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(addr)));
     }
   }
 }
@@ -3144,7 +3144,7 @@
 
   oop moved_oop = (oop) destination();
   compaction_manager()->update_contents(moved_oop);
-  assert(moved_oop->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(moved_oop));
+  assert(oopDesc::is_oop_or_null(moved_oop), "Expected an oop or NULL at " PTR_FORMAT, p2i(moved_oop));
 
   update_state(words);
   assert(destination() == (HeapWord*)moved_oop + moved_oop->size(), "sanity");
--- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -593,9 +593,8 @@
 
 inline bool ParallelCompactData::RegionData::claim()
 {
-  const int los = (int) live_obj_size();
-  const int old = Atomic::cmpxchg(dc_claimed | los,
-                                  (volatile int*) &_dc_and_los, los);
+  const region_sz_t los = static_cast<region_sz_t>(live_obj_size());
+  const region_sz_t old = Atomic::cmpxchg(dc_claimed | los, &_dc_and_los, los);
   return old == los;
 }
 
--- a/hotspot/src/share/vm/gc/parallel/psScavenge.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -95,7 +95,7 @@
 
   template <class T> void do_oop_work(T* p) {
     assert (!oopDesc::is_null(*p), "expected non-null ref");
-    assert ((oopDesc::load_decode_heap_oop_not_null(p))->is_oop(),
+    assert (oopDesc::is_oop(oopDesc::load_decode_heap_oop_not_null(p)),
             "expected an oop while scanning weak refs");
 
     // Weak refs may be visited more than once.
--- a/hotspot/src/share/vm/gc/serial/defNewGeneration.inline.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.inline.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,7 +41,7 @@
     // as a weak reference.
     assert (!oopDesc::is_null(*p), "expected non-null ref");
     oop obj = oopDesc::load_decode_heap_oop_not_null(p);
-    assert (obj->is_oop(), "expected an oop while scanning weak refs");
+    assert (oopDesc::is_oop(obj), "expected an oop while scanning weak refs");
   }
 #endif // ASSERT
 
@@ -74,7 +74,7 @@
     // as a weak reference.
     assert (!oopDesc::is_null(*p), "expected non-null ref");
     oop obj = oopDesc::load_decode_heap_oop_not_null(p);
-    assert (obj->is_oop(), "expected an oop while scanning weak refs");
+    assert (oopDesc::is_oop(obj), "expected an oop while scanning weak refs");
   }
 #endif // ASSERT
 
--- a/hotspot/src/share/vm/gc/shared/blockOffsetTable.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/shared/blockOffsetTable.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -343,7 +343,7 @@
     oop o = oop(start);
     assert(!Universe::is_fully_initialized() ||
            _sp->is_free_block(start) ||
-           o->is_oop_or_null(), "Bad object was found");
+           oopDesc::is_oop_or_null(o), "Bad object was found");
     next_index++;
     last_p = p;
     last_start = start;
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -350,7 +350,7 @@
       assert(is_in(old_obj), "Not in allocated heap");
       assert(!can_elide_initializing_store_barrier(old_obj),
              "Else should have been filtered in new_store_pre_barrier()");
-      assert(old_obj->is_oop(true), "Not an oop");
+      assert(oopDesc::is_oop(old_obj, true), "Not an oop");
       assert(deferred.word_size() == (size_t)(old_obj->size()),
              "Mismatch: multiple objects?");
     }
--- a/hotspot/src/share/vm/gc/shared/collectorPolicy.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/shared/collectorPolicy.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -151,6 +151,8 @@
       _collector_policy->cleared_all_soft_refs();
     }
   }
+
+  bool should_clear() { return _clear_all_soft_refs; }
 };
 
 class GenCollectorPolicy : public CollectorPolicy {
--- a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -401,7 +401,7 @@
 void DiscoveredListIterator::load_ptrs(DEBUG_ONLY(bool allow_null_referent)) {
   _discovered_addr = java_lang_ref_Reference::discovered_addr(_ref);
   oop discovered = java_lang_ref_Reference::discovered(_ref);
-  assert(_discovered_addr && discovered->is_oop_or_null(),
+  assert(_discovered_addr && oopDesc::is_oop_or_null(discovered),
          "Expected an oop or NULL for discovered field at " PTR_FORMAT, p2i(discovered));
   _next = discovered;
   _referent_addr = java_lang_ref_Reference::referent_addr(_ref);
@@ -409,15 +409,15 @@
   assert(Universe::heap()->is_in_reserved_or_null(_referent),
          "Wrong oop found in java.lang.Reference object");
   assert(allow_null_referent ?
-             _referent->is_oop_or_null()
-           : _referent->is_oop(),
+             oopDesc::is_oop_or_null(_referent)
+           : oopDesc::is_oop(_referent),
          "Expected an oop%s for referent field at " PTR_FORMAT,
          (allow_null_referent ? " or NULL" : ""),
          p2i(_referent));
 }
 
 void DiscoveredListIterator::remove() {
-  assert(_ref->is_oop(), "Dropping a bad reference");
+  assert(oopDesc::is_oop(_ref), "Dropping a bad reference");
   oop_store_raw(_discovered_addr, NULL);
 
   // First _prev_next ref actually points into DiscoveredList (gross).
@@ -534,7 +534,7 @@
     oop next = java_lang_ref_Reference::next(iter.obj());
     if ((iter.referent() == NULL || iter.is_referent_alive() ||
          next != NULL)) {
-      assert(next->is_oop_or_null(), "Expected an oop or NULL for next field at " PTR_FORMAT, p2i(next));
+      assert(oopDesc::is_oop_or_null(next), "Expected an oop or NULL for next field at " PTR_FORMAT, p2i(next));
       // Remove Reference object from list
       iter.remove();
       // Trace the cohorts
@@ -582,7 +582,7 @@
     }
     log_develop_trace(gc, ref)("Adding %sreference (" INTPTR_FORMAT ": %s) as pending",
                                clear_referent ? "cleared " : "", p2i(iter.obj()), iter.obj()->klass()->internal_name());
-    assert(iter.obj()->is_oop(UseConcMarkSweepGC), "Adding a bad reference");
+    assert(oopDesc::is_oop(iter.obj(), UseConcMarkSweepGC), "Adding a bad reference");
     iter.next();
   }
   // Close the reachable set
@@ -979,7 +979,7 @@
 void ReferenceProcessor::verify_referent(oop obj) {
   bool da = discovery_is_atomic();
   oop referent = java_lang_ref_Reference::referent(obj);
-  assert(da ? referent->is_oop() : referent->is_oop_or_null(),
+  assert(da ? oopDesc::is_oop(referent) : oopDesc::is_oop_or_null(referent),
          "Bad referent " INTPTR_FORMAT " found in Reference "
          INTPTR_FORMAT " during %satomic discovery ",
          p2i(referent), p2i(obj), da ? "" : "non-");
@@ -1057,7 +1057,7 @@
 
   HeapWord* const discovered_addr = java_lang_ref_Reference::discovered_addr(obj);
   const oop  discovered = java_lang_ref_Reference::discovered(obj);
-  assert(discovered->is_oop_or_null(), "Expected an oop or NULL for discovered field at " PTR_FORMAT, p2i(discovered));
+  assert(oopDesc::is_oop_or_null(discovered), "Expected an oop or NULL for discovered field at " PTR_FORMAT, p2i(discovered));
   if (discovered != NULL) {
     // The reference has already been discovered...
     log_develop_trace(gc, ref)("Already discovered reference (" INTPTR_FORMAT ": %s)",
@@ -1118,7 +1118,7 @@
 
     log_develop_trace(gc, ref)("Discovered reference (" INTPTR_FORMAT ": %s)", p2i(obj), obj->klass()->internal_name());
   }
-  assert(obj->is_oop(), "Discovered a bad reference");
+  assert(oopDesc::is_oop(obj), "Discovered a bad reference");
   verify_referent(obj);
   return true;
 }
--- a/hotspot/src/share/vm/gc/shared/space.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/shared/space.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -491,7 +491,7 @@
     HeapWord* obj_addr = mr.start();                                        \
     HeapWord* t = mr.end();                                                 \
     while (obj_addr < t) {                                                  \
-      assert(oop(obj_addr)->is_oop(), "Should be an oop");                  \
+      assert(oopDesc::is_oop(oop(obj_addr)), "Should be an oop");           \
       obj_addr += oop(obj_addr)->oop_iterate_size(blk);                     \
     }                                                                       \
   }
@@ -584,7 +584,7 @@
       last = cur;
       cur += oop(cur)->size();
     }
-    assert(oop(last)->is_oop(), PTR_FORMAT " should be an object start", p2i(last));
+    assert(oopDesc::is_oop(oop(last)), PTR_FORMAT " should be an object start", p2i(last));
     return last;
   }
 }
@@ -597,10 +597,10 @@
   assert(p <= current_top,
          "p > current top - p: " PTR_FORMAT ", current top: " PTR_FORMAT,
          p2i(p), p2i(current_top));
-  assert(p == current_top || oop(p)->is_oop(),
+  assert(p == current_top || oopDesc::is_oop(oop(p)),
          "p (" PTR_FORMAT ") is not a block start - "
          "current_top: " PTR_FORMAT ", is_oop: %s",
-         p2i(p), p2i(current_top), BOOL_TO_STR(oop(p)->is_oop()));
+         p2i(p), p2i(current_top), BOOL_TO_STR(oopDesc::is_oop(oop(p))));
   if (p < current_top) {
     return oop(p)->size();
   } else {
--- a/hotspot/src/share/vm/gc/shared/workgroup.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/gc/shared/workgroup.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -428,7 +428,7 @@
   assert(t < _n_tasks, "bad task id.");
   uint old = _tasks[t];
   if (old == 0) {
-    old = Atomic::cmpxchg(1, &_tasks[t], 0);
+    old = Atomic::cmpxchg(1u, &_tasks[t], 0u);
   }
   assert(_tasks[t] == 1, "What else?");
   bool res = old != 0;
@@ -442,15 +442,15 @@
 }
 
 void SubTasksDone::all_tasks_completed(uint n_threads) {
-  jint observed = _threads_completed;
-  jint old;
+  uint observed = _threads_completed;
+  uint old;
   do {
     old = observed;
     observed = Atomic::cmpxchg(old+1, &_threads_completed, old);
   } while (observed != old);
   // If this was the last thread checking in, clear the tasks.
   uint adjusted_thread_count = (n_threads == 0 ? 1 : n_threads);
-  if (observed + 1 == (jint)adjusted_thread_count) {
+  if (observed + 1 == adjusted_thread_count) {
     clear();
   }
 }
@@ -474,8 +474,8 @@
 bool SequentialSubTasksDone::is_task_claimed(uint& t) {
   t = _n_claimed;
   while (t < _n_tasks) {
-    jint res = Atomic::cmpxchg(t+1, &_n_claimed, t);
-    if (res == (jint)t) {
+    uint res = Atomic::cmpxchg(t+1, &_n_claimed, t);
+    if (res == t) {
       return false;
     }
     t = res;
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@
 #ifdef ASSERT
 #define VERIFY_OOP(o_) \
       if (VerifyOops) { \
-        assert((oop(o_))->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(o_))); \
+        assert(oopDesc::is_oop_or_null(oop(o_)), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(o_))); \
         StubRoutines::_verify_oop_count++;  \
       }
 #else
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -208,7 +208,7 @@
 
 
 IRT_ENTRY(void, InterpreterRuntime::register_finalizer(JavaThread* thread, oopDesc* obj))
-  assert(obj->is_oop(), "must be a valid oop");
+  assert(oopDesc::is_oop(obj), "must be a valid oop");
   assert(obj->klass()->has_finalizer(), "shouldn't be here otherwise");
   InstanceKlass::register_finalizer(instanceOop(obj), CHECK);
 IRT_END
@@ -435,7 +435,6 @@
     // assertions
 #ifdef ASSERT
     assert(h_exception.not_null(), "NULL exceptions should be handled by athrow");
-    assert(h_exception->is_oop(), "just checking");
     // Check that exception is a subclass of Throwable, otherwise we have a VerifyError
     if (!(h_exception->is_a(SystemDictionary::Throwable_klass()))) {
       if (ExitVMOnVerifyError) vm_exit(-1);
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1318,8 +1318,6 @@
   int vtable_index = Method::invalid_vtable_index;
   methodHandle selected_method;
 
-  assert(recv.is_null() || recv->is_oop(), "receiver is not an oop");
-
   // runtime method resolution
   if (check_null_and_abstract && recv.is_null()) { // check if receiver exists
     THROW(vmSymbols::java_lang_NullPointerException());
--- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -765,7 +765,7 @@
 
 C2V_VMENTRY(jboolean, hasNeverInlineDirective,(JNIEnv *, jobject, jobject jvmci_method))
   methodHandle method = CompilerToVM::asMethod(jvmci_method);
-  return CompilerOracle::should_not_inline(method) || method->dont_inline();
+  return !Inline || CompilerOracle::should_not_inline(method) || method->dont_inline();
 C2V_END
 
 C2V_VMENTRY(jboolean, shouldInlineMethod,(JNIEnv *, jobject, jobject jvmci_method))
--- a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -239,7 +239,6 @@
   }
 #ifdef ASSERT
   assert(exception.not_null(), "NULL exceptions should be handled by throw_exception");
-  assert(exception->is_oop(), "just checking");
   // Check that exception is a subclass of Throwable, otherwise we have a VerifyError
   if (!(exception->is_a(SystemDictionary::Throwable_klass()))) {
     if (ExitVMOnVerifyError) vm_exit(-1);
@@ -385,7 +384,6 @@
   }
 #endif
   Handle h_obj(thread, obj);
-  assert(h_obj()->is_oop(), "must be NULL or an object");
   if (UseBiasedLocking) {
     // Retry fast entry if bias is revoked to avoid unnecessary inflation
     ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK);
@@ -407,7 +405,7 @@
   EXCEPTION_MARK;
 
 #ifdef DEBUG
-  if (!obj->is_oop()) {
+  if (!oopDesc::is_oop(obj)) {
     ResetNoHandleMark rhm;
     nmethod* method = thread->last_frame().cb()->as_nmethod_or_null();
     if (method != NULL) {
@@ -455,8 +453,8 @@
 
   if (obj == NULL) {
     tty->print("NULL");
-  } else if (obj->is_oop_or_null(true) && (!as_string || !java_lang_String::is_instance(obj))) {
-    if (obj->is_oop_or_null(true)) {
+  } else if (oopDesc::is_oop_or_null(obj, true) && (!as_string || !java_lang_String::is_instance(obj))) {
+    if (oopDesc::is_oop_or_null(obj, true)) {
       char buf[O_BUFLEN];
       tty->print("%s@" INTPTR_FORMAT, obj->klass()->name()->as_C_string(buf, O_BUFLEN), p2i(obj));
     } else {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/metaprogramming/isRegisteredEnum.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_METAPROGRAMMING_ISREGISTEREDENUM_HPP
+#define SHARE_VM_METAPROGRAMMING_ISREGISTEREDENUM_HPP
+
+#include "memory/allocation.hpp"
+#include "metaprogramming/integralConstant.hpp"
+
+// Recognize registered enum types.
+// Registration is by specializing this trait.
+//
+// This is a manual stand-in for the C++11 std::is_enum<T> type trait.
+// It's a lot of work to implement is_enum portably in C++98, so this
+// manual approach is being taken for those enum types we need to
+// distinguish.
+template<typename T>
+struct IsRegisteredEnum : public FalseType {};
+
+#endif // SHARE_VM_METAPROGRAMMING_ISREGISTEREDENUM_HPP
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/metaprogramming/primitiveConversions.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_METAPROGRAMMING_PRIMITIVECONVERSIONS_HPP
+#define SHARE_VM_METAPROGRAMMING_PRIMITIVECONVERSIONS_HPP
+
+#include "memory/allocation.hpp"
+#include "metaprogramming/enableIf.hpp"
+#include "metaprogramming/integralConstant.hpp"
+#include "metaprogramming/isFloatingPoint.hpp"
+#include "metaprogramming/isIntegral.hpp"
+#include "metaprogramming/isRegisteredEnum.hpp"
+#include "utilities/debug.hpp"
+
+class PrimitiveConversions : public AllStatic {
+public:
+  // Return a value of type T with the same representation as x.
+  //
+  // T and U must be of the same size.
+  //
+  // At least one of T or U must be an integral type.  The other must
+  // be an integral, floating point, or pointer type.
+  template<typename T, typename U> static T cast(U x);
+
+  // Support thin wrappers over primitive types.
+  // If derived from TrueType, provides representational conversion
+  // from T to some other type.  When true, must provide
+  // - Value: typedef for T.
+  // - Decayed: typedef for decayed type.
+  // - static Decayed decay(T x): return value of type Decayed with
+  //   the same representation as x.
+  // - static T recover(Decayed x): return a value of type T with the
+  //   same representation as x.
+  template<typename T> struct Translate : public FalseType {};
+
+private:
+
+  template<typename T,
+           typename U,
+           bool same_size = sizeof(T) == sizeof(U),
+           typename Enable = void>
+  struct Cast;
+
+  template<typename T, typename U> static T cast_using_union(U x);
+};
+
+// Return an object of type T with the same value representation as x.
+//
+// T and U must be of the same size.  It is expected that one of T and
+// U is an integral type, and the other is an integral type, a
+// (registered) enum type, or a floating point type
+//
+// This implementation uses the "union trick", which seems to be the
+// best of a bad set of options.  Though technically undefined
+// behavior, it is widely and well supported, producing good code.  In
+// some cases, such as gcc, that support is explicitly documented.
+//
+// Using memcpy is the correct method, but some compilers produce
+// wretched code for that method, even at maximal optimization levels.
+//
+// Using static_cast is only possible for integral and enum types, not
+// for floating point types.  And for integral and enum conversions,
+// static_cast has unspecified or implementation-defined behavior for
+// some cases.  C++11 <type_traits> can be used to avoid most or all
+// of those unspecified or implementation-defined issues, though that
+// may require multi-step conversions.
+//
+// Using reinterpret_cast of references has undefined behavior for
+// many cases, and there is much less empirical basis for its use, as
+// compared to the union trick.
+template<typename T, typename U>
+inline T PrimitiveConversions::cast_using_union(U x) {
+  STATIC_ASSERT(sizeof(T) == sizeof(U));
+  union { T t; U u; };
+  u = x;
+  return t;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// cast<T>(x)
+//
+// Cast<T, U, same_size, Enable>
+
+// Give an informative error if the sizes differ.
+template<typename T, typename U>
+struct PrimitiveConversions::Cast<T, U, false> VALUE_OBJ_CLASS_SPEC {
+  STATIC_ASSERT(sizeof(T) == sizeof(U));
+};
+
+// Conversion between integral types.
+template<typename T, typename U>
+struct PrimitiveConversions::Cast<
+  T, U, true,
+  typename EnableIf<IsIntegral<T>::value && IsIntegral<U>::value>::type>
+  VALUE_OBJ_CLASS_SPEC
+{
+  T operator()(U x) const { return cast_using_union<T>(x); }
+};
+
+// Convert an enum or floating point value to an integer value.
+template<typename T, typename U>
+struct PrimitiveConversions::Cast<
+  T, U, true,
+  typename EnableIf<IsIntegral<T>::value &&
+                    (IsRegisteredEnum<U>::value ||
+                     IsFloatingPoint<U>::value)>::type>
+  VALUE_OBJ_CLASS_SPEC
+{
+  T operator()(U x) const { return cast_using_union<T>(x); }
+};
+
+// Convert an integer to an enum or floating point value.
+template<typename T, typename U>
+struct PrimitiveConversions::Cast<
+  T, U, true,
+  typename EnableIf<IsIntegral<U>::value &&
+                    (IsRegisteredEnum<T>::value ||
+                     IsFloatingPoint<T>::value)>::type>
+  VALUE_OBJ_CLASS_SPEC
+{
+  T operator()(U x) const { return cast_using_union<T>(x); }
+};
+
+// Convert a pointer to an integral value.
+template<typename T, typename U>
+struct PrimitiveConversions::Cast<
+  T, U*, true,
+  typename EnableIf<IsIntegral<T>::value>::type>
+  VALUE_OBJ_CLASS_SPEC
+{
+  T operator()(U* x) const { return reinterpret_cast<T>(x); }
+};
+
+// Convert an integral value to a pointer.
+template<typename T, typename U>
+struct PrimitiveConversions::Cast<
+  T*, U, true,
+  typename EnableIf<IsIntegral<U>::value>::type>
+  VALUE_OBJ_CLASS_SPEC
+{
+  T* operator()(U x) const { return reinterpret_cast<T*>(x); }
+};
+
+template<typename T, typename U>
+inline T PrimitiveConversions::cast(U x) {
+  return Cast<T, U>()(x);
+}
+
+#endif // SHARE_VM_METAPROGRAMMING_PRIMITIVECONVERSIONS_HPP
--- a/hotspot/src/share/vm/oops/constantPool.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/oops/constantPool.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -134,7 +134,7 @@
 }
 
 objArrayOop ConstantPool::resolved_references() const {
-  return (objArrayOop)JNIHandles::resolve(_cache->resolved_references());
+  return (objArrayOop)_cache->resolved_references();
 }
 
 // Create resolved_references array and mapping array for original cp indexes
--- a/hotspot/src/share/vm/oops/constantPool.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/oops/constantPool.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -28,6 +28,7 @@
 #include "oops/arrayOop.hpp"
 #include "oops/cpCache.hpp"
 #include "oops/objArrayOop.hpp"
+#include "oops/oopHandle.hpp"
 #include "oops/symbol.hpp"
 #include "oops/typeArrayOop.hpp"
 #include "runtime/handles.hpp"
@@ -821,7 +822,7 @@
 
  private:
 
-  void set_resolved_references(jobject s) { _cache->set_resolved_references(s); }
+  void set_resolved_references(OopHandle s) { _cache->set_resolved_references(s); }
   Array<u2>* reference_map() const        {  return (_cache == NULL) ? NULL :  _cache->reference_map(); }
   void set_reference_map(Array<u2>* o)    { _cache->set_reference_map(o); }
 
--- a/hotspot/src/share/vm/oops/cpCache.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/oops/cpCache.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -28,6 +28,7 @@
 #include "interpreter/bytecodes.hpp"
 #include "memory/allocation.hpp"
 #include "oops/array.hpp"
+#include "oops/oopHandle.hpp"
 #include "runtime/orderAccess.hpp"
 #include "utilities/align.hpp"
 
@@ -413,7 +414,7 @@
   // stored in the ConstantPool, which is read-only.
   // Array of resolved objects from the constant pool and map from resolved
   // object index to original constant pool index
-  jobject              _resolved_references;
+  OopHandle            _resolved_references;
   Array<u2>*           _reference_map;
   // The narrowOop pointer to the archived resolved_references. Set at CDS dump
   // time when caching java heap object is supported.
@@ -455,8 +456,8 @@
   oop  archived_references() NOT_CDS_JAVA_HEAP_RETURN_(NULL);
   void set_archived_references(oop o) NOT_CDS_JAVA_HEAP_RETURN;
 
-  jobject resolved_references()           { return _resolved_references; }
-  void set_resolved_references(jobject s) { _resolved_references = s; }
+  oop resolved_references()                 { return _resolved_references.resolve(); }
+  void set_resolved_references(OopHandle s) { _resolved_references = s; }
   Array<u2>* reference_map() const        { return _reference_map; }
   void set_reference_map(Array<u2>* o)    { _reference_map = o; }
 
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -3207,7 +3207,7 @@
  protected:
   template <class T> void do_oop_work(T* p) {
     oop obj = oopDesc::load_decode_heap_oop(p);
-    if (!obj->is_oop_or_null()) {
+    if (!oopDesc::is_oop_or_null(obj)) {
       tty->print_cr("Failed: " PTR_FORMAT " -> " PTR_FORMAT, p2i(p), p2i(obj));
       Universe::print_on(tty);
       guarantee(false, "boom");
--- a/hotspot/src/share/vm/oops/instanceRefKlass.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/oops/instanceRefKlass.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -72,12 +72,12 @@
   // Verify referent field
   oop referent = java_lang_ref_Reference::referent(obj);
   if (referent != NULL) {
-    guarantee(referent->is_oop(), "referent field heap failed");
+    guarantee(oopDesc::is_oop(referent), "referent field heap failed");
   }
   // Verify next field
   oop next = java_lang_ref_Reference::next(obj);
   if (next != NULL) {
-    guarantee(next->is_oop(), "next field should be an oop");
+    guarantee(oopDesc::is_oop(next), "next field should be an oop");
     guarantee(next->is_instance(), "next field should be an instance");
     guarantee(InstanceKlass::cast(next->klass())->is_reference_instance_klass(), "next field verify failed");
   }
--- a/hotspot/src/share/vm/oops/klass.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/oops/klass.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -713,12 +713,12 @@
   }
 
   if (java_mirror() != NULL) {
-    guarantee(java_mirror()->is_oop(), "should be instance");
+    guarantee(oopDesc::is_oop(java_mirror()), "should be instance");
   }
 }
 
 void Klass::oop_verify_on(oop obj, outputStream* st) {
-  guarantee(obj->is_oop(),  "should be oop");
+  guarantee(oopDesc::is_oop(obj),  "should be oop");
   guarantee(obj->klass()->is_klass(), "klass field is not a klass");
 }
 
--- a/hotspot/src/share/vm/oops/objArrayKlass.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -498,6 +498,6 @@
   guarantee(obj->is_objArray(), "must be objArray");
   objArrayOop oa = objArrayOop(obj);
   for(int index = 0; index < oa->length(); index++) {
-    guarantee(oa->obj_at(index)->is_oop_or_null(), "should be oop");
+    guarantee(oopDesc::is_oop_or_null(oa->obj_at(index)), "should be oop");
   }
 }
--- a/hotspot/src/share/vm/oops/oop.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/oops/oop.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -121,11 +121,44 @@
   }
 }
 
+// used only for asserts and guarantees
+bool oopDesc::is_oop(oop obj, bool ignore_mark_word) {
+  if (!check_obj_alignment(obj)) return false;
+  if (!Universe::heap()->is_in_reserved(obj)) return false;
+  // obj is aligned and accessible in heap
+  if (Universe::heap()->is_in_reserved(obj->klass_or_null())) return false;
+
+  // Header verification: the mark is typically non-NULL. If we're
+  // at a safepoint, it must not be null.
+  // Outside of a safepoint, the header could be changing (for example,
+  // another thread could be inflating a lock on this object).
+  if (ignore_mark_word) {
+    return true;
+  }
+  if (obj->mark() != NULL) {
+    return true;
+  }
+  return !SafepointSynchronize::is_at_safepoint();
+}
+
+// used only for asserts and guarantees
+bool oopDesc::is_oop_or_null(oop obj, bool ignore_mark_word) {
+  return obj == NULL ? true : is_oop(obj, ignore_mark_word);
+}
+
+#ifndef PRODUCT
+// used only for asserts
+bool oopDesc::is_unlocked_oop() const {
+  if (!Universe::heap()->is_in_reserved(this)) return false;
+  return mark()->is_unlocked();
+}
+#endif // PRODUCT
+
 VerifyOopClosure VerifyOopClosure::verify_oop;
 
 template <class T> void VerifyOopClosure::do_oop_work(T* p) {
   oop obj = oopDesc::load_decode_heap_oop(p);
-  guarantee(obj->is_oop_or_null(), "invalid oop: " INTPTR_FORMAT, p2i((oopDesc*) obj));
+  guarantee(oopDesc::is_oop_or_null(obj), "invalid oop: " INTPTR_FORMAT, p2i((oopDesc*) obj));
 }
 
 void VerifyOopClosure::do_oop(oop* p)       { VerifyOopClosure::do_oop_work(p); }
--- a/hotspot/src/share/vm/oops/oop.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/oops/oop.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -287,9 +287,9 @@
   inline bool is_unlocked() const;
   inline bool has_bias_pattern() const;
 
-  // asserts
-  inline bool is_oop(bool ignore_mark_word = false) const;
-  inline bool is_oop_or_null(bool ignore_mark_word = false) const;
+  // asserts and guarantees
+  static bool is_oop(oop obj, bool ignore_mark_word = false);
+  static bool is_oop_or_null(oop obj, bool ignore_mark_word = false);
 #ifndef PRODUCT
   inline bool is_unlocked_oop() const;
 #endif
--- a/hotspot/src/share/vm/oops/oop.inline.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/oops/oop.inline.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -94,7 +94,7 @@
 }
 
 markOop oopDesc::cas_set_mark(markOop new_mark, markOop old_mark) {
-  return (markOop) Atomic::cmpxchg_ptr(new_mark, &_mark, old_mark);
+  return Atomic::cmpxchg(new_mark, &_mark, old_mark);
 }
 
 void oopDesc::init_mark() {
@@ -408,14 +408,14 @@
     narrowOop val = encode_heap_oop(exchange_value);
     narrowOop cmp = encode_heap_oop(compare_value);
 
-    narrowOop old = (narrowOop) Atomic::cmpxchg(val, (narrowOop*)dest, cmp);
+    narrowOop old = Atomic::cmpxchg(val, (narrowOop*)dest, cmp);
     // decode old from T to oop
     return decode_heap_oop(old);
   } else {
     if (prebarrier) {
       update_barrier_set_pre((oop*)dest, exchange_value);
     }
-    return (oop)Atomic::cmpxchg_ptr(exchange_value, (oop*)dest, compare_value);
+    return Atomic::cmpxchg(exchange_value, (oop*)dest, compare_value);
   }
 }
 
@@ -533,41 +533,6 @@
   return mark()->has_bias_pattern();
 }
 
-// used only for asserts
-bool oopDesc::is_oop(bool ignore_mark_word) const {
-  oop obj = (oop) this;
-  if (!check_obj_alignment(obj)) return false;
-  if (!Universe::heap()->is_in_reserved(obj)) return false;
-  // obj is aligned and accessible in heap
-  if (Universe::heap()->is_in_reserved(obj->klass_or_null())) return false;
-
-  // Header verification: the mark is typically non-NULL. If we're
-  // at a safepoint, it must not be null.
-  // Outside of a safepoint, the header could be changing (for example,
-  // another thread could be inflating a lock on this object).
-  if (ignore_mark_word) {
-    return true;
-  }
-  if (mark() != NULL) {
-    return true;
-  }
-  return !SafepointSynchronize::is_at_safepoint();
-}
-
-
-// used only for asserts
-bool oopDesc::is_oop_or_null(bool ignore_mark_word) const {
-  return this == NULL ? true : is_oop(ignore_mark_word);
-}
-
-#ifndef PRODUCT
-// used only for asserts
-bool oopDesc::is_unlocked_oop() const {
-  if (!Universe::heap()->is_in_reserved(this)) return false;
-  return mark()->is_unlocked();
-}
-#endif // PRODUCT
-
 // Used only for markSweep, scavenging
 bool oopDesc::is_gc_marked() const {
   return mark()->is_marked();
@@ -619,7 +584,7 @@
   assert(sizeof(markOop) == sizeof(intptr_t), "CAS below requires this.");
 
   while (!oldMark->is_marked()) {
-    curMark = (markOop)Atomic::cmpxchg_ptr(forwardPtrMark, &_mark, oldMark);
+    curMark = Atomic::cmpxchg(forwardPtrMark, &_mark, oldMark);
     assert(is_forwarded(), "object should have been forwarded");
     if (curMark == oldMark) {
       return NULL;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/oops/oopHandle.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_OOPS_OOPHANDLE_HPP
+#define SHARE_VM_OOPS_OOPHANDLE_HPP
+
+#include "oops/oop.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/orderAccess.hpp"
+
+// Simple class for encapsulating oop pointers stored in metadata.
+// These are different from Handle.  The Handle class stores pointers
+// to oops on the stack, and manages the allocation from a thread local
+// area in the constructor.
+// This assumes that the caller will allocate the handle in the appropriate
+// area.  The reason for the encapsulation is to help with naming and to allow
+// future uses for read barriers.
+
+class OopHandle {
+private:
+  oop* _obj;
+
+public:
+  OopHandle() : _obj(NULL) {}
+  OopHandle(oop* w) : _obj(w) {}
+
+  oop resolve() const { return (_obj == NULL) ? (oop)NULL : *_obj; }
+};
+
+#endif // SHARE_VM_OOPS_OOPHANDLE_HPP
--- a/hotspot/src/share/vm/oops/oopsHierarchy.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/oops/oopsHierarchy.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
 #ifndef SHARE_VM_OOPS_OOPSHIERARCHY_HPP
 #define SHARE_VM_OOPS_OOPSHIERARCHY_HPP
 
+#include "metaprogramming/integralConstant.hpp"
+#include "metaprogramming/primitiveConversions.hpp"
 #include "runtime/globals.hpp"
 #include "utilities/globalDefinitions.hpp"
 
@@ -142,6 +144,15 @@
   operator oop* () const              { return (oop *)obj(); }
 };
 
+template<>
+struct PrimitiveConversions::Translate<oop> : public TrueType {
+  typedef oop Value;
+  typedef oopDesc* Decayed;
+
+  static Decayed decay(Value x) { return x.obj(); }
+  static Value recover(Decayed x) { return oop(x); }
+};
+
 #define DEF_OOP(type)                                                      \
    class type##OopDesc;                                                    \
    class type##Oop : public oop {                                          \
--- a/hotspot/src/share/vm/opto/runtime.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/opto/runtime.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1563,7 +1563,7 @@
 
 
 JRT_ENTRY_NO_ASYNC(void, OptoRuntime::register_finalizer(oopDesc* obj, JavaThread* thread))
-  assert(obj->is_oop(), "must be a valid oop");
+  assert(oopDesc::is_oop(obj), "must be a valid oop");
   assert(obj->klass()->has_finalizer(), "shouldn't be here otherwise");
   InstanceKlass::register_finalizer(instanceOop(obj), CHECK);
 JRT_END
--- a/hotspot/src/share/vm/prims/jni.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/prims/jni.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -4028,7 +4028,7 @@
 }
 
 _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, void *args) {
-  jint result = 0;
+  jint result = JNI_ERR;
   // On Windows, let CreateJavaVM run with SEH protection
 #ifdef _WIN32
   __try {
@@ -4063,7 +4063,7 @@
 DT_RETURN_MARK_DECL(DestroyJavaVM, jint
                     , HOTSPOT_JNI_DESTROYJAVAVM_RETURN(_ret_ref));
 
-jint JNICALL jni_DestroyJavaVM(JavaVM *vm) {
+static jint JNICALL jni_DestroyJavaVM_inner(JavaVM *vm) {
   HOTSPOT_JNI_DESTROYJAVAVM_ENTRY(vm);
   jint res = JNI_ERR;
   DT_RETURN_MARK(DestroyJavaVM, jint, (const jint&)res);
@@ -4099,6 +4099,20 @@
   }
 }
 
+jint JNICALL jni_DestroyJavaVM(JavaVM *vm) {
+  jint result = JNI_ERR;
+  // On Windows, we need SEH protection
+#ifdef _WIN32
+  __try {
+#endif
+    result = jni_DestroyJavaVM_inner(vm);
+#ifdef _WIN32
+  } __except(topLevelExceptionFilter((_EXCEPTION_POINTERS*)_exception_info())) {
+    // Nothing to do.
+  }
+#endif
+  return result;
+}
 
 static jint attach_current_thread(JavaVM *vm, void **penv, void *_args, bool daemon) {
   JavaVMAttachArgs *args = (JavaVMAttachArgs *) _args;
--- a/hotspot/src/share/vm/prims/jvm.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/prims/jvm.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -326,8 +326,8 @@
   }
   arrayOop s = arrayOop(JNIHandles::resolve_non_null(src));
   arrayOop d = arrayOop(JNIHandles::resolve_non_null(dst));
-  assert(s->is_oop(), "JVM_ArrayCopy: src not an oop");
-  assert(d->is_oop(), "JVM_ArrayCopy: dst not an oop");
+  assert(oopDesc::is_oop(s), "JVM_ArrayCopy: src not an oop");
+  assert(oopDesc::is_oop(d), "JVM_ArrayCopy: dst not an oop");
   // Do copy
   s->klass()->copy_array(s, src_pos, d, dst_pos, length, thread);
 JVM_END
--- a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1490,14 +1490,14 @@
   }
 }
 
-GrowableArray<jobject>* JvmtiModuleClosure::_tbl = NULL;
+GrowableArray<OopHandle>* JvmtiModuleClosure::_tbl = NULL;
 
 jvmtiError
 JvmtiModuleClosure::get_all_modules(JvmtiEnv* env, jint* module_count_ptr, jobject** modules_ptr) {
   ResourceMark rm;
   MutexLocker ml(Module_lock);
 
-  _tbl = new GrowableArray<jobject>(77);
+  _tbl = new GrowableArray<OopHandle>(77);
   if (_tbl == NULL) {
     return JVMTI_ERROR_OUT_OF_MEMORY;
   }
@@ -1513,7 +1513,7 @@
     return JVMTI_ERROR_OUT_OF_MEMORY;
   }
   for (jint idx = 0; idx < len; idx++) {
-    array[idx] = _tbl->at(idx);
+    array[idx] = JNIHandles::make_local(Thread::current(), _tbl->at(idx).resolve());
   }
   _tbl = NULL;
   *modules_ptr = array;
--- a/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -30,6 +30,7 @@
 #include "prims/jvmtiEventController.hpp"
 #include "prims/jvmtiThreadState.hpp"
 #include "prims/jvmtiThreadState.inline.hpp"
+#include "oops/oopHandle.hpp"
 #include "runtime/fieldDescriptor.hpp"
 #include "runtime/frame.hpp"
 #include "runtime/handles.inline.hpp"
@@ -704,12 +705,12 @@
 // Jvmti module closure to collect all modules loaded to the system.
 class JvmtiModuleClosure : public StackObj {
 private:
-  static GrowableArray<jobject> *_tbl; // Protected with Module_lock
+  static GrowableArray<OopHandle> *_tbl; // Protected with Module_lock
 
   static void do_module(ModuleEntry* entry) {
     assert_locked_or_safepoint(Module_lock);
-    jobject module = entry->module_handle();
-    guarantee(module != NULL, "module object is NULL");
+    OopHandle module = entry->module_handle();
+    guarantee(module.resolve() != NULL, "module object is NULL");
     _tbl->push(module);
   }
 
--- a/hotspot/src/share/vm/prims/jvmtiExport.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -764,7 +764,7 @@
         ModuleEntry* module_entry = InstanceKlass::cast(klass)->module();
         assert(module_entry != NULL, "module_entry should always be set");
         if (module_entry->is_named() &&
-            module_entry->module_handle() != NULL &&
+            module_entry->module() != NULL &&
             !module_entry->has_default_read_edges()) {
           if (!module_entry->set_has_default_read_edges()) {
             // We won a potential race.
--- a/hotspot/src/share/vm/prims/privilegedStack.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/prims/privilegedStack.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -39,8 +39,8 @@
 #endif // CHECK_UNHANDLED_OOPS
   _frame_id             = vfst->frame_id();
   _next                 = next;
-  assert(_privileged_context == NULL || _privileged_context->is_oop(), "must be an oop");
-  assert(protection_domain() == NULL || protection_domain()->is_oop(), "must be an oop");
+  assert(oopDesc::is_oop_or_null(_privileged_context), "must be an oop");
+  assert(oopDesc::is_oop_or_null(protection_domain()), "must be an oop");
 }
 
 void PrivilegedElement::oops_do(OopClosure* f) {
--- a/hotspot/src/share/vm/runtime/atomic.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/runtime/atomic.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -26,6 +26,11 @@
 #define SHARE_VM_RUNTIME_ATOMIC_HPP
 
 #include "memory/allocation.hpp"
+#include "metaprogramming/enableIf.hpp"
+#include "metaprogramming/isIntegral.hpp"
+#include "metaprogramming/isSame.hpp"
+#include "metaprogramming/primitiveConversions.hpp"
+#include "metaprogramming/removeCV.hpp"
 #include "utilities/align.hpp"
 #include "utilities/macros.hpp"
 
@@ -111,13 +116,132 @@
   // *dest with exchange_value if the comparison succeeded. Returns prior
   // value of *dest. cmpxchg*() provide:
   // <fence> compare-and-exchange <membar StoreLoad|StoreStore>
-  inline static jbyte        cmpxchg    (jbyte        exchange_value, volatile jbyte*        dest, jbyte        compare_value, cmpxchg_memory_order order = memory_order_conservative);
-  inline static jint         cmpxchg    (jint         exchange_value, volatile jint*         dest, jint         compare_value, cmpxchg_memory_order order = memory_order_conservative);
-  // See comment above about using jlong atomics on 32-bit platforms
-  inline static jlong        cmpxchg    (jlong        exchange_value, volatile jlong*        dest, jlong        compare_value, cmpxchg_memory_order order = memory_order_conservative);
-  inline static unsigned int cmpxchg    (unsigned int exchange_value, volatile unsigned int* dest, unsigned int compare_value, cmpxchg_memory_order order = memory_order_conservative);
-  inline static intptr_t     cmpxchg_ptr(intptr_t     exchange_value, volatile intptr_t*     dest, intptr_t     compare_value, cmpxchg_memory_order order = memory_order_conservative);
-  inline static void*        cmpxchg_ptr(void*        exchange_value, volatile void*         dest, void*        compare_value, cmpxchg_memory_order order = memory_order_conservative);
+
+  template<typename T, typename D, typename U>
+  inline static D cmpxchg(T exchange_value,
+                          D volatile* dest,
+                          U compare_value,
+                          cmpxchg_memory_order order = memory_order_conservative);
+
+  // Performs atomic compare of *dest and NULL, and replaces *dest
+  // with exchange_value if the comparison succeeded.  Returns true if
+  // the comparison succeeded and the exchange occurred.  This is
+  // often used as part of lazy initialization, as a lock-free
+  // alternative to the Double-Checked Locking Pattern.
+  template<typename T, typename D>
+  inline static bool replace_if_null(T* value, D* volatile* dest,
+                                     cmpxchg_memory_order order = memory_order_conservative);
+
+  inline static intptr_t cmpxchg_ptr(intptr_t exchange_value,
+                                     volatile intptr_t* dest,
+                                     intptr_t compare_value,
+                                     cmpxchg_memory_order order = memory_order_conservative) {
+    return cmpxchg(exchange_value, dest, compare_value, order);
+  }
+
+  inline static void* cmpxchg_ptr(void* exchange_value,
+                                  volatile void* dest,
+                                  void* compare_value,
+                                  cmpxchg_memory_order order = memory_order_conservative) {
+    return cmpxchg(exchange_value,
+                   reinterpret_cast<void* volatile*>(dest),
+                   compare_value,
+                   order);
+  }
+
+private:
+  // Test whether From is implicitly convertible to To.
+  // From and To must be pointer types.
+  // Note: Provides the limited subset of C++11 std::is_convertible
+  // that is needed here.
+  template<typename From, typename To> struct IsPointerConvertible;
+
+  // Dispatch handler for cmpxchg.  Provides type-based validity
+  // checking and limited conversions around calls to the
+  // platform-specific implementation layer provided by
+  // PlatformCmpxchg.
+  template<typename T, typename D, typename U, typename Enable = void>
+  struct CmpxchgImpl;
+
+  // Platform-specific implementation of cmpxchg.  Support for sizes
+  // of 1, 4, and 8 are required.  The class is a function object that
+  // must be default constructable, with these requirements:
+  //
+  // - dest is of type T*.
+  // - exchange_value and compare_value are of type T.
+  // - order is of type cmpxchg_memory_order.
+  // - platform_cmpxchg is an object of type PlatformCmpxchg<sizeof(T)>.
+  //
+  // Then
+  //   platform_cmpxchg(exchange_value, dest, compare_value, order)
+  // must be a valid expression, returning a result convertible to T.
+  //
+  // A default definition is provided, which declares a function template
+  //   T operator()(T, T volatile*, T, cmpxchg_memory_order) const
+  //
+  // For each required size, a platform must either provide an
+  // appropriate definition of that function, or must entirely
+  // specialize the class template for that size.
+  template<size_t byte_size> struct PlatformCmpxchg;
+
+  // Support for platforms that implement some variants of cmpxchg
+  // using a (typically out of line) non-template helper function.
+  // The generic arguments passed to PlatformCmpxchg need to be
+  // translated to the appropriate type for the helper function, the
+  // helper invoked on the translated arguments, and the result
+  // translated back.  Type is the parameter / return type of the
+  // helper function.
+  template<typename Type, typename Fn, typename T>
+  static T cmpxchg_using_helper(Fn fn,
+                                T exchange_value,
+                                T volatile* dest,
+                                T compare_value);
+
+  // Support platforms that do not provide Read-Modify-Write
+  // byte-level atomic access. To use, derive PlatformCmpxchg<1> from
+  // this class.
+public: // Temporary, can't be private: C++03 11.4/2. Fixed by C++11.
+  struct CmpxchgByteUsingInt;
+private:
+};
+
+template<typename From, typename To>
+struct Atomic::IsPointerConvertible<From*, To*> : AllStatic {
+  // Determine whether From* is implicitly convertible to To*, using
+  // the "sizeof trick".
+  typedef char yes;
+  typedef char (&no)[2];
+
+  static yes test(To*);
+  static no test(...);
+  static From* test_value;
+
+  static const bool value = (sizeof(yes) == sizeof(test(test_value)));
+};
+
+// Define the class before including platform file, which may specialize
+// the operator definition.  No generic definition of specializations
+// of the operator template are provided, nor are there any generic
+// specializations of the class.  The platform file is responsible for
+// providing those.
+template<size_t byte_size>
+struct Atomic::PlatformCmpxchg VALUE_OBJ_CLASS_SPEC {
+  template<typename T>
+  T operator()(T exchange_value,
+               T volatile* dest,
+               T compare_value,
+               cmpxchg_memory_order order) const;
+};
+
+// Define the class before including platform file, which may use this
+// as a base class, requiring it be complete.  The definition is later
+// in this file, near the other definitions related to cmpxchg.
+struct Atomic::CmpxchgByteUsingInt VALUE_OBJ_CLASS_SPEC {
+  template<typename T>
+  T operator()(T exchange_value,
+               T volatile* dest,
+               T compare_value,
+               cmpxchg_memory_order order) const;
 };
 
 // platform specific in-line definitions - must come before shared definitions
@@ -143,61 +267,152 @@
   dec_ptr((volatile intptr_t*) dest);
 }
 
-#ifndef VM_HAS_SPECIALIZED_CMPXCHG_BYTE
-/*
- * This is the default implementation of byte-sized cmpxchg. It emulates jbyte-sized cmpxchg
- * in terms of jint-sized cmpxchg. Platforms may override this by defining their own inline definition
- * as well as defining VM_HAS_SPECIALIZED_CMPXCHG_BYTE. This will cause the platform specific
- * implementation to be used instead.
- */
-inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest,
-                             jbyte compare_value, cmpxchg_memory_order order) {
-  STATIC_ASSERT(sizeof(jbyte) == 1);
-  volatile jint* dest_int =
-      reinterpret_cast<volatile jint*>(align_down(dest, sizeof(jint)));
-  size_t offset = pointer_delta(dest, dest_int, 1);
-  jint cur = *dest_int;
-  jbyte* cur_as_bytes = reinterpret_cast<jbyte*>(&cur);
+template<typename T, typename D, typename U>
+inline D Atomic::cmpxchg(T exchange_value,
+                         D volatile* dest,
+                         U compare_value,
+                         cmpxchg_memory_order order) {
+  return CmpxchgImpl<T, D, U>()(exchange_value, dest, compare_value, order);
+}
+
+template<typename T, typename D>
+inline bool Atomic::replace_if_null(T* value, D* volatile* dest,
+                                    cmpxchg_memory_order order) {
+  // Presently using a trivial implementation in terms of cmpxchg.
+  // Consider adding platform support, to permit the use of compiler
+  // intrinsics like gcc's __sync_bool_compare_and_swap.
+  D* expected_null = NULL;
+  return expected_null == cmpxchg(value, dest, expected_null, order);
+}
+
+// Handle cmpxchg for integral and enum types.
+//
+// All the involved types must be identical.
+template<typename T>
+struct Atomic::CmpxchgImpl<
+  T, T, T,
+  typename EnableIf<IsIntegral<T>::value || IsRegisteredEnum<T>::value>::type>
+  VALUE_OBJ_CLASS_SPEC
+{
+  T operator()(T exchange_value, T volatile* dest, T compare_value,
+               cmpxchg_memory_order order) const {
+    // Forward to the platform handler for the size of T.
+    return PlatformCmpxchg<sizeof(T)>()(exchange_value,
+                                        dest,
+                                        compare_value,
+                                        order);
+  }
+};
+
+// Handle cmpxchg for pointer types.
+//
+// The destination's type and the compare_value type must be the same,
+// ignoring cv-qualifiers; we don't care about the cv-qualifiers of
+// the compare_value.
+//
+// The exchange_value must be implicitly convertible to the
+// destination's type; it must be type-correct to store the
+// exchange_value in the destination.
+template<typename T, typename D, typename U>
+struct Atomic::CmpxchgImpl<
+  T*, D*, U*,
+  typename EnableIf<Atomic::IsPointerConvertible<T*, D*>::value &&
+                    IsSame<typename RemoveCV<D>::type,
+                           typename RemoveCV<U>::type>::value>::type>
+  VALUE_OBJ_CLASS_SPEC
+{
+  D* operator()(T* exchange_value, D* volatile* dest, U* compare_value,
+               cmpxchg_memory_order order) const {
+    // Allow derived to base conversion, and adding cv-qualifiers.
+    D* new_value = exchange_value;
+    // Don't care what the CV qualifiers for compare_value are,
+    // but we need to match D* when calling platform support.
+    D* old_value = const_cast<D*>(compare_value);
+    return PlatformCmpxchg<sizeof(D*)>()(new_value, dest, old_value, order);
+  }
+};
+
+// Handle cmpxchg for types that have a translator.
+//
+// All the involved types must be identical.
+//
+// This translates the original call into a call on the decayed
+// arguments, and returns the recovered result of that translated
+// call.
+template<typename T>
+struct Atomic::CmpxchgImpl<
+  T, T, T,
+  typename EnableIf<PrimitiveConversions::Translate<T>::value>::type>
+  VALUE_OBJ_CLASS_SPEC
+{
+  T operator()(T exchange_value, T volatile* dest, T compare_value,
+               cmpxchg_memory_order order) const {
+    typedef PrimitiveConversions::Translate<T> Translator;
+    typedef typename Translator::Decayed Decayed;
+    STATIC_ASSERT(sizeof(T) == sizeof(Decayed));
+    return Translator::recover(
+      cmpxchg(Translator::decay(exchange_value),
+              reinterpret_cast<Decayed volatile*>(dest),
+              Translator::decay(compare_value),
+              order));
+  }
+};
+
+template<typename Type, typename Fn, typename T>
+inline T Atomic::cmpxchg_using_helper(Fn fn,
+                                      T exchange_value,
+                                      T volatile* dest,
+                                      T compare_value) {
+  STATIC_ASSERT(sizeof(Type) == sizeof(T));
+  return PrimitiveConversions::cast<T>(
+    fn(PrimitiveConversions::cast<Type>(exchange_value),
+       reinterpret_cast<Type volatile*>(dest),
+       PrimitiveConversions::cast<Type>(compare_value)));
+}
+
+template<typename T>
+inline T Atomic::CmpxchgByteUsingInt::operator()(T exchange_value,
+                                                 T volatile* dest,
+                                                 T compare_value,
+                                                 cmpxchg_memory_order order) const {
+  STATIC_ASSERT(sizeof(T) == sizeof(uint8_t));
+  uint8_t canon_exchange_value = exchange_value;
+  uint8_t canon_compare_value = compare_value;
+  volatile uint32_t* aligned_dest
+    = reinterpret_cast<volatile uint32_t*>(align_down(dest, sizeof(uint32_t)));
+  size_t offset = pointer_delta(dest, aligned_dest, 1);
+  uint32_t cur = *aligned_dest;
+  uint8_t* cur_as_bytes = reinterpret_cast<uint8_t*>(&cur);
 
   // current value may not be what we are looking for, so force it
   // to that value so the initial cmpxchg will fail if it is different
-  cur_as_bytes[offset] = compare_value;
+  cur_as_bytes[offset] = canon_compare_value;
 
   // always execute a real cmpxchg so that we get the required memory
   // barriers even on initial failure
   do {
     // value to swap in matches current value ...
-    jint new_value = cur;
+    uint32_t new_value = cur;
     // ... except for the one jbyte we want to update
-    reinterpret_cast<jbyte*>(&new_value)[offset] = exchange_value;
+    reinterpret_cast<uint8_t*>(&new_value)[offset] = canon_exchange_value;
 
-    jint res = cmpxchg(new_value, dest_int, cur, order);
-    if (res == cur) break; // success
+    uint32_t res = cmpxchg(new_value, aligned_dest, cur, order);
+    if (res == cur) break;      // success
 
-    // at least one jbyte in the jint changed value, so update
-    // our view of the current jint
+    // at least one byte in the int changed value, so update
+    // our view of the current int
     cur = res;
-    // if our jbyte is still as cur we loop and try again
-  } while (cur_as_bytes[offset] == compare_value);
+    // if our byte is still as cur we loop and try again
+  } while (cur_as_bytes[offset] == canon_compare_value);
 
-  return cur_as_bytes[offset];
+  return PrimitiveConversions::cast<T>(cur_as_bytes[offset]);
 }
 
-#endif // VM_HAS_SPECIALIZED_CMPXCHG_BYTE
-
 inline unsigned Atomic::xchg(unsigned int exchange_value, volatile unsigned int* dest) {
   assert(sizeof(unsigned int) == sizeof(jint), "more work to do");
   return (unsigned int)Atomic::xchg((jint)exchange_value, (volatile jint*)dest);
 }
 
-inline unsigned Atomic::cmpxchg(unsigned int exchange_value,
-                         volatile unsigned int* dest, unsigned int compare_value,
-                         cmpxchg_memory_order order) {
-  assert(sizeof(unsigned int) == sizeof(jint), "more work to do");
-  return (unsigned int)Atomic::cmpxchg((jint)exchange_value, (volatile jint*)dest,
-                                       (jint)compare_value, order);
-}
-
 inline jshort Atomic::add(jshort add_value, volatile jshort* dest) {
   // Most platforms do not support atomic add on a 2-byte value. However,
   // if the value occupies the most significant 16 bits of an aligned 32-bit
--- a/hotspot/src/share/vm/runtime/deoptimization.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/runtime/deoptimization.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -217,7 +217,7 @@
         // Reallocation may trigger GC. If deoptimization happened on return from
         // call which returns oop we need to save it since it is not in oopmap.
         oop result = deoptee.saved_oop_result(&map);
-        assert(result == NULL || result->is_oop(), "must be oop");
+        assert(oopDesc::is_oop_or_null(result), "must be oop");
         return_value = Handle(thread, result);
         assert(Universe::heap()->is_in_or_null(result), "must be heap pointer");
         if (TraceDeoptimization) {
--- a/hotspot/src/share/vm/runtime/handles.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/runtime/handles.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -34,7 +34,7 @@
 oop* HandleArea::allocate_handle(oop obj) {
   assert(_handle_mark_nesting > 1, "memory leak: allocating handle outside HandleMark");
   assert(_no_handle_mark_nesting == 0, "allocating handle inside NoHandleMark");
-  assert(obj->is_oop(), "not an oop: " INTPTR_FORMAT, p2i(obj));
+  assert(oopDesc::is_oop(obj), "not an oop: " INTPTR_FORMAT, p2i(obj));
   return real_allocate_handle(obj);
 }
 #endif
@@ -99,7 +99,7 @@
   while (bottom < top) {
     // This test can be moved up but for now check every oop.
 
-    assert((*bottom)->is_oop(), "handle should point to oop");
+    assert(oopDesc::is_oop(*bottom), "handle should point to oop");
 
     f->do_oop(bottom++);
   }
--- a/hotspot/src/share/vm/runtime/javaCalls.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/runtime/javaCalls.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -567,7 +567,7 @@
                 "Bad JNI oop argument %d: " PTR_FORMAT, _pos, v);
       // Verify the pointee.
       oop vv = resolve_indirect_oop(v, _value_state[_pos]);
-      guarantee(vv->is_oop_or_null(true),
+      guarantee(oopDesc::is_oop_or_null(vv, true),
                 "Bad JNI oop argument %d: " PTR_FORMAT " -> " PTR_FORMAT,
                 _pos, v, p2i(vv));
     }
--- a/hotspot/src/share/vm/runtime/os.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/runtime/os.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -755,9 +755,9 @@
   // Make updating the random seed thread safe.
   while (true) {
     unsigned int seed = _rand_seed;
-    int rand = random_helper(seed);
+    unsigned int rand = random_helper(seed);
     if (Atomic::cmpxchg(rand, &_rand_seed, seed) == seed) {
-      return rand;
+      return static_cast<int>(rand);
     }
   }
 }
@@ -988,7 +988,7 @@
     // See if we were just given an oop directly
     if (p != NULL && Universe::heap()->block_is_obj(p)) {
       print = true;
-    } else if (p == NULL && ((oopDesc*)addr)->is_oop()) {
+    } else if (p == NULL && oopDesc::is_oop(oop(addr))) {
       p = (HeapWord*) addr;
       print = true;
     }
--- a/hotspot/src/share/vm/runtime/safepoint.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/runtime/safepoint.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1104,7 +1104,7 @@
       // the other registers. In order to preserve it over GCs we need
       // to keep it in a handle.
       oop result = caller_fr.saved_oop_result(&map);
-      assert(result == NULL || result->is_oop(), "must be oop");
+      assert(oopDesc::is_oop_or_null(result), "must be oop");
       return_value = Handle(thread(), result);
       assert(Universe::heap()->is_in_or_null(result), "must be heap pointer");
     }
--- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -209,7 +209,7 @@
     assert(false, "should be optimized out");
     return;
   }
-  assert(orig->is_oop(true /* ignore mark word */), "Error");
+  assert(oopDesc::is_oop(orig, true /* ignore mark word */), "Error");
   // store the original value that was in the field reference
   thread->satb_mark_queue().enqueue(orig);
 JRT_END
@@ -585,7 +585,7 @@
   int args_size = ArgumentSizeComputer(sig).size() + 1;
   assert(args_size <= caller.interpreter_frame_expression_stack_size(), "receiver must be on interpreter stack");
   oop result = cast_to_oop(*caller.interpreter_frame_tos_at(args_size - 1));
-  assert(Universe::heap()->is_in(result) && result->is_oop(), "receiver must be an oop");
+  assert(Universe::heap()->is_in(result) && oopDesc::is_oop(result), "receiver must be an oop");
   return result;
 }
 
@@ -997,7 +997,7 @@
     return;
   }
 #endif // INCLUDE_JVMCI
-  assert(obj->is_oop(), "must be a valid oop");
+  assert(oopDesc::is_oop(obj), "must be a valid oop");
   assert(obj->klass()->has_finalizer(), "shouldn't be here otherwise");
   InstanceKlass::register_finalizer(instanceOop(obj), CHECK);
 JRT_END
@@ -1165,8 +1165,6 @@
     }
   }
 
-  assert(receiver.is_null() || receiver->is_oop(), "wrong receiver");
-
   // Resolve method
   if (attached_method.not_null()) {
     // Parameterized by attached method.
--- a/hotspot/src/share/vm/runtime/thread.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/runtime/thread.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -2514,6 +2514,9 @@
   address low_addr = stack_end();
   size_t len = stack_guard_zone_size();
 
+  assert(is_aligned(low_addr, os::vm_page_size()), "Stack base should be the start of a page");
+  assert(is_aligned(len, os::vm_page_size()), "Stack size should be a multiple of page size");
+
   int must_commit = os::must_commit_stack_guard_pages();
   // warning("Guarding at " PTR_FORMAT " for len " SIZE_FORMAT "\n", low_addr, len);
 
@@ -3187,7 +3190,7 @@
     oop obj = oopDesc::load_decode_heap_oop(p);
     if (obj == NULL) return;
     tty->print(INTPTR_FORMAT ": ", p2i(p));
-    if (obj->is_oop_or_null()) {
+    if (oopDesc::is_oop_or_null(obj)) {
       if (obj->is_objArray()) {
         tty->print_cr("valid objArray: " INTPTR_FORMAT, p2i(obj));
       } else {
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -83,6 +83,7 @@
 #include "oops/objArrayKlass.hpp"
 #include "oops/objArrayOop.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/oopHandle.hpp"
 #include "oops/symbol.hpp"
 #include "oops/typeArrayKlass.hpp"
 #include "oops/typeArrayOop.hpp"
@@ -235,7 +236,7 @@
   nonstatic_field(ConstantPool,                _operands,                                     Array<u2>*)                            \
   nonstatic_field(ConstantPool,                _resolved_klasses,                             Array<Klass*>*)                        \
   nonstatic_field(ConstantPool,                _length,                                       int)                                   \
-  nonstatic_field(ConstantPoolCache,           _resolved_references,                          jobject)                               \
+  nonstatic_field(ConstantPoolCache,           _resolved_references,                          OopHandle)                             \
   nonstatic_field(ConstantPoolCache,           _reference_map,                                Array<u2>*)                            \
   nonstatic_field(ConstantPoolCache,           _length,                                       int)                                   \
   nonstatic_field(ConstantPoolCache,           _constant_pool,                                ConstantPool*)                         \
@@ -1438,6 +1439,7 @@
   declare_oop_type(oop)                                                   \
   declare_oop_type(narrowOop)                                             \
   declare_oop_type(typeArrayOop)                                          \
+  declare_oop_type(OopHandle)                                             \
                                                                           \
   /*************************************/                                 \
   /* MethodOop-related data structures */                                 \
--- a/hotspot/src/share/vm/runtime/vmStructs.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/runtime/vmStructs.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 #define SHARE_VM_RUNTIME_VMSTRUCTS_HPP
 
 #include "utilities/debug.hpp"
+#include "utilities/globalDefinitions.hpp"
 #ifdef COMPILER1
 #include "c1/c1_Runtime1.hpp"
 #endif
--- a/hotspot/src/share/vm/services/heapDumper.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/services/heapDumper.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -764,7 +764,7 @@
 
       // reflection and Unsafe classes may have a reference to a
       // Klass* so filter it out.
-      assert(o->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(o));
+      assert(oopDesc::is_oop_or_null(o), "Expected an oop or NULL at " PTR_FORMAT, p2i(o));
       writer->write_objectID(o);
       break;
     }
--- a/hotspot/src/share/vm/shark/sharkRuntime.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/shark/sharkRuntime.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -136,7 +136,7 @@
 
 JRT_ENTRY(void, SharkRuntime::register_finalizer(JavaThread* thread,
                                                  oop         object))
-  assert(object->is_oop(), "should be");
+  assert(oopDesc::is_oop(object), "should be");
   assert(object->klass()->has_finalizer(), "should have");
   InstanceKlass::register_finalizer(instanceOop(object), CHECK);
 JRT_END
--- a/hotspot/src/share/vm/utilities/bitMap.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/utilities/bitMap.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -210,12 +210,12 @@
   // With a valid range (beg <= end), this test ensures that end != 0, as
   // required by inverted_bit_mask_for_range.  Also avoids an unnecessary write.
   if (beg != end) {
-    intptr_t* pw  = (intptr_t*)word_addr(beg);
-    intptr_t  w   = *pw;
-    intptr_t  mr  = (intptr_t)inverted_bit_mask_for_range(beg, end);
-    intptr_t  nw  = value ? (w | ~mr) : (w & mr);
+    bm_word_t* pw = word_addr(beg);
+    bm_word_t  w  = *pw;
+    bm_word_t  mr = inverted_bit_mask_for_range(beg, end);
+    bm_word_t  nw = value ? (w | ~mr) : (w & mr);
     while (true) {
-      intptr_t res = Atomic::cmpxchg_ptr(nw, pw, w);
+      bm_word_t res = Atomic::cmpxchg(nw, pw, w);
       if (res == w) break;
       w  = res;
       nw = value ? (w | ~mr) : (w & mr);
@@ -617,7 +617,7 @@
   return true;
 }
 
-BitMap::idx_t* BitMap::_pop_count_table = NULL;
+const BitMap::idx_t* BitMap::_pop_count_table = NULL;
 
 void BitMap::init_pop_count_table() {
   if (_pop_count_table == NULL) {
@@ -626,11 +626,8 @@
       table[i] = num_set_bits(i);
     }
 
-    intptr_t res = Atomic::cmpxchg_ptr((intptr_t)  table,
-                                       (intptr_t*) &_pop_count_table,
-                                       (intptr_t)  NULL_WORD);
-    if (res != NULL_WORD) {
-      guarantee( _pop_count_table == (void*) res, "invariant" );
+    if (!Atomic::replace_if_null(table, &_pop_count_table)) {
+      guarantee(_pop_count_table != NULL, "invariant");
       FREE_C_HEAP_ARRAY(idx_t, table);
     }
   }
--- a/hotspot/src/share/vm/utilities/bitMap.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/utilities/bitMap.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -114,7 +114,7 @@
   void verify_range(idx_t beg_index, idx_t end_index) const NOT_DEBUG_RETURN;
 
   // Statistics.
-  static idx_t* _pop_count_table;
+  static const idx_t* _pop_count_table;
   static void init_pop_count_table();
   static idx_t num_set_bits(bm_word_t w);
   static idx_t num_set_bits_from_table(unsigned char c);
--- a/hotspot/src/share/vm/utilities/bitMap.inline.hpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/utilities/bitMap.inline.hpp	Thu Aug 24 21:06:33 2017 +0000
@@ -49,9 +49,7 @@
     if (new_val == old_val) {
       return false;     // Someone else beat us to it.
     }
-    const bm_word_t cur_val = (bm_word_t) Atomic::cmpxchg_ptr((void*) new_val,
-                                                      (volatile void*) addr,
-                                                      (void*) old_val);
+    const bm_word_t cur_val = Atomic::cmpxchg(new_val, addr, old_val);
     if (cur_val == old_val) {
       return true;      // Success.
     }
@@ -70,9 +68,7 @@
     if (new_val == old_val) {
       return false;     // Someone else beat us to it.
     }
-    const bm_word_t cur_val = (bm_word_t) Atomic::cmpxchg_ptr((void*) new_val,
-                                                      (volatile void*) addr,
-                                                      (void*) old_val);
+    const bm_word_t cur_val = Atomic::cmpxchg(new_val, addr, old_val);
     if (cur_val == old_val) {
       return true;      // Success.
     }
--- a/hotspot/src/share/vm/utilities/exceptions.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/src/share/vm/utilities/exceptions.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -47,7 +47,7 @@
 
 
 void ThreadShadow::set_pending_exception(oop exception, const char* file, int line) {
-  assert(exception != NULL && exception->is_oop(), "invalid exception oop");
+  assert(exception != NULL && oopDesc::is_oop(exception), "invalid exception oop");
   _pending_exception = exception;
   _exception_file    = file;
   _exception_line    = line;
--- a/hotspot/test/ProblemList.txt	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/ProblemList.txt	Thu Aug 24 21:06:33 2017 +0000
@@ -54,68 +54,6 @@
 # aot test intermittently failing in jprt 8175791
 compiler/aot/DeoptimizationTest.java 8175791 windows-all
 
-# aot missing tools (linker) on OS-X and Windows 8183337
-compiler/aot/calls/fromAot/AotInvokeDynamic2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeDynamic2CompiledTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeDynamic2InterpretedTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeDynamic2NativeTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeInterface2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeInterface2CompiledTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeInterface2InterpretedTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeInterface2NativeTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeSpecial2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeSpecial2CompiledTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeSpecial2InterpretedTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeSpecial2NativeTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeStatic2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeStatic2CompiledTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeStatic2InterpretedTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeStatic2NativeTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeVirtual2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeVirtual2CompiledTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeVirtual2InterpretedTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromAot/AotInvokeVirtual2NativeTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromCompiled/CompiledInvokeDynamic2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromCompiled/CompiledInvokeInterface2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromCompiled/CompiledInvokeSpecial2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromCompiled/CompiledInvokeStatic2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromCompiled/CompiledInvokeVirtual2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromInterpreted/InterpretedInvokeDynamic2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromInterpreted/InterpretedInvokeInterface2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromInterpreted/InterpretedInvokeSpecial2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromInterpreted/InterpretedInvokeStatic2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromInterpreted/InterpretedInvokeVirtual2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromNative/NativeInvokeSpecial2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromNative/NativeInvokeStatic2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/calls/fromNative/NativeInvokeVirtual2AotTest.java 8183337 windows-all,macosx-all
-compiler/aot/cli/DisabledAOTWithLibraryTest.java 8183337 windows-all,macosx-all
-compiler/aot/cli/IncorrectAOTLibraryTest.java 8183337 windows-all,macosx-all
-compiler/aot/cli/jaotc/ClasspathOptionUnknownClassTest.java 8183337 windows-all,macosx-all
-compiler/aot/cli/jaotc/CompileClassTest.java 8183337 windows-all,macosx-all
-compiler/aot/cli/jaotc/CompileDirectoryTest.java 8183337 windows-all,macosx-all
-compiler/aot/cli/jaotc/CompileJarTest.java 8183337 windows-all,macosx-all
-compiler/aot/cli/jaotc/CompileModuleTest.java 8183337 windows-all,macosx-all
-compiler/aot/cli/jaotc/ListOptionNotExistingTest.java 8183337 windows-all,macosx-all
-compiler/aot/cli/jaotc/ListOptionTest.java 8183337 windows-all,macosx-all
-compiler/aot/cli/jaotc/ListOptionWrongFileTest.java 8183337 windows-all,macosx-all
-compiler/aot/cli/MultipleAOTLibraryTest.java 8183337 windows-all,macosx-all
-compiler/aot/cli/NonExistingAOTLibraryTest.java 8183337 windows-all,macosx-all
-compiler/aot/cli/SingleAOTLibraryTest.java 8183337 windows-all,macosx-all
-compiler/aot/cli/SingleAOTOptionTest.java 8183337 windows-all,macosx-all
-compiler/aot/DeoptimizationTest.java 8183337 windows-all,macosx-all
-compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java 8183337 windows-all,macosx-all
-compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java 8183337 windows-all,macosx-all
-compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java 8183337 windows-all,macosx-all
-compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java 8183337 windows-all,macosx-all
-compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java 8183337 windows-all,macosx-all
-compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java 8183337 windows-all,macosx-all
-compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/NativeOrderOutputStreamTest.java 8183337 windows-all,macosx-all
-compiler/aot/RecompilationTest.java 8183337 windows-all,macosx-all
-compiler/aot/SharedUsageTest.java 8183337 windows-all,macosx-all
-compiler/aot/verification/ClassAndLibraryNotMatchTest.java 8183337 windows-all,macosx-all
-compiler/aot/verification/vmflags/NotTrackedFlagTest.java 8183337 windows-all,macosx-all
-compiler/aot/verification/vmflags/TrackedFlagTest.java 8183337 windows-all,macosx-all
-
 #############################################################################
 
 # :hotspot_gc
@@ -148,7 +86,7 @@
 serviceability/sa/TestInstanceKlassSizeForInterface.java 8184042 macosx-all
 serviceability/sa/TestPrintMdo.java 8184042 macosx-all
 serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java 8184042 macosx-all
-
+serviceability/dcmd/jvmti/LoadAgentDcmdTest.java 8186540 windows-all
 #############################################################################
 
 # :hotspot_misc
--- a/hotspot/test/TEST.ROOT	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/TEST.ROOT	Thu Aug 24 21:06:33 2017 +0000
@@ -54,8 +54,8 @@
     vm.aot \
     vm.cds
 
-# Tests using jtreg 4.2 b07 features
-requiredVersion=4.2 b07
+# Minimum jtreg version
+requiredVersion=4.2 b08
 
 # Path to libraries in the topmost test directory. This is needed so @library
 # does not need ../../ notation to reach them
--- a/hotspot/test/compiler/aot/AotCompiler.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/AotCompiler.java	Thu Aug 24 21:06:33 2017 +0000
@@ -23,9 +23,14 @@
 
 package compiler.aot;
 
+import jdk.test.lib.Platform;
+import jdk.test.lib.artifacts.Artifact;
+import jdk.test.lib.artifacts.ArtifactResolver;
 import jdk.test.lib.process.OutputAnalyzer;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.lang.annotation.Annotation;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -35,6 +40,7 @@
 import java.util.List;
 import jdk.test.lib.JDKToolLauncher;
 import jdk.test.lib.Utils;
+import jdk.test.lib.process.ProcessTools;
 
 /**
  * A simple class calling AOT compiler over requested items
@@ -102,6 +108,11 @@
         }
         args.add("--class-name");
         args.add(item);
+        String linker = resolveLinker();
+        if (linker != null) {
+            args.add("--linker-path");
+            args.add(linker);
+        }
         return launchJaotc(args, extraopts);
     }
 
@@ -119,8 +130,8 @@
             launcher.addToolArg(arg);
         }
         try {
-            return new OutputAnalyzer(new ProcessBuilder(launcher.getCommand()).inheritIO().start());
-        } catch (IOException e) {
+            return ProcessTools.executeCommand(new ProcessBuilder(launcher.getCommand()).redirectErrorStream(true));
+        } catch (Throwable e) {
             throw new Error("Can't start test process: " + e, e);
         }
     }
@@ -130,4 +141,142 @@
                 + " -class <class> -libname <.so name>"
                 + " [-compile <compileItems>]* [-extraopt <java option>]*");
     }
+
+    public static String resolveLinker() {
+        Path linker = null;
+        // 1st, check if PATH has ld
+        for (String path : System.getenv("PATH").split(File.pathSeparator)) {
+            if (Files.exists(Paths.get(path).resolve("ld"))) {
+                // there is ld in PATH, jaotc is supposed to find it by its own
+                return null;
+            }
+        }
+        // there is no ld in PATH, will use ld from devkit
+        // artifacts are got from common/conf/jib-profiles.js
+        try {
+            if (Platform.isWindows()) {
+                if (Platform.isX64()) {
+                    @Artifact(organization = "jpg.infra.builddeps",
+                            name = "devkit-windows_x64",
+                            revision = "VS2013SP4+1.0",
+                            extension = "tar.gz")
+                    class DevkitWindowsX64 { }
+                    String artifactName = "jpg.infra.builddeps."
+                            + "devkit-windows_x64-"
+                            + "VS2013SP4+1.0";
+                    Path devkit = ArtifactResolver.resolve(DevkitWindowsX64.class)
+                                                  .get(artifactName);
+                    linker = devkit.resolve("VC")
+                                   .resolve("bin")
+                                   .resolve("amd64")
+                                   .resolve("link.exe");
+                }
+            } else if (Platform.isOSX()) {
+                @Artifact(organization =  "jpg.infra.builddeps",
+                        name = "devkit-macosx_x64",
+                        revision = "Xcode6.3-MacOSX10.9+1.0",
+                        extension = "tar.gz")
+                class DevkitMacosx { }
+                String artifactName = "jpg.infra.builddeps."
+                        + "devkit-macosx_x64-"
+                        + "Xcode6.3-MacOSX10.9+1.0";
+                Path devkit = ArtifactResolver.resolve(DevkitMacosx.class)
+                                              .get(artifactName);
+                linker = devkit.resolve("Xcode.app")
+                               .resolve("Contents")
+                               .resolve("Developer")
+                               .resolve("Toolchains")
+                               .resolve("XcodeDefault.xctoolchain")
+                               .resolve("usr")
+                               .resolve("bin")
+                               .resolve("ld");
+            } else if (Platform.isSolaris()) {
+                if (Platform.isSparc()) {
+                    @Artifact(organization =  "jpg.infra.builddeps",
+                            name = "devkit-solaris_sparcv9",
+                            revision = "SS12u4-Solaris11u1+1.0",
+                            extension = "tar.gz")
+                    class DevkitSolarisSparc { }
+
+                    String artifactName = "jpg.infra.builddeps."
+                            + "devkit-solaris_sparcv9-"
+                            + "SS12u4-Solaris11u1+1.0";
+                    Path devkit = ArtifactResolver.resolve(DevkitSolarisSparc.class)
+                                                  .get(artifactName);
+                    linker = devkit.resolve("SS12u4-Solaris11u1")
+                                   .resolve("gnu")
+                                   .resolve("bin")
+                                   .resolve("ld");
+                } else if (Platform.isX64()) {
+                    @Artifact(organization =  "jpg.infra.builddeps",
+                            name = "devkit-solaris_x64",
+                            revision = "SS12u4-Solaris11u1+1.0",
+                            extension = "tar.gz")
+                    class DevkitSolarisX64 { }
+
+                    String artifactName = "jpg.infra.builddeps."
+                            + "devkit-solaris_x64-"
+                            + "SS12u4-Solaris11u1+1.0";
+                    Path devkit = ArtifactResolver.resolve(DevkitSolarisX64.class)
+                                                  .get(artifactName);
+                    linker = devkit.resolve("SS12u4-Solaris11u1")
+                                   .resolve("bin")
+                                   .resolve("amd64")
+                                   .resolve("ld");
+                }
+            } else if (Platform.isLinux()) {
+                if (Platform.isAArch64()) {
+                    @Artifact(organization = "jpg.infra.builddeps",
+                            name = "devkit-linux_aarch64",
+                            revision = "gcc-linaro-aarch64-linux-gnu-4.8-2013.11_linux+1.0",
+                            extension = "tar.gz")
+                    class DevkitLinuxAArch64 { }
+
+                    String artifactName = "jpg.infra.builddeps."
+                            + "devkit-linux_aarch64-"
+                            + "gcc-linaro-aarch64-linux-gnu-4.8-2013.11_linux+1.0";
+                    Path devkit = ArtifactResolver.resolve(DevkitLinuxAArch64.class)
+                                                  .get(artifactName);
+                    linker = devkit.resolve("aarch64-linux-gnu")
+                                   .resolve("bin")
+                                   .resolve("ld");
+                } else if (Platform.isARM()) {
+                    @Artifact(organization = "jpg.infra.builddeps",
+                            name = "devkit-linux_arm",
+                            revision = "gcc-linaro-arm-linux-gnueabihf-raspbian-2012.09-20120921_linux+1.0",
+                            extension = "tar.gz")
+                    class DevkitLinuxARM { }
+
+                    String artifactName = "jpg.infra.builddeps."
+                            + "devkit-linux_arm-"
+                            + "gcc-linaro-arm-linux-gnueabihf-raspbian-2012.09-20120921_linux+1.0";
+                    Path devkit = ArtifactResolver.resolve(DevkitLinuxARM.class)
+                                                  .get(artifactName);
+                    linker = devkit.resolve("arm-linux-gnueabihf")
+                                   .resolve("bin")
+                                   .resolve("ld");
+                } else if (Platform.isX64()) {
+                    @Artifact(organization = "jpg.infra.builddeps",
+                            name = "devkit-linux_x64",
+                            revision = "gcc4.9.2-OEL6.4+1.1",
+                            extension = "tar.gz")
+                    class DevkitLinuxX64 { }
+
+                    String artifactName = "jpg.infra.builddeps."
+                            + "devkit-linux_x64-"
+                            + "gcc4.9.2-OEL6.4+1.1";
+                    Path devkit = ArtifactResolver.resolve(DevkitLinuxX64.class)
+                                                  .get(artifactName);
+                    linker = devkit.resolve("bin")
+                                   .resolve("ld");
+                }
+            }
+        } catch (FileNotFoundException e) {
+            throw new Error("artifact resolution error: " + e, e);
+        }
+        if (linker != null) {
+            return linker.toAbsolutePath().toString();
+        }
+        return null;
+    }
 }
--- a/hotspot/test/compiler/aot/DeoptimizationTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/DeoptimizationTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.aot.DeoptimizationTest
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/RecompilationTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/RecompilationTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.aot.RecompilationTest
  *        compiler.aot.AotCompiler
@@ -38,7 +37,7 @@
  *     -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:.
  *     -extraopt -XX:-UseCompressedOops
  *     -extraopt -XX:CompileCommand=dontinline,compiler.whitebox.SimpleTestCaseHelper::*
- * @run main/othervm -Xmixed -Xbatch -XX:+UseAOT -XX:+TieredCompilation
+ * @run main/othervm -Xmixed -Xbatch -XX:+UseAOT -XX:+TieredCompilation -XX:CompilationPolicyChoice=2
  *     -XX:-UseCounterDecay -XX:-UseCompressedOops
  *     -XX:-Inline
  *     -XX:AOTLibrary=./libRecompilationTest1.so -Xbootclasspath/a:.
@@ -51,7 +50,7 @@
  *     -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:.
  *     -extraopt -XX:-UseCompressedOops
  *     -extraopt -XX:CompileCommand=dontinline,compiler.whitebox.SimpleTestCaseHelper::*
- * @run main/othervm -Xmixed -Xbatch -XX:+UseAOT -XX:+TieredCompilation
+ * @run main/othervm -Xmixed -Xbatch -XX:+UseAOT -XX:+TieredCompilation -XX:CompilationPolicyChoice=2
  *     -XX:-UseCounterDecay -XX:-UseCompressedOops
  *     -XX:-Inline
  *     -XX:AOTLibrary=./libRecompilationTest2.so -Xbootclasspath/a:.
--- a/hotspot/test/compiler/aot/SharedUsageTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/SharedUsageTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library /test/lib /testlibrary /
  * @modules java.base/jdk.internal.misc
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @build compiler.aot.SharedUsageTest
  *        compiler.aot.AotCompiler
  * @run main compiler.aot.AotCompiler -libname libSharedUsageTest.so
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/aot/TEST.properties	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,3 @@
+# TODO: remove as soon as JIB supports concurrent installations
+exclusiveAccess.dirs=.
+
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library /test/lib /testlibrary /
  * @ignore 8132547
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.org.objectweb.asm
  *          java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeDynamic
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2CompiledTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2CompiledTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library /test/lib /testlibrary /
  * @ignore 8132547
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.org.objectweb.asm
  *          java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeDynamic
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2InterpretedTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2InterpretedTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library /test/lib /testlibrary /
  * @ignore 8132547
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.org.objectweb.asm
  *          java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeDynamic
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2NativeTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeDynamic2NativeTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library /test/lib /testlibrary /
  * @ignore 8132547
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.org.objectweb.asm
  *          java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeDynamic
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeInterface
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2CompiledTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2CompiledTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeInterface
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2InterpretedTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2InterpretedTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeInterface
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2NativeTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeInterface2NativeTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeInterface
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeSpecial
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2CompiledTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2CompiledTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeSpecial
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2InterpretedTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2InterpretedTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeSpecial
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2NativeTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeSpecial2NativeTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeSpecial
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeStatic
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2CompiledTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2CompiledTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeStatic
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2InterpretedTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2InterpretedTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeStatic
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2NativeTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeStatic2NativeTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeStatic
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeVirtual
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2CompiledTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2CompiledTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeVirtual
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2InterpretedTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2InterpretedTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeVirtual
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2NativeTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromAot/AotInvokeVirtual2NativeTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeVirtual
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeDynamic2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeDynamic2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.org.objectweb.asm
  *          java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeDynamic
--- a/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeInterface2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeInterface2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeInterface
  *      compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeSpecial2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeSpecial2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeSpecial
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeStatic2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeStatic2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeStatic
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeVirtual2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromCompiled/CompiledInvokeVirtual2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeVirtual
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeDynamic2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeDynamic2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.org.objectweb.asm
  *          java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeDynamic
--- a/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeInterface2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeInterface2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeInterface
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeSpecial2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeSpecial2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeSpecial
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeStatic2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeStatic2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeStatic
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeVirtual2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromInterpreted/InterpretedInvokeVirtual2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeVirtual
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromNative/NativeInvokeSpecial2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromNative/NativeInvokeSpecial2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeSpecial
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromNative/NativeInvokeStatic2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromNative/NativeInvokeStatic2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeStatic
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/calls/fromNative/NativeInvokeVirtual2AotTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/calls/fromNative/NativeInvokeVirtual2AotTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.calls.common.InvokeVirtual
  *        compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/cli/DisabledAOTWithLibraryTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/cli/DisabledAOTWithLibraryTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /testlibrary /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @build compiler.aot.cli.DisabledAOTWithLibraryTest
  *        compiler.aot.AotCompiler
  * @run driver compiler.aot.AotCompiler -libname libDisabledAOTWithLibraryTest.so
--- a/hotspot/test/compiler/aot/cli/IncorrectAOTLibraryTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/cli/IncorrectAOTLibraryTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library /test/lib /testlibrary /
  * @modules java.base/jdk.internal.misc
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @run driver ClassFileInstaller ClassFileInstaller
  * @run driver compiler.aot.cli.IncorrectAOTLibraryTest
  * @summary check if incorrect aot library is handled properly
--- a/hotspot/test/compiler/aot/cli/MultipleAOTLibraryTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/cli/MultipleAOTLibraryTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library /test/lib /testlibrary /
  * @modules java.base/jdk.internal.misc
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @build compiler.aot.cli.MultipleAOTLibraryTest
  *        compiler.aot.AotCompiler
  * @run driver compiler.aot.AotCompiler
--- a/hotspot/test/compiler/aot/cli/NonExistingAOTLibraryTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/cli/NonExistingAOTLibraryTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library /test/lib /testlibrary /
  * @modules java.base/jdk.internal.misc
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @run driver compiler.aot.cli.NonExistingAOTLibraryTest
  * @summary check if non-existing aot library is handled properly
  */
--- a/hotspot/test/compiler/aot/cli/SingleAOTLibraryTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/cli/SingleAOTLibraryTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library /test/lib / /testlibrary
  * @modules java.base/jdk.internal.misc
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @build compiler.aot.cli.SingleAOTLibraryTest
  *        compiler.aot.AotCompiler
  * @run driver compiler.aot.AotCompiler -libname libSingleAOTLibraryTest.so
--- a/hotspot/test/compiler/aot/cli/SingleAOTOptionTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/cli/SingleAOTOptionTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library /test/lib /testlibrary /
  * @modules java.base/jdk.internal.misc
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @build compiler.aot.cli.SingleAOTOptionTest
  *        compiler.aot.AotCompiler
  * @run driver compiler.aot.AotCompiler -libname libSingleAOTOptionTest.so
--- a/hotspot/test/compiler/aot/cli/jaotc/ClasspathOptionUnknownClassTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/cli/jaotc/ClasspathOptionUnknownClassTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library / /testlibrary/ /test/lib
  * @modules java.base/jdk.internal.misc
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @compile data/HelloWorldOne.java
  * @run driver compiler.aot.cli.jaotc.ClasspathOptionUnknownClassTest
  * @summary check jaotc can't compile class not from classpath
--- a/hotspot/test/compiler/aot/cli/jaotc/CompileClassTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/cli/jaotc/CompileClassTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library / /test/lib /testlibrary
  * @modules java.base/jdk.internal.misc
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @build compiler.aot.cli.jaotc.CompileClassTest
  * @run driver ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
  * @run driver compiler.aot.cli.jaotc.CompileClassTest
--- a/hotspot/test/compiler/aot/cli/jaotc/CompileDirectoryTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/cli/jaotc/CompileDirectoryTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library / /test/lib /testlibrary
  * @modules java.base/jdk.internal.misc
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @build compiler.aot.cli.jaotc.CompileDirectoryTest
  * @run driver ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
  *                                compiler.aot.cli.jaotc.data.HelloWorldTwo
--- a/hotspot/test/compiler/aot/cli/jaotc/CompileJarTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/cli/jaotc/CompileJarTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library / /test/lib /testlibrary
  * @modules java.base/jdk.internal.misc
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @build compiler.aot.cli.jaotc.CompileJarTest
  * @run driver ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
  *                                compiler.aot.cli.jaotc.data.HelloWorldTwo
--- a/hotspot/test/compiler/aot/cli/jaotc/CompileModuleTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/cli/jaotc/CompileModuleTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library / /test/lib /testlibrary
  * @modules java.base/jdk.internal.misc
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @run driver compiler.aot.cli.jaotc.CompileModuleTest
  * @summary check jaotc can compile module
  */
--- a/hotspot/test/compiler/aot/cli/jaotc/JaotcTestHelper.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/cli/jaotc/JaotcTestHelper.java	Thu Aug 24 21:06:33 2017 +0000
@@ -23,14 +23,18 @@
 
 package compiler.aot.cli.jaotc;
 
+import compiler.aot.AotCompiler;
+
 import java.io.File;
 import java.io.IOException;
+
 import jdk.test.lib.process.ExitCode;
 import jdk.test.lib.Platform;
 import jdk.test.lib.JDKToolLauncher;
 import jdk.test.lib.Utils;
 import jdk.test.lib.cli.CommandLineOptionTest;
 import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
 
 public class JaotcTestHelper {
     public static final String DEFAULT_LIB_PATH = "./unnamed." + Platform.sharedLibraryExt();
@@ -49,10 +53,15 @@
         for (String arg : args) {
             launcher.addToolArg(arg);
         }
+        String linker = AotCompiler.resolveLinker();
+        if (linker != null) {
+            launcher.addToolArg("--linker-path");
+            launcher.addToolArg(linker);
+        }
         String[] cmd = launcher.getCommand();
         try {
-            return new OutputAnalyzer(new ProcessBuilder(cmd).start());
-        } catch (IOException e) {
+            return ProcessTools.executeCommand(cmd);
+        } catch (Throwable e) {
             throw new Error("Can't start test process: " + e, e);
         }
     }
--- a/hotspot/test/compiler/aot/cli/jaotc/ListOptionNotExistingTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/cli/jaotc/ListOptionNotExistingTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library / /test/lib /testlibrary
  * @modules java.base/jdk.internal.misc
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @build compiler.aot.cli.jaotc.ListOptionNotExistingTest
  * @run driver ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
  * @run driver compiler.aot.cli.jaotc.ListOptionNotExistingTest
--- a/hotspot/test/compiler/aot/cli/jaotc/ListOptionTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/cli/jaotc/ListOptionTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library / /test/lib /testlibrary
  * @modules java.base/jdk.internal.misc
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @build compiler.aot.cli.jaotc.ListOptionTest
  * @run driver ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
  * @run driver compiler.aot.cli.jaotc.ListOptionTest
--- a/hotspot/test/compiler/aot/cli/jaotc/ListOptionWrongFileTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/cli/jaotc/ListOptionWrongFileTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -26,7 +26,6 @@
  * @requires vm.aot
  * @library / /test/lib /testlibrary
  * @modules java.base/jdk.internal.misc
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @build compiler.aot.cli.jaotc.ListOptionWrongFileTest
  * @run driver ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne
  * @run driver compiler.aot.cli.jaotc.ListOptionWrongFileTest
--- a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/NativeOrderOutputStreamTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/NativeOrderOutputStreamTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -24,7 +24,6 @@
 /**
  * @test
  * @requires vm.aot
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules jdk.aot/jdk.tools.jaotc.utils
  * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.tools.jaotc.test.NativeOrderOutputStreamTest
  */
--- a/hotspot/test/compiler/aot/verification/ClassAndLibraryNotMatchTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/verification/ClassAndLibraryNotMatchTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.aot.verification.ClassAndLibraryNotMatchTest
  * @run driver compiler.aot.verification.ClassAndLibraryNotMatchTest
--- a/hotspot/test/compiler/aot/verification/vmflags/NotTrackedFlagTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/verification/vmflags/NotTrackedFlagTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.aot.verification.vmflags.BasicFlagsChange
  * @run driver compiler.aot.verification.vmflags.BasicFlagsChange
--- a/hotspot/test/compiler/aot/verification/vmflags/TrackedFlagTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/aot/verification/vmflags/TrackedFlagTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -25,7 +25,6 @@
  * @test
  * @requires vm.aot
  * @library /test/lib /
- * @requires vm.bits == "64" & (os.arch == "amd64" | os.arch == "x86_64")
  * @modules java.base/jdk.internal.misc
  * @build compiler.aot.verification.vmflags.BasicFlagsChange
  * @run driver compiler.aot.verification.vmflags.BasicFlagsChange
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/floatingpoint/TestRound.java	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 4755500
+ * @summary calling Math.round(NaN) can break subsequent calls to Math.round()
+ * @run main compiler.floatingpoint.TestRound
+ */
+
+package compiler.floatingpoint;
+
+public class TestRound {
+    public static void main(String[] args) {
+        // Note: it's really only necessary to run this loop 8 times to
+        // reproduce the bug, but the 10000-length loop causes compilation
+        // of Math.round() without any other command-line flags.
+        // A bug in the d2l NaN case was causing overflow of the FPU
+        // stack, yielding subsequent wrong results for flds.
+        for (int i = 0; i < 10_000; i++) {
+            Math.round(Double.NaN);
+        }
+        if (Math.round(1d) != 1) {
+            throw new AssertionError("TEST FAILED");
+        }
+        System.out.println("Test passed.");
+    }
+}
+
--- a/hotspot/test/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java	Thu Aug 24 21:06:33 2017 +0000
@@ -79,8 +79,17 @@
     }
 
     public static HotSpotResolvedObjectType lookupType(String name,
+            Class<?> accessingClass, boolean resolve) throws ClassNotFoundException {
+        return CTVM.lookupType(name, accessingClass, resolve);
+    }
+
+    public static HotSpotResolvedObjectType lookupTypeHelper(String name,
             Class<?> accessingClass, boolean resolve) {
-        return CTVM.lookupType(name, accessingClass, resolve);
+        try {
+            return lookupType(name, accessingClass, resolve);
+        } catch (ClassNotFoundException e) {
+            throw (NoClassDefFoundError) new NoClassDefFoundError().initCause(e);
+        }
     }
 
     public static Object resolveConstantInPool(ConstantPool constantPool, int cpi) {
--- a/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -107,7 +107,7 @@
         HotSpotResolvedJavaMethod testMethod = CTVMUtilities.getResolvedMethod(method);
 
         HotSpotResolvedObjectType resolvedType = CompilerToVMHelper
-                .lookupType(Utils.toJVMTypeSignature(tcase.receiver), getClass(),
+                .lookupTypeHelper(Utils.toJVMTypeSignature(tcase.receiver), getClass(),
                 /* resolve = */ true);
         HotSpotResolvedJavaMethod concreteMethod = CompilerToVMHelper
                 .findUniqueConcreteMethod(resolvedType, testMethod);
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -82,7 +82,7 @@
         System.out.println(tcase);
         String className = tcase.holder.getName();
         HotSpotResolvedObjectType resolvedClazz = CompilerToVMHelper
-                .lookupType(Utils.toJVMTypeSignature(tcase.holder),
+                .lookupTypeHelper(Utils.toJVMTypeSignature(tcase.holder),
                         getClass(), /* resolve = */ true);
         HotSpotResolvedJavaMethod initializer = CompilerToVMHelper
                 .getClassInitializer(resolvedClazz);
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -65,7 +65,7 @@
 
     public static void testClass(Class cls) {
         HotSpotResolvedObjectType type = CompilerToVMHelper
-                .lookupType(Utils.toJVMTypeSignature(cls),
+                .lookupTypeHelper(Utils.toJVMTypeSignature(cls),
                         GetConstantPoolTest.class, /* resolve = */ true);
         test(type);
     }
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -101,13 +101,13 @@
     private void runTest(TestCase tcase) {
         System.out.println(tcase);
         HotSpotResolvedObjectType resolvedIface = CompilerToVMHelper
-                .lookupType(Utils.toJVMTypeSignature(tcase.anInterface),
+                .lookupTypeHelper(Utils.toJVMTypeSignature(tcase.anInterface),
                         getClass(), /* resolve = */ true);
         HotSpotResolvedObjectType resolvedImplementer = CompilerToVMHelper
                 .getImplementor(resolvedIface);
         HotSpotResolvedObjectType resolvedExpected = null;
         if (tcase.expectedImplementer != null) {
-            resolvedExpected = CompilerToVMHelper.lookupType(Utils
+            resolvedExpected = CompilerToVMHelper.lookupTypeHelper(Utils
                     .toJVMTypeSignature(tcase.expectedImplementer),
                     getClass(), /* resolve = */ true);
         }
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -131,7 +131,7 @@
         System.out.println(tcase);
         Method method = tcase.holder.getDeclaredMethod(tcase.methodName);
         HotSpotResolvedObjectType metaspaceKlass = CompilerToVMHelper
-                .lookupType(Utils.toJVMTypeSignature(tcase.receiver),
+                .lookupTypeHelper(Utils.toJVMTypeSignature(tcase.receiver),
                         getClass(), /* resolve = */ true);
         HotSpotResolvedJavaMethod metaspaceMethod = CTVMUtilities
                 .getResolvedMethod(tcase.holder, method);
--- a/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -85,7 +85,7 @@
     private void runTest(TestCase tcase) {
         System.out.println(tcase);
         HotSpotResolvedObjectType metaspaceKlass = CompilerToVMHelper
-                .lookupType(Utils.toJVMTypeSignature(tcase.aClass),
+                .lookupTypeHelper(Utils.toJVMTypeSignature(tcase.aClass),
                         getClass(), /* resolve = */ true);
         Asserts.assertEQ(tcase.expected,
                 CompilerToVMHelper.hasFinalizableSubclass(metaspaceKlass),
--- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java	Thu Aug 24 21:06:33 2017 +0000
@@ -134,13 +134,13 @@
                 .getResolvedMethod(tcase.holder,
                         tcase.holder.getDeclaredMethod(tcase.methodName));
         HotSpotResolvedObjectType holderMetaspace = CompilerToVMHelper
-                .lookupType(Utils.toJVMTypeSignature(tcase.holder),
+                .lookupTypeHelper(Utils.toJVMTypeSignature(tcase.holder),
                         getClass(), /* resolve = */ true);
         HotSpotResolvedObjectType callerMetaspace = CompilerToVMHelper
-                .lookupType(Utils.toJVMTypeSignature(tcase.caller),
+                .lookupTypeHelper(Utils.toJVMTypeSignature(tcase.caller),
                         getClass(), /* resolve = */ true);
         HotSpotResolvedObjectType receiverMetaspace = CompilerToVMHelper
-                .lookupType(Utils.toJVMTypeSignature(tcase.receiver),
+                .lookupTypeHelper(Utils.toJVMTypeSignature(tcase.receiver),
                         getClass(), /* resolve = */ true);
 
         // Can only resolve methods on a linked class so force initialization
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java	Thu Aug 24 21:06:33 2017 +0000
@@ -257,4 +257,15 @@
             assertEquals("Unexpected debugId", metaAccess.decodeDebugId(value), DEBUG_IDS[i]);
         }
     }
+
+    @Test
+    public void parseSignatureTest() {
+        for (String badSig : new String[]{"", "()", "(", "()Vextra", "()E", "(E)", "(Ljava.lang.Object;)V"}) {
+            try {
+                metaAccess.parseMethodDescriptor(badSig);
+                throw new AssertionError("Expected signature to be invalid: " + badSig);
+            } catch (IllegalArgumentException e) {
+            }
+        }
+    }
 }
--- a/hotspot/test/gc/g1/humongousObjects/TestHumongousClassLoader.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/gc/g1/humongousObjects/TestHumongousClassLoader.java	Thu Aug 24 21:06:33 2017 +0000
@@ -40,6 +40,8 @@
  * @requires vm.gc.G1
  * @requires vm.opt.G1HeapRegionSize == "null" | vm.opt.G1HeapRegionSize == "1M"
  * @requires vm.opt.ExplicitGCInvokesConcurrent != true
+ * @requires vm.opt.ClassUnloading  != false
+ * @requires vm.opt.ClassUnloadingWithConcurrentMark  != false
  * @library /test/lib /
  * @modules java.base/jdk.internal.misc
  * @modules java.management
--- a/hotspot/test/gc/logging/TestPrintReferences.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/gc/logging/TestPrintReferences.java	Thu Aug 24 21:06:33 2017 +0000
@@ -23,7 +23,7 @@
 
 /*
  * @test TestPrintReferences
- * @bug 8136991
+ * @bug 8136991 8186402
  * @summary Validate the reference processing logging
  * @key gc
  * @library /test/lib
@@ -42,6 +42,8 @@
     ProcessBuilder pb_enabled = ProcessTools.createJavaProcessBuilder("-Xlog:gc+phases+ref=debug",
                                                                       "-XX:+UseG1GC",
                                                                       "-Xmx10M",
+                                                                      // Explicit thread setting is required to avoid using only 1 thread
+                                                                      "-XX:ParallelGCThreads=2",
                                                                       GCTest.class.getName());
     OutputAnalyzer output = new OutputAnalyzer(pb_enabled.start());
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/metaprogramming/test_isRegisteredEnum.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "memory/allocation.hpp"
+#include "metaprogramming/integralConstant.hpp"
+#include "metaprogramming/isRegisteredEnum.hpp"
+
+#include "unittest.hpp"
+
+struct IsRegisteredEnumTest : AllStatic {
+  enum A { A_x, A_y, A_z };
+  enum B { B_x, B_y, B_z };
+};
+
+typedef IsRegisteredEnumTest::A A;
+typedef IsRegisteredEnumTest::B B;
+
+template<> struct IsRegisteredEnum<A> : public TrueType {};
+
+STATIC_ASSERT(!IsRegisteredEnum<int>::value);
+STATIC_ASSERT(IsRegisteredEnum<A>::value);
+STATIC_ASSERT(!IsRegisteredEnum<B>::value);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/metaprogramming/test_primitiveConversions.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "memory/allocation.hpp"
+#include "metaprogramming/isSame.hpp"
+#include "metaprogramming/primitiveConversions.hpp"
+#include "unittest.hpp"
+#include "utilities/debug.hpp"
+
+struct PrimitiveConversionsTestSupport: AllStatic {
+
+  template<size_t byte_size> struct SignedTypeOfSize;
+  template<size_t byte_size> struct UnsignedTypeOfSize;
+
+  template<typename T> struct Signed;
+  template<typename T> struct Unsigned;
+};
+
+#define DEFINE_CANONICAL_SIGNED_TYPE(T)                                 \
+  template<>                                                            \
+  struct PrimitiveConversionsTestSupport::SignedTypeOfSize<sizeof(T)>   \
+    : public AllStatic                                                  \
+  {                                                                     \
+    typedef T type;                                                     \
+  };
+
+#define DEFINE_CANONICAL_UNSIGNED_TYPE(T)                               \
+  template<>                                                            \
+  struct PrimitiveConversionsTestSupport::UnsignedTypeOfSize<sizeof(T)> \
+    : public AllStatic                                                  \
+  {                                                                     \
+    typedef T type;                                                     \
+  };
+
+#define DEFINE_INTEGER_TYPES_OF_SIZE(NBITS)            \
+  DEFINE_CANONICAL_SIGNED_TYPE(int ## NBITS ## _t)     \
+  DEFINE_CANONICAL_UNSIGNED_TYPE(uint ## NBITS ## _t)
+
+DEFINE_INTEGER_TYPES_OF_SIZE(8)
+DEFINE_INTEGER_TYPES_OF_SIZE(16)
+DEFINE_INTEGER_TYPES_OF_SIZE(32)
+DEFINE_INTEGER_TYPES_OF_SIZE(64)
+
+#undef DEFINE_INTEGER_TYPES_OF_SIZE
+#undef DEFINE_CANONICAL_SIGNED_TYPE
+#undef DEFINE_CANONICAL_UNSIGNED_TYPE
+
+template<typename T>
+struct PrimitiveConversionsTestSupport::Signed
+  : public SignedTypeOfSize<sizeof(T)>
+{};
+
+template<typename T>
+struct PrimitiveConversionsTestSupport::Unsigned
+  : public UnsignedTypeOfSize<sizeof(T)>
+{};
+
+TEST(PrimitiveConversionsTest, round_trip_int) {
+  int  sfive = 5;
+  int  mfive = -5;
+  uint ufive = 5u;
+
+  typedef PrimitiveConversionsTestSupport::Signed<int>::type SI;
+  typedef PrimitiveConversionsTestSupport::Unsigned<int>::type UI;
+
+  EXPECT_EQ(sfive, PrimitiveConversions::cast<int>(PrimitiveConversions::cast<SI>(sfive)));
+  EXPECT_EQ(sfive, PrimitiveConversions::cast<int>(PrimitiveConversions::cast<UI>(sfive)));
+
+  EXPECT_EQ(mfive, PrimitiveConversions::cast<int>(PrimitiveConversions::cast<SI>(mfive)));
+  EXPECT_EQ(mfive, PrimitiveConversions::cast<int>(PrimitiveConversions::cast<UI>(mfive)));
+
+  EXPECT_EQ(ufive, PrimitiveConversions::cast<uint>(PrimitiveConversions::cast<SI>(ufive)));
+  EXPECT_EQ(ufive, PrimitiveConversions::cast<uint>(PrimitiveConversions::cast<UI>(ufive)));
+}
+
+TEST(PrimitiveConversionsTest, round_trip_float) {
+  float  ffive = 5.0f;
+  double dfive = 5.0;
+
+  typedef PrimitiveConversionsTestSupport::Signed<float>::type SF;
+  typedef PrimitiveConversionsTestSupport::Unsigned<float>::type UF;
+
+  typedef PrimitiveConversionsTestSupport::Signed<double>::type SD;
+  typedef PrimitiveConversionsTestSupport::Unsigned<double>::type UD;
+
+  EXPECT_EQ(ffive, PrimitiveConversions::cast<float>(PrimitiveConversions::cast<SF>(ffive)));
+  EXPECT_EQ(ffive, PrimitiveConversions::cast<float>(PrimitiveConversions::cast<UF>(ffive)));
+
+  EXPECT_EQ(dfive, PrimitiveConversions::cast<double>(PrimitiveConversions::cast<SD>(dfive)));
+  EXPECT_EQ(dfive, PrimitiveConversions::cast<double>(PrimitiveConversions::cast<UD>(dfive)));
+}
+
+TEST(PrimitiveConversionsTest, round_trip_ptr) {
+  int five = 5;
+  int* pfive = &five;
+  const int* cpfive = &five;
+
+  typedef PrimitiveConversionsTestSupport::Signed<int*>::type SIP;
+  typedef PrimitiveConversionsTestSupport::Unsigned<int*>::type UIP;
+
+  EXPECT_EQ(pfive, PrimitiveConversions::cast<int*>(PrimitiveConversions::cast<SIP>(pfive)));
+  EXPECT_EQ(pfive, PrimitiveConversions::cast<int*>(PrimitiveConversions::cast<UIP>(pfive)));
+
+  EXPECT_EQ(cpfive, PrimitiveConversions::cast<const int*>(PrimitiveConversions::cast<SIP>(cpfive)));
+  EXPECT_EQ(cpfive, PrimitiveConversions::cast<const int*>(PrimitiveConversions::cast<UIP>(cpfive)));
+}
--- a/hotspot/test/native/runtime/test_vmStructs.cpp	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/native/runtime/test_vmStructs.cpp	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,11 +22,12 @@
  */
 
 #include "precompiled.hpp"
-#include "runtime/vmStructs.hpp"
 #include "utilities/macros.hpp"
 #include "unittest.hpp"
 
 #if INCLUDE_VM_STRUCTS
+#include "runtime/vmStructs.hpp"
+
 TEST(VMStructs, last_entries)  {
   // Make sure last entry in the each array is indeed the correct end marker.
   // The reason why these are static is to make sure they are zero initialized.
--- a/hotspot/test/runtime/Metaspace/FragmentMetaspaceSimple.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/runtime/Metaspace/FragmentMetaspaceSimple.java	Thu Aug 24 21:06:33 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -21,10 +21,12 @@
  * questions.
  */
 
+// ClassFileInstaller is needed to place test.Empty into well-known place
 /**
  * @test
- * @library classes
+ * @library /test/lib classes
  * @build test.Empty
+ * @run driver ClassFileInstaller test.Empty
  * @run main/othervm/timeout=200 FragmentMetaspaceSimple
  */
 
@@ -51,8 +53,8 @@
         long startTime = System.currentTimeMillis();
         ArrayList<ClassLoader> cls = new ArrayList<>();
         char sep = File.separatorChar;
-        String fileName = "classes" + sep + "test" + sep + "Empty.class";
-        File file = new File(System.getProperty("test.classes",".") + sep + fileName);
+        String fileName = "test" + sep + "Empty.class";
+        File file = new File(fileName);
         byte buff[] = read(file);
 
         int i = 0;
--- a/hotspot/test/serviceability/tmtools/jstat/utils/JstatResults.java	Thu Aug 24 14:03:21 2017 -0700
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatResults.java	Thu Aug 24 21:06:33 2017 +0000
@@ -23,6 +23,9 @@
 package utils;
 
 import common.ToolResults;
+import java.text.NumberFormat;
+import java.text.ParseException;
+
 
 /**
  * Results of running the jstat tool Concrete subclasses will detail the jstat
@@ -55,7 +58,13 @@
      */
     public float getFloatValue(String name) {
         int valueNdx = new StringOfValues(getStdoutLine(0)).getIndex(name);
-        return Float.valueOf(new StringOfValues(getStdoutLine(1)).getValue(valueNdx));
+        // Let the parsing use the current locale format.
+        try {
+            return NumberFormat.getInstance().parse(new StringOfValues(getStdoutLine(1)).getValue(valueNdx)).floatValue();
+        } catch (ParseException e) {
+            throw new NumberFormatException(e.getMessage());
+        }
+
     }
 
     /**
@@ -66,7 +75,11 @@
      */
     public int getIntValue(String name) {
         int valueNdx = new StringOfValues(getStdoutLine(0)).getIndex(name);
-        return Integer.valueOf(new StringOfValues(getStdoutLine(1)).getValue(valueNdx));
+        try {
+            return NumberFormat.getInstance().parse(new StringOfValues(getStdoutLine(1)).getValue(valueNdx)).intValue();
+        } catch (ParseException e) {
+            throw new NumberFormatException(e.getMessage());
+        }
     }
 
     /**