changeset 997:46b819ba120b

Merge
author jrose
date Wed, 30 Sep 2009 13:25:39 -0700
parents 1af62b6ca0f9 (current diff) d6b9fd78f389 (diff)
children 708275a44e4a dcf03e02b020
files src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp src/share/vm/gc_implementation/shared/markSweep.cpp src/share/vm/oops/instanceKlass.cpp src/share/vm/runtime/thread.cpp src/share/vm/runtime/thread.hpp
diffstat 99 files changed, 1952 insertions(+), 1568 deletions(-) [+]
line wrap: on
line diff
--- a/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java	Fri Sep 25 04:39:54 2009 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java	Wed Sep 30 13:25:39 2009 -0700
@@ -33,6 +33,7 @@
 
 public class CodeCache {
   private static AddressField       heapField;
+  private static AddressField       scavengeRootNMethodsField;
   private static VirtualConstructor virtualConstructor;
 
   private CodeHeap heap;
@@ -49,6 +50,7 @@
     Type type = db.lookupType("CodeCache");
 
     heapField = type.getAddressField("_heap");
+    scavengeRootNMethodsField = type.getAddressField("_scavenge_root_nmethods");
 
     virtualConstructor = new VirtualConstructor(db);
     // Add mappings for all possible CodeBlob subclasses
@@ -67,6 +69,10 @@
     heap = (CodeHeap) VMObjectFactory.newObject(CodeHeap.class, heapField.getValue());
   }
 
+  public NMethod scavengeRootMethods() {
+    return (NMethod) VMObjectFactory.newObject(NMethod.class, scavengeRootNMethodsField.getValue());
+  }
+
   public boolean contains(Address p) {
     return getHeap().contains(p);
   }
--- a/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java	Fri Sep 25 04:39:54 2009 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java	Wed Sep 30 13:25:39 2009 -0700
@@ -40,7 +40,10 @@
   /** != InvocationEntryBci if this nmethod is an on-stack replacement method */
   private static CIntegerField entryBCIField;
   /** To support simple linked-list chaining of nmethods */
-  private static AddressField  linkField;
+  private static AddressField  osrLinkField;
+  private static AddressField  scavengeRootLinkField;
+  private static CIntegerField scavengeRootStateField;
+
   /** Offsets for different nmethod parts */
   private static CIntegerField exceptionOffsetField;
   private static CIntegerField deoptOffsetField;
@@ -87,7 +90,10 @@
     zombieInstructionSizeField  = type.getCIntegerField("_zombie_instruction_size");
     methodField                 = type.getOopField("_method");
     entryBCIField               = type.getCIntegerField("_entry_bci");
-    linkField                   = type.getAddressField("_link");
+    osrLinkField                = type.getAddressField("_osr_link");
+    scavengeRootLinkField       = type.getAddressField("_scavenge_root_link");
+    scavengeRootStateField      = type.getCIntegerField("_scavenge_root_state");
+
     exceptionOffsetField        = type.getCIntegerField("_exception_offset");
     deoptOffsetField            = type.getCIntegerField("_deoptimize_offset");
     origPCOffsetField           = type.getCIntegerField("_orig_pc_offset");
@@ -219,10 +225,19 @@
     return getEntryBCI();
   }
 
-  public NMethod getLink() {
-    return (NMethod) VMObjectFactory.newObject(NMethod.class, linkField.getValue(addr));
+  public NMethod getOSRLink() {
+    return (NMethod) VMObjectFactory.newObject(NMethod.class, osrLinkField.getValue(addr));
   }
 
+  public NMethod getScavengeRootLink() {
+    return (NMethod) VMObjectFactory.newObject(NMethod.class, scavengeRootLinkField.getValue(addr));
+  }
+
+  public int getScavengeRootState() {
+    return (int) scavengeRootStateField.getValue(addr);
+  }
+
+
   /** Tells whether frames described by this nmethod can be
       deoptimized. Note: native wrappers cannot be deoptimized. */
   public boolean canBeDeoptimized() { return isJavaMethod(); }
--- a/src/cpu/sparc/vm/assembler_sparc.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/cpu/sparc/vm/assembler_sparc.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -4676,3 +4676,50 @@
     load_ptr_contents(base, G6_heapbase);
   }
 }
+
+// Compare char[] arrays aligned to 4 bytes.
+void MacroAssembler::char_arrays_equals(Register ary1, Register ary2,
+                                        Register limit, Register result,
+                                        Register chr1, Register chr2, Label& Ldone) {
+  Label Lvector, Lloop;
+  assert(chr1 == result, "should be the same");
+
+  // Note: limit contains number of bytes (2*char_elements) != 0.
+  andcc(limit, 0x2, chr1); // trailing character ?
+  br(Assembler::zero, false, Assembler::pt, Lvector);
+  delayed()->nop();
+
+  // compare the trailing char
+  sub(limit, sizeof(jchar), limit);
+  lduh(ary1, limit, chr1);
+  lduh(ary2, limit, chr2);
+  cmp(chr1, chr2);
+  br(Assembler::notEqual, true, Assembler::pt, Ldone);
+  delayed()->mov(G0, result);     // not equal
+
+  // only one char ?
+  br_on_reg_cond(rc_z, true, Assembler::pn, limit, Ldone);
+  delayed()->add(G0, 1, result); // zero-length arrays are equal
+
+  // word by word compare, dont't need alignment check
+  bind(Lvector);
+  // Shift ary1 and ary2 to the end of the arrays, negate limit
+  add(ary1, limit, ary1);
+  add(ary2, limit, ary2);
+  neg(limit, limit);
+
+  lduw(ary1, limit, chr1);
+  bind(Lloop);
+  lduw(ary2, limit, chr2);
+  cmp(chr1, chr2);
+  br(Assembler::notEqual, true, Assembler::pt, Ldone);
+  delayed()->mov(G0, result);     // not equal
+  inccc(limit, 2*sizeof(jchar));
+  // annul LDUW if branch is not taken to prevent access past end of array
+  br(Assembler::notZero, true, Assembler::pt, Lloop);
+  delayed()->lduw(ary1, limit, chr1); // hoisted
+
+  // Caller should set it:
+  // add(G0, 1, result); // equals
+}
+
--- a/src/cpu/sparc/vm/assembler_sparc.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/cpu/sparc/vm/assembler_sparc.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -2455,6 +2455,11 @@
   void inc_counter(address counter_addr, Register Rtmp1, Register Rtmp2);
   void inc_counter(int*    counter_addr, Register Rtmp1, Register Rtmp2);
 
+  // Compare char[] arrays aligned to 4 bytes.
+  void char_arrays_equals(Register ary1, Register ary2,
+                          Register limit, Register result,
+                          Register chr1, Register chr2, Label& Ldone);
+
 #undef VIRTUAL
 
 };
--- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -2171,7 +2171,7 @@
     // subtype which we can't check or src is the same array as dst
     // but not necessarily exactly of type default_type.
     Label known_ok, halt;
-    jobject2reg(op->expected_type()->encoding(), tmp);
+    jobject2reg(op->expected_type()->constant_encoding(), tmp);
     __ ld_ptr(dst, oopDesc::klass_offset_in_bytes(), tmp2);
     if (basic_type != T_OBJECT) {
       __ cmp(tmp, tmp2);
@@ -2429,7 +2429,7 @@
       assert(data->is_BitData(), "need BitData for checkcast");
       Register mdo      = k_RInfo;
       Register data_val = Rtmp1;
-      jobject2reg(md->encoding(), mdo);
+      jobject2reg(md->constant_encoding(), mdo);
 
       int mdo_offset_bias = 0;
       if (!Assembler::is_simm13(md->byte_offset_of_slot(data, DataLayout::header_offset()) + data->size_in_bytes())) {
@@ -2452,7 +2452,7 @@
     // patching may screw with our temporaries on sparc,
     // so let's do it before loading the class
     if (k->is_loaded()) {
-      jobject2reg(k->encoding(), k_RInfo);
+      jobject2reg(k->constant_encoding(), k_RInfo);
     } else {
       jobject2reg_with_patching(k_RInfo, op->info_for_patch());
     }
@@ -2513,7 +2513,7 @@
     // patching may screw with our temporaries on sparc,
     // so let's do it before loading the class
     if (k->is_loaded()) {
-      jobject2reg(k->encoding(), k_RInfo);
+      jobject2reg(k->constant_encoding(), k_RInfo);
     } else {
       jobject2reg_with_patching(k_RInfo, op->info_for_patch());
     }
@@ -2717,7 +2717,7 @@
   assert(op->tmp1()->is_single_cpu(), "tmp1 must be allocated");
   Register mdo  = op->mdo()->as_register();
   Register tmp1 = op->tmp1()->as_register();
-  jobject2reg(md->encoding(), mdo);
+  jobject2reg(md->constant_encoding(), mdo);
   int mdo_offset_bias = 0;
   if (!Assembler::is_simm13(md->byte_offset_of_slot(data, CounterData::count_offset()) +
                             data->size_in_bytes())) {
@@ -2774,7 +2774,7 @@
         if (receiver == NULL) {
           Address recv_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)) -
                             mdo_offset_bias);
-          jobject2reg(known_klass->encoding(), tmp1);
+          jobject2reg(known_klass->constant_encoding(), tmp1);
           __ st_ptr(tmp1, recv_addr);
           Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) -
                             mdo_offset_bias);
--- a/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -896,7 +896,7 @@
   LIR_Opr len = length.result();
   BasicType elem_type = x->elt_type();
 
-  __ oop2reg(ciTypeArrayKlass::make(elem_type)->encoding(), klass_reg);
+  __ oop2reg(ciTypeArrayKlass::make(elem_type)->constant_encoding(), klass_reg);
 
   CodeStub* slow_path = new NewTypeArrayStub(klass_reg, len, reg, info);
   __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, elem_type, klass_reg, slow_path);
--- a/src/cpu/sparc/vm/sparc.ad	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/cpu/sparc/vm/sparc.ad	Wed Sep 30 13:25:39 2009 -0700
@@ -2838,63 +2838,41 @@
   %}
 
 
-  enc_class enc_String_Compare(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result) %{
+  enc_class enc_String_Compare(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, notemp_iRegI result) %{
     Label Ldone, Lloop;
     MacroAssembler _masm(&cbuf);
 
     Register   str1_reg = reg_to_register_object($str1$$reg);
     Register   str2_reg = reg_to_register_object($str2$$reg);
-    Register   tmp1_reg = reg_to_register_object($tmp1$$reg);
-    Register   tmp2_reg = reg_to_register_object($tmp2$$reg);
+    Register   cnt1_reg = reg_to_register_object($cnt1$$reg);
+    Register   cnt2_reg = reg_to_register_object($cnt2$$reg);
     Register result_reg = reg_to_register_object($result$$reg);
 
-    // Get the first character position in both strings
-    //         [8] char array, [12] offset, [16] count
-    int  value_offset = java_lang_String:: value_offset_in_bytes();
-    int offset_offset = java_lang_String::offset_offset_in_bytes();
-    int  count_offset = java_lang_String:: count_offset_in_bytes();
-
-    // load str1 (jchar*) base address into tmp1_reg
-    __ load_heap_oop(str1_reg, value_offset, tmp1_reg);
-    __ ld(str1_reg, offset_offset, result_reg);
-    __ add(tmp1_reg, arrayOopDesc::base_offset_in_bytes(T_CHAR), tmp1_reg);
-    __   ld(str1_reg, count_offset, str1_reg); // hoisted
-    __ sll(result_reg, exact_log2(sizeof(jchar)), result_reg);
-    __   load_heap_oop(str2_reg, value_offset, tmp2_reg); // hoisted
-    __ add(result_reg, tmp1_reg, tmp1_reg);
-
-    // load str2 (jchar*) base address into tmp2_reg
-    // __ ld_ptr(str2_reg, value_offset, tmp2_reg); // hoisted
-    __ ld(str2_reg, offset_offset, result_reg);
-    __ add(tmp2_reg, arrayOopDesc::base_offset_in_bytes(T_CHAR), tmp2_reg);
-    __   ld(str2_reg, count_offset, str2_reg); // hoisted
-    __ sll(result_reg, exact_log2(sizeof(jchar)), result_reg);
-    __   subcc(str1_reg, str2_reg, O7); // hoisted
-    __ add(result_reg, tmp2_reg, tmp2_reg);
+    assert(result_reg != str1_reg &&
+           result_reg != str2_reg &&
+           result_reg != cnt1_reg &&
+           result_reg != cnt2_reg ,
+           "need different registers");
 
     // Compute the minimum of the string lengths(str1_reg) and the
     // difference of the string lengths (stack)
 
-    // discard string base pointers, after loading up the lengths
-    // __ ld(str1_reg, count_offset, str1_reg); // hoisted
-    // __ ld(str2_reg, count_offset, str2_reg); // hoisted
-
     // See if the lengths are different, and calculate min in str1_reg.
     // Stash diff in O7 in case we need it for a tie-breaker.
     Label Lskip;
-    // __ subcc(str1_reg, str2_reg, O7); // hoisted
-    __ sll(str1_reg, exact_log2(sizeof(jchar)), str1_reg); // scale the limit
+    __ subcc(cnt1_reg, cnt2_reg, O7);
+    __ sll(cnt1_reg, exact_log2(sizeof(jchar)), cnt1_reg); // scale the limit
     __ br(Assembler::greater, true, Assembler::pt, Lskip);
-    // str2 is shorter, so use its count:
-    __ delayed()->sll(str2_reg, exact_log2(sizeof(jchar)), str1_reg); // scale the limit
+    // cnt2 is shorter, so use its count:
+    __ delayed()->sll(cnt2_reg, exact_log2(sizeof(jchar)), cnt1_reg); // scale the limit
     __ bind(Lskip);
 
-    // reallocate str1_reg, str2_reg, result_reg
+    // reallocate cnt1_reg, cnt2_reg, result_reg
     // Note:  limit_reg holds the string length pre-scaled by 2
-    Register limit_reg =   str1_reg;
-    Register  chr2_reg =   str2_reg;
+    Register limit_reg =   cnt1_reg;
+    Register  chr2_reg =   cnt2_reg;
     Register  chr1_reg = result_reg;
-    // tmp{12} are the base pointers
+    // str{12} are the base pointers
 
     // Is the minimum length zero?
     __ cmp(limit_reg, (int)(0 * sizeof(jchar))); // use cast to resolve overloading ambiguity
@@ -2902,8 +2880,8 @@
     __ delayed()->mov(O7, result_reg);  // result is difference in lengths
 
     // Load first characters
-    __ lduh(tmp1_reg, 0, chr1_reg);
-    __ lduh(tmp2_reg, 0, chr2_reg);
+    __ lduh(str1_reg, 0, chr1_reg);
+    __ lduh(str2_reg, 0, chr2_reg);
 
     // Compare first characters
     __ subcc(chr1_reg, chr2_reg, chr1_reg);
@@ -2915,7 +2893,7 @@
       // Check after comparing first character to see if strings are equivalent
       Label LSkip2;
       // Check if the strings start at same location
-      __ cmp(tmp1_reg, tmp2_reg);
+      __ cmp(str1_reg, str2_reg);
       __ brx(Assembler::notEqual, true, Assembler::pt, LSkip2);
       __ delayed()->nop();
 
@@ -2932,23 +2910,23 @@
     __ br(Assembler::equal, true, Assembler::pn, Ldone);
     __ delayed()->mov(O7, result_reg);  // result is difference in lengths
 
-    // Shift tmp1_reg and tmp2_reg to the end of the arrays, negate limit
-    __ add(tmp1_reg, limit_reg, tmp1_reg);
-    __ add(tmp2_reg, limit_reg, tmp2_reg);
+    // Shift str1_reg and str2_reg to the end of the arrays, negate limit
+    __ add(str1_reg, limit_reg, str1_reg);
+    __ add(str2_reg, limit_reg, str2_reg);
     __ neg(chr1_reg, limit_reg);  // limit = -(limit-2)
 
     // Compare the rest of the characters
-    __ lduh(tmp1_reg, limit_reg, chr1_reg);
+    __ lduh(str1_reg, limit_reg, chr1_reg);
     __ bind(Lloop);
-    // __ lduh(tmp1_reg, limit_reg, chr1_reg); // hoisted
-    __ lduh(tmp2_reg, limit_reg, chr2_reg);
+    // __ lduh(str1_reg, limit_reg, chr1_reg); // hoisted
+    __ lduh(str2_reg, limit_reg, chr2_reg);
     __ subcc(chr1_reg, chr2_reg, chr1_reg);
     __ br(Assembler::notZero, false, Assembler::pt, Ldone);
     assert(chr1_reg == result_reg, "result must be pre-placed");
     __ delayed()->inccc(limit_reg, sizeof(jchar));
     // annul LDUH if branch is not taken to prevent access past end of string
     __ br(Assembler::notZero, true, Assembler::pt, Lloop);
-    __ delayed()->lduh(tmp1_reg, limit_reg, chr1_reg); // hoisted
+    __ delayed()->lduh(str1_reg, limit_reg, chr1_reg); // hoisted
 
     // If strings are equal up to min length, return the length difference.
     __ mov(O7, result_reg);
@@ -2957,125 +2935,80 @@
     __ bind(Ldone);
   %}
 
-enc_class enc_String_Equals(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result) %{
-    Label Lword, Lword_loop, Lpost_word, Lchar, Lchar_loop, Ldone;
+enc_class enc_String_Equals(o0RegP str1, o1RegP str2, g3RegI cnt, notemp_iRegI result) %{
+    Label Lword_loop, Lpost_word, Lchar, Lchar_loop, Ldone;
     MacroAssembler _masm(&cbuf);
 
     Register   str1_reg = reg_to_register_object($str1$$reg);
     Register   str2_reg = reg_to_register_object($str2$$reg);
-    Register   tmp1_reg = reg_to_register_object($tmp1$$reg);
-    Register   tmp2_reg = reg_to_register_object($tmp2$$reg);
+    Register    cnt_reg = reg_to_register_object($cnt$$reg);
+    Register   tmp1_reg = O7;
     Register result_reg = reg_to_register_object($result$$reg);
 
-    // Get the first character position in both strings
-    //         [8] char array, [12] offset, [16] count
-    int  value_offset = java_lang_String:: value_offset_in_bytes();
-    int offset_offset = java_lang_String::offset_offset_in_bytes();
-    int  count_offset = java_lang_String:: count_offset_in_bytes();
-
-    // load str1 (jchar*) base address into tmp1_reg
-    __ load_heap_oop(Address(str1_reg, value_offset), tmp1_reg);
-    __ ld(Address(str1_reg, offset_offset), result_reg);
-    __ add(tmp1_reg, arrayOopDesc::base_offset_in_bytes(T_CHAR), tmp1_reg);
-    __    ld(Address(str1_reg, count_offset), str1_reg); // hoisted
-    __ sll(result_reg, exact_log2(sizeof(jchar)), result_reg);
-    __    load_heap_oop(Address(str2_reg, value_offset), tmp2_reg); // hoisted
-    __ add(result_reg, tmp1_reg, tmp1_reg);
-
-    // load str2 (jchar*) base address into tmp2_reg
-    // __ ld_ptr(Address(str2_reg, value_offset), tmp2_reg); // hoisted
-    __ ld(Address(str2_reg, offset_offset), result_reg);
-    __ add(tmp2_reg, arrayOopDesc::base_offset_in_bytes(T_CHAR), tmp2_reg);
-    __    ld(Address(str2_reg, count_offset), str2_reg); // hoisted
-    __ sll(result_reg, exact_log2(sizeof(jchar)), result_reg);
-    __   cmp(str1_reg, str2_reg); // hoisted
-    __ add(result_reg, tmp2_reg, tmp2_reg);
-
-    __ sll(str1_reg, exact_log2(sizeof(jchar)), str1_reg);
-    __ br(Assembler::notEqual, true, Assembler::pt, Ldone);
-    __ delayed()->mov(G0, result_reg);    // not equal
-
-    __ br_zero(Assembler::equal, true, Assembler::pn, str1_reg, Ldone);
-    __ delayed()->add(G0, 1, result_reg); //equals
-
-    __ cmp(tmp1_reg, tmp2_reg); //same string ?
+    assert(result_reg != str1_reg &&
+           result_reg != str2_reg &&
+           result_reg !=  cnt_reg &&
+           result_reg != tmp1_reg ,
+           "need different registers");
+
+    __ cmp(str1_reg, str2_reg); //same char[] ?
     __ brx(Assembler::equal, true, Assembler::pn, Ldone);
     __ delayed()->add(G0, 1, result_reg);
 
+    __ br_on_reg_cond(Assembler::rc_z, true, Assembler::pn, cnt_reg, Ldone);
+    __ delayed()->add(G0, 1, result_reg); // count == 0
+
     //rename registers
-    Register limit_reg =   str1_reg;
-    Register  chr2_reg =   str2_reg;
+    Register limit_reg =    cnt_reg;
     Register  chr1_reg = result_reg;
-    // tmp{12} are the base pointers
+    Register  chr2_reg =   tmp1_reg;
 
     //check for alignment and position the pointers to the ends
-    __ or3(tmp1_reg, tmp2_reg, chr1_reg);
-    __ andcc(chr1_reg, 0x3, chr1_reg); // notZero means at least one not 4-byte aligned
-    __ br(Assembler::notZero, false, Assembler::pn, Lchar);
-    __ delayed()->nop();
-
-    __ bind(Lword);
-    __ and3(limit_reg, 0x2, O7); //remember the remainder (either 0 or 2)
-    __ andn(limit_reg, 0x3, limit_reg);
-    __ br_zero(Assembler::zero, false, Assembler::pn, limit_reg, Lpost_word);
-    __ delayed()->nop();
-
-    __ add(tmp1_reg, limit_reg, tmp1_reg);
-    __ add(tmp2_reg, limit_reg, tmp2_reg);
-    __ neg(limit_reg);
-
-    __ lduw(tmp1_reg, limit_reg, chr1_reg);
-    __ bind(Lword_loop);
-    __ lduw(tmp2_reg, limit_reg, chr2_reg);
-    __ cmp(chr1_reg, chr2_reg);
-    __ br(Assembler::notEqual, true, Assembler::pt, Ldone);
-    __ delayed()->mov(G0, result_reg);
-    __ inccc(limit_reg, 2*sizeof(jchar));
-    // annul LDUW if branch i  s not taken to prevent access past end of string
-    __ br(Assembler::notZero, true, Assembler::pt, Lword_loop); //annul on taken
-    __ delayed()->lduw(tmp1_reg, limit_reg, chr1_reg); // hoisted
-
-    __ bind(Lpost_word);
-    __ br_zero(Assembler::zero, true, Assembler::pt, O7, Ldone);
-    __ delayed()->add(G0, 1, result_reg);
-
-    __ lduh(tmp1_reg, 0, chr1_reg);
-    __ lduh(tmp2_reg, 0, chr2_reg);
-    __ cmp (chr1_reg, chr2_reg);
-    __ br(Assembler::notEqual, true, Assembler::pt, Ldone);
-    __ delayed()->mov(G0, result_reg);
+    __ or3(str1_reg, str2_reg, chr1_reg);
+    __ andcc(chr1_reg, 0x3, chr1_reg);
+    // notZero means at least one not 4-byte aligned.
+    // We could optimize the case when both arrays are not aligned
+    // but it is not frequent case and it requires additional checks.
+    __ br(Assembler::notZero, false, Assembler::pn, Lchar); // char by char compare
+    __ delayed()->sll(limit_reg, exact_log2(sizeof(jchar)), limit_reg); // set byte count
+
+    // Compare char[] arrays aligned to 4 bytes.
+    __ char_arrays_equals(str1_reg, str2_reg, limit_reg, result_reg,
+                          chr1_reg, chr2_reg, Ldone);
     __ ba(false,Ldone);
     __ delayed()->add(G0, 1, result_reg);
 
+    // char by char compare
     __ bind(Lchar);
-    __ add(tmp1_reg, limit_reg, tmp1_reg);
-    __ add(tmp2_reg, limit_reg, tmp2_reg);
+    __ add(str1_reg, limit_reg, str1_reg);
+    __ add(str2_reg, limit_reg, str2_reg);
     __ neg(limit_reg); //negate count
 
-    __ lduh(tmp1_reg, limit_reg, chr1_reg);
+    __ lduh(str1_reg, limit_reg, chr1_reg);
+    // Lchar_loop
     __ bind(Lchar_loop);
-    __ lduh(tmp2_reg, limit_reg, chr2_reg);
+    __ lduh(str2_reg, limit_reg, chr2_reg);
     __ cmp(chr1_reg, chr2_reg);
     __ br(Assembler::notEqual, true, Assembler::pt, Ldone);
     __ delayed()->mov(G0, result_reg); //not equal
     __ inccc(limit_reg, sizeof(jchar));
     // annul LDUH if branch is not taken to prevent access past end of string
-    __ br(Assembler::notZero, true, Assembler::pt, Lchar_loop); //annul on taken
-    __ delayed()->lduh(tmp1_reg, limit_reg, chr1_reg); // hoisted
+    __ br(Assembler::notZero, true, Assembler::pt, Lchar_loop);
+    __ delayed()->lduh(str1_reg, limit_reg, chr1_reg); // hoisted
 
     __ add(G0, 1, result_reg);  //equal
 
     __ bind(Ldone);
   %}
 
-enc_class enc_Array_Equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result) %{
+enc_class enc_Array_Equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, notemp_iRegI result) %{
     Label Lvector, Ldone, Lloop;
     MacroAssembler _masm(&cbuf);
 
     Register   ary1_reg = reg_to_register_object($ary1$$reg);
     Register   ary2_reg = reg_to_register_object($ary2$$reg);
     Register   tmp1_reg = reg_to_register_object($tmp1$$reg);
-    Register   tmp2_reg = reg_to_register_object($tmp2$$reg);
+    Register   tmp2_reg = O7;
     Register result_reg = reg_to_register_object($result$$reg);
 
     int length_offset  = arrayOopDesc::length_offset_in_bytes();
@@ -3101,7 +3034,7 @@
     __ br(Assembler::notEqual, true, Assembler::pn, Ldone);
     __ delayed()->mov(G0, result_reg);     // not equal
 
-    __ br_zero(Assembler::zero, true, Assembler::pn, tmp1_reg, Ldone);
+    __ br_on_reg_cond(Assembler::rc_z, true, Assembler::pn, tmp1_reg, Ldone);
     __ delayed()->add(G0, 1, result_reg); // zero-length arrays are equal
 
     // load array addresses
@@ -3109,45 +3042,16 @@
     __ add(ary2_reg, base_offset, ary2_reg);
 
     // renaming registers
-    Register chr1_reg  =  tmp2_reg;   // for characters in ary1
-    Register chr2_reg  =  result_reg; // for characters in ary2
+    Register chr1_reg  =  result_reg; // for characters in ary1
+    Register chr2_reg  =  tmp2_reg;   // for characters in ary2
     Register limit_reg =  tmp1_reg;   // length
 
     // set byte count
     __ sll(limit_reg, exact_log2(sizeof(jchar)), limit_reg);
-    __ andcc(limit_reg, 0x2, chr1_reg); //trailing character ?
-    __ br(Assembler::zero, false, Assembler::pt, Lvector);
-    __ delayed()->nop();
-
-    //compare the trailing char
-    __ sub(limit_reg, sizeof(jchar), limit_reg);
-    __ lduh(ary1_reg, limit_reg, chr1_reg);
-    __ lduh(ary2_reg, limit_reg, chr2_reg);
-    __ cmp(chr1_reg, chr2_reg);
-    __ br(Assembler::notEqual, true, Assembler::pt, Ldone);
-    __ delayed()->mov(G0, result_reg);     // not equal
-
-    // only one char ?
-    __ br_zero(Assembler::zero, true, Assembler::pn, limit_reg, Ldone);
-    __ delayed()->add(G0, 1, result_reg); // zero-length arrays are equal
-
-    __ bind(Lvector);
-    // Shift ary1_reg and ary2_reg to the end of the arrays, negate limit
-    __ add(ary1_reg, limit_reg, ary1_reg);
-    __ add(ary2_reg, limit_reg, ary2_reg);
-    __ neg(limit_reg, limit_reg);
-
-    __ lduw(ary1_reg, limit_reg, chr1_reg);
-    __ bind(Lloop);
-    __ lduw(ary2_reg, limit_reg, chr2_reg);
-    __ cmp(chr1_reg, chr2_reg);
-    __ br(Assembler::notEqual, false, Assembler::pt, Ldone);
-    __ delayed()->mov(G0, result_reg);     // not equal
-    __ inccc(limit_reg, 2*sizeof(jchar));
-    // annul LDUW if branch is not taken to prevent access past end of string
-    __ br(Assembler::notZero, true, Assembler::pt, Lloop); //annul on taken
-    __ delayed()->lduw(ary1_reg, limit_reg, chr1_reg); // hoisted
-
+
+    // Compare char[] arrays aligned to 4 bytes.
+    __ char_arrays_equals(ary1_reg, ary2_reg, limit_reg, result_reg,
+                          chr1_reg, chr2_reg, Ldone);
     __ add(G0, 1, result_reg); // equals
 
     __ bind(Ldone);
@@ -9471,33 +9375,33 @@
   ins_pipe(long_memory_op);
 %}
 
-instruct string_compare(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result,
-                        o7RegI tmp3, flagsReg ccr) %{
-  match(Set result (StrComp str1 str2));
-  effect(USE_KILL str1, USE_KILL str2, KILL tmp1, KILL tmp2, KILL ccr, KILL tmp3);
+instruct string_compare(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, notemp_iRegI result,
+                        o7RegI tmp, flagsReg ccr) %{
+  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
+  effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ccr, KILL tmp);
   ins_cost(300);
-  format %{ "String Compare $str1,$str2 -> $result" %}
-  ins_encode( enc_String_Compare(str1, str2, tmp1, tmp2, result) );
+  format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result   // KILL $tmp" %}
+  ins_encode( enc_String_Compare(str1, str2, cnt1, cnt2, result) );
   ins_pipe(long_memory_op);
 %}
 
-instruct string_equals(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result,
-                       o7RegI tmp3, flagsReg ccr) %{
-  match(Set result (StrEquals str1 str2));
-  effect(USE_KILL str1, USE_KILL str2, KILL tmp1, KILL tmp2, KILL ccr, KILL tmp3);
+instruct string_equals(o0RegP str1, o1RegP str2, g3RegI cnt, notemp_iRegI result,
+                       o7RegI tmp, flagsReg ccr) %{
+  match(Set result (StrEquals (Binary str1 str2) cnt));
+  effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp, KILL ccr);
   ins_cost(300);
-  format %{ "String Equals $str1,$str2 -> $result" %}
-  ins_encode( enc_String_Equals(str1, str2, tmp1, tmp2, result) );
+  format %{ "String Equals $str1,$str2,$cnt -> $result   // KILL $tmp" %}
+  ins_encode( enc_String_Equals(str1, str2, cnt, result) );
   ins_pipe(long_memory_op);
 %}
 
-instruct array_equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result,
-                        flagsReg ccr) %{
+instruct array_equals(o0RegP ary1, o1RegP ary2, g3RegI tmp1, notemp_iRegI result,
+                      o7RegI tmp2, flagsReg ccr) %{
   match(Set result (AryEq ary1 ary2));
   effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL ccr);
   ins_cost(300);
-  format %{ "Array Equals $ary1,$ary2 -> $result" %}
-  ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, result));
+  format %{ "Array Equals $ary1,$ary2 -> $result   // KILL $tmp1,$tmp2" %}
+  ins_encode( enc_Array_Equals(ary1, ary2, tmp1, result));
   ins_pipe(long_memory_op);
 %}
 
--- a/src/cpu/x86/vm/assembler_x86.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/cpu/x86/vm/assembler_x86.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -8404,6 +8404,319 @@
 }
 #endif // _LP64
 
