changeset 1015:a6f533fc33e0

Merge
author kvn
date Mon, 14 Sep 2009 11:45:03 -0700
parents 68ef3fdcdb76 c7e94e8fff43
children d7c9544cc141 e5b31fd85b72
files
diffstat 16 files changed, 154 insertions(+), 83 deletions(-) [+]
line wrap: on
line diff
--- a/src/cpu/sparc/vm/sparc.ad	Thu Sep 10 16:46:17 2009 -0700
+++ b/src/cpu/sparc/vm/sparc.ad	Mon Sep 14 11:45:03 2009 -0700
@@ -5707,7 +5707,7 @@
   effect(TEMP dst, TEMP tmp);
   ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST);
 
-  size(3*4);
+  size((3+1)*4);  // set may use two instructions.
   format %{ "LDUH   $mem,$dst\t! ushort/char & 16-bit mask -> long\n\t"
             "SET    $mask,$tmp\n\t"
             "AND    $dst,$tmp,$dst" %}
@@ -5851,7 +5851,7 @@
   effect(TEMP dst, TEMP tmp);
   ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST);
 
-  size(3*4);
+  size((3+1)*4);  // set may use two instructions.
   format %{ "LDUW   $mem,$dst\t! int & 32-bit mask -> long\n\t"
             "SET    $mask,$tmp\n\t"
             "AND    $dst,$tmp,$dst" %}
--- a/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp	Thu Sep 10 16:46:17 2009 -0700
+++ b/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp	Mon Sep 14 11:45:03 2009 -0700
@@ -827,8 +827,8 @@
     case vmIntrinsics::_dsin:   __ sin  (calc_input, calc_result, tmp1, tmp2);              break;
     case vmIntrinsics::_dcos:   __ cos  (calc_input, calc_result, tmp1, tmp2);              break;
     case vmIntrinsics::_dtan:   __ tan  (calc_input, calc_result, tmp1, tmp2);              break;
-    case vmIntrinsics::_dlog:   __ log  (calc_input, calc_result, LIR_OprFact::illegalOpr); break;
-    case vmIntrinsics::_dlog10: __ log10(calc_input, calc_result, LIR_OprFact::illegalOpr); break;
+    case vmIntrinsics::_dlog:   __ log  (calc_input, calc_result, tmp1);                    break;
+    case vmIntrinsics::_dlog10: __ log10(calc_input, calc_result, tmp1);                    break;
     default:                    ShouldNotReachHere();
   }
 
--- a/src/cpu/x86/vm/c1_LinearScan_x86.cpp	Thu Sep 10 16:46:17 2009 -0700
+++ b/src/cpu/x86/vm/c1_LinearScan_x86.cpp	Mon Sep 14 11:45:03 2009 -0700
@@ -764,8 +764,6 @@
       break;
     }
 
-    case lir_log:
-    case lir_log10:
     case lir_abs:
     case lir_sqrt: {
       // Right argument appears to be unused
@@ -785,6 +783,30 @@
       break;
     }
 
+    case lir_log:
+    case lir_log10: {
+      // log and log10 needs one temporary fpu stack slot, so there is ontemporary
+      // registers stored in temp of the operation.
+      // the stack allocator must guarantee that the stack slots are really free,
+      // otherwise there might be a stack overflow.
+      assert(right->is_illegal(), "must be");
+      assert(left->is_fpu_register(), "must be");
+      assert(res->is_fpu_register(), "must be");
+      assert(op2->tmp_opr()->is_fpu_register(), "must be");
+
+      insert_free_if_dead(op2->tmp_opr());
+      insert_free_if_dead(res, left);
+      insert_exchange(left);
+      do_rename(left, res);
+
+      new_left = to_fpu_stack_top(res);
+      new_res = new_left;
+
+      op2->set_fpu_stack_size(sim()->stack_size());
+      assert(sim()->stack_size() <= 7, "at least one stack slot must be free");
+      break;
+    }
+
 
     case lir_tan:
     case lir_sin:
--- a/src/share/vm/c1/c1_LIR.cpp	Thu Sep 10 16:46:17 2009 -0700
+++ b/src/share/vm/c1/c1_LIR.cpp	Mon Sep 14 11:45:03 2009 -0700
@@ -567,8 +567,6 @@
     case lir_rem:
     case lir_sqrt:
     case lir_abs:
-    case lir_log:
-    case lir_log10:
     case lir_logic_and:
     case lir_logic_or:
     case lir_logic_xor:
@@ -644,13 +642,16 @@
 
     case lir_tan:
     case lir_sin:
-    case lir_cos: {
+    case lir_cos:
+    case lir_log:
+    case lir_log10: {
       assert(op->as_Op2() != NULL, "must be");
       LIR_Op2* op2 = (LIR_Op2*)op;
 
-      // sin and cos need two temporary fpu stack slots, so register
-      // two temp operands.  Register input operand as temp to
-      // guarantee that they do not overlap
+      // On x86 tan/sin/cos need two temporary fpu stack slots and
+      // log/log10 need one so handle opr2 and tmp as temp inputs.
+      // Register input operand as temp to guarantee that it doesn't
+      // overlap with the input.
       assert(op2->_info == NULL, "not used");
       assert(op2->_opr1->is_valid(), "used");
       do_input(op2->_opr1); do_temp(op2->_opr1);
--- a/src/share/vm/c1/c1_LIR.hpp	Thu Sep 10 16:46:17 2009 -0700
+++ b/src/share/vm/c1/c1_LIR.hpp	Mon Sep 14 11:45:03 2009 -0700
@@ -1840,8 +1840,8 @@
 
   void abs (LIR_Opr from, LIR_Opr to, LIR_Opr tmp)                { append(new LIR_Op2(lir_abs , from, tmp, to)); }
   void sqrt(LIR_Opr from, LIR_Opr to, LIR_Opr tmp)                { append(new LIR_Op2(lir_sqrt, from, tmp, to)); }
-  void log (LIR_Opr from, LIR_Opr to, LIR_Opr tmp)                { append(new LIR_Op2(lir_log,  from, tmp, to)); }
-  void log10 (LIR_Opr from, LIR_Opr to, LIR_Opr tmp)              { append(new LIR_Op2(lir_log10, from, tmp, to)); }
+  void log (LIR_Opr from, LIR_Opr to, LIR_Opr tmp)                { append(new LIR_Op2(lir_log,  from, LIR_OprFact::illegalOpr, to, tmp)); }
+  void log10 (LIR_Opr from, LIR_Opr to, LIR_Opr tmp)              { append(new LIR_Op2(lir_log10, from, LIR_OprFact::illegalOpr, to, tmp)); }
   void sin (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_Op2(lir_sin , from, tmp1, to, tmp2)); }
   void cos (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_Op2(lir_cos , from, tmp1, to, tmp2)); }
   void tan (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_Op2(lir_tan , from, tmp1, to, tmp2)); }
--- a/src/share/vm/classfile/javaClasses.cpp	Thu Sep 10 16:46:17 2009 -0700
+++ b/src/share/vm/classfile/javaClasses.cpp	Mon Sep 14 11:45:03 2009 -0700
@@ -252,7 +252,7 @@
   typeArrayOop value  = java_lang_String::value(obj);
   int          offset = java_lang_String::offset(obj);
   int          length = java_lang_String::length(obj);
-  jchar* base = value->char_at_addr(offset);
+  jchar* base = (length == 0) ? NULL : value->char_at_addr(offset);
   symbolOop sym = SymbolTable::lookup_unicode(base, length, THREAD);
   return symbolHandle(THREAD, sym);
 }
@@ -261,7 +261,7 @@
   typeArrayOop value  = java_lang_String::value(java_string);
   int          offset = java_lang_String::offset(java_string);
   int          length = java_lang_String::length(java_string);
-  jchar* base = value->char_at_addr(offset);
+  jchar* base = (length == 0) ? NULL : value->char_at_addr(offset);
   return SymbolTable::probe_unicode(base, length);
 }
 
