Merge
authornever
Mon, 18 Oct 2010 15:43:29 -0700
changeset 7103 4a46a9508d91
parent 6971 11c11e616b91 (current diff)
parent 7102 a20be5bfcbee (diff)
child 7105 849cbf3e4d6a
child 7106 867c9d296c6b
Merge
--- a/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp	Mon Oct 18 09:33:24 2010 -0700
+++ b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp	Mon Oct 18 15:43:29 2010 -0700
@@ -630,9 +630,15 @@
 
       switch (ek) {
       case _adapter_opt_i2i:
+        value = vmarg;
+        break;
       case _adapter_opt_l2i:
-        __ unimplemented(entry_name(ek));
-        value = vmarg;
+        {
+          // just delete the extra slot
+          __ add(Gargs, __ argument_offset(O0_argslot), O0_argslot);
+          remove_arg_slots(_masm, -stack_move_unit(), O0_argslot, O1_scratch, O2_scratch, O3_scratch);
+          value = vmarg = Address(O0_argslot, 0);
+        }
         break;
       case _adapter_opt_unboxi:
         {
--- a/hotspot/src/share/vm/c1/c1_Compilation.hpp	Mon Oct 18 09:33:24 2010 -0700
+++ b/hotspot/src/share/vm/c1/c1_Compilation.hpp	Mon Oct 18 15:43:29 2010 -0700
@@ -178,15 +178,11 @@
     return (int) NMethodSizeLimit;  // default 256K or 512K
 #else
     // conditional branches on PPC are restricted to 16 bit signed
-    return MAX2((unsigned int)NMethodSizeLimit,32*K);
+    return MIN2((unsigned int)NMethodSizeLimit,32*K);
 #endif
   }
   static int desired_max_constant_size() {
-#ifndef PPC
-    return (int) NMethodSizeLimit / 10;  // about 25K
-#else
-    return (MAX2((unsigned int)NMethodSizeLimit, 32*K)) / 10;
-#endif
+    return desired_max_code_buffer_size() / 10;
   }
 
   static void setup_code_buffer(CodeBuffer* cb, int call_stub_estimate);
--- a/hotspot/src/share/vm/c1/c1_IR.cpp	Mon Oct 18 09:33:24 2010 -0700
+++ b/hotspot/src/share/vm/c1/c1_IR.cpp	Mon Oct 18 15:43:29 2010 -0700
@@ -321,7 +321,7 @@
   void visit(Value* n) {
     // Local instructions and Phis for expression stack values at the
     // start of basic blocks are not added to the instruction list
-    if (!(*n)->is_linked()&& (*n)->can_be_linked()) {
+    if (!(*n)->is_linked() && (*n)->can_be_linked()) {
       assert(false, "a node was not appended to the graph");
       Compilation::current()->bailout("a node was not appended to the graph");
     }
--- a/hotspot/src/share/vm/c1/c1_Instruction.cpp	Mon Oct 18 09:33:24 2010 -0700
+++ b/hotspot/src/share/vm/c1/c1_Instruction.cpp	Mon Oct 18 15:43:29 2010 -0700
@@ -415,28 +415,26 @@
   return false;
 }
 
-
-BlockBegin* Constant::compare(Instruction::Condition cond, Value right,
-                              BlockBegin* true_sux, BlockBegin* false_sux) {
+Constant::CompareResult Constant::compare(Instruction::Condition cond, Value right) const {
   Constant* rc = right->as_Constant();
   // other is not a constant
-  if (rc == NULL) return NULL;
+  if (rc == NULL) return not_comparable;
 
   ValueType* lt = type();
   ValueType* rt = rc->type();
   // different types
-  if (lt->base() != rt->base()) return NULL;
+  if (lt->base() != rt->base()) return not_comparable;
   switch (lt->tag()) {
   case intTag: {
     int x = lt->as_IntConstant()->value();
     int y = rt->as_IntConstant()->value();
     switch (cond) {
-    case If::eql: return x == y ? true_sux : false_sux;
-    case If::neq: return x != y ? true_sux : false_sux;
-    case If::lss: return x <  y ? true_sux : false_sux;
-    case If::leq: return x <= y ? true_sux : false_sux;
-    case If::gtr: return x >  y ? true_sux : false_sux;
-    case If::geq: return x >= y ? true_sux : false_sux;
+    case If::eql: return x == y ? cond_true : cond_false;
+    case If::neq: return x != y ? cond_true : cond_false;
+    case If::lss: return x <  y ? cond_true : cond_false;
+    case If::leq: return x <= y ? cond_true : cond_false;
+    case If::gtr: return x >  y ? cond_true : cond_false;
+    case If::geq: return x >= y ? cond_true : cond_false;
     }
     break;
   }
@@ -444,12 +442,12 @@
     jlong x = lt->as_LongConstant()->value();
     jlong y = rt->as_LongConstant()->value();
     switch (cond) {
-    case If::eql: return x == y ? true_sux : false_sux;
-    case If::neq: return x != y ? true_sux : false_sux;
-    case If::lss: return x <  y ? true_sux : false_sux;
-    case If::leq: return x <= y ? true_sux : false_sux;
-    case If::gtr: return x >  y ? true_sux : false_sux;
-    case If::geq: return x >= y ? true_sux : false_sux;
+    case If::eql: return x == y ? cond_true : cond_false;
+    case If::neq: return x != y ? cond_true : cond_false;
+    case If::lss: return x <  y ? cond_true : cond_false;
+    case If::leq: return x <= y ? cond_true : cond_false;
+    case If::gtr: return x >  y ? cond_true : cond_false;
+    case If::geq: return x >= y ? cond_true : cond_false;
     }
     break;
   }
@@ -459,14 +457,14 @@
     assert(xvalue != NULL && yvalue != NULL, "not constants");
     if (xvalue->is_loaded() && yvalue->is_loaded()) {
       switch (cond) {
-      case If::eql: return xvalue == yvalue ? true_sux : false_sux;
-      case If::neq: return xvalue != yvalue ? true_sux : false_sux;
+      case If::eql: return xvalue == yvalue ? cond_true : cond_false;
+      case If::neq: return xvalue != yvalue ? cond_true : cond_false;
       }
     }
     break;
   }
   }
-  return NULL;
+  return not_comparable;
 }
 
 
--- a/hotspot/src/share/vm/c1/c1_Instruction.hpp	Mon Oct 18 09:33:24 2010 -0700
+++ b/hotspot/src/share/vm/c1/c1_Instruction.hpp	Mon Oct 18 15:43:29 2010 -0700
@@ -443,7 +443,7 @@
 
   // generic
   virtual Instruction*      as_Instruction()     { return this; } // to satisfy HASHING1 macro
-  virtual Phi*           as_Phi()          { return NULL; }
+  virtual Phi*              as_Phi()             { return NULL; }
   virtual Local*            as_Local()           { return NULL; }
   virtual Constant*         as_Constant()        { return NULL; }
   virtual AccessField*      as_AccessField()     { return NULL; }
@@ -650,8 +650,24 @@
   virtual intx hash() const;
   virtual bool is_equal(Value v) const;
 
-  virtual BlockBegin* compare(Instruction::Condition condition, Value right,
-                              BlockBegin* true_sux, BlockBegin* false_sux);
+
+  enum CompareResult { not_comparable = -1, cond_false, cond_true };
+
+  virtual CompareResult compare(Instruction::Condition condition, Value right) const;
+  BlockBegin* compare(Instruction::Condition cond, Value right,
+                      BlockBegin* true_sux, BlockBegin* false_sux) const {
+    switch (compare(cond, right)) {
+    case not_comparable:
+      return NULL;
+    case cond_false:
+      return false_sux;
+    case cond_true:
+      return true_sux;
+    default:
+      ShouldNotReachHere();
+      return NULL;
+    }
+  }
 };
 
 
