# HG changeset patch # User never # Date 1287441809 25200 # Node ID 0357ff4bd6b2881bcdb47ebbc470b64d64628cb7 # Parent 75ab0162aa8461ccc18ff87ae351ae5b29b45b8e# Parent 7aff5786cc027ffd6d57db2960627cda59616ed9 Merge diff -r 75ab0162aa84 -r 0357ff4bd6b2 src/cpu/sparc/vm/methodHandles_sparc.cpp --- a/src/cpu/sparc/vm/methodHandles_sparc.cpp Mon Oct 18 09:33:24 2010 -0700 +++ b/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: { diff -r 75ab0162aa84 -r 0357ff4bd6b2 src/share/vm/c1/c1_Compilation.hpp --- a/src/share/vm/c1/c1_Compilation.hpp Mon Oct 18 09:33:24 2010 -0700 +++ b/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); diff -r 75ab0162aa84 -r 0357ff4bd6b2 src/share/vm/c1/c1_IR.cpp --- a/src/share/vm/c1/c1_IR.cpp Mon Oct 18 09:33:24 2010 -0700 +++ b/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"); } diff -r 75ab0162aa84 -r 0357ff4bd6b2 src/share/vm/c1/c1_Instruction.cpp --- a/src/share/vm/c1/c1_Instruction.cpp Mon Oct 18 09:33:24 2010 -0700 +++ b/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; } diff -r 75ab0162aa84 -r 0357ff4bd6b2 src/share/vm/c1/c1_Instruction.hpp --- a/src/share/vm/c1/c1_Instruction.hpp Mon Oct 18 09:33:24 2010 -0700 +++ b/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; + } + } }; diff -r 75ab0162aa84 -r 0357ff4bd6b2 src/share/vm/c1/c1_Optimizer.cpp --- a/src/share/vm/c1/c1_Optimizer.cpp Mon Oct 18 09:33:24 2010 -0700 +++ b/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; diff -r 75ab0162aa84 -r 0357ff4bd6b2 src/share/vm/c1/c1_globals.hpp --- a/src/share/vm/c1/c1_globals.hpp Mon Oct 18 09:33:24 2010 -0700 +++ b/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") \ \ diff -r 75ab0162aa84 -r 0357ff4bd6b2 test/Makefile --- a/test/Makefile Mon Oct 18 09:33:24 2010 -0700 +++ b/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) diff -r 75ab0162aa84 -r 0357ff4bd6b2 test/compiler/6991596/Test6991596.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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.invokeExact((boolean) x); + boolean b = mh2.invokeExact(x); + //boolean c = mh3.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.invokeExact((byte) (x ? 1 : 0)); + byte b = mh2.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.invokeExact((char) (x ? 1 : 0)); + char b = mh2.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.invokeExact((short) (x ? 1 : 0)); + short b = mh2.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.invokeExact((x & 1) == 1); + boolean b = mh2.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.invokeExact((byte) x); + byte b = mh2.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.invokeExact((char) x); + char b = mh2.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.invokeExact((short) x); + short b = mh2.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.invokeExact((x & 1) == 1); + boolean b = mh2.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.invokeExact((byte) x); + byte b = mh2.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.invokeExact((char) x); + char b = mh2.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.invokeExact((short) x); + short b = mh2.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.invokeExact((x & 1) == 1); + boolean b = mh2.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.invokeExact((byte) x); + byte b = mh2.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.invokeExact((char) x); + char b = mh2.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.invokeExact((short) x); + short b = mh2.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.invokeExact((x & 1) == 1); + boolean b = mh2.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.invokeExact((byte) x); + byte b = mh2.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.invokeExact((char) x); + char b = mh2.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.invokeExact((short) x); + short b = mh2.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.invokeExact((int) x); + int b = mh2.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.invokeExact((x & 1L) == 1L); + boolean b = mh2.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.invokeExact((byte) x); + byte b = mh2.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.invokeExact((char) x); + char b = mh2.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.invokeExact((short) x); + short b = mh2.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.invokeExact((int) x); + int b = mh2.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; } +}