6395208: Elide autoboxing for calls to HashMap.get(int) and HashMap.get(long)
authornever
Wed, 05 Dec 2007 09:01:00 -0800
changeset 190 e9a0a9dcd4f6
parent 189 4248c8e21063
child 191 314312979e7a
6395208: Elide autoboxing for calls to HashMap.get(int) and HashMap.get(long) Reviewed-by: kvn, rasbold
hotspot/src/share/vm/ci/ciObjArray.cpp
hotspot/src/share/vm/ci/ciObjArray.hpp
hotspot/src/share/vm/classfile/vmSymbols.hpp
hotspot/src/share/vm/includeDB_core
hotspot/src/share/vm/opto/addnode.cpp
hotspot/src/share/vm/opto/addnode.hpp
hotspot/src/share/vm/opto/c2_globals.hpp
hotspot/src/share/vm/opto/cfgnode.hpp
hotspot/src/share/vm/opto/ifnode.cpp
hotspot/src/share/vm/opto/loopnode.cpp
hotspot/src/share/vm/opto/loopnode.hpp
hotspot/src/share/vm/opto/memnode.cpp
hotspot/src/share/vm/opto/memnode.hpp
hotspot/src/share/vm/opto/parse2.cpp
hotspot/src/share/vm/opto/type.hpp
hotspot/src/share/vm/runtime/arguments.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/ci/ciObjArray.cpp	Wed Dec 05 09:01:00 2007 -0800
@@ -0,0 +1,43 @@
+/*
+ * Copyright 1999-2007 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.
+ *
+ */
+
+#include "incls/_precompiled.incl"
+#include "incls/_ciObjArray.cpp.incl"
+
+// ciObjArray
+//
+// This class represents an objArrayOop in the HotSpot virtual
+// machine.
+
+ciObject* ciObjArray::obj_at(int index) {
+  VM_ENTRY_MARK;
+  objArrayOop array = get_objArrayOop();
+  if (index < 0 || index >= array->length()) return NULL;
+  oop o = array->obj_at(index);
+  if (o == NULL) {
+    return ciNullObject::make();
+  } else {
+    return CURRENT_ENV->get_object(o);
+  }
+}
--- a/hotspot/src/share/vm/ci/ciObjArray.hpp	Wed Dec 05 09:00:00 2007 -0800
+++ b/hotspot/src/share/vm/ci/ciObjArray.hpp	Wed Dec 05 09:01:00 2007 -0800
@@ -43,4 +43,6 @@
 public:
   // What kind of ciObject is this?
   bool is_obj_array() { return true; }
+
+  ciObject* obj_at(int index);
 };
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp	Wed Dec 05 09:00:00 2007 -0800
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp	Wed Dec 05 09:01:00 2007 -0800
@@ -58,12 +58,17 @@
   template(java_lang_ThreadDeath,                     "java/lang/ThreadDeath")                    \
   template(java_lang_Boolean,                         "java/lang/Boolean")                        \
   template(java_lang_Character,                       "java/lang/Character")                      \
+  template(java_lang_Character_CharacterCache,        "java/lang/Character$CharacterCache")       \
   template(java_lang_Float,                           "java/lang/Float")                          \
   template(java_lang_Double,                          "java/lang/Double")                         \
   template(java_lang_Byte,                            "java/lang/Byte")                           \
+  template(java_lang_Byte_Cache,                      "java/lang/Byte$ByteCache")                 \
   template(java_lang_Short,                           "java/lang/Short")                          \
+  template(java_lang_Short_ShortCache,                "java/lang/Short$ShortCache")               \
   template(java_lang_Integer,                         "java/lang/Integer")                        \
+  template(java_lang_Integer_IntegerCache,            "java/lang/Integer$IntegerCache")           \
   template(java_lang_Long,                            "java/lang/Long")                           \
+  template(java_lang_Long_LongCache,                  "java/lang/Long$LongCache")                 \
   template(java_lang_Shutdown,                        "java/lang/Shutdown")                       \
   template(java_lang_ref_Reference,                   "java/lang/ref/Reference")                  \
   template(java_lang_ref_SoftReference,               "java/lang/ref/SoftReference")              \
@@ -274,6 +279,7 @@
   template(exclusive_owner_thread_name,               "exclusiveOwnerThread")                     \
   template(park_blocker_name,                         "parkBlocker")                              \
   template(park_event_name,                           "nativeParkEventPointer")                   \
+  template(cache_field_name,                          "cache")                                    \
   template(value_name,                                "value")                                    \
                                                                                                   \
   /* non-intrinsic name/signature pairs: */                                                       \
--- a/hotspot/src/share/vm/includeDB_core	Wed Dec 05 09:00:00 2007 -0800
+++ b/hotspot/src/share/vm/includeDB_core	Wed Dec 05 09:01:00 2007 -0800
@@ -19,7 +19,7 @@
 // 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.
