src/share/vm/prims/methodHandleWalk.cpp
Index Unified diffs Context diffs Sdiffs Wdiffs Patch New Old Previous File Next File
*** old/src/share/vm/prims/methodHandleWalk.cpp	Thu May 12 14:03:28 2011
--- new/src/share/vm/prims/methodHandleWalk.cpp	Thu May 12 14:03:28 2011

*** 29,38 **** --- 29,43 ---- /* * JSR 292 reference implementation: method handle structure analysis */ + #ifdef PRODUCT + #define print_method_handle(mh) {} + #else //PRODUCT + extern "C" void print_method_handle(oop mh); + #endif //PRODUCT // ----------------------------------------------------------------------------- // MethodHandleChain void MethodHandleChain::set_method_handle(Handle mh, TRAPS) {
*** 204,268 **** --- 209,260 ---- if (arg_state == NULL && conv_op > java_lang_invoke_AdapterMethodHandle::OP_RETYPE_RAW) { lose("bad argument index", CHECK_(empty)); } + bool retain_original_args = false; // used by fold/collect logic + // perform the adapter action ! switch (chain().adapter_conversion_op()) { ! switch (conv_op) { case java_lang_invoke_AdapterMethodHandle::OP_RETYPE_ONLY: // No changes to arguments; pass the bits through. break; case java_lang_invoke_AdapterMethodHandle::OP_RETYPE_RAW: { // To keep the verifier happy, emit bitwise ("raw") conversions as needed. // See MethodHandles::same_basic_type_for_arguments for allowed conversions. Handle incoming_mtype(THREAD, chain().method_type_oop()); + Handle outgoing_mtype; + { oop outgoing_mh_oop = chain().vmtarget_oop(); if (!java_lang_invoke_MethodHandle::is_instance(outgoing_mh_oop)) lose("outgoing target not a MethodHandle", CHECK_(empty)); ! Handle outgoing_mtype(THREAD, java_lang_invoke_MethodHandle::type(outgoing_mh_oop)); outgoing_mh_oop = NULL; // GC safety ! outgoing_mtype = Handle(THREAD, java_lang_invoke_MethodHandle::type(outgoing_mh_oop)); + } int nptypes = java_lang_invoke_MethodType::ptype_count(outgoing_mtype()); if (nptypes != java_lang_invoke_MethodType::ptype_count(incoming_mtype())) lose("incoming and outgoing parameter count do not agree", CHECK_(empty)); + // 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; ArgToken arg = _outgoing.at(slot)._arg; klassOop in_klass = NULL; klassOop out_klass = NULL; BasicType inpbt = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::ptype(incoming_mtype(), i), &in_klass); BasicType outpbt = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::ptype(outgoing_mtype(), i), &out_klass); assert(inpbt == arg.basic_type(), "sanity"); if (inpbt != outpbt) { vmIntrinsics::ID iid = vmIntrinsics::for_raw_conversion(inpbt, outpbt); if (iid == vmIntrinsics::_none) { lose("no raw conversion method", CHECK_(empty)); } ArgToken arglist[2]; arglist[0] = arg; // outgoing 'this' arglist[1] = ArgToken(); // sentinel arg = make_invoke(NULL, iid, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK_(empty)); change_argument(inpbt, slot, outpbt, arg); } + klassOop src_klass = NULL; + klassOop dst_klass = NULL; + BasicType src = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::ptype(incoming_mtype(), i), &src_klass); + BasicType dst = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::ptype(outgoing_mtype(), i), &dst_klass); + retype_raw_argument_type(src, dst, slot, CHECK_(empty)); i++; // We need to skip void slots at the top of the loop. } BasicType inrbt = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(incoming_mtype())); BasicType outrbt = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(outgoing_mtype())); if (inrbt != outrbt) { if (inrbt == T_INT && outrbt == T_VOID) { // See comments in MethodHandles::same_basic_type_for_arguments. } else { assert(false, "IMPLEMENT ME"); lose("no raw conversion method", CHECK_(empty)); } + // Return type. + { + BasicType src = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(incoming_mtype())); + BasicType dst = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(outgoing_mtype())); + retype_raw_return_type(src, dst, CHECK_(empty)); } break; } case java_lang_invoke_AdapterMethodHandle::OP_CHECK_CAST: {
*** 271,281 **** --- 263,273 ---- 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 new_arg = make_conversion(T_OBJECT, dest_klass, Bytecodes::_checkcast, arg, CHECK_(empty)); ! assert(arg.token_type() >= tt_symbolic || arg.index() == new_arg.index(), "should be the same index"); debug_only(dest_klass = (klassOop)badOop); break; } case java_lang_invoke_AdapterMethodHandle::OP_PRIM_TO_PRIM: {
*** 330,340 **** --- 322,332 ---- lose("no boxing method", CHECK_(empty)); } ArgToken arglist[2]; arglist[0] = arg; // outgoing value arglist[1] = ArgToken(); // sentinel ! arg = make_invoke(NULL, boxer, Bytecodes::_invokevirtual, false, 1, &arglist[0], CHECK_(empty)); ! arg = make_invoke(NULL, boxer, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK_(empty)); change_argument(src, arg_slot, T_OBJECT, arg); break; } case java_lang_invoke_AdapterMethodHandle::OP_SWAP_ARGS: {
*** 402,418 **** --- 394,451 ---- _outgoing.remove_at(arg_slot); } break; } ! case java_lang_invoke_AdapterMethodHandle::OP_COLLECT_ARGS: { //NYI, may GC lose("unimplemented", CHECK_(empty)); break; ! case java_lang_invoke_AdapterMethodHandle::OP_FOLD_ARGS: + retain_original_args = true; // and fall through: + case java_lang_invoke_AdapterMethodHandle::OP_COLLECT_ARGS: { + // call argument MH recursively + //{static int x; if (!x++) print_method_handle(chain().method_handle_oop()); --x;} + Handle recursive_mh(THREAD, chain().adapter_arg_oop()); + if (!java_lang_invoke_MethodHandle::is_instance(recursive_mh())) { + lose("recursive target not a MethodHandle", CHECK_(empty)); + } + Handle recursive_mtype(THREAD, java_lang_invoke_MethodHandle::type(recursive_mh())); + int argc = java_lang_invoke_MethodType::ptype_count(recursive_mtype()); + int coll_slots = java_lang_invoke_MethodHandle::vmslots(recursive_mh()); + BasicType rtype = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(recursive_mtype())); + ArgToken* arglist = NEW_RESOURCE_ARRAY(ArgToken, 1 + argc + 1); // 1+: mh, +1: sentinel + arglist[0] = make_oop_constant(recursive_mh(), CHECK_(empty)); + if (arg_slot < 0 || coll_slots < 0 || arg_slot + coll_slots > _outgoing.length()) { + lose("bad fold/collect arg slot", CHECK_(empty)); } case java_lang_invoke_AdapterMethodHandle::OP_FOLD_ARGS: { //NYI, may GC ! lose("unimplemented", 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; + if (arg_type == T_VOID) continue; + ArgToken arg = _outgoing.at(slot)._arg; + if (i >= argc) { lose("bad fold/collect arg", CHECK_(empty)); } + arglist[1+i] = arg; + if (!retain_original_args) + change_argument(arg_type, slot, T_VOID, ArgToken(tt_void)); + } + arglist[1+argc] = ArgToken(); // sentinel + oop invoker = java_lang_invoke_MethodTypeForm::vmlayout( + java_lang_invoke_MethodType::form(recursive_mtype()) ); + if (invoker == NULL || !invoker->is_method()) { + lose("bad vmlayout slot", CHECK_(empty)); + } + // FIXME: consider inlining the invokee at the bytecode level + ArgToken ret = make_invoke(methodOop(invoker), vmIntrinsics::_none, + Bytecodes::_invokevirtual, false, 1+argc, &arglist[0], CHECK_(empty)); + DEBUG_ONLY(invoker = NULL); + if (rtype == T_OBJECT) { + klassOop rklass = java_lang_Class::as_klassOop( java_lang_invoke_MethodType::rtype(recursive_mtype()) ); + if (rklass != SystemDictionary::Object_klass() && + !Klass::cast(rklass)->is_interface()) { + // preserve type safety + ret = make_conversion(T_OBJECT, rklass, Bytecodes::_checkcast, ret, CHECK_(empty)); + } + } + int ret_slot = arg_slot + (retain_original_args ? coll_slots : 0); + change_argument(T_VOID, ret_slot, rtype, ret); break; } case java_lang_invoke_AdapterMethodHandle::OP_SPREAD_ARGS: { klassOop array_klass_oop = NULL;
*** 502,512 **** --- 535,545 ---- arg = make_prim_constant(arg_type, &arg_value, CHECK_(empty)); } else { lose("bad bound value", CHECK_(empty)); } } ! debug_only(arg_oop = badOop); ! DEBUG_ONLY(arg_oop = badOop); change_argument(T_VOID, arg_slot, arg_type, arg); } // this test must come after the body of the loop if (!chain().is_last()) {
*** 545,570 **** --- 578,601 ---- if (argp >= 0) { _outgoing.at_grow(argp, make_state(T_VOID, ArgToken(tt_void))); // presize } for (int i = 0; i < nptypes; i++) { klassOop arg_type_klass = NULL; ! BasicType arg_type = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::ptype(mtype(), i), &arg_type_klass); java_lang_invoke_MethodType::ptype(mtype(), i), &arg_type_klass); 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); ! DEBUG_ONLY(arg_type_klass = (klassOop) NULL); _outgoing.at_put(argp, make_state(arg_type, 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))); } --argp; } // call make_parameter at the end of the list for the return type klassOop ret_type_klass = NULL; ! BasicType ret_type = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(mtype()), &ret_type_klass); 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 }
*** 612,621 **** --- 643,694 ---- } #endif // ----------------------------------------------------------------------------- + // MethodHandleWalker::retype_raw_conversion + // + // Do the raw retype conversions for OP_RETYPE_RAW. + void MethodHandleWalker::retype_raw_conversion(BasicType src, BasicType dst, bool for_return, int slot, TRAPS) { + if (src != dst) { + if (MethodHandles::same_basic_type_for_returns(src, dst, /*raw*/ true)) { + if (MethodHandles::is_float_fixed_reinterpretation_cast(src, dst)) { + if (for_return) Untested("MHW return raw conversion"); // still untested + vmIntrinsics::ID iid = vmIntrinsics::for_raw_conversion(src, dst); + if (iid == vmIntrinsics::_none) { + lose("no raw conversion method", CHECK); + } + ArgToken arglist[2]; + if (!for_return) { + // argument type conversion + ArgToken arg = _outgoing.at(slot)._arg; + assert(arg.token_type() >= tt_symbolic || src == arg.basic_type(), "sanity"); + arglist[0] = arg; // outgoing 'this' + arglist[1] = ArgToken(); // sentinel + arg = make_invoke(NULL, iid, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK); + change_argument(src, slot, dst, arg); + } else { + // return type conversion + klassOop arg_klass = NULL; + arglist[0] = make_parameter(src, arg_klass, -1, CHECK); // return value + arglist[1] = ArgToken(); // sentinel + (void) make_invoke(NULL, iid, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK); + } + } else { + // Nothing to do. + } + } else if (src == T_OBJECT && is_java_primitive(dst)) { + // ref-to-prim: discard ref, push zero + lose("requested ref-to-prim conversion not expected", CHECK); + } else { + lose("requested raw conversion not allowed", CHECK); + } + } + } + + + // ----------------------------------------------------------------------------- // MethodHandleCompiler MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, int invoke_count, bool is_invokedynamic, TRAPS) : MethodHandleWalker(root, is_invokedynamic, THREAD), _callee(callee),
*** 717,726 **** --- 790,800 ---- case Bytecodes::_dstore_3: case Bytecodes::_astore_0: case Bytecodes::_astore_1: case Bytecodes::_astore_2: case Bytecodes::_astore_3: + case Bytecodes::_iand: case Bytecodes::_i2l: case Bytecodes::_i2f: case Bytecodes::_i2d: case Bytecodes::_i2b: case Bytecodes::_i2c:
*** 943,976 **** --- 1017,1056 ---- emit_bc(op, cpool_klass_put(tk)); emit_store(srctype, index); break; default: ShouldNotReachHere(); + if (op == Bytecodes::_illegal) + lose("no such primitive conversion", THREAD); + else + lose("bad primitive conversion op", THREAD); + return make_prim_constant(type, &zero_jvalue, THREAD); } return make_parameter(type, tk, index, THREAD); } // ----------------------------------------------------------------------------- // MethodHandleCompiler // static jvalue zero_jvalue; + // Values used by the compiler. + jvalue MethodHandleCompiler::zero_jvalue = { 0 }; + jvalue MethodHandleCompiler::one_jvalue = { 1 }; // Emit bytecodes for the given invoke instruction. MethodHandleWalker::ArgToken MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, MethodHandleWalker::ArgToken* argv, TRAPS) { + ArgToken zero; if (m == NULL) { // Get the intrinsic methodOop. m = vmIntrinsics::method_for(iid); if (m == NULL) { ArgToken zero; lose(vmIntrinsics::name_at(iid), CHECK_(zero)); } } klassOop klass = m->method_holder();
*** 1039,1061 **** --- 1119,1158 ---- ArgToken ret; if (tailcall) { if (rbt != _rtype) { if (rbt == T_VOID) { // push a zero of the right sort ArgToken zero; if (_rtype == T_OBJECT) { zero = make_oop_constant(NULL, CHECK_(zero)); } else { zero = make_prim_constant(_rtype, &zero_jvalue, CHECK_(zero)); } emit_load_constant(zero); } else if (_rtype == T_VOID) { // We'll emit a _return with something on the stack. // It's OK to ignore what's on the stack. + } else if (rbt == T_INT && is_subword_type(_rtype)) { + // Convert value to match return type. + switch (_rtype) { + case T_BOOLEAN: { + // boolean is treated as a one-bit unsigned integer. + // Cf. API documentation: java/lang/invoke/MethodHandles.html#explicitCastArguments + ArgToken one = make_prim_constant(T_INT, &one_jvalue, CHECK_(zero)); + emit_load_constant(one); + emit_bc(Bytecodes::_iand); + break; + } + case T_BYTE: emit_bc(Bytecodes::_i2b); break; + case T_CHAR: emit_bc(Bytecodes::_i2c); break; + case T_SHORT: emit_bc(Bytecodes::_i2s); break; + default: ShouldNotReachHere(); + } + } else if (is_subword_type(rbt) && (is_subword_type(_rtype) || (_rtype == T_INT))) { + // The subword type was returned as an int and will be passed + // on as an int. } else { ! tty->print_cr("*** rbt=%d != rtype=%d", rbt, _rtype); assert(false, "IMPLEMENT ME"); ! lose("unknown conversion", CHECK_(zero)); } } switch (_rtype) { case T_BOOLEAN: case T_BYTE: case T_CHAR: case T_SHORT: case T_INT: emit_bc(Bytecodes::_ireturn); break;
*** 1214,1246 **** --- 1311,1345 ---- m->set_size_of_parameters(_num_params); typeArrayHandle exception_handlers(THREAD, Universe::the_empty_int_array()); m->set_exception_table(exception_handlers()); // Set the invocation counter's count to the invoke count of the // original call site. InvocationCounter* ic = m->invocation_counter(); ic->set(InvocationCounter::wait_for_compile, _invoke_count); // Rewrite the method and set up the constant pool cache. objArrayOop m_array = oopFactory::new_system_objArray(1, CHECK_(empty)); objArrayHandle methods(THREAD, m_array); methods->obj_at_put(0, m()); Rewriter::rewrite(_target_klass(), cpool, methods, CHECK_(empty)); // Use fake class. + // Set the invocation counter's count to the invoke count of the + // original call site. + InvocationCounter* ic = m->invocation_counter(); + ic->set(InvocationCounter::wait_for_compile, _invoke_count); + // Create a new MDO { methodDataOop mdo = oopFactory::new_methodData(m, CHECK_(empty)); assert(m->method_data() == NULL, "there should not be an MDO yet"); m->set_method_data(mdo); // Iterate over all profile data and set the count of the counter // data entries to the original call site counter. ! for (ProfileData* pd = mdo->first_data(); mdo->is_valid(pd); pd = mdo->next_data(pd)) { if (pd->is_CounterData()) { CounterData* cd = pd->as_CounterData(); cd->set_count(_invoke_count); ! for (ProfileData* profile_data = mdo->first_data(); + mdo->is_valid(profile_data); + profile_data = mdo->next_data(profile_data)) { + if (profile_data->is_CounterData()) { + CounterData* counter_data = profile_data->as_CounterData(); + counter_data->set_count(_invoke_count); } } } #ifndef PRODUCT
*** 1255,1287 **** --- 1354,1393 ---- } #ifndef PRODUCT #if 0 // MH printer for debugging. class MethodHandlePrinter : public MethodHandleWalker { private: outputStream* _out; bool _verbose; int _temp_num; + int _param_state; stringStream _strbuf; const char* strbuf() { const char* s = _strbuf.as_string(); _strbuf.reset(); return s; } ArgToken token(const char* str) { ! return (ArgToken) str; ! jvalue string_con; + string_con.j = (intptr_t) str; + return ArgToken(tt_symbolic, T_LONG, string_con); + } + const char* string(ArgToken token) { + return (const char*) (intptr_t) token.get_jlong(); } void start_params() { + _param_state <<= 1; _out->print("("); } void end_params() { if (_verbose) _out->print("\n"); _out->print(") => {"); + _param_state >>= 1; } void put_type_name(BasicType type, klassOop tk, outputStream* s) { const char* kname = NULL; if (tk != NULL) kname = Klass::cast(tk)->external_name();
*** 1297,1319 **** --- 1403,1427 ---- return token(temp); } public: MethodHandlePrinter(Handle root, bool verbose, outputStream* out, TRAPS) ! : MethodHandleWalker(root, false, THREAD), _out(out), _verbose(verbose), + _param_state(0), _temp_num(0) { start_params(); } virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) { if (argnum < 0) { end_params(); ! return NULL; ! return token("return"); } ! if (argnum == 0) { ! if ((_param_state & 1) == 0) { + _param_state |= 1; _out->print(_verbose ? "\n " : ""); } else { _out->print(_verbose ? ",\n " : ", "); } if (argnum >= _temp_num)
*** 1339,1380 **** --- 1447,1496 ---- } virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) { java_lang_boxing_object::print(type, con, &_strbuf); return maybe_make_temp("constant", type, "k"); } ! virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, ArgToken src, TRAPS) { _strbuf.print("%s(%s", Bytecodes::name(op), (const char*)src); ! void print_bytecode_name(Bytecodes::Code op) { + if (Bytecodes::is_defined(op)) + _strbuf.print("%s", Bytecodes::name(op)); + else + _strbuf.print("bytecode_%d", (int) op); + } + virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS) { + print_bytecode_name(op); + _strbuf.print("(%s", string(src)); if (tk != NULL) { _strbuf.print(", "); put_type_name(type, tk, &_strbuf); } _strbuf.print(")"); return maybe_make_temp("convert", type, "v"); } ! virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, ArgToken base, ArgToken offset, TRAPS) { ! _strbuf.print("%s(%s, %s", Bytecodes::name(op), (const char*)base, (const char*)offset); ! virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS) { ! _strbuf.print("%s(%s, %s", Bytecodes::name(op), string(base), string(offset)); if (tk != NULL) { _strbuf.print(", "); put_type_name(type, tk, &_strbuf); } _strbuf.print(")"); return maybe_make_temp("fetch", type, "x"); } virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS) { - Symbol* name, sig; + Symbol* sig; if (m != NULL) { name = m->name(); sig = m->signature(); } else { name = vmSymbols::symbol_at(vmIntrinsics::name_for(iid)); sig = vmSymbols::symbol_at(vmIntrinsics::signature_for(iid)); } _strbuf.print("%s %s%s(", Bytecodes::name(op), name->as_C_string(), sig->as_C_string()); for (int i = 0; i < argc; i++) { ! _strbuf.print("%s%s", (i > 0 ? ", " : ""), (const char*)argv[i]); ! _strbuf.print("%s%s", (i > 0 ? ", " : ""), string(argv[i])); } _strbuf.print(")"); if (!tailcall) { BasicType rt = char2type(sig->byte_at(sig->utf8_length()-1)); if (rt == T_ILLEGAL) rt = T_OBJECT; // ';' at the end of '(...)L...;'
*** 1408,1435 **** --- 1524,1547 ---- if (!HAS_PENDING_EXCEPTION) printer.walk(THREAD); if (HAS_PENDING_EXCEPTION) { oop ex = PENDING_EXCEPTION; CLEAR_PENDING_EXCEPTION; ! out->print("\n*** "); ! if (ex != Universe::virtual_machine_error_instance()) ! ex->print_on(out); else out->print("lose: %s", printer.lose_message()); out->print("\n}\n"); ! out->print(" *** "); ! if (printer.lose_message() != NULL) out->print("%s ", printer.lose_message()); ! out->print("}"); } out->print("\n"); } }; #endif // 0 extern "C" void print_method_handle(oop mh) { if (!mh->is_oop()) { - tty->print_cr("*** not a method handle: "INTPTR_FORMAT, (intptr_t)mh); } else if (java_lang_invoke_MethodHandle::is_instance(mh)) { - //MethodHandlePrinter::print(mh); } else { tty->print("*** not a method handle: "); mh->print(); } }

src/share/vm/prims/methodHandleWalk.cpp
Index Unified diffs Context diffs Sdiffs Wdiffs Patch New Old Previous File Next File