# HG changeset patch # User iveresov # Date 1306964774 25200 # Node ID 7c907a50c1bb7c5722924bdcf44952909dd8b55b # Parent 3f7a95be91ef9f51805f9b7a2b500e724a80415f# Parent 88559690c95a62d6fa4876edc22f43dfc6f86a2e Merge diff -r 3f7a95be91ef -r 7c907a50c1bb src/share/vm/prims/methodHandleWalk.cpp --- a/src/share/vm/prims/methodHandleWalk.cpp Wed Jun 01 12:15:10 2011 -0700 +++ b/src/share/vm/prims/methodHandleWalk.cpp Wed Jun 01 14:46:14 2011 -0700 @@ -141,6 +141,12 @@ void MethodHandleChain::lose(const char* msg, TRAPS) { _lose_message = msg; +#ifdef ASSERT + if (Verbose) { + tty->print_cr(INTPTR_FORMAT " lose: %s", _method_handle(), msg); + print(); + } +#endif if (!THREAD->is_Java_thread() || ((JavaThread*)THREAD)->thread_state() != _thread_in_vm) { // throw a preallocated exception THROW_OOP(Universe::virtual_machine_error_instance()); @@ -149,6 +155,145 @@ } +#ifdef ASSERT +static const char* adapter_ops[] = { + "retype_only" , + "retype_raw" , + "check_cast" , + "prim_to_prim" , + "ref_to_prim" , + "prim_to_ref" , + "swap_args" , + "rot_args" , + "dup_args" , + "drop_args" , + "collect_args" , + "spread_args" , + "fold_args" +}; + +static const char* adapter_op_to_string(int op) { + if (op >= 0 && op < (int)ARRAY_SIZE(adapter_ops)) + return adapter_ops[op]; + return "unknown_op"; +} + + +void MethodHandleChain::print(Handle mh) { + EXCEPTION_MARK; + MethodHandleChain mhc(mh, THREAD); + if (HAS_PENDING_EXCEPTION) { + oop ex = THREAD->pending_exception(); + CLEAR_PENDING_EXCEPTION; + ex->print(); + return; + } + mhc.print(); +} + + +void MethodHandleChain::print() { + EXCEPTION_MARK; + print_impl(THREAD); + if (HAS_PENDING_EXCEPTION) { + oop ex = THREAD->pending_exception(); + CLEAR_PENDING_EXCEPTION; + ex->print(); + } +} + +void MethodHandleChain::print_impl(TRAPS) { + ResourceMark rm; + + MethodHandleChain chain(_root, CHECK); + for (;;) { + tty->print(INTPTR_FORMAT ": ", chain.method_handle()()); + if (chain.is_bound()) { + tty->print("bound: arg_type %s arg_slot %d", + type2name(chain.bound_arg_type()), + chain.bound_arg_slot()); + oop o = chain.bound_arg_oop(); + if (o != NULL) { + if (o->is_instance()) { + tty->print(" instance %s", o->klass()->klass_part()->internal_name()); + } else { + o->print(); + } + } + } else if (chain.is_adapter()) { + tty->print("adapter: arg_slot %d conversion op %s", + chain.adapter_arg_slot(), + adapter_op_to_string(chain.adapter_conversion_op())); + switch (chain.adapter_conversion_op()) { + case java_lang_invoke_AdapterMethodHandle::OP_RETYPE_ONLY: + case java_lang_invoke_AdapterMethodHandle::OP_RETYPE_RAW: + case java_lang_invoke_AdapterMethodHandle::OP_CHECK_CAST: + case java_lang_invoke_AdapterMethodHandle::OP_PRIM_TO_PRIM: + case java_lang_invoke_AdapterMethodHandle::OP_REF_TO_PRIM: + case java_lang_invoke_AdapterMethodHandle::OP_PRIM_TO_REF: + break; + + case java_lang_invoke_AdapterMethodHandle::OP_SWAP_ARGS: + case java_lang_invoke_AdapterMethodHandle::OP_ROT_ARGS: { + int dest_arg_slot = chain.adapter_conversion_vminfo(); + tty->print(" dest_arg_slot %d type %s", dest_arg_slot, type2name(chain.adapter_conversion_src_type())); + break; + } + + case java_lang_invoke_AdapterMethodHandle::OP_DUP_ARGS: + case java_lang_invoke_AdapterMethodHandle::OP_DROP_ARGS: { + int dup_slots = chain.adapter_conversion_stack_pushes(); + tty->print(" pushes %d", dup_slots); + break; + } + + case java_lang_invoke_AdapterMethodHandle::OP_FOLD_ARGS: + case java_lang_invoke_AdapterMethodHandle::OP_COLLECT_ARGS: { + int coll_slots = chain.MethodHandle_vmslots(); + tty->print(" coll_slots %d", coll_slots); + break; + } + + case java_lang_invoke_AdapterMethodHandle::OP_SPREAD_ARGS: { + // Check the required length. + int spread_slots = 1 + chain.adapter_conversion_stack_pushes(); + tty->print(" spread_slots %d", spread_slots); + break; + } + + default: + tty->print_cr("bad adapter conversion"); + break; + } + } else { + // DMH + tty->print("direct: "); + chain.last_method_oop()->print_short_name(tty); + } + + tty->print(" ("); + objArrayOop ptypes = java_lang_invoke_MethodType::ptypes(chain.method_type_oop()); + for (int i = ptypes->length() - 1; i >= 0; i--) { + BasicType t = java_lang_Class::as_BasicType(ptypes->obj_at(i)); + if (t == T_ARRAY) t = T_OBJECT; + tty->print("%c", type2char(t)); + if (t == T_LONG || t == T_DOUBLE) tty->print("_"); + } + tty->print(")"); + BasicType rtype = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(chain.method_type_oop())); + if (rtype == T_ARRAY) rtype = T_OBJECT; + tty->print("%c", type2char(rtype)); + tty->cr(); + if (!chain.is_last()) { + chain.next(CHECK); + } else { + break; + } + } +} +#endif + + // ----------------------------------------------------------------------------- // MethodHandleWalker @@ -205,10 +350,16 @@ if (chain().is_adapter()) { int conv_op = chain().adapter_conversion_op(); int arg_slot = chain().adapter_arg_slot(); - SlotState* arg_state = slot_state(arg_slot); - if (arg_state == NULL - && conv_op > java_lang_invoke_AdapterMethodHandle::OP_RETYPE_RAW) { - lose("bad argument index", CHECK_(empty)); + + // Check that the arg_slot is valid. In most cases it must be + // within range of the current arguments but there are some + // exceptions. Those are sanity checked in their implemention + // below. + if ((arg_slot < 0 || arg_slot >= _outgoing.length()) && + conv_op > java_lang_invoke_AdapterMethodHandle::OP_RETYPE_RAW && + conv_op != java_lang_invoke_AdapterMethodHandle::OP_COLLECT_ARGS && + conv_op != java_lang_invoke_AdapterMethodHandle::OP_FOLD_ARGS) { + lose(err_msg("bad argument index %d", arg_slot), CHECK_(empty)); } bool retain_original_args = false; // used by fold/collect logic @@ -237,8 +388,7 @@ // Argument types. for (int i = 0, slot = _outgoing.length() - 1; slot >= 0; slot--) { - SlotState* arg_state = slot_state(slot); - if (arg_state->_type == T_VOID) continue; + if (arg_type(slot) == T_VOID) continue; klassOop src_klass = NULL; klassOop dst_klass = NULL; @@ -262,8 +412,8 @@ klassOop dest_klass = NULL; BasicType dest = java_lang_Class::as_BasicType(chain().adapter_arg_oop(), &dest_klass); assert(dest == T_OBJECT, ""); - assert(dest == arg_state->_type, ""); - ArgToken arg = arg_state->_arg; + ArgToken arg = _outgoing.at(arg_slot); + assert(dest == arg.basic_type(), ""); ArgToken new_arg = make_conversion(T_OBJECT, dest_klass, Bytecodes::_checkcast, arg, CHECK_(empty)); assert(!arg.has_index() || arg.index() == new_arg.index(), "should be the same index"); debug_only(dest_klass = (klassOop)badOop); @@ -274,8 +424,8 @@ // i2l, etc., on the Nth outgoing argument in place BasicType src = chain().adapter_conversion_src_type(), dest = chain().adapter_conversion_dest_type(); + ArgToken arg = _outgoing.at(arg_slot); Bytecodes::Code bc = conversion_code(src, dest); - ArgToken arg = arg_state->_arg; if (bc == Bytecodes::_nop) { break; } else if (bc != Bytecodes::_illegal) { @@ -289,7 +439,7 @@ } } if (bc == Bytecodes::_illegal) { - lose("bad primitive conversion", CHECK_(empty)); + lose(err_msg("bad primitive conversion for %s -> %s", type2name(src), type2name(dest)), CHECK_(empty)); } change_argument(src, arg_slot, dest, arg); break; @@ -298,7 +448,7 @@ case java_lang_invoke_AdapterMethodHandle::OP_REF_TO_PRIM: { // checkcast to wrapper type & call intValue, etc. BasicType dest = chain().adapter_conversion_dest_type(); - ArgToken arg = arg_state->_arg; + ArgToken arg = _outgoing.at(arg_slot); arg = make_conversion(T_OBJECT, SystemDictionary::box_klass(dest), Bytecodes::_checkcast, arg, CHECK_(empty)); vmIntrinsics::ID unboxer = vmIntrinsics::for_unboxing(dest); @@ -316,11 +466,11 @@ case java_lang_invoke_AdapterMethodHandle::OP_PRIM_TO_REF: { // call wrapper type.valueOf BasicType src = chain().adapter_conversion_src_type(); - ArgToken arg = arg_state->_arg; vmIntrinsics::ID boxer = vmIntrinsics::for_boxing(src); if (boxer == vmIntrinsics::_none) { lose("no boxing method", CHECK_(empty)); } + ArgToken arg = _outgoing.at(arg_slot); ArgToken arglist[2]; arglist[0] = arg; // outgoing value arglist[1] = ArgToken(); // sentinel @@ -331,40 +481,45 @@ case java_lang_invoke_AdapterMethodHandle::OP_SWAP_ARGS: { int dest_arg_slot = chain().adapter_conversion_vminfo(); - if (!slot_has_argument(dest_arg_slot)) { + if (!has_argument(dest_arg_slot)) { lose("bad swap index", CHECK_(empty)); } // a simple swap between two arguments - SlotState* dest_arg_state = slot_state(dest_arg_slot); - SlotState temp = (*dest_arg_state); - (*dest_arg_state) = (*arg_state); - (*arg_state) = temp; + if (arg_slot > dest_arg_slot) { + int tmp = arg_slot; + arg_slot = dest_arg_slot; + dest_arg_slot = tmp; + } + ArgToken a1 = _outgoing.at(arg_slot); + ArgToken a2 = _outgoing.at(dest_arg_slot); + change_argument(a2.basic_type(), dest_arg_slot, a1); + change_argument(a1.basic_type(), arg_slot, a2); break; } case java_lang_invoke_AdapterMethodHandle::OP_ROT_ARGS: { int dest_arg_slot = chain().adapter_conversion_vminfo(); - if (!slot_has_argument(dest_arg_slot) || arg_slot == dest_arg_slot) { + if (!has_argument(dest_arg_slot) || arg_slot == dest_arg_slot) { lose("bad rotate index", CHECK_(empty)); } - SlotState* dest_arg_state = slot_state(dest_arg_slot); // Rotate the source argument (plus following N slots) into the // position occupied by the dest argument (plus following N slots). - int rotate_count = type2size[dest_arg_state->_type]; + int rotate_count = type2size[chain().adapter_conversion_src_type()]; // (no other rotate counts are currently supported) if (arg_slot < dest_arg_slot) { for (int i = 0; i < rotate_count; i++) { - SlotState temp = _outgoing.at(arg_slot); + ArgToken temp = _outgoing.at(arg_slot); _outgoing.remove_at(arg_slot); _outgoing.insert_before(dest_arg_slot + rotate_count - 1, temp); } } else { // arg_slot > dest_arg_slot for (int i = 0; i < rotate_count; i++) { - SlotState temp = _outgoing.at(arg_slot + rotate_count - 1); + ArgToken temp = _outgoing.at(arg_slot + rotate_count - 1); _outgoing.remove_at(arg_slot + rotate_count - 1); _outgoing.insert_before(dest_arg_slot, temp); } } + assert(_outgoing_argc == argument_count_slow(), "empty slots under control"); break; } @@ -374,11 +529,11 @@ lose("bad dup count", CHECK_(empty)); } for (int i = 0; i < dup_slots; i++) { - SlotState* dup = slot_state(arg_slot + 2*i); - if (dup == NULL) break; // safety net - if (dup->_type != T_VOID) _outgoing_argc += 1; - _outgoing.insert_before(i, (*dup)); + ArgToken dup = _outgoing.at(arg_slot + 2*i); + if (dup.basic_type() != T_VOID) _outgoing_argc += 1; + _outgoing.insert_before(i, dup); } + assert(_outgoing_argc == argument_count_slow(), "empty slots under control"); break; } @@ -388,11 +543,11 @@ lose("bad drop count", CHECK_(empty)); } for (int i = 0; i < drop_slots; i++) { - SlotState* drop = slot_state(arg_slot); - if (drop == NULL) break; // safety net - if (drop->_type != T_VOID) _outgoing_argc -= 1; + ArgToken drop = _outgoing.at(arg_slot); + if (drop.basic_type() != T_VOID) _outgoing_argc -= 1; _outgoing.remove_at(arg_slot); } + assert(_outgoing_argc == argument_count_slow(), "empty slots under control"); break; } @@ -415,10 +570,10 @@ lose("bad fold/collect arg slot", CHECK_(empty)); } for (int i = 0, slot = arg_slot + coll_slots - 1; slot >= arg_slot; slot--) { - SlotState* arg_state = slot_state(slot); - BasicType arg_type = arg_state->_type; + ArgToken arg_state = _outgoing.at(slot); + BasicType arg_type = arg_state.basic_type(); if (arg_type == T_VOID) continue; - ArgToken arg = _outgoing.at(slot)._arg; + ArgToken arg = _outgoing.at(slot); if (i >= argc) { lose("bad fold/collect arg", CHECK_(empty)); } arglist[1+i] = arg; if (!retain_original_args) @@ -466,8 +621,9 @@ debug_only(element_klass_oop = (klassOop)badOop); // Fetch the argument, which we will cast to the required array type. - assert(arg_state->_type == T_OBJECT, ""); - ArgToken array_arg = arg_state->_arg; + ArgToken arg = _outgoing.at(arg_slot); + assert(arg.basic_type() == T_OBJECT, ""); + ArgToken array_arg = arg; array_arg = make_conversion(T_OBJECT, array_klass(), Bytecodes::_checkcast, array_arg, CHECK_(empty)); change_argument(T_OBJECT, arg_slot, T_VOID, ArgToken(tt_void)); @@ -534,10 +690,10 @@ } else { jvalue arg_value; BasicType bt = java_lang_boxing_object::get_value(arg_oop, &arg_value); - if (bt == arg_type) { + if (bt == arg_type || (bt == T_INT && is_subword_type(arg_type))) { arg = make_prim_constant(arg_type, &arg_value, CHECK_(empty)); } else { - lose("bad bound value", CHECK_(empty)); + lose(err_msg("bad bound value: arg_type %s boxing %s", type2name(arg_type), type2name(bt)), CHECK_(empty)); } } DEBUG_ONLY(arg_oop = badOop); @@ -557,9 +713,9 @@ ArgToken* arglist = NEW_RESOURCE_ARRAY(ArgToken, _outgoing.length() + 1); int ap = 0; for (int i = _outgoing.length() - 1; i >= 0; i--) { - SlotState* arg_state = slot_state(i); - if (arg_state->_type == T_VOID) continue; - arglist[ap++] = _outgoing.at(i)._arg; + ArgToken arg_state = _outgoing.at(i); + if (arg_state.basic_type() == T_VOID) continue; + arglist[ap++] = _outgoing.at(i); } assert(ap == _outgoing_argc, ""); arglist[ap] = ArgToken(); // add a sentinel, for the sake of asserts @@ -579,7 +735,7 @@ _outgoing_argc = nptypes; int argp = nptypes - 1; if (argp >= 0) { - _outgoing.at_grow(argp, make_state(T_VOID, ArgToken(tt_void))); // presize + _outgoing.at_grow(argp, ArgToken(tt_void)); // presize } for (int i = 0; i < nptypes; i++) { klassOop arg_type_klass = NULL; @@ -587,10 +743,10 @@ int index = new_local_index(arg_type); ArgToken arg = make_parameter(arg_type, arg_type_klass, index, CHECK); DEBUG_ONLY(arg_type_klass = (klassOop) NULL); - _outgoing.at_put(argp, make_state(arg_type, arg)); + _outgoing.at_put(argp, arg); if (type2size[arg_type] == 2) { // add the extra slot, so we can model the JVM stack - _outgoing.insert_before(argp+1, make_state(T_VOID, ArgToken(tt_void))); + _outgoing.insert_before(argp+1, ArgToken(tt_void)); } --argp; } @@ -599,38 +755,61 @@ BasicType ret_type = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(mtype()), &ret_type_klass); ArgToken ret = make_parameter(ret_type, ret_type_klass, -1, CHECK); // ignore ret; client can catch it if needed + + assert(_outgoing_argc == argument_count_slow(), "empty slots under control"); + + verify_args_and_signature(CHECK); } +#ifdef ASSERT +void MethodHandleWalker::verify_args_and_signature(TRAPS) { + int index = _outgoing.length() - 1; + objArrayOop ptypes = java_lang_invoke_MethodType::ptypes(chain().method_type_oop()); + for (int i = 0, limit = ptypes->length(); i < limit; i++) { + BasicType t = java_lang_Class::as_BasicType(ptypes->obj_at(i)); + if (t == T_ARRAY) t = T_OBJECT; + if (t == T_LONG || t == T_DOUBLE) { + assert(T_VOID == _outgoing.at(index).basic_type(), "types must match"); + index--; + } + assert(t == _outgoing.at(index).basic_type(), "types must match"); + index--; + } +} +#endif + + // ----------------------------------------------------------------------------- // MethodHandleWalker::change_argument // // This is messy because some kinds of arguments are paired with // companion slots containing an empty value. -void MethodHandleWalker::change_argument(BasicType old_type, int slot, BasicType new_type, - const ArgToken& new_arg) { +void MethodHandleWalker::change_argument(BasicType old_type, int slot, const ArgToken& new_arg) { + BasicType new_type = new_arg.basic_type(); int old_size = type2size[old_type]; int new_size = type2size[new_type]; if (old_size == new_size) { // simple case first - _outgoing.at_put(slot, make_state(new_type, new_arg)); + _outgoing.at_put(slot, new_arg); } else if (old_size > new_size) { for (int i = old_size - 1; i >= new_size; i--) { - assert((i != 0) == (_outgoing.at(slot + i)._type == T_VOID), ""); + assert((i != 0) == (_outgoing.at(slot + i).basic_type() == T_VOID), ""); _outgoing.remove_at(slot + i); } if (new_size > 0) - _outgoing.at_put(slot, make_state(new_type, new_arg)); + _outgoing.at_put(slot, new_arg); else _outgoing_argc -= 1; // deleted a real argument } else { for (int i = old_size; i < new_size; i++) { - _outgoing.insert_before(slot + i, make_state(T_VOID, ArgToken(tt_void))); + _outgoing.insert_before(slot + i, ArgToken(tt_void)); } - _outgoing.at_put(slot, make_state(new_type, new_arg)); + _outgoing.at_put(slot, new_arg); if (old_size == 0) _outgoing_argc += 1; // inserted a real argument } + assert(_outgoing_argc == argument_count_slow(), "empty slots under control"); } @@ -638,8 +817,15 @@ int MethodHandleWalker::argument_count_slow() { int args_seen = 0; for (int i = _outgoing.length() - 1; i >= 0; i--) { - if (_outgoing.at(i)._type != T_VOID) { + if (_outgoing.at(i).basic_type() != T_VOID) { ++args_seen; + if (_outgoing.at(i).basic_type() == T_LONG || + _outgoing.at(i).basic_type() == T_DOUBLE) { + assert(_outgoing.at(i + 1).basic_type() == T_VOID, "should only follow two word"); + } + } else { + assert(_outgoing.at(i - 1).basic_type() == T_LONG || + _outgoing.at(i - 1).basic_type() == T_DOUBLE, "should only follow two word"); } } return args_seen; @@ -663,7 +849,7 @@ ArgToken arglist[2]; if (!for_return) { // argument type conversion - ArgToken arg = _outgoing.at(slot)._arg; + ArgToken arg = _outgoing.at(slot); assert(arg.token_type() >= tt_symbolic || src == arg.basic_type(), "sanity"); arglist[0] = arg; // outgoing 'this' arglist[1] = ArgToken(); // sentinel @@ -683,7 +869,7 @@ // ref-to-prim: discard ref, push zero lose("requested ref-to-prim conversion not expected", CHECK); } else { - lose("requested raw conversion not allowed", CHECK); + lose(err_msg("requested raw conversion not allowed: %s -> %s", type2name(src), type2name(dst)), CHECK); } } } @@ -963,6 +1149,7 @@ void MethodHandleCompiler::emit_load_constant(ArgToken arg) { BasicType bt = arg.basic_type(); + if (is_subword_type(bt)) bt = T_INT; switch (bt) { case T_INT: { jint value = arg.get_jint(); @@ -1066,11 +1253,15 @@ emit_store(srctype, index); break; + case Bytecodes::_nop: + // nothing to do + return src; + default: if (op == Bytecodes::_illegal) - lose("no such primitive conversion", THREAD); + lose(err_msg("no such primitive conversion: %s -> %s", type2name(src.basic_type()), type2name(type)), THREAD); else - lose("bad primitive conversion op", THREAD); + lose(err_msg("bad primitive conversion op: %s", Bytecodes::name(op)), THREAD); return make_prim_constant(type, &zero_jvalue, THREAD); } @@ -1300,7 +1491,7 @@ // for (int i = 1, imax = _constants.length(); i < imax; i++) { // ConstantValue* con = _constants.at(i); -// if (con != NULL && con->is_primitive() && con->_type == bt) { +// if (con != NULL && con->is_primitive() && con.basic_type() == bt) { // bool match = false; // switch (type2size[bt]) { // case 1: if (pcon->_value.i == con->i) match = true; break; @@ -1452,8 +1643,8 @@ _strbuf.reset(); return s; } - ArgToken token(const char* str) { - return ArgToken(str); + ArgToken token(const char* str, BasicType type) { + return ArgToken(str, type); } const char* string(ArgToken token) { return token.str(); @@ -1475,12 +1666,12 @@ } ArgToken maybe_make_temp(const char* statement_op, BasicType type, const char* temp_name) { const char* value = strbuf(); - if (!_verbose) return token(value); + if (!_verbose) return token(value, type); // make an explicit binding for each separate value _strbuf.print("%s%d", temp_name, ++_temp_num); const char* temp = strbuf(); _out->print("\n %s %s %s = %s;", statement_op, type2name(type), temp, value); - return token(temp); + return token(temp, type); } public: @@ -1496,7 +1687,7 @@ virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) { if (argnum < 0) { end_params(); - return token("return"); + return token("return", type); } if ((_param_state & 1) == 0) { _param_state |= 1; @@ -1511,7 +1702,7 @@ const char* arg = strbuf(); put_type_name(type, tk, _out); _out->print(" %s", arg); - return token(arg); + return token(arg, type); } virtual ArgToken make_oop_constant(oop con, TRAPS) { if (con == NULL) @@ -1598,7 +1789,7 @@ out->print("\n"); } static void print(Handle root, bool verbose = Verbose, outputStream* out = tty) { - EXCEPTION_MARK; + Thread* THREAD = Thread::current(); ResourceMark rm; MethodHandlePrinter printer(root, verbose, out, THREAD); if (!HAS_PENDING_EXCEPTION) diff -r 3f7a95be91ef -r 7c907a50c1bb src/share/vm/prims/methodHandleWalk.hpp --- a/src/share/vm/prims/methodHandleWalk.hpp Wed Jun 01 12:15:10 2011 -0700 +++ b/src/share/vm/prims/methodHandleWalk.hpp Wed Jun 01 14:46:14 2011 -0700 @@ -56,6 +56,10 @@ int BoundMethodHandle_vmargslot() { return java_lang_invoke_BoundMethodHandle::vmargslot(method_handle_oop()); } int AdapterMethodHandle_conversion() { return java_lang_invoke_AdapterMethodHandle::conversion(method_handle_oop()); } +#ifdef ASSERT + void print_impl(TRAPS); +#endif + public: MethodHandleChain(Handle root, TRAPS) : _root(root) @@ -99,6 +103,14 @@ void lose(const char* msg, TRAPS); const char* lose_message() { return _lose_message; } + +#ifdef ASSERT + // Print a symbolic description of a method handle chain, including + // the signature for each method. The signatures are printed in + // slot order to make it easier to understand. + void print(); + static void print(Handle mh); +#endif }; @@ -126,7 +138,7 @@ Handle _handle; public: - ArgToken(TokenType tt = tt_illegal) : _tt(tt) { + ArgToken(TokenType tt = tt_illegal) : _tt(tt), _bt(tt == tt_void ? T_VOID : T_ILLEGAL) { assert(tt == tt_illegal || tt == tt_void, "invalid token type"); } @@ -135,11 +147,11 @@ _value.i = index; } - ArgToken(BasicType bt, jvalue value) : _tt(tt_constant), _bt(bt), _value(value) {} - ArgToken(BasicType bt, Handle value) : _tt(tt_constant), _bt(bt), _handle(value) {} + ArgToken(BasicType bt, jvalue value) : _tt(tt_constant), _bt(bt), _value(value) { assert(_bt != T_OBJECT, "wrong constructor"); } + ArgToken(Handle handle) : _tt(tt_constant), _bt(T_OBJECT), _handle(handle) {} - ArgToken(const char* str) : _tt(tt_symbolic), _bt(T_LONG) { + ArgToken(const char* str, BasicType type) : _tt(tt_symbolic), _bt(type) { _value.j = (intptr_t)str; } @@ -147,26 +159,14 @@ BasicType basic_type() const { return _bt; } bool has_index() const { return _tt == tt_parameter || _tt == tt_temporary; } int index() const { assert(has_index(), "must have index");; return _value.i; } - Handle object() const { assert(_tt == tt_constant, "value type"); return _handle; } - const char* str() const { assert(_tt == tt_symbolic, "string type"); return (const char*)_value.j; } - - jint get_jint() const { assert(_tt == tt_constant, "value types"); return _value.i; } - jlong get_jlong() const { assert(_tt == tt_constant, "value types"); return _value.j; } - jfloat get_jfloat() const { assert(_tt == tt_constant, "value types"); return _value.f; } - jdouble get_jdouble() const { assert(_tt == tt_constant, "value types"); return _value.d; } - }; + Handle object() const { assert(_bt == T_OBJECT, "wrong accessor"); assert(_tt == tt_constant, "value type"); return _handle; } + const char* str() const { assert(_tt == tt_symbolic, "string type"); return (const char*)(intptr_t)_value.j; } - // Abstract interpretation state: - struct SlotState { - BasicType _type; - ArgToken _arg; - SlotState() : _type(), _arg() {} + jint get_jint() const { assert(_bt == T_INT || is_subword_type(_bt), "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.i; } + jlong get_jlong() const { assert(_bt == T_LONG, "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.j; } + jfloat get_jfloat() const { assert(_bt == T_FLOAT, "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.f; } + jdouble get_jdouble() const { assert(_bt == T_DOUBLE, "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.d; } }; - static SlotState make_state(BasicType type, ArgToken arg) { - SlotState ss; - ss._type = type; ss._arg = arg; - return ss; - } private: MethodHandleChain _chain; @@ -177,33 +177,29 @@ // TOS is always _outgoing.at(0), so simple pushes and pops shift the whole _outgoing array. // If there is a receiver in the current argument list, it is at _outgoing.at(_outgoing.length()-1). // If a value at _outgoing.at(n) is T_LONG or T_DOUBLE, the value at _outgoing.at(n+1) is T_VOID. - GrowableArray _outgoing; // current outgoing parameter slots + GrowableArray _outgoing; // current outgoing parameter slots int _outgoing_argc; // # non-empty outgoing slots // Replace a value of type old_type at slot (and maybe slot+1) with the new value. // If old_type != T_VOID, remove the old argument at that point. // If new_type != T_VOID, insert the new argument at that point. // Insert or delete a second empty slot as needed. - void change_argument(BasicType old_type, int slot, BasicType new_type, const ArgToken& new_arg); + void change_argument(BasicType old_type, int slot, const ArgToken& new_arg); + void change_argument(BasicType old_type, int slot, BasicType type, const ArgToken& new_arg) { + assert(type == new_arg.basic_type(), "must agree"); + change_argument(old_type, slot, new_arg); + } // Raw retype conversions for OP_RAW_RETYPE. void retype_raw_conversion(BasicType src, BasicType dst, bool for_return, int slot, TRAPS); void retype_raw_argument_type(BasicType src, BasicType dst, int slot, TRAPS) { retype_raw_conversion(src, dst, false, slot, CHECK); } void retype_raw_return_type( BasicType src, BasicType dst, TRAPS) { retype_raw_conversion(src, dst, true, -1, CHECK); } - SlotState* slot_state(int slot) { - if (slot < 0 || slot >= _outgoing.length()) - return NULL; - return _outgoing.adr_at(slot); + BasicType arg_type(int slot) { + return _outgoing.at(slot).basic_type(); } - BasicType slot_type(int slot) { - SlotState* ss = slot_state(slot); - if (ss == NULL) - return T_ILLEGAL; - return ss->_type; - } - bool slot_has_argument(int slot) { - return slot_type(slot) < T_VOID; + bool has_argument(int slot) { + return arg_type(slot) < T_VOID; } #ifdef ASSERT @@ -215,6 +211,8 @@ void walk_incoming_state(TRAPS); + void verify_args_and_signature(TRAPS) NOT_DEBUG_RETURN; + public: MethodHandleWalker(Handle root, bool for_invokedynamic, TRAPS) : _chain(root, THREAD), @@ -421,7 +419,7 @@ } virtual ArgToken make_oop_constant(oop con, TRAPS) { Handle h(THREAD, con); - return ArgToken(T_OBJECT, h); + return ArgToken(h); } virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) { return ArgToken(type, *con); diff -r 3f7a95be91ef -r 7c907a50c1bb src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp Wed Jun 01 12:15:10 2011 -0700 +++ b/src/share/vm/prims/methodHandles.cpp Wed Jun 01 14:46:14 2011 -0700 @@ -1305,6 +1305,7 @@ // Verify that argslot points at the given argnum. int check_slot = argument_slot(java_lang_invoke_MethodHandle::type(mh()), argnum); if (argslot != check_slot || argslot < 0) { + ResourceMark rm; const char* fmt = "for argnum of %d, vmargslot is %d, should be %d"; size_t msglen = strlen(fmt) + 3*11 + 1; char* msg = NEW_RESOURCE_ARRAY(char, msglen); @@ -1829,6 +1830,7 @@ bool direct_to_method = false; if (OptimizeMethodHandles && target->klass() == SystemDictionary::DirectMethodHandle_klass() && + (argnum != 0 || java_lang_invoke_BoundMethodHandle::argument(mh()) != NULL) && (argnum == 0 || java_lang_invoke_DirectMethodHandle::vmindex(target()) < 0)) { KlassHandle receiver_limit; int decode_flags = 0; methodHandle m = decode_method(target(), receiver_limit, decode_flags); @@ -1980,7 +1982,6 @@ err = "adapter requires src/dest conversion subfields for swap"; break; } int swap_size = type2size[src]; - int slot_limit = java_lang_invoke_MethodHandle::vmslots(target()); int src_slot = argslot; int dest_slot = vminfo; bool rotate_up = (src_slot > dest_slot); // upward rotation @@ -2333,7 +2334,6 @@ case _adapter_rot_args: { int swap_slots = type2size[src]; - int slot_limit = java_lang_invoke_AdapterMethodHandle::vmslots(mh()); int src_slot = argslot; int dest_slot = vminfo; int rotate = (ek_orig == _adapter_swap_args) ? 0 : (src_slot > dest_slot) ? 1 : -1; @@ -2661,14 +2661,14 @@ ResourceMark rm; // for error messages // This is the guy we are initializing: - if (mh_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); } + if (mh_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "self is null"); } Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh)); // Early returns out of this method leave the DMH in an unfinished state. assert(java_lang_invoke_MethodHandle::vmentry(mh()) == NULL, "must be safely null"); // which method are we really talking about? - if (target_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); } + if (target_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "target is null"); } Handle target(THREAD, JNIHandles::resolve_non_null(target_jh)); if (java_lang_invoke_MemberName::is_instance(target()) && java_lang_invoke_MemberName::vmindex(target()) == VM_INDEX_UNINITIALIZED) { @@ -2722,13 +2722,13 @@ ResourceMark rm; // for error messages // This is the guy we are initializing: - if (mh_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); } + if (mh_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "self is null"); } Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh)); // Early returns out of this method leave the BMH in an unfinished state. assert(java_lang_invoke_MethodHandle::vmentry(mh()) == NULL, "must be safely null"); - if (target_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); } + if (target_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "target is null"); } Handle target(THREAD, JNIHandles::resolve_non_null(target_jh)); if (!java_lang_invoke_MethodHandle::is_instance(target())) { @@ -2753,9 +2753,8 @@ JVM_ENTRY(void, MHN_init_AMH(JNIEnv *env, jobject igcls, jobject mh_jh, jobject target_jh, int argnum)) { // This is the guy we are initializing: - if (mh_jh == NULL || target_jh == NULL) { - THROW(vmSymbols::java_lang_InternalError()); - } + if (mh_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "self is null"); } + if (target_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "target is null"); } Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh)); Handle target(THREAD, JNIHandles::resolve_non_null(target_jh)); @@ -2890,7 +2889,8 @@ // void init(MemberName self, AccessibleObject ref) JVM_ENTRY(void, MHN_init_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jobject target_jh)) { - if (mname_jh == NULL || target_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); } + if (mname_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "mname is null"); } + if (target_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "target is null"); } Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh)); oop target_oop = JNIHandles::resolve_non_null(target_jh); MethodHandles::init_MemberName(mname(), target_oop); @@ -2899,7 +2899,7 @@ // void expand(MemberName self) JVM_ENTRY(void, MHN_expand_Mem(JNIEnv *env, jobject igcls, jobject mname_jh)) { - if (mname_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); } + if (mname_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "mname is null"); } Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh)); MethodHandles::expand_MemberName(mname, 0, CHECK); } @@ -2907,7 +2907,7 @@ // void resolve(MemberName self, Class caller) JVM_ENTRY(void, MHN_resolve_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jclass caller_jh)) { - if (mname_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); } + if (mname_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "mname is null"); } Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh)); // The trusted Java code that calls this method should already have performed