-//  
+//
 //
 
 // NOTE: DO NOT CHANGE THIS COPYRIGHT TO NEW STYLE - IT WILL BREAK makeDeps!
@@ -46,13 +46,13 @@
 // as dependencies.  Header files named H.inline.hpp generally contain
 // bodies for inline functions declared in H.hpp.
 //
-// NOTE: Files that use the token "generate_platform_dependent_include" 
+// NOTE: Files that use the token "generate_platform_dependent_include"
 // are expected to contain macro references like <os>, <arch_model>, ... and
 // makedeps has a dependency on these platform files looking like:
-// foo_<macro>.trailing_string 
+// foo_<macro>.trailing_string
 // (where "trailing_string" can be any legal filename strings but typically
 // is "hpp" or "inline.hpp").
-// 
+//
 // The dependency in makedeps (and enforced) is that an underscore
 // will precedure the macro invocation. Note that this restriction
 // is only enforced on filenames that have the dependency token
@@ -720,6 +720,11 @@
 ciObjArray.hpp                          ciClassList.hpp
 ciObjArray.hpp                          objArrayOop.hpp
 
+ciObjArray.cpp                          ciObjArray.hpp
+ciObjArray.cpp                          ciNullObject.hpp
+ciObjArray.cpp                          ciUtilities.hpp
+ciObjArray.cpp                          objArrayOop.hpp
+
 ciObjArrayKlass.cpp                     ciInstanceKlass.hpp
 ciObjArrayKlass.cpp                     ciObjArrayKlass.hpp
 ciObjArrayKlass.cpp                     ciObjArrayKlassKlass.hpp
@@ -1935,7 +1940,7 @@
 
 init.cpp                                bytecodes.hpp
 init.cpp                                collectedHeap.hpp
-init.cpp				handles.inline.hpp
+init.cpp                                handles.inline.hpp
 init.cpp                                icBuffer.hpp
 init.cpp                                icache.hpp
 init.cpp                                init.hpp
--- a/hotspot/src/share/vm/opto/addnode.cpp	Wed Dec 05 09:00:00 2007 -0800
+++ b/hotspot/src/share/vm/opto/addnode.cpp	Wed Dec 05 09:01:00 2007 -0800
@@ -608,6 +608,28 @@
   return NULL;
 }
 
+//------------------------------unpack_offsets----------------------------------
+// Collect the AddP offset values into the elements array, giving up
+// if there are more than length.
+int AddPNode::unpack_offsets(Node* elements[], int length) {
+  int count = 0;
+  Node* addr = this;
+  Node* base = addr->in(AddPNode::Base);
+  while (addr->is_AddP()) {
+    if (addr->in(AddPNode::Base) != base) {
+      // give up
+      return -1;
+    }
+    elements[count++] = addr->in(AddPNode::Offset);
+    if (count == length) {
+      // give up
+      return -1;
+    }
+    addr = addr->in(AddPNode::Address);
+  }
+  return count;
+}
+
 //------------------------------match_edge-------------------------------------
 // Do we Match on this edge index or not?  Do not match base pointer edge
 uint AddPNode::match_edge(uint idx) const {
--- a/hotspot/src/share/vm/opto/addnode.hpp	Wed Dec 05 09:00:00 2007 -0800
+++ b/hotspot/src/share/vm/opto/addnode.hpp	Wed Dec 05 09:01:00 2007 -0800
@@ -144,6 +144,11 @@
   static Node* Ideal_base_and_offset(Node* ptr, PhaseTransform* phase,
                                      // second return value:
                                      intptr_t& offset);
+
+  // Collect the AddP offset values into the elements array, giving up
+  // if there are more than length.
+  int unpack_offsets(Node* elements[], int length);
+
   // Do not match base-ptr edge
   virtual uint match_edge(uint idx) const;
   static const Type *mach_bottom_type(const MachNode* n);  // used by ad_<arch>.hpp
--- a/hotspot/src/share/vm/opto/c2_globals.hpp	Wed Dec 05 09:00:00 2007 -0800
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp	Wed Dec 05 09:01:00 2007 -0800
@@ -367,6 +367,12 @@
   notproduct(bool, PrintEliminateLocks, false,                              \
           "Print out when locks are eliminated")                            \
                                                                             \
+  diagnostic(bool, EliminateAutoBox, false,                                 \
+          "Private flag to control optimizations for autobox elimination")  \
+                                                                            \
+  product(intx, AutoBoxCacheMax, 128,                                       \
+          "Sets max value cached by the java.lang.Integer autobox cache")   \
+                                                                            \
   product(bool, DoEscapeAnalysis, false,                                    \
           "Perform escape analysis")                                        \
                                                                             \
--- a/hotspot/src/share/vm/opto/cfgnode.hpp	Wed Dec 05 09:00:00 2007 -0800
+++ b/hotspot/src/share/vm/opto/cfgnode.hpp	Wed Dec 05 09:01:00 2007 -0800
@@ -310,8 +310,14 @@
   virtual const RegMask &out_RegMask() const;
   void dominated_by(Node* prev_dom, PhaseIterGVN* igvn);
   int is_range_check(Node* &range, Node* &index, jint &offset);
+  Node* fold_compares(PhaseGVN* phase);
   static Node* up_one_dom(Node* curr, bool linear_only = false);
 
+  // Takes the type of val and filters it through the test represented
+  // by if_proj and returns a more refined type if one is produced.
+  // Returns NULL is it couldn't improve the type.
+  static const TypeInt* filtered_int_type(PhaseGVN* phase, Node* val, Node* if_proj);
+
 #ifndef PRODUCT
   virtual void dump_spec(outputStream *st) const;
 #endif
--- a/hotspot/src/share/vm/opto/ifnode.cpp	Wed Dec 05 09:00:00 2007 -0800
+++ b/hotspot/src/share/vm/opto/ifnode.cpp	Wed Dec 05 09:01:00 2007 -0800
@@ -543,6 +543,159 @@
   return NULL;                  // Dead loop?  Or hit root?
 }
 
