changeset 12204:225cedaf9a4b

Merge
author zgu
date Fri, 13 Sep 2013 10:34:15 -0400
parents 1c6b721a3fbf (current diff) 0821b5d72ca8 (diff)
children b89a1a870965 ff8a09595db3
files src/share/vm/classfile/classFileParser.cpp
diffstat 116 files changed, 3346 insertions(+), 708 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Thu Sep 12 15:53:49 2013 +0400
+++ b/.hgtags	Fri Sep 13 10:34:15 2013 -0400
@@ -373,3 +373,5 @@
 c1604d5885a6f2adc0bcea2fa142a8f6bafad2f0 hs25-b47
 acac3bde66b2c22791c257a8d99611d6d08c6713 jdk8-b105
 18b4798adbc42c6fa16f5ecb7d5cd3ca130754bf hs25-b48
+aed585cafc0d9655726af6d1e1081d1c94cb3b5c jdk8-b106
+50794d8ac11c9579b41dec4de23b808fef9f34a1 hs25-b49
--- a/make/hotspot_version	Thu Sep 12 15:53:49 2013 +0400
+++ b/make/hotspot_version	Fri Sep 13 10:34:15 2013 -0400
@@ -35,7 +35,7 @@
 
 HS_MAJOR_VER=25
 HS_MINOR_VER=0
-HS_BUILD_NUMBER=49
+HS_BUILD_NUMBER=50
 
 JDK_MAJOR_VER=1
 JDK_MINOR_VER=8
--- a/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -307,7 +307,7 @@
       assert(a_byte == *start++, "should be the same code");
     }
 #endif
-  } else if (_id == load_mirror_id) {
+  } else if (_id == load_mirror_id || _id == load_appendix_id) {
     // produce a copy of the load mirror instruction for use by the being initialized case
 #ifdef ASSERT
     address start = __ pc();
@@ -384,6 +384,7 @@
     case access_field_id:  target = Runtime1::entry_for(Runtime1::access_field_patching_id); break;
     case load_klass_id:    target = Runtime1::entry_for(Runtime1::load_klass_patching_id); reloc_type = relocInfo::metadata_type; break;
     case load_mirror_id:   target = Runtime1::entry_for(Runtime1::load_mirror_patching_id); reloc_type = relocInfo::oop_type; break;
+    case load_appendix_id: target = Runtime1::entry_for(Runtime1::load_appendix_patching_id); reloc_type = relocInfo::oop_type; break;
     default: ShouldNotReachHere();
   }
   __ bind(call_patch);
@@ -397,7 +398,7 @@
   ce->add_call_info_here(_info);
   __ br(Assembler::always, false, Assembler::pt, _patch_site_entry);
   __ delayed()->nop();
-  if (_id == load_klass_id || _id == load_mirror_id) {
+  if (_id == load_klass_id || _id == load_mirror_id || _id == load_appendix_id) {
     CodeSection* cs = __ code_section();
     address pc = (address)_pc_start;
     RelocIterator iter(cs, pc, pc + 1);
--- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -520,7 +520,7 @@
 void LIR_Assembler::jobject2reg_with_patching(Register reg, CodeEmitInfo *info) {
   // Allocate a new index in table to hold the object once it's been patched
   int oop_index = __ oop_recorder()->allocate_oop_index(NULL);
-  PatchingStub* patch = new PatchingStub(_masm, PatchingStub::load_mirror_id, oop_index);
+  PatchingStub* patch = new PatchingStub(_masm, patching_id(info), oop_index);
 
   AddressLiteral addrlit(NULL, oop_Relocation::spec(oop_index));
   assert(addrlit.rspec().type() == relocInfo::oop_type, "must be an oop reloc");
--- a/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -804,6 +804,12 @@
       }
       break;
 
+    case load_appendix_patching_id:
+      { __ set_info("load_appendix_patching", dont_gc_arguments);
+        oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_appendix_patching));
+      }
+      break;
+
     case dtrace_object_alloc_id:
       { // O0: object
         __ set_info("dtrace_object_alloc", dont_gc_arguments);
--- a/src/cpu/sparc/vm/c2_globals_sparc.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/cpu/sparc/vm/c2_globals_sparc.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -57,6 +57,7 @@
 define_pd_global(bool, UseTLAB,                      true);
 define_pd_global(bool, ResizeTLAB,                   true);
 define_pd_global(intx, LoopUnrollLimit,              60); // Design center runs on 1.3.1
+define_pd_global(intx, MinJumpTableSize,             5);
 
 // Peephole and CISC spilling both break the graph, and so makes the
 // scheduler sick.
--- a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -402,6 +402,7 @@
     case access_field_id:  target = Runtime1::entry_for(Runtime1::access_field_patching_id); break;
     case load_klass_id:    target = Runtime1::entry_for(Runtime1::load_klass_patching_id); reloc_type = relocInfo::metadata_type; break;
     case load_mirror_id:   target = Runtime1::entry_for(Runtime1::load_mirror_patching_id); reloc_type = relocInfo::oop_type; break;
+    case load_appendix_id:      target = Runtime1::entry_for(Runtime1::load_appendix_patching_id); reloc_type = relocInfo::oop_type; break;
     default: ShouldNotReachHere();
   }
   __ bind(call_patch);
@@ -419,7 +420,7 @@
   for (int j = __ offset() ; j < jmp_off + 5 ; j++ ) {
     __ nop();
   }
-  if (_id == load_klass_id || _id == load_mirror_id) {
+  if (_id == load_klass_id || _id == load_mirror_id || _id == load_appendix_id) {
     CodeSection* cs = __ code_section();
     RelocIterator iter(cs, (address)_pc_start, (address)(_pc_start + 1));
     relocInfo::change_reloc_info_for_address(&iter, (address) _pc_start, reloc_type, relocInfo::none);
--- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -362,7 +362,7 @@
 
 void LIR_Assembler::jobject2reg_with_patching(Register reg, CodeEmitInfo* info) {
   jobject o = NULL;
-  PatchingStub* patch = new PatchingStub(_masm, PatchingStub::load_mirror_id);
+  PatchingStub* patch = new PatchingStub(_masm, patching_id(info));
   __ movoop(reg, o);
   patching_epilog(patch, lir_patch_normal, reg, info);
 }
--- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -1499,6 +1499,13 @@
       }
       break;
 
+    case load_appendix_patching_id:
+      { StubFrame f(sasm, "load_appendix_patching", dont_gc_arguments);
+        // we should set up register map
+        oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_appendix_patching));
+      }
+      break;
+
     case dtrace_object_alloc_id:
       { // rax,: object
         StubFrame f(sasm, "dtrace_object_alloc", dont_gc_arguments);
--- a/src/cpu/x86/vm/c2_globals_x86.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/cpu/x86/vm/c2_globals_x86.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -30,7 +30,6 @@
 
 // Sets the default values for platform dependent flags used by the server compiler.
 // (see c2_globals.hpp).  Alpha-sorted.
-
 define_pd_global(bool, BackgroundCompilation,        true);
 define_pd_global(bool, UseTLAB,                      true);
 define_pd_global(bool, ResizeTLAB,                   true);
@@ -52,6 +51,7 @@
 define_pd_global(intx, ConditionalMoveLimit,         3);
 define_pd_global(intx, FLOATPRESSURE,                6);
 define_pd_global(intx, FreqInlineSize,               325);
+define_pd_global(intx, MinJumpTableSize,             10);
 #ifdef AMD64
 define_pd_global(intx, INTPRESSURE,                  13);
 define_pd_global(intx, InteriorEntryAlignment,       16);
--- a/src/os/linux/vm/os_linux.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/os/linux/vm/os_linux.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -2767,7 +2767,19 @@
   Linux::numa_interleave_memory(addr, bytes);
 }
 
+// Define for numa_set_bind_policy(int). Setting the argument to 0 will set the
+// bind policy to MPOL_PREFERRED for the current thread.
+#define USE_MPOL_PREFERRED 0
+
 void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) {
+  // To make NUMA and large pages more robust when both enabled, we need to ease
+  // the requirements on where the memory should be allocated. MPOL_BIND is the
+  // default policy and it will force memory to be allocated on the specified
+  // node. Changing this to MPOL_PREFERRED will prefer to allocate the memory on
+  // the specified node, but will not force it. Using this policy will prevent
+  // getting SIGBUS when trying to allocate large pages on NUMA nodes with no
+  // free large pages.
+  Linux::numa_set_bind_policy(USE_MPOL_PREFERRED);
   Linux::numa_tonode_memory(addr, bytes, lgrp_hint);
 }
 
@@ -2869,6 +2881,8 @@
                                             libnuma_dlsym(handle, "numa_tonode_memory")));
       set_numa_interleave_memory(CAST_TO_FN_PTR(numa_interleave_memory_func_t,
                                             libnuma_dlsym(handle, "numa_interleave_memory")));
+      set_numa_set_bind_policy(CAST_TO_FN_PTR(numa_set_bind_policy_func_t,
+                                            libnuma_dlsym(handle, "numa_set_bind_policy")));
 
 
       if (numa_available() != -1) {
@@ -2935,6 +2949,7 @@
 os::Linux::numa_available_func_t os::Linux::_numa_available;
 os::Linux::numa_tonode_memory_func_t os::Linux::_numa_tonode_memory;
 os::Linux::numa_interleave_memory_func_t os::Linux::_numa_interleave_memory;
+os::Linux::numa_set_bind_policy_func_t os::Linux::_numa_set_bind_policy;
 unsigned long* os::Linux::_numa_all_nodes;
 
 bool os::pd_uncommit_memory(char* addr, size_t size) {
--- a/src/os/linux/vm/os_linux.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/os/linux/vm/os_linux.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -235,6 +235,7 @@
   typedef int (*numa_available_func_t)(void);
   typedef int (*numa_tonode_memory_func_t)(void *start, size_t size, int node);
   typedef void (*numa_interleave_memory_func_t)(void *start, size_t size, unsigned long *nodemask);
+  typedef void (*numa_set_bind_policy_func_t)(int policy);
 
   static sched_getcpu_func_t _sched_getcpu;
   static numa_node_to_cpus_func_t _numa_node_to_cpus;
@@ -242,6 +243,7 @@
   static numa_available_func_t _numa_available;
   static numa_tonode_memory_func_t _numa_tonode_memory;
   static numa_interleave_memory_func_t _numa_interleave_memory;
+  static numa_set_bind_policy_func_t _numa_set_bind_policy;
   static unsigned long* _numa_all_nodes;
 
   static void set_sched_getcpu(sched_getcpu_func_t func) { _sched_getcpu = func; }
@@ -250,6 +252,7 @@
   static void set_numa_available(numa_available_func_t func) { _numa_available = func; }
   static void set_numa_tonode_memory(numa_tonode_memory_func_t func) { _numa_tonode_memory = func; }
   static void set_numa_interleave_memory(numa_interleave_memory_func_t func) { _numa_interleave_memory = func; }
+  static void set_numa_set_bind_policy(numa_set_bind_policy_func_t func) { _numa_set_bind_policy = func; }
   static void set_numa_all_nodes(unsigned long* ptr) { _numa_all_nodes = ptr; }
   static int sched_getcpu_syscall(void);
 public:
@@ -267,6 +270,11 @@
       _numa_interleave_memory(start, size, _numa_all_nodes);
     }
   }
+  static void numa_set_bind_policy(int policy) {
+    if (_numa_set_bind_policy != NULL) {
+      _numa_set_bind_policy(policy);
+    }
+  }
   static int get_node_by_cpu(int cpu_id);
 };
 
--- a/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -44,6 +44,6 @@
 define_pd_global(intx, CompilerThreadStackSize,  0);
 
 // Used on 64 bit platforms for UseCompressedOops base address
-define_pd_global(uintx,HeapBaseMinAddress,       256*M);
+define_pd_global(uintx,HeapBaseMinAddress,       2*G);
 
 #endif // OS_CPU_SOLARIS_X86_VM_GLOBALS_SOLARIS_X86_HPP
--- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/CallSite.java	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/CallSite.java	Fri Sep 13 10:34:15 2013 -0400
@@ -106,10 +106,12 @@
                         " (" + getMethod().getBytes() + " bytes) " + getReason());
             }
         }
+        stream.printf(" (end time: %6.4f", getTimeStamp());
         if (getEndNodes() > 0) {
-            stream.printf(" (end time: %6.4f nodes: %d live: %d)", getTimeStamp(), getEndNodes(), getEndLiveNodes());
+            stream.printf(" nodes: %d live: %d", getEndNodes(), getEndLiveNodes());
         }
-        stream.println("");
+        stream.println(")");
+
         if (getReceiver() != null) {
             emit(stream, indent + 4);
             //                 stream.println("type profile " + method.holder + " -> " + receiver + " (" +
--- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java	Fri Sep 13 10:34:15 2013 -0400
@@ -207,7 +207,12 @@
     }
 
     String search(Attributes attr, String name) {
-        return search(attr, name, null);
+        String result = attr.getValue(name);
+        if (result != null) {
+            return result;
+        } else {
+            throw new InternalError("can't find " + name);
+        }
     }
 
     String search(Attributes attr, String name, String defaultValue) {
@@ -215,13 +220,7 @@
         if (result != null) {
             return result;
         }
-        if (defaultValue != null) {
-            return defaultValue;
-        }
-        for (int i = 0; i < attr.getLength(); i++) {
-            System.out.println(attr.getQName(i) + " " + attr.getValue(attr.getQName(i)));
-        }
-        throw new InternalError("can't find " + name);
+        return defaultValue;
     }
     int indent = 0;
 
@@ -268,17 +267,18 @@
             Phase p = new Phase(search(atts, "name"),
                     Double.parseDouble(search(atts, "stamp")),
                     Integer.parseInt(search(atts, "nodes", "0")),
-                    Integer.parseInt(search(atts, "live")));
+                    Integer.parseInt(search(atts, "live", "0")));
             phaseStack.push(p);
         } else if (qname.equals("phase_done")) {
             Phase p = phaseStack.pop();
-            if (! p.getId().equals(search(atts, "name"))) {
+            String phaseName = search(atts, "name", null);
+            if (phaseName != null && !p.getId().equals(phaseName)) {
                 System.out.println("phase: " + p.getId());
                 throw new InternalError("phase name mismatch");
             }
             p.setEnd(Double.parseDouble(search(atts, "stamp")));
             p.setEndNodes(Integer.parseInt(search(atts, "nodes", "0")));
-            p.setEndLiveNodes(Integer.parseInt(search(atts, "live")));
+            p.setEndLiveNodes(Integer.parseInt(search(atts, "live", "0")));
             compile.getPhases().add(p);
         } else if (qname.equals("task")) {
             compile = new Compilation(Integer.parseInt(search(atts, "compile_id", "-1")));
@@ -413,8 +413,8 @@
             }
         } else if (qname.equals("parse_done")) {
             CallSite call = scopes.pop();
-            call.setEndNodes(Integer.parseInt(search(atts, "nodes", "1")));
-            call.setEndLiveNodes(Integer.parseInt(search(atts, "live", "1")));
+            call.setEndNodes(Integer.parseInt(search(atts, "nodes", "0")));
+            call.setEndLiveNodes(Integer.parseInt(search(atts, "live", "0")));
             call.setTimeStamp(Double.parseDouble(search(atts, "stamp")));
             scopes.push(call);
         }
--- a/src/share/vm/adlc/output_c.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/adlc/output_c.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -1095,7 +1095,7 @@
         fprintf(fp, "  // Identify previous instruction if inside this block\n");
         fprintf(fp, "  if( ");
         print_block_index(fp, inst_position);
-        fprintf(fp, " > 0 ) {\n    Node *n = block->_nodes.at(");
+        fprintf(fp, " > 0 ) {\n    Node *n = block->get_node(");
         print_block_index(fp, inst_position);
         fprintf(fp, ");\n    inst%d = (n->is_Mach()) ? ", inst_position);
         fprintf(fp, "n->as_Mach() : NULL;\n  }\n");
--- a/src/share/vm/c1/c1_CodeStubs.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/c1/c1_CodeStubs.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -364,7 +364,8 @@
   enum PatchID {
     access_field_id,
     load_klass_id,
-    load_mirror_id
+    load_mirror_id,
+    load_appendix_id
   };
   enum constants {
     patch_info_size = 3
@@ -417,7 +418,7 @@
       }
       NativeMovRegMem* n_move = nativeMovRegMem_at(pc_start());
       n_move->set_offset(field_offset);
-    } else if (_id == load_klass_id || _id == load_mirror_id) {
+    } else if (_id == load_klass_id || _id == load_mirror_id || _id == load_appendix_id) {
       assert(_obj != noreg, "must have register object for load_klass/load_mirror");
 #ifdef ASSERT
       // verify that we're pointing at a NativeMovConstReg
--- a/src/share/vm/c1/c1_Compilation.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/c1/c1_Compilation.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -74,16 +74,19 @@
  private:
   JavaThread* _thread;
   CompileLog* _log;
+  TimerName _timer;
 
  public:
   PhaseTraceTime(TimerName timer)
-  : TraceTime("", &timers[timer], CITime || CITimeEach, Verbose), _log(NULL) {
+  : TraceTime("", &timers[timer], CITime || CITimeEach, Verbose),
+    _log(NULL), _timer(timer)
+  {
     if (Compilation::current() != NULL) {
       _log = Compilation::current()->log();
     }
 
     if (_log != NULL) {
-      _log->begin_head("phase name='%s'", timer_name[timer]);
+      _log->begin_head("phase name='%s'", timer_name[_timer]);
       _log->stamp();
       _log->end_head();
     }
@@ -91,7 +94,7 @@
 
   ~PhaseTraceTime() {
     if (_log != NULL)
-      _log->done("phase");
+      _log->done("phase name='%s'", timer_name[_timer]);
   }
 };
 
--- a/src/share/vm/c1/c1_GraphBuilder.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/c1/c1_GraphBuilder.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -1583,7 +1583,7 @@
       ObjectType* obj_type = obj->type()->as_ObjectType();
       if (obj_type->is_constant() && !PatchALot) {
         ciObject* const_oop = obj_type->constant_value();
-        if (!const_oop->is_null_object()) {
+        if (!const_oop->is_null_object() && const_oop->is_loaded()) {
           if (field->is_constant()) {
             ciConstant field_val = field->constant_value_of(const_oop);
             BasicType field_type = field_val.basic_type();
@@ -1667,9 +1667,8 @@
   const Bytecodes::Code bc_raw = stream()->cur_bc_raw();
   assert(declared_signature != NULL, "cannot be null");
 
-  // FIXME bail out for now
-  if (Bytecodes::has_optional_appendix(bc_raw) && !will_link) {
-    BAILOUT("unlinked call site (FIXME needs patching or recompile support)");
+  if (!C1PatchInvokeDynamic && Bytecodes::has_optional_appendix(bc_raw) && !will_link) {
+    BAILOUT("unlinked call site (C1PatchInvokeDynamic is off)");
   }
 
   // we have to make sure the argument size (incl. the receiver)
@@ -1713,10 +1712,23 @@
       code = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokespecial;
       break;
     }
+  } else {
+    if (bc_raw == Bytecodes::_invokehandle) {
+      assert(!will_link, "should come here only for unlinked call");
+      code = Bytecodes::_invokespecial;
+    }
   }
 
   // Push appendix argument (MethodType, CallSite, etc.), if one.
-  if (stream()->has_appendix()) {
+  bool patch_for_appendix = false;
+  int patching_appendix_arg = 0;
+  if (C1PatchInvokeDynamic &&
+      (Bytecodes::has_optional_appendix(bc_raw) && (!will_link || PatchALot))) {
+    Value arg = append(new Constant(new ObjectConstant(compilation()->env()->unloaded_ciinstance()), copy_state_before()));
+    apush(arg);
+    patch_for_appendix = true;
+    patching_appendix_arg = (will_link && stream()->has_appendix()) ? 0 : 1;
+  } else if (stream()->has_appendix()) {
     ciObject* appendix = stream()->get_appendix();
     Value arg = append(new Constant(new ObjectConstant(appendix)));
     apush(arg);
@@ -1732,7 +1744,8 @@
   if (UseCHA && DeoptC1 && klass->is_loaded() && target->is_loaded() &&
       !(// %%% FIXME: Are both of these relevant?
         target->is_method_handle_intrinsic() ||
-        target->is_compiled_lambda_form())) {
+        target->is_compiled_lambda_form()) &&
+      !patch_for_appendix) {
     Value receiver = NULL;
     ciInstanceKlass* receiver_klass = NULL;
     bool type_is_exact = false;
@@ -1850,7 +1863,8 @@
   // check if we could do inlining
   if (!PatchALot && Inline && klass->is_loaded() &&
       (klass->is_initialized() || klass->is_interface() && target->holder()->is_initialized())
-      && target->is_loaded()) {
+      && target->is_loaded()
+      && !patch_for_appendix) {
     // callee is known => check if we have static binding
     assert(target->is_loaded(), "callee must be known");
     if (code == Bytecodes::_invokestatic  ||
@@ -1901,7 +1915,7 @@
     code == Bytecodes::_invokespecial   ||
     code == Bytecodes::_invokevirtual   ||
     code == Bytecodes::_invokeinterface;
-  Values* args = state()->pop_arguments(target->arg_size_no_receiver());
+  Values* args = state()->pop_arguments(target->arg_size_no_receiver() + patching_appendix_arg);
   Value recv = has_receiver ? apop() : NULL;
   int vtable_index = Method::invalid_vtable_index;
 
--- a/src/share/vm/c1/c1_LIR.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/c1/c1_LIR.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -1211,8 +1211,6 @@
   bool is_invokedynamic() const                  { return code() == lir_dynamic_call; }
   bool is_method_handle_invoke() const {
     return
-      is_invokedynamic()  // An invokedynamic is always a MethodHandle call site.
-      ||
       method()->is_compiled_lambda_form()  // Java-generated adapter
       ||
       method()->is_method_handle_intrinsic();  // JVM-generated MH intrinsic
--- a/src/share/vm/c1/c1_LIRAssembler.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/c1/c1_LIRAssembler.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -93,12 +93,23 @@
       default:
         ShouldNotReachHere();
     }
+  } else if (patch->id() == PatchingStub::load_appendix_id) {
+    Bytecodes::Code bc_raw = info->scope()->method()->raw_code_at_bci(info->stack()->bci());
+    assert(Bytecodes::has_optional_appendix(bc_raw), "unexpected appendix resolution");
   } else {
     ShouldNotReachHere();
   }
 #endif
 }
 
+PatchingStub::PatchID LIR_Assembler::patching_id(CodeEmitInfo* info) {
+  IRScope* scope = info->scope();
+  Bytecodes::Code bc_raw = scope->method()->raw_code_at_bci(info->stack()->bci());
+  if (Bytecodes::has_optional_appendix(bc_raw)) {
+    return PatchingStub::load_appendix_id;
+  }
+  return PatchingStub::load_mirror_id;
+}
 
 //---------------------------------------------------------------
 
--- a/src/share/vm/c1/c1_LIRAssembler.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/c1/c1_LIRAssembler.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -119,6 +119,8 @@
 
   void comp_op(LIR_Condition condition, LIR_Opr src, LIR_Opr result, LIR_Op2* op);
 
+  PatchingStub::PatchID patching_id(CodeEmitInfo* info);
+
  public:
   LIR_Assembler(Compilation* c);
   ~LIR_Assembler();
--- a/src/share/vm/c1/c1_Runtime1.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/c1/c1_Runtime1.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -819,6 +819,7 @@
   KlassHandle init_klass(THREAD, NULL); // klass needed by load_klass_patching code
   KlassHandle load_klass(THREAD, NULL); // klass needed by load_klass_patching code
   Handle mirror(THREAD, NULL);                    // oop needed by load_mirror_patching code
+  Handle appendix(THREAD, NULL);                  // oop needed by appendix_patching code
   bool load_klass_or_mirror_patch_id =
     (stub_id == Runtime1::load_klass_patching_id || stub_id == Runtime1::load_mirror_patching_id);
 
@@ -888,10 +889,32 @@
           mirror = Handle(THREAD, m);
         }
         break;
-      default: Unimplemented();
+      default: fatal("unexpected bytecode for load_klass_or_mirror_patch_id");
     }
     // convert to handle
     load_klass = KlassHandle(THREAD, k);
+  } else if (stub_id == load_appendix_patching_id) {
+    Bytecode_invoke bytecode(caller_method, bci);
+    Bytecodes::Code bc = bytecode.invoke_code();
+
+    CallInfo info;
+    constantPoolHandle pool(thread, caller_method->constants());
+    int index = bytecode.index();
+    LinkResolver::resolve_invoke(info, Handle(), pool, index, bc, CHECK);
+    appendix = info.resolved_appendix();
+    switch (bc) {
+      case Bytecodes::_invokehandle: {
+        int cache_index = ConstantPool::decode_cpcache_index(index, true);
+        assert(cache_index >= 0 && cache_index < pool->cache()->length(), "unexpected cache index");
+        pool->cache()->entry_at(cache_index)->set_method_handle(pool, info);
+        break;
+      }
+      case Bytecodes::_invokedynamic: {
+        pool->invokedynamic_cp_cache_entry_at(index)->set_dynamic_call(pool, info);
+        break;
+      }
+      default: fatal("unexpected bytecode for load_appendix_patching_id");
+    }
   } else {
     ShouldNotReachHere();
   }
@@ -992,8 +1015,8 @@
                    n_copy->data() == (intptr_t)Universe::non_oop_word(),
                    "illegal init value");
             if (stub_id == Runtime1::load_klass_patching_id) {
-            assert(load_klass() != NULL, "klass not set");
-            n_copy->set_data((intx) (load_klass()));
+              assert(load_klass() != NULL, "klass not set");
+              n_copy->set_data((intx) (load_klass()));
             } else {
               assert(mirror() != NULL, "klass not set");
               n_copy->set_data((intx) (mirror()));
@@ -1002,43 +1025,55 @@
             if (TracePatching) {
               Disassembler::decode(copy_buff, copy_buff + *byte_count, tty);
             }
+          }
+        } else if (stub_id == Runtime1::load_appendix_patching_id) {
+          NativeMovConstReg* n_copy = nativeMovConstReg_at(copy_buff);
+          assert(n_copy->data() == 0 ||
+                 n_copy->data() == (intptr_t)Universe::non_oop_word(),
+                 "illegal init value");
+          n_copy->set_data((intx) (appendix()));
 
-#if defined(SPARC) || defined(PPC)
-            // Update the location in the nmethod with the proper
-            // metadata.  When the code was generated, a NULL was stuffed
-            // in the metadata table and that table needs to be update to
-            // have the right value.  On intel the value is kept
-            // directly in the instruction instead of in the metadata
-            // table, so set_data above effectively updated the value.
-            nmethod* nm = CodeCache::find_nmethod(instr_pc);
-            assert(nm != NULL, "invalid nmethod_pc");
-            RelocIterator mds(nm, copy_buff, copy_buff + 1);
-            bool found = false;
-            while (mds.next() && !found) {
-              if (mds.type() == relocInfo::oop_type) {
-                assert(stub_id == Runtime1::load_mirror_patching_id, "wrong stub id");
-                oop_Relocation* r = mds.oop_reloc();
-                oop* oop_adr = r->oop_addr();
-                *oop_adr = mirror();
-                r->fix_oop_relocation();
-                found = true;
-              } else if (mds.type() == relocInfo::metadata_type) {
-                assert(stub_id == Runtime1::load_klass_patching_id, "wrong stub id");
-                metadata_Relocation* r = mds.metadata_reloc();
-                Metadata** metadata_adr = r->metadata_addr();
-                *metadata_adr = load_klass();
-                r->fix_metadata_relocation();
-                found = true;
-              }
-            }
-            assert(found, "the metadata must exist!");
-#endif
-
+          if (TracePatching) {
+            Disassembler::decode(copy_buff, copy_buff + *byte_count, tty);
           }
         } else {
           ShouldNotReachHere();
         }
 
+#if defined(SPARC) || defined(PPC)
+        if (load_klass_or_mirror_patch_id ||
+            stub_id == Runtime1::load_appendix_patching_id) {
+          // Update the location in the nmethod with the proper
+          // metadata.  When the code was generated, a NULL was stuffed
+          // in the metadata table and that table needs to be update to
+          // have the right value.  On intel the value is kept
+          // directly in the instruction instead of in the metadata
+          // table, so set_data above effectively updated the value.
+          nmethod* nm = CodeCache::find_nmethod(instr_pc);
+          assert(nm != NULL, "invalid nmethod_pc");
+          RelocIterator mds(nm, copy_buff, copy_buff + 1);
+          bool found = false;
+          while (mds.next() && !found) {
+            if (mds.type() == relocInfo::oop_type) {
+              assert(stub_id == Runtime1::load_mirror_patching_id ||
+                     stub_id == Runtime1::load_appendix_patching_id, "wrong stub id");
+              oop_Relocation* r = mds.oop_reloc();
+              oop* oop_adr = r->oop_addr();
+              *oop_adr = stub_id == Runtime1::load_mirror_patching_id ? mirror() : appendix();
+              r->fix_oop_relocation();
+              found = true;
+            } else if (mds.type() == relocInfo::metadata_type) {
+              assert(stub_id == Runtime1::load_klass_patching_id, "wrong stub id");
+              metadata_Relocation* r = mds.metadata_reloc();
+              Metadata** metadata_adr = r->metadata_addr();
+              *metadata_adr = load_klass();
+              r->fix_metadata_relocation();
+              found = true;
+            }
+          }
+          assert(found, "the metadata must exist!");
+        }
+#endif
         if (do_patch) {
           // replace instructions
           // first replace the tail, then the call
@@ -1077,7 +1112,8 @@
           ICache::invalidate_range(instr_pc, *byte_count);
           NativeGeneralJump::replace_mt_safe(instr_pc, copy_buff);
 
-          if (load_klass_or_mirror_patch_id) {
+          if (load_klass_or_mirror_patch_id ||
+              stub_id == Runtime1::load_appendix_patching_id) {
             relocInfo::relocType rtype =
               (stub_id == Runtime1::load_klass_patching_id) ?
                                    relocInfo::metadata_type :
@@ -1118,7 +1154,8 @@
 
   // If we are patching in a non-perm oop, make sure the nmethod
   // is on the right list.
-  if (ScavengeRootsInCode && mirror.not_null() && mirror()->is_scavengable()) {
+  if (ScavengeRootsInCode && ((mirror.not_null() && mirror()->is_scavengable()) ||
+                              (appendix.not_null() && appendix->is_scavengable()))) {
     MutexLockerEx ml_code (CodeCache_lock, Mutex::_no_safepoint_check_flag);
     nmethod* nm = CodeCache::find_nmethod(caller_frame.pc());
     guarantee(nm != NULL, "only nmethods can contain non-perm oops");
@@ -1179,6 +1216,24 @@
   return caller_is_deopted();
 }
 
+int Runtime1::move_appendix_patching(JavaThread* thread) {
+//
+// NOTE: we are still in Java
+//
+  Thread* THREAD = thread;
+  debug_only(NoHandleMark nhm;)
+  {
+    // Enter VM mode
+
+    ResetNoHandleMark rnhm;
+    patch_code(thread, load_appendix_patching_id);
+  }
+  // Back in JAVA, use no oops DON'T safepoint
+
+  // Return true if calling code is deoptimized
+
+  return caller_is_deopted();
+}
 //
 // Entry point for compiled code. We want to patch a nmethod.
 // We don't do a normal VM transition here because we want to
--- a/src/share/vm/c1/c1_Runtime1.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/c1/c1_Runtime1.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -67,6 +67,7 @@
   stub(access_field_patching)        \
   stub(load_klass_patching)          \
   stub(load_mirror_patching)         \
+  stub(load_appendix_patching)       \
   stub(g1_pre_barrier_slow)          \
   stub(g1_post_barrier_slow)         \
   stub(fpu2long_stub)                \
@@ -160,6 +161,7 @@
   static int access_field_patching(JavaThread* thread);
   static int move_klass_patching(JavaThread* thread);
   static int move_mirror_patching(JavaThread* thread);
+  static int move_appendix_patching(JavaThread* thread);
 
   static void patch_code(JavaThread* thread, StubID stub_id);
 
--- a/src/share/vm/c1/c1_globals.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/c1/c1_globals.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -25,4 +25,4 @@
 #include "precompiled.hpp"
 #include "c1/c1_globals.hpp"
 
-C1_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_NOTPRODUCT_FLAG)
+C1_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_NOTPRODUCT_FLAG)
--- a/src/share/vm/c1/c1_globals.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/c1/c1_globals.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -54,7 +54,7 @@
 //
 // Defines all global flags used by the client compiler.
 //
-#define C1_FLAGS(develop, develop_pd, product, product_pd, notproduct)      \
+#define C1_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct) \
                                                                             \
   /* Printing */                                                            \
   notproduct(bool, PrintC1Statistics, false,                                \
@@ -333,15 +333,19 @@
           "Use CHA and exact type results at call sites when updating MDOs")\
                                                                             \
   product(bool, C1UpdateMethodData, trueInTiered,                           \
-          "Update MethodData*s in Tier1-generated code")                  \
+          "Update MethodData*s in Tier1-generated code")                    \
                                                                             \
   develop(bool, PrintCFGToFile, false,                                      \
           "print control flow graph to a separate file during compilation") \
                                                                             \
+  diagnostic(bool, C1PatchInvokeDynamic, true,                              \
+             "Patch invokedynamic appendix not known at compile time")      \
+                                                                            \
+                                                                            \
 
 
 // Read default values for c1 globals
 
-C1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_NOTPRODUCT_FLAG)
+C1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_NOTPRODUCT_FLAG)
 
 #endif // SHARE_VM_C1_C1_GLOBALS_HPP
--- a/src/share/vm/ci/ciArray.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/ci/ciArray.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -24,13 +24,92 @@
 
 #include "precompiled.hpp"
 #include "ci/ciArray.hpp"
+#include "ci/ciArrayKlass.hpp"
+#include "ci/ciConstant.hpp"
 #include "ci/ciKlass.hpp"
 #include "ci/ciUtilities.hpp"
+#include "oops/objArrayOop.hpp"
+#include "oops/typeArrayOop.hpp"
 
 // ciArray
 //
 // This class represents an arrayOop in the HotSpot virtual
 // machine.
+static BasicType fixup_element_type(BasicType bt) {
+  if (bt == T_ARRAY)    return T_OBJECT;
+  if (bt == T_BOOLEAN)  return T_BYTE;
+  return bt;
+}
+
+ciConstant ciArray::element_value_impl(BasicType elembt,
+                                       arrayOop ary,
+                                       int index) {
+  if (ary == NULL)
+    return ciConstant();
+  assert(ary->is_array(), "");
+  if (index < 0 || index >= ary->length())
+    return ciConstant();
+  ArrayKlass* ak = (ArrayKlass*) ary->klass();
+  BasicType abt = ak->element_type();
+  if (fixup_element_type(elembt) !=
+      fixup_element_type(abt))
+    return ciConstant();
+  switch (elembt) {
+  case T_ARRAY:
+  case T_OBJECT:
+    {
+      assert(ary->is_objArray(), "");
+      objArrayOop objary = (objArrayOop) ary;
+      oop elem = objary->obj_at(index);
+      ciEnv* env = CURRENT_ENV;
+      ciObject* box = env->get_object(elem);
+      return ciConstant(T_OBJECT, box);
+    }
+  }
+  assert(ary->is_typeArray(), "");
+  typeArrayOop tary = (typeArrayOop) ary;
+  jint value = 0;
+  switch (elembt) {
+  case T_LONG:          return ciConstant(tary->long_at(index));
+  case T_FLOAT:         return ciConstant(tary->float_at(index));
+  case T_DOUBLE:        return ciConstant(tary->double_at(index));
+  default:              return ciConstant();
+  case T_BYTE:          value = tary->byte_at(index);           break;
+  case T_BOOLEAN:       value = tary->byte_at(index) & 1;       break;
+  case T_SHORT:         value = tary->short_at(index);          break;
+  case T_CHAR:          value = tary->char_at(index);           break;
+  case T_INT:           value = tary->int_at(index);            break;
+  }
+  return ciConstant(elembt, value);
+}
+
+// ------------------------------------------------------------------
+// ciArray::element_value
+//
+// Current value of an element.
+// Returns T_ILLEGAL if there is no element at the given index.
+ciConstant ciArray::element_value(int index) {
+  BasicType elembt = element_basic_type();
+  GUARDED_VM_ENTRY(
+    return element_value_impl(elembt, get_arrayOop(), index);
+  )
+}
+
+// ------------------------------------------------------------------
+// ciArray::element_value_by_offset
+//
+// Current value of an element at the specified offset.
+// Returns T_ILLEGAL if there is no element at the given offset.
+ciConstant ciArray::element_value_by_offset(intptr_t element_offset) {
+  BasicType elembt = element_basic_type();
+  intptr_t shift  = exact_log2(type2aelembytes(elembt));
+  intptr_t header = arrayOopDesc::base_offset_in_bytes(elembt);
+  intptr_t index = (element_offset - header) >> shift;
+  intptr_t offset = header + ((intptr_t)index << shift);
+  if (offset != element_offset || index != (jint)index)
+    return ciConstant();
+  return element_value((jint) index);
+}
 
 // ------------------------------------------------------------------
 // ciArray::print_impl
--- a/src/share/vm/ci/ciArray.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/ci/ciArray.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -25,6 +25,8 @@
 #ifndef SHARE_VM_CI_CIARRAY_HPP
 #define SHARE_VM_CI_CIARRAY_HPP
 
+#include "ci/ciArrayKlass.hpp"
+#include "ci/ciConstant.hpp"
 #include "ci/ciObject.hpp"
 #include "oops/arrayOop.hpp"
 #include "oops/objArrayOop.hpp"
@@ -45,15 +47,30 @@
 
   ciArray(ciKlass* klass, int len) : ciObject(klass), _length(len) {}
 
-  arrayOop get_arrayOop() { return (arrayOop)get_oop(); }
+  arrayOop get_arrayOop() const { return (arrayOop)get_oop(); }
 
   const char* type_string() { return "ciArray"; }
 
   void print_impl(outputStream* st);
 
+  ciConstant element_value_impl(BasicType elembt, arrayOop ary, int index);
+
 public:
   int length() { return _length; }
 
+  // Convenience routines.
+  ciArrayKlass* array_type()         { return klass()->as_array_klass(); }
+  ciType*       element_type()       { return array_type()->element_type(); }
+  BasicType     element_basic_type() { return element_type()->basic_type(); }
+
+  // Current value of an element.
+  // Returns T_ILLEGAL if there is no element at the given index.
+  ciConstant element_value(int index);
+
+  // Current value of an element at the specified offset.
+  // Returns T_ILLEGAL if there is no element at the given offset.
+  ciConstant element_value_by_offset(intptr_t element_offset);
+
   // What kind of ciObject is this?
   bool is_array()        { return true; }
   bool is_java_object()  { return true; }
--- a/src/share/vm/ci/ciConstant.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/ci/ciConstant.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -41,7 +41,6 @@
   union {
     jint      _int;
     jlong     _long;
-    jint      _long_half[2];
     jfloat    _float;
     jdouble   _double;
     ciObject* _object;
@@ -111,6 +110,20 @@
     return _value._object;
   }
 
+  bool      is_null_or_zero() const {
+    if (!is_java_primitive(basic_type())) {
+      return as_object()->is_null_object();
+    } else if (type2size[basic_type()] == 1) {
+      // treat float bits as int, to avoid comparison with -0 and NaN
+      return (_value._int == 0);
+    } else if (type2size[basic_type()] == 2) {
+      // treat double bits as long, to avoid comparison with -0 and NaN
+      return (_value._long == 0);
+    } else {
+      return false;
+    }
+  }
+
   // Debugging output
   void print();
 };