+// IndexOf substring.
+void MacroAssembler::string_indexof(Register str1, Register str2,
+                                    Register cnt1, Register cnt2, Register result,
+                                    XMMRegister vec, Register tmp) {
+  assert(UseSSE42Intrinsics, "SSE4.2 is required");
+
+  Label RELOAD_SUBSTR, PREP_FOR_SCAN, SCAN_TO_SUBSTR,
+        SCAN_SUBSTR, RET_NOT_FOUND, CLEANUP;
+
+  push(str1); // string addr
+  push(str2); // substr addr
+  push(cnt2); // substr count
+  jmpb(PREP_FOR_SCAN);
+
+  // Substr count saved at sp
+  // Substr saved at sp+1*wordSize
+  // String saved at sp+2*wordSize
+
+  // Reload substr for rescan
+  bind(RELOAD_SUBSTR);
+  movl(cnt2, Address(rsp, 0));
+  movptr(str2, Address(rsp, wordSize));
+  // We came here after the beginninig of the substring was
+  // matched but the rest of it was not so we need to search
+  // again. Start from the next element after the previous match.
+  subptr(str1, result); // Restore counter
+  shrl(str1, 1);
+  addl(cnt1, str1);
+  lea(str1, Address(result, 2)); // Reload string
+
+  // Load substr
+  bind(PREP_FOR_SCAN);
+  movdqu(vec, Address(str2, 0));
+  addl(cnt1, 8);  // prime the loop
+  subptr(str1, 16);
+
+  // Scan string for substr in 16-byte vectors
+  bind(SCAN_TO_SUBSTR);
+  subl(cnt1, 8);
+  addptr(str1, 16);
+
+  // pcmpestri
+  //   inputs:
+  //     xmm - substring
+  //     rax - substring length (elements count)
+  //     mem - scaned string
+  //     rdx - string length (elements count)
+  //     0xd - mode: 1100 (substring search) + 01 (unsigned shorts)
+  //   outputs:
+  //     rcx - matched index in string
+  assert(cnt1 == rdx && cnt2 == rax && tmp == rcx, "pcmpestri");
+
+  pcmpestri(vec, Address(str1, 0), 0x0d);
+  jcc(Assembler::above, SCAN_TO_SUBSTR);      // CF == 0 && ZF == 0
+  jccb(Assembler::aboveEqual, RET_NOT_FOUND); // CF == 0
+
+  // Fallthrough: found a potential substr
+
+  // Make sure string is still long enough
+  subl(cnt1, tmp);
+  cmpl(cnt1, cnt2);
+  jccb(Assembler::negative, RET_NOT_FOUND);
+  // Compute start addr of substr
+  lea(str1, Address(str1, tmp, Address::times_2));
+  movptr(result, str1); // save
+
+  // Compare potential substr
+  addl(cnt1, 8);     // prime the loop
+  addl(cnt2, 8);
+  subptr(str1, 16);
+  subptr(str2, 16);
+
+  // Scan 16-byte vectors of string and substr
+  bind(SCAN_SUBSTR);
+  subl(cnt1, 8);
+  subl(cnt2, 8);
+  addptr(str1, 16);
+  addptr(str2, 16);
+  movdqu(vec, Address(str2, 0));
+  pcmpestri(vec, Address(str1, 0), 0x0d);
+  jcc(Assembler::noOverflow, RELOAD_SUBSTR); // OF == 0
+  jcc(Assembler::positive, SCAN_SUBSTR);     // SF == 0
+
+  // Compute substr offset
+  subptr(result, Address(rsp, 2*wordSize));
+  shrl(result, 1); // index
+  jmpb(CLEANUP);
+
+  bind(RET_NOT_FOUND);
+  movl(result, -1);
+
+  bind(CLEANUP);
+  addptr(rsp, 3*wordSize);
+}
+
+// Compare strings.
+void MacroAssembler::string_compare(Register str1, Register str2,
+                                    Register cnt1, Register cnt2, Register result,
+                                    XMMRegister vec1, XMMRegister vec2) {
+  Label LENGTH_DIFF_LABEL, POP_LABEL, DONE_LABEL, WHILE_HEAD_LABEL;
+
+  // Compute the minimum of the string lengths and the
+  // difference of the string lengths (stack).
+  // Do the conditional move stuff
+  movl(result, cnt1);
+  subl(cnt1, cnt2);
+  push(cnt1);
+  if (VM_Version::supports_cmov()) {
+    cmovl(Assembler::lessEqual, cnt2, result);
+  } else {
+    Label GT_LABEL;
+    jccb(Assembler::greater, GT_LABEL);
+    movl(cnt2, result);
+    bind(GT_LABEL);
+  }
+
+  // Is the minimum length zero?
+  testl(cnt2, cnt2);
+  jcc(Assembler::zero, LENGTH_DIFF_LABEL);
+
+  // Load first characters
+  load_unsigned_short(result, Address(str1, 0));
+  load_unsigned_short(cnt1, Address(str2, 0));
+
+  // Compare first characters
+  subl(result, cnt1);
+  jcc(Assembler::notZero,  POP_LABEL);
+  decrementl(cnt2);
+  jcc(Assembler::zero, LENGTH_DIFF_LABEL);
+
+  {
+    // Check after comparing first character to see if strings are equivalent
+    Label LSkip2;
+    // Check if the strings start at same location
+    cmpptr(str1, str2);
+    jccb(Assembler::notEqual, LSkip2);
+
+    // Check if the length difference is zero (from stack)
+    cmpl(Address(rsp, 0), 0x0);
+    jcc(Assembler::equal,  LENGTH_DIFF_LABEL);
+
+    // Strings might not be equivalent
+    bind(LSkip2);
+  }
+
+  // Advance to next character
+  addptr(str1, 2);
+  addptr(str2, 2);
+
+  if (UseSSE42Intrinsics) {
+    // With SSE4.2, use double quad vector compare
+    Label COMPARE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL;
+    // Setup to compare 16-byte vectors
+    movl(cnt1, cnt2);
+    andl(cnt2, 0xfffffff8); // cnt2 holds the vector count
+    andl(cnt1, 0x00000007); // cnt1 holds the tail count
+    testl(cnt2, cnt2);
+    jccb(Assembler::zero, COMPARE_TAIL);
+
+    lea(str2, Address(str2, cnt2, Address::times_2));
+    lea(str1, Address(str1, cnt2, Address::times_2));
+    negptr(cnt2);
+
+    bind(COMPARE_VECTORS);
+    movdqu(vec1, Address(str1, cnt2, Address::times_2));
+    movdqu(vec2, Address(str2, cnt2, Address::times_2));
+    pxor(vec1, vec2);
+    ptest(vec1, vec1);
+    jccb(Assembler::notZero, VECTOR_NOT_EQUAL);
+    addptr(cnt2, 8);
+    jcc(Assembler::notZero, COMPARE_VECTORS);
+    jmpb(COMPARE_TAIL);
+
+    // Mismatched characters in the vectors
+    bind(VECTOR_NOT_EQUAL);
+    lea(str1, Address(str1, cnt2, Address::times_2));
+    lea(str2, Address(str2, cnt2, Address::times_2));
+    movl(cnt1, 8);
+
+    // Compare tail (< 8 chars), or rescan last vectors to
+    // find 1st mismatched characters
+    bind(COMPARE_TAIL);
+    testl(cnt1, cnt1);
+    jccb(Assembler::zero, LENGTH_DIFF_LABEL);
+    movl(cnt2, cnt1);
+    // Fallthru to tail compare
+  }
+
+  // Shift str2 and str1 to the end of the arrays, negate min
+  lea(str1, Address(str1, cnt2, Address::times_2, 0));
+  lea(str2, Address(str2, cnt2, Address::times_2, 0));
+  negptr(cnt2);
+
+    // Compare the rest of the characters
+  bind(WHILE_HEAD_LABEL);
+  load_unsigned_short(result, Address(str1, cnt2, Address::times_2, 0));
+  load_unsigned_short(cnt1, Address(str2, cnt2, Address::times_2, 0));
+  subl(result, cnt1);
+  jccb(Assembler::notZero, POP_LABEL);
+  increment(cnt2);
+  jcc(Assembler::notZero, WHILE_HEAD_LABEL);
+
+  // Strings are equal up to min length.  Return the length difference.
+  bind(LENGTH_DIFF_LABEL);
+  pop(result);
+  jmpb(DONE_LABEL);
+
+  // Discard the stored length difference
+  bind(POP_LABEL);
+  addptr(rsp, wordSize);
+
+  // That's it
+  bind(DONE_LABEL);
+}
+
+// Compare char[] arrays aligned to 4 bytes or substrings.
+void MacroAssembler::char_arrays_equals(bool is_array_equ, Register ary1, Register ary2,
+                                        Register limit, Register result, Register chr,
+                                        XMMRegister vec1, XMMRegister vec2) {
+  Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_VECTORS, COMPARE_CHAR;
+
+  int length_offset  = arrayOopDesc::length_offset_in_bytes();
+  int base_offset    = arrayOopDesc::base_offset_in_bytes(T_CHAR);
+
+  // Check the input args
+  cmpptr(ary1, ary2);
+  jcc(Assembler::equal, TRUE_LABEL);
+
+  if (is_array_equ) {
+    // Need additional checks for arrays_equals.
+    andptr(ary1, ary2);
+    jcc(Assembler::zero, FALSE_LABEL); // One pointer is NULL
+
+    // Check the lengths
+    movl(limit, Address(ary1, length_offset));
+    cmpl(limit, Address(ary2, length_offset));
+    jcc(Assembler::notEqual, FALSE_LABEL);
+  }
+
+  // count == 0
+  testl(limit, limit);
+  jcc(Assembler::zero, TRUE_LABEL);
+
+  if (is_array_equ) {
+    // Load array address
+    lea(ary1, Address(ary1, base_offset));
+    lea(ary2, Address(ary2, base_offset));
+  }
+
+  shll(limit, 1);      // byte count != 0
+  movl(result, limit); // copy
+
+  if (UseSSE42Intrinsics) {
+    // With SSE4.2, use double quad vector compare
+    Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
+    // Compare 16-byte vectors
+    andl(result, 0x0000000e);  //   tail count (in bytes)
+    andl(limit, 0xfffffff0);   // vector count (in bytes)
+    jccb(Assembler::zero, COMPARE_TAIL);
+
+    lea(ary1, Address(ary1, limit, Address::times_1));
+    lea(ary2, Address(ary2, limit, Address::times_1));
+    negptr(limit);
+
+    bind(COMPARE_WIDE_VECTORS);
+    movdqu(vec1, Address(ary1, limit, Address::times_1));
+    movdqu(vec2, Address(ary2, limit, Address::times_1));
+    pxor(vec1, vec2);
+    ptest(vec1, vec1);
+    jccb(Assembler::notZero, FALSE_LABEL);
+    addptr(limit, 16);
+    jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
+
+    bind(COMPARE_TAIL); // limit is zero
+    movl(limit, result);
+    // Fallthru to tail compare
+  }
+
+  // Compare 4-byte vectors
+  andl(limit, 0xfffffffc); // vector count (in bytes)
+  jccb(Assembler::zero, COMPARE_CHAR);
+
+  lea(ary1, Address(ary1, limit, Address::times_1));
+  lea(ary2, Address(ary2, limit, Address::times_1));
+  negptr(limit);
+
+  bind(COMPARE_VECTORS);
+  movl(chr, Address(ary1, limit, Address::times_1));
+  cmpl(chr, Address(ary2, limit, Address::times_1));
+  jccb(Assembler::notEqual, FALSE_LABEL);
+  addptr(limit, 4);
+  jcc(Assembler::notZero, COMPARE_VECTORS);
+
+  // Compare trailing char (final 2 bytes), if any
+  bind(COMPARE_CHAR);
+  testl(result, 0x2);   // tail  char
+  jccb(Assembler::zero, TRUE_LABEL);
+  load_unsigned_short(chr, Address(ary1, 0));
+  load_unsigned_short(limit, Address(ary2, 0));
+  cmpl(chr, limit);
+  jccb(Assembler::notEqual, FALSE_LABEL);
+
+  bind(TRUE_LABEL);
+  movl(result, 1);   // return true
+  jmpb(DONE);
+
+  bind(FALSE_LABEL);
+  xorl(result, result); // return false
+
+  // That's it
+  bind(DONE);
+}
+
 Assembler::Condition MacroAssembler::negate_condition(Assembler::Condition cond) {
   switch (cond) {
     // Note some conditions are synonyms for others
--- a/src/cpu/x86/vm/assembler_x86.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/cpu/x86/vm/assembler_x86.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -2206,6 +2206,20 @@
   void movl2ptr(Register dst, Address src) { LP64_ONLY(movslq(dst, src)) NOT_LP64(movl(dst, src)); }
   void movl2ptr(Register dst, Register src) { LP64_ONLY(movslq(dst, src)) NOT_LP64(if (dst != src) movl(dst, src)); }
 
+  // IndexOf strings.
+  void string_indexof(Register str1, Register str2,
+                      Register cnt1, Register cnt2, Register result,
+                      XMMRegister vec, Register tmp);
+
+  // Compare strings.
+  void string_compare(Register str1, Register str2,
+                      Register cnt1, Register cnt2, Register result,
+                      XMMRegister vec1, XMMRegister vec2);
+
+  // Compare char[] arrays.
+  void char_arrays_equals(bool is_array_equ, Register ary1, Register ary2,
+                          Register limit, Register result, Register chr,
+                          XMMRegister vec1, XMMRegister vec2);
 
 #undef VIRTUAL
 
--- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -1638,7 +1638,7 @@
       jobject2reg_with_patching(k_RInfo, op->info_for_patch());
     } else {
 #ifdef _LP64
-      __ movoop(k_RInfo, k->encoding());
+      __ movoop(k_RInfo, k->constant_encoding());
 #else
       k_RInfo = noreg;
 #endif // _LP64
@@ -1661,7 +1661,7 @@
       assert(data != NULL,       "need data for checkcast");
       assert(data->is_BitData(), "need BitData for checkcast");
       Register mdo  = klass_RInfo;
-      __ movoop(mdo, md->encoding());
+      __ movoop(mdo, md->constant_encoding());
       Address data_addr(mdo, md->byte_offset_of_slot(data, DataLayout::header_offset()));
       int header_bits = DataLayout::flag_mask_to_header_mask(BitData::null_seen_byte_constant());
       __ orl(data_addr, header_bits);
@@ -1679,7 +1679,7 @@
 #ifdef _LP64
         __ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes()));
 #else
-        __ cmpoop(Address(obj, oopDesc::klass_offset_in_bytes()), k->encoding());
+        __ cmpoop(Address(obj, oopDesc::klass_offset_in_bytes()), k->constant_encoding());
 #endif // _LP64
       } else {
         __ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes()));
@@ -1696,7 +1696,7 @@
 #ifdef _LP64
         __ cmpptr(k_RInfo, Address(klass_RInfo, k->super_check_offset()));
 #else
-        __ cmpoop(Address(klass_RInfo, k->super_check_offset()), k->encoding());
+        __ cmpoop(Address(klass_RInfo, k->super_check_offset()), k->constant_encoding());
 #endif // _LP64
         if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() != k->super_check_offset()) {
           __ jcc(Assembler::notEqual, *stub->entry());
@@ -1707,7 +1707,7 @@
 #ifdef _LP64
           __ cmpptr(klass_RInfo, k_RInfo);
 #else
-          __ cmpoop(klass_RInfo, k->encoding());
+          __ cmpoop(klass_RInfo, k->constant_encoding());
 #endif // _LP64
           __ jcc(Assembler::equal, done);
 
@@ -1715,7 +1715,7 @@
 #ifdef _LP64
           __ push(k_RInfo);
 #else
-          __ pushoop(k->encoding());
+          __ pushoop(k->constant_encoding());
 #endif // _LP64
           __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
           __ pop(klass_RInfo);
@@ -1763,7 +1763,7 @@
     if (!k->is_loaded()) {
       jobject2reg_with_patching(k_RInfo, op->info_for_patch());
     } else {
-      LP64_ONLY(__ movoop(k_RInfo, k->encoding()));
+      LP64_ONLY(__ movoop(k_RInfo, k->constant_encoding()));
     }
     assert(obj != k_RInfo, "must be different");
 
@@ -1774,7 +1774,7 @@
       // get object class
       // not a safepoint as obj null check happens earlier
       if (LP64_ONLY(false &&) k->is_loaded()) {
-        NOT_LP64(__ cmpoop(Address(obj, oopDesc::klass_offset_in_bytes()), k->encoding()));
+        NOT_LP64(__ cmpoop(Address(obj, oopDesc::klass_offset_in_bytes()), k->constant_encoding()));
         k_RInfo = noreg;
       } else {
         __ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes()));
@@ -1791,14 +1791,14 @@
 #ifndef _LP64
       if (k->is_loaded()) {
         // See if we get an immediate positive hit
-        __ cmpoop(Address(klass_RInfo, k->super_check_offset()), k->encoding());
+        __ cmpoop(Address(klass_RInfo, k->super_check_offset()), k->constant_encoding());
         __ jcc(Assembler::equal, one);
         if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() == k->super_check_offset()) {
           // check for self
-          __ cmpoop(klass_RInfo, k->encoding());
+          __ cmpoop(klass_RInfo, k->constant_encoding());
           __ jcc(Assembler::equal, one);
           __ push(klass_RInfo);
-          __ pushoop(k->encoding());
+          __ pushoop(k->constant_encoding());
           __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
           __ pop(klass_RInfo);
           __ pop(dst);
@@ -3112,7 +3112,7 @@
     // subtype which we can't check or src is the same array as dst
     // but not necessarily exactly of type default_type.
     Label known_ok, halt;
-    __ movoop(tmp, default_type->encoding());
+    __ movoop(tmp, default_type->constant_encoding());
     if (basic_type != T_OBJECT) {
       __ cmpptr(tmp, dst_klass_addr);
       __ jcc(Assembler::notEqual, halt);
@@ -3200,7 +3200,7 @@
   assert(data->is_CounterData(), "need CounterData for calls");
   assert(op->mdo()->is_single_cpu(),  "mdo must be allocated");
   Register mdo  = op->mdo()->as_register();
-  __ movoop(mdo, md->encoding());
+  __ movoop(mdo, md->constant_encoding());
   Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()));
   __ addl(counter_addr, DataLayout::counter_increment);
   Bytecodes::Code bc = method->java_code_at_bci(bci);
@@ -3240,7 +3240,7 @@
         ciKlass* receiver = vc_data->receiver(i);
         if (receiver == NULL) {
           Address recv_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)));
-          __ movoop(recv_addr, known_klass->encoding());
+          __ movoop(recv_addr, known_klass->constant_encoding());
           Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)));
           __ addl(data_addr, DataLayout::counter_increment);
           return;
--- a/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -994,7 +994,7 @@
   LIR_Opr len = length.result();
   BasicType elem_type = x->elt_type();
 
-  __ oop2reg(ciTypeArrayKlass::make(elem_type)->encoding(), klass_reg);
+  __ oop2reg(ciTypeArrayKlass::make(elem_type)->constant_encoding(), klass_reg);
 
   CodeStub* slow_path = new NewTypeArrayStub(klass_reg, len, reg, info);
   __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, elem_type, klass_reg, slow_path);
--- a/src/cpu/x86/vm/x86_32.ad	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/cpu/x86/vm/x86_32.ad	Wed Sep 30 13:25:39 2009 -0700
@@ -379,7 +379,7 @@
         int format) {
 #ifdef ASSERT
   if (rspec.reloc()->type() == relocInfo::oop_type && d32 != 0 && d32 != (int)Universe::non_oop_word()) {
-    assert(oop(d32)->is_oop() && oop(d32)->is_perm(), "cannot embed non-perm oops in code");
+    assert(oop(d32)->is_oop() && (ScavengeRootsInCode || !oop(d32)->is_scavengable()), "cannot embed scavengable oops in code");
   }
 #endif
   cbuf.relocate(cbuf.inst_mark(), rspec, format);
@@ -3701,458 +3701,6 @@
     }
   %}
 
-  enc_class enc_String_Compare(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2,
-                        eAXRegI tmp3, eBXRegI tmp4, eCXRegI result) %{
-    Label ECX_GOOD_LABEL, LENGTH_DIFF_LABEL,
-          POP_LABEL, DONE_LABEL, CONT_LABEL,
-          WHILE_HEAD_LABEL;
-    MacroAssembler masm(&cbuf);
-
-    XMMRegister tmp1Reg   = as_XMMRegister($tmp1$$reg);
-    XMMRegister tmp2Reg   = as_XMMRegister($tmp2$$reg);
-
-    // Get the first character position in both strings
-    //         [8] char array, [12] offset, [16] count
-    int value_offset  = java_lang_String::value_offset_in_bytes();
-    int offset_offset = java_lang_String::offset_offset_in_bytes();
-    int count_offset  = java_lang_String::count_offset_in_bytes();
-    int base_offset   = arrayOopDesc::base_offset_in_bytes(T_CHAR);
-
-    masm.movptr(rax, Address(rsi, value_offset));
-    masm.movl(rcx, Address(rsi, offset_offset));
-    masm.lea(rax, Address(rax, rcx, Address::times_2, base_offset));
-    masm.movptr(rbx, Address(rdi, value_offset));
-    masm.movl(rcx, Address(rdi, offset_offset));
-    masm.lea(rbx, Address(rbx, rcx, Address::times_2, base_offset));
-
-    // Compute the minimum of the string lengths(rsi) and the
-    // difference of the string lengths (stack)
-
-    if (VM_Version::supports_cmov()) {
-      masm.movl(rdi, Address(rdi, count_offset));
-      masm.movl(rsi, Address(rsi, count_offset));
-      masm.movl(rcx, rdi);
-      masm.subl(rdi, rsi);
-      masm.push(rdi);
-      masm.cmovl(Assembler::lessEqual, rsi, rcx);
-    } else {
-      masm.movl(rdi, Address(rdi, count_offset));
-      masm.movl(rcx, Address(rsi, count_offset));
-      masm.movl(rsi, rdi);
-      masm.subl(rdi, rcx);
-      masm.push(rdi);
-      masm.jccb(Assembler::lessEqual, ECX_GOOD_LABEL);
-      masm.movl(rsi, rcx);
-      // rsi holds min, rcx is unused
-    }
-
-    // Is the minimum length zero?
-    masm.bind(ECX_GOOD_LABEL);
-    masm.testl(rsi, rsi);
-    masm.jcc(Assembler::zero, LENGTH_DIFF_LABEL);
-
-    // Load first characters
-    masm.load_unsigned_short(rcx, Address(rbx, 0));
-    masm.load_unsigned_short(rdi, Address(rax, 0));
-
-    // Compare first characters
-    masm.subl(rcx, rdi);
-    masm.jcc(Assembler::notZero,  POP_LABEL);
-    masm.decrementl(rsi);
-    masm.jcc(Assembler::zero, LENGTH_DIFF_LABEL);
-
-    {
-      // Check after comparing first character to see if strings are equivalent
-      Label LSkip2;
-      // Check if the strings start at same location
-      masm.cmpptr(rbx,rax);
-      masm.jccb(Assembler::notEqual, LSkip2);
-
-      // Check if the length difference is zero (from stack)
-      masm.cmpl(Address(rsp, 0), 0x0);
-      masm.jcc(Assembler::equal,  LENGTH_DIFF_LABEL);
-
-      // Strings might not be equivalent
-      masm.bind(LSkip2);
-    }
-
-   // Advance to next character
-    masm.addptr(rax, 2);
-    masm.addptr(rbx, 2);
-
-    if (UseSSE42Intrinsics) {
-      // With SSE4.2, use double quad vector compare
-      Label COMPARE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL;
-      // Setup to compare 16-byte vectors
-      masm.movl(rdi, rsi);
-      masm.andl(rsi, 0xfffffff8); // rsi holds the vector count
-      masm.andl(rdi, 0x00000007); // rdi holds the tail count
-      masm.testl(rsi, rsi);
-      masm.jccb(Assembler::zero, COMPARE_TAIL);
-
-      masm.lea(rax, Address(rax, rsi, Address::times_2));
-      masm.lea(rbx, Address(rbx, rsi, Address::times_2));
-      masm.negl(rsi);
-
-      masm.bind(COMPARE_VECTORS);
-      masm.movdqu(tmp1Reg, Address(rax, rsi, Address::times_2));
-      masm.movdqu(tmp2Reg, Address(rbx, rsi, Address::times_2));
-      masm.pxor(tmp1Reg, tmp2Reg);
-      masm.ptest(tmp1Reg, tmp1Reg);
-      masm.jccb(Assembler::notZero, VECTOR_NOT_EQUAL);
-      masm.addl(rsi, 8);
-      masm.jcc(Assembler::notZero, COMPARE_VECTORS);
-      masm.jmpb(COMPARE_TAIL);
-
-      // Mismatched characters in the vectors
-      masm.bind(VECTOR_NOT_EQUAL);
-      masm.lea(rax, Address(rax, rsi, Address::times_2));
-      masm.lea(rbx, Address(rbx, rsi, Address::times_2));
-      masm.movl(rdi, 8);
-
-      // Compare tail (< 8 chars), or rescan last vectors to
-      // find 1st mismatched characters
-      masm.bind(COMPARE_TAIL);
-      masm.testl(rdi, rdi);
-      masm.jccb(Assembler::zero, LENGTH_DIFF_LABEL);
-      masm.movl(rsi, rdi);
-      // Fallthru to tail compare
-    }
-
-    //Shift rax, and rbx, to the end of the arrays, negate min
-    masm.lea(rax, Address(rax, rsi, Address::times_2, 0));
-    masm.lea(rbx, Address(rbx, rsi, Address::times_2, 0));
-    masm.negl(rsi);
-
-    // Compare the rest of the characters
-    masm.bind(WHILE_HEAD_LABEL);
-    masm.load_unsigned_short(rcx, Address(rbx, rsi, Address::times_2, 0));
-    masm.load_unsigned_short(rdi, Address(rax, rsi, Address::times_2, 0));
-    masm.subl(rcx, rdi);
-    masm.jccb(Assembler::notZero, POP_LABEL);
-    masm.incrementl(rsi);
-    masm.jcc(Assembler::notZero, WHILE_HEAD_LABEL);
-
-    // Strings are equal up to min length.  Return the length difference.
-    masm.bind(LENGTH_DIFF_LABEL);
-    masm.pop(rcx);
-    masm.jmpb(DONE_LABEL);
-
-    // Discard the stored length difference
-    masm.bind(POP_LABEL);
-    masm.addptr(rsp, 4);
-
-    // That's it
-    masm.bind(DONE_LABEL);
-  %}
-
- enc_class enc_String_Equals(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2,
-                       eBXRegI tmp3, eCXRegI tmp4, eAXRegI result) %{
-    Label RET_TRUE, RET_FALSE, DONE, COMPARE_VECTORS, COMPARE_CHAR;
-    MacroAssembler masm(&cbuf);
-
-    XMMRegister tmp1Reg   = as_XMMRegister($tmp1$$reg);
-    XMMRegister tmp2Reg   = as_XMMRegister($tmp2$$reg);
-
-    int value_offset  = java_lang_String::value_offset_in_bytes();
-    int offset_offset = java_lang_String::offset_offset_in_bytes();
-    int count_offset  = java_lang_String::count_offset_in_bytes();
-    int base_offset   = arrayOopDesc::base_offset_in_bytes(T_CHAR);
-
-    // does source == target string?
-    masm.cmpptr(rdi, rsi);
-    masm.jcc(Assembler::equal, RET_TRUE);
-
-    // get and compare counts
-    masm.movl(rcx, Address(rdi, count_offset));
-    masm.movl(rax, Address(rsi, count_offset));
-    masm.cmpl(rcx, rax);
-    masm.jcc(Assembler::notEqual, RET_FALSE);
-    masm.testl(rax, rax);
-    masm.jcc(Assembler::zero, RET_TRUE);
-
-    // get source string offset and value
-    masm.movptr(rbx, Address(rsi, value_offset));
-    masm.movl(rax, Address(rsi, offset_offset));
-    masm.leal(rsi, Address(rbx, rax, Address::times_2, base_offset));
-
-    // get compare string offset and value
-    masm.movptr(rbx, Address(rdi, value_offset));
-    masm.movl(rax, Address(rdi, offset_offset));
-    masm.leal(rdi, Address(rbx, rax, Address::times_2, base_offset));
-
-    // Set byte count
-    masm.shll(rcx, 1);
-    masm.movl(rax, rcx);
-
-    if (UseSSE42Intrinsics) {
-      // With SSE4.2, use double quad vector compare
-      Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
-      // Compare 16-byte vectors
-      masm.andl(rcx, 0xfffffff0);  // vector count (in bytes)
-      masm.andl(rax, 0x0000000e);  // tail count (in bytes)
-      masm.testl(rcx, rcx);
-      masm.jccb(Assembler::zero, COMPARE_TAIL);
-      masm.lea(rdi, Address(rdi, rcx, Address::times_1));
-      masm.lea(rsi, Address(rsi, rcx, Address::times_1));
-      masm.negl(rcx);
-
-      masm.bind(COMPARE_WIDE_VECTORS);
-      masm.movdqu(tmp1Reg, Address(rdi, rcx, Address::times_1));
-      masm.movdqu(tmp2Reg, Address(rsi, rcx, Address::times_1));
-      masm.pxor(tmp1Reg, tmp2Reg);
-      masm.ptest(tmp1Reg, tmp1Reg);
-      masm.jccb(Assembler::notZero, RET_FALSE);
-      masm.addl(rcx, 16);
-      masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
-      masm.bind(COMPARE_TAIL);
-      masm.movl(rcx, rax);
-      // Fallthru to tail compare
-    }
-
-    // Compare 4-byte vectors
-    masm.andl(rcx, 0xfffffffc);  // vector count (in bytes)
-    masm.andl(rax, 0x00000002);  // tail char (in bytes)
-    masm.testl(rcx, rcx);
-    masm.jccb(Assembler::zero, COMPARE_CHAR);
-    masm.lea(rdi, Address(rdi, rcx, Address::times_1));
-    masm.lea(rsi, Address(rsi, rcx, Address::times_1));
-    masm.negl(rcx);
-
-    masm.bind(COMPARE_VECTORS);
-    masm.movl(rbx, Address(rdi, rcx, Address::times_1));
-    masm.cmpl(rbx, Address(rsi, rcx, Address::times_1));
-    masm.jccb(Assembler::notEqual, RET_FALSE);
-    masm.addl(rcx, 4);
-    masm.jcc(Assembler::notZero, COMPARE_VECTORS);
-
-    // Compare trailing char (final 2 bytes), if any
-    masm.bind(COMPARE_CHAR);
-    masm.testl(rax, rax);
-    masm.jccb(Assembler::zero, RET_TRUE);
-    masm.load_unsigned_short(rbx, Address(rdi, 0));
-    masm.load_unsigned_short(rcx, Address(rsi, 0));
-    masm.cmpl(rbx, rcx);
-    masm.jccb(Assembler::notEqual, RET_FALSE);
-
-    masm.bind(RET_TRUE);
-    masm.movl(rax, 1);   // return true
-    masm.jmpb(DONE);
-
-    masm.bind(RET_FALSE);
-    masm.xorl(rax, rax); // return false
-
-    masm.bind(DONE);
-    %}
-
- enc_class enc_String_IndexOf(eSIRegP str1, eDIRegP str2, regXD tmp1, eAXRegI tmp2,
-                        eCXRegI tmp3, eDXRegI tmp4, eBXRegI result) %{
-    // SSE4.2 version
-    Label LOAD_SUBSTR, PREP_FOR_SCAN, SCAN_TO_SUBSTR,
-          SCAN_SUBSTR, RET_NEG_ONE, RET_NOT_FOUND, CLEANUP, DONE;
-    MacroAssembler masm(&cbuf);
-
-    XMMRegister tmp1Reg   = as_XMMRegister($tmp1$$reg);
-
-    // Get the first character position in both strings
-    //         [8] char array, [12] offset, [16] count
-    int value_offset  = java_lang_String::value_offset_in_bytes();
-    int offset_offset = java_lang_String::offset_offset_in_bytes();
-    int count_offset  = java_lang_String::count_offset_in_bytes();
-    int base_offset   = arrayOopDesc::base_offset_in_bytes(T_CHAR);
-
-    // Get counts for string and substr
-    masm.movl(rdx, Address(rsi, count_offset));
-    masm.movl(rax, Address(rdi, count_offset));
-    // Check for substr count > string count
-    masm.cmpl(rax, rdx);
-    masm.jcc(Assembler::greater, RET_NEG_ONE);
-
-    // Start the indexOf operation
-    // Get start addr of string
-    masm.movptr(rbx, Address(rsi, value_offset));
-    masm.movl(rcx, Address(rsi, offset_offset));
-    masm.lea(rsi, Address(rbx, rcx, Address::times_2, base_offset));
-    masm.push(rsi);
-
-    // Get start addr of substr
-    masm.movptr(rbx, Address(rdi, value_offset));
-    masm.movl(rcx, Address(rdi, offset_offset));
-    masm.lea(rdi, Address(rbx, rcx, Address::times_2, base_offset));
-    masm.push(rdi);
-    masm.push(rax);
-    masm.jmpb(PREP_FOR_SCAN);
-
-    // Substr count saved at sp
-    // Substr saved at sp+4
-    // String saved at sp+8
-
-    // Prep to load substr for scan
-    masm.bind(LOAD_SUBSTR);
-    masm.movptr(rdi, Address(rsp, 4));
-    masm.movl(rax, Address(rsp, 0));
-
-    // Load substr
-    masm.bind(PREP_FOR_SCAN);
-    masm.movdqu(tmp1Reg, Address(rdi, 0));
-    masm.addl(rdx, 8);        // prime the loop
-    masm.subptr(rsi, 16);
-
-    // Scan string for substr in 16-byte vectors
-    masm.bind(SCAN_TO_SUBSTR);
-    masm.subl(rdx, 8);
-    masm.addptr(rsi, 16);
-    masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d);
-    masm.jcc(Assembler::above, SCAN_TO_SUBSTR);     // CF == 0 && ZF == 0
-    masm.jccb(Assembler::aboveEqual, RET_NOT_FOUND); // CF == 0
-
-    // Fallthru: found a potential substr
-
-    // Make sure string is still long enough
-    masm.subl(rdx, rcx);
-    masm.cmpl(rdx, rax);
-    masm.jccb(Assembler::negative, RET_NOT_FOUND);
-    // Compute start addr of substr
-    masm.lea(rsi, Address(rsi, rcx, Address::times_2));
-    masm.movptr(rbx, rsi);
-
-    // Compare potential substr
-    masm.addl(rdx, 8);        // prime the loop
-    masm.addl(rax, 8);
-    masm.subptr(rsi, 16);
-    masm.subptr(rdi, 16);
-
-    // Scan 16-byte vectors of string and substr
-    masm.bind(SCAN_SUBSTR);
-    masm.subl(rax, 8);
-    masm.subl(rdx, 8);
-    masm.addptr(rsi, 16);
-    masm.addptr(rdi, 16);
-    masm.movdqu(tmp1Reg, Address(rdi, 0));
-    masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d);
-    masm.jcc(Assembler::noOverflow, LOAD_SUBSTR);   // OF == 0
-    masm.jcc(Assembler::positive, SCAN_SUBSTR);     // SF == 0
-
-    // Compute substr offset
-    masm.movptr(rsi, Address(rsp, 8));
-    masm.subptr(rbx, rsi);
-    masm.shrl(rbx, 1);
-    masm.jmpb(CLEANUP);
-
-    masm.bind(RET_NEG_ONE);
-    masm.movl(rbx, -1);
-    masm.jmpb(DONE);
-
-    masm.bind(RET_NOT_FOUND);
-    masm.movl(rbx, -1);
-
-    masm.bind(CLEANUP);
-    masm.addptr(rsp, 12);
-
-    masm.bind(DONE);
-  %}
-
-  enc_class enc_Array_Equals(eDIRegP ary1, eSIRegP ary2, regXD tmp1, regXD tmp2,
-                             eBXRegI tmp3, eDXRegI tmp4, eAXRegI result) %{
-    Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_VECTORS, COMPARE_CHAR;
-    MacroAssembler masm(&cbuf);
-
-    XMMRegister tmp1Reg   = as_XMMRegister($tmp1$$reg);
-    XMMRegister tmp2Reg   = as_XMMRegister($tmp2$$reg);
-    Register ary1Reg      = as_Register($ary1$$reg);
-    Register ary2Reg      = as_Register($ary2$$reg);
-    Register tmp3Reg      = as_Register($tmp3$$reg);
-    Register tmp4Reg      = as_Register($tmp4$$reg);
-    Register resultReg    = as_Register($result$$reg);
-
-    int length_offset  = arrayOopDesc::length_offset_in_bytes();
-    int base_offset    = arrayOopDesc::base_offset_in_bytes(T_CHAR);
-
-    // Check the input args
-    masm.cmpptr(ary1Reg, ary2Reg);
-    masm.jcc(Assembler::equal, TRUE_LABEL);
-    masm.testptr(ary1Reg, ary1Reg);
-    masm.jcc(Assembler::zero, FALSE_LABEL);
-    masm.testptr(ary2Reg, ary2Reg);
-    masm.jcc(Assembler::zero, FALSE_LABEL);
-
-    // Check the lengths
-    masm.movl(tmp4Reg, Address(ary1Reg, length_offset));
-    masm.movl(resultReg, Address(ary2Reg, length_offset));
-    masm.cmpl(tmp4Reg, resultReg);
-    masm.jcc(Assembler::notEqual, FALSE_LABEL);
-    masm.testl(resultReg, resultReg);
-    masm.jcc(Assembler::zero, TRUE_LABEL);
-
-    // Load array addrs
-    masm.lea(ary1Reg, Address(ary1Reg, base_offset));
-    masm.lea(ary2Reg, Address(ary2Reg, base_offset));
-
-    // Set byte count
-    masm.shll(tmp4Reg, 1);
-    masm.movl(resultReg, tmp4Reg);
-
-    if (UseSSE42Intrinsics) {
-      // With SSE4.2, use double quad vector compare
-      Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
-      // Compare 16-byte vectors
-      masm.andl(tmp4Reg, 0xfffffff0);    // vector count (in bytes)
-      masm.andl(resultReg, 0x0000000e);  // tail count (in bytes)
-      masm.testl(tmp4Reg, tmp4Reg);
-      masm.jccb(Assembler::zero, COMPARE_TAIL);
-      masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
-      masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
-      masm.negl(tmp4Reg);
-
-      masm.bind(COMPARE_WIDE_VECTORS);
-      masm.movdqu(tmp1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
-      masm.movdqu(tmp2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
-      masm.pxor(tmp1Reg, tmp2Reg);
-      masm.ptest(tmp1Reg, tmp1Reg);
-
-      masm.jccb(Assembler::notZero, FALSE_LABEL);
-      masm.addl(tmp4Reg, 16);
-      masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
-      masm.bind(COMPARE_TAIL);
-      masm.movl(tmp4Reg, resultReg);
-      // Fallthru to tail compare
-    }
-
-    // Compare 4-byte vectors
-    masm.andl(tmp4Reg, 0xfffffffc);    // vector count (in bytes)
-    masm.andl(resultReg, 0x00000002);  // tail char (in bytes)
-    masm.testl(tmp4Reg, tmp4Reg);
-    masm.jccb(Assembler::zero, COMPARE_CHAR);
-    masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
-    masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
-    masm.negl(tmp4Reg);
-
-    masm.bind(COMPARE_VECTORS);
-    masm.movl(tmp3Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
-    masm.cmpl(tmp3Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
-    masm.jccb(Assembler::notEqual, FALSE_LABEL);
-    masm.addl(tmp4Reg, 4);
-    masm.jcc(Assembler::notZero, COMPARE_VECTORS);
-
-    // Compare trailing char (final 2 bytes), if any
-    masm.bind(COMPARE_CHAR);
-    masm.testl(resultReg, resultReg);
-    masm.jccb(Assembler::zero, TRUE_LABEL);
-    masm.load_unsigned_short(tmp3Reg, Address(ary1Reg, 0));
-    masm.load_unsigned_short(tmp4Reg, Address(ary2Reg, 0));
-    masm.cmpl(tmp3Reg, tmp4Reg);
-    masm.jccb(Assembler::notEqual, FALSE_LABEL);
-
-    masm.bind(TRUE_LABEL);
-    masm.movl(resultReg, 1);   // return true
-    masm.jmpb(DONE);
-
-    masm.bind(FALSE_LABEL);
-    masm.xorl(resultReg, resultReg); // return false
-
-    // That's it
-    masm.bind(DONE);
-  %}
 
   enc_class enc_pop_rdx() %{
     emit_opcode(cbuf,0x5A);
@@ -12718,48 +12266,64 @@
   ins_pipe( pipe_slow );
 %}
 
-instruct string_compare(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2,
-                        eAXRegI tmp3, eBXRegI tmp4, eCXRegI result, eFlagsReg cr) %{
-  match(Set result (StrComp str1 str2));
-  effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr);
-  //ins_cost(300);
-
-  format %{ "String Compare $str1,$str2 -> $result    // KILL EAX, EBX" %}
-  ins_encode( enc_String_Compare(str1, str2, tmp1, tmp2, tmp3, tmp4, result) );
+instruct string_compare(eDIRegP str1, eCXRegI cnt1, eSIRegP str2, eBXRegI cnt2,
+                        eAXRegI result, regXD tmp1, regXD tmp2, eFlagsReg cr) %{
+  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
+  effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
+
+  format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result   // KILL $tmp1, $tmp2" %}
+  ins_encode %{
+    __ string_compare($str1$$Register, $str2$$Register,
+                      $cnt1$$Register, $cnt2$$Register, $result$$Register,
+                      $tmp1$$XMMRegister, $tmp2$$XMMRegister);
+  %}
   ins_pipe( pipe_slow );
 %}
 
 // fast string equals
-instruct string_equals(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2,
-                       eBXRegI tmp3, eCXRegI tmp4, eAXRegI result, eFlagsReg cr) %{
-  match(Set result (StrEquals str1 str2));
-  effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr);
-
-  format %{ "String Equals $str1,$str2 -> $result    // KILL EBX, ECX" %}
-  ins_encode( enc_String_Equals(tmp1, tmp2, str1, str2, tmp3, tmp4, result) );
-  ins_pipe( pipe_slow );
-%}
-
-instruct string_indexof(eSIRegP str1, eDIRegP str2, regXD tmp1, eAXRegI tmp2,
-                        eCXRegI tmp3, eDXRegI tmp4, eBXRegI result, eFlagsReg cr) %{
+instruct string_equals(eDIRegP str1, eSIRegP str2, eCXRegI cnt, eAXRegI result,
+                       regXD tmp1, regXD tmp2, eBXRegI tmp3, eFlagsReg cr) %{
+  match(Set result (StrEquals (Binary str1 str2) cnt));
+  effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp3, KILL cr);
+
+  format %{ "String Equals $str1,$str2,$cnt -> $result    // KILL $tmp1, $tmp2, $tmp3" %}
+  ins_encode %{
+    __ char_arrays_equals(false, $str1$$Register, $str2$$Register,
+                          $cnt$$Register, $result$$Register, $tmp3$$Register,
+                          $tmp1$$XMMRegister, $tmp2$$XMMRegister);
+  %}
+  ins_pipe( pipe_slow );
+%}
+
+instruct string_indexof(eDIRegP str1, eDXRegI cnt1, eSIRegP str2, eAXRegI cnt2,
+                        eBXRegI result, regXD tmp1, eCXRegI tmp2, eFlagsReg cr) %{
   predicate(UseSSE42Intrinsics);
-  match(Set result (StrIndexOf str1 str2));
-  effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, KILL tmp2, KILL tmp3, KILL tmp4, KILL cr);
-
-  format %{ "String IndexOf $str1,$str2 -> $result    // KILL EAX, ECX, EDX" %}
-  ins_encode( enc_String_IndexOf(str1, str2, tmp1, tmp2, tmp3, tmp4, result) );
+  match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2)));
+  effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL tmp2, KILL cr);
+
+  format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result   // KILL $tmp2, $tmp1" %}
+  ins_encode %{
+    __ string_indexof($str1$$Register, $str2$$Register,
+                      $cnt1$$Register, $cnt2$$Register, $result$$Register,
+                      $tmp1$$XMMRegister, $tmp2$$Register);
+  %}
   ins_pipe( pipe_slow );
 %}
 
 // fast array equals
