6655638: dynamic languages need method handles
Initial implementation, with known omissions (x86/64, sparc, compiler optim., c-oops, C++ interp.) Reviewed-by: kvn, twisti, never
This commit is contained in:
parent
318da3f68c
commit
ce0c084720
@ -3029,6 +3029,58 @@ void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass,
|
||||
|
||||
|
||||
|
||||
void MacroAssembler::check_method_handle_type(Register mtype_reg, Register mh_reg,
|
||||
Register temp_reg,
|
||||
Label& wrong_method_type) {
|
||||
assert_different_registers(mtype_reg, mh_reg, temp_reg);
|
||||
// compare method type against that of the receiver
|
||||
RegisterOrConstant mhtype_offset = delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg);
|
||||
ld_ptr(mh_reg, mhtype_offset, temp_reg);
|
||||
cmp(temp_reg, mtype_reg);
|
||||
br(Assembler::notEqual, false, Assembler::pn, wrong_method_type);
|
||||
delayed()->nop();
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::jump_to_method_handle_entry(Register mh_reg, Register temp_reg) {
|
||||
assert(mh_reg == G3_method_handle, "caller must put MH object in G3");
|
||||
assert_different_registers(mh_reg, temp_reg);
|
||||
|
||||
// pick out the interpreted side of the handler
|
||||
ld_ptr(mh_reg, delayed_value(java_dyn_MethodHandle::vmentry_offset_in_bytes, temp_reg), temp_reg);
|
||||
|
||||
// off we go...
|
||||
ld_ptr(temp_reg, MethodHandleEntry::from_interpreted_entry_offset_in_bytes(), temp_reg);
|
||||
jmp(temp_reg, 0);
|
||||
|
||||
// for the various stubs which take control at this point,
|
||||
// see MethodHandles::generate_method_handle_stub
|
||||
|
||||
// (Can any caller use this delay slot? If so, add an option for supression.)
|
||||
delayed()->nop();
|
||||
}
|
||||
|
||||
RegisterOrConstant MacroAssembler::argument_offset(RegisterOrConstant arg_slot,
|
||||
int extra_slot_offset) {
|
||||
// cf. TemplateTable::prepare_invoke(), if (load_receiver).
|
||||
int stackElementSize = Interpreter::stackElementWords() * wordSize;
|
||||
int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
|
||||
int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1);
|
||||
assert(offset1 - offset == stackElementSize, "correct arithmetic");
|
||||
if (arg_slot.is_constant()) {
|
||||
offset += arg_slot.as_constant() * stackElementSize;
|
||||
return offset;
|
||||
} else {
|
||||
Register temp = arg_slot.as_register();
|
||||
sll_ptr(temp, exact_log2(stackElementSize), temp);
|
||||
if (offset != 0)
|
||||
add(temp, offset, temp);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg,
|
||||
Register temp_reg,
|
||||
Label& done, Label* slow_case,
|
||||
|
@ -84,6 +84,10 @@ REGISTER_DECLARATION(Register, G4_scratch , G4);
|
||||
|
||||
REGISTER_DECLARATION(Register, Gtemp , G5);
|
||||
|
||||
// JSR 292 fixed register usages:
|
||||
REGISTER_DECLARATION(Register, G5_method_type , G5);
|
||||
REGISTER_DECLARATION(Register, G3_method_handle , G3);
|
||||
|
||||
// The compiler requires that G5_megamorphic_method is G5_inline_cache_klass,
|
||||
// because a single patchable "set" instruction (NativeMovConstReg,
|
||||
// or NativeMovConstPatching for compiler1) instruction
|
||||
@ -91,9 +95,13 @@ REGISTER_DECLARATION(Register, Gtemp , G5);
|
||||
// call site is an inline cache or is megamorphic. See the function
|
||||
// CompiledIC::set_to_megamorphic.
|
||||
//
|
||||
// On the other hand, G5_inline_cache_klass must differ from G5_method,
|
||||
// because both registers are needed for an inline cache that calls
|
||||
// an interpreted method.
|
||||
// If a inline cache targets an interpreted method, then the
|
||||
// G5 register will be used twice during the call. First,
|
||||
// the call site will be patched to load a compiledICHolder
|
||||
// into G5. (This is an ordered pair of ic_klass, method.)
|
||||
// The c2i adapter will first check the ic_klass, then load
|
||||
// G5_method with the method part of the pair just before
|
||||
// jumping into the interpreter.
|
||||
//
|
||||
// Note that G5_method is only the method-self for the interpreter,
|
||||
// and is logically unrelated to G5_megamorphic_method.
|
||||
@ -1931,6 +1939,7 @@ class MacroAssembler: public Assembler {
|
||||
inline void store_ptr_contents( Register s, Address& a, int offset = 0 );
|
||||
inline void jumpl_to( Address& a, Register d, int offset = 0 );
|
||||
inline void jump_to( Address& a, int offset = 0 );
|
||||
inline void jump_indirect_to( Address& a, Register temp, int ld_offset = 0, int jmp_offset = 0 );
|
||||
|
||||
// ring buffer traceable jumps
|
||||
|
||||
@ -2366,6 +2375,16 @@ class MacroAssembler: public Assembler {
|
||||
Register temp2_reg,
|
||||
Label& L_success);
|
||||
|
||||
// method handles (JSR 292)
|
||||
void check_method_handle_type(Register mtype_reg, Register mh_reg,
|
||||
Register temp_reg,
|
||||
Label& wrong_method_type);
|
||||
void jump_to_method_handle_entry(Register mh_reg, Register temp_reg);
|
||||
// offset relative to Gargs of argument at tos[arg_slot].
|
||||
// (arg_slot == 0 means the last argument, not the first).
|
||||
RegisterOrConstant argument_offset(RegisterOrConstant arg_slot,
|
||||
int extra_slot_offset = 0);
|
||||
|
||||
|
||||
// Stack overflow checking
|
||||
|
||||
|
@ -671,6 +671,15 @@ inline void MacroAssembler::jump_to( Address& a, int offset ) {
|
||||
}
|
||||
|
||||
|
||||
inline void MacroAssembler::jump_indirect_to( Address& a, Register temp,
|
||||
int ld_offset, int jmp_offset ) {
|
||||
assert_not_delayed();
|
||||
//sethi(a); // sethi is caller responsibility for this one
|
||||
ld_ptr(a, temp, ld_offset);
|
||||
jmp(temp, jmp_offset);
|
||||
}
|
||||
|
||||
|
||||
inline void MacroAssembler::set_oop( jobject obj, Register d ) {
|
||||
set_oop(allocate_oop_address(obj, d));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2007-2009 Sun Microsystems, Inc. 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
|
||||
@ -1017,6 +1017,7 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
|
||||
const int slop_factor = 2*wordSize;
|
||||
|
||||
const int fixed_size = ((sizeof(BytecodeInterpreter) + slop_factor) >> LogBytesPerWord) + // what is the slop factor?
|
||||
//6815692//methodOopDesc::extra_stack_words() + // extra push slots for MH adapters
|
||||
frame::memory_parameter_word_sp_offset + // register save area + param window
|
||||
(native ? frame::interpreter_frame_extra_outgoing_argument_words : 0); // JNI, class
|
||||
|
||||
@ -1163,6 +1164,9 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
|
||||
__ st_ptr(O2, XXX_STATE(_stack)); // PREPUSH
|
||||
|
||||
__ lduh(max_stack, O3); // Full size expression stack
|
||||
guarantee(!EnableMethodHandles, "no support yet for java.dyn.MethodHandle"); //6815692
|
||||
//6815692//if (EnableMethodHandles)
|
||||
//6815692// __ inc(O3, methodOopDesc::extra_stack_entries());
|
||||
__ sll(O3, LogBytesPerWord, O3);
|
||||
__ sub(O2, O3, O3);
|
||||
// __ sub(O3, wordSize, O3); // so prepush doesn't look out of bounds
|
||||
@ -2017,7 +2021,9 @@ static int size_activation_helper(int callee_extra_locals, int max_stack, int mo
|
||||
|
||||
const int fixed_size = sizeof(BytecodeInterpreter)/wordSize + // interpreter state object
|
||||
frame::memory_parameter_word_sp_offset; // register save area + param window
|
||||
const int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
|
||||
return (round_to(max_stack +
|
||||
extra_stack +
|
||||
slop_factor +
|
||||
fixed_size +
|
||||
monitor_size +
|
||||
@ -2104,7 +2110,8 @@ void BytecodeInterpreter::layout_interpreterState(interpreterState to_fill,
|
||||
// Need +1 here because stack_base points to the word just above the first expr stack entry
|
||||
// and stack_limit is supposed to point to the word just below the last expr stack entry.
|
||||
// See generate_compute_interpreter_state.
|
||||
to_fill->_stack_limit = stack_base - (method->max_stack() + 1);
|
||||
int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
|
||||
to_fill->_stack_limit = stack_base - (method->max_stack() + 1 + extra_stack);
|
||||
to_fill->_monitor_base = (BasicObjectLock*) monitor_base;
|
||||
|
||||
// sparc specific
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -29,6 +29,7 @@
|
||||
address generate_normal_entry(bool synchronized);
|
||||
address generate_native_entry(bool synchronized);
|
||||
address generate_abstract_entry(void);
|
||||
address generate_method_handle_entry(void);
|
||||
address generate_math_entry(AbstractInterpreter::MethodKind kind);
|
||||
address generate_empty_entry(void);
|
||||
address generate_accessor_entry(void);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -235,6 +235,19 @@ address InterpreterGenerator::generate_abstract_entry(void) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Method handle invoker
|
||||
// Dispatch a method of the form java.dyn.MethodHandles::invoke(...)
|
||||
address InterpreterGenerator::generate_method_handle_entry(void) {
|
||||
if (!EnableMethodHandles) {
|
||||
return generate_abstract_entry();
|
||||
}
|
||||
return generate_abstract_entry(); //6815692//
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
// Entry points & stack frame layout
|
||||
//
|
||||
@ -364,6 +377,7 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter:
|
||||
case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break;
|
||||
case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break;
|
||||
case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break;
|
||||
case Interpreter::method_handle : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
|
||||
case Interpreter::java_lang_math_sin : break;
|
||||
case Interpreter::java_lang_math_cos : break;
|
||||
case Interpreter::java_lang_math_tan : break;
|
||||
|
70
hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp
Normal file
70
hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "incls/_precompiled.incl"
|
||||
#include "incls/_methodHandles_sparc.cpp.incl"
|
||||
|
||||
#define __ _masm->
|
||||
|
||||
address MethodHandleEntry::start_compiled_entry(MacroAssembler* _masm,
|
||||
address interpreted_entry) {
|
||||
__ align(wordSize);
|
||||
address target = __ pc() + sizeof(Data);
|
||||
while (__ pc() < target) {
|
||||
__ nop();
|
||||
__ align(wordSize);
|
||||
}
|
||||
|
||||
MethodHandleEntry* me = (MethodHandleEntry*) __ pc();
|
||||
me->set_end_address(__ pc()); // set a temporary end_address
|
||||
me->set_from_interpreted_entry(interpreted_entry);
|
||||
me->set_type_checking_entry(NULL);
|
||||
|
||||
return (address) me;
|
||||
}
|
||||
|
||||
MethodHandleEntry* MethodHandleEntry::finish_compiled_entry(MacroAssembler* _masm,
|
||||
address start_addr) {
|
||||
MethodHandleEntry* me = (MethodHandleEntry*) start_addr;
|
||||
assert(me->end_address() == start_addr, "valid ME");
|
||||
|
||||
// Fill in the real end_address:
|
||||
__ align(wordSize);
|
||||
me->set_end_address(__ pc());
|
||||
|
||||
return me;
|
||||
}
|
||||
|
||||
|
||||
// Code generation
|
||||
address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) {
|
||||
ShouldNotReachHere(); //NYI, 6815692
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Generate an "entry" field for a method handle.
|
||||
// This determines how the method handle will respond to calls.
|
||||
void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) {
|
||||
ShouldNotReachHere(); //NYI, 6815692
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2002-2009 Sun Microsystems, Inc. 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
|
||||
@ -142,6 +142,8 @@ REGISTER_DEFINITION(Register, G1_scratch);
|
||||
REGISTER_DEFINITION(Register, G3_scratch);
|
||||
REGISTER_DEFINITION(Register, G4_scratch);
|
||||
REGISTER_DEFINITION(Register, Gtemp);
|
||||
REGISTER_DEFINITION(Register, G5_method_type);
|
||||
REGISTER_DEFINITION(Register, G3_method_handle);
|
||||
REGISTER_DEFINITION(Register, Lentry_args);
|
||||
|
||||
#ifdef CC_INTERP
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2003-2009 Sun Microsystems, Inc. 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
|
||||
@ -937,12 +937,12 @@ void AdapterGenerator::gen_i2c_adapter(
|
||||
// Inputs:
|
||||
// G2_thread - TLS
|
||||
// G5_method - Method oop
|
||||
// O0 - Flag telling us to restore SP from O5
|
||||
// O4_args - Pointer to interpreter's args
|
||||
// O5 - Caller's saved SP, to be restored if needed
|
||||
// G4 (Gargs) - Pointer to interpreter's args
|
||||
// O0..O4 - free for scratch
|
||||
// O5_savedSP - Caller's saved SP, to be restored if needed
|
||||
// O6 - Current SP!
|
||||
// O7 - Valid return address
|
||||
// L0-L7, I0-I7 - Caller's temps (no frame pushed yet)
|
||||
// L0-L7, I0-I7 - Caller's temps (no frame pushed yet)
|
||||
|
||||
// Outputs:
|
||||
// G2_thread - TLS
|
||||
@ -954,7 +954,7 @@ void AdapterGenerator::gen_i2c_adapter(
|
||||
// F0-F7 - more outgoing args
|
||||
|
||||
|
||||
// O4 is about to get loaded up with compiled callee's args
|
||||
// Gargs is the incoming argument base, and also an outgoing argument.
|
||||
__ sub(Gargs, BytesPerWord, Gargs);
|
||||
|
||||
#ifdef ASSERT
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -108,6 +108,24 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
|
||||
}
|
||||
|
||||
|
||||
// Arguments are: required type in G5_method_type, and
|
||||
// failing object (or NULL) in G3_method_handle.
|
||||
address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
|
||||
address entry = __ pc();
|
||||
// expression stack must be empty before entering the VM if an exception
|
||||
// happened
|
||||
__ empty_expression_stack();
|
||||
// load exception object
|
||||
__ call_VM(Oexception,
|
||||
CAST_FROM_FN_PTR(address,
|
||||
InterpreterRuntime::throw_WrongMethodTypeException),
|
||||
G5_method_type, // required
|
||||
G3_method_handle); // actual
|
||||
__ should_not_reach_here();
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) {
|
||||
address entry = __ pc();
|
||||
// expression stack must be empty before entering the VM if an exception happened
|
||||
@ -448,6 +466,7 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
|
||||
|
||||
const int extra_space =
|
||||
rounded_vm_local_words + // frame local scratch space
|
||||
//6815692//methodOopDesc::extra_stack_words() + // extra push slots for MH adapters
|
||||
frame::memory_parameter_word_sp_offset + // register save area
|
||||
(native_call ? frame::interpreter_frame_extra_outgoing_argument_words : 0);
|
||||
|
||||
@ -1447,6 +1466,7 @@ static int size_activation_helper(int callee_extra_locals, int max_stack, int mo
|
||||
round_to(callee_extra_locals * Interpreter::stackElementWords(), WordsPerLong);
|
||||
const int max_stack_words = max_stack * Interpreter::stackElementWords();
|
||||
return (round_to((max_stack_words
|
||||
//6815692//+ methodOopDesc::extra_stack_words()
|
||||
+ rounded_vm_local_words
|
||||
+ frame::memory_parameter_word_sp_offset), WordsPerLong)
|
||||
// already rounded
|
||||
|
@ -7609,6 +7609,83 @@ RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_ad
|
||||
}
|
||||
|
||||
|
||||
// registers on entry:
|
||||
// - rax ('check' register): required MethodType
|
||||
// - rcx: method handle
|
||||
// - rdx, rsi, or ?: killable temp
|
||||
void MacroAssembler::check_method_handle_type(Register mtype_reg, Register mh_reg,
|
||||
Register temp_reg,
|
||||
Label& wrong_method_type) {
|
||||
if (UseCompressedOops) unimplemented(); // field accesses must decode
|
||||
// compare method type against that of the receiver
|
||||
cmpptr(mtype_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg)));
|
||||
jcc(Assembler::notEqual, wrong_method_type);
|
||||
}
|
||||
|
||||
|
||||
// A method handle has a "vmslots" field which gives the size of its
|
||||
// argument list in JVM stack slots. This field is either located directly
|
||||
// in every method handle, or else is indirectly accessed through the
|
||||
// method handle's MethodType. This macro hides the distinction.
|
||||
void MacroAssembler::load_method_handle_vmslots(Register vmslots_reg, Register mh_reg,
|
||||
Register temp_reg) {
|
||||
if (UseCompressedOops) unimplemented(); // field accesses must decode
|
||||
// load mh.type.form.vmslots
|
||||
if (java_dyn_MethodHandle::vmslots_offset_in_bytes() != 0) {
|
||||
// hoist vmslots into every mh to avoid dependent load chain
|
||||
movl(vmslots_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::vmslots_offset_in_bytes, temp_reg)));
|
||||
} else {
|
||||
Register temp2_reg = vmslots_reg;
|
||||
movptr(temp2_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg)));
|
||||
movptr(temp2_reg, Address(temp2_reg, delayed_value(java_dyn_MethodType::form_offset_in_bytes, temp_reg)));
|
||||
movl(vmslots_reg, Address(temp2_reg, delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, temp_reg)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// registers on entry:
|
||||
// - rcx: method handle
|
||||
// - rdx: killable temp (interpreted only)
|
||||
// - rax: killable temp (compiled only)
|
||||
void MacroAssembler::jump_to_method_handle_entry(Register mh_reg, Register temp_reg) {
|
||||
assert(mh_reg == rcx, "caller must put MH object in rcx");
|
||||
assert_different_registers(mh_reg, temp_reg);
|
||||
|
||||
if (UseCompressedOops) unimplemented(); // field accesses must decode
|
||||
|
||||
// pick out the interpreted side of the handler
|
||||
movptr(temp_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::vmentry_offset_in_bytes, temp_reg)));
|
||||
|
||||
// off we go...
|
||||
jmp(Address(temp_reg, MethodHandleEntry::from_interpreted_entry_offset_in_bytes()));
|
||||
|
||||
// for the various stubs which take control at this point,
|
||||
// see MethodHandles::generate_method_handle_stub
|
||||
}
|
||||
|
||||
|
||||
Address MacroAssembler::argument_address(RegisterOrConstant arg_slot,
|
||||
int extra_slot_offset) {
|
||||
// cf. TemplateTable::prepare_invoke(), if (load_receiver).
|
||||
int stackElementSize = Interpreter::stackElementSize();
|
||||
int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
|
||||
#ifdef ASSERT
|
||||
int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1);
|
||||
assert(offset1 - offset == stackElementSize, "correct arithmetic");
|
||||
#endif
|
||||
Register scale_reg = noreg;
|
||||
Address::ScaleFactor scale_factor = Address::no_scale;
|
||||
if (arg_slot.is_constant()) {
|
||||
offset += arg_slot.as_constant() * stackElementSize;
|
||||
} else {
|
||||
scale_reg = arg_slot.as_register();
|
||||
scale_factor = Address::times(stackElementSize);
|
||||
}
|
||||
offset += wordSize; // return PC is on stack
|
||||
return Address(rsp, scale_reg, scale_factor, offset);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::verify_oop_addr(Address addr, const char* s) {
|
||||
if (!VerifyOops) return;
|
||||
|
||||
|
@ -1857,6 +1857,16 @@ class MacroAssembler: public Assembler {
|
||||
Register temp_reg,
|
||||
Label& L_success);
|
||||
|
||||
// method handles (JSR 292)
|
||||
void check_method_handle_type(Register mtype_reg, Register mh_reg,
|
||||
Register temp_reg,
|
||||
Label& wrong_method_type);
|
||||
void load_method_handle_vmslots(Register vmslots_reg, Register mh_reg,
|
||||
Register temp_reg);
|
||||
void jump_to_method_handle_entry(Register mh_reg, Register temp_reg);
|
||||
Address argument_address(RegisterOrConstant arg_slot, int extra_slot_offset = 0);
|
||||
|
||||
|
||||
//----
|
||||
void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0
|
||||
|
||||
|
@ -513,10 +513,11 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
|
||||
// compute full expression stack limit
|
||||
|
||||
const Address size_of_stack (rbx, methodOopDesc::max_stack_offset());
|
||||
const int extra_stack = 0; //6815692//methodOopDesc::extra_stack_words();
|
||||
__ load_unsigned_short(rdx, size_of_stack); // get size of expression stack in words
|
||||
__ negptr(rdx); // so we can subtract in next step
|
||||
// Allocate expression stack
|
||||
__ lea(rsp, Address(rsp, rdx, Address::times_ptr));
|
||||
__ lea(rsp, Address(rsp, rdx, Address::times_ptr, -extra_stack));
|
||||
__ movptr(STATE(_stack_limit), rsp);
|
||||
}
|
||||
|
||||
@ -659,8 +660,9 @@ void InterpreterGenerator::generate_stack_overflow_check(void) {
|
||||
// Always give one monitor to allow us to start interp if sync method.
|
||||
// Any additional monitors need a check when moving the expression stack
|
||||
const int one_monitor = frame::interpreter_frame_monitor_size() * wordSize;
|
||||
const int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
|
||||
__ load_unsigned_short(rax, size_of_stack); // get size of expression stack in words
|
||||
__ lea(rax, Address(noreg, rax, Interpreter::stackElementScale(), one_monitor));
|
||||
__ lea(rax, Address(noreg, rax, Interpreter::stackElementScale(), extra_stack + one_monitor));
|
||||
__ lea(rax, Address(rax, rdx, Interpreter::stackElementScale(), overhead_size));
|
||||
|
||||
#ifdef ASSERT
|
||||
@ -2185,6 +2187,7 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter:
|
||||
case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break;
|
||||
case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break;
|
||||
case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break;
|
||||
case Interpreter::method_handle : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
|
||||
|
||||
case Interpreter::java_lang_math_sin : // fall thru
|
||||
case Interpreter::java_lang_math_cos : // fall thru
|
||||
@ -2224,7 +2227,8 @@ int AbstractInterpreter::size_top_interpreter_activation(methodOop method) {
|
||||
const int overhead_size = sizeof(BytecodeInterpreter)/wordSize +
|
||||
( frame::sender_sp_offset - frame::link_offset) + 2;
|
||||
|
||||
const int method_stack = (method->max_locals() + method->max_stack()) *
|
||||
const int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
|
||||
const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) *
|
||||
Interpreter::stackElementWords();
|
||||
return overhead_size + method_stack + stub_code;
|
||||
}
|
||||
@ -2289,7 +2293,8 @@ void BytecodeInterpreter::layout_interpreterState(interpreterState to_fill,
|
||||
// Need +1 here because stack_base points to the word just above the first expr stack entry
|
||||
// and stack_limit is supposed to point to the word just below the last expr stack entry.
|
||||
// See generate_compute_interpreter_state.
|
||||
to_fill->_stack_limit = stack_base - (method->max_stack() + 1);
|
||||
int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
|
||||
to_fill->_stack_limit = stack_base - (method->max_stack() + extra_stack + 1);
|
||||
to_fill->_monitor_base = (BasicObjectLock*) monitor_base;
|
||||
|
||||
to_fill->_self_link = to_fill;
|
||||
@ -2335,7 +2340,8 @@ int AbstractInterpreter::layout_activation(methodOop method,
|
||||
monitor_size);
|
||||
|
||||
// Now with full size expression stack
|
||||
int full_frame_size = short_frame_size + method->max_stack() * BytesPerWord;
|
||||
int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
|
||||
int full_frame_size = short_frame_size + (method->max_stack() + extra_stack) * BytesPerWord;
|
||||
|
||||
// and now with only live portion of the expression stack
|
||||
short_frame_size = short_frame_size + tempcount * BytesPerWord;
|
||||
|
@ -555,13 +555,18 @@ void InterpreterMacroAssembler::super_call_VM_leaf(address entry_point, Register
|
||||
}
|
||||
|
||||
|
||||
// Jump to from_interpreted entry of a call unless single stepping is possible
|
||||
// in this thread in which case we must call the i2i entry
|
||||
void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
|
||||
void InterpreterMacroAssembler::prepare_to_jump_from_interpreted() {
|
||||
// set sender sp
|
||||
lea(rsi, Address(rsp, wordSize));
|
||||
// record last_sp
|
||||
movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), rsi);
|
||||
}
|
||||
|
||||
|
||||
// Jump to from_interpreted entry of a call unless single stepping is possible
|
||||
// in this thread in which case we must call the i2i entry
|
||||
void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
|
||||
prepare_to_jump_from_interpreted();
|
||||
|
||||
if (JvmtiExport::can_post_interpreter_events()) {
|
||||
Label run_compiled_code;
|
||||
|
@ -161,6 +161,7 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
|
||||
|
||||
// jump to an invoked target
|
||||
void prepare_to_jump_from_interpreted();
|
||||
void jump_from_interpreted(Register method, Register temp);
|
||||
|
||||
// Returning from interpreted functions
|
||||
|
@ -551,13 +551,18 @@ void InterpreterMacroAssembler::super_call_VM_leaf(address entry_point,
|
||||
MacroAssembler::call_VM_leaf_base(entry_point, 3);
|
||||
}
|
||||
|
||||
// Jump to from_interpreted entry of a call unless single stepping is possible
|
||||
// in this thread in which case we must call the i2i entry
|
||||
void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
|
||||
void InterpreterMacroAssembler::prepare_to_jump_from_interpreted() {
|
||||
// set sender sp
|
||||
lea(r13, Address(rsp, wordSize));
|
||||
// record last_sp
|
||||
movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), r13);
|
||||
}
|
||||
|
||||
|
||||
// Jump to from_interpreted entry of a call unless single stepping is possible
|
||||
// in this thread in which case we must call the i2i entry
|
||||
void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
|
||||
prepare_to_jump_from_interpreted();
|
||||
|
||||
if (JvmtiExport::can_post_interpreter_events()) {
|
||||
Label run_compiled_code;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2003-2009 Sun Microsystems, Inc. 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
|
||||
@ -176,6 +176,7 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
void dispatch_via (TosState state, address* table);
|
||||
|
||||
// jump to an invoked target
|
||||
void prepare_to_jump_from_interpreted();
|
||||
void jump_from_interpreted(Register method, Register temp);
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -32,6 +32,7 @@
|
||||
address generate_normal_entry(bool synchronized);
|
||||
address generate_native_entry(bool synchronized);
|
||||
address generate_abstract_entry(void);
|
||||
address generate_method_handle_entry(void);
|
||||
address generate_math_entry(AbstractInterpreter::MethodKind kind);
|
||||
address generate_empty_entry(void);
|
||||
address generate_accessor_entry(void);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -201,11 +201,12 @@ address InterpreterGenerator::generate_abstract_entry(void) {
|
||||
address entry_point = __ pc();
|
||||
|
||||
// abstract method entry
|
||||
// remove return address. Not really needed, since exception handling throws away expression stack
|
||||
__ pop(rbx);
|
||||
|
||||
// adjust stack to what a normal return would do
|
||||
__ mov(rsp, rsi);
|
||||
// pop return address, reset last_sp to NULL
|
||||
__ empty_expression_stack();
|
||||
__ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
|
||||
__ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
|
||||
|
||||
// throw exception
|
||||
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
|
||||
// the call_VM checks for exception, so we should never return here.
|
||||
@ -214,6 +215,20 @@ address InterpreterGenerator::generate_abstract_entry(void) {
|
||||
return entry_point;
|
||||
}
|
||||
|
||||
|
||||
// Method handle invoker
|
||||
// Dispatch a method of the form java.dyn.MethodHandles::invoke(...)
|
||||
address InterpreterGenerator::generate_method_handle_entry(void) {
|
||||
if (!EnableMethodHandles) {
|
||||
return generate_abstract_entry();
|
||||
}
|
||||
|
||||
address entry_point = MethodHandles::generate_method_handle_interpreter_entry(_masm);
|
||||
|
||||
return entry_point;
|
||||
}
|
||||
|
||||
|
||||
// This method tells the deoptimizer how big an interpreted frame must be:
|
||||
int AbstractInterpreter::size_activation(methodOop method,
|
||||
int tempcount,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2003-2009 Sun Microsystems, Inc. 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
|
||||
@ -294,6 +294,16 @@ address InterpreterGenerator::generate_abstract_entry(void) {
|
||||
}
|
||||
|
||||
|
||||
// Method handle invoker
|
||||
// Dispatch a method of the form java.dyn.MethodHandles::invoke(...)
|
||||
address InterpreterGenerator::generate_method_handle_entry(void) {
|
||||
if (!EnableMethodHandles) {
|
||||
return generate_abstract_entry();
|
||||
}
|
||||
return generate_abstract_entry(); //6815692//
|
||||
}
|
||||
|
||||
|
||||
// Empty method, generate a very fast return.
|
||||
|
||||
address InterpreterGenerator::generate_empty_entry(void) {
|
||||
|
1133
hotspot/src/cpu/x86/vm/methodHandles_x86.cpp
Normal file
1133
hotspot/src/cpu/x86/vm/methodHandles_x86.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -2219,6 +2219,16 @@ class StubGenerator: public StubCodeGenerator {
|
||||
|
||||
// arraycopy stubs used by compilers
|
||||
generate_arraycopy_stubs();
|
||||
|
||||
// generic method handle stubs
|
||||
if (EnableMethodHandles && SystemDictionary::MethodHandle_klass() != NULL) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -92,6 +92,33 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
|
||||
return entry;
|
||||
}
|
||||
|
||||
// Arguments are: required type at TOS+8, failing object (or NULL) at TOS+4.
|
||||
// pc at TOS (just for debugging)
|
||||
address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
|
||||
address entry = __ pc();
|
||||
|
||||
__ pop(rbx); // actual failing object is at TOS
|
||||
__ pop(rax); // required type is at TOS+4
|
||||
|
||||
__ verify_oop(rbx);
|
||||
__ verify_oop(rax);
|
||||
|
||||
// Various method handle types use interpreter registers as temps.
|
||||
__ restore_bcp();
|
||||
__ restore_locals();
|
||||
|
||||
// Expression stack must be empty before entering the VM for an exception.
|
||||
__ empty_expression_stack();
|
||||
__ empty_FPU_stack();
|
||||
__ call_VM(noreg,
|
||||
CAST_FROM_FN_PTR(address,
|
||||
InterpreterRuntime::throw_WrongMethodTypeException),
|
||||
// pass required type, failing object (or NULL)
|
||||
rax, rbx);
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) {
|
||||
assert(!pass_oop || message == NULL, "either oop or message but not both");
|
||||
address entry = __ pc();
|
||||
@ -1370,6 +1397,7 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter:
|
||||
case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break;
|
||||
case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break;
|
||||
case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break;
|
||||
case Interpreter::method_handle : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
|
||||
|
||||
case Interpreter::java_lang_math_sin : // fall thru
|
||||
case Interpreter::java_lang_math_cos : // fall thru
|
||||
@ -1400,7 +1428,8 @@ int AbstractInterpreter::size_top_interpreter_activation(methodOop method) {
|
||||
// be sure to change this if you add/subtract anything to/from the overhead area
|
||||
const int overhead_size = -frame::interpreter_frame_initial_sp_offset;
|
||||
|
||||
const int method_stack = (method->max_locals() + method->max_stack()) *
|
||||
const int extra_stack = methodOopDesc::extra_stack_entries();
|
||||
const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) *
|
||||
Interpreter::stackElementWords();
|
||||
return overhead_size + method_stack + stub_code;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2003-2009 Sun Microsystems, Inc. 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
|
||||
@ -100,6 +100,26 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
|
||||
return entry;
|
||||
}
|
||||
|
||||
// Arguments are: required type in rarg1, failing object (or NULL) in rarg2
|
||||
address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
|
||||
address entry = __ pc();
|
||||
|
||||
__ pop(c_rarg2); // failing object is at TOS
|
||||
__ pop(c_rarg1); // required type is at TOS+8
|
||||
|
||||
// expression stack must be empty before entering the VM if an
|
||||
// exception happened
|
||||
__ empty_expression_stack();
|
||||
|
||||
__ call_VM(noreg,
|
||||
CAST_FROM_FN_PTR(address,
|
||||
InterpreterRuntime::
|
||||
throw_WrongMethodTypeException),
|
||||
// pass required type, failing object (or NULL)
|
||||
c_rarg1, c_rarg2);
|
||||
return entry;
|
||||
}
|
||||
|
||||
address TemplateInterpreterGenerator::generate_exception_handler_common(
|
||||
const char* name, const char* message, bool pass_oop) {
|
||||
assert(!pass_oop || message == NULL, "either oop or message but not both");
|
||||
@ -1393,6 +1413,7 @@ address AbstractInterpreterGenerator::generate_method_entry(
|
||||
case Interpreter::empty : entry_point = ((InterpreterGenerator*) this)->generate_empty_entry(); break;
|
||||
case Interpreter::accessor : entry_point = ((InterpreterGenerator*) this)->generate_accessor_entry(); break;
|
||||
case Interpreter::abstract : entry_point = ((InterpreterGenerator*) this)->generate_abstract_entry(); break;
|
||||
case Interpreter::method_handle : entry_point = ((InterpreterGenerator*) this)->generate_method_handle_entry();break;
|
||||
|
||||
case Interpreter::java_lang_math_sin : // fall thru
|
||||
case Interpreter::java_lang_math_cos : // fall thru
|
||||
@ -1423,7 +1444,8 @@ int AbstractInterpreter::size_top_interpreter_activation(methodOop method) {
|
||||
-(frame::interpreter_frame_initial_sp_offset) + entry_size;
|
||||
|
||||
const int stub_code = frame::entry_frame_after_call_words;
|
||||
const int method_stack = (method->max_locals() + method->max_stack()) *
|
||||
const int extra_stack = methodOopDesc::extra_stack_entries();
|
||||
const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) *
|
||||
Interpreter::stackElementWords();
|
||||
return (overhead_size + method_stack + stub_code);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1999-2009 Sun Microsystems, Inc. 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
|
||||
@ -674,6 +674,30 @@ int ciMethod::scale_count(int count, float prof_factor) {
|
||||
return count;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// invokedynamic support
|
||||
//
|
||||
bool ciMethod::is_method_handle_invoke() {
|
||||
check_is_loaded();
|
||||
bool flag = ((flags().as_int() & JVM_MH_INVOKE_BITS) == JVM_MH_INVOKE_BITS);
|
||||
#ifdef ASSERT
|
||||
{
|
||||
VM_ENTRY_MARK;
|
||||
bool flag2 = get_methodOop()->is_method_handle_invoke();
|
||||
assert(flag == flag2, "consistent");
|
||||
}
|
||||
#endif //ASSERT
|
||||
return flag;
|
||||
}
|
||||
|
||||
ciInstance* ciMethod::method_handle_type() {
|
||||
check_is_loaded();
|
||||
VM_ENTRY_MARK;
|
||||
oop mtype = get_methodOop()->method_handle_type();
|
||||
return CURRENT_THREAD_ENV->get_object(mtype)->as_instance();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciMethod::build_method_data
|
||||
//
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1999-2009 Sun Microsystems, Inc. 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
|
||||
@ -207,6 +207,8 @@ class ciMethod : public ciObject {
|
||||
bool check_call(int refinfo_index, bool is_static) const;
|
||||
void build_method_data(); // make sure it exists in the VM also
|
||||
int scale_count(int count, float prof_factor = 1.); // make MDO count commensurate with IIC
|
||||
bool is_method_handle_invoke();
|
||||
ciInstance* method_handle_type();
|
||||
|
||||
// What kind of ciObject is this?
|
||||
bool is_method() { return true; }
|
||||
|
@ -1842,6 +1842,11 @@ methodHandle ClassFileParser::parse_method(constantPoolHandle cp, bool is_interf
|
||||
_has_vanilla_constructor = true;
|
||||
}
|
||||
|
||||
if (EnableMethodHandles && m->is_method_handle_invoke()) {
|
||||
THROW_MSG_(vmSymbols::java_lang_VirtualMachineError(),
|
||||
"Method handle invokers must be defined internally to the VM", nullHandle);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
@ -2465,9 +2470,84 @@ void ClassFileParser::java_lang_Class_fix_post(int* next_nonstatic_oop_offset_pt
|
||||
}
|
||||
|
||||
|
||||
// Force MethodHandle.vmentry to be an unmanaged pointer.
|
||||
// There is no way for a classfile to express this, so we must help it.
|
||||
void ClassFileParser::java_dyn_MethodHandle_fix_pre(constantPoolHandle cp,
|
||||
typeArrayHandle* fields_ptr,
|
||||
FieldAllocationCount *fac_ptr,
|
||||
TRAPS) {
|
||||
// Add fake fields for java.dyn.MethodHandle instances
|
||||
//
|
||||
// This is not particularly nice, but since there is no way to express
|
||||
// a native wordSize field in Java, we must do it at this level.
|
||||
|
||||
if (!EnableMethodHandles) return;
|
||||
|
||||
int word_sig_index = 0;
|
||||
const int cp_size = cp->length();
|
||||
for (int index = 1; index < cp_size; index++) {
|
||||
if (cp->tag_at(index).is_utf8() &&
|
||||
cp->symbol_at(index) == vmSymbols::machine_word_signature()) {
|
||||
word_sig_index = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (word_sig_index == 0)
|
||||
THROW_MSG(vmSymbols::java_lang_VirtualMachineError(),
|
||||
"missing I or J signature (for vmentry) in java.dyn.MethodHandle");
|
||||
|
||||
bool found_vmentry = false;
|
||||
|
||||
const int n = (*fields_ptr)()->length();
|
||||
for (int i = 0; i < n; i += instanceKlass::next_offset) {
|
||||
int name_index = (*fields_ptr)->ushort_at(i + instanceKlass::name_index_offset);
|
||||
int sig_index = (*fields_ptr)->ushort_at(i + instanceKlass::signature_index_offset);
|
||||
int acc_flags = (*fields_ptr)->ushort_at(i + instanceKlass::access_flags_offset);
|
||||
symbolOop f_name = cp->symbol_at(name_index);
|
||||
symbolOop f_sig = cp->symbol_at(sig_index);
|
||||
if (f_sig == vmSymbols::byte_signature() &&
|
||||
f_name == vmSymbols::vmentry_name() &&
|
||||
(acc_flags & JVM_ACC_STATIC) == 0) {
|
||||
// Adjust the field type from byte to an unmanaged pointer.
|
||||
assert(fac_ptr->nonstatic_byte_count > 0, "");
|
||||
fac_ptr->nonstatic_byte_count -= 1;
|
||||
(*fields_ptr)->ushort_at_put(i + instanceKlass::signature_index_offset,
|
||||
word_sig_index);
|
||||
if (wordSize == jintSize) {
|
||||
fac_ptr->nonstatic_word_count += 1;
|
||||
} else {
|
||||
fac_ptr->nonstatic_double_count += 1;
|
||||
}
|
||||
|
||||
FieldAllocationType atype = (FieldAllocationType) (*fields_ptr)->ushort_at(i+4);
|
||||
assert(atype == NONSTATIC_BYTE, "");
|
||||
FieldAllocationType new_atype = NONSTATIC_WORD;
|
||||
if (wordSize > jintSize) {
|
||||
if (Universe::field_type_should_be_aligned(T_LONG)) {
|
||||
atype = NONSTATIC_ALIGNED_DOUBLE;
|
||||
} else {
|
||||
atype = NONSTATIC_DOUBLE;
|
||||
}
|
||||
}
|
||||
(*fields_ptr)->ushort_at_put(i+4, new_atype);
|
||||
|
||||
found_vmentry = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_vmentry)
|
||||
THROW_MSG(vmSymbols::java_lang_VirtualMachineError(),
|
||||
"missing vmentry byte field in java.dyn.MethodHandle");
|
||||
|
||||
}
|
||||
|
||||
|
||||
instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
KlassHandle host_klass,
|
||||
GrowableArray<Handle>* cp_patches,
|
||||
symbolHandle& parsed_name,
|
||||
TRAPS) {
|
||||
@ -2500,6 +2580,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
|
||||
}
|
||||
}
|
||||
|
||||
_host_klass = host_klass;
|
||||
_cp_patches = cp_patches;
|
||||
|
||||
instanceKlassHandle nullHandle;
|
||||
@ -2808,6 +2889,11 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
|
||||
java_lang_Class_fix_pre(&methods, &fac, CHECK_(nullHandle));
|
||||
}
|
||||
|
||||
// adjust the vmentry field declaration in java.dyn.MethodHandle
|
||||
if (EnableMethodHandles && class_name() == vmSymbols::sun_dyn_MethodHandleImpl() && class_loader.is_null()) {
|
||||
java_dyn_MethodHandle_fix_pre(cp, &fields, &fac, CHECK_(nullHandle));
|
||||
}
|
||||
|
||||
// Add a fake "discovered" field if it is not present
|
||||
// for compatibility with earlier jdk's.
|
||||
if (class_name() == vmSymbols::java_lang_ref_Reference()
|
||||
@ -3134,7 +3220,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
|
||||
this_klass->set_method_ordering(method_ordering());
|
||||
this_klass->set_initial_method_idnum(methods->length());
|
||||
this_klass->set_name(cp->klass_name_at(this_class_index));
|
||||
if (LinkWellKnownClasses) // I am well known to myself
|
||||
if (LinkWellKnownClasses || is_anonymous()) // I am well known to myself
|
||||
cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve
|
||||
this_klass->set_protection_domain(protection_domain());
|
||||
this_klass->set_fields_annotations(fields_annotations());
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -33,6 +33,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
u2 _major_version;
|
||||
u2 _minor_version;
|
||||
symbolHandle _class_name;
|
||||
KlassHandle _host_klass;
|
||||
GrowableArray<Handle>* _cp_patches; // overrides for CP entries
|
||||
|
||||
bool _has_finalizer;
|
||||
@ -145,6 +146,11 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
// Adjust the next_nonstatic_oop_offset to place the fake fields
|
||||
// before any Java fields.
|
||||
void java_lang_Class_fix_post(int* next_nonstatic_oop_offset);
|
||||
// Adjust the field allocation counts for java.dyn.MethodHandle to add
|
||||
// a fake address (void*) field.
|
||||
void java_dyn_MethodHandle_fix_pre(constantPoolHandle cp,
|
||||
typeArrayHandle* fields_ptr,
|
||||
FieldAllocationCount *fac_ptr, TRAPS);
|
||||
|
||||
// Format checker methods
|
||||
void classfile_parse_error(const char* msg, TRAPS);
|
||||
@ -204,6 +210,10 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
char* skip_over_field_name(char* name, bool slash_ok, unsigned int length);
|
||||
char* skip_over_field_signature(char* signature, bool void_ok, unsigned int length, TRAPS);
|
||||
|
||||
bool is_anonymous() {
|
||||
assert(AnonymousClasses || _host_klass.is_null(), "");
|
||||
return _host_klass.not_null();
|
||||
}
|
||||
bool has_cp_patch_at(int index) {
|
||||
assert(AnonymousClasses, "");
|
||||
assert(index >= 0, "oob");
|
||||
@ -249,11 +259,13 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
Handle protection_domain,
|
||||
symbolHandle& parsed_name,
|
||||
TRAPS) {
|
||||
return parseClassFile(name, class_loader, protection_domain, NULL, parsed_name, THREAD);
|
||||
KlassHandle no_host_klass;
|
||||
return parseClassFile(name, class_loader, protection_domain, no_host_klass, NULL, parsed_name, THREAD);
|
||||
}
|
||||
instanceKlassHandle parseClassFile(symbolHandle name,
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
KlassHandle host_klass,
|
||||
GrowableArray<Handle>* cp_patches,
|
||||
symbolHandle& parsed_name,
|
||||
TRAPS);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2003-2009 Sun Microsystems, Inc. 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
|
||||
@ -549,6 +549,63 @@ void Dictionary::reorder_dictionary() {
|
||||
}
|
||||
}
|
||||
|
||||
SymbolPropertyTable::SymbolPropertyTable(int table_size)
|
||||
: Hashtable(table_size, sizeof(SymbolPropertyEntry))
|
||||
{
|
||||
}
|
||||
SymbolPropertyTable::SymbolPropertyTable(int table_size, HashtableBucket* t,
|
||||
int number_of_entries)
|
||||
: Hashtable(table_size, sizeof(SymbolPropertyEntry), t, number_of_entries)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SymbolPropertyEntry* SymbolPropertyTable::find_entry(int index, unsigned int hash,
|
||||
symbolHandle sym) {
|
||||
assert(index == index_for(sym), "incorrect index?");
|
||||
for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
|
||||
if (p->hash() == hash && p->symbol() == sym()) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
SymbolPropertyEntry* SymbolPropertyTable::add_entry(int index, unsigned int hash,
|
||||
symbolHandle sym) {
|
||||
assert_locked_or_safepoint(SystemDictionary_lock);
|
||||
assert(index == index_for(sym), "incorrect index?");
|
||||
assert(find_entry(index, hash, sym) == NULL, "no double entry");
|
||||
|
||||
SymbolPropertyEntry* p = new_entry(hash, sym());
|
||||
Hashtable::add_entry(index, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
void SymbolPropertyTable::oops_do(OopClosure* f) {
|
||||
for (int index = 0; index < table_size(); index++) {
|
||||
for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
|
||||
f->do_oop((oop*) p->symbol_addr());
|
||||
if (p->property_oop() != NULL) {
|
||||
f->do_oop(p->property_oop_addr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolPropertyTable::methods_do(void f(methodOop)) {
|
||||
for (int index = 0; index < table_size(); index++) {
|
||||
for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
|
||||
oop prop = p->property_oop();
|
||||
if (prop != NULL && prop->is_method()) {
|
||||
f((methodOop)prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
#ifndef PRODUCT
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2003-2009 Sun Microsystems, Inc. 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
|
||||
@ -217,3 +217,112 @@ class DictionaryEntry : public HashtableEntry {
|
||||
tty->print_cr("pd set = #%d", count);
|
||||
}
|
||||
};
|
||||
|
||||
// Entry in a SymbolPropertyTable, mapping a single symbolOop
|
||||
// to a managed and an unmanaged pointer.
|
||||
class SymbolPropertyEntry : public HashtableEntry {
|
||||
friend class VMStructs;
|
||||
private:
|
||||
oop _property_oop;
|
||||
address _property_data;
|
||||
|
||||
public:
|
||||
symbolOop symbol() const { return (symbolOop) literal(); }
|
||||
|
||||
oop property_oop() const { return _property_oop; }
|
||||
void set_property_oop(oop p) { _property_oop = p; }
|
||||
|
||||
address property_data() const { return _property_data; }
|
||||
void set_property_data(address p) { _property_data = p; }
|
||||
|
||||
SymbolPropertyEntry* next() const {
|
||||
return (SymbolPropertyEntry*)HashtableEntry::next();
|
||||
}
|
||||
|
||||
SymbolPropertyEntry** next_addr() {
|
||||
return (SymbolPropertyEntry**)HashtableEntry::next_addr();
|
||||
}
|
||||
|
||||
oop* symbol_addr() { return literal_addr(); }
|
||||
oop* property_oop_addr() { return &_property_oop; }
|
||||
|
||||
void print_on(outputStream* st) const {
|
||||
symbol()->print_value_on(st);
|
||||
st->print(" -> ");
|
||||
bool printed = false;
|
||||
if (property_oop() != NULL) {
|
||||
property_oop()->print_value_on(st);
|
||||
printed = true;
|
||||
}
|
||||
if (property_data() != NULL) {
|
||||
if (printed) st->print(" and ");
|
||||
st->print(INTPTR_FORMAT, property_data());
|
||||
printed = true;
|
||||
}
|
||||
st->print_cr(printed ? "" : "(empty)");
|
||||
}
|
||||
};
|
||||
|
||||
// A system-internal mapping of symbols to pointers, both managed
|
||||
// and unmanaged. Used to record the auto-generation of each method
|
||||
// MethodHandle.invoke(S)T, for all signatures (S)T.
|
||||
class SymbolPropertyTable : public Hashtable {
|
||||
friend class VMStructs;
|
||||
private:
|
||||
SymbolPropertyEntry* bucket(int i) {
|
||||
return (SymbolPropertyEntry*) Hashtable::bucket(i);
|
||||
}
|
||||
|
||||
// The following method is not MT-safe and must be done under lock.
|
||||
SymbolPropertyEntry** bucket_addr(int i) {
|
||||
return (SymbolPropertyEntry**) Hashtable::bucket_addr(i);
|
||||
}
|
||||
|
||||
void add_entry(int index, SymbolPropertyEntry* new_entry) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
void set_entry(int index, SymbolPropertyEntry* new_entry) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
SymbolPropertyEntry* new_entry(unsigned int hash, symbolOop symbol) {
|
||||
SymbolPropertyEntry* entry = (SymbolPropertyEntry*) Hashtable::new_entry(hash, symbol);
|
||||
entry->set_property_oop(NULL);
|
||||
entry->set_property_data(NULL);
|
||||
return entry;
|
||||
}
|
||||
|
||||
public:
|
||||
SymbolPropertyTable(int table_size);
|
||||
SymbolPropertyTable(int table_size, HashtableBucket* t, int number_of_entries);
|
||||
|
||||
void free_entry(SymbolPropertyEntry* entry) {
|
||||
Hashtable::free_entry(entry);
|
||||
}
|
||||
|
||||
unsigned int compute_hash(symbolHandle sym) {
|
||||
// Use the regular identity_hash.
|
||||
return Hashtable::compute_hash(sym);
|
||||
}
|
||||
|
||||
// need not be locked; no state change
|
||||
SymbolPropertyEntry* find_entry(int index, unsigned int hash, symbolHandle name);
|
||||
|
||||
// must be done under SystemDictionary_lock
|
||||
SymbolPropertyEntry* add_entry(int index, unsigned int hash, symbolHandle name);
|
||||
|
||||
// GC support
|
||||
void oops_do(OopClosure* f);
|
||||
void methods_do(void f(methodOop));
|
||||
|
||||
// Sharing support
|
||||
void dump(SerializeOopClosure* soc);
|
||||
void restore(SerializeOopClosure* soc);
|
||||
void reorder_dictionary();
|
||||
|
||||
#ifndef PRODUCT
|
||||
void print();
|
||||
#endif
|
||||
void verify();
|
||||
};
|
||||
|
||||
|
@ -25,13 +25,24 @@
|
||||
# include "incls/_precompiled.incl"
|
||||
# include "incls/_javaClasses.cpp.incl"
|
||||
|
||||
static bool find_field(instanceKlass* ik,
|
||||
symbolOop name_symbol, symbolOop signature_symbol,
|
||||
fieldDescriptor* fd,
|
||||
bool allow_super = false) {
|
||||
if (allow_super)
|
||||
return ik->find_field(name_symbol, signature_symbol, fd) != NULL;
|
||||
else
|
||||
return ik->find_local_field(name_symbol, signature_symbol, fd);
|
||||
}
|
||||
|
||||
// Helpful routine for computing field offsets at run time rather than hardcoding them
|
||||
static void
|
||||
compute_offset(int &dest_offset,
|
||||
klassOop klass_oop, symbolOop name_symbol, symbolOop signature_symbol) {
|
||||
klassOop klass_oop, symbolOop name_symbol, symbolOop signature_symbol,
|
||||
bool allow_super = false) {
|
||||
fieldDescriptor fd;
|
||||
instanceKlass* ik = instanceKlass::cast(klass_oop);
|
||||
if (!ik->find_local_field(name_symbol, signature_symbol, &fd)) {
|
||||
if (!find_field(ik, name_symbol, signature_symbol, &fd, allow_super)) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("Invalid layout of %s at %s", ik->external_name(), name_symbol->as_C_string());
|
||||
fatal("Invalid layout of preloaded class");
|
||||
@ -42,14 +53,16 @@ compute_offset(int &dest_offset,
|
||||
// Same as above but for "optional" offsets that might not be present in certain JDK versions
|
||||
static void
|
||||
compute_optional_offset(int& dest_offset,
|
||||
klassOop klass_oop, symbolOop name_symbol, symbolOop signature_symbol) {
|
||||
klassOop klass_oop, symbolOop name_symbol, symbolOop signature_symbol,
|
||||
bool allow_super = false) {
|
||||
fieldDescriptor fd;
|
||||
instanceKlass* ik = instanceKlass::cast(klass_oop);
|
||||
if (ik->find_local_field(name_symbol, signature_symbol, &fd)) {
|
||||
if (find_field(ik, name_symbol, signature_symbol, &fd, allow_super)) {
|
||||
dest_offset = fd.offset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Handle java_lang_String::basic_create(int length, bool tenured, TRAPS) {
|
||||
// Create the String object first, so there's a chance that the String
|
||||
// and the char array it points to end up in the same cache line.
|
||||
@ -2107,13 +2120,324 @@ void java_lang_ref_SoftReference::set_clock(jlong value) {
|
||||
}
|
||||
|
||||
|
||||
// Support for java_dyn_MethodHandle
|
||||
|
||||
int java_dyn_MethodHandle::_type_offset;
|
||||
int java_dyn_MethodHandle::_vmtarget_offset;
|
||||
int java_dyn_MethodHandle::_vmentry_offset;
|
||||
int java_dyn_MethodHandle::_vmslots_offset;
|
||||
|
||||
int sun_dyn_MemberName::_clazz_offset;
|
||||
int sun_dyn_MemberName::_name_offset;
|
||||
int sun_dyn_MemberName::_type_offset;
|
||||
int sun_dyn_MemberName::_flags_offset;
|
||||
int sun_dyn_MemberName::_vmtarget_offset;
|
||||
int sun_dyn_MemberName::_vmindex_offset;
|
||||
|
||||
int sun_dyn_DirectMethodHandle::_vmindex_offset;
|
||||
|
||||
int sun_dyn_BoundMethodHandle::_argument_offset;
|
||||
int sun_dyn_BoundMethodHandle::_vmargslot_offset;
|
||||
|
||||
int sun_dyn_AdapterMethodHandle::_conversion_offset;
|
||||
|
||||
void java_dyn_MethodHandle::compute_offsets() {
|
||||
klassOop k = SystemDictionary::MethodHandle_klass();
|
||||
if (k != NULL && EnableMethodHandles) {
|
||||
compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_dyn_MethodType_signature(), true);
|
||||
compute_offset(_vmtarget_offset, k, vmSymbols::vmtarget_name(), vmSymbols::object_signature(), true);
|
||||
compute_offset(_vmentry_offset, k, vmSymbols::vmentry_name(), vmSymbols::machine_word_signature(), true);
|
||||
|
||||
// Note: MH.vmslots (if it is present) is a hoisted copy of MH.type.form.vmslots.
|
||||
// It is optional pending experiments to keep or toss.
|
||||
compute_optional_offset(_vmslots_offset, k, vmSymbols::vmslots_name(), vmSymbols::int_signature(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void sun_dyn_MemberName::compute_offsets() {
|
||||
klassOop k = SystemDictionary::MemberName_klass();
|
||||
if (k != NULL && EnableMethodHandles) {
|
||||
compute_offset(_clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature());
|
||||
compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
|
||||
compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::object_signature());
|
||||
compute_offset(_flags_offset, k, vmSymbols::flags_name(), vmSymbols::int_signature());
|
||||
compute_offset(_vmtarget_offset, k, vmSymbols::vmtarget_name(), vmSymbols::object_signature());
|
||||
compute_offset(_vmindex_offset, k, vmSymbols::vmindex_name(), vmSymbols::int_signature());
|
||||
}
|
||||
}
|
||||
|
||||
void sun_dyn_DirectMethodHandle::compute_offsets() {
|
||||
klassOop k = SystemDictionary::DirectMethodHandle_klass();
|
||||
if (k != NULL && EnableMethodHandles) {
|
||||
compute_offset(_vmindex_offset, k, vmSymbols::vmindex_name(), vmSymbols::int_signature(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void sun_dyn_BoundMethodHandle::compute_offsets() {
|
||||
klassOop k = SystemDictionary::BoundMethodHandle_klass();
|
||||
if (k != NULL && EnableMethodHandles) {
|
||||
compute_offset(_vmargslot_offset, k, vmSymbols::vmargslot_name(), vmSymbols::int_signature(), true);
|
||||
compute_offset(_argument_offset, k, vmSymbols::argument_name(), vmSymbols::object_signature(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void sun_dyn_AdapterMethodHandle::compute_offsets() {
|
||||
klassOop k = SystemDictionary::AdapterMethodHandle_klass();
|
||||
if (k != NULL && EnableMethodHandles) {
|
||||
compute_offset(_conversion_offset, k, vmSymbols::conversion_name(), vmSymbols::int_signature(), true);
|
||||
}
|
||||
}
|
||||
|
||||
oop java_dyn_MethodHandle::type(oop mh) {
|
||||
return mh->obj_field(_type_offset);
|
||||
}
|
||||
|
||||
void java_dyn_MethodHandle::set_type(oop mh, oop mtype) {
|
||||
mh->obj_field_put(_type_offset, mtype);
|
||||
}
|
||||
|
||||
int java_dyn_MethodHandle::vmslots(oop mh) {
|
||||
int vmslots_offset = _vmslots_offset;
|
||||
if (vmslots_offset != 0) {
|
||||
#ifdef ASSERT
|
||||
int x = mh->int_field(vmslots_offset);
|
||||
int y = compute_vmslots(mh);
|
||||
assert(x == y, "correct hoisted value");
|
||||
#endif
|
||||
return mh->int_field(vmslots_offset);
|
||||
} else {
|
||||
return compute_vmslots(mh);
|
||||
}
|
||||
}
|
||||
|
||||
// if MH.vmslots exists, hoist into it the value of type.form.vmslots
|
||||
void java_dyn_MethodHandle::init_vmslots(oop mh) {
|
||||
int vmslots_offset = _vmslots_offset;
|
||||
if (vmslots_offset != 0) {
|
||||
mh->int_field_put(vmslots_offset, compute_vmslots(mh));
|
||||
}
|
||||
}
|
||||
|
||||
// fetch type.form.vmslots, which is the number of JVM stack slots
|
||||
// required to carry the arguments of this MH
|
||||
int java_dyn_MethodHandle::compute_vmslots(oop mh) {
|
||||
oop mtype = type(mh);
|
||||
if (mtype == NULL) return 0; // Java code would get NPE
|
||||
oop form = java_dyn_MethodType::form(mtype);
|
||||
if (form == NULL) return 0; // Java code would get NPE
|
||||
return java_dyn_MethodTypeForm::vmslots(form);
|
||||
}
|
||||
|
||||
// fetch the low-level entry point for this mh
|
||||
MethodHandleEntry* java_dyn_MethodHandle::vmentry(oop mh) {
|
||||
return (MethodHandleEntry*) mh->address_field(_vmentry_offset);
|
||||
}
|
||||
|
||||
void java_dyn_MethodHandle::set_vmentry(oop mh, MethodHandleEntry* me) {
|
||||
assert(_vmentry_offset != 0, "must be present");
|
||||
|
||||
// This is always the final step that initializes a valid method handle:
|
||||
mh->release_address_field_put(_vmentry_offset, (address) me);
|
||||
|
||||
// There should be enough memory barriers on exit from native methods
|
||||
// to ensure that the MH is fully initialized to all threads before
|
||||
// Java code can publish it in global data structures.
|
||||
// But just in case, we use release_address_field_put.
|
||||
}
|
||||
|
||||
/// MemberName accessors
|
||||
|
||||
oop sun_dyn_MemberName::clazz(oop mname) {
|
||||
assert(is_instance(mname), "wrong type");
|
||||
return mname->obj_field(_clazz_offset);
|
||||
}
|
||||
|
||||
void sun_dyn_MemberName::set_clazz(oop mname, oop clazz) {
|
||||
assert(is_instance(mname), "wrong type");
|
||||
mname->obj_field_put(_clazz_offset, clazz);
|
||||
}
|
||||
|
||||
oop sun_dyn_MemberName::name(oop mname) {
|
||||
assert(is_instance(mname), "wrong type");
|
||||
return mname->obj_field(_name_offset);
|
||||
}
|
||||
|
||||
void sun_dyn_MemberName::set_name(oop mname, oop name) {
|
||||
assert(is_instance(mname), "wrong type");
|
||||
mname->obj_field_put(_name_offset, name);
|
||||
}
|
||||
|
||||
oop sun_dyn_MemberName::type(oop mname) {
|
||||
assert(is_instance(mname), "wrong type");
|
||||
return mname->obj_field(_type_offset);
|
||||
}
|
||||
|
||||
void sun_dyn_MemberName::set_type(oop mname, oop type) {
|
||||
assert(is_instance(mname), "wrong type");
|
||||
mname->obj_field_put(_type_offset, type);
|
||||
}
|
||||
|
||||
int sun_dyn_MemberName::flags(oop mname) {
|
||||
assert(is_instance(mname), "wrong type");
|
||||
return mname->int_field(_flags_offset);
|
||||
}
|
||||
|
||||
void sun_dyn_MemberName::set_flags(oop mname, int flags) {
|
||||
assert(is_instance(mname), "wrong type");
|
||||
mname->int_field_put(_flags_offset, flags);
|
||||
}
|
||||
|
||||
oop sun_dyn_MemberName::vmtarget(oop mname) {
|
||||
assert(is_instance(mname), "wrong type");
|
||||
return mname->obj_field(_vmtarget_offset);
|
||||
}
|
||||
|
||||
void sun_dyn_MemberName::set_vmtarget(oop mname, oop ref) {
|
||||
assert(is_instance(mname), "wrong type");
|
||||
mname->obj_field_put(_vmtarget_offset, ref);
|
||||
}
|
||||
|
||||
int sun_dyn_MemberName::vmindex(oop mname) {
|
||||
assert(is_instance(mname), "wrong type");
|
||||
return mname->int_field(_vmindex_offset);
|
||||
}
|
||||
|
||||
void sun_dyn_MemberName::set_vmindex(oop mname, int index) {
|
||||
assert(is_instance(mname), "wrong type");
|
||||
mname->int_field_put(_vmindex_offset, index);
|
||||
}
|
||||
|
||||
oop java_dyn_MethodHandle::vmtarget(oop mh) {
|
||||
assert(is_instance(mh), "MH only");
|
||||
return mh->obj_field(_vmtarget_offset);
|
||||
}
|
||||
|
||||
void java_dyn_MethodHandle::set_vmtarget(oop mh, oop ref) {
|
||||
assert(is_instance(mh), "MH only");
|
||||
mh->obj_field_put(_vmtarget_offset, ref);
|
||||
}
|
||||
|
||||
int sun_dyn_DirectMethodHandle::vmindex(oop mh) {
|
||||
assert(is_instance(mh), "DMH only");
|
||||
return mh->int_field(_vmindex_offset);
|
||||
}
|
||||
|
||||
void sun_dyn_DirectMethodHandle::set_vmindex(oop mh, int index) {
|
||||
assert(is_instance(mh), "DMH only");
|
||||
mh->int_field_put(_vmindex_offset, index);
|
||||
}
|
||||
|
||||
int sun_dyn_BoundMethodHandle::vmargslot(oop mh) {
|
||||
assert(is_instance(mh), "BMH only");
|
||||
return mh->int_field(_vmargslot_offset);
|
||||
}
|
||||
|
||||
oop sun_dyn_BoundMethodHandle::argument(oop mh) {
|
||||
assert(is_instance(mh), "BMH only");
|
||||
return mh->obj_field(_argument_offset);
|
||||
}
|
||||
|
||||
int sun_dyn_AdapterMethodHandle::conversion(oop mh) {
|
||||
assert(is_instance(mh), "AMH only");
|
||||
return mh->int_field(_conversion_offset);
|
||||
}
|
||||
|
||||
void sun_dyn_AdapterMethodHandle::set_conversion(oop mh, int conv) {
|
||||
assert(is_instance(mh), "AMH only");
|
||||
mh->int_field_put(_conversion_offset, conv);
|
||||
}
|
||||
|
||||
|
||||
// Support for java_dyn_MethodType
|
||||
|
||||
int java_dyn_MethodType::_rtype_offset;
|
||||
int java_dyn_MethodType::_ptypes_offset;
|
||||
int java_dyn_MethodType::_form_offset;
|
||||
|
||||
void java_dyn_MethodType::compute_offsets() {
|
||||
klassOop k = SystemDictionary::MethodType_klass();
|
||||
if (k != NULL) {
|
||||
compute_offset(_rtype_offset, k, vmSymbols::rtype_name(), vmSymbols::class_signature());
|
||||
compute_offset(_ptypes_offset, k, vmSymbols::ptypes_name(), vmSymbols::class_array_signature());
|
||||
compute_offset(_form_offset, k, vmSymbols::form_name(), vmSymbols::java_dyn_MethodTypeForm_signature());
|
||||
}
|
||||
}
|
||||
|
||||
void java_dyn_MethodType::print_signature(oop mt, outputStream* st) {
|
||||
st->print("(");
|
||||
objArrayOop pts = ptypes(mt);
|
||||
for (int i = 0, limit = pts->length(); i < limit; i++) {
|
||||
java_lang_Class::print_signature(pts->obj_at(i), st);
|
||||
}
|
||||
st->print(")");
|
||||
java_lang_Class::print_signature(rtype(mt), st);
|
||||
}
|
||||
|
||||
symbolOop java_dyn_MethodType::as_signature(oop mt, bool intern_if_not_found, TRAPS) {
|
||||
ResourceMark rm;
|
||||
stringStream buffer(128);
|
||||
print_signature(mt, &buffer);
|
||||
const char* sigstr = buffer.base();
|
||||
int siglen = (int) buffer.size();
|
||||
if (!intern_if_not_found)
|
||||
return SymbolTable::probe(sigstr, siglen);
|
||||
else
|
||||
return oopFactory::new_symbol(sigstr, siglen, THREAD);
|
||||
}
|
||||
|
||||
oop java_dyn_MethodType::rtype(oop mt) {
|
||||
assert(is_instance(mt), "must be a MethodType");
|
||||
return mt->obj_field(_rtype_offset);
|
||||
}
|
||||
|
||||
objArrayOop java_dyn_MethodType::ptypes(oop mt) {
|
||||
assert(is_instance(mt), "must be a MethodType");
|
||||
return (objArrayOop) mt->obj_field(_ptypes_offset);
|
||||
}
|
||||
|
||||
oop java_dyn_MethodType::form(oop mt) {
|
||||
assert(is_instance(mt), "must be a MethodType");
|
||||
return mt->obj_field(_form_offset);
|
||||
}
|
||||
|
||||
oop java_dyn_MethodType::ptype(oop mt, int idx) {
|
||||
return ptypes(mt)->obj_at(idx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Support for java_dyn_MethodTypeForm
|
||||
|
||||
int java_dyn_MethodTypeForm::_vmslots_offset;
|
||||
int java_dyn_MethodTypeForm::_erasedType_offset;
|
||||
|
||||
void java_dyn_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(_erasedType_offset, k, vmSymbols::erasedType_name(), vmSymbols::java_dyn_MethodType_signature(), true);
|
||||
}
|
||||
}
|
||||
|
||||
int java_dyn_MethodTypeForm::vmslots(oop mtform) {
|
||||
assert(mtform->klass() == SystemDictionary::MethodTypeForm_klass(), "MTForm only");
|
||||
return mtform->int_field(_vmslots_offset);
|
||||
}
|
||||
|
||||
oop java_dyn_MethodTypeForm::erasedType(oop mtform) {
|
||||
assert(mtform->klass() == SystemDictionary::MethodTypeForm_klass(), "MTForm only");
|
||||
return mtform->obj_field(_erasedType_offset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Support for java_security_AccessControlContext
|
||||
|
||||
int java_security_AccessControlContext::_context_offset = 0;
|
||||
int java_security_AccessControlContext::_privilegedContext_offset = 0;
|
||||
int java_security_AccessControlContext::_isPrivileged_offset = 0;
|
||||
|
||||
|
||||
void java_security_AccessControlContext::compute_offsets() {
|
||||
assert(_isPrivileged_offset == 0, "offsets should be initialized only once");
|
||||
fieldDescriptor fd;
|
||||
@ -2442,6 +2766,15 @@ void JavaClasses::compute_offsets() {
|
||||
java_lang_System::compute_offsets();
|
||||
java_lang_Thread::compute_offsets();
|
||||
java_lang_ThreadGroup::compute_offsets();
|
||||
if (EnableMethodHandles) {
|
||||
java_dyn_MethodHandle::compute_offsets();
|
||||
sun_dyn_MemberName::compute_offsets();
|
||||
sun_dyn_DirectMethodHandle::compute_offsets();
|
||||
sun_dyn_BoundMethodHandle::compute_offsets();
|
||||
sun_dyn_AdapterMethodHandle::compute_offsets();
|
||||
java_dyn_MethodType::compute_offsets();
|
||||
java_dyn_MethodTypeForm::compute_offsets();
|
||||
}
|
||||
java_security_AccessControlContext::compute_offsets();
|
||||
// Initialize reflection classes. The layouts of these classes
|
||||
// changed with the new reflection implementation in JDK 1.4, and
|
||||
@ -2459,6 +2792,9 @@ void JavaClasses::compute_offsets() {
|
||||
sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets();
|
||||
}
|
||||
sun_misc_AtomicLongCSImpl::compute_offsets();
|
||||
|
||||
// generated interpreter code wants to know about the offsets we just computed:
|
||||
AbstractAssembler::update_delayed_values();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
@ -151,6 +151,12 @@ class java_lang_Class : AllStatic {
|
||||
// Conversion
|
||||
static klassOop as_klassOop(oop java_class);
|
||||
static BasicType as_BasicType(oop java_class, klassOop* reference_klass = NULL);
|
||||
static BasicType as_BasicType(oop java_class, KlassHandle* reference_klass) {
|
||||
klassOop refk_oop = NULL;
|
||||
BasicType result = as_BasicType(java_class, &refk_oop);
|
||||
(*reference_klass) = KlassHandle(refk_oop);
|
||||
return result;
|
||||
}
|
||||
static symbolOop as_signature(oop java_class, bool intern_if_not_found, TRAPS);
|
||||
static void print_signature(oop java_class, outputStream *st);
|
||||
// Testing
|
||||
@ -778,6 +784,284 @@ class java_lang_ref_SoftReference: public java_lang_ref_Reference {
|
||||
};
|
||||
|
||||
|
||||
// Interface to java.dyn.MethodHandle objects
|
||||
|
||||
class MethodHandleEntry;
|
||||
|
||||
class java_dyn_MethodHandle: AllStatic {
|
||||
friend class JavaClasses;
|
||||
|
||||
private:
|
||||
static int _vmentry_offset; // assembly code trampoline for MH
|
||||
static int _vmtarget_offset; // class-specific target reference
|
||||
static int _type_offset; // the MethodType of this MH
|
||||
static int _vmslots_offset; // OPTIONAL hoisted type.form.vmslots
|
||||
|
||||
static void compute_offsets();
|
||||
|
||||
public:
|
||||
// Accessors
|
||||
static oop type(oop mh);
|
||||
static void set_type(oop mh, oop mtype);
|
||||
|
||||
static oop vmtarget(oop mh);
|
||||
static void set_vmtarget(oop mh, oop target);
|
||||
|
||||
static MethodHandleEntry* vmentry(oop mh);
|
||||
static void set_vmentry(oop mh, MethodHandleEntry* data);
|
||||
|
||||
static int vmslots(oop mh);
|
||||
static void init_vmslots(oop mh);
|
||||
static int compute_vmslots(oop mh);
|
||||
|
||||
// Testers
|
||||
static bool is_subclass(klassOop klass) {
|
||||
return Klass::cast(klass)->is_subclass_of(SystemDictionary::MethodHandle_klass());
|
||||
}
|
||||
static bool is_instance(oop obj) {
|
||||
return obj != NULL && is_subclass(obj->klass());
|
||||
}
|
||||
|
||||
// Accessors for code generation:
|
||||
static int type_offset_in_bytes() { return _type_offset; }
|
||||
static int vmtarget_offset_in_bytes() { return _vmtarget_offset; }
|
||||
static int vmentry_offset_in_bytes() { return _vmentry_offset; }
|
||||
static int vmslots_offset_in_bytes() { return _vmslots_offset; }
|
||||
};
|
||||
|
||||
class sun_dyn_DirectMethodHandle: public java_dyn_MethodHandle {
|
||||
friend class JavaClasses;
|
||||
|
||||
private:
|
||||
// _vmtarget_offset; // method or class or interface
|
||||
static int _vmindex_offset; // negative or vtable idx or itable idx
|
||||
static void compute_offsets();
|
||||
|
||||
public:
|
||||
// Accessors
|
||||
static int vmindex(oop mh);
|
||||
static void set_vmindex(oop mh, int index);
|
||||
|
||||
// Testers
|
||||
static bool is_subclass(klassOop klass) {
|
||||
return Klass::cast(klass)->is_subclass_of(SystemDictionary::DirectMethodHandle_klass());
|
||||
}
|
||||
static bool is_instance(oop obj) {
|
||||
return obj != NULL && is_subclass(obj->klass());
|
||||
}
|
||||
|
||||
// Accessors for code generation:
|
||||
static int vmindex_offset_in_bytes() { return _vmindex_offset; }
|
||||
};
|
||||
|
||||
class sun_dyn_BoundMethodHandle: public java_dyn_MethodHandle {
|
||||
friend class JavaClasses;
|
||||
|
||||
private:
|
||||
static int _argument_offset; // argument value bound into this MH
|
||||
static int _vmargslot_offset; // relevant argument slot (<= vmslots)
|
||||
static void compute_offsets();
|
||||
|
||||
public:
|
||||
static oop argument(oop mh);
|
||||
static void set_argument(oop mh, oop ref);
|
||||
|
||||
static jint vmargslot(oop mh);
|
||||
static void set_vmargslot(oop mh, jint slot);
|
||||
|
||||
// Testers
|
||||
static bool is_subclass(klassOop klass) {
|
||||
return Klass::cast(klass)->is_subclass_of(SystemDictionary::BoundMethodHandle_klass());
|
||||
}
|
||||
static bool is_instance(oop obj) {
|
||||
return obj != NULL && is_subclass(obj->klass());
|
||||
}
|
||||
|
||||
static int argument_offset_in_bytes() { return _argument_offset; }
|
||||
static int vmargslot_offset_in_bytes() { return _vmargslot_offset; }
|
||||
};
|
||||
|
||||
class sun_dyn_AdapterMethodHandle: public sun_dyn_BoundMethodHandle {
|
||||
friend class JavaClasses;
|
||||
|
||||
private:
|
||||
static int _conversion_offset; // type of conversion to apply
|
||||
static void compute_offsets();
|
||||
|
||||
public:
|
||||
static int conversion(oop mh);
|
||||
static void set_conversion(oop mh, int conv);
|
||||
|
||||
// Testers
|
||||
static bool is_subclass(klassOop klass) {
|
||||
return Klass::cast(klass)->is_subclass_of(SystemDictionary::AdapterMethodHandle_klass());
|
||||
}
|
||||
static bool is_instance(oop obj) {
|
||||
return obj != NULL && is_subclass(obj->klass());
|
||||
}
|
||||
|
||||
// Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants):
|
||||
enum {
|
||||
OP_RETYPE_ONLY = 0x0, // no argument changes; straight retype
|
||||
OP_CHECK_CAST = 0x1, // ref-to-ref conversion; requires a Class argument
|
||||
OP_PRIM_TO_PRIM = 0x2, // converts from one primitive to another
|
||||
OP_REF_TO_PRIM = 0x3, // unboxes a wrapper to produce a primitive
|
||||
OP_PRIM_TO_REF = 0x4, // boxes a primitive into a wrapper (NYI)
|
||||
OP_SWAP_ARGS = 0x5, // swap arguments (vminfo is 2nd arg)
|
||||
OP_ROT_ARGS = 0x6, // rotate arguments (vminfo is displaced arg)
|
||||
OP_DUP_ARGS = 0x7, // duplicates one or more arguments (at TOS)
|
||||
OP_DROP_ARGS = 0x8, // remove one or more argument slots
|
||||
OP_COLLECT_ARGS = 0x9, // combine one or more arguments into a varargs (NYI)
|
||||
OP_SPREAD_ARGS = 0xA, // expand in place a varargs array (of known size)
|
||||
OP_FLYBY = 0xB, // operate first on reified argument list (NYI)
|
||||
OP_RICOCHET = 0xC, // run an adapter chain on the return value (NYI)
|
||||
CONV_OP_LIMIT = 0xD, // limit of CONV_OP enumeration
|
||||
|
||||
CONV_OP_MASK = 0xF00, // this nybble contains the conversion op field
|
||||
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
|
||||
CONV_DEST_TYPE_SHIFT = 12, // byte 2 has the adapter BasicType (if needed)
|
||||
CONV_SRC_TYPE_SHIFT = 16, // byte 2 has the source BasicType (if needed)
|
||||
CONV_STACK_MOVE_SHIFT = 20, // high 12 bits give signed SP change
|
||||
CONV_STACK_MOVE_MASK = (1 << (32 - CONV_STACK_MOVE_SHIFT)) - 1
|
||||
};
|
||||
|
||||
static int conversion_offset_in_bytes() { return _conversion_offset; }
|
||||
};
|
||||
|
||||
|
||||
// Interface to sun.dyn.MemberName objects
|
||||
// (These are a private interface for Java code to query the class hierarchy.)
|
||||
|
||||
class sun_dyn_MemberName: AllStatic {
|
||||
friend class JavaClasses;
|
||||
|
||||
private:
|
||||
// From java.dyn.MemberName:
|
||||
// private Class<?> clazz; // class in which the method is defined
|
||||
// private String name; // may be null if not yet materialized
|
||||
// private Object type; // may be null if not yet materialized
|
||||
// private int flags; // modifier bits; see reflect.Modifier
|
||||
// private Object vmtarget; // VM-specific target value
|
||||
// private int vmindex; // method index within class or interface
|
||||
static int _clazz_offset;
|
||||
static int _name_offset;
|
||||
static int _type_offset;
|
||||
static int _flags_offset;
|
||||
static int _vmtarget_offset;
|
||||
static int _vmindex_offset;
|
||||
|
||||
static void compute_offsets();
|
||||
|
||||
public:
|
||||
// Accessors
|
||||
static oop clazz(oop mname);
|
||||
static void set_clazz(oop mname, oop clazz);
|
||||
|
||||
static oop type(oop mname);
|
||||
static void set_type(oop mname, oop type);
|
||||
|
||||
static oop name(oop mname);
|
||||
static void set_name(oop mname, oop name);
|
||||
|
||||
static int flags(oop mname);
|
||||
static void set_flags(oop mname, int flags);
|
||||
|
||||
static int modifiers(oop mname) { return (u2) flags(mname); }
|
||||
static void set_modifiers(oop mname, int mods)
|
||||
{ set_flags(mname, (flags(mname) &~ (u2)-1) | (u2)mods); }
|
||||
|
||||
static oop vmtarget(oop mname);
|
||||
static void set_vmtarget(oop mname, oop target);
|
||||
|
||||
static int vmindex(oop mname);
|
||||
static void set_vmindex(oop mname, int index);
|
||||
|
||||
// Testers
|
||||
static bool is_subclass(klassOop klass) {
|
||||
return Klass::cast(klass)->is_subclass_of(SystemDictionary::MemberName_klass());
|
||||
}
|
||||
static bool is_instance(oop obj) {
|
||||
return obj != NULL && is_subclass(obj->klass());
|
||||
}
|
||||
|
||||
// Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants):
|
||||
enum {
|
||||
MN_IS_METHOD = 0x00010000, // method (not constructor)
|
||||
MN_IS_CONSTRUCTOR = 0x00020000, // constructor
|
||||
MN_IS_FIELD = 0x00040000, // field
|
||||
MN_IS_TYPE = 0x00080000, // nested type
|
||||
MN_SEARCH_SUPERCLASSES = 0x00100000, // for MHN.getMembers
|
||||
MN_SEARCH_INTERFACES = 0x00200000, // for MHN.getMembers
|
||||
VM_INDEX_UNINITIALIZED = -99
|
||||
};
|
||||
|
||||
// Accessors for code generation:
|
||||
static int clazz_offset_in_bytes() { return _clazz_offset; }
|
||||
static int type_offset_in_bytes() { return _type_offset; }
|
||||
static int name_offset_in_bytes() { return _name_offset; }
|
||||
static int flags_offset_in_bytes() { return _flags_offset; }
|
||||
static int vmtarget_offset_in_bytes() { return _vmtarget_offset; }
|
||||
static int vmindex_offset_in_bytes() { return _vmindex_offset; }
|
||||
};
|
||||
|
||||
|
||||
// Interface to java.dyn.MethodType objects
|
||||
|
||||
class java_dyn_MethodType: AllStatic {
|
||||
friend class JavaClasses;
|
||||
|
||||
private:
|
||||
static int _rtype_offset;
|
||||
static int _ptypes_offset;
|
||||
static int _form_offset;
|
||||
|
||||
static void compute_offsets();
|
||||
|
||||
public:
|
||||
// Accessors
|
||||
static oop rtype(oop mt);
|
||||
static objArrayOop ptypes(oop mt);
|
||||
static oop form(oop mt);
|
||||
|
||||
static oop ptype(oop mt, int index);
|
||||
|
||||
static symbolOop as_signature(oop mt, bool intern_if_not_found, TRAPS);
|
||||
static void print_signature(oop mt, outputStream* st);
|
||||
|
||||
static bool is_instance(oop obj) {
|
||||
return obj != NULL && obj->klass() == SystemDictionary::MethodType_klass();
|
||||
}
|
||||
|
||||
// Accessors for code generation:
|
||||
static int rtype_offset_in_bytes() { return _rtype_offset; }
|
||||
static int ptypes_offset_in_bytes() { return _ptypes_offset; }
|
||||
static int form_offset_in_bytes() { return _form_offset; }
|
||||
};
|
||||
|
||||
class java_dyn_MethodTypeForm: AllStatic {
|
||||
friend class JavaClasses;
|
||||
|
||||
private:
|
||||
static int _vmslots_offset; // number of argument slots needed
|
||||
static int _erasedType_offset; // erasedType = canonical MethodType
|
||||
|
||||
static void compute_offsets();
|
||||
|
||||
public:
|
||||
// Accessors
|
||||
static int vmslots(oop mtform);
|
||||
static oop erasedType(oop mtform);
|
||||
|
||||
// Accessors for code generation:
|
||||
static int vmslots_offset_in_bytes() { return _vmslots_offset; }
|
||||
static int erasedType_offset_in_bytes() { return _erasedType_offset; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Interface to java.security.AccessControlContext objects
|
||||
|
||||
class java_security_AccessControlContext: AllStatic {
|
||||
|
@ -31,6 +31,7 @@ PlaceholderTable* SystemDictionary::_placeholders = NULL;
|
||||
Dictionary* SystemDictionary::_shared_dictionary = NULL;
|
||||
LoaderConstraintTable* SystemDictionary::_loader_constraints = NULL;
|
||||
ResolutionErrorTable* SystemDictionary::_resolution_errors = NULL;
|
||||
SymbolPropertyTable* SystemDictionary::_invoke_method_table = NULL;
|
||||
|
||||
|
||||
int SystemDictionary::_number_of_modifications = 0;
|
||||
@ -966,6 +967,8 @@ klassOop SystemDictionary::parse_stream(symbolHandle class_name,
|
||||
instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name,
|
||||
class_loader,
|
||||
protection_domain,
|
||||
host_klass,
|
||||
cp_patches,
|
||||
parsed_name,
|
||||
THREAD);
|
||||
|
||||
@ -1691,6 +1694,10 @@ void SystemDictionary::always_strong_classes_do(OopClosure* blk) {
|
||||
// represent classes we're actively loading.
|
||||
placeholders_do(blk);
|
||||
|
||||
// Visit extra methods
|
||||
if (invoke_method_table() != NULL)
|
||||
invoke_method_table()->oops_do(blk);
|
||||
|
||||
// Loader constraints. We must keep the symbolOop used in the name alive.
|
||||
constraints()->always_strong_classes_do(blk);
|
||||
|
||||
@ -1726,6 +1733,10 @@ void SystemDictionary::oops_do(OopClosure* f) {
|
||||
// Adjust dictionary
|
||||
dictionary()->oops_do(f);
|
||||
|
||||
// Visit extra methods
|
||||
if (invoke_method_table() != NULL)
|
||||
invoke_method_table()->oops_do(f);
|
||||
|
||||
// Partially loaded classes
|
||||
placeholders()->oops_do(f);
|
||||
|
||||
@ -1798,6 +1809,8 @@ void SystemDictionary::placeholders_do(void f(symbolOop, oop)) {
|
||||
|
||||
void SystemDictionary::methods_do(void f(methodOop)) {
|
||||
dictionary()->methods_do(f);
|
||||
if (invoke_method_table() != NULL)
|
||||
invoke_method_table()->methods_do(f);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -1830,6 +1843,7 @@ void SystemDictionary::initialize(TRAPS) {
|
||||
_number_of_modifications = 0;
|
||||
_loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
|
||||
_resolution_errors = new ResolutionErrorTable(_resolution_error_size);
|
||||
// _invoke_method_table is allocated lazily in find_method_handle_invoke()
|
||||
|
||||
// Allocate private object used as system class loader lock
|
||||
_system_loader_lock_obj = oopFactory::new_system_objArray(0, CHECK);
|
||||
@ -1891,6 +1905,9 @@ void SystemDictionary::initialize_wk_klasses_until(WKID limit_id, WKID &start_id
|
||||
wk_klass_name_limits[0] = s;
|
||||
}
|
||||
}
|
||||
|
||||
// move the starting value forward to the limit:
|
||||
start_id = limit_id;
|
||||
}
|
||||
|
||||
|
||||
@ -1924,6 +1941,17 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) {
|
||||
instanceKlass::cast(WK_KLASS(final_reference_klass))->set_reference_type(REF_FINAL);
|
||||
instanceKlass::cast(WK_KLASS(phantom_reference_klass))->set_reference_type(REF_PHANTOM);
|
||||
|
||||
WKID meth_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass);
|
||||
WKID meth_group_end = WK_KLASS_ENUM_NAME(WrongMethodTypeException_klass);
|
||||
initialize_wk_klasses_until(meth_group_start, scan, CHECK);
|
||||
if (EnableMethodHandles) {
|
||||
initialize_wk_klasses_through(meth_group_start, scan, CHECK);
|
||||
}
|
||||
if (_well_known_klasses[meth_group_start] == NULL) {
|
||||
// Skip the rest of the method handle classes, if MethodHandle is not loaded.
|
||||
scan = WKID(meth_group_end+1);
|
||||
}
|
||||
|
||||
initialize_wk_klasses_until(WKID_LIMIT, scan, CHECK);
|
||||
|
||||
_box_klasses[T_BOOLEAN] = WK_KLASS(boolean_klass);
|
||||
@ -2254,6 +2282,91 @@ char* SystemDictionary::check_signature_loaders(symbolHandle signature,
|
||||
}
|
||||
|
||||
|
||||
methodOop SystemDictionary::find_method_handle_invoke(symbolHandle signature,
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
TRAPS) {
|
||||
if (!EnableMethodHandles) return NULL;
|
||||
assert(class_loader.is_null() && protection_domain.is_null(),
|
||||
"cannot load specialized versions of MethodHandle.invoke");
|
||||
if (invoke_method_table() == NULL) {
|
||||
// create this side table lazily
|
||||
_invoke_method_table = new SymbolPropertyTable(_invoke_method_size);
|
||||
}
|
||||
unsigned int hash = invoke_method_table()->compute_hash(signature);
|
||||
int index = invoke_method_table()->hash_to_index(hash);
|
||||
SymbolPropertyEntry* spe = invoke_method_table()->find_entry(index, hash, signature);
|
||||
if (spe == NULL || spe->property_oop() == NULL) {
|
||||
// Must create lots of stuff here, but outside of the SystemDictionary lock.
|
||||
Handle mt = compute_method_handle_type(signature(),
|
||||
class_loader, protection_domain,
|
||||
CHECK_NULL);
|
||||
KlassHandle mh_klass = SystemDictionaryHandles::MethodHandle_klass();
|
||||
methodHandle m = methodOopDesc::make_invoke_method(mh_klass, signature,
|
||||
mt, CHECK_NULL);
|
||||
// Now grab the lock. We might have to throw away the new method,
|
||||
// if a racing thread has managed to install one at the same time.
|
||||
{
|
||||
MutexLocker ml(SystemDictionary_lock, Thread::current());
|
||||
spe = invoke_method_table()->find_entry(index, hash, signature);
|
||||
if (spe == NULL)
|
||||
spe = invoke_method_table()->add_entry(index, hash, signature);
|
||||
if (spe->property_oop() == NULL)
|
||||
spe->set_property_oop(m());
|
||||
}
|
||||
}
|
||||
methodOop m = (methodOop) spe->property_oop();
|
||||
assert(m->is_method(), "");
|
||||
return m;
|
||||
}
|
||||
|
||||
// Ask Java code to find or construct a java.dyn.MethodType for the given
|
||||
// signature, as interpreted relative to the given class loader.
|
||||
// Because of class loader constraints, all method handle usage must be
|
||||
// consistent with this loader.
|
||||
Handle SystemDictionary::compute_method_handle_type(symbolHandle signature,
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
TRAPS) {
|
||||
Handle empty;
|
||||
int npts = ArgumentCount(signature()).size();
|
||||
objArrayHandle pts = oopFactory::new_objArray(SystemDictionary::class_klass(), npts, CHECK_(empty));
|
||||
int arg = 0;
|
||||
Handle rt; // the return type from the signature
|
||||
for (SignatureStream ss(signature()); !ss.is_done(); ss.next()) {
|
||||
oop mirror;
|
||||
if (!ss.is_object()) {
|
||||
mirror = Universe::java_mirror(ss.type());
|
||||
} else {
|
||||
symbolOop name_oop = ss.as_symbol(CHECK_(empty));
|
||||
symbolHandle name(THREAD, name_oop);
|
||||
klassOop klass = resolve_or_fail(name,
|
||||
class_loader, protection_domain,
|
||||
true, CHECK_(empty));
|
||||
mirror = Klass::cast(klass)->java_mirror();
|
||||
}
|
||||
if (ss.at_return_type())
|
||||
rt = Handle(THREAD, mirror);
|
||||
else
|
||||
pts->obj_at_put(arg++, mirror);
|
||||
}
|
||||
assert(arg == npts, "");
|
||||
|
||||
// call MethodType java.dyn.MethodType::makeImpl(Class rt, Class[] pts, false, true)
|
||||
bool varargs = false, trusted = true;
|
||||
JavaCallArguments args(Handle(THREAD, rt()));
|
||||
args.push_oop(pts());
|
||||
args.push_int(false);
|
||||
args.push_int(trusted);
|
||||
JavaValue result(T_OBJECT);
|
||||
JavaCalls::call_static(&result,
|
||||
SystemDictionary::MethodType_klass(),
|
||||
vmSymbols::makeImpl_name(), vmSymbols::makeImpl_signature(),
|
||||
&args, CHECK_(empty));
|
||||
return Handle(THREAD, (oop) result.get_jobject());
|
||||
}
|
||||
|
||||
|
||||
// Since the identity hash code for symbols changes when the symbols are
|
||||
// moved from the regular perm gen (hash in the mark word) to the shared
|
||||
// spaces (hash is the address), the classes loaded into the dictionary
|
||||
|
@ -63,6 +63,7 @@ class PlaceholderTable;
|
||||
class LoaderConstraintTable;
|
||||
class HashtableBucket;
|
||||
class ResolutionErrorTable;
|
||||
class SymbolPropertyTable;
|
||||
|
||||
// Certain classes are preloaded, such as java.lang.Object and java.lang.String.
|
||||
// They are all "well-known", in the sense that no class loader is allowed
|
||||
@ -131,6 +132,16 @@ class ResolutionErrorTable;
|
||||
template(reflect_constant_pool_klass, sun_reflect_ConstantPool, Opt_Only_JDK15) \
|
||||
template(reflect_unsafe_static_field_accessor_impl_klass, sun_reflect_UnsafeStaticFieldAccessorImpl, Opt_Only_JDK15) \
|
||||
\
|
||||
/* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \
|
||||
template(MethodHandle_klass, java_dyn_MethodHandle, Opt) \
|
||||
template(MemberName_klass, sun_dyn_MemberName, Opt) \
|
||||
template(MethodHandleImpl_klass, sun_dyn_MethodHandleImpl, Opt) \
|
||||
template(AdapterMethodHandle_klass, sun_dyn_AdapterMethodHandle, Opt) \
|
||||
template(BoundMethodHandle_klass, sun_dyn_BoundMethodHandle, Opt) \
|
||||
template(DirectMethodHandle_klass, sun_dyn_DirectMethodHandle, Opt) \
|
||||
template(MethodType_klass, java_dyn_MethodType, Opt) \
|
||||
template(MethodTypeForm_klass, java_dyn_MethodTypeForm, Opt) \
|
||||
template(WrongMethodTypeException_klass, java_dyn_WrongMethodTypeException, Opt) \
|
||||
template(vector_klass, java_util_Vector, Pre) \
|
||||
template(hashtable_klass, java_util_Hashtable, Pre) \
|
||||
template(stringBuffer_klass, java_lang_StringBuffer, Pre) \
|
||||
@ -444,6 +455,17 @@ public:
|
||||
static char* check_signature_loaders(symbolHandle signature, Handle loader1,
|
||||
Handle loader2, bool is_method, TRAPS);
|
||||
|
||||
// JSR 292
|
||||
// find the java.dyn.MethodHandles::invoke method for a given signature
|
||||
static methodOop find_method_handle_invoke(symbolHandle signature,
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
TRAPS);
|
||||
// ask Java to compute the java.dyn.MethodType object for a given signature
|
||||
static Handle compute_method_handle_type(symbolHandle signature,
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
TRAPS);
|
||||
// Utility for printing loader "name" as part of tracing constraints
|
||||
static const char* loader_name(oop loader) {
|
||||
return ((loader) == NULL ? "<bootloader>" :
|
||||
@ -460,6 +482,7 @@ public:
|
||||
enum Constants {
|
||||
_loader_constraint_size = 107, // number of entries in constraint table
|
||||
_resolution_error_size = 107, // number of entries in resolution error table
|
||||
_invoke_method_size = 139, // number of entries in invoke method table
|
||||
_nof_buckets = 1009 // number of buckets in hash table
|
||||
};
|
||||
|
||||
@ -489,6 +512,9 @@ public:
|
||||
// Resolution errors
|
||||
static ResolutionErrorTable* _resolution_errors;
|
||||
|
||||
// Invoke methods (JSR 292)
|
||||
static SymbolPropertyTable* _invoke_method_table;
|
||||
|
||||
public:
|
||||
// for VM_CounterDecay iteration support
|
||||
friend class CounterDecay;
|
||||
@ -506,6 +532,7 @@ private:
|
||||
static PlaceholderTable* placeholders() { return _placeholders; }
|
||||
static LoaderConstraintTable* constraints() { return _loader_constraints; }
|
||||
static ResolutionErrorTable* resolution_errors() { return _resolution_errors; }
|
||||
static SymbolPropertyTable* invoke_method_table() { return _invoke_method_table; }
|
||||
|
||||
// Basic loading operations
|
||||
static klassOop resolve_instance_class_or_null(symbolHandle class_name, Handle class_loader, Handle protection_domain, TRAPS);
|
||||
|
@ -216,7 +216,26 @@
|
||||
template(sun_reflect_UnsafeStaticFieldAccessorImpl, "sun/reflect/UnsafeStaticFieldAccessorImpl")\
|
||||
template(base_name, "base") \
|
||||
\
|
||||
/* common method names */ \
|
||||
/* Support for JSR 292 & invokedynamic (JDK 1.7 and above) */ \
|
||||
template(java_dyn_MethodHandle, "java/dyn/MethodHandle") \
|
||||
template(java_dyn_MethodType, "java/dyn/MethodType") \
|
||||
template(java_dyn_WrongMethodTypeException, "java/dyn/WrongMethodTypeException") \
|
||||
template(java_dyn_MethodType_signature, "Ljava/dyn/MethodType;") \
|
||||
template(java_dyn_MethodHandle_signature, "Ljava/dyn/MethodHandle;") \
|
||||
/* internal classes known only to the JVM: */ \
|
||||
template(java_dyn_MethodTypeForm, "java/dyn/MethodTypeForm") \
|
||||
template(java_dyn_MethodTypeForm_signature, "Ljava/dyn/MethodTypeForm;") \
|
||||
template(sun_dyn_MemberName, "sun/dyn/MemberName") \
|
||||
template(sun_dyn_MethodHandleImpl, "sun/dyn/MethodHandleImpl") \
|
||||
template(sun_dyn_AdapterMethodHandle, "sun/dyn/AdapterMethodHandle") \
|
||||
template(sun_dyn_BoundMethodHandle, "sun/dyn/BoundMethodHandle") \
|
||||
template(sun_dyn_DirectMethodHandle, "sun/dyn/DirectMethodHandle") \
|
||||
template(makeImpl_name, "makeImpl") /*MethodType::makeImpl*/ \
|
||||
template(makeImpl_signature, "(Ljava/lang/Class;[Ljava/lang/Class;ZZ)Ljava/dyn/MethodType;") \
|
||||
NOT_LP64( do_alias(machine_word_signature, int_signature) ) \
|
||||
LP64_ONLY( do_alias(machine_word_signature, long_signature) ) \
|
||||
\
|
||||
/* common method and field names */ \
|
||||
template(object_initializer_name, "<init>") \
|
||||
template(class_initializer_name, "<clinit>") \
|
||||
template(println_name, "println") \
|
||||
@ -289,6 +308,21 @@
|
||||
template(bitCount_name, "bitCount") \
|
||||
template(profile_name, "profile") \
|
||||
template(equals_name, "equals") \
|
||||
template(toString_name, "toString") \
|
||||
template(values_name, "values") \
|
||||
template(receiver_name, "receiver") \
|
||||
template(vmtarget_name, "vmtarget") \
|
||||
template(vmentry_name, "vmentry") \
|
||||
template(vmslots_name, "vmslots") \
|
||||
template(vmindex_name, "vmindex") \
|
||||
template(vmargslot_name, "vmargslot") \
|
||||
template(flags_name, "flags") \
|
||||
template(argument_name, "argument") \
|
||||
template(conversion_name, "conversion") \
|
||||
template(rtype_name, "rtype") \
|
||||
template(ptypes_name, "ptypes") \
|
||||
template(form_name, "form") \
|
||||
template(erasedType_name, "erasedType") \
|
||||
\
|
||||
/* non-intrinsic name/signature pairs: */ \
|
||||
template(register_method_name, "register") \
|
||||
@ -353,6 +387,7 @@
|
||||
template(void_classloader_signature, "()Ljava/lang/ClassLoader;") \
|
||||
template(void_object_signature, "()Ljava/lang/Object;") \
|
||||
template(void_class_signature, "()Ljava/lang/Class;") \
|
||||
template(void_string_signature, "()Ljava/lang/String;") \
|
||||
template(object_array_object_object_signature, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")\
|
||||
template(exception_void_signature, "(Ljava/lang/Exception;)V") \
|
||||
template(protectiondomain_signature, "[Ljava/security/ProtectionDomain;") \
|
||||
|
@ -254,6 +254,7 @@ assembler_<arch>.cpp cardTableModRefBS.hpp
|
||||
assembler_<arch>.cpp collectedHeap.inline.hpp
|
||||
assembler_<arch>.cpp interfaceSupport.hpp
|
||||
assembler_<arch>.cpp interpreter.hpp
|
||||
assembler_<arch>.cpp methodHandles.hpp
|
||||
assembler_<arch>.cpp objectMonitor.hpp
|
||||
assembler_<arch>.cpp os.hpp
|
||||
assembler_<arch>.cpp resourceArea.hpp
|
||||
@ -1274,6 +1275,7 @@ cpCacheKlass.cpp bytecodes.hpp
|
||||
cpCacheKlass.cpp collectedHeap.hpp
|
||||
cpCacheKlass.cpp constantPoolOop.hpp
|
||||
cpCacheKlass.cpp cpCacheKlass.hpp
|
||||
cpCacheKlass.cpp genOopClosures.inline.hpp
|
||||
cpCacheKlass.cpp handles.inline.hpp
|
||||
cpCacheKlass.cpp javaClasses.hpp
|
||||
cpCacheKlass.cpp markSweep.inline.hpp
|
||||
@ -2202,6 +2204,7 @@ interpreter_<arch_model>.cpp interpreterGenerator.hpp
|
||||
interpreter_<arch_model>.cpp jvmtiExport.hpp
|
||||
interpreter_<arch_model>.cpp jvmtiThreadState.hpp
|
||||
interpreter_<arch_model>.cpp methodDataOop.hpp
|
||||
interpreter_<arch_model>.cpp methodHandles.hpp
|
||||
interpreter_<arch_model>.cpp methodOop.hpp
|
||||
interpreter_<arch_model>.cpp oop.inline.hpp
|
||||
interpreter_<arch_model>.cpp sharedRuntime.hpp
|
||||
@ -2596,6 +2599,7 @@ linkResolver.cpp handles.inline.hpp
|
||||
linkResolver.cpp instanceKlass.hpp
|
||||
linkResolver.cpp interpreterRuntime.hpp
|
||||
linkResolver.cpp linkResolver.hpp
|
||||
linkResolver.cpp methodHandles.hpp
|
||||
linkResolver.cpp nativeLookup.hpp
|
||||
linkResolver.cpp objArrayOop.hpp
|
||||
linkResolver.cpp reflection.hpp
|
||||
@ -2812,6 +2816,25 @@ methodDataOop.hpp oop.hpp
|
||||
methodDataOop.hpp orderAccess.hpp
|
||||
methodDataOop.hpp universe.hpp
|
||||
|
||||
methodHandles.hpp frame.inline.hpp
|
||||
methodHandles.hpp globals.hpp
|
||||
methodHandles.hpp interfaceSupport.hpp
|
||||
methodHandles.hpp javaClasses.hpp
|
||||
methodHandles.hpp vmSymbols.hpp
|
||||
|
||||
methodHandles.cpp allocation.inline.hpp
|
||||
methodHandles.cpp interpreter.hpp
|
||||
methodHandles.cpp javaCalls.hpp
|
||||
methodHandles.cpp methodHandles.hpp
|
||||
methodHandles.cpp oopFactory.hpp
|
||||
methodHandles.cpp reflection.hpp
|
||||
methodHandles.cpp signature.hpp
|
||||
methodHandles.cpp symbolTable.hpp
|
||||
|
||||
methodHandles_<arch>.cpp allocation.inline.hpp
|
||||
methodHandles_<arch>.cpp interpreter.hpp
|
||||
methodHandles_<arch>.cpp methodHandles.hpp
|
||||
|
||||
methodKlass.cpp collectedHeap.inline.hpp
|
||||
methodKlass.cpp constMethodKlass.hpp
|
||||
methodKlass.cpp gcLocker.hpp
|
||||
@ -3061,6 +3084,7 @@ oop.inline.hpp arrayKlass.hpp
|
||||
oop.inline.hpp arrayOop.hpp
|
||||
oop.inline.hpp atomic.hpp
|
||||
oop.inline.hpp barrierSet.inline.hpp
|
||||
oop.inline.hpp bytes_<arch>.hpp
|
||||
oop.inline.hpp cardTableModRefBS.hpp
|
||||
oop.inline.hpp collectedHeap.inline.hpp
|
||||
oop.inline.hpp compactingPermGenGen.hpp
|
||||
@ -3674,6 +3698,7 @@ sharedRuntime.cpp interpreterRuntime.hpp
|
||||
sharedRuntime.cpp interpreter.hpp
|
||||
sharedRuntime.cpp javaCalls.hpp
|
||||
sharedRuntime.cpp jvmtiExport.hpp
|
||||
sharedRuntime.cpp methodHandles.hpp
|
||||
sharedRuntime.cpp jvmtiRedefineClassesTrace.hpp
|
||||
sharedRuntime.cpp nativeInst_<arch>.hpp
|
||||
sharedRuntime.cpp nativeLookup.hpp
|
||||
@ -3862,6 +3887,7 @@ stubGenerator_<arch_model>.cpp frame.inline.hpp
|
||||
stubGenerator_<arch_model>.cpp handles.inline.hpp
|
||||
stubGenerator_<arch_model>.cpp instanceOop.hpp
|
||||
stubGenerator_<arch_model>.cpp interpreter.hpp
|
||||
stubGenerator_<arch_model>.cpp methodHandles.hpp
|
||||
stubGenerator_<arch_model>.cpp methodOop.hpp
|
||||
stubGenerator_<arch_model>.cpp nativeInst_<arch>.hpp
|
||||
stubGenerator_<arch_model>.cpp objArrayKlass.hpp
|
||||
|
@ -36,6 +36,12 @@ constantPoolKlass.cpp psPromotionManager.inline.hpp
|
||||
constantPoolKlass.cpp psScavenge.inline.hpp
|
||||
constantPoolKlass.cpp parOopClosures.inline.hpp
|
||||
|
||||
constantPoolKlass.cpp cardTableRS.hpp
|
||||
constantPoolKlass.cpp oop.pcgc.inline.hpp
|
||||
constantPoolKlass.cpp psPromotionManager.inline.hpp
|
||||
constantPoolKlass.cpp psScavenge.inline.hpp
|
||||
constantPoolKlass.cpp parOopClosures.inline.hpp
|
||||
|
||||
genCollectedHeap.cpp concurrentMarkSweepThread.hpp
|
||||
genCollectedHeap.cpp vmCMSOperations.hpp
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -61,6 +61,7 @@ class AbstractInterpreter: AllStatic {
|
||||
empty, // empty method (code: _return)
|
||||
accessor, // accessor method (code: _aload_0, _getfield, _(a|i)return)
|
||||
abstract, // abstract method (throws an AbstractMethodException)
|
||||
method_handle, // java.dyn.MethodHandles::invoke
|
||||
java_lang_math_sin, // implementation of java.lang.Math.sin (x)
|
||||
java_lang_math_cos, // implementation of java.lang.Math.cos (x)
|
||||
java_lang_math_tan, // implementation of java.lang.Math.tan (x)
|
||||
@ -91,8 +92,6 @@ class AbstractInterpreter: AllStatic {
|
||||
|
||||
static address _rethrow_exception_entry; // rethrows an activation in previous frame
|
||||
|
||||
|
||||
|
||||
friend class AbstractInterpreterGenerator;
|
||||
friend class InterpreterGenerator;
|
||||
friend class InterpreterMacroAssembler;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -114,6 +114,7 @@ void CppInterpreterGenerator::generate_all() {
|
||||
method_entry(empty);
|
||||
method_entry(accessor);
|
||||
method_entry(abstract);
|
||||
method_entry(method_handle);
|
||||
method_entry(java_lang_math_sin );
|
||||
method_entry(java_lang_math_cos );
|
||||
method_entry(java_lang_math_tan );
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -168,10 +168,14 @@ AbstractInterpreter::MethodKind AbstractInterpreter::method_kind(methodHandle m)
|
||||
// Abstract method?
|
||||
if (m->is_abstract()) return abstract;
|
||||
|
||||
// Invoker for method handles?
|
||||
if (m->is_method_handle_invoke()) return method_handle;
|
||||
|
||||
// Native method?
|
||||
// Note: This test must come _before_ the test for intrinsic
|
||||
// methods. See also comments below.
|
||||
if (m->is_native()) {
|
||||
assert(!m->is_method_handle_invoke(), "overlapping bits here, watch out");
|
||||
return m->is_synchronized() ? native_synchronized : native;
|
||||
}
|
||||
|
||||
@ -249,6 +253,7 @@ void AbstractInterpreter::print_method_kind(MethodKind kind) {
|
||||
case empty : tty->print("empty" ); break;
|
||||
case accessor : tty->print("accessor" ); break;
|
||||
case abstract : tty->print("abstract" ); break;
|
||||
case method_handle : tty->print("method_handle" ); break;
|
||||
case java_lang_math_sin : tty->print("java_lang_math_sin" ); break;
|
||||
case java_lang_math_cos : tty->print("java_lang_math_cos" ); break;
|
||||
case java_lang_math_tan : tty->print("java_lang_math_tan" ); break;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -293,6 +293,24 @@ IRT_ENTRY(void, InterpreterRuntime::throw_ClassCastException(
|
||||
THROW_MSG(vmSymbols::java_lang_ClassCastException(), message);
|
||||
IRT_END
|
||||
|
||||
// required can be either a MethodType, or a Class (for a single argument)
|
||||
// actual (if not null) can be either a MethodHandle, or an arbitrary value (for a single argument)
|
||||
IRT_ENTRY(void, InterpreterRuntime::throw_WrongMethodTypeException(JavaThread* thread,
|
||||
oopDesc* required,
|
||||
oopDesc* actual)) {
|
||||
ResourceMark rm(thread);
|
||||
char* message = SharedRuntime::generate_wrong_method_type_message(thread, required, actual);
|
||||
|
||||
if (ProfileTraps) {
|
||||
note_trap(thread, Deoptimization::Reason_constraint, CHECK);
|
||||
}
|
||||
|
||||
// create exception
|
||||
THROW_MSG(vmSymbols::java_dyn_WrongMethodTypeException(), message);
|
||||
}
|
||||
IRT_END
|
||||
|
||||
|
||||
|
||||
// exception_handler_for_exception(...) returns the continuation address,
|
||||
// the exception oop (via TLS) and sets the bci/bcp for the continuation.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -66,6 +66,7 @@ class InterpreterRuntime: AllStatic {
|
||||
static void throw_StackOverflowError(JavaThread* thread);
|
||||
static void throw_ArrayIndexOutOfBoundsException(JavaThread* thread, char* name, jint index);
|
||||
static void throw_ClassCastException(JavaThread* thread, oopDesc* obj);
|
||||
static void throw_WrongMethodTypeException(JavaThread* thread, oopDesc* mtype = NULL, oopDesc* mhandle = NULL);
|
||||
static void create_exception(JavaThread* thread, char* name, char* message);
|
||||
static void create_klass_exception(JavaThread* thread, char* name, oopDesc* obj);
|
||||
static address exception_handler_for_exception(JavaThread* thread, oopDesc* exception);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -151,6 +151,20 @@ void LinkResolver::lookup_method_in_interfaces(methodHandle& result, KlassHandle
|
||||
result = methodHandle(THREAD, ik->lookup_method_in_all_interfaces(name(), signature()));
|
||||
}
|
||||
|
||||
void LinkResolver::lookup_implicit_method(methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS) {
|
||||
if (EnableMethodHandles && MethodHandles::enabled() &&
|
||||
name == vmSymbolHandles::invoke_name() && klass() == SystemDictionary::MethodHandle_klass()) {
|
||||
methodOop result_oop = SystemDictionary::find_method_handle_invoke(signature,
|
||||
Handle(),
|
||||
Handle(),
|
||||
CHECK);
|
||||
if (result_oop != NULL) {
|
||||
assert(result_oop->is_method_handle_invoke() && result_oop->signature() == signature(), "consistent");
|
||||
result = methodHandle(THREAD, result_oop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinkResolver::check_method_accessability(KlassHandle ref_klass,
|
||||
KlassHandle resolved_klass,
|
||||
KlassHandle sel_klass,
|
||||
@ -239,6 +253,11 @@ void LinkResolver::resolve_method(methodHandle& resolved_method, KlassHandle res
|
||||
// 3. lookup method in all the interfaces implemented by the resolved klass
|
||||
lookup_method_in_interfaces(resolved_method, resolved_klass, method_name, method_signature, CHECK);
|
||||
|
||||
if (resolved_method.is_null()) {
|
||||
// JSR 292: see if this is an implicitly generated method MethodHandle.invoke(*...)
|
||||
lookup_implicit_method(resolved_method, resolved_klass, method_name, method_signature, CHECK);
|
||||
}
|
||||
|
||||
if (resolved_method.is_null()) {
|
||||
// 4. method lookup failed
|
||||
ResourceMark rm(THREAD);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -103,6 +103,7 @@ class LinkResolver: AllStatic {
|
||||
static void lookup_method_in_klasses (methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
|
||||
static void lookup_instance_method_in_klasses (methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
|
||||
static void lookup_method_in_interfaces (methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
|
||||
static void lookup_implicit_method (methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
|
||||
|
||||
static int vtable_index_of_miranda_method(KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -168,6 +168,7 @@ address TemplateInterpreter::_throw_ArrayIndexOutOfBoundsException_entry = NU
|
||||
address TemplateInterpreter::_throw_ArrayStoreException_entry = NULL;
|
||||
address TemplateInterpreter::_throw_ArithmeticException_entry = NULL;
|
||||
address TemplateInterpreter::_throw_ClassCastException_entry = NULL;
|
||||
address TemplateInterpreter::_throw_WrongMethodType_entry = NULL;
|
||||
address TemplateInterpreter::_throw_NullPointerException_entry = NULL;
|
||||
address TemplateInterpreter::_throw_StackOverflowError_entry = NULL;
|
||||
address TemplateInterpreter::_throw_exception_entry = NULL;
|
||||
@ -341,6 +342,7 @@ void TemplateInterpreterGenerator::generate_all() {
|
||||
Interpreter::_throw_ArrayStoreException_entry = generate_klass_exception_handler("java/lang/ArrayStoreException" );
|
||||
Interpreter::_throw_ArithmeticException_entry = generate_exception_handler("java/lang/ArithmeticException" , "/ by zero");
|
||||
Interpreter::_throw_ClassCastException_entry = generate_ClassCastException_handler();
|
||||
Interpreter::_throw_WrongMethodType_entry = generate_WrongMethodType_handler();
|
||||
Interpreter::_throw_NullPointerException_entry = generate_exception_handler("java/lang/NullPointerException" , NULL );
|
||||
Interpreter::_throw_StackOverflowError_entry = generate_StackOverflowError_handler();
|
||||
}
|
||||
@ -358,6 +360,7 @@ void TemplateInterpreterGenerator::generate_all() {
|
||||
method_entry(empty)
|
||||
method_entry(accessor)
|
||||
method_entry(abstract)
|
||||
method_entry(method_handle)
|
||||
method_entry(java_lang_math_sin )
|
||||
method_entry(java_lang_math_cos )
|
||||
method_entry(java_lang_math_tan )
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -77,6 +77,7 @@ class TemplateInterpreter: public AbstractInterpreter {
|
||||
friend class VMStructs;
|
||||
friend class InterpreterMacroAssembler;
|
||||
friend class TemplateInterpreterGenerator;
|
||||
friend class InterpreterGenerator;
|
||||
friend class TemplateTable;
|
||||
// friend class Interpreter;
|
||||
public:
|
||||
@ -93,6 +94,7 @@ class TemplateInterpreter: public AbstractInterpreter {
|
||||
static address _throw_ArrayStoreException_entry;
|
||||
static address _throw_ArithmeticException_entry;
|
||||
static address _throw_ClassCastException_entry;
|
||||
static address _throw_WrongMethodType_entry;
|
||||
static address _throw_NullPointerException_entry;
|
||||
static address _throw_exception_entry;
|
||||
|
||||
@ -137,6 +139,7 @@ class TemplateInterpreter: public AbstractInterpreter {
|
||||
static address remove_activation_entry() { return _remove_activation_entry; }
|
||||
static address throw_exception_entry() { return _throw_exception_entry; }
|
||||
static address throw_ArithmeticException_entry() { return _throw_ArithmeticException_entry; }
|
||||
static address throw_WrongMethodType_entry() { return _throw_WrongMethodType_entry; }
|
||||
static address throw_NullPointerException_entry() { return _throw_NullPointerException_entry; }
|
||||
static address throw_StackOverflowError_entry() { return _throw_StackOverflowError_entry; }
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -48,6 +48,7 @@ class TemplateInterpreterGenerator: public AbstractInterpreterGenerator {
|
||||
}
|
||||
address generate_exception_handler_common(const char* name, const char* message, bool pass_oop);
|
||||
address generate_ClassCastException_handler();
|
||||
address generate_WrongMethodType_handler();
|
||||
address generate_ArrayIndexOutOfBounds_handler(const char* name);
|
||||
address generate_continuation_for(TosState state);
|
||||
address generate_return_entry_for(TosState state, int step);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2003-2009 Sun Microsystems, Inc. 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
|
||||
@ -928,6 +928,9 @@ public:
|
||||
// shared classes at runtime, where constraints were previously created.
|
||||
guarantee(SystemDictionary::constraints()->number_of_entries() == 0,
|
||||
"loader constraints are not saved");
|
||||
// Revisit and implement this if we prelink method handle call sites:
|
||||
guarantee(SystemDictionary::invoke_method_table()->number_of_entries() == 0,
|
||||
"invoke method table is not saved");
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
|
||||
// At this point, many classes have been loaded.
|
||||
|
@ -298,7 +298,11 @@ void methodKlass::oop_print_on(oop obj, outputStream* st) {
|
||||
m->code()->print_value_on(st);
|
||||
st->cr();
|
||||
}
|
||||
if (m->is_native()) {
|
||||
if (m->is_method_handle_invoke()) {
|
||||
st->print_cr(" - invoke method type: " INTPTR_FORMAT, (address) m->method_handle_type());
|
||||
// m is classified as native, but it does not have an interesting
|
||||
// native_function or signature handler
|
||||
} else if (m->is_native()) {
|
||||
st->print_cr(" - native function: " INTPTR_FORMAT, m->native_function());
|
||||
st->print_cr(" - signature handler: " INTPTR_FORMAT, m->signature_handler());
|
||||
}
|
||||
|
@ -304,6 +304,12 @@ void methodOopDesc::cleanup_inline_caches() {
|
||||
}
|
||||
|
||||
|
||||
int methodOopDesc::extra_stack_words() {
|
||||
// not an inline function, to avoid a header dependency on Interpreter
|
||||
return extra_stack_entries() * Interpreter::stackElementSize();
|
||||
}
|
||||
|
||||
|
||||
void methodOopDesc::compute_size_of_parameters(Thread *thread) {
|
||||
symbolHandle h_signature(thread, signature());
|
||||
ArgumentSizeComputer asc(h_signature);
|
||||
@ -564,6 +570,11 @@ void methodOopDesc::set_signature_handler(address handler) {
|
||||
|
||||
|
||||
bool methodOopDesc::is_not_compilable(int comp_level) const {
|
||||
if (is_method_handle_invoke()) {
|
||||
// compilers must recognize this method specially, or not at all
|
||||
return true;
|
||||
}
|
||||
|
||||
methodDataOop mdo = method_data();
|
||||
if (mdo != NULL
|
||||
&& (uint)mdo->decompile_count() > (uint)PerMethodRecompilationCutoff) {
|
||||
@ -651,7 +662,7 @@ void methodOopDesc::link_method(methodHandle h_method, TRAPS) {
|
||||
assert(entry != NULL, "interpreter entry must be non-null");
|
||||
// Sets both _i2i_entry and _from_interpreted_entry
|
||||
set_interpreter_entry(entry);
|
||||
if (is_native()) {
|
||||
if (is_native() && !is_method_handle_invoke()) {
|
||||
set_native_function(
|
||||
SharedRuntime::native_method_throw_unsatisfied_link_error_entry(),
|
||||
!native_bind_event_is_interesting);
|
||||
@ -783,6 +794,100 @@ bool methodOopDesc::should_not_be_cached() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Constant pool structure for invoke methods:
|
||||
enum {
|
||||
_imcp_invoke_name = 1, // utf8: 'invoke'
|
||||
_imcp_invoke_signature, // utf8: (variable symbolOop)
|
||||
_imcp_method_type_value, // string: (variable java/dyn/MethodType, sic)
|
||||
_imcp_limit
|
||||
};
|
||||
|
||||
oop methodOopDesc::method_handle_type() const {
|
||||
if (!is_method_handle_invoke()) { assert(false, "caller resp."); return NULL; }
|
||||
oop mt = constants()->resolved_string_at(_imcp_method_type_value);
|
||||
assert(mt->klass() == SystemDictionary::MethodType_klass(), "");
|
||||
return mt;
|
||||
}
|
||||
|
||||
jint* methodOopDesc::method_type_offsets_chain() {
|
||||
static jint pchase[] = { -1, -1, -1 };
|
||||
if (pchase[0] == -1) {
|
||||
jint step0 = in_bytes(constants_offset());
|
||||
jint step1 = (constantPoolOopDesc::header_size() + _imcp_method_type_value) * HeapWordSize;
|
||||
// do this in reverse to avoid races:
|
||||
OrderAccess::release_store(&pchase[1], step1);
|
||||
OrderAccess::release_store(&pchase[0], step0);
|
||||
}
|
||||
return pchase;
|
||||
}
|
||||
|
||||
methodHandle methodOopDesc::make_invoke_method(KlassHandle holder,
|
||||
symbolHandle signature,
|
||||
Handle method_type, TRAPS) {
|
||||
methodHandle empty;
|
||||
|
||||
assert(holder() == SystemDictionary::MethodHandle_klass(),
|
||||
"must be a JSR 292 magic type");
|
||||
|
||||
if (TraceMethodHandles) {
|
||||
tty->print("Creating invoke method for ");
|
||||
signature->print_value();
|
||||
tty->cr();
|
||||
}
|
||||
|
||||
constantPoolHandle cp;
|
||||
{
|
||||
constantPoolOop cp_oop = oopFactory::new_constantPool(_imcp_limit, IsSafeConc, CHECK_(empty));
|
||||
cp = constantPoolHandle(THREAD, cp_oop);
|
||||
}
|
||||
cp->symbol_at_put(_imcp_invoke_name, vmSymbols::invoke_name());
|
||||
cp->symbol_at_put(_imcp_invoke_signature, signature());
|
||||
cp->string_at_put(_imcp_method_type_value, vmSymbols::void_signature());
|
||||
cp->set_pool_holder(holder());
|
||||
|
||||
// set up the fancy stuff:
|
||||
cp->pseudo_string_at_put(_imcp_method_type_value, method_type());
|
||||
methodHandle m;
|
||||
{
|
||||
int flags_bits = (JVM_MH_INVOKE_BITS | JVM_ACC_PUBLIC | JVM_ACC_FINAL);
|
||||
methodOop m_oop = oopFactory::new_method(0, accessFlags_from(flags_bits),
|
||||
0, 0, 0, IsSafeConc, CHECK_(empty));
|
||||
m = methodHandle(THREAD, m_oop);
|
||||
}
|
||||
m->set_constants(cp());
|
||||
m->set_name_index(_imcp_invoke_name);
|
||||
m->set_signature_index(_imcp_invoke_signature);
|
||||
assert(m->name() == vmSymbols::invoke_name(), "");
|
||||
assert(m->signature() == signature(), "");
|
||||
#ifdef CC_INTERP
|
||||
ResultTypeFinder rtf(signature());
|
||||
m->set_result_index(rtf.type());
|
||||
#endif
|
||||
m->compute_size_of_parameters(THREAD);
|
||||
m->set_exception_table(Universe::the_empty_int_array());
|
||||
|
||||
// Finally, set up its entry points.
|
||||
assert(m->method_handle_type() == method_type(), "");
|
||||
assert(m->can_be_statically_bound(), "");
|
||||
m->set_vtable_index(methodOopDesc::nonvirtual_vtable_index);
|
||||
m->link_method(m, CHECK_(empty));
|
||||
|
||||
#ifdef ASSERT
|
||||
// Make sure the pointer chase works.
|
||||
address p = (address) m();
|
||||
for (jint* pchase = method_type_offsets_chain(); (*pchase) != -1; pchase++) {
|
||||
p = *(address*)(p + (*pchase));
|
||||
}
|
||||
assert((oop)p == method_type(), "pointer chase is correct");
|
||||
#endif
|
||||
|
||||
if (TraceMethodHandles)
|
||||
m->print_on(tty);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
methodHandle methodOopDesc:: clone_with_new_data(methodHandle m, u_char* new_code, int new_code_length,
|
||||
u_char* new_compressed_linenumber_table, int new_compressed_linenumber_size, TRAPS) {
|
||||
|
@ -320,6 +320,7 @@ class methodOopDesc : public oopDesc {
|
||||
enum VtableIndexFlag {
|
||||
// Valid vtable indexes are non-negative (>= 0).
|
||||
// These few negative values are used as sentinels.
|
||||
highest_unused_vtable_index_value = -5,
|
||||
invalid_vtable_index = -4, // distinct from any valid vtable index
|
||||
garbage_vtable_index = -3, // not yet linked; no vtable layout yet
|
||||
nonvirtual_vtable_index = -2 // there is no need for vtable dispatch
|
||||
@ -523,6 +524,18 @@ class methodOopDesc : public oopDesc {
|
||||
// Reflection support
|
||||
bool is_overridden_in(klassOop k) const;
|
||||
|
||||
// JSR 292 support
|
||||
bool is_method_handle_invoke() const { return access_flags().is_method_handle_invoke(); }
|
||||
static methodHandle make_invoke_method(KlassHandle holder,
|
||||
symbolHandle signature,
|
||||
Handle method_type,
|
||||
TRAPS);
|
||||
// these operate only on invoke methods:
|
||||
oop method_handle_type() const;
|
||||
static jint* method_type_offsets_chain(); // series of pointer-offsets, terminated by -1
|
||||
// presize interpreter frames for extra interpreter stack entries, if needed
|
||||
static int extra_stack_entries() { return EnableMethodHandles ? (int)MethodHandlePushLimit : 0; }
|
||||
static int extra_stack_words(); // = extra_stack_entries() * Interpreter::stackElementSize()
|
||||
// RedefineClasses() support:
|
||||
bool is_old() const { return access_flags().is_old(); }
|
||||
void set_is_old() { _access_flags.set_is_old(); }
|
||||
|
@ -263,6 +263,9 @@ class oopDesc {
|
||||
jdouble double_field_acquire(int offset) const;
|
||||
void release_double_field_put(int offset, jdouble contents);
|
||||
|
||||
address address_field_acquire(int offset) const;
|
||||
void release_address_field_put(int offset, address contents);
|
||||
|
||||
// printing functions for VM debugging
|
||||
void print_on(outputStream* st) const; // First level print
|
||||
void print_value_on(outputStream* st) const; // Second level print.
|
||||
|
@ -349,6 +349,9 @@ inline void oopDesc::release_float_field_put(int offset, jfloat contents) { Or
|
||||
inline jdouble oopDesc::double_field_acquire(int offset) const { return OrderAccess::load_acquire(double_field_addr(offset)); }
|
||||
inline void oopDesc::release_double_field_put(int offset, jdouble contents) { OrderAccess::release_store(double_field_addr(offset), contents); }
|
||||
|
||||
inline address oopDesc::address_field_acquire(int offset) const { return (address) OrderAccess::load_ptr_acquire(address_field_addr(offset)); }
|
||||
inline void oopDesc::release_address_field_put(int offset, address contents) { OrderAccess::release_store_ptr(address_field_addr(offset), contents); }
|
||||
|
||||
inline int oopDesc::size_given_klass(Klass* klass) {
|
||||
int lh = klass->layout_helper();
|
||||
int s = lh >> LogHeapWordSize; // deliver size scaled by wordSize
|
||||
|
2347
hotspot/src/share/vm/prims/methodHandles.cpp
Normal file
2347
hotspot/src/share/vm/prims/methodHandles.cpp
Normal file
File diff suppressed because it is too large
Load Diff
435
hotspot/src/share/vm/prims/methodHandles.hpp
Normal file
435
hotspot/src/share/vm/prims/methodHandles.hpp
Normal file
@ -0,0 +1,435 @@
|
||||
/*
|
||||
* Copyright 2008-2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
class MacroAssembler;
|
||||
class Label;
|
||||
class MethodHandleEntry;
|
||||
|
||||
class MethodHandles: AllStatic {
|
||||
// JVM support for MethodHandle, MethodType, and related types
|
||||
// in java.dyn and java.dyn.hotspot.
|
||||
// See also javaClasses for layouts java_dyn_Method{Handle,Type,Type::Form}.
|
||||
public:
|
||||
enum EntryKind {
|
||||
_check_mtype, // how a caller calls a MH
|
||||
_wrong_method_type, // what happens when there is a type mismatch
|
||||
_invokestatic_mh, // how a MH emulates invokestatic
|
||||
_invokespecial_mh, // ditto for the other invokes...
|
||||
_invokevirtual_mh,
|
||||
_invokeinterface_mh,
|
||||
_bound_ref_mh, // reference argument is bound
|
||||
_bound_int_mh, // int argument is bound (via an Integer or Float)
|
||||
_bound_long_mh, // long argument is bound (via a Long or Double)
|
||||
_bound_ref_direct_mh, // same as above, with direct linkage to methodOop
|
||||
_bound_int_direct_mh,
|
||||
_bound_long_direct_mh,
|
||||
|
||||
_adapter_mh_first, // adapter sequence goes here...
|
||||
_adapter_retype_only = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_RETYPE_ONLY,
|
||||
_adapter_check_cast = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_CHECK_CAST,
|
||||
_adapter_prim_to_prim = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_PRIM_TO_PRIM,
|
||||
_adapter_ref_to_prim = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_REF_TO_PRIM,
|
||||
_adapter_prim_to_ref = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_PRIM_TO_REF,
|
||||
_adapter_swap_args = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_SWAP_ARGS,
|
||||
_adapter_rot_args = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_ROT_ARGS,
|
||||
_adapter_dup_args = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_DUP_ARGS,
|
||||
_adapter_drop_args = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_DROP_ARGS,
|
||||
_adapter_collect_args = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_COLLECT_ARGS,
|
||||
_adapter_spread_args = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_SPREAD_ARGS,
|
||||
_adapter_flyby = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_FLYBY,
|
||||
_adapter_ricochet = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_RICOCHET,
|
||||
_adapter_mh_last = _adapter_mh_first + sun_dyn_AdapterMethodHandle::CONV_OP_LIMIT - 1,
|
||||
|
||||
// Optimized adapter types
|
||||
|
||||
// argument list reordering
|
||||
_adapter_opt_swap_1,
|
||||
_adapter_opt_swap_2,
|
||||
_adapter_opt_rot_1_up,
|
||||
_adapter_opt_rot_1_down,
|
||||
_adapter_opt_rot_2_up,
|
||||
_adapter_opt_rot_2_down,
|
||||
// primitive single to single:
|
||||
_adapter_opt_i2i, // i2c, i2z, i2b, i2s
|
||||
// primitive double to single:
|
||||
_adapter_opt_l2i,
|
||||
_adapter_opt_d2f,
|
||||
// primitive single to double:
|
||||
_adapter_opt_i2l,
|
||||
_adapter_opt_f2d,
|
||||
// conversion between floating point and integer type is handled by Java
|
||||
|
||||
// reference to primitive:
|
||||
_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,
|
||||
|
||||
_EK_LIMIT,
|
||||
_EK_FIRST = 0
|
||||
};
|
||||
|
||||
public:
|
||||
static bool enabled() { return _enabled; }
|
||||
static void set_enabled(bool z);
|
||||
|
||||
private:
|
||||
enum { // import sun_dyn_AdapterMethodHandle::CONV_OP_*
|
||||
CONV_OP_LIMIT = sun_dyn_AdapterMethodHandle::CONV_OP_LIMIT,
|
||||
CONV_OP_MASK = sun_dyn_AdapterMethodHandle::CONV_OP_MASK,
|
||||
CONV_VMINFO_MASK = sun_dyn_AdapterMethodHandle::CONV_VMINFO_MASK,
|
||||
CONV_VMINFO_SHIFT = sun_dyn_AdapterMethodHandle::CONV_VMINFO_SHIFT,
|
||||
CONV_OP_SHIFT = sun_dyn_AdapterMethodHandle::CONV_OP_SHIFT,
|
||||
CONV_DEST_TYPE_SHIFT = sun_dyn_AdapterMethodHandle::CONV_DEST_TYPE_SHIFT,
|
||||
CONV_SRC_TYPE_SHIFT = sun_dyn_AdapterMethodHandle::CONV_SRC_TYPE_SHIFT,
|
||||
CONV_STACK_MOVE_SHIFT = sun_dyn_AdapterMethodHandle::CONV_STACK_MOVE_SHIFT,
|
||||
CONV_STACK_MOVE_MASK = sun_dyn_AdapterMethodHandle::CONV_STACK_MOVE_MASK
|
||||
};
|
||||
|
||||
static bool _enabled;
|
||||
static MethodHandleEntry* _entries[_EK_LIMIT];
|
||||
static const char* _entry_names[_EK_LIMIT+1];
|
||||
static bool ek_valid(EntryKind ek) { return (uint)ek < (uint)_EK_LIMIT; }
|
||||
static bool conv_op_valid(int op) { return (uint)op < (uint)CONV_OP_LIMIT; }
|
||||
|
||||
public:
|
||||
static bool have_entry(EntryKind ek) { return ek_valid(ek) && _entries[ek] != NULL; }
|
||||
static MethodHandleEntry* entry(EntryKind ek) { assert(ek_valid(ek), "initialized");
|
||||
return _entries[ek]; }
|
||||
static const char* entry_name(EntryKind ek) { assert(ek_valid(ek), "oob");
|
||||
return _entry_names[ek]; }
|
||||
static EntryKind adapter_entry_kind(int op) { assert(conv_op_valid(op), "oob");
|
||||
return EntryKind(_adapter_mh_first + op); }
|
||||
|
||||
static void init_entry(EntryKind ek, MethodHandleEntry* me) {
|
||||
assert(ek_valid(ek), "oob");
|
||||
assert(_entries[ek] == NULL, "no double initialization");
|
||||
_entries[ek] = me;
|
||||
}
|
||||
|
||||
static jint adapter_conversion(int conv_op, BasicType src, BasicType dest,
|
||||
int stack_move = 0, int vminfo = 0) {
|
||||
assert(conv_op_valid(conv_op), "oob");
|
||||
jint conv = ((conv_op << CONV_OP_SHIFT)
|
||||
| (src << CONV_SRC_TYPE_SHIFT)
|
||||
| (dest << CONV_DEST_TYPE_SHIFT)
|
||||
| (stack_move << CONV_STACK_MOVE_SHIFT)
|
||||
| (vminfo << CONV_VMINFO_SHIFT)
|
||||
);
|
||||
assert(adapter_conversion_op(conv) == conv_op, "decode conv_op");
|
||||
assert(adapter_conversion_src_type(conv) == src, "decode src");
|
||||
assert(adapter_conversion_dest_type(conv) == dest, "decode dest");
|
||||
assert(adapter_conversion_stack_move(conv) == stack_move, "decode stack_move");
|
||||
assert(adapter_conversion_vminfo(conv) == vminfo, "decode vminfo");
|
||||
return conv;
|
||||
}
|
||||
static int adapter_conversion_op(jint conv) {
|
||||
return ((conv >> CONV_OP_SHIFT) & 0xF);
|
||||
}
|
||||
static BasicType adapter_conversion_src_type(jint conv) {
|
||||
return (BasicType)((conv >> CONV_SRC_TYPE_SHIFT) & 0xF);
|
||||
}
|
||||
static BasicType adapter_conversion_dest_type(jint conv) {
|
||||
return (BasicType)((conv >> CONV_DEST_TYPE_SHIFT) & 0xF);
|
||||
}
|
||||
static int adapter_conversion_stack_move(jint conv) {
|
||||
return (conv >> CONV_STACK_MOVE_SHIFT);
|
||||
}
|
||||
static int adapter_conversion_vminfo(jint conv) {
|
||||
return (conv >> CONV_VMINFO_SHIFT) & CONV_VMINFO_MASK;
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
enum { CONV_VMINFO_SIGN_FLAG = 0x80 };
|
||||
static int adapter_subword_vminfo(BasicType dest) {
|
||||
if (dest == T_BOOLEAN) return (BitsPerInt - 1);
|
||||
if (dest == T_CHAR) return (BitsPerInt - 16);
|
||||
if (dest == T_BYTE) return (BitsPerInt - 8) | CONV_VMINFO_SIGN_FLAG;
|
||||
if (dest == T_SHORT) return (BitsPerInt - 16) | CONV_VMINFO_SIGN_FLAG;
|
||||
return 0; // case T_INT
|
||||
}
|
||||
// Here is the transformation the i2i adapter must perform:
|
||||
static int truncate_subword_from_vminfo(jint value, int vminfo) {
|
||||
jint tem = value << vminfo;
|
||||
if ((vminfo & CONV_VMINFO_SIGN_FLAG) != 0) {
|
||||
return (jint)tem >> vminfo;
|
||||
} else {
|
||||
return (juint)tem >> vminfo;
|
||||
}
|
||||
}
|
||||
|
||||
static inline address from_compiled_entry(EntryKind ek);
|
||||
static inline address from_interpreted_entry(EntryKind ek);
|
||||
|
||||
// helpers for decode_method.
|
||||
static methodOop decode_methodOop(methodOop m, int& decode_flags_result);
|
||||
static methodOop decode_vmtarget(oop vmtarget, int vmindex, oop mtype, klassOop& receiver_limit_result, int& decode_flags_result);
|
||||
static methodOop decode_MemberName(oop mname, klassOop& receiver_limit_result, int& decode_flags_result);
|
||||
static methodOop decode_MethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result);
|
||||
static methodOop decode_DirectMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result);
|
||||
static methodOop decode_BoundMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result);
|
||||
static methodOop decode_AdapterMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result);
|
||||
|
||||
// Find out how many stack slots an mh pushes or pops.
|
||||
// The result is *not* reported as a multiple of stack_move_unit();
|
||||
// It is a signed net number of pushes (a difference in vmslots).
|
||||
// To compare with a stack_move value, first multiply by stack_move_unit().
|
||||
static int decode_MethodHandle_stack_pushes(oop mh);
|
||||
|
||||
public:
|
||||
// working with member names
|
||||
static void resolve_MemberName(Handle mname, TRAPS); // compute vmtarget/vmindex from name/type
|
||||
static void expand_MemberName(Handle mname, int suppress, TRAPS); // expand defc/name/type if missing
|
||||
static void init_MemberName(oop mname_oop, oop target); // compute vmtarget/vmindex from target
|
||||
static void init_MemberName(oop mname_oop, methodOop m, bool do_dispatch);
|
||||
static void init_MemberName(oop mname_oop, klassOop field_holder, AccessFlags mods, int offset);
|
||||
static int find_MemberNames(klassOop k, symbolOop name, symbolOop sig,
|
||||
int mflags, klassOop caller,
|
||||
int skip, objArrayOop results);
|
||||
// bit values for suppress argument to expand_MemberName:
|
||||
enum { _suppress_defc = 1, _suppress_name = 2, _suppress_type = 4 };
|
||||
|
||||
// called from InterpreterGenerator and StubGenerator
|
||||
static address generate_method_handle_interpreter_entry(MacroAssembler* _masm);
|
||||
static void generate_method_handle_stub(MacroAssembler* _masm, EntryKind ek);
|
||||
|
||||
// argument list parsing
|
||||
static int argument_slot(oop method_type, int arg);
|
||||
static int argument_slot_count(oop method_type) { return argument_slot(method_type, -1); }
|
||||
static int argument_slot_to_argnum(oop method_type, int argslot);
|
||||
|
||||
// Runtime support
|
||||
enum { // bit-encoded flags from decode_method or decode_vmref
|
||||
_dmf_has_receiver = 0x01, // target method has leading reference argument
|
||||
_dmf_does_dispatch = 0x02, // method handle performs virtual or interface dispatch
|
||||
_dmf_from_interface = 0x04, // peforms interface dispatch
|
||||
_DMF_DIRECT_MASK = (_dmf_from_interface*2 - _dmf_has_receiver),
|
||||
_dmf_binds_method = 0x08,
|
||||
_dmf_binds_argument = 0x10,
|
||||
_DMF_BOUND_MASK = (_dmf_binds_argument*2 - _dmf_binds_method),
|
||||
_dmf_adapter_lsb = 0x20,
|
||||
_DMF_ADAPTER_MASK = (_dmf_adapter_lsb << CONV_OP_LIMIT) - _dmf_adapter_lsb
|
||||
};
|
||||
static methodOop decode_method(oop x, klassOop& receiver_limit_result, int& decode_flags_result);
|
||||
enum {
|
||||
// format of query to getConstant:
|
||||
GC_JVM_PUSH_LIMIT = 0,
|
||||
GC_JVM_STACK_MOVE_LIMIT = 1,
|
||||
|
||||
// format of result from getTarget / encode_target:
|
||||
ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method)
|
||||
ETF_DIRECT_HANDLE = 1, // ultimate method handle (will be a DMH, may be self)
|
||||
ETF_METHOD_NAME = 2, // ultimate method as MemberName
|
||||
ETF_REFLECT_METHOD = 3 // ultimate method as java.lang.reflect object (sans refClass)
|
||||
};
|
||||
static int get_named_constant(int which, Handle name_box, TRAPS);
|
||||
static oop encode_target(Handle mh, int format, TRAPS); // report vmtarget (to Java code)
|
||||
static bool class_cast_needed(klassOop src, klassOop dst);
|
||||
|
||||
private:
|
||||
// These checkers operate on a pair of whole MethodTypes:
|
||||
static const char* check_method_type_change(oop src_mtype, int src_beg, int src_end,
|
||||
int insert_argnum, oop insert_type,
|
||||
int change_argnum, oop change_type,
|
||||
int delete_argnum,
|
||||
oop dst_mtype, int dst_beg, int dst_end);
|
||||
static const char* check_method_type_insertion(oop src_mtype,
|
||||
int insert_argnum, oop insert_type,
|
||||
oop dst_mtype) {
|
||||
oop no_ref = NULL;
|
||||
return check_method_type_change(src_mtype, 0, -1,
|
||||
insert_argnum, insert_type,
|
||||
-1, no_ref, -1, dst_mtype, 0, -1);
|
||||
}
|
||||
static const char* check_method_type_conversion(oop src_mtype,
|
||||
int change_argnum, oop change_type,
|
||||
oop dst_mtype) {
|
||||
oop no_ref = NULL;
|
||||
return check_method_type_change(src_mtype, 0, -1, -1, no_ref,
|
||||
change_argnum, change_type,
|
||||
-1, dst_mtype, 0, -1);
|
||||
}
|
||||
static const char* check_method_type_passthrough(oop src_mtype, oop dst_mtype) {
|
||||
oop no_ref = NULL;
|
||||
return check_method_type_change(src_mtype, 0, -1,
|
||||
-1, no_ref, -1, no_ref, -1,
|
||||
dst_mtype, 0, -1);
|
||||
}
|
||||
|
||||
// These checkers operate on pairs of argument or return types:
|
||||
static const char* check_argument_type_change(BasicType src_type, klassOop src_klass,
|
||||
BasicType dst_type, klassOop dst_klass,
|
||||
int argnum);
|
||||
|
||||
static const char* check_argument_type_change(oop src_type, oop dst_type,
|
||||
int argnum) {
|
||||
klassOop src_klass = NULL, dst_klass = NULL;
|
||||
BasicType src_bt = java_lang_Class::as_BasicType(src_type, &src_klass);
|
||||
BasicType dst_bt = java_lang_Class::as_BasicType(dst_type, &dst_klass);
|
||||
return check_argument_type_change(src_bt, src_klass,
|
||||
dst_bt, dst_klass, argnum);
|
||||
}
|
||||
|
||||
static const char* check_return_type_change(oop src_type, oop dst_type) {
|
||||
return check_argument_type_change(src_type, dst_type, -1);
|
||||
}
|
||||
|
||||
static const char* check_return_type_change(BasicType src_type, klassOop src_klass,
|
||||
BasicType dst_type, klassOop dst_klass) {
|
||||
return check_argument_type_change(src_type, src_klass, dst_type, dst_klass, -1);
|
||||
}
|
||||
|
||||
static const char* check_method_receiver(methodOop m, klassOop passed_recv_type);
|
||||
|
||||
// These verifiers can block, and will throw an error if the checking fails:
|
||||
static void verify_vmslots(Handle mh, TRAPS);
|
||||
static void verify_vmargslot(Handle mh, int argnum, int argslot, TRAPS);
|
||||
|
||||
static void verify_method_type(methodHandle m, Handle mtype,
|
||||
bool has_bound_oop,
|
||||
KlassHandle bound_oop_type,
|
||||
TRAPS);
|
||||
|
||||
static void verify_method_signature(methodHandle m, Handle mtype,
|
||||
int first_ptype_pos,
|
||||
KlassHandle insert_ptype, TRAPS);
|
||||
|
||||
static void verify_DirectMethodHandle(Handle mh, methodHandle m, TRAPS);
|
||||
static void verify_BoundMethodHandle(Handle mh, Handle target, int argnum,
|
||||
bool direct_to_method, TRAPS);
|
||||
static void verify_BoundMethodHandle_with_receiver(Handle mh, methodHandle m, TRAPS);
|
||||
static void verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS);
|
||||
|
||||
public:
|
||||
|
||||
// Fill in the fields of a DirectMethodHandle mh. (MH.type must be pre-filled.)
|
||||
static void init_DirectMethodHandle(Handle mh, methodHandle method, bool do_dispatch, TRAPS);
|
||||
|
||||
// Fill in the fields of a BoundMethodHandle mh. (MH.type, BMH.argument must be pre-filled.)
|
||||
static void init_BoundMethodHandle(Handle mh, Handle target, int argnum, TRAPS);
|
||||
static void init_BoundMethodHandle_with_receiver(Handle mh,
|
||||
methodHandle original_m,
|
||||
KlassHandle receiver_limit,
|
||||
int decode_flags,
|
||||
TRAPS);
|
||||
|
||||
// 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);
|
||||
|
||||
#ifdef ASSERT
|
||||
static bool spot_check_entry_names();
|
||||
#endif
|
||||
|
||||
private:
|
||||
static methodHandle dispatch_decoded_method(methodHandle m,
|
||||
KlassHandle receiver_limit,
|
||||
int decode_flags,
|
||||
KlassHandle receiver_klass,
|
||||
TRAPS);
|
||||
|
||||
static bool same_basic_type_for_arguments(BasicType src, BasicType dst,
|
||||
bool for_return = false);
|
||||
static bool same_basic_type_for_returns(BasicType src, BasicType dst) {
|
||||
return same_basic_type_for_arguments(src, dst, true);
|
||||
}
|
||||
|
||||
enum { // arg_mask values
|
||||
_INSERT_NO_MASK = -1,
|
||||
_INSERT_REF_MASK = 0,
|
||||
_INSERT_INT_MASK = 1,
|
||||
_INSERT_LONG_MASK = 3
|
||||
};
|
||||
static void insert_arg_slots(MacroAssembler* _masm,
|
||||
RegisterOrConstant arg_slots,
|
||||
int arg_mask,
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
// Access methods for the "entry" field of a java.dyn.MethodHandle.
|
||||
// The field is primarily a jump target for compiled calls.
|
||||
// However, we squirrel away some nice pointers for other uses,
|
||||
// just before the jump target.
|
||||
// Aspects of a method handle entry:
|
||||
// - from_compiled_entry - stub used when compiled code calls the MH
|
||||
// - from_interpreted_entry - stub used when the interpreter calls the MH
|
||||
// - type_checking_entry - stub for runtime casting between MHForm siblings (NYI)
|
||||
class MethodHandleEntry {
|
||||
public:
|
||||
class Data {
|
||||
friend class MethodHandleEntry;
|
||||
size_t _total_size; // size including Data and code stub
|
||||
MethodHandleEntry* _type_checking_entry;
|
||||
address _from_interpreted_entry;
|
||||
MethodHandleEntry* method_entry() { return (MethodHandleEntry*)(this + 1); }
|
||||
};
|
||||
|
||||
Data* data() { return (Data*)this - 1; }
|
||||
|
||||
address start_address() { return (address) data(); }
|
||||
address end_address() { return start_address() + data()->_total_size; }
|
||||
|
||||
address from_compiled_entry() { return (address) this; }
|
||||
|
||||
address from_interpreted_entry() { return data()->_from_interpreted_entry; }
|
||||
void set_from_interpreted_entry(address e) { data()->_from_interpreted_entry = e; }
|
||||
|
||||
MethodHandleEntry* type_checking_entry() { return data()->_type_checking_entry; }
|
||||
void set_type_checking_entry(MethodHandleEntry* e) { data()->_type_checking_entry = e; }
|
||||
|
||||
void set_end_address(address end_addr) {
|
||||
size_t total_size = end_addr - start_address();
|
||||
assert(total_size > 0 && total_size < 0x1000, "reasonable end address");
|
||||
data()->_total_size = total_size;
|
||||
}
|
||||
|
||||
// Compiler support:
|
||||
static int from_interpreted_entry_offset_in_bytes() {
|
||||
return (int)( offset_of(Data, _from_interpreted_entry) - sizeof(Data) );
|
||||
}
|
||||
static int type_checking_entry_offset_in_bytes() {
|
||||
return (int)( offset_of(Data, _from_interpreted_entry) - sizeof(Data) );
|
||||
}
|
||||
|
||||
static address start_compiled_entry(MacroAssembler* _masm,
|
||||
address interpreted_entry = NULL);
|
||||
static MethodHandleEntry* finish_compiled_entry(MacroAssembler* masm, address start_addr);
|
||||
};
|
||||
|
||||
address MethodHandles::from_compiled_entry(EntryKind ek) { return entry(ek)->from_compiled_entry(); }
|
||||
address MethodHandles::from_interpreted_entry(EntryKind ek) { return entry(ek)->from_interpreted_entry(); }
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -78,6 +78,7 @@ char* NativeLookup::long_jni_name(methodHandle method) {
|
||||
|
||||
extern "C" {
|
||||
void JNICALL JVM_RegisterUnsafeMethods(JNIEnv *env, jclass unsafecls);
|
||||
void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls);
|
||||
void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
|
||||
}
|
||||
|
||||
@ -97,6 +98,9 @@ static address lookup_special_native(char* jni_name) {
|
||||
if (strstr(jni_name, "Java_sun_misc_Unsafe_registerNatives") != NULL) {
|
||||
return CAST_FROM_FN_PTR(address, JVM_RegisterUnsafeMethods);
|
||||
}
|
||||
if (strstr(jni_name, "Java_sun_dyn_MethodHandleNatives_registerNatives") != NULL) {
|
||||
return CAST_FROM_FN_PTR(address, JVM_RegisterMethodHandleMethods);
|
||||
}
|
||||
if (strstr(jni_name, "Java_sun_misc_Perf_registerNatives") != NULL) {
|
||||
return CAST_FROM_FN_PTR(address, JVM_RegisterPerfMethods);
|
||||
}
|
||||
|
@ -2619,6 +2619,13 @@ jint Arguments::parse(const JavaVMInitArgs* args) {
|
||||
}
|
||||
#endif // PRODUCT
|
||||
|
||||
if (EnableMethodHandles && !AnonymousClasses) {
|
||||
if (!FLAG_IS_DEFAULT(AnonymousClasses)) {
|
||||
warning("forcing AnonymousClasses true to enable EnableMethodHandles");
|
||||
}
|
||||
AnonymousClasses = true;
|
||||
}
|
||||
|
||||
if (PrintGCDetails) {
|
||||
// Turn on -verbose:gc options as well
|
||||
PrintGC = true;
|
||||
|
@ -3298,6 +3298,21 @@ class CommandLineFlags {
|
||||
product(bool, AnonymousClasses, false, \
|
||||
"support sun.misc.Unsafe.defineAnonymousClass") \
|
||||
\
|
||||
product(bool, EnableMethodHandles, false, \
|
||||
"support method handles (true by default under JSR 292)") \
|
||||
\
|
||||
diagnostic(intx, MethodHandlePushLimit, 3, \
|
||||
"number of additional stack slots a method handle may push") \
|
||||
\
|
||||
develop(bool, TraceMethodHandles, false, \
|
||||
"trace internal method handle operations") \
|
||||
\
|
||||
diagnostic(bool, VerifyMethodHandles, trueInDebug, \
|
||||
"perform extra checks when constructing method handles") \
|
||||
\
|
||||
diagnostic(bool, OptimizeMethodHandles, true, \
|
||||
"when constructing method handles, try to improve them") \
|
||||
\
|
||||
product(bool, TaggedStackInterpreter, false, \
|
||||
"Insert tags in interpreter execution stack for oopmap generaion")\
|
||||
\
|
||||
|
@ -1471,9 +1471,73 @@ char* SharedRuntime::generate_class_cast_message(
|
||||
return generate_class_cast_message(objName, targetKlass->external_name());
|
||||
}
|
||||
|
||||
char* SharedRuntime::generate_wrong_method_type_message(JavaThread* thread,
|
||||
oopDesc* required,
|
||||
oopDesc* actual) {
|
||||
assert(EnableMethodHandles, "");
|
||||
oop singleKlass = wrong_method_type_is_for_single_argument(thread, required);
|
||||
if (singleKlass != NULL) {
|
||||
const char* objName = "argument or return value";
|
||||
if (actual != NULL) {
|
||||
// be flexible about the junk passed in:
|
||||
klassOop ak = (actual->is_klass()
|
||||
? (klassOop)actual
|
||||
: actual->klass());
|
||||
objName = Klass::cast(ak)->external_name();
|
||||
}
|
||||
Klass* targetKlass = Klass::cast(required->is_klass()
|
||||
? (klassOop)required
|
||||
: java_lang_Class::as_klassOop(required));
|
||||
return generate_class_cast_message(objName, targetKlass->external_name());
|
||||
} else {
|
||||
// %%% need to get the MethodType string, without messing around too much
|
||||
// Get a signature from the invoke instruction
|
||||
const char* mhName = "method handle";
|
||||
const char* targetType = "the required signature";
|
||||
vframeStream vfst(thread, true);
|
||||
if (!vfst.at_end()) {
|
||||
Bytecode_invoke* call = Bytecode_invoke_at(vfst.method(), vfst.bci());
|
||||
methodHandle target;
|
||||
{
|
||||
EXCEPTION_MARK;
|
||||
target = call->static_target(THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; }
|
||||
}
|
||||
if (target.not_null()
|
||||
&& target->is_method_handle_invoke()
|
||||
&& required == target->method_handle_type()) {
|
||||
targetType = target->signature()->as_C_string();
|
||||
}
|
||||
}
|
||||
klassOop kignore; int fignore;
|
||||
methodOop actual_method = MethodHandles::decode_method(actual,
|
||||
kignore, fignore);
|
||||
if (actual_method != NULL) {
|
||||
if (actual_method->name() == vmSymbols::invoke_name())
|
||||
mhName = "$";
|
||||
else
|
||||
mhName = actual_method->signature()->as_C_string();
|
||||
if (mhName[0] == '$')
|
||||
mhName = actual_method->signature()->as_C_string();
|
||||
}
|
||||
return generate_class_cast_message(mhName, targetType,
|
||||
" cannot be called as ");
|
||||
}
|
||||
}
|
||||
|
||||
oop SharedRuntime::wrong_method_type_is_for_single_argument(JavaThread* thr,
|
||||
oopDesc* required) {
|
||||
if (required == NULL) return NULL;
|
||||
if (required->klass() == SystemDictionary::class_klass())
|
||||
return required;
|
||||
if (required->is_klass())
|
||||
return Klass::cast(klassOop(required))->java_mirror();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
char* SharedRuntime::generate_class_cast_message(
|
||||
const char* objName, const char* targetKlassName) {
|
||||
const char* desc = " cannot be cast to ";
|
||||
const char* objName, const char* targetKlassName, const char* desc) {
|
||||
size_t msglen = strlen(objName) + strlen(desc) + strlen(targetKlassName) + 1;
|
||||
|
||||
char* message = NEW_RESOURCE_ARRAY(char, msglen);
|
||||
|
@ -211,11 +211,33 @@ class SharedRuntime: AllStatic {
|
||||
*/
|
||||
static char* generate_class_cast_message(JavaThread* thr, const char* name);
|
||||
|
||||
/**
|
||||
* Fill in the message for a WrongMethodTypeException
|
||||
*
|
||||
* @param thr the current thread
|
||||
* @param mtype (optional) expected method type (or argument class)
|
||||
* @param mhandle (optional) actual method handle (or argument)
|
||||
* @return the dynamically allocated exception message
|
||||
*
|
||||
* BCP for the frame on top of the stack must refer to an
|
||||
* 'invokevirtual' op for a method handle, or an 'invokedyamic' op.
|
||||
* The caller (or one of its callers) must use a ResourceMark
|
||||
* in order to correctly free the result.
|
||||
*/
|
||||
static char* generate_wrong_method_type_message(JavaThread* thr,
|
||||
oopDesc* mtype = NULL,
|
||||
oopDesc* mhandle = NULL);
|
||||
|
||||
/** Return non-null if the mtype is a klass or Class, not a MethodType. */
|
||||
static oop wrong_method_type_is_for_single_argument(JavaThread* thr,
|
||||
oopDesc* mtype);
|
||||
|
||||
/**
|
||||
* Fill in the "X cannot be cast to a Y" message for ClassCastException
|
||||
*
|
||||
* @param name the name of the class of the object attempted to be cast
|
||||
* @param klass the name of the target klass attempt
|
||||
* @param gripe the specific kind of problem being reported
|
||||
* @return the dynamically allocated exception message (must be freed
|
||||
* by the caller using a resource mark)
|
||||
*
|
||||
@ -224,7 +246,8 @@ class SharedRuntime: AllStatic {
|
||||
* The caller (or one of it's callers) must use a ResourceMark
|
||||
* in order to correctly free the result.
|
||||
*/
|
||||
static char* generate_class_cast_message(const char* name, const char* klass);
|
||||
static char* generate_class_cast_message(const char* name, const char* klass,
|
||||
const char* gripe = " cannot be cast to ");
|
||||
|
||||
// Resolves a call site- may patch in the destination of the call into the
|
||||
// compiled code.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||
@ -47,6 +47,8 @@ enum {
|
||||
JVM_ACC_IS_OLD = 0x00010000, // RedefineClasses() has replaced this method
|
||||
JVM_ACC_IS_OBSOLETE = 0x00020000, // RedefineClasses() has made method obsolete
|
||||
JVM_ACC_IS_PREFIXED_NATIVE = 0x00040000, // JVMTI has prefixed this native method
|
||||
JVM_MH_INVOKE_BITS // = 0x10001100 // MethodHandle.invoke quasi-native
|
||||
= (JVM_ACC_NATIVE | JVM_ACC_SYNTHETIC | JVM_ACC_MONITOR_MATCH),
|
||||
|
||||
// klassOop flags
|
||||
JVM_ACC_HAS_MIRANDA_METHODS = 0x10000000, // True if this class has miranda methods in it's vtable
|
||||
@ -72,6 +74,7 @@ enum {
|
||||
|
||||
// flags accepted by set_field_flags()
|
||||
JVM_ACC_FIELD_FLAGS = 0x00008000 | JVM_ACC_WRITTEN_FLAGS
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -114,6 +117,15 @@ class AccessFlags VALUE_OBJ_CLASS_SPEC {
|
||||
bool is_obsolete () const { return (_flags & JVM_ACC_IS_OBSOLETE ) != 0; }
|
||||
bool is_prefixed_native () const { return (_flags & JVM_ACC_IS_PREFIXED_NATIVE ) != 0; }
|
||||
|
||||
// JSR 292: A method of the form MethodHandle.invoke(A...)R method is
|
||||
// neither bytecoded nor a JNI native, but rather a fast call through
|
||||
// a lightweight method handle object. Because it is not bytecoded,
|
||||
// it has the native bit set, but the monitor-match bit is also set
|
||||
// to distinguish it from a JNI native (which never has the match bit set).
|
||||
// The synthetic bit is also present, because such a method is never
|
||||
// explicitly defined in Java code.
|
||||
bool is_method_handle_invoke () const { return (_flags & JVM_MH_INVOKE_BITS) == JVM_MH_INVOKE_BITS; }
|
||||
|
||||
// klassOop flags
|
||||
bool has_miranda_methods () const { return (_flags & JVM_ACC_HAS_MIRANDA_METHODS ) != 0; }
|
||||
bool has_vanilla_constructor () const { return (_flags & JVM_ACC_HAS_VANILLA_CONSTRUCTOR) != 0; }
|
||||
@ -199,6 +211,14 @@ class AccessFlags VALUE_OBJ_CLASS_SPEC {
|
||||
jshort as_short() { return (jshort)_flags; }
|
||||
jint as_int() { return _flags; }
|
||||
|
||||
inline friend AccessFlags accessFlags_from(jint flags);
|
||||
|
||||
// Printing/debugging
|
||||
void print_on(outputStream* st) const PRODUCT_RETURN;
|
||||
};
|
||||
|
||||
inline AccessFlags accessFlags_from(jint flags) {
|
||||
AccessFlags af;
|
||||
af._flags = flags;
|
||||
return af;
|
||||
}
|
||||
|
@ -237,6 +237,9 @@ class Exceptions {
|
||||
#define THROW_ARG_0(name, signature, arg) THROW_ARG_(name, signature, arg, 0)
|
||||
#define THROW_MSG_CAUSE_0(name, message, cause) THROW_MSG_CAUSE_(name, message, cause, 0)
|
||||
|
||||
#define THROW_NULL(name) THROW_(name, NULL)
|
||||
#define THROW_MSG_NULL(name, message) THROW_MSG_(name, message, NULL)
|
||||
|
||||
// The CATCH macro checks that no exception has been thrown by a function; it is used at
|
||||
// call sites about which is statically known that the callee cannot throw an exception
|
||||
// even though it is declared with TRAPS.
|
||||
|
@ -408,6 +408,15 @@ inline bool is_java_primitive(BasicType t) {
|
||||
return T_BOOLEAN <= t && t <= T_LONG;
|
||||
}
|
||||
|
||||
inline bool is_subword_type(BasicType t) {
|
||||
// these guys are processed exactly like T_INT in calling sequences:
|
||||
return (t == T_BOOLEAN || t == T_CHAR || t == T_BYTE || t == T_SHORT);
|
||||
}
|
||||
|
||||
inline bool is_signed_subword_type(BasicType t) {
|
||||
return (t == T_BYTE || t == T_SHORT);
|
||||
}
|
||||
|
||||
// Convert a char from a classfile signature to a BasicType
|
||||
inline BasicType char2type(char c) {
|
||||
switch( c ) {
|
||||
|
Loading…
Reference in New Issue
Block a user