--- a/src/share/vm/ci/ciEnv.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/ci/ciEnv.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -1150,6 +1150,10 @@
   record_method_not_compilable("out of memory");
 }
 
+ciInstance* ciEnv::unloaded_ciinstance() {
+  GUARDED_VM_ENTRY(return _factory->get_unloaded_object_constant();)
+}
+
 void ciEnv::dump_replay_data(outputStream* out) {
   VM_ENTRY_MARK;
   MutexLocker ml(Compile_lock);
--- a/src/share/vm/ci/ciEnv.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/ci/ciEnv.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -400,6 +400,7 @@
   static ciInstanceKlass* unloaded_ciinstance_klass() {
     return _unloaded_ciinstance_klass;
   }
+  ciInstance* unloaded_ciinstance();
 
   ciKlass*  find_system_klass(ciSymbol* klass_name);
   // Note:  To find a class from its name string, use ciSymbol::make,
--- a/src/share/vm/ci/ciField.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/ci/ciField.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -189,12 +189,14 @@
   _holder = CURRENT_ENV->get_instance_klass(fd->field_holder());
 
   // Check to see if the field is constant.
-  if (_holder->is_initialized() && this->is_final()) {
+  bool is_final = this->is_final();
+  bool is_stable = FoldStableValues && this->is_stable();
+  if (_holder->is_initialized() && (is_final || is_stable)) {
     if (!this->is_static()) {
       // A field can be constant if it's a final static field or if
       // it's a final non-static field of a trusted class (classes in
       // java.lang.invoke and sun.invoke packages and subpackages).
-      if (trust_final_non_static_fields(_holder)) {
+      if (is_stable || trust_final_non_static_fields(_holder)) {
         _is_constant = true;
         return;
       }
@@ -227,7 +229,6 @@
 
     Handle mirror = k->java_mirror();
 
-    _is_constant = true;
     switch(type()->basic_type()) {
     case T_BYTE:
       _constant_value = ciConstant(type()->basic_type(), mirror->byte_field(_offset));
@@ -273,6 +274,12 @@
         }
       }
     }
+    if (is_stable && _constant_value.is_null_or_zero()) {
+      // It is not a constant after all; treat it as uninitialized.
+      _is_constant = false;
+    } else {
+      _is_constant = true;
+    }
   } else {
     _is_constant = false;
   }
@@ -373,8 +380,11 @@
   tty->print(" signature=");
   _signature->print_symbol();
   tty->print(" offset=%d type=", _offset);
-  if (_type != NULL) _type->print_name();
-  else               tty->print("(reference)");
+  if (_type != NULL)
+    _type->print_name();
+  else
+    tty->print("(reference)");
+  tty->print(" flags=%04x", flags().as_int());
   tty->print(" is_constant=%s", bool_to_str(_is_constant));
   if (_is_constant && is_static()) {
     tty->print(" constant_value=");
--- a/src/share/vm/ci/ciField.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/ci/ciField.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -139,7 +139,10 @@
   //      non-constant fields.  These are java.lang.System.in
   //      and java.lang.System.out.  Abomination.
   //
-  // Note: the check for case 4 is not yet implemented.
+  // A field is also considered constant if it is marked @Stable
+  // and is non-null (or non-zero, if a primitive).
+  // For non-static fields, the null/zero check must be
+  // arranged by the user, as constant_value().is_null_or_zero().
   bool is_constant() { return _is_constant; }
 
   // Get the constant value of this field.
@@ -173,6 +176,7 @@
   bool is_protected   () { return flags().is_protected(); }
   bool is_static      () { return flags().is_static(); }
   bool is_final       () { return flags().is_final(); }
+  bool is_stable      () { return flags().is_stable(); }
   bool is_volatile    () { return flags().is_volatile(); }
   bool is_transient   () { return flags().is_transient(); }
 
--- a/src/share/vm/ci/ciFlags.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/ci/ciFlags.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -59,6 +59,7 @@
   bool is_interface   () const         { return (_flags & JVM_ACC_INTERFACE   ) != 0; }
   bool is_abstract    () const         { return (_flags & JVM_ACC_ABSTRACT    ) != 0; }
   bool is_strict      () const         { return (_flags & JVM_ACC_STRICT      ) != 0; }
+  bool is_stable      () const         { return (_flags & JVM_ACC_FIELD_STABLE) != 0; }
 
   // Conversion
   jint   as_int()                      { return _flags; }
--- a/src/share/vm/ci/ciInstance.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/ci/ciInstance.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -60,10 +60,10 @@
 //
 // Constant value of a field.
 ciConstant ciInstance::field_value(ciField* field) {
-  assert(is_loaded() &&
-         field->holder()->is_loaded() &&
-         klass()->is_subclass_of(field->holder()),
-         "invalid access");
+  assert(is_loaded(), "invalid access - must be loaded");
+  assert(field->holder()->is_loaded(), "invalid access - holder must be loaded");
+  assert(klass()->is_subclass_of(field->holder()), "invalid access - must be subclass");
+
   VM_ENTRY_MARK;
   ciConstant result;
   Handle obj = get_oop();
@@ -127,6 +127,8 @@
 ciConstant ciInstance::field_value_by_offset(int field_offset) {
   ciInstanceKlass* ik = klass()->as_instance_klass();
   ciField* field = ik->get_field_by_offset(field_offset, false);
+  if (field == NULL)
+    return ciConstant();  // T_ILLEGAL
   return field_value(field);
 }
 
--- a/src/share/vm/ci/ciMethod.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/ci/ciMethod.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -177,6 +177,10 @@
     address bcp = code() + bci;
     return Bytecodes::java_code_at(NULL, bcp);
   }
+  Bytecodes::Code raw_code_at_bci(int bci) {
+    address bcp = code() + bci;
+    return Bytecodes::code_at(NULL, bcp);
+  }
   BCEscapeAnalyzer  *get_bcea();
   ciMethodBlocks    *get_method_blocks();
 
--- a/src/share/vm/ci/ciObjectFactory.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/ci/ciObjectFactory.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -563,7 +563,10 @@
   return get_unloaded_instance(ciEnv::_MethodType_klass->as_instance_klass());
 }
 
-
+ciInstance* ciObjectFactory::get_unloaded_object_constant() {
+  if (ciEnv::_Object_klass == NULL)  return NULL;
+  return get_unloaded_instance(ciEnv::_Object_klass->as_instance_klass());
+}
 
 //------------------------------------------------------------------
 // ciObjectFactory::get_empty_methodData
--- a/src/share/vm/ci/ciObjectFactory.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/ci/ciObjectFactory.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -131,6 +131,8 @@
   ciInstance* get_unloaded_method_type_constant(ciSymbol* signature);
 
 
+  ciInstance* get_unloaded_object_constant();
+
   // Get the ciMethodData representing the methodData for a method
   // with none.
   ciMethodData* get_empty_methodData();
--- a/src/share/vm/ci/ciTypeArray.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/ci/ciTypeArray.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -39,5 +39,10 @@
 jchar ciTypeArray::char_at(int index) {
   VM_ENTRY_MARK;
   assert(index >= 0 && index < length(), "out of range");
-  return get_typeArrayOop()->char_at(index);
+  jchar c = get_typeArrayOop()->char_at(index);
+#ifdef ASSERT
+  jchar d = element_value(index).as_char();
+  assert(c == d, "");
+#endif //ASSERT
+  return c;
 }
--- a/src/share/vm/classfile/classFileParser.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/classfile/classFileParser.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -1787,6 +1787,10 @@
     if (_location != _in_method)  break;  // only allow for methods
     if (!privileged)              break;  // only allow in privileged code
     return _method_LambdaForm_Hidden;
+  case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_invoke_Stable_signature):
+    if (_location != _in_field)   break;  // only allow for fields
+    if (!privileged)              break;  // only allow in privileged code
+    return _field_Stable;
   case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_misc_Contended_signature):
     if (_location != _in_field && _location != _in_class)          break;  // only allow for fields and classes
     if (!EnableContended || (RestrictContended && !privileged))    break;  // honor privileges
@@ -1799,6 +1803,8 @@
 void ClassFileParser::FieldAnnotationCollector::apply_to(FieldInfo* f) {
   if (is_contended())
     f->set_contended_group(contended_group());
+  if (is_stable())
+    f->set_stable(true);
 }
 
 ClassFileParser::FieldAnnotationCollector::~FieldAnnotationCollector() {
--- a/src/share/vm/classfile/classFileParser.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/classfile/classFileParser.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -125,6 +125,7 @@
       _method_LambdaForm_Compiled,
       _method_LambdaForm_Hidden,
       _sun_misc_Contended,
+      _field_Stable,
       _annotation_LIMIT
     };
     const Location _location;
@@ -143,14 +144,23 @@
       assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
       _annotations_present |= nth_bit((int)id);
     }
+
+    void remove_annotation(ID id) {
+      assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
+      _annotations_present &= ~nth_bit((int)id);
+    }
+
     // Report if the annotation is present.
-    bool has_any_annotations() { return _annotations_present != 0; }
-    bool has_annotation(ID id) { return (nth_bit((int)id) & _annotations_present) != 0; }
+    bool has_any_annotations() const { return _annotations_present != 0; }
+    bool has_annotation(ID id) const { return (nth_bit((int)id) & _annotations_present) != 0; }
 
     void set_contended_group(u2 group) { _contended_group = group; }
-    u2 contended_group() { return _contended_group; }
+    u2 contended_group() const { return _contended_group; }
 
-    bool is_contended() { return has_annotation(_sun_misc_Contended); }
+    bool is_contended() const { return has_annotation(_sun_misc_Contended); }
+
+    void set_stable(bool stable) { set_annotation(_field_Stable); }
+    bool is_stable() const { return has_annotation(_field_Stable); }
   };
 
   // This class also doubles as a holder for metadata cleanup.
--- a/src/share/vm/classfile/vmSymbols.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/classfile/vmSymbols.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -270,6 +270,7 @@
   template(java_lang_invoke_LambdaForm,               "java/lang/invoke/LambdaForm")              \
   template(java_lang_invoke_ForceInline_signature,    "Ljava/lang/invoke/ForceInline;")           \
   template(java_lang_invoke_DontInline_signature,     "Ljava/lang/invoke/DontInline;")            \
+  template(sun_invoke_Stable_signature,               "Lsun/invoke/Stable;")                      \
   template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \
   template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;")  \
   template(java_lang_invoke_MagicLambdaImpl,          "java/lang/invoke/MagicLambdaImpl")         \
--- a/src/share/vm/code/nmethod.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/code/nmethod.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -93,18 +93,21 @@
 #endif
 
 bool nmethod::is_compiled_by_c1() const {
-  if (compiler() == NULL || method() == NULL)  return false;  // can happen during debug printing
-  if (is_native_method()) return false;
+  if (compiler() == NULL) {
+    return false;
+  }
   return compiler()->is_c1();
 }
 bool nmethod::is_compiled_by_c2() const {
-  if (compiler() == NULL || method() == NULL)  return false;  // can happen during debug printing
-  if (is_native_method()) return false;
+  if (compiler() == NULL) {
+    return false;
+  }
   return compiler()->is_c2();
 }
 bool nmethod::is_compiled_by_shark() const {
-  if (is_native_method()) return false;
-  assert(compiler() != NULL, "must be");
+  if (compiler() == NULL) {
+    return false;
+  }
   return compiler()->is_shark();
 }
 
@@ -1401,6 +1404,9 @@
     // nmethods aren't scanned for GC.
     _oops_are_stale = true;
 #endif
+     // the Method may be reclaimed by class unloading now that the
+     // nmethod is in zombie state
+    set_method(NULL);
   } else {
     assert(state == not_entrant, "other cases may need to be handled differently");
   }
--- a/src/share/vm/compiler/compileBroker.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/compiler/compileBroker.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -1718,7 +1718,7 @@
     CodeCache::print_summary(&s, detailed);
   }
   ttyLocker ttyl;
-  tty->print_cr(s.as_string());
+  tty->print(s.as_string());
 }
 
 // ------------------------------------------------------------------
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -2493,11 +2493,11 @@
 
 void G1CollectedHeap::register_concurrent_cycle_end() {
   if (_concurrent_cycle_started) {
-    _gc_timer_cm->register_gc_end(os::elapsed_counter());
-
     if (_cm->has_aborted()) {
       _gc_tracer_cm->report_concurrent_mode_failure();
     }
+
+    _gc_timer_cm->register_gc_end(os::elapsed_counter());
     _gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions());
 
     _concurrent_cycle_started = false;
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -168,7 +168,15 @@
   // Set up the region size and associated fields. Given that the
   // policy is created before the heap, we have to set this up here,
   // so it's done as soon as possible.
-  HeapRegion::setup_heap_region_size(Arguments::min_heap_size());
+
+  // It would have been natural to pass initial_heap_byte_size() and
+  // max_heap_byte_size() to setup_heap_region_size() but those have
+  // not been set up at this point since they should be aligned with
+  // the region size. So, there is a circular dependency here. We base
+  // the region size on the heap size, but the heap size should be
+  // aligned with the region size. To get around this we use the
+  // unaligned values for the heap.
+  HeapRegion::setup_heap_region_size(InitialHeapSize, MaxHeapSize);
   HeapRegionRemSet::setup_remset_size();
 
   G1ErgoVerbose::initialize();
--- a/src/share/vm/gc_implementation/g1/heapRegion.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -149,18 +149,11 @@
 // many regions in the heap (based on the min heap size).
 #define TARGET_REGION_NUMBER          2048
 
-void HeapRegion::setup_heap_region_size(uintx min_heap_size) {
-  // region_size in bytes
+void HeapRegion::setup_heap_region_size(size_t initial_heap_size, size_t max_heap_size) {
   uintx region_size = G1HeapRegionSize;
   if (FLAG_IS_DEFAULT(G1HeapRegionSize)) {
-    // We base the automatic calculation on the min heap size. This
-    // can be problematic if the spread between min and max is quite
-    // wide, imagine -Xms128m -Xmx32g. But, if we decided it based on
-    // the max size, the region size might be way too large for the
-    // min size. Either way, some users might have to set the region
-    // size manually for some -Xms / -Xmx combos.
-
-    region_size = MAX2(min_heap_size / TARGET_REGION_NUMBER,
+    size_t average_heap_size = (initial_heap_size + max_heap_size) / 2;
+    region_size = MAX2(average_heap_size / TARGET_REGION_NUMBER,
                        (uintx) MIN_REGION_SIZE);
   }
 
--- a/src/share/vm/gc_implementation/g1/heapRegion.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -361,7 +361,7 @@
   // CardsPerRegion). All those fields are considered constant
   // throughout the JVM's execution, therefore they should only be set
   // up once during initialization time.
-  static void setup_heap_region_size(uintx min_heap_size);
+  static void setup_heap_region_size(size_t initial_heap_size, size_t max_heap_size);
 
   enum ClaimValues {
     InitialClaimValue          = 0,
--- a/src/share/vm/gc_implementation/shared/gcTraceSend.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/gc_implementation/shared/gcTraceSend.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -28,6 +28,7 @@
 #include "gc_implementation/shared/gcTrace.hpp"
 #include "gc_implementation/shared/gcWhen.hpp"
 #include "gc_implementation/shared/copyFailedInfo.hpp"
+#include "runtime/os.hpp"
 #include "trace/tracing.hpp"
 #include "trace/traceBackend.hpp"
 #if INCLUDE_ALL_GCS
@@ -54,11 +55,12 @@
 }
 
 void GCTracer::send_reference_stats_event(ReferenceType type, size_t count) const {
-  EventGCReferenceStatistics e;
+  EventGCReferenceStatistics e(UNTIMED);
   if (e.should_commit()) {
       e.set_gcId(_shared_gc_info.id());
       e.set_type((u1)type);
       e.set_count(count);
+      e.set_endtime(os::elapsed_counter());
       e.commit();
   }
 }
@@ -105,20 +107,22 @@
 }
 
 void YoungGCTracer::send_promotion_failed_event(const PromotionFailedInfo& pf_info) const {
-  EventPromotionFailed e;
+  EventPromotionFailed e(UNTIMED);
   if (e.should_commit()) {
     e.set_gcId(_shared_gc_info.id());
     e.set_data(to_trace_struct(pf_info));
     e.set_thread(pf_info.thread()->thread_id());
+    e.set_endtime(os::elapsed_counter());
     e.commit();
   }
 }
 
 // Common to CMS and G1
 void OldGCTracer::send_concurrent_mode_failure_event() {
-  EventConcurrentModeFailure e;
+  EventConcurrentModeFailure e(UNTIMED);
   if (e.should_commit()) {
     e.set_gcId(_shared_gc_info.id());
+    e.set_endtime(os::elapsed_counter());
     e.commit();
   }
 }
@@ -136,7 +140,7 @@
 }
 
 void G1NewTracer::send_evacuation_info_event(EvacuationInfo* info) {
-  EventEvacuationInfo e;
+  EventEvacuationInfo e(UNTIMED);
   if (e.should_commit()) {
     e.set_gcId(_shared_gc_info.id());
     e.set_cSetRegions(info->collectionset_regions());
@@ -147,15 +151,17 @@
     e.set_allocRegionsUsedAfter(info->alloc_regions_used_before() + info->bytes_copied());
     e.set_bytesCopied(info->bytes_copied());
     e.set_regionsFreed(info->regions_freed());
+    e.set_endtime(os::elapsed_counter());
     e.commit();
   }
 }
 
 void G1NewTracer::send_evacuation_failed_event(const EvacuationFailedInfo& ef_info) const {
-  EventEvacuationFailed e;
+  EventEvacuationFailed e(UNTIMED);
   if (e.should_commit()) {
     e.set_gcId(_shared_gc_info.id());
     e.set_data(to_trace_struct(ef_info));
+    e.set_endtime(os::elapsed_counter());
     e.commit();
   }
 }
@@ -189,12 +195,13 @@
   void visit(const GCHeapSummary* heap_summary) const {
     const VirtualSpaceSummary& heap_space = heap_summary->heap();
 
-    EventGCHeapSummary e;
+    EventGCHeapSummary e(UNTIMED);
     if (e.should_commit()) {
       e.set_gcId(_id);
       e.set_when((u1)_when);
       e.set_heapSpace(to_trace_struct(heap_space));
       e.set_heapUsed(heap_summary->used());
+      e.set_endtime(os::elapsed_counter());
       e.commit();
     }
   }
@@ -209,7 +216,7 @@
     const SpaceSummary& from_space = ps_heap_summary->from();
     const SpaceSummary& to_space = ps_heap_summary->to();
 
-    EventPSHeapSummary e;
+    EventPSHeapSummary e(UNTIMED);
     if (e.should_commit()) {
       e.set_gcId(_id);
       e.set_when((u1)_when);
@@ -220,6 +227,7 @@
       e.set_edenSpace(to_trace_struct(ps_heap_summary->eden()));
       e.set_fromSpace(to_trace_struct(ps_heap_summary->from()));
       e.set_toSpace(to_trace_struct(ps_heap_summary->to()));
+      e.set_endtime(os::elapsed_counter());
       e.commit();
     }
   }
@@ -241,13 +249,14 @@
 }
 
 void GCTracer::send_meta_space_summary_event(GCWhen::Type when, const MetaspaceSummary& meta_space_summary) const {
-  EventMetaspaceSummary e;
+  EventMetaspaceSummary e(UNTIMED);
   if (e.should_commit()) {
     e.set_gcId(_shared_gc_info.id());
     e.set_when((u1) when);
     e.set_metaspace(to_trace_struct(meta_space_summary.meta_space()));
     e.set_dataSpace(to_trace_struct(meta_space_summary.data_space()));
     e.set_classSpace(to_trace_struct(meta_space_summary.class_space()));
+    e.set_endtime(os::elapsed_counter());
     e.commit();
   }
 }
@@ -282,8 +291,6 @@
       default: /* Ignore sending this phase */ break;
     }
   }
-
-#undef send_phase
 };
 
 void GCTracer::send_phase_events(TimePartitions* time_partitions) const {
--- a/src/share/vm/oops/fieldInfo.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/oops/fieldInfo.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -240,6 +240,14 @@
     return (access_flags() & JVM_ACC_FIELD_INTERNAL) != 0;
   }
 
+  bool is_stable() const {
+    return (access_flags() & JVM_ACC_FIELD_STABLE) != 0;
+  }
+  void set_stable(bool z) {
+    if (z) _shorts[access_flags_offset] |=  JVM_ACC_FIELD_STABLE;
+    else   _shorts[access_flags_offset] &= ~JVM_ACC_FIELD_STABLE;
+  }
+
   Symbol* lookup_symbol(int symbol_index) const {
     assert(is_internal(), "only internal fields");
     return vmSymbols::symbol_at((vmSymbols::SID)symbol_index);
--- a/src/share/vm/oops/method.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/oops/method.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -720,11 +720,22 @@
   }
 }
 