-instruct array_equals(eDIRegP ary1, eSIRegP ary2, regXD tmp1, regXD tmp2, eBXRegI tmp3,
-                      eDXRegI tmp4, eAXRegI result, eFlagsReg cr) %{
+instruct array_equals(eDIRegP ary1, eSIRegP ary2, eAXRegI result,
+                      regXD tmp1, regXD tmp2, eCXRegI tmp3, eBXRegI tmp4, eFlagsReg cr)
+%{
   match(Set result (AryEq ary1 ary2));
   effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr);
   //ins_cost(300);
 
-  format %{ "Array Equals $ary1,$ary2 -> $result    // KILL EBX, EDX" %}
-  ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, tmp3, tmp4, result) );
+  format %{ "Array Equals $ary1,$ary2 -> $result   // KILL $tmp1, $tmp2, $tmp3, $tmp4" %}
+  ins_encode %{
+    __ char_arrays_equals(true, $ary1$$Register, $ary2$$Register,
+                          $tmp3$$Register, $result$$Register, $tmp4$$Register,
+                          $tmp1$$XMMRegister, $tmp2$$XMMRegister);
+  %}
   ins_pipe( pipe_slow );
 %}
 
--- a/src/cpu/x86/vm/x86_64.ad	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/cpu/x86/vm/x86_64.ad	Wed Sep 30 13:25:39 2009 -0700
@@ -683,7 +683,7 @@
 #ifdef ASSERT
   if (rspec.reloc()->type() == relocInfo::oop_type &&
       d32 != 0 && d32 != (intptr_t) Universe::non_oop_word()) {
-    assert(oop((intptr_t)d32)->is_oop() && oop((intptr_t)d32)->is_perm(), "cannot embed non-perm oops in code");
+    assert(oop((intptr_t)d32)->is_oop() && (ScavengeRootsInCode || !oop((intptr_t)d32)->is_scavengable()), "cannot embed scavengable oops in code");
   }
 #endif
   cbuf.relocate(cbuf.inst_mark(), rspec, format);
@@ -721,8 +721,8 @@
 #ifdef ASSERT
   if (rspec.reloc()->type() == relocInfo::oop_type &&
       d64 != 0 && d64 != (int64_t) Universe::non_oop_word()) {
-    assert(oop(d64)->is_oop() && oop(d64)->is_perm(),
-           "cannot embed non-perm oops in code");
+    assert(oop(d64)->is_oop() && (ScavengeRootsInCode || !oop(d64)->is_scavengable()),
+           "cannot embed scavengable oops in code");
   }
 #endif
   cbuf.relocate(cbuf.inst_mark(), rspec, format);
@@ -3701,448 +3701,6 @@
     }
   %}
 
-  enc_class enc_String_Compare(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2,
-                        rax_RegI tmp3, rbx_RegI tmp4, rcx_RegI result) %{
-    Label RCX_GOOD_LABEL, LENGTH_DIFF_LABEL,
-          POP_LABEL, DONE_LABEL, CONT_LABEL,
-          WHILE_HEAD_LABEL;
-    MacroAssembler masm(&cbuf);
-
-    XMMRegister tmp1Reg   = as_XMMRegister($tmp1$$reg);
-    XMMRegister tmp2Reg   = as_XMMRegister($tmp2$$reg);
-
-    // Get the first character position in both strings
-    //         [8] char array, [12] offset, [16] count
-    int value_offset  = java_lang_String::value_offset_in_bytes();
-    int offset_offset = java_lang_String::offset_offset_in_bytes();
-    int count_offset  = java_lang_String::count_offset_in_bytes();
-    int base_offset   = arrayOopDesc::base_offset_in_bytes(T_CHAR);
-
-    masm.load_heap_oop(rax, Address(rsi, value_offset));
-    masm.movl(rcx, Address(rsi, offset_offset));
-    masm.lea(rax, Address(rax, rcx, Address::times_2, base_offset));
-    masm.load_heap_oop(rbx, Address(rdi, value_offset));
-    masm.movl(rcx, Address(rdi, offset_offset));
-    masm.lea(rbx, Address(rbx, rcx, Address::times_2, base_offset));
-
-    // Compute the minimum of the string lengths(rsi) and the
-    // difference of the string lengths (stack)
-
-    // do the conditional move stuff
-    masm.movl(rdi, Address(rdi, count_offset));
-    masm.movl(rsi, Address(rsi, count_offset));
-    masm.movl(rcx, rdi);
-    masm.subl(rdi, rsi);
-    masm.push(rdi);
-    masm.cmov(Assembler::lessEqual, rsi, rcx);
-
-    // Is the minimum length zero?
-    masm.bind(RCX_GOOD_LABEL);
-    masm.testl(rsi, rsi);
-    masm.jcc(Assembler::zero, LENGTH_DIFF_LABEL);
-
-    // Load first characters
-    masm.load_unsigned_short(rcx, Address(rbx, 0));
-    masm.load_unsigned_short(rdi, Address(rax, 0));
-
-    // Compare first characters
-    masm.subl(rcx, rdi);
-    masm.jcc(Assembler::notZero,  POP_LABEL);
-    masm.decrementl(rsi);
-    masm.jcc(Assembler::zero, LENGTH_DIFF_LABEL);
-
-    {
-      // Check after comparing first character to see if strings are equivalent
-      Label LSkip2;
-      // Check if the strings start at same location
-      masm.cmpptr(rbx, rax);
-      masm.jccb(Assembler::notEqual, LSkip2);
-
-      // Check if the length difference is zero (from stack)
-      masm.cmpl(Address(rsp, 0), 0x0);
-      masm.jcc(Assembler::equal,  LENGTH_DIFF_LABEL);
-
-      // Strings might not be equivalent
-      masm.bind(LSkip2);
-    }
-
-    // Advance to next character
-    masm.addptr(rax, 2);
-    masm.addptr(rbx, 2);
-
-    if (UseSSE42Intrinsics) {
-      // With SSE4.2, use double quad vector compare
-      Label COMPARE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL;
-      // Setup to compare 16-byte vectors
-      masm.movl(rdi, rsi);
-      masm.andl(rsi, 0xfffffff8); // rsi holds the vector count
-      masm.andl(rdi, 0x00000007); // rdi holds the tail count
-      masm.testl(rsi, rsi);
-      masm.jccb(Assembler::zero, COMPARE_TAIL);
-
-      masm.lea(rax, Address(rax, rsi, Address::times_2));
-      masm.lea(rbx, Address(rbx, rsi, Address::times_2));
-      masm.negptr(rsi);
-
-      masm.bind(COMPARE_VECTORS);
-      masm.movdqu(tmp1Reg, Address(rax, rsi, Address::times_2));
-      masm.movdqu(tmp2Reg, Address(rbx, rsi, Address::times_2));
-      masm.pxor(tmp1Reg, tmp2Reg);
-      masm.ptest(tmp1Reg, tmp1Reg);
-      masm.jccb(Assembler::notZero, VECTOR_NOT_EQUAL);
-      masm.addptr(rsi, 8);
-      masm.jcc(Assembler::notZero, COMPARE_VECTORS);
-      masm.jmpb(COMPARE_TAIL);
-
-      // Mismatched characters in the vectors
-      masm.bind(VECTOR_NOT_EQUAL);
-      masm.lea(rax, Address(rax, rsi, Address::times_2));
-      masm.lea(rbx, Address(rbx, rsi, Address::times_2));
-      masm.movl(rdi, 8);
-
-      // Compare tail (< 8 chars), or rescan last vectors to
-      // find 1st mismatched characters
-      masm.bind(COMPARE_TAIL);
-      masm.testl(rdi, rdi);
-      masm.jccb(Assembler::zero, LENGTH_DIFF_LABEL);
-      masm.movl(rsi, rdi);
-      // Fallthru to tail compare
-    }
-
-    // Shift RAX and RBX to the end of the arrays, negate min
-    masm.lea(rax, Address(rax, rsi, Address::times_2, 0));
-    masm.lea(rbx, Address(rbx, rsi, Address::times_2, 0));
-    masm.negptr(rsi);
-
-    // Compare the rest of the characters
-    masm.bind(WHILE_HEAD_LABEL);
-    masm.load_unsigned_short(rcx, Address(rbx, rsi, Address::times_2, 0));
-    masm.load_unsigned_short(rdi, Address(rax, rsi, Address::times_2, 0));
-    masm.subl(rcx, rdi);
-    masm.jccb(Assembler::notZero, POP_LABEL);
-    masm.increment(rsi);
-    masm.jcc(Assembler::notZero, WHILE_HEAD_LABEL);
-
-    // Strings are equal up to min length.  Return the length difference.
-    masm.bind(LENGTH_DIFF_LABEL);
-    masm.pop(rcx);
-    masm.jmpb(DONE_LABEL);
-
-    // Discard the stored length difference
-    masm.bind(POP_LABEL);
-    masm.addptr(rsp, 8);
-
-    // That's it
-    masm.bind(DONE_LABEL);
-  %}
-
- enc_class enc_String_IndexOf(rsi_RegP str1, rdi_RegP str2, regD tmp1, rax_RegI tmp2,
-                        rcx_RegI tmp3, rdx_RegI tmp4, rbx_RegI result) %{
-    // SSE4.2 version
-    Label LOAD_SUBSTR, PREP_FOR_SCAN, SCAN_TO_SUBSTR,
-          SCAN_SUBSTR, RET_NEG_ONE, RET_NOT_FOUND, CLEANUP, DONE;
-    MacroAssembler masm(&cbuf);
-
-    XMMRegister tmp1Reg   = as_XMMRegister($tmp1$$reg);
-
-    // Get the first character position in both strings
-    //         [8] char array, [12] offset, [16] count
-    int value_offset  = java_lang_String::value_offset_in_bytes();
-    int offset_offset = java_lang_String::offset_offset_in_bytes();
-    int count_offset  = java_lang_String::count_offset_in_bytes();
-    int base_offset   = arrayOopDesc::base_offset_in_bytes(T_CHAR);
-
-    // Get counts for string and substr
-    masm.movl(rdx, Address(rsi, count_offset));
-    masm.movl(rax, Address(rdi, count_offset));
-    // Check for substr count > string count
-    masm.cmpl(rax, rdx);
-    masm.jcc(Assembler::greater, RET_NEG_ONE);
-
-    // Start the indexOf operation
-    // Get start addr of string
-    masm.load_heap_oop(rbx, Address(rsi, value_offset));
-    masm.movl(rcx, Address(rsi, offset_offset));
-    masm.lea(rsi, Address(rbx, rcx, Address::times_2, base_offset));
-    masm.push(rsi);
-
-    // Get start addr of substr
-    masm.load_heap_oop(rbx, Address(rdi, value_offset));
-    masm.movl(rcx, Address(rdi, offset_offset));
-    masm.lea(rdi, Address(rbx, rcx, Address::times_2, base_offset));
-    masm.push(rdi);
-    masm.push(rax);
-    masm.jmpb(PREP_FOR_SCAN);
-
-    // Substr count saved at sp
-    // Substr saved at sp+8
-    // String saved at sp+16
-
-    // Prep to load substr for scan
-    masm.bind(LOAD_SUBSTR);
-    masm.movptr(rdi, Address(rsp, 8));
-    masm.movl(rax, Address(rsp, 0));
-
-    // Load substr
-    masm.bind(PREP_FOR_SCAN);
-    masm.movdqu(tmp1Reg, Address(rdi, 0));
-    masm.addq(rdx, 8);    // prime the loop
-    masm.subptr(rsi, 16);
-
-    // Scan string for substr in 16-byte vectors
-    masm.bind(SCAN_TO_SUBSTR);
-    masm.subq(rdx, 8);
-    masm.addptr(rsi, 16);
-    masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d);
-    masm.jcc(Assembler::above, SCAN_TO_SUBSTR);
-    masm.jccb(Assembler::aboveEqual, RET_NOT_FOUND);
-
-    // Fallthru: found a potential substr
-
-    //Make sure string is still long enough
-    masm.subl(rdx, rcx);
-    masm.cmpl(rdx, rax);
-    masm.jccb(Assembler::negative, RET_NOT_FOUND);
-    // Compute start addr of substr
-    masm.lea(rsi, Address(rsi, rcx, Address::times_2));
-    masm.movptr(rbx, rsi);
-
-    // Compare potential substr
-    masm.addq(rdx, 8);        // prime the loop
-    masm.addq(rax, 8);
-    masm.subptr(rsi, 16);
-    masm.subptr(rdi, 16);
-
-    // Scan 16-byte vectors of string and substr
-    masm.bind(SCAN_SUBSTR);
-    masm.subq(rax, 8);
-    masm.subq(rdx, 8);
-    masm.addptr(rsi, 16);
-    masm.addptr(rdi, 16);
-    masm.movdqu(tmp1Reg, Address(rdi, 0));
-    masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d);
-    masm.jcc(Assembler::noOverflow, LOAD_SUBSTR);   // OF == 0
-    masm.jcc(Assembler::positive, SCAN_SUBSTR);     // SF == 0
-
-    // Compute substr offset
-    masm.movptr(rsi, Address(rsp, 16));
-    masm.subptr(rbx, rsi);
-    masm.shrl(rbx, 1);
-    masm.jmpb(CLEANUP);
-
-    masm.bind(RET_NEG_ONE);
-    masm.movl(rbx, -1);
-    masm.jmpb(DONE);
-
-    masm.bind(RET_NOT_FOUND);
-    masm.movl(rbx, -1);
-
-    masm.bind(CLEANUP);
-    masm.addptr(rsp, 24);
-
-    masm.bind(DONE);
-  %}
-
-  enc_class enc_String_Equals(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2,
-                              rbx_RegI tmp3, rcx_RegI tmp2, rax_RegI result) %{
-    Label RET_TRUE, RET_FALSE, DONE, COMPARE_VECTORS, COMPARE_CHAR;
-    MacroAssembler masm(&cbuf);
-
-    XMMRegister tmp1Reg   = as_XMMRegister($tmp1$$reg);
-    XMMRegister tmp2Reg   = as_XMMRegister($tmp2$$reg);
-
-    int value_offset  = java_lang_String::value_offset_in_bytes();
-    int offset_offset = java_lang_String::offset_offset_in_bytes();
-    int count_offset  = java_lang_String::count_offset_in_bytes();
-    int base_offset   = arrayOopDesc::base_offset_in_bytes(T_CHAR);
-
-    // does source == target string?
-    masm.cmpptr(rdi, rsi);
-    masm.jcc(Assembler::equal, RET_TRUE);
-
-    // get and compare counts
-    masm.movl(rcx, Address(rdi, count_offset));
-    masm.movl(rax, Address(rsi, count_offset));
-    masm.cmpl(rcx, rax);
-    masm.jcc(Assembler::notEqual, RET_FALSE);
-    masm.testl(rax, rax);
-    masm.jcc(Assembler::zero, RET_TRUE);
-
-    // get source string offset and value
-    masm.load_heap_oop(rbx, Address(rsi, value_offset));
-    masm.movl(rax, Address(rsi, offset_offset));
-    masm.lea(rsi, Address(rbx, rax, Address::times_2, base_offset));
-
-    // get compare string offset and value
-    masm.load_heap_oop(rbx, Address(rdi, value_offset));
-    masm.movl(rax, Address(rdi, offset_offset));
-    masm.lea(rdi, Address(rbx, rax, Address::times_2, base_offset));
-
-    // Set byte count
-    masm.shll(rcx, 1);
-    masm.movl(rax, rcx);
-
-    if (UseSSE42Intrinsics) {
-      // With SSE4.2, use double quad vector compare
-      Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
-      // Compare 16-byte vectors
-      masm.andl(rcx, 0xfffffff0);  // vector count (in bytes)
-      masm.andl(rax, 0x0000000e);  // tail count (in bytes)
-      masm.testl(rcx, rcx);
-      masm.jccb(Assembler::zero, COMPARE_TAIL);
-      masm.lea(rdi, Address(rdi, rcx, Address::times_1));
-      masm.lea(rsi, Address(rsi, rcx, Address::times_1));
-      masm.negptr(rcx);
-
-      masm.bind(COMPARE_WIDE_VECTORS);
-      masm.movdqu(tmp1Reg, Address(rdi, rcx, Address::times_1));
-      masm.movdqu(tmp2Reg, Address(rsi, rcx, Address::times_1));
-      masm.pxor(tmp1Reg, tmp2Reg);
-      masm.ptest(tmp1Reg, tmp1Reg);
-      masm.jccb(Assembler::notZero, RET_FALSE);
-      masm.addptr(rcx, 16);
-      masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
-      masm.bind(COMPARE_TAIL);
-      masm.movl(rcx, rax);
-      // Fallthru to tail compare
-    }
-
-    // Compare 4-byte vectors
-    masm.andl(rcx, 0xfffffffc);  // vector count (in bytes)
-    masm.andl(rax, 0x00000002);  // tail char (in bytes)
-    masm.testl(rcx, rcx);
-    masm.jccb(Assembler::zero, COMPARE_CHAR);
-    masm.lea(rdi, Address(rdi, rcx, Address::times_1));
-    masm.lea(rsi, Address(rsi, rcx, Address::times_1));
-    masm.negptr(rcx);
-
-    masm.bind(COMPARE_VECTORS);
-    masm.movl(rbx, Address(rdi, rcx, Address::times_1));
-    masm.cmpl(rbx, Address(rsi, rcx, Address::times_1));
-    masm.jccb(Assembler::notEqual, RET_FALSE);
-    masm.addptr(rcx, 4);
-    masm.jcc(Assembler::notZero, COMPARE_VECTORS);
-
-    // Compare trailing char (final 2 bytes), if any
-    masm.bind(COMPARE_CHAR);
-    masm.testl(rax, rax);
-    masm.jccb(Assembler::zero, RET_TRUE);
-    masm.load_unsigned_short(rbx, Address(rdi, 0));
-    masm.load_unsigned_short(rcx, Address(rsi, 0));
-    masm.cmpl(rbx, rcx);
-    masm.jccb(Assembler::notEqual, RET_FALSE);
-
-    masm.bind(RET_TRUE);
-    masm.movl(rax, 1);   // return true
-    masm.jmpb(DONE);
-
-    masm.bind(RET_FALSE);
-    masm.xorl(rax, rax); // return false
-
-    masm.bind(DONE);
-  %}
-
-  enc_class enc_Array_Equals(rdi_RegP ary1, rsi_RegP ary2, regD tmp1, regD tmp2,
-                             rax_RegI tmp3, rbx_RegI tmp4, rcx_RegI result) %{
-    Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_VECTORS, COMPARE_CHAR;
-    MacroAssembler masm(&cbuf);
-
-    XMMRegister tmp1Reg   = as_XMMRegister($tmp1$$reg);
-    XMMRegister tmp2Reg   = as_XMMRegister($tmp2$$reg);
-    Register ary1Reg      = as_Register($ary1$$reg);
-    Register ary2Reg      = as_Register($ary2$$reg);
-    Register tmp3Reg      = as_Register($tmp3$$reg);
-    Register tmp4Reg      = as_Register($tmp4$$reg);
-    Register resultReg    = as_Register($result$$reg);
-
-    int length_offset  = arrayOopDesc::length_offset_in_bytes();
-    int base_offset    = arrayOopDesc::base_offset_in_bytes(T_CHAR);
-
-    // Check the input args
-    masm.cmpq(ary1Reg, ary2Reg);
-    masm.jcc(Assembler::equal, TRUE_LABEL);
-    masm.testq(ary1Reg, ary1Reg);
-    masm.jcc(Assembler::zero, FALSE_LABEL);
-    masm.testq(ary2Reg, ary2Reg);
-    masm.jcc(Assembler::zero, FALSE_LABEL);
-
-    // Check the lengths
-    masm.movl(tmp4Reg, Address(ary1Reg, length_offset));
-    masm.movl(resultReg, Address(ary2Reg, length_offset));
-    masm.cmpl(tmp4Reg, resultReg);
-    masm.jcc(Assembler::notEqual, FALSE_LABEL);
-    masm.testl(resultReg, resultReg);
-    masm.jcc(Assembler::zero, TRUE_LABEL);
-
-    //load array address
-    masm.lea(ary1Reg, Address(ary1Reg, base_offset));
-    masm.lea(ary2Reg, Address(ary2Reg, base_offset));
-
-    //set byte count
-    masm.shll(tmp4Reg, 1);
-    masm.movl(resultReg,tmp4Reg);
-
-    if (UseSSE42Intrinsics){
-      // With SSE4.2, use double quad vector compare
-      Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
-      // Compare 16-byte vectors
-      masm.andl(tmp4Reg, 0xfffffff0);    // vector count (in bytes)
-      masm.andl(resultReg, 0x0000000e);  // tail count (in bytes)
-      masm.testl(tmp4Reg, tmp4Reg);
-      masm.jccb(Assembler::zero, COMPARE_TAIL);
-      masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
-      masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
-      masm.negptr(tmp4Reg);
-
-      masm.bind(COMPARE_WIDE_VECTORS);
-      masm.movdqu(tmp1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
-      masm.movdqu(tmp2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
-      masm.pxor(tmp1Reg, tmp2Reg);
-      masm.ptest(tmp1Reg, tmp1Reg);
-
-      masm.jccb(Assembler::notZero, FALSE_LABEL);
-      masm.addptr(tmp4Reg, 16);
-      masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
-      masm.bind(COMPARE_TAIL);
-      masm.movl(tmp4Reg, resultReg);
-      // Fallthru to tail compare
-    }
-
-   // Compare 4-byte vectors
-    masm.andl(tmp4Reg, 0xfffffffc);    // vector count (in bytes)
-    masm.andl(resultReg, 0x00000002);  // tail char (in bytes)
-    masm.testl(tmp4Reg, tmp4Reg); //if tmp2 == 0, only compare char
-    masm.jccb(Assembler::zero, COMPARE_CHAR);
-    masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
-    masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
-    masm.negptr(tmp4Reg);
-
-    masm.bind(COMPARE_VECTORS);
-    masm.movl(tmp3Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
-    masm.cmpl(tmp3Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
-    masm.jccb(Assembler::notEqual, FALSE_LABEL);
-    masm.addptr(tmp4Reg, 4);
-    masm.jcc(Assembler::notZero, COMPARE_VECTORS);
-
-    // Compare trailing char (final 2 bytes), if any
-    masm.bind(COMPARE_CHAR);
-    masm.testl(resultReg, resultReg);
-    masm.jccb(Assembler::zero, TRUE_LABEL);
-    masm.load_unsigned_short(tmp3Reg, Address(ary1Reg, 0));
-    masm.load_unsigned_short(tmp4Reg, Address(ary2Reg, 0));
-    masm.cmpl(tmp3Reg, tmp4Reg);
-    masm.jccb(Assembler::notEqual, FALSE_LABEL);
-
-    masm.bind(TRUE_LABEL);
-    masm.movl(resultReg, 1);   // return true
-    masm.jmpb(DONE);
-
-    masm.bind(FALSE_LABEL);
-    masm.xorl(resultReg, resultReg); // return false
-
-    // That's it
-    masm.bind(DONE);
-  %}
 
   enc_class enc_rethrow()
   %{
@@ -12096,52 +11654,67 @@
   ins_pipe(pipe_slow);
 %}
 
-instruct string_compare(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2,
-                        rax_RegI tmp3, rbx_RegI tmp4, rcx_RegI result, rFlagsReg cr)
-%{
-  match(Set result (StrComp str1 str2));
-  effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr);
-  //ins_cost(300);
-
-  format %{ "String Compare $str1, $str2 -> $result    // XXX KILL RAX, RBX" %}
-  ins_encode( enc_String_Compare(str1, str2, tmp1, tmp2, tmp3, tmp4, result) );
+instruct string_compare(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rbx_RegI cnt2,
+                        rax_RegI result, regD tmp1, regD tmp2, rFlagsReg cr)
+%{
+  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
+  effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
+
+  format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result   // KILL $tmp1, $tmp2" %}
+  ins_encode %{
+    __ string_compare($str1$$Register, $str2$$Register,
+                      $cnt1$$Register, $cnt2$$Register, $result$$Register,
+                      $tmp1$$XMMRegister, $tmp2$$XMMRegister);
+  %}
   ins_pipe( pipe_slow );
 %}
 
-instruct string_indexof(rsi_RegP str1, rdi_RegP str2, regD tmp1, rax_RegI tmp2,
-                        rcx_RegI tmp3, rdx_RegI tmp4, rbx_RegI result, rFlagsReg cr)
+instruct string_indexof(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, rax_RegI cnt2,
+                        rbx_RegI result, regD tmp1, rcx_RegI tmp2, rFlagsReg cr)
 %{
   predicate(UseSSE42Intrinsics);
-  match(Set result (StrIndexOf str1 str2));
-  effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, KILL tmp2, KILL tmp3, KILL tmp4, KILL cr);
-
-  format %{ "String IndexOf $str1,$str2 -> $result   // KILL RAX, RCX, RDX" %}
-  ins_encode( enc_String_IndexOf(str1, str2, tmp1, tmp2, tmp3, tmp4, result) );
+  match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2)));
+  effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL tmp2, KILL cr);
+
+  format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result   // KILL $tmp1, $tmp2" %}
+  ins_encode %{
+    __ string_indexof($str1$$Register, $str2$$Register,
+                      $cnt1$$Register, $cnt2$$Register, $result$$Register,
+                      $tmp1$$XMMRegister, $tmp2$$Register);
+  %}
   ins_pipe( pipe_slow );
 %}
 
 // fast string equals
