--- a/meth.patch Tue Aug 26 03:01:02 2008 -0700
+++ b/meth.patch Fri Aug 29 15:14:28 2008 -0700
@@ -23,7 +23,7 @@ diff --git a/src/cpu/sparc/vm/cppInterpr
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);
++ const int extra_stack = methodOopDesc::extra_stack();
+ return (round_to(max_stack +
+ extra_stack +
slop_factor +
@@ -34,7 +34,7 @@ diff --git a/src/cpu/sparc/vm/cppInterpr
// 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);
++ int extra_stack = methodOopDesc::extra_stack();
+ to_fill->_stack_limit = stack_base - (method->max_stack() + 1 + extra_stack);
to_fill->_monitor_base = (BasicObjectLock*) monitor_base;
@@ -234,7 +234,7 @@ diff --git a/src/cpu/sparc/vm/templateIn
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 extra_stack = methodOopDesc::extra_stack();
+ const int max_stack_words = (max_stack + extra_stack) * Interpreter::stackElementWords();
return (round_to((max_stack_words
+ rounded_vm_local_words
@@ -300,7 +300,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
} else {
InstructionMark im(this);
L.add_patch_at(code(), locator());
-@@ -4702,6 +4702,157 @@
+@@ -4702,6 +4702,189 @@
}
@@ -455,6 +455,38 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+}
+
+
++// registers on entry:
++// - rax ('check' register): required MethodType
++// - rcx: method handle
++// - rdx, rsi, or ?: killable temp
++void MacroAssembler::check_method_handle_type(Register mtype_reg, Register mh_reg,
++ Register temp_reg,
++ Label& wrong_method_type) {
++ // compare method type against that of the receiver
++ cmpl(mtype_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg)));
++ jcc(Assembler::notEqual, wrong_method_type);
++}
++
++
++// registers on entry:
++// - rcx: method handle
++// - rdx: killable temp (interpreted only)
++// - rax: killable temp (compiled only)
++void MacroAssembler::jump_to_method_handle_entry(Register mh_reg, Register temp_reg) {
++ assert(mh_reg == rcx, "caller must put MH object in rcx");
++ assert_different_registers(mh_reg, temp_reg);
++
++ // pick out the interpreted side of the handler
++ movptr(temp_reg, Address(mh_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()));
++
++ // for the various stubs which take control at this point,
++ // see MethodHandle::generate_method_handle_stub
++}
++
++
int MacroAssembler::biased_locking_enter(Register lock_reg, Register obj_reg, Register swap_reg, Register tmp_reg,
bool swap_reg_contains_mark,
Label& done, Label* slow_case,
@@ -558,7 +590,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
private:
bool base_needs_rex() const {
-@@ -1287,6 +1346,29 @@
+@@ -1287,6 +1346,35 @@
);
void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case);
@@ -571,13 +603,19 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ 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
-+ RegisterConstant itable_index, // can be rbx
-+ Register method_result, // usually rbx
-+ Register scan_temp, // rdi or rdx
++ // interface method calling
++ void lookup_interface_method(Register recv_klass,
++ Register intf_klass,
++ RegisterConstant itable_index,
++ Register method_result,
++ Register scan_temp,
+ Label& no_such_interface);
++
++ // method handles (JSR 292)
++ void check_method_handle_type(Register mtype_reg, Register mh_reg,
++ Register temp_reg,
++ Label& wrong_method_type);
++ void jump_to_method_handle_entry(Register mh_reg, Register temp_reg);
+
+ // klass type checking (falls through on failure)
+ void check_klass_subtype(Register sub_klass,
@@ -587,6 +625,183 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+
//----
void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0
+
+@@ -1464,6 +1552,23 @@
+ void movoop(Register dst, jobject obj);
+ void movoop(Address dst, jobject obj);
+
++ void movptr(Register dst, Register src) {
++ LP64_ONLY( movq(dst, src) );
++ NOT_LP64( movl(dst, src) );
++ }
++ void movptr(Register dst, Address src) {
++ LP64_ONLY( movq(dst, src) );
++ NOT_LP64( movl(dst, src) );
++ }
++ void movptr(Address dst, Register src) {
++ LP64_ONLY( movq(dst, src) );
++ NOT_LP64( movl(dst, src) );
++ }
++ void movptr(Address dst, intptr_t src) {
++ LP64_ONLY( movq(dst, src) );
++ NOT_LP64( movl(dst, src) );
++ }
++
+ void movptr(ArrayAddress dst, Register src);
+ // can this do an lea?
+ void movptr(Register dst, ArrayAddress src);
+diff --git a/src/cpu/x86/vm/assembler_x86_64.hpp b/src/cpu/x86/vm/assembler_x86_64.hpp
+--- a/src/cpu/x86/vm/assembler_x86_64.hpp
++++ b/src/cpu/x86/vm/assembler_x86_64.hpp
+@@ -125,6 +125,27 @@
+
+ #endif // _LP64
+
++// A union type for code which has to assemble both constant and non-constant operands.
++class RegisterConstant VALUE_OBJ_CLASS_SPEC {
++ private:
++ Register _r;
++ intptr_t _c;
++
++ public:
++ RegisterConstant(): _r(noreg), _c(0) {}
++ RegisterConstant(Register r): _r(r), _c(0) {}
++ RegisterConstant(intptr_t c): _r(noreg), _c(c) {}
++
++ Register as_register() const { assert(is_register(),""); return _r; }
++ intptr_t as_constant() const { assert(is_constant(),""); return _c; }
++
++ Register register_or_noreg() const { return _r; }
++ intptr_t constant_or_zero() const { return _c; }
++
++ bool is_register() const { return _r != noreg; }
++ bool is_constant() const { return _r == noreg; }
++};
++
+ // Address is an abstraction used to represent a memory location
+ // using any of the amd64 addressing modes with one object.
+ //
+@@ -140,8 +161,17 @@
+ times_1 = 0,
+ times_2 = 1,
+ times_4 = 2,
+- times_8 = 3
++ 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:
+ Register _base;
+@@ -182,6 +212,16 @@
+ "inconsistent address");
+ }
+
++ Address(Register base, RegisterConstant index, ScaleFactor scale = times_1, int disp = 0)
++ : _base (base),
++ _index(index.register_or_noreg()),
++ _scale(scale),
++ _disp (disp + (index.constant_or_zero() * scale_size(scale))) {
++ if (!index.is_register()) scale = Address::no_scale;
++ assert(!_index->is_valid() == (scale == Address::no_scale),
++ "inconsistent address");
++ }
++
+ // 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
+@@ -209,6 +249,17 @@
+ assert(!index->is_valid() == (scale == Address::no_scale),
+ "inconsistent address");
+ }
++
++ Address(Register base, RegisterConstant index, ScaleFactor scale, ByteSize disp)
++ : _base (base),
++ _index(index.register_or_noreg()),
++ _scale(scale),
++ _disp (in_bytes(disp) + (index.constant_or_zero() * scale_size(scale))) {
++ if (!index.is_register()) scale = Address::no_scale;
++ assert(!_index->is_valid() == (scale == Address::no_scale),
++ "inconsistent address");
++ }
++
+ #endif // ASSERT
+
+ // accessors
+@@ -222,6 +273,15 @@
+ static Address make_raw(int base, int index, int scale, int disp);
+
+ static Address make_array(ArrayAddress);
++
++ static int scale_size(ScaleFactor scale) {
++ assert(scale != no_scale, "");
++ assert(((1 << (int)times_1) == 1 &&
++ (1 << (int)times_2) == 2 &&
++ (1 << (int)times_4) == 4 &&
++ (1 << (int)times_8) == 8), "");
++ return (1 << (int)scale);
++ }
+
+ private:
+ bool base_needs_rex() const {
+@@ -1267,6 +1327,35 @@
+ );
+ 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);
++ }
++
++ // interface method calling
++ void lookup_interface_method(Register recv_klass,
++ Register intf_klass,
++ RegisterConstant itable_index,
++ Register method_result,
++ Register scan_temp,
++ Label& no_such_interface);
++
++ // method handles (JSR 292)
++ void check_method_handle_type(Register mtype_reg, Register mh_reg,
++ Register temp_reg,
++ Label& wrong_method_type);
++ void jump_to_method_handle_entry(Register mh_reg, Register temp_reg);
++
++ // klass type checking (falls through on failure)
++ void check_klass_subtype(Register sub_klass,
++ Register super_klass,
++ Register temp_reg,
++ Label& L_success);
++
+ //----
+
+ // Debugging
+@@ -1434,6 +1523,15 @@
+ void movoop(Register dst, jobject obj);
+ void movoop(Address dst, jobject obj);
+
++ void movptr(Address dst, Register src) {
++ LP64_ONLY( movq(dst, src) );
++ NOT_LP64( movl(dst, src) );
++ }
++ void movptr(Register dst, Address src) {
++ LP64_ONLY( movq(dst, src) );
++ NOT_LP64( movl(dst, src) );
++ }
++
+ void movptr(ArrayAddress dst, Register src);
+ void movptr(Register dst, AddressLiteral src);
diff --git a/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp b/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp
--- a/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp
@@ -606,7 +821,7 @@ diff --git a/src/cpu/x86/vm/cppInterpret
// compute full expression stack limit
const Address size_of_stack (rbx, methodOopDesc::max_stack_offset());
-+ const int extra_stack = (InvokeDynamic ? Interpreter::stackElementSize() : 0);
++ const int extra_stack = methodOopDesc::extra_stack() * Interpreter::stackElementSize;
__ 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
@@ -619,7 +834,7 @@ diff --git a/src/cpu/x86/vm/cppInterpret
// 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);
++ const int extra_stack = methodOopDesc::extra_stack() * Interpreter::stackElementSize;
__ 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));
@@ -639,7 +854,7 @@ diff --git a/src/cpu/x86/vm/cppInterpret
( 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 extra_stack = methodOopDesc::extra_stack();
+ const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) *
Interpreter::stackElementWords();
return overhead_size + method_stack + stub_code;
@@ -649,7 +864,7 @@ diff --git a/src/cpu/x86/vm/cppInterpret
// 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);
++ int extra_stack = methodOopDesc::extra_stack();
+ to_fill->_stack_limit = stack_base - (method->max_stack() + extra_stack + 1);
to_fill->_monitor_base = (BasicObjectLock*) monitor_base;
@@ -659,7 +874,7 @@ diff --git a/src/cpu/x86/vm/cppInterpret
// Now with full size expression stack
- int full_frame_size = short_frame_size + method->max_stack() * BytesPerWord;
-+ int extra_stack = (InvokeDynamic ? 1 : 0);
++ int extra_stack = methodOopDesc::extra_stack();
+ int full_frame_size = short_frame_size + (method->max_stack() + extra_stack) * BytesPerWord;
// and now with only live portion of the expression stack
@@ -914,11 +1129,11 @@ diff --git a/src/cpu/x86/vm/interpreter_
+ address entry_point = MethodHandle::generate_method_handle_interpreter_entry(_masm, wrong_method_type);
+
+ __ bind(wrong_method_type);
-+ // make it look like we are in the caller frame
+ __ pushl(rax_mtype); // missed mtype (required)
+ __ pushl(rcx_recv); // bad mh (actual)
-+ __ jump(ExternalAddress(Interpreter::_throw_WrongMethodType_entry));
-+ __ hlt();
++ __ movptr(rdx, ExternalAddress((address) &Interpreter::_throw_WrongMethodType_entry));
++ __ call(rdx);
++
+ return entry_point;
+}
+
@@ -942,6 +1157,464 @@ diff --git a/src/cpu/x86/vm/interpreter_
}
+diff --git a/src/cpu/x86/vm/methodHandles_x86_32.cpp b/src/cpu/x86/vm/methodHandles_x86_32.cpp
+new file mode 100644
+--- /dev/null
++++ b/src/cpu/x86/vm/methodHandles_x86_32.cpp
+@@ -0,0 +1,453 @@
++/*
++ * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ *
++ */
++
++#include "incls/_precompiled.incl"
++#include "incls/_methodHandles_x86_32.cpp.incl"
++
++#define __ _masm->
++
++address MethodEntry::start_compiled_entry(MacroAssembler* _masm,
++ address interpreted_entry) {
++ __ align(wordSize);
++ address target = __ pc() + sizeof(Data);
++ while (__ pc() < target) {
++ __ nop();
++ __ align(wordSize);
++ }
++
++ MethodEntry* me = (MethodEntry*) __ pc();
++ me->set_end_address(__ pc()); // set a temporary end_address
++ me->set_from_interpreted_entry(interpreted_entry);
++ me->set_type_checking_entry(NULL);
++
++ return (address) me;
++}
++
++MethodEntry* MethodEntry::finish_compiled_entry(MacroAssembler* _masm,
++ address start_addr) {
++ MethodEntry* me = (MethodEntry*) start_addr;
++ assert(me->end_address() == start_addr, "valid ME");
++
++ // Fill in the real end_address:
++ __ align(wordSize);
++ me->set_end_address(__ pc());
++
++ return me;
++}
++
++
++// Code generation
++address MethodHandle::generate_method_handle_interpreter_entry(MacroAssembler* _masm,
++ Label& wrong_method_type) {
++ // rbx: methodOop
++ // rcx: receiver method handle (must load from sp[MTForm.vmdata])
++ // rsi: sender SP (must preserve)
++ // rdx: garbage temp, blown away
++
++ Register rbx_method = rbx;
++ Register rcx_recv = rcx;
++ Register rax_mtype = rax;
++ Register rdx_temp = rdx;
++
++ // here's where control starts out:
++ __ align(CodeEntryAlignment);
++ address entry_point = __ pc();
++
++ // fetch the MethodType from the method handle into rax (the 'check' register)
++ Register tem = rbx_method;
++ for (int* pchase = methodOopDesc::method_type_pointer_chase(); (*pchase) != -1; pchase++) {
++ __ movptr(rax_mtype, Address(tem, *pchase));
++ tem = rax_mtype;
++ }
++ Register rbx_temp = rbx_method; // done with incoming methodOop
++
++ // given the MethodType, find out where the MH argument is buried
++ __ movptr(rdx_temp, Address(rax_mtype,
++ __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, rbx_temp),
++ Address::times_1,
++ oopDesc::address_padding_in_bytes()));
++ __ movl(rdx_temp, Address(rdx_temp,
++ __ delayed_value(java_dyn_MethodType::Form::vmdata_offset_in_bytes, rbx_temp)));
++ __ movptr(rcx_recv, argument_address(rdx_temp));
++
++ __ check_method_handle_type(rax_mtype, rcx_recv, rdx_temp, wrong_method_type);
++ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
++
++ // save away the wrong_method_type entry point
++ address wmt_jump_addr = __ pc();
++ __ jmp(wrong_method_type);
++ __ hlt();
++
++ address me_cookie = MethodEntry::start_compiled_entry(_masm, wmt_jump_addr);
++ __ unimplemented("compiled _wrong_method_type NYI"); // %%% FIXME
++ init_entry(_wrong_method_type, MethodEntry::finish_compiled_entry(_masm, me_cookie));
++
++ return entry_point;
++}
++
++// Generate an "entry" field for a method handle.
++// This determines how the method handle will respond to calls.
++void MethodHandle::generate_method_handle_stub(MacroAssembler* _masm, MethodHandle::EntryKind ek) {
++ // Here is the register state during an interpreted call,
++ // as set up by generate_method_handle_interpreter_entry():
++ // - rbx: garbage temp (was MethodHandle.invoke methodOop, unused)
++ // - rcx: receiver method handle
++ // - 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_argslot = rax;
++ Register rbx_index = rbx;
++ Register rdx_temp = rdx;
++
++ guarantee(java_dyn_MethodHandle::vmdata_offset_in_bytes() != 0, "must have offsets");
++
++ if (have_entry(ek)) {
++ __ nop(); // empty stubs make SG sick
++ return;
++ }
++
++ address interp_entry = __ pc();
++ 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]));
++ __ jmp(Address(rdx_temp, MethodEntry::from_interpreted_entry_offset_in_bytes()));
++ __ hlt();
++
++ interp_entry = __ pc();
++ __ check_method_handle_type(rax_mtype, rcx_recv, rdx_temp, wrong_method_type);
++ // now rax_mtype is dead; subsequent stubs will use it as a temp
++
++ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
++ }
++ break;
++
++ case _invokestatic_mh:
++ case _invokespecial_mh:
++ {
++ Register rbx_method = rbx_index;
++ __ movptr(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()));
++ __ movptr(rcx_recv, argument_address(rax_argslot));
++ __ null_check(rcx_recv);
++ __ verify_oop(rcx_recv);
++ }
++ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
++ }
++ break;
++
++ case _invokebound_mh:
++ {
++ Register rbx_temp = rbx_index;
++ __ movl(rax_argslot, Address(rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes()));
++ // get address of inserted argument (-1 means after sp is decremented)
++ __ leal(rax_argslot, argument_address(rax_argslot, -1));
++#ifdef ASSERT
++ {
++ Label L_ok, L_bad;
++ __ cmpl(rax_argslot, rbp);
++ __ jcc(Assembler::aboveEqual, L_bad);
++ __ cmpl(rsp, rax_argslot);
++ __ jcc(Assembler::belowEqual, L_ok);
++ __ bind(L_bad);
++ __ stop("first argument must fall within current frame");
++ __ bind(L_ok);
++ }
++#endif //ASSERT
++
++ // Make space on the stack for the prepended argument.
++ // Everything shallower than rax_argslot, including the
++ // return address, will be pulled down by one slot width.
++ Label loop, done;
++ __ subl(rsp, Interpreter::stackElementSize()); // decrement sp
++ __ movl(rdx_temp, rsp);
++ {
++ __ bind(loop);
++ // pull one word down by 4 (or 8 if TaggedStackInterpreter)
++ __ movl(rbx_temp, Address(rdx_temp, Interpreter::stackElementSize()));
++ __ movl(Address(rdx_temp, 0), rbx_temp);
++ __ addl(rdx_temp, wordSize);
++ __ cmpl(rdx_temp, rax_argslot);
++ __ jcc(Assembler::less, loop);
++ }
++
++ Register rbx_method = rbx_temp;
++ __ movptr(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):
++ __ movptr(rcx_recv, Address(rcx_recv, java_dyn_MethodHandle::receiver_offset_in_bytes()));
++ __ movptr(Address(rax_argslot, 0), rcx_recv);
++ if (TaggedStackInterpreter) {
++ __ movptr(Address(rax_argslot, wordSize), frame::TagReference);
++ }
++ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
++ }
++ break;
++
++ case _invokevirtual_mh:
++ {
++ // same as TemplateTable::invokevirtual,
++ // minus the CP setup and profiling:
++
++ // 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()));
++ __ movptr(rcx_recv, argument_address(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);
++ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
++ }
++ break;
++
++ case _invokeinterface_mh:
++ {
++ // same as TemplateTable::invokeinterface,
++ // minus the CP setup and profiling:
++
++ // pick out the interface and itable index from the MH.
++ Register rdx_intf = rdx_temp;
++
++ __ movptr(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()));
++ __ movptr(rcx_recv, argument_address(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);
++ Register rcx_temp = rcx_recv;
++ Register rbx_method = rbx_index;
++
++ // get interface klass
++ Label no_such_interface;
++ __ 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
++ __ verify_oop(rbx_method);
++ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
++ __ hlt();
++
++ __ bind(no_such_interface);
++ __ popl(rcx_recv); // restore saved receiver
++ // Throw an exception.
++ // For historical reasons, it will be IncompatibleClassChangeError.
++ __ should_not_reach_here(); // %%% FIXME NYI
++ }
++ 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(rax_argslot);
++ __ popl(rdx_temp); // return PC
++ __ leal(rsp, arg); // pop some arguments
++ __ pushl(rdx_temp); // restore PC
++ }
++
++ // immediately jump to the next MH layer:
++ __ movptr(rcx_recv, Address(rcx_recv, java_dyn_MethodHandle::receiver_offset_in_bytes()));
++ __ jump_to_method_handle_entry(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(rax_argslot);
++
++ // get the new MH:
++ __ movptr(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);
++ __ movptr(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
++ __ movptr(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();
++ }
++ __ movptr(arg, rdx_temp);
++ __ xchgl(rcx, rbx_index); // restore rcx_recv
++ }
++
++ __ jump_to_method_handle_entry(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(rax_argslot);
++
++ // What class are we casting to?
++ __ movptr(rbx_klass, Address(rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes()));
++
++ // get the new MH:
++ __ movptr(rcx_recv, Address(rcx_recv, java_dyn_MethodHandle::receiver_offset_in_bytes()));
++ // (now we are done with the old MH)
++
++ Label done;
++ __ movptr(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_method_handle_entry(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();
++
++ address me_cookie = MethodEntry::start_compiled_entry(_masm, interp_entry);
++ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
++
++ init_entry(ek, MethodEntry::finish_compiled_entry(_masm, me_cookie));
++}
++
++Address MethodHandle::argument_address(RegisterConstant arg_slot,
++ int extra_slot_offset) {
++ // cf. TemplateTable::prepare_invoke(), if (load_receiver).
++ int stackElementSize = Interpreter::stackElementWords() * wordSize;
++ int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
++ int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1);
++ assert(offset1 - offset == stackElementSize, "correct arithmetic");
++ Register scale_reg = noreg;
++ Address::ScaleFactor scale_factor = Address::no_scale;
++ if (arg_slot.is_constant()) {
++ offset += arg_slot.as_constant() * stackElementSize;
++ } else {
++ scale_reg = arg_slot.as_register();
++ scale_factor = Address::times(stackElementSize);
++ }
++ offset += wordSize; // return PC is on stack
++ return Address(rsp, scale_reg, scale_factor, offset);
++}
++
diff --git a/src/cpu/x86/vm/stubGenerator_x86_32.cpp b/src/cpu/x86/vm/stubGenerator_x86_32.cpp
--- a/src/cpu/x86/vm/stubGenerator_x86_32.cpp
+++ b/src/cpu/x86/vm/stubGenerator_x86_32.cpp
@@ -975,15 +1648,26 @@ 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
-@@ -92,6 +92,32 @@
+@@ -92,6 +92,43 @@
return entry;
}
-+// Arguments are: required type at TOS+4, failing object (or NULL) at TOS
++#ifdef ASSERT
++address last_WrongMethodType_caller;
++#endif //ASSERT
++
++// Arguments are: required type at TOS+8, failing object (or NULL) at TOS+4.
++// pc at TOS (just for debugging)
+address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
+ address entry = __ pc();
+
-+ __ popl(rbx); // failing object is at TOS
++ __ popl(rcx); // address raising the error (for debug)
++#ifdef ASSERT
++ __ lea(rax, ExternalAddress((address) &last_WrongMethodType_caller));
++ __ movptr(Address(rax, 0), rcx);
++#endif //ASSERT
++
++ __ popl(rbx); // actual failing object is at TOS
+ __ popl(rax); // required type is at TOS+4
+
+ __ verify_oop(rbx);
@@ -1008,7 +1692,7 @@ diff --git a/src/cpu/x86/vm/templateInte
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 @@
+@@ -129,13 +166,22 @@
}
@@ -1033,7 +1717,7 @@ diff --git a/src/cpu/x86/vm/templateInte
for (int i = 1; i < 8; i++) {
__ ffree(i);
}
-@@ -143,7 +178,7 @@
+@@ -143,7 +189,7 @@
__ empty_FPU_stack();
}
#endif
@@ -1042,7 +1726,7 @@ diff --git a/src/cpu/x86/vm/templateInte
__ MacroAssembler::verify_FPU(1, "generate_return_entry_for compiled");
} else {
__ MacroAssembler::verify_FPU(0, "generate_return_entry_for compiled");
-@@ -159,12 +194,12 @@
+@@ -159,12 +205,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.
@@ -1057,7 +1741,7 @@ diff --git a/src/cpu/x86/vm/templateInte
__ subl(rsp, 2*wordSize);
__ movdbl(Address(rsp, 0), xmm0);
__ fld_d(Address(rsp, 0));
-@@ -180,13 +215,120 @@
+@@ -180,13 +226,116 @@
__ restore_bcp();
__ restore_locals();
@@ -1167,19 +1851,15 @@ diff --git a/src/cpu/x86/vm/templateInte
+ __ 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));
-+ }
++ __ movptr(rdx, ExternalAddress((address) &Interpreter::_throw_WrongMethodType_entry));
++ __ call(rdx);
+ }
+ }
+
return entry;
}
-@@ -1364,6 +1506,7 @@
+@@ -1364,6 +1513,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;
@@ -1187,12 +1867,12 @@ 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 @@
+@@ -1394,9 +1544,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 extra_stack = methodOopDesc::extra_stack();
+ const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) *
Interpreter::stackElementWords();
- return overhead_size + method_stack + stub_code;
@@ -1272,16 +1952,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 @@
+@@ -1272,7 +1310,8 @@
+ -(frame::interpreter_frame_initial_sp_offset) + entry_size;
+
const int stub_code = frame::entry_frame_after_call_words;
- const int method_stack = (method->max_locals() + method->max_stack()) *
+- const int method_stack = (method->max_locals() + method->max_stack()) *
++ const int extra_stack = methodOopDesc::extra_stack();
++ const int method_stack = (method->max_locals() + method->max_stack() + extra_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);
+ return (overhead_size + method_stack + stub_code);
}
-
- 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
@@ -1499,7 +2179,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
__ movl(rdi, rdx); // Save klassOop in rdi
-@@ -3005,6 +3078,108 @@
+@@ -3005,6 +3078,79 @@
// rcx: receiver
// rbx,: methodOop
__ jump_from_interpreted(rbx, rdx);
@@ -1537,42 +2217,13 @@ diff --git a/src/cpu/x86/vm/templateTabl
+ __ 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);
++ __ jump_to_method_handle_entry(rcx, rdx);
+
+ // Initial calls come here...
+ __ bind(handle_unlinked_site);
@@ -1604,7 +2255,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
+ __ pushl(rcx); // arglist
+ __ pushl(rbx); // return value
+ __ movl(rcx, rdi);
-+ MethodHandle::jump_to_entry(_masm, rcx, rdx);
++ __ jump_to_method_handle_entry(rcx, rdx);
}
//----------------------------------------------------------------------------------------------------
@@ -1939,7 +2590,22 @@ diff --git a/src/share/vm/c1/c1_GraphBui
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
-@@ -2455,7 +2455,6 @@
+@@ -1541,6 +1541,14 @@
+ if (target->is_loaded() && !target->is_abstract() &&
+ target->can_be_statically_bound() && code == Bytecodes::_invokevirtual) {
+ code = Bytecodes::_invokespecial;
++ }
++
++ if (InvokeDynamic && target->is_method_handle_invoke()) {
++ if (target->holder()->name() == ciSymbol::java_dyn_Dynamic()) {
++ BAILOUT("invokedynamic NYI"); // FIXME
++ return;
++ }
++ // normal method handle invokes should work fine
+ }
+
+ // NEEDS_CLEANUP
+@@ -2455,7 +2463,6 @@
case Bytecodes::_invokespecial : // fall through
case Bytecodes::_invokestatic : // fall through
case Bytecodes::_invokeinterface: invoke(code); break;
@@ -1968,6 +2634,85 @@ diff --git a/src/share/vm/ci/bcEscapeAna
break;
case Bytecodes::_new:
state.apush(allocated_obj);
+diff --git a/src/share/vm/ci/ciEnv.cpp b/src/share/vm/ci/ciEnv.cpp
+--- a/src/share/vm/ci/ciEnv.cpp
++++ b/src/share/vm/ci/ciEnv.cpp
+@@ -484,11 +484,16 @@
+ } else if (tag.is_double()) {
+ return ciConstant((jdouble)cpool->double_at(index));
+ } else if (tag.is_string() || tag.is_unresolved_string()) {
+- oop string = cpool->pseudo_string_at(index, THREAD);
+- if (HAS_PENDING_EXCEPTION) {
+- CLEAR_PENDING_EXCEPTION;
+- record_out_of_memory_failure();
+- return ciConstant();
++ oop string = NULL;
++ if (cpool->is_pseudo_string_at(index)) {
++ string = cpool->pseudo_string_at(index);
++ } else {
++ string = cpool->string_at(index, THREAD);
++ if (HAS_PENDING_EXCEPTION) {
++ CLEAR_PENDING_EXCEPTION;
++ record_out_of_memory_failure();
++ return ciConstant();
++ }
+ }
+ ciObject* constant = get_object(string);
+ assert (constant->is_instance(), "must be an instance, or not? ");
+diff --git a/src/share/vm/ci/ciMethod.cpp b/src/share/vm/ci/ciMethod.cpp
+--- a/src/share/vm/ci/ciMethod.cpp
++++ b/src/share/vm/ci/ciMethod.cpp
+@@ -675,6 +675,37 @@
+ }
+
+ // ------------------------------------------------------------------
++// invokedynamic support
++//
++bool ciMethod::is_method_handle_invoke() {
++ check_is_loaded();
++ bool flag = ((flags().as_int() & JVM_MH_INVOKE_BITS) == JVM_MH_INVOKE_BITS);
++#ifdef ASSERT
++ {
++ VM_ENTRY_MARK;
++ bool flag2 = get_methodOop()->is_method_handle_invoke();
++ assert(flag == flag2, "consistent");
++ }
++#endif //ASSERT
++ return flag;
++}
++
++ciInstance* ciMethod::method_handle_type() {
++ check_is_loaded();
++ VM_ENTRY_MARK;
++ oop mtype = get_methodOop()->method_handle_type();
++ return CURRENT_THREAD_ENV->get_object(mtype)->as_instance();
++}
++
++ciMethod* ciMethod::extended_invoke_method() {
++ check_is_loaded();
++ VM_ENTRY_MARK;
++ methodOop extinv = get_methodOop()->extended_invoke_method();
++ return CURRENT_THREAD_ENV->get_object(extinv)->as_method();
++}
++
++
++// ------------------------------------------------------------------
+ // ciMethod::build_method_data
+ //
+ // Generate new methodDataOop objects at compile time.
+diff --git a/src/share/vm/ci/ciMethod.hpp b/src/share/vm/ci/ciMethod.hpp
+--- a/src/share/vm/ci/ciMethod.hpp
++++ b/src/share/vm/ci/ciMethod.hpp
+@@ -207,6 +207,9 @@
+ bool check_call(int refinfo_index, bool is_static) const;
+ void build_method_data(); // make sure it exists in the VM also
+ int scale_count(int count, float prof_factor = 1.); // make MDO count commensurate with IIC
++ bool is_method_handle_invoke();
++ ciInstance* method_handle_type();
++ ciMethod* extended_invoke_method();
+
+ // What kind of ciObject is this?
+ bool is_method() { return true; }
diff --git a/src/share/vm/ci/ciStreams.cpp b/src/share/vm/ci/ciStreams.cpp
--- a/src/share/vm/ci/ciStreams.cpp
+++ b/src/share/vm/ci/ciStreams.cpp
@@ -2893,7 +3638,7 @@ 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 +2231,203 @@
+@@ -2158,6 +2231,224 @@
sig_strm.next();
}
return NULL;
@@ -2919,7 +3664,9 @@ diff --git a/src/share/vm/classfile/syst
+ Handle mt = compute_method_handle_type(signature(),
+ class_loader, protection_domain,
+ CHECK_NULL);
-+ methodHandle m = methodOopDesc::make_invoke_method(signature, mt, CHECK_NULL);
++ KlassHandle mh_klass = KlassHandles::java_dyn_MethodHandle_klass();
++ methodHandle m = methodOopDesc::make_invoke_method(mh_klass, signature,
++ mt, CHECK_NULL);
+ // Now grab the lock. We might have to throw away the new method,
+ // if a racing thread has managed to install one at the same time.
+ {
@@ -2973,17 +3720,36 @@ diff --git a/src/share/vm/classfile/syst
+ 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);
++ methodOop idm_oop = mhinvoke_oop->invokedynamic_method();
++
++ if (idm_oop != NULL) return idm_oop;
++
++ // First time through, so compute it up.
++ methodHandle mhinvoke(THREAD, mhinvoke_oop); DEBUG_ONLY(mhinvoke_oop = NULL);
++ KlassHandle dyn_klass = KlassHandles::java_dyn_Dynamic_klass();
++ Handle mt(THREAD, mhinvoke->method_handle_type());
++ methodHandle idm = methodOopDesc::make_invoke_method(dyn_klass, signature,
++ mt, CHECK_NULL);
++
++ // Now link in a third method, which is the target type of the invoke:
++ // MH.invoke(abc)d --> Dyn.invoke(abc)d --> MH.invoke(Object;abc)d
++ symbolHandle extsig = prepend_argument_type(vmSymbolHandles::object_signature(), signature, CHECK_NULL);
++ {
++ methodOop extm = find_method_handle_invoke(extsig,
++ class_loader, protection_domain,
++ CHECK_NULL);
++ idm->set_extended_invoke_method(extm);
++ }
++
++ {
++ MutexLocker ml(SystemDictionary_lock, Thread::current());
++ if (mhinvoke->invokedynamic_method() != NULL)
++ // another thread got here first; go with the winner:
++ return mhinvoke->invokedynamic_method();
++
++ mhinvoke->set_invokedynamic_method(idm());
++ return idm();
++ }
+}
+
+// Ask Java code to find or construct a java.dyn.MethodType for the given
@@ -3302,7 +4068,15 @@ diff --git a/src/share/vm/includeDB_core
diff --git a/src/share/vm/includeDB_core b/src/share/vm/includeDB_core
--- a/src/share/vm/includeDB_core
+++ b/src/share/vm/includeDB_core
-@@ -2190,6 +2190,7 @@
+@@ -253,6 +253,7 @@
+ assembler_<arch_model>.cpp collectedHeap.inline.hpp
+ assembler_<arch_model>.cpp interfaceSupport.hpp
+ assembler_<arch_model>.cpp interpreter.hpp
++assembler_<arch_model>.cpp methodHandles.hpp
+ assembler_<arch_model>.cpp objectMonitor.hpp
+ assembler_<arch_model>.cpp os.hpp
+ assembler_<arch_model>.cpp resourceArea.hpp
+@@ -2190,6 +2191,7 @@
interpreter_<arch_model>.cpp jvmtiExport.hpp
interpreter_<arch_model>.cpp jvmtiThreadState.hpp
interpreter_<arch_model>.cpp methodDataOop.hpp
@@ -3310,7 +4084,7 @@ diff --git a/src/share/vm/includeDB_core
interpreter_<arch_model>.cpp methodOop.hpp
interpreter_<arch_model>.cpp oop.inline.hpp
interpreter_<arch_model>.cpp sharedRuntime.hpp
-@@ -2794,6 +2795,18 @@
+@@ -2794,6 +2796,22 @@
methodDataOop.hpp orderAccess.hpp
methodDataOop.hpp universe.hpp
@@ -3326,10 +4100,14 @@ diff --git a/src/share/vm/includeDB_core
+methodHandles.cpp signature.hpp
+methodHandles.cpp symbolTable.hpp
+
++methodHandles_<arch_model>.cpp allocation.inline.hpp
++methodHandles_<arch_model>.cpp interpreter.hpp
++methodHandles_<arch_model>.cpp methodHandles.hpp
++
methodKlass.cpp collectedHeap.inline.hpp
methodKlass.cpp constMethodKlass.hpp
methodKlass.cpp gcLocker.hpp
-@@ -3037,6 +3050,7 @@
+@@ -3037,6 +3055,7 @@
oop.inline.hpp arrayOop.hpp
oop.inline.hpp atomic.hpp
oop.inline.hpp barrierSet.inline.hpp
@@ -3337,7 +4115,7 @@ diff --git a/src/share/vm/includeDB_core
oop.inline.hpp cardTableModRefBS.hpp
oop.inline.hpp collectedHeap.inline.hpp
oop.inline.hpp compactingPermGenGen.hpp
-@@ -3649,6 +3663,7 @@
+@@ -3649,6 +3668,7 @@
sharedRuntime.cpp interpreter.hpp
sharedRuntime.cpp javaCalls.hpp
sharedRuntime.cpp jvmtiExport.hpp
@@ -3345,7 +4123,7 @@ diff --git a/src/share/vm/includeDB_core
sharedRuntime.cpp nativeInst_<arch>.hpp
sharedRuntime.cpp nativeLookup.hpp
sharedRuntime.cpp oop.inline.hpp
-@@ -3824,6 +3839,7 @@
+@@ -3824,6 +3844,7 @@
stubGenerator_<arch_model>.cpp handles.inline.hpp
stubGenerator_<arch_model>.cpp instanceOop.hpp
stubGenerator_<arch_model>.cpp interpreter.hpp
@@ -3353,7 +4131,7 @@ 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 @@
+@@ -4038,6 +4059,7 @@
templateTable_<arch_model>.cpp interpreterRuntime.hpp
templateTable_<arch_model>.cpp interpreter.hpp
templateTable_<arch_model>.cpp methodDataOop.hpp
@@ -3949,7 +4727,7 @@ diff --git a/src/share/vm/interpreter/in
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 @@
+@@ -660,7 +682,131 @@
info.resolved_method(),
info.vtable_index());
}
@@ -4000,8 +4778,9 @@ diff --git a/src/share/vm/interpreter/in
+ }
+
+ // 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.
++ // invokedynamic target call signature. The extended invoke method
++ // has 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(),
@@ -4015,11 +4794,13 @@ diff --git a/src/share/vm/interpreter/in
+ vmdata = jlong_from(method_idnum, bci);
+ }
+
++ methodHandle mh_extinv(THREAD, mh_invdyn->extended_invoke_method());
++ assert(mh_extinv.not_null(), "");
++
+ Handle call_site
+ = SystemDictionary::make_dynamic_call_site(caller_method->method_holder(),
+ pool->uncached_name_ref_at(call_index),
-+ mh_invdyn,
-+ vmdata, CHECK);
++ mh_extinv, vmdata, CHECK);
+ pool->cache()->entry_at(site_index)->set_dynamic_call(call_site(), 0);
+}
+IRT_END
@@ -4839,7 +5620,7 @@ diff --git a/src/share/vm/oops/constantP
case JVM_CONSTANT_UnresolvedString :
case JVM_CONSTANT_String :
- anObj = cp->string_at(index, CATCH);
-+ anObj = cp->pseudo_string_at(index, CATCH);
++ anObj = cp->pseudo_string_at(index);
anObj->print_value_on(st);
st->print(" {0x%lx}", (address)anObj);
break;
@@ -4856,13 +5637,10 @@ 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,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);
-+}
-+
-+
+@@ -263,6 +263,18 @@
+ }
+
+
+
+int constantPoolOopDesc::map_instruction_operand_to_index(int operand) {
+ if (constantPoolCacheOopDesc::is_secondary_index(operand)) {
@@ -4872,13 +5650,69 @@ diff --git a/src/share/vm/oops/constantP
+ assert((int)(u2)operand == operand, "clean u2");
+ int index = Bytes::swap_u2(operand);
+ return cache()->entry_at(index)->constant_pool_index();
++}
++
++
+ void constantPoolOopDesc::verify_constant_pool_resolve(constantPoolHandle this_oop, KlassHandle k, TRAPS) {
+ if (k->oop_is_instance() || k->oop_is_objArray()) {
+ instanceKlassHandle holder (THREAD, this_oop->pool_holder());
+@@ -336,7 +348,6 @@
+ } else if (java_lang_String::is_instance(entry)) {
+ return java_lang_String::as_utf8_string(entry);
+ } else {
+- assert(false, "pseudo-string");
+ return (char*)"<pseudo-string>";
+ }
}
-
+@@ -369,7 +380,7 @@
+ }
+ }
+
+-oop constantPoolOopDesc::string_at_impl(constantPoolHandle this_oop, int which, bool pseudo_ok, TRAPS) {
++oop constantPoolOopDesc::string_at_impl(constantPoolHandle this_oop, int which, TRAPS) {
+ oop entry = *(this_oop->obj_at_addr(which));
+ if (entry->is_symbol()) {
+ ObjectLocker ol(this_oop, THREAD);
+@@ -383,7 +394,7 @@
+ entry = this_oop->resolved_string_at(which);
+ }
+ }
+- assert(pseudo_ok || java_lang_String::is_instance(entry), "must be string");
++ assert(java_lang_String::is_instance(entry), "must be string");
+ return entry;
+ }
diff --git a/src/share/vm/oops/constantPoolOop.hpp b/src/share/vm/oops/constantPoolOop.hpp
--- a/src/share/vm/oops/constantPoolOop.hpp
+++ b/src/share/vm/oops/constantPoolOop.hpp
-@@ -384,16 +384,16 @@
+@@ -269,14 +269,22 @@
+
+ oop string_at(int which, TRAPS) {
+ constantPoolHandle h_this(THREAD, this);
+- return string_at_impl(h_this, which, false, CHECK_NULL);
++ return string_at_impl(h_this, which, CHECK_NULL);
+ }
++
++ // A "pseudo string" is an non-string oop that has found is way into
++ // a String entry.
+
+ bool is_pseudo_string_at(int which);
+
+- oop pseudo_string_at(int which, TRAPS) {
+- constantPoolHandle h_this(THREAD, this);
+- return string_at_impl(h_this, which, true, CHECK_NULL);
++ oop pseudo_string_at(int which) {
++ assert(tag_at(which).is_string(), "Corrupted constant pool");
++ return *obj_at_addr(which);
++ }
++
++ void pseudo_string_at_put(int which, oop x) {
++ assert(tag_at(which).is_string(), "Corrupted constant pool");
++ string_at_put(which, x); // this works just fine
+ }
+
+ // only called when we are sure a string entry is already resolved (via an
+@@ -384,16 +392,16 @@
// byte order (which comes from the bytecodes after rewriting) or,
// if "uncached" is true, a vanilla constant pool index
jint field_or_method_at(int which, bool uncached) {
@@ -4900,6 +5734,15 @@ diff --git a/src/share/vm/oops/constantP
// Used while constructing constant pool (only by ClassFileParser)
jint klass_index_at(int which) {
+@@ -412,7 +420,7 @@
+ // Implementation of methods that needs an exposed 'this' pointer, in order to
+ // handle GC while executing the method
+ static klassOop klass_at_impl(constantPoolHandle this_oop, int which, TRAPS);
+- static oop string_at_impl(constantPoolHandle this_oop, int which, bool pseudo_ok, TRAPS);
++ static oop string_at_impl(constantPoolHandle this_oop, int which, TRAPS);
+
+ // Resolve string constants (to prevent allocation during compilation)
+ static void resolve_string_constants_impl(constantPoolHandle this_oop, TRAPS);
diff --git a/src/share/vm/oops/cpCacheOop.cpp b/src/share/vm/oops/cpCacheOop.cpp
--- a/src/share/vm/oops/cpCacheOop.cpp
+++ b/src/share/vm/oops/cpCacheOop.cpp
@@ -5366,8 +6209,9 @@ diff --git a/src/share/vm/oops/instanceK
FieldPrinter print_static_field(st);
ik->do_local_static_fields(&print_static_field);
- st->print_cr(" - non-static fields:");
+- FieldPrinter print_nonstatic_field(st, obj);
+ st->print_cr(BULLET"---- non-static fields (%d words):", ik->nonstatic_field_size());
- FieldPrinter print_nonstatic_field(st, obj);
++ FieldPrinter print_nonstatic_field(st);
ik->do_nonstatic_fields(&print_nonstatic_field);
- st->print(" - static oop maps: ");
@@ -5482,7 +6326,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 +785,112 @@
+@@ -781,6 +785,138 @@
// caching this method should be just fine
return false;
@@ -5493,7 +6337,7 @@ 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_related_invoke_method, // string: (variable methodOop, sic)
+ _imcp_limit
+};
+
@@ -5504,21 +6348,41 @@ diff --git a/src/share/vm/oops/methodOop
+ return mt;
+}
+
-+symbolOop methodOopDesc::invokedynamic_signature() const {
++methodOop methodOopDesc::related_invoke_method(int relation) 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) {
++ methodOop idm = (methodOop) constants()->pseudo_string_at(_imcp_related_invoke_method);
++ if (idm == this) return NULL;
++#ifdef ASSERT
++ assert(idm->is_method() && methodOop(idm)->is_method_handle_invoke(), "");
++ klassOop expect = ((relation == RM_invdyn)
++ ? SystemDictionary::java_dyn_Dynamic_klass()
++ : SystemDictionary::java_dyn_MethodHandle_klass());
++ assert(idm->method_holder() == expect, "expected type of related method");
++#endif //ASSERT
++ return idm;
++}
++
++void methodOopDesc::set_related_invoke_method(methodOop idm, int relation) {
+ 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);
++
++#ifdef ASSERT
++ assert(idm != NULL && idm != this && idm->is_method() && methodOop(idm)->is_method_handle_invoke(), "");
++ if (method_holder() == SystemDictionary::java_dyn_MethodHandle_klass()) {
++ assert(relation == RM_invdyn, "expected relation");
++ assert(idm->method_holder() == SystemDictionary::java_dyn_Dynamic_klass(), "MH -> Dyn");
++ assert(idm->method_handle_type() == this->method_handle_type(), "same types");
++ } else if (method_holder() == SystemDictionary::java_dyn_Dynamic_klass()) {
++ assert(relation == RM_extinv, "expected relation");
++ assert(idm->method_holder() == SystemDictionary::java_dyn_MethodHandle_klass(), "Dyn -> MH");
++ assert(idm->method_handle_type() != this->method_handle_type(), "MH type is extension");
++ } else {
++ ShouldNotReachHere();
++ }
++ methodOop oldidm = (methodOop) constants()->pseudo_string_at(_imcp_related_invoke_method);
++ assert(oldidm == this || oldidm == idm, "one change allowed");
++#endif //ASSERT
++
++ constants()->pseudo_string_at_put(_imcp_related_invoke_method, idm);
+}
+
+jint* methodOopDesc::method_type_pointer_chase() {
@@ -5533,9 +6397,14 @@ diff --git a/src/share/vm/oops/methodOop
+ return pchase;
+}
+
-+methodHandle methodOopDesc::make_invoke_method(symbolHandle signature,
++methodHandle methodOopDesc::make_invoke_method(KlassHandle holder,
++ symbolHandle signature,
+ Handle method_type, TRAPS) {
+ methodHandle empty;
++
++ assert(holder() == SystemDictionary::java_dyn_MethodHandle_klass() ||
++ holder() == SystemDictionary::java_dyn_Dynamic_klass(),
++ "must be a JSR 292 magic type");
+
+ if (TraceMethodHandles) {
+ tty->print("Creating invoke method for ");
@@ -5551,8 +6420,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->symbol_at_put(_imcp_invokedynamic_signature, vmSymbols::void_signature());
-+ cp->set_pool_holder(SystemDictionary::java_dyn_MethodHandle_klass());
++ cp->string_at_put(_imcp_related_invoke_method, NULL);
++ cp->set_pool_holder(holder());
+
+ methodHandle m;
+ {
@@ -5561,6 +6430,7 @@ diff --git a/src/share/vm/oops/methodOop
+ 0, 0, 0, CHECK_(empty));
+ m = methodHandle(THREAD, m_oop);
+ }
++ cp->string_at_put(_imcp_related_invoke_method, m());
+ m->set_constants(cp());
+ m->set_name_index(_imcp_invoke_name);
+ m->set_signature_index(_imcp_invoke_signature);
@@ -5598,18 +6468,30 @@ 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,15 @@
+@@ -519,6 +519,27 @@
// Reflection support
bool is_overridden_in(klassOop k) const;
+ // JSR 292 support
+ bool is_method_handle_invoke() const { return access_flags().is_method_handle_invoke(); }
-+ static methodHandle make_invoke_method(symbolHandle signature, Handle method_type, TRAPS);
++ static methodHandle make_invoke_method(KlassHandle holder,
++ symbolHandle signature,
++ Handle method_type,
++ TRAPS);
++ // these operate only on invoke methods:
+ oop method_handle_type() const;
+ static jint* method_type_pointer_chase();
-+ // hack for memoizing the signature variant needed by invokedynamic:
-+ symbolOop invokedynamic_signature() const;
-+ void set_invokedynamic_signature(symbolOop sig);
++ // presize interpreter frames for extra stack slots, if needed
++ static int extra_stack() { return InvokeDynamic ? 2 : 0; }
++ private:
++ methodOop related_invoke_method(int relation) const;
++ void set_related_invoke_method(methodOop idm, int relation);
++ enum { RM_invdyn, RM_extinv };
++ public:
++ methodOop invokedynamic_method() const { return related_invoke_method(RM_invdyn); }
++ void set_invokedynamic_method(methodOop idm) { set_related_invoke_method(idm, RM_invdyn); }
++ methodOop extended_invoke_method() const { return related_invoke_method(RM_extinv); }
++ void set_extended_invoke_method(methodOop ext) { set_related_invoke_method(ext, RM_extinv); }
+
// RedefineClasses() support:
bool is_old() const { return access_flags().is_old(); }
@@ -5693,6 +6575,24 @@ diff --git a/src/share/vm/opto/bytecodeI
if( !caller_method->is_klass_loaded(index, true) ) {
return false;
}
+diff --git a/src/share/vm/opto/doCall.cpp b/src/share/vm/opto/doCall.cpp
+--- a/src/share/vm/opto/doCall.cpp
++++ b/src/share/vm/opto/doCall.cpp
+@@ -245,6 +245,14 @@
+ !holder_klass->is_interface()) {
+ uncommon_trap(Deoptimization::Reason_uninitialized,
+ Deoptimization::Action_reinterpret,
++ holder_klass);
++ return true;
++ }
++ if (dest_method->is_method_handle_invoke()
++ && holder_klass->name() == ciSymbol::java_dyn_Dynamic()) {
++ // FIXME: NYI
++ uncommon_trap(Deoptimization::Reason_unhandled,
++ Deoptimization::Action_none,
+ holder_klass);
+ return true;
+ }
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
@@ -5737,7 +6637,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/vm/prims/methodHandles.cpp
-@@ -0,0 +1,1085 @@
+@@ -0,0 +1,674 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -6088,417 +6988,6 @@ new file mode 100644
+}
+
+
-+/// @@ assembly code must be moved
-+#define __ _masm->
-+#define movL_OR_Q movl
-+
-+address MethodEntry::start_compiled_entry(MacroAssembler* _masm,
-+ address interpreted_entry) {
-+ __ align(wordSize);
-+ address target = __ pc() + sizeof(Data);
-+ while (__ pc() < target) {
-+ __ nop();
-+ __ align(wordSize);
-+ }
-+
-+ MethodEntry* me = (MethodEntry*) __ pc();
-+ me->set_end_address(__ pc()); // set a temporary end_address
-+ me->set_from_interpreted_entry(interpreted_entry);
-+ me->set_type_checking_entry(NULL);
-+
-+ return (address) me;
-+}
-+
-+MethodEntry* MethodEntry::finish_compiled_entry(MacroAssembler* _masm,
-+ address start_addr) {
-+ MethodEntry* me = (MethodEntry*) start_addr;
-+ assert(me->end_address() == start_addr, "valid ME");
-+
-+ // Fill in the real end_address:
-+ __ align(wordSize);
-+ me->set_end_address(__ pc());
-+
-+ return me;
-+}
-+
-+
-+// Code generation
-+// %%% FIXME: Move this to src/cpu/<arch>/vm, of course.
-+address MethodHandle::generate_method_handle_interpreter_entry(MacroAssembler* _masm,
-+ Label& wrong_method_type) {
-+ // rbx: methodOop
-+ // rcx: receiver method handle
-+ // rsi: sender SP (must preserve)
-+ // rdx: garbage temp, blown away
-+
-+ Register rbx_method = rbx;
-+ Register rcx_recv = rcx;
-+ Register rax_mtype = rax;
-+ Register rdx_temp = rdx;
-+
-+ // here's where control starts out:
-+ __ align(CodeEntryAlignment);
-+ address entry_point = __ pc();
-+
-+ // fetch the MethodType from the method handle into rax (the 'check' register)
-+ Register tem = rbx_method;
-+ for (int* pchase = methodOopDesc::method_type_pointer_chase(); (*pchase) != -1; pchase++) {
-+ __ movl(rax_mtype, Address(tem, *pchase));
-+ tem = rax_mtype;
-+ }
-+
-+ 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();
-+ __ jmp(wrong_method_type);
-+ __ hlt();
-+
-+ address me_cookie = MethodEntry::start_compiled_entry(_masm, wmt_jump_addr);
-+ __ unimplemented("compiled _wrong_method_type NYI"); // %%% FIXME
-+ init_entry(_wrong_method_type, MethodEntry::finish_compiled_entry(_masm, me_cookie));
-+
-+ return entry_point;
-+}
-+
-+// registers on entry:
-+// - rax ('check' register): required MethodType
-+// - 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, Register temp_reg, Label& wrong_method_type) {
-+ // compare method type against that of the receiver
-+ __ cmpl(mtype_reg, Address(recv_reg, __ delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg)));
-+ __ jcc(Assembler::notEqual, wrong_method_type);
-+}
-+
-+// registers on entry:
-+// - rcx: method handle
-+// - rdx: killable temp (interpreted only)
-+// - 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_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()));
-+
-+ // for the various stubs which take control at this point,
-+ // see the next method
-+ __ hlt();
-+}
-+
-+// Generate an "entry" field for a method handle.
-+// This determines how the method handle will respond to calls.
-+void MethodHandle::generate_method_handle_stub(MacroAssembler* _masm, MethodHandle::EntryKind ek) {
-+ // Here is the register state during an interpreted call,
-+ // 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, then unused)
-+ // - rsi: sender SP (must preserve)
-+ // - rdx: garbage temp, can blow away
-+
-+ Register rcx_recv = rcx;
-+ Register rax_argslot = rax;
-+ Register rsi_savedsp = rsi;
-+ Register rbx_index = rbx;
-+ Register rdx_temp = rdx;
-+
-+ guarantee(java_dyn_MethodHandle::vmdata_offset_in_bytes() != 0, "must have offsets");
-+
-+ if (have_entry(ek)) {
-+ __ nop(); // empty stubs make SG sick
-+ return;
-+ }
-+
-+ address interp_entry = __ pc();
-+ 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]));
-+ __ jmp(Address(rdx_temp, MethodEntry::from_interpreted_entry_offset_in_bytes()));
-+ __ hlt();
-+
-+ interp_entry = __ pc();
-+ 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;
-+
-+ case _invokestatic_mh:
-+ case _invokespecial_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);
-+ // 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()));
-+ }
-+ 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()));
-+ __ movL_OR_Q(argument_address(rsi_savedsp, rax_argslot), rcx_recv);
-+ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
-+ }
-+ break;
-+
-+ case _invokevirtual_mh:
-+ {
-+ // same as TemplateTable::invokevirtual,
-+ // minus the CP setup and profiling:
-+
-+ // 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);
-+ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
-+ }
-+ break;
-+
-+ case _invokeinterface_mh:
-+ {
-+ // same as TemplateTable::invokeinterface,
-+ // minus the CP setup and profiling:
-+
-+ // pick out the interface and itable index from the MH.
-+ Register rdx_intf = rdx_temp;
-+
-+ __ 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);
-+ Register rcx_temp = rcx_recv;
-+ Register rbx_method = rbx_index;
-+
-+ // get interface klass
-+ Label no_such_interface;
-+ __ 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
-+ __ verify_oop(rbx_method);
-+ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
-+ __ hlt();
-+
-+ __ bind(no_such_interface);
-+ __ popl(rcx_recv); // restore saved receiver
-+ // Throw an exception.
-+ // For historical reasons, it will be IncompatibleClassChangeError.
-+ __ should_not_reach_here(); // %%% FIXME NYI
-+ }
-+ 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();
-+
-+ address me_cookie = MethodEntry::start_compiled_entry(_masm, interp_entry);
-+ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
-+
-+ init_entry(ek, MethodEntry::finish_compiled_entry(_masm, me_cookie));
-+}
-+
-+Address MethodHandle::argument_address(Register savedsp_reg, RegisterConstant arg_slot) {
-+ // cf. TemplateTable::prepare_invoke(), if (load_receiver).
-+ 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;
@@ -6827,7 +7316,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/vm/prims/methodHandles.hpp
-@@ -0,0 +1,205 @@
+@@ -0,0 +1,199 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -6923,14 +7412,8 @@ new file mode 100644
+ static address generate_method_handle_interpreter_entry(MacroAssembler* _masm, Label& wrong_method_type);
+ 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, 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);
++ // argument list parsing
++ static Address argument_address(RegisterConstant arg_slot, int extra_slot_offset = 0);
+ static int argument_slot(oop method_type, int arg);
+
+ // Runtime support
@@ -6988,7 +7471,7 @@ new file mode 100644
+// Aspects of a method handle entry:
+// - from_compiled_entry - stub used when compiled code calls the MH
+// - from_interpreted_entry - stub used when the interpreter calls the MH
-+// - type_checking_entry - stub for runtime casting between MHForm siblings
++// - type_checking_entry - stub for runtime casting between MHForm siblings (NYI)
+class MethodEntry {
+ public:
+ class Data {
@@ -7054,6 +7537,23 @@ 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/arguments.cpp b/src/share/vm/runtime/arguments.cpp
+--- a/src/share/vm/runtime/arguments.cpp
++++ b/src/share/vm/runtime/arguments.cpp
+@@ -2508,6 +2508,13 @@
+ }
+ #endif // PRODUCT
+
++ if (InvokeDynamic && !MethodHandles) {
++ if (!FLAG_IS_DEFAULT(MethodHandles)) {
++ warning("forcing MethodHandles true to support InvokeDynamic");
++ }
++ MethodHandles = true;
++ }
++
+ if (PrintGCDetails) {
+ // Turn on -verbose:gc options as well
+ PrintGC = true;
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
@@ -7165,7 +7665,15 @@ diff --git a/src/share/vm/runtime/shared
int bytecode_index = bytecode->index();
// Find receiver for non-static call
-@@ -1481,9 +1440,72 @@
+@@ -816,6 +775,7 @@
+ KlassHandle receiver_klass (THREAD, receiver->klass());
+ klassOop rk = constants->klass_ref_at(bytecode_index, CHECK_(nullHandle));
+ // klass is already loaded
++ assert(rk != SystemDictionary::java_dyn_Dynamic_klass(), "compiler should have caught this");
+ KlassHandle static_receiver_klass (THREAD, rk);
+ assert(receiver_klass->is_subtype_of(static_receiver_klass()), "actual receiver must be subclass of static receiver klass");
+ if (receiver_klass->oop_is_instance()) {
+@@ -1481,9 +1441,72 @@
return generate_class_cast_message(objName, targetKlass->external_name());
}