+
+//------------------------------filtered_int_type--------------------------------
+// Return a possibly more restrictive type for val based on condition control flow for an if
+const TypeInt* IfNode::filtered_int_type(PhaseGVN* gvn, Node *val, Node* if_proj) {
+  assert(if_proj &&
+         (if_proj->Opcode() == Op_IfTrue || if_proj->Opcode() == Op_IfFalse), "expecting an if projection");
+  if (if_proj->in(0) && if_proj->in(0)->is_If()) {
+    IfNode* iff = if_proj->in(0)->as_If();
+    if (iff->in(1) && iff->in(1)->is_Bool()) {
+      BoolNode* bol = iff->in(1)->as_Bool();
+      if (bol->in(1) && bol->in(1)->is_Cmp()) {
+        const CmpNode* cmp  = bol->in(1)->as_Cmp();
+        if (cmp->in(1) == val) {
+          const TypeInt* cmp2_t = gvn->type(cmp->in(2))->isa_int();
+          if (cmp2_t != NULL) {
+            jint lo = cmp2_t->_lo;
+            jint hi = cmp2_t->_hi;
+            BoolTest::mask msk = if_proj->Opcode() == Op_IfTrue ? bol->_test._test : bol->_test.negate();
+            switch (msk) {
+            case BoolTest::ne:
+              // Can't refine type
+              return NULL;
+            case BoolTest::eq:
+              return cmp2_t;
+            case BoolTest::lt:
+              lo = TypeInt::INT->_lo;
+              if (hi - 1 < hi) {
+                hi = hi - 1;
+              }
+              break;
+            case BoolTest::le:
+              lo = TypeInt::INT->_lo;
+              break;
+            case BoolTest::gt:
+              if (lo + 1 > lo) {
+                lo = lo + 1;
+              }
+              hi = TypeInt::INT->_hi;
+              break;
+            case BoolTest::ge:
+              // lo unchanged
+              hi = TypeInt::INT->_hi;
+              break;
+            }
+            const TypeInt* rtn_t = TypeInt::make(lo, hi, cmp2_t->_widen);
+            return rtn_t;
+          }
+        }
+      }
+    }
+  }
+  return NULL;
+}
+
+//------------------------------fold_compares----------------------------
+// See if a pair of CmpIs can be converted into a CmpU.  In some cases
+// the direction of this if is determined by the preciding if so it
+// can be eliminate entirely.  Given an if testing (CmpI n c) check
+// for an immediately control dependent if that is testing (CmpI n c2)
+// and has one projection leading to this if and the other projection
+// leading to a region that merges one of this ifs control
+// projections.
+//
+//                   If
+//                  / |
+//                 /  |
+//                /   |
+//              If    |
+//              /\    |
+//             /  \   |
+//            /    \  |
+//           /    Region
+//
+Node* IfNode::fold_compares(PhaseGVN* phase) {
+  if (!EliminateAutoBox || Opcode() != Op_If) return NULL;
+
+  Node* this_cmp = in(1)->in(1);
+  if (this_cmp != NULL && this_cmp->Opcode() == Op_CmpI &&
+      this_cmp->in(2)->is_Con() && this_cmp->in(2) != phase->C->top()) {
+    Node* ctrl = in(0);
+    BoolNode* this_bool = in(1)->as_Bool();
+    Node* n = this_cmp->in(1);
+    int hi = this_cmp->in(2)->get_int();
+    if (ctrl != NULL && ctrl->is_Proj() && ctrl->outcnt() == 1 &&
+        ctrl->in(0)->is_If() &&
+        ctrl->in(0)->outcnt() == 2 &&
+        ctrl->in(0)->in(1)->is_Bool() &&
+        ctrl->in(0)->in(1)->in(1)->Opcode() == Op_CmpI &&
+        ctrl->in(0)->in(1)->in(1)->in(2)->is_Con() &&
+        ctrl->in(0)->in(1)->in(1)->in(1) == n) {
+      IfNode* dom_iff = ctrl->in(0)->as_If();
+      Node* otherproj = dom_iff->proj_out(!ctrl->as_Proj()->_con);
+      if (otherproj->outcnt() == 1 && otherproj->unique_out()->is_Region() &&
+          this_bool->_test._test != BoolTest::ne && this_bool->_test._test != BoolTest::eq) {
+        // Identify which proj goes to the region and which continues on
+        RegionNode* region = otherproj->unique_out()->as_Region();
+        Node* success = NULL;
+        Node* fail = NULL;
+        for (int i = 0; i < 2; i++) {
+          Node* proj = proj_out(i);
+          if (success == NULL && proj->outcnt() == 1 && proj->unique_out() == region) {
+            success = proj;
+          } else if (fail == NULL) {
+            fail = proj;
+          } else {
+            success = fail = NULL;
+          }
+        }
+        if (success != NULL && fail != NULL && !region->has_phi()) {
+          int lo = dom_iff->in(1)->in(1)->in(2)->get_int();
+          BoolNode* dom_bool = dom_iff->in(1)->as_Bool();
+          Node* dom_cmp =  dom_bool->in(1);
+          const TypeInt* failtype  = filtered_int_type(phase, n, ctrl);
+          if (failtype != NULL) {
+            const TypeInt* type2 = filtered_int_type(phase, n, fail);
+            if (type2 != NULL) {
+              failtype = failtype->join(type2)->is_int();
+            } else {
+              failtype = NULL;
+            }
+          }
+
+          if (failtype != NULL &&
+              dom_bool->_test._test != BoolTest::ne && dom_bool->_test._test != BoolTest::eq) {
+            int bound = failtype->_hi - failtype->_lo + 1;
+            if (failtype->_hi != max_jint && failtype->_lo != min_jint && bound > 1) {
+              // Merge the two compares into a single unsigned compare by building  (CmpU (n - lo) hi)
+              BoolTest::mask cond = fail->as_Proj()->_con ? BoolTest::lt : BoolTest::ge;
+              Node* adjusted = phase->transform(new (phase->C, 3) SubINode(n, phase->intcon(failtype->_lo)));
+              Node* newcmp = phase->transform(new (phase->C, 3) CmpUNode(adjusted, phase->intcon(bound)));
+              Node* newbool = phase->transform(new (phase->C, 2) BoolNode(newcmp, cond));
+              phase->hash_delete(dom_iff);
+              dom_iff->set_req(1, phase->intcon(ctrl->as_Proj()->_con));
+              phase->is_IterGVN()->_worklist.push(dom_iff);
+              phase->hash_delete(this);
+              set_req(1, newbool);
+              return this;
+            }
+            if (failtype->_lo > failtype->_hi) {
+              // previous if determines the result of this if so
+              // replace Bool with constant
+              phase->hash_delete(this);
+              set_req(1, phase->intcon(success->as_Proj()->_con));
+              return this;
+            }
+          }
+        }
+      }
+    }
+  }
+  return NULL;
+}
+
 //------------------------------remove_useless_bool----------------------------
 // Check for people making a useless boolean: things like
 // if( (x < y ? true : false) ) { ... }