-instruct string_equals(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2, rbx_RegI tmp3,
-                       rcx_RegI tmp4, rax_RegI result, rFlagsReg cr)
-%{
-  match(Set result (StrEquals str1 str2));
-  effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr);
-
-  format %{ "String Equals $str1,$str2 -> $result    // KILL RBX, RCX" %}
-  ins_encode( enc_String_Equals(str1, str2, tmp1, tmp2, tmp3, tmp4, result) );
+instruct string_equals(rdi_RegP str1, rsi_RegP str2, rcx_RegI cnt, rax_RegI result,
+                       regD tmp1, regD tmp2, rbx_RegI tmp3, rFlagsReg cr)
+%{
+  match(Set result (StrEquals (Binary str1 str2) cnt));
+  effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp3, KILL cr);
+
+  format %{ "String Equals $str1,$str2,$cnt -> $result    // KILL $tmp1, $tmp2, $tmp3" %}
+  ins_encode %{
+    __ char_arrays_equals(false, $str1$$Register, $str2$$Register,
+                          $cnt$$Register, $result$$Register, $tmp3$$Register,
+                          $tmp1$$XMMRegister, $tmp2$$XMMRegister);
+  %}
   ins_pipe( pipe_slow );
 %}
 
 // fast array equals
-instruct array_equals(rdi_RegP ary1, rsi_RegP ary2, regD tmp1, regD tmp2, rax_RegI tmp3,
-                      rbx_RegI tmp4, rcx_RegI result, rFlagsReg cr)
+instruct array_equals(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result,
+                      regD tmp1, regD tmp2, rcx_RegI tmp3, rbx_RegI tmp4, rFlagsReg cr)
 %{
   match(Set result (AryEq ary1 ary2));
   effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr);
   //ins_cost(300);
 
-  format %{ "Array Equals $ary1,$ary2 -> $result   // KILL RAX, RBX" %}
-  ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, tmp3, tmp4, result) );
+  format %{ "Array Equals $ary1,$ary2 -> $result   // KILL $tmp1, $tmp2, $tmp3, $tmp4" %}
+  ins_encode %{
+    __ char_arrays_equals(true, $ary1$$Register, $ary2$$Register,
+                          $tmp3$$Register, $result$$Register, $tmp4$$Register,
+                          $tmp1$$XMMRegister, $tmp2$$XMMRegister);
+  %}
   ins_pipe( pipe_slow );
 %}
 
--- a/src/share/vm/adlc/formssel.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/adlc/formssel.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -828,11 +828,13 @@
     return AdlcVMDeps::Parms;   // Skip the machine-state edges
 
   if( _matrule->_rChild &&
-      ( strcmp(_matrule->_rChild->_opType,"StrComp"   )==0 ||
+      ( strcmp(_matrule->_rChild->_opType,"AryEq"     )==0 ||
+        strcmp(_matrule->_rChild->_opType,"StrComp"   )==0 ||
         strcmp(_matrule->_rChild->_opType,"StrEquals" )==0 ||
         strcmp(_matrule->_rChild->_opType,"StrIndexOf")==0 )) {
-        // String.(compareTo/equals/indexOf) take 1 control and 4 memory edges.
-    return 5;
+        // String.(compareTo/equals/indexOf) and Arrays.equals
+        // take 1 control and 1 memory edges.
+    return 2;
   }
 
   // Check for handling of 'Memory' input/edge in the ideal world.
--- a/src/share/vm/c1/c1_GraphBuilder.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/c1/c1_GraphBuilder.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -1442,7 +1442,7 @@
         switch (field_type) {
         case T_ARRAY:
         case T_OBJECT:
-          if (field_val.as_object()->has_encoding()) {
+          if (field_val.as_object()->should_be_constant()) {
             constant =  new Constant(as_ValueType(field_val));
           }
           break;
--- a/src/share/vm/c1/c1_InstructionPrinter.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/c1/c1_InstructionPrinter.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -133,12 +133,12 @@
       ciMethod* m = (ciMethod*)value;
       output()->print("<method %s.%s>", m->holder()->name()->as_utf8(), m->name()->as_utf8());
     } else {
-      output()->print("<object 0x%x>", value->encoding());
+      output()->print("<object 0x%x>", value->constant_encoding());
     }
   } else if (type->as_InstanceConstant() != NULL) {
-    output()->print("<instance 0x%x>", type->as_InstanceConstant()->value()->encoding());
+    output()->print("<instance 0x%x>", type->as_InstanceConstant()->value()->constant_encoding());
   } else if (type->as_ArrayConstant() != NULL) {
-    output()->print("<array 0x%x>", type->as_ArrayConstant()->value()->encoding());
+    output()->print("<array 0x%x>", type->as_ArrayConstant()->value()->constant_encoding());
   } else if (type->as_ClassConstant() != NULL) {
     ciInstanceKlass* klass = type->as_ClassConstant()->value();
     if (!klass->is_loaded()) {
--- a/src/share/vm/c1/c1_LIRGenerator.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/c1/c1_LIRGenerator.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -440,7 +440,7 @@
     __ oop2reg_patch(NULL, r, info);
   } else {
     // no patching needed
-    __ oop2reg(obj->encoding(), r);
+    __ oop2reg(obj->constant_encoding(), r);
   }
 }
 
@@ -831,7 +831,7 @@
     int taken_count_offset     = md->byte_offset_of_slot(data, BranchData::taken_offset());
     int not_taken_count_offset = md->byte_offset_of_slot(data, BranchData::not_taken_offset());
     LIR_Opr md_reg = new_register(T_OBJECT);
-    __ move(LIR_OprFact::oopConst(md->encoding()), md_reg);
+    __ move(LIR_OprFact::oopConst(md->constant_encoding()), md_reg);
     LIR_Opr data_offset_reg = new_register(T_INT);
     __ cmove(lir_cond(cond),
              LIR_OprFact::intConst(taken_count_offset),
@@ -1071,7 +1071,7 @@
     LIR_OprList* args = new LIR_OprList();
     args->append(getThreadPointer());
     LIR_Opr meth = new_register(T_OBJECT);
-    __ oop2reg(method()->encoding(), meth);
+    __ oop2reg(method()->constant_encoding(), meth);
     args->append(meth);
     call_runtime(&signature, args, CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), voidType, NULL);
   }
@@ -1784,7 +1784,7 @@
     LIR_OprList* args = new LIR_OprList();
     args->append(getThreadPointer());
     LIR_Opr meth = new_register(T_OBJECT);
-    __ oop2reg(method()->encoding(), meth);
+    __ oop2reg(method()->constant_encoding(), meth);
     args->append(meth);
     call_runtime(&signature, args, CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), voidType, NULL);
   }
@@ -2207,7 +2207,7 @@
     LIR_OprList* args = new LIR_OprList();
     args->append(getThreadPointer());
     LIR_Opr meth = new_register(T_OBJECT);
-    __ oop2reg(method()->encoding(), meth);
+    __ oop2reg(method()->constant_encoding(), meth);
     args->append(meth);
     call_runtime(&signature, args, CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), voidType, NULL);
   }
@@ -2216,7 +2216,7 @@
     LIR_Opr obj;
     if (method()->is_static()) {
       obj = new_register(T_OBJECT);
-      __ oop2reg(method()->holder()->java_mirror()->encoding(), obj);
+      __ oop2reg(method()->holder()->java_mirror()->constant_encoding(), obj);
     } else {
       Local* receiver = x->state()->local_at(0)->as_Local();
       assert(receiver != NULL, "must already exist");
@@ -2660,7 +2660,7 @@
     }
 
     LIR_Opr meth = new_register(T_OBJECT);
-    __ oop2reg(method()->encoding(), meth);
+    __ oop2reg(method()->constant_encoding(), meth);
     LIR_Opr result = increment_and_return_counter(meth, offset, InvocationCounter::count_increment);
     __ cmp(lir_cond_aboveEqual, result, LIR_OprFact::intConst(limit));
     CodeStub* overflow = new CounterOverflowStub(info, info->bci());
--- a/src/share/vm/c1/c1_ValueType.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/c1/c1_ValueType.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -86,7 +86,7 @@
 
 jobject ObjectType::encoding() const {
   assert(is_constant(), "must be");
-  return constant_value()->encoding();
+  return constant_value()->constant_encoding();
 }
 
 bool ObjectType::is_loaded() const {
--- a/src/share/vm/ci/ciEnv.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/ci/ciEnv.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -257,7 +257,7 @@
 
 // ------------------------------------------------------------------
 // ciEnv::make_array
-ciArray* ciEnv::make_array(GrowableArray<ciObject*>* objects) {
+ciArray* ciEnv::make_system_array(GrowableArray<ciObject*>* objects) {
   VM_ENTRY_MARK;
   int length = objects->length();
   objArrayOop a = oopFactory::new_system_objArray(length, THREAD);
--- a/src/share/vm/ci/ciEnv.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/ci/ciEnv.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -339,8 +339,8 @@
   // but consider adding to vmSymbols.hpp instead.
 
   // Use this to make a holder for non-perm compile time constants.
-  // The resulting array is guaranteed to satisfy "has_encoding".
-  ciArray*  make_array(GrowableArray<ciObject*>* objects);
+  // The resulting array is guaranteed to satisfy "can_be_constant".
+  ciArray*  make_system_array(GrowableArray<ciObject*>* objects);
 
   // converts the ciKlass* representing the holder of a method into a
   // ciInstanceKlass*.  This is needed since the holder of a method in
--- a/src/share/vm/ci/ciMethod.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/ci/ciMethod.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -325,10 +325,10 @@
 }
 
 // ------------------------------------------------------------------
-// ciMethod::liveness_at_bci
+// ciMethod::raw_liveness_at_bci
 //
 // Which local variables are live at a specific bci?
-MethodLivenessResult ciMethod::liveness_at_bci(int bci) {
+MethodLivenessResult ciMethod::raw_liveness_at_bci(int bci) {
   check_is_loaded();
   if (_liveness == NULL) {
     // Create the liveness analyzer.
@@ -336,7 +336,17 @@
     _liveness = new (arena) MethodLiveness(arena, this);
     _liveness->compute_liveness();
   }
-  MethodLivenessResult result = _liveness->get_liveness_at(bci);
+  return _liveness->get_liveness_at(bci);
+}
+
+// ------------------------------------------------------------------
+// ciMethod::liveness_at_bci
+//
+// Which local variables are live at a specific bci?  When debugging
+// will return true for all locals in some cases to improve debug
+// information.
+MethodLivenessResult ciMethod::liveness_at_bci(int bci) {
+  MethodLivenessResult result = raw_liveness_at_bci(bci);
   if (CURRENT_ENV->jvmti_can_access_local_variables() || DeoptimizeALot || CompileTheWorld) {
     // Keep all locals live for the user's edification and amusement.
     result.at_put_range(0, result.size(), true);
--- a/src/share/vm/ci/ciMethod.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/ci/ciMethod.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -149,6 +149,12 @@
   bool          has_monitor_bytecodes() const    { return _uses_monitors; }
   bool          has_balanced_monitors();
 
+  // Returns a bitmap indicating which locals are required to be
+  // maintained as live for deopt.  raw_liveness_at_bci is always the
+  // direct output of the liveness computation while liveness_at_bci
+  // may mark all locals as live to improve support for debugging Java
+  // code by maintaining the state of as many locals as possible.
+  MethodLivenessResult raw_liveness_at_bci(int bci);
   MethodLivenessResult liveness_at_bci(int bci);
 
   // Get the interpreters viewpoint on oop liveness.  MethodLiveness is
--- a/src/share/vm/ci/ciObject.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/ci/ciObject.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -55,6 +55,7 @@
   }
   _klass = NULL;
   _ident = 0;
+  init_flags_from(o);
 }
 
 // ------------------------------------------------------------------
@@ -69,6 +70,7 @@
   }
   _klass = NULL;
   _ident = 0;
+  init_flags_from(h());
 }
 
 // ------------------------------------------------------------------
@@ -158,7 +160,7 @@
 }
 
 // ------------------------------------------------------------------
-// ciObject::encoding
+// ciObject::constant_encoding
 //
 // The address which the compiler should embed into the
 // generated code to represent this oop.  This address
@@ -172,16 +174,24 @@
 //
 // This method should be changed to return an generified address
 // to discourage use of the JNI handle.
-jobject ciObject::encoding() {
+jobject ciObject::constant_encoding() {
   assert(is_null_object() || handle() != NULL, "cannot embed null pointer");
-  assert(has_encoding(), "oop must be NULL or perm");
+  assert(can_be_constant(), "oop must be NULL or perm");
   return handle();
 }
 
 // ------------------------------------------------------------------
-// ciObject::has_encoding
-bool ciObject::has_encoding() {
-  return handle() == NULL || is_perm();
+// ciObject::can_be_constant
+bool ciObject::can_be_constant() {
+  if (ScavengeRootsInCode >= 1)  return true;  // now everybody can encode as a constant
+  return handle() == NULL || !is_scavengable();
+}
+
+// ------------------------------------------------------------------
+// ciObject::should_be_constant()
+bool ciObject::should_be_constant() {
+  if (ScavengeRootsInCode >= 2)  return true;  // force everybody to be a constant
+  return handle() == NULL || !is_scavengable();
 }
 
 
@@ -195,8 +205,9 @@
 void ciObject::print(outputStream* st) {
   st->print("<%s", type_string());
   GUARDED_VM_ENTRY(print_impl(st);)
-  st->print(" ident=%d %s address=0x%x>", ident(),
+  st->print(" ident=%d %s%s address=0x%x>", ident(),
         is_perm() ? "PERM" : "",
+        is_scavengable() ? "SCAVENGABLE" : "",
         (address)this);
 }
 
--- a/src/share/vm/ci/ciObject.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/ci/ciObject.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -51,9 +51,10 @@
   ciKlass* _klass;
   uint     _ident;
 
-  enum { FLAG_BITS   = 1};
+  enum { FLAG_BITS   = 2 };
   enum {
-         PERM_FLAG    = 1
+         PERM_FLAG        = 1,
+         SCAVENGABLE_FLAG = 2
        };
 protected:
   ciObject();
@@ -68,8 +69,15 @@
     return JNIHandles::resolve_non_null(_handle);
   }
 
-  void set_perm() {
-    _ident |=  PERM_FLAG;
+  void init_flags_from(oop x) {
+    int flags = 0;
+    if (x != NULL) {
+      if (x->is_perm())
+        flags |= PERM_FLAG;
+      if (x->is_scavengable())
+        flags |= SCAVENGABLE_FLAG;
+    }
+    _ident |= flags;
   }
 
   // Virtual behavior of the print() method.
@@ -91,17 +99,27 @@
   // A hash value for the convenience of compilers.
   int hash();
 
-  // Tells if this oop has an encoding.  (I.e., is it null or perm?)
+  // Tells if this oop has an encoding as a constant.
+  // True if is_scavengable is false.
+  // Also true if ScavengeRootsInCode is non-zero.
   // If it does not have an encoding, the compiler is responsible for
   // making other arrangements for dealing with the oop.
-  // See ciEnv::make_perm_array
-  bool has_encoding();
+  // See ciEnv::make_array
+  bool can_be_constant();
+
+  // Tells if this oop should be made a constant.
+  // True if is_scavengable is false or ScavengeRootsInCode > 1.
+  bool should_be_constant();
 
   // Is this object guaranteed to be in the permanent part of the heap?
   // If so, CollectedHeap::can_elide_permanent_oop_store_barriers is relevant.
   // If the answer is false, no guarantees are made.
   bool is_perm() { return (_ident & PERM_FLAG) != 0; }
 
+  // Might this object possibly move during a scavenge operation?
+  // If the answer is true and ScavengeRootsInCode==0, the oop cannot be embedded in code.
+  bool is_scavengable() { return (_ident & SCAVENGABLE_FLAG) != 0; }
+
   // The address which the compiler should embed into the
   // generated code to represent this oop.  This address
   // is not the true address of the oop -- it will get patched
@@ -109,7 +127,7 @@
   //
   // Usage note: no address arithmetic allowed.  Oop must
   // be registered with the oopRecorder.
-  jobject encoding();
+  jobject constant_encoding();
 
   // What kind of ciObject is this?
   virtual bool is_null_object() const       { return false; }
--- a/src/share/vm/ci/ciObjectFactory.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/ci/ciObjectFactory.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -261,12 +261,11 @@
     ciObject* new_object = create_new_object(keyHandle());
     assert(keyHandle() == new_object->get_oop(), "must be properly recorded");
     init_ident_of(new_object);
-    if (!keyHandle->is_perm()) {
+    if (!new_object->is_perm()) {
       // Not a perm-space object.
       insert_non_perm(bucket, keyHandle(), new_object);
       return new_object;
     }
-    new_object->set_perm();
     if (len != _ci_objects->length()) {
       // creating the new object has recursively entered new objects
       // into the table.  We need to recompute our index.
--- a/src/share/vm/ci/ciTypeFlow.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/ci/ciTypeFlow.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -2486,8 +2486,13 @@
         // Assume irreducible entries need more data flow
         add_to_work_list(succ);
       }
-      lp = lp->parent();
-      assert(lp != NULL, "nested loop must have parent by now");
+      Loop* plp = lp->parent();
+      if (plp == NULL) {
+        // This only happens for some irreducible cases.  The parent
+        // will be updated during a later pass.
+        break;
+      }
+      lp = plp;
     }
 
     // Merge loop tree branch for all successors.
--- a/src/share/vm/classfile/systemDictionary.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/classfile/systemDictionary.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -2417,6 +2417,8 @@
                          vmSymbols::makeSite_name(), vmSymbols::makeSite_signature(),
                          &args, CHECK_(empty));
   oop call_site_oop = (oop) result.get_jobject();
+  assert(call_site_oop->is_oop()
+         /*&& sun_dyn_CallSiteImpl::is_instance(call_site_oop)*/, "must be sane");
   sun_dyn_CallSiteImpl::set_vmmethod(call_site_oop, mh_invdyn());
   if (TraceMethodHandles) {
     tty->print_cr("Linked invokedynamic bci=%d site="INTPTR_FORMAT":", caller_bci, call_site_oop);
@@ -2453,6 +2455,8 @@
   oop boot_method_oop = (oop) result.get_jobject();
 
   if (boot_method_oop != NULL) {
+    assert(boot_method_oop->is_oop()
+           && java_dyn_MethodHandle::is_instance(boot_method_oop), "must be sane");
     // probably no race conditions, but let's be careful:
     if (Atomic::cmpxchg_ptr(boot_method_oop, ik->adr_bootstrap_method(), NULL) == NULL)
       ik->set_bootstrap_method(boot_method_oop);
--- a/src/share/vm/code/codeBlob.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/code/codeBlob.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -175,6 +175,8 @@
                             OopClosure* keep_alive,
                             bool unloading_occurred);
   virtual void oops_do(OopClosure* f) = 0;
+  // (All CodeBlob subtypes other than NMethod currently have
+  // an empty oops_do() method.
 
   // OopMap for frame
   OopMapSet* oop_maps() const                    { return _oop_maps; }
--- a/src/share/vm/code/codeCache.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/code/codeCache.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -95,6 +95,7 @@
 int CodeCache::_number_of_blobs = 0;
 int CodeCache::_number_of_nmethods_with_dependencies = 0;
 bool CodeCache::_needs_cache_clean = false;
+nmethod* CodeCache::_scavenge_root_nmethods = NULL;
 
 
 CodeBlob* CodeCache::first() {
@@ -148,10 +149,7 @@
     }
   }
   verify_if_often();
-  if (PrintCodeCache2) {        // Need to add a new flag
-      ResourceMark rm;
-      tty->print_cr("CodeCache allocation:  addr: " INTPTR_FORMAT ", size: 0x%x\n", cb, size);
-  }
+  print_trace("allocation", cb, size);
   return cb;
 }
 
@@ -159,10 +157,7 @@
   assert_locked_or_safepoint(CodeCache_lock);
   verify_if_often();
 
-  if (PrintCodeCache2) {        // Need to add a new flag
-      ResourceMark rm;
-      tty->print_cr("CodeCache free:  addr: " INTPTR_FORMAT ", size: 0x%x\n", cb, cb->size());
-  }
+  print_trace("free", cb);
   if (cb->is_nmethod() && ((nmethod *)cb)->has_dependencies()) {
     _number_of_nmethods_with_dependencies--;
   }
@@ -260,14 +255,148 @@
   }
 }
 
-void CodeCache::oops_do(OopClosure* f) {
+void CodeCache::blobs_do(CodeBlobClosure* f) {
   assert_locked_or_safepoint(CodeCache_lock);
   FOR_ALL_ALIVE_BLOBS(cb) {
-    cb->oops_do(f);
+    f->do_code_blob(cb);
+
+#ifdef ASSERT
+    if (cb->is_nmethod())
+      ((nmethod*)cb)->verify_scavenge_root_oops();
+#endif //ASSERT
   }
 }
 
+// Walk the list of methods which might contain non-perm oops.
+void CodeCache::scavenge_root_nmethods_do(CodeBlobClosure* f) {
+  assert_locked_or_safepoint(CodeCache_lock);
+  debug_only(mark_scavenge_root_nmethods());
+
+  for (nmethod* cur = scavenge_root_nmethods(); cur != NULL; cur = cur->scavenge_root_link()) {
+    debug_only(cur->clear_scavenge_root_marked());
+    assert(cur->scavenge_root_not_marked(), "");
+    assert(cur->on_scavenge_root_list(), "else shouldn't be on this list");
+
+    bool is_live = (!cur->is_zombie() && !cur->is_unloaded());
+#ifndef PRODUCT
+    if (TraceScavenge) {
+      cur->print_on(tty, is_live ? "scavenge root" : "dead scavenge root"); tty->cr();
+    }
+#endif //PRODUCT
+    if (is_live)
+      // Perform cur->oops_do(f), maybe just once per nmethod.
+      f->do_code_blob(cur);
+  }
+
+  // Check for stray marks.
+  debug_only(verify_perm_nmethods(NULL));
+}
+
+void CodeCache::add_scavenge_root_nmethod(nmethod* nm) {
+  assert_locked_or_safepoint(CodeCache_lock);
+  nm->set_on_scavenge_root_list();
+  nm->set_scavenge_root_link(_scavenge_root_nmethods);
+  set_scavenge_root_nmethods(nm);
+  print_trace("add_scavenge_root", nm);
+}
+
+void CodeCache::drop_scavenge_root_nmethod(nmethod* nm) {
+  assert_locked_or_safepoint(CodeCache_lock);
+  print_trace("drop_scavenge_root", nm);
+  nmethod* last = NULL;
+  nmethod* cur = scavenge_root_nmethods();
+  while (cur != NULL) {
+    nmethod* next = cur->scavenge_root_link();
+    if (cur == nm) {
+      if (last != NULL)
+            last->set_scavenge_root_link(next);
+      else  set_scavenge_root_nmethods(next);
+      nm->set_scavenge_root_link(NULL);
+      nm->clear_on_scavenge_root_list();
+      return;
+    }
+    last = cur;
+    cur = next;
+  }
+  assert(false, "should have been on list");
+}
+
+void CodeCache::prune_scavenge_root_nmethods() {
+  assert_locked_or_safepoint(CodeCache_lock);
+  debug_only(mark_scavenge_root_nmethods());
+
+  nmethod* last = NULL;
+  nmethod* cur = scavenge_root_nmethods();
+  while (cur != NULL) {
+    nmethod* next = cur->scavenge_root_link();
+    debug_only(cur->clear_scavenge_root_marked());
+    assert(cur->scavenge_root_not_marked(), "");
+    assert(cur->on_scavenge_root_list(), "else shouldn't be on this list");
+
+    if (!cur->is_zombie() && !cur->is_unloaded()
+        && cur->detect_scavenge_root_oops()) {
+      // Keep it.  Advance 'last' to prevent deletion.
+      last = cur;
+    } else {
+      // Prune it from the list, so we don't have to look at it any more.
+      print_trace("prune_scavenge_root", cur);
+      cur->set_scavenge_root_link(NULL);
+      cur->clear_on_scavenge_root_list();
+      if (last != NULL)
+            last->set_scavenge_root_link(next);
+      else  set_scavenge_root_nmethods(next);
+    }
+    cur = next;
+  }
+
+  // Check for stray marks.
+  debug_only(verify_perm_nmethods(NULL));
+}
+
+#ifndef PRODUCT
+void CodeCache::asserted_non_scavengable_nmethods_do(CodeBlobClosure* f) {
+  // While we are here, verify the integrity of the list.
+  mark_scavenge_root_nmethods();
+  for (nmethod* cur = scavenge_root_nmethods(); cur != NULL; cur = cur->scavenge_root_link()) {
+    assert(cur->on_scavenge_root_list(), "else shouldn't be on this list");
+    cur->clear_scavenge_root_marked();
+  }
+  verify_perm_nmethods(f);
+}
+
+// Temporarily mark nmethods that are claimed to be on the non-perm list.
+void CodeCache::mark_scavenge_root_nmethods() {
+  FOR_ALL_ALIVE_BLOBS(cb) {
+    if (cb->is_nmethod()) {
+      nmethod *nm = (nmethod*)cb;
+      assert(nm->scavenge_root_not_marked(), "clean state");
+      if (nm->on_scavenge_root_list())
+        nm->set_scavenge_root_marked();
+    }
+  }
+}
+
+// If the closure is given, run it on the unlisted nmethods.
+// Also make sure that the effects of mark_scavenge_root_nmethods is gone.
+void CodeCache::verify_perm_nmethods(CodeBlobClosure* f_or_null) {
+  FOR_ALL_ALIVE_BLOBS(cb) {
+    bool call_f = (f_or_null != NULL);
+    if (cb->is_nmethod()) {
+      nmethod *nm = (nmethod*)cb;
+      assert(nm->scavenge_root_not_marked(), "must be already processed");
+      if (nm->on_scavenge_root_list())
+        call_f = false;  // don't show this one to the client
+      nm->verify_scavenge_root_oops();
+    } else {
+      call_f = false;   // not an nmethod
+    }
+    if (call_f)  f_or_null->do_code_blob(cb);
+  }
+}
+#endif //PRODUCT
+
 void CodeCache::gc_prologue() {
+  assert(!nmethod::oops_do_marking_is_active(), "oops_do_marking_epilogue must be called");
 }
 
 
@@ -285,6 +414,8 @@
     cb->fix_oop_relocations();
   }
   set_needs_cache_clean(false);
+  prune_scavenge_root_nmethods();
+  assert(!nmethod::oops_do_marking_is_active(), "oops_do_marking_prologue must be called");
 }
 
 
@@ -508,6 +639,14 @@
   }
 }
 