--- a/src/share/vm/opto/escape.cpp	Thu Sep 10 16:46:17 2009 -0700
+++ b/src/share/vm/opto/escape.cpp	Mon Sep 14 11:45:03 2009 -0700
@@ -439,6 +439,11 @@
   Node *base = addp->in(AddPNode::Base)->uncast();
   if (base->is_top()) { // The AddP case #3 and #6.
     base = addp->in(AddPNode::Address)->uncast();
+    while (base->is_AddP()) {
+      // Case #6 (unsafe access) may have several chained AddP nodes.
+      assert(base->in(AddPNode::Base)->is_top(), "expected unsafe access address only");
+      base = base->in(AddPNode::Address)->uncast();
+    }
     assert(base->Opcode() == Op_ConP || base->Opcode() == Op_ThreadLocal ||
            base->Opcode() == Op_CastX2P || base->is_DecodeN() ||
            (base->is_Mem() && base->bottom_type() == TypeRawPtr::NOTNULL) ||
--- a/src/share/vm/opto/graphKit.cpp	Thu Sep 10 16:46:17 2009 -0700
+++ b/src/share/vm/opto/graphKit.cpp	Mon Sep 14 11:45:03 2009 -0700
@@ -622,11 +622,13 @@
 
 //---------------------------PreserveReexecuteState----------------------------
 PreserveReexecuteState::PreserveReexecuteState(GraphKit* kit) {
+  assert(!kit->stopped(), "must call stopped() before");
   _kit    =    kit;
   _sp     =    kit->sp();
   _reexecute = kit->jvms()->_reexecute;
 }
 PreserveReexecuteState::~PreserveReexecuteState() {
+  if (_kit->stopped()) return;
   _kit->jvms()->_reexecute = _reexecute;
   _kit->set_sp(_sp);
 }
@@ -1086,7 +1088,7 @@
     alen = _gvn.transform( new (C, 3) LoadRangeNode(0, immutable_memory(), r_adr, TypeInt::POS));
   } else {
     alen = alloc->Ideal_length();
-    Node* ccast = alloc->make_ideal_length(_gvn.type(array)->is_aryptr(), &_gvn);
+    Node* ccast = alloc->make_ideal_length(_gvn.type(array)->is_oopptr(), &_gvn);
     if (ccast != alen) {
       alen = _gvn.transform(ccast);
     }
@@ -1123,8 +1125,8 @@
     case T_OBJECT : {
       const Type *t = _gvn.type( value );
 
-      const TypeInstPtr* tp = t->isa_instptr();
-      if (tp != NULL && !tp->klass()->is_loaded()
+      const TypeOopPtr* tp = t->isa_oopptr();
+      if (tp != NULL && tp->klass() != NULL && !tp->klass()->is_loaded()
           // Only for do_null_check, not any of its siblings:
           && !assert_null && null_control == NULL) {
         // Usually, any field access or invocation on an unloaded oop type
--- a/src/share/vm/opto/library_call.cpp	Thu Sep 10 16:46:17 2009 -0700
+++ b/src/share/vm/opto/library_call.cpp	Mon Sep 14 11:45:03 2009 -0700
@@ -3903,19 +3903,10 @@
     guarantee(alloc != NULL && alloc->maybe_set_complete(&_gvn), "");
   }
 
-  // Cast to Object for arraycopy.
-  // We can't use the original CheckCastPP since it should be moved
-  // after the arraycopy to prevent stores flowing above it.
-  Node* new_obj = new(C, 2) CheckCastPPNode(alloc_obj->in(0), raw_obj,
-                                            TypeInstPtr::NOTNULL);
-  new_obj = _gvn.transform(new_obj);
-  // Substitute in the locally valid dest_oop.
-  replace_in_map(alloc_obj, new_obj);
-
   // Copy the fastest available way.
   // TODO: generate fields copies for small objects instead.
   Node* src  = obj;
-  Node* dest = new_obj;
+  Node* dest = alloc_obj;
   Node* size = _gvn.transform(obj_size);
 
   // Exclude the header but include array length to copy by 8 bytes words.
@@ -3961,7 +3952,7 @@
     int raw_adr_idx = Compile::AliasIdxRaw;
     post_barrier(control(),
                  memory(raw_adr_type),
-                 new_obj,
+                 alloc_obj,
                  no_particular_field,
                  raw_adr_idx,
                  no_particular_value,
@@ -3969,16 +3960,8 @@
                  false);
   }
 
-  // Move the original CheckCastPP after arraycopy.
-  _gvn.hash_delete(alloc_obj);
-  alloc_obj->set_req(0, control());
-  // Replace raw memory edge with new CheckCastPP to have a live oop
-  // at safepoints instead of raw value.
-  assert(new_obj->is_CheckCastPP() && new_obj->in(1) == alloc_obj->in(1), "sanity");
-  alloc_obj->set_req(1, new_obj);    // cast to the original type
-  _gvn.hash_find_insert(alloc_obj);  // put back into GVN table
-  // Restore in the locally valid dest_oop.
-  replace_in_map(new_obj, alloc_obj);
+  // Do not let reads from the cloned object float above the arraycopy.
+  insert_mem_bar(Op_MemBarCPUOrder);
 }
 
 //------------------------inline_native_clone----------------------------
@@ -4448,15 +4431,6 @@
     assert(init->is_complete(), "we just did this");
     assert(dest->is_CheckCastPP(), "sanity");
     assert(dest->in(0)->in(0) == init, "dest pinned");
-
-    // Cast to Object for arraycopy.
-    // We can't use the original CheckCastPP since it should be moved
-    // after the arraycopy to prevent stores flowing above it.
-    Node* new_obj = new(C, 2) CheckCastPPNode(dest->in(0), dest->in(1),
-                                              TypeInstPtr::NOTNULL);
-    dest = _gvn.transform(new_obj);
-    // Substitute in the locally valid dest_oop.
-    replace_in_map(original_dest, dest);
     adr_type = TypeRawPtr::BOTTOM;  // all initializations are into raw memory
     // From this point on, every exit path is responsible for
     // initializing any non-copied parts of the object to zero.
@@ -4786,18 +4760,6 @@
   set_i_o(     _gvn.transform(result_i_o)    );
   set_memory(  _gvn.transform(result_memory), adr_type );
 
-  if (dest != original_dest) {
-    // Pin the "finished" array node after the arraycopy/zeroing operations.
-    _gvn.hash_delete(original_dest);
-    original_dest->set_req(0, control());
-    // Replace raw memory edge with new CheckCastPP to have a live oop
-    // at safepoints instead of raw value.
-    assert(dest->is_CheckCastPP() && dest->in(1) == original_dest->in(1), "sanity");
-    original_dest->set_req(1, dest);       // cast to the original type
-    _gvn.hash_find_insert(original_dest);  // put back into GVN table
-    // Restore in the locally valid dest_oop.
-    replace_in_map(dest, original_dest);
-  }
   // The memory edges above are precise in order to model effects around
   // array copies accurately to allow value numbering of field loads around
   // arraycopy.  Such field loads, both before and after, are common in Java
@@ -4808,7 +4770,9 @@
   // The next memory barrier is added to avoid it. If the arraycopy can be
   // optimized away (which it can, sometimes) then we can manually remove
   // the membar also.
-  if (InsertMemBarAfterArraycopy)
+  //
+  // Do not let reads from the cloned object float above the arraycopy.
+  if (InsertMemBarAfterArraycopy || alloc != NULL)
     insert_mem_bar(Op_MemBarCPUOrder);
 }
 
--- a/src/share/vm/opto/superword.cpp	Thu Sep 10 16:46:17 2009 -0700
+++ b/src/share/vm/opto/superword.cpp	Mon Sep 14 11:45:03 2009 -0700
@@ -990,8 +990,8 @@
 // (5) We know there is no dependence cycle, so there in no other case;
 // (6) Finally, all memory ops in another single pack should be moved in the same direction.
 //
-// To schedule a load pack: the memory edge of every loads in the pack must be
-// the same as the memory edge of the last executed load in the pack
+// To schedule a load pack, we use the memory state of either the first or the last load in
+// the pack, based on the dependence constraint.
 void SuperWord::co_locate_pack(Node_List* pk) {
   if (pk->at(0)->is_Store()) {
     MemNode* first     = executed_first(pk)->as_Mem();
@@ -1076,15 +1076,32 @@
       current = my_mem->as_Mem();
     } // end while
   } else if (pk->at(0)->is_Load()) { //load
-    // all use the memory state that the last executed load uses
-    LoadNode* last_load  = executed_last(pk)->as_Load();
-    Node* last_mem       = last_load->in(MemNode::Memory);
-    _igvn.hash_delete(last_mem);
-    // Give each load same memory state as last
+    // all loads in the pack should have the same memory state. By default,
+    // we use the memory state of the last load. However, if any load could
+    // not be moved down due to the dependence constraint, we use the memory
+    // state of the first load.
+    Node* last_mem  = executed_last(pk)->in(MemNode::Memory);
+    Node* first_mem = executed_first(pk)->in(MemNode::Memory);
+    bool schedule_last = true;
+    for (uint i = 0; i < pk->size(); i++) {
+      Node* ld = pk->at(i);
+      for (Node* current = last_mem; current != ld->in(MemNode::Memory);
+           current=current->in(MemNode::Memory)) {
+        assert(current != first_mem, "corrupted memory graph");
+        if(current->is_Mem() && !independent(current, ld)){
+          schedule_last = false; // a later store depends on this load
+          break;
+        }
+      }
+    }
+
+    Node* mem_input = schedule_last ? last_mem : first_mem;
+    _igvn.hash_delete(mem_input);
+    // Give each load the same memory state
     for (uint i = 0; i < pk->size(); i++) {
       LoadNode* ld = pk->at(i)->as_Load();
       _igvn.hash_delete(ld);
-      ld->set_req(MemNode::Memory, last_mem);
+      ld->set_req(MemNode::Memory, mem_input);
       _igvn._worklist.push(ld);
     }
   }
--- a/src/share/vm/opto/type.cpp	Thu Sep 10 16:46:17 2009 -0700
+++ b/src/share/vm/opto/type.cpp	Mon Sep 14 11:45:03 2009 -0700
@@ -2236,12 +2236,12 @@
 
 //------------------------------make-------------------------------------------
 const TypeOopPtr *TypeOopPtr::make(PTR ptr,
-                                   int offset) {
+                                   int offset, int instance_id) {
   assert(ptr != Constant, "no constant generic pointers");
   ciKlass*  k = ciKlassKlass::make();
   bool      xk = false;
   ciObject* o = NULL;
-  return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, xk, o, offset, InstanceBot))->hashcons();
+  return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, xk, o, offset, instance_id))->hashcons();
 }
 
 
