--- a/meth.patch Fri Aug 29 15:14:28 2008 -0700
+++ b/meth.patch Sat Aug 30 02:47:18 2008 -0700
@@ -1,3 +1,357 @@ diff --git a/src/cpu/sparc/vm/cppInterpr
+diff --git a/src/cpu/sparc/vm/assembler_sparc.cpp b/src/cpu/sparc/vm/assembler_sparc.cpp
+--- a/src/cpu/sparc/vm/assembler_sparc.cpp
++++ b/src/cpu/sparc/vm/assembler_sparc.cpp
+@@ -2581,6 +2581,100 @@
+ restore();
+ }
+ }
++
++RegisterConstant MacroAssembler::delayed_value(intptr_t* delayed_value_addr,
++ Register tmp,
++ int offset) {
++ intptr_t value = *delayed_value_addr;
++ if (value != 0)
++ return value + offset;
++
++ // load indirectly to solve generation ordering problem
++ Address a(tmp, (address) delayed_value_addr);
++ load_ptr_contents(a, tmp);
++
++#ifdef ASSERT
++ tst(tmp);
++ breakpoint_trap(zero, xcc);
++#endif
++
++ if (offset != 0)
++ add(tmp, offset, tmp);
++
++ return tmp;
++}
++
++
++void MacroAssembler::lookup_interface_method(Register recv_klass,
++ Register intf_klass,
++ RegisterConstant itable_index,
++ Register method_result,
++ Register scan_temp,
++ Label& L_no_such_interface) {
++ Unimplemented();
++}
++
++
++// Test sub_klass against super_klass.
++// Fall through on failure, but branch to L_success if there is a match.
++// Use up the given temp_reg, but don't kill any other register.
++// Update the sub's secondary super cache if necesary.
++void MacroAssembler::check_klass_subtype(Register sub_klass,
++ Register super_klass,
++ Register temp_reg,
++ Label& L_success) {
++ Unimplemented();
++}
++
++
++void MacroAssembler::check_method_handle_type(Register mtype_reg, Register mh_reg,
++ Register temp_reg,
++ Label& wrong_method_type) {
++ assert_different_registers(mtype_reg, mh_reg, temp_reg);
++ // compare method type against that of the receiver
++ RegisterConstant mhtype_offset = delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg);
++ ld_ptr(mh_reg, mhtype_offset, temp_reg);
++ cmp(temp_reg, mtype_reg);
++ br(Assembler::notEqual, false, Assembler::pn, wrong_method_type);
++ delayed()->nop();
++}
++
++
++void MacroAssembler::jump_to_method_handle_entry(Register mh_reg, Register temp_reg) {
++ assert(mh_reg == G3_method_handle, "caller must put MH object in G3");
++ assert_different_registers(mh_reg, temp_reg);
++
++ // pick out the interpreted side of the handler
++ ld_ptr(mh_reg, delayed_value(java_dyn_MethodHandle::entry_offset_in_bytes, temp_reg), temp_reg);
++
++ // off we go...
++ ld_ptr(temp_reg, MethodEntry::from_interpreted_entry_offset_in_bytes(), temp_reg);
++ jmp(temp_reg, 0);
++
++ // for the various stubs which take control at this point,
++ // see MethodHandle::generate_method_handle_stub
++}
++
++RegisterConstant MacroAssembler::argument_offset(RegisterConstant arg_slot,
++ int extra_slot_offset) {
++ // cf. TemplateTable::prepare_invoke(), if (load_receiver).
++ int stackElementSize = Interpreter::stackElementWords() * wordSize;
++ int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
++ int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1);
++ assert(offset1 - offset == stackElementSize, "correct arithmetic");
++ if (arg_slot.is_constant()) {
++ offset += arg_slot.as_constant() * stackElementSize;
++ return offset;
++ } else {
++ Register temp = arg_slot.as_register();
++ sll_ptr(temp, exact_log2(stackElementSize), temp);
++ if (offset != 0)
++ add(temp, offset, temp);
++ return temp;
++ }
++}
++
++
+
+ void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg, Register temp_reg,
+ Label& done, Label* slow_case,
+diff --git a/src/cpu/sparc/vm/assembler_sparc.hpp b/src/cpu/sparc/vm/assembler_sparc.hpp
+--- a/src/cpu/sparc/vm/assembler_sparc.hpp
++++ b/src/cpu/sparc/vm/assembler_sparc.hpp
+@@ -84,6 +84,10 @@
+
+ REGISTER_DECLARATION(Register, Gtemp , G5);
+
++// JSR 292 fixed register usages:
++REGISTER_DECLARATION(Register, G5_method_type , G5);
++REGISTER_DECLARATION(Register, G3_method_handle , G3);
++
+ // The compiler requires that G5_megamorphic_method is G5_inline_cache_klass,
+ // because a single patchable "set" instruction (NativeMovConstReg,
+ // or NativeMovConstPatching for compiler1) instruction
+@@ -91,9 +95,13 @@
+ // call site is an inline cache or is megamorphic. See the function
+ // CompiledIC::set_to_megamorphic.
+ //
+-// On the other hand, G5_inline_cache_klass must differ from G5_method,
+-// because both registers are needed for an inline cache that calls
+-// an interpreted method.
++// If a inline cache targets an interpreted method, then the
++// G5 register will be used twice during the call. First,
++// the call site will be patched to load a compiledICHolder
++// into G5. (This is an ordered pair of ic_klass, method.)
++// The c2i adapter will first check the ic_klass, then load
++// G5_method with the method part of the pair just before
++// jumping into the interpreter.
+ //
+ // Note that G5_method is only the method-self for the interpreter,
+ // and is logically unrelated to G5_megamorphic_method.
+@@ -258,6 +266,27 @@
+
+
+ #endif
++
++// 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.
+ //
+@@ -1082,7 +1111,9 @@
+ inline void add( Register s1, Register s2, Register d );
+ inline void add( Register s1, int simm13a, Register d, relocInfo::relocType rtype = relocInfo::none);
+ inline void add( Register s1, int simm13a, Register d, RelocationHolder const& rspec);
++ inline void add( Register s1, RegisterConstant s2, Register d, int offset = 0);
+ inline void add( const Address& a, Register d, int offset = 0);
++
+
+ void addcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
+ void addcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+@@ -1298,6 +1329,11 @@
+ inline void ld( const Address& a, Register d, int offset = 0 );
+ inline void ldd( const Address& a, Register d, int offset = 0 );
+
++ inline void ld( Register s1, RegisterConstant s2, Register d );
++ inline void lduw( Register s1, RegisterConstant s2, Register d );
++ inline void ldsw( Register s1, RegisterConstant s2, Register d );
++ inline void ldx( Register s1, RegisterConstant s2, Register d );
++
+ // pp 177
+
+ void ldsba( Register s1, Register s2, int ia, Register d ) { emit_long( op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+@@ -1513,6 +1549,9 @@
+ inline void stx( Register d, const Address& a, int offset = 0 );
+ inline void st( Register d, const Address& a, int offset = 0 );
+ inline void std( Register d, const Address& a, int offset = 0 );
++
++ inline void st( Register d, Register s1, RegisterConstant s2 );
++ inline void stx( Register d, Register s1, RegisterConstant s2 );
+
+ // pp 177
+
+@@ -1889,6 +1928,7 @@
+ inline void store_ptr_contents( Register s, Address& a, int offset = 0 );
+ inline void jumpl_to( Address& a, Register d, int offset = 0 );
+ inline void jump_to( Address& a, int offset = 0 );
++ inline void jump_indirect_to( Address& a, Register temp, int ld_offset = 0, int jmp_offset = 0 );
+
+ // ring buffer traceable jumps
+
+@@ -1923,9 +1963,11 @@
+ // st_ptr will perform st for 32 bit VM's and stx for 64 bit VM's
+ inline void ld_ptr( Register s1, Register s2, Register d );
+ inline void ld_ptr( Register s1, int simm13a, Register d);
++ inline void ld_ptr( Register s1, RegisterConstant s2, Register d );
+ inline void ld_ptr( const Address& a, Register d, int offset = 0 );
+ inline void st_ptr( Register d, Register s1, Register s2 );
+ inline void st_ptr( Register d, Register s1, int simm13a);
++ inline void st_ptr( Register d, Register s1, RegisterConstant s2 );
+ inline void st_ptr( Register d, const Address& a, int offset = 0 );
+
+ // ld_long will perform ld for 32 bit VM's and ldx for 64 bit VM's
+@@ -2232,6 +2274,43 @@
+ );
+ void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case);
+
++ // small bootstrap problems
++ RegisterConstant delayed_value(intptr_t* delayed_value_addr, Register tmp,
++ int offset = 0);
++ RegisterConstant delayed_value(int(*value_fn)(), Register tmp,
++ int offset = 0) {
++ return delayed_value(delayed_value_addr(value_fn), tmp, offset);
++ }
++ RegisterConstant delayed_value(address(*value_fn)(), Register tmp,
++ int offset = 0) {
++ return delayed_value((intptr_t*) delayed_value_addr(value_fn), tmp, offset);
++ }
++
++ // interface method calling
++ void lookup_interface_method(Register recv_klass,
++ Register intf_klass,
++ RegisterConstant itable_index,
++ Register method_result,
++ Register scan_temp,
++ Label& no_such_interface);
++
++ // method handles (JSR 292)
++ void check_method_handle_type(Register mtype_reg, Register mh_reg,
++ Register temp_reg,
++ Label& wrong_method_type);
++ void jump_to_method_handle_entry(Register mh_reg, Register temp_reg);
++ // offset relative to Gargs of argument at tos[arg_slot].
++ // (arg_slot == 0 means the last argument, not the first).
++ RegisterConstant argument_offset(RegisterConstant arg_slot,
++ int extra_slot_offset = 0);
++
++ // klass type checking (falls through on failure)
++ void check_klass_subtype(Register sub_klass,
++ Register super_klass,
++ Register temp_reg,
++ Label& L_success);
++
++
+ // Stack overflow checking
+
+ // Note: this clobbers G3_scratch
+diff --git a/src/cpu/sparc/vm/assembler_sparc.inline.hpp b/src/cpu/sparc/vm/assembler_sparc.inline.hpp
+--- a/src/cpu/sparc/vm/assembler_sparc.inline.hpp
++++ b/src/cpu/sparc/vm/assembler_sparc.inline.hpp
+@@ -143,6 +143,29 @@
+ inline void Assembler::ld( Register s1, int simm13a, Register d) { lduw( s1, simm13a, d); }
+ #endif
+
++inline void Assembler::ld( Register s1, RegisterConstant s2, Register d) {
++ if (s2.is_register()) ld(s1, s2.as_register(), d);
++ else ld(s1, s2.as_constant(), d);
++}
++inline void Assembler::ldsw( Register s1, RegisterConstant s2, Register d) {
++ if (s2.is_register()) ldsw(s1, s2.as_register(), d);
++ else ldsw(s1, s2.as_constant(), d);
++}
++inline void Assembler::lduw( Register s1, RegisterConstant s2, Register d) {
++ if (s2.is_register()) ldsw(s1, s2.as_register(), d);
++ else ldsw(s1, s2.as_constant(), d);
++}
++inline void Assembler::ldx( Register s1, RegisterConstant s2, Register d) {
++ if (s2.is_register()) ldx(s1, s2.as_register(), d);
++ else ldx(s1, s2.as_constant(), d);
++}
++
++// form effective addresses this way:
++inline void Assembler::add( Register s1, RegisterConstant s2, Register d, int offset) {
++ if (s2.is_register()) add(s1, s2.as_register(), d);
++ else { add(s1, s2.as_constant() + offset, d); offset = 0; }
++ if (offset != 0) add(d, offset, d);
++}
+
+ inline void Assembler::ld( const Address& a, Register d, int offset ) { relocate(a.rspec(offset)); ld( a.base(), a.disp() + offset, d ); }
+ inline void Assembler::ldsb( const Address& a, Register d, int offset ) { relocate(a.rspec(offset)); ldsb( a.base(), a.disp() + offset, d ); }
+@@ -200,6 +223,15 @@
+ inline void Assembler::st( Register d, Register s1, Register s2) { stw(d, s1, s2); }
+ inline void Assembler::st( Register d, Register s1, int simm13a) { stw(d, s1, simm13a); }
+
++inline void Assembler::st( Register d, Register s1, RegisterConstant s2) {
++ if (s2.is_register()) st(d, s1, s2.as_register());
++ else st(d, s1, s2.as_constant());
++}
++inline void Assembler::stx( Register d, Register s1, RegisterConstant s2) {
++ if (s2.is_register()) stx(d, s1, s2.as_register());
++ else stx(d, s1, s2.as_constant());
++}
++
+ inline void Assembler::stb( Register d, const Address& a, int offset) { relocate(a.rspec(offset)); stb( d, a.base(), a.disp() + offset); }
+ inline void Assembler::sth( Register d, const Address& a, int offset) { relocate(a.rspec(offset)); sth( d, a.base(), a.disp() + offset); }
+ inline void Assembler::stw( Register d, const Address& a, int offset) { relocate(a.rspec(offset)); stw( d, a.base(), a.disp() + offset); }
+@@ -241,6 +273,14 @@
+ Assembler::ldx( s1, simm13a, d);
+ #else
+ Assembler::ld( s1, simm13a, d);
++#endif
++}
++
++inline void MacroAssembler::ld_ptr( Register s1, RegisterConstant s2, Register d ) {
++#ifdef _LP64
++ Assembler::ldx( s1, s2, d);
++#else
++ Assembler::ld( s1, s2, d);
+ #endif
+ }
+
+@@ -265,6 +305,14 @@
+ Assembler::stx( d, s1, simm13a);
+ #else
+ Assembler::st( d, s1, simm13a);
++#endif
++}
++
++inline void MacroAssembler::st_ptr( Register d, Register s1, RegisterConstant s2 ) {
++#ifdef _LP64
++ Assembler::stx( d, s1, s2);
++#else
++ Assembler::st( d, s1, s2);
+ #endif
+ }
+
+@@ -570,6 +618,15 @@
+ }
+
+
++inline void MacroAssembler::jump_indirect_to( Address& a, Register temp,
++ int ld_offset, int jmp_offset ) {
++ assert_not_delayed();
++ //sethi(a); // sethi is caller responsibility for this one
++ ld_ptr(a, temp, ld_offset);
++ jmp(temp, jmp_offset);
++}
++
++
+ inline void MacroAssembler::set_oop( jobject obj, Register d ) {
+ set_oop(allocate_oop_address(obj, d));
+ }
diff --git a/src/cpu/sparc/vm/cppInterpreter_sparc.cpp b/src/cpu/sparc/vm/cppInterpreter_sparc.cpp
--- a/src/cpu/sparc/vm/cppInterpreter_sparc.cpp
+++ b/src/cpu/sparc/vm/cppInterpreter_sparc.cpp
@@ -132,15 +486,36 @@ diff --git a/src/cpu/sparc/vm/interprete
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 @@
+@@ -235,6 +235,37 @@
}
++#ifdef ASSERT
++address last_WrongMethodType_caller;
++#endif //ASSERT
++
+
+// Method handle invoker
+// Dispatch a method of the form java.dyn.MethodHandle::invoke(...)
+address InterpreterGenerator::generate_method_handle_entry(void) {
-+ guarantee(false, "NYI");
++ if (!MethodHandles) {
++ return generate_abstract_entry();
++ }
++
++ // incoming registers: O0 (mh), G5 (mtype), O1... (args)
++ Register G5_mtype = G5_inline_cache_reg;
++ Register O0_recv = O0;
++
++ Label wrong_method_type;
++ address entry_point = MethodHandle::generate_method_handle_interpreter_entry(_masm, wrong_method_type);
++
++ __ bind(wrong_method_type);
++ __ mov(O0_recv, O1); // bad mh (actual)
++ __ mov(G5_mtype, O0); // missed mtype (required)
++ DEBUG_ONLY(__ get_pc(O2));
++ __ throw_if_not_x(Assembler::never, Interpreter::_throw_WrongMethodType_entry, G3_scratch);
++
++ return entry_point;
+}
+
+
@@ -149,7 +524,7 @@ diff --git a/src/cpu/sparc/vm/interprete
//----------------------------------------------------------------------------------------------------
// Entry points & stack frame layout
//
-@@ -364,6 +374,7 @@
+@@ -364,6 +395,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;
@@ -157,16 +532,517 @@ diff --git a/src/cpu/sparc/vm/interprete
case Interpreter::java_lang_math_sin : break;
case Interpreter::java_lang_math_cos : break;
case Interpreter::java_lang_math_tan : break;
+diff --git a/src/cpu/sparc/vm/methodHandles_sparc.cpp b/src/cpu/sparc/vm/methodHandles_sparc.cpp
+new file mode 100644
+--- /dev/null
++++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp
+@@ -0,0 +1,444 @@
++/*
++ * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++ * CA 95054 USA or visit www.sun.com if you need additional information or
++ * have any questions.
++ *
++ */
++
++#include "incls/_precompiled.incl"
++#include "incls/_methodHandles_sparc.cpp.incl"
++
++#define __ _masm->
++
++address MethodEntry::start_compiled_entry(MacroAssembler* _masm,
++ address interpreted_entry) {
++ __ align(wordSize);
++ address target = __ pc() + sizeof(Data);
++ while (__ pc() < target) {
++ __ nop();
++ __ align(wordSize);
++ }
++
++ MethodEntry* me = (MethodEntry*) __ pc();
++ me->set_end_address(__ pc()); // set a temporary end_address
++ me->set_from_interpreted_entry(interpreted_entry);
++ me->set_type_checking_entry(NULL);
++
++ return (address) me;
++}
++
++MethodEntry* MethodEntry::finish_compiled_entry(MacroAssembler* _masm,
++ address start_addr) {
++ MethodEntry* me = (MethodEntry*) start_addr;
++ assert(me->end_address() == start_addr, "valid ME");
++
++ // Fill in the real end_address:
++ __ align(wordSize);
++ me->set_end_address(__ pc());
++
++ return me;
++}
++
++
++// Code generation
++address MethodHandle::generate_method_handle_interpreter_entry(MacroAssembler* _masm,
++ Label& wrong_method_type) {
++ // I5_savedSP: sender SP (must preserve)
++ // G4 (Gargs): incoming argument list (must preserve)
++ // G5_method: invoke methodOop; becomes method type.
++ // G3_method_handle: receiver method handle (must load from sp[MTForm.vmdata])
++ // O0, O1: garbage temps, blown away
++ Register O0_argslot = O0;
++ Register O1_scratch = O1;
++
++ // here's where control starts out:
++ __ align(CodeEntryAlignment);
++ address entry_point = __ pc();
++
++ // fetch the MethodType from the method handle into G5_method_type
++ {
++ Register tem = G5_method;
++ for (int* pchase = methodOopDesc::method_type_pointer_chase(); (*pchase) != -1; pchase++) {
++ __ ld_ptr(tem, *pchase, G5_method_type);
++ tem = G5_method_type; // yes, it's the same register...
++ }
++ }
++
++ // given the MethodType, find out where the MH argument is buried
++ __ ld_ptr(G5_method_type,
++ __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, O1_scratch,
++ oopDesc::address_padding_in_bytes()),
++ O0_argslot);
++ __ ldx(O0_argslot,
++ __ delayed_value(java_dyn_MethodType::Form::vmdata_offset_in_bytes, O1_scratch),
++ O0_argslot);
++ __ ld_ptr(Gargs, __ argument_offset(O0_argslot), G3_method_handle);
++
++ __ check_method_handle_type(G5_method_type, G3_method_handle, O1_scratch, wrong_method_type);
++ __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
++ __ delayed()->nop();
++
++ // save away the wrong_method_type entry point
++ address wmt_jump_addr = __ pc();
++ __ ba(false, wrong_method_type);
++ __ delayed()->nop();
++
++ address me_cookie = MethodEntry::start_compiled_entry(_masm, wmt_jump_addr);
++ __ unimplemented("compiled _wrong_method_type NYI"); // %%% FIXME
++ init_entry(_wrong_method_type, MethodEntry::finish_compiled_entry(_masm, me_cookie));
++
++ return entry_point;
++}
++
++// Generate an "entry" field for a method handle.
++// This determines how the method handle will respond to calls.
++void MethodHandle::generate_method_handle_stub(MacroAssembler* _masm, MethodHandle::EntryKind ek) {
++ // Here is the register state during an interpreted call,
++ // as set up by generate_method_handle_interpreter_entry():
++ // - G5: garbage temp (was MethodHandle.invoke methodOop, unused)
++ // - O0: receiver method handle
++ // - rax: method handle type (already checked at call site, then unused)
++ // - rsi: sender SP (must preserve)
++ // - rdx: garbage temp, can blow away
++
++ Register O0_argslot = O0;
++ Register O1_scratch = O1;
++ Register G5_index = G5;
++
++ guarantee(java_dyn_MethodHandle::vmdata_offset_in_bytes() != 0, "must have offsets");
++
++ // some handy addresses
++ Address G5_method_fie( G5_method, 0, in_bytes(methodOopDesc::from_interpreted_offset()) );
++ Address G3_mh_vmref( G3_method_handle, 0, java_dyn_MethodHandle::vmref_offset_in_bytes() );
++ Address G3_mh_vmargslot( G3_method_handle, 0, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes() );
++ Address G3_mh_vmindex( G3_method_handle, 0, java_dyn_MethodHandle::vmdata_index_offset_in_bytes() );
++ Address G3_method_target( G3_method_handle, 0, java_dyn_MethodHandle::target_offset_in_bytes() ); //AMH
++
++ if (have_entry(ek)) {
++ __ nop(); // empty stubs make SG sick
++ return;
++ }
++
++ address interp_entry = __ pc();
++ if (UseCompressedOops) __ unimplemented("UseCompressedOops");
++
++ switch ((int) ek) {
++ case _check_mtype:
++ {
++ // this stub is special, because it requires a live mtype argument
++ Label wrong_method_type;
++ __ bind(wrong_method_type);
++ Address wmt_entry(O1_scratch, (address) &_entries[_wrong_method_type]);
++ __ load_ptr_contents(wmt_entry, O1_scratch);
++ Address wmt_fie(O1_scratch, 0, MethodEntry::from_interpreted_entry_offset_in_bytes());
++ __ jump_indirect_to(wmt_fie, O1_scratch);
++ __ delayed()->nop();
++
++ interp_entry = __ pc();
++ __ check_method_handle_type(G5_method_type, G3_method_handle, O1_scratch, wrong_method_type);
++ // now G5_method_type is dead; subsequent stubs will use it as a temp
++
++ __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
++ __ delayed()->nop();
++ }
++ break;
++
++ case _invokestatic_mh:
++ case _invokespecial_mh:
++ {
++ assert(G5_method == G5_index, "");
++ __ ld_ptr(G3_mh_vmref, G5_method);
++ __ verify_oop(G5_method);
++ // same as TemplateTable::invokestatic or invokespecial,
++ // minus the CP setup and profiling:
++ if (ek == _invokespecial_mh) {
++ // Must load & check the first argument before entering the target method.
++ __ lduw(G3_mh_vmargslot, O0_argslot);
++ __ ld_ptr(Gargs, __ argument_offset(O0_argslot), O0_argslot);
++ __ null_check(O0_argslot);
++ __ verify_oop(O0_argslot);
++ }
++ __ jump_indirect_to(G5_method_fie, G3_scratch);
++ __ delayed()->nop();
++ }
++ break;
++
++ case _invokebound_mh:
++ {
++ Register G5_scratch = G5_method;
++ __ lduw(G3_mh_vmargslot, O0_argslot);
++ // get address of inserted argument (-1 means after sp is decremented)
++ __ add(Gargs, __ argument_offset(O0_argslot, -1), O0_argslot);
++#ifdef ASSERT
++ {
++ Label L_ok, L_bad;
++ __ dec(O0_argslot, STACK_BIAS);
++ __ cmp(O0_argslot, FP);
++ __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, L_bad);
++ __ delayed()->cmp(SP, O0_argslot);
++ __ br(Assembler::lessEqualUnsigned, false, Assembler::pt, L_ok);
++ __ delayed()->inc(O0_argslot, STACK_BIAS);
++ __ bind(L_bad);
++ __ stop("first argument must fall within current frame");
++ __ bind(L_ok);
++ }
++#endif //ASSERT
++
++ // Make space on the stack for the prepended argument.
++ // Everything shallower than O0_argslot, including the
++ // return address, will be pulled down by one slot width.
++ Label loop, done;
++ __ sub(Gargs, Interpreter::stackElementSize(), Gargs); // decrement sp
++ __ mov(Gargs, O1_scratch);
++ {
++ __ bind(loop);
++ // pull one word down by 4 (or 8 if TaggedStackInterpreter)
++ __ ld_ptr(O1_scratch, Interpreter::stackElementSize(), G5_scratch);
++ __ st_ptr(G5_scratch, O1_scratch, 0);
++ __ inc(O1_scratch, wordSize);
++ __ cmp(O1_scratch, O0_argslot);
++ __ br(Assembler::less, false, Assembler::pn, loop);
++ __ delayed()->nop();
++ }
++
++ __ ld_ptr(G3_mh_vmref, G5_method);
++ __ verify_oop(G5_method);
++
++ // replace MH with bound receiver (or first static argument):
++ Address G3_method_receiver(G3_method_handle, 0, java_dyn_MethodHandle::receiver_offset_in_bytes());
++ __ ld_ptr(G3_method_receiver, O1_scratch);
++ __ st_ptr(O1_scratch, O0_argslot, 0);
++ if (TaggedStackInterpreter) {
++ __ mov(frame::TagReference, O1_scratch);
++ __ st_ptr(O1_scratch, O0_argslot, wordSize);
++ }
++ __ jump_indirect_to(G5_method_fie, G3_scratch);
++ __ delayed()->nop();
++ }
++ break;
++
++ case _invokevirtual_mh:
++ {
++ // same as TemplateTable::invokevirtual,
++ // minus the CP setup and profiling:
++
++ // pick out the vtable index and receiver offset from the MH,
++ // and then we can discard it:
++ __ lduw( G3_mh_vmargslot, O0_argslot );
++ __ lduw( G3_mh_vmindex, G5_index );
++ __ ld_ptr(Gargs, __ argument_offset(O0_argslot), O0_argslot);
++ __ null_check(O0_argslot, oopDesc::klass_offset_in_bytes());
++ // get receiver klass
++ Register O0_klass = O0_argslot;
++ // !UseCompressedOops
++ __ ld_ptr(O0_argslot, oopDesc::klass_offset_in_bytes(), O0_klass);
++ __ verify_oop(O0_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");
++ assert(G5_method == G5_index, "");
++ __ sll_ptr(G5_index, LogBytesPerWord, G5_index);
++ __ inc(O0_klass, base + vtableEntry::method_offset_in_bytes());
++ __ ld_ptr(O0_klass, G5_index, G5_method);
++
++ __ verify_oop(G5_method);
++ __ jump_indirect_to(G5_method_fie, G3_scratch);
++ __ delayed()->nop();
++ }
++ 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 O1_intf = O1_scratch;
++
++ __ ld_ptr( G3_mh_vmref, O1_intf );
++ __ lduw( G3_mh_vmargslot, O0_argslot );
++ __ lduw( G3_mh_vmindex, G5_index );
++ __ ld_ptr(Gargs, __ argument_offset(O0_argslot), O0_argslot);
++ __ null_check(O0_argslot, oopDesc::klass_offset_in_bytes());
++
++ // get receiver klass
++ Register O0_klass = O0_argslot;
++ // !UseCompressedOops
++ __ ld_ptr(O0_argslot, oopDesc::klass_offset_in_bytes(), O0_klass);
++ __ verify_oop(O0_klass);
++
++ // get interface klass
++ Label no_such_interface;
++ __ lookup_interface_method(O0_klass, O1_intf,
++ // note: next two args must be the same:
++ G5_index, G5_method,
++ G3_scratch,
++ no_such_interface);
++
++ __ verify_oop(G5_method);
++ __ jump_indirect_to(G5_method_fie, G3_scratch);
++ __ delayed()->nop();
++
++ __ bind(no_such_interface);
++ // Throw an exception.
++ // For historical reasons, it will be IncompatibleClassChangeError.
++ __ should_not_reach_here(); // %%% FIXME NYI
++ }
++ break;
++
++ case _adapter_mh_first+_adapt_retype_only:
++ case _adapter_mh_first+_adapt_drop_initial:
++ case _adapter_mh_first+_adapt_drop_final:
++ {
++ AdapterKind ak = AdapterKind(ek - _adapter_mh_first);
++ if (ak == _adapt_drop_final) {
++ // 'argslot' is number of slots to drop
++ // this is also the rightmost (shallowest) kept argument slot
++ __ lduw(G3_mh_vmargslot, O0_argslot);
++ RegisterConstant arg = __ argument_offset(O0_argslot);
++ __ add(Gargs, arg, Gargs); // pop some arguments
++ }
++
++ // immediately jump to the next MH layer:
++ __ ld_ptr(G3_method_target, G3_method_handle);
++ __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
++ __ delayed()->nop();
++ // This is OK when all parameter types widen.
++ // It is also OK when a return type narrows.
++ // Finally, we can simply ignore leading arguments from here on,
++ // without touching the stack.
++ }
++ break;
++
++ case _adapter_mh_first+_adapt_extend_sign:
++ case _adapter_mh_first+_adapt_extend_zero:
++ case _adapter_mh_first+_adapt_test_boolean:
++ {
++ AdapterKind ak = AdapterKind(ek - _adapter_mh_first);
++ // check an argument, or perform a simple in-place conversion,
++ // before jumping to the next layer of MH:
++ __ lduw(G3_mh_vmargslot, O0_argslot);
++ if (ak == _adapt_extend_zero || ak == _adapt_extend_sign)
++ __ lduw(G3_mh_vmindex, G5_index);
++ RegisterConstant arg = __ argument_offset(O0_argslot);
++
++ // get the new MH:
++ __ ld_ptr(G3_method_target, G3_method_handle);
++ // (now we are done with the old MH)
++
++ if (ak == _adapt_test_boolean) {
++ // convert a 32-bit integer value into a one-bit subword, C-style
++ __ ld_ptr(Gargs, arg, O1_scratch);
++ __ tst(O1_scratch);
++ Label skip;
++ __ br(Assembler::equal, false, Assembler::pt, skip);
++ __ delayed()->set((jint)true, O1_scratch);
++ __ st_ptr(O1_scratch, Gargs, arg);
++ __ bind(skip);
++
++ } else {
++ // original 32-bit vmdata word must be of this form:
++ // | argumentNumber:16 | lowBitCount:8 | conversion:8 |
++ __ srl(G5_index, 8, G5_index); // shift in 2nd LSB
++ __ sub(G0, G5_index, G5_index); // left shift by 32-lowBitCount
++ __ ld_ptr(Gargs, arg, O1_scratch);
++ __ sll_ptr(O1_scratch, G5_index, O1_scratch);
++ if (ak == _adapt_extend_sign) {
++ // this path is taken for int->byte, int->short
++ __ sra(O1_scratch, G5_index, O1_scratch); // 32-bit only!
++ } else if (ak == _adapt_extend_zero) {
++ // this is taken for int->char
++ __ srl(O1_scratch, G5_index, O1_scratch); // 32-bit only!
++ } else {
++ ShouldNotReachHere();
++ }
++ __ st_ptr(O1_scratch, Gargs, arg);
++ }
++
++ __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
++ __ delayed()->nop();
++ }
++ break;
++
++ case _adapter_mh_first+_adapt_check_cast:
++ {
++ // temps:
++ Register G5_klass = G5_index; // interesting AMH data
++
++ // check an argument, or perform a simple in-place conversion,
++ // before jumping to the next layer of MH:
++ __ lduw(G3_mh_vmargslot, O0_argslot);
++ RegisterConstant arg = __ argument_offset(O0_argslot);
++
++ // What class are we casting to?
++ __ ld_ptr(G3_mh_vmref, G5_klass);
++
++ // get the new MH:
++ __ ld_ptr(G3_method_target, G3_method_handle);
++ // (now we are done with the old MH)
++
++ Label done;
++ __ ld_ptr(Gargs, arg, O1_scratch);
++ __ tst(O1_scratch);
++ __ br(Assembler::zero, false, Assembler::pn, done); // no cast if null
++ __ delayed()->nop();
++ // !UseCompressedOops
++ __ ld_ptr(O1_scratch, oopDesc::klass_offset_in_bytes(), O1_scratch);
++
++ // live at this point:
++ // - G5_klass: klass required by the target method
++ // - O1_scratch: argument klass to test
++ // - G3_method_handle: method handle to invoke (after cast succeeds)
++ __ check_klass_subtype(O1_scratch, G5_klass, O0_argslot, done);
++
++ // If we get here, the type check failed!
++ // Call the wrong_method_type stub, passing the failing argument type in rax.
++ __ mov(G5_klass, G5_method_type); // missed klass (required)
++ __ mov(O1_scratch, G3_method_handle); // bad object (actual)
++
++ Address wmt_entry(O1_scratch, (address) &_entries[_wrong_method_type]);
++ __ load_ptr_contents(wmt_entry, O1_scratch);
++ Address wmt_fie(O1_scratch, 0, MethodEntry::from_interpreted_entry_offset_in_bytes());
++ __ jump_indirect_to(wmt_fie, O1_scratch);
++
++ __ bind(done);
++ __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
++ __ delayed()->nop();
++ }
++ break;
++
++ case _adapter_mh_first+_adapt_swap_argument:
++ case _adapter_mh_first+_adapt_push_argument:
++ case _adapter_mh_first+_adapt_push_primitive:
++ case _adapter_mh_first+_adapt_push_reference:
++ case _adapter_mh_first+_adapt_ricochet:
++ case _adapter_mh_first+_adapt_flyby:
++ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
++ break;
++
++ default: ShouldNotReachHere();
++ }
++
++ 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));
++}
+diff --git a/src/cpu/sparc/vm/register_definitions_sparc.cpp b/src/cpu/sparc/vm/register_definitions_sparc.cpp
+--- a/src/cpu/sparc/vm/register_definitions_sparc.cpp
++++ b/src/cpu/sparc/vm/register_definitions_sparc.cpp
+@@ -142,6 +142,8 @@
+ REGISTER_DEFINITION(Register, G3_scratch);
+ REGISTER_DEFINITION(Register, G4_scratch);
+ REGISTER_DEFINITION(Register, Gtemp);
++REGISTER_DEFINITION(Register, G5_method_type);
++REGISTER_DEFINITION(Register, G3_method_handle);
+ REGISTER_DEFINITION(Register, Lentry_args);
+
+ #ifdef CC_INTERP
+diff --git a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp
+--- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp
++++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp
+@@ -938,12 +938,12 @@
+ // Inputs:
+ // G2_thread - TLS
+ // G5_method - Method oop
+- // O0 - Flag telling us to restore SP from O5
+- // O4_args - Pointer to interpreter's args
+- // O5 - Caller's saved SP, to be restored if needed
++ // G4 (Gargs) - Pointer to interpreter's args
++ // O0..O4 - free for scratch
++ // O5_savedSP - Caller's saved SP, to be restored if needed
+ // O6 - Current SP!
+ // O7 - Valid return address
+- // L0-L7, I0-I7 - Caller's temps (no frame pushed yet)
++ // L0-L7, I0-I7 - Caller's temps (no frame pushed yet)
+
+ // Outputs:
+ // G2_thread - TLS
+@@ -955,7 +955,7 @@
+ // F0-F7 - more outgoing args
+
+
+- // O4 is about to get loaded up with compiled callee's args
++ // Gargs is the incoming argument base, and also an outgoing argument.
+ __ sub(Gargs, BytesPerWord, Gargs);
+
+ #ifdef ASSERT
diff --git a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
--- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
+++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
-@@ -108,6 +108,22 @@
+@@ -108,6 +108,34 @@
}
-+// Arguments are: required type in O0, failing object (or NULL) in O1
++#ifdef ASSERT
++address last_WrongMethodType_caller;
++#endif //ASSERT
++
++// Arguments are: required type in G5_method_type, and
++// failing object (or NULL) in G3_method_handle.
++// In the debug build, the caller should put his own PC in G1.
+address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
+ address entry = __ pc();
++#ifdef ASSERT
++ Address last_caller_addr(O3, (address)&last_WrongMethodType_caller);
++ __ sethi(last_caller_addr);
++ __ st_ptr(G1, last_caller_addr);
++#endif //ASSERT
+ // expression stack must be empty before entering the VM if an exception
+ // happened
+ __ empty_expression_stack();
@@ -174,7 +1050,8 @@ diff --git a/src/cpu/sparc/vm/templateIn
+ __ call_VM(Oexception,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::throw_WrongMethodTypeException),
-+ O0, O1);
++ G5_method_type, // required
++ G3_method_handle); // actual
+ __ should_not_reach_here();
+ return entry;
+}
@@ -183,11 +1060,44 @@ diff --git a/src/cpu/sparc/vm/templateIn
address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) {
address entry = __ pc();
// expression stack must be empty before entering the VM if an exception happened
-@@ -167,7 +183,15 @@
+@@ -132,7 +160,16 @@
+ }
+
+
+-address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step) {
++address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, bool unbox) {
++ TosState incoming_state = state;
++ if (InvokeDynamic) {
++ if (unbox) {
++ incoming_state = atos;
++ }
++ } else {
++ assert(!unbox, "old behavior");
++ }
++
+ address compiled_entry = __ pc();
+ Label cont;
+
+@@ -147,7 +184,7 @@
+ // do this here. Unfortunately if we did a rethrow we'd see an machepilog node
+ // first which would move g1 -> O0/O1 and destroy the exception we were throwing.
+
+- if( state == ltos ) {
++ if( incoming_state == ltos ) {
+ __ srl (G1, 0,O1);
+ __ srlx(G1,32,O0);
+ }
+@@ -164,16 +201,42 @@
+
+ __ mov(Llast_SP, SP); // Remove any adapter added stack space.
+
++ if (unbox && state != atos) {
++ // cast and unbox
++ __ unimplemented();
++ }
const Register cache = G3_scratch;
const Register size = G1_scratch;
-- __ get_cache_and_index_at_bcp(cache, G1_scratch, 1);
+ Label L_got_cache, L_giant_index;
+ if (InvokeDynamic) {
+ __ ldub(Lbcp, 0, size);
@@ -195,33 +1105,32 @@ diff --git a/src/cpu/sparc/vm/templateIn
+ __ br(Assembler::equal, false, Assembler::pn, L_giant_index);
+ __ delayed()->nop();
+ }
-+ __ get_cache_and_index_at_bcp(cache, G1_scratch, 1, false);
+ __ get_cache_and_index_at_bcp(cache, G1_scratch, 1);
++ ////__ get_cache_and_index_at_bcp(cache, G1_scratch, 1, false);
+ __ bind(L_got_cache);
++ if (unbox && state == atos) {
++ // insert a casting conversion, to keep verifier sane
++ __ unimplemented();
++ }
__ ld_ptr(Address(cache, 0, in_bytes(constantPoolCacheOopDesc::base_offset()) +
in_bytes(ConstantPoolCacheEntry::flags_offset())), size);
__ and3(size, 0xFF, size); // argument size in words
-@@ -175,7 +199,20 @@
+ __ sll(size, Interpreter::logStackElementSize(), size); // each argument size in bytes
__ add(Lesp, size, Lesp); // pop arguments
__ dispatch_next(state, step);
-
++
+ // out of the main line of code...
+ if (InvokeDynamic) {
+ __ bind(L_giant_index);
-+ __ get_cache_and_index_at_bcp(cache, G1_scratch, 1, true);
-+ __ br(false, L_got_cache);
++ __ unimplemented();
++ ////__ get_cache_and_index_at_bcp(cache, G1_scratch, 1, true);
++ __ ba(false, L_got_cache);
+ __ delayed()->nop();
+ }
-+
+
return entry;
-+}
-+
-+
-+address TemplateInterpreterGenerator::generate_return_unbox_entry_for(TosState state, int step) {
-+ __ unimplemented();
}
-
-
-@@ -448,6 +485,7 @@
+@@ -448,6 +511,7 @@
const int extra_space =
rounded_vm_local_words + // frame local scratch space
@@ -229,7 +1138,7 @@ diff --git a/src/cpu/sparc/vm/templateIn
frame::memory_parameter_word_sp_offset + // register save area
(native_call ? frame::interpreter_frame_extra_outgoing_argument_words : 0);
-@@ -1445,7 +1483,8 @@
+@@ -1445,7 +1509,8 @@
// callee_locals and max_stack are counts, not the size in frame.
const int locals_size =
round_to(callee_extra_locals * Interpreter::stackElementWords(), WordsPerLong);
@@ -252,42 +1161,27 @@ diff --git a/src/cpu/sparc/vm/templateTa
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;
+@@ -3053,6 +3054,20 @@
+ }
+
+
++void TemplateTable::invokedynamic(int byte_no) {
++ transition(vtos, vtos);
++
++ if (!InvokeDynamic) {
++ // We do not encounter this bytecode if !InvokeDynamic.
++ // See Rewriter::rewrite_invokedynamic.
++ __ stop("invokedynamic not enabled");
++ return;
++ }
++
++ __ stop("invokedynamic NYI");
++}
++
++
+ //----------------------------------------------------------------------------------------------------
+ // Allocation
+
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
@@ -300,7 +1194,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
} else {
InstructionMark im(this);
L.add_patch_at(code(), locator());
-@@ -4702,6 +4702,189 @@
+@@ -3969,6 +3969,223 @@
}
@@ -334,11 +1228,11 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ 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;
++ Address::ScaleFactor times_vte_scale = Address::times_ptr;
+ 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));
++ lea( 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);
@@ -346,7 +1240,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+
+ // 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));
++ lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr));
+
+ // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
+ // if (scan->interface() == intf) {
@@ -356,13 +1250,13 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ 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);
++ movptr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
++ cmpptr(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));
++ movptr(method_result, Address(recv_klass, method_result, Address::times_1));
+
+ if (!peel) break;
+ jmp(found_method);
@@ -371,9 +1265,9 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ // 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);
++ testptr(method_result, method_result);
+ jcc(Assembler::zero, L_no_such_interface);
-+ addl(scan_temp, scan_step);
++ addptr(scan_temp, scan_step);
+ }
+
+ bind(found_method);
@@ -405,13 +1299,13 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ Address super_check_offset_addr(super_klass, sco_offset);
+
+ // if the pointers are equal, we are done (e.g., String[] elements)
-+ cmpl(sub_klass, super_klass);
++ cmpptr(sub_klass, super_klass);
+ jcc(Assembler::equal, L_success);
+
+ // check the supertype display:
+ movl(temp_reg, super_check_offset_addr);
+ Address super_check_addr(sub_klass, temp_reg, Address::times_1, 0);
-+ cmpl(super_klass, super_check_addr); // load displayed supertype
++ cmpptr(super_klass, super_check_addr); // load displayed supertype
+ jcc(Assembler::equal, L_success);
+
+ // if it was a primary super, we can just fail immediately
@@ -423,30 +1317,41 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ {
+ // The repne_scan instruction uses fixed registers, which we must spill.
+ // Don't bother to figure out pre-existing connections with the input regs.
-+ pushl(rax);
-+ pushl(rcx);
-+ pushl(rdi);
-+ pushl(super_klass);
-+
-+ movl(rdi, secondary_supers_addr);
++ push(rax);
++ push(rcx);
++ push(rdi);
++ push(super_klass);
++
++ movptr(rdi, secondary_supers_addr);
+ // Load the array length.
+ movl(rcx, Address(rdi, arrayOopDesc::length_offset_in_bytes()));
+ // Skip to start of data.
-+ addl(rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT));
++ addptr(rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT));
+ // Scan rcx words at [edi] for occurance of rax,
+ // Set NZ/Z based on last compare
-+ popl(rax); // super_klass value, even if it was in rdi or rcx
-+ repne_scan();
++ pop(rax); // super_klass value, even if it was in rdi or rcx
++
++
++#ifdef _LP64
++ // This part is tricky, as values in supers array could be 32 or 64 bit wide
++ // and we store values in objArrays always encoded, thus we need to encode
++ // the value of rax before repne. Note that rax is dead after the repne.
++ if (UseCompressedOops) {
++ encode_heap_oop_not_null(rax);
++ repne_scanl();
++ } else
++#endif // _LP64
++ repne_scan();
+
+ // Unspill the temp. registers:
-+ popl(rdi);
-+ popl(rcx);
-+ popl(rax);
++ pop(rdi);
++ pop(rcx);
++ pop(rax);
+ }
+ jcc(Assembler::notEqual, L_failure);
+
+ // Success. Cache the super we found and proceed in triumph.
-+ movl(super_cache_addr, super_klass);
++ movptr(super_cache_addr, super_klass);
+
+ jmp(L_success);
+
@@ -462,8 +1367,9 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+void MacroAssembler::check_method_handle_type(Register mtype_reg, Register mh_reg,
+ Register temp_reg,
+ Label& wrong_method_type) {
++ if (UseCompressedOops) unimplemented(); // field accesses must decode
+ // compare method type against that of the receiver
-+ cmpl(mtype_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg)));
++ cmpptr(mtype_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg)));
+ jcc(Assembler::notEqual, wrong_method_type);
+}
+
@@ -476,6 +1382,8 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ assert(mh_reg == rcx, "caller must put MH object in rcx");
+ assert_different_registers(mh_reg, temp_reg);
+
++ if (UseCompressedOops) unimplemented(); // field accesses must decode
++
+ // pick out the interpreted side of the handler
+ movptr(temp_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::entry_offset_in_bytes, temp_reg)));
+
@@ -487,9 +1395,29 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+}
+
+
- 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,
++Address MacroAssembler::argument_address(RegisterConstant arg_slot,
++ int extra_slot_offset) {
++ // cf. TemplateTable::prepare_invoke(), if (load_receiver).
++ int stackElementSize = Interpreter::stackElementWords() * wordSize;
++ int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
++ int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1);
++ assert(offset1 - offset == stackElementSize, "correct arithmetic");
++ Register scale_reg = noreg;
++ Address::ScaleFactor scale_factor = Address::no_scale;
++ if (arg_slot.is_constant()) {
++ offset += arg_slot.as_constant() * stackElementSize;
++ } else {
++ scale_reg = arg_slot.as_register();
++ scale_factor = Address::times(stackElementSize);
++ }
++ offset += wordSize; // return PC is on stack
++ return Address(rsp, scale_reg, scale_factor, offset);
++}
++
++
+ void MacroAssembler::verify_oop_addr(Address addr, const char* s) {
+ if (!VerifyOops) return;
+ // QQQ fix this
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
@@ -527,7 +1455,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
times_4 = 2,
- times_8 = 3
+ times_8 = 3,
-+ times_wordSize = NOT_LP64(times_4) LP64_ONLY(times_8)
++ times_ptr = LP64_ONLY(times_8) NOT_LP64(times_4)
};
+
+ static ScaleFactor times(int size) {
@@ -590,7 +1518,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
private:
bool base_needs_rex() const {
-@@ -1287,6 +1346,35 @@
+@@ -1287,6 +1346,37 @@
);
void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case);
@@ -616,6 +1544,8 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ Register temp_reg,
+ Label& wrong_method_type);
+ void jump_to_method_handle_entry(Register mh_reg, Register temp_reg);
++ Address argument_address(RegisterConstant arg_slot, int extra_slot_offset = 0);
++
+
+ // klass type checking (falls through on failure)
+ void check_klass_subtype(Register sub_klass,
@@ -626,7 +1556,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
//----
void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0
-@@ -1464,6 +1552,23 @@
+@@ -1464,6 +1554,23 @@
void movoop(Register dst, jobject obj);
void movoop(Address dst, jobject obj);
@@ -650,6 +1580,252 @@ diff --git a/src/cpu/x86/vm/assembler_x8
void movptr(ArrayAddress dst, Register src);
// can this do an lea?
void movptr(Register dst, ArrayAddress src);
+@@ -1481,6 +1588,18 @@
+
+ #undef VIRTUAL
+
++ //%%% temporary until x86 assembler unification hits the baseline
++ void lea(Register d, Address a) { leal(d, a); }
++ void pop(Register d) { popl(d); }
++ void push(Register d) { pushl(d); }
++ void push(intptr_t d) { pushl(d); }
++ void mov(Register a, Register b) { movl(a, b); }
++ void addptr(Register a, Register b) { addl(a, b); }
++ void addptr(Register a, intptr_t b) { addl(a, b); }
++ void testptr(Register a, Register b) { testl(a, b); }
++ void cmpptr(Register a, Register b) { cmpl(a, b); }
++ void cmpptr(Register a, Address b) { cmpl(a, b); }
++ void cmpptr(Address a, intptr_t b) { cmpl(a, b); }
+ };
+
+ /**
+diff --git a/src/cpu/x86/vm/assembler_x86_64.cpp b/src/cpu/x86/vm/assembler_x86_64.cpp
+--- a/src/cpu/x86/vm/assembler_x86_64.cpp
++++ b/src/cpu/x86/vm/assembler_x86_64.cpp
+@@ -4666,6 +4666,223 @@
+ }
+
+
++RegisterConstant MacroAssembler::delayed_value(intptr_t* delayed_value_addr, Register tmp) {
++ intptr_t value = *delayed_value_addr;
++ if (value != 0)
++ return value;
++ movptr(tmp, ExternalAddress((address) delayed_value_addr));
++#ifdef ASSERT
++ Label L;
++ testl(tmp, tmp);
++ jccb(Assembler::notZero, L);
++ hlt();
++ bind(L);
++#endif
++ return tmp;
++}
++
++
++void MacroAssembler::lookup_interface_method(Register recv_klass,
++ Register intf_klass,
++ RegisterConstant itable_index,
++ Register method_result,
++ Register scan_temp,
++ Label& L_no_such_interface) {
++ assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
++ assert(itable_index.is_constant() || itable_index.as_register() == method_result,
++ "caller must use same register for non-constant itable index as for method");
++
++ // 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_ptr;
++ assert(vte_size == wordSize, "else adjust times_vte_scale");
++
++ movl(scan_temp, Address(recv_klass, instanceKlass::vtable_length_offset() * wordSize));
++ lea( 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");
++ lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr));
++
++ // 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--) {
++ movptr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
++ cmpptr(intf_klass, method_result);
++ jccb(Assembler::notEqual, search);
++
++ // Got a hit.
++ movl(method_result, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
++ movptr(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.
++ testptr(method_result, method_result);
++ jcc(Assembler::zero, L_no_such_interface);
++ addptr(scan_temp, scan_step);
++ }
++
++ bind(found_method);
++}
++
++
++// Test sub_klass against super_klass.
++// Fall through on failure, but branch to L_success if there is a match.
++// Use up the given temp_reg, but don't kill any other register.
++// Update the sub's secondary super cache if necesary.
++void MacroAssembler::check_klass_subtype(Register sub_klass,
++ Register super_klass,
++ Register temp_reg,
++ Label& L_success) {
++ Label L_failure; // fallthrough label
++
++ assert_different_registers(sub_klass, super_klass, temp_reg);
++
++ // a couple of useful fields in sub_klass:
++ int ss_offset = (klassOopDesc::header_size() * HeapWordSize +
++ Klass::secondary_supers_offset_in_bytes());
++ int sc_offset = (klassOopDesc::header_size() * HeapWordSize +
++ Klass::secondary_super_cache_offset_in_bytes());
++ Address secondary_supers_addr(sub_klass, ss_offset);
++ Address super_cache_addr( sub_klass, sc_offset);
++
++ int sco_offset = (klassOopDesc::header_size() * HeapWordSize +
++ Klass::super_check_offset_offset_in_bytes());
++ Address super_check_offset_addr(super_klass, sco_offset);
++
++ // if the pointers are equal, we are done (e.g., String[] elements)
++ cmpptr(sub_klass, super_klass);
++ jcc(Assembler::equal, L_success);
++
++ // check the supertype display:
++ movl(temp_reg, super_check_offset_addr);
++ Address super_check_addr(sub_klass, temp_reg, Address::times_1, 0);
++ cmpptr(super_klass, super_check_addr); // load displayed supertype
++ jcc(Assembler::equal, L_success);
++
++ // if it was a primary super, we can just fail immediately
++ cmpl(temp_reg, sc_offset);
++ jcc(Assembler::notEqual, L_failure);
++
++ // Now do a linear scan of the secondary super-klass chain.
++ // This code is rarely used, so simplicity is a virtue here.
++ {
++ // The repne_scan instruction uses fixed registers, which we must spill.
++ // Don't bother to figure out pre-existing connections with the input regs.
++ push(rax);
++ push(rcx);
++ push(rdi);
++ push(super_klass);
++
++ movptr(rdi, secondary_supers_addr);
++ // Load the array length.
++ movl(rcx, Address(rdi, arrayOopDesc::length_offset_in_bytes()));
++ // Skip to start of data.
++ addptr(rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT));
++ // Scan rcx words at [edi] for occurance of rax,
++ // Set NZ/Z based on last compare
++ pop(rax); // super_klass value, even if it was in rdi or rcx
++
++
++#ifdef _LP64
++ // This part is tricky, as values in supers array could be 32 or 64 bit wide
++ // and we store values in objArrays always encoded, thus we need to encode
++ // the value of rax before repne. Note that rax is dead after the repne.
++ if (UseCompressedOops) {
++ encode_heap_oop_not_null(rax);
++ repne_scanl();
++ } else
++#endif // _LP64
++ repne_scan();
++
++ // Unspill the temp. registers:
++ pop(rdi);
++ pop(rcx);
++ pop(rax);
++ }
++ jcc(Assembler::notEqual, L_failure);
++
++ // Success. Cache the super we found and proceed in triumph.
++ movptr(super_cache_addr, super_klass);
++
++ jmp(L_success);
++
++ // Fall through on failure!
++ bind(L_failure);
++}
++
++
++// registers on entry:
++// - rax ('check' register): required MethodType
++// - rcx: method handle
++// - rdx, rsi, or ?: killable temp
++void MacroAssembler::check_method_handle_type(Register mtype_reg, Register mh_reg,
++ Register temp_reg,
++ Label& wrong_method_type) {
++ if (UseCompressedOops) unimplemented(); // field accesses must decode
++ // compare method type against that of the receiver
++ cmpptr(mtype_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg)));
++ jcc(Assembler::notEqual, wrong_method_type);
++}
++
++
++// registers on entry:
++// - rcx: method handle
++// - rdx: killable temp (interpreted only)
++// - rax: killable temp (compiled only)
++void MacroAssembler::jump_to_method_handle_entry(Register mh_reg, Register temp_reg) {
++ assert(mh_reg == rcx, "caller must put MH object in rcx");
++ assert_different_registers(mh_reg, temp_reg);
++
++ if (UseCompressedOops) unimplemented(); // field accesses must decode
++
++ // pick out the interpreted side of the handler
++ movptr(temp_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::entry_offset_in_bytes, temp_reg)));
++
++ // off we go...
++ jmp(Address(temp_reg, MethodEntry::from_interpreted_entry_offset_in_bytes()));
++
++ // for the various stubs which take control at this point,
++ // see MethodHandle::generate_method_handle_stub
++}
++
++
++Address MacroAssembler::argument_address(RegisterConstant arg_slot,
++ int extra_slot_offset) {
++ // cf. TemplateTable::prepare_invoke(), if (load_receiver).
++ int stackElementSize = Interpreter::stackElementWords() * wordSize;
++ int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
++ int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1);
++ assert(offset1 - offset == stackElementSize, "correct arithmetic");
++ Register scale_reg = noreg;
++ Address::ScaleFactor scale_factor = Address::no_scale;
++ if (arg_slot.is_constant()) {
++ offset += arg_slot.as_constant() * stackElementSize;
++ } else {
++ scale_reg = arg_slot.as_register();
++ scale_factor = Address::times(stackElementSize);
++ }
++ offset += wordSize; // return PC is on stack
++ return Address(rsp, scale_reg, scale_factor, offset);
++}
++
++
+ void MacroAssembler::stop(const char* msg) {
+ address rip = pc();
+ pushaq(); // get regs on stack
diff --git a/src/cpu/x86/vm/assembler_x86_64.hpp b/src/cpu/x86/vm/assembler_x86_64.hpp
--- a/src/cpu/x86/vm/assembler_x86_64.hpp
+++ b/src/cpu/x86/vm/assembler_x86_64.hpp
@@ -687,7 +1863,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
times_4 = 2,
- times_8 = 3
+ times_8 = 3,
-+ times_wordSize = NOT_LP64(times_4) LP64_ONLY(times_8)
++ times_ptr = LP64_ONLY(times_8) NOT_LP64(times_4)
};
+
+ static ScaleFactor times(int size) {
@@ -751,7 +1927,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
private:
bool base_needs_rex() const {
-@@ -1267,6 +1327,35 @@
+@@ -1267,6 +1327,37 @@
);
void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case);
@@ -777,6 +1953,8 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ Register temp_reg,
+ Label& wrong_method_type);
+ void jump_to_method_handle_entry(Register mh_reg, Register temp_reg);
++ Address argument_address(RegisterConstant arg_slot, int extra_slot_offset = 0);
++
+
+ // klass type checking (falls through on failure)
+ void check_klass_subtype(Register sub_klass,
@@ -787,7 +1965,7 @@ diff --git a/src/cpu/x86/vm/assembler_x8
//----
// Debugging
-@@ -1434,6 +1523,15 @@
+@@ -1434,6 +1525,15 @@
void movoop(Register dst, jobject obj);
void movoop(Address dst, jobject obj);
@@ -803,6 +1981,25 @@ diff --git a/src/cpu/x86/vm/assembler_x8
void movptr(ArrayAddress dst, Register src);
void movptr(Register dst, AddressLiteral src);
+@@ -1451,6 +1551,18 @@
+ // Can push value or effective address
+ void pushptr(AddressLiteral src);
+
++ //%%% temporary until x86 assembler unification hits the baseline
++ void lea(Register d, Address a) { leaq(d, a); }
++ void pop(Register d) { popq(d); }
++ void push(Register d) { pushq(d); }
++ void push(intptr_t d) { pushq(d); }
++ void mov(Register a, Register b) { movq(a, b); }
++ void addptr(Register a, Register b) { addq(a, b); }
++ void addptr(Register a, intptr_t b) { addq(a, b); }
++ void testptr(Register a, Register b) { testq(a, b); }
++ void cmpptr(Register a, Register b) { cmpq(a, b); }
++ void cmpptr(Register a, Address b) { cmpq(a, b); }
++ void cmpptr(Address a, intptr_t b) { cmpq(a, b); }
+ };
+
+ /**
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
@@ -960,7 +2157,7 @@ diff --git a/src/cpu/x86/vm/interp_masm_
+ Label skip_receiver_profile;
+ if (receiver_can_be_null) {
-+ testl(receiver, receiver);
++ testptr(receiver, receiver);
+ jcc(Assembler::zero, skip_receiver_profile);
+ }
+
@@ -985,7 +2182,23 @@ diff --git a/src/cpu/x86/vm/interp_masm_
// Expression stack
void f2ieee(); // truncate ftos to 32bits
-@@ -152,6 +153,7 @@
+@@ -103,6 +104,15 @@
+
+ void pop(TosState state); // transition vtos -> state
+ void push(TosState state); // transition state -> vtos
++
++ void pop(Register r ) { ((MacroAssembler*)this)->pop(r); }
++
++ void push(Register r ) { ((MacroAssembler*)this)->push(r); }
++ void push(int32_t imm ) { ((MacroAssembler*)this)->push(imm); }
++
++ // These are dummies to prevent surprise implicit conversions to Register
++ void pop(void* v ); // Add unimplemented ambiguous method
++ void push(void* v ); // Add unimplemented ambiguous method
+
+ DEBUG_ONLY(void verify_stack_tag(frame::Tag t);)
+
+@@ -152,6 +162,7 @@
// jump to an invoked target
@@ -993,7 +2206,7 @@ diff --git a/src/cpu/x86/vm/interp_masm_
void jump_from_interpreted(Register method, Register temp);
// Returning from interpreted functions
-@@ -216,7 +218,8 @@
+@@ -216,7 +227,8 @@
void profile_not_taken_branch(Register mdp);
void profile_call(Register mdp);
void profile_final_call(Register mdp);
@@ -1051,6 +2264,55 @@ diff --git a/src/cpu/x86/vm/interp_masm_
assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below");
// convert from field index to ConstantPoolCacheEntry index
// and from word offset to byte offset
+@@ -601,13 +616,18 @@
+ MacroAssembler::call_VM_leaf_base(entry_point, 3);
+ }
+
++void InterpreterMacroAssembler::prepare_to_jump_from_interpreted() {
++ // set sender sp
++ lea(r13, Address(rsp, wordSize));
++ // record last_sp
++ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), r13);
++}
++
++
+ // Jump to from_interpreted entry of a call unless single stepping is possible
+ // in this thread in which case we must call the i2i entry
+ void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
+- // set sender sp
+- leaq(r13, Address(rsp, wordSize));
+- // record last_sp
+- movq(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), r13);
++ prepare_to_jump_from_interpreted();
+
+ if (JvmtiExport::can_post_interpreter_events()) {
+ Label run_compiled_code;
+@@ -1276,7 +1296,8 @@
+
+ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
+ Register mdp,
+- Register reg2) {
++ Register reg2,
++ bool receiver_can_be_null) {
+ if (ProfileInterpreter) {
+ Label profile_continue;
+
+@@ -1286,8 +1307,15 @@
+ // We are making a call. Increment the count.
+ increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
+
++ Label skip_receiver_profile;
++ if (receiver_can_be_null) {
++ testptr(receiver, receiver);
++ jcc(Assembler::zero, skip_receiver_profile);
++ }
++
+ // Record the receiver type.
+ record_klass_in_profile(receiver, mdp, reg2);
++ bind(skip_receiver_profile);
+
+ // The method data pointer needs to be updated to reflect the new target.
+ update_mdp_by_constant(mdp,
diff --git a/src/cpu/x86/vm/interp_masm_x86_64.hpp b/src/cpu/x86/vm/interp_masm_x86_64.hpp
--- a/src/cpu/x86/vm/interp_masm_x86_64.hpp
+++ b/src/cpu/x86/vm/interp_masm_x86_64.hpp
@@ -1067,7 +2329,31 @@ diff --git a/src/cpu/x86/vm/interp_masm_
void pop_ptr(Register r = rax);
void pop_i(Register r = rax);
-@@ -222,7 +223,8 @@
+@@ -111,6 +112,15 @@
+
+ void pop(TosState state); // transition vtos -> state
+ void push(TosState state); // transition state -> vtos
++
++ void pop(Register r ) { ((MacroAssembler*)this)->pop(r); }
++
++ void push(Register r ) { ((MacroAssembler*)this)->push(r); }
++ void push(int32_t imm ) { ((MacroAssembler*)this)->push(imm); }
++
++ // These are dummies to prevent surprise implicit conversions to Register
++ void pop(void* v ); // Add unimplemented ambiguous method
++ void push(void* v ); // Add unimplemented ambiguous method
+
+ // Tagged stack support, pop and push both tag and value.
+ void pop_ptr(Register r, Register tag);
+@@ -166,6 +176,7 @@
+ void dispatch_via (TosState state, address* table);
+
+ // jump to an invoked target
++ void prepare_to_jump_from_interpreted();
+ void jump_from_interpreted(Register method, Register temp);
+
+
+@@ -222,7 +233,8 @@
void profile_call(Register mdp);
void profile_final_call(Register mdp);
void profile_virtual_call(Register receiver, Register mdp,
@@ -1129,8 +2415,8 @@ diff --git a/src/cpu/x86/vm/interpreter_
+ address entry_point = MethodHandle::generate_method_handle_interpreter_entry(_masm, wrong_method_type);
+
+ __ bind(wrong_method_type);
-+ __ pushl(rax_mtype); // missed mtype (required)
-+ __ pushl(rcx_recv); // bad mh (actual)
++ __ push(rax_mtype); // missed mtype (required)
++ __ push(rcx_recv); // bad mh (actual)
+ __ movptr(rdx, ExternalAddress((address) &Interpreter::_throw_WrongMethodType_entry));
+ __ call(rdx);
+
@@ -1143,25 +2429,31 @@ diff --git a/src/cpu/x86/vm/interpreter_
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 @@
+@@ -250,6 +250,19 @@
+ // the call_VM checks for exception, so we should never return here.
__ should_not_reach_here();
- return entry_point;
++ 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");
++ if (!MethodHandles) {
++ return generate_abstract_entry();
++ }
++
++ address entry_point = __ pc();
++ __ unimplemented();
+ return entry_point;
}
-
-diff --git a/src/cpu/x86/vm/methodHandles_x86_32.cpp b/src/cpu/x86/vm/methodHandles_x86_32.cpp
+diff --git a/src/cpu/x86/vm/methodHandles_x86.cpp b/src/cpu/x86/vm/methodHandles_x86.cpp
new file mode 100644
--- /dev/null
-+++ b/src/cpu/x86/vm/methodHandles_x86_32.cpp
-@@ -0,0 +1,453 @@
++++ b/src/cpu/x86/vm/methodHandles_x86.cpp
+@@ -0,0 +1,441 @@
+/*
+ * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -1187,7 +2479,7 @@ new file mode 100644
+ */
+
+#include "incls/_precompiled.incl"
-+#include "incls/_methodHandles_x86_32.cpp.incl"
++#include "incls/_methodHandles_x86.cpp.incl"
+
+#define __ _masm->
+
@@ -1239,10 +2531,12 @@ new file mode 100644
+ address entry_point = __ pc();
+
+ // fetch the MethodType from the method handle into rax (the 'check' register)
-+ Register tem = rbx_method;
-+ for (int* pchase = methodOopDesc::method_type_pointer_chase(); (*pchase) != -1; pchase++) {
-+ __ movptr(rax_mtype, Address(tem, *pchase));
-+ tem = rax_mtype;
++ {
++ Register tem = rbx_method;
++ for (int* pchase = methodOopDesc::method_type_pointer_chase(); (*pchase) != -1; pchase++) {
++ __ movptr(rax_mtype, Address(tem, *pchase));
++ tem = rax_mtype; // in case there is another indirection
++ }
+ }
+ Register rbx_temp = rbx_method; // done with incoming methodOop
+
@@ -1253,7 +2547,7 @@ new file mode 100644
+ oopDesc::address_padding_in_bytes()));
+ __ movl(rdx_temp, Address(rdx_temp,
+ __ delayed_value(java_dyn_MethodType::Form::vmdata_offset_in_bytes, rbx_temp)));
-+ __ movptr(rcx_recv, argument_address(rdx_temp));
++ __ movptr(rcx_recv, __ argument_address(rdx_temp));
+
+ __ check_method_handle_type(rax_mtype, rcx_recv, rdx_temp, wrong_method_type);
+ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
@@ -1288,12 +2582,21 @@ new file mode 100644
+
+ guarantee(java_dyn_MethodHandle::vmdata_offset_in_bytes() != 0, "must have offsets");
+
++ // some handy addresses
++ Address rbx_method_fie( rbx, methodOopDesc::from_interpreted_offset() );
++ Address rcx_mh_vmref( rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes() );
++ Address rcx_mh_vmargslot( rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes() );
++ Address rcx_mh_vmindex( rcx_recv, java_dyn_MethodHandle::vmdata_index_offset_in_bytes() );
++ Address rcx_method_target( rcx_recv, java_dyn_MethodHandle::target_offset_in_bytes() ); //AMH
++
+ if (have_entry(ek)) {
+ __ nop(); // empty stubs make SG sick
+ return;
+ }
+
+ address interp_entry = __ pc();
++ if (UseCompressedOops) __ unimplemented("UseCompressedOops");
++
+ switch ((int) ek) {
+ case _check_mtype:
+ {
@@ -1318,27 +2621,27 @@ new file mode 100644
+ case _invokespecial_mh:
+ {
+ Register rbx_method = rbx_index;
-+ __ movptr(rbx_method, Address(rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes()));
++ __ movptr(rbx_method, rcx_mh_vmref);
+ __ verify_oop(rbx_method);
+ // same as TemplateTable::invokestatic or invokespecial,
+ // minus the CP setup and profiling:
+ if (ek == _invokespecial_mh) {
+ // Must load & check the first argument before entering the target method.
-+ __ movl(rax_argslot, Address(rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes()));
-+ __ movptr(rcx_recv, argument_address(rax_argslot));
++ __ movl(rax_argslot, rcx_mh_vmargslot);
++ __ movptr(rcx_recv, __ argument_address(rax_argslot));
+ __ null_check(rcx_recv);
+ __ verify_oop(rcx_recv);
+ }
-+ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
++ __ jmp(rbx_method_fie);
+ }
+ break;
+
+ case _invokebound_mh:
+ {
+ Register rbx_temp = rbx_index;
-+ __ movl(rax_argslot, Address(rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes()));
++ __ movl(rax_argslot, rcx_mh_vmargslot);
+ // get address of inserted argument (-1 means after sp is decremented)
-+ __ leal(rax_argslot, argument_address(rax_argslot, -1));
++ __ leal(rax_argslot, __ argument_address(rax_argslot, -1));
+#ifdef ASSERT
+ {
+ Label L_ok, L_bad;
@@ -1369,16 +2672,17 @@ new file mode 100644
+ }
+
+ Register rbx_method = rbx_temp;
-+ __ movptr(rbx_method, Address(rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes()));
++ __ movptr(rbx_method, rcx_mh_vmref);
+ __ verify_oop(rbx_method);
+
+ // replace MH with bound receiver (or first static argument):
-+ __ movptr(rcx_recv, Address(rcx_recv, java_dyn_MethodHandle::receiver_offset_in_bytes()));
++ Address rcx_method_receiver(rcx_recv, java_dyn_MethodHandle::receiver_offset_in_bytes());
++ __ movptr(rcx_recv, rcx_method_receiver);
+ __ movptr(Address(rax_argslot, 0), rcx_recv);
+ if (TaggedStackInterpreter) {
+ __ movptr(Address(rax_argslot, wordSize), frame::TagReference);
+ }
-+ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
++ __ jmp(rbx_method_fie);
+ }
+ break;
+
@@ -1389,9 +2693,9 @@ new file mode 100644
+
+ // pick out the vtable index and receiver offset from the MH,
+ // and then we can discard it:
-+ __ movl(rax_argslot, Address(rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes()));
-+ __ movl(rbx_index, Address(rcx_recv, java_dyn_MethodHandle::vmdata_index_offset_in_bytes()));
-+ __ movptr(rcx_recv, argument_address(rax_argslot));
++ __ movl(rax_argslot, rcx_mh_vmargslot);
++ __ movl(rbx_index, rcx_mh_vmindex);
++ __ movptr(rcx_recv, __ argument_address(rax_argslot));
+ __ null_check(rcx_recv, oopDesc::klass_offset_in_bytes());
+
+ // get receiver klass
@@ -1403,10 +2707,10 @@ new file mode 100644
+ const int base = instanceKlass::vtable_start_offset() * wordSize;
+ assert(vtableEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
+ Register rbx_method = rbx_index;
-+ __ movl(rbx_method, Address(rax_klass, rbx_index, Address::times_wordSize, base + vtableEntry::method_offset_in_bytes()));
++ __ movl(rbx_method, Address(rax_klass, rbx_index, Address::times_ptr, base + vtableEntry::method_offset_in_bytes()));
+
+ __ verify_oop(rbx_method);
-+ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
++ __ jmp(rbx_method_fie);
+ }
+ break;
+
@@ -1418,10 +2722,10 @@ new file mode 100644
+ // pick out the interface and itable index from the MH.
+ Register rdx_intf = rdx_temp;
+
-+ __ movptr(rdx_intf, Address(rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes()));
-+ __ movl(rax_argslot, Address(rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes()));
-+ __ movl(rbx_index, Address(rcx_recv, java_dyn_MethodHandle::vmdata_index_offset_in_bytes()));
-+ __ movptr(rcx_recv, argument_address(rax_argslot));
++ __ movptr(rdx_intf, rcx_mh_vmref);
++ __ movl(rax_argslot, rcx_mh_vmargslot);
++ __ movl(rbx_index, rcx_mh_vmindex);
++ __ movptr(rcx_recv, __ argument_address(rax_argslot));
+ __ null_check(rcx_recv, oopDesc::klass_offset_in_bytes());
+
+ // get receiver klass
@@ -1429,8 +2733,6 @@ new file mode 100644
+ __ movl(rax_klass, Address(rcx_recv, oopDesc::klass_offset_in_bytes()));
+ __ verify_oop(rax_klass);
+
-+ // Free up another temp.
-+ __ pushl(rcx_recv);
+ Register rcx_temp = rcx_recv;
+ Register rbx_method = rbx_index;
+
@@ -1442,13 +2744,11 @@ new file mode 100644
+ rcx_temp,
+ no_such_interface);
+
-+ __ popl(rcx_recv); // restore saved receiver
+ __ verify_oop(rbx_method);
-+ __ jmp(Address(rbx_method, methodOopDesc::from_interpreted_offset()));
++ __ jmp(rbx_method_fie);
+ __ hlt();
+
+ __ bind(no_such_interface);
-+ __ popl(rcx_recv); // restore saved receiver
+ // Throw an exception.
+ // For historical reasons, it will be IncompatibleClassChangeError.
+ __ should_not_reach_here(); // %%% FIXME NYI
@@ -1463,15 +2763,15 @@ new file mode 100644
+ if (ak == _adapt_drop_final) {
+ // 'argslot' is number of slots to drop
+ // this is also the rightmost (shallowest) kept argument slot
-+ __ movl(rax_argslot, Address(rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes()));
-+ Address arg = argument_address(rax_argslot);
-+ __ popl(rdx_temp); // return PC
-+ __ leal(rsp, arg); // pop some arguments
-+ __ pushl(rdx_temp); // restore PC
++ __ movl(rax_argslot, rcx_mh_vmargslot);
++ Address arg = __ argument_address(rax_argslot);
++ __ pop(rdx_temp); // return PC
++ __ lea(rsp, arg); // pop some arguments
++ __ push(rdx_temp); // restore PC
+ }
+
+ // immediately jump to the next MH layer:
-+ __ movptr(rcx_recv, Address(rcx_recv, java_dyn_MethodHandle::receiver_offset_in_bytes()));
++ __ movptr(rcx_recv, rcx_method_target);
+ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+ // This is OK when all parameter types widen.
+ // It is also OK when a return type narrows.
@@ -1487,13 +2787,13 @@ new file mode 100644
+ AdapterKind ak = AdapterKind(ek - _adapter_mh_first);
+ // check an argument, or perform a simple in-place conversion,
+ // before jumping to the next layer of MH:
-+ __ movl(rax_argslot, Address(rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes()));
++ __ movl(rax_argslot, rcx_mh_vmargslot);
+ if (ak == _adapt_extend_zero || ak == _adapt_extend_sign)
-+ __ movl(rbx_index, Address(rcx_recv, java_dyn_MethodHandle::vmdata_index_offset_in_bytes()));
-+ Address arg = argument_address(rax_argslot);
++ __ movl(rbx_index, rcx_mh_vmindex);
++ Address arg = __ argument_address(rax_argslot);
+
+ // get the new MH:
-+ __ movptr(rcx_recv, Address(rcx_recv, java_dyn_MethodHandle::receiver_offset_in_bytes()));
++ __ movptr(rcx_recv, rcx_method_target);
+ // (now we are done with the old MH)
+
+ if (ak == _adapt_test_boolean) {
@@ -1506,7 +2806,7 @@ new file mode 100644
+
+ } else {
+ // original 32-bit vmdata word must be of this form:
-+ // | argumentNumber:16 | conversion:8 | lowBitCount:8 |
++ // | argumentNumber:16 | lowBitCount:8 | conversion:8 |
+ __ xchgl(rcx, rbx_index); // free rcx for shifts
+ __ shrl(rcx, 8); // shift in 2nd LSB
+ __ negl(rcx); // left shift by 32-lowBitCount
@@ -1536,14 +2836,14 @@ new file mode 100644
+
+ // check an argument, or perform a simple in-place conversion,
+ // before jumping to the next layer of MH:
-+ __ movl(rax_argslot, Address(rcx_recv, java_dyn_MethodHandle::vmdata_argslot_offset_in_bytes()));
-+ Address arg = argument_address(rax_argslot);
++ __ movl(rax_argslot, rcx_mh_vmargslot);
++ Address arg = __ argument_address(rax_argslot);
+
+ // What class are we casting to?
-+ __ movptr(rbx_klass, Address(rcx_recv, java_dyn_MethodHandle::vmref_offset_in_bytes()));
++ __ movptr(rbx_klass, rcx_mh_vmref);
+
+ // get the new MH:
-+ __ movptr(rcx_recv, Address(rcx_recv, java_dyn_MethodHandle::receiver_offset_in_bytes()));
++ __ movptr(rcx_recv, rcx_method_target);
+ // (now we are done with the old MH)
+
+ Label done;
@@ -1562,12 +2862,12 @@ new file mode 100644
+ // Call the wrong_method_type stub, passing the failing argument type in rax.
+ Register rax_mtype = rax_argslot;
+#if 0
-+ __ pushl(rbx_klass); // missed klass (required)
-+ __ pushl(rdx_temp); // bad object (actual)
++ __ push(rbx_klass); // missed klass (required)
++ __ push(rdx_temp); // bad object (actual)
+ __ jump(ExternalAddress(Interpreter::_throw_WrongMethodType_entry));
+#else
-+ __ movl(rax_mtype, rbx_klass); // missed klass (required)
-+ __ movl(rcx_recv, rdx_temp); // bad object (actual)
++ __ mov(rax_mtype, rbx_klass); // missed klass (required)
++ __ mov(rcx_recv, rdx_temp); // bad object (actual)
+ __ movptr(rdx_temp, ExternalAddress((address) &_entries[_wrong_method_type]));
+ __ jmp(Address(rdx_temp, MethodEntry::from_interpreted_entry_offset_in_bytes()));
+#endif
@@ -1595,26 +2895,6 @@ new file mode 100644
+
+ init_entry(ek, MethodEntry::finish_compiled_entry(_masm, me_cookie));
+}
-+
-+Address MethodHandle::argument_address(RegisterConstant arg_slot,
-+ int extra_slot_offset) {
-+ // cf. TemplateTable::prepare_invoke(), if (load_receiver).
-+ int stackElementSize = Interpreter::stackElementWords() * wordSize;
-+ int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
-+ int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1);
-+ assert(offset1 - offset == stackElementSize, "correct arithmetic");
-+ Register scale_reg = noreg;
-+ Address::ScaleFactor scale_factor = Address::no_scale;
-+ if (arg_slot.is_constant()) {
-+ offset += arg_slot.as_constant() * stackElementSize;
-+ } else {
-+ scale_reg = arg_slot.as_register();
-+ scale_factor = Address::times(stackElementSize);
-+ }
-+ offset += wordSize; // return PC is on stack
-+ return Address(rsp, scale_reg, scale_factor, offset);
-+}
-+
diff --git a/src/cpu/x86/vm/stubGenerator_x86_32.cpp b/src/cpu/x86/vm/stubGenerator_x86_32.cpp
--- a/src/cpu/x86/vm/stubGenerator_x86_32.cpp
+++ b/src/cpu/x86/vm/stubGenerator_x86_32.cpp
@@ -1661,14 +2941,14 @@ diff --git a/src/cpu/x86/vm/templateInte
+address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
+ address entry = __ pc();
+
-+ __ popl(rcx); // address raising the error (for debug)
++ __ pop(rcx); // address raising the error (for debug)
+#ifdef ASSERT
+ __ lea(rax, ExternalAddress((address) &last_WrongMethodType_caller));
+ __ movptr(Address(rax, 0), rcx);
+#endif //ASSERT
+
-+ __ popl(rbx); // actual failing object is at TOS
-+ __ popl(rax); // required type is at TOS+4
++ __ pop(rbx); // actual failing object is at TOS
++ __ pop(rax); // required type is at TOS+4
+
+ __ verify_oop(rbx);
+ __ verify_oop(rax);
@@ -1812,10 +3092,10 @@ diff --git a/src/cpu/x86/vm/templateInte
+ Label L_ok, L_ok_pops;
+ __ testl(rax, rax);
+ __ jcc(Assembler::zero, L_ok);
-+ __ pushl(rax); // save the object to check
++ __ push(rax); // save the object to check
+ __ movl(rax, Address(rax, oopDesc::klass_offset_in_bytes()));
-+ __ pushl(rbx); // save CP cache reference
-+ __ pushl(rcx); // save CP cache reference
++ __ push(rbx); // save CP cache reference
++ __ push(rcx); // save CP cache reference
+ __ movl(rbx, Address(rbx, rcx,
+ Address::times_4, constantPoolCacheOopDesc::base_offset() +
+ ConstantPoolCacheEntry::f1_offset()));
@@ -1823,15 +3103,15 @@ diff --git a/src/cpu/x86/vm/templateInte
+ __ movl(rbx, Address(rbx, __ delayed_value(java_dyn_MethodType::rtype_offset_in_bytes, rcx)));
+ __ movl(rbx, Address(rbx, __ delayed_value(java_lang_Class::klass_offset_in_bytes, rcx)));
+ __ check_klass_subtype(rax, rbx, rcx, L_ok_pops);
-+ __ addl(rsp, 2*wordSize); // toss rcx, keep rbx as failed klass
-+ __ popl(rax);
++ __ addptr(rsp, 2*wordSize); // toss rcx, keep rbx as failed klass
++ __ pop(rax);
+ __ jmp(L_fail);
+
+ __ bind(L_ok_pops);
+ // restore pushed temp regs:
-+ __ popl(rcx);
-+ __ popl(rbx);
-+ __ popl(rax);
++ __ pop(rcx);
++ __ pop(rbx);
++ __ pop(rax);
+ __ bind(L_ok);
+ }
__ movl(rbx, Address(rbx, rcx,
@@ -1849,8 +3129,8 @@ diff --git a/src/cpu/x86/vm/templateInte
+
+ if (unbox) {
+ __ bind(L_fail);
-+ __ pushl(rbx); // missed klass (required)
-+ __ pushl(rax); // bad object (actual)
++ __ push(rbx); // missed klass (required)
++ __ push(rax); // bad object (actual)
+ __ movptr(rdx, ExternalAddress((address) &Interpreter::_throw_WrongMethodType_entry));
+ __ call(rdx);
+ }
@@ -1883,16 +3163,26 @@ diff --git a/src/cpu/x86/vm/templateInte
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
-@@ -98,6 +98,26 @@
+@@ -98,6 +98,36 @@
return entry;
}
-+// Arguments are: required type at TOS+8, failing object (or NULL) at TOS
++#ifdef ASSERT
++address last_WrongMethodType_caller;
++#endif //ASSERT
++
++// Arguments are: required type in rarg1, failing object (or NULL) in rarg2
+address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
+ address entry = __ pc();
+
-+ __ popq(c_rarg2); // failing object is at TOS
-+ __ popq(c_rarg1); // required type is at TOS+8
++ __ pop(rax); // address raising the error (for debug)
++#ifdef ASSERT
++ __ lea(c_rarg1, ExternalAddress((address) &last_WrongMethodType_caller));
++ __ movptr(Address(c_rarg1, 0), rax);
++#endif //ASSERT
++
++ __ pop(c_rarg2); // failing object is at TOS
++ __ pop(c_rarg1); // required type is at TOS+8
+
+ // expression stack must be empty before entering the VM if an
+ // exception happened
@@ -1910,14 +3200,33 @@ diff --git a/src/cpu/x86/vm/templateInte
address TemplateInterpreterGenerator::generate_exception_handler_common(
const char* name, const char* message, bool pass_oop) {
assert(!pass_oop || message == NULL, "either oop or message but not both");
-@@ -159,7 +179,13 @@
+@@ -144,7 +174,17 @@
+
+
+ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
+- int step) {
++ int step,
++ bool unbox) {
++ TosState incoming_state = state;
++ if (InvokeDynamic) {
++ if (unbox) {
++ incoming_state = atos;
++ }
++ Unimplemented();
++ } else {
++ assert(!unbox, "old behavior");
++ }
+
+ // amd64 doesn't need to do anything special about compiled returns
+ // to the interpreter so the code that exists on x86 to place a sentinel
+@@ -159,7 +199,13 @@
__ restore_bcp();
__ restore_locals();
- __ get_cache_and_index_at_bcp(rbx, rcx, 1);
+ Label L_got_cache, L_giant_index;
+ if (InvokeDynamic) {
-+ __ cmpb(r13, Bytecodes::_invokedynamic);
++ __ cmpb(Address(r13, 0), Bytecodes::_invokedynamic);
+ __ jcc(Assembler::equal, L_giant_index);
+ }
+ __ get_cache_and_index_at_bcp(rbx, rcx, 1, false);
@@ -1925,7 +3234,7 @@ diff --git a/src/cpu/x86/vm/templateInte
__ movl(rbx, Address(rbx, rcx,
Address::times_8,
in_bytes(constantPoolCacheOopDesc::base_offset()) +
-@@ -168,7 +194,18 @@
+@@ -168,6 +214,12 @@
if (TaggedStackInterpreter) __ shll(rbx, 1); // 2 slots per parameter.
__ leaq(rsp, Address(rsp, rbx, Address::times_8));
__ dispatch_next(state, step);
@@ -1936,15 +3245,9 @@ diff --git a/src/cpu/x86/vm/templateInte
+ }
+
return entry;
-+}
-+
-+
-+address TemplateInterpreterGenerator::generate_return_unbox_entry_for(TosState state, int step) {
-+ __ unimplemented();
}
-
-@@ -1243,6 +1280,7 @@
+@@ -1243,6 +1295,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;
@@ -1952,7 +3255,7 @@ diff --git a/src/cpu/x86/vm/templateInte
case Interpreter::java_lang_math_sin : break;
case Interpreter::java_lang_math_cos : break;
case Interpreter::java_lang_math_tan : break;
-@@ -1272,7 +1310,8 @@
+@@ -1272,7 +1325,8 @@
-(frame::interpreter_frame_initial_sp_offset) + entry_size;
const int stub_code = frame::entry_frame_after_call_words;
@@ -2004,7 +3307,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
+ __ get_cache_and_index_at_bcp(Rcache, index, 1, is_invokedynamic);
+ if (is_invokedynamic) {
+ // we are resolved if the f1 field contains a non-null CallSite object
-+ __ cmpl(Address(Rcache, index, Address::times_4, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::f1_offset()), NULL);
++ __ cmpptr(Address(Rcache, index, Address::times_ptr, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::f1_offset()), NULL);
+ __ jcc(Assembler::notEqual, resolved);
+ } else {
+ __ movl(temp, Address(Rcache, index, Address::times_4, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::indices_offset()));
@@ -2037,12 +3340,11 @@ diff --git a/src/cpu/x86/vm/templateTabl
-void TemplateTable::prepare_invoke(Register method, Register index, int byte_no, Bytecodes::Code code) {
-- // determine flags
+void TemplateTable::prepare_invoke(Register method, Register index, int byte_no) {
+ bool neg_byte_no = (byte_no < 0);
+ if (neg_byte_no) byte_no = -byte_no;
+
-+ // determine flagsu
+ // determine flags
+ Bytecodes::Code code = bytecode();
const bool is_invokeinterface = code == Bytecodes::_invokeinterface;
+ const bool is_invokedynamic = code == Bytecodes::_invokedynamic;
@@ -2059,33 +3361,43 @@ diff --git a/src/cpu/x86/vm/templateTabl
// save 'interpreter return address'
__ save_bcp();
-@@ -2784,8 +2800,12 @@
+@@ -2784,8 +2800,13 @@
__ movl(recv, flags);
__ andl(recv, 0xFF);
// recv count is 0 based?
- __ movl(recv, Address(rsp, recv, Interpreter::stackElementScale(), -Interpreter::expr_offset_in_bytes(1)));
- __ verify_oop(recv);
++ Address recv_addr(rsp, recv, Interpreter::stackElementScale(), -Interpreter::expr_offset_in_bytes(1));
+ if (is_invokedynamic) {
-+ __ leal(recv, Address(rsp, recv, Interpreter::stackElementScale(), -Interpreter::expr_offset_in_bytes(1)));
++ __ lea(recv, recv_addr);
+ } else {
-+ __ movl(recv, Address(rsp, recv, Interpreter::stackElementScale(), -Interpreter::expr_offset_in_bytes(1)));
++ __ movptr(recv, recv_addr);
+ __ verify_oop(recv);
+ }
}
// do null check if needed
-@@ -2803,7 +2823,9 @@
+@@ -2802,11 +2823,14 @@
+ // Make sure we don't need to mask flags for tosBits after the above shift
ConstantPoolCacheEntry::verify_tosBits();
// load return address
- { const int table =
+- { const int table =
- is_invokeinterface
+- ? (int)Interpreter::return_5_addrs_by_index_table()
+- : (int)Interpreter::return_3_addrs_by_index_table();
+- __ movl(flags, Address(noreg, flags, Address::times_4, table));
++ {
++ address table =
+ (is_invdyn_bootstrap)
-+ ? (int)Interpreter::return_5_unbox_addrs_by_index_table()
++ ? (address)Interpreter::return_5_unbox_addrs_by_index_table()
+ : (is_invokeinterface || is_invokedynamic)
- ? (int)Interpreter::return_5_addrs_by_index_table()
- : (int)Interpreter::return_3_addrs_by_index_table();
- __ movl(flags, Address(noreg, flags, Address::times_4, table));
-@@ -2868,7 +2890,7 @@
++ ? (address)Interpreter::return_5_addrs_by_index_table()
++ : (address)Interpreter::return_3_addrs_by_index_table();
++ __ movl(flags, Address(noreg, flags, Address::times_4, (int)table));
+ }
+
+ // push return address
+@@ -2868,7 +2892,7 @@
void TemplateTable::invokevirtual(int byte_no) {
transition(vtos, vtos);
@@ -2094,7 +3406,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
// rbx,: index
// rcx: receiver
-@@ -2880,7 +2902,7 @@
+@@ -2880,7 +2904,7 @@
void TemplateTable::invokespecial(int byte_no) {
transition(vtos, vtos);
@@ -2103,7 +3415,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
// do the call
__ verify_oop(rbx);
__ profile_call(rax);
-@@ -2890,7 +2912,7 @@
+@@ -2890,7 +2914,7 @@
void TemplateTable::invokestatic(int byte_no) {
transition(vtos, vtos);
@@ -2112,7 +3424,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
// do the call
__ verify_oop(rbx);
__ profile_call(rax);
-@@ -2906,7 +2928,7 @@
+@@ -2906,7 +2930,7 @@
void TemplateTable::invokeinterface(int byte_no) {
transition(vtos, vtos);
@@ -2121,7 +3433,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
// rax,: Interface
// rbx,: index
-@@ -2932,6 +2954,57 @@
+@@ -2932,6 +2956,57 @@
// profile this call
__ profile_virtual_call(rdx, rsi, rdi);
@@ -2141,7 +3453,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
+ // 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);
++ __ testptr(rbx, rbx);
+ __ jcc(Assembler::zero, no_such_method);
+
+ // do the call
@@ -2156,7 +3468,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
+
+ __ bind(no_such_method);
+ // throw exception
-+ __ popl(rbx); // pop return address (pushed by prepare_invoke)
++ __ pop(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));
@@ -2165,7 +3477,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
+
+ __ bind(no_such_interface);
+ // throw exception
-+ __ popl(rbx); // pop return address (pushed by prepare_invoke)
++ __ pop(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,
@@ -2179,7 +3491,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
__ movl(rdi, rdx); // Save klassOop in rdi
-@@ -3005,6 +3078,79 @@
+@@ -3005,6 +3080,79 @@
// rcx: receiver
// rbx,: methodOop
__ jump_from_interpreted(rbx, rdx);
@@ -2218,8 +3530,8 @@ diff --git a/src/cpu/x86/vm/templateTabl
+ }
+
+ Label handle_unlinked_site;
-+ __ movl(rcx, Address(rax, __ delayed_value(java_dyn_impl_DynCallSite::target_offset_in_bytes, rcx)));
-+ __ testl(rcx, rcx);
++ __ movptr(rcx, Address(rax, __ delayed_value(java_dyn_impl_DynCallSite::target_offset_in_bytes, rcx)));
++ __ testptr(rcx, rcx);
+ __ jcc(Assembler::zero, handle_unlinked_site);
+
+ __ prepare_to_jump_from_interpreted();
@@ -2227,7 +3539,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
+
+ // Initial calls come here...
+ __ bind(handle_unlinked_site);
-+ __ popl(rcx); // remove return address pushed by prepare_invoke
++ __ pop(rcx); // remove return address pushed by prepare_invoke
+
+ address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::bootstrap_invokedynamic);
+ // squish stacked arguments together on stack, preceded by call site
@@ -2248,13 +3560,13 @@ diff --git a/src/cpu/x86/vm/templateTabl
+ __ prepare_to_jump_from_interpreted();
+
+ // let's play adapter
-+ __ popl(rbx); // return value
-+ __ pushl(rdi); // boot MH
-+ __ pushl(rax); // call site
-+ __ movl(rcx, Address(rcx, 0));
-+ __ pushl(rcx); // arglist
-+ __ pushl(rbx); // return value
-+ __ movl(rcx, rdi);
++ __ pop(rbx); // return value
++ __ push(rdi); // boot MH
++ __ push(rax); // call site
++ __ movptr(rcx, Address(rcx, 0));
++ __ push(rcx); // arglist
++ __ push(rbx); // return value
++ __ mov(rcx, rdi);
+ __ jump_to_method_handle_entry(rcx, rdx);
}
@@ -2275,7 +3587,62 @@ diff --git a/src/cpu/x86/vm/templateTabl
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 @@
+@@ -144,12 +144,12 @@
+ scratch, r13, 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));
+@@ -1989,6 +1989,7 @@
+ Register Rcache,
+ Register index) {
+ assert(byte_no == 1 || byte_no == 2, "byte_no out of range");
++ bool is_invokedynamic = (bytecode() == Bytecodes::_invokedynamic);
+
+ const Register temp = rbx;
+ assert_different_registers(Rcache, index, temp);
+@@ -1996,19 +1997,29 @@
+ const int shift_count = (1 + byte_no) * BitsPerByte;
+ Label resolved;
+ __ get_cache_and_index_at_bcp(Rcache, index, 1);
+- __ movl(temp, Address(Rcache,
+- index, Address::times_8,
+- constantPoolCacheOopDesc::base_offset() +
+- ConstantPoolCacheEntry::indices_offset()));
+- __ shrl(temp, shift_count);
+- // have we resolved this bytecode?
+- __ andl(temp, 0xFF);
+- __ cmpl(temp, (int) bytecode());
+- __ jcc(Assembler::equal, resolved);
++ if (is_invokedynamic) {
++ // we are resolved if the f1 field contains a non-null CallSite object
++ __ cmpptr(Address(Rcache,
++ index, Address::times_ptr,
++ constantPoolCacheOopDesc::base_offset() +
++ ConstantPoolCacheEntry::f1_offset()), NULL);
++ __ jcc(Assembler::notEqual, resolved);
++ } else {
++ __ movl(temp, Address(Rcache,
++ index, Address::times_ptr,
++ constantPoolCacheOopDesc::base_offset() +
++ ConstantPoolCacheEntry::indices_offset()));
++ __ shrl(temp, shift_count);
++ // have we resolved this bytecode?
++ __ andl(temp, 0xFF);
++ __ cmpl(temp, (int) bytecode());
++ __ jcc(Assembler::equal, resolved);
++ }
// resolve first time through
address entry;
@@ -2285,19 +3652,91 @@ diff --git a/src/cpu/x86/vm/templateTabl
case Bytecodes::_getstatic:
case Bytecodes::_putstatic:
case Bytecodes::_getfield:
-@@ -2764,9 +2765,9 @@
+@@ -2021,6 +2032,9 @@
+ case Bytecodes::_invokeinterface:
+ entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke);
+ break;
++ case Bytecodes::_invokedynamic:
++ entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic);
++ break;
+ default:
+ ShouldNotReachHere();
+ break;
+@@ -2029,7 +2043,7 @@
+ __ call_VM(noreg, entry, temp);
+
+ // Update registers with resolved info
+- __ get_cache_and_index_at_bcp(Rcache, index, 1);
++ __ get_cache_and_index_at_bcp(Rcache, index, 1, is_invokedynamic);
+ __ bind(resolved);
+ }
+
+@@ -2764,10 +2778,14 @@
void TemplateTable::prepare_invoke(Register method,
Register index,
- int byte_no,
- Bytecodes::Code code) {
+ int byte_no) {
++ bool neg_byte_no = (byte_no < 0);
++ if (neg_byte_no) byte_no = -byte_no;
++
// determine flags
-+ Bytecodes::Code code = Bytecodes::java_code(bytecode());
++ Bytecodes::Code code = bytecode();
const bool is_invokeinterface = code == Bytecodes::_invokeinterface;
++ const bool is_invokedynamic = code == Bytecodes::_invokedynamic;
const bool is_invokevirtual = code == Bytecodes::_invokevirtual;
const bool is_invokespecial = code == Bytecodes::_invokespecial;
-@@ -2877,7 +2878,7 @@
+ const bool load_receiver = code != Bytecodes::_invokestatic;
+@@ -2777,6 +2795,9 @@
+ const Register recv = rcx;
+ const Register flags = rdx;
+ assert_different_registers(method, index, recv, flags);
++
++ assert(!neg_byte_no || is_invokedynamic, "byte_no<0 hack only for invdyn");
++ const bool is_invdyn_bootstrap = neg_byte_no;
+
+ // save 'interpreter return address'
+ __ save_bcp();
+@@ -2788,9 +2809,14 @@
+ __ movl(recv, flags);
+ __ andl(recv, 0xFF);
+ if (TaggedStackInterpreter) __ shll(recv, 1); // index*2
+- __ movq(recv, Address(rsp, recv, Address::times_8,
+- -Interpreter::expr_offset_in_bytes(1)));
+- __ verify_oop(recv);
++ Address recv_addr(rsp, recv, Address::times_8,
++ -Interpreter::expr_offset_in_bytes(1));
++ if (is_invokedynamic) {
++ __ lea(recv, recv_addr);
++ } else {
++ __ movptr(recv, recv_addr);
++ __ verify_oop(recv);
++ }
+ }
+
+ // do null check if needed
+@@ -2808,10 +2834,15 @@
+ ConstantPoolCacheEntry::verify_tosBits();
+ // load return address
+ {
+- ExternalAddress return_5((address)Interpreter::return_5_addrs_by_index_table());
+- ExternalAddress return_3((address)Interpreter::return_3_addrs_by_index_table());
+- __ lea(rscratch1, (is_invokeinterface ? return_5 : return_3));
+- __ movq(flags, Address(rscratch1, flags, Address::times_8));
++ address table_addr =
++ (is_invdyn_bootstrap)
++ ? (address)Interpreter::return_5_unbox_addrs_by_index_table()
++ : (is_invokeinterface || is_invokedynamic)
++ ? (address)Interpreter::return_5_addrs_by_index_table()
++ : (address)Interpreter::return_3_addrs_by_index_table();
++ ExternalAddress table(table_addr);
++ __ lea(rscratch1, table);
++ __ movptr(flags, Address(rscratch1, flags, Address::times_ptr));
+ }
+
+ // push return address
+@@ -2877,7 +2908,7 @@
void TemplateTable::invokevirtual(int byte_no) {
transition(vtos, vtos);
@@ -2306,7 +3745,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
// rbx: index
// rcx: receiver
-@@ -2889,7 +2890,7 @@
+@@ -2889,7 +2920,7 @@
void TemplateTable::invokespecial(int byte_no) {
transition(vtos, vtos);
@@ -2315,7 +3754,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
// do the call
__ verify_oop(rbx);
__ profile_call(rax);
-@@ -2899,7 +2900,7 @@
+@@ -2899,7 +2930,7 @@
void TemplateTable::invokestatic(int byte_no) {
transition(vtos, vtos);
@@ -2324,7 +3763,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
// do the call
__ verify_oop(rbx);
__ profile_call(rax);
-@@ -2913,7 +2914,7 @@
+@@ -2913,7 +2944,7 @@
void TemplateTable::invokeinterface(int byte_no) {
transition(vtos, vtos);
@@ -2333,6 +3772,144 @@ diff --git a/src/cpu/x86/vm/templateTabl
// rax: Interface
// rbx: index
+@@ -2939,6 +2970,57 @@
+
+ // profile this call
+ __ profile_virtual_call(rdx, r13, r14);
++
++ if (MethodHandles) { // %%% let's use this refactored code always
++ Label no_such_interface, no_such_method;
++
++ __ lookup_interface_method(// inputs: rec. class, interface, itable index
++ rdx, rax, rbx,
++ // outputs: method, scan temp. reg
++ rbx, r13,
++ no_such_interface);
++
++ // 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.
++ __ testptr(rbx, rbx);
++ __ jcc(Assembler::zero, no_such_method);
++
++ // do the call
++ // rcx: receiver
++ // rbx,: methodOop
++ __ jump_from_interpreted(rbx, rdx);
++ __ should_not_reach_here();
++
++ // exception handling code follows...
++ // note: must restore interpreter registers to canonical
++ // state for exception handling to work correctly!
++
++ __ bind(no_such_method);
++ // throw exception
++ __ pop(rbx); // pop return address (pushed by prepare_invoke)
++ __ restore_bcp(); // r13 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
++ __ pop(rbx); // pop return address (pushed by prepare_invoke)
++ __ restore_bcp(); // r13 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_IncompatibleClassChangeError));
++ // the call_VM checks for exception, so we should never return here.
++ __ should_not_reach_here();
++ return;
++ }
++
++ // %%% remove this old code, in favor of the previous block:
+
+ __ movq(r14, rdx); // Save klassOop in r14
+
+@@ -3029,6 +3111,79 @@
+ // rcx: receiver
+ // rbx: methodOop
+ __ jump_from_interpreted(rbx, rdx);
++}
++
++void TemplateTable::invokedynamic(int byte_no) {
++ transition(vtos, vtos);
++
++ if (!InvokeDynamic) {
++ // We do not encounter this bytecode if !InvokeDynamic.
++ // See Rewriter::rewrite_invokedynamic.
++ __ stop("invokedynamic not enabled");
++ return;
++ }
++
++ prepare_invoke(rax, rbx, byte_no);
++
++ // rax: CallSite object (f1)
++ // rbx: unused (f2)
++ // rcx: receiver address
++ // rdx: flags (unused)
++
++ if (ProfileInterpreter) {
++ Label L;
++ __ movl(rdx, Address(rcx, 0));
++ __ testl(rdx, rdx);
++ __ jcc(Assembler::zero, L);
++
++ // Get receiver klass into rdx
++ __ movl(rdx, Address(rdx, oopDesc::klass_offset_in_bytes()));
++ __ verify_oop(rdx);
++ __ bind(L);
++
++ // profile this call
++ __ profile_virtual_call(rdx, r13, r14, true);
++ }
++
++ Label handle_unlinked_site;
++ __ movptr(rcx, Address(rax, __ delayed_value(java_dyn_impl_DynCallSite::target_offset_in_bytes, rcx)));
++ __ testptr(rcx, rcx);
++ __ jcc(Assembler::zero, handle_unlinked_site);
++
++ __ prepare_to_jump_from_interpreted();
++ __ jump_to_method_handle_entry(rcx, rdx);
++
++ // Initial calls come here...
++ __ bind(handle_unlinked_site);
++ __ pop(rcx); // remove return address pushed by prepare_invoke
++
++ address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::bootstrap_invokedynamic);
++ // squish stacked arguments together on stack, preceded by call site
++ // return bootstrap method as a handle in rcx
++ __ restore_bcp(); // rsi must be correct for call_VM
++ __ call_VM(rax, entry, rax);
++ __ movl(rdi, rax); // protect MH from prepare_invoke
++
++ // recompute return address
++ __ restore_bcp(); // rsi must be correct for prepare_invoke
++ prepare_invoke(rax, rbx, -byte_no);
++ // rax: CallSite object (f1)
++ // rbx: unused (f2)
++ // rcx: receiver address (now holds arglist)
++ // rdx: flags
++
++ // save SP now, before we add the bootstrap call to the stack
++ __ prepare_to_jump_from_interpreted();
++
++ // let's play adapter
++ __ pop(rbx); // return value
++ __ push(rdi); // boot MH
++ __ push(rax); // call site
++ __ movptr(rcx, Address(rcx, 0));
++ __ push(rcx); // arglist
++ __ push(rbx); // return value
++ __ mov(rcx, rdi);
++ __ jump_to_method_handle_entry(rcx, rdx);
+ }
+
+ //-----------------------------------------------------------------------------
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
@@ -2407,11 +3984,11 @@ diff --git a/src/cpu/x86/vm/vtableStubs_
+ if (MethodHandles) { // %%% let's use this refactored code always
+ // Most registers are in use; we'll use rax, rbx, rcx, rsi
+ Register restore_rcx = rcx;
-+ __ pushl(restore_rcx);
++ __ push(restore_rcx);
+
+ // get receiver klass (also an implicit null-check)
+ npe_addr = __ pc();
-+ __ movl(rcx, Address(rcx, oopDesc::klass_offset_in_bytes()));
++ __ movptr(rcx, Address(rcx, oopDesc::klass_offset_in_bytes()));
+
+ const Register method = rbx;
+ Label throw_icce;
@@ -2424,7 +4001,7 @@ diff --git a/src/cpu/x86/vm/vtableStubs_
+ throw_icce);
+
+ // Restore saved register, before possible trap.
-+ __ popl(restore_rcx);
++ __ pop(restore_rcx);
+
+ // method (rbx): methodOop
+ // rcx: receiver
@@ -2446,7 +4023,7 @@ diff --git a/src/cpu/x86/vm/vtableStubs_
+
+ __ bind(throw_icce);
+ // Restore saved register
-+ __ popl(restore_rcx);
++ __ pop(restore_rcx);
+ __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
+ } else {
+ // %%% remove this old code, in favor of the previous block:
@@ -4100,9 +5677,9 @@ diff --git a/src/share/vm/includeDB_core
+methodHandles.cpp signature.hpp
+methodHandles.cpp symbolTable.hpp
+
-+methodHandles_<arch_model>.cpp allocation.inline.hpp
-+methodHandles_<arch_model>.cpp interpreter.hpp
-+methodHandles_<arch_model>.cpp methodHandles.hpp
++methodHandles_<arch>.cpp allocation.inline.hpp
++methodHandles_<arch>.cpp interpreter.hpp
++methodHandles_<arch>.cpp methodHandles.hpp
+
methodKlass.cpp collectedHeap.inline.hpp
methodKlass.cpp constMethodKlass.hpp
@@ -6557,8 +8134,8 @@ diff --git a/src/share/vm/oops/oop.inlin
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 address oopDesc::address_field_acquire(int offset) const { return (address) OrderAccess::load_ptr_acquire(address_field_addr(offset)); }
++inline void oopDesc::release_address_field_put(int offset, address contents) { OrderAccess::release_store_ptr(address_field_addr(offset), contents); }
+
inline int oopDesc::size_given_klass(Klass* klass) {
int lh = klass->layout_helper();
@@ -7316,7 +8893,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/vm/prims/methodHandles.hpp
-@@ -0,0 +1,199 @@
+@@ -0,0 +1,198 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -7413,7 +8990,6 @@ new file mode 100644
+ static void generate_method_handle_stub(MacroAssembler* _masm, EntryKind ek);
+
+ // argument list parsing
-+ static Address argument_address(RegisterConstant arg_slot, int extra_slot_offset = 0);
+ static int argument_slot(oop method_type, int arg);
+
+ // Runtime support