+bool Method::is_always_compilable() const {
+  // Generated adapters must be compiled
+  if (is_method_handle_intrinsic() && is_synthetic()) {
+    assert(!is_not_c1_compilable(), "sanity check");
+    assert(!is_not_c2_compilable(), "sanity check");
+    return true;
+  }
+
+  return false;
+}
+
 bool Method::is_not_compilable(int comp_level) const {
   if (number_of_breakpoints() > 0)
     return true;
-  if (is_method_handle_intrinsic())
-    return !is_synthetic();  // the generated adapters must be compiled
+  if (is_always_compilable())
+    return false;
   if (comp_level == CompLevel_any)
     return is_not_c1_compilable() || is_not_c2_compilable();
   if (is_c1_compile(comp_level))
@@ -736,6 +747,10 @@
 
 // call this when compiler finds that this method is not compilable
 void Method::set_not_compilable(int comp_level, bool report, const char* reason) {
+  if (is_always_compilable()) {
+    // Don't mark a method which should be always compilable
+    return;
+  }
   print_made_not_compilable(comp_level, /*is_osr*/ false, report, reason);
   if (comp_level == CompLevel_all) {
     set_not_c1_compilable();
--- a/src/share/vm/oops/method.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/oops/method.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -796,6 +796,7 @@
   void set_not_osr_compilable_quietly(int comp_level = CompLevel_all) {
     set_not_osr_compilable(comp_level, false);
   }
+  bool is_always_compilable() const;
 
  private:
   void print_made_not_compilable(int comp_level, bool is_osr, bool report, const char* reason);
--- a/src/share/vm/opto/block.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/block.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -112,9 +112,9 @@
 // exceeds OptoLoopAlignment.
 uint Block::compute_first_inst_size(uint& sum_size, uint inst_cnt,
                                     PhaseRegAlloc* ra) {
-  uint last_inst = _nodes.size();
+  uint last_inst = number_of_nodes();
   for( uint j = 0; j < last_inst && inst_cnt > 0; j++ ) {
-    uint inst_size = _nodes[j]->size(ra);
+    uint inst_size = get_node(j)->size(ra);
     if( inst_size > 0 ) {
       inst_cnt--;
       uint sz = sum_size + inst_size;
@@ -131,8 +131,8 @@
 }
 
 uint Block::find_node( const Node *n ) const {
-  for( uint i = 0; i < _nodes.size(); i++ ) {
-    if( _nodes[i] == n )
+  for( uint i = 0; i < number_of_nodes(); i++ ) {
+    if( get_node(i) == n )
       return i;
   }
   ShouldNotReachHere();
@@ -141,7 +141,7 @@
 
 // Find and remove n from block list
 void Block::find_remove( const Node *n ) {
-  _nodes.remove(find_node(n));
+  remove_node(find_node(n));
 }
 
 // Return empty status of a block.  Empty blocks contain only the head, other
@@ -154,10 +154,10 @@
   }
 
   int success_result = completely_empty;
-  int end_idx = _nodes.size()-1;
+  int end_idx = number_of_nodes() - 1;
 
   // Check for ending goto
-  if ((end_idx > 0) && (_nodes[end_idx]->is_MachGoto())) {
+  if ((end_idx > 0) && (get_node(end_idx)->is_MachGoto())) {
     success_result = empty_with_goto;
     end_idx--;
   }
@@ -170,7 +170,7 @@
   // Ideal nodes are allowable in empty blocks: skip them  Only MachNodes
   // turn directly into code, because only MachNodes have non-trivial
   // emit() functions.
-  while ((end_idx > 0) && !_nodes[end_idx]->is_Mach()) {
+  while ((end_idx > 0) && !get_node(end_idx)->is_Mach()) {
     end_idx--;
   }
 
@@ -209,15 +209,15 @@
 
 // True if block is low enough frequency or guarded by a test which
 // mostly does not go here.
-bool Block::is_uncommon(PhaseCFG* cfg) const {
+bool PhaseCFG::is_uncommon(const Block* block) {
   // Initial blocks must never be moved, so are never uncommon.
-  if (head()->is_Root() || head()->is_Start())  return false;
+  if (block->head()->is_Root() || block->head()->is_Start())  return false;
 
   // Check for way-low freq
-  if( _freq < BLOCK_FREQUENCY(0.00001f) ) return true;
+  if(block->_freq < BLOCK_FREQUENCY(0.00001f) ) return true;
 
   // Look for code shape indicating uncommon_trap or slow path
-  if (has_uncommon_code()) return true;
+  if (block->has_uncommon_code()) return true;
 
   const float epsilon = 0.05f;
   const float guard_factor = PROB_UNLIKELY_MAG(4) / (1.f - epsilon);
@@ -225,8 +225,8 @@
   uint freq_preds = 0;
   uint uncommon_for_freq_preds = 0;
 
-  for( uint i=1; i<num_preds(); i++ ) {
-    Block* guard = cfg->get_block_for_node(pred(i));
+  for( uint i=1; i< block->num_preds(); i++ ) {
+    Block* guard = get_block_for_node(block->pred(i));
     // Check to see if this block follows its guard 1 time out of 10000
     // or less.
     //
@@ -244,14 +244,14 @@
       uncommon_preds++;
     } else {
       freq_preds++;
-      if( _freq < guard->_freq * guard_factor ) {
+      if(block->_freq < guard->_freq * guard_factor ) {
         uncommon_for_freq_preds++;
       }
     }
   }
-  if( num_preds() > 1 &&
+  if( block->num_preds() > 1 &&
       // The block is uncommon if all preds are uncommon or
-      (uncommon_preds == (num_preds()-1) ||
+      (uncommon_preds == (block->num_preds()-1) ||
       // it is uncommon for all frequent preds.
        uncommon_for_freq_preds == freq_preds) ) {
     return true;
@@ -344,8 +344,8 @@
 
 void Block::dump(const PhaseCFG* cfg) const {
   dump_head(cfg);
-  for (uint i=0; i< _nodes.size(); i++) {
-    _nodes[i]->dump();
+  for (uint i=0; i< number_of_nodes(); i++) {
+    get_node(i)->dump();
   }
   tty->print("\n");
 }
@@ -434,7 +434,7 @@
       map_node_to_block(p, bb);
       map_node_to_block(x, bb);
       if( x != p ) {                // Only for root is x == p
-        bb->_nodes.push((Node*)x);
+        bb->push_node((Node*)x);
       }
       // Now handle predecessors
       ++sum;                        // Count 1 for self block
@@ -469,11 +469,11 @@
         assert( x != proj, "" );
         // Map basic block of projection
         map_node_to_block(proj, pb);
-        pb->_nodes.push(proj);
+        pb->push_node(proj);
       }
       // Insert self as a child of my predecessor block
       pb->_succs.map(pb->_num_succs++, get_block_for_node(np));
-      assert( pb->_nodes[ pb->_nodes.size() - pb->_num_succs ]->is_block_proj(),
+      assert( pb->get_node(pb->number_of_nodes() - pb->_num_succs)->is_block_proj(),
               "too many control users, not a CFG?" );
     }
   }
@@ -495,7 +495,7 @@
   // surrounding blocks.
   float freq = in->_freq * in->succ_prob(succ_no);
   // get ProjNode corresponding to the succ_no'th successor of the in block
-  ProjNode* proj = in->_nodes[in->_nodes.size() - in->_num_succs + succ_no]->as_Proj();
+  ProjNode* proj = in->get_node(in->number_of_nodes() - in->_num_succs + succ_no)->as_Proj();
   // create region for basic block
   RegionNode* region = new (C) RegionNode(2);
   region->init_req(1, proj);
@@ -507,7 +507,7 @@
   Node* gto = _goto->clone(); // get a new goto node
   gto->set_req(0, region);
   // add it to the basic block
-  block->_nodes.push(gto);
+  block->push_node(gto);
   map_node_to_block(gto, block);
   C->regalloc()->set_bad(gto->_idx);
   // hook up successor block
@@ -527,9 +527,9 @@
 // Does this block end in a multiway branch that cannot have the default case
 // flipped for another case?
 static bool no_flip_branch( Block *b ) {
-  int branch_idx = b->_nodes.size() - b->_num_succs-1;
+  int branch_idx = b->number_of_nodes() - b->_num_succs-1;
   if( branch_idx < 1 ) return false;
-  Node *bra = b->_nodes[branch_idx];
+  Node *bra = b->get_node(branch_idx);
   if( bra->is_Catch() )
     return true;
   if( bra->is_Mach() ) {
@@ -550,16 +550,16 @@
 void PhaseCFG::convert_NeverBranch_to_Goto(Block *b) {
   // Find true target
   int end_idx = b->end_idx();
-  int idx = b->_nodes[end_idx+1]->as_Proj()->_con;
+  int idx = b->get_node(end_idx+1)->as_Proj()->_con;
   Block *succ = b->_succs[idx];
   Node* gto = _goto->clone(); // get a new goto node
   gto->set_req(0, b->head());
-  Node *bp = b->_nodes[end_idx];
-  b->_nodes.map(end_idx,gto); // Slam over NeverBranch
+  Node *bp = b->get_node(end_idx);
+  b->map_node(gto, end_idx); // Slam over NeverBranch
   map_node_to_block(gto, b);
   C->regalloc()->set_bad(gto->_idx);
-  b->_nodes.pop();              // Yank projections
-  b->_nodes.pop();              // Yank projections
+  b->pop_node();              // Yank projections
+  b->pop_node();              // Yank projections
   b->_succs.map(0,succ);        // Map only successor
   b->_num_succs = 1;
   // remap successor's predecessors if necessary
@@ -575,8 +575,8 @@
   // Scan through block, yanking dead path from
   // all regions and phis.
   dead->head()->del_req(j);
-  for( int k = 1; dead->_nodes[k]->is_Phi(); k++ )
-    dead->_nodes[k]->del_req(j);
+  for( int k = 1; dead->get_node(k)->is_Phi(); k++ )
+    dead->get_node(k)->del_req(j);
 }
 
 // Helper function to move block bx to the slot following b_index. Return
@@ -620,7 +620,7 @@
   if (e != Block::not_empty) {
     if (e == Block::empty_with_goto) {
       // Remove the goto, but leave the block.
-      b->_nodes.pop();
+      b->pop_node();
     }
     // Mark this block as a connector block, which will cause it to be
     // ignored in certain functions such as non_connector_successor().
@@ -663,13 +663,13 @@
     // to give a fake exit path to infinite loops.  At this late stage they
     // need to turn into Goto's so that when you enter the infinite loop you
     // indeed hang.
-    if (block->_nodes[block->end_idx()]->Opcode() == Op_NeverBranch) {
+    if (block->get_node(block->end_idx())->Opcode() == Op_NeverBranch) {
       convert_NeverBranch_to_Goto(block);
     }
 
     // Look for uncommon blocks and move to end.
     if (!C->do_freq_based_layout()) {
-      if (block->is_uncommon(this)) {
+      if (is_uncommon(block)) {
         move_to_end(block, i);
         last--;                   // No longer check for being uncommon!
         if (no_flip_branch(block)) { // Fall-thru case must follow?
@@ -720,9 +720,9 @@
     // exchange the true and false targets.
     if (no_flip_branch(block)) {
       // Find fall through case - if must fall into its target
-      int branch_idx = block->_nodes.size() - block->_num_succs;
+      int branch_idx = block->number_of_nodes() - block->_num_succs;
       for (uint j2 = 0; j2 < block->_num_succs; j2++) {
-        const ProjNode* p = block->_nodes[branch_idx + j2]->as_Proj();
+        const ProjNode* p = block->get_node(branch_idx + j2)->as_Proj();
         if (p->_con == 0) {
           // successor j2 is fall through case
           if (block->non_connector_successor(j2) != bnext) {
@@ -743,14 +743,14 @@
 
       // Remove all CatchProjs
       for (uint j = 0; j < block->_num_succs; j++) {
-        block->_nodes.pop();
+        block->pop_node();
       }
 
     } else if (block->_num_succs == 1) {
       // Block ends in a Goto?
       if (bnext == bs0) {
         // We fall into next block; remove the Goto
-        block->_nodes.pop();
+        block->pop_node();
       }
 
     } else if(block->_num_succs == 2) { // Block ends in a If?
@@ -759,9 +759,9 @@
       //       be projections (in any order), the 3rd last node must be
       //       the IfNode (we have excluded other 2-way exits such as
       //       CatchNodes already).
-      MachNode* iff   = block->_nodes[block->_nodes.size() - 3]->as_Mach();
-      ProjNode* proj0 = block->_nodes[block->_nodes.size() - 2]->as_Proj();
-      ProjNode* proj1 = block->_nodes[block->_nodes.size() - 1]->as_Proj();
+      MachNode* iff   = block->get_node(block->number_of_nodes() - 3)->as_Mach();
+      ProjNode* proj0 = block->get_node(block->number_of_nodes() - 2)->as_Proj();
+      ProjNode* proj1 = block->get_node(block->number_of_nodes() - 1)->as_Proj();
 
       // Assert that proj0 and succs[0] match up. Similarly for proj1 and succs[1].
       assert(proj0->raw_out(0) == block->_succs[0]->head(), "Mismatch successor 0");
@@ -833,8 +833,8 @@
         iff->as_MachIf()->negate();
       }
 
-      block->_nodes.pop();          // Remove IfFalse & IfTrue projections
-      block->_nodes.pop();
+      block->pop_node();          // Remove IfFalse & IfTrue projections
+      block->pop_node();
 
     } else {
       // Multi-exit block, e.g. a switch statement
@@ -895,13 +895,13 @@
   // Verify sane CFG
   for (uint i = 0; i < number_of_blocks(); i++) {
     Block* block = get_block(i);
-    uint cnt = block->_nodes.size();
+    uint cnt = block->number_of_nodes();
     uint j;
     for (j = 0; j < cnt; j++)  {
-      Node *n = block->_nodes[j];
+      Node *n = block->get_node(j);
       assert(get_block_for_node(n) == block, "");
       if (j >= 1 && n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_CreateEx) {
-        assert(j == 1 || block->_nodes[j-1]->is_Phi(), "CreateEx must be first instruction in block");
+        assert(j == 1 || block->get_node(j-1)->is_Phi(), "CreateEx must be first instruction in block");
       }
       for (uint k = 0; k < n->req(); k++) {
         Node *def = n->in(k);
@@ -930,14 +930,14 @@
     }
 
     j = block->end_idx();
-    Node* bp = (Node*)block->_nodes[block->_nodes.size() - 1]->is_block_proj();
+    Node* bp = (Node*)block->get_node(block->number_of_nodes() - 1)->is_block_proj();
     assert(bp, "last instruction must be a block proj");
-    assert(bp == block->_nodes[j], "wrong number of successors for this block");
+    assert(bp == block->get_node(j), "wrong number of successors for this block");
     if (bp->is_Catch()) {
-      while (block->_nodes[--j]->is_MachProj()) {
+      while (block->get_node(--j)->is_MachProj()) {
         ;
       }
-      assert(block->_nodes[j]->is_MachCall(), "CatchProj must follow call");
+      assert(block->get_node(j)->is_MachCall(), "CatchProj must follow call");
     } else if (bp->is_Mach() && bp->as_Mach()->ideal_Opcode() == Op_If) {
       assert(block->_num_succs == 2, "Conditional branch must have two targets");
     }
@@ -1440,9 +1440,9 @@
           Block *bnext = next(b);
           Block *bs0 = b->non_connector_successor(0);
 
-          MachNode *iff = b->_nodes[b->_nodes.size()-3]->as_Mach();
-          ProjNode *proj0 = b->_nodes[b->_nodes.size()-2]->as_Proj();
-          ProjNode *proj1 = b->_nodes[b->_nodes.size()-1]->as_Proj();
+          MachNode *iff = b->get_node(b->number_of_nodes() - 3)->as_Mach();
+          ProjNode *proj0 = b->get_node(b->number_of_nodes() - 2)->as_Proj();
+          ProjNode *proj1 = b->get_node(b->number_of_nodes() - 1)->as_Proj();
 
           if (bnext == bs0) {
             // Fall-thru case in succs[0], should be in succs[1]
@@ -1454,8 +1454,8 @@
             b->_succs.map( 1, tbs0 );
 
             // Flip projections to match targets
-            b->_nodes.map(b->_nodes.size()-2, proj1);
-            b->_nodes.map(b->_nodes.size()-1, proj0);
+            b->map_node(proj1, b->number_of_nodes() - 2);
+            b->map_node(proj0, b->number_of_nodes() - 1);
           }
         }
       }
--- a/src/share/vm/opto/block.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/block.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -105,15 +105,53 @@
 // any optimization pass.  They are created late in the game.
 class Block : public CFGElement {
   friend class VMStructs;
- public:
+
+private:
   // Nodes in this block, in order
   Node_List _nodes;
 
+public:
+
+  // Get the node at index 'at_index', if 'at_index' is out of bounds return NULL
+  Node* get_node(uint at_index) const {
+    return _nodes[at_index];
+  }
+
+  // Get the number of nodes in this block
+  uint number_of_nodes() const {
+    return _nodes.size();
+  }
+
+  // Map a node 'node' to index 'to_index' in the block, if the index is out of bounds the size of the node list is increased
+  void map_node(Node* node, uint to_index) {
+    _nodes.map(to_index, node);
+  }
+
+  // Insert a node 'node' at index 'at_index', moving all nodes that are on a higher index one step, if 'at_index' is out of bounds we crash
+  void insert_node(Node* node, uint at_index) {
+    _nodes.insert(at_index, node);
+  }
+
+  // Remove a node at index 'at_index'
+  void remove_node(uint at_index) {
+    _nodes.remove(at_index);
+  }
+
+  // Push a node 'node' onto the node list
+  void push_node(Node* node) {
+    _nodes.push(node);
+  }
+
+  // Pop the last node off the node list
+  Node* pop_node() {
+    return _nodes.pop();
+  }
+
   // Basic blocks have a Node which defines Control for all Nodes pinned in
   // this block.  This Node is a RegionNode.  Exception-causing Nodes
   // (division, subroutines) and Phi functions are always pinned.  Later,
   // every Node will get pinned to some block.
-  Node *head() const { return _nodes[0]; }
+  Node *head() const { return get_node(0); }
 
   // CAUTION: num_preds() is ONE based, so that predecessor numbers match
   // input edges to Regions and Phis.
@@ -274,29 +312,12 @@
 
   // Add an instruction to an existing block.  It must go after the head
   // instruction and before the end instruction.
-  void add_inst( Node *n ) { _nodes.insert(end_idx(),n); }
+  void add_inst( Node *n ) { insert_node(n, end_idx()); }
   // Find node in block
   uint find_node( const Node *n ) const;
   // Find and remove n from block list
   void find_remove( const Node *n );
 
-  // helper function that adds caller save registers to MachProjNode
-  void add_call_kills(MachProjNode *proj, RegMask& regs, const char* save_policy, bool exclude_soe);
-  // Schedule a call next in the block
-  uint sched_call(Matcher &matcher, PhaseCFG* cfg, uint node_cnt, Node_List &worklist, GrowableArray<int> &ready_cnt, MachCallNode *mcall, VectorSet &next_call);
-
-  // Perform basic-block local scheduling
-  Node *select(PhaseCFG *cfg, Node_List &worklist, GrowableArray<int> &ready_cnt, VectorSet &next_call, uint sched_slot);
-  void set_next_call( Node *n, VectorSet &next_call, PhaseCFG* cfg);
-  void needed_for_next_call(Node *this_call, VectorSet &next_call, PhaseCFG* cfg);
-  bool schedule_local(PhaseCFG *cfg, Matcher &m, GrowableArray<int> &ready_cnt, VectorSet &next_call);
-  // Cleanup if any code lands between a Call and his Catch
-  void call_catch_cleanup(PhaseCFG* cfg, Compile *C);
-  // Detect implicit-null-check opportunities.  Basically, find NULL checks
-  // with suitable memory ops nearby.  Use the memory op to do the NULL check.
-  // I can generate a memory op if there is not one nearby.
-  void implicit_null_check(PhaseCFG *cfg, Node *proj, Node *val, int allowed_reasons);
-
   // Return the empty status of a block
   enum { not_empty, empty_with_goto, completely_empty };
   int is_Empty() const;
@@ -328,10 +349,6 @@
   // Examine block's code shape to predict if it is not commonly executed.
   bool has_uncommon_code() const;
 
-  // Use frequency calculations and code shape to predict if the block
-  // is uncommon.
-  bool is_uncommon(PhaseCFG* cfg) const;
-
 #ifndef PRODUCT
   // Debugging print of basic block
   void dump_bidx(const Block* orig, outputStream* st = tty) const;
@@ -414,6 +431,27 @@
   // to late. Helper for schedule_late.
   Block* hoist_to_cheaper_block(Block* LCA, Block* early, Node* self);
 
+  bool schedule_local(Block* block, GrowableArray<int>& ready_cnt, VectorSet& next_call);
+  void set_next_call(Block* block, Node* n, VectorSet& next_call);
+  void needed_for_next_call(Block* block, Node* this_call, VectorSet& next_call);
+
+  // Perform basic-block local scheduling
+  Node* select(Block* block, Node_List& worklist, GrowableArray<int>& ready_cnt, VectorSet& next_call, uint sched_slot);
+
+  // Schedule a call next in the block
+  uint sched_call(Block* block, uint node_cnt, Node_List& worklist, GrowableArray<int>& ready_cnt, MachCallNode* mcall, VectorSet& next_call);
+
+  // Cleanup if any code lands between a Call and his Catch
+  void call_catch_cleanup(Block* block);
+
+  Node* catch_cleanup_find_cloned_def(Block* use_blk, Node* def, Block* def_blk, int n_clone_idx);
+  void  catch_cleanup_inter_block(Node *use, Block *use_blk, Node *def, Block *def_blk, int n_clone_idx);
+
+  // Detect implicit-null-check opportunities.  Basically, find NULL checks
+  // with suitable memory ops nearby.  Use the memory op to do the NULL check.
+  // I can generate a memory op if there is not one nearby.
+  void implicit_null_check(Block* block, Node *proj, Node *val, int allowed_reasons);
+
   // Perform a Depth First Search (DFS).
   // Setup 'vertex' as DFS to vertex mapping.
   // Setup 'semi' as vertex to DFS mapping.
@@ -530,6 +568,10 @@
     return (_node_to_block_mapping.lookup(node->_idx) != NULL);
   }
 
+  // Use frequency calculations and code shape to predict if the block
+  // is uncommon.
+  bool is_uncommon(const Block* block);
+
 #ifdef ASSERT
   Unique_Node_List _raw_oops;
 #endif
@@ -550,7 +592,7 @@
 
   // Insert a node into a block at index and map the node to the block
   void insert(Block *b, uint idx, Node *n) {
-    b->_nodes.insert( idx, n );
+    b->insert_node(n , idx);
     map_node_to_block(n, b);
   }
 
--- a/src/share/vm/opto/buildOopMap.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/buildOopMap.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -121,8 +121,8 @@
 // Given reaching-defs for this block start, compute it for this block end
 void OopFlow::compute_reach( PhaseRegAlloc *regalloc, int max_reg, Dict *safehash ) {
 
-  for( uint i=0; i<_b->_nodes.size(); i++ ) {
-    Node *n = _b->_nodes[i];
+  for( uint i=0; i<_b->number_of_nodes(); i++ ) {
+    Node *n = _b->get_node(i);
 
     if( n->jvms() ) {           // Build an OopMap here?
       JVMState *jvms = n->jvms();
@@ -447,8 +447,8 @@
       }
 
       // Now walk tmp_live up the block backwards, computing live
-      for( int k=b->_nodes.size()-1; k>=0; k-- ) {
-        Node *n = b->_nodes[k];
+      for( int k=b->number_of_nodes()-1; k>=0; k-- ) {
+        Node *n = b->get_node(k);
         // KILL def'd bits
         int first = regalloc->get_reg_first(n);
         int second = regalloc->get_reg_second(n);
@@ -544,12 +544,12 @@
     for (i = 1; i < cfg->number_of_blocks(); i++) {
       Block* block = cfg->get_block(i);
       uint j;
-      for (j = 1; j < block->_nodes.size(); j++) {
-        if (block->_nodes[j]->jvms() && (*safehash)[block->_nodes[j]] == NULL) {
+      for (j = 1; j < block->number_of_nodes(); j++) {
+        if (block->get_node(j)->jvms() && (*safehash)[block->get_node(j)] == NULL) {
            break;
         }
       }
-      if (j < block->_nodes.size()) {
+      if (j < block->number_of_nodes()) {
         break;
       }
     }
--- a/src/share/vm/opto/c2_globals.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/c2_globals.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -421,7 +421,7 @@
   product(bool, UseDivMod, true,                                            \
           "Use combined DivMod instruction if available")                   \
                                                                             \
-  product(intx, MinJumpTableSize, 18,                                       \
+  product_pd(intx, MinJumpTableSize,                                        \
           "Minimum number of targets in a generated jump table")            \
                                                                             \
   product(intx, MaxJumpTableSize, 65000,                                    \
@@ -448,6 +448,9 @@
   product(bool, EliminateAutoBox, true,                                     \
           "Control optimizations for autobox elimination")                  \
                                                                             \
+  experimental(bool, UseImplicitStableValues, false,                        \
+          "Mark well-known stable fields as such (e.g. String.value)")      \
+                                                                            \
   product(intx, AutoBoxCacheMax, 128,                                       \
           "Sets max value cached by the java.lang.Integer autobox cache")   \
                                                                             \
--- a/src/share/vm/opto/callnode.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/callnode.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -458,7 +458,7 @@
       st->print("={");
       uint nf = spobj->n_fields();
       if (nf > 0) {
-        uint first_ind = spobj->first_index();
+        uint first_ind = spobj->first_index(mcall->jvms());
         Node* fld_node = mcall->in(first_ind);
         ciField* cifield;
         if (iklass != NULL) {
@@ -1063,7 +1063,6 @@
   int scloff = jvms->scloff();
   int endoff = jvms->endoff();
   assert(endoff == (int)req(), "no other states or debug info after me");
-  assert(jvms->scl_size() == 0, "parsed code should not have scalar objects");
   Node* top = Compile::current()->top();
   for (uint i = 0; i < grow_by; i++) {
     ins_req(monoff, top);
@@ -1079,32 +1078,31 @@
   const int MonitorEdges = 2;
   assert(JVMState::logMonitorEdges == exact_log2(MonitorEdges), "correct MonitorEdges");
   assert(req() == jvms()->endoff(), "correct sizing");
-  assert((jvms()->scl_size() == 0), "parsed code should not have scalar objects");
   int nextmon = jvms()->scloff();
   if (GenerateSynchronizationCode) {
-    add_req(lock->box_node());
-    add_req(lock->obj_node());
+    ins_req(nextmon,   lock->box_node());
+    ins_req(nextmon+1, lock->obj_node());
   } else {
     Node* top = Compile::current()->top();
-    add_req(top);
-    add_req(top);
+    ins_req(nextmon, top);
+    ins_req(nextmon, top);
   }
-  jvms()->set_scloff(nextmon+MonitorEdges);
+  jvms()->set_scloff(nextmon + MonitorEdges);
   jvms()->set_endoff(req());
 }
 
 void SafePointNode::pop_monitor() {
   // Delete last monitor from debug info
-  assert((jvms()->scl_size() == 0), "parsed code should not have scalar objects");
   debug_only(int num_before_pop = jvms()->nof_monitors());
-  const int MonitorEdges = (1<<JVMState::logMonitorEdges);
+  const int MonitorEdges = 2;
+  assert(JVMState::logMonitorEdges == exact_log2(MonitorEdges), "correct MonitorEdges");
   int scloff = jvms()->scloff();
   int endoff = jvms()->endoff();
   int new_scloff = scloff - MonitorEdges;
   int new_endoff = endoff - MonitorEdges;
   jvms()->set_scloff(new_scloff);
   jvms()->set_endoff(new_endoff);
-  while (scloff > new_scloff)  del_req(--scloff);
+  while (scloff > new_scloff)  del_req_ordered(--scloff);
   assert(jvms()->nof_monitors() == num_before_pop-1, "");
 }
 
@@ -1169,13 +1167,12 @@
 }
 
 SafePointScalarObjectNode*
-SafePointScalarObjectNode::clone(int jvms_adj, Dict* sosn_map) const {
+SafePointScalarObjectNode::clone(Dict* sosn_map) const {
   void* cached = (*sosn_map)[(void*)this];
   if (cached != NULL) {
     return (SafePointScalarObjectNode*)cached;
   }
   SafePointScalarObjectNode* res = (SafePointScalarObjectNode*)Node::clone();
-  res->_first_index += jvms_adj;
   sosn_map->Insert((void*)this, (void*)res);
   return res;
 }
--- a/src/share/vm/opto/callnode.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/callnode.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -449,14 +449,17 @@
 // at a safepoint.
 
 class SafePointScalarObjectNode: public TypeNode {
-  uint _first_index; // First input edge index of a SafePoint node where
+  uint _first_index; // First input edge relative index of a SafePoint node where
                      // states of the scalarized object fields are collected.
+                     // It is relative to the last (youngest) jvms->_scloff.
   uint _n_fields;    // Number of non-static fields of the scalarized object.
   DEBUG_ONLY(AllocateNode* _alloc;)
 
   virtual uint hash() const ; // { return NO_HASH; }
   virtual uint cmp( const Node &n ) const;
 
+  uint first_index() const { return _first_index; }
+
 public:
   SafePointScalarObjectNode(const TypeOopPtr* tp,
 #ifdef ASSERT
@@ -469,7 +472,10 @@
   virtual const RegMask &out_RegMask() const;
   virtual uint           match_edge(uint idx) const;
 
-  uint first_index() const { return _first_index; }
+  uint first_index(JVMState* jvms) const {
+    assert(jvms != NULL, "missed JVMS");
+    return jvms->scloff() + _first_index;
+  }
   uint n_fields()    const { return _n_fields; }
 
 #ifdef ASSERT
@@ -485,7 +491,7 @@
   // corresponds appropriately to "this" in "new_call".  Assumes that
   // "sosn_map" is a map, specific to the translation of "s" to "new_call",
   // mapping old SafePointScalarObjectNodes to new, to avoid multiple copies.
-  SafePointScalarObjectNode* clone(int jvms_adj, Dict* sosn_map) const;
+  SafePointScalarObjectNode* clone(Dict* sosn_map) const;
 
 #ifndef PRODUCT
   virtual void              dump_spec(outputStream *st) const;
--- a/src/share/vm/opto/chaitin.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/chaitin.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -301,7 +301,7 @@
       // Copy kill projections after the cloned node
       Node* kills = proj->clone();
       kills->set_req(0, copy);
-      b->_nodes.insert(idx++, kills);
+      b->insert_node(kills, idx++);
       _cfg.map_node_to_block(kills, b);
       new_lrg(kills, max_lrg_id++);
     }
@@ -682,11 +682,11 @@
   uint lr_counter = 1;
   for( uint i = 0; i < _cfg.number_of_blocks(); i++ ) {
     Block* block = _cfg.get_block(i);
-    uint cnt = block->_nodes.size();
+    uint cnt = block->number_of_nodes();
 
     // Handle all the normal Nodes in the block
     for( uint j = 0; j < cnt; j++ ) {
-      Node *n = block->_nodes[j];
+      Node *n = block->get_node(j);
       // Pre-color to the zero live range, or pick virtual register
       const RegMask &rm = n->out_RegMask();
       _lrg_map.map(n->_idx, rm.is_NotEmpty() ? lr_counter++ : 0);
@@ -710,8 +710,8 @@
     Block* block = _cfg.get_block(i);
 
     // For all instructions
-    for (uint j = 1; j < block->_nodes.size(); j++) {
-      Node* n = block->_nodes[j];
+    for (uint j = 1; j < block->number_of_nodes(); j++) {
+      Node* n = block->get_node(j);
       uint input_edge_start =1; // Skip control most nodes
       if (n->is_Mach()) {
         input_edge_start = n->as_Mach()->oper_input_base();
@@ -1604,7 +1604,7 @@
     // For all instructions in block
     uint last_inst = block->end_idx();
     for (uint j = 1; j <= last_inst; j++) {
-      Node* n = block->_nodes[j];
+      Node* n = block->get_node(j);
 
       // Dead instruction???
       assert( n->outcnt() != 0 ||// Nothing dead after post alloc
@@ -1641,7 +1641,7 @@
             assert( cisc->oper_input_base() == 2, "Only adding one edge");
             cisc->ins_req(1,src);         // Requires a memory edge
           }
-          block->_nodes.map(j,cisc);          // Insert into basic block
+          block->map_node(cisc, j);          // Insert into basic block
           n->subsume_by(cisc, C); // Correct graph
           //
           ++_used_cisc_instructions;
@@ -1698,7 +1698,7 @@
       // (where top() node is placed).
       base->init_req(0, _cfg.get_root_node());
       Block *startb = _cfg.get_block_for_node(C->top());
-      startb->_nodes.insert(startb->find_node(C->top()), base );
+      startb->insert_node(base, startb->find_node(C->top()));
       _cfg.map_node_to_block(base, startb);
       assert(_lrg_map.live_range_id(base) == 0, "should not have LRG yet");
     }
@@ -1743,9 +1743,9 @@
   // Search the current block for an existing base-Phi
   Block *b = _cfg.get_block_for_node(derived);
   for( i = 1; i <= b->end_idx(); i++ ) {// Search for matching Phi
-    Node *phi = b->_nodes[i];
+    Node *phi = b->get_node(i);
     if( !phi->is_Phi() ) {      // Found end of Phis with no match?
-      b->_nodes.insert( i, base ); // Must insert created Phi here as base
+      b->insert_node(base,  i); // Must insert created Phi here as base
       _cfg.map_node_to_block(base, b);
       new_lrg(base,maxlrg++);
       break;
@@ -1786,7 +1786,7 @@
     IndexSet liveout(_live->live(block));
 
     for (uint j = block->end_idx() + 1; j > 1; j--) {
-      Node* n = block->_nodes[j - 1];
+      Node* n = block->get_node(j - 1);
 
       // Pre-split compares of loop-phis.  Loop-phis form a cycle we would
       // like to see in the same register.  Compare uses the loop-phi and so
@@ -1979,8 +1979,8 @@
   b->dump_head(&_cfg);
 
   // For all instructions
-  for( uint j = 0; j < b->_nodes.size(); j++ )
-    dump(b->_nodes[j]);
+  for( uint j = 0; j < b->number_of_nodes(); j++ )
+    dump(b->get_node(j));
   // Print live-out info at end of block
   if( _live ) {
     tty->print("Liveout: ");
@@ -2271,8 +2271,8 @@
     int dump_once = 0;
 
     // For all instructions
-    for( uint j = 0; j < block->_nodes.size(); j++ ) {
-      Node *n = block->_nodes[j];
+    for( uint j = 0; j < block->number_of_nodes(); j++ ) {
+      Node *n = block->get_node(j);
       if (_lrg_map.find_const(n) == lidx) {
         if (!dump_once++) {
           tty->cr();
--- a/src/share/vm/opto/coalesce.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/coalesce.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -54,9 +54,9 @@
     for( j=0; j<b->_num_succs; j++ )
       tty->print("B%d ",b->_succs[j]->_pre_order);
     tty->print(" IDom: B%d/#%d\n", b->_idom ? b->_idom->_pre_order : 0, b->_dom_depth);
-    uint cnt = b->_nodes.size();
+    uint cnt = b->number_of_nodes();
     for( j=0; j<cnt; j++ ) {
-      Node *n = b->_nodes[j];
+      Node *n = b->get_node(j);
       dump( n );
       tty->print("\t%s\t",n->Name());
 
@@ -152,7 +152,7 @@
   // after the last use.  Last use is really first-use on a backwards scan.
   uint i = b->end_idx()-1;
   while(1) {
-    Node *n = b->_nodes[i];
+    Node *n = b->get_node(i);
     // Check for end of virtual copies; this is also the end of the
     // parallel renaming effort.
     if (n->_idx < _unique) {
@@ -174,7 +174,7 @@
   // the last kill.  Thus it is the first kill on a backwards scan.
   i = b->end_idx()-1;
   while (1) {
-    Node *n = b->_nodes[i];
+    Node *n = b->get_node(i);
     // Check for end of virtual copies; this is also the end of the
     // parallel renaming effort.
     if (n->_idx < _unique) {
@@ -200,13 +200,13 @@
     tmp ->set_req(idx,copy->in(idx));
     copy->set_req(idx,tmp);
     // Save source in temp early, before source is killed
-    b->_nodes.insert(kill_src_idx,tmp);
+    b->insert_node(tmp, kill_src_idx);
     _phc._cfg.map_node_to_block(tmp, b);
     last_use_idx++;
   }
 
   // Insert just after last use
-  b->_nodes.insert(last_use_idx+1,copy);
+  b->insert_node(copy, last_use_idx + 1);
 }
 
 void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) {
@@ -237,8 +237,8 @@
     Block *b = _phc._cfg.get_block(i);
     uint cnt = b->num_preds();  // Number of inputs to the Phi
 
-    for( uint l = 1; l<b->_nodes.size(); l++ ) {
-      Node *n = b->_nodes[l];
+    for( uint l = 1; l<b->number_of_nodes(); l++ ) {
+      Node *n = b->get_node(l);
 
       // Do not use removed-copies, use copied value instead
       uint ncnt = n->req();
@@ -260,7 +260,7 @@
         if (_phc._lrg_map.find(n) == _phc._lrg_map.find(def)) {
           n->replace_by(def);
           n->set_req(cidx,NULL);
-          b->_nodes.remove(l);
+          b->remove_node(l);
           l--;
           continue;
         }
@@ -321,13 +321,13 @@
                m->as_Mach()->rematerialize()) {
               copy = m->clone();
               // Insert the copy in the basic block, just before us
-              b->_nodes.insert(l++, copy);
+              b->insert_node(copy, l++);
               l += _phc.clone_projs(b, l, m, copy, _phc._lrg_map);
             } else {
               const RegMask *rm = C->matcher()->idealreg2spillmask[m->ideal_reg()];
               copy = new (C) MachSpillCopyNode(m, *rm, *rm);
               // Insert the copy in the basic block, just before us
-              b->_nodes.insert(l++, copy);
+              b->insert_node(copy, l++);
             }
             // Insert the copy in the use-def chain
             n->set_req(idx, copy);
@@ -339,7 +339,7 @@
         } // End of is two-adr
 
         // Insert a copy at a debug use for a lrg which has high frequency
-        if (b->_freq < OPTO_DEBUG_SPLIT_FREQ || b->is_uncommon(&_phc._cfg)) {
+        if (b->_freq < OPTO_DEBUG_SPLIT_FREQ || _phc._cfg.is_uncommon(b)) {
           // Walk the debug inputs to the node and check for lrg freq
           JVMState* jvms = n->jvms();
           uint debug_start = jvms ? jvms->debug_start() : 999999;
@@ -376,7 +376,7 @@
               // Insert the copy in the use-def chain
               n->set_req(inpidx, copy );
               // Insert the copy in the basic block, just before us
-              b->_nodes.insert( l++, copy );
+              b->insert_node(copy,  l++);
               // Extend ("register allocate") the names array for the copy.
               uint max_lrg_id = _phc._lrg_map.max_lrg_id();
               _phc.new_lrg(copy, max_lrg_id);
@@ -431,8 +431,8 @@
     }
 
     // Visit all the Phis in successor block
-    for( uint k = 1; k<bs->_nodes.size(); k++ ) {
-      Node *n = bs->_nodes[k];
+    for( uint k = 1; k<bs->number_of_nodes(); k++ ) {
+      Node *n = bs->get_node(k);
       if( !n->is_Phi() ) break;
       combine_these_two( n, n->in(j) );
     }
@@ -442,7 +442,7 @@
   // Check _this_ block for 2-address instructions and copies.
   uint cnt = b->end_idx();
   for( i = 1; i<cnt; i++ ) {
-    Node *n = b->_nodes[i];
+    Node *n = b->get_node(i);
     uint idx;
     // 2-address instructions have a virtual Copy matching their input
     // to their output
@@ -490,10 +490,10 @@
   dst_copy->set_req( didx, src_def );
   // Add copy to free list
   // _phc.free_spillcopy(b->_nodes[bindex]);
-  assert( b->_nodes[bindex] == dst_copy, "" );
+  assert( b->get_node(bindex) == dst_copy, "" );
   dst_copy->replace_by( dst_copy->in(didx) );
   dst_copy->set_req( didx, NULL);
-  b->_nodes.remove(bindex);
+  b->remove_node(bindex);
   if( bindex < b->_ihrp_index ) b->_ihrp_index--;
   if( bindex < b->_fhrp_index ) b->_fhrp_index--;
 
@@ -523,8 +523,8 @@
       bindex2 = b2->end_idx()-1;
     }
     // Get prior instruction
-    assert(bindex2 < b2->_nodes.size(), "index out of bounds");
-    Node *x = b2->_nodes[bindex2];
+    assert(bindex2 < b2->number_of_nodes(), "index out of bounds");
+    Node *x = b2->get_node(bindex2);
     if( x == prev_copy ) {      // Previous copy in copy chain?
       if( prev_copy == src_copy)// Found end of chain and all interferences
         break;                  // So break out of loop
@@ -769,14 +769,14 @@
 // Conservative (but pessimistic) copy coalescing of a single block
 void PhaseConservativeCoalesce::coalesce( Block *b ) {
   // Bail out on infrequent blocks
-  if (b->is_uncommon(&_phc._cfg)) {
+  if (_phc._cfg.is_uncommon(b)) {
     return;
   }
   // Check this block for copies.
   for( uint i = 1; i<b->end_idx(); i++ ) {
     // Check for actual copies on inputs.  Coalesce a copy into its
     // input if use and copy's input are compatible.
-    Node *copy1 = b->_nodes[i];
+    Node *copy1 = b->get_node(i);
     uint idx1 = copy1->is_Copy();
     if( !idx1 ) continue;       // Not a copy
 
--- a/src/share/vm/opto/compile.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/compile.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -1297,6 +1297,10 @@
 
   // Array pointers need some flattening
   const TypeAryPtr *ta = tj->isa_aryptr();
+  if (ta && ta->is_stable()) {
+    // Erase stability property for alias analysis.
+    tj = ta = ta->cast_to_stable(false);
+  }
   if( ta && is_known_inst ) {
     if ( offset != Type::OffsetBot &&
          offset > arrayOopDesc::length_offset_in_bytes() ) {
@@ -1497,6 +1501,7 @@
   _index = i;
   _adr_type = at;
   _field = NULL;
+  _element = NULL;
   _is_rewritable = true; // default
   const TypeOopPtr *atoop = (at != NULL) ? at->isa_oopptr() : NULL;
   if (atoop != NULL && atoop->is_known_instance()) {
@@ -1615,6 +1620,16 @@
           && flat->is_instptr()->klass() == env()->Class_klass())
         alias_type(idx)->set_rewritable(false);
     }
+    if (flat->isa_aryptr()) {
+#ifdef ASSERT
+      const int header_size_min  = arrayOopDesc::base_offset_in_bytes(T_BYTE);
+      // (T_BYTE has the weakest alignment and size restrictions...)
+      assert(flat->offset() < header_size_min, "array body reference must be OffsetBot");
+#endif
+      if (flat->offset() == TypePtr::OffsetBot) {
+        alias_type(idx)->set_element(flat->is_aryptr()->elem());
+      }
+    }
     if (flat->isa_klassptr()) {
       if (flat->offset() == in_bytes(Klass::super_check_offset_offset()))
         alias_type(idx)->set_rewritable(false);
@@ -1677,7 +1692,7 @@
   else
     t = TypeOopPtr::make_from_klass_raw(field->holder());
   AliasType* atp = alias_type(t->add_offset(field->offset_in_bytes()), field);
-  assert(field->is_final() == !atp->is_rewritable(), "must get the rewritable bits correct");
+  assert((field->is_final() || field->is_stable()) == !atp->is_rewritable(), "must get the rewritable bits correct");
   return atp;
 }
 
@@ -2258,7 +2273,7 @@
     if (block->is_connector() && !Verbose) {
       continue;
     }
-    n = block->_nodes[0];
+    n = block->head();
     if (pcs && n->_idx < pc_limit) {
       tty->print("%3.3x   ", pcs[n->_idx]);
     } else {
@@ -2273,12 +2288,12 @@
 
     // For all instructions
     Node *delay = NULL;
-    for (uint j = 0; j < block->_nodes.size(); j++) {
+    for (uint j = 0; j < block->number_of_nodes(); j++) {
       if (VMThread::should_terminate()) {
         cut_short = true;
         break;
       }
-      n = block->_nodes[j];
+      n = block->get_node(j);
       if (valid_bundle_info(n)) {
         Bundle* bundle = node_bundling(n);
         if (bundle->used_in_unconditional_delay()) {
--- a/src/share/vm/opto/compile.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/compile.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -72,6 +72,7 @@
 class StartNode;
 class SafePointNode;
 class JVMState;
+class Type;
 class TypeData;
 class TypePtr;
 class TypeOopPtr;
@@ -119,6 +120,7 @@
     int             _index;         // unique index, used with MergeMemNode
     const TypePtr*  _adr_type;      // normalized address type
     ciField*        _field;         // relevant instance field, or null if none
+    const Type*     _element;       // relevant array element type, or null if none
     bool            _is_rewritable; // false if the memory is write-once only
     int             _general_index; // if this is type is an instance, the general
                                     // type that this is an instance of
@@ -129,6 +131,7 @@
     int             index()         const { return _index; }
     const TypePtr*  adr_type()      const { return _adr_type; }
     ciField*        field()         const { return _field; }
+    const Type*     element()       const { return _element; }
     bool            is_rewritable() const { return _is_rewritable; }
     bool            is_volatile()   const { return (_field ? _field->is_volatile() : false); }
     int             general_index() const { return (_general_index != 0) ? _general_index : _index; }
@@ -137,7 +140,14 @@
     void set_field(ciField* f) {
       assert(!_field,"");
       _field = f;
-      if (f->is_final())  _is_rewritable = false;
+      if (f->is_final() || f->is_stable()) {
+        // In the case of @Stable, multiple writes are possible but may be assumed to be no-ops.
+        _is_rewritable = false;
+      }
+    }
+    void set_element(const Type* e) {
+      assert(_element == NULL, "");
+      _element = e;
     }
 
     void print_on(outputStream* st) PRODUCT_RETURN;
--- a/src/share/vm/opto/domgraph.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/domgraph.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -211,21 +211,21 @@
 uint Block_Stack::most_frequent_successor( Block *b ) {
   uint freq_idx = 0;
   int eidx = b->end_idx();
-  Node *n = b->_nodes[eidx];
+  Node *n = b->get_node(eidx);
   int op = n->is_Mach() ? n->as_Mach()->ideal_Opcode() : n->Opcode();
   switch( op ) {
   case Op_CountedLoopEnd:
   case Op_If: {               // Split frequency amongst children
     float prob = n->as_MachIf()->_prob;
     // Is succ[0] the TRUE branch or the FALSE branch?
-    if( b->_nodes[eidx+1]->Opcode() == Op_IfFalse )
+    if( b->get_node(eidx+1)->Opcode() == Op_IfFalse )
       prob = 1.0f - prob;
     freq_idx = prob < PROB_FAIR;      // freq=1 for succ[0] < 0.5 prob
     break;
   }
   case Op_Catch:                // Split frequency amongst children
     for( freq_idx = 0; freq_idx < b->_num_succs; freq_idx++ )
-      if( b->_nodes[eidx+1+freq_idx]->as_CatchProj()->_con == CatchProjNode::fall_through_index )
+      if( b->get_node(eidx+1+freq_idx)->as_CatchProj()->_con == CatchProjNode::fall_through_index )
         break;
     // Handle case of no fall-thru (e.g., check-cast MUST throw an exception)
     if( freq_idx == b->_num_succs ) freq_idx = 0;
--- a/src/share/vm/opto/gcm.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/gcm.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -102,12 +102,12 @@
     uint j = 0;
     if (pb->_num_succs != 1) {  // More then 1 successor?
       // Search for successor
-      uint max = pb->_nodes.size();
+      uint max = pb->number_of_nodes();
       assert( max > 1, "" );
       uint start = max - pb->_num_succs;
       // Find which output path belongs to projection
       for (j = start; j < max; j++) {
-        if( pb->_nodes[j] == in0 )
+        if( pb->get_node(j) == in0 )
           break;
       }
       assert( j < max, "must find" );
@@ -1027,8 +1027,8 @@
   Block* least       = LCA;
   double least_freq  = least->_freq;
   uint target        = get_latency_for_node(self);
-  uint start_latency = get_latency_for_node(LCA->_nodes[0]);
-  uint end_latency   = get_latency_for_node(LCA->_nodes[LCA->end_idx()]);
+  uint start_latency = get_latency_for_node(LCA->head());
+  uint end_latency   = get_latency_for_node(LCA->get_node(LCA->end_idx()));
   bool in_latency    = (target <= start_latency);
   const Block* root_block = get_block_for_node(_root);
 
@@ -1049,9 +1049,9 @@
     self->dump();
     tty->print_cr("#   B%d: start latency for [%4d]=%d, end latency for [%4d]=%d, freq=%g",
       LCA->_pre_order,
-      LCA->_nodes[0]->_idx,
+      LCA->head()->_idx,
       start_latency,
-      LCA->_nodes[LCA->end_idx()]->_idx,
+      LCA->get_node(LCA->end_idx())->_idx,
       end_latency,
       least_freq);
   }
@@ -1074,14 +1074,14 @@
     if (mach && LCA == root_block)
       break;
 
-    uint start_lat = get_latency_for_node(LCA->_nodes[0]);
+    uint start_lat = get_latency_for_node(LCA->head());
     uint end_idx   = LCA->end_idx();
-    uint end_lat   = get_latency_for_node(LCA->_nodes[end_idx]);
+    uint end_lat   = get_latency_for_node(LCA->get_node(end_idx));
     double LCA_freq = LCA->_freq;
 #ifndef PRODUCT
     if (trace_opto_pipelining()) {
       tty->print_cr("#   B%d: start latency for [%4d]=%d, end latency for [%4d]=%d, freq=%g",
-        LCA->_pre_order, LCA->_nodes[0]->_idx, start_lat, end_idx, end_lat, LCA_freq);
+        LCA->_pre_order, LCA->head()->_idx, start_lat, end_idx, end_lat, LCA_freq);
     }
 #endif
     cand_cnt++;
@@ -1342,7 +1342,7 @@
       Node* proj = _matcher._null_check_tests[i];
       Node* val  = _matcher._null_check_tests[i + 1];
       Block* block = get_block_for_node(proj);
-      block->implicit_null_check(this, proj, val, allowed_reasons);
+      implicit_null_check(block, proj, val, allowed_reasons);
       // The implicit_null_check will only perform the transformation
       // if the null branch is truly uncommon, *and* it leads to an
       // uncommon trap.  Combined with the too_many_traps guards
@@ -1363,7 +1363,7 @@
   visited.Clear();
   for (uint i = 0; i < number_of_blocks(); i++) {
     Block* block = get_block(i);
-    if (!block->schedule_local(this, _matcher, ready_cnt, visited)) {
+    if (!schedule_local(block, ready_cnt, visited)) {
       if (!C->failure_reason_is(C2Compiler::retry_no_subsuming_loads())) {
         C->record_method_not_compilable("local schedule failed");
       }
@@ -1375,7 +1375,7 @@
   // clone the instructions on all paths below the Catch.
   for (uint i = 0; i < number_of_blocks(); i++) {
     Block* block = get_block(i);
-    block->call_catch_cleanup(this, C);
+    call_catch_cleanup(block);
   }
 
 #ifndef PRODUCT
@@ -1726,7 +1726,7 @@
 // Determine the probability of reaching successor 'i' from the receiver block.
 float Block::succ_prob(uint i) {
   int eidx = end_idx();
-  Node *n = _nodes[eidx];  // Get ending Node
+  Node *n = get_node(eidx);  // Get ending Node
 
   int op = n->Opcode();
   if (n->is_Mach()) {
@@ -1761,7 +1761,7 @@
     float prob  = n->as_MachIf()->_prob;
     assert(prob >= 0.0 && prob <= 1.0, "out of range probability");
     // If succ[i] is the FALSE branch, invert path info
-    if( _nodes[i + eidx + 1]->Opcode() == Op_IfFalse ) {
+    if( get_node(i + eidx + 1)->Opcode() == Op_IfFalse ) {
       return 1.0f - prob; // not taken
     } else {
       return prob; // taken
@@ -1773,7 +1773,7 @@
     return 1.0f/_num_succs;
 
   case Op_Catch: {
-    const CatchProjNode *ci = _nodes[i + eidx + 1]->as_CatchProj();
+    const CatchProjNode *ci = get_node(i + eidx + 1)->as_CatchProj();
     if (ci->_con == CatchProjNode::fall_through_index) {
       // Fall-thru path gets the lion's share.
       return 1.0f - PROB_UNLIKELY_MAG(5)*_num_succs;
@@ -1810,7 +1810,7 @@
 // Return the number of fall-through candidates for a block
 int Block::num_fall_throughs() {
   int eidx = end_idx();
-  Node *n = _nodes[eidx];  // Get ending Node
+  Node *n = get_node(eidx);  // Get ending Node
 
   int op = n->Opcode();
   if (n->is_Mach()) {
@@ -1834,7 +1834,7 @@
 
   case Op_Catch: {
     for (uint i = 0; i < _num_succs; i++) {
-      const CatchProjNode *ci = _nodes[i + eidx + 1]->as_CatchProj();
+      const CatchProjNode *ci = get_node(i + eidx + 1)->as_CatchProj();
       if (ci->_con == CatchProjNode::fall_through_index) {
         return 1;
       }
@@ -1862,14 +1862,14 @@
 // Return true if a specific successor could be fall-through target.
 bool Block::succ_fall_through(uint i) {
   int eidx = end_idx();
-  Node *n = _nodes[eidx];  // Get ending Node
+  Node *n = get_node(eidx);  // Get ending Node
 
   int op = n->Opcode();
   if (n->is_Mach()) {
     if (n->is_MachNullCheck()) {
       // In theory, either side can fall-thru, for simplicity sake,
       // let's say only the false branch can now.
-      return _nodes[i + eidx + 1]->Opcode() == Op_IfFalse;
+      return get_node(i + eidx + 1)->Opcode() == Op_IfFalse;
     }
     op = n->as_Mach()->ideal_Opcode();
   }
@@ -1883,7 +1883,7 @@
     return true;
 
   case Op_Catch: {
-    const CatchProjNode *ci = _nodes[i + eidx + 1]->as_CatchProj();
+    const CatchProjNode *ci = get_node(i + eidx + 1)->as_CatchProj();
     return ci->_con == CatchProjNode::fall_through_index;
   }
 
@@ -1907,7 +1907,7 @@
 // Update the probability of a two-branch to be uncommon
 void Block::update_uncommon_branch(Block* ub) {
   int eidx = end_idx();
-  Node *n = _nodes[eidx];  // Get ending Node
+  Node *n = get_node(eidx);  // Get ending Node
 
   int op = n->as_Mach()->ideal_Opcode();
 
@@ -1923,7 +1923,7 @@
 
   // If ub is the true path, make the proability small, else
   // ub is the false path, and make the probability large
-  bool invert = (_nodes[s + eidx + 1]->Opcode() == Op_IfFalse);
+  bool invert = (get_node(s + eidx + 1)->Opcode() == Op_IfFalse);
 
   // Get existing probability
   float p = n->as_MachIf()->_prob;
--- a/src/share/vm/opto/generateOptoStub.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/generateOptoStub.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -61,6 +61,7 @@
   JVMState* jvms = new (C) JVMState(0);
   jvms->set_bci(InvocationEntryBci);
   jvms->set_monoff(max_map);
+  jvms->set_scloff(max_map);
   jvms->set_endoff(max_map);
   {
     SafePointNode *map = new (C) SafePointNode( max_map, jvms );
--- a/src/share/vm/opto/graphKit.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/graphKit.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -1501,6 +1501,25 @@
   }
 }
 
+bool GraphKit::can_move_pre_barrier() const {
+  BarrierSet* bs = Universe::heap()->barrier_set();
+  switch (bs->kind()) {
+    case BarrierSet::G1SATBCT:
+    case BarrierSet::G1SATBCTLogging:
+      return true; // Can move it if no safepoint
+
+    case BarrierSet::CardTableModRef:
+    case BarrierSet::CardTableExtension:
+    case BarrierSet::ModRef:
+      return true; // There is no pre-barrier
+
+    case BarrierSet::Other:
+    default      :
+      ShouldNotReachHere();
+  }
+  return false;
+}
+
 void GraphKit::post_barrier(Node* ctl,
                             Node* store,
                             Node* obj,
@@ -3551,6 +3570,8 @@
   } else {
     // In this case both val_type and alias_idx are unused.
     assert(pre_val != NULL, "must be loaded already");
+    // Nothing to be done if pre_val is null.
+    if (pre_val->bottom_type() == TypePtr::NULL_PTR) return;
     assert(pre_val->bottom_type()->basic_type() == T_OBJECT, "or we shouldn't be here");
   }
   assert(bt == T_OBJECT, "or we shouldn't be here");
@@ -3595,7 +3616,7 @@
     if (do_load) {
       // load original value
       // alias_idx correct??
-      pre_val = __ load(no_ctrl, adr, val_type, bt, alias_idx);
+      pre_val = __ load(__ ctrl(), adr, val_type, bt, alias_idx);
     }
 
     // if (pre_val != NULL)
@@ -3804,8 +3825,13 @@
                                                    TypeAry::make(TypeInt::CHAR,TypeInt::POS),
                                                    ciTypeArrayKlass::make(T_CHAR), true, 0);
   int value_field_idx = C->get_alias_index(value_field_type);
-  return make_load(ctrl, basic_plus_adr(str, str, value_offset),
-                   value_type, T_OBJECT, value_field_idx);
+  Node* load = make_load(ctrl, basic_plus_adr(str, str, value_offset),
+                         value_type, T_OBJECT, value_field_idx);
+  // String.value field is known to be @Stable.
+  if (UseImplicitStableValues) {
+    load = cast_array_to_stable(load, value_type);
+  }
+  return load;
 }
 
 void GraphKit::store_String_offset(Node* ctrl, Node* str, Node* value) {
@@ -3823,9 +3849,6 @@
   const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
                                                      false, NULL, 0);
   const TypePtr* value_field_type = string_type->add_offset(value_offset);
-  const TypeAryPtr*  value_type = TypeAryPtr::make(TypePtr::NotNull,
-                                                   TypeAry::make(TypeInt::CHAR,TypeInt::POS),
-                                                   ciTypeArrayKlass::make(T_CHAR), true, 0);
   int value_field_idx = C->get_alias_index(value_field_type);
   store_to_memory(ctrl, basic_plus_adr(str, value_offset),
                   value, T_OBJECT, value_field_idx);
@@ -3840,3 +3863,9 @@
   store_to_memory(ctrl, basic_plus_adr(str, count_offset),
                   value, T_INT, count_field_idx);
 }
+
+Node* GraphKit::cast_array_to_stable(Node* ary, const TypeAryPtr* ary_type) {
+  // Reify the property as a CastPP node in Ideal graph to comply with monotonicity
+  // assumption of CCP analysis.
+  return _gvn.transform(new(C) CastPPNode(ary, ary_type->cast_to_stable(true)));
+}
--- a/src/share/vm/opto/graphKit.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/graphKit.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -695,6 +695,10 @@
   void write_barrier_post(Node *store, Node* obj,
                           Node* adr,  uint adr_idx, Node* val, bool use_precise);
 
+  // Allow reordering of pre-barrier with oop store and/or post-barrier.
+  // Used for load_store operations which loads old value.
+  bool can_move_pre_barrier() const;
+
   // G1 pre/post barriers
   void g1_write_barrier_pre(bool do_load,
                             Node* obj,
@@ -832,6 +836,9 @@
   // Insert a loop predicate into the graph
   void add_predicate(int nargs = 0);
   void add_predicate_impl(Deoptimization::DeoptReason reason, int nargs);
+
+  // Produce new array node of stable type
+  Node* cast_array_to_stable(Node* ary, const TypeAryPtr* ary_type);
 };
 
 // Helper class to support building of control flow branches. Upon
--- a/src/share/vm/opto/idealGraphPrinter.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/idealGraphPrinter.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -639,8 +639,8 @@
     // reachable but are in the CFG so add them here.
     for (uint i = 0; i < C->cfg()->number_of_blocks(); i++) {
       Block* block = C->cfg()->get_block(i);
-      for (uint s = 0; s < block->_nodes.size(); s++) {
-        nodeStack.push(block->_nodes[s]);
+      for (uint s = 0; s < block->number_of_nodes(); s++) {
+        nodeStack.push(block->get_node(s));
       }
     }
   }
@@ -713,9 +713,9 @@
       tail(SUCCESSORS_ELEMENT);
 
       head(NODES_ELEMENT);
-      for (uint s = 0; s < block->_nodes.size(); s++) {
+      for (uint s = 0; s < block->number_of_nodes(); s++) {
         begin_elem(NODE_ELEMENT);
-        print_attr(NODE_ID_PROPERTY, get_node_id(block->_nodes[s]));
+        print_attr(NODE_ID_PROPERTY, get_node_id(block->get_node(s)));
         end_elem();
       }
       tail(NODES_ELEMENT);
--- a/src/share/vm/opto/ifg.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/ifg.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -319,7 +319,7 @@
     // value is then removed from the live-ness set and it's inputs are
     // added to the live-ness set.
     for (uint j = block->end_idx() + 1; j > 1; j--) {
-      Node* n = block->_nodes[j - 1];
+      Node* n = block->get_node(j - 1);
 
       // Get value being defined
       uint r = _lrg_map.live_range_id(n);
@@ -456,7 +456,7 @@
     // Compute first nonphi node index
     uint first_inst;
     for (first_inst = 1; first_inst < last_inst; first_inst++) {
-      if (!block->_nodes[first_inst]->is_Phi()) {
+      if (!block->get_node(first_inst)->is_Phi()) {
         break;
       }
     }
@@ -464,15 +464,15 @@
     // Spills could be inserted before CreateEx node which should be
     // first instruction in block after Phis. Move CreateEx up.
     for (uint insidx = first_inst; insidx < last_inst; insidx++) {
-      Node *ex = block->_nodes[insidx];
+      Node *ex = block->get_node(insidx);
       if (ex->is_SpillCopy()) {
         continue;
       }
       if (insidx > first_inst && ex->is_Mach() && ex->as_Mach()->ideal_Opcode() == Op_CreateEx) {
         // If the CreateEx isn't above all the MachSpillCopies
         // then move it to the top.
-        block->_nodes.remove(insidx);
-        block->_nodes.insert(first_inst, ex);
+        block->remove_node(insidx);
+        block->insert_node(ex, first_inst);
       }
       // Stop once a CreateEx or any other node is found
       break;
@@ -523,7 +523,7 @@
     // to the live-ness set.
     uint j;
     for (j = last_inst + 1; j > 1; j--) {
-      Node* n = block->_nodes[j - 1];
+      Node* n = block->get_node(j - 1);
 
       // Get value being defined
       uint r = _lrg_map.live_range_id(n);
@@ -541,7 +541,7 @@
           if( !n->is_Proj() ||
               // Could also be a flags-projection of a dead ADD or such.
               (_lrg_map.live_range_id(def) && !liveout.member(_lrg_map.live_range_id(def)))) {
-            block->_nodes.remove(j - 1);
+            block->remove_node(j - 1);
             if (lrgs(r)._def == n) {
               lrgs(r)._def = 0;
             }
@@ -605,7 +605,7 @@
             // (j - 1) is index for current instruction 'n'
             Node *m = n;
             for (uint i = j; i <= last_inst && m->is_SpillCopy(); ++i) {
-              m = block->_nodes[i];
+              m = block->get_node(i);
             }
             if (m == single_use) {
               lrgs(r)._area = 0.0;
@@ -772,20 +772,20 @@
 
     // Compute high pressure indice; avoid landing in the middle of projnodes
     j = hrp_index[0];
-    if (j < block->_nodes.size() && j < block->end_idx() + 1) {
-      Node* cur = block->_nodes[j];
+    if (j < block->number_of_nodes() && j < block->end_idx() + 1) {
+      Node* cur = block->get_node(j);
       while (cur->is_Proj() || (cur->is_MachNullCheck()) || cur->is_Catch()) {
         j--;
-        cur = block->_nodes[j];
+        cur = block->get_node(j);
       }
     }
     block->_ihrp_index = j;
     j = hrp_index[1];
-    if (j < block->_nodes.size() && j < block->end_idx() + 1) {
-      Node* cur = block->_nodes[j];
+    if (j < block->number_of_nodes() && j < block->end_idx() + 1) {
+      Node* cur = block->get_node(j);
       while (cur->is_Proj() || (cur->is_MachNullCheck()) || cur->is_Catch()) {
         j--;
-        cur = block->_nodes[j];
+        cur = block->get_node(j);
       }
     }
     block->_fhrp_index = j;
--- a/src/share/vm/opto/lcm.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/lcm.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -58,14 +58,14 @@
 // The proj is the control projection for the not-null case.
 // The val is the pointer being checked for nullness or
 // decodeHeapOop_not_null node if it did not fold into address.
-void Block::implicit_null_check(PhaseCFG *cfg, Node *proj, Node *val, int allowed_reasons) {
+void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allowed_reasons) {
   // Assume if null check need for 0 offset then always needed
   // Intel solaris doesn't support any null checks yet and no
   // mechanism exists (yet) to set the switches at an os_cpu level
   if( !ImplicitNullChecks || MacroAssembler::needs_explicit_null_check(0)) return;
 
   // Make sure the ptr-is-null path appears to be uncommon!
-  float f = end()->as_MachIf()->_prob;
+  float f = block->end()->as_MachIf()->_prob;
   if( proj->Opcode() == Op_IfTrue ) f = 1.0f - f;
   if( f > PROB_UNLIKELY_MAG(4) ) return;
 
@@ -75,13 +75,13 @@
   // Get the successor block for if the test ptr is non-null
   Block* not_null_block;  // this one goes with the proj
   Block* null_block;
-  if (_nodes[_nodes.size()-1] == proj) {
-    null_block     = _succs[0];
-    not_null_block = _succs[1];
+  if (block->get_node(block->number_of_nodes()-1) == proj) {
+    null_block     = block->_succs[0];
+    not_null_block = block->_succs[1];
   } else {
-    assert(_nodes[_nodes.size()-2] == proj, "proj is one or the other");
-    not_null_block = _succs[0];
-    null_block     = _succs[1];
+    assert(block->get_node(block->number_of_nodes()-2) == proj, "proj is one or the other");
+    not_null_block = block->_succs[0];
+    null_block     = block->_succs[1];
   }
   while (null_block->is_Empty() == Block::empty_with_goto) {
     null_block     = null_block->_succs[0];
@@ -93,8 +93,8 @@
   // detect failure of this optimization, as in 6366351.)
   {
     bool found_trap = false;
-    for (uint i1 = 0; i1 < null_block->_nodes.size(); i1++) {
-      Node* nn = null_block->_nodes[i1];
+    for (uint i1 = 0; i1 < null_block->number_of_nodes(); i1++) {
+      Node* nn = null_block->get_node(i1);
       if (nn->is_MachCall() &&
           nn->as_MachCall()->entry_point() == SharedRuntime::uncommon_trap_blob()->entry_point()) {
         const Type* trtype = nn->in(TypeFunc::Parms)->bottom_type();
@@ -237,20 +237,20 @@
     }
 
     // Check ctrl input to see if the null-check dominates the memory op
-    Block *cb = cfg->get_block_for_node(mach);
+    Block *cb = get_block_for_node(mach);
     cb = cb->_idom;             // Always hoist at least 1 block
     if( !was_store ) {          // Stores can be hoisted only one block
-      while( cb->_dom_depth > (_dom_depth + 1))
+      while( cb->_dom_depth > (block->_dom_depth + 1))
         cb = cb->_idom;         // Hoist loads as far as we want
       // The non-null-block should dominate the memory op, too. Live
       // range spilling will insert a spill in the non-null-block if it is
       // needs to spill the memory op for an implicit null check.
-      if (cb->_dom_depth == (_dom_depth + 1)) {
+      if (cb->_dom_depth == (block->_dom_depth + 1)) {
         if (cb != not_null_block) continue;
         cb = cb->_idom;
       }
     }
-    if( cb != this ) continue;
+    if( cb != block ) continue;
 
     // Found a memory user; see if it can be hoisted to check-block
     uint vidx = 0;              // Capture index of value into memop
@@ -262,8 +262,8 @@
         if( is_decoden ) continue;
       }
       // Block of memory-op input
-      Block *inb = cfg->get_block_for_node(mach->in(j));
-      Block *b = this;          // Start from nul check
+      Block *inb = get_block_for_node(mach->in(j));
+      Block *b = block;          // Start from nul check
       while( b != inb && b->_dom_depth > inb->_dom_depth )
         b = b->_idom;           // search upwards for input
       // See if input dominates null check
@@ -272,28 +272,28 @@
     }
     if( j > 0 )
       continue;
-    Block *mb = cfg->get_block_for_node(mach);
+    Block *mb = get_block_for_node(mach);
     // Hoisting stores requires more checks for the anti-dependence case.
     // Give up hoisting if we have to move the store past any load.
     if( was_store ) {
       Block *b = mb;            // Start searching here for a local load
       // mach use (faulting) trying to hoist
       // n might be blocker to hoisting
-      while( b != this ) {
+      while( b != block ) {
         uint k;
-        for( k = 1; k < b->_nodes.size(); k++ ) {
-          Node *n = b->_nodes[k];
+        for( k = 1; k < b->number_of_nodes(); k++ ) {
+          Node *n = b->get_node(k);
           if( n->needs_anti_dependence_check() &&
               n->in(LoadNode::Memory) == mach->in(StoreNode::Memory) )
             break;              // Found anti-dependent load
         }
-        if( k < b->_nodes.size() )
+        if( k < b->number_of_nodes() )
           break;                // Found anti-dependent load
         // Make sure control does not do a merge (would have to check allpaths)
         if( b->num_preds() != 2 ) break;
-        b = cfg->get_block_for_node(b->pred(1)); // Move up to predecessor block
+        b = get_block_for_node(b->pred(1)); // Move up to predecessor block
       }
-      if( b != this ) continue;
+      if( b != block ) continue;
     }
 
     // Make sure this memory op is not already being used for a NullCheck
@@ -303,7 +303,7 @@
 
     // Found a candidate!  Pick one with least dom depth - the highest
     // in the dom tree should be closest to the null check.
-    if (best == NULL || cfg->get_block_for_node(mach)->_dom_depth < cfg->get_block_for_node(best)->_dom_depth) {
+    if (best == NULL || get_block_for_node(mach)->_dom_depth < get_block_for_node(best)->_dom_depth) {
       best = mach;
       bidx = vidx;
     }
@@ -319,46 +319,45 @@
 
   if( is_decoden ) {
     // Check if we need to hoist decodeHeapOop_not_null first.
-    Block *valb = cfg->get_block_for_node(val);
-    if( this != valb && this->_dom_depth < valb->_dom_depth ) {
+    Block *valb = get_block_for_node(val);
+    if( block != valb && block->_dom_depth < valb->_dom_depth ) {
       // Hoist it up to the end of the test block.
       valb->find_remove(val);
-      this->add_inst(val);
-      cfg->map_node_to_block(val, this);
+      block->add_inst(val);
+      map_node_to_block(val, block);
       // DecodeN on x86 may kill flags. Check for flag-killing projections
       // that also need to be hoisted.
       for (DUIterator_Fast jmax, j = val->fast_outs(jmax); j < jmax; j++) {
         Node* n = val->fast_out(j);
         if( n->is_MachProj() ) {
-          cfg->get_block_for_node(n)->find_remove(n);
-          this->add_inst(n);
-          cfg->map_node_to_block(n, this);
+          get_block_for_node(n)->find_remove(n);
+          block->add_inst(n);
+          map_node_to_block(n, block);
         }
       }
     }
   }
   // Hoist the memory candidate up to the end of the test block.
-  Block *old_block = cfg->get_block_for_node(best);
+  Block *old_block = get_block_for_node(best);
   old_block->find_remove(best);
-  add_inst(best);
-  cfg->map_node_to_block(best, this);
+  block->add_inst(best);
+  map_node_to_block(best, block);
 
   // Move the control dependence
-  if (best->in(0) && best->in(0) == old_block->_nodes[0])
-    best->set_req(0, _nodes[0]);
+  if (best->in(0) && best->in(0) == old_block->head())
+    best->set_req(0, block->head());
 
   // Check for flag-killing projections that also need to be hoisted
   // Should be DU safe because no edge updates.
   for (DUIterator_Fast jmax, j = best->fast_outs(jmax); j < jmax; j++) {
     Node* n = best->fast_out(j);
     if( n->is_MachProj() ) {
-      cfg->get_block_for_node(n)->find_remove(n);
-      add_inst(n);
-      cfg->map_node_to_block(n, this);
+      get_block_for_node(n)->find_remove(n);
+      block->add_inst(n);
+      map_node_to_block(n, block);
     }
   }
 
-  Compile *C = cfg->C;
   // proj==Op_True --> ne test; proj==Op_False --> eq test.
   // One of two graph shapes got matched:
   //   (IfTrue  (If (Bool NE (CmpP ptr NULL))))
@@ -368,10 +367,10 @@
   // We need to flip the projections to keep the same semantics.
   if( proj->Opcode() == Op_IfTrue ) {
     // Swap order of projections in basic block to swap branch targets
-    Node *tmp1 = _nodes[end_idx()+1];
-    Node *tmp2 = _nodes[end_idx()+2];
-    _nodes.map(end_idx()+1, tmp2);
-    _nodes.map(end_idx()+2, tmp1);
+    Node *tmp1 = block->get_node(block->end_idx()+1);
+    Node *tmp2 = block->get_node(block->end_idx()+2);
+    block->map_node(tmp2, block->end_idx()+1);
+    block->map_node(tmp1, block->end_idx()+2);
     Node *tmp = new (C) Node(C->top()); // Use not NULL input
     tmp1->replace_by(tmp);
     tmp2->replace_by(tmp1);
@@ -384,8 +383,8 @@
   // it as well.
   Node *old_tst = proj->in(0);
   MachNode *nul_chk = new (C) MachNullCheckNode(old_tst->in(0),best,bidx);
-  _nodes.map(end_idx(),nul_chk);
-  cfg->map_node_to_block(nul_chk, this);
+  block->map_node(nul_chk, block->end_idx());
+  map_node_to_block(nul_chk, block);
   // Redirect users of old_test to nul_chk
   for (DUIterator_Last i2min, i2 = old_tst->last_outs(i2min); i2 >= i2min; --i2)
     old_tst->last_out(i2)->set_req(0, nul_chk);
@@ -393,8 +392,8 @@
   for (uint i3 = 0; i3 < old_tst->req(); i3++)
     old_tst->set_req(i3, NULL);
 
-  cfg->latency_from_uses(nul_chk);
-  cfg->latency_from_uses(best);
+  latency_from_uses(nul_chk);
+  latency_from_uses(best);
 }
 
 
@@ -408,7 +407,7 @@
 // remaining cases (most), choose the instruction with the greatest latency
 // (that is, the most number of pseudo-cycles required to the end of the
 // routine). If there is a tie, choose the instruction with the most inputs.
-Node *Block::select(PhaseCFG *cfg, Node_List &worklist, GrowableArray<int> &ready_cnt, VectorSet &next_call, uint sched_slot) {
+Node* PhaseCFG::select(Block* block, Node_List &worklist, GrowableArray<int> &ready_cnt, VectorSet &next_call, uint sched_slot) {
 
   // If only a single entry on the stack, use it
   uint cnt = worklist.size();
@@ -442,7 +441,7 @@
     }
 
     // Final call in a block must be adjacent to 'catch'
-    Node *e = end();
+    Node *e = block->end();
     if( e->is_Catch() && e->in(0)->in(0) == n )
       continue;
 
@@ -468,7 +467,7 @@
         Node* use = n->fast_out(j);
 
         // The use is a conditional branch, make them adjacent
-        if (use->is_MachIf() && cfg->get_block_for_node(use) == this) {
+        if (use->is_MachIf() && get_block_for_node(use) == block) {
           found_machif = true;
           break;
         }
@@ -501,7 +500,7 @@
       n_choice = 1;
     }
 
-    uint n_latency = cfg->get_latency_for_node(n);
+    uint n_latency = get_latency_for_node(n);
     uint n_score   = n->req();   // Many inputs get high score to break ties
 
     // Keep best latency found
@@ -529,13 +528,13 @@
 
 
 //------------------------------set_next_call----------------------------------
-void Block::set_next_call( Node *n, VectorSet &next_call, PhaseCFG* cfg) {
+void PhaseCFG::set_next_call(Block* block, Node* n, VectorSet& next_call) {
   if( next_call.test_set(n->_idx) ) return;
   for( uint i=0; i<n->len(); i++ ) {
     Node *m = n->in(i);
     if( !m ) continue;  // must see all nodes in block that precede call
-    if (cfg->get_block_for_node(m) == this) {
-      set_next_call(m, next_call, cfg);
+    if (get_block_for_node(m) == block) {
+      set_next_call(block, m, next_call);
     }
   }
 }
@@ -546,24 +545,26 @@
 // next subroutine call get priority - basically it moves things NOT needed
 // for the next call till after the call.  This prevents me from trying to
 // carry lots of stuff live across a call.
-void Block::needed_for_next_call(Node *this_call, VectorSet &next_call, PhaseCFG* cfg) {
+void PhaseCFG::needed_for_next_call(Block* block, Node* this_call, VectorSet& next_call) {
   // Find the next control-defining Node in this block
   Node* call = NULL;
   for (DUIterator_Fast imax, i = this_call->fast_outs(imax); i < imax; i++) {
     Node* m = this_call->fast_out(i);
-    if(cfg->get_block_for_node(m) == this && // Local-block user
+    if (get_block_for_node(m) == block && // Local-block user
         m != this_call &&       // Not self-start node
-        m->is_MachCall() )
+        m->is_MachCall()) {
       call = m;
       break;
+    }
   }
   if (call == NULL)  return;    // No next call (e.g., block end is near)
   // Set next-call for all inputs to this call
-  set_next_call(call, next_call, cfg);
+  set_next_call(block, call, next_call);
 }
 
 //------------------------------add_call_kills-------------------------------------
-void Block::add_call_kills(MachProjNode *proj, RegMask& regs, const char* save_policy, bool exclude_soe) {
+// helper function that adds caller save registers to MachProjNode
+static void add_call_kills(MachProjNode *proj, RegMask& regs, const char* save_policy, bool exclude_soe) {
   // Fill in the kill mask for the call
   for( OptoReg::Name r = OptoReg::Name(0); r < _last_Mach_Reg; r=OptoReg::add(r,1) ) {
     if( !regs.Member(r) ) {     // Not already defined by the call
@@ -579,7 +580,7 @@
 
 
 //------------------------------sched_call-------------------------------------
-uint Block::sched_call( Matcher &matcher, PhaseCFG* cfg, uint node_cnt, Node_List &worklist, GrowableArray<int> &ready_cnt, MachCallNode *mcall, VectorSet &next_call ) {
+uint PhaseCFG::sched_call(Block* block, uint node_cnt, Node_List& worklist, GrowableArray<int>& ready_cnt, MachCallNode* mcall, VectorSet& next_call) {
   RegMask regs;
 
   // Schedule all the users of the call right now.  All the users are
@@ -592,18 +593,18 @@
     ready_cnt.at_put(n->_idx, n_cnt);
     assert( n_cnt == 0, "" );
     // Schedule next to call
-    _nodes.map(node_cnt++, n);
+    block->map_node(n, node_cnt++);
     // Collect defined registers
     regs.OR(n->out_RegMask());
     // Check for scheduling the next control-definer
     if( n->bottom_type() == Type::CONTROL )
       // Warm up next pile of heuristic bits
-      needed_for_next_call(n, next_call, cfg);
+      needed_for_next_call(block, n, next_call);
 
     // Children of projections are now all ready
     for (DUIterator_Fast jmax, j = n->fast_outs(jmax); j < jmax; j++) {
       Node* m = n->fast_out(j); // Get user
-      if(cfg->get_block_for_node(m) != this) {
+      if(get_block_for_node(m) != block) {
         continue;
       }
       if( m->is_Phi() ) continue;
@@ -617,14 +618,14 @@
 
   // Act as if the call defines the Frame Pointer.
   // Certainly the FP is alive and well after the call.
-  regs.Insert(matcher.c_frame_pointer());
+  regs.Insert(_matcher.c_frame_pointer());
 
   // Set all registers killed and not already defined by the call.
   uint r_cnt = mcall->tf()->range()->cnt();
   int op = mcall->ideal_Opcode();
-  MachProjNode *proj = new (matcher.C) MachProjNode( mcall, r_cnt+1, RegMask::Empty, MachProjNode::fat_proj );
-  cfg->map_node_to_block(proj, this);
-  _nodes.insert(node_cnt++, proj);
+  MachProjNode *proj = new (C) MachProjNode( mcall, r_cnt+1, RegMask::Empty, MachProjNode::fat_proj );
+  map_node_to_block(proj, block);
+  block->insert_node(proj, node_cnt++);
 
   // Select the right register save policy.
   const char * save_policy;
@@ -633,13 +634,13 @@
     case Op_CallLeaf:
     case Op_CallLeafNoFP:
       // Calling C code so use C calling convention
-      save_policy = matcher._c_reg_save_policy;
+      save_policy = _matcher._c_reg_save_policy;
       break;
 
     case Op_CallStaticJava:
     case Op_CallDynamicJava:
       // Calling Java code so use Java calling convention
-      save_policy = matcher._register_save_policy;
+      save_policy = _matcher._register_save_policy;
       break;
 
     default:
@@ -674,44 +675,46 @@
 
 //------------------------------schedule_local---------------------------------
 // Topological sort within a block.  Someday become a real scheduler.
-bool Block::schedule_local(PhaseCFG *cfg, Matcher &matcher, GrowableArray<int> &ready_cnt, VectorSet &next_call) {
+bool PhaseCFG::schedule_local(Block* block, GrowableArray<int>& ready_cnt, VectorSet& next_call) {
   // Already "sorted" are the block start Node (as the first entry), and
   // the block-ending Node and any trailing control projections.  We leave
   // these alone.  PhiNodes and ParmNodes are made to follow the block start
   // Node.  Everything else gets topo-sorted.
 
 #ifndef PRODUCT
-    if (cfg->trace_opto_pipelining()) {
-      tty->print_cr("# --- schedule_local B%d, before: ---", _pre_order);
-      for (uint i = 0;i < _nodes.size();i++) {
+    if (trace_opto_pipelining()) {
+      tty->print_cr("# --- schedule_local B%d, before: ---", block->_pre_order);
+      for (uint i = 0;i < block->number_of_nodes(); i++) {
         tty->print("# ");
-        _nodes[i]->fast_dump();
+        block->get_node(i)->fast_dump();
       }
       tty->print_cr("#");
     }
 #endif
 
   // RootNode is already sorted
-  if( _nodes.size() == 1 ) return true;
+  if (block->number_of_nodes() == 1) {
+    return true;
+  }
 
   // Move PhiNodes and ParmNodes from 1 to cnt up to the start
-  uint node_cnt = end_idx();
+  uint node_cnt = block->end_idx();
   uint phi_cnt = 1;
   uint i;
   for( i = 1; i<node_cnt; i++ ) { // Scan for Phi
-    Node *n = _nodes[i];
+    Node *n = block->get_node(i);
     if( n->is_Phi() ||          // Found a PhiNode or ParmNode
-        (n->is_Proj()  && n->in(0) == head()) ) {
+        (n->is_Proj()  && n->in(0) == block->head()) ) {
       // Move guy at 'phi_cnt' to the end; makes a hole at phi_cnt
-      _nodes.map(i,_nodes[phi_cnt]);
-      _nodes.map(phi_cnt++,n);  // swap Phi/Parm up front
+      block->map_node(block->get_node(phi_cnt), i);
+      block->map_node(n, phi_cnt++);  // swap Phi/Parm up front
     } else {                    // All others
       // Count block-local inputs to 'n'
       uint cnt = n->len();      // Input count
       uint local = 0;
       for( uint j=0; j<cnt; j++ ) {
         Node *m = n->in(j);
-        if( m && cfg->get_block_for_node(m) == this && !m->is_top() )
+        if( m && get_block_for_node(m) == block && !m->is_top() )
           local++;              // One more block-local input
       }
       ready_cnt.at_put(n->_idx, local); // Count em up
@@ -723,7 +726,7 @@
           for (uint prec = n->req(); prec < n->len(); prec++) {
             Node* oop_store = n->in(prec);
             if (oop_store != NULL) {
-              assert(cfg->get_block_for_node(oop_store)->_dom_depth <= this->_dom_depth, "oop_store must dominate card-mark");
+              assert(get_block_for_node(oop_store)->_dom_depth <= block->_dom_depth, "oop_store must dominate card-mark");
             }
           }
         }
@@ -747,16 +750,16 @@
       }
     }
   }
-  for(uint i2=i; i2<_nodes.size(); i2++ ) // Trailing guys get zapped count
-    ready_cnt.at_put(_nodes[i2]->_idx, 0);
+  for(uint i2=i; i2< block->number_of_nodes(); i2++ ) // Trailing guys get zapped count
+    ready_cnt.at_put(block->get_node(i2)->_idx, 0);
 
   // All the prescheduled guys do not hold back internal nodes
   uint i3;
   for(i3 = 0; i3<phi_cnt; i3++ ) {  // For all pre-scheduled
-    Node *n = _nodes[i3];       // Get pre-scheduled
+    Node *n = block->get_node(i3);       // Get pre-scheduled
     for (DUIterator_Fast jmax, j = n->fast_outs(jmax); j < jmax; j++) {
       Node* m = n->fast_out(j);
-      if (cfg->get_block_for_node(m) == this) { // Local-block user
+      if (get_block_for_node(m) == block) { // Local-block user
         int m_cnt = ready_cnt.at(m->_idx)-1;
         ready_cnt.at_put(m->_idx, m_cnt);   // Fix ready count
       }
@@ -767,7 +770,7 @@
   // Make a worklist
   Node_List worklist;
   for(uint i4=i3; i4<node_cnt; i4++ ) {    // Put ready guys on worklist
-    Node *m = _nodes[i4];
+    Node *m = block->get_node(i4);
     if( !ready_cnt.at(m->_idx) ) {   // Zero ready count?
       if (m->is_iteratively_computed()) {
         // Push induction variable increments last to allow other uses
@@ -789,15 +792,15 @@
   }
 
   // Warm up the 'next_call' heuristic bits
-  needed_for_next_call(_nodes[0], next_call, cfg);
+  needed_for_next_call(block, block->head(), next_call);
 
 #ifndef PRODUCT
-    if (cfg->trace_opto_pipelining()) {
-      for (uint j=0; j<_nodes.size(); j++) {
-        Node     *n = _nodes[j];
+    if (trace_opto_pipelining()) {
+      for (uint j=0; j< block->number_of_nodes(); j++) {
+        Node     *n = block->get_node(j);
         int     idx = n->_idx;
         tty->print("#   ready cnt:%3d  ", ready_cnt.at(idx));
-        tty->print("latency:%3d  ", cfg->get_latency_for_node(n));
+        tty->print("latency:%3d  ", get_latency_for_node(n));
         tty->print("%4d: %s\n", idx, n->Name());
       }
     }
@@ -808,7 +811,7 @@
   while( worklist.size() ) {    // Worklist is not ready
 
 #ifndef PRODUCT
-    if (cfg->trace_opto_pipelining()) {
+    if (trace_opto_pipelining()) {
       tty->print("#   ready list:");
       for( uint i=0; i<worklist.size(); i++ ) { // Inspect entire worklist
         Node *n = worklist[i];      // Get Node on worklist
@@ -819,13 +822,13 @@
 #endif
 
     // Select and pop a ready guy from worklist
-    Node* n = select(cfg, worklist, ready_cnt, next_call, phi_cnt);
-    _nodes.map(phi_cnt++,n);    // Schedule him next
+    Node* n = select(block, worklist, ready_cnt, next_call, phi_cnt);
+    block->map_node(n, phi_cnt++);    // Schedule him next
 
 #ifndef PRODUCT
-    if (cfg->trace_opto_pipelining()) {
+    if (trace_opto_pipelining()) {
       tty->print("#    select %d: %s", n->_idx, n->Name());
-      tty->print(", latency:%d", cfg->get_latency_for_node(n));
+      tty->print(", latency:%d", get_latency_for_node(n));
       n->dump();
       if (Verbose) {
         tty->print("#   ready list:");
@@ -840,26 +843,26 @@
 #endif
     if( n->is_MachCall() ) {
       MachCallNode *mcall = n->as_MachCall();
-      phi_cnt = sched_call(matcher, cfg, phi_cnt, worklist, ready_cnt, mcall, next_call);
+      phi_cnt = sched_call(block, phi_cnt, worklist, ready_cnt, mcall, next_call);
       continue;
     }
 
     if (n->is_Mach() && n->as_Mach()->has_call()) {
       RegMask regs;
-      regs.Insert(matcher.c_frame_pointer());
+      regs.Insert(_matcher.c_frame_pointer());
       regs.OR(n->out_RegMask());
 
-      MachProjNode *proj = new (matcher.C) MachProjNode( n, 1, RegMask::Empty, MachProjNode::fat_proj );
-      cfg->map_node_to_block(proj, this);
-      _nodes.insert(phi_cnt++, proj);
+      MachProjNode *proj = new (C) MachProjNode( n, 1, RegMask::Empty, MachProjNode::fat_proj );
+      map_node_to_block(proj, block);
+      block->insert_node(proj, phi_cnt++);
 
-      add_call_kills(proj, regs, matcher._c_reg_save_policy, false);
+      add_call_kills(proj, regs, _matcher._c_reg_save_policy, false);
     }
 
     // Children are now all ready
     for (DUIterator_Fast i5max, i5 = n->fast_outs(i5max); i5 < i5max; i5++) {
       Node* m = n->fast_out(i5); // Get user
-      if (cfg->get_block_for_node(m) != this) {
+      if (get_block_for_node(m) != block) {
         continue;
       }
       if( m->is_Phi() ) continue;
@@ -874,9 +877,8 @@
     }
   }
 
-  if( phi_cnt != end_idx() ) {
+  if( phi_cnt != block->end_idx() ) {
     // did not schedule all.  Retry, Bailout, or Die
-    Compile* C = matcher.C;
     if (C->subsume_loads() == true && !C->failing()) {
       // Retry with subsume_loads == false
       // If this is the first failure, the sentinel string will "stick"
@@ -888,12 +890,12 @@
   }
 
 #ifndef PRODUCT
-  if (cfg->trace_opto_pipelining()) {
+  if (trace_opto_pipelining()) {
     tty->print_cr("#");
     tty->print_cr("# after schedule_local");
-    for (uint i = 0;i < _nodes.size();i++) {
+    for (uint i = 0;i < block->number_of_nodes();i++) {
       tty->print("# ");
-      _nodes[i]->fast_dump();
+      block->get_node(i)->fast_dump();
     }
     tty->cr();
   }
@@ -919,7 +921,7 @@
 }
 
 //------------------------------catch_cleanup_find_cloned_def------------------
-static Node *catch_cleanup_find_cloned_def(Block *use_blk, Node *def, Block *def_blk, PhaseCFG* cfg, int n_clone_idx) {
+Node* PhaseCFG::catch_cleanup_find_cloned_def(Block *use_blk, Node *def, Block *def_blk, int n_clone_idx) {
   assert( use_blk != def_blk, "Inter-block cleanup only");
 
   // The use is some block below the Catch.  Find and return the clone of the def
@@ -945,14 +947,14 @@
     // PhiNode, the PhiNode uses from the def and IT's uses need fixup.
     Node_Array inputs = new Node_List(Thread::current()->resource_area());
     for(uint k = 1; k < use_blk->num_preds(); k++) {
-      Block* block = cfg->get_block_for_node(use_blk->pred(k));
-      inputs.map(k, catch_cleanup_find_cloned_def(block, def, def_blk, cfg, n_clone_idx));
+      Block* block = get_block_for_node(use_blk->pred(k));
+      inputs.map(k, catch_cleanup_find_cloned_def(block, def, def_blk, n_clone_idx));
     }
 
     // Check to see if the use_blk already has an identical phi inserted.
     // If it exists, it will be at the first position since all uses of a
     // def are processed together.
-    Node *phi = use_blk->_nodes[1];
+    Node *phi = use_blk->get_node(1);
     if( phi->is_Phi() ) {
       fixup = phi;
       for (uint k = 1; k < use_blk->num_preds(); k++) {
@@ -967,8 +969,8 @@
     // If an existing PhiNode was not found, make a new one.
     if (fixup == NULL) {
       Node *new_phi = PhiNode::make(use_blk->head(), def);
-      use_blk->_nodes.insert(1, new_phi);
-      cfg->map_node_to_block(new_phi, use_blk);
+      use_blk->insert_node(new_phi, 1);
+      map_node_to_block(new_phi, use_blk);
       for (uint k = 1; k < use_blk->num_preds(); k++) {
         new_phi->set_req(k, inputs[k]);
       }
@@ -977,7 +979,7 @@
 
   } else {
     // Found the use just below the Catch.  Make it use the clone.
-    fixup = use_blk->_nodes[n_clone_idx];
+    fixup = use_blk->get_node(n_clone_idx);
   }
 
   return fixup;
@@ -997,36 +999,36 @@
   for( uint k = 0; k < blk->_num_succs; k++ ) {
     // Get clone in each successor block
     Block *sb = blk->_succs[k];
-    Node *clone = sb->_nodes[offset_idx+1];
+    Node *clone = sb->get_node(offset_idx+1);
     assert( clone->Opcode() == use->Opcode(), "" );
 
     // Make use-clone reference the def-clone
-    catch_cleanup_fix_all_inputs(clone, def, sb->_nodes[n_clone_idx]);
+    catch_cleanup_fix_all_inputs(clone, def, sb->get_node(n_clone_idx));
   }
 }
 
 //------------------------------catch_cleanup_inter_block---------------------
 // Fix all input edges in use that reference "def".  The use is in a different
 // block than the def.
-static void catch_cleanup_inter_block(Node *use, Block *use_blk, Node *def, Block *def_blk, PhaseCFG* cfg, int n_clone_idx) {
+void PhaseCFG::catch_cleanup_inter_block(Node *use, Block *use_blk, Node *def, Block *def_blk, int n_clone_idx) {
   if( !use_blk ) return;        // Can happen if the use is a precedence edge
 
-  Node *new_def = catch_cleanup_find_cloned_def(use_blk, def, def_blk, cfg, n_clone_idx);
+  Node *new_def = catch_cleanup_find_cloned_def(use_blk, def, def_blk, n_clone_idx);
   catch_cleanup_fix_all_inputs(use, def, new_def);
 }
 
 //------------------------------call_catch_cleanup-----------------------------
 // If we inserted any instructions between a Call and his CatchNode,
 // clone the instructions on all paths below the Catch.
-void Block::call_catch_cleanup(PhaseCFG* cfg, Compile* C) {
+void PhaseCFG::call_catch_cleanup(Block* block) {
 
   // End of region to clone
-  uint end = end_idx();
-  if( !_nodes[end]->is_Catch() ) return;
+  uint end = block->end_idx();
+  if( !block->get_node(end)->is_Catch() ) return;
   // Start of region to clone
   uint beg = end;
-  while(!_nodes[beg-1]->is_MachProj() ||
-        !_nodes[beg-1]->in(0)->is_MachCall() ) {
+  while(!block->get_node(beg-1)->is_MachProj() ||
+        !block->get_node(beg-1)->in(0)->is_MachCall() ) {
     beg--;
     assert(beg > 0,"Catch cleanup walking beyond block boundary");
   }
@@ -1035,15 +1037,15 @@
 
   // Clone along all Catch output paths.  Clone area between the 'beg' and
   // 'end' indices.
-  for( uint i = 0; i < _num_succs; i++ ) {
-    Block *sb = _succs[i];
+  for( uint i = 0; i < block->_num_succs; i++ ) {
+    Block *sb = block->_succs[i];
     // Clone the entire area; ignoring the edge fixup for now.
     for( uint j = end; j > beg; j-- ) {
       // It is safe here to clone a node with anti_dependence
       // since clones dominate on each path.
-      Node *clone = _nodes[j-1]->clone();
-      sb->_nodes.insert( 1, clone );
-      cfg->map_node_to_block(clone, sb);
+      Node *clone = block->get_node(j-1)->clone();
+      sb->insert_node(clone, 1);
+      map_node_to_block(clone, sb);
     }
   }
 
@@ -1051,7 +1053,7 @@
   // Fixup edges.  Check the def-use info per cloned Node
   for(uint i2 = beg; i2 < end; i2++ ) {
     uint n_clone_idx = i2-beg+1; // Index of clone of n in each successor block
-    Node *n = _nodes[i2];        // Node that got cloned
+    Node *n = block->get_node(i2);        // Node that got cloned
     // Need DU safe iterator because of edge manipulation in calls.
     Unique_Node_List *out = new Unique_Node_List(Thread::current()->resource_area());
     for (DUIterator_Fast j1max, j1 = n->fast_outs(j1max); j1 < j1max; j1++) {
@@ -1060,19 +1062,19 @@
     uint max = out->size();
     for (uint j = 0; j < max; j++) {// For all users
       Node *use = out->pop();
-      Block *buse = cfg->get_block_for_node(use);
+      Block *buse = get_block_for_node(use);
       if( use->is_Phi() ) {
         for( uint k = 1; k < use->req(); k++ )
           if( use->in(k) == n ) {
-            Block* block = cfg->get_block_for_node(buse->pred(k));
-            Node *fixup = catch_cleanup_find_cloned_def(block, n, this, cfg, n_clone_idx);
+            Block* b = get_block_for_node(buse->pred(k));
+            Node *fixup = catch_cleanup_find_cloned_def(b, n, block, n_clone_idx);
             use->set_req(k, fixup);
           }
       } else {
-        if (this == buse) {
-          catch_cleanup_intra_block(use, n, this, beg, n_clone_idx);
+        if (block == buse) {
+          catch_cleanup_intra_block(use, n, block, beg, n_clone_idx);
         } else {
-          catch_cleanup_inter_block(use, buse, n, this, cfg, n_clone_idx);
+          catch_cleanup_inter_block(use, buse, n, block, n_clone_idx);
         }
       }
     } // End for all users
@@ -1081,30 +1083,30 @@
 
   // Remove the now-dead cloned ops
   for(uint i3 = beg; i3 < end; i3++ ) {
-    _nodes[beg]->disconnect_inputs(NULL, C);
-    _nodes.remove(beg);
+    block->get_node(beg)->disconnect_inputs(NULL, C);
+    block->remove_node(beg);
   }
 
   // If the successor blocks have a CreateEx node, move it back to the top
-  for(uint i4 = 0; i4 < _num_succs; i4++ ) {
-    Block *sb = _succs[i4];
+  for(uint i4 = 0; i4 < block->_num_succs; i4++ ) {
+    Block *sb = block->_succs[i4];
     uint new_cnt = end - beg;
     // Remove any newly created, but dead, nodes.
     for( uint j = new_cnt; j > 0; j-- ) {
-      Node *n = sb->_nodes[j];
+      Node *n = sb->get_node(j);
       if (n->outcnt() == 0 &&
           (!n->is_Proj() || n->as_Proj()->in(0)->outcnt() == 1) ){
         n->disconnect_inputs(NULL, C);
-        sb->_nodes.remove(j);
+        sb->remove_node(j);
         new_cnt--;
       }
     }
     // If any newly created nodes remain, move the CreateEx node to the top
     if (new_cnt > 0) {
-      Node *cex = sb->_nodes[1+new_cnt];
+      Node *cex = sb->get_node(1+new_cnt);
       if( cex->is_Mach() && cex->as_Mach()->ideal_Opcode() == Op_CreateEx ) {
-        sb->_nodes.remove(1+new_cnt);
-        sb->_nodes.insert(1,cex);
+        sb->remove_node(1+new_cnt);
+        sb->insert_node(cex, 1);
       }
     }
   }
--- a/src/share/vm/opto/library_call.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/library_call.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -1280,6 +1280,11 @@
   const TypeAry* target_array_type = TypeAry::make(TypeInt::CHAR, TypeInt::make(0, target_length, Type::WidenMin));
   const TypeAryPtr* target_type = TypeAryPtr::make(TypePtr::BotPTR, target_array_type, target_array->klass(), true, Type::OffsetBot);
 
+  // String.value field is known to be @Stable.
+  if (UseImplicitStableValues) {
+    target = cast_array_to_stable(target, target_type);
+  }
+
   IdealKit kit(this, false, true);
 #define __ kit.
   Node* zero             = __ ConI(0);
@@ -2756,10 +2761,28 @@
       newval = _gvn.makecon(TypePtr::NULL_PTR);
 
     // Reference stores need a store barrier.
-    pre_barrier(true /* do_load*/,
-                control(), base, adr, alias_idx, newval, value_type->make_oopptr(),
-                NULL /* pre_val*/,
-                T_OBJECT);
+    if (kind == LS_xchg) {
+      // If pre-barrier must execute before the oop store, old value will require do_load here.
+      if (!can_move_pre_barrier()) {
+        pre_barrier(true /* do_load*/,
+                    control(), base, adr, alias_idx, newval, value_type->make_oopptr(),
+                    NULL /* pre_val*/,
+                    T_OBJECT);
+      } // Else move pre_barrier to use load_store value, see below.
+    } else if (kind == LS_cmpxchg) {
+      // Same as for newval above:
+      if (_gvn.type(oldval) == TypePtr::NULL_PTR) {
+        oldval = _gvn.makecon(TypePtr::NULL_PTR);
+      }
+      // The only known value which might get overwritten is oldval.
+      pre_barrier(false /* do_load */,
+                  control(), NULL, NULL, max_juint, NULL, NULL,
+                  oldval /* pre_val */,
+                  T_OBJECT);
+    } else {
+      ShouldNotReachHere();
+    }
+
 #ifdef _LP64
     if (adr->bottom_type()->is_ptr_to_narrowoop()) {
       Node *newval_enc = _gvn.transform(new (C) EncodePNode(newval, newval->bottom_type()->make_narrowoop()));
@@ -2795,16 +2818,27 @@
   Node* proj = _gvn.transform(new (C) SCMemProjNode(load_store));
   set_memory(proj, alias_idx);
 
+  if (type == T_OBJECT && kind == LS_xchg) {
+#ifdef _LP64
+    if (adr->bottom_type()->is_ptr_to_narrowoop()) {
+      load_store = _gvn.transform(new (C) DecodeNNode(load_store, load_store->get_ptr_type()));
+    }
+#endif
+    if (can_move_pre_barrier()) {
+      // Don't need to load pre_val. The old value is returned by load_store.
+      // The pre_barrier can execute after the xchg as long as no safepoint
+      // gets inserted between them.
+      pre_barrier(false /* do_load */,
+                  control(), NULL, NULL, max_juint, NULL, NULL,
+                  load_store /* pre_val */,
+                  T_OBJECT);
+    }
+  }
+
   // Add the trailing membar surrounding the access
   insert_mem_bar(Op_MemBarCPUOrder);
   insert_mem_bar(Op_MemBarAcquire);
 
-#ifdef _LP64
-  if (type == T_OBJECT && adr->bottom_type()->is_ptr_to_narrowoop() && kind == LS_xchg) {
-    load_store = _gvn.transform(new (C) DecodeNNode(load_store, load_store->get_ptr_type()));
-  }
-#endif
-
   assert(type2size[load_store->bottom_type()->basic_type()] == type2size[rtype], "result type should match");
   set_result(load_store);
   return true;
--- a/src/share/vm/opto/live.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/live.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -85,8 +85,8 @@
     IndexSet* def = &_defs[block->_pre_order-1];
     DEBUG_ONLY(IndexSet *def_outside = getfreeset();)
     uint i;
-    for (i = block->_nodes.size(); i > 1; i--) {
-      Node* n = block->_nodes[i-1];
+    for (i = block->number_of_nodes(); i > 1; i--) {
+      Node* n = block->get_node(i-1);
       if (n->is_Phi()) {
         break;
       }
@@ -112,7 +112,7 @@
 #endif
     // Remove anything defined by Phis and the block start instruction
     for (uint k = i; k > 0; k--) {
-      uint r = _names[block->_nodes[k - 1]->_idx];
+      uint r = _names[block->get_node(k - 1)->_idx];
       def->insert(r);
       use->remove(r);
     }
@@ -124,7 +124,7 @@
 
       // PhiNode uses go in the live-out set of prior blocks.
       for (uint k = i; k > 0; k--) {
-        add_liveout(p, _names[block->_nodes[k-1]->in(l)->_idx], first_pass);
+        add_liveout(p, _names[block->get_node(k-1)->in(l)->_idx], first_pass);
       }
     }
     freeset(block);
@@ -254,10 +254,10 @@
 void PhaseLive::dump( const Block *b ) const {
   tty->print("Block %d: ",b->_pre_order);
   tty->print("LiveOut: ");  _live[b->_pre_order-1].dump();
-  uint cnt = b->_nodes.size();
+  uint cnt = b->number_of_nodes();
   for( uint i=0; i<cnt; i++ ) {
-    tty->print("L%d/", _names[b->_nodes[i]->_idx] );
-    b->_nodes[i]->dump();
+    tty->print("L%d/", _names[b->get_node(i)->_idx] );
+    b->get_node(i)->dump();
   }
   tty->print("\n");
 }
@@ -269,7 +269,7 @@
   for (uint i = 0; i < _cfg.number_of_blocks(); i++) {
     Block* block = _cfg.get_block(i);
     for (uint j = block->end_idx() + 1; j > 1; j--) {
-      Node* n = block->_nodes[j-1];
+      Node* n = block->get_node(j-1);
       if (n->is_Phi()) {
         break;
       }
--- a/src/share/vm/opto/macro.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/macro.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -72,6 +72,8 @@
   int jvms_adj  = new_dbg_start - old_dbg_start;
   assert (new_dbg_start == newcall->req(), "argument count mismatch");
 
+  // SafePointScalarObject node could be referenced several times in debug info.
+  // Use Dict to record cloned nodes.
   Dict* sosn_map = new Dict(cmpkey,hashkey);
   for (uint i = old_dbg_start; i < oldcall->req(); i++) {
     Node* old_in = oldcall->in(i);
@@ -79,8 +81,8 @@
     if (old_in != NULL && old_in->is_SafePointScalarObject()) {
       SafePointScalarObjectNode* old_sosn = old_in->as_SafePointScalarObject();
       uint old_unique = C->unique();
-      Node* new_in = old_sosn->clone(jvms_adj, sosn_map);
-      if (old_unique != C->unique()) {
+      Node* new_in = old_sosn->clone(sosn_map);
+      if (old_unique != C->unique()) { // New node?
         new_in->set_req(0, C->root()); // reset control edge
         new_in = transform_later(new_in); // Register new node.
       }
@@ -725,7 +727,11 @@
   while (safepoints.length() > 0) {
     SafePointNode* sfpt = safepoints.pop();
     Node* mem = sfpt->memory();
-    uint first_ind = sfpt->req();
+    assert(sfpt->jvms() != NULL, "missed JVMS");
+    // Fields of scalar objs are referenced only at the end
+    // of regular debuginfo at the last (youngest) JVMS.
+    // Record relative start index.
+    uint first_ind = (sfpt->req() - sfpt->jvms()->scloff());
     SafePointScalarObjectNode* sobj = new (C) SafePointScalarObjectNode(res_type,
 #ifdef ASSERT
                                                  alloc,
@@ -799,7 +805,7 @@
           for (int i = start; i < end; i++) {
             if (sfpt_done->in(i)->is_SafePointScalarObject()) {
               SafePointScalarObjectNode* scobj = sfpt_done->in(i)->as_SafePointScalarObject();
-              if (scobj->first_index() == sfpt_done->req() &&
+              if (scobj->first_index(jvms) == sfpt_done->req() &&
                   scobj->n_fields() == (uint)nfields) {
                 assert(scobj->alloc() == alloc, "sanity");
                 sfpt_done->set_req(i, res);
--- a/src/share/vm/opto/memnode.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/memnode.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -962,6 +962,19 @@
   return (uintptr_t)in(Control) + (uintptr_t)in(Memory) + (uintptr_t)in(Address);
 }
 
+static bool skip_through_membars(Compile::AliasType* atp, const TypeInstPtr* tp, bool eliminate_boxing) {
+  if ((atp != NULL) && (atp->index() >= Compile::AliasIdxRaw)) {
+    bool non_volatile = (atp->field() != NULL) && !atp->field()->is_volatile();
+    bool is_stable_ary = FoldStableValues &&
+                         (tp != NULL) && (tp->isa_aryptr() != NULL) &&
+                         tp->isa_aryptr()->is_stable();
+
+    return (eliminate_boxing && non_volatile) || is_stable_ary;
+  }
+
+  return false;
+}
+
 //---------------------------can_see_stored_value------------------------------
 // This routine exists to make sure this set of tests is done the same
 // everywhere.  We need to make a coordinated change: first LoadNode::Ideal
@@ -976,11 +989,9 @@
   const TypeInstPtr* tp = phase->type(ld_adr)->isa_instptr();
   Compile::AliasType* atp = (tp != NULL) ? phase->C->alias_type(tp) : NULL;
   // This is more general than load from boxing objects.
-  if (phase->C->eliminate_boxing() && (atp != NULL) &&
-      (atp->index() >= Compile::AliasIdxRaw) &&
-      (atp->field() != NULL) && !atp->field()->is_volatile()) {
+  if (skip_through_membars(atp, tp, phase->C->eliminate_boxing())) {
     uint alias_idx = atp->index();
-    bool final = atp->field()->is_final();
+    bool final = !atp->is_rewritable();
     Node* result = NULL;
     Node* current = st;
     // Skip through chains of MemBarNodes checking the MergeMems for
@@ -1015,7 +1026,6 @@
     }
   }
 
-
   // Loop around twice in the case Load -> Initialize -> Store.
   // (See PhaseIterGVN::add_users_to_worklist, which knows about this case.)
   for (int trip = 0; trip <= 1; trip++) {
@@ -1577,6 +1587,40 @@
   return NULL;
 }
 
+// Try to constant-fold a stable array element.
+static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicType loadbt) {
+  assert(ary->is_stable(), "array should be stable");
+
+  if (ary->const_oop() != NULL) {
+    // Decode the results of GraphKit::array_element_address.
+    ciArray* aobj = ary->const_oop()->as_array();
+    ciConstant con = aobj->element_value_by_offset(off);
+
+    if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) {
+      const Type* con_type = Type::make_from_constant(con);
+      if (con_type != NULL) {
+        if (con_type->isa_aryptr()) {
+          // Join with the array element type, in case it is also stable.
+          int dim = ary->stable_dimension();
+          con_type = con_type->is_aryptr()->cast_to_stable(true, dim-1);
+        }
+        if (loadbt == T_NARROWOOP && con_type->isa_oopptr()) {
+          con_type = con_type->make_narrowoop();
+        }
+#ifndef PRODUCT
+        if (TraceIterativeGVN) {
+          tty->print("FoldStableValues: array element [off=%d]: con_type=", off);
+          con_type->dump(); tty->cr();
+        }
+#endif //PRODUCT
+        return con_type;
+      }
+    }
+  }
+
+  return NULL;
+}
+
 //------------------------------Value-----------------------------------------
 const Type *LoadNode::Value( PhaseTransform *phase ) const {
   // Either input is TOP ==> the result is TOP
@@ -1591,8 +1635,31 @@
   Compile* C = phase->C;
 
   // Try to guess loaded type from pointer type
-  if (tp->base() == Type::AryPtr) {
-    const Type *t = tp->is_aryptr()->elem();
+  if (tp->isa_aryptr()) {
+    const TypeAryPtr* ary = tp->is_aryptr();
+    const Type *t = ary->elem();
+
+    // Determine whether the reference is beyond the header or not, by comparing
+    // the offset against the offset of the start of the array's data.
+    // Different array types begin at slightly different offsets (12 vs. 16).
+    // We choose T_BYTE as an example base type that is least restrictive
+    // as to alignment, which will therefore produce the smallest
+    // possible base offset.
+    const int min_base_off = arrayOopDesc::base_offset_in_bytes(T_BYTE);
+    const bool off_beyond_header = ((uint)off >= (uint)min_base_off);
+
+    // Try to constant-fold a stable array element.
+    if (FoldStableValues && ary->is_stable()) {
+      // Make sure the reference is not into the header
+      if (off_beyond_header && off != Type::OffsetBot) {
+        assert(adr->is_AddP() && adr->in(AddPNode::Offset)->is_Con(), "offset is a constant");
+        const Type* con_type = fold_stable_ary_elem(ary, off, memory_type());
+        if (con_type != NULL) {
+          return con_type;
+        }
+      }
+    }
+
     // Don't do this for integer types. There is only potential profit if
     // the element type t is lower than _type; that is, for int types, if _type is
     // more restrictive than t.  This only happens here if one is short and the other
@@ -1613,14 +1680,7 @@
         && Opcode() != Op_LoadKlass && Opcode() != Op_LoadNKlass) {
       // t might actually be lower than _type, if _type is a unique
       // concrete subclass of abstract class t.
-      // Make sure the reference is not into the header, by comparing
-      // the offset against the offset of the start of the array's data.
-      // Different array types begin at slightly different offsets (12 vs. 16).
-      // We choose T_BYTE as an example base type that is least restrictive
-      // as to alignment, which will therefore produce the smallest
-      // possible base offset.
-      const int min_base_off = arrayOopDesc::base_offset_in_bytes(T_BYTE);
-      if ((uint)off >= (uint)min_base_off) {  // is the offset beyond the header?
+      if (off_beyond_header) {  // is the offset beyond the header?
         const Type* jt = t->join(_type);
         // In any case, do not allow the join, per se, to empty out the type.
         if (jt->empty() && !t->empty()) {
--- a/src/share/vm/opto/node.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/node.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -773,6 +773,21 @@
   _in[_cnt] = NULL;       // NULL out emptied slot
 }
 
+//------------------------------del_req_ordered--------------------------------
+// Delete the required edge and compact the edge array with preserved order
+void Node::del_req_ordered( uint idx ) {
+  assert( idx < _cnt, "oob");
+  assert( !VerifyHashTableKeys || _hash_lock == 0,
+          "remove node from hash table before modifying it");
+  // First remove corresponding def-use edge
+  Node *n = in(idx);
+  if (n != NULL) n->del_out((Node *)this);
+  if (idx < _cnt - 1) { // Not last edge ?
+    Copy::conjoint_words_to_lower((HeapWord*)&_in[idx+1], (HeapWord*)&_in[idx], ((_cnt-idx-1)*sizeof(Node*)));
+  }
+  _in[--_cnt] = NULL;   // NULL out emptied slot
+}
+
 //------------------------------ins_req----------------------------------------
 // Insert a new required input at the end
 void Node::ins_req( uint idx, Node *n ) {
--- a/src/share/vm/opto/node.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/node.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -384,6 +384,7 @@
   void add_req( Node *n ); // Append a NEW required input
   void add_req_batch( Node* n, uint m ); // Append m NEW required inputs (all n).
   void del_req( uint idx ); // Delete required edge & compact
+  void del_req_ordered( uint idx ); // Delete required edge & compact with preserved order
   void ins_req( uint i, Node *n ); // Insert a NEW required input
   void set_req( uint i, Node *n ) {
     assert( is_not_dead(n), "can not use dead node");
--- a/src/share/vm/opto/output.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/output.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -57,7 +57,7 @@
 // Convert Nodes to instruction bits and pass off to the VM
 void Compile::Output() {
   // RootNode goes
-  assert( _cfg->get_root_block()->_nodes.size() == 0, "" );
+  assert( _cfg->get_root_block()->number_of_nodes() == 0, "" );
 
   // The number of new nodes (mostly MachNop) is proportional to
   // the number of java calls and inner loops which are aligned.
@@ -70,11 +70,11 @@
   Block *entry = _cfg->get_block(1);
   Block *broot = _cfg->get_root_block();
 
-  const StartNode *start = entry->_nodes[0]->as_Start();
+  const StartNode *start = entry->head()->as_Start();
 
   // Replace StartNode with prolog
   MachPrologNode *prolog = new (this) MachPrologNode();
-  entry->_nodes.map( 0, prolog );
+  entry->map_node(prolog, 0);
   _cfg->map_node_to_block(prolog, entry);
   _cfg->unmap_node_from_block(start); // start is no longer in any block
 
@@ -144,8 +144,8 @@
     for (uint i = 0; i < _cfg->number_of_blocks(); i++) {
       tty->print("\nBB#%03d:\n", i);
       Block* block = _cfg->get_block(i);
-      for (uint j = 0; j < block->_nodes.size(); j++) {
-        Node* n = block->_nodes[j];
+      for (uint j = 0; j < block->number_of_nodes(); j++) {
+        Node* n = block->get_node(j);
         OptoReg::Name reg = _regalloc->get_reg_first(n);
         tty->print(" %-6s ", reg >= 0 && reg < REG_COUNT ? Matcher::regName[reg] : "");
         n->dump();
@@ -226,8 +226,8 @@
   // Insert call to zap runtime stub before every node with an oop map
   for( uint i=0; i<_cfg->number_of_blocks(); i++ ) {
     Block *b = _cfg->get_block(i);
-    for ( uint j = 0;  j < b->_nodes.size();  ++j ) {
-      Node *n = b->_nodes[j];
+    for ( uint j = 0;  j < b->number_of_nodes();  ++j ) {
+      Node *n = b->get_node(j);
 
       // Determining if we should insert a zap-a-lot node in output.
       // We do that for all nodes that has oopmap info, except for calls
@@ -256,7 +256,7 @@
         }
         if (insert) {
           Node *zap = call_zap_node(n->as_MachSafePoint(), i);
-          b->_nodes.insert( j, zap );
+          b->insert_node(zap, j);
           _cfg->map_node_to_block(zap, b);
           ++j;
         }
@@ -379,10 +379,10 @@
     DEBUG_ONLY( jmp_rule[i]   = 0; )
 
     // Sum all instruction sizes to compute block size
-    uint last_inst = block->_nodes.size();
+    uint last_inst = block->number_of_nodes();
     uint blk_size = 0;
     for (uint j = 0; j < last_inst; j++) {
-      Node* nj = block->_nodes[j];
+      Node* nj = block->get_node(j);
       // Handle machine instruction nodes
       if (nj->is_Mach()) {
         MachNode *mach = nj->as_Mach();
@@ -477,18 +477,18 @@
     for (uint i = 0; i < nblocks; i++) {
       Block* block = _cfg->get_block(i);
       int idx = jmp_nidx[i];
-      MachNode* mach = (idx == -1) ? NULL: block->_nodes[idx]->as_Mach();
+      MachNode* mach = (idx == -1) ? NULL: block->get_node(idx)->as_Mach();
       if (mach != NULL && mach->may_be_short_branch()) {
 #ifdef ASSERT
         assert(jmp_size[i] > 0 && mach->is_MachBranch(), "sanity");
         int j;
         // Find the branch; ignore trailing NOPs.
-        for (j = block->_nodes.size()-1; j>=0; j--) {
-          Node* n = block->_nodes[j];
+        for (j = block->number_of_nodes()-1; j>=0; j--) {
+          Node* n = block->get_node(j);
           if (!n->is_Mach() || n->as_Mach()->ideal_Opcode() != Op_Con)
             break;
         }
-        assert(j >= 0 && j == idx && block->_nodes[j] == (Node*)mach, "sanity");
+        assert(j >= 0 && j == idx && block->get_node(j) == (Node*)mach, "sanity");
 #endif
         int br_size = jmp_size[i];
         int br_offs = blk_starts[i] + jmp_offset[i];
@@ -522,7 +522,7 @@
             diff -= nop_size;
           }
           adjust_block_start += diff;
-          block->_nodes.map(idx, replacement);
+          block->map_node(replacement, idx);
           mach->subsume_by(replacement, C);
           mach = replacement;
           progress = true;
@@ -639,7 +639,7 @@
                            new ConstantOopWriteValue(cik->java_mirror()->constant_encoding()));
       Compile::set_sv_for_object_node(objs, sv);
 
-      uint first_ind = spobj->first_index();
+      uint first_ind = spobj->first_index(sfpt->jvms());
       for (uint i = 0; i < spobj->n_fields(); i++) {
         Node* fld_node = sfpt->in(first_ind+i);
         (void)FillLocArray(sv->field_values()->length(), sfpt, fld_node, sv->field_values(), objs);
@@ -894,7 +894,7 @@
     GrowableArray<MonitorValue*> *monarray = new GrowableArray<MonitorValue*>(num_mon);
 
     // Loop over monitors and insert into array
-    for(idx = 0; idx < num_mon; idx++) {
+    for (idx = 0; idx < num_mon; idx++) {
       // Grab the node that defines this monitor
       Node* box_node = sfn->monitor_box(jvms, idx);
       Node* obj_node = sfn->monitor_obj(jvms, idx);
@@ -902,11 +902,11 @@
       // Create ScopeValue for object
       ScopeValue *scval = NULL;
 
-      if( obj_node->is_SafePointScalarObject() ) {
+      if (obj_node->is_SafePointScalarObject()) {
         SafePointScalarObjectNode* spobj = obj_node->as_SafePointScalarObject();
         scval = Compile::sv_for_node_id(objs, spobj->_idx);
         if (scval == NULL) {
-          const Type *t = obj_node->bottom_type();
+          const Type *t = spobj->bottom_type();
           ciKlass* cik = t->is_oopptr()->klass();
           assert(cik->is_instance_klass() ||
                  cik->is_array_klass(), "Not supported allocation.");
@@ -914,14 +914,14 @@
                                             new ConstantOopWriteValue(cik->java_mirror()->constant_encoding()));
           Compile::set_sv_for_object_node(objs, sv);
 
-          uint first_ind = spobj->first_index();
+          uint first_ind = spobj->first_index(youngest_jvms);
           for (uint i = 0; i < spobj->n_fields(); i++) {
             Node* fld_node = sfn->in(first_ind+i);
             (void)FillLocArray(sv->field_values()->length(), sfn, fld_node, sv->field_values(), objs);
           }
           scval = sv;
         }
-      } else if( !obj_node->is_Con() ) {
+      } else if (!obj_node->is_Con()) {
         OptoReg::Name obj_reg = _regalloc->get_reg_first(obj_node);
         if( obj_node->bottom_type()->base() == Type::NarrowOop ) {
           scval = new_loc_value( _regalloc, obj_reg, Location::narrowoop );
@@ -1088,8 +1088,8 @@
     for (uint i = 0; i < _cfg->number_of_blocks(); i++) {
       Block* b = _cfg->get_block(i);
 
-      for (uint j = 0; j < b->_nodes.size(); j++) {
-        Node* n = b->_nodes[j];
+      for (uint j = 0; j < b->number_of_nodes(); j++) {
+        Node* n = b->get_node(j);
 
         // If the node is a MachConstantNode evaluate the constant
         // value section.
@@ -1247,14 +1247,14 @@
     // Define the label at the beginning of the basic block
     MacroAssembler(cb).bind(blk_labels[block->_pre_order]);
 
-    uint last_inst = block->_nodes.size();
+    uint last_inst = block->number_of_nodes();
 
     // Emit block normally, except for last instruction.
     // Emit means "dump code bits into code buffer".
     for (uint j = 0; j<last_inst; j++) {
 
       // Get the node
-      Node* n = block->_nodes[j];
+      Node* n = block->get_node(j);
 
       // See if delay slots are supported
       if (valid_bundle_info(n) &&
@@ -1308,7 +1308,7 @@
           assert((padding % nop_size) == 0, "padding is not a multiple of NOP size");
           int nops_cnt = padding / nop_size;
           MachNode *nop = new (this) MachNopNode(nops_cnt);
-          block->_nodes.insert(j++, nop);
+          block->insert_node(nop, j++);
           last_inst++;
           _cfg->map_node_to_block(nop, block);
           nop->emit(*cb, _regalloc);
@@ -1394,7 +1394,7 @@
               // Insert padding between avoid_back_to_back branches.
               if (needs_padding && replacement->avoid_back_to_back()) {
                 MachNode *nop = new (this) MachNopNode();
-                block->_nodes.insert(j++, nop);
+                block->insert_node(nop, j++);
                 _cfg->map_node_to_block(nop, block);
                 last_inst++;
                 nop->emit(*cb, _regalloc);
@@ -1407,7 +1407,7 @@
               jmp_size[i]   = new_size;
               jmp_rule[i]   = mach->rule();
 #endif
-              block->_nodes.map(j, replacement);
+              block->map_node(replacement, j);
               mach->subsume_by(replacement, C);
               n    = replacement;
               mach = replacement;
@@ -1438,7 +1438,7 @@
             count++;
             uint i4;
             for (i4 = 0; i4 < last_inst; ++i4) {
-              if (block->_nodes[i4] == oop_store) {
+              if (block->get_node(i4) == oop_store) {
                 break;
               }
             }
@@ -1548,7 +1548,7 @@
       int padding = nb->alignment_padding(current_offset);
       if( padding > 0 ) {
         MachNode *nop = new (this) MachNopNode(padding / nop_size);
-        block->_nodes.insert(block->_nodes.size(), nop);
+        block->insert_node(nop, block->number_of_nodes());
         _cfg->map_node_to_block(nop, block);
         nop->emit(*cb, _regalloc);
         current_offset = cb->insts_size();
@@ -1655,8 +1655,8 @@
     int j;
 
     // Find the branch; ignore trailing NOPs.
-    for (j = block->_nodes.size() - 1; j >= 0; j--) {
-      n = block->_nodes[j];
+    for (j = block->number_of_nodes() - 1; j >= 0; j--) {
+      n = block->get_node(j);
       if (!n->is_Mach() || n->as_Mach()->ideal_Opcode() != Op_Con) {
         break;
       }
@@ -1675,8 +1675,8 @@
       uint call_return = call_returns[block->_pre_order];
 #ifdef ASSERT
       assert( call_return > 0, "no call seen for this basic block" );
-      while (block->_nodes[--j]->is_MachProj()) ;
-      assert(block->_nodes[j]->is_MachCall(), "CatchProj must follow call");
+      while (block->get_node(--j)->is_MachProj()) ;
+      assert(block->get_node(j)->is_MachCall(), "CatchProj must follow call");
 #endif
       // last instruction is a CatchNode, find it's CatchProjNodes
       int nof_succs = block->_num_succs;
@@ -1782,7 +1782,7 @@
   // Get the last node
   Block* block = _cfg->get_block(_cfg->number_of_blocks() - 1);
 
-  _next_node = block->_nodes[block->_nodes.size() - 1];
+  _next_node = block->get_node(block->number_of_nodes() - 1);
 }
 
 #ifndef PRODUCT
@@ -1875,7 +1875,7 @@
     // Used to allow latency 0 to force an instruction to the beginning
     // of the bb
     uint latency = 1;
-    Node *use = bb->_nodes[j];
+    Node *use = bb->get_node(j);
     uint nlen = use->len();
 
     // Walk over all the inputs
@@ -2286,7 +2286,7 @@
        (OptoReg::is_valid(_regalloc->get_reg_first(n)) || op != Op_BoxLock)) ) {
 
     // Push any trailing projections
-    if( bb->_nodes[bb->_nodes.size()-1] != n ) {
+    if( bb->get_node(bb->number_of_nodes()-1) != n ) {
       for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
         Node *foi = n->fast_out(i);
         if( foi->is_Proj() )
@@ -2329,21 +2329,21 @@
   _unconditional_delay_slot = NULL;
 
 #ifdef ASSERT
-  for( uint i=0; i < bb->_nodes.size(); i++ )
-    assert( _uses[bb->_nodes[i]->_idx] == 0, "_use array not clean" );
+  for( uint i=0; i < bb->number_of_nodes(); i++ )
+    assert( _uses[bb->get_node(i)->_idx] == 0, "_use array not clean" );
 #endif
 
   // Force the _uses count to never go to zero for unscheduable pieces
   // of the block
   for( uint k = 0; k < _bb_start; k++ )
-    _uses[bb->_nodes[k]->_idx] = 1;
-  for( uint l = _bb_end; l < bb->_nodes.size(); l++ )
-    _uses[bb->_nodes[l]->_idx] = 1;
+    _uses[bb->get_node(k)->_idx] = 1;
+  for( uint l = _bb_end; l < bb->number_of_nodes(); l++ )
+    _uses[bb->get_node(l)->_idx] = 1;
 
   // Iterate backwards over the instructions in the block.  Don't count the
   // branch projections at end or the block header instructions.
   for( uint j = _bb_end-1; j >= _bb_start; j-- ) {
-    Node *n = bb->_nodes[j];
+    Node *n = bb->get_node(j);
     if( n->is_Proj() ) continue; // Projections handled another way
 
     // Account for all uses
@@ -2398,8 +2398,8 @@
 #ifndef PRODUCT
     if (_cfg->C->trace_opto_output()) {
       tty->print("#  Schedule BB#%03d (initial)\n", i);
-      for (uint j = 0; j < bb->_nodes.size(); j++) {
-        bb->_nodes[j]->dump();
+      for (uint j = 0; j < bb->number_of_nodes(); j++) {
+        bb->get_node(j)->dump();
       }
     }
 #endif
@@ -2426,10 +2426,10 @@
     }
 
     // Leave untouched the starting instruction, any Phis, a CreateEx node
-    // or Top.  bb->_nodes[_bb_start] is the first schedulable instruction.
-    _bb_end = bb->_nodes.size()-1;
+    // or Top.  bb->get_node(_bb_start) is the first schedulable instruction.
+    _bb_end = bb->number_of_nodes()-1;
     for( _bb_start=1; _bb_start <= _bb_end; _bb_start++ ) {
-      Node *n = bb->_nodes[_bb_start];
+      Node *n = bb->get_node(_bb_start);
       // Things not matched, like Phinodes and ProjNodes don't get scheduled.
       // Also, MachIdealNodes do not get scheduled
       if( !n->is_Mach() ) continue;     // Skip non-machine nodes
@@ -2449,19 +2449,19 @@
     // in the block), because they have delay slots we can fill.  Calls all
     // have their delay slots filled in the template expansions, so we don't
     // bother scheduling them.
-    Node *last = bb->_nodes[_bb_end];
+    Node *last = bb->get_node(_bb_end);
     // Ignore trailing NOPs.
     while (_bb_end > 0 && last->is_Mach() &&
            last->as_Mach()->ideal_Opcode() == Op_Con) {
-      last = bb->_nodes[--_bb_end];
+      last = bb->get_node(--_bb_end);
     }
     assert(!last->is_Mach() || last->as_Mach()->ideal_Opcode() != Op_Con, "");
     if( last->is_Catch() ||
        // Exclude unreachable path case when Halt node is in a separate block.
        (_bb_end > 1 && last->is_Mach() && last->as_Mach()->ideal_Opcode() == Op_Halt) ) {
       // There must be a prior call.  Skip it.
-      while( !bb->_nodes[--_bb_end]->is_MachCall() ) {
-        assert( bb->_nodes[_bb_end]->is_MachProj(), "skipping projections after expected call" );
+      while( !bb->get_node(--_bb_end)->is_MachCall() ) {
+        assert( bb->get_node(_bb_end)->is_MachProj(), "skipping projections after expected call" );
       }
     } else if( last->is_MachNullCheck() ) {
       // Backup so the last null-checked memory instruction is
@@ -2470,7 +2470,7 @@
       Node *mem = last->in(1);
       do {
         _bb_end--;
-      } while (mem != bb->_nodes[_bb_end]);
+      } while (mem != bb->get_node(_bb_end));
     } else {
       // Set _bb_end to point after last schedulable inst.
       _bb_end++;
@@ -2499,7 +2499,7 @@
     assert( _scheduled.size() == _bb_end - _bb_start, "wrong number of instructions" );
 #ifdef ASSERT
     for( uint l = _bb_start; l < _bb_end; l++ ) {
-      Node *n = bb->_nodes[l];
+      Node *n = bb->get_node(l);
       uint m;
       for( m = 0; m < _bb_end-_bb_start; m++ )
         if( _scheduled[m] == n )
@@ -2510,14 +2510,14 @@
 
     // Now copy the instructions (in reverse order) back to the block
     for ( uint k = _bb_start; k < _bb_end; k++ )
-      bb->_nodes.map(k, _scheduled[_bb_end-k-1]);
+      bb->map_node(_scheduled[_bb_end-k-1], k);
 
 #ifndef PRODUCT
     if (_cfg->C->trace_opto_output()) {
       tty->print("#  Schedule BB#%03d (final)\n", i);
       uint current = 0;
-      for (uint j = 0; j < bb->_nodes.size(); j++) {
-        Node *n = bb->_nodes[j];
+      for (uint j = 0; j < bb->number_of_nodes(); j++) {
+        Node *n = bb->get_node(j);
         if( valid_bundle_info(n) ) {
           Bundle *bundle = node_bundling(n);
           if (bundle->instr_count() > 0 || bundle->flags() > 0) {
@@ -2579,8 +2579,8 @@
   // Walk over the block backwards.  Check to make sure each DEF doesn't
   // kill a live value (other than the one it's supposed to).  Add each
   // USE to the live set.
-  for( uint i = b->_nodes.size()-1; i >= _bb_start; i-- ) {
-    Node *n = b->_nodes[i];
+  for( uint i = b->number_of_nodes()-1; i >= _bb_start; i-- ) {
+    Node *n = b->get_node(i);
     int n_op = n->Opcode();
     if( n_op == Op_MachProj && n->ideal_reg() == MachProjNode::fat_proj ) {
       // Fat-proj kills a slew of registers
@@ -2711,7 +2711,7 @@
         pinch->req() == 1 ) {   // pinch not yet in block?
       pinch->del_req(0);        // yank pointer to later-def, also set flag
       // Insert the pinch-point in the block just after the last use
-      b->_nodes.insert(b->find_node(use)+1,pinch);
+      b->insert_node(pinch, b->find_node(use) + 1);
       _bb_end++;                // Increase size scheduled region in block
     }
 
@@ -2763,10 +2763,10 @@
   // it being in the current block.
   bool fat_proj_seen = false;
   uint last_safept = _bb_end-1;
-  Node* end_node         = (_bb_end-1 >= _bb_start) ? b->_nodes[last_safept] : NULL;
+  Node* end_node         = (_bb_end-1 >= _bb_start) ? b->get_node(last_safept) : NULL;
   Node* last_safept_node = end_node;
   for( uint i = _bb_end-1; i >= _bb_start; i-- ) {
-    Node *n = b->_nodes[i];
+    Node *n = b->get_node(i);
     int is_def = n->outcnt();   // def if some uses prior to adding precedence edges
     if( n->is_MachProj() && n->ideal_reg() == MachProjNode::fat_proj ) {
       // Fat-proj kills a slew of registers
@@ -2815,7 +2815,7 @@
     // Do not allow defs of new derived values to float above GC
     // points unless the base is definitely available at the GC point.
 
-    Node *m = b->_nodes[i];
+    Node *m = b->get_node(i);
 
     // Add precedence edge from following safepoint to use of derived pointer
     if( last_safept_node != end_node &&
@@ -2832,11 +2832,11 @@
 
     if( n->jvms() ) {           // Precedence edge from derived to safept
       // Check if last_safept_node was moved by pinch-point insertion in anti_do_use()
-      if( b->_nodes[last_safept] != last_safept_node ) {
+      if( b->get_node(last_safept) != last_safept_node ) {
         last_safept = b->find_node(last_safept_node);
       }
       for( uint j=last_safept; j > i; j-- ) {
-        Node *mach = b->_nodes[j];
+        Node *mach = b->get_node(j);
         if( mach->is_Mach() && mach->as_Mach()->ideal_Opcode() == Op_AddP )
           mach->add_prec( n );
       }
--- a/src/share/vm/opto/parse.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/parse.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -518,7 +518,7 @@
 
   // loading from a constant field or the constant pool
   // returns false if push failed (non-perm field constants only, not ldcs)
-  bool push_constant(ciConstant con, bool require_constant = false, bool is_autobox_cache = false);
+  bool push_constant(ciConstant con, bool require_constant = false, bool is_autobox_cache = false, const Type* basic_type = NULL);
 
   // implementation of object creation bytecodes
   void emit_guard_for_new(ciInstanceKlass* klass);
--- a/src/share/vm/opto/parse3.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/parse3.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -147,7 +147,15 @@
 void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) {
   // Does this field have a constant value?  If so, just push the value.
   if (field->is_constant()) {
-    // final field
+    // final or stable field
+    const Type* stable_type = NULL;
+    if (FoldStableValues && field->is_stable()) {
+      stable_type = Type::get_const_type(field->type());
+      if (field->type()->is_array_klass()) {
+        int stable_dimension = field->type()->as_array_klass()->dimension();
+        stable_type = stable_type->is_aryptr()->cast_to_stable(true, stable_dimension);
+      }
+    }
     if (field->is_static()) {
       // final static field
       if (C->eliminate_boxing()) {
@@ -167,11 +175,10 @@
           }
         }
       }
-      if (push_constant(field->constant_value()))
+      if (push_constant(field->constant_value(), false, false, stable_type))
         return;
-    }
-    else {
-      // final non-static field
+    } else {
+      // final or stable non-static field
       // Treat final non-static fields of trusted classes (classes in
       // java.lang.invoke and sun.invoke packages and subpackages) as
       // compile time constants.
@@ -179,8 +186,12 @@
         const TypeOopPtr* oop_ptr = obj->bottom_type()->isa_oopptr();
         ciObject* constant_oop = oop_ptr->const_oop();
         ciConstant constant = field->constant_value_of(constant_oop);
-        if (push_constant(constant, true))
-          return;
+        if (FoldStableValues && field->is_stable() && constant.is_null_or_zero()) {
+          // fall through to field load; the field is not yet initialized
+        } else {
+          if (push_constant(constant, true, false, stable_type))
+            return;
+        }
       }
     }
   }
@@ -301,7 +312,8 @@
   // Note the presence of writes to final non-static fields, so that we
   // can insert a memory barrier later on to keep the writes from floating
   // out of the constructor.
-  if (is_field && field->is_final()) {
+  // Any method can write a @Stable field; insert memory barriers after those also.
+  if (is_field && (field->is_final() || field->is_stable())) {
     set_wrote_final(true);
     // Preserve allocation ptr to create precedent edge to it in membar
     // generated on exit from constructor.
@@ -314,35 +326,21 @@
 }
 
 
-bool Parse::push_constant(ciConstant constant, bool require_constant, bool is_autobox_cache) {
+
+bool Parse::push_constant(ciConstant constant, bool require_constant, bool is_autobox_cache, const Type* stable_type) {
+  const Type* con_type = Type::make_from_constant(constant, require_constant, is_autobox_cache);
   switch (constant.basic_type()) {
-  case T_BOOLEAN:  push( intcon(constant.as_boolean()) ); break;
-  case T_INT:      push( intcon(constant.as_int())     ); break;
-  case T_CHAR:     push( intcon(constant.as_char())    ); break;
-  case T_BYTE:     push( intcon(constant.as_byte())    ); break;
-  case T_SHORT:    push( intcon(constant.as_short())   ); break;
-  case T_FLOAT:    push( makecon(TypeF::make(constant.as_float())) );  break;
-  case T_DOUBLE:   push_pair( makecon(TypeD::make(constant.as_double())) );  break;
-  case T_LONG:     push_pair( longcon(constant.as_long()) ); break;
   case T_ARRAY:
-  case T_OBJECT: {
+  case T_OBJECT:
     // cases:
     //   can_be_constant    = (oop not scavengable || ScavengeRootsInCode != 0)
     //   should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2)
     // An oop is not scavengable if it is in the perm gen.
-    ciObject* oop_constant = constant.as_object();
-    if (oop_constant->is_null_object()) {
-      push( zerocon(T_OBJECT) );
-      break;
-    } else if (require_constant || oop_constant->should_be_constant()) {
-      push( makecon(TypeOopPtr::make_from_constant(oop_constant, require_constant, is_autobox_cache)) );
-      break;
-    } else {
-      // we cannot inline the oop, but we can use it later to narrow a type
-      return false;
-    }
-  }
-  case T_ILLEGAL: {
+    if (stable_type != NULL && con_type != NULL && con_type->isa_oopptr())
+      con_type = con_type->join(stable_type);
+    break;
+
+  case T_ILLEGAL:
     // Invalid ciConstant returned due to OutOfMemoryError in the CI
     assert(C->env()->failing(), "otherwise should not see this");
     // These always occur because of object types; we are going to
@@ -350,17 +348,16 @@
     push( zerocon(T_OBJECT) );
     return false;
   }
-  default:
-    ShouldNotReachHere();
+
+  if (con_type == NULL)
+    // we cannot inline the oop, but we can use it later to narrow a type
     return false;
-  }
 
-  // success
+  push_node(constant.basic_type(), makecon(con_type));
   return true;
 }
 
 
-
 //=============================================================================
 void Parse::do_anewarray() {
   bool will_link;
--- a/src/share/vm/opto/phaseX.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/phaseX.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -1648,10 +1648,10 @@
     bool block_not_printed = true;
 
     // and each instruction within a block
-    uint end_index = block->_nodes.size();
+    uint end_index = block->number_of_nodes();
     // block->end_idx() not valid after PhaseRegAlloc
     for( uint instruction_index = 1; instruction_index < end_index; ++instruction_index ) {
-      Node     *n = block->_nodes.at(instruction_index);
+      Node     *n = block->get_node(instruction_index);
       if( n->is_Mach() ) {
         MachNode *m = n->as_Mach();
         int deleted_count = 0;
@@ -1673,7 +1673,7 @@
             }
             // Print instructions being deleted
             for( int i = (deleted_count - 1); i >= 0; --i ) {
-              block->_nodes.at(instruction_index-i)->as_Mach()->format(_regalloc); tty->cr();
+              block->get_node(instruction_index-i)->as_Mach()->format(_regalloc); tty->cr();
             }
             tty->print_cr("replaced with");
             // Print new instruction
@@ -1687,11 +1687,11 @@
           //  the node index to live range mappings.)
           uint safe_instruction_index = (instruction_index - deleted_count);
           for( ; (instruction_index > safe_instruction_index); --instruction_index ) {
-            block->_nodes.remove( instruction_index );
+            block->remove_node( instruction_index );
           }
           // install new node after safe_instruction_index
-          block->_nodes.insert( safe_instruction_index + 1, m2 );
-          end_index = block->_nodes.size() - 1; // Recompute new block size
+          block->insert_node(m2, safe_instruction_index + 1);
+          end_index = block->number_of_nodes() - 1; // Recompute new block size
           NOT_PRODUCT( inc_peepholes(); )
         }
       }
--- a/src/share/vm/opto/postaloc.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/postaloc.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -423,8 +423,8 @@
 
     // Count of Phis in block
     uint phi_dex;
-    for (phi_dex = 1; phi_dex < block->_nodes.size(); phi_dex++) {
-      Node* phi = block->_nodes[phi_dex];
+    for (phi_dex = 1; phi_dex < block->number_of_nodes(); phi_dex++) {
+      Node* phi = block->get_node(phi_dex);
       if (!phi->is_Phi()) {
         break;
       }
@@ -439,7 +439,7 @@
       Block* pb = _cfg.get_block_for_node(block->pred(j));
       // Remove copies along phi edges
       for (uint k = 1; k < phi_dex; k++) {
-        elide_copy(block->_nodes[k], j, block, *blk2value[pb->_pre_order], *blk2regnd[pb->_pre_order], false);
+        elide_copy(block->get_node(k), j, block, *blk2value[pb->_pre_order], *blk2regnd[pb->_pre_order], false);
       }
       if (blk2value[pb->_pre_order]) { // Have a mapping on this edge?
         // See if this predecessor's mappings have been used by everybody
@@ -510,7 +510,7 @@
     // For all Phi's
     for (j = 1; j < phi_dex; j++) {
       uint k;
-      Node *phi = block->_nodes[j];
+      Node *phi = block->get_node(j);
       uint pidx = _lrg_map.live_range_id(phi);
       OptoReg::Name preg = lrgs(_lrg_map.live_range_id(phi)).reg();
 
@@ -522,7 +522,7 @@
           u = u ? NodeSentinel : x; // Capture unique input, or NodeSentinel for 2nd input
       }
       if (u != NodeSentinel) {    // Junk Phi.  Remove
-        block->_nodes.remove(j--);
+        block->remove_node(j--);
         phi_dex--;
         _cfg.unmap_node_from_block(phi);
         phi->replace_by(u);
@@ -552,8 +552,8 @@
     }
 
     // For all remaining instructions
-    for (j = phi_dex; j < block->_nodes.size(); j++) {
-      Node* n = block->_nodes[j];
+    for (j = phi_dex; j < block->number_of_nodes(); j++) {
+      Node* n = block->get_node(j);
 
       if(n->outcnt() == 0 &&   // Dead?
          n != C->top() &&      // (ignore TOP, it has no du info)
--- a/src/share/vm/opto/reg_split.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/reg_split.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -112,17 +112,17 @@
 void PhaseChaitin::insert_proj( Block *b, uint i, Node *spill, uint maxlrg ) {
   // Skip intervening ProjNodes.  Do not insert between a ProjNode and
   // its definer.
-  while( i < b->_nodes.size() &&
-         (b->_nodes[i]->is_Proj() ||
-          b->_nodes[i]->is_Phi() ) )
+  while( i < b->number_of_nodes() &&
+         (b->get_node(i)->is_Proj() ||
+          b->get_node(i)->is_Phi() ) )
     i++;
 
   // Do not insert between a call and his Catch
-  if( b->_nodes[i]->is_Catch() ) {
+  if( b->get_node(i)->is_Catch() ) {
     // Put the instruction at the top of the fall-thru block.
     // Find the fall-thru projection
     while( 1 ) {
-      const CatchProjNode *cp = b->_nodes[++i]->as_CatchProj();
+      const CatchProjNode *cp = b->get_node(++i)->as_CatchProj();
       if( cp->_con == CatchProjNode::fall_through_index )
         break;
     }
@@ -131,7 +131,7 @@
     i = 1;                      // Right at start of block
   }
 
-  b->_nodes.insert(i,spill);    // Insert node in block
+  b->insert_node(spill, i);    // Insert node in block
   _cfg.map_node_to_block(spill,  b); // Update node->block mapping to reflect
   // Adjust the point where we go hi-pressure
   if( i <= b->_ihrp_index ) b->_ihrp_index++;
@@ -160,9 +160,9 @@
   // (The implicit_null_check function ensures the use is also dominated
   // by the branch-not-taken block.)
   Node *be = b->end();
-  if( be->is_MachNullCheck() && be->in(1) == def && def == b->_nodes[loc] ) {
+  if( be->is_MachNullCheck() && be->in(1) == def && def == b->get_node(loc)) {
     // Spill goes in the branch-not-taken block
-    b = b->_succs[b->_nodes[b->end_idx()+1]->Opcode() == Op_IfTrue];
+    b = b->_succs[b->get_node(b->end_idx()+1)->Opcode() == Op_IfTrue];
     loc = 0;                    // Just past the Region
   }
   assert( loc >= 0, "must insert past block head" );
@@ -450,7 +450,7 @@
 
   // Scan block for 1st use.
   for( uint i = 1; i <= b->end_idx(); i++ ) {
-    Node *n = b->_nodes[i];
+    Node *n = b->get_node(i);
     // Ignore PHI use, these can be up or down
     if (n->is_Phi()) {
       continue;
@@ -647,7 +647,7 @@
 
       // check block for appropriate phinode & update edges
       for( insidx = 1; insidx <= b->end_idx(); insidx++ ) {
-        n1 = b->_nodes[insidx];
+        n1 = b->get_node(insidx);
         // bail if this is not a phi
         phi = n1->is_Phi() ? n1->as_Phi() : NULL;
         if( phi == NULL ) {
@@ -747,7 +747,7 @@
     //----------Walk Instructions in the Block and Split----------
     // For all non-phi instructions in the block
     for( insidx = 1; insidx <= b->end_idx(); insidx++ ) {
-      Node *n = b->_nodes[insidx];
+      Node *n = b->get_node(insidx);
       // Find the defining Node's live range index
       uint defidx = _lrg_map.find_id(n);
       uint cnt = n->req();
@@ -776,7 +776,7 @@
               assert(_lrg_map.find_id(n) == _lrg_map.find_id(u), "should be the same lrg");
               n->replace_by(u); // Then replace with unique input
               n->disconnect_inputs(NULL, C);
-              b->_nodes.remove(insidx);
+              b->remove_node(insidx);
               insidx--;
               b->_ihrp_index--;
               b->_fhrp_index--;
@@ -789,12 +789,12 @@
               (b->_reg_pressure < (uint)INTPRESSURE) ||
               b->_ihrp_index > 4000000 ||
               b->_ihrp_index >= b->end_idx() ||
-              !b->_nodes[b->_ihrp_index]->is_Proj(), "" );
+              !b->get_node(b->_ihrp_index)->is_Proj(), "" );
       assert( insidx > b->_fhrp_index ||
               (b->_freg_pressure < (uint)FLOATPRESSURE) ||
               b->_fhrp_index > 4000000 ||
               b->_fhrp_index >= b->end_idx() ||
-              !b->_nodes[b->_fhrp_index]->is_Proj(), "" );
+              !b->get_node(b->_fhrp_index)->is_Proj(), "" );
 
       // ********** Handle Crossing HRP Boundry **********
       if( (insidx == b->_ihrp_index) || (insidx == b->_fhrp_index) ) {
@@ -819,7 +819,7 @@
                 // Insert point is just past last use or def in the block
                 int insert_point = insidx-1;
                 while( insert_point > 0 ) {
-                  Node *n = b->_nodes[insert_point];
+                  Node *n = b->get_node(insert_point);
                   // Hit top of block?  Quit going backwards
                   if (n->is_Phi()) {
                     break;
@@ -865,7 +865,7 @@
             }
           }  // end if LRG is UP
         }  // end for all spilling live ranges
-        assert( b->_nodes[insidx] == n, "got insidx set incorrectly" );
+        assert( b->get_node(insidx) == n, "got insidx set incorrectly" );
       }  // end if crossing HRP Boundry
 
       // If the LRG index is oob, then this is a new spillcopy, skip it.
@@ -878,7 +878,7 @@
       if (copyidx && defidx == _lrg_map.live_range_id(n->in(copyidx))) {
         n->replace_by( n->in(copyidx) );
         n->set_req( copyidx, NULL );
-        b->_nodes.remove(insidx--);
+        b->remove_node(insidx--);
         b->_ihrp_index--; // Adjust the point where we go hi-pressure
         b->_fhrp_index--;
         continue;
@@ -932,10 +932,10 @@
             // Rematerializable?  Then clone def at use site instead
             // of store/load
             if( def->rematerialize() ) {
-              int old_size = b->_nodes.size();
+              int old_size = b->number_of_nodes();
               def = split_Rematerialize( def, b, insidx, maxlrg, splits, slidx, lrg2reach, Reachblock, true );
               if( !def ) return 0; // Bail out
-              insidx += b->_nodes.size()-old_size;
+              insidx += b->number_of_nodes()-old_size;
             }
 
             MachNode *mach = n->is_Mach() ? n->as_Mach() : NULL;
@@ -1332,8 +1332,8 @@
         // so look at the node before it.
         int insert = pred->end_idx();
         while (insert >= 1 &&
-               pred->_nodes[insert - 1]->is_SpillCopy() &&
-               _lrg_map.find(pred->_nodes[insert - 1]) >= lrgs_before_phi_split) {
+               pred->get_node(insert - 1)->is_SpillCopy() &&
+               _lrg_map.find(pred->get_node(insert - 1)) >= lrgs_before_phi_split) {
           insert--;
         }
         def = split_Rematerialize(def, pred, insert, maxlrg, splits, slidx, lrg2reach, Reachblock, false);
@@ -1402,7 +1402,7 @@
   for (bidx = 0; bidx < _cfg.number_of_blocks(); bidx++) {
     b  = _cfg.get_block(bidx);
     for (insidx = 0; insidx <= b->end_idx(); insidx++) {
-      Node *n = b->_nodes[insidx];
+      Node *n = b->get_node(insidx);
       uint defidx = _lrg_map.find(n);
       assert(defidx < _lrg_map.max_lrg_id(), "Bad live range index in Split");
       assert(defidx < maxlrg,"Bad live range index in Split");
--- a/src/share/vm/opto/type.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/type.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -189,6 +189,38 @@
 }
 
 
+//-----------------------make_from_constant------------------------------------
+const Type* Type::make_from_constant(ciConstant constant,
+                                     bool require_constant, bool is_autobox_cache) {
+  switch (constant.basic_type()) {
+  case T_BOOLEAN:  return TypeInt::make(constant.as_boolean());
+  case T_CHAR:     return TypeInt::make(constant.as_char());
+  case T_BYTE:     return TypeInt::make(constant.as_byte());
+  case T_SHORT:    return TypeInt::make(constant.as_short());
+  case T_INT:      return TypeInt::make(constant.as_int());
+  case T_LONG:     return TypeLong::make(constant.as_long());
+  case T_FLOAT:    return TypeF::make(constant.as_float());
+  case T_DOUBLE:   return TypeD::make(constant.as_double());
+  case T_ARRAY:
+  case T_OBJECT:
+    {
+      // cases:
+      //   can_be_constant    = (oop not scavengable || ScavengeRootsInCode != 0)
+      //   should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2)
+      // An oop is not scavengable if it is in the perm gen.
+      ciObject* oop_constant = constant.as_object();
+      if (oop_constant->is_null_object()) {
+        return Type::get_zero_type(T_OBJECT);
+      } else if (require_constant || oop_constant->should_be_constant()) {
+        return TypeOopPtr::make_from_constant(oop_constant, require_constant, is_autobox_cache);
+      }
+    }
+  }
+  // Fall through to failure
+  return NULL;
+}
+
+
 //------------------------------make-------------------------------------------
 // Create a simple Type, with default empty symbol sets.  Then hashcons it
 // and look for an existing copy in the type dictionary.
@@ -1824,12 +1856,12 @@
 }
 
 //------------------------------make-------------------------------------------
-const TypeAry *TypeAry::make( const Type *elem, const TypeInt *size) {
+const TypeAry* TypeAry::make(const Type* elem, const TypeInt* size, bool stable) {
   if (UseCompressedOops && elem->isa_oopptr()) {
     elem = elem->make_narrowoop();
   }
   size = normalize_array_size(size);
-  return (TypeAry*)(new TypeAry(elem,size))->hashcons();
+  return (TypeAry*)(new TypeAry(elem,size,stable))->hashcons();
 }
 
 //------------------------------meet-------------------------------------------
@@ -1850,7 +1882,8 @@
   case Array: {                 // Meeting 2 arrays?
     const TypeAry *a = t->is_ary();
     return TypeAry::make(_elem->meet(a->_elem),
-                         _size->xmeet(a->_size)->is_int());
+                         _size->xmeet(a->_size)->is_int(),
+                         _stable & a->_stable);
   }
   case Top:
     break;
@@ -1863,7 +1896,7 @@
 const Type *TypeAry::xdual() const {
   const TypeInt* size_dual = _size->dual()->is_int();
   size_dual = normalize_array_size(size_dual);
-  return new TypeAry( _elem->dual(), size_dual);
+  return new TypeAry(_elem->dual(), size_dual, !_stable);
 }
 
 //------------------------------eq---------------------------------------------
@@ -1871,13 +1904,14 @@
 bool TypeAry::eq( const Type *t ) const {
   const TypeAry *a = (const TypeAry*)t;
   return _elem == a->_elem &&
+    _stable == a->_stable &&
     _size == a->_size;
 }
 
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypeAry::hash(void) const {
-  return (intptr_t)_elem + (intptr_t)_size;
+  return (intptr_t)_elem + (intptr_t)_size + (_stable ? 43 : 0);
 }
 
 //----------------------interface_vs_oop---------------------------------------
@@ -1894,6 +1928,7 @@
 //------------------------------dump2------------------------------------------
 #ifndef PRODUCT
 void TypeAry::dump2( Dict &d, uint depth, outputStream *st ) const {
+  if (_stable)  st->print("stable:");
   _elem->dump2(d, depth, st);
   st->print("[");
   _size->dump2(d, depth, st);
@@ -3457,11 +3492,39 @@
   assert(new_size != NULL, "");
   new_size = narrow_size_type(new_size);
   if (new_size == size())  return this;
-  const TypeAry* new_ary = TypeAry::make(elem(), new_size);
+  const TypeAry* new_ary = TypeAry::make(elem(), new_size, is_stable());
   return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id);
 }
 
 
+//------------------------------cast_to_stable---------------------------------
+const TypeAryPtr* TypeAryPtr::cast_to_stable(bool stable, int stable_dimension) const {
+  if (stable_dimension <= 0 || (stable_dimension == 1 && stable == this->is_stable()))
+    return this;
+
+  const Type* elem = this->elem();
+  const TypePtr* elem_ptr = elem->make_ptr();
+
+  if (stable_dimension > 1 && elem_ptr != NULL && elem_ptr->isa_aryptr()) {
+    // If this is widened from a narrow oop, TypeAry::make will re-narrow it.
+    elem = elem_ptr = elem_ptr->is_aryptr()->cast_to_stable(stable, stable_dimension - 1);
+  }
+
+  const TypeAry* new_ary = TypeAry::make(elem, size(), stable);
+
+  return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id);
+}
+
+//-----------------------------stable_dimension--------------------------------
+int TypeAryPtr::stable_dimension() const {
+  if (!is_stable())  return 0;
+  int dim = 1;
+  const TypePtr* elem_ptr = elem()->make_ptr();
+  if (elem_ptr != NULL && elem_ptr->isa_aryptr())
+    dim += elem_ptr->is_aryptr()->stable_dimension();
+  return dim;
+}
+
 //------------------------------eq---------------------------------------------
 // Structural equality check for Type representations
 bool TypeAryPtr::eq( const Type *t ) const {
@@ -3570,7 +3633,7 @@
         // Something like byte[int+] meets char[int+].
         // This must fall to bottom, not (int[-128..65535])[int+].
         instance_id = InstanceBot;
-        tary = TypeAry::make(Type::BOTTOM, tary->_size);
+        tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
       }
     } else // Non integral arrays.
     // Must fall to bottom if exact klasses in upper lattice
@@ -3584,7 +3647,7 @@
          (tap ->_klass_is_exact && !tap->klass()->is_subtype_of(klass())) ||
          // 'this' is exact and super or unrelated:
          (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) {
-      tary = TypeAry::make(Type::BOTTOM, tary->_size);
+      tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
       return make( NotNull, NULL, tary, lazy_klass, false, off, InstanceBot );
     }
 
--- a/src/share/vm/opto/type.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/opto/type.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -372,6 +372,10 @@
   // Mapping from CI type system to compiler type:
   static const Type* get_typeflow_type(ciType* type);
 
+  static const Type* make_from_constant(ciConstant constant,
+                                        bool require_constant = false,
+                                        bool is_autobox_cache = false);
+
 private:
   // support arrays
   static const BasicType _basic_type[];
@@ -588,8 +592,8 @@
 //------------------------------TypeAry----------------------------------------
 // Class of Array Types
 class TypeAry : public Type {
-  TypeAry( const Type *elem, const TypeInt *size) : Type(Array),
-    _elem(elem), _size(size) {}
+  TypeAry(const Type* elem, const TypeInt* size, bool stable) : Type(Array),
+      _elem(elem), _size(size), _stable(stable) {}
 public:
   virtual bool eq( const Type *t ) const;
   virtual int  hash() const;             // Type specific hashing
@@ -599,10 +603,11 @@
 private:
   const Type *_elem;            // Element type of array
   const TypeInt *_size;         // Elements in array
+  const bool _stable;           // Are elements @Stable?
   friend class TypeAryPtr;
 
 public:
-  static const TypeAry *make(  const Type *elem, const TypeInt *size);
+  static const TypeAry* make(const Type* elem, const TypeInt* size, bool stable = false);
 
   virtual const Type *xmeet( const Type *t ) const;
   virtual const Type *xdual() const;    // Compute dual right now.
@@ -988,6 +993,7 @@
   const TypeAry* ary() const  { return _ary; }
   const Type*    elem() const { return _ary->_elem; }
   const TypeInt* size() const { return _ary->_size; }
+  bool      is_stable() const { return _ary->_stable; }
 
   bool is_autobox_cache() const { return _is_autobox_cache; }
 
@@ -1011,6 +1017,9 @@
   virtual const Type *xmeet( const Type *t ) const;
   virtual const Type *xdual() const;    // Compute dual right now.
 
+  const TypeAryPtr* cast_to_stable(bool stable, int stable_dimension = 1) const;
+  int stable_dimension() const;
+
   // Convenience common pre-built types.
   static const TypeAryPtr *RANGE;
   static const TypeAryPtr *OOPS;
--- a/src/share/vm/runtime/arguments.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/runtime/arguments.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -1605,17 +1605,6 @@
   return result;
 }
 
-void Arguments::set_heap_base_min_address() {
-  if (FLAG_IS_DEFAULT(HeapBaseMinAddress) && UseG1GC && HeapBaseMinAddress < 1*G) {
-    // By default HeapBaseMinAddress is 2G on all platforms except Solaris x86.
-    // G1 currently needs a lot of C-heap, so on Solaris we have to give G1
-    // some extra space for the C-heap compared to other collectors.
-    // Use FLAG_SET_DEFAULT here rather than FLAG_SET_ERGO to make sure that
-    // code that checks for default values work correctly.
-    FLAG_SET_DEFAULT(HeapBaseMinAddress, 1*G);
-  }
-}
-
 void Arguments::set_heap_size() {
   if (!FLAG_IS_DEFAULT(DefaultMaxRAMFraction)) {
     // Deprecated flag
@@ -3537,8 +3526,6 @@
     }
   }
 
-  set_heap_base_min_address();
-
   // Set heap size based on available physical memory
   set_heap_size();
 
--- a/src/share/vm/runtime/arguments.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/runtime/arguments.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -334,8 +334,6 @@
   // limits the given memory size by the maximum amount of memory this process is
   // currently allowed to allocate or reserve.
   static julong limit_by_allocatable_memory(julong size);
-  // Setup HeapBaseMinAddress
-  static void set_heap_base_min_address();
   // Setup heap size
   static void set_heap_size();
   // Based on automatic selection criteria, should the
--- a/src/share/vm/runtime/globals.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/runtime/globals.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -205,6 +205,7 @@
 
 #define C1_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C1 product}", DEFAULT },
 #define C1_PD_PRODUCT_FLAG_STRUCT(type, name, doc)     { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C1 pd product}", DEFAULT },
+#define C1_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C1 diagnostic}", DEFAULT },
 #ifdef PRODUCT
   #define C1_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */
   #define C1_PD_DEVELOP_FLAG_STRUCT(type, name, doc)     /* flag is constant */
@@ -260,7 +261,7 @@
  G1_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, RUNTIME_PD_DEVELOP_FLAG_STRUCT, RUNTIME_PRODUCT_FLAG_STRUCT, RUNTIME_PD_PRODUCT_FLAG_STRUCT, RUNTIME_DIAGNOSTIC_FLAG_STRUCT, RUNTIME_EXPERIMENTAL_FLAG_STRUCT, RUNTIME_NOTPRODUCT_FLAG_STRUCT, RUNTIME_MANAGEABLE_FLAG_STRUCT, RUNTIME_PRODUCT_RW_FLAG_STRUCT)
 #endif // INCLUDE_ALL_GCS
 #ifdef COMPILER1
- C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, C1_PD_DEVELOP_FLAG_STRUCT, C1_PRODUCT_FLAG_STRUCT, C1_PD_PRODUCT_FLAG_STRUCT, C1_NOTPRODUCT_FLAG_STRUCT)
+ C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, C1_PD_DEVELOP_FLAG_STRUCT, C1_PRODUCT_FLAG_STRUCT, C1_PD_PRODUCT_FLAG_STRUCT, C1_DIAGNOSTIC_FLAG_STRUCT, C1_NOTPRODUCT_FLAG_STRUCT)
 #endif
 #ifdef COMPILER2
  C2_FLAGS(C2_DEVELOP_FLAG_STRUCT, C2_PD_DEVELOP_FLAG_STRUCT, C2_PRODUCT_FLAG_STRUCT, C2_PD_PRODUCT_FLAG_STRUCT, C2_DIAGNOSTIC_FLAG_STRUCT, C2_EXPERIMENTAL_FLAG_STRUCT, C2_NOTPRODUCT_FLAG_STRUCT)
--- a/src/share/vm/runtime/globals.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/runtime/globals.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -3649,6 +3649,9 @@
   experimental(bool, TrustFinalNonStaticFields, false,                      \
           "trust final non-static declarations for constant folding")       \
                                                                             \
+  experimental(bool, FoldStableValues, false,                               \
+          "Private flag to control optimizations for stable variables")     \
+                                                                            \
   develop(bool, TraceInvokeDynamic, false,                                  \
           "trace internal invoke dynamic operations")                       \
                                                                             \
--- a/src/share/vm/runtime/globals_extension.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/runtime/globals_extension.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -57,6 +57,7 @@
 
 #define C1_PRODUCT_FLAG_MEMBER(type, name, value, doc)         FLAG_MEMBER(name),
 #define C1_PD_PRODUCT_FLAG_MEMBER(type, name, doc)             FLAG_MEMBER(name),
+#define C1_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc)      FLAG_MEMBER(name),
 #ifdef PRODUCT
   #define C1_DEVELOP_FLAG_MEMBER(type, name, value, doc)       /* flag is constant */
   #define C1_PD_DEVELOP_FLAG_MEMBER(type, name, doc)           /* flag is constant */
@@ -99,7 +100,7 @@
  G1_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, RUNTIME_PD_DEVELOP_FLAG_MEMBER, RUNTIME_PRODUCT_FLAG_MEMBER, RUNTIME_PD_PRODUCT_FLAG_MEMBER, RUNTIME_DIAGNOSTIC_FLAG_MEMBER, RUNTIME_EXPERIMENTAL_FLAG_MEMBER, RUNTIME_NOTPRODUCT_FLAG_MEMBER, RUNTIME_MANAGEABLE_FLAG_MEMBER, RUNTIME_PRODUCT_RW_FLAG_MEMBER)
 #endif // INCLUDE_ALL_GCS
 #ifdef COMPILER1
- C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, C1_PD_DEVELOP_FLAG_MEMBER, C1_PRODUCT_FLAG_MEMBER, C1_PD_PRODUCT_FLAG_MEMBER, C1_NOTPRODUCT_FLAG_MEMBER)
+ C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, C1_PD_DEVELOP_FLAG_MEMBER, C1_PRODUCT_FLAG_MEMBER, C1_PD_PRODUCT_FLAG_MEMBER, C1_DIAGNOSTIC_FLAG_MEMBER, C1_NOTPRODUCT_FLAG_MEMBER)
 #endif
 #ifdef COMPILER2
  C2_FLAGS(C2_DEVELOP_FLAG_MEMBER, C2_PD_DEVELOP_FLAG_MEMBER, C2_PRODUCT_FLAG_MEMBER, C2_PD_PRODUCT_FLAG_MEMBER, C2_DIAGNOSTIC_FLAG_MEMBER, C2_EXPERIMENTAL_FLAG_MEMBER, C2_NOTPRODUCT_FLAG_MEMBER)
@@ -131,6 +132,7 @@
 
 #define C1_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc)         FLAG_MEMBER_WITH_TYPE(name,type),
 #define C1_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc)             FLAG_MEMBER_WITH_TYPE(name,type),
+#define C1_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc)      FLAG_MEMBER_WITH_TYPE(name,type),
 #ifdef PRODUCT
   #define C1_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc)       /* flag is constant */
   #define C1_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc)           /* flag is constant */
@@ -204,6 +206,7 @@
           C1_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE,
           C1_PRODUCT_FLAG_MEMBER_WITH_TYPE,
           C1_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE,
+          C1_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
           C1_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE)
 #endif
 #ifdef COMPILER2
--- a/src/share/vm/runtime/interfaceSupport.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/runtime/interfaceSupport.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -471,16 +471,6 @@
     VM_ENTRY_BASE(result_type, header, thread)                       \
     debug_only(VMEntryWrapper __vew;)
 
-// Another special case for nmethod_entry_point so the nmethod that the
-// interpreter is about to branch to doesn't get flushed before as we
-// branch to it's interpreter_entry_point.  Skip stress testing here too.
-// Also we don't allow async exceptions because it is just too painful.
-#define IRT_ENTRY_FOR_NMETHOD(result_type, header)                   \
-  result_type header {                                               \
-    nmethodLocker _nmlock(nm);                                       \
-    ThreadInVMfromJavaNoAsyncException __tiv(thread);                                \
-    VM_ENTRY_BASE(result_type, header, thread)
-
 #define IRT_END }
 
 
--- a/src/share/vm/runtime/sharedRuntime.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/runtime/sharedRuntime.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -1051,7 +1051,8 @@
 
   // Find receiver for non-static call
   if (bc != Bytecodes::_invokestatic &&
-      bc != Bytecodes::_invokedynamic) {
+      bc != Bytecodes::_invokedynamic &&
+      bc != Bytecodes::_invokehandle) {
     // This register map must be update since we need to find the receiver for
     // compiled frames. The receiver might be in a register.
     RegisterMap reg_map2(thread);
@@ -1078,7 +1079,7 @@
 
 #ifdef ASSERT
   // Check that the receiver klass is of the right subtype and that it is initialized for virtual calls
-  if (bc != Bytecodes::_invokestatic && bc != Bytecodes::_invokedynamic) {
+  if (bc != Bytecodes::_invokestatic && bc != Bytecodes::_invokedynamic && bc != Bytecodes::_invokehandle) {
     assert(receiver.not_null(), "should have thrown exception");
     KlassHandle receiver_klass(THREAD, receiver->klass());
     Klass* rk = constants->klass_ref_at(bytecode_index, CHECK_(nullHandle));
@@ -1240,9 +1241,9 @@
 #endif
 
   if (is_virtual) {
-    assert(receiver.not_null(), "sanity check");
+    assert(receiver.not_null() || invoke_code == Bytecodes::_invokehandle, "sanity check");
     bool static_bound = call_info.resolved_method()->can_be_statically_bound();
-    KlassHandle h_klass(THREAD, receiver->klass());
+    KlassHandle h_klass(THREAD, invoke_code == Bytecodes::_invokehandle ? NULL : receiver->klass());
     CompiledIC::compute_monomorphic_entry(callee_method, h_klass,
                      is_optimized, static_bound, virtual_call_info,
                      CHECK_(methodHandle()));
--- a/src/share/vm/runtime/thread.cpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/runtime/thread.cpp	Fri Sep 13 10:34:15 2013 -0400
@@ -3636,6 +3636,16 @@
   CompileBroker::compilation_init();
 #endif
 
+  if (EnableInvokeDynamic) {
+    // Pre-initialize some JSR292 core classes to avoid deadlock during class loading.
+    // It is done after compilers are initialized, because otherwise compilations of
+    // signature polymorphic MH intrinsics can be missed
+    // (see SystemDictionary::find_method_handle_intrinsic).
+    initialize_class(vmSymbols::java_lang_invoke_MethodHandle(), CHECK_0);
+    initialize_class(vmSymbols::java_lang_invoke_MemberName(), CHECK_0);
+    initialize_class(vmSymbols::java_lang_invoke_MethodHandleNatives(), CHECK_0);
+  }
+
 #if INCLUDE_MANAGEMENT
   Management::initialize(THREAD);
 #endif // INCLUDE_MANAGEMENT
--- a/src/share/vm/utilities/accessFlags.hpp	Thu Sep 12 15:53:49 2013 +0400
+++ b/src/share/vm/utilities/accessFlags.hpp	Fri Sep 13 10:34:15 2013 -0400
@@ -78,11 +78,13 @@
   JVM_ACC_FIELD_ACCESS_WATCHED       = 0x00002000,  // field access is watched by JVMTI
   JVM_ACC_FIELD_MODIFICATION_WATCHED = 0x00008000,  // field modification is watched by JVMTI
   JVM_ACC_FIELD_INTERNAL             = 0x00000400,  // internal field, same as JVM_ACC_ABSTRACT
+  JVM_ACC_FIELD_STABLE               = 0x00000020,  // @Stable field, same as JVM_ACC_SYNCHRONIZED
   JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE = 0x00000800, // field has generic signature
 
   JVM_ACC_FIELD_INTERNAL_FLAGS       = JVM_ACC_FIELD_ACCESS_WATCHED |
                                        JVM_ACC_FIELD_MODIFICATION_WATCHED |
                                        JVM_ACC_FIELD_INTERNAL |
+                                       JVM_ACC_FIELD_STABLE |
                                        JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE,
 
                                                     // flags accepted by set_field_flags()
@@ -148,6 +150,7 @@
                                         { return (_flags & JVM_ACC_FIELD_MODIFICATION_WATCHED) != 0; }
   bool on_stack() const                 { return (_flags & JVM_ACC_ON_STACK) != 0; }
   bool is_internal() const              { return (_flags & JVM_ACC_FIELD_INTERNAL) != 0; }
+  bool is_stable() const                { return (_flags & JVM_ACC_FIELD_STABLE) != 0; }
   bool field_has_generic_signature() const
                                         { return (_flags & JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE) != 0; }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/compiler/gcbarriers/G1CrashTest.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013, 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 8023472
+ * @summary C2 optimization breaks with G1
+ *
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -Dcount=100000 G1CrashTest
+ *
+ * @author pbiswal@palantir.com
+ */
+
+public class G1CrashTest {
+    static Object[] set = new Object[11];
+
+    public static void main(String[] args) throws InterruptedException {
+        for (int j = 0; j < Integer.getInteger("count"); j++) {
+            Object key = new Object();
+            insertKey(key);
+            if (j > set.length / 2) {
+                Object[] oldKeys = set;
+                set = new Object[2 * set.length - 1];
+                for (Object o : oldKeys) {
+                    if (o != null)
+                        insertKey(o);
+                }
+            }
+        }
+    }
+
+    static void insertKey(Object key) {
+        int hash = key.hashCode() & 0x7fffffff;
+        int index = hash % set.length;
+        Object cur = set[index];
+        if (cur == null)
+            set[index] = key;
+        else
+            insertKeyRehash(key, index, hash, cur);
+    }
+
+    static void insertKeyRehash(Object key, int index, int hash, Object cur) {
+        int loopIndex = index;
+        int firstRemoved = -1;
+        do {
+            if (cur == "dead")
+                firstRemoved = 1;
+            index--;
+            if (index < 0)
+                index += set.length;
+            cur = set[index];
+            if (cur == null) {
+                if (firstRemoved != -1)
+                    set[firstRemoved] = "dead";
+                else
+                    set[index] = key;
+                return;
+            }
+        } while (index != loopIndex);
+        if (firstRemoved != -1)
+            set[firstRemoved] = null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/compiler/jsr292/ConcurrentClassLoadingTest.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2013, 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 8022595
+ * @summary JSR292: deadlock during class loading of MethodHandles, MethodHandleImpl & MethodHandleNatives
+ *
+ * @run main/othervm ConcurrentClassLoadingTest
+ */
+import java.util.*;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+
+public class ConcurrentClassLoadingTest {
+    int numThreads = 0;
+    long seed = 0;
+    CyclicBarrier l;
+    Random rand;
+
+    public static void main(String[] args) throws Throwable {
+        ConcurrentClassLoadingTest test = new ConcurrentClassLoadingTest();
+        test.parseArgs(args);
+        test.run();
+    }
+
+    void parseArgs(String[] args) {
+        int i = 0;
+        while (i < args.length) {
+            String flag = args[i];
+            switch(flag) {
+                case "-seed":
+                    seed = Long.parseLong(args[++i]);
+                    break;
+                case "-numThreads":
+                    numThreads = Integer.parseInt(args[++i]);
+                    break;
+                default:
+                    throw new Error("Unknown flag: " + flag);
+            }
+            ++i;
+        }
+    }
+
+    void init() {
+        if (numThreads == 0) {
+            numThreads = Runtime.getRuntime().availableProcessors();
+        }
+
+        if (seed == 0) {
+            seed = (new Random()).nextLong();
+        }
+        rand = new Random(seed);
+
+        l = new CyclicBarrier(numThreads + 1);
+
+        System.out.printf("Threads: %d\n", numThreads);
+        System.out.printf("Seed: %d\n", seed);
+    }
+
+    final List<Loader> loaders = new ArrayList<>();
+
+    void prepare() {
+        List<String> c = new ArrayList<>(Arrays.asList(classNames));
+
+        // Split classes between loading threads
+        int count = (classNames.length / numThreads) + 1;
+        for (int t = 0; t < numThreads; t++) {
+            List<String> sel = new ArrayList<>();
+
+            System.out.printf("Thread #%d:\n", t);
+            for (int i = 0; i < count; i++) {
+                if (c.size() == 0) break;
+
+                int k = rand.nextInt(c.size());
+                String elem = c.remove(k);
+                sel.add(elem);
+                System.out.printf("\t%s\n", elem);
+            }
+            loaders.add(new Loader(sel));
+        }
+
+        // Print diagnostic info when the test hangs
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            public void run() {
+                boolean alive = false;
+                for (Loader l : loaders) {
+                    if (!l.isAlive())  continue;
+
+                    if (!alive) {
+                        System.out.println("Some threads are still alive:");
+                        alive = true;
+                    }
+
+                    System.out.println(l.getName());
+                    for (StackTraceElement elem : l.getStackTrace()) {
+                        System.out.println("\t"+elem.toString());
+                    }
+                }
+            }
+        });
+    }
+
+    public void run() throws Throwable {
+        init();
+        prepare();
+
+        for (Loader loader : loaders) {
+            loader.start();
+        }
+
+        l.await();
+
+        for (Loader loader : loaders) {
+            loader.join();
+        }
+    }
+
+    class Loader extends Thread {
+        List<String> classes;
+
+        public Loader(List<String> classes) {
+            this.classes = classes;
+            setDaemon(true);
+        }
+
+        @Override
+        public void run() {
+            try {
+                l.await();
+
+                for (String name : classes) {
+                    Class.forName(name).getName();
+                }
+            } catch (ClassNotFoundException | BrokenBarrierException | InterruptedException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    final static String[] classNames = {
+            "java.lang.invoke.AbstractValidatingLambdaMetafactory",
+            "java.lang.invoke.BoundMethodHandle",
+            "java.lang.invoke.CallSite",
+            "java.lang.invoke.ConstantCallSite",
+            "java.lang.invoke.DirectMethodHandle",
+            "java.lang.invoke.InnerClassLambdaMetafactory",
+            "java.lang.invoke.InvokeDynamic",
+            "java.lang.invoke.InvokeGeneric",
+            "java.lang.invoke.InvokerBytecodeGenerator",
+            "java.lang.invoke.Invokers",
+            "java.lang.invoke.LambdaConversionException",
+            "java.lang.invoke.LambdaForm",
+            "java.lang.invoke.LambdaMetafactory",
+            "java.lang.invoke.MagicLambdaImpl",
+            "java.lang.invoke.MemberName",
+            "java.lang.invoke.MethodHandle",
+            "java.lang.invoke.MethodHandleImpl",
+            "java.lang.invoke.MethodHandleInfo",
+            "java.lang.invoke.MethodHandleNatives",
+            "java.lang.invoke.MethodHandleProxies",
+            "java.lang.invoke.MethodHandles",
+            "java.lang.invoke.MethodHandleStatics",
+            "java.lang.invoke.MethodType",
+            "java.lang.invoke.MethodTypeForm",
+            "java.lang.invoke.MutableCallSite",
+            "java.lang.invoke.SerializedLambda",
+            "java.lang.invoke.SimpleMethodHandle",
+            "java.lang.invoke.SwitchPoint",
+            "java.lang.invoke.TypeConvertingMethodAdapter",
+            "java.lang.invoke.VolatileCallSite",
+            "java.lang.invoke.WrongMethodTypeException"
+    };
+}
--- a/test/gc/TestVerifyDuringStartup.java	Thu Sep 12 15:53:49 2013 +0400
+++ b/test/gc/TestVerifyDuringStartup.java	Fri Sep 13 10:34:15 2013 -0400
@@ -48,7 +48,7 @@
                                              "-XX:+VerifyDuringStartup",
                                              "-version"});
 
-    System.out.print("Testing:\n" + JDKToolFinder.getJDKTool("java"));
+    System.out.print("Testing:\n" + JDKToolFinder.getCurrentJDKTool("java"));
     for (int i = 0; i < vmOpts.size(); i += 1) {
       System.out.print(" " + vmOpts.get(i));
     }
--- a/test/testlibrary/com/oracle/java/testlibrary/JDKToolFinder.java	Thu Sep 12 15:53:49 2013 +0400
+++ b/test/testlibrary/com/oracle/java/testlibrary/JDKToolFinder.java	Fri Sep 13 10:34:15 2013 -0400
@@ -27,24 +27,43 @@
 
 public final class JDKToolFinder {
 
-  private JDKToolFinder() {
-  }
-
-  /**
-   * Returns the full path to an executable in jdk/bin based on System property
-   * test.jdk (set by jtreg test suite)
-   *
-   * @return Full path to an executable in jdk/bin
-   */
-  public static String getJDKTool(String tool) {
-    String binPath = System.getProperty("test.jdk");
-    if (binPath == null) {
-      throw new RuntimeException("System property 'test.jdk' not set. This property is normally set by jtreg. "
-          + "When running test separately, set this property using '-Dtest.jdk=/path/to/jdk'.");
+    private JDKToolFinder() {
     }
 
-    binPath += File.separatorChar + "bin" + File.separatorChar + tool;
+    /**
+     * Returns the full path to an executable in jdk/bin based on System
+     * property {@code compile.jdk} (set by jtreg test suite)
+     *
+     * @return Full path to an executable in jdk/bin
+     */
+    public static String getJDKTool(String tool) {
+        String binPath = System.getProperty("compile.jdk");
+        if (binPath == null) {
+            throw new RuntimeException("System property 'compile.jdk' not set. "
+                    + "This property is normally set by jtreg. "
+                    + "When running test separately, set this property using "
+                    + "'-Dcompile.jdk=/path/to/jdk'.");
+        }
+        binPath += File.separatorChar + "bin" + File.separatorChar + tool;
 
-    return binPath;
-  }
+        return binPath;
+    }
+    /**
+     * Returns the full path to an executable in &lt;current jdk&gt;/bin based
+     * on System property {@code test.jdk} (set by jtreg test suite)
+     *
+     * @return Full path to an executable in jdk/bin
+     */
+    public static String getCurrentJDKTool(String tool) {
+        String binPath = System.getProperty("test.jdk");
+        if (binPath == null) {
+            throw new RuntimeException("System property 'test.jdk' not set. "
+                + "This property is normally set by jtreg. "
+                + "When running test separately, set this property using "
+                + "'-Dtest.jdk=/path/to/jdk'.");
+        }
+        binPath += File.separatorChar + "bin" + File.separatorChar + tool;
+
+        return binPath;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/Makefile	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,73 @@
+#
+# Copyright (c) 2013, 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.
+#
+#
+
+ifneq "x$(ALT_BOOTDIR)" "x"
+	BOOTDIR := $(ALT_BOOTDIR)
+endif
+
+ifeq "x$(BOOTDIR)" "x"
+	JDK_HOME := $(shell dirname $(shell which java))/..
+else
+	JDK_HOME := $(BOOTDIR)
+endif
+
+SRC_DIR = src
+BUILD_DIR = build
+OUTPUT_DIR = $(BUILD_DIR)/classes
+WHITEBOX_DIR = ../whitebox
+
+JAVAC = $(JDK_HOME)/bin/javac
+JAR = $(JDK_HOME)/bin/jar
+
+SRC_FILES = $(shell find $(SRC_DIR) -name '*.java')
+
+MAIN_CLASS = sun.hotspot.tools.ctw.CompileTheWorld
+
+.PHONY: clean cleantmp
+
+all: ctw.jar cleantmp
+
+clean: cleantmp
+	@rm -rf ctw.jar wb.jar
+
+cleantmp:
+	@rm -rf filelist manifest.mf
+	@rm -rf $(BUILD_DIR)
+
+ctw.jar: filelist wb.jar manifest.mf
+	@mkdir -p $(OUTPUT_DIR)
+	$(JAVAC) -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) -cp wb.jar @filelist
+	$(JAR) cfm ctw.jar manifest.mf -C $(OUTPUT_DIR) .
+
+wb.jar: 
+	make -C ${WHITEBOX_DIR} wb.jar
+	cp ${WHITEBOX_DIR}/wb.jar ./
+	make -C ${WHITEBOX_DIR} clean
+
+filelist: $(SRC_FILES)
+	@rm -f $@
+	@echo $(SRC_FILES) > $@
+
+manifest.mf:
+	@echo "Main-Class: ${MAIN_CLASS}" > manifest.mf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/README	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,93 @@
+#
+# Copyright (c) 2013, 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.
+#
+#
+
+DESCRIPTION
+
+This is replacement for CompileTheWorld (CTW) written on java. Its purpose is
+to make possible the use of CTW in product builds.
+
+DEPENDENCES
+
+The tool depends on Whitebox API. Assumed, that the sources of whitebox are
+located in '../whitebox' directory.
+
+BUILDING
+
+Simple way to build, just type 'make'.
+
+Makefile uses environment variables 'ALT_BOOTDIR', 'BOOTDIR' as root-dir of jdk
+that will be used for compilation and creating jar.
+
+On successful building 'ctw.jar' will be created.
+
+RUNNING
+
+Since the tool uses WhiteBox API, options 'UnlockDiagnosticVMOptions' and
+'WhiteBoxAPI' should be specified, and 'wb.jar' should be added to
+boot-classpath:
+  $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar 
+
+Arguments can be paths to '.jar, '.zip', '.lst' files or directories with
+classes, that define which classes will be compiled:
+  - '.jar', '.zip' files and directories are interpreted like in classpath
+(including '<dir>/*' syntax)
+  - '.lst' files -- files with class names (in java notation) to compile.
+CTW will try to find these classes with default class loader, so they should
+be located in classpath.
+
+Without arguments it would work as old version of CTW: all classes in
+boot-classpath will be compiled, excluding classes in 'rt.jar' if 'rt.jar' isn't
+first in boot-classpath.
+
+Due CTW's flags also are not available in product builds, the tool uses
+properties with the same names:
+  - 'CompileTheWorldPreloadClasses' -- type:boolean, default:true, description:
+Preload all classes used by a class before start loading
+  - 'CompileTheWorldStartAt' -- type:long, default:1, description: First class
+to consider
+  - 'CompileTheWorldStopAt' -- type:long, default:Long.MAX_VALUE, description:
+Last class to consider
+
+Also it uses additional properties:
+  - 'sun.hotspot.tools.ctw.verbose' -- type:boolean, default:false,
+description: Verbose output, adds additional information about compilation
+  - 'sun.hotspot.tools.ctw.logfile' -- type:string, default:null,
+description: Path to logfile, if it's null, cout will be used.
+
+EXAMPLES
+
+compile classes from 'rt.jar':
+  $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar ${JAVA_HOME}/jre/lib/rt.jar
+
+compile classes from all '.jar' in './testjars' directory:
+  $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar ./testjars/*
+
+compile classes from './build/classes' directory:
+  $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar ./build/classes
+
+compile only java.lang.String, java.lang.Object classes:
+  $ echo java.lang.String > classes.lst
+  $ echo java.lang.Object >> classes.lst
+  $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar classes.lst
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathDirEntry.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2013, 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 sun.hotspot.tools.ctw;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Set;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.concurrent.Executor;
+
+import java.io.*;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+
+/**
+ * * Handler for dirs containing classes to compile.
+ * @author igor.ignatyev@oracle.com
+ */
+public class ClassPathDirEntry extends PathHandler {
+
+    private final int rootLength = root.toString().length();
+
+    public ClassPathDirEntry(Path root, Executor executor) {
+        super(root, executor);
+        try {
+            URL url = root.toUri().toURL();
+            setLoader(new URLClassLoader(new URL[]{url}));
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void process() {
+        System.out.println("# dir: " + root);
+        if (!Files.exists(root)) {
+            return;
+        }
+        try {
+            Files.walkFileTree(root, EnumSet.of(FileVisitOption.FOLLOW_LINKS),
+                    Integer.MAX_VALUE, new CompileFileVisitor());
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        }
+    }
+
+    private void processFile(Path file) {
+        if (Utils.isClassFile(file.toString())) {
+            processClass(pathToClassName(file));
+        }
+    }
+
+    private String pathToClassName(Path file) {
+        String fileString;
+        if (root == file) {
+            fileString = file.normalize().toString();
+        } else {
+            fileString = file.normalize().toString().substring(rootLength + 1);
+        }
+        return Utils.fileNameToClassName(fileString);
+    }
+
+    private class CompileFileVisitor extends SimpleFileVisitor<Path> {
+
+        private final Set<Path> ready = new HashSet<>();
+
+        @Override
+        public FileVisitResult preVisitDirectory(Path dir,
+                BasicFileAttributes attrs) throws IOException {
+            if (ready.contains(dir)) {
+                return FileVisitResult.SKIP_SUBTREE;
+            }
+            ready.add(dir);
+            return super.preVisitDirectory(dir, attrs);
+        }
+
+        @Override
+        public FileVisitResult visitFile(Path file,
+                BasicFileAttributes attrs) throws IOException {
+            if (!ready.contains(file)) {
+                processFile(file);
+            }
+            return isFinished() ? FileVisitResult.TERMINATE
+                    : FileVisitResult.CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult visitFileFailed(Path file,
+                IOException exc) throws IOException {
+            return FileVisitResult.CONTINUE;
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarEntry.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013, 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 sun.hotspot.tools.ctw;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.*;
+import java.util.jar.*;
+import java.util.concurrent.Executor;
+
+import java.io.*;
+import java.nio.file.*;
+
+/**
+ * Handler for jar-files containing classes to compile.
+ * @author igor.ignatyev@oracle.com
+ */
+public class ClassPathJarEntry extends PathHandler {
+
+    public ClassPathJarEntry(Path root, Executor executor) {
+        super(root, executor);
+        try {
+            URL url = root.toUri().toURL();
+            setLoader(new URLClassLoader(new URL[]{url}));
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void process() {
+        System.out.println("# jar: " + root);
+        if (!Files.exists(root)) {
+            return;
+        }
+        try {
+            JarFile jarFile = new JarFile(root.toFile());
+            JarEntry entry;
+            for (Enumeration<JarEntry> e = jarFile.entries();
+                    e.hasMoreElements(); ) {
+                entry = e.nextElement();
+                processJarEntry(entry);
+                if (isFinished()) {
+                    return;
+                }
+            }
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        }
+    }
+
+     private void processJarEntry(JarEntry entry) {
+        String filename = entry.getName();
+        if (Utils.isClassFile(filename)) {
+            processClass(Utils.fileNameToClassName(filename));
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarInDirEntry.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013, 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 sun.hotspot.tools.ctw;
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.Executor;
+
+/**
+ * Handler for dirs containing jar-files with classes to compile.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public class ClassPathJarInDirEntry extends PathHandler {
+
+    public ClassPathJarInDirEntry(Path root, Executor executor) {
+        super(root, executor);
+    }
+
+    @Override
+    public void process() {
+        System.out.println("# jar_in_dir: " + root);
+        if (!Files.exists(root)) {
+            return;
+        }
+        try (DirectoryStream<Path> ds
+                = Files.newDirectoryStream(root, "*.jar")) {
+            for (Path p : ds) {
+                new ClassPathJarEntry(p, executor).process();
+                if (isFinished()) {
+                    return;
+                }
+            }
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassesListInFile.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, 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 sun.hotspot.tools.ctw;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.Executor;
+
+/**
+ * Handler for files containing a list of classes to compile.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public class ClassesListInFile extends PathHandler {
+    public ClassesListInFile(Path root, Executor executor) {
+        super(root, executor);
+    }
+
+    @Override
+    public void process() {
+        System.out.println("# list: " + root);
+        if (!Files.exists(root)) {
+            return;
+        }
+        try {
+            try (BufferedReader reader = Files.newBufferedReader(root,
+                    StandardCharsets.UTF_8)) {
+                String line;
+                while (!isFinished() && ((line = reader.readLine()) != null)) {
+                    processClass(line);
+                }
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2013, 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 sun.hotspot.tools.ctw;
+
+import sun.management.ManagementFactoryHelper;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * @author igor.ignatyev@oracle.com
+ */
+public class CompileTheWorld {
+    /**
+     * Entry point. Compiles classes in {@code args}, or all classes in
+     * boot-classpath if args is empty
+     *
+     * @param args paths to jar/zip, dir contains classes, or to .lst file
+     *             contains list of classes to compile
+     */
+    public static void main(String[] args) {
+        String logfile = Utils.LOG_FILE;
+        PrintStream os = null;
+        if (logfile != null) {
+            try {
+                os = new PrintStream(Files.newOutputStream(Paths.get(logfile)));
+            } catch (IOException io) {
+            }
+        }
+        if (os != null) {
+            System.setOut(os);
+        }
+
+        try {
+            try {
+                if (ManagementFactoryHelper.getCompilationMXBean() == null) {
+                    throw new RuntimeException(
+                            "CTW can not work in interpreted mode");
+                }
+            } catch (java.lang.NoClassDefFoundError e) {
+                // compact1, compact2 support
+            }
+            String[] paths = args;
+            boolean skipRtJar = false;
+            if (args.length == 0) {
+                paths = getDefaultPaths();
+                skipRtJar = true;
+            }
+            ExecutorService executor = createExecutor();
+            long start = System.currentTimeMillis();
+            try {
+                String path;
+                for (int i = 0, n = paths.length; i < n
+                        && !PathHandler.isFinished(); ++i) {
+                    path = paths[i];
+                    if (skipRtJar && i > 0 && isRtJar(path)) {
+                        // rt.jar is not first, so skip it
+                        continue;
+                    }
+                    PathHandler.create(path, executor).process();
+                }
+            } finally {
+                await(executor);
+            }
+            System.out.printf("Done (%d classes, %d methods, %d ms)%n",
+                    Compiler.getClassCount(),
+                    Compiler.getMethodCount(),
+                    System.currentTimeMillis() - start);
+        } finally {
+            if (os != null) {
+                os.close();
+            }
+        }
+    }
+
+    private static ExecutorService createExecutor() {
+        final int threadsCount = Math.min(
+                Runtime.getRuntime().availableProcessors(),
+                Utils.CI_COMPILER_COUNT);
+        ExecutorService result;
+        if (threadsCount > 1) {
+            result = new ThreadPoolExecutor(threadsCount, threadsCount,
+                    /* keepAliveTime */ 0L, TimeUnit.MILLISECONDS,
+                    new ArrayBlockingQueue<>(threadsCount),
+                    new ThreadPoolExecutor.CallerRunsPolicy());
+        } else {
+            result = new CurrentThreadExecutor();
+        }
+        return result;
+    }
+
+    private static String[] getDefaultPaths() {
+        String property = System.getProperty("sun.boot.class.path");
+        System.out.println(
+                "# use 'sun.boot.class.path' as args: " + property);
+        return Utils.PATH_SEPARATOR.split(property);
+    }
+
+    private static void await(ExecutorService executor) {
+        executor.shutdown();
+        while (!executor.isTerminated()) {
+            try {
+                executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
+            } catch (InterruptedException ie) {
+                Thread.currentThread().interrupt();
+                break;
+            }
+        }
+    }
+
+    private static boolean isRtJar(String path) {
+        return Utils.endsWithIgnoreCase(path, File.separator + "rt.jar");
+    }
+
+    private static class CurrentThreadExecutor extends AbstractExecutorService {
+        private boolean isShutdown;
+
+        @Override
+        public void shutdown() {
+            this.isShutdown = true;
+        }
+
+        @Override
+        public List<Runnable> shutdownNow() {
+            return null;
+        }
+
+        @Override
+        public boolean isShutdown() {
+            return isShutdown;
+        }
+
+        @Override
+        public boolean isTerminated() {
+            return isShutdown;
+        }
+
+        @Override
+        public boolean awaitTermination(long timeout, TimeUnit unit)
+                throws InterruptedException {
+            return isShutdown;
+        }
+
+        @Override
+        public void execute(Runnable command) {
+            command.run();
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2013, 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 sun.hotspot.tools.ctw;
+
+import sun.hotspot.WhiteBox;
+import sun.misc.SharedSecrets;
+import sun.reflect.ConstantPool;
+
+import java.lang.reflect.Executable;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Provide method to compile whole class.
+ * Also contains compiled methods and classes counters.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public class Compiler {
+    private Compiler() { }
+    private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+    private static final AtomicLong CLASS_COUNT = new AtomicLong(0L);
+    private static final AtomicLong METHOD_COUNT = new AtomicLong(0L);
+    private static volatile boolean CLASSES_LIMIT_REACHED = false;
+
+    /**
+     * @return count of processed classes
+     */
+    public static long getClassCount() {
+        return CLASS_COUNT.get();
+    }
+
+    /**
+     * @return count of processed methods
+     */
+    public static long getMethodCount() {
+        return METHOD_COUNT.get();
+    }
+
+    /**
+     * @return {@code true} if classes limit is reached
+     */
+    public static boolean isLimitReached() {
+        return CLASSES_LIMIT_REACHED;
+    }
+
+    /**
+     * Compiles all methods and constructors.
+     *
+     * @param aClass class to compile
+     * @param executor executor used for compile task invocation
+     * @throws NullPointerException if {@code class} or {@code executor}
+     *                              is {@code null}
+     */
+    public static void compileClass(Class aClass, Executor executor) {
+        Objects.requireNonNull(aClass);
+        Objects.requireNonNull(executor);
+        long id = CLASS_COUNT.incrementAndGet();
+        if (id > Utils.COMPILE_THE_WORLD_STOP_AT) {
+            CLASS_COUNT.decrementAndGet();
+            CLASSES_LIMIT_REACHED = true;
+            return;
+        }
+
+        if (id >= Utils.COMPILE_THE_WORLD_START_AT) {
+            String name = aClass.getName();
+            try {
+                System.out.printf("[%d]\t%s%n", id, name);
+                ConstantPool constantPool = SharedSecrets.getJavaLangAccess().
+                        getConstantPool(aClass);
+                if (Utils.COMPILE_THE_WORLD_PRELOAD_CLASSES) {
+                    preloadClasses(name, id, constantPool);
+                }
+                long methodCount = 0;
+                for (Executable e : aClass.getDeclaredConstructors()) {
+                    ++methodCount;
+                    executor.execute(new CompileMethodCommand(id, name, e));
+                }
+                for (Executable e : aClass.getDeclaredMethods()) {
+                    ++methodCount;
+                    executor.execute(new CompileMethodCommand(id, name, e));
+                }
+                METHOD_COUNT.addAndGet(methodCount);
+
+                if (Utils.DEOPTIMIZE_ALL_CLASSES_RATE > 0
+                        && (id % Utils.DEOPTIMIZE_ALL_CLASSES_RATE == 0)) {
+                    WHITE_BOX.deoptimizeAll();
+                }
+            } catch (Throwable t) {
+                System.out.printf("[%d]\t%s\tskipping %s%n", id, name, t);
+                t.printStackTrace();
+            }
+        }
+    }
+
+    private static void preloadClasses(String className, long id,
+            ConstantPool constantPool) {
+        try {
+            for (int i = 0, n = constantPool.getSize(); i < n; ++i) {
+                try {
+                    constantPool.getClassAt(i);
+                } catch (IllegalArgumentException ignore) {
+                }
+            }
+        } catch (Throwable t) {
+            System.out.printf("[%d]\t%s\tpreloading failed : %s%n", id,
+                    className, t);
+        }
+    }
+
+
+
+    /**
+     * Compilation of method.
+     * Will compile method on all available comp levels.
+     */
+    private static class CompileMethodCommand implements Runnable {
+        private final long classId;
+        private final String className;
+        private final Executable method;
+
+        /**
+         * @param classId   id of class
+         * @param className name of class
+         * @param method    compiled for compilation
+         */
+        public CompileMethodCommand(long classId, String className,
+                Executable method) {
+            this.classId = classId;
+            this.className = className;
+            this.method = method;
+        }
+
+        @Override
+        public final void run() {
+            int compLevel = Utils.INITIAL_COMP_LEVEL;
+            if (Utils.TIERED_COMPILATION) {
+                for (int i = compLevel; i <= Utils.TIERED_STOP_AT_LEVEL; ++i) {
+                    WHITE_BOX.deoptimizeMethod(method);
+                    compileMethod(method, i);
+                }
+            } else {
+                compileMethod(method, compLevel);
+            }
+        }
+
+        private void waitCompilation() {
+            if (!Utils.BACKGROUND_COMPILATION) {
+                return;
+            }
+            final Object obj = new Object();
+            synchronized (obj) {
+                for (int i = 0;
+                     i < 10 && WHITE_BOX.isMethodQueuedForCompilation(method);
+                     ++i) {
+                    try {
+                        obj.wait(1000);
+                    } catch (InterruptedException e) {
+                        Thread.currentThread().interrupt();
+                    }
+                }
+            }
+        }
+
+        private void compileMethod(Executable method, int compLevel) {
+            if (WHITE_BOX.isMethodCompilable(method, compLevel)) {
+                try {
+                    WHITE_BOX.enqueueMethodForCompilation(method, compLevel);
+                    waitCompilation();
+                    int tmp = WHITE_BOX.getMethodCompilationLevel(method);
+                    if (tmp != compLevel) {
+                        logMethod(method, "compilation level = " + tmp
+                                + ", but not " + compLevel);
+                    } else if (Utils.IS_VERBOSE) {
+                        logMethod(method, "compilation level = " + tmp + ". OK");
+                    }
+                } catch (Throwable t) {
+                    logMethod(method, "error on compile at " + compLevel
+                            + " level");
+                    t.printStackTrace();
+                }
+            } else if (Utils.IS_VERBOSE) {
+                logMethod(method, "not compilable at " + compLevel);
+            }
+        }
+
+        private void logMethod(Executable method, String message) {
+            StringBuilder builder = new StringBuilder("[");
+            builder.append(classId);
+            builder.append("]\t");
+            builder.append(className);
+            builder.append("::");
+            builder.append(method.getName());
+            builder.append('(');
+            Class[] params = method.getParameterTypes();
+            for (int i = 0, n = params.length - 1; i < n; ++i) {
+                builder.append(params[i].getName());
+                builder.append(", ");
+            }
+            if (params.length != 0) {
+                builder.append(params[params.length - 1].getName());
+            }
+            builder.append(')');
+            if (message != null) {
+                builder.append('\t');
+                builder.append(message);
+            }
+            System.err.println(builder);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/PathHandler.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2013, 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 sun.hotspot.tools.ctw;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.io.File;
+
+import java.util.Objects;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.concurrent.Executor;
+
+/**
+ * Abstract handler for path.
+ * <p/>
+ * Concrete subclasses should implement method {@link #process()}.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public abstract class PathHandler {
+    private static final Pattern JAR_IN_DIR_PATTERN
+            = Pattern.compile("^(.*[/\\\\])?\\*$");
+    protected final Path root;
+    protected final Executor executor;
+    private ClassLoader loader;
+
+    /**
+     * @param root     root path to process
+     * @param executor executor used for process task invocation
+     * @throws NullPointerException if {@code root} or {@code executor} is
+     *                              {@code null}
+     */
+    protected PathHandler(Path root, Executor executor) {
+        Objects.requireNonNull(root);
+        Objects.requireNonNull(executor);
+        this.root = root.normalize();
+        this.executor = executor;
+        this.loader = ClassLoader.getSystemClassLoader();
+    }
+
+   /**
+     * Factory method. Construct concrete handler in depends from {@code path}.
+     *
+     * @param path     the path to process
+     * @param executor executor used for compile task invocation
+     * @throws NullPointerException if {@code path} or {@code executor} is
+     *                              {@code null}
+     */
+    public static PathHandler create(String path, Executor executor) {
+        Objects.requireNonNull(path);
+        Objects.requireNonNull(executor);
+        Matcher matcher = JAR_IN_DIR_PATTERN.matcher(path);
+        if (matcher.matches()) {
+            path = matcher.group(1);
+            path = path.isEmpty() ? "." : path;
+            return new ClassPathJarInDirEntry(Paths.get(path), executor);
+        } else {
+            path = path.isEmpty() ? "." : path;
+            Path p = Paths.get(path);
+            if (isJarFile(p)) {
+                return new ClassPathJarEntry(p, executor);
+            } else if (isListFile(p)) {
+                return new ClassesListInFile(p, executor);
+            } else {
+                return new ClassPathDirEntry(p, executor);
+            }
+        }
+    }
+
+    private static boolean isJarFile(Path path) {
+        if (Files.isRegularFile(path)) {
+            String name = path.toString();
+            return Utils.endsWithIgnoreCase(name, ".zip")
+                    || Utils.endsWithIgnoreCase(name, ".jar");
+        }
+        return false;
+    }
+
+    private static boolean isListFile(Path path) {
+        if (Files.isRegularFile(path)) {
+            String name = path.toString();
+            return Utils.endsWithIgnoreCase(name, ".lst");
+        }
+        return false;
+    }
+
+    /**
+     * Processes all classes in specified path.
+     */
+    public abstract void process();
+
+   /**
+     * Sets class loader, that will be used to define class at
+     * {@link #processClass(String)}.
+     *
+     * @param loader class loader
+     * @throws NullPointerException if {@code loader} is {@code null}
+     */
+    protected final void setLoader(ClassLoader loader) {
+        Objects.requireNonNull(loader);
+        this.loader = loader;
+    }
+
+    /**
+     * Processes specificed class.
+     * @param name fully qualified name of class to process
+     */
+    protected final void processClass(String name) {
+        try {
+            Class aClass = Class.forName(name, true, loader);
+            Compiler.compileClass(aClass, executor);
+        } catch (ClassNotFoundException | LinkageError e) {
+            System.out.printf("Class %s loading failed : %s%n", name,
+                e.getMessage());
+        }
+    }
+
+    /**
+     * @return {@code true} if processing should be stopped
+     */
+    public static boolean isFinished() {
+        return Compiler.isLimitReached();
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2013, 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 sun.hotspot.tools.ctw;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import sun.management.ManagementFactoryHelper;
+
+import java.io.File;
+import java.util.regex.Pattern;
+
+/**
+ * Auxiliary methods.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public class Utils {
+    /**
+     * Value of {@code -XX:CompileThreshold}
+     */
+    public static final boolean TIERED_COMPILATION
+            = Boolean.parseBoolean(getVMOption("TieredCompilation", "false"));
+    /**
+     * Value of {@code -XX:BackgroundCompilation}
+     */
+    public static final boolean BACKGROUND_COMPILATION
+            = Boolean.parseBoolean(getVMOption("BackgroundCompilation",
+            "false"));
+    /**
+     * Value of {@code -XX:TieredStopAtLevel}
+     */
+    public static final int TIERED_STOP_AT_LEVEL;
+    /**
+     * Value of {@code -XX:CICompilerCount}
+     */
+    public static final Integer CI_COMPILER_COUNT
+            = Integer.valueOf(getVMOption("CICompilerCount", "1"));
+    /**
+     * Initial compilation level.
+     */
+    public static final int INITIAL_COMP_LEVEL;
+    /**
+     * Compiled path-separator regexp.
+     */
+    public static final Pattern PATH_SEPARATOR = Pattern.compile(
+            File.pathSeparator, Pattern.LITERAL);
+    /**
+     * Value of {@code -DDeoptimizeAllClassesRate}. Frequency of
+     * {@code WB.deoptimizeAll()} invocation If it less that {@code 0},
+     * {@code WB.deoptimizeAll()} will not be invoked.
+     */
+    public static final int DEOPTIMIZE_ALL_CLASSES_RATE
+            = Integer.getInteger("DeoptimizeAllClassesRate", -1);
+    /**
+     * Value of {@code -DCompileTheWorldStopAt}. Last class to consider.
+     */
+    public static final long COMPILE_THE_WORLD_STOP_AT
+            = Long.getLong("CompileTheWorldStopAt", Long.MAX_VALUE);
+    /**
+     * Value of {@code -DCompileTheWorldStartAt}. First class to consider.
+     */
+    public static final long COMPILE_THE_WORLD_START_AT
+            = Long.getLong("CompileTheWorldStartAt", 1);
+    /**
+     * Value of {@code -DCompileTheWorldPreloadClasses}. Preload all classes
+     * used by a class before start loading.
+     */
+    public static final boolean COMPILE_THE_WORLD_PRELOAD_CLASSES;
+    /**
+     * Value of {@code -Dsun.hotspot.tools.ctw.verbose}. Verbose output,
+     * adds additional information about compilation.
+     */
+    public static final boolean IS_VERBOSE
+            = Boolean.getBoolean("sun.hotspot.tools.ctw.verbose");
+    /**
+     * Value of {@code -Dsun.hotspot.tools.ctw.logfile}.Path to logfile, if
+     * it's null, cout will be used.
+     */
+    public static final String LOG_FILE
+            = System.getProperty("sun.hotspot.tools.ctw.logfile");
+    static {
+        if (Utils.TIERED_COMPILATION) {
+            INITIAL_COMP_LEVEL = 1;
+        } else {
+            String vmName = System.getProperty("java.vm.name");
+            if (Utils.endsWithIgnoreCase(vmName, " Server VM")) {
+                INITIAL_COMP_LEVEL = 4;
+            } else if (Utils.endsWithIgnoreCase(vmName, " Client VM")
+                    || Utils.endsWithIgnoreCase(vmName, " Minimal VM")) {
+                INITIAL_COMP_LEVEL = 1;
+            } else {
+                throw new RuntimeException("Unknown VM: " + vmName);
+            }
+        }
+
+        TIERED_STOP_AT_LEVEL = Integer.parseInt(getVMOption("TieredStopAtLevel",
+                String.valueOf(INITIAL_COMP_LEVEL)));
+    }
+
+    static {
+        String tmp = System.getProperty("CompileTheWorldPreloadClasses");
+        if (tmp == null) {
+            COMPILE_THE_WORLD_PRELOAD_CLASSES = true;
+        } else {
+            COMPILE_THE_WORLD_PRELOAD_CLASSES = Boolean.parseBoolean(tmp);
+        }
+    }
+
+    public static final String CLASSFILE_EXT = ".class";
+
+    private Utils() {
+    }
+
+    /**
+     * Tests if the string ends with the suffix, ignoring case
+     * considerations
+     *
+     * @param string the tested string
+     * @param suffix the suffix
+     * @return {@code true} if {@code string} ends with the {@code suffix}
+     * @see String#endsWith(String)
+     */
+    public static boolean endsWithIgnoreCase(String string, String suffix) {
+        if (string == null || suffix == null) {
+            return false;
+        }
+        int length = suffix.length();
+        int toffset = string.length() - length;
+        if (toffset < 0) {
+            return false;
+        }
+        return string.regionMatches(true, toffset, suffix, 0, length);
+    }
+
+    /**
+     * Returns value of VM option.
+     *
+     * @param name option's name
+     * @return value of option or {@code null}, if option doesn't exist
+     * @throws NullPointerException if name is null
+     */
+    public static String getVMOption(String name) {
+        String result;
+        HotSpotDiagnosticMXBean diagnostic
+                = ManagementFactoryHelper.getDiagnosticMXBean();
+        result = diagnostic.getVMOption(name).getValue();
+        return result;
+    }
+
+    /**
+     * Returns value of VM option or default value.
+     *
+     * @param name         option's name
+     * @param defaultValue default value
+     * @return value of option or {@code defaultValue}, if option doesn't exist
+     * @throws NullPointerException if name is null
+     * @see #getVMOption(String)
+     */
+    public static String getVMOption(String name, String defaultValue) {
+        String result;
+        try {
+            result = getVMOption(name);
+        } catch (NoClassDefFoundError e) {
+            // compact1, compact2 support
+            result = defaultValue;
+        }
+        return result == null ? defaultValue : result;
+    }
+
+    /**
+     * Tests if the filename is valid filename for class file.
+     *
+     * @param filename tested filename
+     */
+    public static boolean isClassFile(String filename) {
+        // If the filename has a period after removing '.class', it's not valid class file
+        return endsWithIgnoreCase(filename, CLASSFILE_EXT)
+                && (filename.indexOf('.')
+                == (filename.length() - CLASSFILE_EXT.length()));
+    }
+
+    /**
+     * Converts the filename to classname.
+     *
+     * @param filename filename to convert
+     * @return corresponding classname.
+     * @throws AssertionError if filename isn't valid filename for class file -
+     *                        {@link #isClassFile(String)}
+     */
+    public static String fileNameToClassName(String filename) {
+        assert isClassFile(filename);
+        return filename.substring(0, filename.length() - CLASSFILE_EXT.length())
+                       .replace(File.separatorChar, '.');
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/test/Bar.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,5 @@
+public class Bar {
+  private static void staticMethod() { }
+  public void method() { }
+  protected Bar() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/test/ClassesDirTest.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, 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 ClassesDirTest
+ * @bug 8012447
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src
+ * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox ClassesDirTest Foo Bar
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * @run main ClassesDirTest prepare
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes
+ * @run main ClassesDirTest check ctw.log
+ * @summary testing of CompileTheWorld :: classes in directory
+ * @author igor.ignatyev@oracle.com
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+
+public class ClassesDirTest extends CtwTest {
+    private static final String[] SHOULD_CONTAIN
+            = {"# dir: classes", "Done (2 classes, 6 methods, "};
+
+    private ClassesDirTest() {
+        super(SHOULD_CONTAIN);
+    }
+
+    public static void main(String[] args) throws Exception {
+        new ClassesDirTest().run(args);
+    }
+
+    protected void prepare() throws Exception {
+        String path = "classes";
+        Files.createDirectory(Paths.get(path));
+        Files.move(Paths.get("Foo.class"), Paths.get(path, "Foo.class"),
+                StandardCopyOption.REPLACE_EXISTING);
+        Files.move(Paths.get("Bar.class"), Paths.get(path, "Bar.class"),
+                StandardCopyOption.REPLACE_EXISTING);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/test/ClassesListTest.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013, 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 ClassesListTest
+ * @bug 8012447
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src
+ * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox ClassesListTest Foo Bar
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * @run main ClassesListTest prepare
+ * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes.lst
+ * @run main ClassesListTest check ctw.log
+ * @summary testing of CompileTheWorld :: list of classes in file
+ * @author igor.ignatyev@oracle.com
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+
+public class ClassesListTest extends CtwTest {
+    private static final String[] SHOULD_CONTAIN
+            = {"# list: classes.lst", "Done (4 classes, "};
+
+    private ClassesListTest() {
+        super(SHOULD_CONTAIN);
+    }
+
+    public static void main(String[] args) throws Exception {
+        new ClassesListTest().run(args);
+    }
+
+    protected void prepare() throws Exception {
+        String path = "classes.lst";
+        Files.copy(Paths.get(System.getProperty("test.src"), path),
+                Paths.get(path), StandardCopyOption.REPLACE_EXISTING);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/test/CtwTest.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.List;
+import java.util.Collections;
+import java.util.ArrayList;
+
+import java.io.File;
+import java.io.Writer;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.BufferedReader;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.nio.charset.Charset;
+
+import com.oracle.java.testlibrary.JDKToolFinder;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+public abstract class CtwTest {
+    protected final String[] shouldContain;
+    protected CtwTest(String[] shouldContain) {
+        this.shouldContain = shouldContain;
+    }
+
+    public void run(String[] args) throws Exception {
+        if (args.length == 0) {
+            throw new Error("args is empty");
+        }
+        switch (args[0]) {
+            case "prepare":
+                prepare();
+                break;
+            case "check":
+                check(args);
+                break;
+            default:
+                throw new Error("unregonized action -- " + args[0]);
+        }
+    }
+
+    protected void prepare() throws Exception { }
+
+    protected void check(String[] args) throws Exception  {
+        if (args.length < 2) {
+            throw new Error("logfile isn't specified");
+        }
+        String logfile = args[1];
+        try (BufferedReader r = Files.newBufferedReader(Paths.get(logfile),
+                Charset.defaultCharset())) {
+            OutputAnalyzer output = readOutput(r);
+           for (String test : shouldContain) {
+                output.shouldContain(test);
+            }
+        }
+    }
+
+    private static OutputAnalyzer readOutput(BufferedReader reader)
+            throws IOException {
+        StringBuilder builder = new StringBuilder();
+        String eol = String.format("%n");
+        String line;
+
+        while ((line = reader.readLine()) != null) {
+            builder.append(line);
+            builder.append(eol);
+        }
+        return new OutputAnalyzer(builder.toString(), "");
+    }
+
+    protected void dump(OutputAnalyzer output, String name) {
+        try (Writer w = new FileWriter(name + ".out")) {
+            String s = output.getStdout();
+            w.write(s, s.length(), 0);
+        } catch (IOException io) {
+            io.printStackTrace();
+        }
+        try (Writer w = new FileWriter(name + ".err")) {
+            String s = output.getStderr();
+            w.write(s, s.length(), 0);
+        } catch (IOException io) {
+            io.printStackTrace();
+        }
+    }
+
+    protected ProcessBuilder createJarProcessBuilder(String... command)
+            throws Exception {
+        String javapath = JDKToolFinder.getJDKTool("jar");
+
+        ArrayList<String> args = new ArrayList<>();
+        args.add(javapath);
+        Collections.addAll(args, command);
+
+        return new ProcessBuilder(args.toArray(new String[args.size()]));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/test/Foo.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,5 @@
+public class Foo {
+  private static void staticMethod() { }
+  public void method() { }
+  protected Foo() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/test/JarDirTest.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013, 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 JarDirTest
+ * @bug 8012447
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src
+ * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox JarDirTest Foo Bar
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * @run main JarDirTest prepare
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld jars/*
+ * @run main JarDirTest check ctw.log
+ * @summary testing of CompileTheWorld :: jars in directory
+ * @author igor.ignatyev@oracle.com
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+public class JarDirTest extends CtwTest {
+    private static final String[] SHOULD_CONTAIN
+            = {"# jar_in_dir: jars",
+                    "# jar: jars" + File.separator +"foo.jar",
+                    "# jar: jars" + File.separator +"bar.jar",
+                    "Done (4 classes, 12 methods, "};
+
+    private JarDirTest() {
+        super(SHOULD_CONTAIN);
+    }
+
+    public static void main(String[] args) throws Exception {
+        new JarDirTest().run(args);
+    }
+
+    protected void prepare() throws Exception {
+        String path = "jars";
+        Files.createDirectory(Paths.get(path));
+
+        ProcessBuilder pb = createJarProcessBuilder("cf", "jars/foo.jar",
+                "Foo.class", "Bar.class");
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        dump(output, "ctw-foo.jar");
+        output.shouldHaveExitValue(0);
+
+        pb = createJarProcessBuilder("cf", "jars/bar.jar", "Foo.class",
+                "Bar.class");
+        output = new OutputAnalyzer(pb.start());
+        dump(output, "ctw-bar.jar");
+        output.shouldHaveExitValue(0);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/test/JarsTest.java	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, 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 JarsTest
+ * @bug 8012447
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src
+ * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox JarsTest Foo Bar
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * @run main JarsTest prepare
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld foo.jar bar.jar
+ * @run main JarsTest check ctw.log
+ * @summary testing of CompileTheWorld :: jars
+ * @author igor.ignatyev@oracle.com
+ */
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+public class JarsTest extends CtwTest {
+    private static final String[] SHOULD_CONTAIN
+            = {"# jar: foo.jar", "# jar: bar.jar",
+                    "Done (4 classes, 12 methods, "};
+
+    private JarsTest() {
+        super(SHOULD_CONTAIN);
+    }
+
+    public static void main(String[] args) throws Exception {
+        new JarsTest().run(args);
+    }
+
+    protected void prepare() throws Exception {
+        ProcessBuilder pb = createJarProcessBuilder("cf", "foo.jar",
+                "Foo.class", "Bar.class");
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        dump(output, "ctw-foo.jar");
+        output.shouldHaveExitValue(0);
+
+        pb = createJarProcessBuilder("cf", "bar.jar", "Foo.class", "Bar.class");
+        output = new OutputAnalyzer(pb.start());
+        dump(output, "ctw-bar.jar");
+        output.shouldHaveExitValue(0);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/test/classes.lst	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,4 @@
+java.lang.String
+java.lang.Object
+Foo
+Bar
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/whitebox/Makefile	Fri Sep 13 10:34:15 2013 -0400
@@ -0,0 +1,63 @@
+#
+# Copyright (c) 2013, 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.
+#
+#
+
+ifneq "x$(ALT_BOOTDIR)" "x"
+	BOOTDIR := $(ALT_BOOTDIR)
+endif
+
+ifeq "x$(BOOTDIR)" "x"
+	JDK_HOME := $(shell dirname $(shell which java))/..
+else
+	JDK_HOME := $(BOOTDIR)
+endif
+
+SRC_DIR = ./
+BUILD_DIR = build
+OUTPUT_DIR = $(BUILD_DIR)/classes
+
+JAVAC = $(JDK_HOME)/bin/javac
+JAR = $(JDK_HOME)/bin/jar
+
+SRC_FILES = $(shell find $(SRC_DIR) -name '*.java')
+
+.PHONY: filelist clean cleantmp
+
+all: wb.jar cleantmp
+
+wb.jar: filelist
+	@mkdir -p $(OUTPUT_DIR)
+	$(JAVAC) -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) -cp $(OUTPUT_DIR) @filelist
+	$(JAR) cf wb.jar -C $(OUTPUT_DIR) .
+	@rm -rf $(OUTPUT_DIR)
+
+filelist: $(SRC_FILES)
+	@rm -f $@
+	@echo $(SRC_FILES) > $@
+
+clean: cleantmp
+	@rm -rf wb.jar
+
+cleantmp:
+	@rm -rf filelist
+	@rm -rf $(BUILD_DIR)