changeset 337:75e0a5b79b1f

Merge
author trims
date Wed, 17 Sep 2008 18:02:38 -0700
parents 51798f0e554f 7484fa4b8825
children e91159f921a5
files
diffstat 23 files changed, 380 insertions(+), 264 deletions(-) [+]
line wrap: on
line diff
--- a/agent/src/share/classes/sun/jvm/hotspot/code/Location.java	Thu Sep 11 11:25:43 2008 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/code/Location.java	Wed Sep 17 18:02:38 2008 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2008 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
@@ -39,9 +39,9 @@
     <P> Encoding: </P>
     <PRE>
     bits:
-    Where:  [15]
-    Type:   [14..12]
-    Offset: [11..0]
+    Type:   [3..0]
+    Where:  [4]
+    Offset: [31..5]
     </PRE>
 */
 
@@ -69,6 +69,7 @@
     // Location::Type constants
     TYPE_NORMAL = db.lookupIntConstant("Location::normal").intValue();
     TYPE_OOP = db.lookupIntConstant("Location::oop").intValue();
+    TYPE_NARROWOOP = db.lookupIntConstant("Location::narrowoop").intValue();
     TYPE_INT_IN_LONG = db.lookupIntConstant("Location::int_in_long").intValue();
     TYPE_LNG = db.lookupIntConstant("Location::lng").intValue();
     TYPE_FLOAT_IN_DBL = db.lookupIntConstant("Location::float_in_dbl").intValue();
@@ -115,6 +116,8 @@
     public static final Type NORMAL       = new Type("normal");
     /** Oop (please GC me!) */
     public static final Type OOP          = new Type("oop");
+    /** NarrowOop (please GC me!) */
+    public static final Type NARROWOOP    = new Type("narrowoop");
     /** Long held in one register */
     public static final Type INT_IN_LONG  = new Type("int_in_long");
     /** Long held in one register */
@@ -142,6 +145,8 @@
         return TYPE_NORMAL;
       } else if (this == OOP) {
         return TYPE_OOP;
+      } else if (this == NARROWOOP) {
+        return TYPE_NARROWOOP;
       } else if (this == INT_IN_LONG) {
         return TYPE_INT_IN_LONG;
       } else if (this == LNG) {
@@ -170,6 +175,7 @@
   // constants in Type enum
   private static int TYPE_NORMAL;
   private static int TYPE_OOP;
+  private static int TYPE_NARROWOOP;
   private static int TYPE_INT_IN_LONG;
   private static int TYPE_LNG;
   private static int TYPE_FLOAT_IN_DBL;
@@ -185,7 +191,7 @@
   Location(Where where, Type type, int offset) {
     setWhere(where);
     setType(type);
-    setOffset(offset & 0x0000FFFF);
+    setOffset(offset);
   }
 
   public Where getWhere() {
@@ -205,6 +211,8 @@
        return Type.NORMAL;
     } else if (type == TYPE_OOP) {
        return Type.OOP;
+    } else if (type == TYPE_NARROWOOP) {
+       return Type.NARROWOOP;
     } else if (type == TYPE_INT_IN_LONG) {
        return Type.INT_IN_LONG;
     } else if (type == TYPE_LNG) {
@@ -238,6 +246,10 @@
     return getType() == Type.OOP;
   }
 
+  public boolean holdsNarrowOop() {
+    return getType() == Type.NARROWOOP;
+  }
+
   public boolean holdsInt() {
     return getType() == Type.INT_IN_LONG;
   }
@@ -266,7 +278,7 @@
     if (Assert.ASSERTS_ENABLED) {
       Assert.that(getWhere() == Where.ON_STACK, "wrong Where");
     }
-    return getOffset() << VM.getVM().getLogAddressSize();
+    return getOffset() * (int)VM.getVM().getIntSize();
   }
 
   public int getRegisterNumber() {
@@ -296,6 +308,8 @@
       if (type == Type.NORMAL) {
       } else if (type == Type.OOP) {
         tty.print(",oop");
+      } else if (type == Type.NARROWOOP) {
+        tty.print(",narrowoop");
       } else if (type == Type.INT_IN_LONG) {
         tty.print(",int");
       } else if (type == Type.LNG) {
@@ -314,26 +328,26 @@
 
   /** Serialization of debugging information */
   public Location(DebugInfoReadStream stream) {
-    value = (0x0000FFFF & stream.readInt());
+    value = stream.readInt();
   }
 
   // FIXME: not yet implementable
   // void write_on(DebugInfoWriteStream* stream);
 
 
-  //--------------------------------------------------------------------------------
+  //-----------------------------------------------------------------------------
   // Internals only below this point
   //
 
   private void setWhere(Where where) {
-    value |= (where.getValue() << WHERE_SHIFT);
+    value |= ((where.getValue() << WHERE_SHIFT) & WHERE_MASK);
   }
 
   private void setType(Type type) {
-    value |= (type.getValue() << TYPE_SHIFT);
+    value |= ((type.getValue() << TYPE_SHIFT) & TYPE_MASK);
   }
 
   private void setOffset(int offset) {
-    value |= (offset << OFFSET_SHIFT);
+    value |= ((offset << OFFSET_SHIFT) & OFFSET_MASK);
   }
 }
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java	Thu Sep 11 11:25:43 2008 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java	Wed Sep 17 18:02:38 2008 -0700
@@ -206,6 +206,16 @@
           Assert.that( loc.isRegister(), "ints always saved to stack in 1 word" );
         }
         return new StackValue(valueAddr.getJLongAt(0) & 0xFFFFFFFF);
+      } else if (loc.holdsNarrowOop()) {  // Holds an narrow oop?
+        if (loc.isRegister() && VM.getVM().isBigEndian()) {
+          // The callee has no clue whether the register holds an narrow oop,
+          // long or is unused.  He always saves a long.  Here we know
+          // a long was saved, but we only want an narrow oop back.  Narrow the
+          // saved long to the narrow oop that the JVM wants.
+          return new StackValue(valueAddr.getCompOopHandleAt(VM.getVM().getIntSize()));
+        } else {
+          return new StackValue(valueAddr.getCompOopHandleAt(0));
+        }
       } else if( loc.holdsOop() ) {  // Holds an oop?
         return new StackValue(valueAddr.getOopHandleAt(0));
       } else if( loc.holdsDouble() ) {
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java	Thu Sep 11 11:25:43 2008 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java	Wed Sep 17 18:02:38 2008 -0700
@@ -621,6 +621,11 @@
     return bytes;
   }
 