+void CodeCache::print_trace(const char* event, CodeBlob* cb, int size) {
+  if (PrintCodeCache2) {  // Need to add a new flag
+    ResourceMark rm;
+    if (size == 0)  size = cb->size();
+    tty->print_cr("CodeCache %s:  addr: " INTPTR_FORMAT ", size: 0x%x", event, cb, size);
+  }
+}
+
 void CodeCache::print_internals() {
   int nmethodCount = 0;
   int runtimeStubCount = 0;
--- a/src/share/vm/code/codeCache.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/code/codeCache.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -45,8 +45,13 @@
   static int _number_of_blobs;
   static int _number_of_nmethods_with_dependencies;
   static bool _needs_cache_clean;
+  static nmethod* _scavenge_root_nmethods;  // linked via nm->scavenge_root_link()
 
   static void verify_if_often() PRODUCT_RETURN;
+
+  static void mark_scavenge_root_nmethods() PRODUCT_RETURN;
+  static void verify_perm_nmethods(CodeBlobClosure* f_or_null) PRODUCT_RETURN;
+
  public:
 
   // Initialization
@@ -61,6 +66,7 @@
   static void flush();                              // flushes all CodeBlobs
   static bool contains(void *p);                    // returns whether p is included
   static void blobs_do(void f(CodeBlob* cb));       // iterates over all CodeBlobs
+  static void blobs_do(CodeBlobClosure* f);         // iterates over all CodeBlobs
   static void nmethods_do(void f(nmethod* nm));     // iterates over all nmethods
 
   // Lookup
@@ -106,12 +112,24 @@
   static void do_unloading(BoolObjectClosure* is_alive,
                            OopClosure* keep_alive,
                            bool unloading_occurred);
-  static void oops_do(OopClosure* f);
+  static void oops_do(OopClosure* f) {
+    CodeBlobToOopClosure oopc(f, /*do_marking=*/ false);
+    blobs_do(&oopc);
+  }
+  static void asserted_non_scavengable_nmethods_do(CodeBlobClosure* f = NULL) PRODUCT_RETURN;
+  static void scavenge_root_nmethods_do(CodeBlobClosure* f);
+
+  static nmethod* scavenge_root_nmethods()          { return _scavenge_root_nmethods; }
+  static void set_scavenge_root_nmethods(nmethod* nm) { _scavenge_root_nmethods = nm; }
+  static void add_scavenge_root_nmethod(nmethod* nm);
+  static void drop_scavenge_root_nmethod(nmethod* nm);
+  static void prune_scavenge_root_nmethods();
 
   // Printing/debugging
   static void print()   PRODUCT_RETURN;          // prints summary
   static void print_internals();
   static void verify();                          // verifies the code cache
+  static void print_trace(const char* event, CodeBlob* cb, int size = 0) PRODUCT_RETURN;
 
   // The full limits of the codeCache
   static address  low_bound()                    { return (address) _heap->low_boundary(); }
--- a/src/share/vm/code/debugInfoRec.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/code/debugInfoRec.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -299,7 +299,7 @@
   stream()->write_int(sender_stream_offset);
 
   // serialize scope
-  jobject method_enc = (method == NULL)? NULL: method->encoding();
+  jobject method_enc = (method == NULL)? NULL: method->constant_encoding();
   stream()->write_int(oop_recorder()->find_index(method_enc));
   stream()->write_bci(bci);
   assert(method == NULL ||
--- a/src/share/vm/code/dependencies.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/code/dependencies.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -302,7 +302,7 @@
       bytes.write_byte(code_byte);
       for (int j = 0; j < stride; j++) {
         if (j == skipj)  continue;
-        bytes.write_int(_oop_recorder->find_index(deps->at(i+j)->encoding()));
+        bytes.write_int(_oop_recorder->find_index(deps->at(i+j)->constant_encoding()));
       }
     }
   }
--- a/src/share/vm/code/nmethod.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/code/nmethod.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -581,10 +581,13 @@
     debug_only(No_Safepoint_Verifier nsv;)
     assert_locked_or_safepoint(CodeCache_lock);
 
-    NOT_PRODUCT(_has_debug_info = false; )
+    NOT_PRODUCT(_has_debug_info = false);
+    _oops_do_mark_link       = NULL;
     _method                  = method;
     _entry_bci               = InvocationEntryBci;
-    _link                    = NULL;
+    _osr_link                = NULL;
+    _scavenge_root_link      = NULL;
+    _scavenge_root_state     = 0;
     _compiler                = NULL;
     // We have no exception handler or deopt handler make the
     // values something that will never match a pc like the nmethod vtable entry
@@ -618,7 +621,7 @@
     _stack_traversal_mark    = 0;
 
     code_buffer->copy_oops_to(this);
-    debug_only(check_store();)
+    debug_only(verify_scavenge_root_oops());
     CodeCache::commit(this);
     VTune::create_nmethod(this);
   }
@@ -668,10 +671,13 @@
     debug_only(No_Safepoint_Verifier nsv;)
     assert_locked_or_safepoint(CodeCache_lock);
 
-    NOT_PRODUCT(_has_debug_info = false; )
+    NOT_PRODUCT(_has_debug_info = false);
+    _oops_do_mark_link       = NULL;
     _method                  = method;
     _entry_bci               = InvocationEntryBci;
-    _link                    = NULL;
+    _osr_link                = NULL;
+    _scavenge_root_link      = NULL;
+    _scavenge_root_state     = 0;
     _compiler                = NULL;
     // We have no exception handler or deopt handler make the
     // values something that will never match a pc like the nmethod vtable entry
@@ -703,7 +709,7 @@
     _stack_traversal_mark    = 0;
 
     code_buffer->copy_oops_to(this);
-    debug_only(check_store();)
+    debug_only(verify_scavenge_root_oops());
     CodeCache::commit(this);
     VTune::create_nmethod(this);
   }
@@ -770,12 +776,15 @@
     debug_only(No_Safepoint_Verifier nsv;)
     assert_locked_or_safepoint(CodeCache_lock);
 
-    NOT_PRODUCT(_has_debug_info = false; )
+    NOT_PRODUCT(_has_debug_info = false);
+    _oops_do_mark_link       = NULL;
     _method                  = method;
     _compile_id              = compile_id;
     _comp_level              = comp_level;
     _entry_bci               = entry_bci;
-    _link                    = NULL;
+    _osr_link                = NULL;
+    _scavenge_root_link      = NULL;
+    _scavenge_root_state     = 0;
     _compiler                = compiler;
     _orig_pc_offset          = orig_pc_offset;
 #ifdef HAVE_DTRACE_H
@@ -813,7 +822,10 @@
     code_buffer->copy_oops_to(this);
     debug_info->copy_to(this);
     dependencies->copy_to(this);
-    debug_only(check_store();)
+    if (ScavengeRootsInCode && detect_scavenge_root_oops()) {
+      CodeCache::add_scavenge_root_nmethod(this);
+    }
+    debug_only(verify_scavenge_root_oops());
 
     CodeCache::commit(this);
 
@@ -902,23 +914,30 @@
   if (st != NULL) {
     ttyLocker ttyl;
     // Print a little tag line that looks like +PrintCompilation output:
-    st->print("%3d%c  %s",
+    int tlen = (int) strlen(title);
+    bool do_nl = false;
+    if (tlen > 0 && title[tlen-1] == '\n') { tlen--; do_nl = true; }
+    st->print("%3d%c  %.*s",
               compile_id(),
               is_osr_method() ? '%' :
               method() != NULL &&
               is_native_method() ? 'n' : ' ',
-              title);
+              tlen, title);
 #ifdef TIERED
     st->print(" (%d) ", comp_level());
 #endif // TIERED
     if (WizardMode) st->print(" (" INTPTR_FORMAT ")", this);
-    if (method() != NULL) {
-      method()->print_short_name(st);
+    if (Universe::heap()->is_gc_active() && method() != NULL) {
+      st->print("(method)");
+    } else if (method() != NULL) {
+        method()->print_short_name(st);
       if (is_osr_method())
         st->print(" @ %d", osr_entry_bci());
       if (method()->code_size() > 0)
         st->print(" (%d bytes)", method()->code_size());
     }
+
+    if (do_nl)  st->cr();
   }
 }
 
@@ -1033,6 +1052,7 @@
   }
 }
 
+// This is a private interface with the sweeper.
 void nmethod::mark_as_seen_on_stack() {
   assert(is_not_entrant(), "must be a non-entrant method");
   set_stack_traversal_mark(NMethodSweeper::traversal_count());
@@ -1077,7 +1097,8 @@
                   " unloadable], methodOop(" INTPTR_FORMAT
                   "), cause(" INTPTR_FORMAT ")",
                   this, (address)_method, (address)cause);
-    cause->klass()->print();
+    if (!Universe::heap()->is_gc_active())
+      cause->klass()->print();
   }
   // Unlink the osr method, so we do not look this up again
   if (is_osr_method()) {
@@ -1109,7 +1130,8 @@
   // The methodOop is gone at this point
   assert(_method == NULL, "Tautology");
 
-  set_link(NULL);
+  set_osr_link(NULL);
+  //set_scavenge_root_link(NULL); // done by prune_scavenge_root_nmethods
   NMethodSweeper::notify(this);
 }
 
@@ -1295,6 +1317,10 @@
     ec = next;
   }
 
+  if (on_scavenge_root_list()) {
+    CodeCache::drop_scavenge_root_nmethod(this);
+  }
+
   ((CodeBlob*)(this))->flush();
 
   CodeCache::free(this);
@@ -1354,7 +1380,10 @@
       return false;
     }
   }
-  assert(unloading_occurred, "Inconsistency in unloading");
+  // If ScavengeRootsInCode is true, an nmethod might be unloaded
+  // simply because one of its constant oops has gone dead.
+  // No actual classes need to be unloaded in order for this to occur.
+  assert(unloading_occurred || ScavengeRootsInCode, "Inconsistency in unloading");
   make_unloaded(is_alive, obj);
   return true;
 }
@@ -1529,13 +1558,12 @@
 // the (strong) marking phase, and then again when walking
 // the code cache contents during the weak roots processing
 // phase. The two uses are distinguished by means of the
-// do_nmethods() method in the closure "f" below -- which
-// answers "yes" in the first case, and "no" in the second
+// 'do_strong_roots_only' flag, which is true in the first
 // case. We want to walk the weak roots in the nmethod
 // only in the second case. The weak roots in the nmethod
 // are the oops in the ExceptionCache and the InlineCache
 // oops.
-void nmethod::oops_do(OopClosure* f) {
+void nmethod::oops_do(OopClosure* f, bool do_strong_roots_only) {
   // make sure the oops ready to receive visitors
   assert(!is_zombie() && !is_unloaded(),
          "should not call follow on zombie or unloaded nmethod");
@@ -1553,7 +1581,7 @@
 
   // Compiled code
   f->do_oop((oop*) &_method);
-  if (!f->do_nmethods()) {
+  if (!do_strong_roots_only) {
     // weak roots processing phase -- update ExceptionCache oops
     ExceptionCache* ec = exception_cache();
     while(ec != NULL) {
@@ -1579,12 +1607,108 @@
   }
 
   // Scopes
+  // This includes oop constants not inlined in the code stream.
   for (oop* p = oops_begin(); p < oops_end(); p++) {
     if (*p == Universe::non_oop_word())  continue;  // skip non-oops
     f->do_oop(p);
   }
 }
 
+#define NMETHOD_SENTINEL ((nmethod*)badAddress)
+
+nmethod* volatile nmethod::_oops_do_mark_nmethods;
+
+// An nmethod is "marked" if its _mark_link is set non-null.
+// Even if it is the end of the linked list, it will have a non-null link value,
+// as long as it is on the list.
+// This code must be MP safe, because it is used from parallel GC passes.
+bool nmethod::test_set_oops_do_mark() {
+  assert(nmethod::oops_do_marking_is_active(), "oops_do_marking_prologue must be called");
+  nmethod* observed_mark_link = _oops_do_mark_link;
+  if (observed_mark_link == NULL) {
+    // Claim this nmethod for this thread to mark.
+    observed_mark_link = (nmethod*)
+      Atomic::cmpxchg_ptr(NMETHOD_SENTINEL, &_oops_do_mark_link, NULL);
+    if (observed_mark_link == NULL) {
+
+      // Atomically append this nmethod (now claimed) to the head of the list:
+      nmethod* observed_mark_nmethods = _oops_do_mark_nmethods;
+      for (;;) {
+        nmethod* required_mark_nmethods = observed_mark_nmethods;
+        _oops_do_mark_link = required_mark_nmethods;
+        observed_mark_nmethods = (nmethod*)
+          Atomic::cmpxchg_ptr(this, &_oops_do_mark_nmethods, required_mark_nmethods);
+        if (observed_mark_nmethods == required_mark_nmethods)
+          break;
+      }
+      // Mark was clear when we first saw this guy.
+      NOT_PRODUCT(if (TraceScavenge)  print_on(tty, "oops_do, mark\n"));
+      return false;
+    }
+  }
+  // On fall through, another racing thread marked this nmethod before we did.
+  return true;
+}
+
+void nmethod::oops_do_marking_prologue() {
+  NOT_PRODUCT(if (TraceScavenge)  tty->print_cr("[oops_do_marking_prologue"));
+  assert(_oops_do_mark_nmethods == NULL, "must not call oops_do_marking_prologue twice in a row");
+  // We use cmpxchg_ptr instead of regular assignment here because the user
+  // may fork a bunch of threads, and we need them all to see the same state.
+  void* observed = Atomic::cmpxchg_ptr(NMETHOD_SENTINEL, &_oops_do_mark_nmethods, NULL);
+  guarantee(observed == NULL, "no races in this sequential code");
+}
+
+void nmethod::oops_do_marking_epilogue() {
+  assert(_oops_do_mark_nmethods != NULL, "must not call oops_do_marking_epilogue twice in a row");
+  nmethod* cur = _oops_do_mark_nmethods;
+  while (cur != NMETHOD_SENTINEL) {
+    assert(cur != NULL, "not NULL-terminated");
+    nmethod* next = cur->_oops_do_mark_link;
+    cur->_oops_do_mark_link = NULL;
+    NOT_PRODUCT(if (TraceScavenge)  cur->print_on(tty, "oops_do, unmark\n"));
+    cur = next;
+  }
+  void* required = _oops_do_mark_nmethods;
+  void* observed = Atomic::cmpxchg_ptr(NULL, &_oops_do_mark_nmethods, required);
+  guarantee(observed == required, "no races in this sequential code");
+  NOT_PRODUCT(if (TraceScavenge)  tty->print_cr("oops_do_marking_epilogue]"));
+}
+
+class DetectScavengeRoot: public OopClosure {
+  bool     _detected_scavenge_root;
+public:
+  DetectScavengeRoot() : _detected_scavenge_root(false)
+  { NOT_PRODUCT(_print_nm = NULL); }
+  bool detected_scavenge_root() { return _detected_scavenge_root; }
+  virtual void do_oop(oop* p) {
+    if ((*p) != NULL && (*p)->is_scavengable()) {
+      NOT_PRODUCT(maybe_print(p));
+      _detected_scavenge_root = true;
+    }
+  }
+  virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
+
+#ifndef PRODUCT
+  nmethod* _print_nm;
+  void maybe_print(oop* p) {
+    if (_print_nm == NULL)  return;
+    if (!_detected_scavenge_root)  _print_nm->print_on(tty, "new scavenge root");
+    tty->print_cr(""PTR_FORMAT"[offset=%d] detected non-perm oop "PTR_FORMAT" (found at "PTR_FORMAT")",
+                  _print_nm, (int)((intptr_t)p - (intptr_t)_print_nm),
+                  (intptr_t)(*p), (intptr_t)p);
+    (*p)->print();
+  }
+#endif //PRODUCT
+};
+
+bool nmethod::detect_scavenge_root_oops() {
+  DetectScavengeRoot detect_scavenge_root;
+  NOT_PRODUCT(if (TraceScavenge)  detect_scavenge_root._print_nm = this);
+  oops_do(&detect_scavenge_root);
+  return detect_scavenge_root.detected_scavenge_root();
+}
+
 // Method that knows how to preserve outgoing arguments at call. This method must be
 // called with a frame corresponding to a Java invoke
 void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) {
@@ -1899,6 +2023,24 @@
 // -----------------------------------------------------------------------------
 // Verification
 
+class VerifyOopsClosure: public OopClosure {
+  nmethod* _nm;
+  bool     _ok;
+public:
+  VerifyOopsClosure(nmethod* nm) : _nm(nm), _ok(true) { }
+  bool ok() { return _ok; }
+  virtual void do_oop(oop* p) {
+    if ((*p) == NULL || (*p)->is_oop())  return;
+    if (_ok) {
+      _nm->print_nmethod(true);
+      _ok = false;
+    }
+    tty->print_cr("*** non-oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)",
+                  (intptr_t)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm));
+  }
+  virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
+};
+
 void nmethod::verify() {
 
   // Hmm. OSR methods can be deopted but not marked as zombie or not_entrant
@@ -1932,6 +2074,11 @@
     }
   }
 
+  VerifyOopsClosure voc(this);
+  oops_do(&voc);
+  assert(voc.ok(), "embedded oops must be OK");
+  verify_scavenge_root_oops();
+
   verify_scopes();
 }
 
@@ -1995,19 +2142,34 @@
 // Non-product code
 #ifndef PRODUCT
 
-void nmethod::check_store() {
-  // Make sure all oops in the compiled code are tenured
+class DebugScavengeRoot: public OopClosure {
+  nmethod* _nm;
+  bool     _ok;
+public:
+  DebugScavengeRoot(nmethod* nm) : _nm(nm), _ok(true) { }
+  bool ok() { return _ok; }
+  virtual void do_oop(oop* p) {
+    if ((*p) == NULL || !(*p)->is_scavengable())  return;
+    if (_ok) {
+      _nm->print_nmethod(true);
+      _ok = false;
+    }
+    tty->print_cr("*** non-perm oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)",
+                  (intptr_t)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm));
+    (*p)->print();
+  }
+  virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
+};
 
-  RelocIterator iter(this);
-  while (iter.next()) {
-    if (iter.type() == relocInfo::oop_type) {
-      oop_Relocation* reloc = iter.oop_reloc();
-      oop obj = reloc->oop_value();
-      if (obj != NULL && !obj->is_perm()) {
-        fatal("must be permanent oop in compiled code");
-      }
-    }
+void nmethod::verify_scavenge_root_oops() {
+  if (!on_scavenge_root_list()) {
+    // Actually look inside, to verify the claim that it's clean.
+    DebugScavengeRoot debug_scavenge_root(this);
+    oops_do(&debug_scavenge_root);
+    if (!debug_scavenge_root.ok())
+      fatal("found an unadvertised bad non-perm oop in the code cache");
   }
+  assert(scavenge_root_not_marked(), "");
 }
 
 #endif // PRODUCT
@@ -2040,6 +2202,7 @@
     if (is_not_entrant()) tty->print("not_entrant ");
     if (is_zombie())      tty->print("zombie ");
     if (is_unloaded())    tty->print("unloaded ");
+    if (on_scavenge_root_list())  tty->print("scavenge_root ");
     tty->print_cr("}:");
   }
   if (size              () > 0) tty->print_cr(" total in heap  [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
--- a/src/share/vm/code/nmethod.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/code/nmethod.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -125,6 +125,7 @@
 class nmethod : public CodeBlob {
   friend class VMStructs;
   friend class NMethodSweeper;
+  friend class CodeCache;  // non-perm oops
  private:
   // Shared fields for all nmethod's
   static int _zombie_instruction_size;
@@ -132,7 +133,12 @@
   methodOop _method;
   int       _entry_bci;        // != InvocationEntryBci if this nmethod is an on-stack replacement method
 
-  nmethod*  _link;             // To support simple linked-list chaining of nmethods
+  // To support simple linked-list chaining of nmethods:
+  nmethod*  _osr_link;         // from instanceKlass::osr_nmethods_head
+  nmethod*  _scavenge_root_link; // from CodeCache::scavenge_root_nmethods
+
+  static nmethod* volatile _oops_do_mark_nmethods;
+  nmethod*        volatile _oops_do_mark_link;
 
   AbstractCompiler* _compiler; // The compiler which compiled this nmethod
 
@@ -174,6 +180,8 @@
   // used by jvmti to track if an unload event has been posted for this nmethod.
   bool _unload_reported;
 
+  jbyte _scavenge_root_state;
+
   NOT_PRODUCT(bool _has_debug_info; )
 
   // Nmethod Flushing lock (if non-zero, then the nmethod is not removed)
@@ -242,7 +250,6 @@
 
   // helper methods
   void* operator new(size_t size, int nmethod_size);
-  void check_store();
 
   const char* reloc_string_for(u_char* begin, u_char* end);
   void make_not_entrant_or_zombie(int state);
@@ -406,6 +413,24 @@
   int   version() const                           { return flags.version; }
   void  set_version(int v);
 
+  // Non-perm oop support
+  bool  on_scavenge_root_list() const                  { return (_scavenge_root_state & 1) != 0; }
+ protected:
+  enum { npl_on_list = 0x01, npl_marked = 0x10 };
+  void  set_on_scavenge_root_list()                    { _scavenge_root_state = npl_on_list; }
+  void  clear_on_scavenge_root_list()                  { _scavenge_root_state = 0; }
+  // assertion-checking and pruning logic uses the bits of _scavenge_root_state
+#ifndef PRODUCT
+  void  set_scavenge_root_marked()                     { _scavenge_root_state |= npl_marked; }
+  void  clear_scavenge_root_marked()                   { _scavenge_root_state &= ~npl_marked; }
+  bool  scavenge_root_not_marked()                     { return (_scavenge_root_state &~ npl_on_list) == 0; }
+  // N.B. there is no positive marked query, and we only use the not_marked query for asserts.
+#endif //PRODUCT
+  nmethod* scavenge_root_link() const                  { return _scavenge_root_link; }
+  void     set_scavenge_root_link(nmethod *n)          { _scavenge_root_link = n; }
+
+ public:
+
   // Sweeper support
   long  stack_traversal_mark()                    { return _stack_traversal_mark; }
   void  set_stack_traversal_mark(long l)          { _stack_traversal_mark = l; }
@@ -424,8 +449,8 @@
   int   osr_entry_bci() const                     { assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod"); return _entry_bci; }
   address  osr_entry() const                      { assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod"); return _osr_entry_point; }
   void  invalidate_osr_method();
-  nmethod* link() const                           { return _link; }
-  void     set_link(nmethod *n)                   { _link = n; }
+  nmethod* osr_link() const                       { return _osr_link; }
+  void     set_osr_link(nmethod *n)               { _osr_link = n; }
 
   // tells whether frames described by this nmethod can be deoptimized
   // note: native wrappers cannot be deoptimized.
@@ -465,7 +490,16 @@
 
   void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map,
                                      OopClosure* f);
-  void oops_do(OopClosure* f);
+  virtual void oops_do(OopClosure* f) { oops_do(f, false); }
+  void         oops_do(OopClosure* f, bool do_strong_roots_only);
+  bool detect_scavenge_root_oops();
+  void verify_scavenge_root_oops() PRODUCT_RETURN;
+
+  bool test_set_oops_do_mark();
+  static void oops_do_marking_prologue();
+  static void oops_do_marking_epilogue();
+  static bool oops_do_marking_is_active() { return _oops_do_mark_nmethods != NULL; }
+  DEBUG_ONLY(bool test_oops_do_mark() { return _oops_do_mark_link != NULL; })
 
   // ScopeDesc for an instruction
   ScopeDesc* scope_desc_at(address pc);
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -47,20 +47,15 @@
  private:
   const MemRegion _span;
   CMSBitMap*      _bitMap;
-  const bool      _should_do_nmethods;
  protected:
   DO_OOP_WORK_DEFN
  public:
-  MarkRefsIntoClosure(MemRegion span, CMSBitMap* bitMap,
-                      bool should_do_nmethods);
+  MarkRefsIntoClosure(MemRegion span, CMSBitMap* bitMap);
   virtual void do_oop(oop* p);
   virtual void do_oop(narrowOop* p);
   inline void do_oop_nv(oop* p)       { MarkRefsIntoClosure::do_oop_work(p); }
   inline void do_oop_nv(narrowOop* p) { MarkRefsIntoClosure::do_oop_work(p); }
   bool do_header() { return true; }
-  virtual const bool do_nmethods() const {
-    return _should_do_nmethods;
-  }
   Prefetch::style prefetch_style() {
     return Prefetch::do_read;
   }
@@ -73,20 +68,16 @@
   const MemRegion _span;
   CMSBitMap*      _verification_bm;
   CMSBitMap*      _cms_bm;
-  const bool      _should_do_nmethods;
  protected:
   DO_OOP_WORK_DEFN
  public:
   MarkRefsIntoVerifyClosure(MemRegion span, CMSBitMap* verification_bm,
-                            CMSBitMap* cms_bm, bool should_do_nmethods);
+                            CMSBitMap* cms_bm);
   virtual void do_oop(oop* p);
   virtual void do_oop(narrowOop* p);
   inline void do_oop_nv(oop* p)       { MarkRefsIntoVerifyClosure::do_oop_work(p); }
   inline void do_oop_nv(narrowOop* p) { MarkRefsIntoVerifyClosure::do_oop_work(p); }
   bool do_header() { return true; }
-  virtual const bool do_nmethods() const {
-    return _should_do_nmethods;
-  }
   Prefetch::style prefetch_style() {
     return Prefetch::do_read;
   }
@@ -228,7 +219,6 @@
   inline void do_oop_nv(oop* p)       { MarkRefsIntoAndScanClosure::do_oop_work(p); }
   inline void do_oop_nv(narrowOop* p) { MarkRefsIntoAndScanClosure::do_oop_work(p); }
   bool do_header() { return true; }
-  virtual const bool do_nmethods() const { return true; }
   Prefetch::style prefetch_style() {
     return Prefetch::do_read;
   }
@@ -273,7 +263,6 @@
   inline void do_oop_nv(oop* p)       { Par_MarkRefsIntoAndScanClosure::do_oop_work(p); }
   inline void do_oop_nv(narrowOop* p) { Par_MarkRefsIntoAndScanClosure::do_oop_work(p); }
   bool do_header() { return true; }
-  virtual const bool do_nmethods() const { return true; }
   // When ScanMarkedObjectsAgainClosure is used,
   // it passes [Par_]MarkRefsIntoAndScanClosure to oop_oop_iterate(),
   // and this delegation is used.
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -2852,14 +2852,17 @@
   GenCollectedHeap* gch = GenCollectedHeap::heap();
 
   // Mark from roots one level into CMS
-  MarkRefsIntoClosure notOlder(_span, verification_mark_bm(), true /* nmethods */);
+  MarkRefsIntoClosure notOlder(_span, verification_mark_bm());
   gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
 
   gch->gen_process_strong_roots(_cmsGen->level(),
                                 true,   // younger gens are roots
+                                true,   // activate StrongRootsScope
                                 true,   // collecting perm gen
                                 SharedHeap::ScanningOption(roots_scanning_options()),
-                                NULL, &notOlder);
+                                &notOlder,
+                                true,   // walk code active on stacks
+                                NULL);
 
   // Now mark from the roots
   assert(_revisitStack.isEmpty(), "Should be empty");
@@ -2901,13 +2904,16 @@
 
   // Mark from roots one level into CMS
   MarkRefsIntoVerifyClosure notOlder(_span, verification_mark_bm(),
-                                     markBitMap(), true /* nmethods */);
+                                     markBitMap());
   gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
   gch->gen_process_strong_roots(_cmsGen->level(),
                                 true,   // younger gens are roots
+                                true,   // activate StrongRootsScope
                                 true,   // collecting perm gen
                                 SharedHeap::ScanningOption(roots_scanning_options()),
-                                NULL, &notOlder);
+                                &notOlder,
+                                true,   // walk code active on stacks
+                                NULL);
 
   // Now mark from the roots
   assert(_revisitStack.isEmpty(), "Should be empty");
@@ -3484,8 +3490,10 @@
   FalseClosure falseClosure;
   // In the case of a synchronous collection, we will elide the
   // remark step, so it's important to catch all the nmethod oops
-  // in this step; hence the last argument to the constrcutor below.
-  MarkRefsIntoClosure notOlder(_span, &_markBitMap, !asynch /* nmethods */);
+  // in this step.
+  // The final 'true' flag to gen_process_strong_roots will ensure this.
+  // If 'async' is true, we can relax the nmethod tracing.
+  MarkRefsIntoClosure notOlder(_span, &_markBitMap);
   GenCollectedHeap* gch = GenCollectedHeap::heap();
 
   verify_work_stacks_empty();
@@ -3504,9 +3512,12 @@
     gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
     gch->gen_process_strong_roots(_cmsGen->level(),
                                   true,   // younger gens are roots
+                                  true,   // activate StrongRootsScope
                                   true,   // collecting perm gen
                                   SharedHeap::ScanningOption(roots_scanning_options()),
-                                  NULL, &notOlder);
+                                  &notOlder,
+                                  true,   // walk all of code cache if (so & SO_CodeCache)
+                                  NULL);
   }
 
   // Clear mod-union table; it will be dirtied in the prologue of
@@ -5040,9 +5051,15 @@
   _timer.start();
   gch->gen_process_strong_roots(_collector->_cmsGen->level(),
                                 false,     // yg was scanned above
+                                false,     // this is parallel code
                                 true,      // collecting perm gen
                                 SharedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
-                                NULL, &par_mrias_cl);
+                                &par_mrias_cl,
+                                true,   // walk all of code cache if (so & SO_CodeCache)
+                                NULL);
+  assert(_collector->should_unload_classes()
+         || (_collector->CMSCollector::roots_scanning_options() & SharedHeap::SO_CodeCache),
+         "if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops");
   _timer.stop();
   if (PrintCMSStatistics != 0) {
     gclog_or_tty->print_cr(
@@ -5423,7 +5440,6 @@
 
   // Set up for parallel process_strong_roots work.
   gch->set_par_threads(n_workers);
-  gch->change_strong_roots_parity();
   // We won't be iterating over the cards in the card table updating
   // the younger_gen cards, so we shouldn't call the following else
   // the verification code as well as subsequent younger_refs_iterate
@@ -5454,8 +5470,10 @@
   if (n_workers > 1) {
     // Make refs discovery MT-safe
     ReferenceProcessorMTMutator mt(ref_processor(), true);
+    GenCollectedHeap::StrongRootsScope srs(gch);
     workers->run_task(&tsk);
   } else {
+    GenCollectedHeap::StrongRootsScope srs(gch);
     tsk.work(0);
   }
   gch->set_par_threads(0);  // 0 ==> non-parallel.
@@ -5539,11 +5557,18 @@
     verify_work_stacks_empty();
 
     gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
+    GenCollectedHeap::StrongRootsScope srs(gch);
     gch->gen_process_strong_roots(_cmsGen->level(),
                                   true,  // younger gens as roots
+                                  false, // use the local StrongRootsScope
                                   true,  // collecting perm gen
                                   SharedHeap::ScanningOption(roots_scanning_options()),
-                                  NULL, &mrias_cl);
+                                  &mrias_cl,
+                                  true,   // walk code active on stacks
+                                  NULL);
+    assert(should_unload_classes()
+           || (roots_scanning_options() & SharedHeap::SO_CodeCache),
+           "if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops");
   }
   verify_work_stacks_empty();
   // Restore evacuated mark words, if any, used for overflow list links
@@ -6418,10 +6443,9 @@
 // generation then this will lose younger_gen cards!
 
 MarkRefsIntoClosure::MarkRefsIntoClosure(
-  MemRegion span, CMSBitMap* bitMap, bool should_do_nmethods):
+  MemRegion span, CMSBitMap* bitMap):
     _span(span),
-    _bitMap(bitMap),
-    _should_do_nmethods(should_do_nmethods)
+    _bitMap(bitMap)
 {
     assert(_ref_processor == NULL, "deliberately left NULL");
     assert(_bitMap->covers(_span), "_bitMap/_span mismatch");
@@ -6442,12 +6466,11 @@
 
 // A variant of the above, used for CMS marking verification.
 MarkRefsIntoVerifyClosure::MarkRefsIntoVerifyClosure(
-  MemRegion span, CMSBitMap* verification_bm, CMSBitMap* cms_bm,
-  bool should_do_nmethods):
+  MemRegion span, CMSBitMap* verification_bm, CMSBitMap* cms_bm):
     _span(span),
     _verification_bm(verification_bm),