--- a/hotspot/src/share/vm/c1/c1_Optimizer.cpp	Mon Oct 18 09:33:24 2010 -0700
+++ b/hotspot/src/share/vm/c1/c1_Optimizer.cpp	Mon Oct 18 15:43:29 2010 -0700
@@ -38,18 +38,20 @@
  private:
   IR* _hir;
   int _cee_count;                                // the number of CEs successfully eliminated
+  int _ifop_count;                               // the number of IfOps successfully simplified
   int _has_substitution;
 
  public:
-  CE_Eliminator(IR* hir) : _cee_count(0), _hir(hir) {
+  CE_Eliminator(IR* hir) : _cee_count(0), _ifop_count(0), _hir(hir) {
     _has_substitution = false;
     _hir->iterate_preorder(this);
     if (_has_substitution) {
-      // substituted some phis so resolve the substitution
+      // substituted some ifops/phis, so resolve the substitution
       SubstitutionResolver sr(_hir);
     }
   }
   int cee_count() const                          { return _cee_count; }
+  int ifop_count() const                         { return _ifop_count; }
 
   void adjust_exception_edges(BlockBegin* block, BlockBegin* sux) {
     int e = sux->number_of_exception_handlers();
@@ -68,156 +70,214 @@
     }
   }
 
-  virtual void block_do(BlockBegin* block) {
-    // 1) find conditional expression
-    // check if block ends with an If
-    If* if_ = block->end()->as_If();
-    if (if_ == NULL) return;
+  virtual void block_do(BlockBegin* block);
+
+ private:
+  Value make_ifop(Value x, Instruction::Condition cond, Value y, Value tval, Value fval);
+};
 