+  /** Returns true if this is a isBigEndian, false otherwise */
+  public boolean isBigEndian() {
+    return isBigEndian;
+  }
+
   /** Returns true if this is a "core" build, false if either C1 or C2
       is present */
   public boolean isCore() {
--- a/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java	Thu Sep 11 11:25:43 2008 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java	Wed Sep 17 18:02:38 2008 -0700
@@ -1135,6 +1135,8 @@
             buf.append("normal");
          } else if (type == Location.Type.OOP) {
             buf.append("oop");
+         } else if (type == Location.Type.NARROWOOP) {
+            buf.append("narrowoop");
          } else if (type == Location.Type.INT_IN_LONG) {
             buf.append("int");
          } else if (type == Location.Type.LNG) {
--- a/make/jprt.properties	Thu Sep 11 11:25:43 2008 -0700
+++ b/make/jprt.properties	Wed Sep 17 18:02:38 2008 -0700
@@ -295,3 +295,9 @@
   ${jprt.my.windows.i586.test.targets}, \
   ${jprt.my.windows.x64.test.targets}
 
+# The default test/Makefile targets that should be run
+
+# Example:
+#   jprt.make.rule.test.targets=*-*-*-packtest
+#jprt.make.rule.test.targets=*-product-*-packtest
+
--- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp	Wed Sep 17 18:02:38 2008 -0700
@@ -1129,8 +1129,8 @@
 #else
     __ pushl(frame_map()->address_for_slot(src ->double_stack_ix(), 0));
     // push and pop the part at src + wordSize, adding wordSize for the previous push
-    __ pushl(frame_map()->address_for_slot(src ->double_stack_ix(), wordSize));
-    __ popl (frame_map()->address_for_slot(dest->double_stack_ix(), wordSize));
+    __ pushl(frame_map()->address_for_slot(src ->double_stack_ix(), 2 * wordSize));
+    __ popl (frame_map()->address_for_slot(dest->double_stack_ix(), 2 * wordSize));
     __ popl (frame_map()->address_for_slot(dest->double_stack_ix(), 0));
 #endif // _LP64
 
--- a/src/share/vm/code/location.cpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/share/vm/code/location.cpp	Wed Sep 17 18:02:38 2008 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2008 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
@@ -26,7 +26,7 @@
 #include "incls/_location.cpp.incl"
 
 void Location::print_on(outputStream* st) const {
-  if(type() == invalid && !legal_offset_in_bytes(offset() * BytesPerInt)) {
+  if(type() == invalid) {
     // product of Location::invalid_loc() or Location::Location().
     switch (where()) {
     case on_stack:     st->print("empty");    break;
@@ -42,6 +42,7 @@
   switch (type()) {
   case normal:                                 break;
   case oop:          st->print(",oop");        break;
+  case narrowoop:    st->print(",narrowoop");  break;
   case int_in_long:  st->print(",int");        break;
   case lng:          st->print(",long");       break;
   case float_in_dbl: st->print(",float");      break;
@@ -53,17 +54,17 @@
 
 
 Location::Location(DebugInfoReadStream* stream) {
-  _value = (uint16_t) stream->read_int();
+  _value = (juint) stream->read_int();
 }
 
 
 void Location::write_on(DebugInfoWriteStream* stream) {
-  stream->write_int(_value & 0x0000FFFF);
+  stream->write_int(_value);
 }
 
 
 // Valid argument to Location::new_stk_loc()?
 bool Location::legal_offset_in_bytes(int offset_in_bytes) {
   if ((offset_in_bytes % BytesPerInt) != 0)  return false;
-  return (offset_in_bytes / BytesPerInt) < (OFFSET_MASK >> OFFSET_SHIFT);
+  return (juint)(offset_in_bytes / BytesPerInt) < (OFFSET_MASK >> OFFSET_SHIFT);
 }
--- a/src/share/vm/code/location.hpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/share/vm/code/location.hpp	Wed Sep 17 18:02:38 2008 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2008 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
@@ -28,10 +28,10 @@
 //
 // Encoding:
 //
-// bits:
-//  Where:  [15]
-//  Type:   [14..12]
-//  Offset: [11..0]
+// bits (use low bits for best compression):
+//  Type:   [3..0]
+//  Where:  [4]
+//  Offset: [31..5]
 
 class Location VALUE_OBJ_CLASS_SPEC {
   friend class VMStructs;
@@ -42,6 +42,7 @@
   };
 
   enum Type {
+    invalid,                    // Invalid location
     normal,                     // Ints, floats, double halves
     oop,                        // Oop (please GC me!)
     int_in_long,                // Integer held in long register
@@ -49,21 +50,21 @@
     float_in_dbl,               // Float held in double register
     dbl,                        // Double held in one register
     addr,                       // JSR return address
-    invalid                     // Invalid location
+    narrowoop                   // Narrow Oop (please GC me!)
   };
 
 
  private:
   enum {
-    OFFSET_MASK  = (jchar) 0x0FFF,
-    OFFSET_SHIFT = 0,
-    TYPE_MASK    = (jchar) 0x7000,
-    TYPE_SHIFT   = 12,
-    WHERE_MASK   = (jchar) 0x8000,
-    WHERE_SHIFT  = 15
+    TYPE_MASK    = (juint) 0x0F,
+    TYPE_SHIFT   = 0,
+    WHERE_MASK   = (juint) 0x10,
+    WHERE_SHIFT  = 4,
+    OFFSET_MASK  = (juint) 0xFFFFFFE0,
+    OFFSET_SHIFT = 5
   };
 
-  uint16_t _value;
+  juint _value;
 
   // Create a bit-packed Location
   Location(Where where_, Type type_, unsigned offset_) {
@@ -74,9 +75,9 @@
   }
 
   inline void set(Where where_, Type type_, unsigned offset_) {
-    _value = (uint16_t) ((where_  << WHERE_SHIFT) |
-                         (type_   << TYPE_SHIFT)  |
-                         ((offset_ << OFFSET_SHIFT) & OFFSET_MASK));
+    _value = (juint) ((where_  << WHERE_SHIFT) |
+                      (type_   << TYPE_SHIFT)  |
+                      ((offset_ << OFFSET_SHIFT) & OFFSET_MASK));
   }
 
  public:
@@ -86,7 +87,7 @@
   // Register location Factory
   static Location new_reg_loc( Type t, VMReg reg ) { return Location(in_register, t, reg->value()); }
   // Default constructor
-  Location() { set(on_stack,invalid,(unsigned) -1); }
+  Location() { set(on_stack,invalid,0); }
 
   // Bit field accessors
   Where where()  const { return (Where)       ((_value & WHERE_MASK)  >> WHERE_SHIFT);}
--- a/src/share/vm/opto/addnode.cpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/share/vm/opto/addnode.cpp	Wed Sep 17 18:02:38 2008 -0700
@@ -157,6 +157,7 @@
     Node *a12 = add1->in(2);
     const Type *t12 = phase->type( a12 );
     if( t12->singleton() && t12 != Type::TOP && (add1 != add1->in(1)) ) {
+      assert(add1->in(1) != this, "dead loop in AddNode::Ideal");
       add2 = add1->clone();
       add2->set_req(2, in(2));
       add2 = phase->transform(add2);
@@ -173,6 +174,7 @@
     Node *a22 = add2->in(2);
     const Type *t22 = phase->type( a22 );
     if( t22->singleton() && t22 != Type::TOP && (add2 != add2->in(1)) ) {
+      assert(add2->in(1) != this, "dead loop in AddNode::Ideal");
       Node *addx = add2->clone();
       addx->set_req(1, in(1));
       addx->set_req(2, add2->in(1));
--- a/src/share/vm/opto/callnode.cpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/share/vm/opto/callnode.cpp	Wed Sep 17 18:02:38 2008 -0700
@@ -334,6 +334,9 @@
     case Type::InstPtr:
       st->print(" %s%d]=#Ptr" INTPTR_FORMAT,msg,i,t->isa_oopptr()->const_oop());
       break;
+    case Type::NarrowOop:
+      st->print(" %s%d]=#Ptr" INTPTR_FORMAT,msg,i,t->make_ptr()->isa_oopptr()->const_oop());
+      break;
     case Type::RawPtr:
       st->print(" %s%d]=#Raw" INTPTR_FORMAT,msg,i,t->is_rawptr());
       break;
--- a/src/share/vm/opto/compile.cpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/share/vm/opto/compile.cpp	Wed Sep 17 18:02:38 2008 -0700
@@ -1967,6 +1967,7 @@
           !n->is_Proj() &&
           nop != Op_CreateEx &&
           nop != Op_CheckCastPP &&
+          nop != Op_DecodeN &&
           !n->is_Mem() ) {
         Node *x = n->clone();
         call->set_req( TypeFunc::Parms, x );
@@ -2075,20 +2076,27 @@
   case Op_CmpP:
     // Do this transformation here to preserve CmpPNode::sub() and
     // other TypePtr related Ideal optimizations (for example, ptr nullness).
-    if( n->in(1)->is_DecodeN() ) {
+    if (n->in(1)->is_DecodeN() || n->in(2)->is_DecodeN()) {
+      Node* in1 = n->in(1);
+      Node* in2 = n->in(2);
+      if (!in1->is_DecodeN()) {
+        in2 = in1;
+        in1 = n->in(2);
+      }
+      assert(in1->is_DecodeN(), "sanity");
+
       Compile* C = Compile::current();
-      Node* in2 = NULL;
-      if( n->in(2)->is_DecodeN() ) {
-        in2 = n->in(2)->in(1);
-      } else if ( n->in(2)->Opcode() == Op_ConP ) {
-        const Type* t = n->in(2)->bottom_type();
-        if (t == TypePtr::NULL_PTR) {
-          Node *in1 = n->in(1);
+      Node* new_in2 = NULL;
+      if (in2->is_DecodeN()) {
+        new_in2 = in2->in(1);
+      } else if (in2->Opcode() == Op_ConP) {
+        const Type* t = in2->bottom_type();
+        if (t == TypePtr::NULL_PTR && UseImplicitNullCheckForNarrowOop) {
           if (Matcher::clone_shift_expressions) {
             // x86, ARM and friends can handle 2 adds in addressing mode.
             // Decode a narrow oop and do implicit NULL check in address
             // [R12 + narrow_oop_reg<<3 + offset]
-            in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR);
+            new_in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR);
           } else {
             // Don't replace CmpP(o ,null) if 'o' is used in AddP
             // to generate implicit NULL check on Sparc where
@@ -2099,16 +2107,22 @@
                 break;
             }
             if (i >= in1->outcnt()) {
-              in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR);
+              new_in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR);
             }
           }
         } else if (t->isa_oopptr()) {
-          in2 = ConNode::make(C, t->make_narrowoop());
+          new_in2 = ConNode::make(C, t->make_narrowoop());
         }
       }
-      if( in2 != NULL ) {
-        Node* cmpN = new (C, 3) CmpNNode(n->in(1)->in(1), in2);
+      if (new_in2 != NULL) {
+        Node* cmpN = new (C, 3) CmpNNode(in1->in(1), new_in2);
         n->subsume_by( cmpN );
+        if (in1->outcnt() == 0) {
+          in1->disconnect_inputs(NULL);
+        }
+        if (in2->outcnt() == 0) {
+          in2->disconnect_inputs(NULL);
+        }
       }
     }
     break;
@@ -2214,6 +2228,9 @@
 // Replacing Opaque nodes with their input in final_graph_reshaping_impl(),
 // requires that the walk visits a node's inputs before visiting the node.
 static void final_graph_reshaping_walk( Node_Stack &nstack, Node *root, Final_Reshape_Counts &fpu ) {
+  ResourceArea *area = Thread::current()->resource_area();
+  Unique_Node_List sfpt(area);
+
   fpu._visited.set(root->_idx); // first, mark node as visited
   uint cnt = root->req();
   Node *n = root;
@@ -2224,6 +2241,8 @@
       Node* m = n->in(i);
       ++i;
       if (m != NULL && !fpu._visited.test_set(m->_idx)) {
+        if (m->is_SafePoint() && m->as_SafePoint()->jvms() != NULL)
+          sfpt.push(m);
         cnt = m->req();
         nstack.push(n, i); // put on stack parent and next input's index
         n = m;
@@ -2240,6 +2259,41 @@
       nstack.pop();        // Shift to the next node on stack
     }
   }
+
+  // Go over safepoints nodes to skip DecodeN nodes for debug edges.
+  // It could be done for an uncommon traps or any safepoints/calls
+  // if the DecodeN node is referenced only in a debug info.
+  while (sfpt.size() > 0) {
+    n = sfpt.pop();
+    JVMState *jvms = n->as_SafePoint()->jvms();
+    assert(jvms != NULL, "sanity");
+    int start = jvms->debug_start();
+    int end   = n->req();
+    bool is_uncommon = (n->is_CallStaticJava() &&
+                        n->as_CallStaticJava()->uncommon_trap_request() != 0);
+    for (int j = start; j < end; j++) {
+      Node* in = n->in(j);
+      if (in->is_DecodeN()) {
+        bool safe_to_skip = true;
+        if (!is_uncommon ) {
+          // Is it safe to skip?
+          for (uint i = 0; i < in->outcnt(); i++) {
+            Node* u = in->raw_out(i);
+            if (!u->is_SafePoint() ||
+                 u->is_Call() && u->as_Call()->has_non_debug_use(n)) {
+              safe_to_skip = false;
+            }
+          }
+        }
+        if (safe_to_skip) {
+          n->set_req(j, in->in(1));
+        }
+        if (in->outcnt() == 0) {
+          in->disconnect_inputs(NULL);
+        }
+      }
+    }
+  }
 }
 
 //------------------------------final_graph_reshaping--------------------------
--- a/src/share/vm/opto/graphKit.cpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/share/vm/opto/graphKit.cpp	Wed Sep 17 18:02:38 2008 -0700
@@ -1212,6 +1212,7 @@
                     Deoptimization::Action_make_not_entrant,
                     NULL, "assert_null");
     } else {
+      replace_in_map(value, zerocon(type));
       builtin_throw(reason);
     }
   }
@@ -1960,6 +1961,7 @@
     // method will be compiled to handle NULLs.
     PreserveJVMState pjvms(this);
     set_control(*null_control);
+    replace_in_map(value, null());
     uncommon_trap(Deoptimization::Reason_null_check,
                   Deoptimization::Action_make_not_entrant);
     (*null_control) = top();    // NULL path is dead
--- a/src/share/vm/opto/lcm.cpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/share/vm/opto/lcm.cpp	Wed Sep 17 18:02:38 2008 -0700
@@ -58,6 +58,9 @@
     not_null_block = _succs[0];
     null_block     = _succs[1];
   }
+  while (null_block->is_Empty() == Block::empty_with_goto) {
+    null_block     = null_block->_succs[0];
+  }
 
   // Search the exception block for an uncommon trap.
   // (See Parse::do_if and Parse::do_ifnull for the reason
@@ -149,6 +152,10 @@
       const TypePtr *adr_type = NULL;  // Do not need this return value here
       const Node* base = mach->get_base_and_disp(offset, adr_type);
       if (base == NULL || base == NodeSentinel) {
+        // Narrow oop address doesn't have base, only index
+        if( val->bottom_type()->isa_narrowoop() &&
+            MacroAssembler::needs_explicit_null_check(offset) )
+          continue;             // Give up if offset is beyond page size
         // cannot reason about it; is probably not implicit null exception
       } else {
         const TypePtr* tptr = base->bottom_type()->is_ptr();
--- a/src/share/vm/opto/loopopts.cpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/share/vm/opto/loopopts.cpp	Wed Sep 17 18:02:38 2008 -0700
@@ -932,7 +932,7 @@
             // to fold a StoreP and an AddP together (as part of an
             // address expression) and the AddP and StoreP have
             // different controls.
-            if( !x->is_Load() ) _igvn._worklist.yank(x);
+            if( !x->is_Load() && !x->is_DecodeN() ) _igvn._worklist.yank(x);
           }
           _igvn.remove_dead_node(n);
         }
--- a/src/share/vm/opto/output.cpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/share/vm/opto/output.cpp	Wed Sep 17 18:02:38 2008 -0700
@@ -685,6 +685,8 @@
     } else if( t->base() == Type::Int && OptoReg::is_reg(regnum) ) {
       array->append(new_loc_value( _regalloc, regnum, Matcher::int_in_long
                                    ? Location::int_in_long : Location::normal ));
+    } else if( t->base() == Type::NarrowOop ) {
+      array->append(new_loc_value( _regalloc, regnum, Location::narrowoop ));
     } else {
       array->append(new_loc_value( _regalloc, regnum, _regalloc->is_oop(local) ? Location::oop : Location::normal ));
     }
