meth: International Invokedynamic Day
authorjrose
Tue Aug 26 02:44:43 2008 -0700 (15 months ago)
changeset 1670401b91c4f7
parent 15e205623138c2
child 1715cb6a10af43
meth: International Invokedynamic Day
meth.patch
--- a/meth.patch Sat Aug 16 01:31:35 2008 -0700
+++ b/meth.patch Tue Aug 26 02:44:43 2008 -0700
@@ -1,3 +1,123 @@ diff --git a/src/cpu/sparc/vm/interprete
+diff --git a/src/cpu/sparc/vm/cppInterpreter_sparc.cpp b/src/cpu/sparc/vm/cppInterpreter_sparc.cpp
+--- a/src/cpu/sparc/vm/cppInterpreter_sparc.cpp
++++ b/src/cpu/sparc/vm/cppInterpreter_sparc.cpp
+@@ -1017,6 +1017,7 @@
+ const int slop_factor = 2*wordSize;
+
+ const int fixed_size = ((sizeof(BytecodeInterpreter) + slop_factor) >> LogBytesPerWord) + // what is the slop factor?
++ (InvokeDynamic ? 1 : 0) + // extra push slot for MH insertion
+ 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,8 @@
+ __ st_ptr(O2, XXX_STATE(_stack)); // PREPUSH
+
+ __ lduh(max_stack, O3); // Full size expression stack
++ if (InvokeDynamic)
++ __ inc(O3, wordSize);
+ __ sll(O3, LogBytesPerWord, O3);
+ __ sub(O2, O3, O3);
+ // __ sub(O3, wordSize, O3); // so prepush doesn't look out of bounds
+@@ -2017,7 +2020,9 @@
+
+ const int fixed_size = sizeof(BytecodeInterpreter)/wordSize + // interpreter state object
+ frame::memory_parameter_word_sp_offset; // register save area + param window
+- return (round_to(max_stack +
++ const int extra_stack = (InvokeDynamic ? 1 : 0);
++ return (round_to(max_stack +
++ extra_stack +
+ slop_factor +
+ fixed_size +
+ monitor_size +
+@@ -2104,7 +2109,8 @@
+ // 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 = (InvokeDynamic ? 1 : 0);
++ to_fill->_stack_limit = stack_base - (method->max_stack() + 1 + extra_stack);
+ to_fill->_monitor_base = (BasicObjectLock*) monitor_base;
+
+ // sparc specific
+diff --git a/src/cpu/sparc/vm/interp_masm_sparc.cpp b/src/cpu/sparc/vm/interp_masm_sparc.cpp
+--- a/src/cpu/sparc/vm/interp_masm_sparc.cpp
++++ b/src/cpu/sparc/vm/interp_masm_sparc.cpp
+@@ -831,10 +831,26 @@
+ }
+
+
+-void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, Register tmp, int bcp_offset) {
++void InterpreterMacroAssembler::get_index_at_bcp(Register Rtmp, Register Rdst,
++ int bcp_offset, bool giant_index) {
++ assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
++ if (!giant_index) {
++ get_2_byte_integer_at_bcp(bcp_offset, Rtmp, Rdst, Unsigned);
++ } else {
++ assert(InvokeDynamic, "giant index used only for InvokeDynamic");
++ get_4_byte_integer_at_bcp(bcp_offset, Rtmp, Rdst);
++ assert(constantPoolCacheOopDesc::decode_secondary_index(~123) == 123, "else change next line");
++ xor3(Rdst, -1, Rdst); // convert to plain index
++ }
++}
++
++
++void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, Register tmp,
++ int bcp_offset, bool giant_index) {
+ assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
+ assert_different_registers(cache, tmp);
+ assert_not_delayed();
++ assert(!giant_index,"NYI");
+ get_2_byte_integer_at_bcp(bcp_offset, cache, tmp, Unsigned);
+ // convert from field index to ConstantPoolCacheEntry index
+ // and from word index to byte offset
+@@ -843,10 +859,12 @@
+ }
+
+
+-void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset) {
++void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, Register tmp,
++ int bcp_offset, bool giant_index) {
+ assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
+ assert_different_registers(cache, tmp);
+ assert_not_delayed();
++ assert(!giant_index,"NYI");
+ get_2_byte_integer_at_bcp(bcp_offset, cache, tmp, Unsigned);
+ // convert from field index to ConstantPoolCacheEntry index
+ // and from word index to byte offset
+@@ -1739,7 +1757,8 @@
+ // Count a virtual call in the bytecodes.
+
+ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
+- Register scratch) {
++ Register scratch,
++ bool receiver_can_be_null) {
+ if (ProfileInterpreter) {
+ Label profile_continue;
+
+diff --git a/src/cpu/sparc/vm/interp_masm_sparc.hpp b/src/cpu/sparc/vm/interp_masm_sparc.hpp
+--- a/src/cpu/sparc/vm/interp_masm_sparc.hpp
++++ b/src/cpu/sparc/vm/interp_masm_sparc.hpp
+@@ -191,8 +191,9 @@
+ Register Rdst,
+ setCCOrNot should_set_CC = dont_set_CC );
+
+- void get_cache_and_index_at_bcp(Register cache, Register tmp, int bcp_offset);
+- void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset);
++ void get_cache_and_index_at_bcp(Register cache, Register tmp, int bcp_offset, bool giant_index = false);
++ void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, bool giant_index = false);
++ void get_index_at_bcp(Register Rtmp, Register Rdst, int bcp_offset, bool giant_index = false);
+
+
+ // common code
+@@ -304,7 +305,7 @@
+ void profile_not_taken_branch(Register scratch);
+ void profile_call(Register scratch);
+ void profile_final_call(Register scratch);
+- void profile_virtual_call(Register receiver, Register scratch);
++ void profile_virtual_call(Register receiver, Register scratch, bool receiver_can_be_null = false);
+ void profile_ret(TosState state, Register return_bci, Register scratch);
+ void profile_null_seen(Register scratch);
+ void profile_typecheck(Register klass, Register scratch);
diff --git a/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp b/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp
--- a/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp
+++ b/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp
@@ -37,6 +157,88 @@ diff --git a/src/cpu/sparc/vm/interprete
case Interpreter::java_lang_math_sin : break;
case Interpreter::java_lang_math_cos : break;
case Interpreter::java_lang_math_tan : break;
+diff --git a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
+--- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
++++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
+@@ -108,6 +108,22 @@
+ }
+
+
++// Arguments are: required type in O0, failing object (or NULL) in O1
++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),
++ O0, O1);
++ __ 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
+@@ -167,7 +183,15 @@
+
+ const Register cache = G3_scratch;
+ const Register size = G1_scratch;
+- __ get_cache_and_index_at_bcp(cache, G1_scratch, 1);
++ Label L_got_cache, L_giant_index;
++ if (InvokeDynamic) {
++ __ ldub(Lbcp, 0, size);
++ __ cmp(size, Bytecodes::_invokedynamic);
++ __ br(Assembler::equal, false, Assembler::pn, L_giant_index);
++ __ delayed()->nop();
++ }
++ __ get_cache_and_index_at_bcp(cache, G1_scratch, 1, false);
++ __ bind(L_got_cache);
+ __ ld_ptr(Address(cache, 0, in_bytes(constantPoolCacheOopDesc::base_offset()) +
+ in_bytes(ConstantPoolCacheEntry::flags_offset())), size);
+ __ and3(size, 0xFF, size); // argument size in words
+@@ -175,7 +199,20 @@
+ __ add(Lesp, size, Lesp); // pop arguments
+ __ dispatch_next(state, step);
+
++ // out of the main line of code...
++ if (InvokeDynamic) {
++ __ bind(L_giant_index);
++ __ get_cache_and_index_at_bcp(cache, G1_scratch, 1, true);
++ __ br(false, L_got_cache);
++ __ delayed()->nop();
++ }
++
+ return entry;
++}
++
++
++address TemplateInterpreterGenerator::generate_return_unbox_entry_for(TosState state, int step) {
++ __ unimplemented();
+ }
+
+
+@@ -448,6 +485,7 @@
+
+ const int extra_space =
+ rounded_vm_local_words + // frame local scratch space
++ (InvokeDynamic ? 1 : 0) + // extra push slot for MH insertion
+ frame::memory_parameter_word_sp_offset + // register save area
+ (native_call ? frame::interpreter_frame_extra_outgoing_argument_words : 0);
+
+@@ -1445,7 +1483,8 @@
+ // callee_locals and max_stack are counts, not the size in frame.
+ const int locals_size =
+ round_to(callee_extra_locals * Interpreter::stackElementWords(), WordsPerLong);
+- const int max_stack_words = max_stack * Interpreter::stackElementWords();
++ const int extra_stack = (InvokeDynamic ? 1 : 0);
++ const int max_stack_words = (max_stack + extra_stack) * Interpreter::stackElementWords();
+ return (round_to((max_stack_words
+ + rounded_vm_local_words
+ + frame::memory_parameter_word_sp_offset), WordsPerLong)
diff --git a/src/cpu/sparc/vm/templateTable_sparc.cpp b/src/cpu/sparc/vm/templateTable_sparc.cpp
--- a/src/cpu/sparc/vm/templateTable_sparc.cpp
+++ b/src/cpu/sparc/vm/templateTable_sparc.cpp
@@ -98,16 +300,32 @@ diff --git a/src/cpu/x86/vm/assembler_x8
} else {
InstructionMark im(this);
L.add_patch_at(code(), locator());
-@@ -4702,6 +4702,67 @@
+@@ -4702,6 +4702,157 @@
}
-+void MacroAssembler::lookup_interface_method(Register recv_klass, // rdx or rcx
-+ Register intf_klass, // usually rax
-+ RegisterConstant itable_index, // can be rbx
-+ Register method_result, // usually rbx
-+ Register scan_temp, // rdx or rsi
-+ Label& no_such_interface) {
++RegisterConstant MacroAssembler::delayed_value(intptr_t* delayed_value_addr, Register tmp) {
++ intptr_t value = *delayed_value_addr;
++ if (value != 0)
++ return value;
++ movptr(tmp, ExternalAddress((address) delayed_value_addr));
++#ifdef ASSERT
++ Label L;
++ testl(tmp, tmp);
++ jccb(Assembler::notZero, L);
++ hlt();
++ bind(L);
++#endif
++ return tmp;
++}
++
++
++void MacroAssembler::lookup_interface_method(Register recv_klass,
++ Register intf_klass,
++ RegisterConstant itable_index,
++ Register method_result,
++ Register scan_temp,
++ Label& L_no_such_interface) {
+ assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
+ assert(itable_index.is_constant() || itable_index.as_register() == method_result,
+ "caller must use same register for non-constant itable index as for method");
@@ -154,13 +372,87 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ // the reciever class doesn't implement the interface, and wasn't the
+ // same as when the caller was compiled.
+ testl(method_result, method_result);
-+ jcc(Assembler::zero, no_such_interface);
++ jcc(Assembler::zero, L_no_such_interface);
+ addl(scan_temp, scan_step);
+ }
+
+ bind(found_method);
+}
+
++
++// Test sub_klass against super_klass.
++// Fall through on failure, but branch to L_success if there is a match.
++// Use up the given temp_reg, but don't kill any other register.
++// Update the sub's secondary super cache if necesary.
++void MacroAssembler::check_klass_subtype(Register sub_klass,
++ Register super_klass,
++ Register temp_reg,
++ Label& L_success) {
++ Label L_failure; // fallthrough label
++
++ assert_different_registers(sub_klass, super_klass, temp_reg);
++
++ // a couple of useful fields in sub_klass:
++ int ss_offset = (klassOopDesc::header_size() * HeapWordSize +
++ Klass::secondary_supers_offset_in_bytes());
++ int sc_offset = (klassOopDesc::header_size() * HeapWordSize +
++ Klass::secondary_super_cache_offset_in_bytes());
++ Address secondary_supers_addr(sub_klass, ss_offset);
++ Address super_cache_addr( sub_klass, sc_offset);
++
++ int sco_offset = (klassOopDesc::header_size() * HeapWordSize +
++ Klass::super_check_offset_offset_in_bytes());
++ Address super_check_offset_addr(super_klass, sco_offset);
++
++ // if the pointers are equal, we are done (e.g., String[] elements)
++ cmpl(sub_klass, super_klass);
++ jcc(Assembler::equal, L_success);
++
++ // check the supertype display:
++ movl(temp_reg, super_check_offset_addr);
++ Address super_check_addr(sub_klass, temp_reg, Address::times_1, 0);
++ cmpl(super_klass, super_check_addr); // load displayed supertype
++ jcc(Assembler::equal, L_success);
++
++ // if it was a primary super, we can just fail immediately
++ cmpl(temp_reg, sc_offset);
++ jcc(Assembler::notEqual, L_failure);
++
++ // Now do a linear scan of the secondary super-klass chain.
++ // This code is rarely used, so simplicity is a virtue here.
++ {
++ // The repne_scan instruction uses fixed registers, which we must spill.
++ // Don't bother to figure out pre-existing connections with the input regs.
++ pushl(rax);
++ pushl(rcx);
++ pushl(rdi);
++ pushl(super_klass);
++
++ movl(rdi, secondary_supers_addr);
++ // Load the array length.
++ movl(rcx, Address(rdi, arrayOopDesc::length_offset_in_bytes()));
++ // Skip to start of data.
++ addl(rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT));
++ // Scan rcx words at [edi] for occurance of rax,
++ // Set NZ/Z based on last compare
++ popl(rax); // super_klass value, even if it was in rdi or rcx
++ repne_scan();
++
++ // Unspill the temp. registers:
++ popl(rdi);
++ popl(rcx);
++ popl(rax);
++ }
++ jcc(Assembler::notEqual, L_failure);
++
++ // Success. Cache the super we found and proceed in triumph.
++ movl(super_cache_addr, super_klass);
++
++ jmp(L_success);
++
++ // Fall through on failure!
++ bind(L_failure);
++}
+
+
int MacroAssembler::biased_locking_enter(Register lock_reg, Register obj_reg, Register swap_reg, Register tmp_reg,
@@ -197,7 +489,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
// Address is an abstraction used to represent a memory location
// using any of the amd64 addressing modes with one object.
//
-@@ -143,7 +164,8 @@
+@@ -143,8 +164,17 @@
times_1 = 0,
times_2 = 1,
times_4 = 2,
@@ -205,13 +497,22 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ times_8 = 3,
+ times_wordSize = NOT_LP64(times_4) LP64_ONLY(times_8)
};
++
++ static ScaleFactor times(int size) {
++ assert(size >= 1 && size <= 8 && is_power_of_2(size), "bad scale size");
++ if (size == 8) return times_8;
++ if (size == 4) return times_4;
++ if (size == 2) return times_2;
++ return times_1;
++ }
private:
-@@ -186,6 +208,16 @@
+ Register _base;
+@@ -186,6 +216,16 @@
"inconsistent address");
}
-+ Address(Register base, RegisterConstant index, ScaleFactor scale, int disp = 0)
++ Address(Register base, RegisterConstant index, ScaleFactor scale = times_1, int disp = 0)
+ : _base (base),
+ _index(index.register_or_noreg()),
+ _scale(scale),
@@ -224,7 +525,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
// The following two overloads are used in connection with the
// ByteSize type (see sizes.hpp). They simplify the use of
// ByteSize'd arguments in assembly code. Note that their equivalent
-@@ -213,6 +245,17 @@
+@@ -213,6 +253,17 @@
assert(!index->is_valid() == (scale == Address::no_scale),
"inconsistent address");
}
@@ -242,7 +543,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
#endif // ASSERT
// accessors
-@@ -227,6 +270,14 @@
+@@ -227,6 +278,14 @@
static Address make_array(ArrayAddress);
@@ -257,10 +558,19 @@ diff --git a/src/cpu/x86/vm/assembler_x8
private:
bool base_needs_rex() const {
-@@ -1287,6 +1338,14 @@
+@@ -1287,6 +1346,29 @@
);
void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case);
++ // small bootstrap problems
++ RegisterConstant delayed_value(intptr_t* delayed_value_addr, Register tmp);
++ RegisterConstant delayed_value(int(*value_fn)(), Register tmp) {
++ return delayed_value(delayed_value_addr(value_fn), tmp);
++ }
++ RegisterConstant delayed_value(address(*value_fn)(), Register tmp) {
++ return delayed_value((intptr_t*) delayed_value_addr(value_fn), tmp);
++ }
++
+ // method calling
+ void lookup_interface_method(Register recv_klass, // rdx or rcx
+ Register intf_klass, // usually rax
@@ -268,6 +578,12 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ Register method_result, // usually rbx
+ Register scan_temp, // rdi or rdx
+ Label& no_such_interface);
++
++ // klass type checking (falls through on failure)
++ void check_klass_subtype(Register sub_klass,
++ Register super_klass,
++ Register temp_reg,
++ Label& L_success);
+
//----
void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0
@@ -286,7 +602,31 @@ diff --git a/src/cpu/x86/vm/cppInterpret
diff --git a/src/cpu/x86/vm/cppInterpreter_x86.cpp b/src/cpu/x86/vm/cppInterpreter_x86.cpp
--- a/src/cpu/x86/vm/cppInterpreter_x86.cpp
+++ b/src/cpu/x86/vm/cppInterpreter_x86.cpp
-@@ -2104,6 +2104,7 @@
+@@ -502,10 +502,11 @@
+ // compute full expression stack limit
+
+ const Address size_of_stack (rbx, methodOopDesc::max_stack_offset());
++ const int extra_stack = (InvokeDynamic ? Interpreter::stackElementSize() : 0);
+ __ load_unsigned_word(rdx, size_of_stack); // get size of expression stack in words
+ __ negl(rdx); // so we can subtract in next step
+ // Allocate expression stack
+- __ leal(rsp, Address(rsp, rdx, Address::times_4));
++ __ leal(rsp, Address(rsp, rdx, Address::times_4, -extra_stack));
+ __ movl(STATE(_stack_limit), rsp);
+ }
+
+@@ -642,8 +643,9 @@
+ // 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 one_monitor = frame::interpreter_frame_monitor_size() * wordSize;
++ const int extra_stack = (InvokeDynamic ? Interpreter::stackElementSize() : 0);
+ __ load_unsigned_word(rax, size_of_stack); // get size of expression stack in words
+- __ leal(rax, Address(noreg, rax, Interpreter::stackElementScale(), one_monitor));
++ __ leal(rax, Address(noreg, rax, Interpreter::stackElementScale(), extra_stack + one_monitor));
+ __ leal(rax, Address(rax, rdx, Interpreter::stackElementScale(), overhead_size));
+
+ #ifdef ASSERT
+@@ -2104,6 +2106,7 @@
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;
@@ -294,6 +634,234 @@ diff --git a/src/cpu/x86/vm/cppInterpret
case Interpreter::java_lang_math_sin : // fall thru
case Interpreter::java_lang_math_cos : // fall thru
+@@ -2143,7 +2146,8 @@
+ 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 = (InvokeDynamic ? 1 : 0);
++ const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) *
+ Interpreter::stackElementWords();
+ return overhead_size + method_stack + stub_code;
+ }
+@@ -2208,7 +2212,8 @@
+ // 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 = (InvokeDynamic ? 1 : 0);
++ 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;
+@@ -2254,7 +2259,8 @@
+ monitor_size);
+
+ // Now with full size expression stack
+- int full_frame_size = short_frame_size + method->max_stack() * BytesPerWord;
++ int extra_stack = (InvokeDynamic ? 1 : 0);
++ 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;
+diff --git a/src/cpu/x86/vm/interp_masm_x86_32.cpp b/src/cpu/x86/vm/interp_masm_x86_32.cpp
+--- a/src/cpu/x86/vm/interp_masm_x86_32.cpp
++++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp
+@@ -188,20 +188,33 @@
+ }
+
+
+-void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, Register index, int bcp_offset) {
++void InterpreterMacroAssembler::get_cache_index_at_bcp(Register reg, int bcp_offset, bool giant_index) {
+ assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
++ if (!giant_index) {
++ load_unsigned_word(reg, Address(rsi, bcp_offset));
++ } else {
++ assert(InvokeDynamic, "giant index used only for InvokeDynamic");
++ movl(reg, Address(rsi, bcp_offset));
++ assert(constantPoolCacheOopDesc::decode_secondary_index(~123) == 123, "else change next line");
++ notl(reg); // convert to plain index
++ }
++}
++
++
++void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, Register index,
++ int bcp_offset, bool giant_index) {
+ assert(cache != index, "must use different registers");
+- load_unsigned_word(index, Address(rsi, bcp_offset));
++ get_cache_index_at_bcp(index, bcp_offset, giant_index);
+ movl(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize));
+ assert(sizeof(ConstantPoolCacheEntry) == 4*wordSize, "adjust code below");
+ shll(index, 2); // convert from field index to ConstantPoolCacheEntry index
+ }
+
+
+-void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset) {
+- assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
++void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, Register tmp,
++ int bcp_offset, bool giant_index) {
+ assert(cache != tmp, "must use different register");
+- load_unsigned_word(tmp, Address(rsi, bcp_offset));
++ get_cache_index_at_bcp(tmp, bcp_offset, giant_index);
+ assert(sizeof(ConstantPoolCacheEntry) == 4*wordSize, "adjust code below");
+ // convert from field index to ConstantPoolCacheEntry index
+ // and from word offset to byte offset
+@@ -587,13 +600,18 @@
+ }
+
+
+-// 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
+ leal(rsi, Address(rsp, wordSize));
+ // record last_sp
+ movl(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;
+@@ -1236,7 +1254,9 @@
+ }
+
+
+-void InterpreterMacroAssembler::profile_virtual_call(Register receiver, Register mdp, Register reg2) {
++void InterpreterMacroAssembler::profile_virtual_call(Register receiver, Register mdp,
++ Register reg2,
++ bool receiver_can_be_null) {
+ if (ProfileInterpreter) {
+ Label profile_continue;
+
+@@ -1246,8 +1266,15 @@
+ // We are making a call. Increment the count.
+ increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
+
++ Label skip_receiver_profile;
++ if (receiver_can_be_null) {
++ testl(receiver, receiver);
++ jcc(Assembler::zero, skip_receiver_profile);
++ }
++
+ // Record the receiver type.
+ record_klass_in_profile(receiver, mdp, reg2);
++ bind(skip_receiver_profile);
+
+ // The method data pointer needs to be updated to reflect the new target.
+ update_mdp_by_constant(mdp,
+diff --git a/src/cpu/x86/vm/interp_masm_x86_32.hpp b/src/cpu/x86/vm/interp_masm_x86_32.hpp
+--- a/src/cpu/x86/vm/interp_masm_x86_32.hpp
++++ b/src/cpu/x86/vm/interp_masm_x86_32.hpp
+@@ -76,8 +76,9 @@
+ void get_cpool_and_tags(Register cpool, Register tags) { get_constant_pool(cpool); movl(tags, Address(cpool, constantPoolOopDesc::tags_offset_in_bytes()));
+ }
+ void get_unsigned_2_byte_index_at_bcp(Register reg, int bcp_offset);
+- void get_cache_and_index_at_bcp(Register cache, Register index, int bcp_offset);
+- void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset);
++ void get_cache_and_index_at_bcp(Register cache, Register index, int bcp_offset, bool giant_index = false);
++ void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, bool giant_index = false);
++ void get_cache_index_at_bcp(Register index, int bcp_offset, bool giant_index = false);
+
+ // Expression stack
+ void f2ieee(); // truncate ftos to 32bits
+@@ -152,6 +153,7 @@
+
+
+ // jump to an invoked target
++ void prepare_to_jump_from_interpreted();
+ void jump_from_interpreted(Register method, Register temp);
+
+ // Returning from interpreted functions
+@@ -216,7 +218,8 @@
+ void profile_not_taken_branch(Register mdp);
+ void profile_call(Register mdp);
+ void profile_final_call(Register mdp);
+- void profile_virtual_call(Register receiver, Register mdp, Register scratch2);
++ void profile_virtual_call(Register receiver, Register mdp, Register scratch2,
++ bool receiver_can_be_null = false);
+ void profile_ret(Register return_bci, Register mdp);
+ void profile_null_seen(Register mdp);
+ void profile_typecheck(Register mdp, Register klass, Register scratch);
+diff --git a/src/cpu/x86/vm/interp_masm_x86_64.cpp b/src/cpu/x86/vm/interp_masm_x86_64.cpp
+--- a/src/cpu/x86/vm/interp_masm_x86_64.cpp
++++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp
+@@ -186,12 +186,27 @@
+ }
+
+
++void InterpreterMacroAssembler::get_cache_index_at_bcp(Register index,
++ int bcp_offset,
++ bool giant_index) {
++ assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
++ if (!giant_index) {
++ load_unsigned_word(index, Address(r13, bcp_offset));
++ } else {
++ assert(InvokeDynamic, "giant index used only for InvokeDynamic");
++ movl(index, Address(r13, bcp_offset));
++ assert(constantPoolCacheOopDesc::decode_secondary_index(~123) == 123, "else change next line");
++ notl(index); // convert to plain index
++ }
++}
++
++
+ void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache,
+ Register index,
+- int bcp_offset) {
+- assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
++ int bcp_offset,
++ bool giant_index) {
+ assert(cache != index, "must use different registers");
+- load_unsigned_word(index, Address(r13, bcp_offset));
++ get_cache_index_at_bcp(index, bcp_offset, giant_index);
+ movq(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize));
+ assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below");
+ // convert from field index to ConstantPoolCacheEntry index
+@@ -201,10 +216,10 @@
+
+ void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache,
+ Register tmp,
+- int bcp_offset) {
+- assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
++ int bcp_offset,
++ bool giant_index) {
+ assert(cache != tmp, "must use different register");
+- load_unsigned_word(tmp, Address(r13, bcp_offset));
++ get_cache_index_at_bcp(tmp, bcp_offset, giant_index);
+ assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below");
+ // convert from field index to ConstantPoolCacheEntry index
+ // and from word offset to byte offset
+diff --git a/src/cpu/x86/vm/interp_masm_x86_64.hpp b/src/cpu/x86/vm/interp_masm_x86_64.hpp
+--- a/src/cpu/x86/vm/interp_masm_x86_64.hpp
++++ b/src/cpu/x86/vm/interp_masm_x86_64.hpp
+@@ -94,9 +94,10 @@
+
+ void get_unsigned_2_byte_index_at_bcp(Register reg, int bcp_offset);
+ void get_cache_and_index_at_bcp(Register cache, Register index,
+- int bcp_offset);
++ int bcp_offset, bool giant_index = false);
+ void get_cache_entry_pointer_at_bcp(Register cache, Register tmp,
+- int bcp_offset);
++ int bcp_offset, bool giant_index = false);
++ void get_cache_index_at_bcp(Register index, int bcp_offset, bool giant_index = false);
+
+ void pop_ptr(Register r = rax);
+ void pop_i(Register r = rax);
+@@ -222,7 +223,8 @@
+ void profile_call(Register mdp);
+ void profile_final_call(Register mdp);
+ void profile_virtual_call(Register receiver, Register mdp,
+- Register scratch2);
++ Register scratch2,
++ bool receiver_can_be_null = false);
+ void profile_ret(Register return_bci, Register mdp);
+ void profile_null_seen(Register mdp);
+ void profile_typecheck(Register mdp, Register klass, Register scratch);
diff --git a/src/cpu/x86/vm/interpreterGenerator_x86.hpp b/src/cpu/x86/vm/interpreterGenerator_x86.hpp
--- a/src/cpu/x86/vm/interpreterGenerator_x86.hpp
+++ b/src/cpu/x86/vm/interpreterGenerator_x86.hpp
@@ -325,7 +893,7 @@ diff --git a/src/cpu/x86/vm/interpreter_
// 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.
-@@ -213,6 +214,34 @@
+@@ -213,6 +214,31 @@
return entry_point;
}
@@ -347,12 +915,9 @@ diff --git a/src/cpu/x86/vm/interpreter_
+
+ __ bind(wrong_method_type);
+ // make it look like we are in the caller frame
-+ __ 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)
-+ __ call_VM(noreg, CAST_FROM_FN_PTR(address,
-+ InterpreterRuntime::throw_WrongMethodTypeException),
-+ rax_mtype, rcx_recv);
++ __ pushl(rax_mtype); // missed mtype (required)
++ __ pushl(rcx_recv); // bad mh (actual)
++ __ jump(ExternalAddress(Interpreter::_throw_WrongMethodType_entry));
+ __ hlt();
+ return entry_point;
+}
@@ -396,7 +961,7 @@ diff --git a/src/cpu/x86/vm/stubGenerato
generate_arraycopy_stubs();
+
+ // generic method handle stubs
-+ if (MethodHandles && SystemDictionary::methodHandle_klass() != NULL) {
++ if (MethodHandles && SystemDictionary::java_dyn_MethodHandle_klass() != NULL) {
+ for (MethodHandle::EntryKind ek = MethodHandle::_EK_FIRST;
+ ek < MethodHandle::_EK_LIMIT;
+ ek = MethodHandle::EntryKind(1 + (int)ek)) {
@@ -410,7 +975,211 @@ diff --git a/src/cpu/x86/vm/templateInte
diff --git a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
--- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
+++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
-@@ -1364,6 +1364,7 @@
+@@ -92,6 +92,32 @@
+ return entry;
+ }
+
++// Arguments are: required type at TOS+4, failing object (or NULL) at TOS
++address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
++ address entry = __ pc();
++
++ __ popl(rbx); // failing object is at TOS
++ __ popl(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();
+@@ -129,13 +155,22 @@
+ }
+
+
+-address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step) {
++address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, bool unbox) {
++ TosState incoming_state = state;
++ if (InvokeDynamic) {
++ if (unbox) {
++ incoming_state = atos;
++ }
++ } else {
++ assert(!unbox, "old behavior");
++ }
++
+ Label interpreter_entry;
+ address compiled_entry = __ pc();
+
+ #ifdef COMPILER2
+ // The FPU stack is clean if UseSSE >= 2 but must be cleaned in other cases
+- if ((state == ftos && UseSSE < 1) || (state == dtos && UseSSE < 2)) {
++ if ((incoming_state == ftos && UseSSE < 1) || (incoming_state == dtos && UseSSE < 2)) {
+ for (int i = 1; i < 8; i++) {
+ __ ffree(i);
+ }
+@@ -143,7 +178,7 @@
+ __ empty_FPU_stack();
+ }
+ #endif
+- if ((state == ftos && UseSSE < 1) || (state == dtos && UseSSE < 2)) {
++ if ((incoming_state == ftos && UseSSE < 1) || (incoming_state == dtos && UseSSE < 2)) {
+ __ MacroAssembler::verify_FPU(1, "generate_return_entry_for compiled");
+ } else {
+ __ MacroAssembler::verify_FPU(0, "generate_return_entry_for compiled");
+@@ -159,12 +194,12 @@
+
+ // In SSE mode, interpreter returns FP results in xmm0 but they need
+ // to end up back on the FPU so it can operate on them.
+- if (state == ftos && UseSSE >= 1) {
++ if (incoming_state == ftos && UseSSE >= 1) {
+ __ subl(rsp, wordSize);
+ __ movflt(Address(rsp, 0), xmm0);
+ __ fld_s(Address(rsp, 0));
+ __ addl(rsp, wordSize);
+- } else if (state == dtos && UseSSE >= 2) {
++ } else if (incoming_state == dtos && UseSSE >= 2) {
+ __ subl(rsp, 2*wordSize);
+ __ movdbl(Address(rsp, 0), xmm0);
+ __ fld_d(Address(rsp, 0));
+@@ -180,13 +215,120 @@
+
+ __ restore_bcp();
+ __ restore_locals();
+- __ get_cache_and_index_at_bcp(rbx, rcx, 1);
++
++ Label L_fail;
++
++ if (unbox && state != atos) {
++ // cast and unbox
++ BasicType type = as_BasicType(state);
++ if (type == T_BYTE) type = T_BOOLEAN; // FIXME
++ KlassHandle boxk = KlassHandles::box_klass(type);
++ __ mov32(rbx, ExternalAddress((address) boxk.raw_value()));
++ __ testl(rax, rax);
++ Label L_got_value, L_get_value;
++ // convert nulls to zeroes (avoid NPEs here)
++ if (!(type == T_FLOAT || type == T_DOUBLE)) {
++ // if rax already contains zero bits, forge ahead
++ __ jcc(Assembler::zero, L_got_value);
++ } else {
++ __ jcc(Assembler::notZero, L_get_value);
++ __ fldz();
++ __ jmp(L_got_value);
++ }
++ __ bind(L_get_value);
++ __ cmp32(rbx, Address(rax, oopDesc::klass_offset_in_bytes()));
++ __ jcc(Assembler::notEqual, L_fail);
++ int offset = java_lang_boxing_object::value_offset_in_bytes(type);
++ // Cf. TemplateTable::getfield_or_static
++ switch (type) {
++ case T_BYTE: // fall through:
++ case T_BOOLEAN: __ load_signed_byte(rax, Address(rax, offset)); break;
++ case T_CHAR: __ load_unsigned_word(rax, Address(rax, offset)); break;
++ case T_SHORT: __ load_signed_word(rax, Address(rax, offset)); break;
++ case T_INT: __ movl(rax, Address(rax, offset)); break;
++ case T_FLOAT: __ fld_s(Address(rax, offset)); break;
++ case T_DOUBLE: __ fld_d(Address(rax, offset)); break;
++ // Access to java.lang.Double.value does not need to be atomic:
++ case T_LONG: { __ movl(rdx, Address(rax, offset + 4));
++ __ movl(rax, Address(rax, offset + 0)); } break;
++ default: ShouldNotReachHere();
++ }
++ __ bind(L_got_value);
++
++ // put FPU results into xmm0, as above:
++ if (state == ftos && UseSSE >= 1) {
++ __ subl(rsp, wordSize);
++ __ movflt(Address(rsp, 0), xmm0);
++ __ fld_s(Address(rsp, 0));
++ __ addl(rsp, wordSize);
++ } else if (state == dtos && UseSSE >= 2) {
++ __ subl(rsp, 2*wordSize);
++ __ movdbl(Address(rsp, 0), xmm0);
++ __ fld_d(Address(rsp, 0));
++ __ addl(rsp, 2*wordSize);
++ }
++ }
++
++ Label L_got_cache, L_giant_index;
++ if (InvokeDynamic) {
++ __ cmpb(Address(rsi, 0), Bytecodes::_invokedynamic);
++ __ jcc(Assembler::equal, L_giant_index);
++ }
++ __ get_cache_and_index_at_bcp(rbx, rcx, 1, false);
++ __ bind(L_got_cache);
++ if (unbox && state == atos) {
++ // insert a casting conversion, to keep verifier sane
++ Label L_ok, L_ok_pops;
++ __ testl(rax, rax);
++ __ jcc(Assembler::zero, L_ok);
++ __ pushl(rax); // save the object to check
++ __ movl(rax, Address(rax, oopDesc::klass_offset_in_bytes()));
++ __ pushl(rbx); // save CP cache reference
++ __ pushl(rcx); // save CP cache reference
++ __ movl(rbx, Address(rbx, rcx,
++ Address::times_4, constantPoolCacheOopDesc::base_offset() +
++ ConstantPoolCacheEntry::f1_offset()));
++ __ movl(rbx, Address(rbx, __ delayed_value(java_dyn_impl_DynCallSite::type_offset_in_bytes, rcx)));
++ __ movl(rbx, Address(rbx, __ delayed_value(java_dyn_MethodType::rtype_offset_in_bytes, rcx)));
++ __ movl(rbx, Address(rbx, __ delayed_value(java_lang_Class::klass_offset_in_bytes, rcx)));
++ __ check_klass_subtype(rax, rbx, rcx, L_ok_pops);
++ __ addl(rsp, 2*wordSize); // toss rcx, keep rbx as failed klass
++ __ popl(rax);
++ __ jmp(L_fail);
++
++ __ bind(L_ok_pops);
++ // restore pushed temp regs:
++ __ popl(rcx);
++ __ popl(rbx);
++ __ popl(rax);
++ __ bind(L_ok);
++ }
+ __ movl(rbx, Address(rbx, rcx,
+ Address::times_4, constantPoolCacheOopDesc::base_offset() +
+ ConstantPoolCacheEntry::flags_offset()));
+ __ andl(rbx, 0xFF);
+ __ leal(rsp, Address(rsp, rbx, Interpreter::stackElementScale()));
+ __ dispatch_next(state, step);
++
++ // out of the main line of code...
++ if (InvokeDynamic) {
++ __ bind(L_giant_index);
++ __ get_cache_and_index_at_bcp(rbx, rcx, 1, true);
++ __ jmp(L_got_cache);
++
++ if (unbox) {
++ __ bind(L_fail);
++ __ pushl(rbx); // missed klass (required)
++ __ pushl(rax); // bad object (actual)
++ if (Interpreter::_throw_WrongMethodType_entry == NULL) {
++ __ movptr(rdx, ExternalAddress((address) &Interpreter::_throw_WrongMethodType_entry));
++ __ jmp(rdx);
++ } else {
++ __ jump(ExternalAddress(Interpreter::_throw_WrongMethodType_entry));
++ }
++ }
++ }
++
+ return entry;
+ }
+
+@@ -1364,6 +1506,7 @@
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;
@@ -418,10 +1187,84 @@ diff --git a/src/cpu/x86/vm/templateInte
case Interpreter::java_lang_math_sin : // fall thru
case Interpreter::java_lang_math_cos : // fall thru
+@@ -1394,9 +1537,10 @@
+ // 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 = (InvokeDynamic ? 1 : 0);
++ const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) *
+ Interpreter::stackElementWords();
+- return overhead_size + method_stack + stub_code;
++ return overhead_size + method_stack + extra_stack + stub_code;
+ }
+
+ // asm based interpreter deoptimization helpers
diff --git a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
--- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
+++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
-@@ -1243,6 +1243,7 @@
+@@ -98,6 +98,26 @@
+ return entry;
+ }
+
++// Arguments are: required type at TOS+8, failing object (or NULL) at TOS
++address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
++ address entry = __ pc();
++
++ __ popq(c_rarg2); // failing object is at TOS
++ __ popq(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");
+@@ -159,7 +179,13 @@
+
+ __ restore_bcp();
+ __ restore_locals();
+- __ get_cache_and_index_at_bcp(rbx, rcx, 1);
++ Label L_got_cache, L_giant_index;
++ if (InvokeDynamic) {
++ __ cmpb(r13, Bytecodes::_invokedynamic);
++ __ jcc(Assembler::equal, L_giant_index);
++ }
++ __ get_cache_and_index_at_bcp(rbx, rcx, 1, false);
++ __ bind(L_got_cache);
+ __ movl(rbx, Address(rbx, rcx,
+ Address::times_8,
+ in_bytes(constantPoolCacheOopDesc::base_offset()) +
+@@ -168,7 +194,18 @@
+ if (TaggedStackInterpreter) __ shll(rbx, 1); // 2 slots per parameter.
+ __ leaq(rsp, Address(rsp, rbx, Address::times_8));
+ __ dispatch_next(state, step);
++
++ if (InvokeDynamic) {
++ __ get_cache_and_index_at_bcp(rbx, rcx, 1, true);
++ __ jmp(L_got_cache);
++ }
++
+ return entry;
++}
++
++
++address TemplateInterpreterGenerator::generate_return_unbox_entry_for(TosState state, int step) {
++ __ unimplemented();
+ }
+
+
+@@ -1243,6 +1280,7 @@
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;
@@ -429,6 +1272,16 @@ diff --git a/src/cpu/x86/vm/templateInte
case Interpreter::java_lang_math_sin : break;
case Interpreter::java_lang_math_cos : break;
case Interpreter::java_lang_math_tan : break;
+@@ -1274,7 +1312,8 @@
+ const int stub_code = frame::entry_frame_after_call_words;
+ const int method_stack = (method->max_locals() + method->max_stack()) *
+ Interpreter::stackElementWords();
+- return (overhead_size + method_stack + stub_code);
++ const int extra_stack = (InvokeDynamic ? Interpreter::stackElementWords() : 0);
++ return (overhead_size + method_stack + stub_code + extra_stack);
+ }
+
+ int AbstractInterpreter::layout_activation(methodOop method,
diff --git a/src/cpu/x86/vm/templateTable_x86_32.cpp b/src/cpu/x86/vm/templateTable_x86_32.cpp
--- a/src/cpu/x86/vm/templateTable_x86_32.cpp
+++ b/src/cpu/x86/vm/templateTable_x86_32.cpp
@@ -449,35 +1302,110 @@ diff --git a/src/cpu/x86/vm/templateTabl
Label okay;
__ load_unsigned_byte(scratch, at_bcp(0));
__ cmpl(scratch, (int)Bytecodes::java_code(bytecode));
-@@ -2032,7 +2032,8 @@
+@@ -2015,6 +2015,7 @@
+
+ void TemplateTable::resolve_cache_and_index(int byte_no, Register Rcache, Register index) {
+ assert(byte_no == 1 || byte_no == 2, "byte_no out of range");
++ bool is_invokedynamic = (bytecode() == Bytecodes::_invokedynamic);
+
+ Register temp = rbx;
+
+@@ -2022,13 +2023,19 @@
+
+ const int shift_count = (1 + byte_no)*BitsPerByte;
+ Label resolved;
+- __ get_cache_and_index_at_bcp(Rcache, index, 1);
+- __ movl(temp, Address(Rcache, index, Address::times_4, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::indices_offset()));
+- __ shrl(temp, shift_count);
+- // have we resolved this bytecode?
+- __ andl(temp, 0xFF);
+- __ cmpl(temp, (int)bytecode());
+- __ jcc(Assembler::equal, resolved);
++ __ get_cache_and_index_at_bcp(Rcache, index, 1, is_invokedynamic);
++ if (is_invokedynamic) {
++ // we are resolved if the f1 field contains a non-null CallSite object
++ __ cmpl(Address(Rcache, index, Address::times_4, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::f1_offset()), NULL);
++ __ jcc(Assembler::notEqual, resolved);
++ } else {
++ __ movl(temp, Address(Rcache, index, Address::times_4, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::indices_offset()));
++ __ shrl(temp, shift_count);
++ // have we resolved this bytecode?
++ __ andl(temp, 0xFF);
++ __ cmpl(temp, (int)bytecode());
++ __ jcc(Assembler::equal, resolved);
++ }
// resolve first time through
address entry;
-- switch (bytecode()) {
-+ Bytecodes::Code code = Bytecodes::java_code(bytecode());
-+ switch (code) {
- case Bytecodes::_getstatic : // fall through
- case Bytecodes::_putstatic : // fall through
- case Bytecodes::_getfield : // fall through
-@@ -2761,14 +2762,16 @@
+@@ -2041,12 +2048,13 @@
+ case Bytecodes::_invokespecial : // fall through
+ case Bytecodes::_invokestatic : // fall through
+ case Bytecodes::_invokeinterface: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke); break;
++ case Bytecodes::_invokedynamic : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic); break;
+ default : ShouldNotReachHere(); break;
+ }
+ __ movl(temp, (int)bytecode());
+ __ call_VM(noreg, entry, temp);
+ // Update registers with resolved info
+- __ get_cache_and_index_at_bcp(Rcache, index, 1);
++ __ get_cache_and_index_at_bcp(Rcache, index, 1, is_invokedynamic);
+ __ bind(resolved);
}
+@@ -2761,9 +2769,14 @@
+ }
+
-void TemplateTable::prepare_invoke(Register method, Register index, int byte_no, Bytecodes::Code code) {
+- // determine flags
+void TemplateTable::prepare_invoke(Register method, Register index, int byte_no) {
- // determine flags
-+ Bytecodes::Code code = Bytecodes::java_code(bytecode());
++ bool neg_byte_no = (byte_no < 0);
++ if (neg_byte_no) byte_no = -byte_no;
++
++ // determine flagsu
++ Bytecodes::Code code = bytecode();
const bool is_invokeinterface = code == Bytecodes::_invokeinterface;
++ const bool is_invokedynamic = code == Bytecodes::_invokedynamic;
const bool is_invokevirtual = code == Bytecodes::_invokevirtual;
const bool is_invokespecial = code == Bytecodes::_invokespecial;
const bool load_receiver = code != Bytecodes::_invokestatic;
- const bool receiver_null_check = is_invokespecial;
- const bool save_flags = is_invokeinterface || is_invokevirtual;
-+ const bool is_extended = (bytecode() == Bytecodes::_invokedynamic);
- // setup registers & access constant pool cache
+@@ -2773,6 +2786,9 @@
const Register recv = rcx;
const Register flags = rdx;
-@@ -2868,7 +2871,7 @@
+ assert_different_registers(method, index, recv, flags);
++
++ assert(!neg_byte_no || is_invokedynamic, "byte_no<0 hack only for invdyn");
++ const bool is_invdyn_bootstrap = neg_byte_no;
+
+ // save 'interpreter return address'
+ __ save_bcp();
+@@ -2784,8 +2800,12 @@
+ __ movl(recv, flags);
+ __ andl(recv, 0xFF);
+ // recv count is 0 based?
+- __ movl(recv, Address(rsp, recv, Interpreter::stackElementScale(), -Interpreter::expr_offset_in_bytes(1)));
+- __ verify_oop(recv);
++ if (is_invokedynamic) {
++ __ leal(recv, Address(rsp, recv, Interpreter::stackElementScale(), -Interpreter::expr_offset_in_bytes(1)));
++ } else {
++ __ movl(recv, Address(rsp, recv, Interpreter::stackElementScale(), -Interpreter::expr_offset_in_bytes(1)));
++ __ verify_oop(recv);
++ }
+ }
+
+ // do null check if needed
+@@ -2803,7 +2823,9 @@
+ ConstantPoolCacheEntry::verify_tosBits();
+ // load return address
+ { const int table =
+- is_invokeinterface
++ (is_invdyn_bootstrap)
++ ? (int)Interpreter::return_5_unbox_addrs_by_index_table()
++ : (is_invokeinterface || is_invokedynamic)
+ ? (int)Interpreter::return_5_addrs_by_index_table()
+ : (int)Interpreter::return_3_addrs_by_index_table();
+ __ movl(flags, Address(noreg, flags, Address::times_4, table));
+@@ -2868,7 +2890,7 @@
void TemplateTable::invokevirtual(int byte_no) {
transition(vtos, vtos);
@@ -486,7 +1414,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
// rbx,: index
// rcx: receiver
-@@ -2880,7 +2883,7 @@
+@@ -2880,7 +2902,7 @@
void TemplateTable::invokespecial(int byte_no) {
transition(vtos, vtos);
@@ -495,7 +1423,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
// do the call
__ verify_oop(rbx);
__ profile_call(rax);
-@@ -2890,7 +2893,7 @@
+@@ -2890,7 +2912,7 @@
void TemplateTable::invokestatic(int byte_no) {
transition(vtos, vtos);
@@ -504,7 +1432,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
// do the call
__ verify_oop(rbx);
__ profile_call(rax);
-@@ -2906,7 +2909,7 @@
+@@ -2906,7 +2928,7 @@
void TemplateTable::invokeinterface(int byte_no) {
transition(vtos, vtos);
@@ -513,7 +1441,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
// rax,: Interface
// rbx,: index
-@@ -2932,6 +2935,57 @@
+@@ -2932,6 +2954,57 @@
// profile this call
__ profile_virtual_call(rdx, rsi, rdi);
@@ -571,6 +1499,115 @@ diff --git a/src/cpu/x86/vm/templateTabl
__ movl(rdi, rdx); // Save klassOop in rdi
+@@ -3005,6 +3078,108 @@
+ // rcx: receiver
+ // rbx,: methodOop
+ __ jump_from_interpreted(rbx, rdx);
++}
++
++void TemplateTable::invokedynamic(int byte_no) {
++ transition(vtos, vtos);
++
++ if (!InvokeDynamic) {
++ // We do not encounter this bytecode if !InvokeDynamic.
++ // See Rewriter::rewrite_invokedynamic.
++ __ stop("invokedynamic not enabled");
++ return;
++ }
++
++ prepare_invoke(rax, rbx, byte_no);
++
++ // rax: CallSite object (f1)
++ // rbx: unused (f2)
++ // rcx: receiver address
++ // rdx: flags (unused)
++
++ if (ProfileInterpreter) {
++ Label L;
++ __ movl(rdx, Address(rcx, 0));
++ __ testl(rdx, rdx);
++ __ jcc(Assembler::zero, L);
++
++ // Get receiver klass into rdx
++ __ movl(rdx, Address(rdx, oopDesc::klass_offset_in_bytes()));
++ __ verify_oop(rdx);
++ __ bind(L);
++
++ // profile this call
++ __ profile_virtual_call(rdx, rsi, rdi, true);
++ }
++
++ // Make space on the stack for a prepended argument, if any.
++ // (We could probably make this lazier.)
++ {
++ Label loop, done;
++ __ subl(rsp, Interpreter::stackElementSize());
++ __ movl(rdx, rsp);
++ __ bind(loop);
++ // pull one word down by 4 (or 8 if TaggedStackInterpreter)
++ __ movl(rbx, Address(rdx, Interpreter::stackElementSize()));
++ __ movl(Address(rdx, 0), rbx);
++ __ addl(rdx, wordSize);
++ __ cmpl(rdx, rcx);
++ __ jcc(Assembler::less, loop);
++
++ // replace original copy of receiver by NULL:
++ __ movl(Address(rdx, 0), NULL);
++
++ // If TaggedStackInterpreter, note that the NULL is tagged as a reference.
++ // We now have the same stack as if the target method handle
++ // were being invoked via MH.invoke, with target as receiver,
++ // except that there is a NULL instead of a MethodHandle on stack.
++
++ // Pulling the arguments outward like this does not affect
++ // the correctness of frame::oops_interpreted_do,
++ // as long as we put a null in the resulting gap.
++ // This is important to remember, since in the unlinked case
++ // we go out to the JVM again.
++ }
++
++ Label handle_unlinked_site;
++ __ movl(rcx, Address(rax, __ delayed_value(java_dyn_impl_DynCallSite::target_offset_in_bytes, rcx)));
++ __ testl(rcx, rcx);
++ __ jcc(Assembler::zero, handle_unlinked_site);
++
++ __ prepare_to_jump_from_interpreted();
++ MethodHandle::jump_to_entry(_masm, rcx, rdx);
++
++ // Initial calls come here...
++ __ bind(handle_unlinked_site);
++ __ popl(rcx); // remove return address pushed by prepare_invoke
++
++ address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::bootstrap_invokedynamic);
++ // squish stacked arguments together on stack, preceded by call site
++ // return bootstrap method as a handle in rcx
++ __ restore_bcp(); // rsi must be correct for call_VM
++ __ call_VM(rax, entry, rax);
++ __ movl(rdi, rax); // protect MH from prepare_invoke
++
++ // recompute return address
++ __ restore_bcp(); // rsi must be correct for prepare_invoke
++ prepare_invoke(rax, rbx, -byte_no);
++ // rax: CallSite object (f1)
++ // rbx: unused (f2)
++ // rcx: receiver address (now holds arglist)
++ // rdx: flags
++
++ // save SP now, before we add the bootstrap call to the stack
++ __ prepare_to_jump_from_interpreted();
++
++ // let's play adapter
++ __ popl(rbx); // return value
++ __ pushl(rdi); // boot MH
++ __ pushl(rax); // call site
++ __ movl(rcx, Address(rcx, 0));
++ __ pushl(rcx); // arglist
++ __ pushl(rbx); // return value
++ __ movl(rcx, rdi);
++ MethodHandle::jump_to_entry(_masm, rcx, rdx);
+ }
+
+ //----------------------------------------------------------------------------------------------------
diff --git a/src/cpu/x86/vm/templateTable_x86_32.hpp b/src/cpu/x86/vm/templateTable_x86_32.hpp
--- a/src/cpu/x86/vm/templateTable_x86_32.hpp
+++ b/src/cpu/x86/vm/templateTable_x86_32.hpp
@@ -812,6 +1849,93 @@ diff --git a/src/cpu/x86/vm/vtableStubs_
return (DebugVtables ? 144 : 64) + (CountCompiledCalls ? 6 : 0);
}
}
+diff --git a/src/share/vm/asm/assembler.cpp b/src/share/vm/asm/assembler.cpp
+--- a/src/share/vm/asm/assembler.cpp
++++ b/src/share/vm/asm/assembler.cpp
+@@ -239,6 +239,65 @@
+ }
+ }
+
++struct DelayedConstant {
++ typedef void (*value_fn_t)();
++ BasicType type;
++ intptr_t value;
++ value_fn_t value_fn;
++ enum { DC_LIMIT = 20 };
++ static DelayedConstant delayed_constants[DC_LIMIT];
++ static DelayedConstant* add(BasicType type, value_fn_t value_fn);
++ bool match(BasicType t, value_fn_t cfn) {
++ return type == t && value_fn == cfn;
++ }
++ static void update_all();
++};
++DelayedConstant DelayedConstant::delayed_constants[DC_LIMIT];
++DelayedConstant* DelayedConstant::add(BasicType type,
++ DelayedConstant::value_fn_t cfn) {
++ for (int i = 0; i < DC_LIMIT; i++) {
++ DelayedConstant* dcon = &delayed_constants[i];
++ if (dcon->match(type, cfn))
++ return dcon;
++ if (dcon->value_fn == NULL) {
++ if (Atomic::cmpxchg_ptr(CAST_FROM_FN_PTR(void*, cfn), &dcon->value_fn, NULL) == NULL) {
++ dcon->type = type;
++ return dcon;
++ }
++ }
++ }
++ assert(false, "too many delayed constants");
++ return NULL;
++}
++
++void DelayedConstant::update_all() {
++ for (int i = 0; i < DC_LIMIT; i++) {
++ DelayedConstant* dcon = &delayed_constants[i];
++ if (dcon->value_fn != NULL && dcon->value == 0) {
++ typedef int (*int_fn_t)();
++ typedef address (*address_fn_t)();
++ switch (dcon->type) {
++ case T_INT: dcon->value = (intptr_t) ((int_fn_t) dcon->value_fn)(); break;
++ case T_ADDRESS: dcon->value = (intptr_t) ((address_fn_t)dcon->value_fn)(); break;
++ }
++ }
++ }
++}
++
++intptr_t* AbstractAssembler::delayed_value_addr(int(*value_fn)()) {
++ DelayedConstant* dcon = DelayedConstant::add(T_INT, (DelayedConstant::value_fn_t) value_fn);
++ return &dcon->value;
++}
++address* AbstractAssembler::delayed_value_addr(address(*value_fn)()) {
++ DelayedConstant* dcon = DelayedConstant::add(T_ADDRESS, (DelayedConstant::value_fn_t) value_fn);
++ return (address*) &dcon->value;
++}
++void AbstractAssembler::update_delayed_values() {
++ DelayedConstant::update_all();
++}
++
++
++
+
+ void AbstractAssembler::block_comment(const char* comment) {
+ if (sect() == CodeBuffer::SECT_INSTS) {
+diff --git a/src/share/vm/asm/assembler.hpp b/src/share/vm/asm/assembler.hpp
+--- a/src/share/vm/asm/assembler.hpp
++++ b/src/share/vm/asm/assembler.hpp
+@@ -280,6 +280,14 @@
+ inline address address_constant(Label& L);
+ inline address address_table_constant(GrowableArray<Label*> label);
+
++ // Bootstrapping aid to cope with delayed determination of constants.
++ // Returns a static address which will eventually contain the constant.
++ // The value zero (NULL) stands instead of a constant which is still uncomputed.
++ // Use sparingly.
++ static intptr_t* delayed_value_addr(int(*constant_fn)());
++ static address* delayed_value_addr(address(*constant_fn)());
++ static void update_delayed_values();
++
+ // Bang stack to trigger StackOverflowError at a safe location
+ // implementation delegates to machine-specific bang_stack_with_offset
+ void generate_stack_overflow_check( int frame_size_in_bytes );
diff --git a/src/share/vm/c1/c1_GraphBuilder.cpp b/src/share/vm/c1/c1_GraphBuilder.cpp
--- a/src/share/vm/c1/c1_GraphBuilder.cpp
+++ b/src/share/vm/c1/c1_GraphBuilder.cpp
@@ -1166,10 +2290,11 @@ diff --git a/src/share/vm/classfile/java
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");
-@@ -39,16 +50,29 @@
+@@ -39,16 +50,31 @@
dest_offset = fd.offset();
}
++#if 0 //@@@@
+static void
+compute_offset(int &dest_offset,
+ klassOop klass_oop, symbolOop name_symbol, klassOop signature_klass,
@@ -1180,6 +2305,7 @@ diff --git a/src/share/vm/classfile/java
+ symbolOop signature_symbol = oopFactory::new_symbol(signature_name, CATCH);
+ compute_offset(dest_offset, klass_oop, name_symbol, signature_symbol, allow_super);
+}
++#endif //@@@
+
// Same as above but for "optional" offsets that might not be present in certain JDK versions
static void
@@ -1198,7 +2324,7 @@ diff --git a/src/share/vm/classfile/java
Handle java_lang_String::basic_create(int length, bool tenured, TRAPS) {
// Create the String object first, so there's a chance that the String
-@@ -1970,6 +1994,21 @@
+@@ -1970,6 +1996,21 @@
}
@@ -1220,7 +2346,7 @@ diff --git a/src/share/vm/classfile/java
// Support for java_lang_ref_Reference
oop java_lang_ref_Reference::pending_list_lock() {
instanceKlass* ik = instanceKlass::cast(SystemDictionary::reference_klass());
-@@ -2016,6 +2055,126 @@
+@@ -2016,6 +2057,207 @@
int offset = ik->offset_of_static_fields() + static_clock_offset;
SystemDictionary::soft_reference_klass()->long_field_put(offset, value);
@@ -1232,27 +2358,50 @@ diff --git a/src/share/vm/classfile/java
+int java_dyn_MethodHandle::_type_offset;
+int java_dyn_MethodHandle::_vmref_offset;
+int java_dyn_MethodHandle::_vmdata_offset;
++int java_dyn_MethodHandle::_vmdata_argslot_offset;
++int java_dyn_MethodHandle::_vmdata_index_offset;
+int java_dyn_MethodHandle::_entry_offset;
+int java_dyn_MethodHandle::_receiver_offset;
++int java_dyn_MethodHandle::_target_offset;
+
+void java_dyn_MethodHandle::compute_offsets() {
-+ klassOop k = SystemDictionary::methodHandle_klass();
++ klassOop k = SystemDictionary::java_dyn_MethodHandle_klass();
+ if (k != NULL && MethodHandles) {
-+ compute_offset(_type_offset, k, vmSymbols::type_name(), SystemDictionary::methodType_klass(), true);
-+ compute_optional_offset(_vmref_offset, k, vmSymbols::vmref_name(), vmSymbols::object_signature(), true);
-+ compute_optional_offset(_vmdata_offset, k, vmSymbols::vmdata_name(), vmSymbols::long_signature(), true);
-+ compute_optional_offset(_entry_offset, k, vmSymbols::entry_name(), vmSymbols::long_signature(), true);
++ compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_dyn_MethodType_signature(), true);
++ compute_offset(_vmref_offset, k, vmSymbols::vmref_name(), vmSymbols::object_signature(), true);
++ compute_offset(_vmdata_offset, k, vmSymbols::vmdata_name(), vmSymbols::long_signature(), true);
++ compute_offset(_entry_offset, k, vmSymbols::entry_name(), vmSymbols::long_signature(), true);
+ if (_entry_offset != 0) _entry_offset += oopDesc::address_padding_in_bytes();
-+ if (_vmdata_offset != 0) _vmdata_offset += oopDesc::address_padding_in_bytes();
++ if (_vmdata_offset != 0) {
++ // Detect the ordering of halves in vmdata [ index:32 | argslot:32 ].
++ int ioff = 0, aoff = 0;
++ if (Bytes::is_Java_byte_ordering_different()) {
++ ioff += jintSize; // Little-endian ordering {argslot, index}
++ } else {
++ aoff += jintSize; // Big-endian ordering {index, argslot}
++ }
++ _vmdata_index_offset = _vmdata_offset + ioff;
++ _vmdata_argslot_offset = _vmdata_offset + aoff;
++#ifdef ASSERT
++ { // test it another way, just to make sure:
++ union { jlong as_long; jint as_ints[2]; } vmdata;
++ vmdata.as_long = jlong_from('i', 'a');
++ if (vmdata.as_ints[0] == 'i' && vmdata.as_ints[1] == 'a')
++ { assert(aoff != 0, "big-endian"); }
++ else if (vmdata.as_ints[0] == 'a' && vmdata.as_ints[1] == 'i')
++ { assert(ioff != 0, "little-endian"); }
++ else { assert(false, "no-endian!?"); }
++ }
++#endif
++ }
+ klassOop bmhk = SystemDictionary::dyn_impl_BMH_klass();
+ guarantee(bmhk != NULL, "BMH must be present also");
-+ compute_optional_offset(_receiver_offset, bmhk,
-+ vmSymbols::receiver_name(), vmSymbols::object_signature(), true);
-+ guarantee((_vmref_offset != 0 &&
-+ _vmdata_offset != 0 &&
-+ _receiver_offset != 0 &&
-+ _entry_offset != 0), "mismatched method handle support");
-+
++ compute_offset(_receiver_offset, bmhk,
++ vmSymbols::receiver_name(), vmSymbols::object_signature(), true);
++ klassOop amhk = SystemDictionary::dyn_impl_AMH_klass();
++ guarantee(amhk != NULL, "AMH must be present also");
++ compute_offset(_target_offset, amhk,
++ vmSymbols::target_name(), vmSymbols::java_dyn_MethodHandle_signature(), true);
+ }
+}
+
@@ -1268,12 +2417,12 @@ diff --git a/src/share/vm/classfile/java
+ mh->obj_field_put(_vmref_offset, ref);
+}
+
-+address java_dyn_MethodHandle::vmdata(oop mh) {
-+ return mh->address_field(_vmdata_offset);
-+}
-+
-+void java_dyn_MethodHandle::set_vmdata(oop mh, address data) {
-+ mh->address_field_put(_vmdata_offset, data);
++jlong java_dyn_MethodHandle::vmdata(oop mh) {
++ return mh->long_field(_vmdata_offset);
++}
++
++void java_dyn_MethodHandle::set_vmdata(oop mh, jlong data) {
++ mh->long_field_put(_vmdata_offset, data);
+}
+
+MethodEntry* java_dyn_MethodHandle::entry(oop mh) {
@@ -1281,13 +2430,23 @@ diff --git a/src/share/vm/classfile/java
+}
+
+void java_dyn_MethodHandle::set_entry(oop mh, MethodEntry* me) {
-+ // this is the final step that initializes a valid method handle:
++ // This is always the final step that initializes a valid method handle:
+ mh->release_address_field_put(_entry_offset, (address) me);
-+}
-+
-+oop java_dyn_MethodHandle::receiver(oop mh) {
++
++ // 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.
++}
++
++oop java_dyn_MethodHandle::BMH_receiver(oop mh) {
+ assert(mh->klass() == SystemDictionary::dyn_impl_BMH_klass(), "BMH only");
+ return mh->obj_field(_receiver_offset);
++}
++
++oop java_dyn_MethodHandle::AMH_target(oop mh) {
++ assert(mh->klass() == SystemDictionary::dyn_impl_AMH_klass(), "AMH only");
++ return mh->obj_field(_target_offset);
+}
+
+
@@ -1300,17 +2459,17 @@ diff --git a/src/share/vm/classfile/java
+int java_dyn_MethodType::Form::_vmdata_offset;
+
+void java_dyn_MethodType::compute_offsets() {
-+ klassOop k = SystemDictionary::methodType_klass();
++ klassOop k = SystemDictionary::java_dyn_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::methodTypeForm_signature());
++ compute_offset(_form_offset, k, vmSymbols::form_name(), vmSymbols::java_dyn_MethodTypeForm_signature());
+ }
+ java_dyn_MethodType::Form::compute_offsets();
+}
+
+void java_dyn_MethodType::Form::compute_offsets() {
-+ klassOop k = SystemDictionary::methodTypeForm_klass();
++ klassOop k = SystemDictionary::java_dyn_MethodTypeForm_klass();
+ if (k != NULL) {
+ compute_optional_offset(_vmref_offset, k, vmSymbols::vmref_name(), vmSymbols::object_signature(), true);
+ compute_optional_offset(_vmdata_offset, k, vmSymbols::vmdata_name(), vmSymbols::long_signature(), true);
@@ -1344,10 +2503,58 @@ diff --git a/src/share/vm/classfile/java
+
+void java_dyn_MethodType::Form::set_vmdata(oop mtform, address data) {
+ mtform->address_field_put(_vmdata_offset, data);
++}
++
++
++// Support for java_dyn_impl_DynCallSite
++
++int java_dyn_impl_DynCallSite::_type_offset;
++int java_dyn_impl_DynCallSite::_target_offset;
++int java_dyn_impl_DynCallSite::_vmref_offset;
++int java_dyn_impl_DynCallSite::_vmdata_offset;
++
++void java_dyn_impl_DynCallSite::compute_offsets() {
++ if (!InvokeDynamic) return;
++ klassOop k = SystemDictionary::dyn_impl_DynCallSite_klass();
++ if (k != NULL) {
++ compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_dyn_MethodType_signature(), true);
++ compute_offset(_target_offset, k, vmSymbols::target_name(), vmSymbols::java_dyn_MethodHandle_signature(), true);
++ compute_offset(_vmref_offset, k, vmSymbols::vmref_name(), vmSymbols::object_signature(), true);
++ compute_offset(_vmdata_offset, k, vmSymbols::vmdata_name(), vmSymbols::long_signature(), true);
++ if (_vmdata_offset != 0) _vmdata_offset += oopDesc::address_padding_in_bytes();
++ }
++}
++
++oop java_dyn_impl_DynCallSite::type(oop site) {
++ return site->obj_field(_type_offset);
++}
++
++oop java_dyn_impl_DynCallSite::target(oop site) {
++ return site->obj_field(_target_offset);
++}
++
++void java_dyn_impl_DynCallSite::set_target(oop site, oop target) {
++ site->obj_field_put(_target_offset, target);
++}
++
++oop java_dyn_impl_DynCallSite::vmref(oop site) {
++ return site->obj_field(_vmref_offset);
++}
++
++void java_dyn_impl_DynCallSite::set_vmref(oop site, oop ref) {
++ site->obj_field_put(_vmref_offset, ref);
++}
++
++address java_dyn_impl_DynCallSite::vmdata(oop site) {
++ return site->address_field(_vmdata_offset);
++}
++
++void java_dyn_impl_DynCallSite::set_vmdata(oop site, address data) {
++ site->address_field_put(_vmdata_offset, data);
}
-@@ -2354,6 +2513,10 @@
+@@ -2354,6 +2596,13 @@
java_lang_System::compute_offsets();
java_lang_Thread::compute_offsets();
java_lang_ThreadGroup::compute_offsets();
@@ -1355,9 +2562,22 @@ diff --git a/src/share/vm/classfile/java
+ java_dyn_MethodHandle::compute_offsets();
+ java_dyn_MethodType::compute_offsets();
+ }
++ if (InvokeDynamic) {
++ java_dyn_impl_DynCallSite::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
+@@ -2371,6 +2620,9 @@
+ 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
diff --git a/src/share/vm/classfile/javaClasses.hpp b/src/share/vm/classfile/javaClasses.hpp
--- a/src/share/vm/classfile/javaClasses.hpp
+++ b/src/share/vm/classfile/javaClasses.hpp
@@ -1370,7 +2590,7 @@ diff --git a/src/share/vm/classfile/java
static int value_offset_in_bytes(BasicType type) {
return ( type == T_LONG || type == T_DOUBLE ) ? long_value_offset :
-@@ -769,6 +771,101 @@
+@@ -769,6 +771,141 @@
};
@@ -1385,8 +2605,11 @@ diff --git a/src/share/vm/classfile/java
+ static int _type_offset;
+ static int _vmref_offset;
+ static int _vmdata_offset;
++ static int _vmdata_argslot_offset; // arithmetic low half of vmdata
++ static int _vmdata_index_offset; // arithmetic high half of vmdata
+ static int _entry_offset;
+ static int _receiver_offset;
++ static int _target_offset;
+
+ static void compute_offsets();
+
@@ -1397,26 +2620,29 @@ diff --git a/src/share/vm/classfile/java
+ static oop vmref(oop mh);
+ static void set_vmref(oop mh, oop ref);
+
-+ static address vmdata(oop mh);
-+ static void set_vmdata(oop mh, address data);
-+
-+ // vmdata field can store either an address or a simple int:
-+ static jint vmdata_int(oop mh)
-+ { return (jint)(intptr_t) vmdata(mh); }
-+ static void set_vmdata_int(oop mh, jint data)
-+ { set_vmdata(mh, (address)(intptr_t) data); }
++ static jlong vmdata(oop mh);
++ static void set_vmdata(oop mh, jlong data);
++
++ static jint vmdata_argslot(oop mh) { return low(vmdata(mh)); }
++ static jint vmdata_index(oop mh) { return high(vmdata(mh)); }
++ static void set_vmdata(oop mh, jint index, jint argslot)
++ { set_vmdata(mh, jlong_from(index, argslot)); }
+
+ static MethodEntry* entry(oop mh);
+ static void set_entry(oop mh, MethodEntry* data);
+
-+ static oop receiver(oop mh);
++ static oop BMH_receiver(oop mh);
++ static oop AMH_target(oop mh);
+
+ // Accessors for code generation:
+ static int type_offset_in_bytes() { return _type_offset; }
+ static int vmref_offset_in_bytes() { return _vmref_offset; }
+ static int vmdata_offset_in_bytes() { return _vmdata_offset; }
++ static int vmdata_argslot_offset_in_bytes() { return _vmdata_argslot_offset; }
++ static int vmdata_index_offset_in_bytes() { return _vmdata_index_offset; }
+ static int entry_offset_in_bytes() { return _entry_offset; }
+ static int receiver_offset_in_bytes() { return _receiver_offset; }
++ static int target_offset_in_bytes() { return _target_offset; }
+};
+
+
@@ -1466,6 +2692,40 @@ diff --git a/src/share/vm/classfile/java
+ static int vmdata_offset_in_bytes() { return _vmdata_offset; }
+ };
+
++};
++
++
++// Interface to java.dyn.impl.DynCallSite objects
++
++class java_dyn_impl_DynCallSite: AllStatic {
++ friend class JavaClasses;
++
++private:
++ static int _type_offset;
++ static int _target_offset;
++ static int _vmref_offset;
++ static int _vmdata_offset;
++
++ static void compute_offsets();
++
++public:
++ // Accessors
++ static oop type(oop site);
++
++ static oop target(oop site);
++ static void set_target(oop site, oop target);
++
++ static oop vmref(oop site);
++ static void set_vmref(oop site, oop ref);
++
++ static address vmdata(oop site);
++ static void set_vmdata(oop site, address data);
++
++ // Accessors for code generation:
++ static int target_offset_in_bytes() { return _target_offset; }
++ static int type_offset_in_bytes() { return _type_offset; }
++ static int vmref_offset_in_bytes() { return _vmref_offset; }
++ static int vmdata_offset_in_bytes() { return _vmdata_offset; }
+};
+
+
@@ -1499,18 +2759,29 @@ diff --git a/src/share/vm/classfile/syst
int SystemDictionary::_number_of_modifications = 0;
-@@ -1685,6 +1686,10 @@
+@@ -1650,6 +1651,10 @@
+ // 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);
+
+@@ -1684,6 +1689,10 @@
+
// 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);
-
-@@ -1757,6 +1762,8 @@
+@@ -1757,6 +1766,8 @@
void SystemDictionary::methods_do(void f(methodOop)) {
dictionary()->methods_do(f);
@@ -1519,7 +2790,7 @@ diff --git a/src/share/vm/classfile/syst
}
// ----------------------------------------------------------------------------
-@@ -1789,6 +1796,7 @@
+@@ -1789,6 +1800,7 @@
_number_of_modifications = 0;
_loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
_resolution_errors = new ResolutionErrorTable(_resolution_error_size);
@@ -1527,7 +2798,7 @@ diff --git a/src/share/vm/classfile/syst
// Allocate private object used as system class loader lock
_system_loader_lock_obj = oopFactory::new_system_objArray(0, CHECK);
-@@ -1850,6 +1858,9 @@
+@@ -1850,6 +1862,9 @@
wk_klass_name_limits[0] = s;
}
}
@@ -1537,20 +2808,34 @@ diff --git a/src/share/vm/classfile/syst
}
-@@ -1882,6 +1893,12 @@
+@@ -1882,6 +1897,12 @@
instanceKlass::cast(WK_KLASS(weak_reference_klass))->set_reference_type(REF_WEAK);
instanceKlass::cast(WK_KLASS(final_reference_klass))->set_reference_type(REF_FINAL);
instanceKlass::cast(WK_KLASS(phantom_reference_klass))->set_reference_type(REF_PHANTOM);
+
-+ initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(methodHandle_klass), scan, CHECK);
-+ if (WK_KLASS(methodHandle_klass) == NULL) {
++ initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(java_dyn_MethodHandle_klass), scan, CHECK);
++ if (WK_KLASS(java_dyn_MethodHandle_klass) == NULL) {
+ // Skip the rest of the dynamic typing classes, if MethodHandle is not found.
-+ scan = WKID(WK_KLASS_ENUM_NAME(dynamic_klass)+1);
++ scan = WKID(WK_KLASS_ENUM_NAME(java_dyn_Dynamic_klass)+1);
+ }
initialize_wk_klasses_until(WKID_LIMIT, scan, CHECK);
-@@ -2133,11 +2150,56 @@
+@@ -1921,6 +1942,13 @@
+ return (BasicType)i;
+ }
+ return T_OBJECT;
++}
++
++KlassHandle KlassHandles::box_klass(BasicType t) {
++ if (t >= T_BOOLEAN && t <= T_VOID)
++ return KlassHandle(&SystemDictionary::_box_klasses[t], true);
++ else
++ return KlassHandle();
+ }
+
+ // Constraints on class loaders. The details of the algorithm can be
+@@ -2133,11 +2161,56 @@
}
@@ -1608,15 +2893,20 @@ diff --git a/src/share/vm/classfile/syst
char* SystemDictionary::check_signature_loaders(symbolHandle signature,
Handle loader1, Handle loader2,
bool is_method, TRAPS) {
-@@ -2158,6 +2220,80 @@
+@@ -2158,6 +2231,203 @@
sig_strm.next();
}
return NULL;
+}
+
+
-+methodOop SystemDictionary::find_method_handle_invoke(symbolHandle signature, TRAPS) {
-+ assert(MethodHandles, "");
++methodOop SystemDictionary::find_method_handle_invoke(symbolHandle signature,
++ Handle class_loader,
++ Handle protection_domain,
++ TRAPS) {
++ if (!MethodHandles) 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);
@@ -1626,11 +2916,9 @@ diff --git a/src/share/vm/classfile/syst
+ 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;
-+ {
-+ oop mt_oop = compute_method_handle_type(signature(), CHECK_NULL);
-+ mt = Handle(THREAD, mt_oop);
-+ }
++ Handle mt = compute_method_handle_type(signature(),
++ class_loader, protection_domain,
++ CHECK_NULL);
+ methodHandle m = methodOopDesc::make_invoke_method(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.
@@ -1648,23 +2936,79 @@ diff --git a/src/share/vm/classfile/syst
+ return m;
+}
+
++static symbolHandle prepend_argument_type(symbolHandle prepend,
++ symbolHandle signature,
++ TRAPS) {
++ ResourceMark rm;
++ char fixed_buf[512 DEBUG_ONLY(* 0 + 20)];
++ int buf_len = prepend->utf8_length() + signature->utf8_length() + 1;
++ char* buf = (buf_len <= sizeof(fixed_buf)
++ ? fixed_buf
++ : NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buf_len));
++ assert(prepend->byte_at(0) != '(', "argument sig");
++ assert(signature->byte_at(0) == '(', "method sig");
++ int fillp = buf_len, len;
++ buf[--fillp] = 0;
++ fillp -= (len = signature->utf8_length());
++ memcpy(&buf[fillp], signature->bytes(), len);
++ assert(strlen(&buf[fillp]) == len, "");
++ assert(buf[fillp] == '(', "skip this");
++ fillp++; // kill the paren
++ fillp -= (len = prepend->utf8_length());
++ memcpy(&buf[fillp], prepend->bytes(), len);
++ buf[--fillp] = '(';
++ assert(fillp == 0, "dead reckoning");
++ assert(strlen(buf) == buf_len - 1, "");
++ return oopFactory::new_symbol_handle(buf, THREAD);
++}
++
++methodOop SystemDictionary::find_invokedynamic_invoke(symbolHandle signature,
++ Handle class_loader,
++ Handle protection_domain,
++ TRAPS) {
++ if (!InvokeDynamic || !MethodHandles) return NULL;
++
++ methodOop mhinvoke_oop = find_method_handle_invoke(signature,
++ class_loader,
++ protection_domain,
++ CHECK_NULL);
++
++ // prepend Object to the signature, to represent the untyped receiver
++ symbolHandle dynsig(THREAD, mhinvoke_oop->invokedynamic_signature());
++ if (dynsig.is_null()) {
++ // First time through, compute it up.
++ methodHandle mhinvoke(THREAD, mhinvoke_oop);
++ mhinvoke_oop = NULL; // nuke dangling pointer
++ dynsig = prepend_argument_type(vmSymbolHandles::object_signature(), signature, CHECK_NULL);
++ mhinvoke->set_invokedynamic_signature(dynsig()); // save for next time
++ }
++
++ return find_method_handle_invoke(dynsig, class_loader, protection_domain, THREAD);
++}
++
+// Ask Java code to find or construct a java.dyn.MethodType for the given
-+// signature, as interpreted relative to the system class loader.
-+// Because of class loader constraints, all method handle usage is
++// signature, as interpreted relative to the given class loader.
++// Because of class loader constraints, all method handle usage must be
+// consistent with this loader.
-+oop SystemDictionary::compute_method_handle_type(symbolHandle signature, TRAPS) {
-+ Handle rt;
++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::object_klass(), npts, CHECK_NULL);
++ 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_NULL);
++ symbolOop name_oop = ss.as_symbol(CHECK_(empty));
+ symbolHandle name(THREAD, name_oop);
-+ klassOop klass = resolve_or_fail(name, true, CHECK_NULL);
++ klassOop klass = resolve_or_fail(name,
++ class_loader, protection_domain,
++ true, CHECK_(empty));
+ mirror = Klass::cast(klass)->java_mirror();
+ }
+ if (ss.at_return_type())
@@ -1682,10 +3026,74 @@ diff --git a/src/share/vm/classfile/syst
+ args.push_int(trusted);
+ JavaValue result(T_OBJECT);
+ JavaCalls::call_static(&result,
-+ SystemDictionary::methodType_klass(),
++ SystemDictionary::java_dyn_MethodType_klass(),
+ vmSymbols::makeImpl_name(), vmSymbols::makeImpl_signature(),
-+ &args, CHECK_NULL);
-+ return (oop) result.get_jobject();
++ &args, CHECK_(empty));
++ return Handle(THREAD, (oop) result.get_jobject());
++}
++
++
++// Ask Java code to find or construct a java.dyn.CallSite for the given
++// name and signature, as interpreted relative to the given class loader.
++Handle SystemDictionary::make_dynamic_call_site(KlassHandle caller,
++ symbolHandle name,
++ methodHandle mh_invdyn,
++ jlong vmdata,
++ TRAPS) {
++ Handle empty;
++ // call java.dyn.impl.DynCallSite::makeSite(caller, name, mtype, vmdata)
++ oop name_str_oop = StringTable::intern(name(), CHECK_(empty)); // not a handle!
++ JavaCallArguments args(caller->java_mirror());
++ args.push_oop(name_str_oop);
++ args.push_oop(mh_invdyn->method_handle_type());
++ args.push_long(vmdata);
++ JavaValue result(T_OBJECT);
++ JavaCalls::call_static(&result,
++ SystemDictionary::dyn_impl_DynCallSite_klass(),
++ vmSymbols::makeSite_name(), vmSymbols::makeSite_signature(),
++ &args, CHECK_(empty));
++ oop call_site_oop = (oop) result.get_jobject();
++ java_dyn_impl_DynCallSite::set_vmref(call_site_oop, mh_invdyn());
++ return call_site_oop;
++}
++
++Handle SystemDictionary::find_bootstrap_method(KlassHandle caller,
++ KlassHandle search_bootstrap_klass,
++ TRAPS) {
++ Handle empty;
++ if (!caller->oop_is_instance()) return empty;
++
++ instanceKlassHandle ik(THREAD, caller());
++
++ if (ik->bootstrap_method() != NULL) {
++ return Handle(THREAD, ik->bootstrap_method());
++ }
++
++ // call java.dyn.Linkage::findBootstrapMethod(caller, sbk)
++ JavaCallArguments args(ik->java_mirror());
++ if (search_bootstrap_klass.is_null())
++ args.push_oop(NULL);
++ else
++ args.push_oop(search_bootstrap_klass->java_mirror());
++ JavaValue result(T_OBJECT);
++ JavaCalls::call_static(&result,
++ SystemDictionary::java_dyn_Linkage_klass(),
++ vmSymbols::findBootstrapMethod_name(),
++ vmSymbols::findBootstrapMethod_signature(),
++ &args, CHECK_(empty));
++ oop boot_method_oop = (oop) result.get_jobject();
++
++ if (boot_method_oop != NULL) {
++ // probably no race conditions, but let's be careful:
++ if (Atomic::cmpxchg_ptr(boot_method_oop, ik->adr_bootstrap_method(), NULL) == NULL)
++ ik->set_bootstrap_method(boot_method_oop);
++ else
++ boot_method_oop = ik->bootstrap_method();
++ } else {
++ boot_method_oop = ik->bootstrap_method();
++ }
++
++ return Handle(THREAD, boot_method_oop);
}
@@ -1700,40 +3108,74 @@ diff --git a/src/share/vm/classfile/syst
// 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
-@@ -130,6 +131,19 @@
- template(reflect_delegating_classloader_klass, sun_reflect_DelegatingClassLoader, Opt) \
+@@ -131,6 +132,21 @@
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(java_dyn_MethodHandle_klass, java_dyn_MethodHandle, Opt) \
+ template(dyn_impl_AMH_klass, java_dyn_impl_AMH, Opt) \
+ template(dyn_impl_BMH_klass, java_dyn_impl_BMH, Opt) \
+ template(dyn_impl_DMH_klass, java_dyn_impl_DMH, Opt) \
+ template(dyn_impl_MTForm_klass, java_dyn_impl_MTForm, Opt) \
-+ template(methodType_klass, java_dyn_MethodType, Opt) \
-+ template(methodTypeForm_klass, java_dyn_MethodTypeForm, Opt) \
-+ template(WrongMethodTypeException_klass, java_dyn_WrongMethodTypeException, Opt) \
-+ template(callSite_klass, java_dyn_CallSite, Opt) \
-+ template(dynamic_klass, java_dyn_Dynamic, Opt) \
++ template(java_dyn_MethodType_klass, java_dyn_MethodType, Opt) \
++ template(java_dyn_MethodTypeForm_klass, java_dyn_MethodTypeForm, Opt) \
++ template(java_dyn_WrongMethodTypeException_klass, java_dyn_WrongMethodTypeException, Opt) \
++ template(java_dyn_Linkage_klass, java_dyn_Linkage, Opt) \
++ template(java_dyn_CallSite_klass, java_dyn_CallSite, Opt) \
++ template(dyn_impl_DynCallSite_klass, java_dyn_impl_DynCallSite, Opt) \
++ template(java_dyn_Dynamic_klass, java_dyn_Dynamic, Opt) \
+ /* Note: MethodHandle must be first, and Dynamic last in group */ \
- \
++ \
template(vector_klass, java_util_Vector, Pre) \
template(hashtable_klass, java_util_Hashtable, Pre) \
-@@ -447,6 +461,12 @@
+ template(stringBuffer_klass, java_lang_StringBuffer, Pre) \
+@@ -161,6 +177,7 @@
+ class SystemDictionary : AllStatic {
+ friend class VMStructs;
+ friend class CompactingPermGenGen;
++ friend class KlassHandles;
+ NOT_PRODUCT(friend class instanceKlassKlass;)
+
+ public:
+@@ -447,6 +464,36 @@
static char* check_signature_loaders(symbolHandle signature, Handle loader1,
Handle loader2, bool is_method, TRAPS);
+ // JSR 292
+ // find the java.dyn.MethodHandle::invoke method for a given signature
-+ static methodOop find_method_handle_invoke(symbolHandle signature, TRAPS);
++ static methodOop find_method_handle_invoke(symbolHandle signature,
++ Handle class_loader,
++ Handle protection_domain,
++ TRAPS);
++ // find the MH::invoke method for an invokedynamic instruction
++ static methodOop find_invokedynamic_invoke(symbolHandle signature,
++ Handle class_loader,
++ Handle protection_domain,
++ TRAPS);
+ // ask Java to compute the java.dyn.MethodType object for a given signature
-+ static oop compute_method_handle_type(symbolHandle signature, TRAPS);
++ static Handle compute_method_handle_type(symbolHandle signature,
++ Handle class_loader,
++ Handle protection_domain,
++ TRAPS);
++ // ask Java to create a dynamic call site, while linking an invokedynamic op
++ static Handle make_dynamic_call_site(KlassHandle caller,
++ symbolHandle name,
++ methodHandle mh_invoke,
++ jlong vmdata,
++ TRAPS);
++
++ // coordinate with Java about bootstrap methods
++ static Handle find_bootstrap_method(KlassHandle caller,
++ // This argument is non-null only when a
++ // classfile attribute has been found:
++ KlassHandle search_bootstrap_klass,
++ TRAPS);
+
// Utility for printing loader "name" as part of tracing constraints
static const char* loader_name(oop loader) {
return ((loader) == NULL ? "<bootloader>" :
-@@ -463,6 +483,7 @@
+@@ -463,6 +510,7 @@
enum Constants {
_loader_constraint_size = 107, // number of entries in constraint table
_resolution_error_size = 107, // number of entries in resolution error table
@@ -1741,7 +3183,7 @@ diff --git a/src/share/vm/classfile/syst
_nof_buckets = 1009 // number of buckets in hash table
};
-@@ -492,6 +513,9 @@
+@@ -492,6 +540,9 @@
// Resolution errors
static ResolutionErrorTable* _resolution_errors;
@@ -1751,7 +3193,7 @@ diff --git a/src/share/vm/classfile/syst
public:
// for VM_CounterDecay iteration support
friend class CounterDecay;
-@@ -509,6 +533,7 @@
+@@ -509,6 +560,7 @@
static PlaceholderTable* placeholders() { return _placeholders; }
static LoaderConstraintTable* constraints() { return _loader_constraints; }
static ResolutionErrorTable* resolution_errors() { return _resolution_errors; }
@@ -1759,6 +3201,24 @@ diff --git a/src/share/vm/classfile/syst
// Basic loading operations
static klassOop resolve_instance_class_or_null(symbolHandle class_name, Handle class_loader, Handle protection_domain, TRAPS);
+@@ -598,3 +650,17 @@
+ static bool _has_loadClassInternal;
+ static bool _has_checkPackageAccess;
+ };
++
++class KlassHandles : AllStatic {
++public:
++ #define WK_KLASS_HANDLE_DECLARE(name, ignore_symbol, option) \
++ static KlassHandle name() { \
++ SystemDictionary::name(); \
++ klassOop* loc = &SystemDictionary::_well_known_klasses[SystemDictionary::WK_KLASS_ENUM_NAME(name)]; \
++ return KlassHandle(loc, true); \
++ }
++ WK_KLASSES_DO(WK_KLASS_HANDLE_DECLARE);
++ #undef WK_KLASS_HANDLE_DECLARE
++
++ static KlassHandle box_klass(BasicType t);
++};
diff --git a/src/share/vm/classfile/vmSymbols.hpp b/src/share/vm/classfile/vmSymbols.hpp
--- a/src/share/vm/classfile/vmSymbols.hpp
+++ b/src/share/vm/classfile/vmSymbols.hpp
@@ -1770,33 +3230,41 @@ diff --git a/src/share/vm/classfile/vmSy
\
/* exception klasses: at least all exceptions thrown by the VM have entries here */ \
template(java_lang_ArithmeticException, "java/lang/ArithmeticException") \
-@@ -214,7 +215,24 @@
+@@ -214,7 +215,32 @@
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_Dynamic, "java/dyn/Dynamic") \
++ template(java_dyn_Linkage, "java/dyn/Linkage") \
+ template(java_dyn_CallSite, "java/dyn/CallSite") \
+ template(java_dyn_MethodHandle, "java/dyn/MethodHandle") \
+ template(java_dyn_MethodType, "java/dyn/MethodType") \
+ template(java_dyn_MethodTypeForm, "java/dyn/MethodTypeForm") \
+ template(java_dyn_WrongMethodTypeException, "java/dyn/WrongMethodTypeException") \
++ template(java_dyn_MethodType_signature, "Ljava/dyn/MethodType;") \
++ template(java_dyn_MethodHandle_signature, "Ljava/dyn/MethodHandle;") \
++ template(java_dyn_MethodTypeForm_signature, "Ljava/dyn/MethodTypeForm;") \
+ /* internal classes known only to the JVM: */ \
+ template(java_dyn_impl_MTForm, "java/dyn/impl/MTForm") \
++ template(java_dyn_impl_DynCallSite, "java/dyn/impl/DynCallSite") \
+ template(java_dyn_impl_MH, "java/dyn/impl/MH") \
+ template(java_dyn_impl_AMH, "java/dyn/impl/AMH") \
+ template(java_dyn_impl_BMH, "java/dyn/impl/BMH") \
+ template(java_dyn_impl_DMH, "java/dyn/impl/DMH") \
-+ template(methodTypeForm_signature, "Ljava/dyn/MethodTypeForm;") \
+ template(makeImpl_name, "makeImpl") /*MethodType::makeImpl*/ \
+ template(makeImpl_signature, "(Ljava/lang/Class;[Ljava/lang/Class;ZZ)Ljava/dyn/MethodType;") \
++ template(makeSite_name, "makeSite") /*DynCallSite::makeImpl*/ \
++ template(makeSite_signature, "(Ljava/lang/Class;Ljava/lang/String;Ljava/dyn/MethodType;J)Ljava/dyn/impl/DynCallSite;") \
++ template(findBootstrapMethod_name, "findBootstrapMethod") \
++ template(findBootstrapMethod_signature, "(Ljava/lang/Class;Ljava/lang/Class;)Ljava/dyn/MethodHandle;") \
+ \
+ /* common method and field names */ \
template(object_initializer_name, "<init>") \
template(class_initializer_name, "<clinit>") \
template(println_name, "println") \
-@@ -284,6 +302,16 @@
+@@ -284,6 +310,16 @@
template(value_name, "value") \
template(frontCacheEnabled_name, "frontCacheEnabled") \
template(stringCacheEnabled_name, "stringCacheEnabled") \
@@ -1813,7 +3281,7 @@ diff --git a/src/share/vm/classfile/vmSy
\
/* non-intrinsic name/signature pairs: */ \
template(register_method_name, "register") \
-@@ -347,6 +375,7 @@
+@@ -347,6 +383,7 @@
template(void_classloader_signature, "()Ljava/lang/ClassLoader;") \
template(void_object_signature, "()Ljava/lang/Object;") \
template(void_class_signature, "()Ljava/lang/Class;") \
@@ -1821,7 +3289,7 @@ diff --git a/src/share/vm/classfile/vmSy
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;") \
-@@ -418,8 +447,8 @@
+@@ -418,8 +455,8 @@
template(serializePropertiesToByteArray_signature, "()[B") \
template(serializeAgentPropertiesToByteArray_name, "serializeAgentPropertiesToByteArray") \
template(classRedefinedCount_name, "classRedefinedCount") \
@@ -1869,7 +3337,15 @@ diff --git a/src/share/vm/includeDB_core
oop.inline.hpp cardTableModRefBS.hpp
oop.inline.hpp collectedHeap.inline.hpp
oop.inline.hpp compactingPermGenGen.hpp
-@@ -3824,6 +3838,7 @@
+@@ -3649,6 +3663,7 @@
+ sharedRuntime.cpp interpreter.hpp
+ sharedRuntime.cpp javaCalls.hpp
+ sharedRuntime.cpp jvmtiExport.hpp
++sharedRuntime.cpp methodHandles.hpp
+ sharedRuntime.cpp nativeInst_<arch>.hpp
+ sharedRuntime.cpp nativeLookup.hpp
+ sharedRuntime.cpp oop.inline.hpp
+@@ -3824,6 +3839,7 @@
stubGenerator_<arch_model>.cpp handles.inline.hpp
stubGenerator_<arch_model>.cpp instanceOop.hpp
stubGenerator_<arch_model>.cpp interpreter.hpp
@@ -1877,6 +3353,40 @@ diff --git a/src/share/vm/includeDB_core
stubGenerator_<arch_model>.cpp methodOop.hpp
stubGenerator_<arch_model>.cpp nativeInst_<arch>.hpp
stubGenerator_<arch_model>.cpp objArrayKlass.hpp
+@@ -4038,6 +4054,7 @@
+ templateTable_<arch_model>.cpp interpreterRuntime.hpp
+ templateTable_<arch_model>.cpp interpreter.hpp
+ templateTable_<arch_model>.cpp methodDataOop.hpp
++templateTable_<arch_model>.cpp methodHandles.hpp
+ templateTable_<arch_model>.cpp objArrayKlass.hpp
+ templateTable_<arch_model>.cpp oop.inline.hpp
+ templateTable_<arch_model>.cpp sharedRuntime.hpp
+diff --git a/src/share/vm/includeDB_gc_parallel b/src/share/vm/includeDB_gc_parallel
+--- a/src/share/vm/includeDB_gc_parallel
++++ b/src/share/vm/includeDB_gc_parallel
+@@ -25,6 +25,11 @@
+ collectorPolicy.cpp cmsGCAdaptivePolicyCounters.hpp
+
+ compiledICHolderKlass.cpp oop.pcgc.inline.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
+diff --git a/src/share/vm/includeDB_jvmti b/src/share/vm/includeDB_jvmti
+--- a/src/share/vm/includeDB_jvmti
++++ b/src/share/vm/includeDB_jvmti
+@@ -28,6 +28,7 @@
+ jvmtiClassFileReconstituter.cpp bytes_<arch>.hpp
+ jvmtiClassFileReconstituter.cpp jvmtiClassFileReconstituter.hpp
+ jvmtiClassFileReconstituter.cpp symbolTable.hpp
++jvmtiClassFileReconstituter.cpp signature.hpp
+
+ jvmtiClassFileReconstituter.hpp jvmtiEnv.hpp
+
diff --git a/src/share/vm/interpreter/abstractInterpreter.hpp b/src/share/vm/interpreter/abstractInterpreter.hpp
--- a/src/share/vm/interpreter/abstractInterpreter.hpp
+++ b/src/share/vm/interpreter/abstractInterpreter.hpp
@@ -1888,6 +3398,93 @@ diff --git a/src/share/vm/interpreter/ab
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)
+@@ -90,8 +91,6 @@
+ static address _slow_signature_handler; // the native method generic (slow) signature handler
+
+ static address _rethrow_exception_entry; // rethrows an activation in previous frame
+-
+-
+
+ friend class AbstractInterpreterGenerator;
+ friend class InterpreterGenerator;
+@@ -218,6 +217,77 @@
+ stackElementSize()) + tag_offset_in_bytes();
+ }
+
++ // access to stacked values according to type:
++ static oop* oop_addr_in_slot(intptr_t* slot_addr) {
++ return (oop*) slot_addr;
++ }
++ template<class T>
++ static T* subword_addr_in_slot(intptr_t* slot_addr) {
++ if (sizeof(T) < wordSize && !Bytes::is_Java_byte_ordering_different())
++ // big-endian LP64
++ return (T*)(slot_addr + 1) - 1;
++ else
++ return (T*) slot_addr;
++ }
++ static jint* int_addr_in_slot(intptr_t* slot_addr) {
++ return subword_addr_in_slot<jint>(slot_addr);
++ }
++ static jlong long_in_slot(intptr_t* slot_addr) {
++ if (sizeof(intptr_t) >= sizeof(jlong)) {
++ return *(jlong*) slot_addr;
++ } else if (!TaggedStackInterpreter) {
++ return Bytes::get_native_u8((address)slot_addr);
++ } else {
++ assert(sizeof(intptr_t) * 2 == sizeof(jlong), "ILP32");
++ // assemble the long in memory order (not arithmetic order)
++ union { jlong j; jint i[2]; } u;
++ u.i[0] = (jint) slot_addr[0*stackElementSize()];
++ u.i[1] = (jint) slot_addr[1*stackElementSize()];
++ return u.j;
++ }
++ }
++ static void set_long_in_slot(intptr_t* slot_addr, jlong value) {
++ if (sizeof(intptr_t) >= sizeof(jlong)) {
++ *(jlong*) slot_addr = value;
++ } else if (!TaggedStackInterpreter) {
++ Bytes::put_native_u8((address)slot_addr, value);
++ } else {
++ assert(sizeof(intptr_t) * 2 == sizeof(jlong), "ILP32");
++ // assemble the long in memory order (not arithmetic order)
++ union { jlong j; jint i[2]; } u;
++ u.j = value;
++ slot_addr[0*stackElementSize()] = (intptr_t) u.i[0];
++ slot_addr[1*stackElementSize()] = (intptr_t) u.i[1];
++ }
++ }
++ static void get_jvalue_in_slot(intptr_t* slot_addr, BasicType type, jvalue* value) {
++ switch (type) {
++ case T_BOOLEAN: value->z = *subword_addr_in_slot<jboolean>(slot_addr); break;
++ case T_CHAR: value->c = *subword_addr_in_slot<jchar>(slot_addr); break;
++ case T_BYTE: value->c = *subword_addr_in_slot<jbyte>(slot_addr); break;
++ case T_SHORT: value->c = *subword_addr_in_slot<jshort>(slot_addr); break;
++ case T_INT: value->i = *subword_addr_in_slot<jint>(slot_addr); break;
++ case T_LONG: value->j = long_in_slot(slot_addr); break;
++ case T_FLOAT: value->f = *subword_addr_in_slot<jfloat>(slot_addr); break;
++ case T_DOUBLE: value->d = jdouble_cast(long_in_slot(slot_addr)); break;
++ case T_OBJECT: value->l = (jobject) *oop_addr_in_slot(slot_addr); break;
++ default: ShouldNotReachHere();
++ }
++ }
++ static void set_jvalue_in_slot(intptr_t* slot_addr, BasicType type, jvalue* value) {
++ switch (type) {
++ case T_BOOLEAN: *subword_addr_in_slot<jbyte>(slot_addr) = (value->z != 0); break;
++ case T_CHAR: *subword_addr_in_slot<jchar>(slot_addr) = value->c; break;
++ case T_BYTE: *subword_addr_in_slot<jbyte>(slot_addr) = value->c; break;
++ case T_SHORT: *subword_addr_in_slot<jshort>(slot_addr) = value->c; break;
++ case T_INT: *subword_addr_in_slot<jint>(slot_addr) = value->i; break;
++ case T_LONG: set_long_in_slot(slot_addr, value->j); break;
++ case T_FLOAT: *subword_addr_in_slot<jfloat>(slot_addr) = value->f; break;
++ case T_DOUBLE: set_long_in_slot(slot_addr, jlong_cast(value->d)); break;
++ case T_OBJECT: *oop_addr_in_slot(slot_addr) = (oop) value->l; break;
++ default: ShouldNotReachHere();
++ }
++ }
+ };
+
+ //------------------------------------------------------------------------------------------------------------------------
diff --git a/src/share/vm/interpreter/bytecode.cpp b/src/share/vm/interpreter/bytecode.cpp
--- a/src/share/vm/interpreter/bytecode.cpp
+++ b/src/share/vm/interpreter/bytecode.cpp
@@ -1904,15 +3501,7 @@ diff --git a/src/share/vm/interpreter/by
bool Bytecode::check_must_rewrite() const {
assert(Bytecodes::can_rewrite(code()), "post-check only");
-@@ -108,6 +102,7 @@
- KlassHandle resolved_klass;
- constantPoolHandle constants(THREAD, _method->constants());
-
-+ // %%% TO DO: MethodHandle.invoke(*)* and Dynamic.*(*)* have no top method.
- if (adjusted_invoke_code() != Bytecodes::_invokeinterface) {
- LinkResolver::resolve_method(m, resolved_klass, constants, index(), CHECK_(methodHandle()));
- } else {
-@@ -118,7 +113,10 @@
+@@ -118,7 +112,10 @@
int Bytecode_invoke::index() const {
@@ -2062,17 +3651,17 @@ diff --git a/src/share/vm/interpreter/by
bool is_wide() { return _is_wide; }
-+ bool check_index(int i, bool in_cp_cache, outputStream* st = tty);
++ bool check_index(int i, bool in_cp_cache, int& cp_index, outputStream* st = tty);
void print_constant(int i, outputStream* st = tty);
+ void print_field_or_method(int i, outputStream* st = tty);
void print_attributes(Bytecodes::Code code, int bci, outputStream* st = tty);
void bytecode_epilog(int bci, outputStream* st = tty);
-@@ -182,7 +185,69 @@
+@@ -182,7 +185,71 @@
}
}
-+bool BytecodePrinter::check_index(int i, bool in_cp_cache, outputStream* st) {
++bool BytecodePrinter::check_index(int i, bool in_cp_cache, int& cp_index, outputStream* st) {
+ constantPoolOop constants = method()->constants();
+ int ilimit = constants->length(), climit = 0;
+
@@ -2113,6 +3702,7 @@ diff --git a/src/share/vm/interpreter/by
+ check_cp_index:
+ if (i >= 0 && i < ilimit) {
+ if (WizardMode) st->print(" cp[%d]", i);
++ cp_index = i;
+ return true;
+ }
+
@@ -2133,12 +3723,13 @@ diff --git a/src/share/vm/interpreter/by
+}
+
void BytecodePrinter::print_constant(int i, outputStream* st) {
-+ if (!check_index(i, false, st)) return;
++ int orig_i = i;
++ if (!check_index(orig_i, false, i, st)) return;
+
constantPoolOop constants = method()->constants();
constantTag tag = constants->tag_at(i);
-@@ -203,13 +268,36 @@
+@@ -203,13 +270,37 @@
st->print_cr(" %s", constants->resolved_klass_at(i)->klass_part()->external_name());
} else if (tag.is_unresolved_klass()) {
st->print_cr(" <unresolved klass at %d>", i);
@@ -2149,7 +3740,8 @@ diff --git a/src/share/vm/interpreter/by
}
+void BytecodePrinter::print_field_or_method(int i, outputStream* st) {
-+ if (!check_index(i, true, st)) return;
++ int orig_i = i;
++ if (!check_index(orig_i, true, i, st)) return;
-void BytecodePrinter::print_attributes(Bytecodes::Code code, int bci, outputStream* st) {
+ constantPoolOop constants = method()->constants();
@@ -2165,8 +3757,8 @@ diff --git a/src/share/vm/interpreter/by
+ return;
+ }
+
-+ symbolOop name = constants->name_ref_at(i);
-+ symbolOop signature = constants->signature_ref_at(i);
++ symbolOop name = constants->name_ref_at(orig_i);
++ symbolOop signature = constants->signature_ref_at(orig_i);
+ st->print_cr(" %d <%s> <%s> ", i, name->as_C_string(), signature->as_C_string());
+}
+
@@ -2178,7 +3770,7 @@ diff --git a/src/share/vm/interpreter/by
// If the code doesn't have any fields there's nothing to print.
// note this is ==1 because the tableswitch and lookupswitch are
// zero size (for some reason) and we want to print stuff out for them.
-@@ -354,33 +442,25 @@
+@@ -354,33 +445,25 @@
case Bytecodes::_putstatic:
case Bytecodes::_getstatic:
case Bytecodes::_putfield:
@@ -2230,18 +3822,20 @@ diff --git a/src/share/vm/interpreter/by
def(_invokestatic , "invokestatic" , "bjj" , NULL , T_ILLEGAL, 0, true);
def(_invokeinterface , "invokeinterface" , "bjj__", NULL , T_ILLEGAL, -1, true);
- def(_xxxunusedxxx , "xxxunusedxxx" , NULL , NULL , T_VOID , 0, false);
-+ //fast_invokedynamic is below
++ //_invokedynamic is below
def(_new , "new" , "bii" , NULL , T_OBJECT , 1, true );
def(_newarray , "newarray" , "bc" , NULL , T_OBJECT , 0, true );
def(_anewarray , "anewarray" , "bii" , NULL , T_OBJECT , 0, true );
-@@ -395,6 +395,7 @@
-
+@@ -396,6 +396,9 @@
// Faster method invocation.
def(_fast_invokevfinal , "fast_invokevfinal" , "bjj" , NULL , T_ILLEGAL, -1, true, _invokevirtual );
+
++ // JSR 292 (this is not an externally visible bytecode)
+ def(_invokedynamic , "invokedynamic" , "bjjjj", NULL , T_ILLEGAL, -1, true, _invokeinterface );
-
++
def(_fast_linearswitch , "fast_linearswitch" , "" , NULL , T_VOID , -1, false, _lookupswitch );
def(_fast_binaryswitch , "fast_binaryswitch" , "" , NULL , T_VOID , -1, false, _lookupswitch );
+
diff --git a/src/share/vm/interpreter/bytecodes.hpp b/src/share/vm/interpreter/bytecodes.hpp
--- a/src/share/vm/interpreter/bytecodes.hpp
+++ b/src/share/vm/interpreter/bytecodes.hpp
@@ -2308,17 +3902,25 @@ diff --git a/src/share/vm/interpreter/in
diff --git a/src/share/vm/interpreter/interpreterRuntime.cpp b/src/share/vm/interpreter/interpreterRuntime.cpp
--- a/src/share/vm/interpreter/interpreterRuntime.cpp
+++ b/src/share/vm/interpreter/interpreterRuntime.cpp
-@@ -292,6 +292,21 @@
+@@ -292,6 +292,29 @@
// create exception
THROW_MSG(vmSymbols::java_lang_ClassCastException(), message);
IRT_END
+
-+IRT_ENTRY(void, InterpreterRuntime::throw_WrongMethodTypeException(JavaThread* thread, oopDesc* mtype, oopDesc* mhandle)) {
-+
++// 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, mtype, mhandle);
++ char* message = SharedRuntime::generate_wrong_method_type_message(thread, required, actual);
+
+ if (ProfileTraps) {
++ /* %%% do it this way?
++ if (SharedRuntime::wrong_method_type_is_for_single_argument(thread, required) != NULL)
++ note_trap(thread, Deoptimization::Reason_class_check, CHECK);
++ else
++ */
+ note_trap(thread, Deoptimization::Reason_constraint, CHECK);
+ }
+
@@ -2330,20 +3932,169 @@ diff --git a/src/share/vm/interpreter/in
// exception_handler_for_exception(...) returns the continuation address,
-@@ -591,7 +606,8 @@
+@@ -591,7 +614,7 @@
JvmtiExport::post_raw_breakpoint(thread, method, bcp);
IRT_END
-IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code bytecode))
-+IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code raw_bytecode))
-+ Bytecodes::Code bytecode = Bytecodes::java_code(raw_bytecode);
++IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code bytecode)) {
// extract receiver from the outgoing argument list if necessary
Handle receiver(thread, NULL);
if (bytecode == Bytecodes::_invokevirtual || bytecode == Bytecodes::_invokeinterface) {
+@@ -636,7 +659,6 @@
+ if (already_resolved(thread)) return;
+
+ if (bytecode == Bytecodes::_invokeinterface) {
+-
+ if (TraceItables && Verbose) {
+ ResourceMark rm(thread);
+ tty->print_cr("Resolving: klass: %s to method: %s", info.resolved_klass()->name()->as_C_string(), info.resolved_method()->name()->as_C_string());
+@@ -660,7 +682,128 @@
+ info.resolved_method(),
+ info.vtable_index());
+ }
++}
+ IRT_END
++
++
++// First time execution: Resolve symbols, create a permanent DynCallSite object.
++IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) {
++ ResourceMark rm(thread);
++
++ assert(InvokeDynamic, "");
++ const Bytecodes::Code bytecode = Bytecodes::_invokedynamic;
++
++ methodHandle caller_method(thread, method(thread));
++
++ // first determine if there is a bootstrap method
++ {
++ KlassHandle caller_klass(thread, caller_method->method_holder());
++ Handle bootm = SystemDictionary::find_bootstrap_method(caller_klass, KlassHandle(), CHECK);
++ if (bootm.is_null()) {
++ // if there is no bootstrap method, the Dynamic call was really
++ // an old-fashioned invokeinterface, so we must throw an ICCE
++ THROW(vmSymbols::java_lang_IncompatibleClassChangeError());
++ }
++ }
++
++ constantPoolHandle pool(thread, caller_method->constants());
++ int raw_index = four_byte_index(thread);
++ assert(constantPoolCacheOopDesc::is_secondary_index(raw_index), "invokedynamic indexes marked specially");
++
++ // there are two CPC entries that are of interest:
++ int site_index = constantPoolCacheOopDesc::decode_secondary_index(raw_index);
++ int main_index = pool->cache()->entry_at(site_index)->main_entry_index();
++ // here is the CP index of the call site linkage info:
++ int call_index = pool->cache()->entry_at(main_index)->constant_pool_index();
++
++ // first resolve the signature to a MH.invoke methodOop
++ if (!pool->cache()->entry_at(main_index)->is_resolved(bytecode)) {
++ JvmtiHideSingleStepping jhss(thread);
++ CallInfo info;
++ LinkResolver::resolve_invoke(info, Handle(), pool,
++ raw_index, bytecode, CHECK);
++ pool->cache()->entry_at(main_index)->set_method(
++ bytecode,
++ info.resolved_method(),
++ info.vtable_index());
++ }
++
++ // The method (f2 entry) of the main entry is the MH.invoke for the
++ // invokedynamic call signature, which is the explicit signature
++ // plus a prepended Object argument to represent the "Dynamic" receiver.
++ intptr_t f2_value = pool->cache()->entry_at(main_index)->f2();
++ methodHandle mh_invdyn(THREAD, (methodOop) f2_value);
++ assert(mh_invdyn.not_null() && mh_invdyn->is_method() && mh_invdyn->is_method_handle_invoke(),
++ "correct result from LinkResolver::resolve_invokedynamic");
++
++ // Find out more information about the call site.
++ jlong vmdata = 0;
++ {
++ int method_idnum = caller_method->method_idnum();
++ int bci = caller_method->bci_from(bcp(thread));
++ vmdata = jlong_from(method_idnum, bci);
++ }
++
++ Handle call_site
++ = SystemDictionary::make_dynamic_call_site(caller_method->method_holder(),
++ pool->uncached_name_ref_at(call_index),
++ mh_invdyn,
++ vmdata, CHECK);
++ pool->cache()->entry_at(site_index)->set_dynamic_call(call_site(), 0);
++}
++IRT_END
++
++
++// Called on first time execution, and also whenever the CallSite.target is null.
++// FIXME: Do more of this in Java code.
++IRT_ENTRY(void, InterpreterRuntime::bootstrap_invokedynamic(JavaThread* thread, oopDesc* call_site)) {
++ methodHandle mh_invdyn(thread, (methodOop) java_dyn_impl_DynCallSite::vmref(call_site));
++ Handle mh_type(thread, mh_invdyn->method_handle_type());
++ objArrayHandle mh_ptypes(thread, java_dyn_MethodType::ptypes(mh_type()));
++
++ // squish the arguments down to a single array
++ int nargs = mh_ptypes->length();
++ objArrayHandle arg_array;
++ {
++ objArrayOop aaoop = oopFactory::new_objArray(SystemDictionary::object_klass(), nargs, CHECK);
++ arg_array = objArrayHandle(thread, aaoop);
++ }
++ frame fr = thread->last_frame();
++ assert(fr.interpreter_frame_bcp() != NULL, "sanity");
++ int tos_offset = 0;
++ for (int i = nargs; --i >= 0; ) {
++ intptr_t* slot_addr = fr.interpreter_frame_tos_at(tos_offset++);
++ oop ptype = mh_ptypes->obj_at(i);
++ oop arg = NULL;
++ if (!java_lang_Class::is_primitive(ptype)) {
++ arg = *(oop*) slot_addr;
++ } else {
++ assert(i > 0, "first argument is always an oop");
++ BasicType bt = java_lang_Class::primitive_type(ptype);
++ assert(frame::interpreter_frame_expression_stack_direction() < 0, "else reconsider this code");
++ jvalue value;
++ Interpreter::get_jvalue_in_slot(slot_addr, bt, &value);
++ tos_offset += type2size[bt]-1;
++ arg = java_lang_boxing_object::create(bt, &value, CHECK);
++ // FIXME: These boxing objects are not canonicalized under
++ // the Java autoboxing rules. They should be...
++ // The best approach would be to push the arglist creation into Java.
++ // The JVM should use a lower-level interface to communicate argument lists.
++ }
++ arg_array->obj_at_put(i, arg);
++ }
++
++ // return the argument array by storing it down over the first argument:
++ assert(nargs > 0, "always a first argument");
++ *fr.interpreter_frame_tos_at(tos_offset - 1) = (intptr_t) arg_array();
++
++ // now find the bootstrap method
++ oop bootstrap_mh_oop = instanceKlass::cast(fr.interpreter_frame_method()->method_holder())->bootstrap_method();
++ assert(bootstrap_mh_oop != NULL, "must already be determined");
++ thread->set_vm_result(bootstrap_mh_oop);
++}
++IRT_END
++
+
+
+ //------------------------------------------------------------------------------------------------------------------------
diff --git a/src/share/vm/interpreter/interpreterRuntime.hpp b/src/share/vm/interpreter/interpreterRuntime.hpp
--- a/src/share/vm/interpreter/interpreterRuntime.hpp
+++ b/src/share/vm/interpreter/interpreterRuntime.hpp
-@@ -66,6 +66,7 @@
+@@ -42,8 +42,11 @@
+ static bool already_resolved(JavaThread *thread) { return cache_entry(thread)->is_resolved(code(thread)); }
+ static int one_byte_index(JavaThread *thread) { return bcp(thread)[1]; }
+ static int two_byte_index(JavaThread *thread) { return Bytes::get_Java_u2(bcp(thread) + 1); }
++ static int four_byte_index(JavaThread *thread) { return Bytes::get_native_u4(bcp(thread) + 1); }
+ static int number_of_dimensions(JavaThread *thread) { return bcp(thread)[3]; }
+- static ConstantPoolCacheEntry* cache_entry(JavaThread *thread) { return method(thread)->constants()->cache()->entry_at(Bytes::get_native_u2(bcp(thread) + 1)); }
++
++ static ConstantPoolCacheEntry* cache_entry_at(JavaThread *thread, int i) { return method(thread)->constants()->cache()->entry_at(i); }
++ static ConstantPoolCacheEntry* cache_entry(JavaThread *thread) { return cache_entry_at(thread, Bytes::get_native_u2(bcp(thread) + 1)); }
+ static void note_trap(JavaThread *thread, int reason, TRAPS);
+
+ public:
+@@ -66,6 +69,7 @@
static void throw_StackOverflowError(JavaThread* thread);
static void throw_ArrayIndexOutOfBoundsException(JavaThread* thread, char* name, jint index);
static void throw_ClassCastException(JavaThread* thread, oopDesc* obj);
@@ -2351,10 +4102,21 @@ diff --git a/src/share/vm/interpreter/in
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);
+@@ -82,7 +86,9 @@
+ static void new_illegal_monitor_state_exception(JavaThread* thread);
+
+ // Calls
+- static void resolve_invoke (JavaThread* thread, Bytecodes::Code bytecode);
++ static void resolve_invoke (JavaThread* thread, Bytecodes::Code bytecode);
++ static void resolve_invokedynamic(JavaThread* thread);
++ static void bootstrap_invokedynamic(JavaThread* thread, oopDesc* call_site);
+
+ // Breakpoints
+ static void _breakpoint(JavaThread* thread, methodOopDesc* method, address bcp);
diff --git a/src/share/vm/interpreter/linkResolver.cpp b/src/share/vm/interpreter/linkResolver.cpp
--- a/src/share/vm/interpreter/linkResolver.cpp
+++ b/src/share/vm/interpreter/linkResolver.cpp
-@@ -149,6 +149,17 @@
+@@ -149,6 +149,33 @@
void LinkResolver::lookup_method_in_interfaces(methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS) {
instanceKlass *ik = instanceKlass::cast(klass());
result = methodHandle(THREAD, ik->lookup_method_in_all_interfaces(name(), signature()));
@@ -2362,28 +4124,94 @@ diff --git a/src/share/vm/interpreter/li
+
+void LinkResolver::lookup_implicit_method(methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS) {
+ if (MethodHandles &&
-+ name == vmSymbolHandles::invoke_name() && klass() == SystemDictionary::methodHandle_klass()) {
-+ methodOop result_oop = SystemDictionary::find_method_handle_invoke(signature, CHECK);
++ name == vmSymbolHandles::invoke_name() && klass() == SystemDictionary::java_dyn_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);
+ }
+ }
++ if (InvokeDynamic &&
++ klass() == SystemDictionary::java_dyn_Dynamic_klass()) {
++ // same as find_method_handle_invoke, except the receiver
++ // is explicitly prepended as an Object argument
++ methodOop result_oop = SystemDictionary::find_invokedynamic_invoke(signature,
++ Handle(),
++ Handle(),
++ CHECK);
++ if (result_oop != NULL) {
++ assert(result_oop->is_method_handle_invoke(), "consistent");
++ result = methodHandle(THREAD, result_oop);
++ }
++ }
}
void LinkResolver::check_method_accessability(KlassHandle ref_klass,
-@@ -238,6 +249,11 @@
+@@ -238,6 +265,11 @@
if (resolved_method.is_null()) { // not found in the class hierarchy
// 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
++ // 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
+@@ -315,6 +347,11 @@
+
+ // lookup method in this interface or its super, java.lang.Object
+ lookup_instance_method_in_klasses(resolved_method, resolved_klass, method_name, method_signature, CHECK);
++
++ if (resolved_method.is_null()) {
++ // JSR 292: see if this is an implicitly generated method Dynamic.*(*...)
++ lookup_implicit_method(resolved_method, resolved_klass, method_name, method_signature, CHECK);
++ }
+
+ if (resolved_method.is_null()) {
+ // lookup method in all the super-interfaces
+@@ -746,6 +783,10 @@
+ bool check_access, bool check_null_and_abstract, TRAPS) {
+ methodHandle resolved_method;
+ linktime_resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK);
++ if (InvokeDynamic && resolved_method->is_method_handle_invoke()) {
++ result.set_static(resolved_klass, resolved_method, CHECK);
++ return; // do not perform runtime checks on implicit method
++ }
+ runtime_resolve_interface_method(result, resolved_method, resolved_klass, recv, recv_klass, check_null_and_abstract, CHECK);
+ }
+
+@@ -928,6 +969,7 @@
+ case Bytecodes::_invokestatic : resolve_invokestatic (result, pool, index, CHECK); break;
+ case Bytecodes::_invokespecial : resolve_invokespecial (result, pool, index, CHECK); break;
+ case Bytecodes::_invokevirtual : resolve_invokevirtual (result, recv, pool, index, CHECK); break;
++ case Bytecodes::_invokedynamic : resolve_invokedynamic (result, pool, index, CHECK); break;
+ case Bytecodes::_invokeinterface: resolve_invokeinterface(result, recv, pool, index, CHECK); break;
+ }
+ return;
+@@ -989,6 +1031,18 @@
+ resolve_interface_call(result, recv, recvrKlass, resolved_klass, method_name, method_signature, current_klass, true, true, CHECK);
+ }
+
++
++void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle pool, int index, TRAPS) {
++ assert(constantPoolCacheOopDesc::is_secondary_index(index), "must be secondary index");
++ KlassHandle resolved_klass;
++ symbolHandle method_name;
++ symbolHandle method_signature;
++ KlassHandle current_klass;
++ resolve_pool(resolved_klass, method_name, method_signature, current_klass, pool, index, CHECK);
++ assert(resolved_klass() == SystemDictionary::java_dyn_Dynamic_klass(), "else can't get here");
++ resolve_interface_call(result, Handle(), KlassHandle(), resolved_klass, method_name, method_signature, current_klass, true, true, CHECK);
++}
++
+ //------------------------------------------------------------------------------------------------------------------------
+ #ifndef PRODUCT
+
diff --git a/src/share/vm/interpreter/linkResolver.hpp b/src/share/vm/interpreter/linkResolver.hpp
--- a/src/share/vm/interpreter/linkResolver.hpp
+++ b/src/share/vm/interpreter/linkResolver.hpp
@@ -2395,10 +4223,26 @@ diff --git a/src/share/vm/interpreter/li
static int vtable_index_of_miranda_method(KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
+@@ -146,6 +147,7 @@
+ static void resolve_special_call (CallInfo& result, KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass, bool check_access, TRAPS);
+ static void resolve_virtual_call (CallInfo& result, Handle recv, KlassHandle recv_klass, KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass, bool check_access, bool check_null_and_abstract, TRAPS);
+ static void resolve_interface_call(CallInfo& result, Handle recv, KlassHandle recv_klass, KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass, bool check_access, bool check_null_and_abstract, TRAPS);
++ static void resolve_dynamic_call (CallInfo& result, KlassHandle resolved_klass, symbolHandle method_name, symbolHandle method_signature, KlassHandle current_klass, bool check_access, TRAPS);
+
+ // same as above for compile-time resolution; but returns null handle instead of throwing an exception on error
+ // also, does not initialize klass (i.e., no side effects)
+@@ -166,6 +168,7 @@
+ static void resolve_invokespecial (CallInfo& result, constantPoolHandle pool, int index, TRAPS);
+ static void resolve_invokevirtual (CallInfo& result, Handle recv, constantPoolHandle pool, int index, TRAPS);
+ static void resolve_invokeinterface(CallInfo& result, Handle recv, constantPoolHandle pool, int index, TRAPS);
++ static void resolve_invokedynamic (CallInfo& result, constantPoolHandle pool, int index, TRAPS);
+
+ static void resolve_invoke (CallInfo& result, Handle recv, constantPoolHandle pool, int index, Bytecodes::Code byte, TRAPS);
+ };
diff --git a/src/share/vm/interpreter/rewriter.cpp b/src/share/vm/interpreter/rewriter.cpp
--- a/src/share/vm/interpreter/rewriter.cpp
+++ b/src/share/vm/interpreter/rewriter.cpp
-@@ -25,34 +25,56 @@
+@@ -25,34 +25,57 @@
# include "incls/_precompiled.incl"
# include "incls/_rewriter.cpp.incl"
@@ -2459,7 +4303,8 @@ diff --git a/src/share/vm/interpreter/re
+ // Hack: We put it on the map as an encoded value.
+ // The only place that consumes this is ConstantPoolCacheEntry::set_initial_state
+ int encoded = constantPoolCacheOopDesc::encode_secondary_index(main_entry);
-+ return _cp_cache_map.append(encoded);
++ int plain_secondary_index = _cp_cache_map.append(encoded);
++ return constantPoolCacheOopDesc::encode_secondary_index(plain_secondary_index);
+}
+
+
@@ -2474,7 +4319,7 @@ diff --git a/src/share/vm/interpreter/re
}
-@@ -96,8 +118,40 @@
+@@ -96,8 +119,40 @@
}
@@ -2516,7 +4361,7 @@ diff --git a/src/share/vm/interpreter/re
int nof_jsrs = 0;
bool has_monitor_bytecodes = false;
-@@ -114,8 +168,10 @@
+@@ -114,8 +169,10 @@
const int code_length = method->code_size();
int bc_length;
@@ -2527,7 +4372,7 @@ diff --git a/src/share/vm/interpreter/re
c = (Bytecodes::Code)(*bcp);
// Since we have the code, see if we can get the length
-@@ -130,6 +186,7 @@
+@@ -130,6 +187,7 @@
// by 'wide'. We don't currently examine any of the bytecodes
// modified by wide, but in case we do in the future...
if (c == Bytecodes::_wide) {
@@ -2535,7 +4380,7 @@ diff --git a/src/share/vm/interpreter/re
c = (Bytecodes::Code)bcp[1];
}
}
-@@ -152,14 +209,20 @@
+@@ -152,14 +210,20 @@
case Bytecodes::_putstatic : // fall through
case Bytecodes::_getfield : // fall through
case Bytecodes::_putfield : // fall through
@@ -2562,7 +4407,7 @@ diff --git a/src/share/vm/interpreter/re
case Bytecodes::_jsr : // fall through
case Bytecodes::_jsr_w : nof_jsrs++; break;
case Bytecodes::_monitorenter : // fall through
-@@ -177,53 +240,56 @@
+@@ -177,53 +241,56 @@
// have to be rewritten, so we run the oopMapGenerator on the method
if (nof_jsrs > 0) {
method->set_has_jsrs();
@@ -2652,7 +4497,7 @@ diff --git a/src/share/vm/interpreter/re
if (method->intrinsic_id() == vmIntrinsics::_Object_init) {
// rewrite the return bytecodes of Object.<init> to register the
// object for finalization if needed.
-@@ -234,13 +300,27 @@
+@@ -234,13 +301,27 @@
}
}
@@ -2742,7 +4587,75 @@ diff --git a/src/share/vm/interpreter/te
diff --git a/src/share/vm/interpreter/templateInterpreter.cpp b/src/share/vm/interpreter/templateInterpreter.cpp
--- a/src/share/vm/interpreter/templateInterpreter.cpp
+++ b/src/share/vm/interpreter/templateInterpreter.cpp
-@@ -358,6 +358,7 @@
+@@ -168,6 +168,7 @@
+ 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;
+@@ -177,12 +178,14 @@
+ #endif // !PRODUCT
+ EntryPoint TemplateInterpreter::_return_entry[TemplateInterpreter::number_of_return_entries];
+ EntryPoint TemplateInterpreter::_earlyret_entry;
++EntryPoint TemplateInterpreter::_return_unbox_entry;
+ EntryPoint TemplateInterpreter::_deopt_entry [TemplateInterpreter::number_of_deopt_entries ];
+ EntryPoint TemplateInterpreter::_continuation_entry;
+ EntryPoint TemplateInterpreter::_safept_entry;
+
+ address TemplateInterpreter::_return_3_addrs_by_index[TemplateInterpreter::number_of_return_addrs];
+ address TemplateInterpreter::_return_5_addrs_by_index[TemplateInterpreter::number_of_return_addrs];
++address TemplateInterpreter::_return_5_unbox_addrs_by_index[TemplateInterpreter::number_of_return_addrs];
+
+ DispatchTable TemplateInterpreter::_active_table;
+ DispatchTable TemplateInterpreter::_normal_table;
+@@ -250,6 +253,22 @@
+ }
+ }
+
++ if (InvokeDynamic) {
++ CodeletMark cm(_masm, "unboxing return entry points");
++ Interpreter::_return_unbox_entry =
++ EntryPoint(
++ generate_return_unbox_entry_for(btos, 5),
++ generate_return_unbox_entry_for(ctos, 5),
++ generate_return_unbox_entry_for(stos, 5),
++ generate_return_unbox_entry_for(atos, 5), // cast conversion
++ generate_return_unbox_entry_for(itos, 5),
++ generate_return_unbox_entry_for(ltos, 5),
++ generate_return_unbox_entry_for(ftos, 5),
++ generate_return_unbox_entry_for(dtos, 5),
++ Interpreter::_return_entry[5].entry(vtos) // no unboxing for void
++ );
++ }
++
+ { CodeletMark cm(_masm, "earlyret entry points");
+ Interpreter::_earlyret_entry =
+ EntryPoint(
+@@ -297,8 +316,11 @@
+
+ for (int j = 0; j < number_of_states; j++) {
+ const TosState states[] = {btos, ctos, stos, itos, ltos, ftos, dtos, atos, vtos};
+- Interpreter::_return_3_addrs_by_index[Interpreter::TosState_as_index(states[j])] = Interpreter::return_entry(states[j], 3);
+- Interpreter::_return_5_addrs_by_index[Interpreter::TosState_as_index(states[j])] = Interpreter::return_entry(states[j], 5);
++ int index = Interpreter::TosState_as_index(states[j]);
++ Interpreter::_return_3_addrs_by_index[index] = Interpreter::return_entry(states[j], 3);
++ Interpreter::_return_5_addrs_by_index[index] = Interpreter::return_entry(states[j], 5);
++ if (InvokeDynamic)
++ Interpreter::_return_5_unbox_addrs_by_index[index] = Interpreter::return_unbox_entry(states[j], 5);
+ }
+
+ { CodeletMark cm(_masm, "continuation entry points");
+@@ -341,6 +363,7 @@
+ 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 +381,7 @@
method_entry(empty)
method_entry(accessor)
method_entry(abstract)
@@ -2750,17 +4663,124 @@ diff --git a/src/share/vm/interpreter/te
method_entry(java_lang_math_sin )
method_entry(java_lang_math_cos )
method_entry(java_lang_math_tan )
+@@ -520,6 +544,18 @@
+ address TemplateInterpreter::return_entry(TosState state, int length) {
+ guarantee(0 <= length && length < Interpreter::number_of_return_entries, "illegal length");
+ return _return_entry[length].entry(state);
++}
++
++
++address TemplateInterpreter::return_unbox_entry(TosState state, int length) {
++ assert(InvokeDynamic, "");
++ if (state == vtos) {
++ // no unboxing to do, actually
++ return return_entry(state, length);
++ } else {
++ assert(length == 5, "unboxing entries generated for invokedynamic only");
++ return _return_unbox_entry.entry(state);
++ }
+ }
+
+
+diff --git a/src/share/vm/interpreter/templateInterpreter.hpp b/src/share/vm/interpreter/templateInterpreter.hpp
+--- a/src/share/vm/interpreter/templateInterpreter.hpp
++++ b/src/share/vm/interpreter/templateInterpreter.hpp
+@@ -77,14 +77,15 @@
+ friend class VMStructs;
+ friend class InterpreterMacroAssembler;
+ friend class TemplateInterpreterGenerator;
++ friend class InterpreterGenerator;
+ friend class TemplateTable;
+ // friend class Interpreter;
+ public:
+
+ enum MoreConstants {
+- number_of_return_entries = 9, // number of return entry points
+- number_of_deopt_entries = 9, // number of deoptimization entry points
+- number_of_return_addrs = 9 // number of return addresses
++ number_of_return_entries = number_of_states, // number of return entry points
++ number_of_deopt_entries = number_of_states, // number of deoptimization entry points
++ number_of_return_addrs = number_of_states // number of return addresses
+ };
+
+ protected:
+@@ -93,6 +94,7 @@
+ 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;
+
+@@ -108,12 +110,14 @@
+ #endif // !PRODUCT
+ static EntryPoint _return_entry[number_of_return_entries]; // entry points to return to from a call
+ static EntryPoint _earlyret_entry; // entry point to return early from a call
++ static EntryPoint _return_unbox_entry; // entry point to unbox a return value from a call
+ static EntryPoint _deopt_entry[number_of_deopt_entries]; // entry points to return to from a deoptimization
+ static EntryPoint _continuation_entry;
+ static EntryPoint _safept_entry;
+
+ static address _return_3_addrs_by_index[number_of_return_addrs]; // for invokevirtual return entries
+ static address _return_5_addrs_by_index[number_of_return_addrs]; // for invokeinterface return entries
++ static address _return_5_unbox_addrs_by_index[number_of_return_addrs]; // for invokedynamic bootstrap methods
+
+ static DispatchTable _active_table; // the active dispatch table (used by the interpreter for dispatch)
+ static DispatchTable _normal_table; // the normal dispatch table (used to set the active table in normal mode)
+@@ -154,10 +158,12 @@
+ // Support for invokes
+ static address* return_3_addrs_by_index_table() { return _return_3_addrs_by_index; }
+ static address* return_5_addrs_by_index_table() { return _return_5_addrs_by_index; }
++ static address* return_5_unbox_addrs_by_index_table() { return _return_5_unbox_addrs_by_index; }
+ static int TosState_as_index(TosState state); // computes index into return_3_entry_by_index table
+
+ static address return_entry (TosState state, int length);
+ static address deopt_entry (TosState state, int length);
++ static address return_unbox_entry(TosState state, int length);
+
+ // Safepoint support
+ static void notice_safepoints(); // stops the thread when reaching a safepoint
+diff --git a/src/share/vm/interpreter/templateInterpreterGenerator.hpp b/src/share/vm/interpreter/templateInterpreterGenerator.hpp
+--- a/src/share/vm/interpreter/templateInterpreterGenerator.hpp
++++ b/src/share/vm/interpreter/templateInterpreterGenerator.hpp
+@@ -48,9 +48,13 @@
+ }
+ 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);
++ address generate_return_entry_for(TosState state, int step, bool unbox = false);
++ address generate_return_unbox_entry_for(TosState state, int step) {
++ return generate_return_entry_for(state, step, true);
++ }
+ address generate_earlyret_entry_for(TosState state);
+ address generate_deopt_entry_for(TosState state, int step);
+ address generate_safept_entry_for(TosState state, address runtime_entry);
diff --git a/src/share/vm/interpreter/templateTable.cpp b/src/share/vm/interpreter/templateTable.cpp
--- a/src/share/vm/interpreter/templateTable.cpp
+++ b/src/share/vm/interpreter/templateTable.cpp
-@@ -500,6 +500,7 @@
+@@ -500,6 +500,8 @@
def(Bytecodes::_fast_invokevfinal , ubcp|disp|clvm|____, vtos, vtos, fast_invokevfinal , 2 );
-+ def(Bytecodes::_invokedynamic , ubcp|disp|clvm|____, vtos, vtos, invokeinterface , 1 );
++ // JSR 292 (this is not an externally visible bytecode)
++ def(Bytecodes::_invokedynamic , ubcp|disp|clvm|____, vtos, vtos, invokedynamic , 1 );
def(Bytecodes::_fast_linearswitch , ubcp|disp|____|____, itos, vtos, fast_linearswitch , _ );
def(Bytecodes::_fast_binaryswitch , ubcp|disp|____|____, itos, vtos, fast_binaryswitch , _ );
+diff --git a/src/share/vm/interpreter/templateTable.hpp b/src/share/vm/interpreter/templateTable.hpp
+--- a/src/share/vm/interpreter/templateTable.hpp
++++ b/src/share/vm/interpreter/templateTable.hpp
+@@ -260,6 +260,7 @@
+ static void invokespecial(int byte_no);
+ static void invokestatic(int byte_no);
+ static void invokeinterface(int byte_no);
++ static void invokedynamic(int byte_no);
+ static void fast_invokevfinal(int byte_no);
+
+ static void getfield_or_static(int byte_no, bool is_static);
diff --git a/src/share/vm/memory/dump.cpp b/src/share/vm/memory/dump.cpp
--- a/src/share/vm/memory/dump.cpp
+++ b/src/share/vm/memory/dump.cpp
@@ -2777,9 +4797,55 @@ diff --git a/src/share/vm/oops/constantP
diff --git a/src/share/vm/oops/constantPoolKlass.cpp b/src/share/vm/oops/constantPoolKlass.cpp
--- a/src/share/vm/oops/constantPoolKlass.cpp
+++ b/src/share/vm/oops/constantPoolKlass.cpp
-@@ -383,7 +383,8 @@
+@@ -261,10 +261,36 @@
+
+ void constantPoolKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
+ assert(obj->is_constantPool(), "should be constant pool");
++ constantPoolOop cp = (constantPoolOop) obj;
++ if (MethodHandles && cp->tags() != NULL) {
++ // FIXME: This only helps if there are pseudo-strings in this CP.
++ // Mark such CP's with a dirty bit.
++ oop* base = (oop*)cp->base();
++ for (int i = 0; i < cp->length(); ++i, ++base) {
++ if (cp->tag_at(i).is_string()) {
++ if (PSScavenge::should_scavenge(base)) {
++ pm->claim_or_forward_breadth(base);
++ }
++ }
++ }
++ }
+ }
+
+ void constantPoolKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
+ assert(obj->is_constantPool(), "should be constant pool");
++ constantPoolOop cp = (constantPoolOop) obj;
++ if (MethodHandles && cp->tags() != NULL) {
++ // FIXME: This only helps if there are pseudo-strings in this CP.
++ // Mark such CP's with a dirty bit.
++ oop* base = (oop*)cp->base();
++ for (int i = 0; i < cp->length(); ++i, ++base) {
++ if (cp->tag_at(i).is_string()) {
++ if (PSScavenge::should_scavenge(base)) {
++ pm->claim_or_forward_depth(base);
++ }
++ }
++ }
++ }
+ }
+ #endif // SERIALGC
+
+@@ -302,7 +328,7 @@
+ break;
+ case JVM_CONSTANT_UnresolvedString :
+ case JVM_CONSTANT_String :
+- anObj = cp->string_at(index, CATCH);
++ anObj = cp->pseudo_string_at(index, CATCH);
+ anObj->print_value_on(st);
+ st->print(" {0x%lx}", (address)anObj);
+ break;
+@@ -383,7 +409,8 @@
}
- if (false) // @@@@ pseudo strings can be in non-perm
+ if (false) // %%% pseudo strings can be in non-perm
if (cp->tag_at(i).is_string()) {
- guarantee((*base)->is_perm(), "should be in permspace");
+ // %%% split pseudo-string out of string
@@ -2790,7 +4856,7 @@ diff --git a/src/share/vm/oops/constantP
diff --git a/src/share/vm/oops/constantPoolOop.cpp b/src/share/vm/oops/constantPoolOop.cpp
--- a/src/share/vm/oops/constantPoolOop.cpp
+++ b/src/share/vm/oops/constantPoolOop.cpp
-@@ -260,6 +260,17 @@
+@@ -260,6 +260,18 @@
int constantPoolOopDesc::uncached_klass_ref_index_at(int which) {
jint ref_index = field_or_method_at(which, true);
return extract_low_short_from_int(ref_index);
@@ -2800,6 +4866,7 @@ diff --git a/src/share/vm/oops/constantP
+
+int constantPoolOopDesc::map_instruction_operand_to_index(int operand) {
+ if (constantPoolCacheOopDesc::is_secondary_index(operand)) {
++ assert(InvokeDynamic, "rewriter only produces four-byte indexes for invokedynamic");
+ return cache()->main_entry_at(operand)->constant_pool_index();
+ }
+ assert((int)(u2)operand == operand, "clean u2");
@@ -2856,7 +4923,39 @@ diff --git a/src/share/vm/oops/cpCacheOo
}
-@@ -392,7 +402,11 @@
+@@ -136,6 +146,7 @@
+ int byte_no = -1;
+ bool needs_vfinal_flag = false;
+ switch (invoke_code) {
++ case Bytecodes::_invokedynamic:
+ case Bytecodes::_invokevirtual:
+ case Bytecodes::_invokeinterface: {
+ if (method->can_be_statically_bound()) {
+@@ -208,6 +219,23 @@
+ set_f2(index);
+ set_flags(as_flags(as_TosState(method->result_type()), method->is_final_method(), false, false, false, true) | method()->size_of_parameters());
+ set_bytecode_1(Bytecodes::_invokeinterface);
++}
++
++
++void ConstantPoolCacheEntry::set_dynamic_call(Handle call_site, int index) {
++ methodOop method = (methodOop) java_dyn_impl_DynCallSite::vmref(call_site());
++ assert(method->is_method(), "must be initialized properly");
++ int param_size = method->size_of_parameters();
++ assert(param_size > 1, "method argument size must include MH.this & initial dynamic receiver");
++ param_size -= 1; // do not count MH.this; it is not stacked for invokedynamic
++ if (Atomic::cmpxchg_ptr(call_site(), &_f1, NULL) == NULL) {
++ // racing threads might be trying to install their own favorites
++ set_f1(call_site());
++ }
++ set_f2(index);
++ set_flags(as_flags(as_TosState(method->result_type()), method->is_final_method(), false, false, false, true) | param_size);
++ // do not do set_bytecode on a secondary CP cache entry
++ //set_bytecode_1(Bytecodes::_invokedynamic);
+ }
+
+
+@@ -392,7 +420,11 @@
// print separator
if (index == 0) tty->print_cr(" -------------");
// print entry
@@ -2872,7 +4971,28 @@ diff --git a/src/share/vm/oops/cpCacheOo
diff --git a/src/share/vm/oops/cpCacheOop.hpp b/src/share/vm/oops/cpCacheOop.hpp
--- a/src/share/vm/oops/cpCacheOop.hpp
+++ b/src/share/vm/oops/cpCacheOop.hpp
-@@ -216,7 +216,11 @@
+@@ -89,6 +89,8 @@
+ // _f1 = method for all but virtual calls, unused by virtual calls
+ // (note: for interface calls, which are essentially virtual,
+ // contains klassOop for the corresponding interface.
++// for invokedynamic (a variant of invokeiterface), f1 contains
++// the CallSite object for the invocation
+ // _f2 = method/vtable index for virtual calls only, unused by all other
+ // calls. The vf flag indicates this is a method pointer not an
+ // index.
+@@ -175,6 +177,11 @@
+ int index // Method index into interface
+ );
+
++ void set_dynamic_call(
++ Handle call_site, // Resolved java.dyn.CallSite (f1)
++ int index // index (unused f2)
++ );
++
+ void set_parameter_size(int value) {
+ assert(parameter_size() == 0 || parameter_size() == value,
+ "size must not change");
+@@ -216,7 +223,11 @@
}
// Accessors
@@ -2885,7 +5005,7 @@ diff --git a/src/share/vm/oops/cpCacheOo
Bytecodes::Code bytecode_1() const { return Bytecodes::cast((_indices >> 16) & 0xFF); }
Bytecodes::Code bytecode_2() const { return Bytecodes::cast((_indices >> 24) & 0xFF); }
volatile oop f1() const { return _f1; }
-@@ -311,10 +315,30 @@
+@@ -311,10 +322,30 @@
// Initialization
void initialize(intArray& inverse_index_map);
@@ -2916,19 +5036,91 @@ diff --git a/src/share/vm/oops/cpCacheOo
// Code generation
static ByteSize base_offset() { return in_ByteSize(sizeof(constantPoolCacheOopDesc)); }
+diff --git a/src/share/vm/oops/generateOopMap.cpp b/src/share/vm/oops/generateOopMap.cpp
+--- a/src/share/vm/oops/generateOopMap.cpp
++++ b/src/share/vm/oops/generateOopMap.cpp
+@@ -1265,7 +1265,7 @@
+ case Bytecodes::_invokespecial:
+ case Bytecodes::_invokestatic:
+ case Bytecodes::_invokeinterface:
+- int idx = currentBC->get_index_big();
++ int idx = currentBC->get_index_int();
+ constantPoolOop cp = method()->constants();
+ int nameAndTypeIdx = cp->name_and_type_ref_index_at(idx);
+ int signatureIdx = cp->signature_ref_index_at(nameAndTypeIdx);
+@@ -1296,7 +1296,7 @@
+ case Bytecodes::_invokespecial:
+ case Bytecodes::_invokestatic:
+ case Bytecodes::_invokeinterface:
+- int idx = currentBC->get_index_big();
++ int idx = currentBC->get_index_int();
+ constantPoolOop cp = method()->constants();
+ int nameAndTypeIdx = cp->name_and_type_ref_index_at(idx);
+ int signatureIdx = cp->signature_ref_index_at(nameAndTypeIdx);
+@@ -1568,7 +1568,7 @@
+ case Bytecodes::_invokevirtual:
+ case Bytecodes::_invokespecial: do_method(false, false, itr->get_index_big(), itr->bci()); break;
+ case Bytecodes::_invokestatic: do_method(true, false, itr->get_index_big(), itr->bci()); break;
+- case Bytecodes::_invokeinterface: do_method(false, true, itr->get_index_big(), itr->bci()); break;
++ case Bytecodes::_invokeinterface: do_method(false, true, itr->get_index_int(), itr->bci()); break;
+ case Bytecodes::_newarray:
+ case Bytecodes::_anewarray: pp_new_ref(vCTS, itr->bci()); break;
+ case Bytecodes::_checkcast: do_checkcast(); break;
diff --git a/src/share/vm/oops/instanceKlass.cpp b/src/share/vm/oops/instanceKlass.cpp
--- a/src/share/vm/oops/instanceKlass.cpp
+++ b/src/share/vm/oops/instanceKlass.cpp
-@@ -1974,7 +1974,7 @@
+@@ -1973,9 +1973,11 @@
+
// Printing
++#define BULLET " - "
++
void FieldPrinter::do_field(fieldDescriptor* fd) {
- if (fd->is_static() == (_obj == NULL)) {
+- _st->print(" - ");
++ _st->print(BULLET);
+ if (fd->is_static() || (_obj == NULL)) {
- _st->print(" - ");
fd->print_on(_st);
_st->cr();
-@@ -2028,6 +2028,28 @@
+ } else {
+@@ -1996,7 +1998,7 @@
+ value->is_typeArray() &&
+ offset <= (juint) value->length() &&
+ offset + length <= (juint) value->length()) {
+- st->print("string: ");
++ st->print(BULLET"string: ");
+ Handle h_obj(obj);
+ java_lang_String::print(h_obj, st);
+ st->cr();
+@@ -2004,22 +2006,22 @@
+ }
+ }
+
+- st->print_cr("fields:");
++ st->print_cr(BULLET"---- fields (total size %d words):", oop_size(obj));
+ FieldPrinter print_nonstatic_field(st, obj);
+ do_nonstatic_fields(&print_nonstatic_field);
+
+ if (as_klassOop() == SystemDictionary::class_klass()) {
+ klassOop mirrored_klass = java_lang_Class::as_klassOop(obj);
+- st->print(" - fake entry for mirror: ");
++ st->print(BULLET"fake entry for mirror: ");
+ mirrored_klass->print_value_on(st);
+ st->cr();
+- st->print(" - fake entry resolved_constructor: ");
++ st->print(BULLET"fake entry resolved_constructor: ");
+ methodOop ctor = java_lang_Class::resolved_constructor(obj);
+ ctor->print_value_on(st);
+ klassOop array_klass = java_lang_Class::array_klass(obj);
+- st->print(" - fake entry for array: ");
++ st->cr();
++ st->print(BULLET"fake entry for array: ");
+ array_klass->print_value_on(st);
+- st->cr();
+ st->cr();
+ }
+ }
+@@ -2028,6 +2030,28 @@
st->print("a ");
name()->print_value_on(st);
obj->print_address_on(st);
@@ -2957,6 +5149,240 @@ diff --git a/src/share/vm/oops/instanceK
}
#endif // ndef PRODUCT
+diff --git a/src/share/vm/oops/instanceKlass.hpp b/src/share/vm/oops/instanceKlass.hpp
+--- a/src/share/vm/oops/instanceKlass.hpp
++++ b/src/share/vm/oops/instanceKlass.hpp
+@@ -161,6 +161,8 @@
+ klassOop _implementors[implementors_limit];
+ // Generic signature, or null if none.
+ symbolOop _generic_signature;
++ // invokedynamic bootstrap method (a java.dyn.MethodHandle)
++ oop _bootstrap_method;
+ // Annotations for this class, or null if none.
+ typeArrayOop _class_annotations;
+ // Annotation objects (byte arrays) for fields, or null if no annotations.
+@@ -443,6 +445,10 @@
+ u2 method_index) { _enclosing_method_class_index = class_index;
+ _enclosing_method_method_index = method_index; }
+
++ // JSR 292 support
++ oop bootstrap_method() const { return _bootstrap_method; }
++ void set_bootstrap_method(oop mh) { oop_store(&_bootstrap_method, mh); }
++
+ // jmethodID support
+ static jmethodID get_jmethod_id(instanceKlassHandle ik_h, size_t idnum,
+ jmethodID new_id, jmethodID* new_jmeths);
+@@ -715,6 +721,7 @@
+ oop* adr_inner_classes() const { return (oop*)&this->_inner_classes;}
+ oop* adr_implementors() const { return (oop*)&this->_implementors[0];}
+ oop* adr_generic_signature() const { return (oop*)&this->_generic_signature;}
++ oop* adr_bootstrap_method() const { return (oop*)&this->_bootstrap_method;}
+ oop* adr_methods_jmethod_ids() const { return (oop*)&this->_methods_jmethod_ids;}
+ oop* adr_methods_cached_itable_indices() const { return (oop*)&this->_methods_cached_itable_indices;}
+ oop* adr_class_annotations() const { return (oop*)&this->_class_annotations;}
+diff --git a/src/share/vm/oops/instanceKlassKlass.cpp b/src/share/vm/oops/instanceKlassKlass.cpp
+--- a/src/share/vm/oops/instanceKlassKlass.cpp
++++ b/src/share/vm/oops/instanceKlassKlass.cpp
+@@ -84,6 +84,7 @@
+ MarkSweep::mark_and_push(ik->adr_host_klass());
+ MarkSweep::mark_and_push(ik->adr_signers());
+ MarkSweep::mark_and_push(ik->adr_generic_signature());
++ MarkSweep::mark_and_push(ik->adr_bootstrap_method());
+ MarkSweep::mark_and_push(ik->adr_class_annotations());
+ MarkSweep::mark_and_push(ik->adr_fields_annotations());
+ MarkSweep::mark_and_push(ik->adr_methods_annotations());
+@@ -124,6 +125,7 @@
+ PSParallelCompact::mark_and_push(cm, ik->adr_host_klass());
+ PSParallelCompact::mark_and_push(cm, ik->adr_signers());
+ PSParallelCompact::mark_and_push(cm, ik->adr_generic_signature());
++ PSParallelCompact::mark_and_push(cm, ik->adr_bootstrap_method());
+ PSParallelCompact::mark_and_push(cm, ik->adr_class_annotations());
+ PSParallelCompact::mark_and_push(cm, ik->adr_fields_annotations());
+ PSParallelCompact::mark_and_push(cm, ik->adr_methods_annotations());
+@@ -170,6 +172,7 @@
+ blk->do_oop(&ik->adr_implementors()[i]);
+ }
+ blk->do_oop(ik->adr_generic_signature());
++ blk->do_oop(ik->adr_bootstrap_method());
+ blk->do_oop(ik->adr_class_annotations());
+ blk->do_oop(ik->adr_fields_annotations());
+ blk->do_oop(ik->adr_methods_annotations());
+@@ -230,6 +233,8 @@
+ }
+ adr = ik->adr_generic_signature();
+ if (mr.contains(adr)) blk->do_oop(adr);
++ adr = ik->adr_bootstrap_method();
++ if (mr.contains(adr)) blk->do_oop(adr);
+ adr = ik->adr_class_annotations();
+ if (mr.contains(adr)) blk->do_oop(adr);
+ adr = ik->adr_fields_annotations();
+@@ -274,6 +279,7 @@
+ MarkSweep::adjust_pointer(&ik->adr_implementors()[i]);
+ }
+ MarkSweep::adjust_pointer(ik->adr_generic_signature());
++ MarkSweep::adjust_pointer(ik->adr_bootstrap_method());
+ MarkSweep::adjust_pointer(ik->adr_class_annotations());
+ MarkSweep::adjust_pointer(ik->adr_fields_annotations());
+ MarkSweep::adjust_pointer(ik->adr_methods_annotations());
+@@ -454,6 +460,7 @@
+ ik->set_breakpoints(NULL);
+ ik->init_previous_versions();
+ ik->set_generic_signature(NULL);
++ ik->set_bootstrap_method(NULL);
+ ik->release_set_methods_jmethod_ids(NULL);
+ ik->release_set_methods_cached_itable_indices(NULL);
+ ik->set_class_annotations(NULL);
+@@ -487,6 +494,8 @@
+
+ // Printing
+
++#define BULLET " - "
++
+ static const char* state_names[] = {
+ "unparseable_by_gc", "allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error"
+ };
+@@ -497,13 +506,13 @@
+ instanceKlass* ik = instanceKlass::cast(klassOop(obj));
+ klassKlass::oop_print_on(obj, st);
+
+- st->print(" - instance size: %d", ik->size_helper()); st->cr();
+- st->print(" - klass size: %d", ik->object_size()); st->cr();
+- st->print(" - access: "); ik->access_flags().print_on(st); st->cr();
+- st->print(" - state: "); st->print_cr(state_names[ik->_init_state]);
+- st->print(" - name: "); ik->name()->print_value_on(st); st->cr();
+- st->print(" - super: "); ik->super()->print_value_on(st); st->cr();
+- st->print(" - sub: ");
++ st->print(BULLET"instance size: %d", ik->size_helper()); st->cr();
++ st->print(BULLET"klass size: %d", ik->object_size()); st->cr();
++ st->print(BULLET"access: "); ik->access_flags().print_on(st); st->cr();
++ st->print(BULLET"state: "); st->print_cr(state_names[ik->_init_state]);
++ st->print(BULLET"name: "); ik->name()->print_value_on(st); st->cr();
++ st->print(BULLET"super: "); ik->super()->print_value_on(st); st->cr();
++ st->print(BULLET"sub: ");
+ Klass* sub = ik->subklass();
+ int n;
+ for (n = 0; sub != NULL; n++, sub = sub->next_sibling()) {
+@@ -516,12 +525,12 @@
+ st->cr();
+
+ if (ik->is_interface()) {
+- st->print_cr(" - nof implementors: %d", ik->nof_implementors());
++ st->print_cr(BULLET"nof implementors: %d", ik->nof_implementors());
+ int print_impl = 0;
+ for (int i = 0; i < instanceKlass::implementors_limit; i++) {
+ if (ik->implementor(i) != NULL) {
+ if (++print_impl == 1)
+- st->print_cr(" - implementor: ");
++ st->print_cr(BULLET"implementor: ");
+ st->print(" ");
+ ik->implementor(i)->print_value_on(st);
+ }
+@@ -529,34 +538,33 @@
+ if (print_impl > 0) st->cr();
+ }
+
+- st->print(" - arrays: "); ik->array_klasses()->print_value_on(st); st->cr();
+- st->print(" - methods: "); ik->methods()->print_value_on(st); st->cr();
++ st->print(BULLET"arrays: "); ik->array_klasses()->print_value_on(st); st->cr();
++ st->print(BULLET"methods: "); ik->methods()->print_value_on(st); st->cr();
+ if (Verbose) {
+ objArrayOop methods = ik->methods();
+ for(int i = 0; i < methods->length(); i++) {
+ tty->print("%d : ", i); methods->obj_at(i)->print_value(); tty->cr();
+ }
+ }
+- st->print(" - method ordering: "); ik->method_ordering()->print_value_on(st); st->cr();
+- st->print(" - local interfaces: "); ik->local_interfaces()->print_value_on(st); st->cr();
+- st->print(" - trans. interfaces: "); ik->transitive_interfaces()->print_value_on(st); st->cr();
+- st->print(" - constants: "); ik->constants()->print_value_on(st); st->cr();
+- st->print(" - class loader: "); ik->class_loader()->print_value_on(st); st->cr();
+- st->print(" - protection domain: "); ik->protection_domain()->print_value_on(st); st->cr();
+- st->print(" - host class: "); ik->host_klass()->print_value_on(st); st->cr();
+- st->print(" - signers: "); ik->signers()->print_value_on(st); st->cr();
++ st->print(BULLET"method ordering: "); ik->method_ordering()->print_value_on(st); st->cr();
++ st->print(BULLET"local interfaces: "); ik->local_interfaces()->print_value_on(st); st->cr();
++ st->print(BULLET"trans. interfaces: "); ik->transitive_interfaces()->print_value_on(st); st->cr();
++ st->print(BULLET"constants: "); ik->constants()->print_value_on(st); st->cr();
++ st->print(BULLET"class loader: "); ik->class_loader()->print_value_on(st); st->cr();
++ st->print(BULLET"protection domain: "); ik->protection_domain()->print_value_on(st); st->cr();
++ st->print(BULLET"host class: "); ik->host_klass()->print_value_on(st); st->cr();
++ st->print(BULLET"signers: "); ik->signers()->print_value_on(st); st->cr();
+ if (ik->source_file_name() != NULL) {
+- st->print(" - source file: ");
++ st->print(BULLET"source file: ");
+ ik->source_file_name()->print_value_on(st);
+ st->cr();
+ }
+ if (ik->source_debug_extension() != NULL) {
+- st->print(" - source debug extension: ");
++ st->print(BULLET"source debug extension: ");
+ ik->source_debug_extension()->print_value_on(st);
+ st->cr();
+ }
+
+- st->print_cr(" - previous version: ");
+ {
+ ResourceMark rm;
+ // PreviousVersionInfo objects returned via PreviousVersionWalker
+@@ -564,38 +572,48 @@
+ // GrowableArray _after_ the PreviousVersionWalker destructor
+ // has destroyed the handles.
+ {
++ bool have_pv = false;
+ PreviousVersionWalker pvw(ik);
+ for (PreviousVersionInfo * pv_info = pvw.next_previous_version();
+ pv_info != NULL; pv_info = pvw.next_previous_version()) {
++ if (!have_pv)
++ st->print(BULLET"previous version: ");
++ have_pv = true;
+ pv_info->prev_constant_pool_handle()()->print_value_on(st);
+ }
+- st->cr();
++ if (have_pv) st->cr();
+ } // pvw is cleaned up
+ } // rm is cleaned up
+
+ if (ik->generic_signature() != NULL) {
+- st->print(" - generic signature: ");
++ st->print(BULLET"generic signature: ");
+ ik->generic_signature()->print_value_on(st);
++ st->cr();
+ }
+- st->print(" - inner classes: "); ik->inner_classes()->print_value_on(st); st->cr();
+- st->print(" - java mirror: "); ik->java_mirror()->print_value_on(st); st->cr();
+- st->print(" - vtable length %d (start addr: " INTPTR_FORMAT ")", ik->vtable_length(), ik->start_of_vtable()); st->cr();
+- st->print(" - itable length %d (start addr: " INTPTR_FORMAT ")", ik->itable_length(), ik->start_of_itable()); st->cr();
+- st->print_cr(" - static fields:");
++ if (ik->bootstrap_method() != NULL) {
++ st->print(BULLET"bootstrap method: ");
++ ik->bootstrap_method()->print_value_on(st);
++ st->cr();
++ }
++ st->print(BULLET"inner classes: "); ik->inner_classes()->print_value_on(st); st->cr();
++ st->print(BULLET"java mirror: "); ik->java_mirror()->print_value_on(st); st->cr();
++ st->print(BULLET"vtable length %d (start addr: " INTPTR_FORMAT ")", ik->vtable_length(), ik->start_of_vtable()); st->cr();
++ st->print(BULLET"itable length %d (start addr: " INTPTR_FORMAT ")", ik->itable_length(), ik->start_of_itable()); st->cr();
++ st->print_cr(BULLET"---- static fields (%d words):", ik->static_field_size());
+ FieldPrinter print_static_field(st);
+ ik->do_local_static_fields(&print_static_field);
+- st->print_cr(" - non-static fields:");
++ st->print_cr(BULLET"---- non-static fields (%d words):", ik->nonstatic_field_size());
+ FieldPrinter print_nonstatic_field(st, obj);
+ ik->do_nonstatic_fields(&print_nonstatic_field);
+
+- st->print(" - static oop maps: ");
++ st->print(BULLET"static oop maps: ");
+ if (ik->static_oop_field_size() > 0) {
+ int first_offset = ik->offset_of_static_fields();
+ st->print("%d-%d", first_offset, first_offset + ik->static_oop_field_size() - 1);
+ }
+ st->cr();
+
+- st->print(" - non-static oop maps: ");
++ st->print(BULLET"non-static oop maps: ");
+ OopMapBlock* map = ik->start_of_nonstatic_oop_maps();
+ OopMapBlock* end_map = map + ik->nonstatic_oop_map_size();
+ while (map < end_map) {
diff --git a/src/share/vm/oops/klassVtable.cpp b/src/share/vm/oops/klassVtable.cpp
--- a/src/share/vm/oops/klassVtable.cpp
+++ b/src/share/vm/oops/klassVtable.cpp
@@ -3036,7 +5462,18 @@ diff --git a/src/share/vm/oops/methodOop
diff --git a/src/share/vm/oops/methodOop.cpp b/src/share/vm/oops/methodOop.cpp
--- a/src/share/vm/oops/methodOop.cpp
+++ b/src/share/vm/oops/methodOop.cpp
-@@ -651,7 +651,7 @@
+@@ -564,6 +564,10 @@
+
+
+ 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 +655,7 @@
assert(entry != NULL, "interpreter entry must be non-null");
// Sets both _i2i_entry and _from_interpreted_entry
set_interpreter_entry(entry);
@@ -3045,7 +5482,7 @@ diff --git a/src/share/vm/oops/methodOop
set_native_function(
SharedRuntime::native_method_throw_unsatisfied_link_error_entry(),
!native_bind_event_is_interesting);
-@@ -781,6 +781,91 @@
+@@ -781,6 +785,112 @@
// caching this method should be just fine
return false;
@@ -3056,22 +5493,42 @@ diff --git a/src/share/vm/oops/methodOop
+ _imcp_invoke_name = 1, // utf8: 'invoke'
+ _imcp_invoke_signature, // utf8: (variable symbolOop)
+ _imcp_method_type_value, // string: (variable java/dyn/MethodType, sic)
++ _imcp_invokedynamic_signature,// utf8: (Object,args*)ret
+ _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(), "");
++ assert(mt->klass() == SystemDictionary::java_dyn_MethodType_klass(), "");
+ return mt;
+}
+
-+int* methodOopDesc::method_type_pointer_chase() {
-+ static int pchase[] = { -1, -1, -1 };
++symbolOop methodOopDesc::invokedynamic_signature() const {
++ if (!is_method_handle_invoke()) { assert(false, "caller resp."); return NULL; }
++ symbolOop sig = constants()->symbol_at(_imcp_invokedynamic_signature);
++ assert(sig->is_symbol(), "");
++ if (sig == vmSymbols::void_signature()) return NULL;
++ assert(sig->byte_at(0) == '(', "");
++ return sig;
++}
++
++void methodOopDesc::set_invokedynamic_signature(symbolOop sig) {
++ if (!is_method_handle_invoke()) { assert(false, "caller resp."); return; }
++ assert(sig != NULL && sig != vmSymbols::void_signature() && sig->byte_at(0) == '(', "");
++ DEBUG_ONLY(symbolOop oldsig = constants()->symbol_at(_imcp_invokedynamic_signature));
++ assert(oldsig == vmSymbols::void_signature() || oldsig == sig, "one change allowed");
++ constants()->symbol_at_put(_imcp_invokedynamic_signature, sig);
++}
++
++jint* methodOopDesc::method_type_pointer_chase() {
++ static jint pchase[] = { -1, -1, -1 };
+ if (pchase[0] == -1) {
-+ // be sure to do this in reverse to avoid races:
-+ pchase[1] = (constantPoolOopDesc::header_size() + _imcp_method_type_value) * HeapWordSize;
-+ pchase[0] = in_bytes(constants_offset());
++ 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;
+}
@@ -3079,7 +5536,7 @@ diff --git a/src/share/vm/oops/methodOop
+methodHandle methodOopDesc::make_invoke_method(symbolHandle signature,
+ Handle method_type, TRAPS) {
+ methodHandle empty;
-+
++
+ if (TraceMethodHandles) {
+ tty->print("Creating invoke method for ");
+ signature->print_value();
@@ -3094,7 +5551,8 @@ diff --git a/src/share/vm/oops/methodOop
+ 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, method_type());
-+ cp->set_pool_holder(SystemDictionary::methodHandle_klass());
++ cp->symbol_at_put(_imcp_invokedynamic_signature, vmSymbols::void_signature());
++ cp->set_pool_holder(SystemDictionary::java_dyn_MethodHandle_klass());
+
+ methodHandle m;
+ {
@@ -3140,7 +5598,7 @@ diff --git a/src/share/vm/oops/methodOop
diff --git a/src/share/vm/oops/methodOop.hpp b/src/share/vm/oops/methodOop.hpp
--- a/src/share/vm/oops/methodOop.hpp
+++ b/src/share/vm/oops/methodOop.hpp
-@@ -519,6 +519,12 @@
+@@ -519,6 +519,15 @@
// Reflection support
bool is_overridden_in(klassOop k) const;
@@ -3148,11 +5606,30 @@ diff --git a/src/share/vm/oops/methodOop
+ bool is_method_handle_invoke() const { return access_flags().is_method_handle_invoke(); }
+ static methodHandle make_invoke_method(symbolHandle signature, Handle method_type, TRAPS);
+ oop method_handle_type() const;
-+ static int* method_type_pointer_chase();
++ static jint* method_type_pointer_chase();
++ // hack for memoizing the signature variant needed by invokedynamic:
++ symbolOop invokedynamic_signature() const;
++ void set_invokedynamic_signature(symbolOop sig);
+
// RedefineClasses() support:
bool is_old() const { return access_flags().is_old(); }
void set_is_old() { _access_flags.set_is_old(); }
+diff --git a/src/share/vm/oops/oop.cpp b/src/share/vm/oops/oop.cpp
+--- a/src/share/vm/oops/oop.cpp
++++ b/src/share/vm/oops/oop.cpp
+@@ -65,11 +65,7 @@
+
+ void oopDesc::print_address_on(outputStream* st) const {
+ if (PrintOopAddress) {
+- st->print("{");
+- if (PrintOopAddress) {
+- st->print(INTPTR_FORMAT, this);
+- }
+- st->print("}");
++ st->print("{"INTPTR_FORMAT"}", this);
+ }
+ }
+
diff --git a/src/share/vm/oops/oop.hpp b/src/share/vm/oops/oop.hpp
--- a/src/share/vm/oops/oop.hpp
+++ b/src/share/vm/oops/oop.hpp
@@ -3219,15 +5696,29 @@ diff --git a/src/share/vm/prims/jvmtiCla
diff --git a/src/share/vm/prims/jvmtiClassFileReconstituter.cpp b/src/share/vm/prims/jvmtiClassFileReconstituter.cpp
--- a/src/share/vm/prims/jvmtiClassFileReconstituter.cpp
+++ b/src/share/vm/prims/jvmtiClassFileReconstituter.cpp
-@@ -664,7 +664,7 @@
+@@ -662,12 +662,21 @@
+ case Bytecodes::_invokeinterface :
+ assert(len == 3 || (code == Bytecodes::_invokeinterface && len ==5),
"sanity check");
++ int cpci = Bytes::get_native_u2(bcp+1);
++ bool is_invokedynamic = (InvokeDynamic && bs.raw_code() == Bytecodes::_invokedynamic);
++ if (is_invokedynamic)
++ cpci = Bytes::get_native_u4(bcp+1);
// cache cannot be pre-fetched since some classes won't have it yet
ConstantPoolCacheEntry* entry =
- mh->constants()->cache()->entry_at(Bytes::get_native_u2(bcp+1));
-+ mh->constants()->cache()->main_entry_at(Bytes::get_native_u2(bcp+1));
++ mh->constants()->cache()->main_entry_at(cpci);
int i = entry->constant_pool_index();
assert(i < mh->constants()->length(), "sanity check");
Bytes::put_Java_u2((address)(p+1), (u2)i); // java byte ordering
++ if (is_invokedynamic) {
++ ArgumentSizeComputer size_it(mh->constants()->uncached_signature_ref_at(i));
++ *(p+3) = (unsigned char)(size_it.size() + 1);
++ *(p+4) = 0;
++ }
+ break;
+ }
+ }
diff --git a/src/share/vm/prims/methodComparator.cpp b/src/share/vm/prims/methodComparator.cpp
--- a/src/share/vm/prims/methodComparator.cpp
+++ b/src/share/vm/prims/methodComparator.cpp
@@ -3246,7 +5737,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/vm/prims/methodHandles.cpp
-@@ -0,0 +1,852 @@
+@@ -0,0 +1,1085 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -3286,14 +5777,28 @@ new file mode 100644
+ "invokespecial", // ditto for the other invokes...
+ "invokevirtual",
+ "invokeinterface",
-+ "invokebound" // for BMH
++ "invokebound", // for BMH
++ "adapt_retype_only", // these are for AMH
++ "adapt_drop_initial",
++ "adapt_drop_final",
++ "adapt_check_cast",
++ "adapt_extend_sign",
++ "adapt_extend_zero",
++ "adapt_test_boolean",
++ "adapt_swap_argument",
++ "adapt_push_argument",
++ "adapt_push_primitive",
++ "adapt_push_reference",
++ "adapt_ricochet",
++ "adapt_flyby"
+};
+
+static methodOop decode_DMH(oop mh, int& decode_flags_result) {
+ assert(mh->klass() == SystemDictionary::dyn_impl_DMH_klass(), "");
+ oop ref = java_dyn_MethodHandle::vmref(mh);
-+ int index = java_dyn_MethodHandle::vmdata_int(mh);
++ int index = java_dyn_MethodHandle::vmdata_index(mh);
+ if (ref == NULL) return NULL;
++ index = (short) index; // ignore high order bits
+ if (index != methodOopDesc::nonvirtual_vtable_index) {
+ decode_flags_result |= MethodHandle::_dmf_does_dispatch;
+ }
@@ -3325,16 +5830,24 @@ new file mode 100644
+}
+
+static methodOop decode_AMH(oop mh, int& decode_flags_result) {
-+ assert(mh->klass() == SystemDictionary::dyn_impl_AMH_klass(), "");
-+ oop ref = java_dyn_MethodHandle::vmref(mh);
-+ if (ref == NULL) return NULL;
-+ if (ref->klass() == SystemDictionary::dyn_impl_DMH_klass()) {
-+ decode_flags_result |= MethodHandle::_dmf_has_casts;
-+ return decode_DMH(ref, decode_flags_result);
-+ }
-+ if (ref->klass() == SystemDictionary::dyn_impl_BMH_klass()) {
-+ decode_flags_result |= MethodHandle::_dmf_has_casts;
-+ return decode_BMH(ref, decode_flags_result);
++ for (;;) {
++ assert(mh->klass() == SystemDictionary::dyn_impl_AMH_klass(), "");
++ oop ref = java_dyn_MethodHandle::vmref(mh);
++ if (ref == NULL) return NULL;
++ if (ref->klass() == SystemDictionary::dyn_impl_DMH_klass()) {
++ decode_flags_result |= MethodHandle::_dmf_has_casts;
++ return decode_DMH(ref, decode_flags_result);
++ }
++ if (ref->klass() == SystemDictionary::dyn_impl_BMH_klass()) {
++ decode_flags_result |= MethodHandle::_dmf_has_casts;
++ return decode_BMH(ref, decode_flags_result);
++ }
++ if (ref->klass() == SystemDictionary::dyn_impl_AMH_klass()) {
++ // adapters can be stacked:
++ mh = ref;
++ } else {
++ break;
++ }
+ }
+ ShouldNotReachHere();
+ return NULL; // cannot parse
@@ -3351,7 +5864,7 @@ new file mode 100644
+ if (!xm->can_be_statically_bound())
+ decode_flags_result |= _dmf_does_dispatch;
+ return xm;
-+ } else if (Klass::cast(xk)->is_subclass_of(SystemDictionary::methodHandle_klass())) {
++ } else if (Klass::cast(xk)->is_subclass_of(SystemDictionary::java_dyn_MethodHandle_klass())) {
+ if (xk == SystemDictionary::dyn_impl_DMH_klass())
+ return decode_DMH(x, decode_flags_result);
+ else if (xk == SystemDictionary::dyn_impl_BMH_klass())
@@ -3376,6 +5889,26 @@ new file mode 100644
+ // unrecognized object
+ assert(!x->is_method(), "got this case first");
+ }
++ return NULL;
++}
++
++// Decode the vmref field of a method handle.
++// Sanitize out methodOops, klassOops, and any other non-Java data.
++oop MethodHandle::decode_vmref(oop x, int& decode_flags_result) {
++ if (x == NULL) return NULL;
++ decode_flags_result = 0;
++ klassOop xk = x->klass();
++ if (Klass::cast(xk)->is_subclass_of(SystemDictionary::java_dyn_MethodHandle_klass())) {
++ x = java_dyn_MethodHandle::vmref(x);
++ if (x == NULL) return NULL;
++ xk = x->klass();
++ }
++ // at this point is it known not to be an MH
++ if (Klass::cast(xk)->oop_is_instance())
++ return x;
++ if (Klass::cast(xk)->oop_is_klass())
++ return Klass::cast(klassOop(x))->java_mirror();
++ // it's inscrutable!
+ return NULL;
+}
+
@@ -3614,19 +6147,8 @@ new file mode 100644
+ tem = rax_mtype;
+ }
+
-+ if (java_dyn_MethodHandle::type_offset_in_bytes() == 0 ||
-+ java_dyn_MethodHandle::entry_offset_in_bytes() == 0) {
-+ // Bootstrapping problem, because the interpreter must be ready for
-+ // action before we link java classes (including java.dyn.*).
-+ // So we have to code generate the following code later,
-+ // after javaClasses.cpp gets initialized.
-+ __ movptr(rdx_temp, ExternalAddress((address) &_entries[_check_mtype]));
-+ __ jmp(Address(rdx_temp, MethodEntry::from_interpreted_entry_offset_in_bytes()));
-+ __ hlt();
-+ } else {
-+ check_method_type(_masm, rax_mtype, rcx_recv, wrong_method_type);
-+ jump_to_entry(_masm, rcx_recv, rdx_temp);
-+ }
++ check_method_type(_masm, rax_mtype, rcx_recv, rdx_temp, wrong_method_type);
++ jump_to_entry(_masm, rcx_recv, rdx_temp);
+
+ // save away the wrong_method_type entry point
+ address wmt_jump_addr = __ pc();
@@ -3645,9 +6167,9 @@ new file mode 100644
+// - rcx: method handle
+// - rdx, rsi, or ?: killable temp
+// %%% FIXME: move to masm
-+void MethodHandle::check_method_type(MacroAssembler* _masm, Register mtype_reg, Register recv_reg, Label& wrong_method_type) {
++void MethodHandle::check_method_type(MacroAssembler* _masm, Register mtype_reg, Register recv_reg, Register temp_reg, Label& wrong_method_type) {
+ // compare method type against that of the receiver
-+ __ cmpl(mtype_reg, Address(recv_reg, java_dyn_MethodHandle::type_offset_in_bytes()));
++ __ cmpl(mtype_reg, Address(recv_reg, __ delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg)));
+ __ jcc(Assembler::notEqual, wrong_method_type);
+}
+
@@ -3657,8 +6179,11 @@ new file mode 100644
+// - rax: killable temp (compiled only)
+// %%% FIXME: move to masm
+void MethodHandle::jump_to_entry(MacroAssembler* _masm, Register recv_reg, Register temp_reg) {
++ assert(recv_reg == rcx, "caller must put MH object in rcx");
++ assert_different_registers(recv_reg, temp_reg);
++
+ // pick out the interpreted side of the handler
-+ __ movl(temp_reg, Address(recv_reg, java_dyn_MethodHandle::entry_offset_in_bytes()));
++ __ movL_OR_Q(temp_reg, Address(recv_reg, __ delayed_value(java_dyn_MethodHandle::entry_offset_in_bytes, temp_reg)));
+
+ // off we go...
+ __ jmp(Address(temp_reg, MethodEntry::from_interpreted_entry_offset_in_bytes()));
@@ -3675,14 +6200,14 @@ new file mode 100644
+ // as set up by generate_method_handle_interpreter_entry():
+ // - rbx: methodOop (MethodHandle.invoke pseudo-method, unused)
+ // - rcx: receiver method handle
-+ // - rax: method handle type (already checked at call site)
++ // - rax: method handle type (already checked at call site, then unused)
+ // - rsi: sender SP (must preserve)
+ // - rdx: garbage temp, can blow away
+
+ Register rcx_recv = rcx;
-+ Register rax_mtype = rax;
++ Register rax_argslot = rax;
+ Register rsi_savedsp = rsi;
-+ Register rbx_method = rbx;
++ Register rbx_index = rbx;
+ Register rdx_temp = rdx;
+
+ guarantee(java_dyn_MethodHandle::vmdata_offset_in_bytes() != 0, "must have offsets");
@@ -3693,9 +6218,12 @@ new file mode 100644
+ }
+
+ address interp_entry = __ pc();
-+ switch (ek) {
++ switch ((int) ek) {
+ case _check_mtype:
+ {
++ // this stub is special, because it requires a live mtype argument
++ Register rax_mtype = rax;
++
+ Label wrong_method_type;
+ __ bind(wrong_method_type);
+ __ movptr(rdx_temp, ExternalAddress((address) &_entries[_wrong_method_type]));
@@ -3703,59 +6231,66 @@ new file mode 100644
+ __ hlt();
+
+ interp_entry = __ pc();
-+ check_method_type(_masm, rax_mtype, rcx_recv, wrong_method_type);
++ check_method_type(_masm, rax_mtype, rcx_recv, rdx_temp, wrong_method_type);
++ // now rax_mtype is dead; subsequent stubs will use it as a temp
++
+ jump_to_entry(_masm, rcx_recv, rdx_temp);
-+ break;
+ }
++ break;
+
+ case _invokestatic_mh:
+ case _invokespecial_mh:
-+ __ movL_OR_Q(rbx_method, Address(rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes()));
-+ __ verify_oop(rbx_method);
-+ // same as TemplateTable::invokestatic or invokespecial,
-+ // minus the CP setup and profiling:
-+ if (ek == _invokespecial_mh) {
-+ // Must load & check the first argument before entering the target method.
-+ __ movL_OR_Q(rcx_recv, find_mh_argument(_masm, rax_mtype, rsi_savedsp, 0, rcx_recv));
-+ __ null_check(rcx_recv);
-+ __ verify_oop(rcx_recv);
++ {
++ Register rbx_method = rbx_index;
++ __ movL_OR_Q(rbx_method, Address(rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes()));
++ __ verify_oop(rbx_method);
++ // same as TemplateTable::invokestatic or invokespecial,
++ // minus the CP setup and profiling:
++ if (ek == _invokespecial_mh) {
++ // Must load & check the first argument before entering the target method.
++ __ movl(rax_argslot, Address(rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes()));
++ __ movL_OR_Q(rcx_recv, argument_address(rsi_savedsp, rax_argslot));
++ __ null_check(rcx_recv);
++ __ verify_oop(rcx_recv);
++ }
++ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
+ }
-+ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
+ break;
+
+ case _invokebound_mh:
+ {
++ Register rbx_method = rbx_index;
+ __ movL_OR_Q(rbx_method, Address(rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes()));
+ __ verify_oop(rbx_method);
+ // replace MH with bound receiver (or first static argument):
++ __ movl(rax_argslot, Address(rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes()));
+ __ movL_OR_Q(rcx_recv, Address(rcx_recv, java_dyn_MethodHandle::receiver_offset_in_bytes()));
-+ Address recv_arg_slot = find_mh_argument(_masm, rax_mtype, rsi_savedsp, -1, rax_mtype);
-+ __ movL_OR_Q(recv_arg_slot, rcx_recv);
++ __ movL_OR_Q(argument_address(rsi_savedsp, rax_argslot), rcx_recv);
+ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
+ }
+ break;
+
+ case _invokevirtual_mh:
+ {
-+ Register rbx_index = rbx_method;
-+ Register rax_klass = rax_mtype;
-+
+ // same as TemplateTable::invokevirtual,
+ // minus the CP setup and profiling:
+
-+ // pick out the vtable index from the MH, and then we can discard it:
-+ __ movL_OR_Q(rbx_index, Address(rcx_recv, java_dyn_MethodHandle::vmdata_offset_in_bytes()));
-+
-+ __ movL_OR_Q(rcx_recv, find_mh_argument(_masm, rax_mtype, rsi_savedsp, 0, rcx_recv));
++ // pick out the vtable index and receiver offset from the MH,
++ // and then we can discard it:
++ __ movl(rax_argslot, Address(rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes()));
++ __ movl(rbx_index, Address(rcx_recv, java_dyn_MethodHandle::vmdata_index_offset_in_bytes()));
++ __ movL_OR_Q(rcx_recv, argument_address(rsi_savedsp, rax_argslot));
+ __ null_check(rcx_recv, oopDesc::klass_offset_in_bytes());
+
+ // get receiver klass
++ Register rax_klass = rax_argslot;
+ __ movl(rax_klass, Address(rcx_recv, oopDesc::klass_offset_in_bytes()));
+ __ verify_oop(rax_klass);
+
+ // get target methodOop & entry point
+ const int base = instanceKlass::vtable_start_offset() * wordSize;
+ assert(vtableEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
++ Register rbx_method = rbx_index;
+ __ movl(rbx_method, Address(rax_klass, rbx_index, Address::times_wordSize, base + vtableEntry::method_offset_in_bytes()));
+
+ __ verify_oop(rbx_method);
@@ -3770,24 +6305,29 @@ new file mode 100644
+
+ // pick out the interface and itable index from the MH.
+ Register rdx_intf = rdx_temp;
-+ Register rbx_index = rbx_method;
-+
-+ __ movL_OR_Q(rdx_intf, Address(rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes()));
-+ __ movL_OR_Q(rbx_index, Address(rcx_recv, java_dyn_MethodHandle::vmdata_offset_in_bytes()));
-+
-+ __ movL_OR_Q(rcx_recv, find_mh_argument(_masm, rax_mtype, rsi_savedsp, 0, rcx_recv));
-+
-+ // Free up some temps.
++
++ __ movL_OR_Q(rdx_intf, Address(rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes()));
++ __ movl(rax_argslot, Address(rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes()));
++ __ movl(rbx_index, Address(rcx_recv, java_dyn_MethodHandle::vmdata_index_offset_in_bytes()));
++ __ movL_OR_Q(rcx_recv, argument_address(rsi_savedsp, rax_argslot));
++ __ null_check(rcx_recv, oopDesc::klass_offset_in_bytes());
++
++ // get receiver klass
++ Register rax_klass = rax_argslot;
++ __ movl(rax_klass, Address(rcx_recv, oopDesc::klass_offset_in_bytes()));
++ __ verify_oop(rax_klass);
++
++ // Free up another temp.
+ __ pushl(rcx_recv);
-+
-+ // get receiver klass
-+ __ movl(rcx, Address(rcx_recv, oopDesc::klass_offset_in_bytes()));
-+ __ verify_oop(rcx);
++ Register rcx_temp = rcx_recv;
++ Register rbx_method = rbx_index;
+
+ // get interface klass
+ Label no_such_interface;
-+ __ lookup_interface_method(rcx, rdx_intf, rbx_index,
-+ rbx_method, rax,
++ __ lookup_interface_method(rax_klass, rdx_intf,
++ // note: next two args must be the same:
++ rbx_index, rbx_method,
++ rcx_temp,
+ no_such_interface);
+
+ __ popl(rcx_recv); // restore saved receiver
@@ -3803,6 +6343,135 @@ new file mode 100644
+ }
+ break;
+
++ case _adapter_mh_first+_adapt_retype_only:
++ case _adapter_mh_first+_adapt_drop_initial:
++ case _adapter_mh_first+_adapt_drop_final:
++ {
++ AdapterKind ak = AdapterKind(ek - _adapter_mh_first);
++ if (ak == _adapt_drop_final) {
++ // 'argslot' is number of slots to drop
++ // this is also the rightmost (shallowest) kept argument slot
++ __ movl(rax_argslot, Address(rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes()));
++ Address arg = argument_address(rsi_savedsp, rax_argslot);
++ __ leal(rsi_savedsp, arg); // pop some arguments
++ }
++
++ // immediately jump to the next MH layer:
++ __ movL_OR_Q(rcx_recv, Address(rcx_recv, java_dyn_MethodHandle::receiver_offset_in_bytes()));
++ jump_to_entry(_masm, rcx_recv, rdx_temp);
++ // This is OK when all parameter types widen.
++ // It is also OK when a return type narrows.
++ // Finally, we can simply ignore leading arguments from here on,
++ // without touching the stack.
++ }
++ break;
++
++ case _adapter_mh_first+_adapt_extend_sign:
++ case _adapter_mh_first+_adapt_extend_zero:
++ case _adapter_mh_first+_adapt_test_boolean:
++ {
++ AdapterKind ak = AdapterKind(ek - _adapter_mh_first);
++ // check an argument, or perform a simple in-place conversion,
++ // before jumping to the next layer of MH:
++ __ movl(rax_argslot, Address(rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes()));
++ if (ak == _adapt_extend_zero || ak == _adapt_extend_sign)
++ __ movl(rbx_index, Address(rcx_recv, java_dyn_MethodHandle::vmdata_index_offset_in_bytes()));
++ Address arg = argument_address(rsi_savedsp, rax_argslot);
++
++ // get the new MH:
++ __ movL_OR_Q(rcx_recv, Address(rcx_recv, java_dyn_MethodHandle::receiver_offset_in_bytes()));
++ // (now we are done with the old MH)
++
++ if (ak == _adapt_test_boolean) {
++ // convert a 32-bit integer value into a one-bit subword, C-style
++ __ cmpl(arg, (jint)0);
++ Label skip;
++ __ jccb(Assembler::equal, skip);
++ __ movL_OR_Q(arg, (jint)1);
++ __ bind(skip);
++
++ } else {
++ // original 32-bit vmdata word must be of this form:
++ // | argumentNumber:16 | conversion:8 | lowBitCount:8 |
++ __ xchgl(rcx, rbx_index); // free rcx for shifts
++ __ shrl(rcx, 8); // shift in 2nd LSB
++ __ negl(rcx); // left shift by 32-lowBitCount
++ __ movL_OR_Q(rdx_temp, arg);
++ __ shll(rdx_temp /*, rcx*/);
++ if (ak == _adapt_extend_sign) {
++ // this path is taken for int->byte, int->short
++ __ sarl(rdx_temp /*, rcx*/);
++ } else if (ak == _adapt_extend_zero) {
++ // this is taken for int->char
++ __ shrl(rdx_temp /*, rcx*/);
++ } else {
++ ShouldNotReachHere();
++ }
++ __ movL_OR_Q(arg, rdx_temp);
++ __ xchgl(rcx, rbx_index); // restore rcx_recv
++ }
++
++ jump_to_entry(_masm, rcx_recv, rdx_temp);
++ }
++ break;
++
++ case _adapter_mh_first+_adapt_check_cast:
++ {
++ // temps:
++ Register rbx_klass = rbx_index; // interesting AMH data
++
++ // check an argument, or perform a simple in-place conversion,
++ // before jumping to the next layer of MH:
++ __ movl(rax_argslot, Address(rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes()));
++ Address arg = argument_address(rsi_savedsp, rax_argslot);
++
++ // What class are we casting to?
++ __ movL_OR_Q(rbx_klass, Address(rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes()));
++
++ // get the new MH:
++ __ movL_OR_Q(rcx_recv, Address(rcx_recv, java_dyn_MethodHandle::receiver_offset_in_bytes()));
++ // (now we are done with the old MH)
++
++ Label done;
++ __ movL_OR_Q(rdx_temp, arg);
++ __ testl(rdx_temp, rdx_temp);
++ __ jcc(Assembler::zero, done); // no cast if null
++ __ movl(rdx_temp, Address(rdx_temp, oopDesc::klass_offset_in_bytes()));
++
++ // live at this point:
++ // - rbx_klass: klass required by the target method
++ // - rdx_temp: argument klass to test
++ // - rcx_recv: method handle to invoke (after cast succeeds)
++ __ check_klass_subtype(rdx_temp, rbx_klass, rax_argslot, done);
++
++ // If we get here, the type check failed!
++ // Call the wrong_method_type stub, passing the failing argument type in rax.
++ Register rax_mtype = rax_argslot;
++#if 0
++ __ pushl(rbx_klass); // missed klass (required)
++ __ pushl(rdx_temp); // bad object (actual)
++ __ jump(ExternalAddress(Interpreter::_throw_WrongMethodType_entry));
++#else
++ __ movl(rax_mtype, rbx_klass); // missed klass (required)
++ __ movl(rcx_recv, rdx_temp); // bad object (actual)
++ __ movptr(rdx_temp, ExternalAddress((address) &_entries[_wrong_method_type]));
++ __ jmp(Address(rdx_temp, MethodEntry::from_interpreted_entry_offset_in_bytes()));
++#endif
++
++ __ bind(done);
++ jump_to_entry(_masm, rcx_recv, rdx_temp);
++ }
++ break;
++
++ case _adapter_mh_first+_adapt_swap_argument:
++ case _adapter_mh_first+_adapt_push_argument:
++ case _adapter_mh_first+_adapt_push_primitive:
++ case _adapter_mh_first+_adapt_push_reference:
++ case _adapter_mh_first+_adapt_ricochet:
++ case _adapter_mh_first+_adapt_flyby:
++ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
++ break;
++
+ default: ShouldNotReachHere();
+ }
+ __ hlt();
@@ -3813,52 +6482,42 @@ new file mode 100644
+ init_entry(ek, MethodEntry::finish_compiled_entry(_masm, me_cookie));
+}
+
-+// If which_argument is 0, picks out the first argument being passed to the MH,
-+// which will be the receiver if the MH is for a non-static method.
-+// If which_argument is -1, picks out the stacked method handle itself,
-+// which can be overwritten by a bound receiver (for a BMH only).
-+//
-+// Register arguments:
-+// mtype_reg - the type of the current call
-+// savedsp_reg - address of the argument stack (points to _last_ argument)
-+// addr_temp_reg - temporary used to form the result address (can be mtype_reg)
-+Address MethodHandle::find_mh_argument(MacroAssembler* _masm,
-+ Register mtype_reg,
-+ Register savedsp_reg,
-+ int which_argument,
-+ Register addr_temp_reg) {
-+ assert_different_registers(mtype_reg, savedsp_reg);
-+ assert_different_registers(savedsp_reg, addr_temp_reg);
-+
-+ __ movl(addr_temp_reg, Address(mtype_reg, java_dyn_MethodType::form_offset_in_bytes()));
-+
-+ // The vmdata contains the number of parameter slots
-+ // in the interpreter stack for this kind of call (see MTForm.init).
-+ __ movl(addr_temp_reg, Address(addr_temp_reg, java_dyn_MethodType::Form::vmdata_offset_in_bytes()));
-+
-+#ifdef ASSERT
-+ if (which_argument >= 0) {
-+ Label L;
-+ __ testl(addr_temp_reg, addr_temp_reg);
-+ __ jccb(Assembler::notZero, L);
-+ __ stop("zero parameter count; cannot find receiver");
-+ __ bind(L);
-+ }
-+#endif
-+
++Address MethodHandle::argument_address(Register savedsp_reg, RegisterConstant arg_slot) {
+ // cf. TemplateTable::prepare_invoke(), if (load_receiver).
-+ int offset = -Interpreter::expr_offset_in_bytes(which_argument + 1);
-+ return Address(savedsp_reg, addr_temp_reg,
-+ Interpreter::stackElementScale(), offset);
-+}
-+
-+
++ int stackElementSize = Interpreter::stackElementWords() * wordSize;
++ int offset = Interpreter::expr_offset_in_bytes(0);
++ int offset1 = Interpreter::expr_offset_in_bytes(1);
++ assert(offset1 - offset == stackElementSize, "correct arithmetic");
++ 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);
++ }
++ return Address(savedsp_reg, scale_reg, scale_factor, offset);
++}
++
++int MethodHandle::argument_slot(oop method_type, int arg) {
++ objArrayOop ptypes = java_dyn_MethodType::ptypes(method_type);
++ int result = 0;
++ for (int i = arg+1, imax = ptypes->length(); i < imax; i++) {
++ oop ptype = ptypes->obj_at(i);
++ BasicType bt = T_OBJECT;
++ if (java_lang_Class::is_primitive(ptype))
++ bt = java_lang_Class::primitive_type(ptype);
++ result += type2size[bt];
++ }
++ return result;
++}
+
+// direct method handles
+JVM_ENTRY(void, MH_init_DMH(JNIEnv *env, jobject igcls, jobject mh_jh, jobject rmethod_jh, jboolean do_dispatch)) {
+ ResourceMark rm; // for error messages
+
+ // This is the guy we are initializing:
++ if (mh_jh == NULL) return;
+ Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh));
+
+ // Early returns out of this method leave the DMH in an unfinished state.
@@ -3871,6 +6530,8 @@ new file mode 100644
+ MethodHandle::decode_method(JNIHandles::resolve(rmethod_jh),
+ decode_flags));
+ if (m.is_null()) return; // robustness
++
++ int argslot = m->size_of_parameters() - 1; // pos. of 1st arg.
+
+ // The privileged code which invokes this routine should not make
+ // a mistake about types, but it's better to verify.
@@ -3897,14 +6558,15 @@ new file mode 100644
+ // Set up same bits as ConstantPoolCacheEntry::set_interface_call().
+ klassOop interf = m->method_holder();
+ java_dyn_MethodHandle::set_vmref(mh(), interf);
-+ java_dyn_MethodHandle::set_vmdata_int(mh(), index);
++ java_dyn_MethodHandle::set_vmdata(mh(), index, argslot);
+ me = MethodHandle::entry(MethodHandle::_invokeinterface_mh);
+ } else if (!do_dispatch || m->can_be_statically_bound()) {
+ // We are simulating an invokestatic or invokespecial instruction.
+ // Set up the method pointer, just like ConstantPoolCacheEntry::set_method().
+ java_dyn_MethodHandle::set_vmref(mh(), m());
-+ // this does not help dispatch, but it will make it possible to parse this MH:
-+ java_dyn_MethodHandle::set_vmdata_int(mh(), methodOopDesc::nonvirtual_vtable_index);
++ // this does not help dispatch, but it will make it possible to parse this MH:
++ int index = methodOopDesc::nonvirtual_vtable_index;
++ java_dyn_MethodHandle::set_vmdata(mh(), index, m->is_static() ? -1 : argslot);
+ if (m->is_static())
+ me = MethodHandle::entry(MethodHandle::_invokestatic_mh);
+ else
@@ -3915,8 +6577,7 @@ new file mode 100644
+ // The key logic is LinkResolver::runtime_resolve_virtual_method.
+ int index = m->vtable_index();
+ assert(index >= 0, "");
-+ java_dyn_MethodHandle::set_vmdata_int(mh(), index);
-+ // this does not help dispatch, but it will make decode_method happy:
++ java_dyn_MethodHandle::set_vmdata(mh(), index, argslot);
+ java_dyn_MethodHandle::set_vmref(mh(), m());
+ me = MethodHandle::entry(MethodHandle::_invokevirtual_mh);
+ }
@@ -3934,6 +6595,7 @@ new file mode 100644
+ ResourceMark rm; // for error messages
+
+ // This is the guy we are initializing:
++ if (mh_jh == NULL) return;
+ Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh));
+
+ // Early returns out of this method leave the BMH in an unfinished state.
@@ -3963,7 +6625,7 @@ new file mode 100644
+ true, recv_klass->as_klassOop(), CHECK);
+
+ MethodEntry* me = NULL;
-+ //java_dyn_MethodHandle::set_vmdata_int(mh(), 0);
++ //java_dyn_MethodHandle::set_vmdata(mh(), 0, 0);
+ if ((decode_flags & MethodHandle::_dmf_does_dispatch) == 0) {
+ // copy contents of target DMH, which is pre-dispatched
+ java_dyn_MethodHandle::set_vmref(mh(), m());
@@ -3974,7 +6636,7 @@ new file mode 100644
+ if (!recv_klass->is_subtype_of(m->method_holder()))
+ return; // caller should check, but...
+
-+ int vtable_index = java_dyn_MethodHandle::vmdata_int(mh());
++ int vtable_index = java_dyn_MethodHandle::vmdata_index(mh());
+ guarantee(vtable_index >= 0, "valid vtable index");
+
+ // recv_klass might be an arrayKlassOop but all vtables start at
@@ -3984,7 +6646,7 @@ new file mode 100644
+ DEBUG_ONLY(inst->verify_vtable_index(vtable_index));
+ methodOop disp_m = inst->method_at_vtable(vtable_index);
+ if (disp_m->is_abstract())
-+ THROW_OOP(vmSymbols::java_lang_AbstractMethodError());
++ THROW(vmSymbols::java_lang_AbstractMethodError());
+ java_dyn_MethodHandle::set_vmref(mh(), disp_m);
+
+ } else {
@@ -3993,7 +6655,7 @@ new file mode 100644
+ if (!recv_klass->is_subtype_of(m->method_holder()))
+ return; // caller should check, but...
+
-+ int itable_index = java_dyn_MethodHandle::vmdata_int(mh());
++ int itable_index = java_dyn_MethodHandle::vmdata_index(mh());
+ guarantee(itable_index >= 0, "valid itable index");
+
+ instanceKlass* inst = instanceKlass::cast(recv_klass());
@@ -4010,8 +6672,55 @@ new file mode 100644
+JVM_END
+
+// adapter method handles
-+JVM_ENTRY(void, MH_init_AMH(JNIEnv *env, jobject igcls, jobject mh_jh)) {
-+ tty->print_cr("*** NYI: AMH");
++JVM_ENTRY(void, MH_init_AMH(JNIEnv *env, jobject igcls, jobject mh_jh,
++ int argslot, int conversion, jobject vmref_jh)) {
++ MethodHandle::AdapterKind ak = MethodHandle::AdapterKind(conversion & MethodHandle::_AK_MASK);
++ if (ak < MethodHandle::_adapt_retype_only || ak > MethodHandle::_AK_LIMIT)
++ return; // bad data
++
++ // adjust the adapter code to the internal EntryKind enumeration:
++ conversion += MethodHandle::_adapter_mh_first;
++
++ assert((conversion & ~MethodHandle::_AK_MASK) == 0
++ || ak == MethodHandle::_adapt_extend_sign
++ || ak == MethodHandle::_adapt_extend_zero
++ || ak == MethodHandle::_adapt_swap_argument
++ || ak == MethodHandle::_adapt_push_argument
++ || ak == MethodHandle::_adapt_ricochet,
++ "optional fields must be zero, or adapter must take an optional argument");
++
++ switch (ak) {
++ case MethodHandle::_adapt_swap_argument:
++ case MethodHandle::_adapt_push_argument:
++ case MethodHandle::_adapt_push_primitive:
++ case MethodHandle::_adapt_push_reference:
++ case MethodHandle::_adapt_ricochet:
++ case MethodHandle::_adapt_flyby:
++ // FIXME: these adapters are NYI
++ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), MethodHandle::adapter_entry_name(ak));
++ }
++
++ // This is the guy we are initializing:
++ if (mh_jh == NULL) return;
++ Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh));
++
++ java_dyn_MethodHandle::set_vmdata(JNIHandles::resolve_non_null(mh_jh),
++ conversion, argslot);
++
++ if (vmref_jh != NULL) {
++ oop vmref = JNIHandles::resolve_non_null(vmref_jh);
++ if (java_lang_Class::is_instance(vmref))
++ vmref = java_lang_Class::as_klassOop(vmref);
++ java_dyn_MethodHandle::set_vmref(mh(), vmref);
++ }
++
++ // Done!
++ MethodHandle::EntryKind ek = MethodHandle::EntryKind(MethodHandle::_adapter_mh_first + (int)ak);
++ java_dyn_MethodHandle::set_entry(mh(), MethodHandle::entry(ek));
++
++ // 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.
+}
+JVM_END
+
@@ -4040,14 +6749,27 @@ new file mode 100644
+ int junk;
+ methodHandle m(THREAD, MethodHandle::decode_method(JNIHandles::resolve(mh_jh), junk));
+ if (m.is_null()) return NULL;
-+ Handle str = java_lang_String::create_from_symbol(m->name(), CHECK_NULL);
-+ return JNIHandles::make_local(THREAD, str());
++ oop str_oop = StringTable::intern(m->name(), CHECK_NULL);
++ return JNIHandles::make_local(THREAD, str_oop);
+}
+JVM_END
+
+
-+JVM_ENTRY(void, MH_initDMHclasses(JNIEnv *env, jobject igcls, jobjectArray class_array)) {
-+ //FIXME: NYI
++JVM_ENTRY(jobject, MH_vmref(JNIEnv *env, jobject igcls, jobject mh_jh)) {
++ int junk;
++ if (mh_jh == NULL) return NULL;
++ oop vmref = MethodHandle::decode_vmref(JNIHandles::resolve(mh_jh), junk);
++ return JNIHandles::make_local(THREAD, vmref);
++}
++JVM_END
++
++
++JVM_ENTRY(void, MH_linkCallSite(JNIEnv *env, jobject igcls, jobject site_jh, jobject target_jh)) {
++ // No special action required, yet.
++ oop site_oop = JNIHandles::resolve(site_jh);
++ if (site_oop == NULL || site_oop->klass() != SystemDictionary::dyn_impl_DynCallSite_klass())
++ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "call site");
++ java_dyn_impl_DynCallSite::set_target(site_oop, JNIHandles::resolve(target_jh));
+}
+JVM_END
+
@@ -4069,18 +6791,20 @@ new file mode 100644
+#define DMH DYNI"DMH;"
+#define MT DYNP"MethodType;"
+#define MTFM DYNI"MTForm;"
++#define DCST DYNI"DynCallSite;"
+
+#define CC (char*) /*cast a literal from (const char*)*/
+#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
+
+// These are the correct methods, moving forward:
+static JNINativeMethod methods[] = {
-+ {CC"init", CC"("AMH")V", FN_PTR(MH_init_AMH)},
++ {CC"init", CC"("AMH"II"OBJ")V", FN_PTR(MH_init_AMH)},
+ {CC"init", CC"("BMH OBJ OBJ")V", FN_PTR(MH_init_BMH)},
+ {CC"init", CC"("DMH OBJ"Z)V", FN_PTR(MH_init_DMH)},
+ {CC"init", CC"("MTFM MT")V", FN_PTR(MH_init_MTForm)},
-+ {CC"methodName", CC"("MH")"STRG, FN_PTR(MH_methodName)},
-+ {CC"initDMHclasses", CC"(["CLS")V", FN_PTR(MH_initDMHclasses)},
++ {CC"getMethodName", CC"("MH")"STRG, FN_PTR(MH_methodName)},
++ {CC"getVMRef", CC"("MH")"OBJ, FN_PTR(MH_vmref)},
++ {CC"linkCallSite", CC"("DCST MH")V", FN_PTR(MH_linkCallSite)}
+};
+
+
@@ -4103,7 +6827,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/vm/prims/methodHandles.hpp
-@@ -0,0 +1,177 @@
+@@ -0,0 +1,205 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -4137,6 +6861,24 @@ new file mode 100644
+ // in java.dyn and java.dyn.hotspot.
+ // See also javaClasses for layouts java_dyn_Method{Handle,Type,Type::Form}.
+ public:
++ enum AdapterKind {
++ // these constants must align with a set of values in java/dyn/impl/AMH.java:
++ _adapt_retype_only = 0, // retype with no argument changes
++ _adapt_drop_initial, // pass through after ignoring deep stack
++ _adapt_drop_final, // pass through after popping shallow stack
++ _adapt_check_cast, // pass through with one argument checkcast
++ _adapt_extend_sign, // mask an argument down to a subword type
++ _adapt_extend_zero, // mask an argument down to a subword type
++ _adapt_test_boolean, // zero-test an argument down to a boolean 1/0
++ _adapt_swap_argument, // swap two arguments (or two pairs)
++ _adapt_push_argument, // push copy of existing argument (or pair)
++ _adapt_push_primitive, // push a primitive constant (from a wrapper)
++ _adapt_push_reference, // push a reference parameter
++ _adapt_ricochet, // make a call, then another call on return value
++ _adapt_flyby, // make a call on reified arglist, then make another call
++ _AK_LIMIT,
++ _AK_MASK = 0xFF
++ };
+ enum EntryKind {
+ _check_mtype, // how a caller calls a MH
+ _wrong_method_type, // what happens when there is a type mismatch
@@ -4145,6 +6887,10 @@ new file mode 100644
+ _invokevirtual_mh,
+ _invokeinterface_mh,
+ _invokebound_mh, // invokespecial, with a saved receiver
++
++ _adapter_mh_first, // adapter sequence goes here...
++ _adapter_mh_last = _adapter_mh_first + (_AK_LIMIT - 1),
++
+ _EK_LIMIT,
+ _EK_FIRST = 0
+ };
@@ -4152,6 +6898,7 @@ new file mode 100644
+ static MethodEntry* _entries[_EK_LIMIT];
+ static const char* _entry_names[_EK_LIMIT];
+ static bool ek_valid(EntryKind ek) { return (uint)ek < (uint)_EK_LIMIT; }
++ static bool ak_valid(AdapterKind ak) { return (uint)ak < (uint)_AK_LIMIT; }
+
+ public:
+ static bool have_entry(EntryKind ek) { return ek_valid(ek) && _entries[ek] != NULL; }
@@ -4159,6 +6906,8 @@ new file mode 100644
+ return _entries[ek]; }
+ static const char* entry_name(EntryKind ek) { assert(ek_valid(ek), "oob");
+ return _entry_names[ek]; }
++ static const char* adapter_entry_name(AdapterKind ak) { assert(ak_valid(ak), "oob");
++ return entry_name(EntryKind(_adapter_mh_first + (int)ak)); }
+
+ static void init_entry(EntryKind ek, MethodEntry* me) {
+ assert(ek_valid(ek), "oob");
@@ -4175,22 +6924,25 @@ new file mode 100644
+ static void generate_method_handle_stub(MacroAssembler* _masm, EntryKind ek);
+
+ // Lower level calls:
-+ static void check_method_type(MacroAssembler* _masm, Register mtype_reg, Register recv_reg, Label& wrong_method_type);
-+ static void jump_to_entry(MacroAssembler* _masm, Register recv_reg, Register temp_reg);
-+ static Address find_mh_argument(MacroAssembler* _masm,
-+ Register mtype_reg,
-+ Register savedsp_reg,
-+ int which_argument,
-+ Register addr_temp_reg);
++ static void check_method_type(MacroAssembler* _masm,
++ Register mtype_reg, Register recv_reg, Register temp_reg,
++ Label& wrong_method_type);
++ static void jump_to_entry(MacroAssembler* _masm,
++ Register recv_reg, Register temp_reg);
++
++ static Address argument_address(Register savedsp_reg, RegisterConstant arg_slot);
++ static int argument_slot(oop method_type, int arg);
+
+ // Runtime support
-+ enum { // bit-encoded flags from decode_method
-+ _dmf_does_dispatch = 1, // method handle performs virtual or interface dispatch
-+ _dmf_is_interface = 2, // peforms interface dispatch
-+ _dmf_has_receiver = 4,
-+ _dmf_has_casts = 8
++ enum { // bit-encoded flags from decode_method or decode_vmref
++ _dmf_does_dispatch = 0x01, // method handle performs virtual or interface dispatch
++ _dmf_is_interface = 0x02, // peforms interface dispatch
++ _dmf_has_receiver = 0x04,
++ _dmf_has_klass = 0x08,
++ _dmf_has_casts = 0x10
+ };
+ static methodOop decode_method(oop x, int& decode_flags_result);
++ static oop decode_vmref(oop x, int& decode_flags_result);
+ static bool class_cast_needed(klassOop src, klassOop dst);
+
+ static void verify_method_type(methodHandle m,
@@ -4302,6 +7054,17 @@ diff --git a/src/share/vm/prims/nativeLo
}
if (strstr(jni_name, "Java_sun_misc_Perf_registerNatives") != NULL) {
return CAST_FROM_FN_PTR(address, JVM_RegisterPerfMethods);
+diff --git a/src/share/vm/runtime/frame.hpp b/src/share/vm/runtime/frame.hpp
+--- a/src/share/vm/runtime/frame.hpp
++++ b/src/share/vm/runtime/frame.hpp
+@@ -267,7 +267,6 @@
+ intptr_t* interpreter_frame_tos_at(jint offset) const;
+ intptr_t* interpreter_frame_tos_address() const;
+
+-
+ jint interpreter_frame_expression_stack_size() const;
+
+ intptr_t* interpreter_frame_sender_sp() const;
diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp
--- a/src/share/vm/runtime/globals.hpp
+++ b/src/share/vm/runtime/globals.hpp
@@ -4324,6 +7087,24 @@ diff --git a/src/share/vm/runtime/global
product(bool, TaggedStackInterpreter, false, \
"Insert tags in interpreter execution stack for oopmap generaion")\
\
+diff --git a/src/share/vm/runtime/handles.hpp b/src/share/vm/runtime/handles.hpp
+--- a/src/share/vm/runtime/handles.hpp
++++ b/src/share/vm/runtime/handles.hpp
+@@ -137,6 +137,14 @@
+ assert(is_null() || obj()->is_klass(), "not a klassOop");
+ }
+
++ // Direct interface, use very sparingly.
++ // Used by KlassHandles to create handles on existing WKKs in SystemDictionary.
++ // The obj of such a klass handle may be null, because the handle is formed
++ // during system bootstrapping.
++ KlassHandle(klassOop *handle, bool dummy) : Handle((oop*)handle, dummy) {
++ assert(SharedSkipVerify || is_null() || obj() == NULL || obj()->is_klass(), "not a klassOop");
++ }
++
+ // General access
+ klassOop operator () () const { return obj(); }
+ Klass* operator -> () const { return as_klass(); }
diff --git a/src/share/vm/runtime/sharedRuntime.cpp b/src/share/vm/runtime/sharedRuntime.cpp
--- a/src/share/vm/runtime/sharedRuntime.cpp
+++ b/src/share/vm/runtime/sharedRuntime.cpp
@@ -4384,26 +7165,81 @@ diff --git a/src/share/vm/runtime/shared
int bytecode_index = bytecode->index();
// Find receiver for non-static call
-@@ -1479,6 +1438,19 @@
- Klass* targetKlass = Klass::cast(vfst.method()->constants()->klass_at(
- cc->index(), thread));
+@@ -1481,9 +1440,72 @@
return generate_class_cast_message(objName, targetKlass->external_name());
-+}
-+
+ }
+
+char* SharedRuntime::generate_wrong_method_type_message(JavaThread* thread,
-+ oopDesc* mtype, oopDesc* mhandle) {
-+
-+#if 0
-+ // Get target class name from the invokevirtual instruction
-+ vframeStream vfst(thread, true);
-+ assert(!vfst.at_end(), "Java frame must exist");
-+ Bytecode_invoke* inv = Bytecode_invoke_at(vfst.method()->bcp_from(vfst.bci()));
-+ methodOop m = inv->static_receiver();
-+#endif
-+ return (char*)"(message NYI)";
- }
-
++ oopDesc* required,
++ oopDesc* actual) {
++ assert(InvokeDynamic, "");
++ 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(actual->klass())->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();
++ }
++ }
++ int ignore;
++ methodOop actual_method = MethodHandle::decode_method(actual, ignore);
++ 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 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);
diff --git a/src/share/vm/runtime/sharedRuntime.hpp b/src/share/vm/runtime/sharedRuntime.hpp
--- a/src/share/vm/runtime/sharedRuntime.hpp
+++ b/src/share/vm/runtime/sharedRuntime.hpp
@@ -4417,30 +7253,44 @@ diff --git a/src/share/vm/runtime/shared
static void register_finalizer(JavaThread* thread, oopDesc* obj);
// dtrace notifications
-@@ -204,6 +201,23 @@
- * in order to correctly free the result.
- */
+@@ -206,6 +203,27 @@
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
-+ * @param mhandle (optional) actual method handle (of wrong type)
++ * @param mtype (optional) expected method type (or argument class)
++ * @param mhandle (optional) actual method handle (or argument)
+ * @return the dynamically allocated exception message
+ *
-+ * BCP must refer to the current 'invokevirtual' opcode for the frame
-+ * on top of the stack.
-+ * The caller (or one of it's callers) must use a ResourceMark
++ * 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
+@@ -218,7 +236,8 @@
+ * 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.
diff --git a/src/share/vm/utilities/accessFlags.hpp b/src/share/vm/utilities/accessFlags.hpp
--- a/src/share/vm/utilities/accessFlags.hpp
+++ b/src/share/vm/utilities/accessFlags.hpp
@@ -4562,6 +7412,41 @@ diff --git a/src/share/vm/utilities/arra
void appendAll(const stack_name* stack) { push_all(stack); } \
etype last() const { return top(); } \
}; \
+diff --git a/src/share/vm/utilities/globalDefinitions.hpp b/src/share/vm/utilities/globalDefinitions.hpp
+--- a/src/share/vm/utilities/globalDefinitions.hpp
++++ b/src/share/vm/utilities/globalDefinitions.hpp
+@@ -574,7 +574,7 @@
+ inline TosState as_TosState(BasicType type) {
+ switch (type) {
+ case T_BYTE : return btos;
+- case T_BOOLEAN: return btos;
++ case T_BOOLEAN: return btos; // FIXME: Add ztos
+ case T_CHAR : return ctos;
+ case T_SHORT : return stos;
+ case T_INT : return itos;
+@@ -586,6 +586,22 @@
+ case T_OBJECT : return atos;
+ }
+ return ilgl;
++}
++
++inline BasicType as_BasicType(TosState state) {
++ switch (state) {
++ //case ztos: return T_BOOLEAN;//FIXME
++ case btos : return T_BYTE;
++ case ctos : return T_CHAR;
++ case stos : return T_SHORT;
++ case itos : return T_INT;
++ case ltos : return T_LONG;
++ case ftos : return T_FLOAT;
++ case dtos : return T_DOUBLE;
++ case atos : return T_ARRAY;
++ case vtos : return T_VOID;
++ }
++ return T_ILLEGAL;
+ }
+
+
diff --git a/src/share/vm/utilities/growableArray.hpp b/src/share/vm/utilities/growableArray.hpp
--- a/src/share/vm/utilities/growableArray.hpp
+++ b/src/share/vm/utilities/growableArray.hpp