mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-03 20:50:19 +00:00
6998541: JSR 292 implement missing return-type conversion for OP_RETYPE_RAW
Reviewed-by: jrose, kvn, never
This commit is contained in:
parent
3327033b50
commit
db9005f0d3
@ -142,18 +142,8 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler*
|
||||
Register O2_form = O2_scratch;
|
||||
Register O3_adapter = O3_scratch;
|
||||
__ load_heap_oop(Address(O0_mtype, __ delayed_value(java_lang_invoke_MethodType::form_offset_in_bytes, O1_scratch)), O2_form);
|
||||
// load_heap_oop(Address(O2_form, __ delayed_value(java_lang_invoke_MethodTypeForm::genericInvoker_offset_in_bytes, O1_scratch)), O3_adapter);
|
||||
// deal with old JDK versions:
|
||||
__ add( Address(O2_form, __ delayed_value(java_lang_invoke_MethodTypeForm::genericInvoker_offset_in_bytes, O1_scratch)), O3_adapter);
|
||||
__ cmp(O3_adapter, O2_form);
|
||||
Label sorry_no_invoke_generic;
|
||||
__ brx(Assembler::lessUnsigned, false, Assembler::pn, sorry_no_invoke_generic);
|
||||
__ delayed()->nop();
|
||||
|
||||
__ load_heap_oop(Address(O3_adapter, 0), O3_adapter);
|
||||
__ tst(O3_adapter);
|
||||
__ brx(Assembler::zero, false, Assembler::pn, sorry_no_invoke_generic);
|
||||
__ delayed()->nop();
|
||||
__ load_heap_oop(Address(O2_form, __ delayed_value(java_lang_invoke_MethodTypeForm::genericInvoker_offset_in_bytes, O1_scratch)), O3_adapter);
|
||||
__ verify_oop(O3_adapter);
|
||||
__ st_ptr(O3_adapter, Address(O4_argbase, 1 * Interpreter::stackElementSize));
|
||||
// As a trusted first argument, pass the type being called, so the adapter knows
|
||||
// the actual types of the arguments and return values.
|
||||
@ -164,12 +154,6 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler*
|
||||
trace_method_handle(_masm, "invokeGeneric");
|
||||
__ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
|
||||
|
||||
__ bind(sorry_no_invoke_generic); // no invokeGeneric implementation available!
|
||||
__ mov(O0_mtype, G5_method_type); // required by throw_WrongMethodType
|
||||
// mov(G3_method_handle, G3_method_handle); // already in this register
|
||||
__ jump_to(AddressLiteral(Interpreter::throw_WrongMethodType_entry()), O1_scratch);
|
||||
__ delayed()->nop();
|
||||
|
||||
return entry_point;
|
||||
}
|
||||
|
||||
|
||||
@ -163,7 +163,7 @@ void MethodHandles::RicochetFrame::generate_ricochet_blob(MacroAssembler* _masm,
|
||||
BLOCK_COMMENT("ricochet_blob.bounce");
|
||||
|
||||
if (VerifyMethodHandles) RicochetFrame::verify_clean(_masm);
|
||||
trace_method_handle(_masm, "ricochet_blob.bounce");
|
||||
trace_method_handle(_masm, "return/ricochet_blob.bounce");
|
||||
|
||||
__ jmp(frame_address(continuation_offset_in_bytes()));
|
||||
__ hlt();
|
||||
@ -615,18 +615,10 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler*
|
||||
rcx_argslot, rbx_temp, rdx_temp);
|
||||
|
||||
// load up an adapter from the calling type (Java weaves this)
|
||||
__ load_heap_oop(rdx_temp, Address(rax_mtype, __ delayed_value(java_lang_invoke_MethodType::form_offset_in_bytes, rdi_temp)));
|
||||
Register rdx_adapter = rdx_temp;
|
||||
// __ load_heap_oop(rdx_adapter, Address(rdx_temp, java_lang_invoke_MethodTypeForm::genericInvoker_offset_in_bytes()));
|
||||
// deal with old JDK versions:
|
||||
__ lea(rdi_temp, Address(rdx_temp, __ delayed_value(java_lang_invoke_MethodTypeForm::genericInvoker_offset_in_bytes, rdi_temp)));
|
||||
__ cmpptr(rdi_temp, rdx_temp);
|
||||
Label sorry_no_invoke_generic;
|
||||
__ jcc(Assembler::below, sorry_no_invoke_generic);
|
||||
|
||||
__ load_heap_oop(rdx_adapter, Address(rdi_temp, 0));
|
||||
__ testptr(rdx_adapter, rdx_adapter);
|
||||
__ jcc(Assembler::zero, sorry_no_invoke_generic);
|
||||
__ load_heap_oop(rdx_temp, Address(rax_mtype, __ delayed_value(java_lang_invoke_MethodType::form_offset_in_bytes, rdi_temp)));
|
||||
__ load_heap_oop(rdx_adapter, Address(rdx_temp, __ delayed_value(java_lang_invoke_MethodTypeForm::genericInvoker_offset_in_bytes, rdi_temp)));
|
||||
__ verify_oop(rdx_adapter);
|
||||
__ movptr(Address(rcx_argslot, 1 * Interpreter::stackElementSize), rdx_adapter);
|
||||
// As a trusted first argument, pass the type being called, so the adapter knows
|
||||
// the actual types of the arguments and return values.
|
||||
@ -637,12 +629,6 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler*
|
||||
trace_method_handle(_masm, "invokeGeneric");
|
||||
__ jump_to_method_handle_entry(rcx, rdi_temp);
|
||||
|
||||
__ bind(sorry_no_invoke_generic); // no invokeGeneric implementation available!
|
||||
__ movptr(rcx_recv, Address(rcx_argslot, -1 * Interpreter::stackElementSize)); // recover original MH
|
||||
__ push(rax_mtype); // required mtype
|
||||
__ push(rcx_recv); // bad mh (1st stacked argument)
|
||||
__ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
|
||||
|
||||
return entry_point;
|
||||
}
|
||||
|
||||
@ -688,7 +674,7 @@ void MethodHandles::insert_arg_slots(MacroAssembler* _masm,
|
||||
__ movptr(Address(rdx_temp, arg_slots, Interpreter::stackElementScale()), rbx_temp);
|
||||
__ addptr(rdx_temp, wordSize);
|
||||
__ cmpptr(rdx_temp, rax_argslot);
|
||||
__ jcc(Assembler::less, loop);
|
||||
__ jcc(Assembler::below, loop);
|
||||
}
|
||||
|
||||
// Now move the argslot down, to point to the opened-up space.
|
||||
@ -731,7 +717,7 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm,
|
||||
__ movptr(Address(rdx_temp, arg_slots, Interpreter::stackElementScale()), rbx_temp);
|
||||
__ addptr(rdx_temp, -wordSize);
|
||||
__ cmpptr(rdx_temp, rsp);
|
||||
__ jcc(Assembler::greaterEqual, loop);
|
||||
__ jcc(Assembler::aboveEqual, loop);
|
||||
}
|
||||
|
||||
// Now move the argslot up, to point to the just-copied block.
|
||||
@ -980,12 +966,21 @@ void trace_method_handle_stub(const char* adaptername,
|
||||
intptr_t* saved_sp,
|
||||
intptr_t* saved_bp) {
|
||||
// called as a leaf from native code: do not block the JVM!
|
||||
bool has_mh = (strstr(adaptername, "return/") == NULL); // return adapters don't have rcx_mh
|
||||
intptr_t* last_sp = (intptr_t*) saved_bp[frame::interpreter_frame_last_sp_offset];
|
||||
intptr_t* base_sp = (intptr_t*) saved_bp[frame::interpreter_frame_monitor_block_top_offset];
|
||||
tty->print_cr("MH %s mh="INTPTR_FORMAT" sp=("INTPTR_FORMAT"+"INTX_FORMAT") stack_size="INTX_FORMAT" bp="INTPTR_FORMAT,
|
||||
adaptername, (intptr_t)mh, (intptr_t)entry_sp, (intptr_t)(saved_sp - entry_sp), (intptr_t)(base_sp - last_sp), (intptr_t)saved_bp);
|
||||
if (last_sp != saved_sp && last_sp != NULL)
|
||||
tty->print_cr("*** last_sp="INTPTR_FORMAT, (intptr_t)last_sp);
|
||||
intptr_t* base_sp = last_sp;
|
||||
typedef MethodHandles::RicochetFrame RicochetFrame;
|
||||
RicochetFrame* rfp = (RicochetFrame*)((address)saved_bp - RicochetFrame::sender_link_offset_in_bytes());
|
||||
if (!UseRicochetFrames || Universe::heap()->is_in((address) rfp->saved_args_base())) {
|
||||
// Probably an interpreter frame.
|
||||
base_sp = (intptr_t*) saved_bp[frame::interpreter_frame_monitor_block_top_offset];
|
||||
}
|
||||
intptr_t mh_reg = (intptr_t)mh;
|
||||
const char* mh_reg_name = "rcx_mh";
|
||||
if (!has_mh) mh_reg_name = "rcx";
|
||||
tty->print_cr("MH %s %s="PTR_FORMAT" sp=("PTR_FORMAT"+"INTX_FORMAT") stack_size="INTX_FORMAT" bp="PTR_FORMAT,
|
||||
adaptername, mh_reg_name, mh_reg,
|
||||
(intptr_t)entry_sp, (intptr_t)(saved_sp - entry_sp), (intptr_t)(base_sp - last_sp), (intptr_t)saved_bp);
|
||||
if (Verbose) {
|
||||
tty->print(" reg dump: ");
|
||||
int saved_regs_count = (entry_sp-1) - saved_regs;
|
||||
@ -996,18 +991,21 @@ void trace_method_handle_stub(const char* adaptername,
|
||||
tty->cr();
|
||||
tty->print(" + dump: ");
|
||||
}
|
||||
tty->print(" %d: "INTPTR_FORMAT, i, saved_regs[i]);
|
||||
tty->print(" %d: "PTR_FORMAT, i, saved_regs[i]);
|
||||
}
|
||||
tty->cr();
|
||||
if (last_sp != saved_sp && last_sp != NULL)
|
||||
tty->print_cr("*** last_sp="PTR_FORMAT, (intptr_t)last_sp);
|
||||
int stack_dump_count = 16;
|
||||
if (stack_dump_count < (int)(saved_bp + 2 - saved_sp))
|
||||
stack_dump_count = (int)(saved_bp + 2 - saved_sp);
|
||||
if (stack_dump_count > 64) stack_dump_count = 48;
|
||||
for (i = 0; i < stack_dump_count; i += 4) {
|
||||
tty->print_cr(" dump at SP[%d] "INTPTR_FORMAT": "INTPTR_FORMAT" "INTPTR_FORMAT" "INTPTR_FORMAT" "INTPTR_FORMAT,
|
||||
tty->print_cr(" dump at SP[%d] "PTR_FORMAT": "PTR_FORMAT" "PTR_FORMAT" "PTR_FORMAT" "PTR_FORMAT,
|
||||
i, (intptr_t) &entry_sp[i+0], entry_sp[i+0], entry_sp[i+1], entry_sp[i+2], entry_sp[i+3]);
|
||||
}
|
||||
print_method_handle(mh);
|
||||
if (has_mh)
|
||||
print_method_handle(mh);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1073,7 +1071,6 @@ int MethodHandles::adapter_conversion_ops_supported_mask() {
|
||||
//OP_COLLECT_ARGS is below...
|
||||
|(1<<java_lang_invoke_AdapterMethodHandle::OP_SPREAD_ARGS)
|
||||
|(!UseRicochetFrames ? 0 :
|
||||
LP64_ONLY(FLAG_IS_DEFAULT(UseRicochetFrames) ? 0 :)
|
||||
java_lang_invoke_MethodTypeForm::vmlayout_offset_in_bytes() <= 0 ? 0 :
|
||||
((1<<java_lang_invoke_AdapterMethodHandle::OP_PRIM_TO_REF)
|
||||
|(1<<java_lang_invoke_AdapterMethodHandle::OP_COLLECT_ARGS)
|
||||
@ -1546,7 +1543,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
#else //_LP64
|
||||
if (ek == _adapter_opt_f2d) {
|
||||
__ fld_s(vmarg); // load float to ST0
|
||||
__ fstp_s(vmarg); // store single
|
||||
__ fstp_d(vmarg); // store double
|
||||
} else {
|
||||
__ fld_d(vmarg); // load double to ST0
|
||||
__ fstp_s(vmarg); // store single
|
||||
@ -2353,7 +2350,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
rbx_temp, rdi_temp);
|
||||
__ addptr(rsi_source, type2aelembytes(elem_type));
|
||||
__ cmpptr(rdx_fill_ptr, rax_argslot);
|
||||
__ jcc(Assembler::greater, loop);
|
||||
__ jcc(Assembler::above, loop);
|
||||
} else if (length_constant == 0) {
|
||||
// nothing to copy
|
||||
} else {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2011, 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
|
||||
@ -233,7 +233,10 @@ private:
|
||||
|
||||
public:
|
||||
bool is_method_data() { return true; }
|
||||
bool is_empty() { return _state == empty_state; }
|
||||
|
||||
void set_mature() { _state = mature_state; }
|
||||
|
||||
bool is_empty() { return _state == empty_state; }
|
||||
bool is_mature() { return _state == mature_state; }
|
||||
|
||||
int creation_mileage() { return _orig.creation_mileage(); }
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "ci/ciClassList.hpp"
|
||||
#include "ci/ciInstance.hpp"
|
||||
#include "ci/ciMethodData.hpp"
|
||||
#include "ci/ciMethodHandle.hpp"
|
||||
#include "ci/ciUtilities.hpp"
|
||||
#include "prims/methodHandleWalk.hpp"
|
||||
@ -36,13 +37,13 @@
|
||||
// ciMethodHandle::get_adapter
|
||||
//
|
||||
// Return an adapter for this MethodHandle.
|
||||
ciMethod* ciMethodHandle::get_adapter(bool is_invokedynamic) const {
|
||||
ciMethod* ciMethodHandle::get_adapter_impl(bool is_invokedynamic) const {
|
||||
VM_ENTRY_MARK;
|
||||
Handle h(get_oop());
|
||||
methodHandle callee(_callee->get_methodOop());
|
||||
// We catch all exceptions here that could happen in the method
|
||||
// handle compiler and stop the VM.
|
||||
MethodHandleCompiler mhc(h, callee, call_profile()->count(), is_invokedynamic, THREAD);
|
||||
MethodHandleCompiler mhc(h, callee, _profile->count(), is_invokedynamic, THREAD);
|
||||
if (!HAS_PENDING_EXCEPTION) {
|
||||
methodHandle m = mhc.compile(THREAD);
|
||||
if (!HAS_PENDING_EXCEPTION) {
|
||||
@ -58,6 +59,22 @@ ciMethod* ciMethodHandle::get_adapter(bool is_invokedynamic) const {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciMethodHandle::get_adapter
|
||||
//
|
||||
// Return an adapter for this MethodHandle.
|
||||
ciMethod* ciMethodHandle::get_adapter(bool is_invokedynamic) const {
|
||||
ciMethod* result = get_adapter_impl(is_invokedynamic);
|
||||
if (result) {
|
||||
// Fake up the MDO maturity.
|
||||
ciMethodData* mdo = result->method_data();
|
||||
if (mdo != NULL && _caller->method_data() != NULL && _caller->method_data()->is_mature()) {
|
||||
mdo->set_mature();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciMethodHandle::print_impl
|
||||
|
||||
@ -35,35 +35,36 @@
|
||||
class ciMethodHandle : public ciInstance {
|
||||
private:
|
||||
ciMethod* _callee;
|
||||
ciMethod* _caller;
|
||||
ciCallProfile* _profile;
|
||||
|
||||
// Return an adapter for this MethodHandle.
|
||||
ciMethod* get_adapter(bool is_invokedynamic) const;
|
||||
ciMethod* get_adapter_impl(bool is_invokedynamic) const;
|
||||
ciMethod* get_adapter( bool is_invokedynamic) const;
|
||||
|
||||
protected:
|
||||
void print_impl(outputStream* st);
|
||||
|
||||
public:
|
||||
ciMethodHandle(instanceHandle h_i) : ciInstance(h_i) {};
|
||||
ciMethodHandle(instanceHandle h_i) :
|
||||
ciInstance(h_i),
|
||||
_callee(NULL),
|
||||
_caller(NULL),
|
||||
_profile(NULL)
|
||||
{}
|
||||
|
||||
// What kind of ciObject is this?
|
||||
bool is_method_handle() const { return true; }
|
||||
|
||||
ciMethod* callee() const { return _callee; }
|
||||
void set_callee(ciMethod* m) { _callee = m; }
|
||||
|
||||
ciCallProfile* call_profile() const { return _profile; }
|
||||
void set_call_profile(ciCallProfile* profile) { _profile = profile; }
|
||||
void set_callee(ciMethod* m) { _callee = m; }
|
||||
void set_caller(ciMethod* m) { _caller = m; }
|
||||
void set_call_profile(ciCallProfile* profile) { _profile = profile; }
|
||||
|
||||
// Return an adapter for a MethodHandle call.
|
||||
ciMethod* get_method_handle_adapter() const {
|
||||
return get_adapter(false);
|
||||
}
|
||||
ciMethod* get_method_handle_adapter() const { return get_adapter(false); }
|
||||
|
||||
// Return an adapter for an invokedynamic call.
|
||||
ciMethod* get_invokedynamic_adapter() const {
|
||||
return get_adapter(true);
|
||||
}
|
||||
ciMethod* get_invokedynamic_adapter() const { return get_adapter(true); }
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_CI_CIMETHODHANDLE_HPP
|
||||
|
||||
@ -62,7 +62,10 @@ void trace_type_profile(ciMethod *method, int depth, int bci, ciMethod *prof_met
|
||||
CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index, bool call_is_virtual,
|
||||
JVMState* jvms, bool allow_inline,
|
||||
float prof_factor) {
|
||||
CallGenerator* cg;
|
||||
CallGenerator* cg;
|
||||
ciMethod* caller = jvms->method();
|
||||
int bci = jvms->bci();
|
||||
Bytecodes::Code bytecode = caller->java_code_at_bci(bci);
|
||||
guarantee(call_method != NULL, "failed method resolution");
|
||||
|
||||
// Dtrace currently doesn't work unless all calls are vanilla
|
||||
@ -73,8 +76,7 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
|
||||
// Note: When we get profiling during stage-1 compiles, we want to pull
|
||||
// from more specific profile data which pertains to this inlining.
|
||||
// Right now, ignore the information in jvms->caller(), and do method[bci].
|
||||
ciCallProfile profile = jvms->method()->call_profile_at_bci(jvms->bci());
|
||||
Bytecodes::Code bytecode = jvms->method()->java_code_at_bci(jvms->bci());
|
||||
ciCallProfile profile = caller->call_profile_at_bci(bci);
|
||||
|
||||
// See how many times this site has been invoked.
|
||||
int site_count = profile.count();
|
||||
@ -126,9 +128,10 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
|
||||
ciObject* const_oop = oop_ptr->const_oop();
|
||||
ciMethodHandle* method_handle = const_oop->as_method_handle();
|
||||
|
||||
// Set the actually called method to have access to the class
|
||||
// and signature in the MethodHandleCompiler.
|
||||
// Set the callee to have access to the class and signature in
|
||||
// the MethodHandleCompiler.
|
||||
method_handle->set_callee(call_method);
|
||||
method_handle->set_caller(caller);
|
||||
method_handle->set_call_profile(&profile);
|
||||
|
||||
// Get an adapter for the MethodHandle.
|
||||
@ -150,9 +153,10 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
|
||||
ciCallSite* call_site = str.get_call_site();
|
||||
ciMethodHandle* method_handle = call_site->get_target();
|
||||
|
||||
// Set the actually called method to have access to the class
|
||||
// and signature in the MethodHandleCompiler.
|
||||
// Set the callee to have access to the class and signature in
|
||||
// the MethodHandleCompiler.
|
||||
method_handle->set_callee(call_method);
|
||||
method_handle->set_caller(caller);
|
||||
method_handle->set_call_profile(&profile);
|
||||
|
||||
// Get an adapter for the MethodHandle.
|
||||
|
||||
@ -31,6 +31,11 @@
|
||||
* 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
|
||||
@ -206,8 +211,10 @@ MethodHandleWalker::walk(TRAPS) {
|
||||
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;
|
||||
@ -216,51 +223,36 @@ MethodHandleWalker::walk(TRAPS) {
|
||||
// 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());
|
||||
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
|
||||
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));
|
||||
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;
|
||||
}
|
||||
@ -273,7 +265,7 @@ MethodHandleWalker::walk(TRAPS) {
|
||||
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.index() == new_arg.index(), "should be the same index");
|
||||
assert(arg.token_type() >= tt_symbolic || arg.index() == new_arg.index(), "should be the same index");
|
||||
debug_only(dest_klass = (klassOop)badOop);
|
||||
break;
|
||||
}
|
||||
@ -332,7 +324,7 @@ MethodHandleWalker::walk(TRAPS) {
|
||||
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;
|
||||
}
|
||||
@ -404,13 +396,54 @@ MethodHandleWalker::walk(TRAPS) {
|
||||
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: { //NYI, may GC
|
||||
lose("unimplemented", CHECK_(empty));
|
||||
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));
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -504,7 +537,7 @@ MethodHandleWalker::walk(TRAPS) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -547,11 +580,10 @@ void MethodHandleWalker::walk_incoming_state(TRAPS) {
|
||||
}
|
||||
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);
|
||||
BasicType arg_type = java_lang_Class::as_BasicType(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
|
||||
@ -561,8 +593,7 @@ void MethodHandleWalker::walk_incoming_state(TRAPS) {
|
||||
}
|
||||
// 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);
|
||||
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
|
||||
}
|
||||
@ -613,6 +644,48 @@ int MethodHandleWalker::argument_count_slow() {
|
||||
#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
|
||||
|
||||
@ -719,6 +792,7 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) {
|
||||
case Bytecodes::_astore_1:
|
||||
case Bytecodes::_astore_2:
|
||||
case Bytecodes::_astore_3:
|
||||
case Bytecodes::_iand:
|
||||
case Bytecodes::_i2l:
|
||||
case Bytecodes::_i2f:
|
||||
case Bytecodes::_i2d:
|
||||
@ -945,7 +1019,11 @@ MethodHandleCompiler::make_conversion(BasicType type, klassOop tk, Bytecodes::Co
|
||||
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);
|
||||
@ -956,7 +1034,9 @@ MethodHandleCompiler::make_conversion(BasicType type, klassOop tk, Bytecodes::Co
|
||||
// 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
|
||||
@ -964,18 +1044,18 @@ 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();
|
||||
Symbol* name = m->name();
|
||||
Symbol* signature = m->signature();
|
||||
klassOop klass = m->method_holder();
|
||||
Symbol* name = m->name();
|
||||
Symbol* signature = m->signature();
|
||||
|
||||
if (tailcall) {
|
||||
// Actually, in order to make these methods more recognizable,
|
||||
@ -1041,7 +1121,6 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
|
||||
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 {
|
||||
@ -1051,9 +1130,27 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
|
||||
} 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) {
|
||||
@ -1216,17 +1313,17 @@ methodHandle MethodHandleCompiler::get_method_oop(TRAPS) const {
|
||||
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));
|
||||
@ -1235,10 +1332,12 @@ methodHandle MethodHandleCompiler::get_method_oop(TRAPS) const {
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1257,7 +1356,6 @@ methodHandle MethodHandleCompiler::get_method_oop(TRAPS) const {
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
#if 0
|
||||
// MH printer for debugging.
|
||||
|
||||
class MethodHandlePrinter : public MethodHandleWalker {
|
||||
@ -1265,6 +1363,7 @@ private:
|
||||
outputStream* _out;
|
||||
bool _verbose;
|
||||
int _temp_num;
|
||||
int _param_state;
|
||||
stringStream _strbuf;
|
||||
const char* strbuf() {
|
||||
const char* s = _strbuf.as_string();
|
||||
@ -1272,14 +1371,21 @@ private:
|
||||
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;
|
||||
@ -1299,9 +1405,10 @@ private:
|
||||
|
||||
public:
|
||||
MethodHandlePrinter(Handle root, bool verbose, outputStream* out, TRAPS)
|
||||
: MethodHandleWalker(root, THREAD),
|
||||
: MethodHandleWalker(root, false, THREAD),
|
||||
_out(out),
|
||||
_verbose(verbose),
|
||||
_param_state(0),
|
||||
_temp_num(0)
|
||||
{
|
||||
start_params();
|
||||
@ -1309,9 +1416,10 @@ public:
|
||||
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 " : ", ");
|
||||
@ -1341,8 +1449,15 @@ public:
|
||||
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);
|
||||
@ -1350,8 +1465,8 @@ public:
|
||||
_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);
|
||||
@ -1362,7 +1477,8 @@ public:
|
||||
virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid,
|
||||
Bytecodes::Code op, bool tailcall,
|
||||
int argc, ArgToken* argv, TRAPS) {
|
||||
Symbol* name, sig;
|
||||
Symbol* name;
|
||||
Symbol* sig;
|
||||
if (m != NULL) {
|
||||
name = m->name();
|
||||
sig = m->signature();
|
||||
@ -1372,7 +1488,7 @@ public:
|
||||
}
|
||||
_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) {
|
||||
@ -1410,24 +1526,20 @@ public:
|
||||
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);
|
||||
tty->print_cr("*** not a method handle: "PTR_FORMAT, (intptr_t)mh);
|
||||
} else if (java_lang_invoke_MethodHandle::is_instance(mh)) {
|
||||
//MethodHandlePrinter::print(mh);
|
||||
MethodHandlePrinter::print(mh);
|
||||
} else {
|
||||
tty->print("*** not a method handle: ");
|
||||
mh->print();
|
||||
|
||||
@ -113,6 +113,7 @@ public:
|
||||
tt_parameter,
|
||||
tt_temporary,
|
||||
tt_constant,
|
||||
tt_symbolic,
|
||||
tt_illegal
|
||||
};
|
||||
|
||||
@ -164,6 +165,10 @@ private:
|
||||
bool _for_invokedynamic;
|
||||
int _local_index;
|
||||
|
||||
// This array is kept in an unusual order, indexed by low-level "slot number".
|
||||
// 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<SlotState> _outgoing; // current outgoing parameter slots
|
||||
int _outgoing_argc; // # non-empty outgoing slots
|
||||
|
||||
@ -173,6 +178,11 @@ private:
|
||||
// Insert or delete a second empty slot as needed.
|
||||
void change_argument(BasicType old_type, int slot, BasicType new_type, const ArgToken& 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;
|
||||
@ -221,12 +231,12 @@ public:
|
||||
int max_locals() const { return _local_index; }
|
||||
|
||||
// plug-in abstract interpretation steps:
|
||||
virtual ArgToken make_parameter( BasicType type, klassOop tk, int argnum, TRAPS ) = 0;
|
||||
virtual ArgToken make_prim_constant( BasicType type, jvalue* con, TRAPS ) = 0;
|
||||
virtual ArgToken make_oop_constant( oop con, TRAPS ) = 0;
|
||||
virtual ArgToken make_conversion( BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS ) = 0;
|
||||
virtual ArgToken make_fetch( BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS ) = 0;
|
||||
virtual ArgToken make_invoke( methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS ) = 0;
|
||||
virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) = 0;
|
||||
virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) = 0;
|
||||
virtual ArgToken make_oop_constant(oop con, TRAPS) = 0;
|
||||
virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS) = 0;
|
||||
virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS) = 0;
|
||||
virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS) = 0;
|
||||
|
||||
// For make_invoke, the methodOop can be NULL if the intrinsic ID
|
||||
// is something other than vmIntrinsics::_none.
|
||||
@ -253,6 +263,10 @@ private:
|
||||
KlassHandle _target_klass;
|
||||
Thread* _thread;
|
||||
|
||||
// Values used by the compiler.
|
||||
static jvalue zero_jvalue;
|
||||
static jvalue one_jvalue;
|
||||
|
||||
// Fake constant pool entry.
|
||||
class ConstantValue {
|
||||
private:
|
||||
@ -417,7 +431,7 @@ private:
|
||||
methodHandle get_method_oop(TRAPS) const;
|
||||
|
||||
public:
|
||||
MethodHandleCompiler(Handle root, methodHandle call_method, int invoke_count, bool for_invokedynamic, TRAPS);
|
||||
MethodHandleCompiler(Handle root, methodHandle callee, int invoke_count, bool for_invokedynamic, TRAPS);
|
||||
|
||||
// Compile the given MH chain into bytecode.
|
||||
methodHandle compile(TRAPS);
|
||||
|
||||
@ -1099,6 +1099,14 @@ static oop object_java_mirror() {
|
||||
return Klass::cast(SystemDictionary::Object_klass())->java_mirror();
|
||||
}
|
||||
|
||||
bool MethodHandles::is_float_fixed_reinterpretation_cast(BasicType src, BasicType dst) {
|
||||
if (src == T_FLOAT) return dst == T_INT;
|
||||
if (src == T_INT) return dst == T_FLOAT;
|
||||
if (src == T_DOUBLE) return dst == T_LONG;
|
||||
if (src == T_LONG) return dst == T_DOUBLE;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MethodHandles::same_basic_type_for_arguments(BasicType src,
|
||||
BasicType dst,
|
||||
bool raw,
|
||||
@ -1125,10 +1133,8 @@ bool MethodHandles::same_basic_type_for_arguments(BasicType src,
|
||||
return true; // remaining case: byte fits in short
|
||||
}
|
||||
// allow float/fixed reinterpretation casts
|
||||
if (src == T_FLOAT) return dst == T_INT;
|
||||
if (src == T_INT) return dst == T_FLOAT;
|
||||
if (src == T_DOUBLE) return dst == T_LONG;
|
||||
if (src == T_LONG) return dst == T_DOUBLE;
|
||||
if (is_float_fixed_reinterpretation_cast(src, dst))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1399,7 +1405,7 @@ const char* MethodHandles::check_argument_type_change(BasicType src_type,
|
||||
int argnum,
|
||||
bool raw) {
|
||||
const char* err = NULL;
|
||||
bool for_return = (argnum < 0);
|
||||
const bool for_return = (argnum < 0);
|
||||
|
||||
// just in case:
|
||||
if (src_type == T_ARRAY) src_type = T_OBJECT;
|
||||
@ -1408,17 +1414,17 @@ const char* MethodHandles::check_argument_type_change(BasicType src_type,
|
||||
// Produce some nice messages if VerifyMethodHandles is turned on:
|
||||
if (!same_basic_type_for_arguments(src_type, dst_type, raw, for_return)) {
|
||||
if (src_type == T_OBJECT) {
|
||||
if (raw && dst_type == T_INT && is_always_null_type(src_klass))
|
||||
return NULL; // OK to convert a null pointer to a garbage int
|
||||
err = ((argnum >= 0)
|
||||
if (raw && is_java_primitive(dst_type))
|
||||
return NULL; // ref-to-prim discards ref and returns zero
|
||||
err = (!for_return
|
||||
? "type mismatch: passing a %s for method argument #%d, which expects primitive %s"
|
||||
: "type mismatch: returning a %s, but caller expects primitive %s");
|
||||
} else if (dst_type == T_OBJECT) {
|
||||
err = ((argnum >= 0)
|
||||
err = (!for_return
|
||||
? "type mismatch: passing a primitive %s for method argument #%d, which expects %s"
|
||||
: "type mismatch: returning a primitive %s, but caller expects %s");
|
||||
} else {
|
||||
err = ((argnum >= 0)
|
||||
err = (!for_return
|
||||
? "type mismatch: passing a %s for method argument #%d, which expects %s"
|
||||
: "type mismatch: returning a %s, but caller expects %s");
|
||||
}
|
||||
@ -1427,11 +1433,11 @@ const char* MethodHandles::check_argument_type_change(BasicType src_type,
|
||||
if (!class_cast_needed(dst_klass, src_klass)) {
|
||||
if (raw)
|
||||
return NULL; // reverse cast is OK; the MH target is trusted to enforce it
|
||||
err = ((argnum >= 0)
|
||||
err = (!for_return
|
||||
? "cast required: passing a %s for method argument #%d, which expects %s"
|
||||
: "cast required: returning a %s, but caller expects %s");
|
||||
} else {
|
||||
err = ((argnum >= 0)
|
||||
err = (!for_return
|
||||
? "reference mismatch: passing a %s for method argument #%d, which expects %s"
|
||||
: "reference mismatch: returning a %s, but caller expects %s");
|
||||
}
|
||||
@ -1452,7 +1458,7 @@ const char* MethodHandles::check_argument_type_change(BasicType src_type,
|
||||
|
||||
size_t msglen = strlen(err) + strlen(src_name) + strlen(dst_name) + (argnum < 10 ? 1 : 11);
|
||||
char* msg = NEW_RESOURCE_ARRAY(char, msglen + 1);
|
||||
if (argnum >= 0) {
|
||||
if (!for_return) {
|
||||
assert(strstr(err, "%d") != NULL, "");
|
||||
jio_snprintf(msg, msglen, err, src_name, argnum, dst_name);
|
||||
} else {
|
||||
@ -2180,9 +2186,10 @@ void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
|
||||
}
|
||||
|
||||
void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnum, TRAPS) {
|
||||
int argslot = java_lang_invoke_AdapterMethodHandle::vmargslot(mh());
|
||||
jint conversion = java_lang_invoke_AdapterMethodHandle::conversion(mh());
|
||||
jint conv_op = adapter_conversion_op(conversion);
|
||||
Handle argument = java_lang_invoke_AdapterMethodHandle::argument(mh());
|
||||
int argslot = java_lang_invoke_AdapterMethodHandle::vmargslot(mh());
|
||||
jint conversion = java_lang_invoke_AdapterMethodHandle::conversion(mh());
|
||||
jint conv_op = adapter_conversion_op(conversion);
|
||||
|
||||
// adjust the adapter code to the internal EntryKind enumeration:
|
||||
EntryKind ek_orig = adapter_entry_kind(conv_op);
|
||||
@ -2241,7 +2248,7 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
|
||||
} else if (src == T_DOUBLE && dest == T_FLOAT) {
|
||||
ek_opt = _adapter_opt_d2f;
|
||||
} else {
|
||||
assert(false, "");
|
||||
goto throw_not_impl; // runs user code, hence could block
|
||||
}
|
||||
break;
|
||||
case 1 *4+ 2:
|
||||
@ -2250,11 +2257,11 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
|
||||
} else if (src == T_FLOAT && dest == T_DOUBLE) {
|
||||
ek_opt = _adapter_opt_f2d;
|
||||
} else {
|
||||
assert(false, "");
|
||||
goto throw_not_impl; // runs user code, hence could block
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false, "");
|
||||
goto throw_not_impl; // runs user code, hence could block
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2271,7 +2278,7 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
|
||||
ek_opt = _adapter_opt_unboxl;
|
||||
break;
|
||||
default:
|
||||
assert(false, "");
|
||||
goto throw_not_impl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2284,6 +2291,9 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
|
||||
vminfo = argslot;
|
||||
ek_opt = _adapter_opt_collect_ref;
|
||||
ensure_vmlayout_field(target, CHECK);
|
||||
// for MethodHandleWalk:
|
||||
if (java_lang_invoke_AdapterMethodHandle::is_instance(argument()))
|
||||
ensure_vmlayout_field(argument, CHECK);
|
||||
if (!OptimizeMethodHandles) break;
|
||||
switch (type2size[src]) {
|
||||
case 1:
|
||||
@ -2311,7 +2321,7 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
|
||||
ek_opt = _adapter_opt_collect_2_ref;
|
||||
break;
|
||||
default:
|
||||
assert(false, "");
|
||||
goto throw_not_impl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2335,7 +2345,7 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
|
||||
rotate > 0 ? _adapter_opt_rot_2_up : _adapter_opt_rot_2_down);
|
||||
break;
|
||||
default:
|
||||
assert(false, "");
|
||||
goto throw_not_impl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2402,12 +2412,11 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
|
||||
case _adapter_collect_args:
|
||||
{
|
||||
assert(UseRicochetFrames, "else don't come here");
|
||||
int elem_slots = argument_slot_count(
|
||||
java_lang_invoke_MethodHandle::type(
|
||||
java_lang_invoke_AdapterMethodHandle::argument(mh()) ) );
|
||||
int elem_slots = argument_slot_count(java_lang_invoke_MethodHandle::type(argument()));
|
||||
// vminfo will be the location to insert the return value
|
||||
vminfo = argslot;
|
||||
ensure_vmlayout_field(target, CHECK);
|
||||
ensure_vmlayout_field(argument, CHECK);
|
||||
|
||||
// general case:
|
||||
switch (dest) {
|
||||
@ -2472,12 +2481,11 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
|
||||
case _adapter_fold_args:
|
||||
{
|
||||
assert(UseRicochetFrames, "else don't come here");
|
||||
int elem_slots = argument_slot_count(
|
||||
java_lang_invoke_MethodHandle::type(
|
||||
java_lang_invoke_AdapterMethodHandle::argument(mh()) ) );
|
||||
int elem_slots = argument_slot_count(java_lang_invoke_MethodHandle::type(argument()));
|
||||
// vminfo will be the location to insert the return value
|
||||
vminfo = argslot + elem_slots;
|
||||
ensure_vmlayout_field(target, CHECK);
|
||||
ensure_vmlayout_field(argument, CHECK);
|
||||
|
||||
switch (dest) {
|
||||
default : if (!is_subword_type(dest)) goto throw_not_impl;
|
||||
@ -2527,15 +2535,31 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
|
||||
break;
|
||||
}
|
||||
|
||||
if (err != NULL && (vminfo & CONV_VMINFO_MASK) != vminfo) {
|
||||
if (err == NULL && (vminfo & CONV_VMINFO_MASK) != vminfo) {
|
||||
// should not happen, since vminfo is used to encode arg/slot indexes < 255
|
||||
err = "vminfo overflow";
|
||||
}
|
||||
|
||||
if (err != NULL && !have_entry(ek_opt)) {
|
||||
if (err == NULL && !have_entry(ek_opt)) {
|
||||
err = "adapter stub for this kind of method handle is missing";
|
||||
}
|
||||
|
||||
if (err == NULL && ek_opt == ek_orig) {
|
||||
switch (ek_opt) {
|
||||
case _adapter_prim_to_prim:
|
||||
case _adapter_ref_to_prim:
|
||||
case _adapter_prim_to_ref:
|
||||
case _adapter_swap_args:
|
||||
case _adapter_rot_args:
|
||||
case _adapter_collect_args:
|
||||
case _adapter_fold_args:
|
||||
case _adapter_spread_args:
|
||||
// should be handled completely by optimized cases; see above
|
||||
err = "init_AdapterMethodHandle should not issue this";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (err != NULL) {
|
||||
throw_InternalError_for_bad_conversion(conversion, err, THREAD);
|
||||
return;
|
||||
|
||||
@ -698,6 +698,8 @@ class MethodHandles: AllStatic {
|
||||
KlassHandle receiver_klass,
|
||||
TRAPS);
|
||||
|
||||
public:
|
||||
static bool is_float_fixed_reinterpretation_cast(BasicType src, BasicType dst);
|
||||
static bool same_basic_type_for_arguments(BasicType src, BasicType dst,
|
||||
bool raw = false,
|
||||
bool for_return = false);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user