@@ -2330,7 +2330,8 @@
 
   case OopPtr: {                 // Meeting to other OopPtrs
     const TypeOopPtr *tp = t->is_oopptr();
-    return make( meet_ptr(tp->ptr()), meet_offset(tp->offset()) );
+    int instance_id = meet_instance_id(tp->instance_id());
+    return make( meet_ptr(tp->ptr()), meet_offset(tp->offset()), instance_id );
   }
 
   case InstPtr:                  // For these, flip the call around to cut down
@@ -2801,7 +2802,7 @@
 
   case OopPtr: {                // Meeting to OopPtrs
     // Found a OopPtr type vs self-InstPtr type
-    const TypePtr *tp = t->is_oopptr();
+    const TypeOopPtr *tp = t->is_oopptr();
     int offset = meet_offset(tp->offset());
     PTR ptr = meet_ptr(tp->ptr());
     switch (tp->ptr()) {
@@ -2812,8 +2813,10 @@
                   (ptr == Constant ? const_oop() : NULL), offset, instance_id);
     }
     case NotNull:
-    case BotPTR:
-      return TypeOopPtr::make(ptr, offset);
+    case BotPTR: {
+      int instance_id = meet_instance_id(tp->instance_id());
+      return TypeOopPtr::make(ptr, offset, instance_id);
+    }
     default: typerr(t);
     }
   }