@@ -704,6 +706,13 @@
   case Type::KlassPtr:          // fall through
     array->append(new ConstantOopWriteValue(t->isa_oopptr()->const_oop()->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()));
+    }
+    break;
   case Type::Int:
     array->append(new ConstantIntValue(t->is_int()->get_con()));
     break;
@@ -878,9 +887,14 @@
         }
       } else if( !obj_node->is_Con() ) {
         OptoReg::Name obj_reg = _regalloc->get_reg_first(obj_node);
-        scval = new_loc_value( _regalloc, obj_reg, Location::oop );
+        if( obj_node->bottom_type()->base() == Type::NarrowOop ) {
+          scval = new_loc_value( _regalloc, obj_reg, Location::narrowoop );
+        } else {
+          scval = new_loc_value( _regalloc, obj_reg, Location::oop );
+        }
       } else {
-        scval = new ConstantOopWriteValue(obj_node->bottom_type()->is_instptr()->const_oop()->encoding());
+        const TypePtr *tp = obj_node->bottom_type()->make_ptr();
+        scval = new ConstantOopWriteValue(tp->is_instptr()->const_oop()->encoding());
       }
 
       OptoReg::Name box_reg = BoxLockNode::stack_slot(box_node);
--- a/src/share/vm/opto/reg_split.cpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/share/vm/opto/reg_split.cpp	Wed Sep 17 18:02:38 2008 -0700
@@ -527,6 +527,7 @@
       // Initialize needs_phi and needs_split
       bool needs_phi = false;
       bool needs_split = false;