@@ -744,6 +897,11 @@
     // Normal equivalent-test check.
     if( !dom ) return NULL;     // Dead loop?
 
+    Node* result = fold_compares(phase);
+    if (result != NULL) {
+      return result;
+    }
+
     // Search up the dominator tree for an If with an identical test
     while( dom->Opcode() != op    ||  // Not same opcode?
            dom->in(1)    != in(1) ||  // Not same input 1?
--- a/hotspot/src/share/vm/opto/loopnode.cpp	Wed Dec 05 09:00:00 2007 -0800
+++ b/hotspot/src/share/vm/opto/loopnode.cpp	Wed Dec 05 09:01:00 2007 -0800
@@ -651,7 +651,7 @@
     while (if_cnt < if_limit) {
       if ((pred->Opcode() == Op_IfTrue || pred->Opcode() == Op_IfFalse)) {
         if_cnt++;
-        const TypeInt* if_t = filtered_type_at_if(val, pred);
+        const TypeInt* if_t = IfNode::filtered_int_type(&_igvn, val, pred);
         if (if_t != NULL) {
           if (rtn_t == NULL) {
             rtn_t = if_t;
@@ -674,59 +674,6 @@
 }
 
 
-//------------------------------filtered_type_at_if--------------------------------
-// Return a possibly more restrictive type for val based on condition control flow for an if
-const TypeInt* PhaseIdealLoop::filtered_type_at_if( Node* val, Node *if_proj) {
-  assert(if_proj &&
-         (if_proj->Opcode() == Op_IfTrue || if_proj->Opcode() == Op_IfFalse), "expecting an if projection");
-  if (if_proj->in(0) && if_proj->in(0)->is_If()) {
-    IfNode* iff = if_proj->in(0)->as_If();
-    if (iff->in(1) && iff->in(1)->is_Bool()) {
-      BoolNode* bol = iff->in(1)->as_Bool();
-      if (bol->in(1) && bol->in(1)->is_Cmp()) {
-        const CmpNode* cmp  = bol->in(1)->as_Cmp();
-        if (cmp->in(1) == val) {
-          const TypeInt* cmp2_t = _igvn.type(cmp->in(2))->isa_int();
-          if (cmp2_t != NULL) {
-            jint lo = cmp2_t->_lo;
-            jint hi = cmp2_t->_hi;
-            BoolTest::mask msk = if_proj->Opcode() == Op_IfTrue ? bol->_test._test : bol->_test.negate();
-            switch (msk) {
-            case BoolTest::ne:
-              // Can't refine type
-              return NULL;
-            case BoolTest::eq:
-              return cmp2_t;
-            case BoolTest::lt:
-              lo = TypeInt::INT->_lo;
-              if (hi - 1 < hi) {
-                hi = hi - 1;
-              }
-              break;
-            case BoolTest::le:
-              lo = TypeInt::INT->_lo;
-              break;
-            case BoolTest::gt:
-              if (lo + 1 > lo) {
-                lo = lo + 1;
-              }
-              hi = TypeInt::INT->_hi;
-              break;
-            case BoolTest::ge:
-              // lo unchanged
-              hi = TypeInt::INT->_hi;
-              break;
-            }
-            const TypeInt* rtn_t = TypeInt::make(lo, hi, cmp2_t->_widen);
-            return rtn_t;
-          }
-        }
-      }
-    }
-  }
-  return NULL;
-}
-
 //------------------------------dump_spec--------------------------------------
 // Dump special per-node info
 #ifndef PRODUCT
--- a/hotspot/src/share/vm/opto/loopnode.hpp	Wed Dec 05 09:00:00 2007 -0800
+++ b/hotspot/src/share/vm/opto/loopnode.hpp	Wed Dec 05 09:01:00 2007 -0800
@@ -850,7 +850,6 @@
   const TypeInt* filtered_type( Node *n ) { return filtered_type(n, NULL); }
  // Helpers for filtered type
   const TypeInt* filtered_type_from_dominators( Node* val, Node *val_ctrl);
-  const TypeInt* filtered_type_at_if( Node* val, Node *if_proj);
 
   // Helper functions
   void register_new_node( Node *n, Node *blk );
--- a/hotspot/src/share/vm/opto/memnode.cpp	Wed Dec 05 09:00:00 2007 -0800
+++ b/hotspot/src/share/vm/opto/memnode.cpp	Wed Dec 05 09:01:00 2007 -0800
@@ -634,6 +634,46 @@
 Node* MemNode::can_see_stored_value(Node* st, PhaseTransform* phase) const {
   Node* ld_adr = in(MemNode::Address);
 
+  const TypeInstPtr* tp = phase->type(ld_adr)->isa_instptr();
+  Compile::AliasType* atp = tp != NULL ? phase->C->alias_type(tp) : NULL;
+  if (EliminateAutoBox && atp != NULL && atp->index() >= Compile::AliasIdxRaw &&
+      atp->field() != NULL && !atp->field()->is_volatile()) {
+    uint alias_idx = atp->index();
+    bool final = atp->field()->is_final();
+    Node* result = NULL;
+    Node* current = st;
+    // Skip through chains of MemBarNodes checking the MergeMems for
+    // new states for the slice of this load.  Stop once any other
+    // kind of node is encountered.  Loads from final memory can skip
+    // through any kind of MemBar but normal loads shouldn't skip
+    // through MemBarAcquire since the could allow them to move out of
+    // a synchronized region.
+    while (current->is_Proj()) {
+      int opc = current->in(0)->Opcode();
+      if ((final && opc == Op_MemBarAcquire) ||
+          opc == Op_MemBarRelease || opc == Op_MemBarCPUOrder) {
+        Node* mem = current->in(0)->in(TypeFunc::Memory);
+        if (mem->is_MergeMem()) {
+          MergeMemNode* merge = mem->as_MergeMem();
+          Node* new_st = merge->memory_at(alias_idx);
+          if (new_st == merge->base_memory()) {
+            // Keep searching
+            current = merge->base_memory();
+            continue;
+          }
+          // Save the new memory state for the slice and fall through
+          // to exit.
+          result = new_st;
+        }
+      }
+      break;
+    }
+    if (result != NULL) {
+      st = result;
+    }
+  }
+
+
   // Loop around twice in the case Load -> Initialize -> Store.
   // (See PhaseIterGVN::add_users_to_worklist, which knows about this case.)
   for (int trip = 0; trip <= 1; trip++) {
@@ -723,6 +763,168 @@
   return this;
 }
 
+
+// Returns true if the AliasType refers to the field that holds the
+// cached box array.  Currently only handles the IntegerCache case.
+static bool is_autobox_cache(Compile::AliasType* atp) {
+  if (atp != NULL && atp->field() != NULL) {
+    ciField* field = atp->field();
+    ciSymbol* klass = field->holder()->name();
+    if (field->name() == ciSymbol::cache_field_name() &&
+        field->holder()->uses_default_loader() &&
+        klass == ciSymbol::java_lang_Integer_IntegerCache()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Fetch the base value in the autobox array
+static bool fetch_autobox_base(Compile::AliasType* atp, int& cache_offset) {
+  if (atp != NULL && atp->field() != NULL) {
+    ciField* field = atp->field();
+    ciSymbol* klass = field->holder()->name();
+    if (field->name() == ciSymbol::cache_field_name() &&
+        field->holder()->uses_default_loader() &&
+        klass == ciSymbol::java_lang_Integer_IntegerCache()) {
+      assert(field->is_constant(), "what?");
+      ciObjArray* array = field->constant_value().as_object()->as_obj_array();
+      // Fetch the box object at the base of the array and get its value
+      ciInstance* box = array->obj_at(0)->as_instance();
+      ciInstanceKlass* ik = box->klass()->as_instance_klass();
+      if (ik->nof_nonstatic_fields() == 1) {
+        // This should be true nonstatic_field_at requires calling
+        // nof_nonstatic_fields so check it anyway
+        ciConstant c = box->field_value(ik->nonstatic_field_at(0));
+        cache_offset = c.as_int();
+      }
+      return true;
+    }
+  }
+  return false;
+}
+
+// Returns true if the AliasType refers to the value field of an
+// autobox object.  Currently only handles Integer.
+static bool is_autobox_object(Compile::AliasType* atp) {
+  if (atp != NULL && atp->field() != NULL) {
+    ciField* field = atp->field();
+    ciSymbol* klass = field->holder()->name();
+    if (field->name() == ciSymbol::value_name() &&
+        field->holder()->uses_default_loader() &&
+        klass == ciSymbol::java_lang_Integer()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+// We're loading from an object which has autobox behaviour.
+// If this object is result of a valueOf call we'll have a phi
+// merging a newly allocated object and a load from the cache.
+// We want to replace this load with the original incoming
+// argument to the valueOf call.
+Node* LoadNode::eliminate_autobox(PhaseGVN* phase) {
+  Node* base = in(Address)->in(AddPNode::Base);
+  if (base->is_Phi() && base->req() == 3) {
+    AllocateNode* allocation = NULL;
+    int allocation_index = -1;
+    int load_index = -1;
+    for (uint i = 1; i < base->req(); i++) {
+      allocation = AllocateNode::Ideal_allocation(base->in(i), phase);
+      if (allocation != NULL) {
+        allocation_index = i;
+        load_index = 3 - allocation_index;
+        break;
+      }
+    }
+    LoadNode* load = NULL;
+    if (allocation != NULL && base->in(load_index)->is_Load()) {
+      load = base->in(load_index)->as_Load();
+    }
+    if (load != NULL && in(Memory)->is_Phi() && in(Memory)->in(0) == base->in(0)) {
+      // Push the loads from the phi that comes from valueOf up
+      // through it to allow elimination of the loads and the recovery
+      // of the original value.
+      Node* mem_phi = in(Memory);
+      Node* offset = in(Address)->in(AddPNode::Offset);
+
+      Node* in1 = clone();
+      Node* in1_addr = in1->in(Address)->clone();
+      in1_addr->set_req(AddPNode::Base, base->in(allocation_index));
+      in1_addr->set_req(AddPNode::Address, base->in(allocation_index));
+      in1_addr->set_req(AddPNode::Offset, offset);
+      in1->set_req(0, base->in(allocation_index));
+      in1->set_req(Address, in1_addr);
+      in1->set_req(Memory, mem_phi->in(allocation_index));
+
+      Node* in2 = clone();
+      Node* in2_addr = in2->in(Address)->clone();
+      in2_addr->set_req(AddPNode::Base, base->in(load_index));
+      in2_addr->set_req(AddPNode::Address, base->in(load_index));
+      in2_addr->set_req(AddPNode::Offset, offset);
+      in2->set_req(0, base->in(load_index));
+      in2->set_req(Address, in2_addr);
+      in2->set_req(Memory, mem_phi->in(load_index));
+
+      in1_addr = phase->transform(in1_addr);
+      in1 =      phase->transform(in1);
+      in2_addr = phase->transform(in2_addr);
+      in2 =      phase->transform(in2);
+
+      PhiNode* result = PhiNode::make_blank(base->in(0), this);
+      result->set_req(allocation_index, in1);
+      result->set_req(load_index, in2);
+      return result;
+    }
+  } else if (base->is_Load()) {
+    // Eliminate the load of Integer.value for integers from the cache
+    // array by deriving the value from the index into the array.
+    // Capture the offset of the load and then reverse the computation.
+    Node* load_base = base->in(Address)->in(AddPNode::Base);
+    if (load_base != NULL) {
+      Compile::AliasType* atp = phase->C->alias_type(load_base->adr_type());
+      intptr_t cache_offset;
+      int shift = -1;
+      Node* cache = NULL;
+      if (is_autobox_cache(atp)) {
+        shift  = exact_log2(type2aelembytes[T_OBJECT]);
+        cache = AddPNode::Ideal_base_and_offset(load_base->in(Address), phase, cache_offset);
+      }
+      if (cache != NULL && base->in(Address)->is_AddP()) {
+        Node* elements[4];
+        int count = base->in(Address)->as_AddP()->unpack_offsets(elements, ARRAY_SIZE(elements));
+        int cache_low;
+        if (count > 0 && fetch_autobox_base(atp, cache_low)) {
+          int offset = arrayOopDesc::base_offset_in_bytes(memory_type()) - (cache_low << shift);
+          // Add up all the offsets making of the address of the load
+          Node* result = elements[0];
+          for (int i = 1; i < count; i++) {
+            result = phase->transform(new (phase->C, 3) AddXNode(result, elements[i]));
+          }
+          // Remove the constant offset from the address and then
+          // remove the scaling of the offset to recover the original index.
+          result = phase->transform(new (phase->C, 3) AddXNode(result, phase->MakeConX(-offset)));
+          if (result->Opcode() == Op_LShiftX && result->in(2) == phase->intcon(shift)) {
+            // Peel the shift off directly but wrap it in a dummy node
+            // since Ideal can't return existing nodes
+            result = new (phase->C, 3) RShiftXNode(result->in(1), phase->intcon(0));
+          } else {
+            result = new (phase->C, 3) RShiftXNode(result, phase->intcon(shift));
+          }
+#ifdef _LP64
+          result = new (phase->C, 2) ConvL2INode(phase->transform(result));
+#endif
+          return result;
+        }
+      }
+    }
+  }
+  return NULL;
+}
+
+
 //------------------------------Ideal------------------------------------------
 // If the load is from Field memory and the pointer is non-null, we can
 // zero out the control input.
@@ -755,6 +957,17 @@
     }
   }
 
+  if (EliminateAutoBox && can_reshape && in(Address)->is_AddP()) {
+    Node* base = in(Address)->in(AddPNode::Base);
+    if (base != NULL) {
+      Compile::AliasType* atp = phase->C->alias_type(adr_type());
+      if (is_autobox_object(atp)) {
+        Node* result = eliminate_autobox(phase);
+        if (result != NULL) return result;
+      }
+    }
+  }
+
   // Check for prior store with a different base or offset; make Load
   // independent.  Skip through any number of them.  Bail out if the stores
   // are in an endless dead cycle and report no progress.  This is a key
@@ -858,6 +1071,17 @@
           // This can happen if a interface-typed array narrows to a class type.
           jt = _type;
         }
+
+        if (EliminateAutoBox) {
+          // The pointers in the autobox arrays are always non-null
+          Node* base = in(Address)->in(AddPNode::Base);
+          if (base != NULL) {
+            Compile::AliasType* atp = phase->C->alias_type(base->adr_type());
+            if (is_autobox_cache(atp)) {
+              return jt->join(TypePtr::NOTNULL)->is_ptr();
+            }
+          }
+        }
         return jt;
       }
     }
--- a/hotspot/src/share/vm/opto/memnode.hpp	Wed Dec 05 09:00:00 2007 -0800
+++ b/hotspot/src/share/vm/opto/memnode.hpp	Wed Dec 05 09:01:00 2007 -0800
@@ -141,6 +141,9 @@
   // zero out the control input.
   virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
 
+  // Recover original value from boxed values
+  Node *eliminate_autobox(PhaseGVN *phase);
+
   // Compute a new Type for this node.  Basically we just do the pre-check,
   // then call the virtual add() to set the type.
   virtual const Type *Value( PhaseTransform *phase ) const;
--- a/hotspot/src/share/vm/opto/parse2.cpp	Wed Dec 05 09:00:00 2007 -0800
+++ b/hotspot/src/share/vm/opto/parse2.cpp	Wed Dec 05 09:01:00 2007 -0800
@@ -885,6 +885,9 @@
 void Parse::do_ifnull(BoolTest::mask btest) {
   int target_bci = iter().get_dest();
 
+  Block* branch_block = successor_for_bci(target_bci);
+  Block* next_block   = successor_for_bci(iter().next_bci());
+
   float cnt;
   float prob = branch_prediction(cnt, btest, target_bci);
   if (prob == PROB_UNKNOWN) {
@@ -902,13 +905,16 @@
     uncommon_trap(Deoptimization::Reason_unreached,
                   Deoptimization::Action_reinterpret,
                   NULL, "cold");
+    if (EliminateAutoBox) {
+      // Mark the successor blocks as parsed
+      branch_block->next_path_num();
+      next_block->next_path_num();
+    }
     return;
   }
 
   // If this is a backwards branch in the bytecodes, add Safepoint
   maybe_add_safepoint(target_bci);
-  Block* branch_block = successor_for_bci(target_bci);
-  Block* next_block   = successor_for_bci(iter().next_bci());
 
   explicit_null_checks_inserted++;
   Node* a = null();
@@ -935,6 +941,10 @@
 
     if (stopped()) {            // Path is dead?
       explicit_null_checks_elided++;
+      if (EliminateAutoBox) {
+        // Mark the successor block as parsed
+        branch_block->next_path_num();
+      }
     } else {                    // Path is live.
       // Update method data
       profile_taken_branch(target_bci);
@@ -950,6 +960,10 @@
 
   if (stopped()) {              // Path is dead?
     explicit_null_checks_elided++;
+    if (EliminateAutoBox) {
+      // Mark the successor block as parsed
+      next_block->next_path_num();
+    }
   } else  {                     // Path is live.
     // Update method data
     profile_not_taken_branch();
@@ -962,6 +976,9 @@
 void Parse::do_if(BoolTest::mask btest, Node* c) {
   int target_bci = iter().get_dest();
 
+  Block* branch_block = successor_for_bci(target_bci);
+  Block* next_block   = successor_for_bci(iter().next_bci());
+
   float cnt;
   float prob = branch_prediction(cnt, btest, target_bci);
   float untaken_prob = 1.0 - prob;
@@ -980,6 +997,11 @@
     uncommon_trap(Deoptimization::Reason_unreached,
                   Deoptimization::Action_reinterpret,
                   NULL, "cold");
+    if (EliminateAutoBox) {
+      // Mark the successor blocks as parsed
+      branch_block->next_path_num();
+      next_block->next_path_num();
+    }
     return;
   }
 
@@ -1018,15 +1040,17 @@
     untaken_branch = tmp;
   }
 
-  Block* branch_block = successor_for_bci(target_bci);
-  Block* next_block   = successor_for_bci(iter().next_bci());
-
   // Branch is taken:
   { PreserveJVMState pjvms(this);
     taken_branch = _gvn.transform(taken_branch);
     set_control(taken_branch);
 
-    if (!stopped()) {
+    if (stopped()) {
+      if (EliminateAutoBox) {
+        // Mark the successor block as parsed
+        branch_block->next_path_num();
+      }
+    } else {
       // Update method data
       profile_taken_branch(target_bci);
       adjust_map_after_if(taken_btest, c, prob, branch_block, next_block);
@@ -1039,7 +1063,12 @@
   set_control(untaken_branch);
 
   // Branch not taken.
-  if (!stopped()) {
+  if (stopped()) {
+    if (EliminateAutoBox) {
+      // Mark the successor block as parsed
+      next_block->next_path_num();
+    }
+  } else {
     // Update method data
     profile_not_taken_branch();
     adjust_map_after_if(untaken_btest, c, untaken_prob,
--- a/hotspot/src/share/vm/opto/type.hpp	Wed Dec 05 09:00:00 2007 -0800
+++ b/hotspot/src/share/vm/opto/type.hpp	Wed Dec 05 09:01:00 2007 -0800
@@ -1070,6 +1070,7 @@
 #define LShiftXNode  LShiftLNode
 // For object size computation:
 #define AddXNode     AddLNode
+#define RShiftXNode  RShiftLNode
 // For card marks and hashcodes
 #define URShiftXNode URShiftLNode
 // Opcodes
@@ -1108,6 +1109,7 @@
 #define LShiftXNode  LShiftINode
 // For object size computation:
 #define AddXNode     AddINode
+#define RShiftXNode  RShiftINode
 // For card marks and hashcodes
 #define URShiftXNode URShiftINode
 // Opcodes
--- a/hotspot/src/share/vm/runtime/arguments.cpp	Wed Dec 05 09:00:00 2007 -0800
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Wed Dec 05 09:01:00 2007 -0800
@@ -1254,6 +1254,22 @@
 
 // Aggressive optimization flags  -XX:+AggressiveOpts
 void Arguments::set_aggressive_opts_flags() {
+#ifdef COMPILER2
+  if (AggressiveOpts || !FLAG_IS_DEFAULT(AutoBoxCacheMax)) {
+    if (FLAG_IS_DEFAULT(EliminateAutoBox)) {
+      FLAG_SET_DEFAULT(EliminateAutoBox, true);
+    }
+    if (FLAG_IS_DEFAULT(AutoBoxCacheMax)) {
+      FLAG_SET_DEFAULT(AutoBoxCacheMax, 20000);
+    }
+
+    // Feed the cache size setting into the JDK
+    char buffer[1024];
+    sprintf(buffer, "java.lang.Integer.IntegerCache.high=%d", AutoBoxCacheMax);
+    add_property(buffer);
+  }
+#endif
+
   if (AggressiveOpts) {
 NOT_WINDOWS(
     // No measured benefit on Windows