@@ -3259,7 +3262,7 @@
 
   case OopPtr: {                // Meeting to OopPtrs
     // Found a OopPtr type vs self-AryPtr type
-    const TypePtr *tp = t->is_oopptr();
+    const TypeOopPtr *tp = t->is_oopptr();
     int offset = meet_offset(tp->offset());
     PTR ptr = meet_ptr(tp->ptr());
     switch (tp->ptr()) {
@@ -3270,8 +3273,10 @@
                   _ary, _klass, _klass_is_exact, offset, instance_id);
     }
     case BotPTR:
-    case NotNull:
-      return TypeOopPtr::make(ptr, offset);
+    case NotNull: {
+      int instance_id = meet_instance_id(tp->instance_id());
+      return TypeOopPtr::make(ptr, offset, instance_id);
+    }
     default: ShouldNotReachHere();
     }
   }
--- a/src/share/vm/opto/type.hpp	Thu Sep 10 16:46:17 2009 -0700
+++ b/src/share/vm/opto/type.hpp	Mon Sep 14 11:45:03 2009 -0700
@@ -714,7 +714,7 @@
   static const TypeOopPtr* make_from_constant(ciObject* o);
 
   // Make a generic (unclassed) pointer to an oop.
-  static const TypeOopPtr* make(PTR ptr, int offset);
+  static const TypeOopPtr* make(PTR ptr, int offset, int instance_id = InstanceBot);
 
   ciObject* const_oop()    const { return _const_oop; }
   virtual ciKlass* klass() const { return _klass;     }