-    // check if If works on int or object types
-    // (we cannot handle If's working on long, float or doubles yet,
-    // since IfOp doesn't support them - these If's show up if cmp
-    // operations followed by If's are eliminated)
-    ValueType* if_type = if_->x()->type();
-    if (!if_type->is_int() && !if_type->is_object()) return;
+void CE_Eliminator::block_do(BlockBegin* block) {
+  // 1) find conditional expression
+  // check if block ends with an If
+  If* if_ = block->end()->as_If();
+  if (if_ == NULL) return;
 
-    BlockBegin* t_block = if_->tsux();
-    BlockBegin* f_block = if_->fsux();
-    Instruction* t_cur = t_block->next();
-    Instruction* f_cur = f_block->next();
+  // check if If works on int or object types
+  // (we cannot handle If's working on long, float or doubles yet,
+  // since IfOp doesn't support them - these If's show up if cmp
+  // operations followed by If's are eliminated)
+  ValueType* if_type = if_->x()->type();
+  if (!if_type->is_int() && !if_type->is_object()) return;
 
-    // one Constant may be present between BlockBegin and BlockEnd
-    Value t_const = NULL;
-    Value f_const = NULL;
-    if (t_cur->as_Constant() != NULL && !t_cur->can_trap()) {
-      t_const = t_cur;
-      t_cur = t_cur->next();
-    }
-    if (f_cur->as_Constant() != NULL && !f_cur->can_trap()) {
-      f_const = f_cur;
-      f_cur = f_cur->next();
-    }
+  BlockBegin* t_block = if_->tsux();
+  BlockBegin* f_block = if_->fsux();
+  Instruction* t_cur = t_block->next();
+  Instruction* f_cur = f_block->next();
 
-    // check if both branches end with a goto
-    Goto* t_goto = t_cur->as_Goto();
-    if (t_goto == NULL) return;
-    Goto* f_goto = f_cur->as_Goto();
-    if (f_goto == NULL) return;
+  // one Constant may be present between BlockBegin and BlockEnd
+  Value t_const = NULL;
+  Value f_const = NULL;
+  if (t_cur->as_Constant() != NULL && !t_cur->can_trap()) {
+    t_const = t_cur;
+    t_cur = t_cur->next();
+  }
+  if (f_cur->as_Constant() != NULL && !f_cur->can_trap()) {
+    f_const = f_cur;
+    f_cur = f_cur->next();
+  }
 
-    // check if both gotos merge into the same block
-    BlockBegin* sux = t_goto->default_sux();
-    if (sux != f_goto->default_sux()) return;
+  // check if both branches end with a goto
+  Goto* t_goto = t_cur->as_Goto();
+  if (t_goto == NULL) return;
+  Goto* f_goto = f_cur->as_Goto();
+  if (f_goto == NULL) return;
 
-    // check if at least one word was pushed on sux_state
-    ValueStack* sux_state = sux->state();
-    if (sux_state->stack_size() <= if_->state()->stack_size()) return;
+  // check if both gotos merge into the same block
+  BlockBegin* sux = t_goto->default_sux();
+  if (sux != f_goto->default_sux()) return;
 
-    // check if phi function is present at end of successor stack and that
-    // only this phi was pushed on the stack
-    Value sux_phi = sux_state->stack_at(if_->state()->stack_size());
-    if (sux_phi == NULL || sux_phi->as_Phi() == NULL || sux_phi->as_Phi()->block() != sux) return;
-    if (sux_phi->type()->size() != sux_state->stack_size() - if_->state()->stack_size()) return;
-
-    // get the values that were pushed in the true- and false-branch
-    Value t_value = t_goto->state()->stack_at(if_->state()->stack_size());
-    Value f_value = f_goto->state()->stack_at(if_->state()->stack_size());
+  // check if at least one word was pushed on sux_state
+  ValueStack* sux_state = sux->state();
+  if (sux_state->stack_size() <= if_->state()->stack_size()) return;
 
-    // backend does not support floats
-    assert(t_value->type()->base() == f_value->type()->base(), "incompatible types");
-    if (t_value->type()->is_float_kind()) return;
+  // check if phi function is present at end of successor stack and that
+  // only this phi was pushed on the stack
+  Value sux_phi = sux_state->stack_at(if_->state()->stack_size());
+  if (sux_phi == NULL || sux_phi->as_Phi() == NULL || sux_phi->as_Phi()->block() != sux) return;
+  if (sux_phi->type()->size() != sux_state->stack_size() - if_->state()->stack_size()) return;
 
-    // check that successor has no other phi functions but sux_phi
-    // this can happen when t_block or f_block contained additonal stores to local variables
-    // that are no longer represented by explicit instructions
-    for_each_phi_fun(sux, phi,
-                     if (phi != sux_phi) return;
-                     );
-    // true and false blocks can't have phis
-    for_each_phi_fun(t_block, phi, return; );
-    for_each_phi_fun(f_block, phi, return; );
+  // get the values that were pushed in the true- and false-branch
+  Value t_value = t_goto->state()->stack_at(if_->state()->stack_size());
+  Value f_value = f_goto->state()->stack_at(if_->state()->stack_size());
+
+  // backend does not support floats
+  assert(t_value->type()->base() == f_value->type()->base(), "incompatible types");
+  if (t_value->type()->is_float_kind()) return;
 
-    // 2) substitute conditional expression
-    //    with an IfOp followed by a Goto
-    // cut if_ away and get node before
-    Instruction* cur_end = if_->prev(block);
+  // check that successor has no other phi functions but sux_phi
+  // this can happen when t_block or f_block contained additonal stores to local variables
+  // that are no longer represented by explicit instructions
+  for_each_phi_fun(sux, phi,
+                   if (phi != sux_phi) return;
+                   );
+  // true and false blocks can't have phis
+  for_each_phi_fun(t_block, phi, return; );
+  for_each_phi_fun(f_block, phi, return; );
+
+  // 2) substitute conditional expression
+  //    with an IfOp followed by a Goto
+  // cut if_ away and get node before
+  Instruction* cur_end = if_->prev(block);
 
-    // append constants of true- and false-block if necessary
-    // clone constants because original block must not be destroyed
-    assert((t_value != f_const && f_value != t_const) || t_const == f_const, "mismatch");
-    if (t_value == t_const) {
-      t_value = new Constant(t_const->type());
-      NOT_PRODUCT(t_value->set_printable_bci(if_->printable_bci()));
-      cur_end = cur_end->set_next(t_value);
-    }
-    if (f_value == f_const) {
-      f_value = new Constant(f_const->type());
-      NOT_PRODUCT(f_value->set_printable_bci(if_->printable_bci()));
-      cur_end = cur_end->set_next(f_value);
-    }
+  // append constants of true- and false-block if necessary
+  // clone constants because original block must not be destroyed
+  assert((t_value != f_const && f_value != t_const) || t_const == f_const, "mismatch");
+  if (t_value == t_const) {
+    t_value = new Constant(t_const->type());
+    NOT_PRODUCT(t_value->set_printable_bci(if_->printable_bci()));
+    cur_end = cur_end->set_next(t_value);
+  }
+  if (f_value == f_const) {
+    f_value = new Constant(f_const->type());
+    NOT_PRODUCT(f_value->set_printable_bci(if_->printable_bci()));
+    cur_end = cur_end->set_next(f_value);
+  }
 
-    // it is very unlikely that the condition can be statically decided
-    // (this was checked previously by the Canonicalizer), so always
-    // append IfOp
-    Value result = new IfOp(if_->x(), if_->cond(), if_->y(), t_value, f_value);
+  Value result = make_ifop(if_->x(), if_->cond(), if_->y(), t_value, f_value);
+  assert(result != NULL, "make_ifop must return a non-null instruction");
+  if (!result->is_linked() && result->can_be_linked()) {
     NOT_PRODUCT(result->set_printable_bci(if_->printable_bci()));
     cur_end = cur_end->set_next(result);
+  }
 
-    // append Goto to successor
-    ValueStack* state_before = if_->is_safepoint() ? if_->state_before() : NULL;
-    Goto* goto_ = new Goto(sux, state_before, if_->is_safepoint() || t_goto->is_safepoint() || f_goto->is_safepoint());
+  // append Goto to successor
+  ValueStack* state_before = if_->is_safepoint() ? if_->state_before() : NULL;
+  Goto* goto_ = new Goto(sux, state_before, if_->is_safepoint() || t_goto->is_safepoint() || f_goto->is_safepoint());
+
+  // prepare state for Goto
+  ValueStack* goto_state = if_->state();
+  while (sux_state->scope() != goto_state->scope()) {
+    goto_state = goto_state->caller_state();
+    assert(goto_state != NULL, "states do not match up");
+  }
+  goto_state = goto_state->copy(ValueStack::StateAfter, goto_state->bci());
+  goto_state->push(result->type(), result);
+  assert(goto_state->is_same(sux_state), "states must match now");
+  goto_->set_state(goto_state);
+
+  cur_end = cur_end->set_next(goto_, goto_state->bci());
+
+  // Adjust control flow graph
+  BlockBegin::disconnect_edge(block, t_block);
+  BlockBegin::disconnect_edge(block, f_block);
+  if (t_block->number_of_preds() == 0) {
+    BlockBegin::disconnect_edge(t_block, sux);
+  }
+  adjust_exception_edges(block, t_block);
+  if (f_block->number_of_preds() == 0) {
+    BlockBegin::disconnect_edge(f_block, sux);
+  }
+  adjust_exception_edges(block, f_block);
+
+  // update block end
+  block->set_end(goto_);
+
+  // substitute the phi if possible
+  if (sux_phi->as_Phi()->operand_count() == 1) {
+    assert(sux_phi->as_Phi()->operand_at(0) == result, "screwed up phi");
+    sux_phi->set_subst(result);
+    _has_substitution = true;
+  }
+
+  // 3) successfully eliminated a conditional expression
+  _cee_count++;
+  if (PrintCEE) {
+    tty->print_cr("%d. CEE in B%d (B%d B%d)", cee_count(), block->block_id(), t_block->block_id(), f_block->block_id());
+    tty->print_cr("%d. IfOp in B%d", ifop_count(), block->block_id());
+  }
 
-    // prepare state for Goto
-    ValueStack* goto_state = if_->state();
-    while (sux_state->scope() != goto_state->scope()) {
-      goto_state = goto_state->caller_state();
-      assert(goto_state != NULL, "states do not match up");
-    }
-    goto_state = goto_state->copy(ValueStack::StateAfter, goto_state->bci());
-    goto_state->push(result->type(), result);
-    assert(goto_state->is_same(sux_state), "states must match now");
-    goto_->set_state(goto_state);
+  _hir->verify();
+}
+
+Value CE_Eliminator::make_ifop(Value x, Instruction::Condition cond, Value y, Value tval, Value fval) {
+  if (!OptimizeIfOps) {
+    return new IfOp(x, cond, y, tval, fval);
+  }
+
+  tval = tval->subst();
+  fval = fval->subst();
+  if (tval == fval) {
+    _ifop_count++;
+    return tval;
+  }
+
+  x = x->subst();
+  y = y->subst();
+
+  Constant* y_const = y->as_Constant();
+  if (y_const != NULL) {
+    IfOp* x_ifop = x->as_IfOp();
+    if (x_ifop != NULL) {                 // x is an ifop, y is a constant
+      Constant* x_tval_const = x_ifop->tval()->subst()->as_Constant();
+      Constant* x_fval_const = x_ifop->fval()->subst()->as_Constant();
 
-    cur_end = cur_end->set_next(goto_, goto_state->bci());
+      if (x_tval_const != NULL && x_fval_const != NULL) {
+        Instruction::Condition x_ifop_cond = x_ifop->cond();
+
+        Constant::CompareResult t_compare_res = x_tval_const->compare(cond, y_const);
+        Constant::CompareResult f_compare_res = x_fval_const->compare(cond, y_const);
+
+        guarantee(t_compare_res != Constant::not_comparable && f_compare_res != Constant::not_comparable, "incomparable constants in IfOp");
+
+        Value new_tval = t_compare_res == Constant::cond_true ? tval : fval;
+        Value new_fval = f_compare_res == Constant::cond_true ? tval : fval;
 
-    // Adjust control flow graph
-    BlockBegin::disconnect_edge(block, t_block);
-    BlockBegin::disconnect_edge(block, f_block);
-    if (t_block->number_of_preds() == 0) {
-      BlockBegin::disconnect_edge(t_block, sux);
+        _ifop_count++;
+        if (new_tval == new_fval) {
+          return new_tval;
+        } else {
+          return new IfOp(x_ifop->x(), x_ifop_cond, x_ifop->y(), new_tval, new_fval);
+        }
+      }
+    } else {
+      Constant* x_const = x->as_Constant();
+      if (x_const != NULL) {         // x and y are constants
+        Constant::CompareResult x_compare_res = x_const->compare(cond, y_const);
+        guarantee(x_compare_res != Constant::not_comparable, "incomparable constants in IfOp");
+
+        _ifop_count++;
+        return x_compare_res == Constant::cond_true ? tval : fval;
+      }
     }
-    adjust_exception_edges(block, t_block);
-    if (f_block->number_of_preds() == 0) {
-      BlockBegin::disconnect_edge(f_block, sux);
-    }
-    adjust_exception_edges(block, f_block);
-
-    // update block end
-    block->set_end(goto_);
-
-    // substitute the phi if possible
-    if (sux_phi->as_Phi()->operand_count() == 1) {
-      assert(sux_phi->as_Phi()->operand_at(0) == result, "screwed up phi");
-      sux_phi->set_subst(result);
-      _has_substitution = true;
-    }
-
-    // 3) successfully eliminated a conditional expression
-    _cee_count++;
-    if (PrintCEE) {
-      tty->print_cr("%d. CEE in B%d (B%d B%d)", cee_count(), block->block_id(), t_block->block_id(), f_block->block_id());
-    }
-
-    _hir->verify();
   }
-};
-
+  return new IfOp(x, cond, y, tval, fval);
+}
 
 void Optimizer::eliminate_conditional_expressions() {
   // find conditional expressions & replace them with IfOps
   CE_Eliminator ce(ir());
 }
 