+      bool has_phi = false;
       // Walk the predecessor blocks to check inputs for that live range
       // Grab predecessor block header
       n1 = b->pred(1);
@@ -570,28 +571,30 @@
         }
       }  // End for all potential Phi inputs
 
-      // If a phi is needed, check for it
-      if( needs_phi ) {
-        // check block for appropriate phinode & update edges
-        for( insidx = 1; insidx <= b->end_idx(); insidx++ ) {
-          n1 = b->_nodes[insidx];
-          // bail if this is not a phi
-          phi = n1->is_Phi() ? n1->as_Phi() : NULL;
-          if( phi == NULL ) {
-            // Keep track of index of first non-PhiNode instruction in block
-            non_phi = insidx;
-            // break out of the for loop as we have handled all phi nodes
-            break;
-          }
-          // must be looking at a phi
-          if( Find_id(n1) == lidxs.at(slidx) ) {
-            // found the necessary phi
-            needs_phi = false;
-            // initialize the Reaches entry for this LRG
-            Reachblock[slidx] = phi;
-            break;
-          }  // end if found correct phi
-        }  // end for all phi's
+      // check block for appropriate phinode & update edges
+      for( insidx = 1; insidx <= b->end_idx(); insidx++ ) {
+        n1 = b->_nodes[insidx];
+        // bail if this is not a phi
+        phi = n1->is_Phi() ? n1->as_Phi() : NULL;
+        if( phi == NULL ) {
+          // Keep track of index of first non-PhiNode instruction in block
+          non_phi = insidx;
+          // break out of the for loop as we have handled all phi nodes
+          break;
+        }
+        // must be looking at a phi
+        if( Find_id(n1) == lidxs.at(slidx) ) {
+          // found the necessary phi
+          needs_phi = false;
+          has_phi = true;
+          // initialize the Reaches entry for this LRG
+          Reachblock[slidx] = phi;
+          break;
+        }  // end if found correct phi
+      }  // end for all phi's
+
+      // If a phi is needed or exist, check for it
+      if( needs_phi || has_phi ) {
         // add new phinode if one not already found
         if( needs_phi ) {
           // create a new phi node and insert it into the block
@@ -695,7 +698,8 @@
               }
             }
             assert( u, "at least 1 valid input expected" );
-            if( i >= cnt ) {    // Didn't find 2+ unique inputs?
+            if( i >= cnt ) {    // Found one unique input
+              assert(Find_id(n) == Find_id(u), "should be the same lrg");
               n->replace_by(u); // Then replace with unique input
               n->disconnect_inputs(NULL);
               b->_nodes.remove(insidx);
--- a/src/share/vm/runtime/arguments.cpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/share/vm/runtime/arguments.cpp	Wed Sep 17 18:02:38 2008 -0700
@@ -1204,15 +1204,17 @@
       // Turn off until bug is fixed.
       // FLAG_SET_ERGO(bool, UseCompressedOops, true);
     }
+#ifdef _WIN64
+    if (UseLargePages && UseCompressedOops) {
+      // Cannot allocate guard pages for implicit checks in indexed addressing
+      // mode, when large pages are specified on windows.
+      FLAG_SET_DEFAULT(UseImplicitNullCheckForNarrowOop, false);
+    }
+#endif //  _WIN64
   } else {
     if (UseCompressedOops && !FLAG_IS_DEFAULT(UseCompressedOops)) {
       // If specified, give a warning
-      if (UseConcMarkSweepGC){
-        warning("Compressed Oops does not work with CMS");
-      } else {
-        warning(
-          "Max heap size too large for Compressed Oops");
-      }
+      warning( "Max heap size too large for Compressed Oops");
       FLAG_SET_DEFAULT(UseCompressedOops, false);
     }
   }
--- a/src/share/vm/runtime/globals.hpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/share/vm/runtime/globals.hpp	Wed Sep 17 18:02:38 2008 -0700
@@ -294,6 +294,9 @@
   lp64_product(bool, CheckCompressedOops, trueInDebug,                      \
             "generate checks in encoding/decoding code")                    \
                                                                             \
+  product(bool, UseImplicitNullCheckForNarrowOop, true,                     \
+            "generate implicit null check in indexed addressing mode.")     \
+                                                                            \
   /* UseMembar is theoretically a temp flag used for memory barrier         \
    * removal testing.  It was supposed to be removed before FCS but has     \
    * been re-added (see 6401008) */                                         \
--- a/src/share/vm/runtime/stackValue.cpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/share/vm/runtime/stackValue.cpp	Wed Sep 17 18:02:38 2008 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2008 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
@@ -86,6 +86,22 @@
     case Location::lng:
       // Long   value in an aligned adjacent pair
       return new StackValue(*(intptr_t*)value_addr);
+    case Location::narrowoop: {
+      union { intptr_t p; narrowOop noop;} value;
+      value.p = (intptr_t) CONST64(0xDEADDEAFDEADDEAF);
+      if (loc.is_register()) {
+        // The callee has no clue whether the register holds an int,
+        // long or is unused.  He always saves a long.  Here we know
+        // a long was saved, but we only want an int back.  Narrow the
+        // saved long to the int that the JVM wants.
+        value.noop =  (narrowOop) *(julong*) value_addr;
+      } else {
+        value.noop = *(narrowOop*) value_addr;
+      }
+      // Decode narrowoop and wrap a handle around the oop
+      Handle h(oopDesc::decode_heap_oop(value.noop));
+      return new StackValue(h);
+    }
 #endif
     case Location::oop: {
       Handle h(*(oop *)value_addr); // Wrap a handle around the oop
--- a/src/share/vm/runtime/thread.cpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/share/vm/runtime/thread.cpp	Wed Sep 17 18:02:38 2008 -0700
@@ -2756,13 +2756,17 @@
   // For now, just manually iterate through them.
   tc->do_thread(VMThread::vm_thread());
   Universe::heap()->gc_threads_do(tc);
-  {
-    // Grab the Terminator_lock to prevent watcher_thread from being terminated.
-    MutexLockerEx mu(Terminator_lock, Mutex::_no_safepoint_check_flag);
-    WatcherThread *wt = WatcherThread::watcher_thread();
-    if (wt != NULL)
-      tc->do_thread(wt);
-  }
+  WatcherThread *wt = WatcherThread::watcher_thread();
+  // Strictly speaking, the following NULL check isn't sufficient to make sure
+  // the data for WatcherThread is still valid upon being examined. However,
+  // considering that WatchThread terminates when the VM is on the way to
+  // exit at safepoint, the chance of the above is extremely small. The right
+  // way to prevent termination of WatcherThread would be to acquire
+  // Terminator_lock, but we can't do that without violating the lock rank
+  // checking in some cases.
+  if (wt != NULL)
+    tc->do_thread(wt);
+
   // If CompilerThreads ever become non-JavaThreads, add them here
 }
 
--- a/src/share/vm/runtime/virtualspace.cpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/share/vm/runtime/virtualspace.cpp	Wed Sep 17 18:02:38 2008 -0700
@@ -380,7 +380,8 @@
                                      bool large, char* requested_address) :
   ReservedSpace(size, alignment, large,
                 requested_address,
-                UseCompressedOops ? lcm(os::vm_page_size(), alignment) : 0) {
+                UseCompressedOops && UseImplicitNullCheckForNarrowOop ?
+                  lcm(os::vm_page_size(), alignment) : 0) {
   // Only reserved space for the java heap should have a noaccess_prefix
   // if using compressed oops.
   protect_noaccess_prefix(size);
@@ -391,7 +392,8 @@
                                      const size_t suffix_size,
                                      const size_t suffix_align) :
   ReservedSpace(prefix_size, prefix_align, suffix_size, suffix_align,
-                UseCompressedOops ? lcm(os::vm_page_size(), prefix_align) : 0) {
+                UseCompressedOops && UseImplicitNullCheckForNarrowOop ?
+                  lcm(os::vm_page_size(), prefix_align) : 0) {
   protect_noaccess_prefix(prefix_size+suffix_size);
 }
 
