--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/meth.patch Thu Jul 31 03:58:45 2008 -0700
@@ -0,0 +1,4451 @@
+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
+@@ -29,6 +29,7 @@
+ address generate_normal_entry(bool synchronized);
+ address generate_native_entry(bool synchronized);
+ address generate_abstract_entry(void);
++ address generate_method_handle_entry(void);
+ address generate_math_entry(AbstractInterpreter::MethodKind kind);
+ address generate_empty_entry(void);
+ address generate_accessor_entry(void);
+diff --git a/src/cpu/sparc/vm/interpreter_sparc.cpp b/src/cpu/sparc/vm/interpreter_sparc.cpp
+--- a/src/cpu/sparc/vm/interpreter_sparc.cpp
++++ b/src/cpu/sparc/vm/interpreter_sparc.cpp
+@@ -235,6 +235,16 @@
+ }
+
+
++
++// Method handle invoker
++// Dispatch a method of the form java.dyn.MethodHandle::invoke(...)
++address InterpreterGenerator::generate_method_handle_entry(void) {
++ guarantee(false, "NYI");
++}
++
++
++
++
+ //----------------------------------------------------------------------------------------------------
+ // Entry points & stack frame layout
+ //
+@@ -364,6 +374,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;
++ case Interpreter::method_handle : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
+ case Interpreter::java_lang_math_sin : break;
+ case Interpreter::java_lang_math_cos : break;
+ case Interpreter::java_lang_math_tan : break;
+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
+@@ -1907,7 +1907,8 @@
+ __ delayed()->set((int)bytecode(), O1);
+
+ 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
+@@ -2900,34 +2901,7 @@
+ void TemplateTable::invokeinterface_object_method(Register RklassOop,
+ Register Rcall,
+ Register Rret,
+- Register Rflags) {
+- Register Rscratch = G4_scratch;
+- Register Rindex = Lscratch;
+-
+- assert_different_registers(Rscratch, Rindex, Rret);
+-
+- Label notFinal;
+-
+- // Check for vfinal
+- __ set((1 << ConstantPoolCacheEntry::vfinalMethod), Rscratch);
+- __ btst(Rflags, Rscratch);
+- __ br(Assembler::zero, false, Assembler::pt, notFinal);
+- __ delayed()->nop();
+-
+- __ profile_final_call(O4);
+-
+- // do the call - the index (f2) contains the methodOop
+- assert_different_registers(G5_method, Gargs, Rcall);
+- __ mov(Rindex, G5_method);
+- __ call_from_interpreter(Rcall, Gargs, Rret);
+- __ bind(notFinal);
+-
+- __ profile_virtual_call(RklassOop, O4);
+- generate_vtable_call(RklassOop, Rindex, Rret);
+-}
+-
+-
+-void TemplateTable::invokeinterface(int byte_no) {
++ Register Rflags) void TemplateTable::invokeinterface(int byte_no) {
+ transition(vtos, vtos);
+
+ Register Rscratch = G4_scratch;
+diff --git a/src/cpu/x86/vm/assembler_x86_32.cpp b/src/cpu/x86/vm/assembler_x86_32.cpp
+--- a/src/cpu/x86/vm/assembler_x86_32.cpp
++++ b/src/cpu/x86/vm/assembler_x86_32.cpp
+@@ -1898,7 +1898,7 @@
+ // 0111 tttn #8-bit disp
+ emit_byte(0x70 | cc);
+ emit_byte((offs - short_size) & 0xFF);
+- jcc(cc, L);
++ // same code in this case as jcc(cc, L)
+ } else {
+ InstructionMark im(this);
+ L.add_patch_at(code(), locator());
+@@ -4702,6 +4702,67 @@
+ }
+
+
++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) {
++ 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");
++
++ // Compute start of first itableOffsetEntry (which is at the end of the vtable)
++ int vtable_base = instanceKlass::vtable_start_offset() * wordSize;
++ int scan_step = itableOffsetEntry::size() * wordSize;
++ int vte_size = vtableEntry::size() * wordSize;
++ Address::ScaleFactor times_vte_scale = Address::times_wordSize;
++ assert(vte_size == wordSize, "else adjust times_vte_scale");
++
++ movl(scan_temp, Address(recv_klass, instanceKlass::vtable_length_offset() * wordSize));
++ leal(scan_temp, Address(recv_klass, scan_temp, times_vte_scale, vtable_base));
++ if (HeapWordsPerLong > 1) {
++ // Round up to align_object_offset boundary
++ round_to(scan_temp, BytesPerLong);
++ }
++
++ // Adjust recv_klass by scaled itable_index, so we can free itable_index.
++ assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
++ leal(recv_klass, Address(recv_klass, itable_index, Address::times_wordSize));
++
++ // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
++ // if (scan->interface() == intf) {
++ // result = (klass + scan->offset() + itable_index);
++ // }
++ // }
++ Label search, found_method;
++
++ for (int peel = 1; peel >= 0; peel--) {
++ movl(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
++ cmpl(intf_klass, method_result);
++ jccb(Assembler::notEqual, search);
++
++ // Got a hit.
++ movl(method_result, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
++ movl(method_result, Address(recv_klass, method_result, Address::times_1));
++
++ if (!peel) break;
++ jmp(found_method);
++
++ bind(search);
++ // Check that the previous entry is non-null. A null entry means that
++ // 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);
++ addl(scan_temp, scan_step);
++ }
++
++ bind(found_method);
++}
++
++
++
+ 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,
+diff --git a/src/cpu/x86/vm/assembler_x86_32.hpp b/src/cpu/x86/vm/assembler_x86_32.hpp
+--- a/src/cpu/x86/vm/assembler_x86_32.hpp
++++ b/src/cpu/x86/vm/assembler_x86_32.hpp
+@@ -128,6 +128,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.
+ //
+@@ -143,7 +164,8 @@
+ 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)
+ };
+
+ private:
+@@ -186,6 +208,16 @@
+ "inconsistent address");
+ }
+
++ Address(Register base, RegisterConstant index, ScaleFactor scale, 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
+@@ -213,6 +245,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
+@@ -227,6 +270,14 @@
+
+ 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 {
+@@ -1287,6 +1338,14 @@
+ );
+ void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case);
+
++ // 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
++ Label& no_such_interface);
++
+ //----
+ void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0
+
+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
++++ b/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp
+@@ -28,6 +28,7 @@
+ address generate_asm_interpreter_entry(bool synchronized);
+ address generate_native_entry(bool synchronized);
+ address generate_abstract_entry(void);
++ address generate_method_handle_entry(void);
+ address generate_math_entry(AbstractInterpreter::MethodKind kind);
+ address generate_empty_entry(void);
+ address generate_accessor_entry(void);
+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 @@
+ case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break;
+ case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break;
+ case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break;
++ case Interpreter::method_handle : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
+
+ case Interpreter::java_lang_math_sin : // fall thru
+ case Interpreter::java_lang_math_cos : // fall thru
+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
+@@ -32,6 +32,7 @@
+ address generate_normal_entry(bool synchronized);
+ address generate_native_entry(bool synchronized);
+ address generate_abstract_entry(void);
++ address generate_method_handle_entry(void);
+ address generate_math_entry(AbstractInterpreter::MethodKind kind);
+ address generate_empty_entry(void);
+ address generate_accessor_entry(void);
+diff --git a/src/cpu/x86/vm/interpreter_x86_32.cpp b/src/cpu/x86/vm/interpreter_x86_32.cpp
+--- a/src/cpu/x86/vm/interpreter_x86_32.cpp
++++ b/src/cpu/x86/vm/interpreter_x86_32.cpp
+@@ -201,11 +201,12 @@
+ address entry_point = __ pc();
+
+ // abstract method entry
+- // remove return address. Not really needed, since exception handling throws away expression stack
+- __ popl(rbx);
+
+- // adjust stack to what a normal return would do
+- __ movl(rsp, rsi);
++ // pop return address, reset last_sp to NULL
++ __ empty_expression_stack();
++ __ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
++ __ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
++
+ // throw exception
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
+ // the call_VM checks for exception, so we should never return here.
+@@ -213,6 +214,34 @@
+
+ return entry_point;
+ }
++
++
++// Method handle invoker
++// Dispatch a method of the form java.dyn.MethodHandle::invoke(...)
++address InterpreterGenerator::generate_method_handle_entry(void) {
++ if (!MethodHandles) {
++ return generate_abstract_entry();
++ }
++
++ // incoming registers: rax, rcx
++ Register rax_mtype = rax;
++ Register rcx_recv = rcx;
++
++ Label wrong_method_type;
++ 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
++ __ 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);
++ __ hlt();
++ return entry_point;
++}
++
+
+ // This method tells the deoptimizer how big an interpreted frame must be:
+ int AbstractInterpreter::size_activation(methodOop method,
+diff --git a/src/cpu/x86/vm/interpreter_x86_64.cpp b/src/cpu/x86/vm/interpreter_x86_64.cpp
+--- a/src/cpu/x86/vm/interpreter_x86_64.cpp
++++ b/src/cpu/x86/vm/interpreter_x86_64.cpp
+@@ -251,6 +251,13 @@
+ __ should_not_reach_here();
+
+ return entry_point;
++}
++
++
++// Method handle invoker
++// Dispatch a method of the form java.dyn.MethodHandle::invoke(...)
++address InterpreterGenerator::generate_method_handle_entry(void) {
++ guarantee(false, "NYI");
+ }
+
+
+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
+@@ -2087,6 +2087,9 @@
+ return stub->entry_point();
+ }
+
++#undef __
++#define __ _masm->
++
+
+ void create_control_words() {
+ // Round to nearest, 53-bit mode, exceptions masked
+@@ -2166,6 +2169,16 @@
+
+ // arraycopy stubs used by compilers
+ generate_arraycopy_stubs();
++
++ // generic method handle stubs
++ if (MethodHandles && SystemDictionary::methodHandle_klass() != NULL) {
++ for (MethodHandle::EntryKind ek = MethodHandle::_EK_FIRST;
++ ek < MethodHandle::_EK_LIMIT;
++ ek = MethodHandle::EntryKind(1 + (int)ek)) {
++ StubCodeMark mark(this, "MethodHandle", MethodHandle::entry_name(ek));
++ MethodHandle::generate_method_handle_stub(_masm, ek);
++ }
++ }
+ }
+
+
+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 @@
+ case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break;
+ case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break;
+ case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break;
++ case Interpreter::method_handle : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
+
+ case Interpreter::java_lang_math_sin : // fall thru
+ case Interpreter::java_lang_math_cos : // fall thru
+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 @@
+ case Interpreter::empty : entry_point = ((InterpreterGenerator*) this)->generate_empty_entry(); break;
+ case Interpreter::accessor : entry_point = ((InterpreterGenerator*) this)->generate_accessor_entry(); break;
+ case Interpreter::abstract : entry_point = ((InterpreterGenerator*) this)->generate_abstract_entry(); break;
++ case Interpreter::method_handle : entry_point = ((InterpreterGenerator*) this)->generate_method_handle_entry();break;
+ case Interpreter::java_lang_math_sin : break;
+ case Interpreter::java_lang_math_cos : break;
+ case Interpreter::java_lang_math_tan : break;
+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
+@@ -132,12 +132,12 @@
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::set_original_bytecode_at), scratch, rsi, bc);
+ #ifndef ASSERT
+ __ jmpb(patch_done);
++#else
++ __ jmp(patch_done);
++#endif
+ __ bind(fast_patch);
+ }
+-#else
+- __ jmp(patch_done);
+- __ bind(fast_patch);
+- }
++#ifdef ASSERT
+ Label okay;
+ __ load_unsigned_byte(scratch, at_bcp(0));
+ __ cmpl(scratch, (int)Bytecodes::java_code(bytecode));
+@@ -2032,7 +2032,8 @@
+
+ // 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 @@
+ }
+
+
+-void TemplateTable::prepare_invoke(Register method, Register index, int byte_no, Bytecodes::Code code) {
++void TemplateTable::prepare_invoke(Register method, Register index, int byte_no) {
+ // determine flags
++ Bytecodes::Code code = Bytecodes::java_code(bytecode());
+ const bool is_invokeinterface = code == Bytecodes::_invokeinterface;
+ 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
+ const Register recv = rcx;
+ const Register flags = rdx;
+@@ -2868,7 +2871,7 @@
+
+ void TemplateTable::invokevirtual(int byte_no) {
+ transition(vtos, vtos);
+- prepare_invoke(rbx, noreg, byte_no, bytecode());
++ prepare_invoke(rbx, noreg, byte_no);
+
+ // rbx,: index
+ // rcx: receiver
+@@ -2880,7 +2883,7 @@
+
+ void TemplateTable::invokespecial(int byte_no) {
+ transition(vtos, vtos);
+- prepare_invoke(rbx, noreg, byte_no, bytecode());
++ prepare_invoke(rbx, noreg, byte_no);
+ // do the call
+ __ verify_oop(rbx);
+ __ profile_call(rax);
+@@ -2890,7 +2893,7 @@
+
+ void TemplateTable::invokestatic(int byte_no) {
+ transition(vtos, vtos);
+- prepare_invoke(rbx, noreg, byte_no, bytecode());
++ prepare_invoke(rbx, noreg, byte_no);
+ // do the call
+ __ verify_oop(rbx);
+ __ profile_call(rax);
+@@ -2906,7 +2909,7 @@
+
+ void TemplateTable::invokeinterface(int byte_no) {
+ transition(vtos, vtos);
+- prepare_invoke(rax, rbx, byte_no, bytecode());
++ prepare_invoke(rax, rbx, byte_no);
+
+ // rax,: Interface
+ // rbx,: index
+@@ -2933,35 +2936,44 @@
+ // profile this call
+ __ profile_virtual_call(rdx, rsi, rdi);
+
+- __ movl(rdi, rdx); // Save klassOop in rdi
++ Label no_such_interface, no_such_method;
+
+- // Compute start of first itableOffsetEntry (which is at the end of the vtable)
+- const int base = instanceKlass::vtable_start_offset() * wordSize;
+- assert(vtableEntry::size() * wordSize == 4, "adjust the scaling in the code below");
+- __ movl(rsi, Address(rdx, instanceKlass::vtable_length_offset() * wordSize)); // Get length of vtable
+- __ leal(rdx, Address(rdx, rsi, Address::times_4, base));
+- if (HeapWordsPerLong > 1) {
+- // Round up to align_object_offset boundary
+- __ round_to(rdx, BytesPerLong);
+- }
++ __ lookup_interface_method(// inputs: rec. class, interface, itable index
++ rdx, rax, rbx,
++ // outputs: method, scan temp. reg
++ rbx, rsi,
++ no_such_interface);
+
+- Label entry, search, interface_ok;
++ // rbx,: methodOop to call
++ // rcx: receiver
++ // Check for abstract method error
++ // Note: This should be done more efficiently via a throw_abstract_method_error
++ // interpreter entry point and a conditional jump to it in case of a null
++ // method.
++ __ testl(rbx, rbx);
++ __ jcc(Assembler::zero, no_such_method);
+
+- __ jmpb(entry);
+- __ bind(search);
+- __ addl(rdx, itableOffsetEntry::size() * wordSize);
++ // do the call
++ // rcx: receiver
++ // rbx,: methodOop
++ __ jump_from_interpreted(rbx, rdx);
++ __ should_not_reach_here();
+
+- __ bind(entry);
++ // exception handling code follows...
++ // note: must restore interpreter registers to canonical
++ // state for exception handling to work correctly!
+
+- // Check that the entry is non-null. A null entry means that the receiver
+- // class doesn't implement the interface, and wasn't the same as the
+- // receiver class checked when the interface was resolved.
+- __ pushl(rdx);
+- __ movl(rdx, Address(rdx, itableOffsetEntry::interface_offset_in_bytes()));
+- __ testl(rdx, rdx);
+- __ jcc(Assembler::notZero, interface_ok);
++ __ bind(no_such_method);
+ // throw exception
+- __ popl(rdx); // pop saved register first.
++ __ popl(rbx); // pop return address (pushed by prepare_invoke)
++ __ 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_AbstractMethodError));
++ // the call_VM checks for exception, so we should never return here.
++ __ should_not_reach_here();
++
++ __ bind(no_such_interface);
++ // throw exception
+ __ popl(rbx); // pop return address (pushed by prepare_invoke)
+ __ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
+ __ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
+@@ -2969,42 +2981,6 @@
+ InterpreterRuntime::throw_IncompatibleClassChangeError));
+ // the call_VM checks for exception, so we should never return here.
+ __ should_not_reach_here();
+- __ bind(interface_ok);
+-
+- __ popl(rdx);
+-
+- __ cmpl(rax, Address(rdx, itableOffsetEntry::interface_offset_in_bytes()));
+- __ jcc(Assembler::notEqual, search);
+-
+- __ movl(rdx, Address(rdx, itableOffsetEntry::offset_offset_in_bytes()));
+- __ addl(rdx, rdi); // Add offset to klassOop
+- assert(itableMethodEntry::size() * wordSize == 4, "adjust the scaling in the code below");
+- __ movl(rbx, Address(rdx, rbx, Address::times_4));
+- // rbx,: methodOop to call
+- // rcx: receiver
+- // Check for abstract method error
+- // Note: This should be done more efficiently via a throw_abstract_method_error
+- // interpreter entry point and a conditional jump to it in case of a null
+- // method.
+- { Label L;
+- __ testl(rbx, rbx);
+- __ jcc(Assembler::notZero, L);
+- // throw exception
+- // note: must restore interpreter registers to canonical
+- // state for exception handling to work correctly!
+- __ popl(rbx); // pop return address (pushed by prepare_invoke)
+- __ 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_AbstractMethodError));
+- // the call_VM checks for exception, so we should never return here.
+- __ should_not_reach_here();
+- __ bind(L);
+- }
+-
+- // do the call
+- // rcx: receiver
+- // rbx,: methodOop
+- __ jump_from_interpreted(rbx, 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
+@@ -22,8 +22,7 @@
+ *
+ */
+
+- static void prepare_invoke(Register method, Register index, int byte_no,
+- Bytecodes::Code code);
++ static void prepare_invoke(Register method, Register index, int byte_no);
+ static void invokevirtual_helper(Register index, Register recv,
+ Register flags);
+ static void volatile_barrier( );
+diff --git a/src/cpu/x86/vm/templateTable_x86_64.cpp b/src/cpu/x86/vm/templateTable_x86_64.cpp
+--- a/src/cpu/x86/vm/templateTable_x86_64.cpp
++++ b/src/cpu/x86/vm/templateTable_x86_64.cpp
+@@ -2008,7 +2008,8 @@
+
+ // resolve first time through
+ address entry;
+- switch (bytecode()) {
++ Bytecodes::Code code = Bytecodes::java_code(bytecode());
++ switch (code) {
+ case Bytecodes::_getstatic:
+ case Bytecodes::_putstatic:
+ case Bytecodes::_getfield:
+@@ -2764,9 +2765,9 @@
+
+ void TemplateTable::prepare_invoke(Register method,
+ Register index,
+- int byte_no,
+- Bytecodes::Code code) {
++ int byte_no) {
+ // determine flags
++ Bytecodes::Code code = Bytecodes::java_code(bytecode());
+ const bool is_invokeinterface = code == Bytecodes::_invokeinterface;
+ const bool is_invokevirtual = code == Bytecodes::_invokevirtual;
+ const bool is_invokespecial = code == Bytecodes::_invokespecial;
+@@ -2877,7 +2878,7 @@
+
+ void TemplateTable::invokevirtual(int byte_no) {
+ transition(vtos, vtos);
+- prepare_invoke(rbx, noreg, byte_no, bytecode());
++ prepare_invoke(rbx, noreg, byte_no);
+
+ // rbx: index
+ // rcx: receiver
+@@ -2889,7 +2890,7 @@
+
+ void TemplateTable::invokespecial(int byte_no) {
+ transition(vtos, vtos);
+- prepare_invoke(rbx, noreg, byte_no, bytecode());
++ prepare_invoke(rbx, noreg, byte_no);
+ // do the call
+ __ verify_oop(rbx);
+ __ profile_call(rax);
+@@ -2899,7 +2900,7 @@
+
+ void TemplateTable::invokestatic(int byte_no) {
+ transition(vtos, vtos);
+- prepare_invoke(rbx, noreg, byte_no, bytecode());
++ prepare_invoke(rbx, noreg, byte_no);
+ // do the call
+ __ verify_oop(rbx);
+ __ profile_call(rax);
+@@ -2913,7 +2914,7 @@
+
+ void TemplateTable::invokeinterface(int byte_no) {
+ transition(vtos, vtos);
+- prepare_invoke(rax, rbx, byte_no, bytecode());
++ prepare_invoke(rax, rbx, byte_no);
+
+ // rax: Interface
+ // rbx: index
+diff --git a/src/cpu/x86/vm/templateTable_x86_64.hpp b/src/cpu/x86/vm/templateTable_x86_64.hpp
+--- a/src/cpu/x86/vm/templateTable_x86_64.hpp
++++ b/src/cpu/x86/vm/templateTable_x86_64.hpp
+@@ -22,8 +22,7 @@
+ *
+ */
+
+- static void prepare_invoke(Register method, Register index, int byte_no,
+- Bytecodes::Code code);
++ static void prepare_invoke(Register method, Register index, int byte_no);
+ static void invokevirtual_helper(Register index, Register recv,
+ Register flags);
+ static void volatile_barrier(Assembler::Membar_mask_bits order_constraint);
+diff --git a/src/cpu/x86/vm/vtableStubs_x86_32.cpp b/src/cpu/x86/vm/vtableStubs_x86_32.cpp
+--- a/src/cpu/x86/vm/vtableStubs_x86_32.cpp
++++ b/src/cpu/x86/vm/vtableStubs_x86_32.cpp
+@@ -34,10 +34,16 @@
+ extern "C" void bad_compiled_vtable_index(JavaThread* thread, oop receiver, int index);
+ #endif
+
+-// used by compiler only; may use only caller saved registers rax, rbx, rcx.
+-// rdx holds first int arg, rsi, rdi, rbp are callee-save & must be preserved.
+-// Leave receiver in rcx; required behavior when +OptoArgsInRegisters
+-// is modifed to put first oop in rcx.
++// These stubs are used by the compiler only.
++// Argument registers, which must be preserved:
++// rcx - receiver (always first argument)
++// rdx - second argument (if any)
++// Other registers that might be usable:
++// rax - inline cache register (is interface for itable stub)
++// rbx - method (used when calling out to interpreter)
++// Callee-save registers (when?):
++// rsi, rdi
++// Note that rax and rdx are also used for return values.
+ //
+ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
+ const int i486_code_length = VtableStub::pd_code_size_limit(true);
+@@ -94,16 +100,25 @@
+ __ jmp( Address(method, methodOopDesc::from_compiled_offset()));
+
+ masm->flush();
++
++ if (PrintMiscellaneous && (WizardMode || Verbose)) {
++ tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d",
++ vtable_index, s->entry_point(),
++ (int)(s->code_end() - s->entry_point()),
++ (int)(s->code_end() - __ pc()));
++ }
++ guarantee(__ pc() <= s->code_end(), "overflowed buffer");
++
+ s->set_exception_points(npe_addr, ame_addr);
+ return s;
+ }
+
+
+-VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
++VtableStub* VtableStubs::create_itable_stub(int itable_index) {
+ // Note well: pd_code_size_limit is the absolute minimum we can get away with. If you
+ // add code here, bump the code stub size returned by pd_code_size_limit!
+ const int i486_code_length = VtableStub::pd_code_size_limit(false);
+- VtableStub* s = new(i486_code_length) VtableStub(false, vtable_index);
++ VtableStub* s = new(i486_code_length) VtableStub(false, itable_index);
+ ResourceMark rm;
+ CodeBuffer cb(s->entry_point(), i486_code_length);
+ MacroAssembler* masm = new MacroAssembler(&cb);
+@@ -121,52 +136,26 @@
+
+ assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx");
+
++ // Most registers are in use; we'll use rax, rbx, rcx, rsi
++ Register restore_rcx = rcx;
++ __ pushl(restore_rcx);
++
+ // get receiver klass (also an implicit null-check)
+ address npe_addr = __ pc();
+- __ movl(rbx, Address(rcx, oopDesc::klass_offset_in_bytes()));
++ __ movl(rcx, Address(rcx, oopDesc::klass_offset_in_bytes()));
+
+- __ movl(rsi, rbx); // Save klass in free register
+- // Most registers are in use, so save a few
+- __ pushl(rdx);
+- // compute itable entry offset (in words)
+- const int base = instanceKlass::vtable_start_offset() * wordSize;
+- assert(vtableEntry::size() * wordSize == 4, "adjust the scaling in the code below");
+- __ movl(rdx, Address(rbx, instanceKlass::vtable_length_offset() * wordSize)); // Get length of vtable
+- __ leal(rbx, Address(rbx, rdx, Address::times_4, base));
+- if (HeapWordsPerLong > 1) {
+- // Round up to align_object_offset boundary
+- __ round_to(rbx, BytesPerLong);
+- }
+-
+- Label hit, next, entry, throw_icce;
+-
+- __ jmpb(entry);
+-
+- __ bind(next);
+- __ addl(rbx, itableOffsetEntry::size() * wordSize);
+-
+- __ bind(entry);
+-
+- // If the entry is NULL then we've reached the end of the table
+- // without finding the expected interface, so throw an exception
+- __ movl(rdx, Address(rbx, itableOffsetEntry::interface_offset_in_bytes()));
+- __ testl(rdx, rdx);
+- __ jcc(Assembler::zero, throw_icce);
+- __ cmpl(rax, rdx);
+- __ jcc(Assembler::notEqual, next);
+-
+- // We found a hit, move offset into rbx,
+- __ movl(rdx, Address(rbx, itableOffsetEntry::offset_offset_in_bytes()));
+-
+- // Compute itableMethodEntry.
+- const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) + itableMethodEntry::method_offset_in_bytes();
++ const Register method = rbx;
++ Label throw_icce;
+
+ // Get methodOop and entrypoint for compiler
+- const Register method = rbx;
+- __ movl(method, Address(rsi, rdx, Address::times_1, method_offset));
++ __ lookup_interface_method(// inputs: rec. class, interface, itable index
++ rcx, rax, itable_index,
++ // outputs: method, scan temp. reg
++ method, rsi,
++ throw_icce);
+
+ // Restore saved register, before possible trap.
+- __ popl(rdx);
++ __ popl(restore_rcx);
+
+ // method (rbx): methodOop
+ // rcx: receiver
+@@ -188,11 +177,17 @@
+
+ __ bind(throw_icce);
+ // Restore saved register
+- __ popl(rdx);
++ __ popl(restore_rcx);
+ __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
+
+ masm->flush();
+
++ if (PrintMiscellaneous && (WizardMode || Verbose)) {
++ tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d",
++ itable_index, s->entry_point(),
++ (int)(s->code_end() - s->entry_point()),
++ (int)(s->code_end() - __ pc()));
++ }
+ guarantee(__ pc() <= s->code_end(), "overflowed buffer");
+
+ s->set_exception_points(npe_addr, ame_addr);
+@@ -207,7 +202,7 @@
+ return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0);
+ } else {
+ // Itable stub size
+- return (DebugVtables ? 144 : 64) + (CountCompiledCalls ? 6 : 0);
++ return (DebugVtables ? 159 : 79) + (CountCompiledCalls ? 6 : 0);
+ }
+ }
+
+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 @@
+ case Bytecodes::_invokespecial : // fall through
+ case Bytecodes::_invokestatic : // fall through
+ case Bytecodes::_invokeinterface: invoke(code); break;
+- case Bytecodes::_xxxunusedxxx : ShouldNotReachHere(); break;
+ case Bytecodes::_new : new_instance(s.get_index_big()); break;
+ case Bytecodes::_newarray : new_type_array(); break;
+ case Bytecodes::_anewarray : new_object_array(); break;
+diff --git a/src/share/vm/ci/bcEscapeAnalyzer.cpp b/src/share/vm/ci/bcEscapeAnalyzer.cpp
+--- a/src/share/vm/ci/bcEscapeAnalyzer.cpp
++++ b/src/share/vm/ci/bcEscapeAnalyzer.cpp
+@@ -834,6 +834,7 @@
+ case Bytecodes::_invokespecial:
+ case Bytecodes::_invokestatic:
+ case Bytecodes::_invokeinterface:
++ do_invoke:
+ { bool will_link;
+ ciMethod* target = s.get_method(will_link);
+ ciKlass* holder = s.get_declared_method_holder();
+@@ -847,9 +848,6 @@
+ state.lpush();
+ }
+ }
+- break;
+- case Bytecodes::_xxxunusedxxx:
+- ShouldNotReachHere();
+ break;
+ case Bytecodes::_new:
+ state.apush(allocated_obj);
+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
+@@ -303,7 +303,7 @@
+ int ciBytecodeStream::get_method_index() {
+ switch (cur_bc()) {
+ case Bytecodes::_invokeinterface:
+- return Bytes::get_Java_u2(_pc-4);
++ return get_index_int();
+ case Bytecodes::_invokevirtual:
+ case Bytecodes::_invokespecial:
+ case Bytecodes::_invokestatic:
+diff --git a/src/share/vm/ci/ciStreams.hpp b/src/share/vm/ci/ciStreams.hpp
+--- a/src/share/vm/ci/ciStreams.hpp
++++ b/src/share/vm/ci/ciStreams.hpp
+@@ -91,11 +91,13 @@
+ _end = _start + max;
+ }
+
+- address cur_bcp() { return _bc_start; } // Returns bcp to current instruction
++ address cur_bcp() const { return _bc_start; } // Returns bcp to current instruction
+ int next_bci() const { return _pc -_start; }
+ int cur_bci() const { return _bc_start - _start; }
++ int instruction_size() const { return _pc - _bc_start; }
+
+ Bytecodes::Code cur_bc() const{ return check_java(_bc); }
++ Bytecodes::Code raw_cur_bc() const { return Bytecodes::raw_code_at(cur_bcp()); }
+ Bytecodes::Code next_bc() { return Bytecodes::java_code((Bytecodes::Code)* _pc); }
+
+ // Return current ByteCode and increment PC to next bytecode, skipping all
+@@ -121,33 +123,38 @@
+ return check_java(_bc);
+ }
+
+- bool is_wide() { return ( _pc == _was_wide ); }
++ bool is_wide() const { return ( _pc == _was_wide ); }
+
+ // Get a byte index following this bytecode.
+ // If prefixed with a wide bytecode, get a wide index.
+ int get_index() const {
++ assert_index_size(is_wide() ? 2 : 1);
+ return (_pc == _was_wide) // was widened?
+ ? Bytes::get_Java_u2(_bc_start+2) // yes, return wide index
+ : _bc_start[1]; // no, return narrow index
+ }
+
+- // Set a byte index following this bytecode.
+- // If prefixed with a wide bytecode, get a wide index.
+- void put_index(int idx) {
+- if (_pc == _was_wide) // was widened?
+- Bytes::put_Java_u2(_bc_start+2,idx); // yes, set wide index
+- else
+- _bc_start[1]=idx; // no, set narrow index
++ // Get 2-byte index (getfield/putstatic/etc)
++ int get_index_big() const {
++ assert_index_size(2);
++ return Bytes::get_Java_u2(_bc_start+1);
+ }
+
+- // Get 2-byte index (getfield/putstatic/etc)
+- int get_index_big() const { return Bytes::get_Java_u2(_bc_start+1); }
++ // Get 2-byte index (or 4-byte, for invokedynamic)
++ int get_index_int() const {
++ return has_giant_index() ? get_index_giant() : get_index_big();
++ }
++
++ // Get 4-byte index, for invokedynamic.
++ int get_index_giant() const {
++ assert_index_size(4);
++ return Bytes::get_native_u4(_bc_start+1);
++ }
++
++ bool has_giant_index() const { return (raw_cur_bc() == Bytecodes::_invokedynamic); }
+
+ // Get dimensions byte (multinewarray)
+ int get_dimensions() const { return *(unsigned char*)(_pc-1); }
+-
+- // Get unsigned index fast
+- int get_index_fast() const { return Bytes::get_native_u2(_pc-2); }
+
+ // Sign-extended index byte/short, no widening
+ int get_byte() const { return (int8_t)(_pc[-1]); }
+@@ -225,6 +232,22 @@
+ ciKlass* get_declared_method_holder();
+ int get_method_holder_index();
+ int get_method_signature_index();
++
++ private:
++ void assert_index_size(int required_size) const {
++#ifdef ASSERT
++ int isize = instruction_size() - (is_wide() ? 1 : 0) - 1;
++ if (isize == 2 && raw_cur_bc() == Bytecodes::_iinc)
++ isize = 1;
++ else if (isize <= 2)
++ ; // no change
++ else if (has_giant_index())
++ isize = 4;
++ else
++ isize = 2;
++ assert(isize = required_size, "wrong index size");
++#endif
++ }
+ };
+
+
+diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile/classFileParser.cpp
+--- a/src/share/vm/classfile/classFileParser.cpp
++++ b/src/share/vm/classfile/classFileParser.cpp
+@@ -1723,6 +1723,11 @@
+ _has_vanilla_constructor = true;
+ }
+
++ if (MethodHandles && m->is_method_handle_invoke()) {
++ THROW_MSG_(vmSymbols::java_lang_VirtualMachineError(),
++ "Method handle invokers must be defined internally to the VM", nullHandle);
++ }
++
+ return m;
+ }
+
+diff --git a/src/share/vm/classfile/dictionary.cpp b/src/share/vm/classfile/dictionary.cpp
+--- a/src/share/vm/classfile/dictionary.cpp
++++ b/src/share/vm/classfile/dictionary.cpp
+@@ -550,6 +550,53 @@
+ }
+
+
++SymbolPropertyEntry* SymbolPropertyTable::find_entry(int index, unsigned int hash,
++ symbolHandle sym) {
++ assert(index == index_for(sym), "incorrect index?");
++ for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
++ if (p->hash() == hash && p->symbol() == sym()) {
++ return p;
++ }
++ }
++ return NULL;
++}
++
++
++SymbolPropertyEntry* SymbolPropertyTable::add_entry(int index, unsigned int hash,
++ symbolHandle sym) {
++ assert_locked_or_safepoint(SystemDictionary_lock);
++ assert(index == index_for(sym), "incorrect index?");
++ assert(find_entry(index, hash, sym) == NULL, "no double entry");
++
++ SymbolPropertyEntry* p = new_entry(hash, sym());
++ Hashtable::add_entry(index, p);
++ return p;
++}
++
++
++void SymbolPropertyTable::oops_do(OopClosure* f) {
++ for (int index = 0; index < table_size(); index++) {
++ for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
++ f->do_oop((oop*) p->symbol_addr());
++ if (p->property_oop() != NULL) {
++ f->do_oop(p->property_oop_addr());
++ }
++ }
++ }
++}
++
++void SymbolPropertyTable::methods_do(void f(methodOop)) {
++ for (int index = 0; index < table_size(); index++) {
++ for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
++ oop prop = p->property_oop();
++ if (prop != NULL && prop->is_method()) {
++ f((methodOop)prop);
++ }
++ }
++ }
++}
++
++
+ // ----------------------------------------------------------------------------
+ #ifndef PRODUCT
+
+diff --git a/src/share/vm/classfile/dictionary.hpp b/src/share/vm/classfile/dictionary.hpp
+--- a/src/share/vm/classfile/dictionary.hpp
++++ b/src/share/vm/classfile/dictionary.hpp
+@@ -217,3 +217,111 @@
+ tty->print_cr("pd set = #%d", count);
+ }
+ };
++
++class SymbolPropertyEntry : public HashtableEntry {
++ friend class VMStructs;
++ private:
++ oop _property_oop;
++ address _property_data;
++
++ public:
++ symbolOop symbol() const { return (symbolOop) literal(); }
++
++ oop property_oop() const { return _property_oop; }
++ void set_property_oop(oop p) { _property_oop = p; }
++
++ address property_data() const { return _property_data; }
++ void set_property_data(address p) { _property_data = p; }
++
++ SymbolPropertyEntry* next() const {
++ return (SymbolPropertyEntry*)HashtableEntry::next();
++ }
++
++ SymbolPropertyEntry** next_addr() {
++ return (SymbolPropertyEntry**)HashtableEntry::next_addr();
++ }
++
++ oop* symbol_addr() { return literal_addr(); }
++ oop* property_oop_addr() { return &_property_oop; }
++
++ void print_on(outputStream* st) const {
++ symbol()->print_value_on(st);
++ st->print(" -> ");
++ bool printed = false;
++ if (property_oop() != NULL) {
++ property_oop()->print_value_on(st);
++ printed = true;
++ }
++ if (property_data() != NULL) {
++ if (printed) st->print(" and ");
++ st->print(INTPTR_FORMAT, property_data());
++ printed = true;
++ }
++ st->print_cr(printed ? "" : "(empty)");
++ }
++};
++
++class SymbolPropertyTable : public Hashtable {
++ friend class VMStructs;
++private:
++ SymbolPropertyEntry* bucket(int i) {
++ return (SymbolPropertyEntry*) Hashtable::bucket(i);
++ }
++
++ // The following method is not MT-safe and must be done under lock.
++ SymbolPropertyEntry** bucket_addr(int i) {
++ return (SymbolPropertyEntry**) Hashtable::bucket_addr(i);
++ }
++
++ void add_entry(int index, SymbolPropertyEntry* new_entry) {
++ ShouldNotReachHere();
++ }
++ void set_entry(int index, SymbolPropertyEntry* new_entry) {
++ ShouldNotReachHere();
++ }
++
++ SymbolPropertyEntry* new_entry(unsigned int hash, symbolOop symbol) {
++ SymbolPropertyEntry* entry = (SymbolPropertyEntry*) Hashtable::new_entry(hash, symbol);
++ entry->set_property_oop(NULL);
++ entry->set_property_data(NULL);
++ return entry;
++ }
++
++public:
++ SymbolPropertyTable(int table_size)
++ : Hashtable(table_size, sizeof(SymbolPropertyEntry))
++ { }
++ SymbolPropertyTable(int table_size, HashtableBucket* t, int number_of_entries)
++ : Hashtable(table_size, sizeof(SymbolPropertyEntry), t, number_of_entries)
++ { }
++
++ void free_entry(SymbolPropertyEntry* entry) {
++ Hashtable::free_entry(entry);
++ }
++
++ unsigned int compute_hash(symbolHandle sym) {
++ // Use the regular identity_hash.
++ return Hashtable::compute_hash(sym);
++ }
++
++ // need not be locked; no state change
++ SymbolPropertyEntry* find_entry(int index, unsigned int hash, symbolHandle name);
++
++ // must be done under SystemDictionary_lock
++ SymbolPropertyEntry* add_entry(int index, unsigned int hash, symbolHandle name);
++
++ // GC support
++ void oops_do(OopClosure* f);
++ void methods_do(void f(methodOop));
++
++ // Sharing support
++ void dump(SerializeOopClosure* soc);
++ void restore(SerializeOopClosure* soc);
++ void reorder_dictionary();
++
++#ifndef PRODUCT
++ void print();
++#endif
++ void verify();
++};
++
+diff --git a/src/share/vm/classfile/javaClasses.cpp b/src/share/vm/classfile/javaClasses.cpp
+--- a/src/share/vm/classfile/javaClasses.cpp
++++ b/src/share/vm/classfile/javaClasses.cpp
+@@ -25,13 +25,24 @@
+ # include "incls/_precompiled.incl"
+ # include "incls/_javaClasses.cpp.incl"
+
++static bool find_field(instanceKlass* ik,
++ symbolOop name_symbol, symbolOop signature_symbol,
++ fieldDescriptor* fd,
++ bool allow_super = false) {
++ if (allow_super)
++ return ik->find_field(name_symbol, signature_symbol, fd);
++ else
++ return ik->find_local_field(name_symbol, signature_symbol, fd);
++}
++
+ // Helpful routine for computing field offsets at run time rather than hardcoding them
+ static void
+ compute_offset(int &dest_offset,
+- klassOop klass_oop, symbolOop name_symbol, symbolOop signature_symbol) {
++ klassOop klass_oop, symbolOop name_symbol, symbolOop signature_symbol,
++ bool allow_super = false) {
+ fieldDescriptor fd;
+ instanceKlass* ik = instanceKlass::cast(klass_oop);
+- if (!ik->find_local_field(name_symbol, signature_symbol, &fd)) {
++ if (!find_field(ik, name_symbol, signature_symbol, &fd, allow_super)) {
+ ResourceMark rm;
+ tty->print_cr("Invalid layout of %s at %s", ik->external_name(), name_symbol->as_C_string());
+ fatal("Invalid layout of preloaded class");
+@@ -39,16 +50,29 @@
+ dest_offset = fd.offset();
+ }
+
++static void
++compute_offset(int &dest_offset,
++ klassOop klass_oop, symbolOop name_symbol, klassOop signature_klass,
++ bool allow_super = false) {
++ EXCEPTION_MARK;
++ ResourceMark rm(THREAD);
++ const char* signature_name = Klass::cast(signature_klass)->signature_name();
++ symbolOop signature_symbol = oopFactory::new_symbol(signature_name, CATCH);
++ compute_offset(dest_offset, klass_oop, name_symbol, signature_symbol, allow_super);
++}
++
+ // Same as above but for "optional" offsets that might not be present in certain JDK versions
+ static void
+ compute_optional_offset(int& dest_offset,
+- klassOop klass_oop, symbolOop name_symbol, symbolOop signature_symbol) {
++ klassOop klass_oop, symbolOop name_symbol, symbolOop signature_symbol,
++ bool allow_super = false) {
+ fieldDescriptor fd;
+ instanceKlass* ik = instanceKlass::cast(klass_oop);
+- if (ik->find_local_field(name_symbol, signature_symbol, &fd)) {
++ if (find_field(ik, name_symbol, signature_symbol, &fd, allow_super)) {
+ dest_offset = fd.offset();
+ }
+ }
++
+
+ Handle java_lang_String::basic_create(int length, bool tenured, TRAPS) {
+ // Create the String object first, so there's a chance that the String
+@@ -1970,6 +1994,21 @@
+ }
+
+
++void java_lang_boxing_object::print(BasicType type, jvalue* value, outputStream* st) {
++ switch (type) {
++ case T_BOOLEAN: st->print("%s", value->z ? "true" : "false"); break;
++ case T_CHAR: st->print("%d", value->c); break;
++ case T_BYTE: st->print("%d", value->b); break;
++ case T_SHORT: st->print("%d", value->s); break;
++ case T_INT: st->print("%d", value->i); break;
++ case T_LONG: st->print(INT64_FORMAT, value->j); break;
++ case T_FLOAT: st->print("%f", value->f); break;
++ case T_DOUBLE: st->print("%lf", value->d); break;
++ default: st->print("type %d?", type); break;
++ }
++}
++
++
+ // Support for java_lang_ref_Reference
+ oop java_lang_ref_Reference::pending_list_lock() {
+ instanceKlass* ik = instanceKlass::cast(SystemDictionary::reference_klass());
+@@ -2016,6 +2055,135 @@
+ int offset = ik->offset_of_static_fields() + static_clock_offset;
+
+ SystemDictionary::soft_reference_klass()->long_field_put(offset, value);
++}
++
++
++// Support for java_dyn_MethodHandle
++
++int java_dyn_MethodHandle::_type_offset;
++int java_dyn_MethodHandle::_vmref_offset;
++int java_dyn_MethodHandle::_vmdata_offset;
++int java_dyn_MethodHandle::_entry_offset;
++
++void java_dyn_MethodHandle::compute_offsets() {
++ klassOop k = SystemDictionary::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);
++ if (_entry_offset != 0) _entry_offset += oopDesc::address_padding_in_bytes();
++ if (_vmdata_offset != 0) _vmdata_offset += oopDesc::address_padding_in_bytes();
++ guarantee((_vmref_offset != 0 &&
++ _vmdata_offset != 0 &&
++ _entry_offset != 0), "mismatched method handle support");
++
++ }
++}
++
++oop java_dyn_MethodHandle::type(oop mh) {
++ return mh->obj_field(_type_offset);
++}
++
++oop java_dyn_MethodHandle::vmref(oop mh) {
++ return mh->obj_field(_vmref_offset);
++}
++
++void java_dyn_MethodHandle::set_vmref(oop mh, oop ref) {
++ 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);
++}
++
++MethodEntry* java_dyn_MethodHandle::entry(oop mh) {
++ return (MethodEntry*) mh->address_field(_entry_offset);
++}
++
++void java_dyn_MethodHandle::set_entry(oop mh, MethodEntry* me) {
++ // this is the final step that initializes a valid method handle:
++ mh->release_address_field_put(_entry_offset, (address) me);
++}
++
++methodOop java_dyn_MethodHandle::method(oop mh) {
++ klassOop mhk = mh->klass();
++ if (mhk == SystemDictionary::hotspot_DMH_klass()) {
++ oop ref = java_dyn_MethodHandle::vmref(mh);
++ if (ref != NULL) {
++ if (ref->is_method()) {
++ // an invokestatic or invokespecial DMH mentions the method
++ // to make things easier, an invokevirtual DMH also mentions it
++ return (methodOop) ref;
++ }
++ if (ref->is_klass() && Klass::cast((klassOop)ref)->is_interface()) {
++ // an itable linkage is <interface, itable indemh>
++ intptr_t index = (intptr_t) java_dyn_MethodHandle::vmdata(mh);
++ return klassItable::method_for_itable_index((klassOop)ref, index);
++ }
++ }
++ }
++ return NULL;
++}
++
++
++// Support for java_dyn_MethodType
++
++int java_dyn_MethodType::_rtype_offset;
++int java_dyn_MethodType::_ptypes_offset;
++int java_dyn_MethodType::_form_offset;
++int java_dyn_MethodType::Form::_vmref_offset;
++int java_dyn_MethodType::Form::_vmdata_offset;
++
++void java_dyn_MethodType::compute_offsets() {
++ klassOop k = SystemDictionary::methodType_klass();
++ if (k != NULL) {
++ compute_offset(_rtype_offset, k, vmSymbols::rtype_name(), vmSymbols::class_signature());
++ compute_offset(_ptypes_offset, k, vmSymbols::ptypes_name(), vmSymbols::class_array_signature());
++ compute_offset(_form_offset, k, vmSymbols::form_name(), vmSymbols::methodTypeForm_signature());
++ }
++ java_dyn_MethodType::Form::compute_offsets();
++}
++
++void java_dyn_MethodType::Form::compute_offsets() {
++ klassOop k = SystemDictionary::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);
++ if (_vmdata_offset != 0) _vmdata_offset += oopDesc::address_padding_in_bytes();
++ }
++}
++
++oop java_dyn_MethodType::rtype(oop mt) {
++ return mt->obj_field(_rtype_offset);
++}
++
++objArrayOop java_dyn_MethodType::ptypes(oop mt) {
++ return (objArrayOop) mt->obj_field(_ptypes_offset);
++}
++
++oop java_dyn_MethodType::form(oop mt) {
++ return mt->obj_field(_form_offset);
++}
++
++oop java_dyn_MethodType::Form::vmref(oop mtform) {
++ return mtform->obj_field(_vmref_offset);
++}
++
++void java_dyn_MethodType::Form::set_vmref(oop mtform, oop ref) {
++ mtform->obj_field_put(_vmref_offset, ref);
++}
++
++address java_dyn_MethodType::Form::vmdata(oop mtform) {
++ return mtform->address_field(_vmdata_offset);
++}
++
++void java_dyn_MethodType::Form::set_vmdata(oop mtform, address data) {
++ mtform->address_field_put(_vmdata_offset, data);
+ }
+
+
+@@ -2354,6 +2522,10 @@
+ java_lang_System::compute_offsets();
+ java_lang_Thread::compute_offsets();
+ java_lang_ThreadGroup::compute_offsets();
++ if (MethodHandles || InvokeDynamic) {
++ java_dyn_MethodHandle::compute_offsets();
++ java_dyn_MethodType::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
+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
+@@ -665,6 +665,8 @@
+ static BasicType basic_type(oop box);
+ static bool is_instance(oop box) { return basic_type(box) != T_ILLEGAL; }
+ static bool is_instance(oop box, BasicType type) { return basic_type(box) == type; }
++ static void print(oop box, outputStream* st) { jvalue value; print(get_value(box, &value), &value, st); }
++ static void print(BasicType type, jvalue* value, outputStream* st);
+
+ static int value_offset_in_bytes(BasicType type) {
+ return ( type == T_LONG || type == T_DOUBLE ) ? long_value_offset :
+@@ -769,6 +771,93 @@
+ };
+
+
++// Interface to java.dyn.MethodHandle objects
++
++class MethodEntry;
++
++class java_dyn_MethodHandle: AllStatic {
++ friend class JavaClasses;
++
++ private:
++ static int _type_offset;
++ static int _vmref_offset;
++ static int _vmdata_offset;
++ static int _entry_offset;
++
++ static void compute_offsets();
++
++ public:
++ // Accessors
++ static oop type(oop mh);
++
++ 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);
++
++ static MethodEntry* entry(oop mh);
++ static void set_entry(oop mh, MethodEntry* data);
++
++ static methodOop method(oop mh); // returns NULL if not available
++
++ // 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 entry_offset_in_bytes() { return _entry_offset; }
++};
++
++
++// Interface to java.dyn.MethodType objects
++
++class java_dyn_MethodType: AllStatic {
++ friend class JavaClasses;
++
++ private:
++ static int _rtype_offset;
++ static int _ptypes_offset;
++ static int _form_offset;
++
++ static void compute_offsets();
++
++ public:
++ // Accessors
++ static oop rtype(oop mh);
++ static objArrayOop ptypes(oop mh);
++ static oop form(oop mh);
++
++ // Accessors for code generation:
++ static int rtype_offset_in_bytes() { return _rtype_offset; }
++ static int ptypes_offset_in_bytes() { return _ptypes_offset; }
++ static int form_offset_in_bytes() { return _form_offset; }
++
++ class Form: AllStatic {
++ friend class JavaClasses;
++ friend class java_dyn_MethodType;
++
++ private:
++ static int _vmref_offset;
++ static int _vmdata_offset;
++
++ static void compute_offsets();
++
++ public:
++ // Accessors
++ 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);
++
++ // Accessors for code generation:
++ static int vmref_offset_in_bytes() { return _vmref_offset; }
++ static int vmdata_offset_in_bytes() { return _vmdata_offset; }
++ };
++
++};
++
++
+ // Interface to java.security.AccessControlContext objects
+
+ class java_security_AccessControlContext: AllStatic {
+diff --git a/src/share/vm/classfile/loaderConstraints.hpp b/src/share/vm/classfile/loaderConstraints.hpp
+--- a/src/share/vm/classfile/loaderConstraints.hpp
++++ b/src/share/vm/classfile/loaderConstraints.hpp
+@@ -60,8 +60,10 @@
+ bool add_entry(symbolHandle name, klassOop klass1, Handle loader1,
+ klassOop klass2, Handle loader2);
+
+- void check_signature_loaders(symbolHandle signature, Handle loader1,
+- Handle loader2, bool is_method, TRAPS);
++ // Note: The main entry point for this module is via SystemDictionary.
++ // SystemDictionary::check_signature_loaders(symbolHandle signature,
++ // Handle loader1, Handle loader2,
++ // bool is_method, TRAPS)
+
+ klassOop find_constrained_klass(symbolHandle name, Handle loader);
+ klassOop find_constrained_elem_klass(symbolHandle name, symbolHandle elem_name,
+diff --git a/src/share/vm/classfile/systemDictionary.cpp b/src/share/vm/classfile/systemDictionary.cpp
+--- a/src/share/vm/classfile/systemDictionary.cpp
++++ b/src/share/vm/classfile/systemDictionary.cpp
+@@ -31,6 +31,7 @@
+ Dictionary* SystemDictionary::_shared_dictionary = NULL;
+ LoaderConstraintTable* SystemDictionary::_loader_constraints = NULL;
+ ResolutionErrorTable* SystemDictionary::_resolution_errors = NULL;
++SymbolPropertyTable* SystemDictionary::_invoke_method_table = NULL;
+
+
+ int SystemDictionary::_number_of_modifications = 0;
+@@ -1660,6 +1661,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);
+
+@@ -1732,6 +1737,8 @@
+
+ void SystemDictionary::methods_do(void f(methodOop)) {
+ dictionary()->methods_do(f);
++ if (invoke_method_table() != NULL)
++ invoke_method_table()->methods_do(f);
+ }
+
+ // ----------------------------------------------------------------------------
+@@ -1764,6 +1771,7 @@
+ _number_of_modifications = 0;
+ _loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
+ _resolution_errors = new ResolutionErrorTable(_resolution_error_size);
++ //_invoke_method_table = new SymbolPropertyTable(_invoke_method_size);
+
+ // Allocate private object used as system class loader lock
+ _system_loader_lock_obj = oopFactory::new_system_objArray(0, CHECK);
+@@ -1825,6 +1833,9 @@
+ wk_klass_name_limits[0] = s;
+ }
+ }
++
++ // move the starting value forward to the limit:
++ start_id = limit_id;
+ }
+
+
+@@ -1857,6 +1868,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) {
++ // Skip the rest of the dynamic typing classes, if MethodHandle is not found.
++ scan = WKID(WK_KLASS_ENUM_NAME(dynamic_klass)+1);
++ }
+
+ initialize_wk_klasses_until(WKID_LIMIT, scan, CHECK);
+
+@@ -2108,11 +2125,56 @@
+ }
+
+
++// Signature constraints ensure that callers and callees agree about
++// the meaning of type names in their signatures. This routine is the
++// intake for constraints. It collects them from several places:
++//
++// * LinkResolver::resolve_method (if check_access is true) requires
++// that the resolving class (the caller) and the defining class of
++// the resolved method (the callee) agree on each type in the
++// method's signature.
++//
++// * LinkResolver::resolve_interface_method performs exactly the same
++// checks.
++//
++// * LinkResolver::resolve_field requires that the constant pool
++// attempting to link to a field agree with the field's defining
++// class about the type of the field signature.
++//
++// * klassVtable::initialize_vtable requires that, when a class
++// overrides a vtable entry allocated by a superclass, that the
++// overriding method (i.e., the callee) agree with the superclass
++// on each type in the method's signature.
++//
++// * klassItable::initialize_itable requires that, when a class fills
++// in its itables, for each non-abstract method installed in an
++// itable, the method (i.e., the callee) agree with the interface
++// on each type in the method's signature.
++//
++// All those methods have a boolean (check_access, checkconstraints)
++// which turns off the checks. This is used from specialized contexts
++// such as bootstrapping, dumping, and debugging.
++//
++// No direct constraint is placed between the class and its
++// supertypes. Constraints are only placed along linked relations
++// between callers and callees. When a method overrides or implements
++// an abstract method in a supertype (superclass or interface), the
++// constraints are placed as if the supertype were the caller to the
++// overriding method. (This works well, since callers to the
++// supertype have already established agreement between themselves and
++// the supertype.) As a result of all this, a class can disagree with
++// its supertype about the meaning of a type name, as long as that
++// class neither calls a relevant method of the supertype, nor is
++// called (perhaps via an override) from the supertype.
++//
++//
++// SystemDictionary::check_signature_loaders(sig, l1, l2)
++//
+ // Make sure all class components (including arrays) in the given
+ // signature will be resolved to the same class in both loaders.
+ // Returns the name of the type that failed a loader constraint check, or
+ // NULL if no constraint failed. The returned C string needs cleaning up
+-// with a ResourceMark in the caller
++// with a ResourceMark in the caller. No exception except OOME is thrown.
+ char* SystemDictionary::check_signature_loaders(symbolHandle signature,
+ Handle loader1, Handle loader2,
+ bool is_method, TRAPS) {
+@@ -2133,6 +2195,80 @@
+ sig_strm.next();
+ }
+ return NULL;
++}
++
++
++methodOop SystemDictionary::find_method_handle_invoke(symbolHandle signature, TRAPS) {
++ assert(MethodHandles, "");
++ if (invoke_method_table() == NULL) {
++ // create this side table lazily
++ _invoke_method_table = new SymbolPropertyTable(_invoke_method_size);
++ }
++ unsigned int hash = invoke_method_table()->compute_hash(signature);
++ int index = invoke_method_table()->hash_to_index(hash);
++ SymbolPropertyEntry* spe = invoke_method_table()->find_entry(index, hash, signature);
++ if (spe == NULL || spe->property_oop() == NULL) {
++ // Must create lots of stuff here, but outside of the SystemDictionary lock.
++ Handle mt;
++ {
++ oop mt_oop = compute_method_handle_type(signature(), CHECK_NULL);
++ mt = Handle(THREAD, mt_oop);
++ }
++ 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.
++ {
++ MutexLocker ml(SystemDictionary_lock, Thread::current());
++ spe = invoke_method_table()->find_entry(index, hash, signature);
++ if (spe == NULL)
++ spe = invoke_method_table()->add_entry(index, hash, signature);
++ if (spe->property_oop() == NULL)
++ spe->set_property_oop(m());
++ }
++ }
++ methodOop m = (methodOop) spe->property_oop();
++ assert(m->is_method(), "");
++ return m;
++}
++
++// Ask Java code to find or construct a java.dyn.MethodType for the given
++// signature, as interpreted relative to the system class loader.
++// Because of class loader constraints, all method handle usage is
++// consistent with this loader.
++oop SystemDictionary::compute_method_handle_type(symbolHandle signature, TRAPS) {
++ Handle rt;
++ int npts = ArgumentCount(signature()).size();
++ objArrayHandle pts = oopFactory::new_objArray(SystemDictionary::object_klass(), npts, CHECK_NULL);
++ int arg = 0;
++ 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);
++ symbolHandle name(THREAD, name_oop);
++ klassOop klass = resolve_or_fail(name, true, CHECK_NULL);
++ mirror = Klass::cast(klass)->java_mirror();
++ }
++ if (ss.at_return_type())
++ rt = Handle(THREAD, mirror);
++ else
++ pts->obj_at_put(arg++, mirror);
++ }
++ assert(arg == npts, "");
++
++ // call MethodType java.dyn.MethodType::makeImpl(Class rt, Class[] pts, false, true)
++ bool varargs = false, trusted = true;
++ JavaCallArguments args(rt());
++ args.push_oop(pts());
++ args.push_int(false);
++ args.push_int(trusted);
++ JavaValue result(T_OBJECT);
++ JavaCalls::call_static(&result,
++ SystemDictionary::methodType_klass(),
++ vmSymbols::makeImpl_name(), vmSymbols::makeImpl_signature(),
++ &args, CHECK_NULL);
++ return (oop) result.get_jobject();
+ }
+
+
+diff --git a/src/share/vm/classfile/systemDictionary.hpp b/src/share/vm/classfile/systemDictionary.hpp
+--- a/src/share/vm/classfile/systemDictionary.hpp
++++ b/src/share/vm/classfile/systemDictionary.hpp
+@@ -63,6 +63,7 @@
+ class LoaderConstraintTable;
+ class HashtableBucket;
+ class ResolutionErrorTable;
++class SymbolPropertyTable;
+
+ // Certain classes are preloaded, such as java.lang.Object and java.lang.String.
+ // They are all "well-known", in the sense that no class loader is allowed
+@@ -130,6 +131,19 @@
+ template(reflect_delegating_classloader_klass, sun_reflect_DelegatingClassLoader, Opt) \
+ 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(hotspot_AMH_klass, java_dyn_hotspot_AMH, Opt) \
++ template(hotspot_BMH_klass, java_dyn_hotspot_BMH, Opt) \
++ template(hotspot_DMH_klass, java_dyn_hotspot_DMH, Opt) \
++ template(hotspot_MTForm_klass, java_dyn_hotspot_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) \
++ /* Note: MethodHandle must be first, and Dynamic last in group */ \
+ \
+ template(vector_klass, java_util_Vector, Pre) \
+ template(hashtable_klass, java_util_Hashtable, Pre) \
+@@ -433,6 +447,12 @@
+ 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);
++ // ask Java to compute the java.dyn.MethodType object for a given signature
++ static oop compute_method_handle_type(symbolHandle signature, TRAPS);
++
+ // Utility for printing loader "name" as part of tracing constraints
+ static const char* loader_name(oop loader) {
+ return ((loader) == NULL ? "<bootloader>" :
+@@ -449,6 +469,7 @@
+ enum Constants {
+ _loader_constraint_size = 107, // number of entries in constraint table
+ _resolution_error_size = 107, // number of entries in resolution error table
++ _invoke_method_size = 139, // number of entries in invoke method table
+ _nof_buckets = 1009 // number of buckets in hash table
+ };
+
+@@ -478,6 +499,9 @@
+ // Resolution errors
+ static ResolutionErrorTable* _resolution_errors;
+
++ // Invoke methods (JSR 292)
++ static SymbolPropertyTable* _invoke_method_table;
++
+ public:
+ // for VM_CounterDecay iteration support
+ friend class CounterDecay;
+@@ -495,6 +519,7 @@
+ static PlaceholderTable* placeholders() { return _placeholders; }
+ static LoaderConstraintTable* constraints() { return _loader_constraints; }
+ static ResolutionErrorTable* resolution_errors() { return _resolution_errors; }
++ static SymbolPropertyTable* invoke_method_table() { return _invoke_method_table; }
+
+ // Basic loading operations
+ static klassOop resolve_instance_class_or_null(symbolHandle class_name, Handle class_loader, Handle protection_domain, TRAPS);
+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
+@@ -123,6 +123,7 @@
+ template(tag_runtime_invisible_parameter_annotations,"RuntimeInvisibleParameterAnnotations") \
+ template(tag_annotation_default, "AnnotationDefault") \
+ template(tag_enclosing_method, "EnclosingMethod") \
++ template(tag_bootstrap_invoke_dynamic, "BootstrapInvokeDynamic") \
+ \
+ /* exception klasses: at least all exceptions thrown by the VM have entries here */ \
+ template(java_lang_ArithmeticException, "java/lang/ArithmeticException") \
+@@ -214,7 +215,24 @@
+ 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_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") \
++ /* internal classes known only to the JVM: */ \
++ template(java_dyn_hotspot_MTForm, "java/dyn/hotspot/MTForm") \
++ template(java_dyn_hotspot_MH, "java/dyn/hotspot/MH") \
++ template(java_dyn_hotspot_AMH, "java/dyn/hotspot/AMH") \
++ template(java_dyn_hotspot_BMH, "java/dyn/hotspot/BMH") \
++ template(java_dyn_hotspot_DMH, "java/dyn/hotspot/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;") \
++ \
++ /* common method and field names */ \
+ template(object_initializer_name, "<init>") \
+ template(class_initializer_name, "<clinit>") \
+ template(println_name, "println") \
+@@ -284,6 +302,16 @@
+ template(value_name, "value") \
+ template(frontCacheEnabled_name, "frontCacheEnabled") \
+ template(stringCacheEnabled_name, "stringCacheEnabled") \
++ template(toString_name, "toString") \
++ template(target_name, "target") \
++ template(values_name, "values") \
++ template(receiver_name, "receiver") \
++ template(vmdata_name, "vmdata") \
++ template(vmref_name, "vmref") \
++ template(rtype_name, "rtype") \
++ template(ptypes_name, "ptypes") \
++ template(form_name, "form") \
++ template(entry_name, "entry") \
+ \
+ /* non-intrinsic name/signature pairs: */ \
+ template(register_method_name, "register") \
+@@ -347,6 +375,7 @@
+ template(void_classloader_signature, "()Ljava/lang/ClassLoader;") \
+ template(void_object_signature, "()Ljava/lang/Object;") \
+ template(void_class_signature, "()Ljava/lang/Class;") \
++ template(void_string_signature, "()Ljava/lang/String;") \
+ template(object_array_object_object_signature, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")\
+ template(exception_void_signature, "(Ljava/lang/Exception;)V") \
+ template(protectiondomain_signature, "[Ljava/security/ProtectionDomain;") \
+@@ -418,8 +447,8 @@
+ template(serializePropertiesToByteArray_signature, "()[B") \
+ template(serializeAgentPropertiesToByteArray_name, "serializeAgentPropertiesToByteArray") \
+ template(classRedefinedCount_name, "classRedefinedCount") \
++ \
+ /*end*/
+-
+
+
+ // Here are all the intrinsics known to the runtime and the CI.
+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 @@
+ interpreter_<arch_model>.cpp jvmtiExport.hpp
+ interpreter_<arch_model>.cpp jvmtiThreadState.hpp
+ interpreter_<arch_model>.cpp methodDataOop.hpp
++interpreter_<arch_model>.cpp methodHandles.hpp
+ interpreter_<arch_model>.cpp methodOop.hpp
+ interpreter_<arch_model>.cpp oop.inline.hpp
+ interpreter_<arch_model>.cpp sharedRuntime.hpp
+@@ -2794,6 +2795,18 @@
+ methodDataOop.hpp orderAccess.hpp
+ methodDataOop.hpp universe.hpp
+
++methodHandles.hpp globals.hpp
++methodHandles.hpp interfaceSupport.hpp
++methodHandles.hpp vmSymbols.hpp
++
++methodHandles.cpp allocation.inline.hpp
++methodHandles.cpp interpreter.hpp
++methodHandles.cpp javaCalls.hpp
++methodHandles.cpp methodHandles.hpp
++methodHandles.cpp reflection.hpp
++methodHandles.cpp signature.hpp
++methodHandles.cpp symbolTable.hpp
++
+ methodKlass.cpp collectedHeap.inline.hpp
+ methodKlass.cpp constMethodKlass.hpp
+ methodKlass.cpp gcLocker.hpp
+@@ -3037,6 +3050,7 @@
+ oop.inline.hpp arrayOop.hpp
+ oop.inline.hpp atomic.hpp
+ oop.inline.hpp barrierSet.inline.hpp
++oop.inline.hpp bytes_<arch>.hpp
+ oop.inline.hpp cardTableModRefBS.hpp
+ oop.inline.hpp collectedHeap.inline.hpp
+ oop.inline.hpp compactingPermGenGen.hpp
+@@ -3824,6 +3838,7 @@
+ stubGenerator_<arch_model>.cpp handles.inline.hpp
+ stubGenerator_<arch_model>.cpp instanceOop.hpp
+ stubGenerator_<arch_model>.cpp interpreter.hpp
++stubGenerator_<arch_model>.cpp methodHandles.hpp
+ stubGenerator_<arch_model>.cpp methodOop.hpp
+ stubGenerator_<arch_model>.cpp nativeInst_<arch>.hpp
+ stubGenerator_<arch_model>.cpp objArrayKlass.hpp
+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
+@@ -61,6 +61,7 @@
+ empty, // empty method (code: _return)
+ accessor, // accessor method (code: _aload_0, _getfield, _(a|i)return)
+ abstract, // abstract method (throws an AbstractMethodException)
++ method_handle, // java.dyn.MethodHandle::invoke
+ java_lang_math_sin, // implementation of java.lang.Math.sin (x)
+ java_lang_math_cos, // implementation of java.lang.Math.cos (x)
+ java_lang_math_tan, // implementation of java.lang.Math.tan (x)
+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
+@@ -34,12 +34,6 @@
+ }
+
+
+-void Bytecode::set_fast_index(int i) {
+- assert(0 <= i && i < 0x10000, "illegal index value");
+- Bytes::put_native_u2(addr_at(1), (jushort)i);
+-}
+-
+-
+ 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 @@
+
+
+ int Bytecode_invoke::index() const {
+- return Bytes::get_Java_u2(bcp() + 1);
++ if (has_giant_index())
++ return Bytes::get_native_u4(bcp() + 1);
++ else
++ return Bytes::get_Java_u2(bcp() + 1);
+ }
+
+
+diff --git a/src/share/vm/interpreter/bytecode.hpp b/src/share/vm/interpreter/bytecode.hpp
+--- a/src/share/vm/interpreter/bytecode.hpp
++++ b/src/share/vm/interpreter/bytecode.hpp
+@@ -65,14 +65,6 @@
+ // The base class for different kinds of bytecode abstractions.
+ // Provides the primitive operations to manipulate code relative
+ // to an objects 'this' pointer.
+-//
+-// Note: Even though it seems that the fast_index & set_fast_index
+-// functions are machine specific, they're not. They only use
+-// the natural way to store a 16bit index on a given machine,
+-// independent of the particular byte ordering. Since all other
+-// places in the system that refer to these indices use the
+-// same method (the natural byte ordering on the platform)
+-// this will always work and be machine-independent).
+
+ class Bytecode: public ThisRelativeObj {
+ protected:
+@@ -83,24 +75,41 @@
+ // Attributes
+ address bcp() const { return addr_at(0); }
+ address next_bcp() const { return addr_at(0) + Bytecodes::length_at(bcp()); }
++ int instruction_size() const { return Bytecodes::length_at(bcp()); }
+
+ Bytecodes::Code code() const { return Bytecodes::code_at(addr_at(0)); }
++ Bytecodes::Code raw_code() const { return Bytecodes::raw_code_at(addr_at(0)); }
+ Bytecodes::Code java_code() const { return Bytecodes::java_code(code()); }
+ bool must_rewrite() const { return Bytecodes::can_rewrite(code()) && check_must_rewrite(); }
+ bool is_active_breakpoint() const { return Bytecodes::is_active_breakpoint_at(bcp()); }
+
+- int one_byte_index() const { return byte_at(1); }
+- int two_byte_index() const { return (byte_at(1) << 8) + byte_at(2); }
++ int one_byte_index() const { assert_index_size(1); return byte_at(1); }
++ int two_byte_index() const { assert_index_size(2); return (byte_at(1) << 8) + byte_at(2); }
++
+ int offset() const { return (two_byte_index() << 16) >> 16; }
+ address destination() const { return bcp() + offset(); }
+- int fast_index() const { return Bytes::get_native_u2(addr_at(1)); }
+
+ // Attribute modification
+ void set_code(Bytecodes::Code code);
+- void set_fast_index(int i);
+
+ // Creation
+ inline friend Bytecode* Bytecode_at(address bcp);
++
++ private:
++ void assert_index_size(int required_size) const {
++#ifdef ASSERT
++ int isize = instruction_size() - 1;
++ if (isize == 2 && raw_code() == Bytecodes::_iinc)
++ isize = 1;
++ else if (isize <= 2)
++ ; // no change
++ else if (raw_code() == Bytecodes::_invokedynamic)
++ isize = 4;
++ else
++ isize = 2;
++ assert(isize = required_size, "wrong index size");
++#endif
++ }
+ };
+
+ inline Bytecode* Bytecode_at(address bcp) {
+@@ -185,6 +194,7 @@
+ symbolOop signature() const; // returns the signature of the invoked method
+ BasicType result_type(Thread *thread) const; // returns the result type of the invoke
+
++ Bytecodes::Code raw_code() const { return Bytecodes::raw_code_at(bcp(), _method()); }
+ Bytecodes::Code code() const { return Bytecodes::code_at(bcp(), _method()); }
+ Bytecodes::Code adjusted_invoke_code() const { return Bytecodes::java_code(code()); }
+
+@@ -195,6 +205,7 @@
+ bool is_invokevirtual() const { return adjusted_invoke_code() == Bytecodes::_invokevirtual; }
+ bool is_invokestatic() const { return adjusted_invoke_code() == Bytecodes::_invokestatic; }
+ bool is_invokespecial() const { return adjusted_invoke_code() == Bytecodes::_invokespecial; }
++ bool has_giant_index() const { return raw_code() == Bytecodes::_invokedynamic; }
+
+ bool is_valid() const { return is_invokeinterface() ||
+ is_invokevirtual() ||
+diff --git a/src/share/vm/interpreter/bytecodeStream.hpp b/src/share/vm/interpreter/bytecodeStream.hpp
+--- a/src/share/vm/interpreter/bytecodeStream.hpp
++++ b/src/share/vm/interpreter/bytecodeStream.hpp
+@@ -108,7 +108,9 @@
+ int end_bci() const { return _end_bci; }
+
+ Bytecodes::Code code() const { return _code; }
++ Bytecodes::Code raw_code() const { return Bytecodes::raw_code_at(bcp()); }
+ bool is_wide() const { return _is_wide; }
++ int instruction_size() const { return (_next_bci - _bci); }
+ bool is_last_bytecode() const { return _next_bci >= _end_bci; }
+
+ address bcp() const { return method()->code_base() + _bci; }
+@@ -122,8 +124,29 @@
+ int dest_w() const { return bci() + (int )Bytes::get_Java_u4(bcp() + 1); }
+
+ // Unsigned indices, widening
+- int get_index() const { return (is_wide()) ? Bytes::get_Java_u2(bcp() + 2) : bcp()[1]; }
+- int get_index_big() const { return (int)Bytes::get_Java_u2(bcp() + 1); }
++ int get_index() const { assert_index_size(is_wide() ? 2 : 1);
++ return (is_wide()) ? Bytes::get_Java_u2(bcp() + 2) : bcp()[1]; }
++ int get_index_big() const { assert_index_size(2);
++ return (int)Bytes::get_Java_u2(bcp() + 1); }
++ int get_index_int() const { return has_giant_index() ? get_index_giant() : get_index_big(); }
++ int get_index_giant() const { assert_index_size(4); return Bytes::get_native_u4(bcp() + 1); }
++ int has_giant_index() const { return (raw_code() == Bytecodes::_invokedynamic); }
++
++ private:
++ void assert_index_size(int required_size) const {
++#ifdef ASSERT
++ int isize = instruction_size() - (int)_is_wide - 1;
++ if (isize == 2 && raw_code() == Bytecodes::_iinc)
++ isize = 1;
++ else if (isize <= 2)
++ ; // no change
++ else if (has_giant_index())
++ isize = 4;
++ else
++ isize = 2;
++ assert(isize = required_size, "wrong index size");
++#endif
++ }
+ };
+
+ // In BytecodeStream, non-java bytecodes will be translated into the
+diff --git a/src/share/vm/interpreter/bytecodeTracer.cpp b/src/share/vm/interpreter/bytecodeTracer.cpp
+--- a/src/share/vm/interpreter/bytecodeTracer.cpp
++++ b/src/share/vm/interpreter/bytecodeTracer.cpp
+@@ -48,12 +48,15 @@
+
+ int get_index() { return *(address)_next_pc++; }
+ int get_big_index() { int i=Bytes::get_Java_u2(_next_pc); _next_pc+=2; return i; }
++ int get_giant_index() { int i=Bytes::get_native_u4(_next_pc); _next_pc+=4; return i; }
+ int get_index_special() { return (is_wide()) ? get_big_index() : get_index(); }
+ methodOop method() { return _current_method; }
+ bool is_wide() { return _is_wide; }
+
+
++ bool check_index(int i, bool in_cp_cache, 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 @@
+ }
+ }
+
++bool BytecodePrinter::check_index(int i, bool in_cp_cache, outputStream* st) {
++ constantPoolOop constants = method()->constants();
++ int ilimit = constants->length(), climit = 0;
++
++ constantPoolCacheOop cache = NULL;
++ if (in_cp_cache) {
++ cache = constants->cache();
++ if (cache != NULL) {
++ //climit = cache->length(); // %%% private!
++ size_t size = cache->size() * HeapWordSize;
++ size -= sizeof(constantPoolCacheOopDesc);
++ size /= sizeof(ConstantPoolCacheEntry);
++ climit = size;
++ }
++ }
++
++ if (in_cp_cache && constantPoolCacheOopDesc::is_secondary_index(i)) {
++ i = constantPoolCacheOopDesc::decode_secondary_index(i);
++ st->print(" secondary cache[%d] of", i);
++ if (i >= 0 && i < climit) {
++ if (!cache->entry_at(i)->is_secondary_entry()) {
++ st->print_cr(" not secondary entry?", i);
++ return false;
++ }
++ i = cache->entry_at(i)->main_entry_index();
++ goto check_cache_index;
++ } else {
++ st->print_cr(" not in cache[*]?", i);
++ return false;
++ }
++ }
++
++ if (cache != NULL) {
++ i = Bytes::swap_u2(i);
++ if (WizardMode) st->print(" (swap=%d)", i);
++ goto check_cache_index;
++ }
++
++ check_cp_index:
++ if (i >= 0 && i < ilimit) {
++ if (WizardMode) st->print(" cp[%d]", i);
++ return true;
++ }
++
++ st->print_cr(" CP[%d] not in CP", i);
++ return false;
++
++ check_cache_index:
++ if (i >= 0 && i < climit) {
++ if (cache->entry_at(i)->is_secondary_entry()) {
++ st->print_cr(" secondary entry?");
++ return false;
++ }
++ i = cache->entry_at(i)->constant_pool_index();
++ goto check_cp_index;
++ }
++ st->print_cr(" not in CP[*]?", i);
++ return false;
++}
++
+ void BytecodePrinter::print_constant(int i, outputStream* st) {
++ if (!check_index(i, false, st)) return;
++
+ constantPoolOop constants = method()->constants();
+ constantTag tag = constants->tag_at(i);
+
+@@ -203,13 +268,36 @@
+ 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);
+- } else ShouldNotReachHere();
++ } else {
++ st->print_cr(" bad tag=%d at %d", tag.value(), i);
++ }
+ }
+
++void BytecodePrinter::print_field_or_method(int i, outputStream* st) {
++ if (!check_index(i, true, st)) return;
+
+-void BytecodePrinter::print_attributes(Bytecodes::Code code, int bci, outputStream* st) {
++ constantPoolOop constants = method()->constants();
++ constantTag tag = constants->tag_at(i);
++
++ switch (tag.value()) {
++ case JVM_CONSTANT_InterfaceMethodref:
++ case JVM_CONSTANT_Methodref:
++ case JVM_CONSTANT_Fieldref:
++ break;
++ default:
++ st->print_cr(" bad tag=%d at %d", tag.value(), i);
++ return;
++ }
++
++ symbolOop name = constants->name_ref_at(i);
++ symbolOop signature = constants->signature_ref_at(i);
++ st->print_cr(" %d <%s> <%s> ", i, name->as_C_string(), signature->as_C_string());
++}
++
++
++void BytecodePrinter::print_attributes(Bytecodes::Code raw_code, int bci, outputStream* st) {
+ // Show attributes of pre-rewritten codes
+- code = Bytecodes::java_code(code);
++ Bytecodes::Code code = Bytecodes::java_code(raw_code);
+ // 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 @@
+ case Bytecodes::_putstatic:
+ case Bytecodes::_getstatic:
+ case Bytecodes::_putfield:
+- case Bytecodes::_getfield: {
+- int i = get_big_index();
+- constantPoolOop constants = method()->constants();
+- symbolOop field = constants->name_ref_at(i);
+- st->print_cr(" %d <%s>", i, field->as_C_string());
+- }
++ case Bytecodes::_getfield:
++ print_field_or_method(get_big_index(), st);
+ break;
+
+ case Bytecodes::_invokevirtual:
+ case Bytecodes::_invokespecial:
+ case Bytecodes::_invokestatic:
+- { int i = get_big_index();
+- constantPoolOop constants = method()->constants();
+- symbolOop name = constants->name_ref_at(i);
+- symbolOop signature = constants->signature_ref_at(i);
+- st->print_cr(" %d <%s> <%s> ", i, name->as_C_string(), signature->as_C_string());
+- }
++ print_field_or_method(get_big_index(), st);
+ break;
+
+ case Bytecodes::_invokeinterface:
+- { int i = get_big_index();
++ if (raw_code == Bytecodes::_invokedynamic) {
++ int i = get_giant_index();
++ print_field_or_method(i, st);
++ } else {
++ int i = get_big_index();
+ int n = get_index();
+- get_index();
+- constantPoolOop constants = method()->constants();
+- symbolOop name = constants->name_ref_at(i);
+- symbolOop signature = constants->signature_ref_at(i);
+- st->print_cr(" %d <%s> <%s> %d", i, name->as_C_string(), signature->as_C_string(), n);
++ get_index(); // ignore zero byte
++ print_field_or_method(i, st);
+ }
+ break;
+
+diff --git a/src/share/vm/interpreter/bytecodes.cpp b/src/share/vm/interpreter/bytecodes.cpp
+--- a/src/share/vm/interpreter/bytecodes.cpp
++++ b/src/share/vm/interpreter/bytecodes.cpp
+@@ -345,7 +345,7 @@
+ def(_invokespecial , "invokespecial" , "bjj" , NULL , T_ILLEGAL, -1, true);
+ 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
+ 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 @@
+
+ // Faster method invocation.
+ def(_fast_invokevfinal , "fast_invokevfinal" , "bjj" , NULL , T_ILLEGAL, -1, true, _invokevirtual );
++ 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
+@@ -218,7 +218,7 @@
+ _invokespecial = 183, // 0xb7
+ _invokestatic = 184, // 0xb8
+ _invokeinterface = 185, // 0xb9
+- _xxxunusedxxx = 186, // 0xba
++ _invokedynamic = 186, // 0xba // if InvokeDynamic
+ _new = 187, // 0xbb
+ _newarray = 188, // 0xbc
+ _anewarray = 189, // 0xbd
+@@ -305,8 +305,12 @@
+
+
+ // Fetch a bytecode, hiding breakpoints as necessary:
++ static Code raw_code_at(address bcp, methodOop method = NULL) {
++ return cast(*bcp);
++ }
+ static Code code_at(address bcp, methodOop method = NULL) {
+- Code code = cast(*bcp); return (code != _breakpoint) ? code : non_breakpoint_code_at(bcp, method);
++ Code code = raw_code_at(bcp);
++ return (code != _breakpoint) ? code : non_breakpoint_code_at(bcp, method);
+ }
+ static Code java_code_at(address bcp, methodOop method = NULL) {
+ return java_code(code_at(bcp, method));
+diff --git a/src/share/vm/interpreter/cppInterpreter.cpp b/src/share/vm/interpreter/cppInterpreter.cpp
+--- a/src/share/vm/interpreter/cppInterpreter.cpp
++++ b/src/share/vm/interpreter/cppInterpreter.cpp
+@@ -114,6 +114,7 @@
+ method_entry(empty);
+ method_entry(accessor);
+ method_entry(abstract);
++ method_entry(invoke_method);
+ method_entry(java_lang_math_sin );
+ method_entry(java_lang_math_cos );
+ method_entry(java_lang_math_tan );
+diff --git a/src/share/vm/interpreter/interpreter.cpp b/src/share/vm/interpreter/interpreter.cpp
+--- a/src/share/vm/interpreter/interpreter.cpp
++++ b/src/share/vm/interpreter/interpreter.cpp
+@@ -168,10 +168,14 @@
+ // Abstract method?
+ if (m->is_abstract()) return abstract;
+
++ // Invoker for method handles?
++ if (m->is_method_handle_invoke()) return method_handle;
++
+ // Native method?
+ // Note: This test must come _before_ the test for intrinsic
+ // methods. See also comments below.
+ if (m->is_native()) {
++ assert(!m->is_method_handle_invoke(), "overlapping bits here, watch out");
+ return m->is_synchronized() ? native_synchronized : native;
+ }
+
+@@ -249,6 +253,7 @@
+ case empty : tty->print("empty" ); break;
+ case accessor : tty->print("accessor" ); break;
+ case abstract : tty->print("abstract" ); break;
++ case method_handle : tty->print("method_handle" ); break;
+ case java_lang_math_sin : tty->print("java_lang_math_sin" ); break;
+ case java_lang_math_cos : tty->print("java_lang_math_cos" ); break;
+ case java_lang_math_tan : tty->print("java_lang_math_tan" ); break;
+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 @@
+ // create exception
+ THROW_MSG(vmSymbols::java_lang_ClassCastException(), message);
+ IRT_END
++
++IRT_ENTRY(void, InterpreterRuntime::throw_WrongMethodTypeException(JavaThread* thread, oopDesc* mtype, oopDesc* mhandle)) {
++
++ ResourceMark rm(thread);
++ char* message = SharedRuntime::generate_wrong_method_type_message(thread, mtype, mhandle);
++
++ if (ProfileTraps) {
++ note_trap(thread, Deoptimization::Reason_constraint, CHECK);
++ }
++
++ // create exception
++ THROW_MSG(vmSymbols::java_dyn_WrongMethodTypeException(), message);
++}
++IRT_END
++
+
+
+ // exception_handler_for_exception(...) returns the continuation address,
+@@ -591,7 +606,8 @@
+ 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);
+ // extract receiver from the outgoing argument list if necessary
+ Handle receiver(thread, NULL);
+ if (bytecode == Bytecodes::_invokevirtual || bytecode == Bytecodes::_invokeinterface) {
+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 @@
+ static void throw_StackOverflowError(JavaThread* thread);
+ static void throw_ArrayIndexOutOfBoundsException(JavaThread* thread, char* name, jint index);
+ static void throw_ClassCastException(JavaThread* thread, oopDesc* obj);
++ static void throw_WrongMethodTypeException(JavaThread* thread, oopDesc* mtype = NULL, oopDesc* mhandle = NULL);
+ static void create_exception(JavaThread* thread, char* name, char* message);
+ static void create_klass_exception(JavaThread* thread, char* name, oopDesc* obj);
+ static address exception_handler_for_exception(JavaThread* thread, oopDesc* exception);
+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 @@
+ 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()));
++}
++
++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);
++ if (result_oop != NULL) {
++ assert(result_oop->is_method_handle_invoke() && result_oop->signature() == signature(), "consistent");
++ result = methodHandle(THREAD, result_oop);
++ }
++ }
+ }
+
+ void LinkResolver::check_method_accessability(KlassHandle ref_klass,
+@@ -238,6 +249,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
++ lookup_implicit_method(resolved_method, resolved_klass, method_name, method_signature, CHECK);
++ }
+
+ if (resolved_method.is_null()) {
+ // 4. method lookup failed
+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
+@@ -103,6 +103,7 @@
+ static void lookup_method_in_klasses (methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
+ static void lookup_instance_method_in_klasses (methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
+ static void lookup_method_in_interfaces (methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
++ static void lookup_implicit_method (methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
+
+ static int vtable_index_of_miranda_method(KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
+
+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 @@
+ # include "incls/_precompiled.incl"
+ # include "incls/_rewriter.cpp.incl"
+
+-
+-// Computes an index_map (new_index -> original_index) for contant pool entries
++// Computes a CPC map (new_index -> original_index) for constant pool entries
+ // that are referred to by the interpreter at runtime via the constant pool cache.
+-void Rewriter::compute_index_maps(constantPoolHandle pool, intArray*& index_map, intStack*& inverse_index_map) {
+- const int length = pool->length();
+- index_map = new intArray(length, -1);
+- // Choose an initial value large enough that we don't get frequent
+- // calls to grow().
+- inverse_index_map = new intStack(length / 2);
++// Also computes a CP map (original_index -> new_index).
++// Marks entries in CP which require additional processing.
++void Rewriter::compute_index_maps() {
++ const int length = _pool->length();
++ init_cp_map(length);
+ for (int i = 0; i < length; i++) {
+- switch (pool->tag_at(i).value()) {
++ int tag = _pool->tag_at(i).value();
++ switch (tag) {
++ case JVM_CONSTANT_InterfaceMethodref:
++ if (InvokeDynamic) {
++ int k_index = _pool->klass_ref_index_at(i);
++ symbolOop k_name = _pool->klass_name_at(k_index);
++ if (k_name == vmSymbols::java_dyn_Dynamic()) {
++ // all calls of the form Dynamic.*(...)
++ add_cp_cache_entry(i, true);
++ // more cpc entries added later, one per call site
++ break;
++ }
++ }
++ // else fall through...
+ case JVM_CONSTANT_Fieldref : // fall through
+ case JVM_CONSTANT_Methodref : // fall through
+- case JVM_CONSTANT_InterfaceMethodref: {
+- index_map->at_put(i, inverse_index_map->length());
+- inverse_index_map->append(i);
+- }
++ add_cp_cache_entry(i);
++ break;
+ }
+ }
++
++ guarantee((int)_cp_cache_map.length()-1 <= (int)((u2)-1),
++ "all cp cache indexes fit in a u2");
+ }
+
+
+-// Creates a constant pool cache given an inverse_index_map
+-constantPoolCacheHandle Rewriter::new_constant_pool_cache(intArray& inverse_index_map, TRAPS) {
+- const int length = inverse_index_map.length();
+- constantPoolCacheOop cache = oopFactory::new_constantPoolCache(length, CHECK_(constantPoolCacheHandle()));
+- cache->initialize(inverse_index_map);
+- return constantPoolCacheHandle(THREAD, cache);
++int Rewriter::add_extra_cp_cache_entry(int main_entry) {
++ // 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);
++}
++
++
++
++// Creates a constant pool cache given a CPC map
++void Rewriter::make_constant_pool_cache(TRAPS) {
++ const int length = _cp_cache_map.length();
++ constantPoolCacheOop cache = oopFactory::new_constantPoolCache(length, CHECK);
++ cache->initialize(_cp_cache_map);
++ _pool->set_cache(cache);
++ cache->set_constant_pool(_pool());
+ }
+
+
+@@ -96,8 +118,40 @@
+ }
+
+
++// Rewrite a classfile-order CP index into a native-order CPC index.
++int Rewriter::rewrite_member_reference(address bcp, int offset) {
++ address p = bcp + offset;
++ int cp_index = Bytes::get_Java_u2(p);
++ int cache_index = cp_entry_to_cp_cache(cp_index);
++ Bytes::put_native_u2(p, cache_index);
++ return cp_index;
++}
++
++
++void Rewriter::rewrite_invokedynamic(address bcp, int offset, int cp_index) {
++ address p = bcp + offset;
++ assert(InvokeDynamic, "");
++ assert(p[-1] == Bytecodes::_invokeinterface, "");
++ p[-1] = Bytecodes::_invokedynamic;
++ int cpc = cp_entry_to_cp_cache(cp_index);
++ int cpc2 = add_extra_cp_cache_entry(cpc);
++ assert(Bytes::get_native_u2(p) == cpc, "already patched");
++
++ // Replace the trailing four bytes with a CPC index for the dynamic
++ // call site. Unlike other CPC entries, there is one per bytecode,
++ // not just one per distinct CP entry. In other words, the
++ // CPC-to-CP relation is many-to-one for invokedynamic entries.
++ // This means we must use a larger index size than u2 to address
++ // all these entries. That is the main reason invokedynamic
++ // must have a five-byte instruction format. (Of course, other JVM
++ // implementations can use the bytes for other purposes.)
++ Bytes::put_native_u4(p, cpc2);
++ // Note: We use native_u4 format exclusively for 4-byte indexes.
++}
++
++
+ // Rewrites a method given the index_map information
+-methodHandle Rewriter::rewrite_method(methodHandle method, intArray& index_map, TRAPS) {
++void Rewriter::scan_method(methodOop method) {
+
+ int nof_jsrs = 0;
+ bool has_monitor_bytecodes = false;
+@@ -114,8 +168,10 @@
+ const int code_length = method->code_size();
+
+ int bc_length;
++ int cp_index;
+ for (int bci = 0; bci < code_length; bci += bc_length) {
+ address bcp = code_base + bci;
++ int prefix_length = 0;
+ c = (Bytecodes::Code)(*bcp);
+
+ // Since we have the code, see if we can get the length
+@@ -130,6 +186,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) {
++ prefix_length = 1;
+ c = (Bytecodes::Code)bcp[1];
+ }
+ }
+@@ -152,14 +209,20 @@
+ case Bytecodes::_putstatic : // fall through
+ case Bytecodes::_getfield : // fall through
+ case Bytecodes::_putfield : // fall through
++ case Bytecodes::_invokespecial : // fall through
+ case Bytecodes::_invokevirtual : // fall through
+- case Bytecodes::_invokespecial : // fall through
+- case Bytecodes::_invokestatic : // fall through
+- case Bytecodes::_invokeinterface: {
+- address p = bcp + 1;
+- Bytes::put_native_u2(p, index_map[Bytes::get_Java_u2(p)]);
++ case Bytecodes::_invokestatic :
++ rewrite_member_reference(bcp, prefix_length+1);
++ // Note: cp_entry_is_extended() may be true for invokespecial.
++ // The interpreter must watch for this corner case,
++ // and support it as usual.
+ break;
+- }
++
++ case Bytecodes::_invokeinterface:
++ cp_index = rewrite_member_reference(bcp, prefix_length+1);
++ if (cp_entry_is_extended(cp_index))
++ rewrite_invokedynamic(bcp, prefix_length+1, cp_index);
++ break;
+ case Bytecodes::_jsr : // fall through
+ case Bytecodes::_jsr_w : nof_jsrs++; break;
+ case Bytecodes::_monitorenter : // fall through
+@@ -177,53 +240,56 @@
+ // have to be rewritten, so we run the oopMapGenerator on the method
+ if (nof_jsrs > 0) {
+ method->set_has_jsrs();
+- ResolveOopMapConflicts romc(method);
+- methodHandle original_method = method;
+- method = romc.do_potential_rewrite(CHECK_(methodHandle()));
+- if (method() != original_method()) {
+- // Insert invalid bytecode into original methodOop and set
+- // interpreter entrypoint, so that a executing this method
+- // will manifest itself in an easy recognizable form.
+- address bcp = original_method->bcp_from(0);
+- *bcp = (u1)Bytecodes::_shouldnotreachhere;
+- int kind = Interpreter::method_kind(original_method);
+- original_method->set_interpreter_kind(kind);
+- }
++ // Second pass will revisit this method.
++ assert(method->has_jsrs(), "");
++ }
++}
+
+- // Update monitor matching info.
+- if (romc.monitor_safe()) {
+- method->set_guaranteed_monitor_matching();
+- }
++// After constant pool is created, revisit methods containing jsrs.
++methodHandle Rewriter::rewrite_jsrs(methodHandle method, TRAPS) {
++ ResolveOopMapConflicts romc(method);
++ methodHandle original_method = method;
++ method = romc.do_potential_rewrite(CHECK_(methodHandle()));
++ if (method() != original_method()) {
++ // Insert invalid bytecode into original methodOop and set
++ // interpreter entrypoint, so that a executing this method
++ // will manifest itself in an easy recognizable form.
++ address bcp = original_method->bcp_from(0);
++ *bcp = (u1)Bytecodes::_shouldnotreachhere;
++ int kind = Interpreter::method_kind(original_method);
++ original_method->set_interpreter_kind(kind);
+ }
+
+- // Setup method entrypoints for compiler and interpreter
+- method->link_method(method, CHECK_(methodHandle()));
++ // Update monitor matching info.
++ if (romc.monitor_safe()) {
++ method->set_guaranteed_monitor_matching();
++ }
+
+ return method;
+ }
+
+
+ void Rewriter::rewrite(instanceKlassHandle klass, TRAPS) {
+- // gather starting points
+ ResourceMark rm(THREAD);
+- constantPoolHandle pool (THREAD, klass->constants());
+- objArrayHandle methods (THREAD, klass->methods());
+- assert(pool->cache() == NULL, "constant pool cache must not be set yet");
++ Rewriter rw(klass, CHECK);
++ // (That's all, folks.)
++}
++
++Rewriter::Rewriter(instanceKlassHandle klass, TRAPS)
++ : _klass(klass),
++ // gather starting points
++ _pool( THREAD, klass->constants()),
++ _methods(THREAD, klass->methods())
++{
++ assert(_pool->cache() == NULL, "constant pool cache must not be set yet");
+
+ // determine index maps for methodOop rewriting
+- intArray* index_map = NULL;
+- intStack* inverse_index_map = NULL;
+- compute_index_maps(pool, index_map, inverse_index_map);
++ compute_index_maps();
+
+- // allocate constant pool cache
+- constantPoolCacheHandle cache = new_constant_pool_cache(*inverse_index_map, CHECK);
+- pool->set_cache(cache());
+- cache->set_constant_pool(pool());
+-
+- if (RegisterFinalizersAtInit && klass->name() == vmSymbols::java_lang_Object()) {
+- int i = methods->length();
++ if (RegisterFinalizersAtInit && _klass->name() == vmSymbols::java_lang_Object()) {
++ int i = _methods->length();
+ while (i-- > 0) {
+- methodOop method = (methodOop)methods->obj_at(i);
++ methodOop method = (methodOop)_methods->obj_at(i);
+ 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 @@
+ }
+ }
+
+- // rewrite methods
+- { int i = methods->length();
+- while (i-- > 0) {
+- methodHandle m(THREAD, (methodOop)methods->obj_at(i));
+- m = rewrite_method(m, *index_map, CHECK);
++ // rewrite methods, in two passes
++ int i, len = _methods->length();
++
++ for (i = len; --i >= 0; ) {
++ methodOop method = (methodOop)_methods->obj_at(i);
++ scan_method(method);
++ }
++
++ // allocate constant pool cache, now that we've seen all the bytecodes
++ make_constant_pool_cache(CHECK);
++
++ for (i = len; --i >= 0; ) {
++ methodHandle m(THREAD, (methodOop)_methods->obj_at(i));
++
++ if (m->has_jsrs()) {
++ m = rewrite_jsrs(m, CHECK);
+ // Method might have gotten rewritten.
+- methods->obj_at_put(i, m());
++ _methods->obj_at_put(i, m());
+ }
++
++ // Set up method entry points for compiler and interpreter.
++ m->link_method(m, CHECK);
+ }
+ }
+diff --git a/src/share/vm/interpreter/rewriter.hpp b/src/share/vm/interpreter/rewriter.hpp
+--- a/src/share/vm/interpreter/rewriter.hpp
++++ b/src/share/vm/interpreter/rewriter.hpp
+@@ -25,13 +25,44 @@
+ // The Rewriter adds caches to the constant pool and rewrites bytecode indices
+ // pointing into the constant pool for better interpreter performance.
+
+-class Rewriter: public AllStatic {
++class Rewriter: public StackObj {
+ private:
+- static void compute_index_maps(constantPoolHandle pool, intArray*& index_map, intStack*& inverse_index_map);
+- static constantPoolCacheHandle new_constant_pool_cache(intArray& inverse_index_map, TRAPS);
+- static methodHandle rewrite_method(methodHandle method, intArray& index_map, TRAPS);
+- static void rewrite_Object_init(methodHandle method, TRAPS);
++ instanceKlassHandle _klass;
++ constantPoolHandle _pool;
++ objArrayHandle _methods;
++ intArray _cp_map;
++ intStack _cp_cache_map;
++
++ void init_cp_map(int length) {
++ _cp_map.initialize(length, -1);
++ // Choose an initial value large enough that we don't get frequent
++ // calls to grow().
++ _cp_cache_map.initialize(length / 2);
++ }
++ int cp_entry_to_cp_cache(int i) { return _cp_map[i] >> 1; }
++ bool cp_entry_is_extended(int i) { return (_cp_map[i] & 1) != 0; }
++ int add_cp_cache_entry(int cp_index, bool is_extended = false) {
++ assert(_cp_map[cp_index] == -1, "not twice on same cp_index");
++ int cache_index = _cp_cache_map.append(cp_index);
++ _cp_map.at_put(cp_index, (cache_index << 1) | (is_extended ? 1 : 0));
++ assert(cp_entry_to_cp_cache(cp_index) == cache_index, "");
++ assert(cp_entry_is_extended(cp_index) == is_extended, "");
++ return cache_index;
++ }
++ int add_extra_cp_cache_entry(int main_entry);
++
++ // All the work goes in here:
++ Rewriter(instanceKlassHandle klass, TRAPS);
++
++ void compute_index_maps();
++ void make_constant_pool_cache(TRAPS);
++ void scan_method(methodOop m);
++ methodHandle rewrite_jsrs(methodHandle m, TRAPS);
++ void rewrite_Object_init(methodHandle m, TRAPS);
++ int rewrite_member_reference(address bcp, int offset);
++ void rewrite_invokedynamic(address bcp, int offset, int cp_index);
+
+ public:
++ // Driver routine:
+ static void rewrite(instanceKlassHandle klass, TRAPS);
+ };
+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 @@
+ method_entry(empty)
+ method_entry(accessor)
+ method_entry(abstract)
++ method_entry(method_handle)
+ method_entry(java_lang_math_sin )
+ method_entry(java_lang_math_cos )
+ method_entry(java_lang_math_tan )
+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 @@
+
+ def(Bytecodes::_fast_invokevfinal , ubcp|disp|clvm|____, vtos, vtos, fast_invokevfinal , 2 );
+
++ def(Bytecodes::_invokedynamic , ubcp|disp|clvm|____, vtos, vtos, invokeinterface , 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/memory/dump.cpp b/src/share/vm/memory/dump.cpp
+--- a/src/share/vm/memory/dump.cpp
++++ b/src/share/vm/memory/dump.cpp
+@@ -894,6 +894,9 @@
+ // shared classes at runtime, where constraints were previously created.
+ guarantee(SystemDictionary::constraints()->number_of_entries() == 0,
+ "loader constraints are not saved");
++ // Revisit and implement this if we prelink method handle call sites:
++ guarantee(SystemDictionary::invoke_method_table()->number_of_entries() == 0,
++ "invoke method table is not saved");
+ GenCollectedHeap* gch = GenCollectedHeap::heap();
+
+ // At this point, many classes have been loaded.
+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
+@@ -382,7 +382,8 @@
+ "should be symbol or instance");
+ }
+ if (cp->tag_at(i).is_string()) {
+- guarantee((*base)->is_perm(), "should be in permspace");
++ // %%% split pseudo-string out of string
++ //guarantee((*base)->is_perm(), "should be in permspace");
+ guarantee((*base)->is_instance(), "should be instance");
+ }
+ base++;
+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 @@
+ 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);
++}
++
++
++
++int constantPoolOopDesc::map_instruction_operand_to_index(int operand) {
++ if (constantPoolCacheOopDesc::is_secondary_index(operand)) {
++ return cache()->main_entry_at(operand)->constant_pool_index();
++ }
++ assert((int)(u2)operand == operand, "clean u2");
++ int index = Bytes::swap_u2(operand);
++ return cache()->entry_at(index)->constant_pool_index();
+ }
+
+
+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
+@@ -376,16 +376,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) {
+- int i = -1;
+- if (uncached || cache() == NULL) {
+- i = which;
+- } else {
++ int i = which;
++ if (!uncached && cache() != NULL) {
+ // change byte-ordering and go via cache
+- i = cache()->entry_at(Bytes::swap_u2(which))->constant_pool_index();
++ i = map_instruction_operand_to_index(which);
+ }
+ assert(tag_at(i).is_field_or_method(), "Corrupted constant pool");
+ return *int_at_addr(i);
+ }
++
++ int map_instruction_operand_to_index(int operand);
+
+ // Used while constructing constant pool (only by ClassFileParser)
+ jint klass_index_at(int which) {
+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
+@@ -29,8 +29,18 @@
+ // Implememtation of ConstantPoolCacheEntry
+
+ void ConstantPoolCacheEntry::set_initial_state(int index) {
+- assert(0 <= index && index < 0x10000, "sanity check");
++ if (constantPoolCacheOopDesc::is_secondary_index(index)) {
++ // Hack: The rewriter is trying to say that this entry itself
++ // will be a secondary entry.
++ int main_index = constantPoolCacheOopDesc::decode_secondary_index(index);
++ assert(0 <= main_index && main_index < 0x10000, "sanity check");
++ _indices = (main_index << 16);
++ assert(main_entry_index() == main_index, "");
++ return;
++ }
++ assert(0 < index && index < 0x10000, "sanity check");
+ _indices = index;
++ assert(constant_pool_index() == index, "");
+ }
+
+
+@@ -392,7 +402,11 @@
+ // print separator
+ if (index == 0) tty->print_cr(" -------------");
+ // print entry
+- tty->print_cr("%3d (%08x) [%02x|%02x|%5d]", index, this, bytecode_2(), bytecode_1(), constant_pool_index());
++ tty->print_cr("%3d (%08x) ", index, this);
++ if (is_secondary_entry())
++ tty->print_cr("[%5d|secondary]", main_entry_index());
++ else
++ tty->print_cr("[%02x|%02x|%5d]", bytecode_2(), bytecode_1(), constant_pool_index());
+ tty->print_cr(" [ %08x]", (address)(oop)_f1);
+ tty->print_cr(" [ %08x]", _f2);
+ tty->print_cr(" [ %08x]", _flags);
+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 @@
+ }
+
+ // Accessors
+- int constant_pool_index() const { return _indices & 0xFFFF; }
++ bool is_secondary_entry() const { return (_indices & 0xFFFF) == 0; }
++ int constant_pool_index() const { assert((_indices & 0xFFFF) != 0, "must be main entry");
++ return (_indices & 0xFFFF); }
++ int main_entry_index() const { assert((_indices & 0xFFFF) == 0, "must be secondary entry");
++ return ((uintx)_indices >> 16); }
+ 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 @@
+ // Initialization
+ void initialize(intArray& inverse_index_map);
+
++ // Secondary indexes.
++ // They must look completely different from normal indexes.
++ // The main reason is that byte swapping is sometimes done on normal indexes.
++ // Also, it is helpful for debugging to tell the two apart.
++ static bool is_secondary_index(int i) { return (i < 0); }
++ static int decode_secondary_index(int i) { assert(is_secondary_index(i), ""); return ~i; }
++ static int encode_secondary_index(int i) { assert(!is_secondary_index(i), ""); return ~i; }
++
+ // Accessors
+ void set_constant_pool(constantPoolOop pool) { oop_store_without_check((oop*)&_constant_pool, (oop)pool); }
+ constantPoolOop constant_pool() const { return _constant_pool; }
+ ConstantPoolCacheEntry* entry_at(int i) const { assert(0 <= i && i < length(), "index out of bounds"); return base() + i; }
++ ConstantPoolCacheEntry* main_entry_at(int i) const {
++ ConstantPoolCacheEntry* e;
++ if (is_secondary_index(i)) {
++ // run through an extra level of indirection:
++ i = decode_secondary_index(i);
++ e = entry_at(i);
++ i = e->main_entry_index();
++ }
++ e = entry_at(i);
++ assert(!e->is_secondary_entry(), "only one level of indirection");
++ return e;
++ }
+
+ // Code generation
+ static ByteSize base_offset() { return in_ByteSize(sizeof(constantPoolCacheOopDesc)); }
+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 @@
+ // Printing
+
+ void FieldPrinter::do_field(fieldDescriptor* fd) {
+- if (fd->is_static() == (_obj == NULL)) {
++ if (fd->is_static() || (_obj == NULL)) {
+ _st->print(" - ");
+ fd->print_on(_st);
+ _st->cr();
+@@ -2028,6 +2028,28 @@
+ st->print("a ");
+ name()->print_value_on(st);
+ obj->print_address_on(st);
++ if (as_klassOop() == SystemDictionary::string_klass()
++ && java_lang_String::value(obj) != NULL) {
++ ResourceMark rm;
++ int len = java_lang_String::length(obj);
++ int plen = (len < 24 ? len : 12);
++ char* str = java_lang_String::as_utf8_string(obj, 0, plen);
++ st->print(" = \"%s\"", str);
++ if (len > plen)
++ st->print("...[%d]", len);
++ } else if (as_klassOop() == SystemDictionary::class_klass()) {
++ klassOop k = java_lang_Class::as_klassOop(obj);
++ st->print(" = ");
++ if (k != NULL) {
++ k->print_value_on(st);
++ } else {
++ const char* tname = type2name(java_lang_Class::primitive_type(obj));
++ st->print("%s", tname ? tname : "type?");
++ }
++ } else if (java_lang_boxing_object::is_instance(obj)) {
++ st->print(" = ");
++ java_lang_boxing_object::print(obj, st);
++ }
+ }
+
+ #endif // ndef PRODUCT
+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
+@@ -1150,6 +1150,26 @@
+ return index;
+ }
+
++
++methodOop klassItable::method_for_itable_index(klassOop intf, int itable_index) {
++ assert(instanceKlass::cast(intf)->is_interface(), "sanity check");
++ objArrayOop methods = instanceKlass::cast(intf)->methods();
++
++ int index = itable_index;
++ // Adjust for <clinit>, which is left out of table if first method
++ if (methods->length() > 0 && ((methodOop)methods->obj_at(0))->name() == vmSymbols::class_initializer_name()) {
++ index++;
++ }
++
++ if (itable_index < 0 || index >= methods->length())
++ return NULL; // help caller defend against bad indexes
++
++ methodOop m = (methodOop)methods->obj_at(index);
++ assert(compute_itable_index(m) == itable_index, "correct inverse");
++
++ return m;
++}
++
+ void klassVtable::verify(outputStream* st, bool forced) {
+ // make sure table is initialized
+ if (!Universe::is_fully_initialized()) return;
+diff --git a/src/share/vm/oops/klassVtable.hpp b/src/share/vm/oops/klassVtable.hpp
+--- a/src/share/vm/oops/klassVtable.hpp
++++ b/src/share/vm/oops/klassVtable.hpp
+@@ -298,6 +298,8 @@
+
+ // Resolving of method to index
+ static int compute_itable_index(methodOop m);
++ // ...and back again:
++ static methodOop method_for_itable_index(klassOop klass, int itable_index);
+
+ // Debugging/Statistics
+ static void print_statistics() PRODUCT_RETURN;
+diff --git a/src/share/vm/oops/methodKlass.cpp b/src/share/vm/oops/methodKlass.cpp
+--- a/src/share/vm/oops/methodKlass.cpp
++++ b/src/share/vm/oops/methodKlass.cpp
+@@ -247,9 +247,14 @@
+ st->print_cr(" - size of params: %d", m->size_of_parameters());
+ st->print_cr(" - method size: %d", m->method_size());
+ st->print_cr(" - vtable index: %d", m->_vtable_index);
++ st->print_cr(" - i2i entry: " INTPTR_FORMAT, m->interpreter_entry());
++ st->print_cr(" - adapter: " INTPTR_FORMAT, m->adapter());
++ st->print_cr(" - compiled entry " INTPTR_FORMAT, m->from_compiled_entry());
+ st->print_cr(" - code size: %d", m->code_size());
+- st->print_cr(" - code start: " INTPTR_FORMAT, m->code_base());
+- st->print_cr(" - code end (excl): " INTPTR_FORMAT, m->code_base() + m->code_size());
++ if (m->code_size() != 0) {
++ st->print_cr(" - code start: " INTPTR_FORMAT, m->code_base());
++ st->print_cr(" - code end (excl): " INTPTR_FORMAT, m->code_base() + m->code_size());
++ }
+ if (m->method_data() != NULL) {
+ st->print_cr(" - method data: " INTPTR_FORMAT, (address)m->method_data());
+ }
+@@ -293,6 +298,13 @@
+ m->code()->print_value_on(st);
+ st->cr();
+ }
++ if (m->is_native()) {
++ st->print_cr(" - native function: " INTPTR_FORMAT, m->native_function());
++ st->print_cr(" - signature handler: " INTPTR_FORMAT, m->signature_handler());
++ }
++ if (m->is_method_handle_invoke()) {
++ st->print_cr(" - invoke method type: " INTPTR_FORMAT, (address) m->method_handle_type());
++ }
+ }
+
+
+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 @@
+ assert(entry != NULL, "interpreter entry must be non-null");
+ // Sets both _i2i_entry and _from_interpreted_entry
+ set_interpreter_entry(entry);
+- if (is_native()) {
++ if (is_native() && !is_method_handle_invoke()) {
+ set_native_function(
+ SharedRuntime::native_method_throw_unsatisfied_link_error_entry(),
+ !native_bind_event_is_interesting);
+@@ -781,6 +781,91 @@
+
+ // caching this method should be just fine
+ return false;
++}
++
++// Constant pool structure for invoke methods:
++enum {
++ _imcp_invoke_name = 1, // utf8: 'invoke'
++ _imcp_invoke_signature, // utf8: (variable symbolOop)
++ _imcp_method_type_value, // string: (variable java/dyn/MethodType, sic)
++ _imcp_limit
++};
++
++oop methodOopDesc::method_handle_type() const {
++ if (!is_method_handle_invoke()) { assert(false, "caller resp."); return NULL; }
++ oop mt = constants()->resolved_string_at(_imcp_method_type_value);
++ assert(mt->klass() == SystemDictionary::methodType_klass(), "");
++ return mt;
++}
++
++int* methodOopDesc::method_type_pointer_chase() {
++ static int 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());
++ }
++ return pchase;
++}
++
++methodHandle methodOopDesc::make_invoke_method(symbolHandle signature,
++ Handle method_type, TRAPS) {
++ methodHandle empty;
++
++ if (TraceMethodHandles) {
++ tty->print("Creating invoke method for ");
++ signature->print_value();
++ tty->cr();
++ }
++
++ constantPoolHandle cp;
++ {
++ constantPoolOop cp_oop = oopFactory::new_constantPool(_imcp_limit, CHECK_(empty));
++ cp = constantPoolHandle(THREAD, cp_oop);
++ }
++ cp->symbol_at_put(_imcp_invoke_name, vmSymbols::invoke_name());
++ cp->symbol_at_put(_imcp_invoke_signature, signature());
++ cp->string_at_put(_imcp_method_type_value, method_type());
++ cp->set_pool_holder(SystemDictionary::methodHandle_klass());
++
++ methodHandle m;
++ {
++ int flags_bits = (JVM_MH_INVOKE_BITS | JVM_ACC_PUBLIC | JVM_ACC_FINAL);
++ methodOop m_oop = oopFactory::new_method(0, accessFlags_from(flags_bits),
++ 0, 0, 0, CHECK_(empty));
++ m = methodHandle(THREAD, m_oop);
++ }
++ m->set_constants(cp());
++ m->set_name_index(_imcp_invoke_name);
++ m->set_signature_index(_imcp_invoke_signature);
++ assert(m->name() == vmSymbols::invoke_name(), "");
++ assert(m->signature() == signature(), "");
++#ifdef CC_INTERP
++ ResultTypeFinder rtf(signature());
++ m->set_result_index(rtf.type());
++#endif
++ m->compute_size_of_parameters(THREAD);
++ m->set_exception_table(Universe::the_empty_int_array());
++
++ // Finally, set up its entry points.
++ assert(m->method_handle_type() == method_type(), "");
++ assert(m->can_be_statically_bound(), "");
++ m->set_vtable_index(methodOopDesc::nonvirtual_vtable_index);
++ m->link_method(m, CHECK_(empty));
++
++#ifdef ASSERT
++ // Make sure the pointer chase works.
++ address p = (address) m();
++ for (int* pchase = method_type_pointer_chase(); (*pchase) != -1; pchase++) {
++ p = *(address*)(p + (*pchase));
++ }
++ assert((oop)p == method_type(), "pointer chase is correct");
++#endif
++
++ if (TraceMethodHandles)
++ m->print_on(tty);
++
++ return m;
+ }
+
+
+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 @@
+ // 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);
++ oop method_handle_type() const;
++ static int* method_type_pointer_chase();
++
+ // 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.hpp b/src/share/vm/oops/oop.hpp
+--- a/src/share/vm/oops/oop.hpp
++++ b/src/share/vm/oops/oop.hpp
+@@ -256,6 +256,9 @@
+ jdouble double_field_acquire(int offset) const;
+ void release_double_field_put(int offset, jdouble contents);
+
++ address address_field_acquire(int offset) const;
++ void release_address_field_put(int offset, address contents);
++
+ // printing functions for VM debugging
+ void print_on(outputStream* st) const; // First level print
+ void print_value_on(outputStream* st) const; // Second level print.
+@@ -388,4 +391,10 @@
+ static int mark_offset_in_bytes() { return offset_of(oopDesc, _mark); }
+ static int klass_offset_in_bytes() { return offset_of(oopDesc, _metadata._klass); }
+ static int klass_gap_offset_in_bytes();
++
++ // Machine addresses may be stored in jlong fields.
++ // On 32-bit big-endian machines, we must increase field offset by four
++ // in order to address raw address embedded in the jlong field.
++ // (The goal is to preserve the value even if it is cast between jlong and intptr_t.)
++ static int address_padding_in_bytes();
+ };
+diff --git a/src/share/vm/oops/oop.inline.hpp b/src/share/vm/oops/oop.inline.hpp
+--- a/src/share/vm/oops/oop.inline.hpp
++++ b/src/share/vm/oops/oop.inline.hpp
+@@ -96,6 +96,13 @@
+ } else {
+ _metadata._klass = (klassOop)k;
+ }
++}
++
++inline int oopDesc::address_padding_in_bytes() {
++ if (longSize > wordSize && !Bytes::is_Java_byte_ordering_different())
++ // On a big-endian 32-bit system, push address fields 4 bytes into containing jlong fields.
++ return (longSize - wordSize);
++ return 0;
+ }
+
+ inline void oopDesc::init_mark() { set_mark(markOopDesc::prototype_for_object(this)); }
+@@ -347,6 +354,9 @@
+ inline jdouble oopDesc::double_field_acquire(int offset) const { return OrderAccess::load_acquire(double_field_addr(offset)); }
+ inline void oopDesc::release_double_field_put(int offset, jdouble contents) { OrderAccess::release_store(double_field_addr(offset), contents); }
+
++inline address oopDesc::address_field_acquire(int offset) const { return (address) OrderAccess::load_acquire((intptr_t*)address_field_addr(offset)); }
++inline void oopDesc::release_address_field_put(int offset, address contents) { OrderAccess::release_store((intptr_t*)address_field_addr(offset), (intptr_t) contents); }
++
+ inline int oopDesc::size_given_klass(Klass* klass) {
+ int lh = klass->layout_helper();
+ int s = lh >> LogHeapWordSize; // deliver size scaled by wordSize
+diff --git a/src/share/vm/opto/bytecodeInfo.cpp b/src/share/vm/opto/bytecodeInfo.cpp
+--- a/src/share/vm/opto/bytecodeInfo.cpp
++++ b/src/share/vm/opto/bytecodeInfo.cpp
+@@ -326,7 +326,7 @@
+ // stricter than callee_holder->is_initialized()
+ ciBytecodeStream iter(caller_method);
+ iter.force_bci(caller_bci);
+- int index = iter.get_index_big();
++ int index = iter.get_index_int();
+ if( !caller_method->is_klass_loaded(index, true) ) {
+ return false;
+ }
+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 @@
+ "sanity check");
+ // 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));
+ 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
+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
+@@ -148,8 +148,8 @@
+ case Bytecodes::_invokespecial : // fall through
+ case Bytecodes::_invokestatic : // fall through
+ case Bytecodes::_invokeinterface : {
+- u2 cpci_old = _s_old->get_index_big();
+- u2 cpci_new = _s_new->get_index_big();
++ u2 cpci_old = _s_old->get_index_int();
++ u2 cpci_new = _s_new->get_index_int();
+ // Check if the names of classes, field/method names and signatures at these indexes
+ // are the same. Indices which are really into constantpool cache (rather than constant
+ // pool itself) are accepted by the constantpool query routines below.
+diff --git a/src/share/vm/prims/methodHandles.cpp b/src/share/vm/prims/methodHandles.cpp
+new file mode 100644
+--- /dev/null
++++ b/src/share/vm/prims/methodHandles.cpp
+@@ -0,0 +1,647 @@
++/*
++ * Copyright 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.
++ *
++ */
++
++/*
++ * JSR 292 reference implementation: method handles
++ */
++
++#include "incls/_precompiled.incl"
++#include "incls/_methodHandles.cpp.incl"
++
++MethodEntry* MethodHandle::_entries[MethodHandle::_EK_LIMIT] = {NULL};
++const char* MethodHandle::_entry_names[_EK_LIMIT] = {
++ "check_mtype",
++ "wrong_method_type", // what happens when there is a type mismatch
++ "invokestatic", // how a MH emulates invokestatic
++ "invokespecial", // ditto for the other invokes...
++ "invokevirtual",
++ "invokeinterface"
++};
++
++// A trusted party is handing us a cookie to determine a method.
++// Let's boil it down to the method oop they really want.
++methodOop MethodHandle::decode_method(oop x) {
++ klassOop xk = x->klass();
++ if (xk == Universe::methodKlassObj()) {
++ assert(x->is_method(), "");
++ return (methodOop) x;
++ } else if (xk == SystemDictionary::reflect_method_klass()) {
++ oop clazz = java_lang_reflect_Method::clazz(x);
++ int slot = java_lang_reflect_Method::slot(x);
++ klassOop k = java_lang_Class::as_klassOop(clazz);
++ if (k != NULL && Klass::cast(k)->oop_is_instance())
++ return instanceKlass::cast(k)->method_with_idnum(slot);
++ } else if (xk == SystemDictionary::reflect_constructor_klass()) {
++ oop clazz = java_lang_reflect_Constructor::clazz(x);
++ int slot = java_lang_reflect_Constructor::slot(x);
++ klassOop k = java_lang_Class::as_klassOop(clazz);
++ if (k != NULL && Klass::cast(k)->oop_is_instance())
++ return instanceKlass::cast(k)->method_with_idnum(slot);
++ } else if (x->is_a(SystemDictionary::methodHandle_klass())) {
++ return java_dyn_MethodHandle::method(x);
++ } else {
++ // unrecognized object
++ assert(!x->is_method(), "got this case first");
++ }
++ return NULL;
++}
++
++bool MethodHandle::class_cast_needed(klassOop src, klassOop dst) {
++ if (src == dst || dst == SystemDictionary::object_klass())
++ return false; // quickest checks
++ Klass* srck = Klass::cast(src);
++ Klass* dstk = Klass::cast(dst);
++ if (dstk->is_interface()) {
++ // interface receivers can safely be viewed as untyped,
++ // because interface calls always include a dynamic check
++ //dstk = Klass::cast(SystemDictionary::object_klass());
++ return false;
++ }
++ if (srck->is_interface()) {
++ // interface arguments must be viewed as untyped
++ //srck = Klass::cast(SystemDictionary::object_klass());
++ return true;
++ }
++ return !srck->is_subclass_of(dstk->as_klassOop());
++}
++
++const char* MethodHandle::check_method_receiver(methodHandle m,
++ Handle mtype,
++ objArrayHandle ptypes) {
++ if (!m->is_static()) {
++ if (ptypes->length() == 0)
++ return "receiver type is missing";
++ klassOop pklass = java_lang_Class::as_klassOop(ptypes->obj_at(0));
++ if (pklass == NULL)
++ return "receiver type is primitive";
++ if (class_cast_needed(pklass, m->method_holder())) {
++ Klass* formal = Klass::cast(m->method_holder());
++ return SharedRuntime::generate_class_cast_message("receiver type",
++ formal->external_name());
++ }
++ }
++ return NULL; // checks passed
++}
++
++const char* MethodHandle::check_method_signature(methodHandle m,
++ Handle mtype,
++ objArrayHandle ptypes,
++ TRAPS) {
++ int pnum = m->is_static() ? 0 : 1;
++ int pmax = ptypes->length();
++ const char* err = NULL;
++ BasicType errtype = T_VOID;
++ klassOop errklass = NULL;
++ for (SignatureStream ss(m->signature()); !ss.is_done(); ss.next()) {
++ oop ptype = NULL;
++ if (ss.at_return_type()) {
++ if (pnum != pmax)
++ return "too many arguments";
++ ptype = java_dyn_MethodType::rtype(mtype());
++ } else {
++ if (pnum >= pmax)
++ return "not enough arguments";
++ ptype = ptypes->obj_at(pnum++);
++ }
++ errtype = ss.type();
++ klassOop pklass = java_lang_Class::as_klassOop(ptype);
++ BasicType pt = (pklass != NULL) ? T_OBJECT : java_lang_Class::primitive_type(ptype);
++ if (!ss.is_object()) {
++ // primitives must match exactly, except perhaps for subword types
++ if (pt == T_OBJECT) {
++ err = (ss.at_return_type()
++ ? "returning %s, but expecting a reference"
++ : "argument #%d expected %s, got a reference");
++ break;
++ }
++ if (ss.at_return_type()) {
++ if (!same_basic_type_for_returns(ss.type(), pt)) {
++ err = "returning %s, but expecting a different value";
++ break;
++ }
++ } else {
++ if (!same_basic_type_for_arguments(pt, ss.type())) {
++ err = "argument #%d expected %s, got a different value";
++ break;
++ }
++ }
++ } else {
++ symbolOop name_oop = ss.as_symbol(CHECK_NULL);
++ symbolHandle name(THREAD, name_oop);
++ klassOop mklass = SystemDictionary::resolve_or_fail(name, true, CHECK_NULL);
++ if (mklass != pklass) {
++ errtype = T_OBJECT;
++ errklass = mklass;
++ if (pt != T_OBJECT) {
++ err = (ss.at_return_type()
++ ? "returning %s, but expecting a value"
++ : "argument #%d expected %s, got a value");
++ break;
++ }
++ if (ss.at_return_type()) {
++ if (class_cast_needed(mklass, pklass)) {
++ err = "returning %s, but expecting a different reference";
++ break;
++ }
++ } else {
++ if (class_cast_needed(pklass, mklass)) {
++ err = "argument %#d expected %s, got a different reference";
++ break;
++ }
++ }
++ }
++ }
++ }
++ if (err == NULL) {
++ return NULL;
++ } else {
++ // format, format, format
++ char msgbuf[1000];
++ const char* errarg = "";
++ if (errtype == T_OBJECT && errklass != NULL)
++ errarg = Klass::cast(errklass)->external_name();
++ else
++ errarg = type2name(errtype);
++ if (errarg == NULL) errarg = "unknown type";
++ if (strstr(err, "%d")) {
++ jio_snprintf(msgbuf, sizeof(msgbuf)-1, err, pnum, errarg);
++ } else {
++ jio_snprintf(msgbuf, sizeof(msgbuf)-1, err, errarg);
++ }
++ char* msg = NEW_RESOURCE_ARRAY(char, strlen(msgbuf)+1);
++ strcpy(msg, msgbuf);
++ return msg;
++ }
++}
++
++
++#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
++// %%% 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;
++
++ address me_cookie;
++ MethodEntry* me;
++
++ // 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;
++ }
++
++ 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);
++ }
++
++ // 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, 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()));
++ __ 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) {
++ // pick out the interpreted side of the handler
++ __ movl(temp_reg, Address(recv_reg, java_dyn_MethodHandle::entry_offset_in_bytes()));
++
++ // 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();
++}
++
++void MethodHandle::generate_method_handle_stub(MacroAssembler* _masm, MethodHandle::EntryKind ek) {
++ // 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;
++ Register rsi_savedsp = rsi;
++
++ 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 (ek) {
++ case _check_mtype:
++ {
++ 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();
++
++ check_method_type(_masm, rax_mtype, rcx_recv, wrong_method_type);
++ jump_to_entry(_masm, rcx_recv, rdx_temp);
++ break;
++ }
++
++ case _invokestatic_mh:
++ // same as TemplateTable::invokestatic,
++ // minus the CP setup and profiling:
++ __ verify_oop(rbx_method);
++ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
++ break;
++
++ case _invokespecial_mh:
++ // same as TemplateTable::invokespecial,
++ // minus the CP setup and profiling:
++ load_mh_receiver(_masm, rax_mtype, rsi_savedsp, rcx_recv);
++ __ null_check(rcx_recv);
++ __ verify_oop(rbx_method);
++ __ 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(rbx_index, Address(rcx_recv, java_dyn_MethodHandle::vmdata_offset_in_bytes()));
++
++ load_mh_receiver(_masm, rax_mtype, rsi_savedsp, rcx_recv);
++ __ null_check(rcx_recv, oopDesc::klass_offset_in_bytes());
++
++ // get receiver klass
++ __ 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");
++ __ 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;
++ Register rbx_index = rbx_method;
++
++ __ movl(rdx_intf, Address(rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes()));
++ __ movl(rbx_index, Address(rcx_recv, java_dyn_MethodHandle::vmdata_offset_in_bytes()));
++
++ load_mh_receiver(_masm, rax_mtype, rsi_savedsp, rcx_recv);
++
++ // Free up some temps.
++ __ pushl(rcx_recv);
++
++ // get receiver klass
++ __ movl(rcx, Address(rcx_recv, oopDesc::klass_offset_in_bytes()));
++ __ verify_oop(rcx);
++
++ // get interface klass
++ Label no_such_interface;
++ __ lookup_interface_method(rcx, rdx_intf, rbx_index,
++ rbx_method, rax,
++ no_such_interface);
++
++ __ verify_oop(rbx_method);
++ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
++ __ hlt();
++
++ __ bind(no_such_interface);
++ // Throw an exception.
++ // For historical reasons, it will be IncompatibleClassChangeError.
++ __ should_not_reach_here(); // %%% 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));
++}
++
++// smashes mtype_reg, but first picks out the receiver depth in the stack
++void MethodHandle::load_mh_receiver(MacroAssembler* _masm,
++ Register mtype_reg,
++ Register savedsp_reg,
++ Register recv_result) {
++ assert_different_registers(mtype_reg, savedsp_reg, recv_result);
++
++ Register temp_reg = mtype_reg;
++ __ movl(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(temp_reg, Address(temp_reg, java_dyn_MethodType::Form::vmdata_offset_in_bytes()));
++
++#ifdef ASSERT
++ { Label L;
++ __ testl(temp_reg, temp_reg);
++ __ jccb(Assembler::notZero, L);
++ __ stop("zero parameter count; cannot find receiver");
++ __ bind(L);
++ }
++#endif
++
++ // cf. TemplateTable::prepare_invoke(), if (load_receiver).
++ int offset = -Interpreter::expr_offset_in_bytes(1);
++ __ movl(recv_result, Address(savedsp_reg, temp_reg,
++ Interpreter::stackElementScale(), offset));
++ __ verify_oop(recv_result);
++}
++
++
++
++// direct method handles
++JVM_ENTRY(void, MH_init_DMH(JNIEnv *env, jobject igcls, jobject mh_jh, jobject rmethod_jh, jboolean doDispatch)) {
++ ResourceMark rm; // for error messages
++
++ // This is the guy we are initializing:
++ Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh));
++
++ // Early returns out of this method leave the DMH
++ // in a broken state that will throw a WrongMethodTypeException,
++ // but will not break the JVM:
++ MethodEntry* me = MethodHandle::entry(MethodHandle::_wrong_method_type);
++ java_dyn_MethodHandle::set_entry(mh(), me);
++
++ // which method are we really talking about?
++ methodHandle m(THREAD, MethodHandle::decode_method(JNIHandles::resolve(rmethod_jh)));
++ if (m.is_null()) return; // robustness
++
++ // Now inspect the proposed type of this guy.
++ Handle mtype(THREAD, java_dyn_MethodHandle::type(mh()));
++ objArrayHandle ptypes(THREAD, java_dyn_MethodType::ptypes(mtype()));
++
++ // The privileged code which invokes this routine should not make
++ // a mistake about types, but it's better to verify.
++ const char* err = MethodHandle::check_method_receiver(m, mtype, ptypes);
++
++ // Check the other arguments for mistypes.
++ if (err == NULL)
++ err = MethodHandle::check_method_signature(m, mtype, ptypes, CHECK);
++
++ if (err != NULL)
++ THROW_MSG(vmSymbols::java_dyn_WrongMethodTypeException(), err);
++
++ // Finally, after safety checks are done, link to the target method.
++ // We will follow the same path as the latter part of
++ // InterpreterRuntime::resolve_invoke(), which first finds the method
++ // and then decides how to populate the constant pool cache entry
++ // that links the interpreter calls to the method. We need the same
++ // bits, and will use the same calling sequence code.
++
++ if (!doDispatch && m->is_abstract()) return; // robustness
++
++ if (doDispatch && Klass::cast(m->method_holder())->is_interface()) {
++ // We are simulating an invokeinterface instruction.
++ // (We might also be simulating an invokevirtual on a miranda method,
++ // but it is safe to treat it as an invokeinterface.)
++ assert(!m->can_be_statically_bound(), "no final methods on interfaces");
++ intptr_t index = klassItable::compute_itable_index(m());
++ assert(index >= 0, "");
++ // 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(mh(), (address)index);
++ me = MethodHandle::entry(MethodHandle::_invokeinterface_mh);
++ } else if (!doDispatch || 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 easier to parse this MH:
++ java_dyn_MethodHandle::set_vmdata(mh(), (address)methodOopDesc::nonvirtual_vtable_index);
++ if (m->is_static())
++ me = MethodHandle::entry(MethodHandle::_invokestatic_mh);
++ else
++ me = MethodHandle::entry(MethodHandle::_invokespecial_mh);
++ } else {
++ // We are simulating an invokevirtual instruction.
++ // Set up the vtable index, just like ConstantPoolCacheEntry::set_method().
++ // The key logic is LinkResolver::runtime_resolve_virtual_method.
++ intptr_t index = m->vtable_index();
++ assert(index >= 0, "");
++ java_dyn_MethodHandle::set_vmdata(mh(), (address)index);
++ // this does not help dispatch, but it will make decode_method happy:
++ java_dyn_MethodHandle::set_vmref(mh(), m());
++ me = MethodHandle::entry(MethodHandle::_invokevirtual_mh);
++ }
++
++ assert(MethodHandle::decode_method(mh()) == m(), "properly stored for later decoding");
++
++ // Done!
++ java_dyn_MethodHandle::set_entry(mh(), me);
++}
++JVM_END
++
++// bound method handles
++JVM_ENTRY(void, MH_init_BMH(JNIEnv *env, jobject igcls, jobject mh_jh, jobject rmethod_jh, jobject recv_jh)) {
++ tty->print_cr("*** NYI: BMH");
++}
++JVM_END
++
++// adapter method handles
++JVM_ENTRY(void, MH_init_AMH(JNIEnv *env, jobject igcls, jobject mh_jh)) {
++ tty->print_cr("*** NYI: AMH");
++}
++JVM_END
++
++// method type forms
++JVM_ENTRY(void, MH_init_MTForm(JNIEnv *env, jobject igcls, jobject form_jh, jobject erased_jh)) {
++ if (erased_jh == NULL) return;
++ if (TraceMethodHandles) {
++ tty->print("creating MethodType form ");
++ if (WizardMode || Verbose) { // Warning: this calls Java code on the MH!
++ // call Object.toString()
++ symbolOop name = vmSymbols::toString_name(), sig = vmSymbols::void_string_signature();
++ JavaCallArguments args(JNIHandles::resolve_non_null(erased_jh));
++ JavaValue result(T_OBJECT);
++ JavaCalls::call_virtual(&result, SystemDictionary::object_klass(), name, sig,
++ &args, CHECK);
++ Handle str(THREAD, (oop)result.get_jobject());
++ java_lang_String::print(str, tty);
++ }
++ tty->cr();
++ }
++}
++JVM_END
++
++// debugging
++JVM_ENTRY(jobject, MH_methodName(JNIEnv *env, jobject igcls, jobject mh_jh)) {
++ methodHandle m(THREAD, MethodHandle::decode_method(JNIHandles::resolve(mh_jh)));
++ if (m.is_null()) return NULL;
++ Handle str = java_lang_String::create_from_symbol(m->name(), CHECK_NULL);
++ return JNIHandles::make_local(THREAD, str());
++}
++JVM_END
++
++
++JVM_ENTRY(void, MH_initDMHclasses(JNIEnv *env, jobject igcls, jobjectArray class_array)) {
++ //FIXME: NYI
++}
++JVM_END
++
++
++/// JVM_RegisterMethodHandleMethods
++
++#define ADR "J"
++
++#define LANG "Ljava/lang/"
++#define DYNP "Ljava/dyn/"
++#define DYNH "Ljava/dyn/hotspot/"
++
++#define OBJ LANG"Object;"
++#define CLS LANG"Class;"
++#define STRG LANG"String;"
++#define MH DYNH"MH;"
++#define AMH DYNH"AMH;"
++#define BMH DYNH"BMH;"
++#define DMH DYNH"DMH;"
++#define MT DYNP"MethodType;"
++#define MTFM DYNH"MTForm;"
++
++#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"("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)},
++};
++
++
++// This one function is exported, used by NativeLookup.
++
++JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass mhcls))
++ {
++ ThreadToNativeFromVM ttnfv(thread);
++
++ int status = env->RegisterNatives(mhcls, methods, sizeof(methods)/sizeof(JNINativeMethod));
++ if (env->ExceptionOccurred()) {
++ if (PrintMiscellaneous && (Verbose || WizardMode)) {
++ tty->print_cr("Warning: java.dyn.hotspot.MH not found.");
++ }
++ env->ExceptionClear();
++ }
++ }
++JVM_END
+diff --git a/src/share/vm/prims/methodHandles.hpp b/src/share/vm/prims/methodHandles.hpp
+new file mode 100644
+--- /dev/null
++++ b/src/share/vm/prims/methodHandles.hpp
+@@ -0,0 +1,155 @@
++/*
++ * Copyright 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.
++ *
++ */
++
++class MacroAssembler;
++class Label;
++class MethodEntry;
++
++class MethodHandle: AllStatic {
++ // JVM support for MethodHandle, MethodType, and related types
++ // in java.dyn and java.dyn.hotspot.
++ // See also javaClasses for layouts java_dyn_Method{Handle,Type,Type::Form}.
++ public:
++ enum EntryKind {
++ _check_mtype, // how a caller calls a MH
++ _wrong_method_type, // what happens when there is a type mismatch
++ _invokestatic_mh, // how a MH emulates invokestatic
++ _invokespecial_mh, // ditto for the other invokes...
++ _invokevirtual_mh,
++ _invokeinterface_mh,
++ _EK_LIMIT,
++ _EK_FIRST = 0
++ };
++ private:
++ static MethodEntry* _entries[_EK_LIMIT];
++ static const char* _entry_names[_EK_LIMIT];
++ static bool ek_valid(EntryKind ek) { return (uint)ek < (uint)_EK_LIMIT; }
++
++ public:
++ static bool have_entry(EntryKind ek) { return ek_valid(ek) && _entries[ek] != NULL; }
++ static MethodEntry* entry(EntryKind ek) { assert(ek_valid(ek), "initialized");
++ return _entries[ek]; }
++ static const char* entry_name(EntryKind ek) { assert(ek_valid(ek), "oob");
++ return _entry_names[ek]; }
++
++ static void init_entry(EntryKind ek, MethodEntry* me) {
++ assert(ek_valid(ek), "oob");
++ assert(_entries[ek] == NULL, "no double initialization");
++ _entries[ek] = me;
++ }
++
++ static inline address from_compiled_entry(EntryKind ek);
++ static inline address from_interpreted_entry(EntryKind ek);
++
++public:
++ // called from InterpreterGenerator and StubGenerator
++ 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, Label& wrong_method_type);
++ static void jump_to_entry(MacroAssembler* _masm, Register recv_reg, Register temp_reg);
++ static void load_mh_receiver(MacroAssembler* _masm,
++ Register mtype_reg, Register savedsp_reg, Register recv_result);
++
++ // Runtime support
++ static methodOop decode_method(oop x);
++ static bool class_cast_needed(klassOop src, klassOop dst);
++ static const char* check_method_receiver(methodHandle m, Handle mtype, objArrayHandle ptypes);
++ static const char* check_method_signature(methodHandle m, Handle mtype, objArrayHandle ptypes, TRAPS);
++
++ static BasicType subword_to_int(BasicType t) {
++ if (t == T_BOOLEAN || t == T_CHAR || t == T_BYTE || t == T_SHORT)
++ // these guys are processed exactly like T_INT in calling sequences:
++ return T_INT;
++ return t;
++ }
++
++ static bool same_basic_type_for_arguments(BasicType src, BasicType dst) {
++ assert(src != T_VOID && dst != T_VOID, "should not be here");
++ if (src == dst) return true;
++ if (src <= T_INT && dst <= T_INT) return subword_to_int(src) == subword_to_int(dst);
++ return false;
++ }
++
++ static bool same_basic_type_for_returns(BasicType src, BasicType dst) {
++ if (dst == T_VOID) return true; // return values can always be forgotten
++ return same_basic_type_for_arguments(src, dst);
++ }
++
++};
++
++
++// Access methods for the "entry" field of a java.dyn.MethodHandle.
++// The field is primarily a jump target for compiled calls.
++// However, we squirrel away some nice pointers for other uses,
++// just before the jump target.
++// Aspects of a method handle entry:
++// - from_compiled_entry - stub used when compiled code calls the MH
++// - from_interpreted_entry - stub used when the interpreter calls the MH
++// - type_checking_entry - stub for runtime casting between MHForm siblings
++class MethodEntry {
++ public:
++ class Data {
++ friend MethodEntry;
++ size_t _total_size; // size including Data and code stub
++ MethodEntry* _type_checking_entry;
++ address _from_interpreted_entry;
++ MethodEntry* method_entry() { return (MethodEntry*)(this + 1); }
++ };
++
++ Data* data() { return (Data*)this - 1; }
++
++ address start_address() { return (address) data(); }
++ address end_address() { return start_address() + data()->_total_size; }
++
++ address from_compiled_entry() { return (address) this; }
++
++ address from_interpreted_entry() { return data()->_from_interpreted_entry; }
++ void set_from_interpreted_entry(address e) { data()->_from_interpreted_entry = e; }
++
++ MethodEntry* type_checking_entry() { return data()->_type_checking_entry; }
++ void set_type_checking_entry(MethodEntry* e) { data()->_type_checking_entry = e; }
++
++ void set_end_address(address end_addr) {
++ size_t total_size = end_addr - start_address();
++ assert(total_size > 0 && total_size < 0x1000, "reasonable end address");
++ data()->_total_size = total_size;
++ }
++
++ // Compiler support:
++ static int from_interpreted_entry_offset_in_bytes() {
++ return offset_of(Data, _from_interpreted_entry) - sizeof(Data);
++ }
++ static int type_checking_entry_offset_in_bytes() {
++ return offset_of(Data, _from_interpreted_entry) - sizeof(Data);
++ }
++
++ static address start_compiled_entry(MacroAssembler* _masm,
++ address interpreted_entry = NULL);
++ static MethodEntry* finish_compiled_entry(MacroAssembler* masm, address start_addr);
++};
++
++address MethodHandle::from_compiled_entry(EntryKind ek) { return entry(ek)->from_compiled_entry(); }
++address MethodHandle::from_interpreted_entry(EntryKind ek) { return entry(ek)->from_interpreted_entry(); }
+diff --git a/src/share/vm/prims/nativeLookup.cpp b/src/share/vm/prims/nativeLookup.cpp
+--- a/src/share/vm/prims/nativeLookup.cpp
++++ b/src/share/vm/prims/nativeLookup.cpp
+@@ -78,6 +78,7 @@
+
+ extern "C" {
+ void JNICALL JVM_RegisterUnsafeMethods(JNIEnv *env, jclass unsafecls);
++ void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls);
+ void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
+ }
+
+@@ -96,6 +97,9 @@
+ }
+ if (strstr(jni_name, "Java_sun_misc_Unsafe_registerNatives") != NULL) {
+ return CAST_FROM_FN_PTR(address, JVM_RegisterUnsafeMethods);
++ }
++ if (strstr(jni_name, "Java_java_dyn_hotspot_MH_registerNatives") != NULL) {
++ return CAST_FROM_FN_PTR(address, JVM_RegisterMethodHandleMethods);
+ }
+ if (strstr(jni_name, "Java_sun_misc_Perf_registerNatives") != NULL) {
+ return CAST_FROM_FN_PTR(address, JVM_RegisterPerfMethods);
+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
+@@ -3181,6 +3181,18 @@
+ "Skip assert() and verify() which page-in unwanted shared " \
+ "objects. ") \
+ \
++ product(bool, MethodHandles, false, \
++ "support method handles") \
++ \
++ develop(bool, TraceMethodHandles, false, \
++ "trace internal method handle operations") \
++ \
++ product(bool, InvokeDynamic, false, \
++ "recognize the invokedynamic instruction") \
++ \
++ develop(bool, TraceInvokeDynamic, false, \
++ "trace internal invoke dynamic operations") \
++ \
+ product(bool, TaggedStackInterpreter, false, \
+ "Insert tags in interpreter execution stack for oopmap generaion")\
+ \
+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
+@@ -643,48 +643,6 @@
+ JRT_END
+
+
+-// ---------------------------------------------------------------------------------------------------------
+-// Non-product code
+-#ifndef PRODUCT
+-
+-void SharedRuntime::verify_caller_frame(frame caller_frame, methodHandle callee_method) {
+- ResourceMark rm;
+- assert (caller_frame.is_interpreted_frame(), "sanity check");
+- assert (callee_method->has_compiled_code(), "callee must be compiled");
+- methodHandle caller_method (Thread::current(), caller_frame.interpreter_frame_method());
+- jint bci = caller_frame.interpreter_frame_bci();
+- methodHandle method = find_callee_method_inside_interpreter(caller_frame, caller_method, bci);
+- assert (callee_method == method, "incorrect method");
+-}
+-
+-methodHandle SharedRuntime::find_callee_method_inside_interpreter(frame caller_frame, methodHandle caller_method, int bci) {
+- EXCEPTION_MARK;
+- Bytecode_invoke* bytecode = Bytecode_invoke_at(caller_method, bci);
+- methodHandle staticCallee = bytecode->static_target(CATCH); // Non-product code
+-
+- bytecode = Bytecode_invoke_at(caller_method, bci);
+- int bytecode_index = bytecode->index();
+- Bytecodes::Code bc = bytecode->adjusted_invoke_code();
+-
+- Handle receiver;
+- if (bc == Bytecodes::_invokeinterface ||
+- bc == Bytecodes::_invokevirtual ||
+- bc == Bytecodes::_invokespecial) {
+- symbolHandle signature (THREAD, staticCallee->signature());
+- receiver = Handle(THREAD, retrieve_receiver(signature, caller_frame));
+- } else {
+- receiver = Handle();
+- }
+- CallInfo result;
+- constantPoolHandle constants (THREAD, caller_method->constants());
+- LinkResolver::resolve_invoke(result, receiver, constants, bytecode_index, bc, CATCH); // Non-product code
+- methodHandle calleeMethod = result.selected_method();
+- return calleeMethod;
+-}
+-
+-#endif // PRODUCT
+-
+-
+ JRT_ENTRY_NO_ASYNC(void, SharedRuntime::register_finalizer(JavaThread* thread, oopDesc* obj))
+ assert(obj->is_oop(), "must be a valid oop");
+ assert(obj->klass()->klass_part()->has_finalizer(), "shouldn't be here otherwise");
+@@ -781,6 +739,7 @@
+ // Find bytecode
+ Bytecode_invoke* bytecode = Bytecode_invoke_at(caller, bci);
+ bc = bytecode->adjusted_invoke_code();
++ // @@@ what about tail calls?
+ 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));
+ 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)";
+ }
+
+ char* SharedRuntime::generate_class_cast_message(
+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
+@@ -171,9 +171,6 @@
+
+ static oop retrieve_receiver( symbolHandle sig, frame caller );
+
+- static void verify_caller_frame(frame caller_frame, methodHandle callee_method) PRODUCT_RETURN;
+- static methodHandle find_callee_method_inside_interpreter(frame caller_frame, methodHandle caller_method, int bci) PRODUCT_RETURN_(return methodHandle(););
+-
+ static void register_finalizer(JavaThread* thread, oopDesc* obj);
+
+ // dtrace notifications
+@@ -204,6 +201,23 @@
+ * in order to correctly free the result.
+ */
+ 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)
++ * @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
++ * in order to correctly free the result.
++ */
++ static char* generate_wrong_method_type_message(JavaThread* thr,
++ oopDesc* mtype = NULL,
++ oopDesc* mhandle = NULL);
+
+ /**
+ * Fill in the "X cannot be cast to a Y" message for ClassCastException
+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
+@@ -47,6 +47,7 @@
+ JVM_ACC_IS_OLD = 0x00010000, // RedefineClasses() has replaced this method
+ JVM_ACC_IS_OBSOLETE = 0x00020000, // RedefineClasses() has made method obsolete
+ JVM_ACC_IS_PREFIXED_NATIVE = 0x00040000, // JVMTI has prefixed this native method
++ JVM_MH_INVOKE_BITS = (JVM_ACC_NATIVE | JVM_ACC_SYNTHETIC | JVM_ACC_MONITOR_MATCH),
+
+ // klassOop flags
+ JVM_ACC_HAS_MIRANDA_METHODS = 0x10000000, // True if this class has miranda methods in it's vtable
+@@ -72,6 +73,7 @@
+
+ // flags accepted by set_field_flags()
+ JVM_ACC_FIELD_FLAGS = 0x00008000 | JVM_ACC_WRITTEN_FLAGS
++
+ };
+
+
+@@ -113,6 +115,7 @@
+ bool is_old () const { return (_flags & JVM_ACC_IS_OLD ) != 0; }
+ bool is_obsolete () const { return (_flags & JVM_ACC_IS_OBSOLETE ) != 0; }
+ bool is_prefixed_native () const { return (_flags & JVM_ACC_IS_PREFIXED_NATIVE ) != 0; }
++ bool is_method_handle_invoke () const { return (_flags & JVM_MH_INVOKE_BITS) == JVM_MH_INVOKE_BITS; }
+
+ // klassOop flags
+ bool has_miranda_methods () const { return (_flags & JVM_ACC_HAS_MIRANDA_METHODS ) != 0; }
+@@ -199,6 +202,14 @@
+ jshort as_short() { return (jshort)_flags; }
+ jint as_int() { return _flags; }
+
++ inline friend AccessFlags accessFlags_from(jint flags);
++
+ // Printing/debugging
+ void print_on(outputStream* st) const PRODUCT_RETURN;
+ };
++
++inline AccessFlags accessFlags_from(jint flags) {
++ AccessFlags af;
++ af._flags = flags;
++ return af;
++}
+diff --git a/src/share/vm/utilities/array.hpp b/src/share/vm/utilities/array.hpp
+--- a/src/share/vm/utilities/array.hpp
++++ b/src/share/vm/utilities/array.hpp
+@@ -40,11 +40,18 @@
+ _length = 0;
+ _data = NULL;
+ DEBUG_ONLY(init_nesting();)
++ // client may call initialize, at most once
+ }
+
+
+ ResourceArray(size_t esize, int length) {
++ DEBUG_ONLY(_data = NULL);
++ initialize(esize, length);
++ }
++
++ void initialize(size_t esize, int length) {
+ assert(length >= 0, "illegal length");
++ assert(_data == NULL, "must be new object");
+ _length = length;
+ _data = resource_allocate_bytes(esize * length);
+ DEBUG_ONLY(init_nesting();)
+@@ -111,7 +118,10 @@
+ /* creation */ \
+ array_name() : base_class() {} \
+ array_name(const int length) : base_class(esize, length) {} \
+- array_name(const int length, const etype fx) : base_class(esize, length) { \
++ array_name(const int length, const etype fx) { initialize(length, fx); } \
++ void initialize(const int length) { base_class::initialize(esize, length); } \
++ void initialize(const int length, const etype fx) { \
++ initialize(length); \
+ for (int i = 0; i < length; i++) ((etype*)_data)[i] = fx; \
+ } \
+ \
+@@ -157,16 +167,29 @@
+ \
+ public: \
+ /* creation */ \
+- stack_name() : array_name() { _size = 0; } \
+- stack_name(const int size) : array_name(size){ _length = 0; _size = size; } \
+- stack_name(const int size, const etype fx) : array_name(size, fx) { _size = size; } \
++ stack_name() : array_name() { _size = 0; } \
++ stack_name(const int size) { initialize(size); } \
++ stack_name(const int size, const etype fx) { initialize(size, fx); } \
++ void initialize(const int size, const etype fx) { \
++ _size = size; \
++ array_name::initialize(size, fx); \
++ /* _length == size, allocation and size are the same */ \
++ } \
++ void initialize(const int size) { \
++ _size = size; \
++ array_name::initialize(size); \
++ _length = 0; /* reset length to zero; _size records the allocation */ \
++ } \
+ \
+ /* standard operations */ \
+ int size() const { return _size; } \
+ \
+- void push(const etype x) { \
+- if (length() >= size()) expand(esize, length(), _size); \
+- ((etype*)_data)[_length++] = x; \
++ int push(const etype x) { \
++ int len = length(); \
++ if (len >= size()) expand(esize, len, _size); \
++ ((etype*)_data)[len] = x; \
++ _length = len+1; \
++ return len; \
+ } \
+ \
+ etype pop() { \
+@@ -235,7 +258,7 @@
+ int capacity() const { return size(); } \
+ void clear() { truncate(0); } \
+ void trunc_to(const int length) { truncate(length); } \
+- void append(const etype x) { push(x); } \
++ int append(const etype x) { return push(x); } \
+ void appendAll(const stack_name* stack) { push_all(stack); } \
+ etype last() const { return top(); } \
+ }; \
+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
+@@ -111,6 +111,12 @@
+ }
+
+ void* raw_allocate(int elementSize);
++
++ // some uses pass the Thread explicitly for speed (4990299 tuning)
++ void* raw_allocate(Thread* thread, int elementSize) {
++ assert(on_stack(), "fast ResourceObj path only");
++ return (void*)resource_allocate_bytes(thread, elementSize * _max);
++ }
+ };
+
+ template<class E> class GrowableArray : public GenericGrowableArray {
+@@ -121,6 +127,11 @@
+ void raw_at_put_grow(int i, const E& p, const E& fill);
+ void clear_and_deallocate();
+ public:
++ GrowableArray(Thread* thread, int initial_size) : GenericGrowableArray(initial_size, 0, false) {
++ _data = (E*)raw_allocate(thread, sizeof(E));
++ for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E();
++ }
++
+ GrowableArray(int initial_size, bool C_heap = false) : GenericGrowableArray(initial_size, 0, C_heap) {
+ _data = (E*)raw_allocate(sizeof(E));
+ for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E();
+@@ -159,10 +170,12 @@
+
+ void print();
+
+- void append(const E& elem) {
++ int append(const E& elem) {
+ check_nesting();
+ if (_len == _max) grow(_len);
+- _data[_len++] = elem;
++ int idx = _len++;
++ _data[idx] = elem;
++ return idx;
+ }
+
+ void append_if_missing(const E& elem) {
+diff --git a/src/share/vm/utilities/hashtable.cpp b/src/share/vm/utilities/hashtable.cpp
+--- a/src/share/vm/utilities/hashtable.cpp
++++ b/src/share/vm/utilities/hashtable.cpp
+@@ -43,9 +43,11 @@
+ entry = _free_list;
+ _free_list = _free_list->next();
+ } else {
+- const int block_size = 500;
+- if (_first_free_entry == _end_block) {
++ if (_first_free_entry + _entry_size >= _end_block) {
++ int block_size = MIN2(512, MAX2((int)_table_size / 2, (int)_number_of_entries));
+ int len = _entry_size * block_size;
++ len = 1 << log2_intptr(len); // round down to power of 2
++ assert(len >= _entry_size, "");
+ _first_free_entry = NEW_C_HEAP_ARRAY(char, len);
+ _end_block = _first_free_entry + len;
+ }
+@@ -53,6 +55,7 @@
+ _first_free_entry += _entry_size;
+ }
+
++ assert(_entry_size % HeapWordSize == 0, "");
+ entry->set_hash(hashValue);
+ return entry;
+ }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/meth.proj.patch Thu Jul 31 03:58:45 2008 -0700
@@ -0,0 +1,3631 @@
+diff --git a/src/share/projects/meth/README.txt b/src/share/projects/meth/README.txt
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/meth/README.txt
+@@ -0,0 +1,21 @@
++Standalone NetBeans project of JSR 292 RI
++
++(Not yet merged with the JDK; use -Xbootclasspath.)
++
++To open:
++ open -a netbeans . # Open Project => select this directory
++
++To build:
++ cd .; ant clean compile run
++
++To run a unit test (requires modified JVM):
++ #NetBeansResources=$(find /Applications/NetBeans* -type d -name Resources | tail -1)
++ #NetBeansResources="/Applications/NetBeans/NetBeans 6.1.app/Contents/Resources"
++ #junit="$NetBeansResources/NetBeans/java2/modules/ext/junit-3.8.2.jar"
++ export junit=$HOME/env/jars/junit-3.8.2.jar
++ export mhproj="$HOME/Projects/MethodHandle" #(pwd -P)
++ export cpath="$mhproj/build/classes:$mhproj/build/test/classes:$junit"
++ gamma -Xbootclasspath/a:"$cpath" jsr292.dyn.MethodHandleBytecodeTest
++
++Simpler (currently broken) demo:
++ gamma -Xbootclasspath/a:dist/MethodHandle.jar MethodHandleDemo
+diff --git a/src/share/projects/meth/build.xml b/src/share/projects/meth/build.xml
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/meth/build.xml
+@@ -0,0 +1,146 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!-- You may freely edit this file. See commented blocks below for -->
++<!-- some examples of how to customize the build. -->
++<!-- (If you delete it and reopen the project it will be recreated.) -->
++<project name="MethodHandle" default="default" basedir=".">
++ <description>Builds, tests, and runs the project MethodHandle.</description>
++ <import file="nbproject/build-impl.xml"/>
++
++<!-- For some reason, the run.jvmargs property does not expand from this file.
++ It must be placed in nbproject/project.properties as follows:
++ run.jvmargs=-Xbootclasspath/a:${build.classes.dir}:${local.junit.jar}
++ -->
++ <property name="--broken--run.jvmargs" value="-Xbootclasspath/a:${build.classes.dir}:${local.junit.jar}"/>
++
++ <target name="-pre-compile-test">
++ <!--
++ <copy file="${libs.junit.classpath}" tofile="${local.junit.jar}"/>
++ -->
++ <mkdir dir="${build.dir}/handl3"/>
++ <echo level="info" message="junit classpath: ${libs.junit.classpath}"/>
++ <echo level="info" message="-pre-compile-test MethodHandl3 in ${test.src.dir} => ${build.dir}/handl3"/>
++ <javac srcdir="${test.src.dir}"
++ destdir="${build.dir}/handl3"
++ includes="**/*Handl3.java"
++ classpath="${build.classes.dir}"
++ />
++ <java
++ classname="java.dyn.InstallMethodHandl3"
++ >
++ <jvmarg value="-Xbootclasspath/a:${build.dir}/handl3"/>
++ <arg file="${build.dir}/handl3"/>
++ </java>
++ <echo level="info" message="done with -pre-compile-test"/>
++ </target>
++
++ <property name="javadoc.includes" value="java/dyn/*.java"/>
++
++ <target depends="init" name="-javadoc-build">
++ <mkdir dir="${dist.javadoc.dir}"/>
++ <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" executable="${platform.javadoc}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}"
++ verbose="yes"
++ public="yes"
++ >
++ <classpath>
++ <path path="${javac.classpath}"/>
++ </classpath>
++ <fileset dir="${src.dir}" excludes="${excludes}" includes="${javadoc.includes}">
++ <filename name="**/*.java"/>
++ </fileset>
++ </javadoc>
++ </target>
++
++
++<!-- FOR TRACING:
++ <target name="-init-macrodef-junit">
++ <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
++ <attribute default="${includes}" name="includes"/>
++ <attribute default="${excludes}" name="excludes"/>
++ <attribute default="**" name="testincludes"/>
++ <sequential>
++ <echo message="junit jvmargs: ${run.jvmargs}"/>
++ <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" jvm="${platform.java}" showoutput="true"
++ >
++ <batchtest todir="${build.test.results.dir}">
++ <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
++ <filename name="@{testincludes}"/>
++ </fileset>
++ </batchtest>
++ <classpath>
++ <path path="${run.test.classpath}"/>
++ </classpath>
++ <syspropertyset>
++ <propertyref prefix="test-sys-prop."/>
++ <mapper from="test-sys-prop.*" to="*" type="glob"/>
++ </syspropertyset>
++ <formatter type="brief" usefile="false"/>
++ <formatter type="xml"/>
++ <jvmarg line="${run.jvmargs}"/>
++ </junit>
++ </sequential>
++ </macrodef>
++ </target>
++-->
++
++ <!--
++
++ There exist several targets which are by default empty and which can be
++ used for execution of your tasks. These targets are usually executed
++ before and after some main targets. They are:
++
++ -pre-init: called before initialization of project properties
++ -post-init: called after initialization of project properties
++ -pre-compile: called before javac compilation
++ -post-compile: called after javac compilation
++ -pre-compile-single: called before javac compilation of single file
++ -post-compile-single: called after javac compilation of single file
++ -pre-compile-test: called before javac compilation of JUnit tests
++ -post-compile-test: called after javac compilation of JUnit tests
++ -pre-compile-test-single: called before javac compilation of single JUnit test
++ -post-compile-test-single: called after javac compilation of single JUunit test
++ -pre-jar: called before JAR building
++ -post-jar: called after JAR building
++ -post-clean: called after cleaning build products
++
++ (Targets beginning with '-' are not intended to be called on their own.)
++
++ Example of inserting an obfuscator after compilation could look like this:
++
++ <target name="-post-compile">
++ <obfuscate>
++ <fileset dir="${build.classes.dir}"/>
++ </obfuscate>
++ </target>
++
++ For list of available properties check the imported
++ nbproject/build-impl.xml file.
++
++
++ Another way to customize the build is by overriding existing main targets.
++ The targets of interest are:
++
++ -init-macrodef-javac: defines macro for javac compilation
++ -init-macrodef-junit: defines macro for junit execution
++ -init-macrodef-debug: defines macro for class debugging
++ -init-macrodef-java: defines macro for class execution
++ -do-jar-with-manifest: JAR building (if you are using a manifest)
++ -do-jar-without-manifest: JAR building (if you are not using a manifest)
++ run: execution of project
++ -javadoc-build: Javadoc generation
++ test-report: JUnit report generation
++
++ An example of overriding the target for project execution could look like this:
++
++ <target name="run" depends="MethodHandle-impl.jar">
++ <exec dir="bin" executable="launcher.exe">
++ <arg file="${dist.jar}"/>
++ </exec>
++ </target>
++
++ Notice that the overridden target depends on the jar target and not only on
++ the compile target as the regular run target does. Again, for a list of available
++ properties which you can use, check the target you are overriding in the
++ nbproject/build-impl.xml file.
++
++ -->
++</project>
+diff --git a/src/share/projects/meth/build/handl3/README.txt b/src/share/projects/meth/build/handl3/README.txt
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/meth/build/handl3/README.txt
+@@ -0,0 +1,1 @@
++this directory hold a non-standard MethodHandle, used in compilation environments
+diff --git a/src/share/projects/meth/nbproject/project.properties b/src/share/projects/meth/nbproject/project.properties
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/meth/nbproject/project.properties
+@@ -0,0 +1,70 @@
++application.args=
++application.title=MethodHandle
++application.vendor=jrose
++build.classes.dir=${build.dir}/classes
++build.classes.excludes=**/*.java,**/*.form
++# This directory is removed when the project is cleaned:
++build.dir=build
++build.generated.dir=${build.dir}/generated
++# Only compile against the classpath explicitly listed here:
++build.sysclasspath=ignore
++build.test.classes.dir=${build.dir}/test/classes
++build.test.results.dir=${build.dir}/test/results
++debug.classpath=\
++ ${run.classpath}
++debug.test.classpath=\
++ ${run.test.classpath}
++# This directory is removed when the project is cleaned:
++dist.dir=dist
++dist.jar=${dist.dir}/MethodHandle.jar
++dist.javadoc.dir=${dist.dir}/javadoc
++excludes=
++file.reference.build-handl3=${build.dir}/handl3
++includes=**
++jar.compress=false
++javac.classpath=
++# Space-separated list of extra javac options
++javac.compilerargs=-Xlint:unchecked
++javac.deprecation=false
++javac.source=1.5
++javac.target=1.5
++javac.test.classpath=\
++ ${file.reference.build-handl3}:\
++ ${javac.classpath}:\
++ ${build.classes.dir}:\
++ ${libs.junit.classpath}
++javadoc.additionalparam=
++javadoc.author=false
++javadoc.encoding=
++javadoc.noindex=false
++javadoc.nonavbar=false
++javadoc.notree=false
++javadoc.private=false
++javadoc.splitindex=true
++javadoc.use=true
++javadoc.version=false
++javadoc.windowtitle=
++jnlp.codebase.type=local
++jnlp.codebase.url=file:/Users/jrose/Projects/MethodHandle/dist/
++jnlp.enabled=false
++jnlp.offline-allowed=false
++jnlp.signed=false
++main.class=MethodHandleDemo
++manifest.file=manifest.mf
++meta.inf.dir=${src.dir}/META-INF
++platform.active=JDK_1.6
++run.classpath=\
++ ${javac.classpath}:\
++ ${build.classes.dir}
++# Space-separated list of JVM arguments used when running the project
++# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
++# or test-sys-prop.name=value to set system properties for unit tests):
++run.test.classpath=\
++ ${javac.test.classpath}:\
++ ${build.test.classes.dir}
++source.encoding=UTF-8
++src.dir=src
++test.src.dir=test
++project.license=openjdk
++##platform.bootclasspath=${build.classes.dir}:${libs.junit.classpath}
++run.jvmargs=-Xbootclasspath/a:"${build.classes.dir}:${libs.junit.classpath}"
+diff --git a/src/share/projects/meth/nbproject/project.xml b/src/share/projects/meth/nbproject/project.xml
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/meth/nbproject/project.xml
+@@ -0,0 +1,17 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<project xmlns="http://www.netbeans.org/ns/project/1">
++ <type>org.netbeans.modules.java.j2seproject</type>
++ <configuration>
++ <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
++ <name>MethodHandle</name>
++ <minimum-ant-version>1.6.5</minimum-ant-version>
++ <explicit-platform explicit-source-supported="true"/>
++ <source-roots>
++ <root id="src.dir"/>
++ </source-roots>
++ <test-roots>
++ <root id="test.src.dir"/>
++ </test-roots>
++ </data>
++ </configuration>
++</project>
+diff --git a/src/share/projects/meth/src/MethodHandleDemo.java b/src/share/projects/meth/src/MethodHandleDemo.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/meth/src/MethodHandleDemo.java
+@@ -0,0 +1,64 @@
++//
++// MethodHandleDemo.java
++// MethodHandle
++//
++// Created by John Rose on 6/12/07.
++// Copyright 2007 __MyCompanyName__. All rights reserved.
++//
++
++//package '';
++import java.dyn.*;
++import java.lang.reflect.*;
++import java.util.*;
++
++public class MethodHandleDemo {
++
++ public static void main(String... av) {
++ Class caller = MethodHandleDemo.class;
++ Class returnType = String.class;
++ Class[] signature = {String.class};
++ String result;
++// MethodCall mc
++// = new MethodCall(caller, "test", returnType, signature);
++// result = idi.<String,RuntimeException>invoke("hello", "world");
++ MethodHandle mh0 = MethodHandles.findVirtual(Object.class,
++ "toString", MethodType.make(String.class));
++ System.out.println("found "+mh0);
++ MethodHandle mh = MethodHandles.findStatic(MethodHandleDemo.class,
++ "test0", MethodType.make(String.class));
++ System.out.println("calling "+mh);
++ result = null; //(String) MethodHandles.invoke(mh.type(), mh);
++ System.out.println(result);
++ }
++
++ // static methods we make handles for:
++ public static String test0() {
++ return "[test0]";
++ }
++
++ public static String test1(String x) {
++ return "[test1 " + x + "]";
++ }
++
++ public static String test2(String x, String y) {
++ return "[test2 " + x + " " + y + "]";
++ }
++
++ // virtual methods we make handles for:
++ static class Obj {
++
++ String x;
++
++ Obj(String x) {
++ this.x = x;
++ }
++
++ public String test1() {
++ return "[test1 " + x + "]";
++ }
++
++ public String test2(String y) {
++ return "[test2 " + x + " " + y + "]";
++ }
++ }
++}
+diff --git a/src/share/projects/meth/src/java/dyn/CallSite.java b/src/share/projects/meth/src/java/dyn/CallSite.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/meth/src/java/dyn/CallSite.java
+@@ -0,0 +1,75 @@
++/*
++ * Copyright 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. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * 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.
++ */
++
++package java.dyn;
++
++/**
++ * An <code>invokedynamic</code> call site, as reified to the bootstrap method.
++ * Every instance of a call site corresponds to a distinct instance
++ * of the <code>invokedynamic</code> instruction.
++ * Call sites have state, one reference word, called the <code>target</code>,
++ * and typed as a {@link MethodHandle}. When this state is null (as it is
++ * initially) the call site is in the unlinked state. Otherwise, it is said
++ * to be linked to its target.
++ * <p>
++ * When an unlinked call site is executed, a bootstrap routine is called
++ * to finish the execution of the call site, and optionally to link
++ * the call site.
++ * <p>
++ * FIXME: Make this into a concrete (but non-final) class.
++ * @author jrose
++ */
++public interface CallSite {
++ /**
++ * Report the current linkage state of the call site. (This is mutable.)
++ * @return the current linkage state of the call site
++ */
++ public MethodHandle getTarget();
++
++ /**
++ * Link or relink the call site, by setting its target method.
++ * @param target the new target, or null if it is to be unlinked
++ */
++ public void setTarget(MethodHandle target);
++
++ /**
++ * Report the class containing the call site. (This is immutable static context.)
++ * @return class containing the call site
++ */
++ Class callerClass();
++
++ /**
++ * Report the method name specified in the {@code invokedynamic} instruction. (This is immutable static context.)
++ * @return method name specified by the call site
++ */
++ String name();
++
++ /*
++ * Report the result and parameter types, derived from the invocation descriptor, and resolved
++ * against the calling class's class loader. (This is immutable static context.)
++ * @return method type specified by the call site
++ */
++ MethodType type();
++}
+diff --git a/src/share/projects/meth/src/java/dyn/Dynamic.java b/src/share/projects/meth/src/java/dyn/Dynamic.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/meth/src/java/dyn/Dynamic.java
+@@ -0,0 +1,37 @@
++/*
++ * Copyright 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. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * 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.
++ */
++
++package java.dyn;
++
++/**
++ * Syntactic marker interface for {@code invokedynamic} instructions.
++ * This type has no particular meaning as a class or interface supertype, and need never be implemented by any class.
++ * Logically, it denotes a dynamically typed reference to any object.
++ * As such it may be viewed as logically containing all methods on any of those types.
++ * @author jrose
++ */
++public class Dynamic {
++ // no methods
++}
+diff --git a/src/share/projects/meth/src/java/dyn/Linkage.java b/src/share/projects/meth/src/java/dyn/Linkage.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/meth/src/java/dyn/Linkage.java
+@@ -0,0 +1,111 @@
++package java.dyn;
++
++/*
++ * Copyright 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. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * 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.
++ */
++
++/**
++ *
++ * @author jrose
++ */
++public class Linkage {
++ /**
++ * Register a bootstrap method for use for a given caller class.
++ * The method handle must be of a type equivalent to {@link Linkage#bootstrapInvokeDynamic}.
++ * <p>
++ * The operation will fail with an exception if any of the following conditions hold:
++ * <ul>
++ * <li>The caller of this method is in a different package than the {@code callerClass},
++ * and there is a security manager, and its {@code checkPermission} call throws
++ * when passed {@link LinkagePermission("registerBootstrapMethod",callerClass)}.
++ * <li>The given class already has a bootstrap method, either from an embedded
++ * {@code BootstrapInvokeDynamic} classfile attribute, or from a previous
++ * call to this method.
++ * <li>The given class is already fully initialized.
++ * <li>The given class is in the process of initialization, in another thread.
++ * </ul>
++ * Because of these rules, a class may install its own bootstrap method in
++ * a static initializer.
++ */
++ void registerBootstrapMethod(Class callerClass, MethodHandle mh) {
++ SecurityManager security = System.getSecurityManager();
++ if (security != null) {
++ // FIXME: do not run this check if my caller and callerClass are package-mates.
++ security.checkPermission(new LinkagePermission("registerBootstrapMethod",callerClass));
++ }
++ throw new UnsupportedOperationException("NYI");
++ }
++
++ /** Determine if the caller class has declared or registered its own bootstrap method.
++ * If so, delegate this call to it. Otherwise, throw an IncompatibleClassChangeError.
++ */
++ public static
++ Object bootstrapInvokeDynamic(CallSite site, Object... receiverAndArguments) {
++ throw new UnsupportedOperationException("NYI");
++ }
++
++ /**
++ * Invalidate all <code>invokedynamic</code> call sites everywhere.
++ * <p>
++ * When this method returns, every <code>invokedynamic</code> instruction
++ * will invoke its bootstrap method on next call.
++ * <p>
++ * It is unspecified whether call sites already known to the Java
++ * code will continue to be associated with <code>invokedynamic</code>
++ * instructions. If any call site is still so associated, its
++ * {@link CallSite#getTarget()} method is guaranteed to return null
++ * the invalidation operation completes.
++ * <p>
++ * Invalidation operations are likely to be slow. Use them sparingly.
++ */
++ public static
++ Object invalidateAll() {
++ SecurityManager security = System.getSecurityManager();
++ if (security != null) {
++ security.checkPermission(new LinkagePermission("invalidateAll"));
++ }
++ throw new UnsupportedOperationException("NYI");
++ }
++
++ /**
++ * Invalidate all <code>invokedynamic</code> call sites associated
++ * with the given class.
++ * (These are exactly those sites which report the given class
++ * via the {@link CallSite#callerClass()} method.)
++ * <p>
++ * When this method returns, every matching <code>invokedynamic</code>
++ * instruction will invoke its bootstrap method on next call.
++ * <p>
++ * For additional semantics of call site invalidation,
++ * see {@link #invalidateAll()}.
++ */
++ public static
++ Object invalidateCallerClass(Class<?> callerClass) {
++ SecurityManager security = System.getSecurityManager();
++ if (security != null) {
++ security.checkPermission(new LinkagePermission("invalidateAll", callerClass));
++ }
++ throw new UnsupportedOperationException("NYI");
++ }
++}
+diff --git a/src/share/projects/meth/src/java/dyn/LinkagePermission.java b/src/share/projects/meth/src/java/dyn/LinkagePermission.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/meth/src/java/dyn/LinkagePermission.java
+@@ -0,0 +1,111 @@
++/*
++ * Copyright 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. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * 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.
++ */
++
++package java.dyn;
++
++import java.security.*;
++import java.util.Enumeration;
++import java.util.Hashtable;
++import java.util.StringTokenizer;
++
++/**
++ * This class is for runtime permissions. A RuntimePermission
++ * contains a name (also referred to as a "target name") but
++ * no actions list; you either have the named permission
++ * or you don't.
++ *
++ * <P>
++ * The target name is the name of the runtime permission (see below). The
++ * naming convention follows the hierarchical property naming convention.
++ * Also, an asterisk
++ * may appear at the end of the name, following a ".", or by itself, to
++ * signify a wildcard match. For example: "loadLibrary.*" or "*" is valid,
++ * "*loadLibrary" or "a*b" is not valid.
++ * <P>
++ * The following table lists all the possible RuntimePermission target names,
++ * and for each provides a description of what the permission allows
++ * and a discussion of the risks of granting code the permission.
++ * <P>
++ *
++ * <table border=1 cellpadding=5 summary="permission target name,
++ * what the target allows,and associated risks">
++ * <tr>
++ * <th>Permission Target Name</th>
++ * <th>What the Permission Allows</th>
++ * <th>Risks of Allowing this Permission</th>
++ * </tr>
++ *
++ * <tr>
++ * <td>registerBootstrapMethod.{class name}</td>
++ * <td>Specifying a bootstrap method for invokedynamic, within a class of the given name</td>
++ * <td>An attacker could attempt to attach a bootstrap method to a class which
++ * has just been loaded, thus gaining control of its invokedynamic calls.</td>
++ * </tr>
++ *
++ * <tr>
++ * <td>invalidateAll</td>
++ * <td>Force the relinking of invokedynamic call sites everywhere.</td>
++ * <td>This could allow an attacker to slow down the system, or perhaps surface timing bugs in a dynamic language implementations, by forcing redundant relinking operations.</td>
++ * </tr>
++ *
++ *
++ * <tr>
++ * <td>invalidateCallerClass.{class name}</td>
++ * <td>Force the relinking of invokedynamic call sites in the given class.</td>
++ * <td>See {@code invalidateAll}.</td>
++ * </tr>
++ * </table>
++ *
++ * @see java.security.BasicPermission
++ * @see java.lang.SecurityManager
++ *
++ * @author jrose
++ */
++
++public final class LinkagePermission extends BasicPermission {
++ /**
++ * Create a new LinkagePermission with the given name.
++ * The name is the symbolic name of the LinkagePermission, such as
++ * "registerBootstrapMethod", "invalidateClass.*", etc. An asterisk
++ * may appear at the end of the name, following a ".", or by itself, to
++ * signify a wildcard match.
++ *
++ * @param name the name of the LinkagePermission
++ */
++ public LinkagePermission(String name) {
++ super(name);
++ }
++
++ /**
++ * Create a new LinkagePermission with the given name on the given class.
++ * Equivalent to {@code LinkagePermission(name+"."+clazz.getName())}.
++ *
++ * @param name the name of the LinkagePermission
++ * @param clazz the class affected by the permission
++ */
++ public LinkagePermission(String name, Class<?> clazz) {
++ super(name + "." + clazz.getName());
++ }
++}
+diff --git a/src/share/projects/meth/src/java/dyn/MethodHandle.java b/src/share/projects/meth/src/java/dyn/MethodHandle.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/meth/src/java/dyn/MethodHandle.java
+@@ -0,0 +1,128 @@
++/*
++ * Copyright 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. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun in the LICENSE file that accompanied this code.
++ *
++ * 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.
++ */
++
++package java.dyn;
++
++//import java.dyn.emu.*;
++import java.dyn.hotspot.*;
++
++/**
++ * A method handle is a typed reference to the entry point of a method.
++ * <p>
++ * Method handles are strongly typed according to signature.
++ * They are not distinguished by method name or enclosing class.
++ * A method handle must be invoked under a signature which exactly matches
++ * the method handle's own type.
++ * <p>
++ * Every method handle confesses its type via the <code>type</code> accessor.
++ * The structure of this type is a series of classes, one of which is
++ * the return type of the method (or <code>void.class</code> if none).
++ * <p>
++ * Every method handle appears as an object containing a method named
++ * <code>invoke</code>, whose signature exactly matches
++ * the method handle's type.
++ * <p>
++ * Every call to a method handle specifies an intended method type,
++ * which must exactly match the type of the method handle.
++ * The call looks within the receiver object for a method
++ * named <code>invoke</code> of the intended method type.
++ * The call fails with a linkage error if the method does not exist,
++ * even if there is an <code>invoke</code> method
++ * of a closely similar signature.
++ * <p>
++ * The receiver object must either be of type <code>MethodHandle</code>
++ * or else possess an <code>invoke</code> method in a public supertype
++ * of the receiver object. In other words, invocation of method handles
++ * is structurally typed, and will succeed as long as the receiver
++ * contains a public method of the correct name and type.
++ * <p>
++ * A method handle is an unrestricted capability to call a method.
++ * A method handle can be formed on a non-public method by a class
++ * that has access to that method; the resulting handle can be used
++ * in any place by any caller who gets access to it. Thus, access
++ * checking is performed when the method handle is created, not
++ * (as in reflection) every time it is called. Handles to non-public
++ * methods, or in non-public classes, should generally be kept secret.
++ * They should not be passed to untrusted code.
++ * <p>
++ * Bytecode in an extended JVM can directly call a method handle's
++ * <code>invoke</code> from an <code>invokeinterface</code> instruction.
++ * The interface type must be <code>MethodHandle</code> and the method name
++ * must be <code>invoke</code>. The signature of the invocation must
++ * (after linking symbolic type names) exactly match the method type
++ * of the target method.
++ * <p>
++ * Bytecode in an extended JVM can directly obtain a method handle
++ * for any accessible method from a <code>ldc</code> instruction
++ * which refers to a <code>CONSTANT_Methodref</code> or
++ * <code>CONSTANT_InterfaceMethodref</code> constant pool entry.
++ * <p>
++ * All JVMs can also use a reflective API called <code>MethodHandles</code>
++ * for creating and calling method handles.
++ * <p>
++ * A method reference may refer either to a static or non-static method.
++ * In the non-static case, the method handle type includes an explicit
++ * receiver argument, prepended before any other arguments.
++ * In the method handle's type, the initial receiver argument is typed
++ * according to the class under which the method was initially requested.
++ * (E.g., if a non-static method handle is obtained via <code>ldc</code>,
++ * the type of the receiver is the class named in the constant pool entry.)
++ * <p>
++ * When a method handle to a virtual method is invoked, the method is
++ * always looked up in the receiver.
++ * <p>
++ * A non-virtual method handles to a specific virtual method implementation
++ * can also be created. These do not perform virtual lookup based on
++ * receiver type. Such a method handle can only be created directly by
++ * the JVM, or synthesized from bytecode that also is allowed to contain
++ * an <code>invokespecial</code> instruction to the same method.
++ *
++ * @see MethodType
++ * @see MethodHandles
++ * @author jrose
++ */
++public class MethodHandle /*<T extends MethodType>*/ extends MH {
++ // interface MethodHandle<T extends MethodType<R,A...>>
++ // { T type(); <R,A...> public R invoke(A...); }
++
++ /**
++ * Report the type of this method handle.
++ * Every invocation of this method handle must exactly match this type.
++ * @return the method handle type
++ */
++ public MethodType type() {
++ return type; // inherited field
++ }
++
++ /**
++ * Subclasses may be in other packages, but must possess
++ * a token which they obtained from MH with a security check.
++ * @param token
++ */
++ protected MethodHandle(Access token, MethodType type) {
++ super(token, type);
++ }
++
++}
+diff --git a/src/share/projects/meth/src/java/dyn/MethodHandles.java b/src/share/projects/meth/src/java/dyn/MethodHandles.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/meth/src/java/dyn/MethodHandles.java
+@@ -0,0 +1,710 @@
++package java.dyn;
++
++import java.util.ArrayList;
++import sun.reflect.Reflection;
++
++//import java.dyn.emu.*;
++import java.dyn.hotspot.*;
++
++/**
++ * Fundamental operations and utilities for MethodHandle.
++ * <p>
++ * <em>API Note:</em> The matching of method types in this API cannot
++ * be completely checked by Java's generic type system for three reasons:
++ * <ol>
++ * <li>Method types range over all possible arities,
++ * from no arguments to an arbitrary number of arguments.
++ * Generics are not variadic, and so cannot represent this.</li>
++ * <li>Method types can specify arguments of primitive types,
++ * which Java generic types cannot range over.</li>
++ * <li>Method types can optionally specify varargs (ellipsis).</li>
++ * </ol>
++ * @author jrose
++ */
++public class MethodHandles {
++
++ private MethodHandles() { } // do not instantiate
++
++ private static final Access TOKEN = Access.getToken();
++
++ //// Method handle creation from ordinary methods.
++
++ /**
++ * Produce a method handle for a static method.
++ * The type of the method handle will be that of the method.
++ * The method and all its argument types must be accessible to the caller.
++ * @param defc the class from which the method is accessed
++ * @param name the name of the method
++ * @param type the type of the method
++ * @return the desired method handle, or null if no such method exists
++ */
++ public static
++ MethodHandle findStatic(Class<?> defc, String name, MethodType type) {
++ Class<?> callc = Reflection.getCallerClass(2);
++ return MH.findMethod(TOKEN, defc, name, null, type, false, callc);
++ }
++
++ /**
++ * Produce a method handle for a virtual method.
++ * The type of the method handle will be that of the method,
++ * with the receiver type (<code>defc</code>) prepended.
++ * The method and all its argument types must be accessible to the caller.
++ * <p>
++ * When called, the handle will treat the first argument as a receiver
++ * and dispatch on the receiver's type to determine which method
++ * implementation to enter.
++ * (The dispatching action is identical with that performed by an
++ * <code>invokevirtual</code> or <code>invokeinterface</code> instruction.)
++ * @param defc the class or interface from which the method is accessed
++ * @param name the name of the method
++ * @param type the type of the method, with the receiver argument omitted
++ * @return the desired method handle, or null if no such method exists
++ */
++ public static
++ MethodHandle findVirtual(Class<?> defc, String name, MethodType type) {
++ Class<?> callc = Reflection.getCallerClass(2);
++ return MH.findMethod(TOKEN, defc, name, defc, type, true, callc);
++ }
++
++ /**
++ * Produce an early-bound method handle for a virtual method.
++ * The type of the method handle will be that of the method,
++ * with the receiver type (<code>defc</code>) prepended.
++ * The method and all its argument types must be accessible to the caller.
++ * <p>
++ * When called, the handle will treat the first argument as a receiver,
++ * but will not dispatch on the receiver's type.
++ * (This direct invocation action is identical with that performed by an
++ * <code>invokespecial</code> instruction.)
++ * @param defc the class or interface from which the method is accessed
++ * @param name the name of the method
++ * @param type the type of the method, with the receiver argument omitted
++ * @return the desired method handle, or null if no such method exists
++ */
++ public static
++ MethodHandle findSpecial(Class<?> defc, String name, MethodType type) {
++ Class<?> callc = Reflection.getCallerClass(2);
++ return MH.findMethod(TOKEN, defc, name, defc, type, false, callc);
++ }
++
++ /**
++ * Make a direct method handle to <i>m</i>, if the current caller has permission.
++ * If <i>m</i> is non-static, the receiver argument is treated as an initial argument.
++ * If <i>m</i> is virtual, overriding is respected on every call.
++ * Unlike the Core Reflection API, exceptions are <em>not</em> wrapped.
++ * The type of the method handle will be that of the method,
++ * with the receiver type prepended (but only if it is non-static).
++ * If the method's <code>accessible</code> flag is not set,
++ * access checking is performed immediately on behalf of the caller.
++ * If <i>m</i> is not public, do not share the resulting handle with untrusted callers.
++ * @param m the reflected method
++ * @return a method handle which can invoke the reflected method
++ */
++ public static
++ MethodHandle unreflect(java.lang.reflect.Method m) {
++ throw new UnsupportedOperationException("NYI");
++ }
++
++ /**
++ * Produce a method handle for a reflected method.
++ * It will bypass checks for overriding methods on the receiver,
++ * as if by the <code>invokespecial</code> instruction.
++ * The type of the method handle will be that of the method,
++ * with the receiver type prepended.
++ * If the method's <code>accessible</code> flag is not set,
++ * access checking is performed immediately on behalf of the caller,
++ * as if <code>invokespecial</code> instruction were being linked.
++ * @param m the reflected method
++ * @return a method handle which can invoke the reflected method
++ */
++ public static
++ MethodHandle unreflectSpecial(java.lang.reflect.Method m) {
++ throw new UnsupportedOperationException("NYI");
++ }
++
++ /**
++ * Produce a method handle giving read access to a reflected field.
++ * The type of the method handle will have a return type of the field's
++ * value type. Its sole argument will be the field's containing class
++ * (but only if it is non-static).
++ * If the method's <code>accessible</code> flag is not set,
++ * access checking is performed immediately on behalf of the caller.
++ * @param f the reflected field
++ * @return a method handle which can load values from the reflected field
++ */
++ public static
++ MethodHandle unreflectGetter(java.lang.reflect.Field f) {
++ throw new UnsupportedOperationException("NYI");
++ }
++
++ /**
++ * Produce a method handle giving write access to a reflected field.
++ * The type of the method handle will have a void return type.
++ * Its last argument will be the field's value type.
++ * Its other argument will be the field's containing class
++ * (but only if it is non-static).
++ * If the method's <code>accessible</code> flag is not set,
++ * access checking is performed immediately on behalf of the caller.
++ * @param f the reflected field
++ * @return a method handle which can store values into the reflected field
++ */
++ public static
++ MethodHandle unreflectSetter(java.lang.reflect.Field f) {
++ throw new UnsupportedOperationException("NYI");
++ }
++
++ /// method handle modification (creation from other method handles)
++
++ /**
++ * Return the given method handle unchanged, after ensuring that
++ * its type is equal to the given type.
++ * @param mh
++ * @param type
++ * @return the original method handle
++ */
++ static <M extends MethodHandle>
++ M castType(M mh, MethodType type) {
++ MethodType mhType = mh.type();
++ if (!type.equals(mhType))
++ throw new ClassCastException(mhType.toString());
++ return mh;
++ }
++
++ /**
++ * Perform value checking, exactly as if for an adapted method handle.
++ * It is assumed that the given value is either null, of type T0,
++ * or (if T0 is primitive) of the wrapper type corresponding to T0.
++ * The following checks and conversions are made:
++ * <ul>
++ * <li>If T0 and T1 are references, then a cast to T1 is applied.
++ * (The types do not need to be related in any particular way.)
++ * <li>If T0 and T1 are primitives, then a widening or narrowing
++ * conversion is applied, if one exists.
++ * <li>If T0 is a primitive and T1 a reference, and
++ * T0 has a wrapper type TW, a boxing conversion to TW is applied,
++ * possibly followed by a reference conversion.
++ * T1 must be TW or a supertype.
++ * <li>If T0 is a reference and T1 a primitive, and
++ * T1 has a wrapper type TW, an unboxing conversion is applied,
++ * possibly preceded by a reference conversion.
++ * T0 must be TW or a supertype.
++ * <li>If T1 is void, the return value is discarded
++ * <li>If T0 is void and T1 a reference, a null value is introduced.
++ * <li>If T0 is void and T1 a primitive, a zero value is introduced.
++ * </ul>
++ * If the value is discarded, null will be returned.
++ * @param valueType
++ * @param value
++ * @return the value, converted if necessary
++ * @throws java.lang.ClassCastException if a cast fails
++ */
++ static
++ Object checkValue(Class<?> T0, Class<?> T1, Object value)
++ throws ClassCastException
++ {
++ if (T0 == T1) {
++ // no conversion needed
++ return value;
++ }
++ boolean prim0 = T0.isPrimitive(), prim1 = T1.isPrimitive();
++ Class<?> TW;
++ if (!prim0) {
++ if (!prim1) {
++ return T1.cast(T0.cast(value));
++ }
++ // convert reference to primitive by unboxing
++ TW = Wrappers.asWrapperType(T0);
++ return T1.cast(TW.cast(value));
++ }
++ if (!prim1) {
++ // convert primitive to reference type by boxing
++ TW = Wrappers.asWrapperType(T1);
++ return TW.cast(T0.cast(value));
++ }
++ // convert primitive to primitive; this requires a real value change
++ if (value == null)
++ return Wrappers.zeroValue(T1);
++ // convert non-Number primitives to Integer:
++ if (value instanceof Character) {
++ char ch = (char) (Character) value;
++ value = Integer.valueOf(ch);
++ if (T1 == Integer.class)
++ return value;
++ } else if (value instanceof Boolean) {
++ boolean z = (boolean) (Boolean) value;
++ value = Integer.valueOf(z ? 1 : 0);
++ if (T1 == Integer.class)
++ return value;
++ }
++ Number numval = (Number) value;
++ switch (Wrappers.basicTypeChar(T1)) {
++ case 'Z': return (numval.intValue() != 0);
++ case 'B': return numval.byteValue();
++ case 'C': return (char) numval.intValue();
++ case 'S': return numval.shortValue();
++ case 'I': return numval.intValue();
++ case 'J': return numval.longValue();
++ case 'F': return numval.floatValue();
++ case 'D': return numval.doubleValue();
++ }
++ return null;
++ }
++
++ static
++ Object checkValue(Class<?> T1, Object value)
++ throws ClassCastException
++ {
++ return checkValue(T1, value.getClass(), value);
++ }
++
++ /**
++ * Produce a method handle which calls the original method handle,
++ * after performing general-purpose argument list conversions.
++ * The resulting method handle is guaranteed to confess a type
++ * which is equal to the desired newType.
++ * <p>
++ * An <i>outgoing argument</i> is one which will be passed to the
++ * original method handle. An <i>incoming argument</i> is one which
++ * will be passed to the new method handle. The old and
++ * new method types are determined by the original method handle's
++ * <code>getType</code> operation and the <code>newType</code> parameter,
++ * respectively.
++ * <p>
++ * The arguments string must specify the data source for every outgoing
++ * argument. The string contains zero or more short char sequences
++ * called <i>argument descriptors</i>, each of which determines
++ * how the corresponding outgoing parameter is supplied with an incoming
++ * argument, how an extra check is made during the call, or how a return
++ * value is to be produced.
++ * <p>
++ * An argument descriptor must have one of the following forms:
++ * <ul>
++ * <li>$<i>N</i> — the <i>N</i>th incoming argument ($0 is first)
++ * <li>$<i>N</i>/<i>I</i> — the <i>I</i>th array element of $<i>N</i>
++ * <li>$V — the values argument passed to this method
++ * <li>$V/<i>I</i> — the <i>I</i>th array element of $V
++ * <li>!$<i>N</i>/<i>L</i> — Array length cutoff:
++ * The incoming array argument <i>N</i> must be exactly of length L.
++ * (If L is zero, the array may be null also.)
++ * <li>{<i>D...</i>} — This is an array argument descriptor;
++ * a sequence of one or more argument descriptors
++ * is collected into an array. The brackets may not be nested.
++ * <li>{<i>...</i>*$<i>N</i>} — An array argument
++ * specifier may end with a starred argument reference,
++ * meaning that it and all remaining arguments are included
++ * in the tail of the outgoing argument array.
++ * <li>{<i>...</i>*<i>D</i>/<i>I</i>} — An array argument
++ * specifier may end with a starred element reference,
++ * meaning that all remaining elements of the incoming argument
++ * or value array are included in the tail of the
++ * outgoing argument array. (As a limiting case,
++ * if <i>I</i> is the incoming array length, no additional
++ * elements are added to the outgoing array.)
++ * <li>$X0 — a zero or null of the expected argument type
++ * <li>$X<i>X</i> — an integer hexadecimal constant is passed
++ * <li>$N — the new method handle itself is passed
++ * <li>$M — the original method handle itself is passed
++ * <li>*<i>D</i> — The final argument descriptor may be
++ * starred if it is an incoming argument or element descriptor,
++ * meaning that all remaining outgoing arguments are
++ * taken from that argument (or element) onward.
++ * (E.g., "*$1" means pass all arguments except the first,
++ * and "*$V/0" means pass all elements of the value array.)
++ * <li>=<i>D</i> — An equal sign introduces an optional
++ * return descriptor. The <i>N</i>th incoming argument is saved
++ * and used as the final return value from the new method handle.
++ * Any argument descriptor can be used after the equal sign.
++ * This descriptor must come last, if it appears at all.
++ * <li><i>...</i>*<i>D</i>=<i>D</i> — Star and equal sign
++ * can appear together; in this case the return descriptor is last.
++ * <li>commas and whitespace are ignored before and after descriptors
++ * </ul>
++ * All values N, I, L must be decimal numerals in the range 0..255.
++ * For outgoing arrays, if L is zero, a constant zero-length array
++ * may be passed instead of a new array.
++ * <p>
++ * Any argument array can be spread or unspread, though the
++ * Java varargs convention treats only the final argument this way.
++ * Spreading and unspreading respects the element type of the
++ * affected array(s), performing element-by-element conversion
++ * if necessary.
++ * <p>
++ * There must be exactly enough argument descriptors (not counting
++ * a final return descriptor) to supply every
++ * outgoing argument to the old method handle.
++ * <p>
++ * If an equals sign is present, the following specifier is not for
++ * an outgoing argument, but rather for the ultimate return value
++ * produced by the new method handle. In that case any return
++ * value produced by the original method is discarded.
++ * (This may be used to force an adapted method handle to return
++ * a fixed value, or a selected argument, such as the receiver.)
++ * <p>
++ * Additional conversions are applied as needed to ensure that
++ * the outgoing argument types and final return type are respected.
++ * These value-oriented conversions perform casting, boxing,
++ * and unboxing, exactly as described in {@link #convertArguments}.
++ * <p>
++ * If an array is created (because a curly bracket '{' is present)
++ * the type of the new array is exactly that specified by the
++ * corresponding outgoing argument or return type.
++ *
++ * @param mh the method handle to invoke after the argument is prepended
++ * @param newType the expected type of the new method handle
++ * @param arguments descriptions of individual arguments to pass to mh
++ * @param values the argument to prepend
++ * @return a new method handle which converts the argument list,
++ * before calling the original method handle
++ */
++ static
++ MethodHandle adaptArguments(MethodHandle mh, MethodType newType,
++ String arguments, Object values) {
++ throw new UnsupportedOperationException("NYI");
++ }
++
++ /**
++ * Produce a method handle which adapts the type of the
++ * given method handle to a new type, by pairwise argument conversion.
++ * The fourth and following arguments are collected into a values array
++ * and passed to the main overloading of {@link #adaptArguments}.
++ */
++ static
++ MethodHandle adaptArguments(MethodHandle mh, MethodType newType,
++ String arguments, Object... values) {
++ return adaptArguments(mh, newType, arguments, (Object) values);
++ }
++
++ /**
++ * Produce a method handle which adapts the type of the
++ * given method handle to a new type, by pairwise argument conversion.
++ * The missing value argument defaults to null, which is passed to
++ * the main overloading of {@link #adaptArguments}.
++ */
++ static
++ MethodHandle adaptArguments(MethodHandle mh, MethodType newType,
++ String arguments) {
++ return adaptArguments(mh, newType, arguments, (Object) null);
++ }
++
++ /**
++ * Produce a method handle which adapts the type of the
++ * given method handle to a new type, by pairwise argument conversion.
++ * The original type and new type must have the same number of
++ * arguments.
++ * The resulting method handle is guaranteed to confess a type
++ * which is equal to the desired new type.
++ * <p>
++ * If the original typ