-    _cms_bm(cms_bm),
-    _should_do_nmethods(should_do_nmethods) {
+    _cms_bm(cms_bm)
+{
     assert(_ref_processor == NULL, "deliberately left NULL");
     assert(_verification_bm->covers(_span), "_verification_bm/_span mismatch");
 }
--- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -746,10 +746,11 @@
   // clear the mark bitmap (no grey objects to start with)
   _nextMarkBitMap->clearAll();
   PrintReachableClosure prcl(_nextMarkBitMap);
-  g1h->process_strong_roots(
+  g1h->process_strong_roots(true,    // activate StrongRootsScope
                             false,   // fake perm gen collection
                             SharedHeap::SO_AllClasses,
                             &prcl, // Regular roots
+                            NULL,  // do not visit active blobs
                             &prcl    // Perm Gen Roots
                             );
   // The root iteration above "consumed" dirty cards in the perm gen.
@@ -852,9 +853,11 @@
   g1h->set_marking_started();
   g1h->rem_set()->prepare_for_younger_refs_iterate(false);
 
-  g1h->process_strong_roots(false,   // fake perm gen collection
+  g1h->process_strong_roots(true,    // activate StrongRootsScope
+                            false,   // fake perm gen collection
                             SharedHeap::SO_AllClasses,
                             &notOlder, // Regular roots
+                            NULL,     // do not visit active blobs
                             &older    // Perm Gen Roots
                             );
   checkpointRootsInitialPost();
@@ -1915,7 +1918,7 @@
   g1h->ensure_parsability(false);
 
   if (ParallelGCThreads > 0) {
-    g1h->change_strong_roots_parity();
+    G1CollectedHeap::StrongRootsScope srs(g1h);
     // this is remark, so we'll use up all available threads
     int active_workers = ParallelGCThreads;
     set_phase(active_workers, false);
@@ -1932,7 +1935,7 @@
     SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
     guarantee( satb_mq_set.completed_buffers_num() == 0, "invariant" );
   } else {
-    g1h->change_strong_roots_parity();
+    G1CollectedHeap::StrongRootsScope srs(g1h);
     // this is remark, so we'll use up all available threads
     int active_workers = 1;
     set_phase(active_workers, false);
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -2300,9 +2300,12 @@
   if (SafepointSynchronize::is_at_safepoint() || ! UseTLAB) {
     if (!silent) { gclog_or_tty->print("roots "); }
     VerifyRootsClosure rootsCl(use_prev_marking);
-    process_strong_roots(false,
+    CodeBlobToOopClosure blobsCl(&rootsCl, /*do_marking=*/ false);
+    process_strong_roots(true,  // activate StrongRootsScope
+                         false,
                          SharedHeap::SO_AllClasses,
                          &rootsCl,
+                         &blobsCl,
                          &rootsCl);
     rem_set()->invalidate(perm_gen()->used_region(), false);
     if (!silent) { gclog_or_tty->print("heapRegions "); }
@@ -3987,8 +3990,14 @@
   BufferingOopsInGenClosure buf_scan_perm(scan_perm);
   buf_scan_perm.set_generation(perm_gen());
 
-  process_strong_roots(collecting_perm_gen, so,
+  // Walk the code cache w/o buffering, because StarTask cannot handle
+  // unaligned oop locations.
+  CodeBlobToOopClosure eager_scan_code_roots(scan_non_heap_roots, /*do_marking=*/ true);
+
+  process_strong_roots(false, // no scoping; this is parallel code
+                       collecting_perm_gen, so,
                        &buf_scan_non_heap_roots,
+                       &eager_scan_code_roots,
                        &buf_scan_perm);
   // Finish up any enqueued closure apps.
   buf_scan_non_heap_roots.done();
@@ -4078,7 +4087,8 @@
 void
 G1CollectedHeap::g1_process_weak_roots(OopClosure* root_closure,
                                        OopClosure* non_root_closure) {
-  SharedHeap::process_weak_roots(root_closure, non_root_closure);
+  CodeBlobToOopClosure roots_in_blobs(root_closure, /*do_marking=*/ false);
+  SharedHeap::process_weak_roots(root_closure, &roots_in_blobs, non_root_closure);
 }
 
 
@@ -4112,15 +4122,16 @@
 
   init_for_evac_failure(NULL);
 
-  change_strong_roots_parity();  // In preparation for parallel strong roots.
   rem_set()->prepare_for_younger_refs_iterate(true);
 
   assert(dirty_card_queue_set().completed_buffers_num() == 0, "Should be empty");
   double start_par = os::elapsedTime();
   if (ParallelGCThreads > 0) {
     // The individual threads will set their evac-failure closures.
+    StrongRootsScope srs(this);
     workers()->run_task(&g1_par_task);
   } else {
+    StrongRootsScope srs(this);
     g1_par_task.work(0);
   }
 
--- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -121,9 +121,11 @@
 
   SharedHeap* sh = SharedHeap::heap();
 
-  sh->process_strong_roots(true,  // Collecting permanent generation.
+  sh->process_strong_roots(true,  // activeate StrongRootsScope
+                           true,  // Collecting permanent generation.
                            SharedHeap::SO_SystemClasses,
                            &GenMarkSweep::follow_root_closure,
+                           &GenMarkSweep::follow_code_root_closure,
                            &GenMarkSweep::follow_root_closure);
 
   // Process reference objects found during marking
@@ -286,9 +288,11 @@
 
   SharedHeap* sh = SharedHeap::heap();
 
-  sh->process_strong_roots(true,  // Collecting permanent generation.
+  sh->process_strong_roots(true,  // activate StrongRootsScope
+                           true,  // Collecting permanent generation.
                            SharedHeap::SO_AllClasses,
                            &GenMarkSweep::adjust_root_pointer_closure,
+                           NULL,  // do not touch code cache here
                            &GenMarkSweep::adjust_pointer_closure);
 
   g1h->ref_processor()->weak_oops_do(&GenMarkSweep::adjust_root_pointer_closure);
--- a/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge	Wed Sep 30 13:25:39 2009 -0700
@@ -373,6 +373,7 @@
 psScavenge.inline.hpp                   psPromotionManager.hpp
 psScavenge.inline.hpp                   psScavenge.hpp
 
+pcTasks.cpp                             codeCache.hpp
 pcTasks.cpp                             collectedHeap.hpp
 pcTasks.cpp                             fprofiler.hpp
 pcTasks.cpp                             jniHandles.hpp
@@ -392,6 +393,7 @@
 pcTasks.hpp				psTasks.hpp
 
 psTasks.cpp                             cardTableExtension.hpp
+psTasks.cpp                             codeCache.hpp
 psTasks.cpp                             fprofiler.hpp
 psTasks.cpp                             gcTaskManager.hpp
 psTasks.cpp                             iterator.hpp
--- a/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -480,12 +480,14 @@
 
   par_scan_state.start_strong_roots();
   gch->gen_process_strong_roots(_gen->level(),
-                                true, // Process younger gens, if any,
-                                      // as strong roots.
-                                false,// not collecting perm generation.
+                                true,  // Process younger gens, if any,
+                                       // as strong roots.
+                                false, // no scope; this is parallel code
+                                false, // not collecting perm generation.
                                 SharedHeap::SO_AllClasses,
-                                &par_scan_state.older_gen_closure(),
-                                &par_scan_state.to_space_root_closure());
+                                &par_scan_state.to_space_root_closure(),
+                                true,   // walk *all* scavengable nmethods
+                                &par_scan_state.older_gen_closure());
   par_scan_state.end_strong_roots();
 
   // "evacuate followers".
@@ -799,15 +801,16 @@
   ParNewGenTask tsk(this, _next_gen, reserved().end(), &thread_state_set);
   int n_workers = workers->total_workers();
   gch->set_par_threads(n_workers);
-  gch->change_strong_roots_parity();
   gch->rem_set()->prepare_for_younger_refs_iterate(true);
   // It turns out that even when we're using 1 thread, doing the work in a
   // separate thread causes wide variance in run times.  We can't help this
   // in the multi-threaded case, but we special-case n=1 here to get
   // repeatable measurements of the 1-thread overhead of the parallel code.
   if (n_workers > 1) {
+    GenCollectedHeap::StrongRootsScope srs(gch);
     workers->run_task(&tsk);
   } else {
+    GenCollectedHeap::StrongRootsScope srs(gch);
     tsk.work(0);
   }
   thread_state_set.reset();
--- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -962,6 +962,14 @@
   _old_gen->resize(desired_free_space);
 }
 
+ParallelScavengeHeap::ParStrongRootsScope::ParStrongRootsScope() {
+  // nothing particular
+}
+
+ParallelScavengeHeap::ParStrongRootsScope::~ParStrongRootsScope() {
+  // nothing particular
+}
+
 #ifndef PRODUCT
 void ParallelScavengeHeap::record_gen_tops_before_GC() {
   if (ZapUnusedHeapArea) {
--- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -234,6 +234,13 @@
 
   // Mangle the unused parts of all spaces in the heap
   void gen_mangle_unused_area() PRODUCT_RETURN;
+
+  // Call these in sequential code around the processing of strong roots.
+  class ParStrongRootsScope : public MarkingCodeBlobClosure::MarkScope {
+  public:
+    ParStrongRootsScope();
+    ~ParStrongRootsScope();
+  };
 };
 
 inline size_t ParallelScavengeHeap::set_alignment(size_t& var, size_t val)
--- a/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -39,12 +39,13 @@
   ParCompactionManager* cm =
     ParCompactionManager::gc_thread_compaction_manager(which);
   PSParallelCompact::MarkAndPushClosure mark_and_push_closure(cm);
+  CodeBlobToOopClosure mark_and_push_in_blobs(&mark_and_push_closure, /*do_marking=*/ true);
 
   if (_java_thread != NULL)
-    _java_thread->oops_do(&mark_and_push_closure);
+    _java_thread->oops_do(&mark_and_push_closure, &mark_and_push_in_blobs);
 
   if (_vm_thread != NULL)
-    _vm_thread->oops_do(&mark_and_push_closure);
+    _vm_thread->oops_do(&mark_and_push_closure, &mark_and_push_in_blobs);
 
   // Do the real work
   cm->drain_marking_stacks(&mark_and_push_closure);
@@ -78,7 +79,8 @@
     case threads:
     {
       ResourceMark rm;
-      Threads::oops_do(&mark_and_push_closure);
+      CodeBlobToOopClosure each_active_code_blob(&mark_and_push_closure, /*do_marking=*/ true);
+      Threads::oops_do(&mark_and_push_closure, &each_active_code_blob);
     }
     break;
 
@@ -106,6 +108,11 @@
       vmSymbols::oops_do(&mark_and_push_closure);
       break;
 
+    case code_cache:
+      // Do not treat nmethods as strong roots for mark/sweep, since we can unload them.
+      //CodeCache::scavenge_root_nmethods_do(CodeBlobToOopClosure(&mark_and_push_closure));
+      break;
+
     default:
       fatal("Unknown root type");
   }
--- a/src/share/vm/gc_implementation/parallelScavenge/pcTasks.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/pcTasks.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -92,7 +92,8 @@
     jvmti                 = 7,
     system_dictionary     = 8,
     vm_symbols            = 9,
-    reference_processing  = 10
+    reference_processing  = 10,
+    code_cache            = 11
   };
  private:
   RootType _root_type;
--- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -511,16 +511,22 @@
   assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");
 
   // General strong roots.
-  Universe::oops_do(mark_and_push_closure());
-  ReferenceProcessor::oops_do(mark_and_push_closure());
-  JNIHandles::oops_do(mark_and_push_closure());   // Global (strong) JNI handles
-  Threads::oops_do(mark_and_push_closure());
-  ObjectSynchronizer::oops_do(mark_and_push_closure());
-  FlatProfiler::oops_do(mark_and_push_closure());
-  Management::oops_do(mark_and_push_closure());
-  JvmtiExport::oops_do(mark_and_push_closure());
-  SystemDictionary::always_strong_oops_do(mark_and_push_closure());
-  vmSymbols::oops_do(mark_and_push_closure());
+  {
+    ParallelScavengeHeap::ParStrongRootsScope psrs;
+    Universe::oops_do(mark_and_push_closure());
+    ReferenceProcessor::oops_do(mark_and_push_closure());
+    JNIHandles::oops_do(mark_and_push_closure());   // Global (strong) JNI handles
+    CodeBlobToOopClosure each_active_code_blob(mark_and_push_closure(), /*do_marking=*/ true);
+    Threads::oops_do(mark_and_push_closure(), &each_active_code_blob);
+    ObjectSynchronizer::oops_do(mark_and_push_closure());
+    FlatProfiler::oops_do(mark_and_push_closure());
+    Management::oops_do(mark_and_push_closure());
+    JvmtiExport::oops_do(mark_and_push_closure());
+    SystemDictionary::always_strong_oops_do(mark_and_push_closure());
+    vmSymbols::oops_do(mark_and_push_closure());
+    // Do not treat nmethods as strong roots for mark/sweep, since we can unload them.
+    //CodeCache::scavenge_root_nmethods_do(CodeBlobToOopClosure(mark_and_push_closure()));
+  }
 
   // Flush marking stack.
   follow_stack();
@@ -617,7 +623,7 @@
   Universe::oops_do(adjust_root_pointer_closure());
   ReferenceProcessor::oops_do(adjust_root_pointer_closure());
   JNIHandles::oops_do(adjust_root_pointer_closure());   // Global (strong) JNI handles
-  Threads::oops_do(adjust_root_pointer_closure());
+  Threads::oops_do(adjust_root_pointer_closure(), NULL);
   ObjectSynchronizer::oops_do(adjust_root_pointer_closure());
   FlatProfiler::oops_do(adjust_root_pointer_closure());
   Management::oops_do(adjust_root_pointer_closure());
@@ -625,6 +631,7 @@
   // SO_AllClasses
   SystemDictionary::oops_do(adjust_root_pointer_closure());
   vmSymbols::oops_do(adjust_root_pointer_closure());
+  //CodeCache::scavenge_root_nmethods_oops_do(adjust_root_pointer_closure());
 
   // Now adjust pointers in remaining weak roots.  (All of which should
   // have been cleared if they pointed to non-surviving objects.)
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -2322,6 +2322,7 @@
 
   {
     TraceTime tm_m("par mark", print_phases(), true, gclog_or_tty);
+    ParallelScavengeHeap::ParStrongRootsScope psrs;
 
     GCTaskQueue* q = GCTaskQueue::create();
 
@@ -2335,6 +2336,7 @@
     q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::system_dictionary));
     q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::jvmti));
     q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::vm_symbols));
+    q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::code_cache));
 
     if (parallel_gc_threads > 1) {
       for (uint j = 0; j < parallel_gc_threads; j++) {
@@ -2408,7 +2410,7 @@
   Universe::oops_do(adjust_root_pointer_closure());
   ReferenceProcessor::oops_do(adjust_root_pointer_closure());
   JNIHandles::oops_do(adjust_root_pointer_closure());   // Global (strong) JNI handles
-  Threads::oops_do(adjust_root_pointer_closure());
+  Threads::oops_do(adjust_root_pointer_closure(), NULL);
   ObjectSynchronizer::oops_do(adjust_root_pointer_closure());
   FlatProfiler::oops_do(adjust_root_pointer_closure());
   Management::oops_do(adjust_root_pointer_closure());
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -799,8 +799,7 @@
     FollowRootClosure(ParCompactionManager* cm) : _compaction_manager(cm) { }
     virtual void do_oop(oop* p);
     virtual void do_oop(narrowOop* p);
-    virtual const bool do_nmethods() const { return true; }
-  };
+ };
 
   class FollowStackClosure: public VoidClosure {
    private:
@@ -817,6 +816,8 @@
     AdjustPointerClosure(bool is_root) : _is_root(is_root) { }
     virtual void do_oop(oop* p);
     virtual void do_oop(narrowOop* p);
+    // do not walk from thread stacks to the code cache on this phase
+    virtual void do_code_blob(CodeBlob* cb) const { }
   };
 
   // Closure for verifying update of pointers.  Does not
@@ -1063,7 +1064,6 @@
     MarkAndPushClosure(ParCompactionManager* cm) : _compaction_manager(cm) { }
     virtual void do_oop(oop* p);
     virtual void do_oop(narrowOop* p);
-    virtual const bool do_nmethods() const { return true; }
   };
 
   PSParallelCompact();
--- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -358,6 +358,7 @@
     PSPromotionManager* promotion_manager = PSPromotionManager::vm_thread_promotion_manager();
     {
       // TraceTime("Roots");
+      ParallelScavengeHeap::ParStrongRootsScope psrs;
 
       GCTaskQueue* q = GCTaskQueue::create();
 
@@ -376,6 +377,7 @@
       q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::management));
       q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::system_dictionary));
       q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::jvmti));
+      q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::code_cache));
 
       ParallelTaskTerminator terminator(
         gc_task_manager()->workers(),
--- a/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -66,7 +66,7 @@
     case threads:
     {
       ResourceMark rm;
-      Threads::oops_do(&roots_closure);
+      Threads::oops_do(&roots_closure, NULL);
     }
     break;
 
@@ -90,6 +90,14 @@
       JvmtiExport::oops_do(&roots_closure);
       break;
 
+
+    case code_cache:
+      {
+        CodeBlobToOopClosure each_scavengable_code_blob(&roots_closure, /*do_marking=*/ true);
+        CodeCache::scavenge_root_nmethods_do(&each_scavengable_code_blob);
+      }
+      break;
+
     default:
       fatal("Unknown root type");
   }
@@ -107,12 +115,13 @@
 
   PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(which);
   PSScavengeRootsClosure roots_closure(pm);
+  CodeBlobToOopClosure roots_in_blobs(&roots_closure, /*do_marking=*/ true);
 
   if (_java_thread != NULL)
-    _java_thread->oops_do(&roots_closure);
+    _java_thread->oops_do(&roots_closure, &roots_in_blobs);
 
   if (_vm_thread != NULL)
-    _vm_thread->oops_do(&roots_closure);
+    _vm_thread->oops_do(&roots_closure, &roots_in_blobs);
 
   // Do the real work
   pm->drain_stacks(false);
--- a/src/share/vm/gc_implementation/parallelScavenge/psTasks.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/psTasks.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -54,7 +54,8 @@
     flat_profiler         = 5,
     system_dictionary     = 6,
     management            = 7,
-    jvmti                 = 8
+    jvmti                 = 8,
+    code_cache            = 9
   };
  private:
   RootType _root_type;
--- a/src/share/vm/gc_implementation/shared/markSweep.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/shared/markSweep.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -93,6 +93,7 @@
 }
 
 MarkSweep::FollowRootClosure  MarkSweep::follow_root_closure;
+CodeBlobToOopClosure MarkSweep::follow_code_root_closure(&MarkSweep::follow_root_closure, /*do_marking=*/ true);
 
 void MarkSweep::FollowRootClosure::do_oop(oop* p)       { follow_root(p); }
 void MarkSweep::FollowRootClosure::do_oop(narrowOop* p) { follow_root(p); }
--- a/src/share/vm/gc_implementation/shared/markSweep.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_implementation/shared/markSweep.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -58,14 +58,12 @@
    public:
     virtual void do_oop(oop* p);
     virtual void do_oop(narrowOop* p);
-    virtual const bool do_nmethods() const { return true; }
   };
 
   class MarkAndPushClosure: public OopClosure {
    public:
     virtual void do_oop(oop* p);
     virtual void do_oop(narrowOop* p);
-    virtual const bool do_nmethods() const { return true; }
     virtual const bool should_remember_mdo() const { return true; }
     virtual void remember_mdo(DataLayout* p) { MarkSweep::revisit_mdo(p); }
   };
@@ -173,6 +171,7 @@
  public:
   // Public closures
   static FollowRootClosure    follow_root_closure;
+  static CodeBlobToOopClosure follow_code_root_closure; // => follow_root_closure
   static MarkAndPushClosure   mark_and_push_closure;
   static FollowStackClosure   follow_stack_closure;
   static AdjustPointerClosure adjust_root_pointer_closure;
--- a/src/share/vm/gc_interface/collectedHeap.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/gc_interface/collectedHeap.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -263,6 +263,14 @@
     return p == NULL || is_permanent(p);
   }
 
+  // An object is scavengable if its location may move during a scavenge.
+  // (A scavenge is a GC which is not a full GC.)
+  // Currently, this just means it is not perm (and not null).
+  // This could change if we rethink what's in perm-gen.
+  bool is_scavengable(const void *p) const {
+    return !is_in_permanent_or_null(p);
+  }
+
   // Returns "TRUE" if "p" is a method oop in the
   // current heap, with high probability. This predicate
   // is not stable, in general.
--- a/src/share/vm/memory/defNewGeneration.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/memory/defNewGeneration.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -555,12 +555,14 @@
          "save marks have not been newly set.");
 
   gch->gen_process_strong_roots(_level,
-                                true, // Process younger gens, if any, as
-                                      // strong roots.
-                                false,// not collecting permanent generation.
+                                true,  // Process younger gens, if any,
+                                       // as strong roots.
+                                true,  // activate StrongRootsScope
+                                false, // not collecting perm generation.
                                 SharedHeap::SO_AllClasses,
-                                &fsc_with_gc_barrier,
-                                &fsc_with_no_gc_barrier);
+                                &fsc_with_no_gc_barrier,
+                                true,   // walk *all* scavengable nmethods
+                                &fsc_with_gc_barrier);
 
   // "evacuate followers".
   evacuate_followers.do_void();
--- a/src/share/vm/memory/genCollectedHeap.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/memory/genCollectedHeap.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -677,13 +677,23 @@
 void GenCollectedHeap::
 gen_process_strong_roots(int level,
                          bool younger_gens_as_roots,
+                         bool activate_scope,
                          bool collecting_perm_gen,
                          SharedHeap::ScanningOption so,
-                         OopsInGenClosure* older_gens,
-                         OopsInGenClosure* not_older_gens) {
+                         OopsInGenClosure* not_older_gens,
+                         bool do_code_roots,
+                         OopsInGenClosure* older_gens) {
   // General strong roots.
-  SharedHeap::process_strong_roots(collecting_perm_gen, so,
-                                   not_older_gens, older_gens);
+
+  if (!do_code_roots) {
+    SharedHeap::process_strong_roots(activate_scope, collecting_perm_gen, so,
+                                     not_older_gens, NULL, older_gens);
+  } else {
+    bool do_code_marking = (activate_scope || nmethod::oops_do_marking_is_active());
+    CodeBlobToOopClosure code_roots(not_older_gens, /*do_marking=*/ do_code_marking);
+    SharedHeap::process_strong_roots(activate_scope, collecting_perm_gen, so,
+                                     not_older_gens, &code_roots, older_gens);
+  }
 
   if (younger_gens_as_roots) {
     if (!_gen_process_strong_tasks->is_task_claimed(GCH_PS_younger_gens)) {
@@ -706,8 +716,9 @@
 }
 
 void GenCollectedHeap::gen_process_weak_roots(OopClosure* root_closure,
+                                              CodeBlobClosure* code_roots,
                                               OopClosure* non_root_closure) {
-  SharedHeap::process_weak_roots(root_closure, non_root_closure);
+  SharedHeap::process_weak_roots(root_closure, code_roots, non_root_closure);
   // "Local" "weak" refs
   for (int i = 0; i < _n_gens; i++) {
     _gens[i]->ref_processor()->weak_oops_do(root_closure);
--- a/src/share/vm/memory/genCollectedHeap.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/memory/genCollectedHeap.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -408,16 +408,22 @@
   // "SO_SystemClasses" to all the "system" classes and loaders;
   // "SO_Symbols_and_Strings" applies the closure to all entries in
   // SymbolsTable and StringTable.
-  void gen_process_strong_roots(int level, bool younger_gens_as_roots,
+  void gen_process_strong_roots(int level,
+                                bool younger_gens_as_roots,
+                                // The remaining arguments are in an order
+                                // consistent with SharedHeap::process_strong_roots:
+                                bool activate_scope,
                                 bool collecting_perm_gen,
                                 SharedHeap::ScanningOption so,
-                                OopsInGenClosure* older_gens,
-                                OopsInGenClosure* not_older_gens);
+                                OopsInGenClosure* not_older_gens,
+                                bool do_code_roots,
+                                OopsInGenClosure* older_gens);
 
   // Apply "blk" to all the weak roots of the system.  These include
   // JNI weak roots, the code cache, system dictionary, symbol table,
   // string table, and referents of reachable weak refs.
   void gen_process_weak_roots(OopClosure* root_closure,
+                              CodeBlobClosure* code_roots,
                               OopClosure* non_root_closure);
 
   // Set the saved marks of generations, if that makes sense.
--- a/src/share/vm/memory/genMarkSweep.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/memory/genMarkSweep.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -244,9 +244,12 @@
 
   gch->gen_process_strong_roots(level,
                                 false, // Younger gens are not roots.
+                                true,  // activate StrongRootsScope
                                 true,  // Collecting permanent generation.
                                 SharedHeap::SO_SystemClasses,
-                                &follow_root_closure, &follow_root_closure);
+                                &follow_root_closure,
+                                true,   // walk code active on stacks
+                                &follow_root_closure);
 
   // Process reference objects found during marking
   {
@@ -338,14 +341,19 @@
 
   gch->gen_process_strong_roots(level,
                                 false, // Younger gens are not roots.
+                                true,  // activate StrongRootsScope
                                 true,  // Collecting permanent generation.
                                 SharedHeap::SO_AllClasses,
                                 &adjust_root_pointer_closure,
+                                false, // do not walk code
                                 &adjust_root_pointer_closure);
 
   // Now adjust pointers in remaining weak roots.  (All of which should
   // have been cleared if they pointed to non-surviving objects.)
+  CodeBlobToOopClosure adjust_code_pointer_closure(&adjust_pointer_closure,
+                                                   /*do_marking=*/ false);
   gch->gen_process_weak_roots(&adjust_root_pointer_closure,
+                              &adjust_code_pointer_closure,
                               &adjust_pointer_closure);
 
   adjust_marks();
--- a/src/share/vm/memory/iterator.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/memory/iterator.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -46,3 +46,42 @@
 }
 #endif
 
+
+MarkingCodeBlobClosure::MarkScope::MarkScope(bool activate)
+  : _active(activate)
+{
+  if (_active)  nmethod::oops_do_marking_prologue();
+}
+
+MarkingCodeBlobClosure::MarkScope::~MarkScope() {
+  if (_active)  nmethod::oops_do_marking_epilogue();
+}
+
+void MarkingCodeBlobClosure::do_code_blob(CodeBlob* cb) {
+  if (!cb->is_nmethod())  return;
+  nmethod* nm = (nmethod*) cb;
+  if (!nm->test_set_oops_do_mark()) {
+    NOT_PRODUCT(if (TraceScavenge)  nm->print_on(tty, "oops_do, 1st visit\n"));
+    do_newly_marked_nmethod(nm);
+  } else {
+    NOT_PRODUCT(if (TraceScavenge)  nm->print_on(tty, "oops_do, skipped on 2nd visit\n"));
+  }
+}
+
+void CodeBlobToOopClosure::do_newly_marked_nmethod(nmethod* nm) {
+  nm->oops_do(_cl, /*do_strong_roots_only=*/ true);
+}
+
+void CodeBlobToOopClosure::do_code_blob(CodeBlob* cb) {
+  if (!_do_marking) {
+    NOT_PRODUCT(if (TraceScavenge && Verbose && cb->is_nmethod())  ((nmethod*)cb)->print_on(tty, "oops_do, unmarked visit\n"));
+    // This assert won't work, since there are lots of mini-passes
+    // (mostly in debug mode) that co-exist with marking phases.
+    //assert(!(cb->is_nmethod() && ((nmethod*)cb)->test_oops_do_mark()), "found marked nmethod during mark-free phase");
+    cb->oops_do(_cl);
+  } else {
+    MarkingCodeBlobClosure::do_code_blob(cb);
+  }
+}
+
+
--- a/src/share/vm/memory/iterator.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/memory/iterator.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -24,6 +24,8 @@
 
 // The following classes are C++ `closures` for iterating over objects, roots and spaces
 
+class CodeBlob;
+class nmethod;
 class ReferenceProcessor;
 class DataLayout;
 
@@ -69,9 +71,6 @@
   virtual const bool should_remember_mdo() const { return false; }
   virtual void remember_mdo(DataLayout* v) { /* do nothing */ }
 
-  // If "true", invoke on nmethods (when scanning compiled frames).
-  virtual const bool do_nmethods() const { return false; }
-
   // The methods below control how object iterations invoking this closure
   // should be performed:
 
@@ -176,6 +175,51 @@
 };
 
 
+// CodeBlobClosure is used for iterating through code blobs
+// in the code cache or on thread stacks
+
+class CodeBlobClosure : public Closure {
+ public:
+  // Called for each code blob.
+  virtual void do_code_blob(CodeBlob* cb) = 0;
+};
+
+
+class MarkingCodeBlobClosure : public CodeBlobClosure {
+ public:
+  // Called for each code blob, but at most once per unique blob.
+  virtual void do_newly_marked_nmethod(nmethod* nm) = 0;
+
+  virtual void do_code_blob(CodeBlob* cb);
+    // = { if (!nmethod(cb)->test_set_oops_do_mark())  do_newly_marked_nmethod(cb); }
+
+  class MarkScope : public StackObj {
+  protected:
+    bool _active;
+  public:
+    MarkScope(bool activate = true);
+      // = { if (active) nmethod::oops_do_marking_prologue(); }
+    ~MarkScope();
+      // = { if (active) nmethod::oops_do_marking_epilogue(); }
+  };
+};
+
+
+// Applies an oop closure to all ref fields in code blobs
+// iterated over in an object iteration.
+class CodeBlobToOopClosure: public MarkingCodeBlobClosure {
+  OopClosure* _cl;
+  bool _do_marking;
+public:
+  virtual void do_newly_marked_nmethod(nmethod* cb);
+    // = { cb->oops_do(_cl); }
+  virtual void do_code_blob(CodeBlob* cb);
+    // = { if (_do_marking)  super::do_code_blob(cb); else cb->oops_do(_cl); }
+  CodeBlobToOopClosure(OopClosure* cl, bool do_marking)
+    : _cl(cl), _do_marking(do_marking) {}
+};
+
+
 
 // MonitorClosure is used for iterating over monitors in the monitors cache
 
--- a/src/share/vm/memory/sharedHeap.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/memory/sharedHeap.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -100,12 +100,27 @@
          "Not in range.");
 }
 