--- a/src/share/vm/runtime/vmStructs.cpp	Thu Sep 11 11:25:43 2008 -0700
+++ b/src/share/vm/runtime/vmStructs.cpp	Wed Sep 17 18:02:38 2008 -0700
@@ -1577,6 +1577,7 @@
                                                                           \
   declare_constant(Location::normal)                                      \
   declare_constant(Location::oop)                                         \
+  declare_constant(Location::narrowoop)                                   \
   declare_constant(Location::int_in_long)                                 \
   declare_constant(Location::lng)                                         \
   declare_constant(Location::float_in_dbl)                                \
--- a/test/Makefile	Thu Sep 11 11:25:43 2008 -0700
+++ b/test/Makefile	Wed Sep 17 18:02:38 2008 -0700
@@ -1,5 +1,5 @@
 #
-# Copyright 2006 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 1995-2008 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
@@ -19,17 +19,18 @@
 # 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.
-#  
+#
 #
 
 #
-# Makefile to run jtreg
+# Makefile to run various jdk tests
 #
 
+# Get OS/ARCH specifics
 OSNAME = $(shell uname -s)
+SLASH_JAVA = /java
 ifeq ($(OSNAME), SunOS)
   PLATFORM = solaris
-  JCT_PLATFORM = solaris
   ARCH = $(shell uname -p)
   ifeq ($(ARCH), i386)
     ARCH=i586