--- a/test/compiler/6636138/Test1.java	Thu Sep 10 16:46:17 2009 -0700
+++ b/test/compiler/6636138/Test1.java	Mon Sep 14 11:45:03 2009 -0700
@@ -45,7 +45,7 @@
         for (int i = 0; i < src.length; i++) {
             if (src[i] != ref[i]) {
                 System.out.println("Error: src and ref don't match at " + i);
-                System.exit(-1);
+                System.exit(97);
             }
         }
     }
--- a/test/compiler/6636138/Test2.java	Thu Sep 10 16:46:17 2009 -0700
+++ b/test/compiler/6636138/Test2.java	Mon Sep 14 11:45:03 2009 -0700
@@ -51,7 +51,7 @@
             int value = (i-1 + src.length)%src.length; // correct value after shifting
                 if (src[i] != value) {
                     System.out.println("Error: src["+i+"] should be "+ value + " instead of " + src[i]);
-                    System.exit(-1);
+                    System.exit(97);
                 }
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/compiler/6855215/Test6855215.java	Mon Sep 14 11:45:03 2009 -0700
@@ -0,0 +1,55 @@
+/*
+ * 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 6855215
+ * @summary Calculation error (NaN) after about 1500 calculations
+ *
+ * @run main/othervm -Xbatch -XX:UseSSE=0 Test6855215
+ */
+
+public class Test6855215 {
+    private double m;
+    private double b;
+
+    public static double log10(double x) {
+        return Math.log(x) / Math.log(10);
+    }
+
+    void calcMapping(double xmin, double xmax, double ymin, double ymax) {
+        m = (ymax - ymin) / (log10(xmax) - log10(xmin));
+        b = (log10(xmin) * ymax - log10(xmax) * ymin);
+    }
+
+    public static void main(String[] args) {
+        Test6855215 c = new Test6855215();
+        for (int i = 0; i < 30000; i++) {
+            c.calcMapping(91, 121, 177, 34);
+            if (c.m != c.m) {
+                throw new InternalError();
+            }
+        }
+    }
+}
--- a/test/compiler/6865031/Test.java	Thu Sep 10 16:46:17 2009 -0700
+++ b/test/compiler/6865031/Test.java	Mon Sep 14 11:45:03 2009 -0700
@@ -26,7 +26,7 @@
  * @test
  * @bug 6865031
  * @summary Application gives bad result (throws bad exception) with compressed oops
- * @run main/othervm -XX:+UseCompressedOops -XX:HeapBaseMinAddress=32g -XX:-LoopUnswitching -XX:CompileCommand=inline,AbstractMemoryEfficientList.equals Test hello goodbye
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops -XX:HeapBaseMinAddress=32g -XX:-LoopUnswitching -XX:CompileCommand=inline,AbstractMemoryEfficientList.equals Test hello goodbye
  */
 
 import java.lang.ref.ReferenceQueue;