--- 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; }
+}