-
 class BlockMerger: public BlockClosure {
  private:
   IR* _hir;
--- a/hotspot/src/share/vm/c1/c1_globals.hpp	Mon Oct 18 09:33:24 2010 -0700
+++ b/hotspot/src/share/vm/c1/c1_globals.hpp	Mon Oct 18 15:43:29 2010 -0700
@@ -75,6 +75,9 @@
   develop(bool, SelectivePhiFunctions, true,                                \
           "create phi functions at loop headers only when necessary")       \
                                                                             \
+  develop(bool, OptimizeIfOps, true,                                        \
+          "Optimize multiple IfOps")                                        \
+                                                                            \
   develop(bool, DoCEE, true,                                                \
           "Do Conditional Expression Elimination to simplify CFG")          \
                                                                             \
--- a/hotspot/test/Makefile	Mon Oct 18 09:33:24 2010 -0700
+++ b/hotspot/test/Makefile	Mon Oct 18 15:43:29 2010 -0700
@@ -78,7 +78,11 @@
 TEST_ROOT := $(shell pwd)
 
 # Root of all test results
-ABS_BUILD_ROOT = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH)
+ifdef ALT_OUTPUTDIR
+  ABS_BUILD_ROOT = $(ALT_OUTPUTDIR)/$(PLATFORM)-$(ARCH)
+else
+  ABS_BUILD_ROOT = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH)
+endif
 ABS_TEST_OUTPUT_DIR = $(ABS_BUILD_ROOT)/testoutput
 
 # Expect JPRT to set PRODUCT_HOME (the product or jdk in this case to test)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6991596/Test6991596.java	Mon Oct 18 15:43:29 2010 -0700
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/**
+ * @test
+ * @bug 6991596
+ * @summary JSR 292 unimplemented adapter_opt_i2i and adapter_opt_l2i on SPARC
+ *
+ * @run main/othervm -ea -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic -XX:+UnlockDiagnosticVMOptions -XX:+VerifyMethodHandles Test6991596
+ */
+
+import java.dyn.*;
+
+public class Test6991596 {
+    private static final Class   CLASS = Test6991596.class;
+    private static final String  NAME  = "foo";
+    private static final boolean DEBUG = false;
+
+    public static void main(String[] args) throws Throwable {
+        testboolean();
+        testbyte();
+        testchar();
+        testshort();
+        testint();
+        testlong();
+    }
+
+    // Helpers to get various methods.
+    static MethodHandle getmh1(Class ret, Class arg) {
+        return MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(ret, arg));
+    }
+    static MethodHandle getmh2(MethodHandle mh1, Class ret, Class arg) {
+        return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg));
+    }
+    static MethodHandle getmh3(MethodHandle mh1, Class ret, Class arg) {
+        return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg));
+    }
+
+    // test adapter_opt_i2i
+    static void testboolean() throws Throwable {
+        boolean[] a = new boolean[] {
+            true,
+            false
+        };
+        for (int i = 0; i < a.length; i++) {
+            doboolean(a[i]);
+        }
+    }
+    static void doboolean(boolean x) throws Throwable {
+        if (DEBUG)  System.out.println("boolean=" + x);
+
+        // boolean
+        {
+            MethodHandle mh1 = getmh1(     boolean.class, boolean.class);
+            MethodHandle mh2 = getmh2(mh1, boolean.class, boolean.class);
+            // TODO add this for all cases when the bugs are fixed.
+            //MethodHandle mh3 = getmh3(mh1, boolean.class, boolean.class);
+            boolean a = mh1.<boolean>invokeExact((boolean) x);
+            boolean b = mh2.<boolean>invokeExact(x);
+            //boolean c = mh3.<boolean>invokeExact((boolean) x);
+            assert a == b : a + " != " + b;
+            //assert c == x : c + " != " + x;
+        }
+
+        // byte
+        {
+            MethodHandle mh1 = getmh1(     byte.class,    byte.class   );
+            MethodHandle mh2 = getmh2(mh1, byte.class,    boolean.class);
+            byte    a = mh1.<byte>invokeExact((byte) (x ? 1 : 0));
+            byte    b = mh2.<byte>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // char
+        {
+            MethodHandle mh1 = getmh1(     char.class, char.class);
+            MethodHandle mh2 = getmh2(mh1, char.class, boolean.class);
+            char a = mh1.<char>invokeExact((char) (x ? 1 : 0));
+            char b = mh2.<char>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // short
+        {
+            MethodHandle mh1 = getmh1(     short.class, short.class);
+            MethodHandle mh2 = getmh2(mh1, short.class, boolean.class);
+            short a = mh1.<short>invokeExact((short) (x ? 1 : 0));
+            short b = mh2.<short>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+    }
+
+    static void testbyte() throws Throwable {
+        byte[] a = new byte[] {
+            Byte.MIN_VALUE,
+            Byte.MIN_VALUE + 1,
+            -0x0F,
+            -1,
+            0,
+            1,
+            0x0F,
+            Byte.MAX_VALUE - 1,
+            Byte.MAX_VALUE
+        };
+        for (int i = 0; i < a.length; i++) {
+            dobyte(a[i]);
+        }
+    }
+    static void dobyte(byte x) throws Throwable {
+        if (DEBUG)  System.out.println("byte=" + x);
+
+        // boolean
+        {
+            MethodHandle mh1 = getmh1(     boolean.class, boolean.class);
+            MethodHandle mh2 = getmh2(mh1, boolean.class, byte.class);
+            boolean a = mh1.<boolean>invokeExact((x & 1) == 1);
+            boolean b = mh2.<boolean>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // byte
+        {
+            MethodHandle mh1 = getmh1(     byte.class, byte.class);
+            MethodHandle mh2 = getmh2(mh1, byte.class, byte.class);
+            byte a = mh1.<byte>invokeExact((byte) x);
+            byte b = mh2.<byte>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // char
+        {
+            MethodHandle mh1 = getmh1(     char.class, char.class);
+            MethodHandle mh2 = getmh2(mh1, char.class, byte.class);
+            char a = mh1.<char>invokeExact((char) x);
+            char b = mh2.<char>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // short
+        {
+            MethodHandle mh1 = getmh1(     short.class, short.class);
+            MethodHandle mh2 = getmh2(mh1, short.class, byte.class);
+            short a = mh1.<short>invokeExact((short) x);
+            short b = mh2.<short>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+    }
+
+    static void testchar() throws Throwable {
+        char[] a = new char[] {
+            Character.MIN_VALUE,
+            Character.MIN_VALUE + 1,
+            0x000F,
+            0x00FF,
+            0x0FFF,
+            Character.MAX_VALUE - 1,
+            Character.MAX_VALUE
+        };
+        for (int i = 0; i < a.length; i++) {
+            dochar(a[i]);
+        }
+    }
+    static void dochar(char x) throws Throwable {
+        if (DEBUG)  System.out.println("char=" + x);
+
+        // boolean
+        {
+            MethodHandle mh1 = getmh1(     boolean.class, boolean.class);
+            MethodHandle mh2 = getmh2(mh1, boolean.class, char.class);
+            boolean a = mh1.<boolean>invokeExact((x & 1) == 1);
+            boolean b = mh2.<boolean>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // byte
+        {
+            MethodHandle mh1 = getmh1(     byte.class, byte.class);
+            MethodHandle mh2 = getmh2(mh1, byte.class, char.class);
+            byte a = mh1.<byte>invokeExact((byte) x);
+            byte b = mh2.<byte>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // char
+        {
+            MethodHandle mh1 = getmh1(     char.class, char.class);
+            MethodHandle mh2 = getmh2(mh1, char.class, char.class);
+            char a = mh1.<char>invokeExact((char) x);
+            char b = mh2.<char>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // short
+        {
+            MethodHandle mh1 = getmh1(     short.class, short.class);
+            MethodHandle mh2 = getmh2(mh1, short.class, char.class);
+            short a = mh1.<short>invokeExact((short) x);
+            short b = mh2.<short>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+    }
+
+    static void testshort() throws Throwable {
+        short[] a = new short[] {
+            Short.MIN_VALUE,
+            Short.MIN_VALUE + 1,
+            -0x0FFF,
+            -0x00FF,
+            -0x000F,
+            -1,
+            0,
+            1,
+            0x000F,
+            0x00FF,
+            0x0FFF,
+            Short.MAX_VALUE - 1,
+            Short.MAX_VALUE
+        };
+        for (int i = 0; i < a.length; i++) {
+            doshort(a[i]);
+        }
+    }
+    static void doshort(short x) throws Throwable {
+        if (DEBUG)  System.out.println("short=" + x);
+
+        // boolean
+        {
+            MethodHandle mh1 = getmh1(     boolean.class, boolean.class);
+            MethodHandle mh2 = getmh2(mh1, boolean.class, short.class);
+            boolean a = mh1.<boolean>invokeExact((x & 1) == 1);
+            boolean b = mh2.<boolean>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // byte
+        {
+            MethodHandle mh1 = getmh1(     byte.class, byte.class);
+            MethodHandle mh2 = getmh2(mh1, byte.class, short.class);
+            byte a = mh1.<byte>invokeExact((byte) x);
+            byte b = mh2.<byte>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // char
+        {
+            MethodHandle mh1 = getmh1(     char.class, char.class);
+            MethodHandle mh2 = getmh2(mh1, char.class, short.class);
+            char a = mh1.<char>invokeExact((char) x);
+            char b = mh2.<char>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // short
+        {
+            MethodHandle mh1 = getmh1(     short.class, short.class);
+            MethodHandle mh2 = getmh2(mh1, short.class, short.class);
+            short a = mh1.<short>invokeExact((short) x);
+            short b = mh2.<short>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+    }
+
+    static void testint() throws Throwable {
+        int[] a = new int[] {
+            Integer.MIN_VALUE,
+            Integer.MIN_VALUE + 1,
+            -0x0FFFFFFF,
+            -0x00FFFFFF,
+            -0x000FFFFF,
+            -0x0000FFFF,
+            -0x00000FFF,
+            -0x000000FF,
+            -0x0000000F,
+            -1,
+            0,
+            1,
+            0x0000000F,
+            0x000000FF,
+            0x00000FFF,
+            0x0000FFFF,
+            0x000FFFFF,
+            0x00FFFFFF,
+            0x0FFFFFFF,
+            Integer.MAX_VALUE - 1,
+            Integer.MAX_VALUE
+        };
+        for (int i = 0; i < a.length; i++) {
+            doint(a[i]);
+        }
+    }
+    static void doint(int x) throws Throwable {
+        if (DEBUG)  System.out.println("int=" + x);
+
+        // boolean
+        {
+            MethodHandle mh1 = getmh1(     boolean.class, boolean.class);
+            MethodHandle mh2 = getmh2(mh1, boolean.class, int.class);
+            boolean a = mh1.<boolean>invokeExact((x & 1) == 1);
+            boolean b = mh2.<boolean>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // byte
+        {
+            MethodHandle mh1 = getmh1(     byte.class, byte.class);
+            MethodHandle mh2 = getmh2(mh1, byte.class, int.class);
+            byte a = mh1.<byte>invokeExact((byte) x);
+            byte b = mh2.<byte>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // char
+        {
+            MethodHandle mh1 = getmh1(     char.class, char.class);
+            MethodHandle mh2 = getmh2(mh1, char.class, int.class);
+            char a = mh1.<char>invokeExact((char) x);
+            char b = mh2.<char>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // short
+        {
+            MethodHandle mh1 = getmh1(     short.class, short.class);
+            MethodHandle mh2 = getmh2(mh1, short.class, int.class);
+            short a = mh1.<short>invokeExact((short) x);
+            short b = mh2.<short>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // int
+        {
+            MethodHandle mh1 = getmh1(     int.class, int.class);
+            MethodHandle mh2 = getmh2(mh1, int.class, int.class);
+            int a = mh1.<int>invokeExact((int) x);
+            int b = mh2.<int>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+    }
+
+    // test adapter_opt_l2i
+    static void testlong() throws Throwable {
+        long[] a = new long[] {
+            Long.MIN_VALUE,
+            Long.MIN_VALUE + 1,
+            -0x000000000FFFFFFFL,
+            -0x0000000000FFFFFFL,
+            -0x00000000000FFFFFL,
+            -0x000000000000FFFFL,
+            -0x0000000000000FFFL,
+            -0x00000000000000FFL,
+            -0x000000000000000FL,
+            -1L,
+            0L,
+            1L,
+            0x000000000000000FL,
+            0x00000000000000FFL,
+            0x0000000000000FFFL,
+            0x0000000000000FFFL,
+            0x000000000000FFFFL,
+            0x00000000000FFFFFL,
+            0x0000000000FFFFFFL,
+            0x000000000FFFFFFFL,
+            Long.MAX_VALUE - 1,
+            Long.MAX_VALUE
+        };
+        for (int i = 0; i < a.length; i++) {
+            dolong(a[i]);
+        }
+    }
+    static void dolong(long x) throws Throwable {
+        if (DEBUG)  System.out.println("long=" + x);
+
+        // boolean
+        {
+            MethodHandle mh1 = getmh1(     boolean.class, boolean.class);
+            MethodHandle mh2 = getmh2(mh1, boolean.class, long.class);
+            boolean a = mh1.<boolean>invokeExact((x & 1L) == 1L);
+            boolean b = mh2.<boolean>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // byte
+        {
+            MethodHandle mh1 = getmh1(     byte.class, byte.class);
+            MethodHandle mh2 = getmh2(mh1, byte.class, long.class);
+            byte a = mh1.<byte>invokeExact((byte) x);
+            byte b = mh2.<byte>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // char
+        {
+            MethodHandle mh1 = getmh1(     char.class, char.class);
+            MethodHandle mh2 = getmh2(mh1, char.class, long.class);
+            char a = mh1.<char>invokeExact((char) x);
+            char b = mh2.<char>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // short
+        {
+            MethodHandle mh1 = getmh1(     short.class, short.class);
+            MethodHandle mh2 = getmh2(mh1, short.class, long.class);
+            short a = mh1.<short>invokeExact((short) x);
+            short b = mh2.<short>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+        // int
+        {
+            MethodHandle mh1 = getmh1(     int.class, int.class);
+            MethodHandle mh2 = getmh2(mh1, int.class, long.class);
+            int a = mh1.<int>invokeExact((int) x);
+            int b = mh2.<int>invokeExact(x);
+            assert a == b : a + " != " + b;
+        }
+
+    }
+
+    // to int
+    public static boolean foo(boolean i) { return i; }
+    public static byte    foo(byte    i) { return i; }
+    public static char    foo(char    i) { return i; }
+    public static short   foo(short   i) { return i; }
+    public static int     foo(int     i) { return i; }
+}