@@ -37,203 +38,165 @@
 endif
 ifeq ($(OSNAME), Linux)
   PLATFORM = linux
-  JCT_PLATFORM = linux
   ARCH = $(shell uname -m)
   ifeq ($(ARCH), i386)
-    ARCH=i586
+    ARCH = i586
   endif
 endif
 ifeq ($(OSNAME), Windows_NT)
   PLATFORM = windows
-  JCT_PLATFORM = win32
+  SLASH_JAVA = J:
   ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),ia64)
-    ARCH=ia64
+    ARCH = ia64
   else
     ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),AMD64)
-      ARCH=x64
+      ARCH = x64
     else
       ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),EM64T)
-        ARCH=x64
+        ARCH = x64
       else
-        ARCH=i586
+        ARCH = i586
       endif
     endif
   endif
+  EXESUFFIX = .exe
 endif
 
-# Default bundle of all test results (passed or not)
-JPRT_ARCHIVE_BUNDLE=$(TEST_ROOT)/JPRT_ARCHIVE_BUNDLE.zip
+# Utilities used
+CD    = cd
+CP    = cp
+ECHO  = echo
+MKDIR = mkdir
+ZIP   = zip
 
-# Default home for JTREG
-ifeq ($(PLATFORM), windows)
-  JT_HOME = J:/svc/jct-tools3.2.2_01
-else
-  JT_HOME = /java/svc/jct-tools3.2.2_01
+# Root of this test area (important to use full paths in some places)
+TEST_ROOT := $(shell pwd)
+
+# Root of all test results
+ABS_BUILD_ROOT = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH)
+ABS_TEST_OUTPUT_DIR = $(ABS_BUILD_ROOT)/testoutput
+
+# Expect JPRT to set PRODUCT_HOME (the product or jdk in this case to test)
+ifndef PRODUCT_HOME
+  # Try to use j2sdk-image if it exists
+  ABS_JDK_IMAGE = $(ABS_BUILD_ROOT)/j2sdk-image
+  PRODUCT_HOME :=                       \
+    $(shell                             \
+      if [ -d $(ABS_JDK_IMAGE) ] ; then \
+         $(ECHO) "$(ABS_JDK_IMAGE)";    \
+       else                             \
+         $(ECHO) "$(ABS_BUILD_ROOT)" ;  \
+       fi)
 endif
 
-# Default JTREG to run
-JTREG = $(JT_HOME)/$(JCT_PLATFORM)/bin/jtreg
+# Expect JPRT to set JAVA_ARGS (e.g. -server etc.)
+JAVA_OPTIONS = 
+ifdef JAVA_ARGS
+  JAVA_OPTIONS = $(JAVA_ARGS)
+endif
 
-# Root of this test area
-TEST_ROOT := $(shell pwd)
+# Expect JPRT to set JPRT_ARCHIVE_BUNDLE (path to zip bundle for results)
+ARCHIVE_BUNDLE = $(ABS_TEST_OUTPUT_DIR)/ARCHIVE_BUNDLE.zip
+ifdef JPRT_ARCHIVE_BUNDLE
+  ARCHIVE_BUNDLE = $(JPRT_ARCHIVE_BUNDLE)
+endif
 
-# Default JDK to test
-JAVA_HOME = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH)
+# How to create the test bundle (pass or fail, we want to create this)
+BUNDLE_UP = ( $(MKDIR) -p `dirname $(ARCHIVE_BUNDLE)`     \
+	      && $(CD) $(ABS_TEST_OUTPUT_DIR)             \
+	      && $(ZIP) -q -r $(ARCHIVE_BUNDLE) . )
+BUNDLE_UP_FAILED = ( exitCode=$$? && $(BUNDLE_UP) && exit $${exitCode} )
 
-# The test directories to run
-DEFAULT_TESTDIRS = serviceability
-TESTDIRS = $(DEFAULT_TESTDIRS)
+################################################################
 
