This commit is contained in:
Tom Rodriguez 2011-05-06 19:34:55 -07:00
commit 9b9953cb0b
32 changed files with 3080 additions and 662 deletions

View File

@ -234,6 +234,20 @@ class Address VALUE_OBJ_CLASS_SPEC {
a._disp += disp;
return a;
}
Address plus_disp(RegisterOrConstant disp, ScaleFactor scale = times_1) const {
Address a = (*this);
a._disp += disp.constant_or_zero() * scale_size(scale);
if (disp.is_register()) {
assert(!a.index()->is_valid(), "competing indexes");
a._index = disp.as_register();
a._scale = scale;
}
return a;
}
bool is_same_address(Address a) const {
// disregard _rspec
return _base == a._base && _disp == a._disp && _index == a._index && _scale == a._scale;
}
// The following two overloads are used in connection with the
// ByteSize type (see sizes.hpp). They simplify the use of
@ -2029,6 +2043,10 @@ class MacroAssembler: public Assembler {
void addptr(Register dst, Address src) { LP64_ONLY(addq(dst, src)) NOT_LP64(addl(dst, src)); }
void addptr(Register dst, int32_t src);
void addptr(Register dst, Register src);
void addptr(Register dst, RegisterOrConstant src) {
if (src.is_constant()) addptr(dst, (int) src.as_constant());
else addptr(dst, src.as_register());
}
void andptr(Register dst, int32_t src);
void andptr(Register src1, Register src2) { LP64_ONLY(andq(src1, src2)) NOT_LP64(andl(src1, src2)) ; }
@ -2090,7 +2108,10 @@ class MacroAssembler: public Assembler {
void subptr(Register dst, Address src) { LP64_ONLY(subq(dst, src)) NOT_LP64(subl(dst, src)); }
void subptr(Register dst, int32_t src);
void subptr(Register dst, Register src);
void subptr(Register dst, RegisterOrConstant src) {
if (src.is_constant()) subptr(dst, (int) src.as_constant());
else subptr(dst, src.as_register());
}
void sbbptr(Address dst, int32_t src) { LP64_ONLY(sbbq(dst, src)) NOT_LP64(sbbl(dst, src)); }
void sbbptr(Register dst, int32_t src) { LP64_ONLY(sbbq(dst, src)) NOT_LP64(sbbl(dst, src)); }
@ -2288,6 +2309,11 @@ public:
void movptr(Address dst, Register src);
void movptr(Register dst, RegisterOrConstant src) {
if (src.is_constant()) movptr(dst, src.as_constant());
else movptr(dst, src.as_register());
}
#ifdef _LP64
// Generally the next two are only used for moving NULL
// Although there are situations in initializing the mark word where

View File

@ -339,7 +339,6 @@ frame frame::sender_for_entry_frame(RegisterMap* map) const {
return fr;
}
//------------------------------------------------------------------------------
// frame::verify_deopt_original_pc
//
@ -361,6 +360,55 @@ void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool
}
#endif
//------------------------------------------------------------------------------
// frame::adjust_unextended_sp
void frame::adjust_unextended_sp() {
// If we are returning to a compiled MethodHandle call site, the
// saved_fp will in fact be a saved value of the unextended SP. The
// simplest way to tell whether we are returning to such a call site
// is as follows:
nmethod* sender_nm = (_cb == NULL) ? NULL : _cb->as_nmethod_or_null();
if (sender_nm != NULL) {
// If the sender PC is a deoptimization point, get the original
// PC. For MethodHandle call site the unextended_sp is stored in
// saved_fp.
if (sender_nm->is_deopt_mh_entry(_pc)) {
DEBUG_ONLY(verify_deopt_mh_original_pc(sender_nm, _fp));
_unextended_sp = _fp;
}
else if (sender_nm->is_deopt_entry(_pc)) {
DEBUG_ONLY(verify_deopt_original_pc(sender_nm, _unextended_sp));
}
else if (sender_nm->is_method_handle_return(_pc)) {
_unextended_sp = _fp;
}
}
}
//------------------------------------------------------------------------------
// frame::update_map_with_saved_link
void frame::update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr) {
// The interpreter and compiler(s) always save EBP/RBP in a known
// location on entry. We must record where that location is
// so this if EBP/RBP was live on callout from c2 we can find
// the saved copy no matter what it called.
// Since the interpreter always saves EBP/RBP if we record where it is then
// we don't have to always save EBP/RBP on entry and exit to c2 compiled
// code, on entry will be enough.
map->set_location(rbp->as_VMReg(), (address) link_addr);
#ifdef AMD64
// this is weird "H" ought to be at a higher address however the
// oopMaps seems to have the "H" regs at the same address and the
// vanilla register.
// XXXX make this go away
if (true) {
map->set_location(rbp->as_VMReg()->next(), (address) link_addr);
}
#endif // AMD64
}
//------------------------------------------------------------------------------
// frame::sender_for_interpreter_frame
@ -372,54 +420,13 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
// This is the sp before any possible extension (adapter/locals).
intptr_t* unextended_sp = interpreter_frame_sender_sp();
// Stored FP.
intptr_t* saved_fp = link();
address sender_pc = this->sender_pc();
CodeBlob* sender_cb = CodeCache::find_blob_unsafe(sender_pc);
assert(sender_cb, "sanity");
nmethod* sender_nm = sender_cb->as_nmethod_or_null();
if (sender_nm != NULL) {
// If the sender PC is a deoptimization point, get the original
// PC. For MethodHandle call site the unextended_sp is stored in
// saved_fp.
if (sender_nm->is_deopt_mh_entry(sender_pc)) {
DEBUG_ONLY(verify_deopt_mh_original_pc(sender_nm, saved_fp));
unextended_sp = saved_fp;
}
else if (sender_nm->is_deopt_entry(sender_pc)) {
DEBUG_ONLY(verify_deopt_original_pc(sender_nm, unextended_sp));
}
else if (sender_nm->is_method_handle_return(sender_pc)) {
unextended_sp = saved_fp;
}
}
// The interpreter and compiler(s) always save EBP/RBP in a known
// location on entry. We must record where that location is
// so this if EBP/RBP was live on callout from c2 we can find
// the saved copy no matter what it called.
// Since the interpreter always saves EBP/RBP if we record where it is then
// we don't have to always save EBP/RBP on entry and exit to c2 compiled
// code, on entry will be enough.
#ifdef COMPILER2
if (map->update_map()) {
map->set_location(rbp->as_VMReg(), (address) addr_at(link_offset));
#ifdef AMD64
// this is weird "H" ought to be at a higher address however the
// oopMaps seems to have the "H" regs at the same address and the
// vanilla register.
// XXXX make this go away
if (true) {
map->set_location(rbp->as_VMReg()->next(), (address)addr_at(link_offset));
}
#endif // AMD64
update_map_with_saved_link(map, (intptr_t**) addr_at(link_offset));
}
#endif // COMPILER2
return frame(sender_sp, unextended_sp, saved_fp, sender_pc);
return frame(sender_sp, unextended_sp, link(), sender_pc());
}
@ -427,6 +434,7 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
// frame::sender_for_compiled_frame
frame frame::sender_for_compiled_frame(RegisterMap* map) const {
assert(map != NULL, "map must be set");
assert(!is_ricochet_frame(), "caller must handle this");
// frame owned by optimizing compiler
assert(_cb->frame_size() >= 0, "must have non-zero frame size");
@ -438,31 +446,7 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const {
// This is the saved value of EBP which may or may not really be an FP.
// It is only an FP if the sender is an interpreter frame (or C1?).
intptr_t* saved_fp = (intptr_t*) *(sender_sp - frame::sender_sp_offset);
// If we are returning to a compiled MethodHandle call site, the
// saved_fp will in fact be a saved value of the unextended SP. The
// simplest way to tell whether we are returning to such a call site
// is as follows:
CodeBlob* sender_cb = CodeCache::find_blob_unsafe(sender_pc);
assert(sender_cb, "sanity");
nmethod* sender_nm = sender_cb->as_nmethod_or_null();
if (sender_nm != NULL) {
// If the sender PC is a deoptimization point, get the original
// PC. For MethodHandle call site the unextended_sp is stored in
// saved_fp.
if (sender_nm->is_deopt_mh_entry(sender_pc)) {
DEBUG_ONLY(verify_deopt_mh_original_pc(sender_nm, saved_fp));
unextended_sp = saved_fp;
}
else if (sender_nm->is_deopt_entry(sender_pc)) {
DEBUG_ONLY(verify_deopt_original_pc(sender_nm, unextended_sp));
}
else if (sender_nm->is_method_handle_return(sender_pc)) {
unextended_sp = saved_fp;
}
}
intptr_t** saved_fp_addr = (intptr_t**) (sender_sp - frame::sender_sp_offset);
if (map->update_map()) {
// Tell GC to use argument oopmaps for some runtime stubs that need it.
@ -472,23 +456,15 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const {
if (_cb->oop_maps() != NULL) {
OopMapSet::update_register_map(this, map);
}
// Since the prolog does the save and restore of EBP there is no oopmap
// for it so we must fill in its location as if there was an oopmap entry
// since if our caller was compiled code there could be live jvm state in it.
map->set_location(rbp->as_VMReg(), (address) (sender_sp - frame::sender_sp_offset));
#ifdef AMD64
// this is weird "H" ought to be at a higher address however the
// oopMaps seems to have the "H" regs at the same address and the
// vanilla register.
// XXXX make this go away
if (true) {
map->set_location(rbp->as_VMReg()->next(), (address) (sender_sp - frame::sender_sp_offset));
}
#endif // AMD64
update_map_with_saved_link(map, saved_fp_addr);
}
assert(sender_sp != sp(), "must have changed");
return frame(sender_sp, unextended_sp, saved_fp, sender_pc);
return frame(sender_sp, unextended_sp, *saved_fp_addr, sender_pc);
}
@ -502,6 +478,7 @@ frame frame::sender(RegisterMap* map) const {
if (is_entry_frame()) return sender_for_entry_frame(map);
if (is_interpreted_frame()) return sender_for_interpreter_frame(map);
assert(_cb == CodeCache::find_blob(pc()),"Must be the same");
if (is_ricochet_frame()) return sender_for_ricochet_frame(map);
if (_cb != NULL) {
return sender_for_compiled_frame(map);

View File

@ -164,6 +164,7 @@
// original sp we use that convention.
intptr_t* _unextended_sp;
void adjust_unextended_sp();
intptr_t* ptr_at_addr(int offset) const {
return (intptr_t*) addr_at(offset);
@ -197,6 +198,9 @@
// expression stack tos if we are nested in a java call
intptr_t* interpreter_frame_last_sp() const;
// helper to update a map with callee-saved RBP
static void update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr);
#ifndef CC_INTERP
// deoptimization support
void interpreter_frame_set_last_sp(intptr_t* sp);

View File

@ -62,6 +62,7 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address
_pc = pc;
assert(pc != NULL, "no pc?");
_cb = CodeCache::find_blob(pc);
adjust_unextended_sp();
address original_pc = nmethod::get_deopt_original_pc(this);
if (original_pc != NULL) {

View File

@ -26,7 +26,9 @@
#define CPU_X86_VM_INTERPRETER_X86_HPP
public:
static Address::ScaleFactor stackElementScale() { return Address::times_4; }
static Address::ScaleFactor stackElementScale() {
return NOT_LP64(Address::times_4) LP64_ONLY(Address::times_8);
}
// Offset from rsp (which points to the last stack element)
static int expr_offset_in_bytes(int i) { return stackElementSize * i; }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,292 @@
/*
* Copyright (c) 2010, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
// Platform-specific definitions for method handles.
// These definitions are inlined into class MethodHandles.
public:
// The stack just after the recursive call from a ricochet frame
// looks something like this. Offsets are marked in words, not bytes.
// rsi (r13 on LP64) is part of the interpreter calling sequence
// which tells the callee where is my real rsp (for frame walking).
// (...lower memory addresses)
// rsp: [ return pc ] always the global RicochetBlob::bounce_addr
// rsp+1: [ recursive arg N ]
// rsp+2: [ recursive arg N-1 ]
// ...
// rsp+N: [ recursive arg 1 ]
// rsp+N+1: [ recursive method handle ]
// ...
// rbp-6: [ cleanup continuation pc ] <-- (struct RicochetFrame)
// rbp-5: [ saved target MH ] the MH we will call on the saved args
// rbp-4: [ saved args layout oop ] an int[] array which describes argument layout
// rbp-3: [ saved args pointer ] address of transformed adapter arg M (slot 0)
// rbp-2: [ conversion ] information about how the return value is used
// rbp-1: [ exact sender sp ] exact TOS (rsi/r13) of original sender frame
// rbp+0: [ saved sender fp ] (for original sender of AMH)
// rbp+1: [ saved sender pc ] (back to original sender of AMH)
// rbp+2: [ transformed adapter arg M ] <-- (extended TOS of original sender)
// rbp+3: [ transformed adapter arg M-1]
// ...
// rbp+M+1: [ transformed adapter arg 1 ]
// rbp+M+2: [ padding ] <-- (rbp + saved args base offset)
// ... [ optional padding]
// (higher memory addresses...)
//
// The arguments originally passed by the original sender
// are lost, and arbitrary amounts of stack motion might have
// happened due to argument transformation.
// (This is done by C2I/I2C adapters and non-direct method handles.)
// This is why there is an unpredictable amount of memory between
// the extended and exact TOS of the sender.
// The ricochet adapter itself will also (in general) perform
// transformations before the recursive call.
//
// The transformed and saved arguments, immediately above the saved
// return PC, are a well-formed method handle invocation ready to execute.
// When the GC needs to walk the stack, these arguments are described
// via the saved arg types oop, an int[] array with a private format.
// This array is derived from the type of the transformed adapter
// method handle, which also sits at the base of the saved argument
// bundle. Since the GC may not be able to fish out the int[]
// array, so it is pushed explicitly on the stack. This may be
// an unnecessary expense.
//
// The following register conventions are significant at this point:
// rsp the thread stack, as always; preserved by caller
// rsi/r13 exact TOS of recursive frame (contents of [rbp-2])
// rcx recursive method handle (contents of [rsp+N+1])
// rbp preserved by caller (not used by caller)
// Unless otherwise specified, all registers can be blown by the call.
//
// If this frame must be walked, the transformed adapter arguments
// will be found with the help of the saved arguments descriptor.
//
// Therefore, the descriptor must match the referenced arguments.
// The arguments must be followed by at least one word of padding,
// which will be necessary to complete the final method handle call.
// That word is not treated as holding an oop. Neither is the word
//
// The word pointed to by the return argument pointer is not
// treated as an oop, even if points to a saved argument.
// This allows the saved argument list to have a "hole" in it
// to receive an oop from the recursive call.
// (The hole might temporarily contain RETURN_VALUE_PLACEHOLDER.)
//
// When the recursive callee returns, RicochetBlob::bounce_addr will
// immediately jump to the continuation stored in the RF.
// This continuation will merge the recursive return value
// into the saved argument list. At that point, the original
// rsi, rbp, and rsp will be reloaded, the ricochet frame will
// disappear, and the final target of the adapter method handle
// will be invoked on the transformed argument list.
class RicochetFrame {
friend class MethodHandles;
private:
intptr_t* _continuation; // what to do when control gets back here
oopDesc* _saved_target; // target method handle to invoke on saved_args
oopDesc* _saved_args_layout; // caching point for MethodTypeForm.vmlayout cookie
intptr_t* _saved_args_base; // base of pushed arguments (slot 0, arg N) (-3)
intptr_t _conversion; // misc. information from original AdapterMethodHandle (-2)
intptr_t* _exact_sender_sp; // parallel to interpreter_frame_sender_sp (-1)
intptr_t* _sender_link; // *must* coincide with frame::link_offset (0)
address _sender_pc; // *must* coincide with frame::return_addr_offset (1)
public:
intptr_t* continuation() const { return _continuation; }
oop saved_target() const { return _saved_target; }
oop saved_args_layout() const { return _saved_args_layout; }
intptr_t* saved_args_base() const { return _saved_args_base; }
intptr_t conversion() const { return _conversion; }
intptr_t* exact_sender_sp() const { return _exact_sender_sp; }
intptr_t* sender_link() const { return _sender_link; }
address sender_pc() const { return _sender_pc; }
intptr_t* extended_sender_sp() const { return saved_args_base(); }
intptr_t return_value_slot_number() const {
return adapter_conversion_vminfo(conversion());
}
BasicType return_value_type() const {
return adapter_conversion_dest_type(conversion());
}
bool has_return_value_slot() const {
return return_value_type() != T_VOID;
}
intptr_t* return_value_slot_addr() const {
assert(has_return_value_slot(), "");
return saved_arg_slot_addr(return_value_slot_number());
}
intptr_t* saved_target_slot_addr() const {
return saved_arg_slot_addr(saved_args_length());
}
intptr_t* saved_arg_slot_addr(int slot) const {
assert(slot >= 0, "");
return (intptr_t*)( (address)saved_args_base() + (slot * Interpreter::stackElementSize) );
}
jint saved_args_length() const;
jint saved_arg_offset(int arg) const;
// GC interface
oop* saved_target_addr() { return (oop*)&_saved_target; }
oop* saved_args_layout_addr() { return (oop*)&_saved_args_layout; }
oop compute_saved_args_layout(bool read_cache, bool write_cache);
// Compiler/assembler interface.
static int continuation_offset_in_bytes() { return offset_of(RicochetFrame, _continuation); }
static int saved_target_offset_in_bytes() { return offset_of(RicochetFrame, _saved_target); }
static int saved_args_layout_offset_in_bytes(){ return offset_of(RicochetFrame, _saved_args_layout); }
static int saved_args_base_offset_in_bytes() { return offset_of(RicochetFrame, _saved_args_base); }
static int conversion_offset_in_bytes() { return offset_of(RicochetFrame, _conversion); }
static int exact_sender_sp_offset_in_bytes() { return offset_of(RicochetFrame, _exact_sender_sp); }
static int sender_link_offset_in_bytes() { return offset_of(RicochetFrame, _sender_link); }
static int sender_pc_offset_in_bytes() { return offset_of(RicochetFrame, _sender_pc); }
// This value is not used for much, but it apparently must be nonzero.
static int frame_size_in_bytes() { return sender_link_offset_in_bytes(); }
#ifdef ASSERT
// The magic number is supposed to help find ricochet frames within the bytes of stack dumps.
enum { MAGIC_NUMBER_1 = 0xFEED03E, MAGIC_NUMBER_2 = 0xBEEF03E };
static int magic_number_1_offset_in_bytes() { return -wordSize; }
static int magic_number_2_offset_in_bytes() { return sizeof(RicochetFrame); }
intptr_t magic_number_1() const { return *(intptr_t*)((address)this + magic_number_1_offset_in_bytes()); };
intptr_t magic_number_2() const { return *(intptr_t*)((address)this + magic_number_2_offset_in_bytes()); };
#endif //ASSERT
enum { RETURN_VALUE_PLACEHOLDER = (NOT_DEBUG(0) DEBUG_ONLY(42)) };
static void verify_offsets() NOT_DEBUG_RETURN;
void verify() const NOT_DEBUG_RETURN; // check for MAGIC_NUMBER, etc.
void zap_arguments() NOT_DEBUG_RETURN;
static void generate_ricochet_blob(MacroAssembler* _masm,
// output params:
int* frame_size_in_words, int* bounce_offset, int* exception_offset);
static void enter_ricochet_frame(MacroAssembler* _masm,
Register rcx_recv,
Register rax_argv,
address return_handler,
Register rbx_temp);
static void leave_ricochet_frame(MacroAssembler* _masm,
Register rcx_recv,
Register new_sp_reg,
Register sender_pc_reg);
static Address frame_address(int offset = 0) {
// The RicochetFrame is found by subtracting a constant offset from rbp.
return Address(rbp, - sender_link_offset_in_bytes() + offset);
}
static RicochetFrame* from_frame(const frame& fr) {
address bp = (address) fr.fp();
RicochetFrame* rf = (RicochetFrame*)(bp - sender_link_offset_in_bytes());
rf->verify();
return rf;
}
static void verify_clean(MacroAssembler* _masm) NOT_DEBUG_RETURN;
};
// Additional helper methods for MethodHandles code generation:
public:
static void load_klass_from_Class(MacroAssembler* _masm, Register klass_reg);
static void load_conversion_vminfo(MacroAssembler* _masm, Register reg, Address conversion_field_addr);
static void load_conversion_dest_type(MacroAssembler* _masm, Register reg, Address conversion_field_addr);
static void load_stack_move(MacroAssembler* _masm,
Register rdi_stack_move,
Register rcx_amh,
bool might_be_negative);
static void insert_arg_slots(MacroAssembler* _masm,
RegisterOrConstant arg_slots,
Register rax_argslot,
Register rbx_temp, Register rdx_temp);
static void remove_arg_slots(MacroAssembler* _masm,
RegisterOrConstant arg_slots,
Register rax_argslot,
Register rbx_temp, Register rdx_temp);
static void push_arg_slots(MacroAssembler* _masm,
Register rax_argslot,
RegisterOrConstant slot_count,
int skip_words_count,
Register rbx_temp, Register rdx_temp);
static void move_arg_slots_up(MacroAssembler* _masm,
Register rbx_bottom, // invariant
Address top_addr, // can use rax_temp
RegisterOrConstant positive_distance_in_slots,
Register rax_temp, Register rdx_temp);
static void move_arg_slots_down(MacroAssembler* _masm,
Address bottom_addr, // can use rax_temp
Register rbx_top, // invariant
RegisterOrConstant negative_distance_in_slots,
Register rax_temp, Register rdx_temp);
static void move_typed_arg(MacroAssembler* _masm,
BasicType type, bool is_element,
Address slot_dest, Address value_src,
Register rbx_temp, Register rdx_temp);
static void move_return_value(MacroAssembler* _masm, BasicType type,
Address return_slot);
static void verify_argslot(MacroAssembler* _masm, Register argslot_reg,
const char* error_message) NOT_DEBUG_RETURN;
static void verify_argslots(MacroAssembler* _masm,
RegisterOrConstant argslot_count,
Register argslot_reg,
bool negate_argslot,
const char* error_message) NOT_DEBUG_RETURN;
static void verify_stack_move(MacroAssembler* _masm,
RegisterOrConstant arg_slots,
int direction) NOT_DEBUG_RETURN;
static void verify_klass(MacroAssembler* _masm,
Register obj, KlassHandle klass,
const char* error_message = "wrong klass") NOT_DEBUG_RETURN;
static void verify_method_handle(MacroAssembler* _masm, Register mh_reg) {
verify_klass(_masm, mh_reg, SystemDictionaryHandles::MethodHandle_klass(),
"reference is a MH");
}
static void trace_method_handle(MacroAssembler* _masm, const char* adaptername) PRODUCT_RETURN;
static Register saved_last_sp_register() {
// Should be in sharedRuntime, not here.
return LP64_ONLY(r13) NOT_LP64(rsi);
}

View File

@ -2253,6 +2253,31 @@ uint SharedRuntime::out_preserve_stack_slots() {
return 0;
}
//----------------------------generate_ricochet_blob---------------------------
void SharedRuntime::generate_ricochet_blob() {
if (!EnableInvokeDynamic) return; // leave it as a null
// allocate space for the code
ResourceMark rm;
// setup code generation tools
CodeBuffer buffer("ricochet_blob", 256, 256);
MacroAssembler* masm = new MacroAssembler(&buffer);
int frame_size_in_words = -1, bounce_offset = -1, exception_offset = -1;
MethodHandles::RicochetFrame::generate_ricochet_blob(masm, &frame_size_in_words, &bounce_offset, &exception_offset);
// -------------
// make sure all code is generated
masm->flush();
// failed to generate?
if (frame_size_in_words < 0 || bounce_offset < 0 || exception_offset < 0) {
assert(false, "bad ricochet blob");
return;
}
_ricochet_blob = RicochetBlob::create(&buffer, bounce_offset, exception_offset, frame_size_in_words);
}
//------------------------------generate_deopt_blob----------------------------
void SharedRuntime::generate_deopt_blob() {
@ -2996,6 +3021,8 @@ void SharedRuntime::generate_stubs() {
generate_handler_blob(CAST_FROM_FN_PTR(address,
SafepointSynchronize::handle_polling_page_exception), true);
generate_ricochet_blob();
generate_deopt_blob();
#ifdef COMPILER2
generate_uncommon_trap_blob();

View File

@ -2530,6 +2530,32 @@ uint SharedRuntime::out_preserve_stack_slots() {
}
//----------------------------generate_ricochet_blob---------------------------
void SharedRuntime::generate_ricochet_blob() {
if (!EnableInvokeDynamic) return; // leave it as a null
// allocate space for the code
ResourceMark rm;
// setup code generation tools
CodeBuffer buffer("ricochet_blob", 512, 512);
MacroAssembler* masm = new MacroAssembler(&buffer);
int frame_size_in_words = -1, bounce_offset = -1, exception_offset = -1;
MethodHandles::RicochetFrame::generate_ricochet_blob(masm, &frame_size_in_words, &bounce_offset, &exception_offset);
// -------------
// make sure all code is generated
masm->flush();
// failed to generate?
if (frame_size_in_words < 0 || bounce_offset < 0 || exception_offset < 0) {
assert(false, "bad ricochet blob");
return;
}
_ricochet_blob = RicochetBlob::create(&buffer, bounce_offset, exception_offset, frame_size_in_words);
}
//------------------------------generate_deopt_blob----------------------------
void SharedRuntime::generate_deopt_blob() {
// Allocate space for the code
@ -3205,6 +3231,8 @@ void SharedRuntime::generate_stubs() {
generate_handler_blob(CAST_FROM_FN_PTR(address,
SafepointSynchronize::handle_polling_page_exception), true);
generate_ricochet_blob();
generate_deopt_blob();
#ifdef COMPILER2

View File

@ -36,7 +36,7 @@ enum platform_dependent_constants {
// MethodHandles adapters
enum method_handles_platform_dependent_constants {
method_handles_adapters_code_size = 10000
method_handles_adapters_code_size = 30000 DEBUG_ONLY(+ 10000)
};
class x86 {

View File

@ -38,7 +38,7 @@ enum platform_dependent_constants {
// MethodHandles adapters
enum method_handles_platform_dependent_constants {
method_handles_adapters_code_size = 40000
method_handles_adapters_code_size = 80000 DEBUG_ONLY(+ 120000)
};
class x86 {

View File

@ -132,17 +132,22 @@ void InstructionPrinter::print_object(Value obj) {
if (value->is_null_object()) {
output()->print("null");
} else if (!value->is_loaded()) {
output()->print("<unloaded object 0x%x>", value);
output()->print("<unloaded object " PTR_FORMAT ">", value);
} else if (value->is_method()) {
ciMethod* m = (ciMethod*)value;
output()->print("<method %s.%s>", m->holder()->name()->as_utf8(), m->name()->as_utf8());
} else {
output()->print("<object 0x%x>", value->constant_encoding());
output()->print("<object " PTR_FORMAT ">", value->constant_encoding());
}
} else if (type->as_InstanceConstant() != NULL) {
output()->print("<instance 0x%x>", type->as_InstanceConstant()->value()->constant_encoding());
ciInstance* value = type->as_InstanceConstant()->value();
if (value->is_loaded()) {
output()->print("<instance " PTR_FORMAT ">", value->constant_encoding());
} else {
output()->print("<unloaded instance " PTR_FORMAT ">", value);
}
} else if (type->as_ArrayConstant() != NULL) {
output()->print("<array 0x%x>", type->as_ArrayConstant()->value()->constant_encoding());
output()->print("<array " PTR_FORMAT ">", type->as_ArrayConstant()->value()->constant_encoding());
} else if (type->as_ClassConstant() != NULL) {
ciInstanceKlass* klass = type->as_ClassConstant()->value();
if (!klass->is_loaded()) {

View File

@ -252,26 +252,28 @@ Value CE_Eliminator::make_ifop(Value x, Instruction::Condition cond, Value y, Va
Constant::CompareResult t_compare_res = x_tval_const->compare(cond, y_const);
Constant::CompareResult f_compare_res = x_fval_const->compare(cond, y_const);
guarantee(t_compare_res != Constant::not_comparable && f_compare_res != Constant::not_comparable, "incomparable constants in IfOp");
// not_comparable here is a valid return in case we're comparing unloaded oop constants
if (t_compare_res != Constant::not_comparable && f_compare_res != Constant::not_comparable) {
Value new_tval = t_compare_res == Constant::cond_true ? tval : fval;
Value new_fval = f_compare_res == Constant::cond_true ? tval : fval;
Value new_tval = t_compare_res == Constant::cond_true ? tval : fval;
Value new_fval = f_compare_res == Constant::cond_true ? tval : fval;
_ifop_count++;
if (new_tval == new_fval) {
return new_tval;
} else {
return new IfOp(x_ifop->x(), x_ifop_cond, x_ifop->y(), new_tval, new_fval);
_ifop_count++;
if (new_tval == new_fval) {
return new_tval;
} else {
return new IfOp(x_ifop->x(), x_ifop_cond, x_ifop->y(), new_tval, new_fval);
}
}
}
} else {
Constant* x_const = x->as_Constant();
if (x_const != NULL) { // x and y are constants
Constant::CompareResult x_compare_res = x_const->compare(cond, y_const);
guarantee(x_compare_res != Constant::not_comparable, "incomparable constants in IfOp");
_ifop_count++;
return x_compare_res == Constant::cond_true ? tval : fval;
// not_comparable here is a valid return in case we're comparing unloaded oop constants
if (x_compare_res != Constant::not_comparable) {
_ifop_count++;
return x_compare_res == Constant::cond_true ? tval : fval;
}
}
}
}

View File

@ -2602,6 +2602,7 @@ int java_lang_invoke_MethodType::ptype_count(oop mt) {
// Support for java_lang_invoke_MethodTypeForm
int java_lang_invoke_MethodTypeForm::_vmslots_offset;
int java_lang_invoke_MethodTypeForm::_vmlayout_offset;
int java_lang_invoke_MethodTypeForm::_erasedType_offset;
int java_lang_invoke_MethodTypeForm::_genericInvoker_offset;
@ -2609,6 +2610,7 @@ void java_lang_invoke_MethodTypeForm::compute_offsets() {
klassOop k = SystemDictionary::MethodTypeForm_klass();
if (k != NULL) {
compute_optional_offset(_vmslots_offset, k, vmSymbols::vmslots_name(), vmSymbols::int_signature(), true);
compute_optional_offset(_vmlayout_offset, k, vmSymbols::vmlayout_name(), vmSymbols::object_signature());
compute_optional_offset(_erasedType_offset, k, vmSymbols::erasedType_name(), vmSymbols::java_lang_invoke_MethodType_signature(), true);
compute_optional_offset(_genericInvoker_offset, k, vmSymbols::genericInvoker_name(), vmSymbols::java_lang_invoke_MethodHandle_signature(), true);
if (_genericInvoker_offset == 0) _genericInvoker_offset = -1; // set to explicit "empty" value
@ -2617,9 +2619,31 @@ void java_lang_invoke_MethodTypeForm::compute_offsets() {
int java_lang_invoke_MethodTypeForm::vmslots(oop mtform) {
assert(mtform->klass() == SystemDictionary::MethodTypeForm_klass(), "MTForm only");
assert(_vmslots_offset > 0, "");
return mtform->int_field(_vmslots_offset);
}
oop java_lang_invoke_MethodTypeForm::vmlayout(oop mtform) {
assert(mtform->klass() == SystemDictionary::MethodTypeForm_klass(), "MTForm only");
assert(_vmlayout_offset > 0, "");
return mtform->obj_field(_vmlayout_offset);
}
oop java_lang_invoke_MethodTypeForm::init_vmlayout(oop mtform, oop cookie) {
assert(mtform->klass() == SystemDictionary::MethodTypeForm_klass(), "MTForm only");
oop previous = vmlayout(mtform);
if (previous != NULL) {
return previous; // someone else beat us to it
}
HeapWord* cookie_addr = (HeapWord*) mtform->obj_field_addr<oop>(_vmlayout_offset);
OrderAccess::storestore(); // make sure our copy is fully committed
previous = oopDesc::atomic_compare_exchange_oop(cookie, cookie_addr, previous);
if (previous != NULL) {
return previous; // someone else beat us to it
}
return cookie;
}
oop java_lang_invoke_MethodTypeForm::erasedType(oop mtform) {
assert(mtform->klass() == SystemDictionary::MethodTypeForm_klass(), "MTForm only");
return mtform->obj_field(_erasedType_offset);

View File

@ -949,18 +949,19 @@ class java_lang_invoke_AdapterMethodHandle: public java_lang_invoke_BoundMethodH
OP_CHECK_CAST = 0x2, // ref-to-ref conversion; requires a Class argument
OP_PRIM_TO_PRIM = 0x3, // converts from one primitive to another
OP_REF_TO_PRIM = 0x4, // unboxes a wrapper to produce a primitive
OP_PRIM_TO_REF = 0x5, // boxes a primitive into a wrapper (NYI)
OP_PRIM_TO_REF = 0x5, // boxes a primitive into a wrapper
OP_SWAP_ARGS = 0x6, // swap arguments (vminfo is 2nd arg)
OP_ROT_ARGS = 0x7, // rotate arguments (vminfo is displaced arg)
OP_DUP_ARGS = 0x8, // duplicates one or more arguments (at TOS)
OP_DROP_ARGS = 0x9, // remove one or more argument slots
OP_COLLECT_ARGS = 0xA, // combine one or more arguments into a varargs (NYI)
OP_COLLECT_ARGS = 0xA, // combine arguments using an auxiliary function
OP_SPREAD_ARGS = 0xB, // expand in place a varargs array (of known size)
OP_FLYBY = 0xC, // operate first on reified argument list (NYI)
OP_RICOCHET = 0xD, // run an adapter chain on the return value (NYI)
OP_FOLD_ARGS = 0xC, // combine but do not remove arguments; prepend result
//OP_UNUSED_13 = 0xD, // unused code, perhaps for reified argument lists
CONV_OP_LIMIT = 0xE, // limit of CONV_OP enumeration
CONV_OP_MASK = 0xF00, // this nybble contains the conversion op field
CONV_TYPE_MASK = 0x0F, // fits T_ADDRESS and below
CONV_VMINFO_MASK = 0x0FF, // LSB is reserved for JVM use
CONV_VMINFO_SHIFT = 0, // position of bits in CONV_VMINFO_MASK
CONV_OP_SHIFT = 8, // position of bits in CONV_OP_MASK
@ -1089,6 +1090,7 @@ class java_lang_invoke_MethodTypeForm: AllStatic {
private:
static int _vmslots_offset; // number of argument slots needed
static int _vmlayout_offset; // object describing internal calling sequence
static int _erasedType_offset; // erasedType = canonical MethodType
static int _genericInvoker_offset; // genericInvoker = adapter for invokeGeneric
@ -1100,8 +1102,12 @@ class java_lang_invoke_MethodTypeForm: AllStatic {
static oop erasedType(oop mtform);
static oop genericInvoker(oop mtform);
static oop vmlayout(oop mtform);
static oop init_vmlayout(oop mtform, oop cookie);
// Accessors for code generation:
static int vmslots_offset_in_bytes() { return _vmslots_offset; }
static int vmlayout_offset_in_bytes() { return _vmlayout_offset; }
static int erasedType_offset_in_bytes() { return _erasedType_offset; }
static int genericInvoker_offset_in_bytes() { return _genericInvoker_offset; }
};

View File

@ -2362,8 +2362,15 @@ methodOop SystemDictionary::find_method_handle_invoke(Symbol* name,
spe = invoke_method_table()->find_entry(index, hash, signature, name_id);
if (spe == NULL)
spe = invoke_method_table()->add_entry(index, hash, signature, name_id);
if (spe->property_oop() == NULL)
if (spe->property_oop() == NULL) {
spe->set_property_oop(m());
// Link m to his method type, if it is suitably generic.
oop mtform = java_lang_invoke_MethodType::form(mt());
if (mtform != NULL && mt() == java_lang_invoke_MethodTypeForm::erasedType(mtform)
&& java_lang_invoke_MethodTypeForm::vmlayout_offset_in_bytes() > 0) {
java_lang_invoke_MethodTypeForm::init_vmlayout(mtform, m());
}
}
} else {
non_cached_result = m;
}

View File

@ -341,6 +341,7 @@
template(vmtarget_name, "vmtarget") \
template(vmentry_name, "vmentry") \
template(vmslots_name, "vmslots") \
template(vmlayout_name, "vmlayout") \
template(vmindex_name, "vmindex") \
template(vmargslot_name, "vmargslot") \
template(flags_name, "flags") \
@ -393,6 +394,7 @@
template(void_signature, "V") \
template(byte_array_signature, "[B") \
template(char_array_signature, "[C") \
template(int_array_signature, "[I") \
template(object_void_signature, "(Ljava/lang/Object;)V") \
template(object_int_signature, "(Ljava/lang/Object;)I") \
template(object_boolean_signature, "(Ljava/lang/Object;)Z") \

View File

@ -152,6 +152,32 @@ void CodeBlob::set_oop_maps(OopMapSet* p) {
}
void CodeBlob::trace_new_stub(CodeBlob* stub, const char* name1, const char* name2) {
// Do not hold the CodeCache lock during name formatting.
assert(!CodeCache_lock->owned_by_self(), "release CodeCache before registering the stub");
if (stub != NULL) {
char stub_id[256];
assert(strlen(name1) + strlen(name2) < sizeof(stub_id), "");
jio_snprintf(stub_id, sizeof(stub_id), "%s%s", name1, name2);
if (PrintStubCode) {
tty->print_cr("Decoding %s " INTPTR_FORMAT, stub_id, (intptr_t) stub);
Disassembler::decode(stub->code_begin(), stub->code_end());
}
Forte::register_stub(stub_id, stub->code_begin(), stub->code_end());
if (JvmtiExport::should_post_dynamic_code_generated()) {
const char* stub_name = name2;
if (name2[0] == '\0') stub_name = name1;
JvmtiExport::post_dynamic_code_generated(stub_name, stub->code_begin(), stub->code_end());
}
}
// Track memory usage statistic after releasing CodeCache_lock
MemoryService::track_code_cache_memory_usage();
}
void CodeBlob::flush() {
if (_oop_maps) {
FREE_C_HEAP_ARRAY(unsigned char, _oop_maps);
@ -312,23 +338,7 @@ RuntimeStub* RuntimeStub::new_runtime_stub(const char* stub_name,
stub = new (size) RuntimeStub(stub_name, cb, size, frame_complete, frame_size, oop_maps, caller_must_gc_arguments);
}
// Do not hold the CodeCache lock during name formatting.
if (stub != NULL) {
char stub_id[256];
jio_snprintf(stub_id, sizeof(stub_id), "RuntimeStub - %s", stub_name);
if (PrintStubCode) {
tty->print_cr("Decoding %s " INTPTR_FORMAT, stub_id, stub);
Disassembler::decode(stub->code_begin(), stub->code_end());
}
Forte::register_stub(stub_id, stub->code_begin(), stub->code_end());
if (JvmtiExport::should_post_dynamic_code_generated()) {
JvmtiExport::post_dynamic_code_generated(stub_name, stub->code_begin(), stub->code_end());
}
}
// Track memory usage statistic after releasing CodeCache_lock
MemoryService::track_code_cache_memory_usage();
trace_new_stub(stub, "RuntimeStub - ", stub_name);
return stub;
}
@ -340,6 +350,50 @@ void* RuntimeStub::operator new(size_t s, unsigned size) {
return p;
}
// operator new shared by all singletons:
void* SingletonBlob::operator new(size_t s, unsigned size) {
void* p = CodeCache::allocate(size);
if (!p) fatal("Initial size of CodeCache is too small");
return p;
}
//----------------------------------------------------------------------------------------------------
// Implementation of RicochetBlob
RicochetBlob::RicochetBlob(
CodeBuffer* cb,
int size,
int bounce_offset,
int exception_offset,
int frame_size
)
: SingletonBlob("RicochetBlob", cb, sizeof(RicochetBlob), size, frame_size, (OopMapSet*) NULL)
{
_bounce_offset = bounce_offset;
_exception_offset = exception_offset;
}
RicochetBlob* RicochetBlob::create(
CodeBuffer* cb,
int bounce_offset,
int exception_offset,
int frame_size)
{
RicochetBlob* blob = NULL;
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
unsigned int size = allocation_size(cb, sizeof(RicochetBlob));
blob = new (size) RicochetBlob(cb, size, bounce_offset, exception_offset, frame_size);
}
trace_new_stub(blob, "RicochetBlob");
return blob;
}
//----------------------------------------------------------------------------------------------------
// Implementation of DeoptimizationBlob
@ -386,34 +440,12 @@ DeoptimizationBlob* DeoptimizationBlob::create(
frame_size);
}
// Do not hold the CodeCache lock during name formatting.
if (blob != NULL) {
char blob_id[256];
jio_snprintf(blob_id, sizeof(blob_id), "DeoptimizationBlob@" PTR_FORMAT, blob->code_begin());
if (PrintStubCode) {
tty->print_cr("Decoding %s " INTPTR_FORMAT, blob_id, blob);
Disassembler::decode(blob->code_begin(), blob->code_end());
}
Forte::register_stub(blob_id, blob->code_begin(), blob->code_end());
if (JvmtiExport::should_post_dynamic_code_generated()) {
JvmtiExport::post_dynamic_code_generated("DeoptimizationBlob", blob->code_begin(), blob->code_end());
}
}
// Track memory usage statistic after releasing CodeCache_lock
MemoryService::track_code_cache_memory_usage();
trace_new_stub(blob, "DeoptimizationBlob");
return blob;
}
void* DeoptimizationBlob::operator new(size_t s, unsigned size) {
void* p = CodeCache::allocate(size);
if (!p) fatal("Initial size of CodeCache is too small");
return p;
}
//----------------------------------------------------------------------------------------------------
// Implementation of UncommonTrapBlob
@ -441,33 +473,12 @@ UncommonTrapBlob* UncommonTrapBlob::create(
blob = new (size) UncommonTrapBlob(cb, size, oop_maps, frame_size);
}
// Do not hold the CodeCache lock during name formatting.
if (blob != NULL) {
char blob_id[256];
jio_snprintf(blob_id, sizeof(blob_id), "UncommonTrapBlob@" PTR_FORMAT, blob->code_begin());
if (PrintStubCode) {
tty->print_cr("Decoding %s " INTPTR_FORMAT, blob_id, blob);
Disassembler::decode(blob->code_begin(), blob->code_end());
}
Forte::register_stub(blob_id, blob->code_begin(), blob->code_end());
if (JvmtiExport::should_post_dynamic_code_generated()) {
JvmtiExport::post_dynamic_code_generated("UncommonTrapBlob", blob->code_begin(), blob->code_end());
}
}
// Track memory usage statistic after releasing CodeCache_lock
MemoryService::track_code_cache_memory_usage();
trace_new_stub(blob, "UncommonTrapBlob");
return blob;
}
void* UncommonTrapBlob::operator new(size_t s, unsigned size) {
void* p = CodeCache::allocate(size);
if (!p) fatal("Initial size of CodeCache is too small");
return p;
}
#endif // COMPILER2
@ -498,33 +509,12 @@ ExceptionBlob* ExceptionBlob::create(
blob = new (size) ExceptionBlob(cb, size, oop_maps, frame_size);
}
// We do not need to hold the CodeCache lock during name formatting
if (blob != NULL) {
char blob_id[256];
jio_snprintf(blob_id, sizeof(blob_id), "ExceptionBlob@" PTR_FORMAT, blob->code_begin());
if (PrintStubCode) {
tty->print_cr("Decoding %s " INTPTR_FORMAT, blob_id, blob);
Disassembler::decode(blob->code_begin(), blob->code_end());
}
Forte::register_stub(blob_id, blob->code_begin(), blob->code_end());
if (JvmtiExport::should_post_dynamic_code_generated()) {
JvmtiExport::post_dynamic_code_generated("ExceptionBlob", blob->code_begin(), blob->code_end());
}
}
// Track memory usage statistic after releasing CodeCache_lock
MemoryService::track_code_cache_memory_usage();
trace_new_stub(blob, "ExceptionBlob");
return blob;
}
void* ExceptionBlob::operator new(size_t s, unsigned size) {
void* p = CodeCache::allocate(size);
if (!p) fatal("Initial size of CodeCache is too small");
return p;
}
#endif // COMPILER2
@ -554,35 +544,12 @@ SafepointBlob* SafepointBlob::create(
blob = new (size) SafepointBlob(cb, size, oop_maps, frame_size);
}
// We do not need to hold the CodeCache lock during name formatting.
if (blob != NULL) {
char blob_id[256];
jio_snprintf(blob_id, sizeof(blob_id), "SafepointBlob@" PTR_FORMAT, blob->code_begin());
if (PrintStubCode) {
tty->print_cr("Decoding %s " INTPTR_FORMAT, blob_id, blob);
Disassembler::decode(blob->code_begin(), blob->code_end());
}
Forte::register_stub(blob_id, blob->code_begin(), blob->code_end());
if (JvmtiExport::should_post_dynamic_code_generated()) {
JvmtiExport::post_dynamic_code_generated("SafepointBlob", blob->code_begin(), blob->code_end());
}
}
// Track memory usage statistic after releasing CodeCache_lock
MemoryService::track_code_cache_memory_usage();
trace_new_stub(blob, "SafepointBlob");
return blob;
}
void* SafepointBlob::operator new(size_t s, unsigned size) {
void* p = CodeCache::allocate(size);
if (!p) fatal("Initial size of CodeCache is too small");
return p;
}
//----------------------------------------------------------------------------------------------------
// Verification and printing

View File

@ -35,6 +35,7 @@
// Suptypes are:
// nmethod : Compiled Java methods (include method that calls to native code)
// RuntimeStub : Call to VM runtime methods
// RicochetBlob : Used for blocking MethodHandle adapters
// DeoptimizationBlob : Used for deoptimizatation
// ExceptionBlob : Used for stack unrolling
// SafepointBlob : Used to handle illegal instruction exceptions
@ -95,12 +96,13 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
void flush();
// Typing
virtual bool is_buffer_blob() const { return false; }
virtual bool is_nmethod() const { return false; }
virtual bool is_runtime_stub() const { return false; }
virtual bool is_deoptimization_stub() const { return false; }
virtual bool is_uncommon_trap_stub() const { return false; }
virtual bool is_exception_stub() const { return false; }
virtual bool is_buffer_blob() const { return false; }
virtual bool is_nmethod() const { return false; }
virtual bool is_runtime_stub() const { return false; }
virtual bool is_ricochet_stub() const { return false; }
virtual bool is_deoptimization_stub() const { return false; }
virtual bool is_uncommon_trap_stub() const { return false; }
virtual bool is_exception_stub() const { return false; }
virtual bool is_safepoint_stub() const { return false; }
virtual bool is_adapter_blob() const { return false; }
virtual bool is_method_handles_adapter_blob() const { return false; }
@ -182,6 +184,9 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
virtual void print_on(outputStream* st) const;
virtual void print_value_on(outputStream* st) const;
// Deal with Disassembler, VTune, Forte, JvmtiExport, MemoryService.
static void trace_new_stub(CodeBlob* blob, const char* name1, const char* name2 = "");
// Print the comment associated with offset on stream, if there is one
virtual void print_block_comment(outputStream* stream, address block_begin) {
intptr_t offset = (intptr_t)(block_begin - code_begin());
@ -318,7 +323,11 @@ class RuntimeStub: public CodeBlob {
class SingletonBlob: public CodeBlob {
friend class VMStructs;
public:
protected:
void* operator new(size_t s, unsigned size);
public:
SingletonBlob(
const char* name,
CodeBuffer* cb,
@ -340,6 +349,50 @@ class SingletonBlob: public CodeBlob {
};
//----------------------------------------------------------------------------------------------------
// RicochetBlob
// Holds an arbitrary argument list indefinitely while Java code executes recursively.
class RicochetBlob: public SingletonBlob {
friend class VMStructs;
private:
int _bounce_offset;
int _exception_offset;
// Creation support
RicochetBlob(
CodeBuffer* cb,
int size,
int bounce_offset,
int exception_offset,
int frame_size
);
public:
// Creation
static RicochetBlob* create(
CodeBuffer* cb,
int bounce_offset,
int exception_offset,
int frame_size
);
// Typing
bool is_ricochet_stub() const { return true; }
// GC for args
void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { /* Nothing to do */ }
address bounce_addr() const { return code_begin() + _bounce_offset; }
address exception_addr() const { return code_begin() + _exception_offset; }
bool returns_to_bounce_addr(address pc) const {
address bounce_pc = bounce_addr();
return (pc == bounce_pc || (pc + frame::pc_return_offset) == bounce_pc);
}
};
//----------------------------------------------------------------------------------------------------
// DeoptimizationBlob
@ -363,8 +416,6 @@ class DeoptimizationBlob: public SingletonBlob {
int frame_size
);
void* operator new(size_t s, unsigned size);
public:
// Creation
static DeoptimizationBlob* create(
@ -378,7 +429,6 @@ class DeoptimizationBlob: public SingletonBlob {
// Typing
bool is_deoptimization_stub() const { return true; }
const DeoptimizationBlob *as_deoptimization_stub() const { return this; }
bool exception_address_is_unpack_entry(address pc) const {
address unpack_pc = unpack();
return (pc == unpack_pc || (pc + frame::pc_return_offset) == unpack_pc);
@ -426,8 +476,6 @@ class UncommonTrapBlob: public SingletonBlob {
int frame_size
);
void* operator new(size_t s, unsigned size);
public:
// Creation
static UncommonTrapBlob* create(
@ -458,8 +506,6 @@ class ExceptionBlob: public SingletonBlob {
int frame_size
);
void* operator new(size_t s, unsigned size);
public:
// Creation
static ExceptionBlob* create(
@ -491,8 +537,6 @@ class SafepointBlob: public SingletonBlob {
int frame_size
);
void* operator new(size_t s, unsigned size);
public:
// Creation
static SafepointBlob* create(

View File

@ -796,6 +796,7 @@ void CodeCache::print_internals() {
int nmethodCount = 0;
int runtimeStubCount = 0;
int adapterCount = 0;
int ricochetStubCount = 0;
int deoptimizationStubCount = 0;
int uncommonTrapStubCount = 0;
int bufferBlobCount = 0;
@ -840,6 +841,8 @@ void CodeCache::print_internals() {
}
} else if (cb->is_runtime_stub()) {
runtimeStubCount++;
} else if (cb->is_ricochet_stub()) {
ricochetStubCount++;
} else if (cb->is_deoptimization_stub()) {
deoptimizationStubCount++;
} else if (cb->is_uncommon_trap_stub()) {
@ -876,6 +879,7 @@ void CodeCache::print_internals() {
tty->print_cr("runtime_stubs: %d",runtimeStubCount);
tty->print_cr("adapters: %d",adapterCount);
tty->print_cr("buffer blobs: %d",bufferBlobCount);
tty->print_cr("ricochet_stubs: %d",ricochetStubCount);
tty->print_cr("deoptimization_stubs: %d",deoptimizationStubCount);
tty->print_cr("uncommon_traps: %d",uncommonTrapStubCount);
tty->print_cr("\nnmethod size distribution (non-zombie java)");

View File

@ -283,10 +283,10 @@ void decode_env::print_address(address adr) {
st->print("Stub::%s", desc->name());
if (desc->begin() != adr)
st->print("%+d 0x%p",adr - desc->begin(), adr);
else if (WizardMode) st->print(" " INTPTR_FORMAT, adr);
else if (WizardMode) st->print(" " PTR_FORMAT, adr);
return;
}
st->print("Stub::<unknown> " INTPTR_FORMAT, adr);
st->print("Stub::<unknown> " PTR_FORMAT, adr);
return;
}
@ -314,8 +314,8 @@ void decode_env::print_address(address adr) {
}
}
// Fall through to a simple numeral.
st->print(INTPTR_FORMAT, (intptr_t)adr);
// Fall through to a simple (hexadecimal) numeral.
st->print(PTR_FORMAT, adr);
}
void decode_env::print_insn_labels() {
@ -326,7 +326,7 @@ void decode_env::print_insn_labels() {
cb->print_block_comment(st, p);
}
if (_print_pc) {
st->print(" " INTPTR_FORMAT ": ", (intptr_t) p);
st->print(" " PTR_FORMAT ": ", p);
}
}
@ -432,7 +432,7 @@ address decode_env::decode_instructions(address start, address end) {
void Disassembler::decode(CodeBlob* cb, outputStream* st) {
if (!load_library()) return;
decode_env env(cb, st);
env.output()->print_cr("Decoding CodeBlob " INTPTR_FORMAT, cb);
env.output()->print_cr("Decoding CodeBlob " PTR_FORMAT, cb);
env.decode_instructions(cb->code_begin(), cb->code_end());
}
@ -446,7 +446,7 @@ void Disassembler::decode(address start, address end, outputStream* st) {
void Disassembler::decode(nmethod* nm, outputStream* st) {
if (!load_library()) return;
decode_env env(nm, st);
env.output()->print_cr("Decoding compiled method " INTPTR_FORMAT ":", nm);
env.output()->print_cr("Decoding compiled method " PTR_FORMAT ":", nm);
env.output()->print_cr("Code:");
#ifdef SHARK
@ -478,9 +478,9 @@ void Disassembler::decode(nmethod* nm, outputStream* st) {
int offset = 0;
for (address p = nm->consts_begin(); p < nm->consts_end(); p += 4, offset += 4) {
if ((offset % 8) == 0) {
env.output()->print_cr(" " INTPTR_FORMAT " (offset: %4d): " PTR32_FORMAT " " PTR64_FORMAT, (intptr_t) p, offset, *((int32_t*) p), *((int64_t*) p));
env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT " " PTR64_FORMAT, p, offset, *((int32_t*) p), *((int64_t*) p));
} else {
env.output()->print_cr(" " INTPTR_FORMAT " (offset: %4d): " PTR32_FORMAT, (intptr_t) p, offset, *((int32_t*) p));
env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT, p, offset, *((int32_t*) p));
}
}
}

View File

@ -3158,6 +3158,9 @@ inline bool VM_HeapWalkOperation::collect_stack_roots(JavaThread* java_thread,
if (fr->is_entry_frame()) {
last_entry_frame = fr;
}
if (fr->is_ricochet_frame()) {
fr->oops_ricochet_do(blk, vf->register_map());
}
}
vf = vf->sender();

View File

@ -409,6 +409,11 @@ MethodHandleWalker::walk(TRAPS) {
break;
}
case java_lang_invoke_AdapterMethodHandle::OP_FOLD_ARGS: { //NYI, may GC
lose("unimplemented", CHECK_(empty));
break;
}
case java_lang_invoke_AdapterMethodHandle::OP_SPREAD_ARGS: {
klassOop array_klass_oop = NULL;
BasicType array_type = java_lang_Class::as_BasicType(chain().adapter_arg_oop(),
@ -452,9 +457,18 @@ MethodHandleWalker::walk(TRAPS) {
Bytecodes::_invokestatic, false, 3, &arglist[0], CHECK_(empty));
// Spread out the array elements.
Bytecodes::Code aload_op = Bytecodes::_aaload;
if (element_type != T_OBJECT) {
lose("primitive array NYI", CHECK_(empty));
Bytecodes::Code aload_op = Bytecodes::_nop;
switch (element_type) {
case T_INT: aload_op = Bytecodes::_iaload; break;
case T_LONG: aload_op = Bytecodes::_laload; break;
case T_FLOAT: aload_op = Bytecodes::_faload; break;
case T_DOUBLE: aload_op = Bytecodes::_daload; break;
case T_OBJECT: aload_op = Bytecodes::_aaload; break;
case T_BOOLEAN: // fall through:
case T_BYTE: aload_op = Bytecodes::_baload; break;
case T_CHAR: aload_op = Bytecodes::_caload; break;
case T_SHORT: aload_op = Bytecodes::_saload; break;
default: lose("primitive array NYI", CHECK_(empty));
}
int ap = arg_slot;
for (int i = 0; i < spread_length; i++) {
@ -467,11 +481,6 @@ MethodHandleWalker::walk(TRAPS) {
break;
}
case java_lang_invoke_AdapterMethodHandle::OP_FLYBY: //NYI, runs Java code
case java_lang_invoke_AdapterMethodHandle::OP_RICOCHET: //NYI, runs Java code
lose("unimplemented", CHECK_(empty));
break;
default:
lose("bad adapter conversion", CHECK_(empty));
break;

View File

@ -66,8 +66,8 @@ const char* MethodHandles::_entry_names[_EK_LIMIT+1] = {
"adapter_drop_args",
"adapter_collect_args",
"adapter_spread_args",
"adapter_flyby",
"adapter_ricochet",
"adapter_fold_args",
"adapter_unused_13",
// optimized adapter types:
"adapter_swap_args/1",
@ -83,9 +83,76 @@ const char* MethodHandles::_entry_names[_EK_LIMIT+1] = {
"adapter_prim_to_prim/f2d",
"adapter_ref_to_prim/unboxi",
"adapter_ref_to_prim/unboxl",
"adapter_spread_args/0",
"adapter_spread_args/1",
"adapter_spread_args/more",
// return value handlers for collect/filter/fold adapters:
"return/ref",
"return/int",
"return/long",
"return/float",
"return/double",
"return/void",
"return/S0/ref",
"return/S1/ref",
"return/S2/ref",
"return/S3/ref",
"return/S4/ref",
"return/S5/ref",
"return/any",
// spreading (array length cases 0, 1, ...)
"adapter_spread/0",
"adapter_spread/1/ref",
"adapter_spread/2/ref",
"adapter_spread/3/ref",
"adapter_spread/4/ref",
"adapter_spread/5/ref",
"adapter_spread/ref",
"adapter_spread/byte",
"adapter_spread/char",
"adapter_spread/short",
"adapter_spread/int",
"adapter_spread/long",
"adapter_spread/float",
"adapter_spread/double",
// blocking filter/collect conversions:
"adapter_collect/ref",
"adapter_collect/int",
"adapter_collect/long",
"adapter_collect/float",
"adapter_collect/double",
"adapter_collect/void",
"adapter_collect/0/ref",
"adapter_collect/1/ref",
"adapter_collect/2/ref",
"adapter_collect/3/ref",
"adapter_collect/4/ref",
"adapter_collect/5/ref",
"adapter_filter/S0/ref",
"adapter_filter/S1/ref",
"adapter_filter/S2/ref",
"adapter_filter/S3/ref",
"adapter_filter/S4/ref",
"adapter_filter/S5/ref",
"adapter_collect/2/S0/ref",
"adapter_collect/2/S1/ref",
"adapter_collect/2/S2/ref",
"adapter_collect/2/S3/ref",
"adapter_collect/2/S4/ref",
"adapter_collect/2/S5/ref",
// blocking fold conversions:
"adapter_fold/ref",
"adapter_fold/int",
"adapter_fold/long",
"adapter_fold/float",
"adapter_fold/double",
"adapter_fold/void",
"adapter_fold/1/ref",
"adapter_fold/2/ref",
"adapter_fold/3/ref",
"adapter_fold/4/ref",
"adapter_fold/5/ref",
NULL
};
@ -96,13 +163,23 @@ int MethodHandles::_adapter_code_size = StubRoutines::meth
jobject MethodHandles::_raise_exception_method;
address MethodHandles::_adapter_return_handlers[CONV_TYPE_MASK+1];
#ifdef ASSERT
bool MethodHandles::spot_check_entry_names() {
assert(!strcmp(entry_name(_invokestatic_mh), "invokestatic"), "");
assert(!strcmp(entry_name(_bound_ref_mh), "bound_ref"), "");
assert(!strcmp(entry_name(_adapter_retype_only), "adapter_retype_only"), "");
assert(!strcmp(entry_name(_adapter_ricochet), "adapter_ricochet"), "");
assert(!strcmp(entry_name(_adapter_fold_args), "adapter_fold_args"), "");
assert(!strcmp(entry_name(_adapter_opt_unboxi), "adapter_ref_to_prim/unboxi"), "");
assert(!strcmp(entry_name(_adapter_opt_spread_char), "adapter_spread/char"), "");
assert(!strcmp(entry_name(_adapter_opt_spread_double), "adapter_spread/double"), "");
assert(!strcmp(entry_name(_adapter_opt_collect_int), "adapter_collect/int"), "");
assert(!strcmp(entry_name(_adapter_opt_collect_0_ref), "adapter_collect/0/ref"), "");
assert(!strcmp(entry_name(_adapter_opt_collect_2_S3_ref), "adapter_collect/2/S3/ref"), "");
assert(!strcmp(entry_name(_adapter_opt_filter_S5_ref), "adapter_filter/S5/ref"), "");
assert(!strcmp(entry_name(_adapter_opt_fold_3_ref), "adapter_fold/3/ref"), "");
assert(!strcmp(entry_name(_adapter_opt_fold_void), "adapter_fold/void"), "");
return true;
}
#endif
@ -112,6 +189,9 @@ bool MethodHandles::spot_check_entry_names() {
// MethodHandles::generate_adapters
//
void MethodHandles::generate_adapters() {
#ifdef TARGET_ARCH_NYI_6939861
if (FLAG_IS_DEFAULT(UseRicochetFrames)) UseRicochetFrames = false;
#endif
if (!EnableInvokeDynamic || SystemDictionary::MethodHandle_klass() == NULL) return;
assert(_adapter_code == NULL, "generate only once");
@ -126,7 +206,6 @@ void MethodHandles::generate_adapters() {
g.generate();
}
//------------------------------------------------------------------------------
// MethodHandlesAdapterGenerator::generate
//
@ -135,12 +214,62 @@ void MethodHandlesAdapterGenerator::generate() {
for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST;
ek < MethodHandles::_EK_LIMIT;
ek = MethodHandles::EntryKind(1 + (int)ek)) {
StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
MethodHandles::generate_method_handle_stub(_masm, ek);
if (MethodHandles::ek_supported(ek)) {
StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
MethodHandles::generate_method_handle_stub(_masm, ek);
}
}
}
#ifdef TARGET_ARCH_NYI_6939861
// these defs belong in methodHandles_<arch>.cpp
frame MethodHandles::ricochet_frame_sender(const frame& fr, RegisterMap *map) {
ShouldNotCallThis();
return fr;
}
void MethodHandles::ricochet_frame_oops_do(const frame& fr, OopClosure* f, const RegisterMap* reg_map) {
ShouldNotCallThis();
}
#endif //TARGET_ARCH_NYI_6939861
//------------------------------------------------------------------------------
// MethodHandles::ek_supported
//
bool MethodHandles::ek_supported(MethodHandles::EntryKind ek) {
MethodHandles::EntryKind ek_orig = MethodHandles::ek_original_kind(ek);
switch (ek_orig) {
case _adapter_unused_13:
return false; // not defined yet
case _adapter_prim_to_ref:
return UseRicochetFrames && conv_op_supported(java_lang_invoke_AdapterMethodHandle::OP_PRIM_TO_REF);
case _adapter_collect_args:
return UseRicochetFrames && conv_op_supported(java_lang_invoke_AdapterMethodHandle::OP_COLLECT_ARGS);
case _adapter_fold_args:
return UseRicochetFrames && conv_op_supported(java_lang_invoke_AdapterMethodHandle::OP_FOLD_ARGS);
case _adapter_opt_return_any:
return UseRicochetFrames;
#ifdef TARGET_ARCH_NYI_6939861
// ports before 6939861 supported only three kinds of spread ops
case _adapter_spread_args:
// restrict spreads to three kinds:
switch (ek) {
case _adapter_opt_spread_0:
case _adapter_opt_spread_1:
case _adapter_opt_spread_more:
break;
default:
return false;
break;
}
break;
#endif //TARGET_ARCH_NYI_6939861
}
return true;
}
void MethodHandles::set_enabled(bool z) {
if (_enabled != z) {
guarantee(z && EnableInvokeDynamic, "can only enable once, and only if -XX:+EnableInvokeDynamic");
@ -1564,6 +1693,8 @@ void MethodHandles::init_BoundMethodHandle_with_receiver(Handle mh,
if (m->is_abstract()) { THROW(vmSymbols::java_lang_AbstractMethodError()); }
java_lang_invoke_MethodHandle::init_vmslots(mh());
int vmargslot = m->size_of_parameters() - 1;
assert(java_lang_invoke_BoundMethodHandle::vmargslot(mh()) == vmargslot, "");
if (VerifyMethodHandles) {
verify_BoundMethodHandle_with_receiver(mh, m, CHECK);
@ -1642,14 +1773,9 @@ void MethodHandles::verify_BoundMethodHandle(Handle mh, Handle target, int argnu
DEBUG_ONLY(int this_pushes = decode_MethodHandle_stack_pushes(mh()));
if (direct_to_method) {
assert(this_pushes == slots_pushed, "BMH pushes one or two stack slots");
assert(slots_pushed <= MethodHandlePushLimit, "");
} else {
int target_pushes = decode_MethodHandle_stack_pushes(target());
assert(this_pushes == slots_pushed + target_pushes, "BMH stack motion must be correct");
// do not blow the stack; use a Java-based adapter if this limit is exceeded
// FIXME
// if (slots_pushed + target_pushes > MethodHandlePushLimit)
// err = "too many bound parameters";
}
}
@ -1672,10 +1798,11 @@ void MethodHandles::init_BoundMethodHandle(Handle mh, Handle target, int argnum,
}
java_lang_invoke_MethodHandle::init_vmslots(mh());
int argslot = java_lang_invoke_BoundMethodHandle::vmargslot(mh());
if (VerifyMethodHandles) {
int insert_after = argnum - 1;
verify_vmargslot(mh, insert_after, java_lang_invoke_BoundMethodHandle::vmargslot(mh()), CHECK);
verify_vmargslot(mh, insert_after, argslot, CHECK);
verify_vmslots(mh, CHECK);
}
@ -1769,6 +1896,7 @@ void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
Handle target(THREAD, java_lang_invoke_AdapterMethodHandle::vmtarget(mh()));
Handle src_mtype(THREAD, java_lang_invoke_MethodHandle::type(mh()));
Handle dst_mtype(THREAD, java_lang_invoke_MethodHandle::type(target()));
Handle arg_mtype;
const char* err = NULL;
@ -1777,25 +1905,29 @@ void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
switch (ek) {
case _adapter_check_cast: // target type of cast
case _adapter_ref_to_prim: // wrapper type from which to unbox
case _adapter_prim_to_ref: // wrapper type to box into
case _adapter_collect_args: // array type to collect into
case _adapter_spread_args: // array type to spread from
if (!java_lang_Class::is_instance(argument())
|| java_lang_Class::is_primitive(argument()))
{ err = "adapter requires argument of type java.lang.Class"; break; }
if (ek == _adapter_collect_args ||
ek == _adapter_spread_args) {
if (ek == _adapter_spread_args) {
// Make sure it is a suitable collection type. (Array, for now.)
Klass* ak = Klass::cast(java_lang_Class::as_klassOop(argument()));
if (!ak->oop_is_objArray()) {
{ err = "adapter requires argument of type java.lang.Class<Object[]>"; break; }
}
if (!ak->oop_is_array())
{ err = "spread adapter requires argument representing an array class"; break; }
BasicType et = arrayKlass::cast(ak->as_klassOop())->element_type();
if (et != dest && stack_move <= 0)
{ err = "spread adapter requires array class argument of correct type"; break; }
}
break;
case _adapter_flyby:
case _adapter_ricochet:
case _adapter_prim_to_ref: // boxer MH to use
case _adapter_collect_args: // method handle which collects the args
case _adapter_fold_args: // method handle which collects the args
if (!UseRicochetFrames) {
{ err = "box/collect/fold operators are not supported"; break; }
}
if (!java_lang_invoke_MethodHandle::is_instance(argument()))
{ err = "MethodHandle adapter argument required"; break; }
arg_mtype = Handle(THREAD, java_lang_invoke_MethodHandle::type(argument()));
break;
default:
if (argument.not_null())
@ -1806,6 +1938,7 @@ void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
if (err == NULL) {
// Check that the src/dest types are supplied if needed.
// Also check relevant parameter or return types.
switch (ek) {
case _adapter_check_cast:
if (src != T_OBJECT || dest != T_OBJECT) {
@ -1828,8 +1961,7 @@ void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
}
break;
case _adapter_prim_to_ref:
if (!is_java_primitive(src) || dest != T_OBJECT
|| argument() != Klass::cast(SystemDictionary::box_klass(src))->java_mirror()) {
if (!is_java_primitive(src) || dest != T_OBJECT) {
err = "adapter requires primitive src conversion subfield"; break;
}
break;
@ -1840,14 +1972,12 @@ void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
err = "adapter requires src/dest conversion subfields for swap"; break;
}
int swap_size = type2size[src];
oop src_mtype = java_lang_invoke_AdapterMethodHandle::type(mh());
oop dest_mtype = java_lang_invoke_AdapterMethodHandle::type(target());
int slot_limit = java_lang_invoke_AdapterMethodHandle::vmslots(target());
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
int src_arg = argnum;
int dest_arg = argument_slot_to_argnum(dest_mtype, dest_slot);
int dest_arg = argument_slot_to_argnum(dst_mtype(), dest_slot);
verify_vmargslot(mh, dest_arg, dest_slot, CHECK);
if (!(dest_slot >= src_slot + swap_size) &&
!(src_slot >= dest_slot + swap_size)) {
@ -1855,8 +1985,8 @@ void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
} else if (ek == _adapter_swap_args && !(src_slot > dest_slot)) {
err = "source of swap must be deeper in stack";
} else if (ek == _adapter_swap_args) {
err = check_argument_type_change(java_lang_invoke_MethodType::ptype(src_mtype, dest_arg),
java_lang_invoke_MethodType::ptype(dest_mtype, src_arg),
err = check_argument_type_change(java_lang_invoke_MethodType::ptype(src_mtype(), dest_arg),
java_lang_invoke_MethodType::ptype(dst_mtype(), src_arg),
dest_arg);
} else if (ek == _adapter_rot_args) {
if (rotate_up) {
@ -1864,8 +1994,8 @@ void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
// rotate up: [dest_slot..src_slot-ss] --> [dest_slot+ss..src_slot]
// that is: [src_arg+1..dest_arg] --> [src_arg..dest_arg-1]
for (int i = src_arg+1; i <= dest_arg && err == NULL; i++) {
err = check_argument_type_change(java_lang_invoke_MethodType::ptype(src_mtype, i),
java_lang_invoke_MethodType::ptype(dest_mtype, i-1),
err = check_argument_type_change(java_lang_invoke_MethodType::ptype(src_mtype(), i),
java_lang_invoke_MethodType::ptype(dst_mtype(), i-1),
i);
}
} else { // rotate down
@ -1873,28 +2003,54 @@ void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
// rotate down: [src_slot+ss..dest_slot] --> [src_slot..dest_slot-ss]
// that is: [dest_arg..src_arg-1] --> [dst_arg+1..src_arg]
for (int i = dest_arg; i <= src_arg-1 && err == NULL; i++) {
err = check_argument_type_change(java_lang_invoke_MethodType::ptype(src_mtype, i),
java_lang_invoke_MethodType::ptype(dest_mtype, i+1),
err = check_argument_type_change(java_lang_invoke_MethodType::ptype(src_mtype(), i),
java_lang_invoke_MethodType::ptype(dst_mtype(), i+1),
i);
}
}
}
if (err == NULL)
err = check_argument_type_change(java_lang_invoke_MethodType::ptype(src_mtype, src_arg),
java_lang_invoke_MethodType::ptype(dest_mtype, dest_arg),
err = check_argument_type_change(java_lang_invoke_MethodType::ptype(src_mtype(), src_arg),
java_lang_invoke_MethodType::ptype(dst_mtype(), dest_arg),
src_arg);
}
break;
case _adapter_collect_args:
case _adapter_spread_args:
case _adapter_collect_args:
case _adapter_fold_args:
{
BasicType coll_type = (ek == _adapter_collect_args) ? dest : src;
BasicType elem_type = (ek == _adapter_collect_args) ? src : dest;
if (coll_type != T_OBJECT || elem_type != T_OBJECT) {
err = "adapter requires src/dest subfields"; break;
// later:
// - consider making coll be a primitive array
// - consider making coll be a heterogeneous collection
bool is_spread = (ek == _adapter_spread_args);
bool is_fold = (ek == _adapter_fold_args);
BasicType coll_type = is_spread ? src : dest;
BasicType elem_type = is_spread ? dest : src;
// coll_type is type of args in collected form (or T_VOID if none)
// elem_type is common type of args in spread form (or T_VOID if missing or heterogeneous)
if (coll_type == 0 || elem_type == 0) {
err = "adapter requires src/dest subfields for spread or collect"; break;
}
if (is_spread && coll_type != T_OBJECT) {
err = "spread adapter requires object type for argument bundle"; break;
}
Handle spread_mtype = (is_spread ? dst_mtype : src_mtype);
int spread_slot = argslot;
int spread_arg = argnum;
int slots_pushed = stack_move / stack_move_unit();
int coll_slot_count = type2size[coll_type];
int spread_slot_count = (is_spread ? slots_pushed : -slots_pushed) + coll_slot_count;
if (is_fold) spread_slot_count = argument_slot_count(arg_mtype());
if (!is_spread) {
int init_slots = argument_slot_count(src_mtype());
int coll_slots = argument_slot_count(arg_mtype());
if (spread_slot_count > init_slots ||
spread_slot_count != coll_slots) {
err = "collect adapter has inconsistent arg counts"; break;
}
int next_slots = argument_slot_count(dst_mtype());
int unchanged_slots_in = (init_slots - spread_slot_count);
int unchanged_slots_out = (next_slots - coll_slot_count - (is_fold ? spread_slot_count : 0));
if (unchanged_slots_in != unchanged_slots_out) {
err = "collect adapter continuation has inconsistent arg counts"; break;
}
}
}
break;
@ -1929,8 +2085,9 @@ void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
}
break;
case _adapter_collect_args:
if (slots_pushed > 1) {
err = "adapter requires conversion subfield slots_pushed <= 1";
case _adapter_fold_args:
if (slots_pushed > 2) {
err = "adapter requires conversion subfield slots_pushed <= 2";
}
break;
case _adapter_spread_args:
@ -1950,32 +2107,36 @@ void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
}
if (err == NULL) {
// Make sure this adapter does not push too deeply.
// Make sure this adapter's stack pushing is accurately recorded.
int slots_pushed = stack_move / stack_move_unit();
int this_vmslots = java_lang_invoke_MethodHandle::vmslots(mh());
int target_vmslots = java_lang_invoke_MethodHandle::vmslots(target());
int target_pushes = decode_MethodHandle_stack_pushes(target());
if (slots_pushed != (target_vmslots - this_vmslots)) {
err = "stack_move inconsistent with previous and current MethodType vmslots";
} else if (slots_pushed > 0) {
// verify stack_move against MethodHandlePushLimit
int target_pushes = decode_MethodHandle_stack_pushes(target());
// do not blow the stack; use a Java-based adapter if this limit is exceeded
if (slots_pushed + target_pushes > MethodHandlePushLimit) {
err = "adapter pushes too many parameters";
} else {
int this_pushes = decode_MethodHandle_stack_pushes(mh());
if (slots_pushed + target_pushes != this_pushes) {
if (this_pushes == 0)
err = "adapter push count not initialized";
else
err = "adapter push count is wrong";
}
}
// While we're at it, check that the stack motion decoder works:
DEBUG_ONLY(int target_pushes = decode_MethodHandle_stack_pushes(target()));
DEBUG_ONLY(int this_pushes = decode_MethodHandle_stack_pushes(mh()));
assert(this_pushes == slots_pushed + target_pushes, "AMH stack motion must be correct");
}
if (err == NULL && vminfo != 0) {
switch (ek) {
case _adapter_swap_args:
case _adapter_rot_args:
break; // OK
case _adapter_swap_args:
case _adapter_rot_args:
case _adapter_prim_to_ref:
case _adapter_collect_args:
case _adapter_fold_args:
break; // OK
default:
err = "vminfo subfield is reserved to the JVM";
}
@ -2026,6 +2187,7 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
// adjust the adapter code to the internal EntryKind enumeration:
EntryKind ek_orig = adapter_entry_kind(conv_op);
EntryKind ek_opt = ek_orig; // may be optimized
EntryKind ek_try; // temp
// Finalize the vmtarget field (Java initialized it to null).
if (!java_lang_invoke_MethodHandle::is_instance(target())) {
@ -2034,17 +2196,23 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
}
java_lang_invoke_AdapterMethodHandle::set_vmtarget(mh(), target());
if (VerifyMethodHandles) {
verify_AdapterMethodHandle(mh, argnum, CHECK);
}
int stack_move = adapter_conversion_stack_move(conversion);
BasicType src = adapter_conversion_src_type(conversion);
BasicType dest = adapter_conversion_dest_type(conversion);
int vminfo = adapter_conversion_vminfo(conversion); // should be zero
int slots_pushed = stack_move / stack_move_unit();
if (VerifyMethodHandles) {
verify_AdapterMethodHandle(mh, argnum, CHECK);
}
const char* err = NULL;
if (!conv_op_supported(conv_op)) {
err = "adapter not yet implemented in the JVM";
}
// Now it's time to finish the case analysis and pick a MethodHandleEntry.
switch (ek_orig) {
case _adapter_retype_only:
@ -2077,7 +2245,7 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
}
break;
case 1 *4+ 2:
if (src == T_INT && dest == T_LONG) {
if ((src == T_INT || is_subword_type(src)) && dest == T_LONG) {
ek_opt = _adapter_opt_i2l;
} else if (src == T_FLOAT && dest == T_DOUBLE) {
ek_opt = _adapter_opt_f2d;
@ -2110,7 +2278,44 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
break;
case _adapter_prim_to_ref:
goto throw_not_impl; // allocates, hence could block
{
assert(UseRicochetFrames, "else don't come here");
// vminfo will be the location to insert the return value
vminfo = argslot;
ek_opt = _adapter_opt_collect_ref;
ensure_vmlayout_field(target, CHECK);
if (!OptimizeMethodHandles) break;
switch (type2size[src]) {
case 1:
ek_try = EntryKind(_adapter_opt_filter_S0_ref + argslot);
if (ek_try < _adapter_opt_collect_LAST &&
ek_adapter_opt_collect_slot(ek_try) == argslot) {
assert(ek_adapter_opt_collect_count(ek_try) == 1 &&
ek_adapter_opt_collect_type(ek_try) == T_OBJECT, "");
ek_opt = ek_try;
break;
}
// else downgrade to variable slot:
ek_opt = _adapter_opt_collect_1_ref;
break;
case 2:
ek_try = EntryKind(_adapter_opt_collect_2_S0_ref + argslot);
if (ek_try < _adapter_opt_collect_LAST &&
ek_adapter_opt_collect_slot(ek_try) == argslot) {
assert(ek_adapter_opt_collect_count(ek_try) == 2 &&
ek_adapter_opt_collect_type(ek_try) == T_OBJECT, "");
ek_opt = ek_try;
break;
}
// else downgrade to variable slot:
ek_opt = _adapter_opt_collect_2_ref;
break;
default:
assert(false, "");
break;
}
}
break;
case _adapter_swap_args:
case _adapter_rot_args:
@ -2136,29 +2341,180 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
}
break;
case _adapter_collect_args:
goto throw_not_impl; // allocates, hence could block
case _adapter_spread_args:
{
// vminfo will be the required length of the array
int slots_pushed = stack_move / stack_move_unit();
int array_size = slots_pushed + 1;
assert(array_size >= 0, "");
vminfo = array_size;
switch (array_size) {
case 0: ek_opt = _adapter_opt_spread_0; break;
case 1: ek_opt = _adapter_opt_spread_1; break;
default: ek_opt = _adapter_opt_spread_more; break;
#ifdef TARGET_ARCH_NYI_6939861
// ports before 6939861 supported only three kinds of spread ops
if (!UseRicochetFrames) {
int array_size = slots_pushed + 1;
assert(array_size >= 0, "");
vminfo = array_size;
switch (array_size) {
case 0: ek_opt = _adapter_opt_spread_0; break;
case 1: ek_opt = _adapter_opt_spread_1; break;
default: ek_opt = _adapter_opt_spread_more; break;
}
break;
}
if ((vminfo & CONV_VMINFO_MASK) != vminfo)
goto throw_not_impl; // overflow
#endif //TARGET_ARCH_NYI_6939861
// vminfo will be the required length of the array
int array_size = (slots_pushed + 1) / (type2size[dest] == 2 ? 2 : 1);
vminfo = array_size;
// general case
switch (dest) {
case T_BOOLEAN : // fall through to T_BYTE:
case T_BYTE : ek_opt = _adapter_opt_spread_byte; break;
case T_CHAR : ek_opt = _adapter_opt_spread_char; break;
case T_SHORT : ek_opt = _adapter_opt_spread_short; break;
case T_INT : ek_opt = _adapter_opt_spread_int; break;
case T_LONG : ek_opt = _adapter_opt_spread_long; break;
case T_FLOAT : ek_opt = _adapter_opt_spread_float; break;
case T_DOUBLE : ek_opt = _adapter_opt_spread_double; break;
case T_OBJECT : ek_opt = _adapter_opt_spread_ref; break;
case T_VOID : if (array_size != 0) goto throw_not_impl;
ek_opt = _adapter_opt_spread_ref; break;
default : goto throw_not_impl;
}
assert(array_size == 0 || // it doesn't matter what the spreader is
(ek_adapter_opt_spread_count(ek_opt) == -1 &&
(ek_adapter_opt_spread_type(ek_opt) == dest ||
(ek_adapter_opt_spread_type(ek_opt) == T_BYTE && dest == T_BOOLEAN))),
err_msg("dest=%d ek_opt=%d", dest, ek_opt));
if (array_size <= 0) {
// since the general case does not handle length 0, this case is required:
ek_opt = _adapter_opt_spread_0;
break;
}
if (dest == T_OBJECT) {
ek_try = EntryKind(_adapter_opt_spread_1_ref - 1 + array_size);
if (ek_try < _adapter_opt_spread_LAST &&
ek_adapter_opt_spread_count(ek_try) == array_size) {
assert(ek_adapter_opt_spread_type(ek_try) == dest, "");
ek_opt = ek_try;
break;
}
}
break;
}
break;
case _adapter_flyby:
case _adapter_ricochet:
goto throw_not_impl; // runs Java code, hence could block
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()) ) );
// vminfo will be the location to insert the return value
vminfo = argslot;
ensure_vmlayout_field(target, CHECK);
// general case:
switch (dest) {
default : if (!is_subword_type(dest)) goto throw_not_impl;
// else fall through:
case T_INT : ek_opt = _adapter_opt_collect_int; break;
case T_LONG : ek_opt = _adapter_opt_collect_long; break;
case T_FLOAT : ek_opt = _adapter_opt_collect_float; break;
case T_DOUBLE : ek_opt = _adapter_opt_collect_double; break;
case T_OBJECT : ek_opt = _adapter_opt_collect_ref; break;
case T_VOID : ek_opt = _adapter_opt_collect_void; break;
}
assert(ek_adapter_opt_collect_slot(ek_opt) == -1 &&
ek_adapter_opt_collect_count(ek_opt) == -1 &&
(ek_adapter_opt_collect_type(ek_opt) == dest ||
ek_adapter_opt_collect_type(ek_opt) == T_INT && is_subword_type(dest)),
"");
if (dest == T_OBJECT && elem_slots == 1 && OptimizeMethodHandles) {
// filter operation on a ref
ek_try = EntryKind(_adapter_opt_filter_S0_ref + argslot);
if (ek_try < _adapter_opt_collect_LAST &&
ek_adapter_opt_collect_slot(ek_try) == argslot) {
assert(ek_adapter_opt_collect_count(ek_try) == elem_slots &&
ek_adapter_opt_collect_type(ek_try) == dest, "");
ek_opt = ek_try;
break;
}
ek_opt = _adapter_opt_collect_1_ref;
break;
}
if (dest == T_OBJECT && elem_slots == 2 && OptimizeMethodHandles) {
// filter of two arguments
ek_try = EntryKind(_adapter_opt_collect_2_S0_ref + argslot);
if (ek_try < _adapter_opt_collect_LAST &&
ek_adapter_opt_collect_slot(ek_try) == argslot) {
assert(ek_adapter_opt_collect_count(ek_try) == elem_slots &&
ek_adapter_opt_collect_type(ek_try) == dest, "");
ek_opt = ek_try;
break;
}
ek_opt = _adapter_opt_collect_2_ref;
break;
}
if (dest == T_OBJECT && OptimizeMethodHandles) {
// try to use a fixed length adapter
ek_try = EntryKind(_adapter_opt_collect_0_ref + elem_slots);
if (ek_try < _adapter_opt_collect_LAST &&
ek_adapter_opt_collect_count(ek_try) == elem_slots) {
assert(ek_adapter_opt_collect_slot(ek_try) == -1 &&
ek_adapter_opt_collect_type(ek_try) == dest, "");
ek_opt = ek_try;
break;
}
}
break;
}
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()) ) );
// vminfo will be the location to insert the return value
vminfo = argslot + elem_slots;
ensure_vmlayout_field(target, CHECK);
switch (dest) {
default : if (!is_subword_type(dest)) goto throw_not_impl;
// else fall through:
case T_INT : ek_opt = _adapter_opt_fold_int; break;
case T_LONG : ek_opt = _adapter_opt_fold_long; break;
case T_FLOAT : ek_opt = _adapter_opt_fold_float; break;
case T_DOUBLE : ek_opt = _adapter_opt_fold_double; break;
case T_OBJECT : ek_opt = _adapter_opt_fold_ref; break;
case T_VOID : ek_opt = _adapter_opt_fold_void; break;
}
assert(ek_adapter_opt_collect_slot(ek_opt) == -1 &&
ek_adapter_opt_collect_count(ek_opt) == -1 &&
(ek_adapter_opt_collect_type(ek_opt) == dest ||
ek_adapter_opt_collect_type(ek_opt) == T_INT && is_subword_type(dest)),
"");
if (dest == T_OBJECT && elem_slots == 0 && OptimizeMethodHandles) {
// if there are no args, just pretend it's a collect
ek_opt = _adapter_opt_collect_0_ref;
break;
}
if (dest == T_OBJECT && OptimizeMethodHandles) {
// try to use a fixed length adapter
ek_try = EntryKind(_adapter_opt_fold_1_ref - 1 + elem_slots);
if (ek_try < _adapter_opt_fold_LAST &&
ek_adapter_opt_collect_count(ek_try) == elem_slots) {
assert(ek_adapter_opt_collect_slot(ek_try) == -1 &&
ek_adapter_opt_collect_type(ek_try) == dest, "");
ek_opt = ek_try;
break;
}
}
break;
}
default:
// should have failed much earlier; must be a missing case here
@ -2166,11 +2522,20 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
// and fall through:
throw_not_impl:
// FIXME: these adapters are NYI
err = "adapter not yet implemented in the JVM";
if (err == NULL)
err = "unknown adapter type";
break;
}
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)) {
err = "adapter stub for this kind of method handle is missing";
}
if (err != NULL) {
throw_InternalError_for_bad_conversion(conversion, err, THREAD);
return;
@ -2190,6 +2555,26 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
// Java code can publish it in global data structures.
}
void MethodHandles::ensure_vmlayout_field(Handle target, TRAPS) {
Handle mtype(THREAD, java_lang_invoke_MethodHandle::type(target()));
Handle mtform(THREAD, java_lang_invoke_MethodType::form(mtype()));
if (mtform.is_null()) { THROW(vmSymbols::java_lang_InternalError()); }
if (java_lang_invoke_MethodTypeForm::vmlayout_offset_in_bytes() > 0) {
if (java_lang_invoke_MethodTypeForm::vmlayout(mtform()) == NULL) {
// fill it in
Handle erased_mtype(THREAD, java_lang_invoke_MethodTypeForm::erasedType(mtform()));
TempNewSymbol erased_signature
= java_lang_invoke_MethodType::as_signature(erased_mtype(), /*intern:*/true, CHECK);
methodOop cookie
= SystemDictionary::find_method_handle_invoke(vmSymbols::invokeExact_name(),
erased_signature,
SystemDictionaryHandles::Object_klass(),
THREAD);
java_lang_invoke_MethodTypeForm::init_vmlayout(mtform(), cookie);
}
}
}
//
// Here are the native methods on sun.invoke.MethodHandleImpl.
// They are the private interface between this JVM and the HotSpot-specific
@ -2360,8 +2745,10 @@ JVM_END
#ifndef PRODUCT
#define EACH_NAMED_CON(template) \
template(MethodHandles,GC_JVM_PUSH_LIMIT) \
template(MethodHandles,GC_JVM_STACK_MOVE_UNIT) \
/* hold back this one until JDK stabilizes */ \
/* template(MethodHandles,GC_JVM_PUSH_LIMIT) */ \
/* hold back this one until JDK stabilizes */ \
/* template(MethodHandles,GC_JVM_STACK_MOVE_UNIT) */ \
template(MethodHandles,ETF_HANDLE_OR_METHOD_NAME) \
template(MethodHandles,ETF_DIRECT_HANDLE) \
template(MethodHandles,ETF_METHOD_NAME) \
@ -2385,9 +2772,8 @@ JVM_END
template(java_lang_invoke_AdapterMethodHandle,OP_DROP_ARGS) \
template(java_lang_invoke_AdapterMethodHandle,OP_COLLECT_ARGS) \
template(java_lang_invoke_AdapterMethodHandle,OP_SPREAD_ARGS) \
template(java_lang_invoke_AdapterMethodHandle,OP_FLYBY) \
template(java_lang_invoke_AdapterMethodHandle,OP_RICOCHET) \
template(java_lang_invoke_AdapterMethodHandle,CONV_OP_LIMIT) \
/* hold back this one until JDK stabilizes */ \
/*template(java_lang_invoke_AdapterMethodHandle,CONV_OP_LIMIT)*/ \
template(java_lang_invoke_AdapterMethodHandle,CONV_OP_MASK) \
template(java_lang_invoke_AdapterMethodHandle,CONV_VMINFO_MASK) \
template(java_lang_invoke_AdapterMethodHandle,CONV_VMINFO_SHIFT) \

View File

@ -66,8 +66,8 @@ class MethodHandles: AllStatic {
_adapter_drop_args = _adapter_mh_first + java_lang_invoke_AdapterMethodHandle::OP_DROP_ARGS,
_adapter_collect_args = _adapter_mh_first + java_lang_invoke_AdapterMethodHandle::OP_COLLECT_ARGS,
_adapter_spread_args = _adapter_mh_first + java_lang_invoke_AdapterMethodHandle::OP_SPREAD_ARGS,
_adapter_flyby = _adapter_mh_first + java_lang_invoke_AdapterMethodHandle::OP_FLYBY,
_adapter_ricochet = _adapter_mh_first + java_lang_invoke_AdapterMethodHandle::OP_RICOCHET,
_adapter_fold_args = _adapter_mh_first + java_lang_invoke_AdapterMethodHandle::OP_FOLD_ARGS,
_adapter_unused_13 = _adapter_mh_first + 13, //hole in the CONV_OP enumeration
_adapter_mh_last = _adapter_mh_first + java_lang_invoke_AdapterMethodHandle::CONV_OP_LIMIT - 1,
// Optimized adapter types
@ -93,10 +93,99 @@ class MethodHandles: AllStatic {
_adapter_opt_unboxi,
_adapter_opt_unboxl,
// spreading (array length cases 0, 1, >=2)
_adapter_opt_spread_0,
_adapter_opt_spread_1,
_adapter_opt_spread_more,
// %% Maybe tame the following with a VM_SYMBOLS_DO type macro?
// how a blocking adapter returns (platform-dependent)
_adapter_opt_return_ref,
_adapter_opt_return_int,
_adapter_opt_return_long,
_adapter_opt_return_float,
_adapter_opt_return_double,
_adapter_opt_return_void,
_adapter_opt_return_S0_ref, // return ref to S=0 (last slot)
_adapter_opt_return_S1_ref, // return ref to S=1 (2nd-to-last slot)
_adapter_opt_return_S2_ref,
_adapter_opt_return_S3_ref,
_adapter_opt_return_S4_ref,
_adapter_opt_return_S5_ref,
_adapter_opt_return_any, // dynamically select r/i/l/f/d
_adapter_opt_return_FIRST = _adapter_opt_return_ref,
_adapter_opt_return_LAST = _adapter_opt_return_any,
// spreading (array length cases 0, 1, ...)
_adapter_opt_spread_0, // spread empty array to N=0 arguments
_adapter_opt_spread_1_ref, // spread Object[] to N=1 argument
_adapter_opt_spread_2_ref, // spread Object[] to N=2 arguments
_adapter_opt_spread_3_ref, // spread Object[] to N=3 arguments
_adapter_opt_spread_4_ref, // spread Object[] to N=4 arguments
_adapter_opt_spread_5_ref, // spread Object[] to N=5 arguments
_adapter_opt_spread_ref, // spread Object[] to N arguments
_adapter_opt_spread_byte, // spread byte[] or boolean[] to N arguments
_adapter_opt_spread_char, // spread char[], etc., to N arguments
_adapter_opt_spread_short, // spread short[], etc., to N arguments
_adapter_opt_spread_int, // spread int[], short[], etc., to N arguments
_adapter_opt_spread_long, // spread long[] to N arguments
_adapter_opt_spread_float, // spread float[] to N arguments
_adapter_opt_spread_double, // spread double[] to N arguments
_adapter_opt_spread_FIRST = _adapter_opt_spread_0,
_adapter_opt_spread_LAST = _adapter_opt_spread_double,
// blocking filter/collect conversions
// These collect N arguments and replace them (at slot S) by a return value
// which is passed to the final target, along with the unaffected arguments.
// collect_{N}_{T} collects N arguments at any position into a T value
// collect_{N}_S{S}_{T} collects N arguments at slot S into a T value
// collect_{T} collects any number of arguments at any position
// filter_S{S}_{T} is the same as collect_1_S{S}_{T} (a unary collection)
// (collect_2 is also usable as a filter, with long or double arguments)
_adapter_opt_collect_ref, // combine N arguments, replace with a reference
_adapter_opt_collect_int, // combine N arguments, replace with an int, short, etc.
_adapter_opt_collect_long, // combine N arguments, replace with a long
_adapter_opt_collect_float, // combine N arguments, replace with a float
_adapter_opt_collect_double, // combine N arguments, replace with a double
_adapter_opt_collect_void, // combine N arguments, replace with nothing
// if there is a small fixed number to push, do so without a loop:
_adapter_opt_collect_0_ref, // collect N=0 arguments, insert a reference
_adapter_opt_collect_1_ref, // collect N=1 argument, replace with a reference
_adapter_opt_collect_2_ref, // combine N=2 arguments, replace with a reference
_adapter_opt_collect_3_ref, // combine N=3 arguments, replace with a reference
_adapter_opt_collect_4_ref, // combine N=4 arguments, replace with a reference
_adapter_opt_collect_5_ref, // combine N=5 arguments, replace with a reference
// filters are an important special case because they never move arguments:
_adapter_opt_filter_S0_ref, // filter N=1 argument at S=0, replace with a reference
_adapter_opt_filter_S1_ref, // filter N=1 argument at S=1, replace with a reference
_adapter_opt_filter_S2_ref, // filter N=1 argument at S=2, replace with a reference
_adapter_opt_filter_S3_ref, // filter N=1 argument at S=3, replace with a reference
_adapter_opt_filter_S4_ref, // filter N=1 argument at S=4, replace with a reference
_adapter_opt_filter_S5_ref, // filter N=1 argument at S=5, replace with a reference
// these move arguments, but they are important for boxing
_adapter_opt_collect_2_S0_ref, // combine last N=2 arguments, replace with a reference
_adapter_opt_collect_2_S1_ref, // combine N=2 arguments at S=1, replace with a reference
_adapter_opt_collect_2_S2_ref, // combine N=2 arguments at S=2, replace with a reference
_adapter_opt_collect_2_S3_ref, // combine N=2 arguments at S=3, replace with a reference
_adapter_opt_collect_2_S4_ref, // combine N=2 arguments at S=4, replace with a reference
_adapter_opt_collect_2_S5_ref, // combine N=2 arguments at S=5, replace with a reference
_adapter_opt_collect_FIRST = _adapter_opt_collect_ref,
_adapter_opt_collect_LAST = _adapter_opt_collect_2_S5_ref,
// blocking folding conversions
// these are like collects, but retain all the N arguments for the final target
//_adapter_opt_fold_0_ref, // same as _adapter_opt_collect_0_ref
// fold_{N}_{T} processes N arguments at any position into a T value, which it inserts
// fold_{T} processes any number of arguments at any position
_adapter_opt_fold_ref, // process N arguments, prepend a reference
_adapter_opt_fold_int, // process N arguments, prepend an int, short, etc.
_adapter_opt_fold_long, // process N arguments, prepend a long
_adapter_opt_fold_float, // process N arguments, prepend a float
_adapter_opt_fold_double, // process N arguments, prepend a double
_adapter_opt_fold_void, // process N arguments, but leave the list unchanged
_adapter_opt_fold_1_ref, // process N=1 argument, prepend a reference
_adapter_opt_fold_2_ref, // process N=2 arguments, prepend a reference
_adapter_opt_fold_3_ref, // process N=3 arguments, prepend a reference
_adapter_opt_fold_4_ref, // process N=4 arguments, prepend a reference
_adapter_opt_fold_5_ref, // process N=5 arguments, prepend a reference
_adapter_opt_fold_FIRST = _adapter_opt_fold_ref,
_adapter_opt_fold_LAST = _adapter_opt_fold_5_ref,
_EK_LIMIT,
_EK_FIRST = 0
@ -110,6 +199,7 @@ class MethodHandles: AllStatic {
enum { // import java_lang_invoke_AdapterMethodHandle::CONV_OP_*
CONV_OP_LIMIT = java_lang_invoke_AdapterMethodHandle::CONV_OP_LIMIT,
CONV_OP_MASK = java_lang_invoke_AdapterMethodHandle::CONV_OP_MASK,
CONV_TYPE_MASK = java_lang_invoke_AdapterMethodHandle::CONV_TYPE_MASK,
CONV_VMINFO_MASK = java_lang_invoke_AdapterMethodHandle::CONV_VMINFO_MASK,
CONV_VMINFO_SHIFT = java_lang_invoke_AdapterMethodHandle::CONV_VMINFO_SHIFT,
CONV_OP_SHIFT = java_lang_invoke_AdapterMethodHandle::CONV_OP_SHIFT,
@ -123,6 +213,7 @@ class MethodHandles: AllStatic {
static MethodHandleEntry* _entries[_EK_LIMIT];
static const char* _entry_names[_EK_LIMIT+1];
static jobject _raise_exception_method;
static address _adapter_return_handlers[CONV_TYPE_MASK+1];
// Adapters.
static MethodHandlesAdapterBlob* _adapter_code;
@ -147,39 +238,195 @@ class MethodHandles: AllStatic {
}
// Some adapter helper functions.
static void get_ek_bound_mh_info(EntryKind ek, BasicType& arg_type, int& arg_mask, int& arg_slots) {
static EntryKind ek_original_kind(EntryKind ek) {
if (ek <= _adapter_mh_last) return ek;
switch (ek) {
case _bound_int_mh : // fall-thru
case _bound_int_direct_mh : arg_type = T_INT; arg_mask = _INSERT_INT_MASK; break;
case _bound_long_mh : // fall-thru
case _bound_long_direct_mh: arg_type = T_LONG; arg_mask = _INSERT_LONG_MASK; break;
case _bound_ref_mh : // fall-thru
case _bound_ref_direct_mh : arg_type = T_OBJECT; arg_mask = _INSERT_REF_MASK; break;
default: ShouldNotReachHere();
case _adapter_opt_swap_1:
case _adapter_opt_swap_2:
return _adapter_swap_args;
case _adapter_opt_rot_1_up:
case _adapter_opt_rot_1_down:
case _adapter_opt_rot_2_up:
case _adapter_opt_rot_2_down:
return _adapter_rot_args;
case _adapter_opt_i2i:
case _adapter_opt_l2i:
case _adapter_opt_d2f:
case _adapter_opt_i2l:
case _adapter_opt_f2d:
return _adapter_prim_to_prim;
case _adapter_opt_unboxi:
case _adapter_opt_unboxl:
return _adapter_ref_to_prim;
}
arg_slots = type2size[arg_type];
if (ek >= _adapter_opt_spread_FIRST && ek <= _adapter_opt_spread_LAST)
return _adapter_spread_args;
if (ek >= _adapter_opt_collect_FIRST && ek <= _adapter_opt_collect_LAST)
return _adapter_collect_args;
if (ek >= _adapter_opt_fold_FIRST && ek <= _adapter_opt_fold_LAST)
return _adapter_fold_args;
if (ek >= _adapter_opt_return_FIRST && ek <= _adapter_opt_return_LAST)
return _adapter_opt_return_any;
assert(false, "oob");
return _EK_LIMIT;
}
static void get_ek_adapter_opt_swap_rot_info(EntryKind ek, int& swap_bytes, int& rotate) {
int swap_slots = 0;
static bool ek_supported(MethodHandles::EntryKind ek);
static BasicType ek_bound_mh_arg_type(EntryKind ek) {
switch (ek) {
case _adapter_opt_swap_1: swap_slots = 1; rotate = 0; break;
case _adapter_opt_swap_2: swap_slots = 2; rotate = 0; break;
case _adapter_opt_rot_1_up: swap_slots = 1; rotate = 1; break;
case _adapter_opt_rot_1_down: swap_slots = 1; rotate = -1; break;
case _adapter_opt_rot_2_up: swap_slots = 2; rotate = 1; break;
case _adapter_opt_rot_2_down: swap_slots = 2; rotate = -1; break;
default: ShouldNotReachHere();
case _bound_int_mh : // fall-thru
case _bound_int_direct_mh : return T_INT;
case _bound_long_mh : // fall-thru
case _bound_long_direct_mh : return T_LONG;
default : return T_OBJECT;
}
// Return the size of the stack slots to move in bytes.
swap_bytes = swap_slots * Interpreter::stackElementSize;
}
static int get_ek_adapter_opt_spread_info(EntryKind ek) {
static int ek_adapter_opt_swap_slots(EntryKind ek) {
switch (ek) {
case _adapter_opt_spread_0: return 0;
case _adapter_opt_spread_1: return 1;
default : return -1;
case _adapter_opt_swap_1 : return 1;
case _adapter_opt_swap_2 : return 2;
case _adapter_opt_rot_1_up : return 1;
case _adapter_opt_rot_1_down : return 1;
case _adapter_opt_rot_2_up : return 2;
case _adapter_opt_rot_2_down : return 2;
default : ShouldNotReachHere(); return -1;
}
}
static int ek_adapter_opt_swap_mode(EntryKind ek) {
switch (ek) {
case _adapter_opt_swap_1 : return 0;
case _adapter_opt_swap_2 : return 0;
case _adapter_opt_rot_1_up : return 1;
case _adapter_opt_rot_1_down : return -1;
case _adapter_opt_rot_2_up : return 1;
case _adapter_opt_rot_2_down : return -1;
default : ShouldNotReachHere(); return 0;
}
}
static int ek_adapter_opt_collect_count(EntryKind ek) {
assert(ek >= _adapter_opt_collect_FIRST && ek <= _adapter_opt_collect_LAST ||
ek >= _adapter_opt_fold_FIRST && ek <= _adapter_opt_fold_LAST, "");
switch (ek) {
case _adapter_opt_collect_0_ref : return 0;
case _adapter_opt_filter_S0_ref :
case _adapter_opt_filter_S1_ref :
case _adapter_opt_filter_S2_ref :
case _adapter_opt_filter_S3_ref :
case _adapter_opt_filter_S4_ref :
case _adapter_opt_filter_S5_ref :
case _adapter_opt_fold_1_ref :
case _adapter_opt_collect_1_ref : return 1;
case _adapter_opt_collect_2_S0_ref :
case _adapter_opt_collect_2_S1_ref :
case _adapter_opt_collect_2_S2_ref :
case _adapter_opt_collect_2_S3_ref :
case _adapter_opt_collect_2_S4_ref :
case _adapter_opt_collect_2_S5_ref :
case _adapter_opt_fold_2_ref :
case _adapter_opt_collect_2_ref : return 2;
case _adapter_opt_fold_3_ref :
case _adapter_opt_collect_3_ref : return 3;
case _adapter_opt_fold_4_ref :
case _adapter_opt_collect_4_ref : return 4;
case _adapter_opt_fold_5_ref :
case _adapter_opt_collect_5_ref : return 5;
default : return -1; // sentinel value for "variable"
}
}
static int ek_adapter_opt_collect_slot(EntryKind ek) {
assert(ek >= _adapter_opt_collect_FIRST && ek <= _adapter_opt_collect_LAST ||
ek >= _adapter_opt_fold_FIRST && ek <= _adapter_opt_fold_LAST, "");
switch (ek) {
case _adapter_opt_collect_2_S0_ref :
case _adapter_opt_filter_S0_ref : return 0;
case _adapter_opt_collect_2_S1_ref :
case _adapter_opt_filter_S1_ref : return 1;
case _adapter_opt_collect_2_S2_ref :
case _adapter_opt_filter_S2_ref : return 2;
case _adapter_opt_collect_2_S3_ref :
case _adapter_opt_filter_S3_ref : return 3;
case _adapter_opt_collect_2_S4_ref :
case _adapter_opt_filter_S4_ref : return 4;
case _adapter_opt_collect_2_S5_ref :
case _adapter_opt_filter_S5_ref : return 5;
default : return -1; // sentinel value for "variable"
}
}
static BasicType ek_adapter_opt_collect_type(EntryKind ek) {
assert(ek >= _adapter_opt_collect_FIRST && ek <= _adapter_opt_collect_LAST ||
ek >= _adapter_opt_fold_FIRST && ek <= _adapter_opt_fold_LAST, "");
switch (ek) {
case _adapter_opt_fold_int :
case _adapter_opt_collect_int : return T_INT;
case _adapter_opt_fold_long :
case _adapter_opt_collect_long : return T_LONG;
case _adapter_opt_fold_float :
case _adapter_opt_collect_float : return T_FLOAT;
case _adapter_opt_fold_double :
case _adapter_opt_collect_double : return T_DOUBLE;
case _adapter_opt_fold_void :
case _adapter_opt_collect_void : return T_VOID;
default : return T_OBJECT;
}
}
static int ek_adapter_opt_return_slot(EntryKind ek) {
assert(ek >= _adapter_opt_return_FIRST && ek <= _adapter_opt_return_LAST, "");
switch (ek) {
case _adapter_opt_return_S0_ref : return 0;
case _adapter_opt_return_S1_ref : return 1;
case _adapter_opt_return_S2_ref : return 2;
case _adapter_opt_return_S3_ref : return 3;
case _adapter_opt_return_S4_ref : return 4;
case _adapter_opt_return_S5_ref : return 5;
default : return -1; // sentinel value for "variable"
}
}
static BasicType ek_adapter_opt_return_type(EntryKind ek) {
assert(ek >= _adapter_opt_return_FIRST && ek <= _adapter_opt_return_LAST, "");
switch (ek) {
case _adapter_opt_return_int : return T_INT;
case _adapter_opt_return_long : return T_LONG;
case _adapter_opt_return_float : return T_FLOAT;
case _adapter_opt_return_double : return T_DOUBLE;
case _adapter_opt_return_void : return T_VOID;
case _adapter_opt_return_any : return T_CONFLICT; // sentinel value for "variable"
default : return T_OBJECT;
}
}
static int ek_adapter_opt_spread_count(EntryKind ek) {
assert(ek >= _adapter_opt_spread_FIRST && ek <= _adapter_opt_spread_LAST, "");
switch (ek) {
case _adapter_opt_spread_0 : return 0;
case _adapter_opt_spread_1_ref : return 1;
case _adapter_opt_spread_2_ref : return 2;
case _adapter_opt_spread_3_ref : return 3;
case _adapter_opt_spread_4_ref : return 4;
case _adapter_opt_spread_5_ref : return 5;
default : return -1; // sentinel value for "variable"
}
}
static BasicType ek_adapter_opt_spread_type(EntryKind ek) {
assert(ek >= _adapter_opt_spread_FIRST && ek <= _adapter_opt_spread_LAST, "");
switch (ek) {
// (there is no _adapter_opt_spread_boolean; we use byte)
case _adapter_opt_spread_byte : return T_BYTE;
case _adapter_opt_spread_char : return T_CHAR;
case _adapter_opt_spread_short : return T_SHORT;
case _adapter_opt_spread_int : return T_INT;
case _adapter_opt_spread_long : return T_LONG;
case _adapter_opt_spread_float : return T_FLOAT;
case _adapter_opt_spread_double : return T_DOUBLE;
default : return T_OBJECT;
}
}
@ -228,12 +475,21 @@ class MethodHandles: AllStatic {
// Bit mask of conversion_op values. May vary by platform.
static int adapter_conversion_ops_supported_mask();
static bool conv_op_supported(int conv_op) {
assert(conv_op_valid(conv_op), "");
return ((adapter_conversion_ops_supported_mask() & nth_bit(conv_op)) != 0);
}
// Offset in words that the interpreter stack pointer moves when an argument is pushed.
// The stack_move value must always be a multiple of this.
static int stack_move_unit() {
return frame::interpreter_frame_expression_stack_direction() * Interpreter::stackElementWords;
}
// Adapter frame traversal. (Implementation-specific.)
static frame ricochet_frame_sender(const frame& fr, RegisterMap* reg_map);
static void ricochet_frame_oops_do(const frame& fr, OopClosure* blk, const RegisterMap* reg_map);
enum { CONV_VMINFO_SIGN_FLAG = 0x80 };
// Shift values for prim-to-prim conversions.
static int adapter_prim_to_prim_subword_vminfo(BasicType dest) {
@ -429,6 +685,7 @@ class MethodHandles: AllStatic {
// Fill in the fields of an AdapterMethodHandle mh. (MH.type must be pre-filled.)
static void init_AdapterMethodHandle(Handle mh, Handle target, int argnum, TRAPS);
static void ensure_vmlayout_field(Handle target, TRAPS);
#ifdef ASSERT
static bool spot_check_entry_names();
@ -448,12 +705,54 @@ class MethodHandles: AllStatic {
return same_basic_type_for_arguments(src, dst, raw, true);
}
enum { // arg_mask values
static Symbol* convert_to_signature(oop type_str, bool polymorphic, TRAPS);
#ifdef TARGET_ARCH_x86
# include "methodHandles_x86.hpp"
#endif
#ifdef TARGET_ARCH_sparc
#define TARGET_ARCH_NYI_6939861 1 //FIXME
//# include "methodHandles_sparc.hpp"
#endif
#ifdef TARGET_ARCH_zero
#define TARGET_ARCH_NYI_6939861 1 //FIXME
//# include "methodHandles_zero.hpp"
#endif
#ifdef TARGET_ARCH_arm
#define TARGET_ARCH_NYI_6939861 1 //FIXME
//# include "methodHandles_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
#define TARGET_ARCH_NYI_6939861 1 //FIXME
//# include "methodHandles_ppc.hpp"
#endif
#ifdef TARGET_ARCH_NYI_6939861
// Here are some backward compatible declarations until the 6939861 ports are updated.
#define _adapter_flyby (_EK_LIMIT + 10)
#define _adapter_ricochet (_EK_LIMIT + 11)
#define _adapter_opt_spread_1 _adapter_opt_spread_1_ref
#define _adapter_opt_spread_more _adapter_opt_spread_ref
enum {
_INSERT_NO_MASK = -1,
_INSERT_REF_MASK = 0,
_INSERT_INT_MASK = 1,
_INSERT_LONG_MASK = 3
};
static void get_ek_bound_mh_info(EntryKind ek, BasicType& arg_type, int& arg_mask, int& arg_slots) {
arg_type = ek_bound_mh_arg_type(ek);
arg_mask = 0;
arg_slots = type2size[arg_type];;
}
static void get_ek_adapter_opt_swap_rot_info(EntryKind ek, int& swap_bytes, int& rotate) {
int swap_slots = ek_adapter_opt_swap_slots(ek);
rotate = ek_adapter_opt_swap_mode(ek);
swap_bytes = swap_slots * Interpreter::stackElementSize;
}
static int get_ek_adapter_opt_spread_info(EntryKind ek) {
return ek_adapter_opt_spread_count(ek);
}
static void insert_arg_slots(MacroAssembler* _masm,
RegisterOrConstant arg_slots,
int arg_mask,
@ -466,8 +765,7 @@ class MethodHandles: AllStatic {
Register temp_reg, Register temp2_reg, Register temp3_reg = noreg);
static void trace_method_handle(MacroAssembler* _masm, const char* adaptername) PRODUCT_RETURN;
static Symbol* convert_to_signature(oop type_str, bool polymorphic, TRAPS);
#endif //TARGET_ARCH_NYI_6939861
};

View File

@ -33,6 +33,7 @@
#include "oops/methodOop.hpp"
#include "oops/oop.inline.hpp"
#include "oops/oop.inline2.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/javaCalls.hpp"
@ -169,6 +170,11 @@ void frame::set_pc(address newpc ) {
}
// type testers
bool frame::is_ricochet_frame() const {
RicochetBlob* rcb = SharedRuntime::ricochet_blob();
return (_cb == rcb && rcb != NULL && rcb->returns_to_bounce_addr(_pc));
}
bool frame::is_deoptimized_frame() const {
assert(_deopt_state != unknown, "not answerable");
return _deopt_state == is_deoptimized;
@ -341,12 +347,18 @@ frame frame::java_sender() const {
frame frame::real_sender(RegisterMap* map) const {
frame result = sender(map);
while (result.is_runtime_frame()) {
while (result.is_runtime_frame() ||
result.is_ricochet_frame()) {
result = result.sender(map);
}
return result;
}
frame frame::sender_for_ricochet_frame(RegisterMap* map) const {
assert(is_ricochet_frame(), "");
return MethodHandles::ricochet_frame_sender(*this, map);
}
// Note: called by profiler - NOT for current thread
frame frame::profile_find_Java_sender_frame(JavaThread *thread) {
// If we don't recognize this frame, walk back up the stack until we do
@ -529,6 +541,7 @@ jint frame::interpreter_frame_expression_stack_size() const {
const char* frame::print_name() const {
if (is_native_frame()) return "Native";
if (is_interpreted_frame()) return "Interpreted";
if (is_ricochet_frame()) return "Ricochet";
if (is_compiled_frame()) {
if (is_deoptimized_frame()) return "Deoptimized";
return "Compiled";
@ -715,6 +728,8 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose
st->print("v ~RuntimeStub::%s", ((RuntimeStub *)_cb)->name());
} else if (_cb->is_deoptimization_stub()) {
st->print("v ~DeoptimizationBlob");
} else if (_cb->is_ricochet_stub()) {
st->print("v ~RichochetBlob");
} else if (_cb->is_exception_stub()) {
st->print("v ~ExceptionBlob");
} else if (_cb->is_safepoint_stub()) {
@ -978,6 +993,9 @@ void frame::oops_interpreted_arguments_do(Symbol* signature, bool has_receiver,
void frame::oops_code_blob_do(OopClosure* f, CodeBlobClosure* cf, const RegisterMap* reg_map) {
assert(_cb != NULL, "sanity check");
if (_cb == SharedRuntime::ricochet_blob()) {
oops_ricochet_do(f, reg_map);
}
if (_cb->oop_maps() != NULL) {
OopMapSet::oops_do(this, reg_map, f);
@ -996,6 +1014,11 @@ void frame::oops_code_blob_do(OopClosure* f, CodeBlobClosure* cf, const Register
cf->do_code_blob(_cb);
}
void frame::oops_ricochet_do(OopClosure* f, const RegisterMap* map) {
assert(is_ricochet_frame(), "");
MethodHandles::ricochet_frame_oops_do(*this, f, map);
}
class CompiledArgumentOopFinder: public SignatureInfo {
protected:
OopClosure* _f;

View File

@ -135,6 +135,7 @@ class frame VALUE_OBJ_CLASS_SPEC {
bool is_interpreted_frame() const;
bool is_java_frame() const;
bool is_entry_frame() const; // Java frame called from C?
bool is_ricochet_frame() const;
bool is_native_frame() const;
bool is_runtime_frame() const;
bool is_compiled_frame() const;
@ -175,6 +176,7 @@ class frame VALUE_OBJ_CLASS_SPEC {
// Helper methods for better factored code in frame::sender
frame sender_for_compiled_frame(RegisterMap* map) const;
frame sender_for_entry_frame(RegisterMap* map) const;
frame sender_for_ricochet_frame(RegisterMap* map) const;
frame sender_for_interpreter_frame(RegisterMap* map) const;
frame sender_for_native_frame(RegisterMap* map) const;
@ -400,6 +402,7 @@ class frame VALUE_OBJ_CLASS_SPEC {
// Oops-do's
void oops_compiled_arguments_do(Symbol* signature, bool has_receiver, const RegisterMap* reg_map, OopClosure* f);
void oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool query_oop_map_cache = true);
void oops_ricochet_do(OopClosure* f, const RegisterMap* map);
private:
void oops_interpreted_arguments_do(Symbol* signature, bool has_receiver, OopClosure* f);

View File

@ -3708,6 +3708,10 @@ class CommandLineFlags {
diagnostic(bool, OptimizeMethodHandles, true, \
"when constructing method handles, try to improve them") \
\
diagnostic(bool, UseRicochetFrames, true, \
"use ricochet stack frames for method handle combination, " \
"if the platform supports them") \
\
experimental(bool, TrustFinalNonStaticFields, false, \
"trust final non-static declarations for constant folding") \
\

View File

@ -88,6 +88,8 @@ HS_DTRACE_PROBE_DECL7(hotspot, method__entry, int,
HS_DTRACE_PROBE_DECL7(hotspot, method__return, int,
char*, int, char*, int, char*, int);
RicochetBlob* SharedRuntime::_ricochet_blob = NULL;
// Implementation of SharedRuntime
#ifndef PRODUCT
@ -460,6 +462,10 @@ address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* thre
if (Interpreter::contains(return_address)) {
return Interpreter::rethrow_exception_entry();
}
// Ricochet frame unwind code
if (SharedRuntime::ricochet_blob() != NULL && SharedRuntime::ricochet_blob()->returns_to_bounce_addr(return_address)) {
return SharedRuntime::ricochet_blob()->exception_addr();
}
guarantee(blob == NULL || !blob->is_runtime_stub(), "caller should have skipped stub");
guarantee(!VtableStubs::contains(return_address), "NULL exceptions in vtables should have been handled already!");
@ -1174,6 +1180,7 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method_ic_miss(JavaThread*
assert(stub_frame.is_runtime_frame(), "sanity check");
frame caller_frame = stub_frame.sender(&reg_map);
assert(!caller_frame.is_interpreted_frame() && !caller_frame.is_entry_frame(), "unexpected frame");
assert(!caller_frame.is_ricochet_frame(), "unexpected frame");
#endif /* ASSERT */
methodHandle callee_method;
@ -1222,6 +1229,7 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method(JavaThread* thread))
if (caller_frame.is_interpreted_frame() ||
caller_frame.is_entry_frame() ||
caller_frame.is_ricochet_frame() ||
is_mh_invoke_via_adapter) {
methodOop callee = thread->callee_target();
guarantee(callee != NULL && callee->is_method(), "bad handshake");

View File

@ -58,6 +58,8 @@ class SharedRuntime: AllStatic {
static RuntimeStub* _resolve_virtual_call_blob;
static RuntimeStub* _resolve_static_call_blob;
static RicochetBlob* _ricochet_blob;
static SafepointBlob* _polling_page_safepoint_handler_blob;
static SafepointBlob* _polling_page_return_handler_blob;
#ifdef COMPILER2
@ -213,6 +215,16 @@ class SharedRuntime: AllStatic {
return _resolve_static_call_blob->entry_point();
}
static RicochetBlob* ricochet_blob() {
#ifdef X86
// Currently only implemented on x86
assert(!EnableInvokeDynamic || _ricochet_blob != NULL, "oops");
#endif
return _ricochet_blob;
}
static void generate_ricochet_blob();
static SafepointBlob* polling_page_return_handler_blob() { return _polling_page_return_handler_blob; }
static SafepointBlob* polling_page_safepoint_handler_blob() { return _polling_page_safepoint_handler_blob; }

View File

@ -1649,6 +1649,9 @@ int VM_HeapDumper::do_thread(JavaThread* java_thread, u4 thread_serial_num) {
if (fr->is_entry_frame()) {
last_entry_frame = fr;
}
if (fr->is_ricochet_frame()) {
fr->oops_ricochet_do(&blk, vf->register_map());
}
}
vf = vf->sender();
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
/**
* @test
* @bug 7042153
* @summary Bad folding of IfOps with unloaded constant arguments in C1
*
* @run main/othervm -Xcomp Test7042153
*/
import java.lang.reflect.*;
public class Test7042153 {
static public class Bar { }
static public class Foo { }
static volatile boolean z;
public static void main(String [] args) {
Class cx = Bar.class;
Class cy = Foo.class;
z = (cx == cy);
}
}