-void SharedHeap::process_strong_roots(bool collecting_perm_gen,
+SharedHeap::StrongRootsScope::StrongRootsScope(SharedHeap* outer, bool activate)
+  : MarkScope(activate)
+{
+  if (_active) {
+    outer->change_strong_roots_parity();
+  }
+}
+
+SharedHeap::StrongRootsScope::~StrongRootsScope() {
+  // nothing particular
+}
+
+void SharedHeap::process_strong_roots(bool activate_scope,
+                                      bool collecting_perm_gen,
                                       ScanningOption so,
                                       OopClosure* roots,
+                                      CodeBlobClosure* code_roots,
                                       OopsInGenClosure* perm_blk) {
+  StrongRootsScope srs(this, activate_scope);
   // General strong roots.
-  if (n_par_threads() == 0) change_strong_roots_parity();
+  assert(_strong_roots_parity != 0, "must have called prologue code");
   if (!_process_strong_tasks->is_task_claimed(SH_PS_Universe_oops_do)) {
     Universe::oops_do(roots);
     ReferenceProcessor::oops_do(roots);
@@ -117,9 +132,9 @@
     JNIHandles::oops_do(roots);
   // All threads execute this; the individual threads are task groups.
   if (ParallelGCThreads > 0) {
-    Threads::possibly_parallel_oops_do(roots);
+    Threads::possibly_parallel_oops_do(roots, code_roots);
   } else {
-    Threads::oops_do(roots);
+    Threads::oops_do(roots, code_roots);
   }
   if (!_process_strong_tasks-> is_task_claimed(SH_PS_ObjectSynchronizer_oops_do))
     ObjectSynchronizer::oops_do(roots);
@@ -156,11 +171,29 @@
   }
 
   if (!_process_strong_tasks->is_task_claimed(SH_PS_CodeCache_oops_do)) {
-     if (so & SO_CodeCache) {
-       CodeCache::oops_do(roots);
-     }
+    if (so & SO_CodeCache) {
+      // (Currently, CMSCollector uses this to do intermediate-strength collections.)
+      assert(collecting_perm_gen, "scanning all of code cache");
+      assert(code_roots != NULL, "must supply closure for code cache");
+      if (code_roots != NULL) {
+        CodeCache::blobs_do(code_roots);
+      }
+    } else if (so & (SO_SystemClasses|SO_AllClasses)) {
+      if (!collecting_perm_gen) {
+        // If we are collecting from class statics, but we are not going to
+        // visit all of the CodeCache, collect from the non-perm roots if any.
+        // This makes the code cache function temporarily as a source of strong
+        // roots for oops, until the next major collection.
+        //
+        // If collecting_perm_gen is true, we require that this phase will call
+        // CodeCache::do_unloading.  This will kill off nmethods with expired
+        // weak references, such as stale invokedynamic targets.
+        CodeCache::scavenge_root_nmethods_do(code_roots);
+      }
+    }
     // Verify if the code cache contents are in the perm gen
-    NOT_PRODUCT(CodeCache::oops_do(&assert_is_perm_closure));
+    NOT_PRODUCT(CodeBlobToOopClosure assert_code_is_perm(&assert_is_perm_closure, /*do_marking=*/ false));
+    NOT_PRODUCT(CodeCache::asserted_non_scavengable_nmethods_do(&assert_code_is_perm));
   }
 
   // Roots that should point only into permanent generation.
@@ -220,11 +253,12 @@
 // just skip adjusting any shared entries in the string table.
 
 void SharedHeap::process_weak_roots(OopClosure* root_closure,
+                                    CodeBlobClosure* code_roots,
                                     OopClosure* non_root_closure) {
   // Global (weak) JNI handles
   JNIHandles::weak_oops_do(&always_true, root_closure);
 
-  CodeCache::oops_do(non_root_closure);
+  CodeCache::blobs_do(code_roots);
   SymbolTable::oops_do(root_closure);
   if (UseSharedSpaces && !DumpSharedSpaces) {
     SkipAdjustingSharedStrings skip_closure(root_closure);
--- a/src/share/vm/memory/sharedHeap.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/memory/sharedHeap.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -165,9 +165,21 @@
   //   c) to never return a distinguished value (zero) with which such
   //      task-claiming variables may be initialized, to indicate "never
   //      claimed".
+ private:
   void change_strong_roots_parity();
+ public:
   int strong_roots_parity() { return _strong_roots_parity; }
 
+  // Call these in sequential code around process_strong_roots.
+  // strong_roots_prologue calls change_strong_roots_parity, if
+  // parallel tasks are enabled.
+  class StrongRootsScope : public MarkingCodeBlobClosure::MarkScope {
+  public:
+    StrongRootsScope(SharedHeap* outer, bool activate = true);
+    ~StrongRootsScope();
+  };
+  friend class StrongRootsScope;
+
   enum ScanningOption {
     SO_None                = 0x0,
     SO_AllClasses          = 0x1,
@@ -198,15 +210,18 @@
   // "SO_Symbols" applies the closure to all entries in SymbolsTable;
   // "SO_Strings" applies the closure to all entries in StringTable;
   // "SO_CodeCache" applies the closure to all elements of the CodeCache.
-  void process_strong_roots(bool collecting_perm_gen,
+  void process_strong_roots(bool activate_scope,
+                            bool collecting_perm_gen,
                             ScanningOption so,
                             OopClosure* roots,
+                            CodeBlobClosure* code_roots,
                             OopsInGenClosure* perm_blk);
 
   // Apply "blk" to all the weak roots of the system.  These include
   // JNI weak roots, the code cache, system dictionary, symbol table,
   // string table.
   void process_weak_roots(OopClosure* root_closure,
+                          CodeBlobClosure* code_roots,
                           OopClosure* non_root_closure);
 
 
--- a/src/share/vm/oops/instanceKlass.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/oops/instanceKlass.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -2152,7 +2152,7 @@
   // This is a short non-blocking critical region, so the no safepoint check is ok.
   OsrList_lock->lock_without_safepoint_check();
   assert(n->is_osr_method(), "wrong kind of nmethod");
-  n->set_link(osr_nmethods_head());
+  n->set_osr_link(osr_nmethods_head());
   set_osr_nmethods_head(n);
   // Remember to unlock again
   OsrList_lock->unlock();
@@ -2168,17 +2168,17 @@
   // Search for match
   while(cur != NULL && cur != n) {
     last = cur;
-    cur = cur->link();
+    cur = cur->osr_link();
   }
   if (cur == n) {
     if (last == NULL) {
       // Remove first element
-      set_osr_nmethods_head(osr_nmethods_head()->link());
+      set_osr_nmethods_head(osr_nmethods_head()->osr_link());
     } else {
-      last->set_link(cur->link());
+      last->set_osr_link(cur->osr_link());
     }
   }
-  n->set_link(NULL);
+  n->set_osr_link(NULL);
   // Remember to unlock again
   OsrList_lock->unlock();
 }
@@ -2195,7 +2195,7 @@
       OsrList_lock->unlock();
       return osr;
     }
-    osr = osr->link();
+    osr = osr->osr_link();
   }
   OsrList_lock->unlock();
   return NULL;
--- a/src/share/vm/oops/oop.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/oops/oop.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -330,6 +330,7 @@
 
   bool is_perm() const;
   bool is_perm_or_null() const;
+  bool is_scavengable() const;
   bool is_shared() const;
   bool is_shared_readonly() const;
   bool is_shared_readwrite() const;
--- a/src/share/vm/oops/oop.inline2.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/oops/oop.inline2.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -34,3 +34,7 @@
 inline bool oopDesc::is_perm_or_null() const {
   return this == NULL || is_perm();
 }
+
+inline bool oopDesc::is_scavengable() const {
+  return Universe::heap()->is_scavengable(this);
+}
--- a/src/share/vm/opto/connode.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/connode.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -1085,6 +1085,9 @@
   switch (op) {
   case Op_SubX:
     x = in(1)->in(1);
+    // Avoid ideal transformations ping-pong between this and AddP for raw pointers.
+    if (phase->find_intptr_t_con(x, -1) == 0)
+      break;
     y = in(1)->in(2);
     if (fits_in_int(phase->type(y), true)) {
       return addP_of_X2P(phase, x, y, true);
--- a/src/share/vm/opto/escape.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/escape.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -524,12 +524,15 @@
   // inlining) which was not eliminated during parsing since the exactness
   // of the allocation type was not propagated to the subclass type check.
   //
+  // Or the type 't' could be not related to 'base_t' at all.
+  // It could happened when CHA type is different from MDO type on a dead path
+  // (for example, from instanceof check) which is not collapsed during parsing.
+  //
   // Do nothing for such AddP node and don't process its users since
   // this code branch will go away.
   //
   if (!t->is_known_instance() &&
-      !t->klass()->equals(base_t->klass()) &&
-      t->klass()->is_subtype_of(base_t->klass())) {
+      !base_t->klass()->is_subtype_of(t->klass())) {
      return false; // bail out
   }
 
--- a/src/share/vm/opto/graphKit.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/graphKit.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -1450,7 +1450,7 @@
 
     case BarrierSet::CardTableModRef:
     case BarrierSet::CardTableExtension:
-      write_barrier_post(store, obj, adr, val, use_precise);
+      write_barrier_post(store, obj, adr, adr_idx, val, use_precise);
       break;
 
     case BarrierSet::ModRef:
@@ -3165,6 +3165,7 @@
 void GraphKit::write_barrier_post(Node* oop_store,
                                   Node* obj,
                                   Node* adr,
+                                  uint  adr_idx,
                                   Node* val,
                                   bool use_precise) {
   // No store check needed if we're storing a NULL or an old object
@@ -3214,7 +3215,7 @@
     __ store(__ ctrl(), card_adr, zero, bt, adr_type);
   } else {
     // Specialized path for CM store barrier
-    __ storeCM(__ ctrl(), card_adr, zero, oop_store, bt, adr_type);
+    __ storeCM(__ ctrl(), card_adr, zero, oop_store, adr_idx, bt, adr_type);
   }
 
   // Final sync IdealKit and GraphKit.
@@ -3314,6 +3315,7 @@
 void GraphKit::g1_mark_card(IdealKit& ideal,
                             Node* card_adr,
                             Node* oop_store,
+                            uint oop_alias_idx,
                             Node* index,
                             Node* index_adr,
                             Node* buffer,
@@ -3323,7 +3325,7 @@
   Node* no_base = __ top();
   BasicType card_bt = T_BYTE;
   // Smash zero into card. MUST BE ORDERED WRT TO STORE
-  __ storeCM(__ ctrl(), card_adr, zero, oop_store, card_bt, Compile::AliasIdxRaw);
+  __ storeCM(__ ctrl(), card_adr, zero, oop_store, oop_alias_idx, card_bt, Compile::AliasIdxRaw);
 
   //  Now do the queue work
   __ if_then(index, BoolTest::ne, zero); {
@@ -3435,13 +3437,13 @@
         Node* card_val = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw);
 
         __ if_then(card_val, BoolTest::ne, zero); {
-          g1_mark_card(ideal, card_adr, oop_store, index, index_adr, buffer, tf);
+          g1_mark_card(ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf);
         } __ end_if();
       } __ end_if();
     } __ end_if();
   } else {
     // Object.clone() instrinsic uses this path.
-    g1_mark_card(ideal, card_adr, oop_store, index, index_adr, buffer, tf);
+    g1_mark_card(ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf);
   }
 
   // Final sync IdealKit and GraphKit.
--- a/src/share/vm/opto/graphKit.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/graphKit.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -603,7 +603,8 @@
   void sync_kit(IdealKit& ideal);
 
   // vanilla/CMS post barrier
-  void write_barrier_post(Node *store, Node* obj, Node* adr, Node* val, bool use_precise);
+  void write_barrier_post(Node *store, Node* obj,
+                          Node* adr,  uint adr_idx, Node* val, bool use_precise);
 
   // G1 pre/post barriers
   void g1_write_barrier_pre(Node* obj,
@@ -622,7 +623,8 @@
                              bool use_precise);
   // Helper function for g1
   private:
-  void g1_mark_card(IdealKit& ideal, Node* card_adr, Node* store,  Node* index, Node* index_adr,
+  void g1_mark_card(IdealKit& ideal, Node* card_adr, Node* store, uint oop_alias_idx,
+                    Node* index, Node* index_adr,
                     Node* buffer, const TypeFunc* tf);
 
   public:
--- a/src/share/vm/opto/idealKit.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/idealKit.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -378,7 +378,7 @@
 
 // Card mark store. Must be ordered so that it will come after the store of
 // the oop.
-Node* IdealKit::storeCM(Node* ctl, Node* adr, Node *val, Node* oop_store,
+Node* IdealKit::storeCM(Node* ctl, Node* adr, Node *val, Node* oop_store, int oop_adr_idx,
                         BasicType bt,
                         int adr_idx) {
   assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" );
@@ -388,7 +388,7 @@
 
   // Add required edge to oop_store, optimizer does not support precedence edges.
   // Convert required edge to precedence edge before allocation.
-  Node* st = new (C, 5) StoreCMNode(ctl, mem, adr, adr_type, val, oop_store);
+  Node* st = new (C, 5) StoreCMNode(ctl, mem, adr, adr_type, val, oop_store, oop_adr_idx);
 
   st = transform(st);
   set_memory(st, adr_idx);
--- a/src/share/vm/opto/idealKit.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/idealKit.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -216,6 +216,7 @@
                 Node* adr,
                 Node* val,
                 Node* oop_store,
+                int oop_adr_idx,
                 BasicType bt,
                 int adr_idx);
 
--- a/src/share/vm/opto/library_call.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/library_call.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -133,6 +133,7 @@
     return generate_method_call(method_id, true, false);
   }
 
+  Node* make_string_method_node(int opcode, Node* str1, Node* cnt1, Node* str2, Node* cnt2);
   bool inline_string_compareTo();
   bool inline_string_indexOf();
   Node* string_indexOf(Node* string_object, ciTypeArray* target_array, jint offset, jint cache_i, jint md2_i);
@@ -796,6 +797,64 @@
 }
 
 
+//------------------------------make_string_method_node------------------------
+// Helper method for String intrinsic finctions.
+Node* LibraryCallKit::make_string_method_node(int opcode, Node* str1, Node* cnt1, Node* str2, Node* cnt2) {
+  const int value_offset  = java_lang_String::value_offset_in_bytes();
+  const int count_offset  = java_lang_String::count_offset_in_bytes();
+  const int offset_offset = java_lang_String::offset_offset_in_bytes();
+
+  Node* no_ctrl = NULL;
+
+  ciInstanceKlass* klass = env()->String_klass();
+  const TypeInstPtr* string_type =
+        TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0);
+
+  const TypeAryPtr* value_type =
+        TypeAryPtr::make(TypePtr::NotNull,
+                         TypeAry::make(TypeInt::CHAR,TypeInt::POS),
+                         ciTypeArrayKlass::make(T_CHAR), true, 0);
+
+  // Get start addr of string and substring
+  Node* str1_valuea  = basic_plus_adr(str1, str1, value_offset);
+  Node* str1_value   = make_load(no_ctrl, str1_valuea, value_type, T_OBJECT, string_type->add_offset(value_offset));
+  Node* str1_offseta = basic_plus_adr(str1, str1, offset_offset);
+  Node* str1_offset  = make_load(no_ctrl, str1_offseta, TypeInt::INT, T_INT, string_type->add_offset(offset_offset));
+  Node* str1_start   = array_element_address(str1_value, str1_offset, T_CHAR);
+
+  // Pin loads from String::equals() argument since it could be NULL.
+  Node* str2_ctrl = (opcode == Op_StrEquals) ? control() : no_ctrl;
+  Node* str2_valuea  = basic_plus_adr(str2, str2, value_offset);
+  Node* str2_value   = make_load(str2_ctrl, str2_valuea, value_type, T_OBJECT, string_type->add_offset(value_offset));
+  Node* str2_offseta = basic_plus_adr(str2, str2, offset_offset);
+  Node* str2_offset  = make_load(str2_ctrl, str2_offseta, TypeInt::INT, T_INT, string_type->add_offset(offset_offset));
+  Node* str2_start   = array_element_address(str2_value, str2_offset, T_CHAR);
+
+  Node* result = NULL;
+  switch (opcode) {
+  case Op_StrIndexOf:
+    result = new (C, 6) StrIndexOfNode(control(), memory(TypeAryPtr::CHARS),
+                                       str1_start, cnt1, str2_start, cnt2);
+    break;
+  case Op_StrComp:
+    result = new (C, 6) StrCompNode(control(), memory(TypeAryPtr::CHARS),
+                                    str1_start, cnt1, str2_start, cnt2);
+    break;
+  case Op_StrEquals:
+    result = new (C, 5) StrEqualsNode(control(), memory(TypeAryPtr::CHARS),
+                                      str1_start, str2_start, cnt1);
+    break;
+  default:
+    ShouldNotReachHere();
+    return NULL;
+  }
+
+  // All these intrinsics have checks.
+  C->set_has_split_ifs(true); // Has chance for split-if optimization
+
+  return _gvn.transform(result);
+}
+
 //------------------------------inline_string_compareTo------------------------
 bool LibraryCallKit::inline_string_compareTo() {
 
@@ -824,16 +883,16 @@
   ciInstanceKlass* klass = env()->String_klass();
   const TypeInstPtr* string_type =
     TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0);
-
-  Node* compare =
-    _gvn.transform(new (C, 7) StrCompNode(
-                        control(),
-                        memory(TypeAryPtr::CHARS),
-                        memory(string_type->add_offset(value_offset)),
-                        memory(string_type->add_offset(count_offset)),
-                        memory(string_type->add_offset(offset_offset)),
-                        receiver,
-                        argument));
+  Node* no_ctrl = NULL;
+
+  // Get counts for string and argument
+  Node* receiver_cnta = basic_plus_adr(receiver, receiver, count_offset);
+  Node* receiver_cnt  = make_load(no_ctrl, receiver_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset));
+
+  Node* argument_cnta = basic_plus_adr(argument, argument, count_offset);
+  Node* argument_cnt  = make_load(no_ctrl, argument_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset));
+
+  Node* compare = make_string_method_node(Op_StrComp, receiver, receiver_cnt, argument, argument_cnt);
   push(compare);
   return true;
 }
@@ -865,45 +924,71 @@
     return true;
   }
 
+  // paths (plus control) merge
+  RegionNode* region = new (C, 5) RegionNode(5);
+  Node* phi = new (C, 5) PhiNode(region, TypeInt::BOOL);
+
+  // does source == target string?
+  Node* cmp = _gvn.transform(new (C, 3) CmpPNode(receiver, argument));
+  Node* bol = _gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::eq));
+
+  Node* if_eq = generate_slow_guard(bol, NULL);
+  if (if_eq != NULL) {
+    // receiver == argument
+    phi->init_req(2, intcon(1));
+    region->init_req(2, if_eq);
+  }
+
   // get String klass for instanceOf
   ciInstanceKlass* klass = env()->String_klass();
 
-  // two paths (plus control) merge
-  RegionNode* region = new (C, 3) RegionNode(3);
-  Node* phi = new (C, 3) PhiNode(region, TypeInt::BOOL);
-
-  Node* inst = gen_instanceof(argument, makecon(TypeKlassPtr::make(klass)));
-  Node* cmp  = _gvn.transform(new (C, 3) CmpINode(inst, intcon(1)));
-  Node* bol  = _gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::eq));
-
-  IfNode* iff = create_and_map_if(control(), bol, PROB_MAX, COUNT_UNKNOWN);
-
-  Node* if_true  = _gvn.transform(new (C, 1) IfTrueNode(iff));
-  set_control(if_true);
+  if (!stopped()) {
+    Node* inst = gen_instanceof(argument, makecon(TypeKlassPtr::make(klass)));
+    Node* cmp  = _gvn.transform(new (C, 3) CmpINode(inst, intcon(1)));
+    Node* bol  = _gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::ne));
+
+    Node* inst_false = generate_guard(bol, NULL, PROB_MIN);
+    //instanceOf == true, fallthrough
+
+    if (inst_false != NULL) {
+      phi->init_req(3, intcon(0));
+      region->init_req(3, inst_false);
+    }
+  }
 
   const TypeInstPtr* string_type =
     TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0);
 
-  // instanceOf == true
-  Node* equals =
-    _gvn.transform(new (C, 7) StrEqualsNode(
-                        control(),
-                        memory(TypeAryPtr::CHARS),
-                        memory(string_type->add_offset(value_offset)),
-                        memory(string_type->add_offset(count_offset)),
-                        memory(string_type->add_offset(offset_offset)),
-                        receiver,
-                        argument));
-
-  phi->init_req(1, _gvn.transform(equals));
-  region->init_req(1, if_true);
-
-  //instanceOf == false, fallthrough
-  Node* if_false = _gvn.transform(new (C, 1) IfFalseNode(iff));
-  set_control(if_false);
-
-  phi->init_req(2, _gvn.transform(intcon(0)));
-  region->init_req(2, if_false);
+  Node* no_ctrl = NULL;
+  Node* receiver_cnt;
+  Node* argument_cnt;
+
+  if (!stopped()) {
+    // Get counts for string and argument
+    Node* receiver_cnta = basic_plus_adr(receiver, receiver, count_offset);
+    receiver_cnt  = make_load(no_ctrl, receiver_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset));
+
+    // Pin load from argument string since it could be NULL.
+    Node* argument_cnta = basic_plus_adr(argument, argument, count_offset);
+    argument_cnt  = make_load(control(), argument_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset));
+
+    // Check for receiver count != argument count
+    Node* cmp = _gvn.transform( new(C, 3) CmpINode(receiver_cnt, argument_cnt) );
+    Node* bol = _gvn.transform( new(C, 2) BoolNode(cmp, BoolTest::ne) );
+    Node* if_ne = generate_slow_guard(bol, NULL);
+    if (if_ne != NULL) {
+      phi->init_req(4, intcon(0));
+      region->init_req(4, if_ne);
+    }
+  }
+
+  // Check for count == 0 is done by mach node StrEquals.
+
+  if (!stopped()) {
+    Node* equals = make_string_method_node(Op_StrEquals, receiver, receiver_cnt, argument, argument_cnt);
+    phi->init_req(1, equals);
+    region->init_req(1, control());
+  }
 
   // post merge
   set_control(_gvn.transform(region));
@@ -924,10 +1009,8 @@
   Node *argument1 = pop();
 
   Node* equals =
-    _gvn.transform(new (C, 3) AryEqNode(control(),
-                                        argument1,
-                                        argument2)
-                   );
+    _gvn.transform(new (C, 4) AryEqNode(control(), memory(TypeAryPtr::CHARS),
+                                        argument1, argument2) );
   push(equals);
   return true;
 }
@@ -1108,19 +1191,40 @@
       return true;
     }
 
+    // Make the merge point
+    RegionNode* result_rgn = new (C, 3) RegionNode(3);
+    Node*       result_phi = new (C, 3) PhiNode(result_rgn, TypeInt::INT);
+    Node* no_ctrl  = NULL;
+
     ciInstanceKlass* klass = env()->String_klass();
     const TypeInstPtr* string_type =
       TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0);
 
-    result =
-      _gvn.transform(new (C, 7)
-                     StrIndexOfNode(control(),
-                                    memory(TypeAryPtr::CHARS),
-                                    memory(string_type->add_offset(value_offset)),
-                                    memory(string_type->add_offset(count_offset)),
-                                    memory(string_type->add_offset(offset_offset)),
-                                    receiver,
-                                    argument));
+    // Get counts for string and substr
+    Node* source_cnta = basic_plus_adr(receiver, receiver, count_offset);
+    Node* source_cnt  = make_load(no_ctrl, source_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset));
+
+    Node* substr_cnta = basic_plus_adr(argument, argument, count_offset);
+    Node* substr_cnt  = make_load(no_ctrl, substr_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset));
+
+    // Check for substr count > string count
+    Node* cmp = _gvn.transform( new(C, 3) CmpINode(substr_cnt, source_cnt) );
+    Node* bol = _gvn.transform( new(C, 2) BoolNode(cmp, BoolTest::gt) );
+    Node* if_gt = generate_slow_guard(bol, NULL);
+    if (if_gt != NULL) {
+      result_phi->init_req(2, intcon(-1));
+      result_rgn->init_req(2, if_gt);
+    }
+
+    if (!stopped()) {
+      result = make_string_method_node(Op_StrIndexOf, receiver, source_cnt, argument, substr_cnt);
+      result_phi->init_req(1, result);
+      result_rgn->init_req(1, control());
+    }
+    set_control(_gvn.transform(result_rgn));
+    record_for_igvn(result_rgn);
+    result = _gvn.transform(result_phi);
+
   } else { //Use LibraryCallKit::string_indexOf
     // don't intrinsify is argument isn't a constant string.
     if (!argument->is_Con()) {
--- a/src/share/vm/opto/matcher.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/matcher.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -2032,6 +2032,23 @@
         n->del_req(3);
         break;
       }
+      case Op_StrEquals: {
+        Node *pair1 = new (C, 3) BinaryNode(n->in(2),n->in(3));
+        n->set_req(2,pair1);
+        n->set_req(3,n->in(4));
+        n->del_req(4);
+        break;
+      }
+      case Op_StrComp:
+      case Op_StrIndexOf: {
+        Node *pair1 = new (C, 3) BinaryNode(n->in(2),n->in(3));
+        n->set_req(2,pair1);
+        Node *pair2 = new (C, 3) BinaryNode(n->in(4),n->in(5));
+        n->set_req(3,pair2);
+        n->del_req(5);
+        n->del_req(4);
+        break;
+      }
       default:
         break;
       }
--- a/src/share/vm/opto/memnode.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/memnode.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -2313,6 +2313,22 @@
   return this;
 }
 
+//=============================================================================
+//------------------------------Ideal---------------------------------------
+Node *StoreCMNode::Ideal(PhaseGVN *phase, bool can_reshape){
+  Node* progress = StoreNode::Ideal(phase, can_reshape);
+  if (progress != NULL) return progress;
+
+  Node* my_store = in(MemNode::OopStore);
+  if (my_store->is_MergeMem()) {
+    Node* mem = my_store->as_MergeMem()->memory_at(oop_alias_idx());
+    set_req(MemNode::OopStore, mem);
+    return this;
+  }
+
+  return NULL;
+}
+
 //------------------------------Value-----------------------------------------
 const Type *StoreCMNode::Value( PhaseTransform *phase ) const {
   // Either input is TOP ==> the result is TOP
@@ -2498,7 +2514,7 @@
 //=============================================================================
 // Do we match on this edge? No memory edges
 uint StrCompNode::match_edge(uint idx) const {
-  return idx == 5 || idx == 6;
+  return idx == 2 || idx == 3; // StrComp (Binary str1 cnt1) (Binary str2 cnt2)
 }
 
 //------------------------------Ideal------------------------------------------
@@ -2508,9 +2524,10 @@
   return remove_dead_region(phase, can_reshape) ? this : NULL;
 }
 
+//=============================================================================
 // Do we match on this edge? No memory edges
 uint StrEqualsNode::match_edge(uint idx) const {
-  return idx == 5 || idx == 6;
+  return idx == 2 || idx == 3; // StrEquals (Binary str1 str2) cnt
 }
 
 //------------------------------Ideal------------------------------------------
@@ -2523,7 +2540,7 @@
 //=============================================================================
 // Do we match on this edge? No memory edges
 uint StrIndexOfNode::match_edge(uint idx) const {
-  return idx == 5 || idx == 6;
+  return idx == 2 || idx == 3; // StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2)
 }
 
 //------------------------------Ideal------------------------------------------
@@ -2533,6 +2550,11 @@
   return remove_dead_region(phase, can_reshape) ? this : NULL;
 }
 
+//=============================================================================
+// Do we match on this edge? No memory edges
+uint AryEqNode::match_edge(uint idx) const {
+  return idx == 2 || idx == 3; // StrEquals ary1 ary2
+}
 //------------------------------Ideal------------------------------------------
 // Return a node which is more "ideal" than the current node.  Strip out
 // control copies
--- a/src/share/vm/opto/memnode.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/memnode.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -582,12 +582,16 @@
 // The last StoreCM before a SafePoint must be preserved and occur after its "oop" store
 // Preceeding equivalent StoreCMs may be eliminated.
 class StoreCMNode : public StoreNode {
+ private:
+  int _oop_alias_idx;   // The alias_idx of OopStore
 public:
-  StoreCMNode( Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, Node *oop_store ) : StoreNode(c,mem,adr,at,val,oop_store) {}
+  StoreCMNode( Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, Node *oop_store, int oop_alias_idx ) : StoreNode(c,mem,adr,at,val,oop_store), _oop_alias_idx(oop_alias_idx) {}
   virtual int Opcode() const;
   virtual Node *Identity( PhaseTransform *phase );
+  virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
   virtual const Type *Value( PhaseTransform *phase ) const;
   virtual BasicType memory_type() const { return T_VOID; } // unspecific
+  int oop_alias_idx() const { return _oop_alias_idx; }
 };
 
 //------------------------------LoadPLockedNode---------------------------------
@@ -744,22 +748,15 @@
 //------------------------------StrComp-------------------------------------
 class StrCompNode: public Node {
 public:
-  StrCompNode(Node *control,
-              Node* char_array_mem,
-              Node* value_mem,
-              Node* count_mem,
-              Node* offset_mem,
-              Node* s1, Node* s2): Node(control,
-                                        char_array_mem,
-                                        value_mem,
-                                        count_mem,
-                                        offset_mem,
-                                        s1, s2) {};
+  StrCompNode(Node* control, Node* char_array_mem,
+              Node* s1, Node* c1,
+              Node* s2, Node* c2): Node(control, char_array_mem,
+                                        s1, c1,
+                                        s2, c2) {};
   virtual int Opcode() const;
   virtual bool depends_only_on_test() const { return false; }
   virtual const Type* bottom_type() const { return TypeInt::INT; }
-  // a StrCompNode (conservatively) aliases with everything:
-  virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; }
+  virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; }
   virtual uint match_edge(uint idx) const;
   virtual uint ideal_reg() const { return Op_RegI; }
   virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
@@ -768,22 +765,13 @@
 //------------------------------StrEquals-------------------------------------
 class StrEqualsNode: public Node {
 public:
-  StrEqualsNode(Node *control,
-                Node* char_array_mem,
-                Node* value_mem,
-                Node* count_mem,
-                Node* offset_mem,
-                Node* s1, Node* s2): Node(control,
-                                          char_array_mem,
-                                          value_mem,
-                                          count_mem,
-                                          offset_mem,
-                                          s1, s2) {};
+  StrEqualsNode(Node* control, Node* char_array_mem,
+                Node* s1, Node* s2, Node* c): Node(control, char_array_mem,
+                                                   s1, s2, c) {};
   virtual int Opcode() const;
   virtual bool depends_only_on_test() const { return false; }
   virtual const Type* bottom_type() const { return TypeInt::BOOL; }
-  // a StrEqualsNode (conservatively) aliases with everything:
-  virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; }
+  virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; }
   virtual uint match_edge(uint idx) const;
   virtual uint ideal_reg() const { return Op_RegI; }
   virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
@@ -792,22 +780,15 @@
 //------------------------------StrIndexOf-------------------------------------
 class StrIndexOfNode: public Node {
 public:
-  StrIndexOfNode(Node *control,
-                 Node* char_array_mem,
-                 Node* value_mem,
-                 Node* count_mem,
-                 Node* offset_mem,
-                 Node* s1, Node* s2): Node(control,
-                                           char_array_mem,
-                                           value_mem,
-                                           count_mem,
-                                           offset_mem,
-                                           s1, s2) {};
+  StrIndexOfNode(Node* control, Node* char_array_mem,
+                 Node* s1, Node* c1,
+                 Node* s2, Node* c2): Node(control, char_array_mem,
+                                           s1, c1,
+                                           s2, c2) {};
   virtual int Opcode() const;
   virtual bool depends_only_on_test() const { return false; }
   virtual const Type* bottom_type() const { return TypeInt::INT; }
-  // a StrIndexOfNode (conservatively) aliases with everything:
-  virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; }
+  virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; }
   virtual uint match_edge(uint idx) const;
   virtual uint ideal_reg() const { return Op_RegI; }
   virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
@@ -816,11 +797,13 @@
 //------------------------------AryEq---------------------------------------
 class AryEqNode: public Node {
 public:
-  AryEqNode(Node *control, Node* s1, Node* s2): Node(control, s1, s2) {};
+  AryEqNode(Node* control, Node* char_array_mem,
+            Node* s1, Node* s2): Node(control, char_array_mem, s1, s2) {};
   virtual int Opcode() const;
   virtual bool depends_only_on_test() const { return false; }
   virtual const Type* bottom_type() const { return TypeInt::BOOL; }
   virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; }
+  virtual uint match_edge(uint idx) const;
   virtual uint ideal_reg() const { return Op_RegI; }
   virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
 };
--- a/src/share/vm/opto/output.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/output.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -611,7 +611,7 @@
       assert(cik->is_instance_klass() ||
              cik->is_array_klass(), "Not supported allocation.");
       sv = new ObjectValue(spobj->_idx,
-                           new ConstantOopWriteValue(cik->encoding()));
+                           new ConstantOopWriteValue(cik->constant_encoding()));
       Compile::set_sv_for_object_node(objs, sv);
 
       uint first_ind = spobj->first_index();
@@ -702,13 +702,13 @@
   case Type::AryPtr:
   case Type::InstPtr:
   case Type::KlassPtr:          // fall through
-    array->append(new ConstantOopWriteValue(t->isa_oopptr()->const_oop()->encoding()));
+    array->append(new ConstantOopWriteValue(t->isa_oopptr()->const_oop()->constant_encoding()));
     break;
   case Type::NarrowOop:
     if (t == TypeNarrowOop::NULL_PTR) {
       array->append(new ConstantOopWriteValue(NULL));
     } else {
-      array->append(new ConstantOopWriteValue(t->make_ptr()->isa_oopptr()->const_oop()->encoding()));
+      array->append(new ConstantOopWriteValue(t->make_ptr()->isa_oopptr()->const_oop()->constant_encoding()));
     }
     break;
   case Type::Int:
@@ -871,7 +871,7 @@
           assert(cik->is_instance_klass() ||
                  cik->is_array_klass(), "Not supported allocation.");
           ObjectValue* sv = new ObjectValue(spobj->_idx,
-                                new ConstantOopWriteValue(cik->encoding()));
+                                new ConstantOopWriteValue(cik->constant_encoding()));
           Compile::set_sv_for_object_node(objs, sv);
 
           uint first_ind = spobj->first_index();
@@ -890,7 +890,7 @@
         }
       } else {
         const TypePtr *tp = obj_node->bottom_type()->make_ptr();
-        scval = new ConstantOopWriteValue(tp->is_instptr()->const_oop()->encoding());
+        scval = new ConstantOopWriteValue(tp->is_instptr()->const_oop()->constant_encoding());
       }
 
       OptoReg::Name box_reg = BoxLockNode::stack_slot(box_node);
--- a/src/share/vm/opto/parse.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/parse.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -469,7 +469,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 push_constant(ciConstant con, bool require_constant = false);
 
   // implementation of object creation bytecodes
   void do_new();
--- a/src/share/vm/opto/parse1.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/parse1.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -229,7 +229,9 @@
     }
   }
 
-  MethodLivenessResult live_locals = method()->liveness_at_bci(osr_bci());
+  // Use the raw liveness computation to make sure that unexpected
+  // values don't propagate into the OSR frame.
+  MethodLivenessResult live_locals = method()->raw_liveness_at_bci(osr_bci());
   if (!live_locals.is_valid()) {
     // Degenerate or breakpointed method.
     C->record_method_not_compilable("OSR in empty or breakpointed method");
--- a/src/share/vm/opto/parse2.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/parse2.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -1325,7 +1325,8 @@
           }
         }
       }
-      push_constant(constant);
+      bool pushed = push_constant(constant, true);
+      guarantee(pushed, "must be possible to push this constant");
     }
 
     break;
--- a/src/share/vm/opto/parse3.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/parse3.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -267,7 +267,7 @@
 }
 
 
-bool Parse::push_constant(ciConstant constant) {
+bool Parse::push_constant(ciConstant constant, bool require_constant) {
   switch (constant.basic_type()) {
   case T_BOOLEAN:  push( intcon(constant.as_boolean()) ); break;
   case T_INT:      push( intcon(constant.as_int())     ); break;
@@ -279,13 +279,16 @@
   case T_LONG:     push_pair( longcon(constant.as_long()) ); break;
   case T_ARRAY:
   case T_OBJECT: {
-    // the oop is in perm space if the ciObject "has_encoding"
+    // 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 (oop_constant->has_encoding()) {
-      push( makecon(TypeOopPtr::make_from_constant(oop_constant)) );
+    } else if (require_constant || oop_constant->should_be_constant()) {
+      push( makecon(TypeOopPtr::make_from_constant(oop_constant, require_constant)) );
       break;
     } else {
       // we cannot inline the oop, but we can use it later to narrow a type
--- a/src/share/vm/opto/superword.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/superword.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -457,10 +457,6 @@
         } else if (out->Opcode() == Op_StoreCM && out->in(MemNode::OopStore) == n) {
           // StoreCM has an input edge used as a precedence edge.
           // Maybe an issue when oop stores are vectorized.
-        } else if( out->is_MergeMem() && prev &&
-                   prev->Opcode() == Op_StoreCM && out == prev->in(MemNode::OopStore)) {
-          // Oop store is a MergeMem! This should not happen. Temporarily remove the assertion
-          // for this case because it could not be superwordized anyway.
         } else {
           assert(out == prev || prev == NULL, "no branches off of store slice");
         }
@@ -477,6 +473,12 @@
 // Can s1 and s2 be in a pack with s1 immediately preceding s2 and
 // s1 aligned at "align"
 bool SuperWord::stmts_can_pack(Node* s1, Node* s2, int align) {
+
+  // Do not use superword for non-primitives
+  if((s1->is_Mem() && !is_java_primitive(s1->as_Mem()->memory_type())) ||
+     (s2->is_Mem() && !is_java_primitive(s2->as_Mem()->memory_type())))
+    return false;
+
   if (isomorphic(s1, s2)) {
     if (independent(s1, s2)) {
       if (!exists_at(s1, 0) && !exists_at(s2, 1)) {
--- a/src/share/vm/opto/type.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/type.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -296,7 +296,7 @@
                                            false, 0, oopDesc::mark_offset_in_bytes());
   TypeInstPtr::KLASS   = TypeInstPtr::make(TypePtr::BotPTR,  current->env()->Object_klass(),
                                            false, 0, oopDesc::klass_offset_in_bytes());
-  TypeOopPtr::BOTTOM  = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot);
+  TypeOopPtr::BOTTOM  = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot, TypeOopPtr::InstanceBot);
 
   TypeNarrowOop::NULL_PTR = TypeNarrowOop::make( TypePtr::NULL_PTR );
   TypeNarrowOop::BOTTOM   = TypeNarrowOop::make( TypeInstPtr::BOTTOM );
@@ -492,8 +492,13 @@
 bool Type::interface_vs_oop(const Type *t) const {
   bool result = false;
 
-  const TypeInstPtr* this_inst = this->isa_instptr();
-  const TypeInstPtr*    t_inst =    t->isa_instptr();
+  const TypePtr* this_ptr = this->make_ptr(); // In case it is narrow_oop
+  const TypePtr*    t_ptr =    t->make_ptr();
+  if( this_ptr == NULL || t_ptr == NULL )
+    return result;
+
+  const TypeInstPtr* this_inst = this_ptr->isa_instptr();
+  const TypeInstPtr*    t_inst =    t_ptr->isa_instptr();
   if( this_inst && this_inst->is_loaded() && t_inst && t_inst->is_loaded() ) {
     bool this_interface = this_inst->klass()->is_interface();
     bool    t_interface =    t_inst->klass()->is_interface();
@@ -2249,7 +2254,7 @@
 const Type *TypeOopPtr::cast_to_ptr_type(PTR ptr) const {
   assert(_base == OopPtr, "subclass must override cast_to_ptr_type");
   if( ptr == _ptr ) return this;
-  return make(ptr, _offset);
+  return make(ptr, _offset, _instance_id);
 }
 
 //-----------------------------cast_to_instance_id----------------------------
@@ -2319,8 +2324,10 @@
       if (ptr == Null)  return TypePtr::make(AnyPtr, ptr, offset);
       // else fall through:
     case TopPTR:
-    case AnyNull:
-      return make(ptr, offset);
+    case AnyNull: {
+      int instance_id = meet_instance_id(InstanceTop);
+      return make(ptr, offset, instance_id);
+    }
     case BotPTR:
     case NotNull:
       return TypePtr::make(AnyPtr, ptr, offset);
@@ -2411,14 +2418,13 @@
 
 //------------------------------make_from_constant-----------------------------
 // Make a java pointer from an oop constant
-const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o) {
+const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_constant) {
   if (o->is_method_data() || o->is_method()) {
     // Treat much like a typeArray of bytes, like below, but fake the type...
-    assert(o->has_encoding(), "must be a perm space object");
     const Type* etype = (Type*)get_const_basic_type(T_BYTE);
     const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS);
     ciKlass *klass = ciTypeArrayKlass::make((BasicType) T_BYTE);
-    assert(o->has_encoding(), "method data oops should be tenured");
+    assert(o->can_be_constant(), "method data oops should be tenured");
     const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
     return arr;
   } else {
@@ -2427,8 +2433,9 @@
     ciKlass *klass = o->klass();
     if (klass->is_instance_klass()) {
       // Element is an instance
-      if (!o->has_encoding()) {  // not a perm-space constant
-        // %%% remove this restriction by rewriting non-perm ConPNodes in a later phase
+      if (require_constant) {
+        if (!o->can_be_constant())  return NULL;
+      } else if (!o->should_be_constant()) {
         return TypeInstPtr::make(TypePtr::NotNull, klass, true, NULL, 0);
       }
       return TypeInstPtr::make(o);
@@ -2440,8 +2447,9 @@
       // We used to pass NotNull in here, asserting that the sub-arrays
       // are all not-null.  This is not true in generally, as code can
       // slam NULLs down in the subarrays.
-      if (!o->has_encoding()) {  // not a perm-space constant
-        // %%% remove this restriction by rewriting non-perm ConPNodes in a later phase
+      if (require_constant) {
+        if (!o->can_be_constant())  return NULL;
+      } else if (!o->should_be_constant()) {
         return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
       }
       const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
@@ -2453,8 +2461,9 @@
       const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
       // We used to pass NotNull in here, asserting that the array pointer
       // is not-null. That was not true in general.
-      if (!o->has_encoding()) {  // not a perm-space constant
-        // %%% remove this restriction by rewriting non-perm ConPNodes in a later phase
+      if (require_constant) {
+        if (!o->can_be_constant())  return NULL;
+      } else if (!o->should_be_constant()) {
         return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
       }
       const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
@@ -2483,7 +2492,7 @@
     ShouldNotReachHere();
   }
 
-  return (intptr_t)const_oop()->encoding();
+  return (intptr_t)const_oop()->constant_encoding();
 }
 
 
@@ -2591,7 +2600,7 @@
 
 //------------------------------add_offset-------------------------------------
 const TypePtr *TypeOopPtr::add_offset( intptr_t offset ) const {
-  return make( _ptr, xadd_offset(offset) );
+  return make( _ptr, xadd_offset(offset), _instance_id);
 }
 
 //------------------------------meet_instance_id--------------------------------
@@ -2694,6 +2703,7 @@
 const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst) const {
     int off = meet_offset(tinst->offset());
     PTR ptr = meet_ptr(tinst->ptr());
+    int instance_id = meet_instance_id(tinst->instance_id());
 
     const TypeInstPtr *loaded    = is_loaded() ? this  : tinst;
     const TypeInstPtr *unloaded  = is_loaded() ? tinst : this;
@@ -2714,7 +2724,7 @@
       assert(loaded->ptr() != TypePtr::Null, "insanity check");
       //
       if(      loaded->ptr() == TypePtr::TopPTR ) { return unloaded; }
-      else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make( ptr, unloaded->klass() ); }
+      else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make( ptr, unloaded->klass(), false, NULL, off, instance_id ); }
       else if (loaded->ptr() == TypePtr::BotPTR ) { return TypeInstPtr::BOTTOM; }
       else if (loaded->ptr() == TypePtr::Constant || loaded->ptr() == TypePtr::NotNull) {
         if (unloaded->ptr() == TypePtr::BotPTR  ) { return TypeInstPtr::BOTTOM;  }
@@ -3338,14 +3348,19 @@
       ciObject* o = const_oop();
       if( _ptr == Constant ) {
         if( tap->const_oop() != NULL && !o->equals(tap->const_oop()) ) {
+          xk = (klass() == tap->klass());
           ptr = NotNull;
           o = NULL;
           instance_id = InstanceBot;
+        } else {
+          xk = true;
         }
       } else if( above_centerline(_ptr) ) {
         o = tap->const_oop();
+        xk = true;
+      } else {
+        xk = this->_klass_is_exact;
       }
-      xk = true;
       return TypeAryPtr::make( ptr, o, tary, tap->_klass, xk, off, instance_id );
     }
     case NotNull:
--- a/src/share/vm/opto/type.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/opto/type.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -711,10 +711,13 @@
     return make_from_klass_common(klass, false, false);
   }
   // Creates a singleton type given an object.
-  static const TypeOopPtr* make_from_constant(ciObject* o);
+  // If the object cannot be rendered as a constant,
+  // may return a non-singleton type.
+  // If require_constant, produce a NULL if a singleton is not possible.
+  static const TypeOopPtr* make_from_constant(ciObject* o, bool require_constant = false);
 
   // Make a generic (unclassed) pointer to an oop.
-  static const TypeOopPtr* make(PTR ptr, int offset, int instance_id = InstanceBot);
+  static const TypeOopPtr* make(PTR ptr, int offset, int instance_id);
 
   ciObject* const_oop()    const { return _const_oop; }
   virtual ciKlass* klass() const { return _klass;     }
--- a/src/share/vm/prims/jvmtiTagMap.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/prims/jvmtiTagMap.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -3126,6 +3126,12 @@
   // exceptions) will be visible.
   blk.set_kind(JVMTI_HEAP_REFERENCE_OTHER);
   Universe::oops_do(&blk);
+
+  // If there are any non-perm roots in the code cache, visit them.
+  blk.set_kind(JVMTI_HEAP_REFERENCE_OTHER);
+  CodeBlobToOopClosure look_in_blobs(&blk, false);
+  CodeCache::scavenge_root_nmethods_do(&look_in_blobs);
+
   return true;
 }
 
--- a/src/share/vm/runtime/arguments.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/runtime/arguments.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -2648,16 +2648,22 @@
 
   if (EnableInvokeDynamic && !EnableMethodHandles) {
     if (!FLAG_IS_DEFAULT(EnableMethodHandles)) {
-      warning("forcing EnableMethodHandles true to allow EnableInvokeDynamic");
+      warning("forcing EnableMethodHandles true because EnableInvokeDynamic is true");
     }
     EnableMethodHandles = true;
   }
   if (EnableMethodHandles && !AnonymousClasses) {
     if (!FLAG_IS_DEFAULT(AnonymousClasses)) {
-      warning("forcing AnonymousClasses true to enable EnableMethodHandles");
+      warning("forcing AnonymousClasses true because EnableMethodHandles is true");
     }
     AnonymousClasses = true;
   }
+  if ((EnableMethodHandles || AnonymousClasses) && ScavengeRootsInCode == 0) {
+    if (!FLAG_IS_DEFAULT(ScavengeRootsInCode)) {
+      warning("forcing ScavengeRootsInCode non-zero because EnableMethodHandles or AnonymousClasses is true");
+    }
+    ScavengeRootsInCode = 1;
+  }
 
   if (PrintGCDetails) {
     // Turn on -verbose:gc options as well
--- a/src/share/vm/runtime/frame.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/runtime/frame.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -1043,7 +1043,7 @@
   finder.oops_do();
 }
 
-void frame::oops_code_blob_do(OopClosure* f, const RegisterMap* reg_map) {
+void frame::oops_code_blob_do(OopClosure* f, CodeBlobClosure* cf, const RegisterMap* reg_map) {
   assert(_cb != NULL, "sanity check");
   if (_cb->oop_maps() != NULL) {
     OopMapSet::oops_do(this, reg_map, f);
@@ -1058,21 +1058,9 @@
   // oops referenced from nmethods active on thread stacks so as to
   // prevent them from being collected. However, this visit should be
   // restricted to certain phases of the collection only. The
-  // closure answers whether it wants nmethods to be traced.
-  // (All CodeBlob subtypes other than NMethod currently have
-  // an empty oops_do() method.
-  if (f->do_nmethods()) {
-    _cb->oops_do(f);
-  }
-}
-
-void frame::nmethods_code_blob_do() {
-  assert(_cb != NULL, "sanity check");
-
-  // If we see an activation belonging to a non_entrant nmethod, we mark it.
-  if (_cb->is_nmethod() && ((nmethod *)_cb)->is_not_entrant()) {
-    ((nmethod*)_cb)->mark_as_seen_on_stack();
-  }
+  // closure decides how it wants nmethods to be traced.
+  if (cf != NULL)
+    cf->do_code_blob(_cb);
 }
 
 class CompiledArgumentOopFinder: public SignatureInfo {
@@ -1201,18 +1189,18 @@
 }
 
 
-void frame::oops_do_internal(OopClosure* f, RegisterMap* map, bool use_interpreter_oop_map_cache) {
+void frame::oops_do_internal(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map, bool use_interpreter_oop_map_cache) {
          if (is_interpreted_frame())    { oops_interpreted_do(f, map, use_interpreter_oop_map_cache);
   } else if (is_entry_frame())          { oops_entry_do      (f, map);
-  } else if (CodeCache::contains(pc())) { oops_code_blob_do  (f, map);
+  } else if (CodeCache::contains(pc())) { oops_code_blob_do  (f, cf, map);
   } else {
     ShouldNotReachHere();
   }
 }
 
-void frame::nmethods_do() {
+void frame::nmethods_do(CodeBlobClosure* cf) {
   if (_cb != NULL && _cb->is_nmethod()) {
-    nmethods_code_blob_do();
+    cf->do_code_blob(_cb);
   }
 }
 
@@ -1358,7 +1346,7 @@
     }
   }
   COMPILER2_PRESENT(assert(DerivedPointerTable::is_empty(), "must be empty before verify");)
-  oops_do_internal(&VerifyOopClosure::verify_oop, (RegisterMap*)map, false);
+  oops_do_internal(&VerifyOopClosure::verify_oop, NULL, (RegisterMap*)map, false);
 }
 
 
--- a/src/share/vm/runtime/frame.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/runtime/frame.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -384,16 +384,14 @@
   void oops_interpreted_arguments_do(symbolHandle signature, bool is_static, OopClosure* f);
 
   // Iteration of oops
-  void oops_do_internal(OopClosure* f, RegisterMap* map, bool use_interpreter_oop_map_cache);
+  void oops_do_internal(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map, bool use_interpreter_oop_map_cache);
   void oops_entry_do(OopClosure* f, const RegisterMap* map);
-  void oops_code_blob_do(OopClosure* f, const RegisterMap* map);
+  void oops_code_blob_do(OopClosure* f, CodeBlobClosure* cf, const RegisterMap* map);
   int adjust_offset(methodOop method, int index); // helper for above fn
-  // Iteration of nmethods
-  void nmethods_code_blob_do();
  public:
   // Memory management
-  void oops_do(OopClosure* f, RegisterMap* map) { oops_do_internal(f, map, true); }
-  void nmethods_do();
+  void oops_do(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map) { oops_do_internal(f, cf, map, true); }
+  void nmethods_do(CodeBlobClosure* cf);
 
   void gc_prologue();
   void gc_epilogue();
--- a/src/share/vm/runtime/globals.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/runtime/globals.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -714,6 +714,11 @@
   diagnostic(bool, TraceNMethodInstalls, false,                             \
              "Trace nmethod intallation")                                   \
                                                                             \
+  diagnostic(intx, ScavengeRootsInCode, 0,                                  \
+             "0: do not allow scavengable oops in the code cache; "         \
+             "1: allow scavenging from the code cache; "                    \
+             "2: emit as many constants as the compiler can see")           \
+                                                                            \
   diagnostic(bool, TraceOSRBreakpoint, false,                               \
              "Trace OSR Breakpoint ")                                       \
                                                                             \
--- a/src/share/vm/runtime/sweeper.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/runtime/sweeper.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -34,6 +34,17 @@
 jint      NMethodSweeper::_not_entrant_seen_on_stack = 0;
 bool      NMethodSweeper::_rescan = false;
 
+class MarkActivationClosure: public CodeBlobClosure {
+public:
+  virtual void do_code_blob(CodeBlob* cb) {
+    // If we see an activation belonging to a non_entrant nmethod, we mark it.
+    if (cb->is_nmethod() && ((nmethod*)cb)->is_not_entrant()) {
+      ((nmethod*)cb)->mark_as_seen_on_stack();
+    }
+  }
+};
+static MarkActivationClosure mark_activation_closure;
+
 void NMethodSweeper::sweep() {
   assert(SafepointSynchronize::is_at_safepoint(), "must be executed at a safepoint");
   if (!MethodFlushing) return;
@@ -57,7 +68,7 @@
     if (PrintMethodFlushing) {
       tty->print_cr("### Sweep: stack traversal %d", _traversals);
     }
-    Threads::nmethods_do();
+    Threads::nmethods_do(&mark_activation_closure);
 
     // reset the flags since we started a scan from the beginning.
     _rescan = false;
--- a/src/share/vm/runtime/thread.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/runtime/thread.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -683,14 +683,15 @@
   return false;
 }
 
-void Thread::oops_do(OopClosure* f) {
+void Thread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
   active_handles()->oops_do(f);
   // Do oop for ThreadShadow
   f->do_oop((oop*)&_pending_exception);
   handle_area()->oops_do(f);
 }
 
-void Thread::nmethods_do() {
+void Thread::nmethods_do(CodeBlobClosure* cf) {
+  // no nmethods in a generic thread...
 }
 
 void Thread::print_on(outputStream* st) const {
@@ -2316,12 +2317,12 @@
 }
 
 
-void JavaThread::oops_do(OopClosure* f) {
+void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
   // The ThreadProfiler oops_do is done from FlatProfiler::oops_do
   // since there may be more than one thread using each ThreadProfiler.
 
   // Traverse the GCHandles
-  Thread::oops_do(f);
+  Thread::oops_do(f, cf);
 
   assert( (!has_last_Java_frame() && java_call_counter() == 0) ||
           (has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!");
@@ -2347,7 +2348,7 @@
 
     // Traverse the execution stack
     for(StackFrameStream fst(this); !fst.is_done(); fst.next()) {
-      fst.current()->oops_do(f, fst.register_map());
+      fst.current()->oops_do(f, cf, fst.register_map());
     }
   }
 
@@ -2379,9 +2380,8 @@
   }
 }
 
-void JavaThread::nmethods_do() {
-  // Traverse the GCHandles
-  Thread::nmethods_do();
+void JavaThread::nmethods_do(CodeBlobClosure* cf) {
+  Thread::nmethods_do(cf);  // (super method is a no-op)
 
   assert( (!has_last_Java_frame() && java_call_counter() == 0) ||
           (has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!");
@@ -2389,7 +2389,7 @@
   if (has_last_Java_frame()) {
     // Traverse the execution stack
     for(StackFrameStream fst(this); !fst.is_done(); fst.next()) {
-      fst.current()->nmethods_do();
+      fst.current()->nmethods_do(cf);
     }
   }
 }
@@ -2463,7 +2463,7 @@
 
 void JavaThread::verify() {
   // Verify oops in the thread.
-  oops_do(&VerifyOopClosure::verify_oop);
+  oops_do(&VerifyOopClosure::verify_oop, NULL);
 
   // Verify the stack frames.
   frames_do(frame_verify);
@@ -3602,14 +3602,14 @@
 // uses the Threads_lock to gurantee this property. It also makes sure that
 // all threads gets blocked when exiting or starting).
 
-void Threads::oops_do(OopClosure* f) {
+void Threads::oops_do(OopClosure* f, CodeBlobClosure* cf) {
   ALL_JAVA_THREADS(p) {
-    p->oops_do(f);
+    p->oops_do(f, cf);
   }
-  VMThread::vm_thread()->oops_do(f);
+  VMThread::vm_thread()->oops_do(f, cf);
 }
 
-void Threads::possibly_parallel_oops_do(OopClosure* f) {
+void Threads::possibly_parallel_oops_do(OopClosure* f, CodeBlobClosure* cf) {
   // Introduce a mechanism allowing parallel threads to claim threads as
   // root groups.  Overhead should be small enough to use all the time,
   // even in sequential code.
@@ -3618,12 +3618,12 @@
   int cp = SharedHeap::heap()->strong_roots_parity();
   ALL_JAVA_THREADS(p) {
     if (p->claim_oops_do(is_par, cp)) {
-      p->oops_do(f);
+      p->oops_do(f, cf);
     }
   }
   VMThread* vmt = VMThread::vm_thread();
   if (vmt->claim_oops_do(is_par, cp))
-    vmt->oops_do(f);
+    vmt->oops_do(f, cf);
 }
 
 #ifndef SERIALGC
@@ -3644,11 +3644,11 @@
 }
 #endif // SERIALGC
 
-void Threads::nmethods_do() {
+void Threads::nmethods_do(CodeBlobClosure* cf) {
   ALL_JAVA_THREADS(p) {
-    p->nmethods_do();
+    p->nmethods_do(cf);
   }
-  VMThread::vm_thread()->nmethods_do();
+  VMThread::vm_thread()->nmethods_do(cf);
 }
 
 void Threads::gc_epilogue() {
--- a/src/share/vm/runtime/thread.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/runtime/thread.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -374,7 +374,8 @@
 
   // GC support
   // Apply "f->do_oop" to all root oops in "this".
-  void oops_do(OopClosure* f);
+  // Apply "cf->do_code_blob" (if !NULL) to all code blobs active in frames
+  void oops_do(OopClosure* f, CodeBlobClosure* cf);
 
   // Handles the parallel case for the method below.
 private:
@@ -398,7 +399,7 @@
   }
 
   // Sweeper support
-  void nmethods_do();
+  void nmethods_do(CodeBlobClosure* cf);
 
   // Tells if adr belong to this thread. This is used
   // for checking if a lock is owned by the running thread.
@@ -1229,10 +1230,10 @@
   void frames_do(void f(frame*, const RegisterMap*));
 
   // Memory operations
-  void oops_do(OopClosure* f);
+  void oops_do(OopClosure* f, CodeBlobClosure* cf);
 
   // Sweeper operations
-  void nmethods_do();
+  void nmethods_do(CodeBlobClosure* cf);
 
   // Memory management operations
   void gc_epilogue();
@@ -1620,9 +1621,9 @@
 
   // Apply "f->do_oop" to all root oops in all threads.
   // This version may only be called by sequential code.
-  static void oops_do(OopClosure* f);
+  static void oops_do(OopClosure* f, CodeBlobClosure* cf);
   // This version may be called by sequential or parallel code.
-  static void possibly_parallel_oops_do(OopClosure* f);
+  static void possibly_parallel_oops_do(OopClosure* f, CodeBlobClosure* cf);
   // This creates a list of GCTasks, one per thread.
   static void create_thread_roots_tasks(GCTaskQueue* q);
   // This creates a list of GCTasks, one per thread, for marking objects.
@@ -1630,13 +1631,13 @@
 
   // Apply "f->do_oop" to roots in all threads that
   // are part of compiled frames
-  static void compiled_frame_oops_do(OopClosure* f);
+  static void compiled_frame_oops_do(OopClosure* f, CodeBlobClosure* cf);
 
   static void convert_hcode_pointers();
   static void restore_hcode_pointers();
 
   // Sweeper
-  static void nmethods_do();
+  static void nmethods_do(CodeBlobClosure* cf);
 
   static void gc_epilogue();
   static void gc_prologue();
--- a/src/share/vm/runtime/vmStructs.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/runtime/vmStructs.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -549,6 +549,7 @@
   /********************************/                                                                                                 \
                                                                                                                                      \
      static_field(CodeCache,                   _heap,                                         CodeHeap*)                             \
+     static_field(CodeCache,                   _scavenge_root_nmethods,                       nmethod*)                              \
                                                                                                                                      \
   /*******************************/                                                                                                  \
   /* CodeHeap (NOTE: incomplete) */                                                                                                  \
@@ -618,7 +619,9 @@
      static_field(nmethod,             _zombie_instruction_size,                      int)                                   \
   nonstatic_field(nmethod,             _method,                                       methodOop)                             \
   nonstatic_field(nmethod,             _entry_bci,                                    int)                                   \
-  nonstatic_field(nmethod,             _link,                                         nmethod*)                              \
+  nonstatic_field(nmethod,             _osr_link,                                     nmethod*)                              \
+  nonstatic_field(nmethod,             _scavenge_root_link,                           nmethod*)                              \
+  nonstatic_field(nmethod,             _scavenge_root_state,                          jbyte)                                 \
   nonstatic_field(nmethod,             _exception_offset,                             int)                                   \
   nonstatic_field(nmethod,             _deoptimize_offset,                            int)                                   \
   nonstatic_field(nmethod,             _orig_pc_offset,                               int)                                   \
--- a/src/share/vm/runtime/vmThread.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/runtime/vmThread.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -619,8 +619,8 @@
 }
 
 
-void VMThread::oops_do(OopClosure* f) {
-  Thread::oops_do(f);
+void VMThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
+  Thread::oops_do(f, cf);
   _vm_queue->oops_do(f);
 }
 
@@ -652,5 +652,5 @@
 #endif
 
 void VMThread::verify() {
-  oops_do(&VerifyOopClosure::verify_oop);
+  oops_do(&VerifyOopClosure::verify_oop, NULL);
 }
--- a/src/share/vm/runtime/vmThread.hpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/runtime/vmThread.hpp	Wed Sep 30 13:25:39 2009 -0700
@@ -121,7 +121,7 @@
   static VMThread* vm_thread()                    { return _vm_thread; }
 
   // GC support
-  void oops_do(OopClosure* f);
+  void oops_do(OopClosure* f, CodeBlobClosure* cf);
 
   // Debugging
   void print_on(outputStream* st) const;
--- a/src/share/vm/utilities/debug.cpp	Fri Sep 25 04:39:54 2009 -0700
+++ b/src/share/vm/utilities/debug.cpp	Wed Sep 30 13:25:39 2009 -0700
@@ -702,11 +702,14 @@
   tty->print_cr("Searching strong roots:");
   Universe::oops_do(&lookFor, false);
   JNIHandles::oops_do(&lookFor);   // Global (strong) JNI handles
-  Threads::oops_do(&lookFor);
+  Threads::oops_do(&lookFor, NULL);
   ObjectSynchronizer::oops_do(&lookFor);
   //FlatProfiler::oops_do(&lookFor);
   SystemDictionary::oops_do(&lookFor);
 
+  tty->print_cr("Searching code cache:");
+  CodeCache::oops_do(&lookFor);
+
   tty->print_cr("Done.");
 }
 
--- a/test/compiler/6823453/Test.java	Fri Sep 25 04:39:54 2009 -0700
+++ b/test/compiler/6823453/Test.java	Wed Sep 30 13:25:39 2009 -0700
@@ -26,7 +26,7 @@
  * @test
  * @bug 6823453
  * @summary DeoptimizeALot causes fastdebug server jvm to fail with assert(false,"unscheduable graph")
- * @run main/othervm -Xcomp -XX:CompileOnly=Test -XX:+DeoptimizeALot Test
+ * @run main/othervm -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:CompileOnly=Test -XX:+DeoptimizeALot Test
  */
 
 public class Test {
--- a/test/compiler/6833129/Test.java	Fri Sep 25 04:39:54 2009 -0700
+++ b/test/compiler/6833129/Test.java	Wed Sep 30 13:25:39 2009 -0700
@@ -25,7 +25,7 @@
  * @test
  * @bug 6833129
  * @summary Object.clone() and Arrays.copyOf ignore coping with -XX:+DeoptimizeALot
- * @run main/othervm -Xbatch -XX:+DeoptimizeALot Test
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+DeoptimizeALot Test
  */
 
 public class Test{
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/compiler/6875866/Test.java	Wed Sep 30 13:25:39 2009 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @bug 6875866
+ * @summary Intrinsic for String.indexOf() is broken on x86 with SSE4.2
+ *
+ * @run main/othervm -Xcomp Test
+ */
+
+public class Test {
+
+  static int IndexOfTest(String str) {
+    return str.indexOf("11111xx1x");
+  }
+
+  public static void main(String args[]) {
+    String str = "11111xx11111xx1x";
+    int idx = IndexOfTest(str);
+    System.out.println("IndexOf = " + idx);
+    if (idx != 7) {
+      System.exit(97);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/compiler/6877254/Test.java	Wed Sep 30 13:25:39 2009 -0700
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @bug 6877254
+ * @summary Implement StoreCMNode::Ideal to promote its OopStore above the MergeMem
+ *
+ * @run main/othervm -server -Xcomp -XX:+UseConcMarkSweepGC Test
+ */
+
+public class Test {
+    static byte var_1;
+    static String var_2 = "";
+    static byte var_3;
+    static float var_4 = 0;
+
+    public static void main(String[] args) {
+        int i = 0;
+
+        for (String var_tmp = var_2; i < 11; var_1 = 0, i++) {
+            var_2 = var_2;
+            var_4 *= (var_4 *= (var_3 = 0));
+        }
+
+        System.out.println("var_1 = " + var_1);
+        System.out.println("var_2 = " + var_2);
+        System.out.println("var_3 = " + var_3);
+        System.out.println("var_4 = " + var_4);
+    }
+}