aboutsummaryrefslogtreecommitdiff
path: root/src/cpu
diff options
context:
space:
mode:
authorjrose <none@none>2009-04-08 10:56:49 -0700
committerjrose <none@none>2009-04-08 10:56:49 -0700
commit36801011c9b0d8edaf6a7f97a8394c439de607ba (patch)
treeb7300e43ab49aea0527e81c61bf1232f7a2c6567 /src/cpu
parentf8ba0457fc2cdb878a2fc2cf183152f7a4b4c05b (diff)
6655638: dynamic languages need method handles
Summary: initial implementation, with known omissions (x86/64, sparc, compiler optim., c-oops, C++ interp.) Reviewed-by: kvn, twisti, never
Diffstat (limited to 'src/cpu')
-rw-r--r--src/cpu/sparc/vm/assembler_sparc.cpp52
-rw-r--r--src/cpu/sparc/vm/assembler_sparc.hpp25
-rw-r--r--src/cpu/sparc/vm/assembler_sparc.inline.hpp9
-rw-r--r--src/cpu/sparc/vm/cppInterpreter_sparc.cpp11
-rw-r--r--src/cpu/sparc/vm/interpreterGenerator_sparc.hpp3
-rw-r--r--src/cpu/sparc/vm/interpreter_sparc.cpp16
-rw-r--r--src/cpu/sparc/vm/methodHandles_sparc.cpp70
-rw-r--r--src/cpu/sparc/vm/register_definitions_sparc.cpp4
-rw-r--r--src/cpu/sparc/vm/sharedRuntime_sparc.cpp12
-rw-r--r--src/cpu/sparc/vm/templateInterpreter_sparc.cpp22
-rw-r--r--src/cpu/x86/vm/assembler_x86.cpp77
-rw-r--r--src/cpu/x86/vm/assembler_x86.hpp10
-rw-r--r--src/cpu/x86/vm/cppInterpreter_x86.cpp16
-rw-r--r--src/cpu/x86/vm/interp_masm_x86_32.cpp11
-rw-r--r--src/cpu/x86/vm/interp_masm_x86_32.hpp1
-rw-r--r--src/cpu/x86/vm/interp_masm_x86_64.cpp11
-rw-r--r--src/cpu/x86/vm/interp_masm_x86_64.hpp3
-rw-r--r--src/cpu/x86/vm/interpreterGenerator_x86.hpp3
-rw-r--r--src/cpu/x86/vm/interpreter_x86_32.cpp25
-rw-r--r--src/cpu/x86/vm/interpreter_x86_64.cpp12
-rw-r--r--src/cpu/x86/vm/methodHandles_x86.cpp1133
-rw-r--r--src/cpu/x86/vm/stubGenerator_x86_32.cpp10
-rw-r--r--src/cpu/x86/vm/templateInterpreter_x86_32.cpp31
-rw-r--r--src/cpu/x86/vm/templateInterpreter_x86_64.cpp26
24 files changed, 1556 insertions, 37 deletions
diff --git a/src/cpu/sparc/vm/assembler_sparc.cpp b/src/cpu/sparc/vm/assembler_sparc.cpp
index 597a91ae3..d36caf55f 100644
--- a/src/cpu/sparc/vm/assembler_sparc.cpp
+++ b/src/cpu/sparc/vm/assembler_sparc.cpp
@@ -3029,6 +3029,58 @@ void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass,
+void MacroAssembler::check_method_handle_type(Register mtype_reg, Register mh_reg,
+ Register temp_reg,
+ Label& wrong_method_type) {
+ assert_different_registers(mtype_reg, mh_reg, temp_reg);
+ // compare method type against that of the receiver
+ RegisterOrConstant mhtype_offset = delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg);
+ ld_ptr(mh_reg, mhtype_offset, temp_reg);
+ cmp(temp_reg, mtype_reg);
+ br(Assembler::notEqual, false, Assembler::pn, wrong_method_type);
+ delayed()->nop();
+}
+
+
+void MacroAssembler::jump_to_method_handle_entry(Register mh_reg, Register temp_reg) {
+ assert(mh_reg == G3_method_handle, "caller must put MH object in G3");
+ assert_different_registers(mh_reg, temp_reg);
+
+ // pick out the interpreted side of the handler
+ ld_ptr(mh_reg, delayed_value(java_dyn_MethodHandle::vmentry_offset_in_bytes, temp_reg), temp_reg);
+
+ // off we go...
+ ld_ptr(temp_reg, MethodHandleEntry::from_interpreted_entry_offset_in_bytes(), temp_reg);
+ jmp(temp_reg, 0);
+
+ // for the various stubs which take control at this point,
+ // see MethodHandles::generate_method_handle_stub
+
+ // (Can any caller use this delay slot? If so, add an option for supression.)
+ delayed()->nop();
+}
+
+RegisterOrConstant MacroAssembler::argument_offset(RegisterOrConstant arg_slot,
+ int extra_slot_offset) {
+ // cf. TemplateTable::prepare_invoke(), if (load_receiver).
+ int stackElementSize = Interpreter::stackElementWords() * wordSize;
+ int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
+ int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1);
+ assert(offset1 - offset == stackElementSize, "correct arithmetic");
+ if (arg_slot.is_constant()) {
+ offset += arg_slot.as_constant() * stackElementSize;
+ return offset;
+ } else {
+ Register temp = arg_slot.as_register();
+ sll_ptr(temp, exact_log2(stackElementSize), temp);
+ if (offset != 0)
+ add(temp, offset, temp);
+ return temp;
+ }
+}
+
+
+
void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg,
Register temp_reg,
Label& done, Label* slow_case,
diff --git a/src/cpu/sparc/vm/assembler_sparc.hpp b/src/cpu/sparc/vm/assembler_sparc.hpp
index 5c756c4b6..cfd935987 100644
--- a/src/cpu/sparc/vm/assembler_sparc.hpp
+++ b/src/cpu/sparc/vm/assembler_sparc.hpp
@@ -84,6 +84,10 @@ REGISTER_DECLARATION(Register, G4_scratch , G4);
REGISTER_DECLARATION(Register, Gtemp , G5);
+// JSR 292 fixed register usages:
+REGISTER_DECLARATION(Register, G5_method_type , G5);
+REGISTER_DECLARATION(Register, G3_method_handle , G3);
+
// The compiler requires that G5_megamorphic_method is G5_inline_cache_klass,
// because a single patchable "set" instruction (NativeMovConstReg,
// or NativeMovConstPatching for compiler1) instruction
@@ -91,9 +95,13 @@ REGISTER_DECLARATION(Register, Gtemp , G5);
// call site is an inline cache or is megamorphic. See the function
// CompiledIC::set_to_megamorphic.
//
-// On the other hand, G5_inline_cache_klass must differ from G5_method,
-// because both registers are needed for an inline cache that calls
-// an interpreted method.
+// If a inline cache targets an interpreted method, then the
+// G5 register will be used twice during the call. First,
+// the call site will be patched to load a compiledICHolder
+// into G5. (This is an ordered pair of ic_klass, method.)
+// The c2i adapter will first check the ic_klass, then load
+// G5_method with the method part of the pair just before
+// jumping into the interpreter.
//
// Note that G5_method is only the method-self for the interpreter,
// and is logically unrelated to G5_megamorphic_method.
@@ -1931,6 +1939,7 @@ class MacroAssembler: public Assembler {
inline void store_ptr_contents( Register s, Address& a, int offset = 0 );
inline void jumpl_to( Address& a, Register d, int offset = 0 );
inline void jump_to( Address& a, int offset = 0 );
+ inline void jump_indirect_to( Address& a, Register temp, int ld_offset = 0, int jmp_offset = 0 );
// ring buffer traceable jumps
@@ -2366,6 +2375,16 @@ class MacroAssembler: public Assembler {
Register temp2_reg,
Label& L_success);
+ // method handles (JSR 292)
+ void check_method_handle_type(Register mtype_reg, Register mh_reg,
+ Register temp_reg,
+ Label& wrong_method_type);
+ void jump_to_method_handle_entry(Register mh_reg, Register temp_reg);
+ // offset relative to Gargs of argument at tos[arg_slot].
+ // (arg_slot == 0 means the last argument, not the first).
+ RegisterOrConstant argument_offset(RegisterOrConstant arg_slot,
+ int extra_slot_offset = 0);
+
// Stack overflow checking
diff --git a/src/cpu/sparc/vm/assembler_sparc.inline.hpp b/src/cpu/sparc/vm/assembler_sparc.inline.hpp
index d9053f7f6..692c8650b 100644
--- a/src/cpu/sparc/vm/assembler_sparc.inline.hpp
+++ b/src/cpu/sparc/vm/assembler_sparc.inline.hpp
@@ -671,6 +671,15 @@ inline void MacroAssembler::jump_to( Address& a, int offset ) {
}
+inline void MacroAssembler::jump_indirect_to( Address& a, Register temp,
+ int ld_offset, int jmp_offset ) {
+ assert_not_delayed();
+ //sethi(a); // sethi is caller responsibility for this one
+ ld_ptr(a, temp, ld_offset);
+ jmp(temp, jmp_offset);
+}
+
+
inline void MacroAssembler::set_oop( jobject obj, Register d ) {
set_oop(allocate_oop_address(obj, d));
}
diff --git a/src/cpu/sparc/vm/cppInterpreter_sparc.cpp b/src/cpu/sparc/vm/cppInterpreter_sparc.cpp
index f2d6486f8..c89d6e169 100644
--- a/src/cpu/sparc/vm/cppInterpreter_sparc.cpp
+++ b/src/cpu/sparc/vm/cppInterpreter_sparc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1017,6 +1017,7 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
const int slop_factor = 2*wordSize;
const int fixed_size = ((sizeof(BytecodeInterpreter) + slop_factor) >> LogBytesPerWord) + // what is the slop factor?
+ //6815692//methodOopDesc::extra_stack_words() + // extra push slots for MH adapters
frame::memory_parameter_word_sp_offset + // register save area + param window
(native ? frame::interpreter_frame_extra_outgoing_argument_words : 0); // JNI, class
@@ -1163,6 +1164,9 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
__ st_ptr(O2, XXX_STATE(_stack)); // PREPUSH
__ lduh(max_stack, O3); // Full size expression stack
+ guarantee(!EnableMethodHandles, "no support yet for java.dyn.MethodHandle"); //6815692
+ //6815692//if (EnableMethodHandles)
+ //6815692// __ inc(O3, methodOopDesc::extra_stack_entries());
__ sll(O3, LogBytesPerWord, O3);
__ sub(O2, O3, O3);
// __ sub(O3, wordSize, O3); // so prepush doesn't look out of bounds
@@ -2017,7 +2021,9 @@ static int size_activation_helper(int callee_extra_locals, int max_stack, int mo
const int fixed_size = sizeof(BytecodeInterpreter)/wordSize + // interpreter state object
frame::memory_parameter_word_sp_offset; // register save area + param window
+ const int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
return (round_to(max_stack +
+ extra_stack +
slop_factor +
fixed_size +
monitor_size +
@@ -2104,7 +2110,8 @@ void BytecodeInterpreter::layout_interpreterState(interpreterState to_fill,
// Need +1 here because stack_base points to the word just above the first expr stack entry
// and stack_limit is supposed to point to the word just below the last expr stack entry.
// See generate_compute_interpreter_state.
- to_fill->_stack_limit = stack_base - (method->max_stack() + 1);
+ int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
+ to_fill->_stack_limit = stack_base - (method->max_stack() + 1 + extra_stack);
to_fill->_monitor_base = (BasicObjectLock*) monitor_base;
// sparc specific
diff --git a/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp b/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp
index 3352d2abd..3ed9bc471 100644
--- a/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp
+++ b/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
address generate_normal_entry(bool synchronized);
address generate_native_entry(bool synchronized);
address generate_abstract_entry(void);
+ address generate_method_handle_entry(void);
address generate_math_entry(AbstractInterpreter::MethodKind kind);
address generate_empty_entry(void);
address generate_accessor_entry(void);
diff --git a/src/cpu/sparc/vm/interpreter_sparc.cpp b/src/cpu/sparc/vm/interpreter_sparc.cpp
index 898d37060..9f0dd7166 100644
--- a/src/cpu/sparc/vm/interpreter_sparc.cpp
+++ b/src/cpu/sparc/vm/interpreter_sparc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -235,6 +235,19 @@ address InterpreterGenerator::generate_abstract_entry(void) {
}
+
+// Method handle invoker
+// Dispatch a method of the form java.dyn.MethodHandles::invoke(...)
+address InterpreterGenerator::generate_method_handle_entry(void) {
+ if (!EnableMethodHandles) {
+ return generate_abstract_entry();
+ }
+ return generate_abstract_entry(); //6815692//
+}
+
+
+
+
//----------------------------------------------------------------------------------------------------
// Entry points & stack frame layout
//
@@ -364,6 +377,7 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter:
case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break;
case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break;
case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break;
+ case Interpreter::method_handle : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
case Interpreter::java_lang_math_sin : break;
case Interpreter::java_lang_math_cos : break;
case Interpreter::java_lang_math_tan : break;
diff --git a/src/cpu/sparc/vm/methodHandles_sparc.cpp b/src/cpu/sparc/vm/methodHandles_sparc.cpp
new file mode 100644
index 000000000..dd40006e1
--- /dev/null
+++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#include "incls/_precompiled.incl"
+#include "incls/_methodHandles_sparc.cpp.incl"
+
+#define __ _masm->
+
+address MethodHandleEntry::start_compiled_entry(MacroAssembler* _masm,
+ address interpreted_entry) {
+ __ align(wordSize);
+ address target = __ pc() + sizeof(Data);
+ while (__ pc() < target) {
+ __ nop();
+ __ align(wordSize);
+ }
+
+ MethodHandleEntry* me = (MethodHandleEntry*) __ pc();
+ me->set_end_address(__ pc()); // set a temporary end_address
+ me->set_from_interpreted_entry(interpreted_entry);
+ me->set_type_checking_entry(NULL);
+
+ return (address) me;
+}
+
+MethodHandleEntry* MethodHandleEntry::finish_compiled_entry(MacroAssembler* _masm,
+ address start_addr) {
+ MethodHandleEntry* me = (MethodHandleEntry*) start_addr;
+ assert(me->end_address() == start_addr, "valid ME");
+
+ // Fill in the real end_address:
+ __ align(wordSize);
+ me->set_end_address(__ pc());
+
+ return me;
+}
+
+
+// Code generation
+address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) {
+ ShouldNotReachHere(); //NYI, 6815692
+ return NULL;
+}
+
+// Generate an "entry" field for a method handle.
+// This determines how the method handle will respond to calls.
+void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) {
+ ShouldNotReachHere(); //NYI, 6815692
+}
diff --git a/src/cpu/sparc/vm/register_definitions_sparc.cpp b/src/cpu/sparc/vm/register_definitions_sparc.cpp
index d3e805570..410f62aeb 100644
--- a/src/cpu/sparc/vm/register_definitions_sparc.cpp
+++ b/src/cpu/sparc/vm/register_definitions_sparc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -142,6 +142,8 @@ REGISTER_DEFINITION(Register, G1_scratch);
REGISTER_DEFINITION(Register, G3_scratch);
REGISTER_DEFINITION(Register, G4_scratch);
REGISTER_DEFINITION(Register, Gtemp);
+REGISTER_DEFINITION(Register, G5_method_type);
+REGISTER_DEFINITION(Register, G3_method_handle);
REGISTER_DEFINITION(Register, Lentry_args);
#ifdef CC_INTERP
diff --git a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp
index 5804fbbfe..e2bd04436 100644
--- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp
+++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -937,12 +937,12 @@ void AdapterGenerator::gen_i2c_adapter(
// Inputs:
// G2_thread - TLS
// G5_method - Method oop
- // O0 - Flag telling us to restore SP from O5
- // O4_args - Pointer to interpreter's args
- // O5 - Caller's saved SP, to be restored if needed
+ // G4 (Gargs) - Pointer to interpreter's args
+ // O0..O4 - free for scratch
+ // O5_savedSP - Caller's saved SP, to be restored if needed
// O6 - Current SP!
// O7 - Valid return address
- // L0-L7, I0-I7 - Caller's temps (no frame pushed yet)
+ // L0-L7, I0-I7 - Caller's temps (no frame pushed yet)
// Outputs:
// G2_thread - TLS
@@ -954,7 +954,7 @@ void AdapterGenerator::gen_i2c_adapter(
// F0-F7 - more outgoing args
- // O4 is about to get loaded up with compiled callee's args
+ // Gargs is the incoming argument base, and also an outgoing argument.
__ sub(Gargs, BytesPerWord, Gargs);
#ifdef ASSERT
diff --git a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
index 090242c17..6cbcf9272 100644
--- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
+++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -108,6 +108,24 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
}
+// Arguments are: required type in G5_method_type, and
+// failing object (or NULL) in G3_method_handle.
+address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
+ address entry = __ pc();
+ // expression stack must be empty before entering the VM if an exception
+ // happened
+ __ empty_expression_stack();
+ // load exception object
+ __ call_VM(Oexception,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::throw_WrongMethodTypeException),
+ G5_method_type, // required
+ G3_method_handle); // actual
+ __ should_not_reach_here();
+ return entry;
+}
+
+
address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) {
address entry = __ pc();
// expression stack must be empty before entering the VM if an exception happened
@@ -448,6 +466,7 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
const int extra_space =
rounded_vm_local_words + // frame local scratch space
+ //6815692//methodOopDesc::extra_stack_words() + // extra push slots for MH adapters
frame::memory_parameter_word_sp_offset + // register save area
(native_call ? frame::interpreter_frame_extra_outgoing_argument_words : 0);
@@ -1447,6 +1466,7 @@ static int size_activation_helper(int callee_extra_locals, int max_stack, int mo
round_to(callee_extra_locals * Interpreter::stackElementWords(), WordsPerLong);
const int max_stack_words = max_stack * Interpreter::stackElementWords();
return (round_to((max_stack_words
+ //6815692//+ methodOopDesc::extra_stack_words()
+ rounded_vm_local_words
+ frame::memory_parameter_word_sp_offset), WordsPerLong)
// already rounded
diff --git a/src/cpu/x86/vm/assembler_x86.cpp b/src/cpu/x86/vm/assembler_x86.cpp
index 35ee7e540..be4c842bb 100644
--- a/src/cpu/x86/vm/assembler_x86.cpp
+++ b/src/cpu/x86/vm/assembler_x86.cpp
@@ -7609,6 +7609,83 @@ RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_ad
}
+// registers on entry:
+// - rax ('check' register): required MethodType
+// - rcx: method handle
+// - rdx, rsi, or ?: killable temp
+void MacroAssembler::check_method_handle_type(Register mtype_reg, Register mh_reg,
+ Register temp_reg,
+ Label& wrong_method_type) {
+ if (UseCompressedOops) unimplemented(); // field accesses must decode
+ // compare method type against that of the receiver
+ cmpptr(mtype_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg)));
+ jcc(Assembler::notEqual, wrong_method_type);
+}
+
+
+// A method handle has a "vmslots" field which gives the size of its
+// argument list in JVM stack slots. This field is either located directly
+// in every method handle, or else is indirectly accessed through the
+// method handle's MethodType. This macro hides the distinction.
+void MacroAssembler::load_method_handle_vmslots(Register vmslots_reg, Register mh_reg,
+ Register temp_reg) {
+ if (UseCompressedOops) unimplemented(); // field accesses must decode
+ // load mh.type.form.vmslots
+ if (java_dyn_MethodHandle::vmslots_offset_in_bytes() != 0) {
+ // hoist vmslots into every mh to avoid dependent load chain
+ movl(vmslots_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::vmslots_offset_in_bytes, temp_reg)));
+ } else {
+ Register temp2_reg = vmslots_reg;
+ movptr(temp2_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg)));
+ movptr(temp2_reg, Address(temp2_reg, delayed_value(java_dyn_MethodType::form_offset_in_bytes, temp_reg)));
+ movl(vmslots_reg, Address(temp2_reg, delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, temp_reg)));
+ }
+}
+
+
+// registers on entry:
+// - rcx: method handle
+// - rdx: killable temp (interpreted only)
+// - rax: killable temp (compiled only)
+void MacroAssembler::jump_to_method_handle_entry(Register mh_reg, Register temp_reg) {
+ assert(mh_reg == rcx, "caller must put MH object in rcx");
+ assert_different_registers(mh_reg, temp_reg);
+
+ if (UseCompressedOops) unimplemented(); // field accesses must decode
+
+ // pick out the interpreted side of the handler
+ movptr(temp_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::vmentry_offset_in_bytes, temp_reg)));
+
+ // off we go...
+ jmp(Address(temp_reg, MethodHandleEntry::from_interpreted_entry_offset_in_bytes()));
+
+ // for the various stubs which take control at this point,
+ // see MethodHandles::generate_method_handle_stub
+}
+
+
+Address MacroAssembler::argument_address(RegisterOrConstant arg_slot,
+ int extra_slot_offset) {
+ // cf. TemplateTable::prepare_invoke(), if (load_receiver).
+ int stackElementSize = Interpreter::stackElementSize();
+ int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
+#ifdef ASSERT
+ int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1);
+ assert(offset1 - offset == stackElementSize, "correct arithmetic");
+#endif
+ Register scale_reg = noreg;
+ Address::ScaleFactor scale_factor = Address::no_scale;
+ if (arg_slot.is_constant()) {
+ offset += arg_slot.as_constant() * stackElementSize;
+ } else {
+ scale_reg = arg_slot.as_register();
+ scale_factor = Address::times(stackElementSize);
+ }
+ offset += wordSize; // return PC is on stack
+ return Address(rsp, scale_reg, scale_factor, offset);
+}
+
+
void MacroAssembler::verify_oop_addr(Address addr, const char* s) {
if (!VerifyOops) return;
diff --git a/src/cpu/x86/vm/assembler_x86.hpp b/src/cpu/x86/vm/assembler_x86.hpp
index 89ac6dd53..92b55b9de 100644
--- a/src/cpu/x86/vm/assembler_x86.hpp
+++ b/src/cpu/x86/vm/assembler_x86.hpp
@@ -1857,6 +1857,16 @@ class MacroAssembler: public Assembler {
Register temp_reg,
Label& L_success);
+ // method handles (JSR 292)
+ void check_method_handle_type(Register mtype_reg, Register mh_reg,
+ Register temp_reg,
+ Label& wrong_method_type);
+ void load_method_handle_vmslots(Register vmslots_reg, Register mh_reg,
+ Register temp_reg);
+ void jump_to_method_handle_entry(Register mh_reg, Register temp_reg);
+ Address argument_address(RegisterOrConstant arg_slot, int extra_slot_offset = 0);
+
+
//----
void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0
diff --git a/src/cpu/x86/vm/cppInterpreter_x86.cpp b/src/cpu/x86/vm/cppInterpreter_x86.cpp
index 31afca773..98af0c244 100644
--- a/src/cpu/x86/vm/cppInterpreter_x86.cpp
+++ b/src/cpu/x86/vm/cppInterpreter_x86.cpp
@@ -513,10 +513,11 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
// compute full expression stack limit
const Address size_of_stack (rbx, methodOopDesc::max_stack_offset());
+ const int extra_stack = 0; //6815692//methodOopDesc::extra_stack_words();
__ load_unsigned_short(rdx, size_of_stack); // get size of expression stack in words
__ negptr(rdx); // so we can subtract in next step
// Allocate expression stack
- __ lea(rsp, Address(rsp, rdx, Address::times_ptr));
+ __ lea(rsp, Address(rsp, rdx, Address::times_ptr, -extra_stack));
__ movptr(STATE(_stack_limit), rsp);
}
@@ -659,8 +660,9 @@ void InterpreterGenerator::generate_stack_overflow_check(void) {
// Always give one monitor to allow us to start interp if sync method.
// Any additional monitors need a check when moving the expression stack
const int one_monitor = frame::interpreter_frame_monitor_size() * wordSize;
+ const int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
__ load_unsigned_short(rax, size_of_stack); // get size of expression stack in words
- __ lea(rax, Address(noreg, rax, Interpreter::stackElementScale(), one_monitor));
+ __ lea(rax, Address(noreg, rax, Interpreter::stackElementScale(), extra_stack + one_monitor));
__ lea(rax, Address(rax, rdx, Interpreter::stackElementScale(), overhead_size));
#ifdef ASSERT
@@ -2185,6 +2187,7 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter:
case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break;
case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break;
case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break;
+ case Interpreter::method_handle : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
case Interpreter::java_lang_math_sin : // fall thru
case Interpreter::java_lang_math_cos : // fall thru
@@ -2224,7 +2227,8 @@ int AbstractInterpreter::size_top_interpreter_activation(methodOop method) {
const int overhead_size = sizeof(BytecodeInterpreter)/wordSize +
( frame::sender_sp_offset - frame::link_offset) + 2;
- const int method_stack = (method->max_locals() + method->max_stack()) *
+ const int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
+ const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) *
Interpreter::stackElementWords();
return overhead_size + method_stack + stub_code;
}
@@ -2289,7 +2293,8 @@ void BytecodeInterpreter::layout_interpreterState(interpreterState to_fill,
// Need +1 here because stack_base points to the word just above the first expr stack entry
// and stack_limit is supposed to point to the word just below the last expr stack entry.
// See generate_compute_interpreter_state.
- to_fill->_stack_limit = stack_base - (method->max_stack() + 1);
+ int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
+ to_fill->_stack_limit = stack_base - (method->max_stack() + extra_stack + 1);
to_fill->_monitor_base = (BasicObjectLock*) monitor_base;
to_fill->_self_link = to_fill;
@@ -2335,7 +2340,8 @@ int AbstractInterpreter::layout_activation(methodOop method,
monitor_size);
// Now with full size expression stack
- int full_frame_size = short_frame_size + method->max_stack() * BytesPerWord;
+ int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
+ int full_frame_size = short_frame_size + (method->max_stack() + extra_stack) * BytesPerWord;
// and now with only live portion of the expression stack
short_frame_size = short_frame_size + tempcount * BytesPerWord;
diff --git a/src/cpu/x86/vm/interp_masm_x86_32.cpp b/src/cpu/x86/vm/interp_masm_x86_32.cpp
index bb14db905..413e59735 100644
--- a/src/cpu/x86/vm/interp_masm_x86_32.cpp
+++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp
@@ -555,13 +555,18 @@ void InterpreterMacroAssembler::super_call_VM_leaf(address entry_point, Register
}
-// Jump to from_interpreted entry of a call unless single stepping is possible
-// in this thread in which case we must call the i2i entry
-void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
+void InterpreterMacroAssembler::prepare_to_jump_from_interpreted() {
// set sender sp
lea(rsi, Address(rsp, wordSize));
// record last_sp
movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), rsi);
+}
+
+
+// Jump to from_interpreted entry of a call unless single stepping is possible
+// in this thread in which case we must call the i2i entry
+void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
+ prepare_to_jump_from_interpreted();
if (JvmtiExport::can_post_interpreter_events()) {
Label run_compiled_code;
diff --git a/src/cpu/x86/vm/interp_masm_x86_32.hpp b/src/cpu/x86/vm/interp_masm_x86_32.hpp
index dc6c7bce2..3500b5fbd 100644
--- a/src/cpu/x86/vm/interp_masm_x86_32.hpp
+++ b/src/cpu/x86/vm/interp_masm_x86_32.hpp
@@ -161,6 +161,7 @@ class InterpreterMacroAssembler: public MacroAssembler {
// jump to an invoked target
+ void prepare_to_jump_from_interpreted();
void jump_from_interpreted(Register method, Register temp);
// Returning from interpreted functions
diff --git a/src/cpu/x86/vm/interp_masm_x86_64.cpp b/src/cpu/x86/vm/interp_masm_x86_64.cpp
index 56bd0c8c9..dbd858da2 100644
--- a/src/cpu/x86/vm/interp_masm_x86_64.cpp
+++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp
@@ -551,13 +551,18 @@ void InterpreterMacroAssembler::super_call_VM_leaf(address entry_point,
MacroAssembler::call_VM_leaf_base(entry_point, 3);
}
-// Jump to from_interpreted entry of a call unless single stepping is possible
-// in this thread in which case we must call the i2i entry
-void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
+void InterpreterMacroAssembler::prepare_to_jump_from_interpreted() {
// set sender sp
lea(r13, Address(rsp, wordSize));
// record last_sp
movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), r13);
+}
+
+
+// Jump to from_interpreted entry of a call unless single stepping is possible
+// in this thread in which case we must call the i2i entry
+void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
+ prepare_to_jump_from_interpreted();
if (JvmtiExport::can_post_interpreter_events()) {
Label run_compiled_code;
diff --git a/src/cpu/x86/vm/interp_masm_x86_64.hpp b/src/cpu/x86/vm/interp_masm_x86_64.hpp
index 62396c94b..c35cb3a19 100644
--- a/src/cpu/x86/vm/interp_masm_x86_64.hpp
+++ b/src/cpu/x86/vm/interp_masm_x86_64.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -176,6 +176,7 @@ class InterpreterMacroAssembler: public MacroAssembler {
void dispatch_via (TosState state, address* table);
// jump to an invoked target
+ void prepare_to_jump_from_interpreted();
void jump_from_interpreted(Register method, Register temp);
diff --git a/src/cpu/x86/vm/interpreterGenerator_x86.hpp b/src/cpu/x86/vm/interpreterGenerator_x86.hpp
index 066d89d5f..168579511 100644
--- a/src/cpu/x86/vm/interpreterGenerator_x86.hpp
+++ b/src/cpu/x86/vm/interpreterGenerator_x86.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
address generate_normal_entry(bool synchronized);
address generate_native_entry(bool synchronized);
address generate_abstract_entry(void);
+ address generate_method_handle_entry(void);
address generate_math_entry(AbstractInterpreter::MethodKind kind);
address generate_empty_entry(void);
address generate_accessor_entry(void);
diff --git a/src/cpu/x86/vm/interpreter_x86_32.cpp b/src/cpu/x86/vm/interpreter_x86_32.cpp
index 221cd8561..2db290c43 100644
--- a/src/cpu/x86/vm/interpreter_x86_32.cpp
+++ b/src/cpu/x86/vm/interpreter_x86_32.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -201,11 +201,12 @@ address InterpreterGenerator::generate_abstract_entry(void) {
address entry_point = __ pc();
// abstract method entry
- // remove return address. Not really needed, since exception handling throws away expression stack
- __ pop(rbx);
- // adjust stack to what a normal return would do
- __ mov(rsp, rsi);
+ // pop return address, reset last_sp to NULL
+ __ empty_expression_stack();
+ __ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
+ __ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
+
// throw exception
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
// the call_VM checks for exception, so we should never return here.
@@ -214,6 +215,20 @@ address InterpreterGenerator::generate_abstract_entry(void) {
return entry_point;
}
+
+// Method handle invoker
+// Dispatch a method of the form java.dyn.MethodHandles::invoke(...)
+address InterpreterGenerator::generate_method_handle_entry(void) {
+ if (!EnableMethodHandles) {
+ return generate_abstract_entry();
+ }
+
+ address entry_point = MethodHandles::generate_method_handle_interpreter_entry(_masm);
+
+ return entry_point;
+}
+
+
// This method tells the deoptimizer how big an interpreted frame must be:
int AbstractInterpreter::size_activation(methodOop method,
int tempcount,
diff --git a/src/cpu/x86/vm/interpreter_x86_64.cpp b/src/cpu/x86/vm/interpreter_x86_64.cpp
index 34e5b56b8..c3cbf56ca 100644
--- a/src/cpu/x86/vm/interpreter_x86_64.cpp
+++ b/src/cpu/x86/vm/interpreter_x86_64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -294,6 +294,16 @@ address InterpreterGenerator::generate_abstract_entry(void) {
}
+// Method handle invoker
+// Dispatch a method of the form java.dyn.MethodHandles::invoke(...)
+address InterpreterGenerator::generate_method_handle_entry(void) {
+ if (!EnableMethodHandles) {
+ return generate_abstract_entry();
+ }
+ return generate_abstract_entry(); //6815692//
+}
+
+
// Empty method, generate a very fast return.
address InterpreterGenerator::generate_empty_entry(void) {
diff --git a/src/cpu/x86/vm/methodHandles_x86.cpp b/src/cpu/x86/vm/methodHandles_x86.cpp
new file mode 100644
index 000000000..24210bf5d
--- /dev/null
+++ b/src/cpu/x86/vm/methodHandles_x86.cpp
@@ -0,0 +1,1133 @@
+/*
+ * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#include "incls/_precompiled.incl"
+#include "incls/_methodHandles_x86.cpp.incl"
+
+#define __ _masm->
+
+address MethodHandleEntry::start_compiled_entry(MacroAssembler* _masm,
+ address interpreted_entry) {
+ // Just before the actual machine code entry point, allocate space
+ // for a MethodHandleEntry::Data record, so that we can manage everything
+ // from one base pointer.
+ __ align(wordSize);
+ address target = __ pc() + sizeof(Data);
+ while (__ pc() < target) {
+ __ nop();
+ __ align(wordSize);
+ }
+
+ MethodHandleEntry* me = (MethodHandleEntry*) __ pc();
+ me->set_end_address(__ pc()); // set a temporary end_address
+ me->set_from_interpreted_entry(interpreted_entry);
+ me->set_type_checking_entry(NULL);
+
+ return (address) me;
+}
+
+MethodHandleEntry* MethodHandleEntry::finish_compiled_entry(MacroAssembler* _masm,
+ address start_addr) {
+ MethodHandleEntry* me = (MethodHandleEntry*) start_addr;
+ assert(me->end_address() == start_addr, "valid ME");
+
+ // Fill in the real end_address:
+ __ align(wordSize);
+ me->set_end_address(__ pc());
+
+ return me;
+}
+
+#ifdef ASSERT
+static void verify_argslot(MacroAssembler* _masm, Register rax_argslot,
+ const char* error_message) {
+ // Verify that argslot lies within (rsp, rbp].
+ Label L_ok, L_bad;
+ __ cmpptr(rax_argslot, rbp);
+ __ jcc(Assembler::above, L_bad);
+ __ cmpptr(rsp, rax_argslot);
+ __ jcc(Assembler::below, L_ok);
+ __ bind(L_bad);
+ __ stop(error_message);
+ __ bind(L_ok);
+}
+#endif
+
+
+// Code generation
+address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) {
+ // rbx: methodOop
+ // rcx: receiver method handle (must load from sp[MethodTypeForm.vmslots])
+ // rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted)
+ // rdx: garbage temp, blown away
+
+ Register rbx_method = rbx;
+ Register rcx_recv = rcx;
+ Register rax_mtype = rax;
+ Register rdx_temp = rdx;
+
+ // emit WrongMethodType path first, to enable jccb back-branch from main path
+ Label wrong_method_type;
+ __ bind(wrong_method_type);
+ __ push(rax_mtype); // required mtype
+ __ push(rcx_recv); // bad mh (1st stacked argument)
+ __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
+
+ // here's where control starts out:
+ __ align(CodeEntryAlignment);
+ address entry_point = __ pc();
+
+ // fetch the MethodType from the method handle into rax (the 'check' register)
+ {
+ Register tem = rbx_method;
+ for (jint* pchase = methodOopDesc::method_type_offsets_chain(); (*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
+
+ // given the MethodType, find out where the MH argument is buried
+ __ movptr(rdx_temp, Address(rax_mtype,
+ __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, rbx_temp)));
+ __ movl(rdx_temp, Address(rdx_temp,
+ __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, rbx_temp)));
+ __ movptr(rcx_recv, __ argument_address(rdx_temp));
+
+ __ check_method_handle_type(rax_mtype, rcx_recv, rdx_temp, wrong_method_type);
+ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+
+ return entry_point;
+}
+
+// Helper to insert argument slots into the stack.
+// arg_slots must be a multiple of stack_move_unit() and <= 0
+void MethodHandles::insert_arg_slots(MacroAssembler* _masm,
+ RegisterOrConstant arg_slots,
+ int arg_mask,
+ Register rax_argslot,
+ Register rbx_temp, Register rdx_temp) {
+ assert_different_registers(rax_argslot, rbx_temp, rdx_temp,
+ (!arg_slots.is_register() ? rsp : arg_slots.as_register()));
+
+#ifdef ASSERT
+ verify_argslot(_masm, rax_argslot, "insertion point must fall within current frame");
+ if (arg_slots.is_register()) {
+ Label L_ok, L_bad;
+ __ cmpptr(arg_slots.as_register(), (int32_t) NULL_WORD);
+ __ jcc(Assembler::greater, L_bad);
+ __ testl(arg_slots.as_register(), -stack_move_unit() - 1);
+ __ jcc(Assembler::zero, L_ok);
+ __ bind(L_bad);
+ __ stop("assert arg_slots <= 0 and clear low bits");
+ __ bind(L_ok);
+ } else {
+ assert(arg_slots.as_constant() <= 0, "");
+ assert(arg_slots.as_constant() % -stack_move_unit() == 0, "");
+ }
+#endif //ASSERT
+
+#ifdef _LP64
+ if (arg_slots.is_register()) {
+ // clean high bits of stack motion register (was loaded as an int)
+ __ movslq(arg_slots.as_register(), arg_slots.as_register());
+ }
+#endif
+
+ // Make space on the stack for the inserted argument(s).
+ // Then pull down everything shallower than rax_argslot.
+ // The stacked return address gets pulled down with everything else.
+ // That is, copy [rsp, argslot) downward by -size words. In pseudo-code:
+ // rsp -= size;
+ // for (rdx = rsp + size; rdx < argslot; rdx++)
+ // rdx[-size] = rdx[0]
+ // argslot -= size;
+ __ mov(rdx_temp, rsp); // source pointer for copy
+ __ lea(rsp, Address(rsp, arg_slots, Address::times_ptr));
+ {
+ Label loop;
+ __ bind(loop);
+ // pull one word down each time through the loop
+ __ movptr(rbx_temp, Address(rdx_temp, 0));
+ __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp);
+ __ addptr(rdx_temp, wordSize);
+ __ cmpptr(rdx_temp, rax_argslot);
+ __ jcc(Assembler::less, loop);
+ }
+
+ // Now move the argslot down, to point to the opened-up space.
+ __ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr));
+
+ if (TaggedStackInterpreter && arg_mask != _INSERT_NO_MASK) {
+ // The caller has specified a bitmask of tags to put into the opened space.
+ // This only works when the arg_slots value is an assembly-time constant.
+ int constant_arg_slots = arg_slots.as_constant() / stack_move_unit();
+ int tag_offset = Interpreter::tag_offset_in_bytes() - Interpreter::value_offset_in_bytes();
+ for (int slot = 0; slot < constant_arg_slots; slot++) {
+ BasicType slot_type = ((arg_mask & (1 << slot)) == 0 ? T_OBJECT : T_INT);
+ int slot_offset = Interpreter::stackElementSize() * slot;
+ Address tag_addr(rax_argslot, slot_offset + tag_offset);
+ __ movptr(tag_addr, frame::tag_for_basic_type(slot_type));
+ }
+ // Note that the new argument slots are tagged properly but contain
+ // garbage at this point. The value portions must be initialized
+ // by the caller. (Especially references!)
+ }
+}
+
+// Helper to remove argument slots from the stack.
+// arg_slots must be a multiple of stack_move_unit() and >= 0
+void MethodHandles::remove_arg_slots(MacroAssembler* _masm,
+ RegisterOrConstant arg_slots,
+ Register rax_argslot,
+ Register rbx_temp, Register rdx_temp) {
+ assert_different_registers(rax_argslot, rbx_temp, rdx_temp,
+ (!arg_slots.is_register() ? rsp : arg_slots.as_register()));
+
+#ifdef ASSERT
+ {
+ // Verify that [argslot..argslot+size) lies within (rsp, rbp).
+ Label L_ok, L_bad;
+ __ lea(rbx_temp, Address(rax_argslot, arg_slots, Address::times_ptr));
+ __ cmpptr(rbx_temp, rbp);
+ __ jcc(Assembler::above, L_bad);
+ __ cmpptr(rsp, rax_argslot);
+ __ jcc(Assembler::below, L_ok);
+ __ bind(L_bad);
+ __ stop("deleted argument(s) must fall within current frame");
+ __ bind(L_ok);
+ }
+ if (arg_slots.is_register()) {
+ Label L_ok, L_bad;
+ __ cmpptr(arg_slots.as_register(), (int32_t) NULL_WORD);
+ __ jcc(Assembler::less, L_bad);
+ __ testl(arg_slots.as_register(), -stack_move_unit() - 1);
+ __ jcc(Assembler::zero, L_ok);
+ __ bind(L_bad);
+ __ stop("assert arg_slots >= 0 and clear low bits");
+ __ bind(L_ok);
+ } else {
+ assert(arg_slots.as_constant() >= 0, "");
+ assert(arg_slots.as_constant() % -stack_move_unit() == 0, "");
+ }
+#endif //ASSERT
+
+#ifdef _LP64
+ if (false) { // not needed, since register is positive
+ // clean high bits of stack motion register (was loaded as an int)
+ if (arg_slots.is_register())
+ __ movslq(arg_slots.as_register(), arg_slots.as_register());
+ }
+#endif
+
+ // Pull up everything shallower than rax_argslot.
+ // Then remove the excess space on the stack.
+ // The stacked return address gets pulled up with everything else.
+ // That is, copy [rsp, argslot) upward by size words. In pseudo-code:
+ // for (rdx = argslot-1; rdx >= rsp; --rdx)
+ // rdx[size] = rdx[0]
+ // argslot += size;
+ // rsp += size;
+ __ lea(rdx_temp, Address(rax_argslot, -wordSize)); // source pointer for copy
+ {
+ Label loop;
+ __ bind(loop);
+ // pull one word up each time through the loop
+ __ movptr(rbx_temp, Address(rdx_temp, 0));
+ __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp);
+ __ addptr(rdx_temp, -wordSize);
+ __ cmpptr(rdx_temp, rsp);
+ __ jcc(Assembler::greaterEqual, loop);
+ }
+
+ // Now move the argslot up, to point to the just-copied block.
+ __ lea(rsp, Address(rsp, arg_slots, Address::times_ptr));
+ // And adjust the argslot address to point at the deletion point.
+ __ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr));
+}
+
+#ifndef PRODUCT
+void trace_method_handle_stub(const char* adaptername,
+ oop mh,
+ intptr_t* entry_sp,
+ intptr_t* saved_sp) {
+ // called as a leaf from native code: do not block the JVM!
+ printf("MH %s "PTR_FORMAT" "PTR_FORMAT" "INTX_FORMAT"\n", adaptername, mh, entry_sp, entry_sp - saved_sp);
+}
+#endif //PRODUCT
+
+// Generate an "entry" field for a method handle.
+// This determines how the method handle will respond to calls.
+void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) {
+ // Here is the register state during an interpreted call,
+ // as set up by generate_method_handle_interpreter_entry():
+ // - rbx: garbage temp (was MethodHandle.invoke methodOop, unused)
+ // - rcx: receiver method handle
+ // - rax: method handle type (only used by the check_mtype entry point)
+ // - rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted)
+ // - rdx: garbage temp, can blow away
+
+ Register rcx_recv = rcx;
+ Register rax_argslot = rax;
+ Register rbx_temp = rbx;
+ Register rdx_temp = rdx;
+
+ guarantee(java_dyn_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets");
+
+ // some handy addresses
+ Address rbx_method_fie( rbx, methodOopDesc::from_interpreted_offset() );
+
+ Address rcx_mh_vmtarget( rcx_recv, java_dyn_MethodHandle::vmtarget_offset_in_bytes() );
+ Address rcx_dmh_vmindex( rcx_recv, sun_dyn_DirectMethodHandle::vmindex_offset_in_bytes() );
+
+ Address rcx_bmh_vmargslot( rcx_recv, sun_dyn_BoundMethodHandle::vmargslot_offset_in_bytes() );
+ Address rcx_bmh_argument( rcx_recv, sun_dyn_BoundMethodHandle::argument_offset_in_bytes() );
+
+ Address rcx_amh_vmargslot( rcx_recv, sun_dyn_AdapterMethodHandle::vmargslot_offset_in_bytes() );
+ Address rcx_amh_argument( rcx_recv, sun_dyn_AdapterMethodHandle::argument_offset_in_bytes() );
+ Address rcx_amh_conversion( rcx_recv, sun_dyn_AdapterMethodHandle::conversion_offset_in_bytes() );
+ Address vmarg; // __ argument_address(vmargslot)
+
+ int tag_offset = -1;
+ if (TaggedStackInterpreter) {
+ tag_offset = Interpreter::tag_offset_in_bytes() - Interpreter::value_offset_in_bytes();
+ assert(tag_offset = wordSize, "stack grows as expected");
+ }
+
+ if (have_entry(ek)) {
+ __ nop(); // empty stubs make SG sick
+ return;
+ }
+
+ address interp_entry = __ pc();
+ if (UseCompressedOops) __ unimplemented("UseCompressedOops");
+
+#ifndef PRODUCT
+ if (TraceMethodHandles) {
+ __ push(rax); __ push(rbx); __ push(rcx); __ push(rdx); __ push(rsi); __ push(rdi);
+ __ lea(rax, Address(rsp, wordSize*6)); // entry_sp
+ // arguments:
+ __ push(rsi); // saved_sp
+ __ push(rax); // entry_sp
+ __ push(rcx); // mh
+ __ push(rcx);
+ __ movptr(Address(rsp, 0), (intptr_t)entry_name(ek));
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub), 4);
+ __ pop(rdi); __ pop(rsi); __ pop(rdx); __ pop(rcx); __ pop(rbx); __ pop(rax);
+ }
+#endif //PRODUCT
+
+ switch ((int) ek) {
+ case _check_mtype:
+ {
+ // this stub is special, because it requires a live mtype argument
+ Register rax_mtype = rax;
+
+ // emit WrongMethodType path first, to enable jccb back-branch
+ Label wrong_method_type;
+ __ bind(wrong_method_type);
+ __ movptr(rdx_temp, ExternalAddress((address) &_entries[_wrong_method_type]));
+ __ jmp(Address(rdx_temp, MethodHandleEntry::from_interpreted_entry_offset_in_bytes()));
+ __ hlt();
+
+ interp_entry = __ pc();
+ __ check_method_handle_type(rax_mtype, rcx_recv, rdx_temp, wrong_method_type);
+ // now rax_mtype is dead; subsequent stubs will use it as a temp
+
+ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+ }
+ break;
+
+ case _wrong_method_type:
+ {
+ // this stub is special, because it requires a live mtype argument
+ Register rax_mtype = rax;
+
+ interp_entry = __ pc();
+ __ push(rax_mtype); // required mtype
+ __ push(rcx_recv); // random mh (1st stacked argument)
+ __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
+ }
+ break;
+
+ case _invokestatic_mh:
+ case _invokespecial_mh:
+ {
+ Register rbx_method = rbx_temp;
+ __ movptr(rbx_method, rcx_mh_vmtarget); // target is a methodOop
+ __ 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.
+ __ load_method_handle_vmslots(rax_argslot, rcx_recv, rdx_temp);
+ __ movptr(rcx_recv, __ argument_address(rax_argslot, -1));
+ __ null_check(rcx_recv);
+ __ verify_oop(rcx_recv);
+ }
+ __ jmp(rbx_method_fie);
+ }
+ 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:
+ __ load_method_handle_vmslots(rax_argslot, rcx_recv, rdx_temp);
+ Register rbx_index = rbx_temp;
+ __ movl(rbx_index, rcx_dmh_vmindex);
+ // Note: The verifier allows us to ignore rcx_mh_vmtarget.
+ __ movptr(rcx_recv, __ argument_address(rax_argslot, -1));
+ __ null_check(rcx_recv, oopDesc::klass_offset_in_bytes());
+
+ // get receiver klass
+ Register rax_klass = rax_argslot;
+ __ load_klass(rax_klass, rcx_recv);
+ __ verify_oop(rax_klass);
+
+ // get target methodOop & entry point
+ const int base = instanceKlass::vtable_start_offset() * wordSize;
+ assert(vtableEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
+ Address vtable_entry_addr(rax_klass,
+ rbx_index, Address::times_ptr,
+ base + vtableEntry::method_offset_in_bytes());
+ Register rbx_method = rbx_temp;
+ __ movl(rbx_method, vtable_entry_addr);
+
+ __ verify_oop(rbx_method);
+ __ jmp(rbx_method_fie);
+ }
+ break;
+
+ case _invokeinterface_mh:
+ {
+ // same as TemplateTable::invokeinterface,
+ // minus the CP setup and profiling:
+
+ // pick out the interface and itable index from the MH.
+ __ load_method_handle_vmslots(rax_argslot, rcx_recv, rdx_temp);
+ Register rdx_intf = rdx_temp;
+ Register rbx_index = rbx_temp;
+ __ movptr(rdx_intf, rcx_mh_vmtarget);
+ __ movl(rbx_index, rcx_dmh_vmindex);
+ __ movptr(rcx_recv, __ argument_address(rax_argslot, -1));
+ __ null_check(rcx_recv, oopDesc::klass_offset_in_bytes());
+
+ // get receiver klass
+ Register rax_klass = rax_argslot;
+ __ load_klass(rax_klass, rcx_recv);
+ __ verify_oop(rax_klass);
+
+ Register rcx_temp = rcx_recv;
+ Register rbx_method = rbx_index;
+
+ // get interface klass
+ Label no_such_interface;
+ __ verify_oop(rdx_intf);
+ __ lookup_interface_method(rax_klass, rdx_intf,
+ // note: next two args must be the same:
+ rbx_index, rbx_method,
+ rcx_temp,
+ no_such_interface);
+
+ __ verify_oop(rbx_method);
+ __ jmp(rbx_method_fie);
+ __ hlt();
+
+ __ bind(no_such_interface);
+ // Throw an exception.
+ // For historical reasons, it will be IncompatibleClassChangeError.
+ __ should_not_reach_here(); // %%% FIXME NYI
+ }
+ break;
+
+ case _bound_ref_mh:
+ case _bound_int_mh:
+ case _bound_long_mh:
+ case _bound_ref_direct_mh:
+ case _bound_int_direct_mh:
+ case _bound_long_direct_mh:
+ {
+ bool direct_to_method = (ek >= _bound_ref_direct_mh);
+ BasicType arg_type = T_ILLEGAL;
+ if (ek == _bound_long_mh || ek == _bound_long_direct_mh) {
+ arg_type = T_LONG;
+ } else if (ek == _bound_int_mh || ek == _bound_int_direct_mh) {
+ arg_type = T_INT;
+ } else {
+ assert(ek == _bound_ref_mh || ek == _bound_ref_direct_mh, "must be ref");
+ arg_type = T_OBJECT;
+ }
+ int arg_slots = type2size[arg_type];
+ int arg_mask = (arg_type == T_OBJECT ? _INSERT_REF_MASK :
+ arg_slots == 1 ? _INSERT_INT_MASK : _INSERT_LONG_MASK);
+
+ // make room for the new argument:
+ __ movl(rax_argslot, rcx_bmh_vmargslot);
+ __ lea(rax_argslot, __ argument_address(rax_argslot));
+ insert_arg_slots(_masm, arg_slots * stack_move_unit(), arg_mask,
+ rax_argslot, rbx_temp, rdx_temp);
+
+ // store bound argument into the new stack slot:
+ __ movptr(rbx_temp, rcx_bmh_argument);
+ Address prim_value_addr(rbx_temp, java_lang_boxing_object::value_offset_in_bytes(arg_type));
+ if (arg_type == T_OBJECT) {
+ __ movptr(Address(rax_argslot, 0), rbx_temp);
+ } else {
+ __ load_sized_value(rbx_temp, prim_value_addr,
+ type2aelembytes(arg_type), is_signed_subword_type(arg_type));
+ __ movptr(Address(rax_argslot, 0), rbx_temp);
+#ifndef _LP64
+ if (arg_slots == 2) {
+ __ movl(rbx_temp, prim_value_addr.plus_disp(wordSize));
+ __ movl(Address(rax_argslot, Interpreter::stackElementSize()), rbx_temp);
+ }
+#endif //_LP64
+ break;
+ }
+
+ if (direct_to_method) {
+ Register rbx_method = rbx_temp;
+ __ movptr(rbx_method, rcx_mh_vmtarget);
+ __ verify_oop(rbx_method);
+ __ jmp(rbx_method_fie);
+ } else {
+ __ movptr(rcx_recv, rcx_mh_vmtarget);
+ __ verify_oop(rcx_recv);
+ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+ }
+ }
+ break;
+
+ case _adapter_retype_only:
+ // immediately jump to the next MH layer:
+ __ movptr(rcx_recv, rcx_mh_vmtarget);
+ __ verify_oop(rcx_recv);
+ __ 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.
+ break;
+
+ case _adapter_check_cast:
+ {
+ // temps:
+ Register rbx_klass = rbx_temp; // interesting AMH data
+
+ // check a reference argument before jumping to the next layer of MH:
+ __ movl(rax_argslot, rcx_amh_vmargslot);
+ vmarg = __ argument_address(rax_argslot);
+
+ // What class are we casting to?
+ __ movptr(rbx_klass, rcx_amh_argument); // this is a Class object!
+ __ movptr(rbx_klass, Address(rbx_klass, java_lang_Class::klass_offset_in_bytes()));
+
+ // get the new MH:
+ __ movptr(rcx_recv, rcx_mh_vmtarget);
+ // (now we are done with the old MH)
+
+ Label done;
+ __ movptr(rdx_temp, vmarg);
+ __ testl(rdx_temp, rdx_temp);
+ __ jcc(Assembler::zero, done); // no cast if null
+ __ load_klass(rdx_temp, rdx_temp);
+
+ // live at this point:
+ // - rbx_klass: klass required by the target method
+ // - rdx_temp: argument klass to test
+ // - rcx_recv: method handle to invoke (after cast succeeds)
+ __ check_klass_subtype(rdx_temp, rbx_klass, rax_argslot, done);
+
+ // If we get here, the type check failed!
+ // Call the wrong_method_type stub, passing the failing argument type in rax.
+ Register rax_mtype = rax_argslot;
+ __ push(rbx_klass); // missed klass (required type)
+ __ push(rdx_temp); // bad actual type (1st stacked argument)
+ __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
+
+ __ bind(done);
+ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+ }
+ break;
+
+ case _adapter_prim_to_prim:
+ case _adapter_ref_to_prim:
+ // handled completely by optimized cases
+ __ stop("init_AdapterMethodHandle should not issue this");
+ break;
+
+ case _adapter_opt_i2i: // optimized subcase of adapt_prim_to_prim
+//case _adapter_opt_f2i: // optimized subcase of adapt_prim_to_prim
+ case _adapter_opt_l2i: // optimized subcase of adapt_prim_to_prim
+ case _adapter_opt_unboxi: // optimized subcase of adapt_ref_to_prim
+ {
+ // perform an in-place conversion to int or an int subword
+ __ movl(rax_argslot, rcx_amh_vmargslot);
+ vmarg = __ argument_address(rax_argslot);
+
+ switch (ek) {
+ case _adapter_opt_i2i:
+ __ movl(rdx_temp, vmarg);
+ break;
+ case _adapter_opt_l2i:
+ {
+ // just delete the extra slot; on a little-endian machine we keep the first
+ __ lea(rax_argslot, __ argument_address(rax_argslot, 1));
+ remove_arg_slots(_masm, -stack_move_unit(),
+ rax_argslot, rbx_temp, rdx_temp);
+ vmarg = Address(rax_argslot, -Interpreter::stackElementSize());
+ __ movl(rdx_temp, vmarg);
+ }
+ break;
+ case _adapter_opt_unboxi:
+ {
+ // Load the value up from the heap.
+ __ movptr(rdx_temp, vmarg);
+ int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_INT);
+#ifdef ASSERT
+ for (int bt = T_BOOLEAN; bt < T_INT; bt++) {
+ if (is_subword_type(BasicType(bt)))
+ assert(value_offset == java_lang_boxing_object::value_offset_in_bytes(BasicType(bt)), "");
+ }
+#endif
+ __ null_check(rdx_temp, value_offset);
+ __ movl(rdx_temp, Address(rdx_temp, value_offset));
+ // We load this as a word. Because we are little-endian,
+ // the low bits will be correct, but the high bits may need cleaning.
+ // The vminfo will guide us to clean those bits.
+ }
+ break;
+ default:
+ assert(false, "");
+ }
+ goto finish_int_conversion;
+ }
+
+ finish_int_conversion:
+ {
+ Register rbx_vminfo = rbx_temp;
+ __ movl(rbx_vminfo, rcx_amh_conversion);
+ assert(CONV_VMINFO_SHIFT == 0, "preshifted");
+
+ // get the new MH:
+ __ movptr(rcx_recv, rcx_mh_vmtarget);
+ // (now we are done with the old MH)
+
+ // original 32-bit vmdata word must be of this form:
+ // | MBZ:16 | signBitCount:8 | srcDstTypes:8 | conversionOp:8 |
+ __ xchgl(rcx, rbx_vminfo); // free rcx for shifts
+ __ shll(rdx_temp /*, rcx*/);
+ Label zero_extend, done;
+ __ testl(rcx, CONV_VMINFO_SIGN_FLAG);
+ __ jcc(Assembler::zero, zero_extend);
+
+ // this path is taken for int->byte, int->short
+ __ sarl(rdx_temp /*, rcx*/);
+ __ jmp(done);
+
+ __ bind(zero_extend);
+ // this is taken for int->char
+ __ shrl(rdx_temp /*, rcx*/);
+
+ __ bind(done);
+ __ movptr(vmarg, rdx_temp);
+ __ xchgl(rcx, rbx_vminfo); // restore rcx_recv
+
+ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+ }
+ break;
+
+ case _adapter_opt_i2l: // optimized subcase of adapt_prim_to_prim
+ case _adapter_opt_unboxl: // optimized subcase of adapt_ref_to_prim
+ {
+ // perform an in-place int-to-long or ref-to-long conversion
+ __ movl(rax_argslot, rcx_amh_vmargslot);
+
+ // on a little-endian machine we keep the first slot and add another after
+ __ lea(rax_argslot, __ argument_address(rax_argslot, 1));
+ insert_arg_slots(_masm, stack_move_unit(), _INSERT_INT_MASK,
+ rax_argslot, rbx_temp, rdx_temp);
+ Address vmarg1(rax_argslot, -Interpreter::stackElementSize());
+ Address vmarg2 = vmarg1.plus_disp(Interpreter::stackElementSize());
+
+ switch (ek) {
+ case _adapter_opt_i2l:
+ {
+ __ movl(rdx_temp, vmarg1);
+ __ sarl(rdx_temp, 31); // __ extend_sign()
+ __ movl(vmarg2, rdx_temp); // store second word
+ }
+ break;
+ case _adapter_opt_unboxl:
+ {
+ // Load the value up from the heap.
+ __ movptr(rdx_temp, vmarg1);
+ int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_LONG);
+ assert(value_offset == java_lang_boxing_object::value_offset_in_bytes(T_DOUBLE), "");
+ __ null_check(rdx_temp, value_offset);
+ __ movl(rbx_temp, Address(rdx_temp, value_offset + 0*BytesPerInt));
+ __ movl(rdx_temp, Address(rdx_temp, value_offset + 1*BytesPerInt));
+ __ movl(vmarg1, rbx_temp);
+ __ movl(vmarg2, rdx_temp);
+ }
+ break;
+ default:
+ assert(false, "");
+ }
+
+ __ movptr(rcx_recv, rcx_mh_vmtarget);
+ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+ }
+ break;
+
+ case _adapter_opt_f2d: // optimized subcase of adapt_prim_to_prim
+ case _adapter_opt_d2f: // optimized subcase of adapt_prim_to_prim
+ {
+ // perform an in-place floating primitive conversion
+ __ movl(rax_argslot, rcx_amh_vmargslot);
+ __ lea(rax_argslot, __ argument_address(rax_argslot, 1));
+ if (ek == _adapter_opt_f2d) {
+ insert_arg_slots(_masm, stack_move_unit(), _INSERT_INT_MASK,
+ rax_argslot, rbx_temp, rdx_temp);
+ }
+ Address vmarg(rax_argslot, -Interpreter::stackElementSize());
+
+#ifdef _LP64
+ if (ek == _adapter_opt_f2d) {
+ __ movflt(xmm0, vmarg);
+ __ cvtss2sd(xmm0, xmm0);
+ __ movdbl(vmarg, xmm0);
+ } else {
+ __ movdbl(xmm0, vmarg);
+ __ cvtsd2ss(xmm0, xmm0);
+ __ movflt(vmarg, xmm0);
+ }
+#else //_LP64
+ if (ek == _adapter_opt_f2d) {
+ __ fld_s(vmarg); // load float to ST0
+ __ fstp_s(vmarg); // store single
+ } else if (!TaggedStackInterpreter) {
+ __ fld_d(vmarg); // load double to ST0
+ __ fstp_s(vmarg); // store single
+ } else {
+ Address vmarg_tag = vmarg.plus_disp(tag_offset);
+ Address vmarg2 = vmarg.plus_disp(Interpreter::stackElementSize());
+ // vmarg2_tag does not participate in this code
+ Register rbx_tag = rbx_temp;
+ __ movl(rbx_tag, vmarg_tag); // preserve tag
+ __ movl(rdx_temp, vmarg2); // get second word of double
+ __ movl(vmarg_tag, rdx_temp); // align with first word
+ __ fld_d(vmarg); // load double to ST0
+ __ movl(vmarg_tag, rbx_tag); // restore tag
+ __ fstp_s(vmarg); // store single
+ }
+#endif //_LP64
+
+ if (ek == _adapter_opt_d2f) {
+ remove_arg_slots(_masm, -stack_move_unit(),
+ rax_argslot, rbx_temp, rdx_temp);
+ }
+
+ __ movptr(rcx_recv, rcx_mh_vmtarget);
+ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+ }
+ break;
+
+ case _adapter_prim_to_ref:
+ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
+ break;
+
+ case _adapter_swap_args:
+ case _adapter_rot_args:
+ // handled completely by optimized cases
+ __ stop("init_AdapterMethodHandle should not issue this");
+ break;
+
+ case _adapter_opt_swap_1:
+ case _adapter_opt_swap_2:
+ case _adapter_opt_rot_1_up:
+ case _adapter_opt_rot_1_down:
+ case _adapter_opt_rot_2_up:
+ case _adapter_opt_rot_2_down:
+ {
+ int rotate = 0, swap_slots = 0;
+ switch ((int)ek) {
+ case _adapter_opt_swap_1: swap_slots = 1; break;
+ case _adapter_opt_swap_2: swap_slots = 2; break;
+ case _adapter_opt_rot_1_up: swap_slots = 1; rotate++; break;
+ case _adapter_opt_rot_1_down: swap_slots = 1; rotate--; break;
+ case _adapter_opt_rot_2_up: swap_slots = 2; rotate++; break;
+ case _adapter_opt_rot_2_down: swap_slots = 2; rotate--; break;
+ default: assert(false, "");
+ }
+
+ // the real size of the move must be doubled if TaggedStackInterpreter:
+ int swap_bytes = (int)( swap_slots * Interpreter::stackElementWords() * wordSize );
+
+ // 'argslot' is the position of the first argument to swap
+ __ movl(rax_argslot, rcx_amh_vmargslot);
+ __ lea(rax_argslot, __ argument_address(rax_argslot));
+
+ // 'vminfo' is the second
+ Register rbx_destslot = rbx_temp;
+ __ movl(rbx_destslot, rcx_amh_conversion);
+ assert(CONV_VMINFO_SHIFT == 0, "preshifted");
+ __ andl(rbx_destslot, CONV_VMINFO_MASK);
+ __ lea(rbx_destslot, __ argument_address(rbx_destslot));
+ DEBUG_ONLY(verify_argslot(_masm, rbx_destslot, "swap point must fall within current frame"));
+
+ if (!rotate) {
+ for (int i = 0; i < swap_bytes; i += wordSize) {
+ __ movptr(rdx_temp, Address(rax_argslot , i));
+ __ push(rdx_temp);
+ __ movptr(rdx_temp, Address(rbx_destslot, i));
+ __ movptr(Address(rax_argslot, i), rdx_temp);
+ __ pop(rdx_temp);
+ __ movptr(Address(rbx_destslot, i), rdx_temp);
+ }
+ } else {
+ // push the first chunk, which is going to get overwritten
+ for (int i = swap_bytes; (i -= wordSize) >= 0; ) {
+ __ movptr(rdx_temp, Address(rax_argslot, i));
+ __ push(rdx_temp);
+ }
+
+ if (rotate > 0) {
+ // rotate upward
+ __ subptr(rax_argslot, swap_bytes);
+#ifdef ASSERT
+ {
+ // Verify that argslot > destslot, by at least swap_bytes.
+ Label L_ok;
+ __ cmpptr(rax_argslot, rbx_destslot);
+ __ jcc(Assembler::aboveEqual, L_ok);
+ __ stop("source must be above destination (upward rotation)");
+ __ bind(L_ok);
+ }
+#endif
+ // work argslot down to destslot, copying contiguous data upwards
+ // pseudo-code:
+ // rax = src_addr - swap_bytes
+ // rbx = dest_addr
+ // while (rax >= rbx) *(rax + swap_bytes) = *(rax + 0), rax--;
+ Label loop;
+ __ bind(loop);
+ __ movptr(rdx_temp, Address(rax_argslot, 0));
+ __ movptr(Address(rax_argslot, swap_bytes), rdx_temp);
+ __ addptr(rax_argslot, -wordSize);
+ __ cmpptr(rax_argslot, rbx_destslot);
+ __ jcc(Assembler::aboveEqual, loop);
+ } else {
+ __ addptr(rax_argslot, swap_bytes);
+#ifdef ASSERT
+ {
+ // Verify that argslot < destslot, by at least swap_bytes.
+ Label L_ok;
+ __ cmpptr(rax_argslot, rbx_destslot);
+ __ jcc(Assembler::belowEqual, L_ok);
+ __ stop("source must be below destination (downward rotation)");
+ __ bind(L_ok);
+ }
+#endif
+ // work argslot up to destslot, copying contiguous data downwards
+ // pseudo-code:
+ // rax = src_addr + swap_bytes
+ // rbx = dest_addr
+ // while (rax <= rbx) *(rax - swap_bytes) = *(rax + 0), rax++;
+ Label loop;
+ __ bind(loop);
+ __ movptr(rdx_temp, Address(rax_argslot, 0));
+ __ movptr(Address(rax_argslot, -swap_bytes), rdx_temp);
+ __ addptr(rax_argslot, wordSize);
+ __ cmpptr(rax_argslot, rbx_destslot);
+ __ jcc(Assembler::belowEqual, loop);
+ }
+
+ // pop the original first chunk into the destination slot, now free
+ for (int i = 0; i < swap_bytes; i += wordSize) {
+ __ pop(rdx_temp);
+ __ movptr(Address(rbx_destslot, i), rdx_temp);
+ }
+ }
+
+ __ movptr(rcx_recv, rcx_mh_vmtarget);
+ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+ }
+ break;
+
+ case _adapter_dup_args:
+ {
+ // 'argslot' is the position of the first argument to duplicate
+ __ movl(rax_argslot, rcx_amh_vmargslot);
+ __ lea(rax_argslot, __ argument_address(rax_argslot));
+
+ // 'stack_move' is negative number of words to duplicate
+ Register rdx_stack_move = rdx_temp;
+ __ movl(rdx_stack_move, rcx_amh_conversion);
+ __ sarl(rdx_stack_move, CONV_STACK_MOVE_SHIFT);
+
+ int argslot0_num = 0;
+ Address argslot0 = __ argument_address(RegisterOrConstant(argslot0_num));
+ assert(argslot0.base() == rsp, "");
+ int pre_arg_size = argslot0.disp();
+ assert(pre_arg_size % wordSize == 0, "");
+ assert(pre_arg_size > 0, "must include PC");
+
+ // remember the old rsp+1 (argslot[0])
+ Register rbx_oldarg = rbx_temp;
+ __ lea(rbx_oldarg, argslot0);
+
+ // move rsp down to make room for dups
+ __ lea(rsp, Address(rsp, rdx_stack_move, Address::times_ptr));
+
+ // compute the new rsp+1 (argslot[0])
+ Register rdx_newarg = rdx_temp;
+ __ lea(rdx_newarg, argslot0);
+
+ __ push(rdi); // need a temp
+ // (preceding push must be done after arg addresses are taken!)
+
+ // pull down the pre_arg_size data (PC)
+ for (int i = -pre_arg_size; i < 0; i += wordSize) {
+ __ movptr(rdi, Address(rbx_oldarg, i));
+ __ movptr(Address(rdx_newarg, i), rdi);
+ }
+
+ // copy from rax_argslot[0...] down to new_rsp[1...]
+ // pseudo-code:
+ // rbx = old_rsp+1
+ // rdx = new_rsp+1
+ // rax = argslot
+ // while (rdx < rbx) *rdx++ = *rax++
+ Label loop;
+ __ bind(loop);
+ __ movptr(rdi, Address(rax_argslot, 0));
+ __ movptr(Address(rdx_newarg, 0), rdi);
+ __ addptr(rax_argslot, wordSize);
+ __ addptr(rdx_newarg, wordSize);
+ __ cmpptr(rdx_newarg, rbx_oldarg);
+ __ jcc(Assembler::less, loop);
+
+ __ pop(rdi); // restore temp
+
+ __ movptr(rcx_recv, rcx_mh_vmtarget);
+ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+ }
+ break;
+
+ case _adapter_drop_args:
+ {
+ // 'argslot' is the position of the first argument to nuke
+ __ movl(rax_argslot, rcx_amh_vmargslot);
+ __ lea(rax_argslot, __ argument_address(rax_argslot));
+
+ __ push(rdi); // need a temp
+ // (must do previous push after argslot address is taken)
+
+ // 'stack_move' is number of words to drop
+ Register rdi_stack_move = rdi;
+ __ movl(rdi_stack_move, rcx_amh_conversion);
+ __ sarl(rdi_stack_move, CONV_STACK_MOVE_SHIFT);
+ remove_arg_slots(_masm, rdi_stack_move,
+ rax_argslot, rbx_temp, rdx_temp);
+
+ __ pop(rdi); // restore temp
+
+ __ movptr(rcx_recv, rcx_mh_vmtarget);
+ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+ }
+ break;
+
+ case _adapter_collect_args:
+ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
+ break;
+
+ case _adapter_spread_args:
+ // handled completely by optimized cases
+ __ stop("init_AdapterMethodHandle should not issue this");
+ break;
+
+ case _adapter_opt_spread_0:
+ case _adapter_opt_spread_1:
+ case _adapter_opt_spread_more:
+ {
+ // spread an array out into a group of arguments
+ int length_constant = -1;
+ switch (ek) {
+ case _adapter_opt_spread_0: length_constant = 0; break;
+ case _adapter_opt_spread_1: length_constant = 1; break;
+ }
+
+ // find the address of the array argument
+ __ movl(rax_argslot, rcx_amh_vmargslot);
+ __ lea(rax_argslot, __ argument_address(rax_argslot));
+
+ // grab some temps
+ { __ push(rsi); __ push(rdi); }
+ // (preceding pushes must be done after argslot address is taken!)
+#define UNPUSH_RSI_RDI \
+ { __ pop(rdi); __ pop(rsi); }
+
+ // arx_argslot points both to the array and to the first output arg
+ vmarg = Address(rax_argslot, 0);
+
+ // Get the array value.
+ Register rsi_array = rsi;
+ Register rdx_array_klass = rdx_temp;
+ BasicType elem_type = T_OBJECT;
+ int length_offset = arrayOopDesc::length_offset_in_bytes();
+ int elem0_offset = arrayOopDesc::base_offset_in_bytes(elem_type);
+ __ movptr(rsi_array, vmarg);
+ Label skip_array_check;
+ if (length_constant == 0) {
+ __ testptr(rsi_array, rsi_array);
+ __ jcc(Assembler::zero, skip_array_check);
+ }
+ __ null_check(rsi_array, oopDesc::klass_offset_in_bytes());
+ __ load_klass(rdx_array_klass, rsi_array);
+
+ // Check the array type.
+ Register rbx_klass = rbx_temp;
+ __ movptr(rbx_klass, rcx_amh_argument); // this is a Class object!
+ __ movptr(rbx_klass, Address(rbx_klass, java_lang_Class::klass_offset_in_bytes()));
+
+ Label ok_array_klass, bad_array_klass, bad_array_length;
+ __ check_klass_subtype(rdx_array_klass, rbx_klass, rdi, ok_array_klass);
+ // If we get here, the type check failed!
+ __ jmp(bad_array_klass);
+ __ bind(ok_array_klass);
+
+ // Check length.
+ if (length_constant >= 0) {
+ __ cmpl(Address(rsi_array, length_offset), length_constant);
+ } else {
+ Register rbx_vminfo = rbx_temp;
+ __ movl(rbx_vminfo, rcx_amh_conversion);
+ assert(CONV_VMINFO_SHIFT == 0, "preshifted");
+ __ andl(rbx_vminfo, CONV_VMINFO_MASK);
+ __ cmpl(rbx_vminfo, Address(rsi_array, length_offset));
+ }
+ __ jcc(Assembler::notEqual, bad_array_length);
+
+ Register rdx_argslot_limit = rdx_temp;
+
+ // Array length checks out. Now insert any required stack slots.
+ if (length_constant == -1) {
+ // Form a pointer to the end of the affected region.
+ __ lea(rdx_argslot_limit, Address(rax_argslot, Interpreter::stackElementSize()));
+ // 'stack_move' is negative number of words to insert
+ Register rdi_stack_move = rdi;
+ __ movl(rdi_stack_move, rcx_amh_conversion);
+ __ sarl(rdi_stack_move, CONV_STACK_MOVE_SHIFT);
+ Register rsi_temp = rsi_array; // spill this
+ insert_arg_slots(_masm, rdi_stack_move, -1,
+ rax_argslot, rbx_temp, rsi_temp);
+ // reload the array (since rsi was killed)
+ __ movptr(rsi_array, vmarg);
+ } else if (length_constant > 1) {
+ int arg_mask = 0;
+ int new_slots = (length_constant - 1);
+ for (int i = 0; i < new_slots; i++) {
+ arg_mask <<= 1;
+ arg_mask |= _INSERT_REF_MASK;
+ }
+ insert_arg_slots(_masm, new_slots * stack_move_unit(), arg_mask,
+ rax_argslot, rbx_temp, rdx_temp);
+ } else if (length_constant == 1) {
+ // no stack resizing required
+ } else if (length_constant == 0) {
+ remove_arg_slots(_masm, -stack_move_unit(),
+ rax_argslot, rbx_temp, rdx_temp);
+ }
+
+ // Copy from the array to the new slots.
+ // Note: Stack change code preserves integrity of rax_argslot pointer.
+ // So even after slot insertions, rax_argslot still points to first argument.
+ if (length_constant == -1) {
+ // [rax_argslot, rdx_argslot_limit) is the area we are inserting into.
+ Register rsi_source = rsi_array;
+ __ lea(rsi_source, Address(rsi_array, elem0_offset));
+ Label loop;
+ __ bind(loop);
+ __ movptr(rbx_temp, Address(rsi_source, 0));
+ __ movptr(Address(rax_argslot, 0), rbx_temp);
+ __ addptr(rsi_source, type2aelembytes(elem_type));
+ if (TaggedStackInterpreter) {
+ __ movptr(Address(rax_argslot, tag_offset),
+ frame::tag_for_basic_type(elem_type));
+ }
+ __ addptr(rax_argslot, Interpreter::stackElementSize());
+ __ cmpptr(rax_argslot, rdx_argslot_limit);
+ __ jcc(Assembler::less, loop);
+ } else if (length_constant == 0) {
+ __ bind(skip_array_check);
+ // nothing to copy
+ } else {
+ int elem_offset = elem0_offset;
+ int slot_offset = 0;
+ for (int index = 0; index < length_constant; index++) {
+ __ movptr(rbx_temp, Address(rsi_array, elem_offset));
+ __ movptr(Address(rax_argslot, slot_offset), rbx_temp);
+ elem_offset += type2aelembytes(elem_type);
+ if (TaggedStackInterpreter) {
+ __ movptr(Address(rax_argslot, slot_offset + tag_offset),
+ frame::tag_for_basic_type(elem_type));
+ }
+ slot_offset += Interpreter::stackElementSize();
+ }
+ }
+
+ // Arguments are spread. Move to next method handle.
+ UNPUSH_RSI_RDI;
+ __ movptr(rcx_recv, rcx_mh_vmtarget);
+ __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+
+ __ bind(bad_array_klass);
+ UNPUSH_RSI_RDI;
+ __ stop("bad array klass NYI");
+
+ __ bind(bad_array_length);
+ UNPUSH_RSI_RDI;
+ __ stop("bad array length NYI");
+
+#undef UNPUSH_RSI_RDI
+ }
+ break;
+
+ case _adapter_flyby:
+ case _adapter_ricochet:
+ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
+ break;
+
+ default: ShouldNotReachHere();
+ }
+ __ hlt();
+
+ address me_cookie = MethodHandleEntry::start_compiled_entry(_masm, interp_entry);
+ __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
+
+ init_entry(ek, MethodHandleEntry::finish_compiled_entry(_masm, me_cookie));
+}
diff --git a/src/cpu/x86/vm/stubGenerator_x86_32.cpp b/src/cpu/x86/vm/stubGenerator_x86_32.cpp
index aca937780..e38fc1d0f 100644
--- a/src/cpu/x86/vm/stubGenerator_x86_32.cpp
+++ b/src/cpu/x86/vm/stubGenerator_x86_32.cpp
@@ -2219,6 +2219,16 @@ class StubGenerator: public StubCodeGenerator {
// arraycopy stubs used by compilers
generate_arraycopy_stubs();
+
+ // generic method handle stubs
+ if (EnableMethodHandles && SystemDictionary::MethodHandle_klass() != NULL) {
+ for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST;
+ ek < MethodHandles::_EK_LIMIT;
+ ek = MethodHandles::EntryKind(1 + (int)ek)) {
+ StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
+ MethodHandles::generate_method_handle_stub(_masm, ek);
+ }
+ }
}
diff --git a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
index 8d94671e6..5769873dc 100644
--- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
+++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
@@ -92,6 +92,33 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
return entry;
}
+// Arguments are: required type at TOS+8, failing object (or NULL) at TOS+4.
+// pc at TOS (just for debugging)
+address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
+ address entry = __ pc();
+
+ __ pop(rbx); // actual failing object is at TOS
+ __ pop(rax); // required type is at TOS+4
+
+ __ verify_oop(rbx);
+ __ verify_oop(rax);
+
+ // Various method handle types use interpreter registers as temps.
+ __ restore_bcp();
+ __ restore_locals();
+
+ // Expression stack must be empty before entering the VM for an exception.
+ __ empty_expression_stack();
+ __ empty_FPU_stack();
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::throw_WrongMethodTypeException),
+ // pass required type, failing object (or NULL)
+ rax, rbx);
+ return entry;
+}
+
+
address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) {
assert(!pass_oop || message == NULL, "either oop or message but not both");
address entry = __ pc();
@@ -1370,6 +1397,7 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter:
case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break;
case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break;
case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break;
+ case Interpreter::method_handle : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
case Interpreter::java_lang_math_sin : // fall thru
case Interpreter::java_lang_math_cos : // fall thru
@@ -1400,7 +1428,8 @@ int AbstractInterpreter::size_top_interpreter_activation(methodOop method) {
// be sure to change this if you add/subtract anything to/from the overhead area
const int overhead_size = -frame::interpreter_frame_initial_sp_offset;
- const int method_stack = (method->max_locals() + method->max_stack()) *
+ const int extra_stack = methodOopDesc::extra_stack_entries();
+ const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) *
Interpreter::stackElementWords();
return overhead_size + method_stack + stub_code;
}
diff --git a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
index ec7712760..cd9d08915 100644
--- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
+++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -100,6 +100,26 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
return entry;
}
+// Arguments are: required type in rarg1, failing object (or NULL) in rarg2
+address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
+ address entry = __ pc();
+
+ __ pop(c_rarg2); // failing object is at TOS
+ __ pop(c_rarg1); // required type is at TOS+8
+
+ // expression stack must be empty before entering the VM if an
+ // exception happened
+ __ empty_expression_stack();
+
+ __ call_VM(noreg,
+ CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::
+ throw_WrongMethodTypeException),
+ // pass required type, failing object (or NULL)
+ c_rarg1, c_rarg2);
+ return entry;
+}
+
address TemplateInterpreterGenerator::generate_exception_handler_common(
const char* name, const char* message, bool pass_oop) {
assert(!pass_oop || message == NULL, "either oop or message but not both");
@@ -1393,6 +1413,7 @@ address AbstractInterpreterGenerator::generate_method_entry(
case Interpreter::empty : entry_point = ((InterpreterGenerator*) this)->generate_empty_entry(); break;
case Interpreter::accessor : entry_point = ((InterpreterGenerator*) this)->generate_accessor_entry(); break;
case Interpreter::abstract : entry_point = ((InterpreterGenerator*) this)->generate_abstract_entry(); break;
+ case Interpreter::method_handle : entry_point = ((InterpreterGenerator*) this)->generate_method_handle_entry();break;
case Interpreter::java_lang_math_sin : // fall thru
case Interpreter::java_lang_math_cos : // fall thru
@@ -1423,7 +1444,8 @@ int AbstractInterpreter::size_top_interpreter_activation(methodOop method) {
-(frame::interpreter_frame_initial_sp_offset) + entry_size;
const int stub_code = frame::entry_frame_after_call_words;
- const int method_stack = (method->max_locals() + method->max_stack()) *
+ const int extra_stack = methodOopDesc::extra_stack_entries();
+ const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) *
Interpreter::stackElementWords();
return (overhead_size + method_stack + stub_code);
}