-# Files that hold total passed and failed counts (passed==0 is bad)
-JTREG_TOTALS_DIR = $(TEST_ROOT)/JTREG_TOTALS_$(PLATFORM)_$(ARCH)
-JTREG_FAILED = $(JTREG_TOTALS_DIR)/failed_count
-JTREG_PASSED = $(JTREG_TOTALS_DIR)/passed_count
+# Default make rule (runs jtreg_tests)
+all: jtreg_tests
+	@$(ECHO) "Testing completed successfully"
 
-# Root of all test results
-JTREG_ALL_OUTPUT_DIRNAME = JTREG_OUTPUT_$(PLATFORM)_$(ARCH)
-JTREG_ALL_OUTPUT_DIR = $(TEST_ROOT)/$(JTREG_ALL_OUTPUT_DIRNAME)
-
-# Test results for one test directory
-JTREG_TEST_OUTPUT_DIR = $(JTREG_ALL_OUTPUT_DIR)/$@
-JTREG_TEST_REPORT_DIR = $(JTREG_TEST_OUTPUT_DIR)/JTreport
-JTREG_TEST_WORK_DIR   = $(JTREG_TEST_OUTPUT_DIR)/JTwork
-JTREG_TEST_SUMMARY    =	$(JTREG_TEST_REPORT_DIR)/summary.txt
-
-# Temp files used by this Makefile
-JTREG_TEST_TEMP_DIR   = $(JTREG_ALL_OUTPUT_DIR)/$@/temp
-JTREG_TEMP_PASSED     = $(JTREG_TEST_TEMP_DIR)/passed
-JTREG_TEMP_FAILED     = $(JTREG_TEST_TEMP_DIR)/failed
-JTREG_TEMP_OUTPUT     = $(JTREG_TEST_TEMP_DIR)/output
-JTREG_TEMP_RESULTS    = $(JTREG_TEST_TEMP_DIR)/results
-
-# JTREG options (different for 2.1.6 and 3.2.2_01)
-JTREG_COMMON_OPTIONS = -r:$(JTREG_TEST_REPORT_DIR) \
-                       -w:$(JTREG_TEST_WORK_DIR) \
-                       -testjdk:$(JAVA_HOME) \
-                       -automatic \
-	               -verbose:all
-JTREG_216_OPTIONS = $(JTREG_COMMON_OPTIONS) $@ $(JAVA_ARGS)
-JTREG_322_OPTIONS = $(JTREG_COMMON_OPTIONS) $(JAVA_ARGS:%=-vmoption:%) $@
-
-# Default make rule
-all: clean check tests
-
-# Chaeck to make sure these directories exist
-check: $(JT_HOME) $(JAVA_HOME) $(JTREG)
-
-# Prime the test run
-primecounts: FRC
-	@rm -f -r $(JTREG_TOTALS_DIR)
-	@mkdir -p $(JTREG_TOTALS_DIR)
-	@echo "0" > $(JTREG_FAILED)
-	@echo "0" > $(JTREG_PASSED)
-
-# Run the tests and determine the 'make' command exit status
-#   Ultimately we determine the make exit code based on the passed/failed count
-tests: primecounts $(TESTDIRS)
-	@echo "JTREG TOTAL: passed=`cat $(JTREG_PASSED)` failed=`cat $(JTREG_FAILED)`"
-	zip -q -r $(JPRT_ARCHIVE_BUNDLE) $(JTREG_ALL_OUTPUT_DIRNAME)
-	@if [ `cat $(JTREG_FAILED)` -ne 0 -o \
-	     `cat $(JTREG_PASSED)` -le 0 ] ; then \
-	  echo "JTREG FAILED"; \
-	  exit 1; \
-	else \
-	  echo "JTREG PASSED"; \
-	  exit 0; \
-	fi
-
-# Just make sure these directires exist
-$(JT_HOME) $(JAVA_HOME): FRC
-	@if [ ! -d $@ ] ; then \
-	    echo "ERROR: Directory $@ does not exist"; \
-	    exit 1; \
-	fi
-
-# Make sure this file exists
-$(JTREG): FRC
-	@if [ ! -f $@ ] ; then \
-	    echo "ERROR: File $@ does not exist"; \
-	    exit 1; \
-	fi
-
-# Process each test directory one by one, this rule always completes.
-#    Note that the use of 'tee' tosses the jtreg process exit status, this
-#    is as expected because even if jtreg fails, we need to save the
-#    output. So we update the JTREG_PASSED and JTREG_FAILED count files.
-#    Note that missing the 'results:' line in the last few lines of output
-#    will indicate a failure (or a bump by one of the JTREG_FAILED file.
-#    Note that passed: 0 or no passed: indication means a failure.
-#    Note that any indication of the word 'failed' indicates failure.
-#    Ultimately if the contents of JTREG_FAILED is not 0, we have failed 
-#    tests, and if the contents of JTREG_PASSED is 0, we consider that a
-#    failure.
-$(TESTDIRS):  FRC
-	@if [ ! -d $@ ] ; then \
-	    echo "ERROR: Directory $@ does not exist"; \
-	    exit 1; \
-	fi
-	@echo "---------------------------------------------------"
-	@rm -f -r $(JTREG_TEST_OUTPUT_DIR)
-	@mkdir -p $(JTREG_TEST_OUTPUT_DIR)
-	@mkdir -p $(JTREG_TEST_WORK_DIR)
-	@mkdir -p $(JTREG_TEST_WORK_DIR)/scratch
-	@mkdir -p $(JTREG_TEST_REPORT_DIR)
-	@mkdir -p $(JTREG_TEST_TEMP_DIR)
-	@echo "Testing $@"
-	@echo "Using JAVA_HOME=$(JAVA_HOME)"
-	@echo "Using JAVA_ARGS=$(JAVA_ARGS)"
-	@if [ "`$(JTREG) -help 2>&1 | fgrep -- -vmoption`" != "" ] ; then \
-	  echo "Assume we are using jtreg 3.2.2_01 or newer"; \
-	  echo "$(JTREG) $(JTREG_322_OPTIONS)"; \
-	  $(JTREG) $(JTREG_322_OPTIONS) 2>&1 | tee $(JTREG_TEMP_OUTPUT) ; \
-	else \
-	  echo "Assume we are using jtreg 2.1.6"; \
-	  echo "$(JTREG) $(JTREG_216_OPTIONS)"; \
-	  $(JTREG) $(JTREG_216_OPTIONS) 2>&1 | tee $(JTREG_TEMP_OUTPUT) ; \
-	fi
-	@echo "---------------------------------------------------"
-	@echo "Extracting passed and failed counts from jtreg output"
-	@tail -10 $(JTREG_TEMP_OUTPUT) | fgrep -i 'results:' | \
-	       tail -1 | tee $(JTREG_TEMP_RESULTS)
-	@sed -e 's@.*\ passed:\ \([1-9][0-9]*\).*@\1@' $(JTREG_TEMP_RESULTS) \
-	       > $(JTREG_TEMP_PASSED)
-	@if [ "`cat $(JTREG_TEMP_PASSED)`" = "" ] ; then \
-	  echo "ERROR: No passed indication in results"; \
-	  expr `cat $(JTREG_FAILED)` '+' 1 > $(JTREG_FAILED); \
-	elif [ `cat $(JTREG_TEMP_PASSED)` -le 0 ] ; then \
-	  echo "ERROR: Passed count appears to be 0"; \
-	  expr `cat $(JTREG_FAILED)` '+' 1 > $(JTREG_FAILED); \
-	elif [ "`fgrep -i failed $(JTREG_TEMP_RESULTS)`" = "" ] ; then \
-	  echo "No indication anything failed"; \
-	  expr `cat $(JTREG_PASSED)` '+' `cat $(JTREG_TEMP_PASSED)` \
-		> $(JTREG_PASSED); \
-	else \
-	  sed -e 's@.*\ failed:\ \([1-9][0-9]*\).*@\1@' $(JTREG_TEMP_FAILED) \
-		> $(JTREG_TEMP_FAILED); \
-	  if [ "`cat $(JTREG_TEMP_FAILED)`" = "" ] ; then \
-	    echo "ERROR: Failed pattern but no failed count in results"; \
-	    expr `cat $(JTREG_FAILED)` '+' 1 > $(JTREG_FAILED); \
-	  elif [ `cat $(JTREG_TEMP_FAILED)` -le 0 ] ; then \
-	    echo "ERROR: Failed count is 0, did something failed or not?"; \
-	    expr `cat $(JTREG_FAILED)` '+' 1 > $(JTREG_FAILED); \
-	  else \
-	    expr `cat $(JTREG_FAILED)` '+' `cat $(JTREG_TEMP_FAILED)` \
-		  > $(JTREG_FAILED); \
-	  fi; \
-	fi
-	@echo "---------------------------------------------------"
-	@echo "Summary: "
-	@if [ -f $(JTREG_TEST_SUMMARY) ] ; then \
-	  cat $(JTREG_TEST_SUMMARY) ; \
-	else \
-	  echo "ERROR: Missing $(JTREG_TEST_SUMMARY)"; \
-	fi
-	@echo "---------------------------------------------------"
+# Prep for output
+prep: clean
+	@$(MKDIR) -p $(ABS_TEST_OUTPUT_DIR)
+	@$(MKDIR) -p `dirname $(ARCHIVE_BUNDLE)`
 
 # Cleanup
 clean:
-	rm -f -r $(JTREG_ALL_OUTPUT_DIR)
-	rm -f $(JPRT_ARCHIVE_BUNDLE)
+	$(RM) -r $(ABS_TEST_OUTPUT_DIR)
+	$(RM) $(ARCHIVE_BUNDLE)
 
-FRC:
+################################################################
 
+# jtreg tests
+
+# Expect JT_HOME to be set for jtreg tests. (home for jtreg)
+JT_HOME = $(SLASH_JAVA)/re/jtreg/4.0/promoted/latest/binaries/jtreg
+ifdef JPRT_JTREG_HOME
+  JT_HOME = $(JPRT_JTREG_HOME)
+endif
+
+# Expect JPRT to set TESTDIRS to the jtreg test dirs
+JTREG_TESTDIRS = demo/jvmti/gctest demo/jvmti/hprof
+ifdef TESTDIRS
+  JTREG_TESTDIRS = $(TESTDIRS)
+endif
+
+# Default JTREG to run (win32 script works for everybody)
+JTREG = $(JT_HOME)/win32/bin/jtreg
+
+# Option to tell jtreg to not run tests marked with "ignore"
+ifeq ($(PLATFORM), windows)
+  JTREG_KEY_OPTION = -k:!ignore
+else
+  JTREG_KEY_OPTION = -k:\!ignore
+endif
+
+#EXTRA_JTREG_OPTIONS =
+
+jtreg_tests: prep $(JT_HOME) $(PRODUCT_HOME) $(JTREG)
+	$(JTREG) -a -v:fail,error               \
+          $(JTREG_KEY_OPTION)                   \
+          $(EXTRA_JTREG_OPTIONS)                \
+          -r:$(ABS_TEST_OUTPUT_DIR)/JTreport    \
+          -w:$(ABS_TEST_OUTPUT_DIR)/JTwork      \
+          -jdk:$(PRODUCT_HOME)                  \
+          $(JAVA_OPTIONS:%=-vmoption:%)         \
+          $(JTREG_TESTDIRS)                     \
+	  || $(BUNDLE_UP_FAILED)
+	$(BUNDLE_UP)
+
+PHONY_LIST += jtreg_tests
+
+################################################################
+
+# packtest
+
+# Expect JPRT to set JPRT_PACKTEST_HOME.
+PACKTEST_HOME = /net/jprt-web.sfbay.sun.com/jprt/allproducts/packtest
+ifdef JPRT_PACKTEST_HOME
+  PACKTEST_HOME = $(JPRT_PACKTEST_HOME)
+endif
+
+#EXTRA_PACKTEST_OPTIONS =
+
+packtest: prep $(PACKTEST_HOME)/ptest $(PRODUCT_HOME)
+	( $(CD) $(PACKTEST_HOME) &&            \
+	    $(PACKTEST_HOME)/ptest             \
+		 -t "$(PRODUCT_HOME)"          \
+	         $(PACKTEST_STRESS_OPTION)     \
+		 $(EXTRA_PACKTEST_OPTIONS)     \
+		 -W $(ABS_TEST_OUTPUT_DIR)     \
+                 $(JAVA_OPTIONS:%=-J %)        \
+	 ) || $(BUNDLE_UP_FAILED)
+	$(BUNDLE_UP)
+
+packtest_stress: PACKTEST_STRESS_OPTION=-s
+packtest_stress: packtest
+
+PHONY_LIST += packtest packtest_stress
+
+################################################################
+
+# Phony targets (e.g. these are not filenames)
+.PHONY: all clean prep $(PHONY_LIST)
+
+################################################################
+