--- a/tailc.patch Tue May 26 18:07:34 2009 -0700
+++ b/tailc.patch Tue Jun 02 23:41:37 2009 -0700
@@ -1,13 +1,40 @@ diff --git a/src/cpu/x86/vm/assembler_x8
-diff --git a/src/cpu/x86/vm/assembler_x86.cpp b/src/cpu/x86/vm/assembler_x86.cpp
---- a/src/cpu/x86/vm/assembler_x86.cpp
-+++ b/src/cpu/x86/vm/assembler_x86.cpp
-@@ -3276,6 +3276,16 @@
+diff -r ce2272390558 src/cpu/sparc/vm/sparc.ad
+--- a/src/cpu/sparc/vm/sparc.ad Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/sparc/vm/sparc.ad Mon Mar 16 11:44:02 2009 +0100
+@@ -1559,7 +1559,7 @@ void emit_java_to_interp(CodeBuffer &cbu
+ // jmp -1
+
+ address mark = cbuf.inst_mark(); // get mark within main instrs section
+-
++ tty->print_cr("java_to_interp "INTPTR_FORMAT, mark);
+ MacroAssembler _masm(&cbuf);
+
+ address base =
+diff -r ce2272390558 src/cpu/x86/vm/assembler_x86.cpp
+--- a/src/cpu/x86/vm/assembler_x86.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/assembler_x86.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -1342,6 +1342,15 @@ void Assembler::jmp(Address adr) {
+ emit_byte(0xFF);
+ emit_operand(rsp, adr);
+ }
++// Tail call.
++void Assembler::mov_label(Address dst, Label& L, relocInfo::relocType rtype) {
++ InstructionMark im(this);
++ L.add_patch_at(code(), locator());
++ assert(is8bit(dst.disp()), "Assume 8bit immediate in pd_patch_instruction");
++ emit_byte(0xC7);
++ emit_operand(rax, dst, 4);
++ emit_data(0, rtype, 0);
++}
+
+ void Assembler::jmp(Label& L, relocInfo::relocType rtype) {
+ if (L.is_bound()) {
+@@ -3276,6 +3285,15 @@ void Assembler::shrdl(Register dst, Regi
emit_byte(0xC0 | src->encoding() << 3 | dst->encoding());
}
-+
-+void MacroAssembler::parent_is_not_interpreter_jcc(Register temp, Label& is_not_interpreter_continutation) {
-+ movl(temp, Address(rbp, frame::return_addr_offset * wordSize));
++void MacroAssembler::parent_is_not_interpreter_jcc(Register base_pointer, Register temp, Label& is_not_interpreter_continutation) {
++ movl(temp, Address(base_pointer, frame::return_addr_offset * wordSize));
+ cmp32 (temp, ExternalAddress(Interpreter::interpreter_code_begin_address()));
+ jcc(Assembler::less, is_not_interpreter_continutation);
+ cmp32 (temp, ExternalAddress(Interpreter::interpreter_code_end_address()));
@@ -18,10 +45,12 @@ diff --git a/src/cpu/x86/vm/assembler_x8
#else // LP64
// 64bit only pieces of the assembler
-@@ -3738,6 +3748,15 @@
+@@ -3736,6 +3754,15 @@ void Assembler::cvttss2siq(Register dst,
+ emit_byte(0x0F);
+ emit_byte(0x2C);
emit_byte(0xC0 | encode);
- }
-
++}
++
+void MacroAssembler::parent_is_not_interpreter_jcc(Register temp, Label& is_not_interpreter_continutation) {
+ assert(0, "update this code");
+ movl(temp, Address(rbp, frame::return_addr_offset * wordSize));
@@ -29,35 +58,82 @@ diff --git a/src/cpu/x86/vm/assembler_x8
+ jcc(Assembler::less, is_not_interpreter_continutation);
+ cmp32 (temp, ExternalAddress(Interpreter::interpreter_code_end_address()));
+ jcc(Assembler::greater, is_not_interpreter_continutation);
-+}
-+
+ }
+
void Assembler::decl(Register dst) {
- // Don't use it directly. Use MacroAssembler::decrementl() instead.
- // Use two-byte form (one-byte form is a REX prefix in 64-bit mode)
-diff --git a/src/cpu/x86/vm/assembler_x86.hpp b/src/cpu/x86/vm/assembler_x86.hpp
---- a/src/cpu/x86/vm/assembler_x86.hpp
-+++ b/src/cpu/x86/vm/assembler_x86.hpp
-@@ -2033,6 +2033,8 @@
+diff -r ce2272390558 src/cpu/x86/vm/assembler_x86.hpp
+--- a/src/cpu/x86/vm/assembler_x86.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/assembler_x86.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -560,7 +560,12 @@ private:
+
+ void call_literal(address entry, RelocationHolder const& rspec);
+ void jmp_literal(address entry, RelocationHolder const& rspec);
+-
++public:
++ // Server compiler needs this method when emitting tail calls.
++ void tail_call_jmp_literal(address entry, RelocationHolder const& rspec) {
++ jmp_literal(entry, rspec);
++ }
++protected:
+ // Avoid using directly section
+ // Instructions in this section are actually usable by anyone without danger
+ // of failure but have performance issues that are addressed my enhanced
+@@ -1065,7 +1070,8 @@ private:
+ void movl(Register dst, Register src);
+ void movl(Register dst, Address src);
+ void movl(Address dst, Register src);
+-
++ // Tail call support.
++ void mov_label(Address dst, Label& L, relocInfo::relocType rtype = relocInfo::internal_word_type);
+ // These dummies prevent using movl from converting a zero (like NULL) into Register
+ // by giving the compiler two choices it can't resolve
+
+@@ -2033,6 +2039,8 @@ public:
// Can push value or effective address
void pushptr(AddressLiteral src);
-+ void parent_is_not_interpreter_jcc(Register temp, Label& is_not_interpreter_continutation);
++ void parent_is_not_interpreter_jcc(Register base_pointer, Register temp, Label& is_not_interpreter_continutation);
+
void pushptr(Address src) { LP64_ONLY(pushq(src)) NOT_LP64(pushl(src)); }
void popptr(Address src) { LP64_ONLY(popq(src)) NOT_LP64(popl(src)); }
-@@ -2042,7 +2044,6 @@
+@@ -2041,7 +2049,6 @@ public:
+ // sign extend as need a l to ptr sized element
void movl2ptr(Register dst, Address src) { LP64_ONLY(movslq(dst, src)) NOT_LP64(movl(dst, src)); }
void movl2ptr(Register dst, Register src) { LP64_ONLY(movslq(dst, src)) NOT_LP64(if (dst != src) movl(dst, src)); }
-
-
+
#undef VIRTUAL
- };
-diff --git a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp
---- a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp
-+++ b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp
-@@ -441,7 +441,7 @@
+diff -r ce2272390558 src/cpu/x86/vm/assembler_x86.inline.hpp
+--- a/src/cpu/x86/vm/assembler_x86.inline.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/assembler_x86.inline.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -24,14 +24,19 @@
+
+ inline void MacroAssembler::pd_patch_instruction(address branch, address target) {
+ unsigned char op = branch[0];
+- assert(op == 0xE8 /* call */ ||
++ assert(op == 0xC7 /* movl reg $label*/||
++ op == 0xE8 /* call */ ||
+ op == 0xE9 /* jmp */ ||
+ op == 0xEB /* short jmp */ ||
+ (op & 0xF0) == 0x70 /* short jcc */ ||
+ op == 0x0F && (branch[1] & 0xF0) == 0x80 /* jcc */,
+ "Invalid opcode at patch point");
+
+- if (op == 0xEB || (op & 0xF0) == 0x70) {
++ if (op == 0xC7) {
++ int * disp = (int*) &branch[4];
++ assert (*disp == 0, "offset wrong");
++ *disp = (int)target;
++ } else if (op == 0xEB || (op & 0xF0) == 0x70) {
+ // short offset operators (jmp and jcc)
+ char* disp = (char*) &branch[1];
+ int imm8 = target - (address) &disp[1];
+diff -r ce2272390558 src/cpu/x86/vm/c1_CodeStubs_x86.cpp
+--- a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -441,7 +441,7 @@ void ArrayCopyStub::emit_code(LIR_Assemb
}
}
@@ -66,9 +142,9 @@ diff --git a/src/cpu/x86/vm/c1_CodeStubs
ce->emit_static_call_stub();
AddressLiteral resolve(SharedRuntime::get_resolve_static_call_stub(),
-diff --git a/src/cpu/x86/vm/c1_FrameMap_x86.cpp b/src/cpu/x86/vm/c1_FrameMap_x86.cpp
---- a/src/cpu/x86/vm/c1_FrameMap_x86.cpp
-+++ b/src/cpu/x86/vm/c1_FrameMap_x86.cpp
+diff -r ce2272390558 src/cpu/x86/vm/c1_FrameMap_x86.cpp
+--- a/src/cpu/x86/vm/c1_FrameMap_x86.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/c1_FrameMap_x86.cpp Mon Mar 16 11:44:02 2009 +0100
@@ -27,7 +27,7 @@
const int FrameMap::pd_c_runtime_reserved_arg_size = 0;
@@ -78,7 +154,7 @@ diff --git a/src/cpu/x86/vm/c1_FrameMap_
LIR_Opr opr = LIR_OprFact::illegalOpr;
VMReg r_1 = reg->first();
VMReg r_2 = reg->second();
-@@ -36,7 +36,13 @@
+@@ -36,7 +36,13 @@ LIR_Opr FrameMap::map_to_opr(BasicType t
// The calling convention does not count the SharedRuntime::out_preserve_stack_slots() value
// so we must add it in here.
int st_off = (r_1->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size;
@@ -93,10 +169,10 @@ diff --git a/src/cpu/x86/vm/c1_FrameMap_
} else if (r_1->is_Register()) {
Register reg = r_1->as_Register();
if (r_2->is_Register() && (type == T_LONG || type == T_DOUBLE)) {
-diff --git a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
---- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
-+++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
-@@ -510,6 +510,270 @@
+diff -r ce2272390558 src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
+--- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -510,6 +510,296 @@ void LIR_Assembler::emit_deopt_handler()
}
@@ -124,13 +200,13 @@ diff --git a/src/cpu/x86/vm/c1_LIRAssemb
+ int offset = code_offset();
+#endif // ASSERT
+ __ align(CodeEntryAlignment);
-+ compilation()->offsets()->set_value(CodeOffsets::Static_Not_Sibling_Tail_Call_Entry, code_offset());
-+ if (TraceTailCalls) __ warn("Compiled entry point: Static_Not_Sibling_Tail_Call_Entry");
++ compilation()->offsets()->set_value(CodeOffsets::Verified_Not_Sibling_Tail_Call_Entry, code_offset());
++ if (TraceTailCalls) __ warn("Compiled entry point: Verified_Not_Sibling_Tail_Call_Entry");
+ // Fast case: parent is interpreter. This means we can extend its stack frame.
+ // Assume: rax, rbx are scratch. rbx would hold methodOop, rax the IC_klass token
+ Register tmp = rax; // scratch
+ Register last_sp = rbx; // scratch
-+ __ parent_is_not_interpreter_jcc(rbx, call_to_interpreter);
++ __ parent_is_not_interpreter_jcc(rbp, rbx, call_to_interpreter);
+ // Store old rbp
+ __ movl(tmp, Address(rbp, frame::link_offset*wordSize));
+ __ push_reg(tmp);
@@ -170,7 +246,8 @@ diff --git a/src/cpu/x86/vm/c1_LIRAssemb
+ // Slow case: parent is not interpreted. Jump to interpreter entry of called
+ // function in order to lazily create an interpreted frame on the stack.
+ __ bind(call_to_interpreter);
-+ compilation()->offsets()->set_value(CodeOffsets::Static_Not_Sibling_Tail_Call_Set_Data_Entry, code_offset());
++ if (TraceTailCalls) __ warn("c1 LIR: call_to_interpreter");
++ compilation()->offsets()->set_value(CodeOffsets::Verified_Not_Sibling_Tail_Call_Set_Data_Entry, code_offset());
+ // Set methodoop.
+ __ movoop(rbx, (jobject)Universe::non_oop_word());
+ // Jump to C2I Entry Point
@@ -204,16 +281,19 @@ diff --git a/src/cpu/x86/vm/c1_LIRAssemb
+ int offset = code_offset();
+#endif // ASSERT
+ __ align(CodeEntryAlignment);
-+ compilation()->offsets()->set_value(CodeOffsets::Static_Tail_Call_Entry, code_offset());
-+ if (TraceTailCalls) __ warn("Compiled entry point: Static_Tail_Call_Entry");
++ compilation()->offsets()->set_value(CodeOffsets::Verified_Tail_Call_Entry, code_offset());
++ if (TraceTailCalls) __ warn("Compiled entry point: Verified_Tail_Call_Entry");
++ __ generate_stack_overflow_check(initial_frame_size_in_bytes());
++
+ // Move arguments.
+ emit_tail_call_argument_move(arg_slots);
+ // Remove tail calling caller's stack frame.
-+ __ leave();
-+
++ Address new_stack_pointer(rbp, -1*initial_frame_size_in_bytes());
++ __ leal(rsp, new_stack_pointer);
+ // Compute target of jump. Verified entry point of current method.
+ address vep_entry = compilation()->code()->insts()->start() +
-+ compilation()->offsets()->value(CodeOffsets::Verified_Entry);
++ compilation()->offsets()->value(CodeOffsets::Frame_Complete);
++ //compilation()->offsets()->value(CodeOffsets::Verified_Entry);
+ RelocationHolder rh = section_call_Relocation::spec(vep_entry, CodeBuffer::SECT_INSTS);
+ // Jump to vep.
+ __ jump(AddressLiteral((address)vep_entry, rh));
@@ -225,8 +305,27 @@ diff --git a/src/cpu/x86/vm/c1_LIRAssemb
+
+void LIR_Assembler::emit_tail_call_argument_move(int arg_slots) {
+ // Copy the args to tail call position using register rbx.
++ int sizeargs = 0;
++ BasicTypeArray* sig = FrameMap::signature_type_array_for(method());
++ for (int i = 0; i < sig->length(); i++) {
++ sizeargs += type2size[sig->at(i)];
++ }
++ VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, sizeargs);
++ BasicType * sig_bt = NEW_RESOURCE_ARRAY(BasicType, sizeargs);
++ int sig_index = 0;
++ for (int i = 0; i < sizeargs; i++, sig_index++) {
++ sig_bt[i] = sig->at(sig_index);
++ if (sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) {
++ sig_bt[i + 1] = T_VOID;
++ i++;
++ }
++ }
++ // Get exact (hence the 3) arg size on stack.
+ Register tmp = rbx;
-+ for (int slot = 1; slot <= arg_slots; slot++) {
++ Register tmp2 = rax;
++ arg_slots = SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs, 3);
++ for (int slot = 1+SharedRuntime::tail_call_protection_domain_slots();
++ slot <= arg_slots; slot++) {
+ Address src (rsp, VMRegImpl::stack_slot_size * (SharedRuntime::out_preserve_stack_slots()+slot));
+ // Need to add safed eip slot so slot+1 VVV
+ Address dest(rbp, VMRegImpl::stack_slot_size * (SharedRuntime::out_preserve_stack_slots()+slot+1));
@@ -259,15 +358,15 @@ diff --git a/src/cpu/x86/vm/c1_LIRAssemb
+ int offset = code_offset();
+#endif // ASSERT
+ __ align(CodeEntryAlignment);
-+ compilation()->offsets()->set_value(CodeOffsets::Monomorphic_Not_Sibling_Tail_Call_Entry, code_offset());
-+ if (TraceTailCalls) __ warn("Compiled entry point: Monomorphic_Not_Sibling_Tail_Call_Entry");
++ compilation()->offsets()->set_value(CodeOffsets::Not_Sibling_Tail_Call_Entry, code_offset());
++ if (TraceTailCalls) __ warn("Compiled entry point: Not_Sibling_Tail_Call_Entry");
+ check_icache();
+ // Fast case: parent is interpreter. This means we can extend its stack frame.
+ // Assume: rax, rbx are scratch here since rax is needed only for
+ // check_icache. rbx would hold methodOop, rax the IC_klass token
+ Register tmp = rax; // scratch
+ Register last_sp = rbx; // scratch
-+ __ parent_is_not_interpreter_jcc(tmp, call_to_interpreter);
++ __ parent_is_not_interpreter_jcc(rbp, tmp, call_to_interpreter);
+ // Store old rbp
+ __ movl(tmp, Address(rbp, frame::link_offset*wordSize));
+ __ push_reg(tmp);
@@ -307,7 +406,7 @@ diff --git a/src/cpu/x86/vm/c1_LIRAssemb
+ // Slow case: parent is not interpreted. Jump to interpreter entry of called
+ // function in order to lazily create an interpreted frame on the stack.
+ __ bind(call_to_interpreter);
-+ compilation()->offsets()->set_value(CodeOffsets::Monomorphic_Not_Sibling_Tail_Call_Set_Data_Entry, code_offset());
++ compilation()->offsets()->set_value(CodeOffsets::Not_Sibling_Tail_Call_Set_Data_Entry, code_offset());
+ // Set methodoop.
+ __ movoop(rbx, (jobject)Universe::non_oop_word());
+ // Jump to C2I Entry Point
@@ -341,21 +440,24 @@ diff --git a/src/cpu/x86/vm/c1_LIRAssemb
+ int offset = code_offset();
+#endif // ASSERT
+ __ align(CodeEntryAlignment);
-+ compilation()->offsets()->set_value(CodeOffsets::Monomorphic_Tail_Call_Entry, code_offset());
-+ if (TraceTailCalls) __ warn("Compiled entry point: Monomorphic_Tail_Call_Entry");
++ compilation()->offsets()->set_value(CodeOffsets::Tail_Call_Entry, code_offset());
++ if (TraceTailCalls) __ warn("Compiled entry point: Tail_Call_Entry");
+ // Check inline cache - needs to be done before poping the frame.
+ // If the check is done after popping the frame and the icache check fails,
+ // the frame would be popped again by handle_ic_miss code path.
+ check_icache();
++ __ generate_stack_overflow_check(initial_frame_size_in_bytes());
+ // Move arguments.
+ emit_tail_call_argument_move(arg_slots);
+
+ // Remove tail calling caller's stack frame.
-+ __ leave();
++ Address new_stack_pointer(rbp, -1*initial_frame_size_in_bytes());
++ __ leal(rsp, new_stack_pointer);
+
+ // Compute target of jump. Verified entry point of current method.
+ address vep_entry = compilation()->code()->insts()->start() +
-+ compilation()->offsets()->value(CodeOffsets::Verified_Entry);
++ //compilation()->offsets()->value(CodeOffsets::Verified_Entry);
++ compilation()->offsets()->value(CodeOffsets::Frame_Complete);
+ RelocationHolder rh = section_call_Relocation::spec(vep_entry, CodeBuffer::SECT_INSTS);
+ // Jump to vep.
+ __ jump(AddressLiteral((address)vep_entry, rh));
@@ -367,7 +469,7 @@ diff --git a/src/cpu/x86/vm/c1_LIRAssemb
// This is the fast version of java.lang.String.compare; it has not
// OSR-entry and therefore, we generate a slow version for OSR's
-@@ -2751,7 +3015,7 @@
+@@ -2751,7 +3041,7 @@ void LIR_Assembler::comp_fl2i(LIR_Code c
}
@@ -376,22 +478,24 @@ diff --git a/src/cpu/x86/vm/c1_LIRAssemb
if (os::is_MP()) {
// make sure that the displacement word of the call ends up word aligned
int offset = __ offset();
-@@ -2759,9 +3023,12 @@
+@@ -2759,9 +3049,14 @@ void LIR_Assembler::align_call(LIR_Code
case lir_static_call:
case lir_optvirtual_call:
offset += NativeCall::displacement_offset;
- break;
++ if (is_tail_call) offset += NativeJump::tail_call_push_ret_offset;
+ break;
case lir_icvirtual_call:
- offset += NativeCall::displacement_offset + NativeMovConstReg::instruction_size;
-+ if (is_tail_call)
++ if (is_tail_call) {
+ offset += NativeCall::displacement_offset + NativeMovConstReg::instruction_size+NativeMovConstProtectionDomain::instruction_size;
-+ else
++ offset += NativeJump::tail_call_push_ret_offset;
++ } else
+ offset += NativeCall::displacement_offset + NativeMovConstReg::instruction_size;
break;
case lir_virtual_call: // currently, sparc-specific for niagara
default: ShouldNotReachHere();
-@@ -2772,17 +3039,62 @@
+@@ -2772,22 +3067,93 @@ void LIR_Assembler::align_call(LIR_Code
}
}
@@ -399,29 +503,52 @@ diff --git a/src/cpu/x86/vm/c1_LIRAssemb
+ // needs 7 bytes on x86-32
+ __ movoop(Address(rsp, 0), (jobject)Universe::non_oop_word());
+}
++
++#ifdef ASSERT
++void check_call_alignment(C1_MacroAssembler * _masm) {
++ assert(!os::is_MP() || ((__ offset() + NativeCall::displacement_offset) % BytesPerWord == 0),
++ "must be aligned");
++}
++# else
++ void check_call_alignment(C1_MacroAssembler * _masm) {}
++#endif
++
++
++void LIR_Assembler::tail_call(address entry, RelocationHolder& rh) {
++ Label return_address;
++ __ mov_label(Address(rsp,-4), return_address);
++ __ subl (rsp, wordSize);
++ check_call_alignment(_masm);
++ __ jmp_literal(entry, rh);
++ __ bind (return_address);
++}
void LIR_Assembler::call(address entry, relocInfo::relocType rtype, CodeEmitInfo* info) {
- assert(!os::is_MP() || (__ offset() + NativeCall::displacement_offset) % BytesPerWord == 0,
-+ assert(!os::is_MP() || ((__ offset() + NativeCall::displacement_offset) % BytesPerWord == 0),
- "must be aligned");
+- "must be aligned");
- __ call(AddressLiteral(entry, rtype));
+ if (entry == SharedRuntime::get_resolve_not_sibling_static_tail_call_stub()) {
+ assert(rtype == relocInfo::static_call_type, "expect static call");
-+ RelocationHolder rh = static_call_Relocation::spec(relocInfo::not_sibling_tail_call_type);
-+ __ call(AddressLiteral(entry, rh));
++
++ RelocationHolder rh = static_call_Relocation::spec(relocInfo::not_sibling_tail_call_type);
++ tail_call(entry,rh);
+ } else if (entry == SharedRuntime::get_resolve_static_tail_call_stub() ) {
+ assert(rtype==relocInfo::static_call_type, "expect static call");
++
+ RelocationHolder rh = static_call_Relocation::spec(relocInfo::sibling_tail_call_type);
-+ __ call(AddressLiteral(entry, rh));
++ tail_call(entry, rh);
+ } else if (entry == SharedRuntime::get_resolve_opt_virtual_tail_call_stub()) {
+ assert(rtype==relocInfo::opt_virtual_call_type, "expect opt virtual call");
++
+ RelocationHolder rh = opt_virtual_call_Relocation::spec(relocInfo::sibling_tail_call_type);
-+ __ call(AddressLiteral(entry, rh));
++ tail_call(entry, rh);
+ } else if (entry == SharedRuntime::get_resolve_opt_not_sibling_virtual_tail_call_stub()) {
+ assert(rtype==relocInfo::opt_virtual_call_type, "expect opt virtual call");
++
+ RelocationHolder rh = opt_virtual_call_Relocation::spec(relocInfo::not_sibling_tail_call_type);
-+ __ call(AddressLiteral(entry, rh));
++ tail_call(entry, rh);
+ } else {
++ check_call_alignment(_masm);
+ __ call(AddressLiteral(entry, rtype));
+ }
add_call_info(code_offset(), info);
@@ -456,11 +583,22 @@ diff --git a/src/cpu/x86/vm/c1_LIRAssemb
+ relocInfo::tailCallType type = tail_call_type_from_resolve_stub(entry);
+ RelocationHolder rh = virtual_call_Relocation::spec(pc(), NULL, type);
__ movoop(IC_Klass, (jobject)Universe::non_oop_word());
- assert(!os::is_MP() ||
+- assert(!os::is_MP() ||
++ if (is_tail_call)
++ tail_call(entry, rh);
++ else {
++ assert(!os::is_MP() ||
(__ offset() + NativeCall::displacement_offset) % BytesPerWord == 0,
-diff --git a/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp b/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp
---- a/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp
-+++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp
+ "must be aligned");
+- __ call(AddressLiteral(entry, rh));
++ __ call(AddressLiteral(entry, rh));
++ }
+ add_call_info(code_offset(), info);
+ }
+
+diff -r ce2272390558 src/cpu/x86/vm/c1_LIRAssembler_x86.hpp
+--- a/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp Mon Mar 16 11:44:02 2009 +0100
@@ -36,6 +36,9 @@
address float_constant(float f);
address double_constant(double d);
@@ -471,7 +609,7 @@ diff --git a/src/cpu/x86/vm/c1_LIRAssemb
bool is_literal_address(LIR_Address* addr);
// When we need to use something other than rscratch1 use this
-@@ -51,5 +54,9 @@
+@@ -51,5 +54,9 @@ public:
enum { call_stub_size = NOT_LP64(15) LP64_ONLY(28),
exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175),
@@ -481,9 +619,9 @@ diff --git a/src/cpu/x86/vm/c1_LIRAssemb
+ monomorphic_not_sibling_tail_call_stub_size = NOT_LP64(300) LP64_ONLY(xxx),
deopt_handler_size = NOT_LP64(10) LP64_ONLY(17)
};
-diff --git a/src/cpu/x86/vm/frame_x86.hpp b/src/cpu/x86/vm/frame_x86.hpp
---- a/src/cpu/x86/vm/frame_x86.hpp
-+++ b/src/cpu/x86/vm/frame_x86.hpp
+diff -r ce2272390558 src/cpu/x86/vm/frame_x86.hpp
+--- a/src/cpu/x86/vm/frame_x86.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/frame_x86.hpp Mon Mar 16 11:44:02 2009 +0100
@@ -109,7 +109,9 @@
interpreter_frame_cache_offset = interpreter_frame_mdx_offset - 1,
interpreter_frame_locals_offset = interpreter_frame_cache_offset - 1,
@@ -495,10 +633,10 @@ diff --git a/src/cpu/x86/vm/frame_x86.hp
interpreter_frame_monitor_block_top_offset = interpreter_frame_initial_sp_offset,
interpreter_frame_monitor_block_bottom_offset = interpreter_frame_initial_sp_offset,
-diff --git a/src/cpu/x86/vm/frame_x86.inline.hpp b/src/cpu/x86/vm/frame_x86.inline.hpp
---- a/src/cpu/x86/vm/frame_x86.inline.hpp
-+++ b/src/cpu/x86/vm/frame_x86.inline.hpp
-@@ -191,6 +191,9 @@
+diff -r ce2272390558 src/cpu/x86/vm/frame_x86.inline.hpp
+--- a/src/cpu/x86/vm/frame_x86.inline.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/frame_x86.inline.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -191,6 +191,9 @@ inline intptr_t* frame::interpreter_fram
#else /* asm interpreter */
inline intptr_t* frame::sender_sp() const { return addr_at( sender_sp_offset); }
@@ -508,10 +646,10 @@ diff --git a/src/cpu/x86/vm/frame_x86.in
inline intptr_t** frame::interpreter_frame_locals_addr() const {
return (intptr_t**)addr_at(interpreter_frame_locals_offset);
}
-diff --git a/src/cpu/x86/vm/interp_masm_x86_32.cpp b/src/cpu/x86/vm/interp_masm_x86_32.cpp
---- a/src/cpu/x86/vm/interp_masm_x86_32.cpp
-+++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp
-@@ -588,11 +588,15 @@
+diff -r ce2272390558 src/cpu/x86/vm/interp_masm_x86_32.cpp
+--- a/src/cpu/x86/vm/interp_masm_x86_32.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -588,11 +588,15 @@ void InterpreterMacroAssembler::super_ca
// 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
@@ -531,10 +669,10 @@ diff --git a/src/cpu/x86/vm/interp_masm_
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
---- a/src/cpu/x86/vm/interp_masm_x86_32.hpp
-+++ b/src/cpu/x86/vm/interp_masm_x86_32.hpp
-@@ -161,7 +161,7 @@
+diff -r ce2272390558 src/cpu/x86/vm/interp_masm_x86_32.hpp
+--- a/src/cpu/x86/vm/interp_masm_x86_32.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/interp_masm_x86_32.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -161,7 +161,7 @@ class InterpreterMacroAssembler: public
// jump to an invoked target
@@ -543,10 +681,10 @@ diff --git a/src/cpu/x86/vm/interp_masm_
// Returning from interpreted functions
//
-diff --git a/src/cpu/x86/vm/nativeInst_x86.cpp b/src/cpu/x86/vm/nativeInst_x86.cpp
---- a/src/cpu/x86/vm/nativeInst_x86.cpp
-+++ b/src/cpu/x86/vm/nativeInst_x86.cpp
-@@ -114,7 +114,18 @@
+diff -r ce2272390558 src/cpu/x86/vm/nativeInst_x86.cpp
+--- a/src/cpu/x86/vm/nativeInst_x86.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/nativeInst_x86.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -114,7 +114,18 @@ void NativeCall::replace_mt_safe(address
}
@@ -566,7 +704,17 @@ diff --git a/src/cpu/x86/vm/nativeInst_x
// Similar to replace_mt_safe, but just changes the destination. The
// important thing is that free-running threads are able to execute this
// call instruction at all times. If the displacement field is aligned
-@@ -199,6 +210,21 @@
+@@ -129,7 +140,8 @@ void NativeCall::replace_mt_safe(address
+ // Used in the runtime linkage of calls; see class CompiledIC.
+ // (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.)
+ void NativeCall::set_destination_mt_safe(address dest) {
+- debug_only(verify());
++ //debug_only(verify()); TODO: check only if really call and not a jmp.
++
+ // Make sure patching code is locked. No two threads can patch at the same
+ // time but one may be executing this code.
+ assert(Patching_lock->is_locked() ||
+@@ -199,6 +211,21 @@ void NativeCall::set_destination_mt_safe
}
@@ -588,7 +736,26 @@ diff --git a/src/cpu/x86/vm/nativeInst_x
void NativeMovConstReg::verify() {
#ifdef AMD64
// make sure code pattern is actually a mov reg64, imm64 instruction
-@@ -565,8 +591,6 @@
+@@ -211,7 +238,17 @@ void NativeMovConstReg::verify() {
+ // make sure code pattern is actually a mov reg, imm32 instruction
+ u_char test_byte = *(u_char*)instruction_address();
+ u_char test_byte_2 = test_byte & ( 0xff ^ register_mask);
+- if (test_byte_2 != instruction_code) fatal("not a mov reg, imm32");
++ if (test_byte_2 != instruction_code) {
++ HandleMark hm;
++ CodeBlob* cb = CodeCache::find_blob_unsafe(instruction_address());
++ assert(cb != NULL && cb->is_nmethod(), "must be nmethod");
++ nmethod * nm = (nmethod*) cb;
++ nm->print();
++ nm->print_code();
++ nm->print_pcs();
++ nm->print_relocations();
++ fatal("not a mov reg, imm32");
++ }
+ #endif // AMD64
+ }
+
+@@ -565,8 +602,6 @@ void NativeGeneralJump::replace_mt_safe(
}
@@ -597,10 +764,10 @@ diff --git a/src/cpu/x86/vm/nativeInst_x
address NativeGeneralJump::jump_destination() const {
int op_code = ubyte_at(0);
bool is_rel32off = (op_code == 0xE9 || op_code == 0x0F);
-diff --git a/src/cpu/x86/vm/nativeInst_x86.hpp b/src/cpu/x86/vm/nativeInst_x86.hpp
---- a/src/cpu/x86/vm/nativeInst_x86.hpp
-+++ b/src/cpu/x86/vm/nativeInst_x86.hpp
-@@ -154,6 +154,8 @@
+diff -r ce2272390558 src/cpu/x86/vm/nativeInst_x86.hpp
+--- a/src/cpu/x86/vm/nativeInst_x86.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/nativeInst_x86.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -154,6 +154,8 @@ class NativeCall: public NativeInstructi
static void insert(address code_pos, address entry);
static void replace_mt_safe(address instr_addr, address code_buffer);
@@ -609,10 +776,12 @@ diff --git a/src/cpu/x86/vm/nativeInst_x
};
inline NativeCall* nativeCall_at(address address) {
-@@ -172,6 +174,48 @@
+@@ -170,6 +172,48 @@ inline NativeCall* nativeCall_before(add
+ call->verify();
+ #endif
return call;
- }
-
++}
++
+// An interface for accessing/manipultation of mov (%esp,offset) imm32
+// protection domain token instructions.
+class NativeMovConstProtectionDomain : public NativeInstruction {
@@ -653,15 +822,49 @@ diff --git a/src/cpu/x86/vm/nativeInst_x
+ test->verify();
+#endif
+ return test;
-+}
-+
+ }
+
// An interface for accessing/manipulating native mov reg, imm32 instructions.
- // (used to manipulate inlined 32bit data dll calls, etc.)
- class NativeMovConstReg: public NativeInstruction {
-diff --git a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp
---- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp
-+++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp
-@@ -38,6 +38,12 @@
+@@ -372,7 +416,10 @@ class NativeJump: public NativeInstructi
+ instruction_size = 5,
+ instruction_offset = 0,
+ data_offset = 1,
+- next_instruction_offset = 5
++ next_instruction_offset = 5,
++ // A tail call replace a call instruction by
++ // movl %esp $ret_addr ; subl esp 4 ; jmp target
++ tail_call_push_ret_offset = 11
+ };
+
+ address instruction_address() const { return addr_at(instruction_offset); }
+@@ -413,8 +460,23 @@ class NativeJump: public NativeInstructi
+ // MT-safe insertion of native jump at verified method entry
+ static void check_verified_entry_alignment(address entry, address verified_entry);
+ static void patch_verified_entry(address entry, address verified_entry, address dest);
++
++ static bool is_jump_at(address instr) {
++ return ((*instr) & 0xFF) == NativeJump::instruction_code;
++ }
++
++ static bool is_jump_before(address return_address) {
++ return is_jump_at(return_address - NativeCall::return_address_offset);
++ }
+ };
+
++inline NativeJump* nativeJump_before(address return_address) {
++ NativeJump* call = (NativeJump*)(return_address - NativeCall::return_address_offset);
++#ifdef ASSERT
++ call->verify();
++#endif
++ return call;
++}
+ inline NativeJump* nativeJump_at(address address) {
+ NativeJump* jump = (NativeJump*)(address - NativeJump::instruction_offset);
+ #ifdef ASSERT
+diff -r ce2272390558 src/cpu/x86/vm/sharedRuntime_x86_32.cpp
+--- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -38,6 +38,12 @@ RuntimeStub* SharedRuntime::_resol
RuntimeStub* SharedRuntime::_resolve_opt_virtual_call_blob;
RuntimeStub* SharedRuntime::_resolve_virtual_call_blob;
RuntimeStub* SharedRuntime::_resolve_static_call_blob;
@@ -674,7 +877,7 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size;
-@@ -318,6 +324,13 @@
+@@ -318,6 +324,13 @@ static int reg2offset_out(VMReg r) {
return (r->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size;
}
@@ -682,13 +885,13 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
+// Tail call support: slots used on top of stack for the protection domain
+// token. Currently set to 18 to find bugs. Normally we would need only one.
+int SharedRuntime::tail_call_protection_domain_slots() {
-+ if (TailCalls) return 1;
++ if (TailCalls) return 2;
+ else return 0;
+}
// ---------------------------------------------------------------------------
// Read the array of BasicTypes from a signature, and compute where the
// arguments should go. Values in the VMRegPair regs array refer to 4-byte
-@@ -349,12 +362,14 @@
+@@ -349,12 +362,14 @@ int SharedRuntime::java_calling_conventi
VMRegPair *regs,
int total_args_passed,
int is_outgoing) {
@@ -704,7 +907,7 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
// Pass first two float/double args in registers XMM0 and XMM1.
// Doubles have precedence, so if you pass a mix of floats and doubles
-@@ -383,7 +398,7 @@
+@@ -383,7 +398,7 @@ int SharedRuntime::java_calling_conventi
stack += 2;
}
}
@@ -713,7 +916,17 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
// Now pick where all else goes.
for( i = 0; i < total_args_passed; i++) {
-@@ -538,7 +553,8 @@
+@@ -441,7 +456,8 @@ int SharedRuntime::java_calling_conventi
+ break;
+ }
+ }
+-
++ // return exact stack size. Used for tail calls moving their arguments.
++ if (is_outgoing==3) return stack;
+ // return value can be odd number of VMRegImpl stack slots make multiple of 2
+ return round_to(stack, 2);
+ }
+@@ -538,7 +554,8 @@ static void gen_c2i_adapter(MacroAssembl
int comp_args_on_stack,
const BasicType *sig_bt,
const VMRegPair *regs,
@@ -723,7 +936,7 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
// Before we get into the guts of the C2I adapter, see if we should be here
// at all. We've come from compiled code and are attempting to jump to the
// interpreter, which means the caller made a static call to get here
-@@ -566,7 +582,8 @@
+@@ -566,7 +583,8 @@ static void gen_c2i_adapter(MacroAssembl
__ pop(rax);
// set senderSP value
@@ -733,7 +946,7 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
__ subptr(rsp, extraspace);
-@@ -913,6 +930,163 @@
+@@ -913,6 +931,181 @@ AdapterHandlerEntry* SharedRuntime::gene
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
// -------------------------------------------------------------------------
@@ -742,11 +955,19 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
+ assert (SharedRuntime::out_preserve_stack_slots() == 0, "This code assumes that there are not preserved stack slots");
+ Label skip_fixup_tail_call;
+ Label parent_is_not_interpreted;
-+ Label static_tail_call;
-+ Label static_tail_call_not_sibling;
++ Label verified_tail_call;
++ Label verified_tail_call_not_sibling;
+ Label continue_in_interpreter;
+ Label skip_fixup_tailcall;
+ Label skip_fixup;
++
++#ifdef COMPILER2
++ // opto puts the 'base pointer' into rsi when tail calling.
++ Register base_pointer = rsi;
++#else
++ Register base_pointer = rbp;
++#endif
++
+ address c2i_unverified_not_sibling_tail_call_entry = __ pc();
+ {
+
@@ -766,25 +987,27 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
+ // interpreted if that is the case treat it as a miss so we can get
+ // the call site corrected.
+ __ cmpl(Address(rbx, in_bytes(methodOopDesc::code_offset())), NULL_WORD);
-+ __ jcc(Assembler::equal, static_tail_call_not_sibling);
++ __ jcc(Assembler::equal, verified_tail_call_not_sibling);
+
+ __ bind(missed);
+ __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub()));
+ }
+
-+ address c2i_static_not_sibling_tail_call_entry = __ pc();
++ address c2i_verified_not_sibling_tail_call_entry = __ pc();
+ {
+ //__ warn("c2i_not_sibling_tail_call_entry");
+ patch_callers_callsite(masm);
+ __ verify_oop(rbx); // Rbx should contain methodoop of callee
+ Register tmp = rax; // Rax (IC_klass) is not used for static calls.
-+ __ bind(static_tail_call_not_sibling);
-+ __ parent_is_not_interpreter_jcc(tmp, continue_in_interpreter);
++ __ bind(verified_tail_call_not_sibling);
++ if (TraceTailCalls) __ warn("c2i static not sib tail call entry");
++ __ parent_is_not_interpreter_jcc(base_pointer, tmp, continue_in_interpreter);
+ //__ warn("c2i_not_sibling_tail_call_entry: parent is interpreted");
+ // Parent is interpreted: can use code path of static tail call.
+ // It moves the arguments relative to the last_sp of the parent frame.
-+ __ jmp(static_tail_call);
++ __ jmp(verified_tail_call);
+ __ bind(continue_in_interpreter);
++ if (TraceTailCalls) __ warn("c2i continue in interpreter");
+ //__ warn("c2i_not_sibling_tail_call_entry: parent is compiled: continue in interpreted");
+ // Leave an int frame - lazily create an interpreter frame (the callee frame)
+ // Since we want to guarantee an interpreter frame on the stack we turn off
@@ -819,7 +1042,7 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
+ // interpreted if that is the case treat it as a miss so we can get
+ // the call site corrected.
+ __ cmpl(Address(rbx, in_bytes(methodOopDesc::code_offset())), NULL_WORD);
-+ __ jcc(Assembler::equal, static_tail_call);
++ __ jcc(Assembler::equal, verified_tail_call);
+
+ __ bind(missed);
+ __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub()));
@@ -828,26 +1051,29 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
+ // Static tail call entry: We know that the protection domain and klass is
+ // correct.
+
-+ address static_tail_call_c2i_entry = __ pc();;
++ address verified_tail_call_c2i_entry = __ pc();
+ patch_callers_callsite(masm);
-+ __ bind (static_tail_call);
++ __ bind (verified_tail_call);
++ if (TraceTailCalls) __ warn("c2i static tail call entry");
+ // Check whether parent frame is interpreter.
+ Register tmp = rax; // Klass not used if static call.
-+ __ parent_is_not_interpreter_jcc(tmp, parent_is_not_interpreted);
++
++
++ __ parent_is_not_interpreter_jcc(base_pointer, tmp, parent_is_not_interpreted);
+ //__ warn("c2i_static_tail_call_entry: parent is interpreted");
+ // Parent is interpreted
+ // Safe some registers.
+ __ push(rax);
+ __ push(rbx);
+ // store rbp
-+ __ movl(tmp, Address(rbp, frame::link_offset*wordSize));
++ __ movl(tmp, Address(base_pointer, frame::link_offset*wordSize));
+ __ push(tmp);
+ // Store ret address.
-+ __ movl(tmp, Address(rbp, frame::return_addr_offset * wordSize));
++ __ movl(tmp, Address(base_pointer, frame::return_addr_offset * wordSize));
+ __ push(tmp);
+ // Get last_sp from parent frame.
+ Register last_sp = tmp; tmp = rbx;
-+ __ movl(tmp, Address(rbp, frame::link_offset * wordSize)); // old rbp
++ __ movl(tmp, Address(base_pointer, frame::link_offset * wordSize)); // old rbp
+ __ movl(last_sp, Address(tmp, frame::interpreter_frame_last_sp_offset * wordSize));
+ __ movl(rsi, last_sp); // old_sp for interpreter
+ // Shuffle arguments
@@ -880,12 +1106,17 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
+ for (int slot = 1; slot <= comp_args_on_stack; slot++) {
+ Address src (rsp, VMRegImpl::stack_slot_size * (SharedRuntime::out_preserve_stack_slots()+slot));
+ // Need to add safed rbp slot so slot+1 VVV
-+ Address dest(rbp, VMRegImpl::stack_slot_size * (SharedRuntime::out_preserve_stack_slots()+slot+1));
++ Address dest(base_pointer, VMRegImpl::stack_slot_size * (SharedRuntime::out_preserve_stack_slots()+slot+1));
+ __ movl(tmp, src);
+ __ movl(dest, tmp);
+ }
+ // pop frame
++#ifdef COMPILER2
++ __ mov(rsp, rsi); // Rsi contains base_pointer for opto.
++ __ pop(rbp);
++#else
+ __ leave();
++#endif
+ // set old_sp
+ __ leal(rsi,Address(rsp, wordSize)); // ret addr on stack
+ // jump to normal c2i entry
@@ -897,41 +1128,44 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
// Generate a C2I adapter. On entry we know rbx, holds the methodOop during calls
// to the interpreter. The args start out packed in the compiled layout. They
// need to be unpacked into the interpreter layout. This will almost always
-@@ -922,7 +1096,7 @@
+@@ -922,7 +1115,8 @@ AdapterHandlerEntry* SharedRuntime::gene
// compiled code, which relys solely on SP and not EBP, get sick).
address c2i_unverified_entry = __ pc();
- Label skip_fixup;
++ if (TraceTailCalls) __ warn("c2i_unverified_entry (not tail call)");
+ //Label skip_fixup;
Register holder = rax;
Register receiver = rcx;
-@@ -948,13 +1122,21 @@
+@@ -948,13 +1142,22 @@ AdapterHandlerEntry* SharedRuntime::gene
__ bind(missed);
__ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub()));
}
-
+ // For tail calls (lazy adapter/ interpreter frame) we skip the fix up check.
+ address c2i_entry_skip_fixup = __ pc();
++ if (TraceTailCalls) __ warn("c2i entry skip fixup");
+ __ jmp(continue_in_interpreter);
+ //__ jmp(skip_fixup);
+
address c2i_entry = __ pc();
-
+-
- gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
++ //if (TraceTailCalls) __ warn("c2i_entry (not tail call)");
+ gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup, false);
__ flush();
- return new AdapterHandlerEntry(i2c_entry, c2i_entry, c2i_unverified_entry);
+ return new AdapterHandlerEntry(i2c_entry, c2i_entry, c2i_unverified_entry,
-+ static_tail_call_c2i_entry, c2i_unverified_tail_call_entry,
++ verified_tail_call_c2i_entry, c2i_unverified_tail_call_entry,
+ c2i_entry_skip_fixup,
-+ c2i_static_not_sibling_tail_call_entry,
++ c2i_verified_not_sibling_tail_call_entry,
+ c2i_unverified_not_sibling_tail_call_entry);
}
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
-@@ -1453,7 +1635,9 @@
+@@ -1453,7 +1656,9 @@ nmethod *SharedRuntime::generate_native_
// sure we can capture all the incoming oop args from the
// caller.
//
@@ -942,7 +1176,86 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
// Mark location of rbp,
// map->set_callee_saved(VMRegImpl::stack2reg( stack_slots - 2), stack_slots * 2, 0, rbp->as_VMReg());
-@@ -2952,7 +3136,7 @@
+@@ -2328,7 +2533,7 @@ void SharedRuntime::generate_deopt_blob(
+ // allocate space for the code
+ ResourceMark rm;
+ // setup code generation tools
+- CodeBuffer buffer("deopt_blob", 1024, 1024);
++ CodeBuffer buffer("deopt_blob", 2048, 2048);
+ MacroAssembler* masm = new MacroAssembler(&buffer);
+ int frame_size_in_words;
+ OopMap* map = NULL;
+@@ -2390,6 +2595,29 @@ void SharedRuntime::generate_deopt_blob(
+ __ push(Deoptimization::Unpack_reexecute);
+ __ jmp(cont);
+
++ // Stack compression case
++ int stack_compression_offset = __ pc() - start;
++ Label stack_comp_cont; // Where to continue after we fetch the unroll info.
++ {
++ OopMap* comp_map = RegisterSaver::save_live_registers(masm, additional_words, &frame_size_in_words);
++ __ push(Deoptimization::Unpack_stack_compression);
++ __ empty_FPU_stack();
++ // Call C code. Need thread and this frame, but NOT official VM entry
++ // crud. We cannot block on this call, no GC can happen.
++ __ get_thread(rcx);
++ __ push(rcx);
++ // fetch_unroll_info_stack_compression needs to call last_java_frame()
++ __ set_last_Java_frame(rcx, noreg, noreg, NULL);
++ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::fetch_unroll_info_stack_compression)));
++ oop_maps->add_gc_map( __ pc()-start, comp_map);
++ // If fetch_unroll_info_stack_compression returned NULL it means
++ // stack compression failed. Throw an exception.
++ __ cmpl(rax, (intptr_t)0);
++ __ jcc(Assembler::notEqual, stack_comp_cont);
++ __ pop(rax); __ pop(rax);
++ RegisterSaver::restore_live_registers(masm);
++ __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
++ }
+ int exception_offset = __ pc() - start;
+
+ // Prolog for exception case
+@@ -2469,6 +2697,8 @@ void SharedRuntime::generate_deopt_blob(
+
+ oop_maps->add_gc_map( __ pc()-start, map);
+
++ __ bind(stack_comp_cont); // comming from fetch_unroll_info_stack_compression.
++
+ // Discard arg to fetch_unroll_info
+ __ pop(rcx);
+
+@@ -2529,7 +2759,7 @@ void SharedRuntime::generate_deopt_blob(
+
+ // Stack bang to make sure there's enough room for these interpreter frames.
+ if (UseStackBanging) {
+- __ movl(rbx, Address(rdi ,Deoptimization::UnrollBlock::total_frame_sizes_offset_in_bytes()));
++ __ movl(rbx, Address(rdi, Deoptimization::UnrollBlock::total_frame_sizes_offset_in_bytes()));
+ __ bang_stack_size(rbx, rcx);
+ }
+
+@@ -2549,9 +2779,9 @@ void SharedRuntime::generate_deopt_blob(
+ // Pick up the initial fp we should save
+ __ movptr(rbp, Address(rdi, Deoptimization::UnrollBlock::initial_fp_offset_in_bytes()));
+
+- // Now adjust the caller's stack to make up for the extra locals
+- // but record the original sp so that we can save it in the skeletal interpreter
+- // frame and the stack walking of interpreter_sender will get the unextended sp
++ // Now adjust the caller's stack to make up for the extra locals but record
++ // the original sp so that we can save it in the skeletal interpreter frame
++ // and the stack walking of interpreter_sender will get the unextended sp
+ // value and not the "real" sp value.
+
+ Address sp_temp(rdi, Deoptimization::UnrollBlock::sender_sp_temp_offset_in_bytes());
+@@ -2667,7 +2897,7 @@ void SharedRuntime::generate_deopt_blob(
+ // make sure all code is generated
+ masm->flush();
+
+- _deopt_blob = DeoptimizationBlob::create( &buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words);
++ _deopt_blob = DeoptimizationBlob::create( &buffer, oop_maps, 0, exception_offset, reexecute_offset, stack_compression_offset, frame_size_in_words);
+ _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
+ }
+
+@@ -2952,7 +3182,7 @@ static SafepointBlob* generate_handler_b
// but since this is generic code we don't know what they are and the caller
// must do any gc of the args.
//
@@ -951,7 +1264,7 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
assert (StubRoutines::forward_exception_entry() != NULL, "must be generated before");
// allocate space for the code
-@@ -3007,10 +3191,24 @@
+@@ -3007,10 +3237,24 @@ static RuntimeStub* generate_resolve_blo
__ movptr(Address(rsp, RegisterSaver::rax_offset() * wordSize), rax);
@@ -978,7 +1291,7 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
__ jmp(rax);
// Pending exception after the safepoint
-@@ -3052,6 +3250,23 @@
+@@ -3052,6 +3296,23 @@ void SharedRuntime::generate_stubs() {
_resolve_static_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C),
"resolve_static_call");
@@ -1002,9 +1315,136 @@ diff --git a/src/cpu/x86/vm/sharedRuntim
_polling_page_safepoint_handler_blob =
generate_handler_blob(CAST_FROM_FN_PTR(address,
SafepointSynchronize::handle_polling_page_exception), false);
-diff --git a/src/cpu/x86/vm/templateInterpreterGenerator_x86.hpp b/src/cpu/x86/vm/templateInterpreterGenerator_x86.hpp
---- a/src/cpu/x86/vm/templateInterpreterGenerator_x86.hpp
-+++ b/src/cpu/x86/vm/templateInterpreterGenerator_x86.hpp
+@@ -3061,6 +3322,10 @@ void SharedRuntime::generate_stubs() {
+ SafepointSynchronize::handle_polling_page_exception), true);
+
+ generate_deopt_blob();
++ // we now have the stack compression entry point and can set its address in
++ // the Interpeter.
++ NativeJump * jmp = nativeJump_at(TemplateInterpreter::tail_call_handle_stack_overflow_patch_addr());
++ jmp->set_jump_destination(_deopt_blob->stack_compression());
+ #ifdef COMPILER2
+ generate_uncommon_trap_blob();
+ #endif // COMPILER2
+diff -r ce2272390558 src/cpu/x86/vm/stubGenerator_x86_32.cpp
+--- a/src/cpu/x86/vm/stubGenerator_x86_32.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/stubGenerator_x86_32.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -2101,12 +2101,28 @@ class StubGenerator: public StubCodeGene
+ // exceptions (e.g., NullPointerException or AbstractMethodError on entry) are
+ // either at call sites or otherwise assume that stack unwinding will be initiated,
+ // so caller saved registers were assumed volatile in the compiler.
++ //
++ // tail call overflow stores safes register parameters to the stack.
++ enum tail_call_safe_layout {
++ xmm0_off=0, xmm0H_off,
++ xmm1_off, xmm1H_off,
++ xmm2_off, xmm2H_off,
++ xmm3_off, xmm3H_off,
++ xmm4_off, xmm4H_off,
++ xmm5_off, xmm5H_off,
++ xmm6_off, xmm6H_off,
++ xmm7_off, xmm7H_off,
++ rdx_off,
++ rcx_off,
++ tail_call_safe_layout_size
++ };
+ address generate_throw_exception(const char* name, address runtime_entry,
+- bool restore_saved_exception_pc) {
++ bool restore_saved_exception_pc,
++ bool is_tail_call_stack_overflow_stub = false) {
+
+- int insts_size = 256;
++ int insts_size = is_tail_call_stack_overflow_stub ? 512 : 256;
+ int locs_size = 32;
+-
++ int frame_size = framesize;
+ CodeBuffer code(name, insts_size, locs_size);
+ OopMapSet* oop_maps = new OopMapSet();
+ MacroAssembler* masm = new MacroAssembler(&code);
+@@ -2125,7 +2141,22 @@ class StubGenerator: public StubCodeGene
+ }
+
+ __ enter(); // required for proper stackwalking of RuntimeStub frame
+-
++ if (is_tail_call_stack_overflow_stub) {
++ // Safe parameter registers
++ // rcx, rdx, xmm1 ....
++ __ push(rcx);
++ __ push(rdx);
++ __ subptr(rsp,16*wordSize); // Push FPU registers space
++ assert(UseSSE>=2, "assume sse2 for now");
++ __ movdbl(Address(rsp,xmm0_off*wordSize),xmm0);
++ __ movdbl(Address(rsp,xmm1_off*wordSize),xmm1);
++ __ movdbl(Address(rsp,xmm2_off*wordSize),xmm2);
++ __ movdbl(Address(rsp,xmm3_off*wordSize),xmm3);
++ __ movdbl(Address(rsp,xmm4_off*wordSize),xmm4);
++ __ movdbl(Address(rsp,xmm5_off*wordSize),xmm5);
++ __ movdbl(Address(rsp,xmm6_off*wordSize),xmm6);
++ __ movdbl(Address(rsp,xmm7_off*wordSize),xmm7);
++ }
+ // pc and rbp, already pushed
+ __ subptr(rsp, (framesize-2) * wordSize); // prolog
+
+@@ -2152,9 +2183,33 @@ class StubGenerator: public StubCodeGene
+ __ get_thread(java_thread);
+
+ __ reset_last_Java_frame(java_thread, true, false);
+-
++ if (is_tail_call_stack_overflow_stub) {
++ // Restore safed parameter registers
++ __ addptr(rsp, (framesize-2) * wordSize);
++
++ __ movdbl(xmm0,Address(rsp,xmm0_off*wordSize));
++ __ movdbl(xmm1,Address(rsp,xmm1_off*wordSize));
++ __ movdbl(xmm2,Address(rsp,xmm2_off*wordSize));
++ __ movdbl(xmm3,Address(rsp,xmm3_off*wordSize));
++ __ movdbl(xmm4,Address(rsp,xmm4_off*wordSize));
++ __ movdbl(xmm5,Address(rsp,xmm5_off*wordSize));
++ __ movdbl(xmm6,Address(rsp,xmm6_off*wordSize));
++ __ movdbl(xmm7,Address(rsp,xmm7_off*wordSize));
++ __ addptr(rsp, 16*wordSize);
++ __ pop(rdx);
++ __ pop(rcx);
++ // add tail call parameter slots
++ frame_size += tail_call_safe_layout_size;
++ }
+ __ leave(); // required for proper stackwalking of RuntimeStub frame
+-
++
++ if (is_tail_call_stack_overflow_stub) {
++ Label L;
++ __ cmpptr(Address(java_thread, JavaThread::tail_call_do_stack_compression_offset()), (int32_t)NULL_WORD);
++ __ jcc(Assembler::equal, L);
++ __ jump(RuntimeAddress(SharedRuntime::deopt_blob()->stack_compression()));
++ __ bind(L);
++ }
+ // check for pending exceptions
+ #ifdef ASSERT
+ Label L;
+@@ -2165,8 +2220,8 @@ class StubGenerator: public StubCodeGene
+ #endif /* ASSERT */
+ __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
+
+-
+- RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, framesize, oop_maps, false);
++ assert( __ pc() - start < insts_size, "Enough place for instructions");
++ RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, frame_size, oop_maps, false);
+ return stub->entry_point();
+ }
+
+@@ -2240,6 +2295,9 @@ class StubGenerator: public StubCodeGene
+ StubRoutines::_throw_NullPointerException_entry = generate_throw_exception("NullPointerException throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException), true);
+ StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call), false);
+ StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false);
++ StubRoutines::_throw_TailCallException_entry = generate_throw_exception("TailCallException throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_TailCallException), false);
++
++ StubRoutines::_tail_call_handle_stack_overflow_entry = generate_throw_exception("Tail call handle stack overflow", CAST_FROM_FN_PTR(address, SharedRuntime::tail_call_handle_stack_overflow), false, true);
+
+ //------------------------------------------------------------------------------------------------------------------------
+ // entry points that are platform specific
+diff -r ce2272390558 src/cpu/x86/vm/templateInterpreterGenerator_x86.hpp
+--- a/src/cpu/x86/vm/templateInterpreterGenerator_x86.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/templateInterpreterGenerator_x86.hpp Mon Mar 16 11:44:02 2009 +0100
@@ -24,6 +24,6 @@
protected:
@@ -1013,10 +1453,64 @@ diff --git a/src/cpu/x86/vm/templateInte
+void generate_fixed_frame(bool native_call, bool disable_osr=false);
// address generate_asm_interpreter_entry(bool synchronized);
-diff --git a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
---- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
-+++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
-@@ -132,7 +132,8 @@
+diff -r ce2272390558 src/cpu/x86/vm/templateInterpreter_x86_32.cpp
+--- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -34,6 +34,53 @@ const int locals_offset = frame::interpr
+ const int locals_offset = frame::interpreter_frame_locals_offset * wordSize;
+
+ //------------------------------------------------------------------------------------------------------------------------
++
++address TemplateInterpreterGenerator::generate_tail_call_stack_overflow_handler() {
++ address entry = __ pc();
++ // Check whether we should compress.
++ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::tail_call_handle_stack_overflow));
++ // Check result of previous operation.
++ {
++ Label L;
++ __ get_thread(rax);
++ __ cmpptr(Address(rax, JavaThread::tail_call_do_stack_compression_offset()), (int32_t)NULL_WORD);
++ __ jcc(Assembler::equal, L);
++ // When we get here an new interpreter frame sits on the stack. the
++ // expression stack is empty. no interpreter return address is on the stack.
++ // Stack compression expects this frame to be removed so we do.
++ __ leave();
++ address patch_addr = __ pc();
++ TemplateInterpreter::_tail_call_handle_stack_overflow_patch_address = patch_addr;
++ __ jump(RuntimeAddress((address) -1));
++ __ bind(L);
++ }
++ // Note: There should be a minimal interpreter frame set up when stack
++ // overflow occurs since we check explicitly for it now.
++ //
++#ifdef ASSERT
++ { Label L;
++ __ lea(rax, Address(rbp,
++ frame::interpreter_frame_monitor_block_top_offset * wordSize));
++ __ cmpptr(rax, rsp); // rax, = maximal rsp for current rbp,
++ // (stack grows negative)
++ __ jcc(Assembler::aboveEqual, L); // check if frame is complete
++ __ stop ("interpreter frame not set up");
++ __ bind(L);
++ }
++#endif // ASSERT
++
++ // Restore bcp under the assumption that the current frame is still
++ // interpreted
++ __ restore_bcp();
++
++ // expression stack must be empty before entering the VM if an exception
++ // happened
++ __ empty_expression_stack();
++ __ empty_FPU_stack();
++ // throw exception
++ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_StackOverflowError));
++ return entry;
++}
+
+ address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
+ address entry = __ pc();
+@@ -132,7 +179,8 @@ address TemplateInterpreterGenerator::ge
address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step) {
Label interpreter_entry;
address compiled_entry = __ pc();
@@ -1026,7 +1520,7 @@ diff --git a/src/cpu/x86/vm/templateInte
#ifdef COMPILER2
// The FPU stack is clean if UseSSE >= 2 but must be cleaned in other cases
if ((state == ftos && UseSSE < 1) || (state == dtos && UseSSE < 2)) {
-@@ -180,7 +181,10 @@
+@@ -180,7 +228,10 @@ address TemplateInterpreterGenerator::ge
__ restore_bcp();
__ restore_locals();
@@ -1038,7 +1532,26 @@ diff --git a/src/cpu/x86/vm/templateInte
__ movl(rbx, Address(rbx, rcx,
Address::times_ptr, constantPoolCacheOopDesc::base_offset() +
ConstantPoolCacheEntry::flags_offset()));
-@@ -526,7 +530,7 @@
+@@ -427,7 +478,6 @@ void InterpreterGenerator::generate_stac
+ // for the additional locals.
+ __ cmpl(rdx, (page_size - overhead_size)/Interpreter::stackElementSize());
+ __ jcc(Assembler::belowEqual, after_frame_check);
+-
+ // compute rsp as if this were going to be the last frame on
+ // the stack before the red zone
+
+@@ -441,10 +491,8 @@ void InterpreterGenerator::generate_stac
+
+ const Address stack_base(thread, Thread::stack_base_offset());
+ const Address stack_size(thread, Thread::stack_size_offset());
+-
+ // locals + overhead, in bytes
+ __ lea(rax, Address(noreg, rdx, Interpreter::stackElementScale(), overhead_size));
+-
+ #ifdef ASSERT
+ Label stack_base_okay, stack_size_okay;
+ // verify that thread stack base is non-zero
+@@ -526,7 +574,7 @@ void InterpreterGenerator::lock_method(v
// Generate a fixed interpreter frame. This is identical setup for interpreted methods
// and for native methods hence the shared code.
@@ -1047,7 +1560,7 @@ diff --git a/src/cpu/x86/vm/templateInte
// initialize fixed part of activation frame
__ push(rax); // save return address
__ enter(); // save old & set new rbp,
-@@ -558,6 +562,11 @@
+@@ -558,6 +606,11 @@ void TemplateInterpreterGenerator::gener
} else {
__ push(rsi); // set bcp
}
@@ -1059,10 +1572,18 @@ diff --git a/src/cpu/x86/vm/templateInte
__ push(0); // reserve word for pointer to expression stack bottom
__ movptr(Address(rsp, 0), rsp); // set expression stack bottom
}
-@@ -749,8 +758,38 @@
+@@ -748,7 +801,6 @@ address InterpreterGenerator::generate_n
+
if (inc_counter) __ movl(rcx, invocation_counter); // (pre-)fetch invocation count
// initialize fixed part of activation frame
-
+-
+ generate_fixed_frame(true);
+
+ // make sure method is native & not abstract
+@@ -1193,7 +1245,39 @@ address InterpreterGenerator::generate_n
+
+ if (inc_counter) __ movl(rcx, invocation_counter); // (pre-)fetch invocation count
+ // initialize fixed part of activation frame
+ // Tail calls want to disable OSR if we are comming from a compiled frame that
+ // tried to do a non sibling tail call and failed because the parent was not
+ // interpreted.
@@ -1080,7 +1601,7 @@ diff --git a/src/cpu/x86/vm/templateInte
+ __ jcc(Assembler::zero, normal_frame);
+ // Generate frame which temporary disables osr.
+ __ pop(temp); // restore register
-+ generate_fixed_frame(true, true);
++ generate_fixed_frame(false, true);
+ if (TraceTailCalls) __ warn("saw disabled osr");
+ __ push(temp);
+ // Turn osr back on (That is if DoOnStackReplacement is set to true).
@@ -1093,16 +1614,35 @@ diff --git a/src/cpu/x86/vm/templateInte
+ __ pop(temp);
+ }
+
- generate_fixed_frame(true);
+ generate_fixed_frame(false);
++ __ bind(disable_osr_frame_generated);
++ // generate_fixed_frame(false);
+
+ // make sure method is not native & not abstract
+ #ifdef ASSERT
+@@ -1236,7 +1320,7 @@ address InterpreterGenerator::generate_n
+ }
+ Label continue_after_compile;
+ __ bind(continue_after_compile);
-
-+ __ bind(disable_osr_frame_generated);
- // make sure method is native & not abstract
- #ifdef ASSERT
- __ movl(rax, access_flags);
-diff --git a/src/cpu/x86/vm/templateTable_x86_32.cpp b/src/cpu/x86/vm/templateTable_x86_32.cpp
---- a/src/cpu/x86/vm/templateTable_x86_32.cpp
-+++ b/src/cpu/x86/vm/templateTable_x86_32.cpp
-@@ -1699,6 +1699,21 @@
++
+ bang_stack_shadow_pages(false);
+
+ // reset the _do_not_unlock_if_synchronized flag
+@@ -1446,6 +1530,9 @@ int AbstractInterpreter::layout_activati
+ assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(), "Frame not properly walkable");
+ assert(caller->sp() == interpreter_frame->sender_sp(), "Frame not properly walkable(2)");
+ #endif
++
++ // set osr field (for tail calls)
++ //interpreter_frame->interpreter_frame_set_osr(0);
+
+ interpreter_frame->interpreter_frame_set_method(method);
+ // NOTE the difference in using sender_sp and interpreter_frame_sender_sp
+diff -r ce2272390558 src/cpu/x86/vm/templateTable_x86_32.cpp
+--- a/src/cpu/x86/vm/templateTable_x86_32.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/templateTable_x86_32.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -1699,6 +1699,23 @@ void TemplateTable::branch(bool is_jsr,
// invocation counter overflow
__ bind(backedge_counter_overflow);
@@ -1113,18 +1653,29 @@ diff --git a/src/cpu/x86/vm/templateTabl
+ // the interpreter.
+ __ push (rcx);
+ Address disable_osr_offset(rbp, frame::interpreter_frame_osr_offset * wordSize);
++ __ movl(rcx, disable_osr_offset);
+ __ testl(rcx, rcx);
+ __ jcc(Assembler::zero, continue_osr);
+ __ pop(rcx);
+ if (TraceTailCalls) __ warn("continue with loop because osr disabled");
+ __ jmp(dispatch);
+ __ bind(continue_osr);
++ if (TraceTailCalls) __ warn("backedge_counter_overflow: may be doing osr.");
+ __ pop(rcx);
+ }
__ negptr(rdx);
__ addptr(rdx, rsi); // branch bcp
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), rdx);
-@@ -2103,7 +2118,7 @@
+@@ -1727,7 +1744,7 @@ void TemplateTable::branch(bool is_jsr,
+ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin));
+ // rax, is OSR buffer, move it to expected parameter location
+ __ mov(rcx, rax);
+-
++ if (TraceTailCalls) __ warn("Performing OSR");
+ // pop the interpreter frame
+ __ movptr(rdx, Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize)); // get sender sp
+ __ leave(); // remove frame anchor
+@@ -2103,7 +2120,7 @@ void TemplateTable::volatile_barrier(Ass
__ membar(order_constraint);
}
@@ -1133,7 +1684,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
assert(byte_no == 1 || byte_no == 2, "byte_no out of range");
Register temp = rbx;
-@@ -2112,7 +2127,10 @@
+@@ -2112,7 +2129,10 @@ void TemplateTable::resolve_cache_and_in
const int shift_count = (1 + byte_no)*BitsPerByte;
Label resolved;
@@ -1145,7 +1696,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
__ movl(temp, Address(Rcache,
index,
Address::times_ptr,
-@@ -2139,7 +2157,10 @@
+@@ -2139,7 +2159,10 @@ void TemplateTable::resolve_cache_and_in
__ movl(temp, (int)bytecode());
__ call_VM(noreg, entry, temp);
// Update registers with resolved info
@@ -1157,7 +1708,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
__ bind(resolved);
}
-@@ -2169,6 +2190,7 @@
+@@ -2169,6 +2192,7 @@ void TemplateTable::load_field_cp_cache_
}
void TemplateTable::load_invoke_cp_cache_entry(int byte_no,
@@ -1165,7 +1716,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
Register method,
Register itable_index,
Register flags,
-@@ -2195,7 +2217,7 @@
+@@ -2195,13 +2219,30 @@ void TemplateTable::load_invoke_cp_cache
const int index_offset = in_bytes(constantPoolCacheOopDesc::base_offset() +
ConstantPoolCacheEntry::f2_offset());
@@ -1174,10 +1725,11 @@ diff --git a/src/cpu/x86/vm/templateTabl
__ movptr(method, Address(cache, index, Address::times_ptr, method_offset));
if (itable_index != noreg) {
-@@ -2204,6 +2226,23 @@
+ __ movptr(itable_index, Address(cache, index, Address::times_ptr, index_offset));
+ }
__ movl(flags , Address(cache, index, Address::times_ptr, flags_offset ));
- }
-
++}
++
+void TemplateTable::load_invoke_cp_cache_flags(int byte_no,
+ Register Rcache,
+ Register Rindex,
@@ -1193,12 +1745,10 @@ diff --git a/src/cpu/x86/vm/templateTabl
+
+ assert(wordSize == 4, "adjust code below");
+ __ movl(OutFlags , Address(Rcache, Rindex, Address::times_4, flags_offset ));
-+}
-+
-
- // The registers cache and index expected to be set before call.
- // Correct values of the cache and index registers are preserved.
-@@ -2255,7 +2294,7 @@
+ }
+
+
+@@ -2255,7 +2296,7 @@ void TemplateTable::getfield_or_static(i
const Register off = rbx;
const Register flags = rax;
@@ -1207,7 +1757,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
jvmti_post_field_access(cache, index, is_static, false);
load_field_cp_cache_entry(obj, cache, index, off, flags, is_static);
-@@ -2464,7 +2503,7 @@
+@@ -2464,7 +2505,7 @@ void TemplateTable::putfield_or_static(i
const Register off = rbx;
const Register flags = rax;
@@ -1216,7 +1766,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
jvmti_post_field_mod(cache, index, is_static);
load_field_cp_cache_entry(obj, cache, index, off, flags, is_static);
-@@ -2884,7 +2923,7 @@
+@@ -2884,7 +2925,7 @@ void TemplateTable::count_calls(Register
}
@@ -1225,7 +1775,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
// determine flags
const bool is_invokeinterface = code == Bytecodes::_invokeinterface;
const bool is_invokevirtual = code == Bytecodes::_invokevirtual;
-@@ -2900,7 +2939,7 @@
+@@ -2900,7 +2941,7 @@ void TemplateTable::prepare_invoke(Regis
// save 'interpreter return address'
__ save_bcp();
@@ -1234,7 +1784,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
// load receiver if needed (note: no return address pushed yet)
if (load_receiver) {
-@@ -2926,8 +2965,9 @@
+@@ -2926,8 +2967,9 @@ void TemplateTable::prepare_invoke(Regis
ConstantPoolCacheEntry::verify_tosBits();
// load return address
{
@@ -1246,7 +1796,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
__ movptr(flags, ArrayAddress(table, Address(noreg, flags, Address::times_ptr)));
}
-@@ -2942,15 +2982,49 @@
+@@ -2942,15 +2984,46 @@ void TemplateTable::prepare_invoke(Regis
}
}
@@ -1260,15 +1810,12 @@ diff --git a/src/cpu/x86/vm/templateTabl
+ __ verify_oop(klass);
+}
+
-+void TemplateTable::jcc_protection_domain_mismatch(Register temp, Register temp2, Register recv, Label& mismatch_cont, bool receiver_holds_klass) {
++void TemplateTable::jcc_protection_domain_mismatch(Register temp, Register temp2, Register recv_method, Label& mismatch_cont) {
+ // Check protection domains.
-+ // Get receiver PD.
-+ if (receiver_holds_klass) {
-+ __ movl (temp, Address(recv, instanceKlass::protection_domain_offset() * wordSize));
-+ } else {
-+ __ movl (temp, Address(recv, oopDesc::klass_offset_in_bytes()));
-+ __ movl (temp, Address(temp, instanceKlass::protection_domain_offset() * wordSize));
-+ }
++ // Get receiver method PD.
++ load_pool_holder_of_method(recv_method, temp);
++ __ verify_oop(temp);
++ __ movl (temp, Address(temp, instanceKlass::protection_domain_offset() * wordSize));
+ __ verify_oop(temp);
+ // Get caller PD.
+ __ movl (temp2, Address(rbp, frame::interpreter_frame_method_offset * wordSize));
@@ -1297,7 +1844,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
__ movl(rax, flags);
__ andl(rax, (1 << ConstantPoolCacheEntry::vfinalMethod));
__ jcc(Assembler::zero, notFinal);
-@@ -2966,8 +3040,13 @@
+@@ -2966,8 +3039,16 @@ void TemplateTable::invokevirtual_helper
// profile this call
__ profile_final_call(rax);
@@ -1306,14 +1853,17 @@ diff --git a/src/cpu/x86/vm/templateTabl
+
+ // Prepare for tail call.
+ if (is_tail_call) {
-+ jcc_protection_domain_mismatch(rax, rdx, recv, protection_domain_mismatch_cont, false);
++ if (TailCallsStackCompression)
++ jcc_protection_domain_mismatch(rax, rdx, method, regular_call_continuation);
++ else
++ jcc_protection_domain_mismatch(rax, rdx, method, protection_domain_mismatch_cont);
+ tail_call(byte_no, regular_call_continuation);
+ }
+ __ jump_from_interpreted(method, rax, is_tail_call);
__ bind(notFinal);
-@@ -2984,41 +3063,212 @@
+@@ -2984,41 +3065,220 @@ void TemplateTable::invokevirtual_helper
const int base = instanceKlass::vtable_start_offset() * wordSize;
assert(vtableEntry::size() * wordSize == 4, "adjust the scaling in the code below");
__ movptr(method, Address(rax, index, Address::times_ptr, base + vtableEntry::method_offset_in_bytes()));
@@ -1321,7 +1871,10 @@ diff --git a/src/cpu/x86/vm/templateTabl
+
+ if (is_tail_call) {
+ // Check protection domain.
-+ jcc_protection_domain_mismatch(rax, rdx, recv, protection_domain_mismatch_cont, false);
++ if (TailCallsStackCompression)
++ jcc_protection_domain_mismatch(rax, rdx, method, regular_call_continuation);
++ else
++ jcc_protection_domain_mismatch(rax, rdx, method, protection_domain_mismatch_cont);
+ // Shift arguments onto caller's outgoing parameter area
+ // pop frame.
+ tail_call(byte_no, regular_call_continuation);
@@ -1344,7 +1897,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
+ // c2i adapter sitting around that nobody takes care of. And that would not be
+ // nice (i.e result in a wrong rsp). This is also needed in order for lazy
+ // adapter frame creation in the not sibling tail call code path.
-+ __ parent_is_not_interpreter_jcc(temp, regular_call_continuation);
++ __ parent_is_not_interpreter_jcc(rbp, temp, regular_call_continuation);
+ // Assumption can use rdx, rdi since they contain no vital info. Rsi is
+ // computed from sender_sp so its free too. Other registers need to be saved.
+ // Store return_addr, link (old fp), sender_sp (old sp) to top of stack to
@@ -1458,12 +2011,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
+ __ profile_call(rax);
+ __ push(rax);
+ __ push(rdx);
-+ __ push(rcx);
-+ // Load the 'receiver' (e.g the class holding the method) class.
-+ load_pool_holder_of_method(rbx, rcx);
-+ __ verify_oop(rcx);
-+ jcc_protection_domain_mismatch(rax, rdx, rcx, protection_domain_mismatch_cont, true);
-+ __ pop(rcx);
++ jcc_protection_domain_mismatch(rax, rdx, rbx, protection_domain_mismatch_cont);
+ __ pop(rdx);
+ __ pop(rax);
+ tail_call(byte_no, regular_call_continuation);
@@ -1494,6 +2042,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
+void TemplateTable::wide_invokestatic(int byte_no) {
+ transition(vtos, vtos);
+ Label regular_call_continuation;
++ Label regular_call_continuation_pd_mismatch;
+ Label protection_domain_mismatch_cont;
+ // Bcp points to wide, advance to invoke instruction.
+ //__ increment(rsi, 1);
@@ -1502,25 +2051,34 @@ diff --git a/src/cpu/x86/vm/templateTabl
+ // do the call
+ __ verify_oop(rbx);
+ __ profile_call(rax);
-+ __ null_check(rcx); //receiver
++ //__ null_check(rcx); //receiver
+ // Store clobbered registers.
+ __ push(rax);
+ __ push(rdx);
+ __ push(rcx);
-+ // Load the 'receiver' (e.g the class holding the method) class.
-+ load_pool_holder_of_method(rbx, rcx);
-+ __ verify_oop(rcx);
-+ jcc_protection_domain_mismatch(rax, rdx, rcx, protection_domain_mismatch_cont, true);
++ __ push(rbx);
++ if (TailCallsStackCompression)
++ jcc_protection_domain_mismatch(rax, rdx, rbx, regular_call_continuation_pd_mismatch);
++ else
++ jcc_protection_domain_mismatch(rax, rdx, rbx, protection_domain_mismatch_cont);
++ __ pop(rbx);
+ __ pop(rcx);
+ __ pop(rdx);
+ __ pop(rax);
+ tail_call(byte_no, regular_call_continuation);
+ __ jump_from_interpreted(rbx, rax, true);
+ // not a tail call
-+ __ bind (regular_call_continuation);
++ __ bind (regular_call_continuation_pd_mismatch);
++ __ pop(rbx);
++ __ pop(rcx);
++ __ pop(rdx);
++ __ pop(rax);
++ __ bind(regular_call_continuation);
++ if (TraceTailCalls) __ warn("wide_invokestatic: not a tail call");
+ __ jump_from_interpreted(rbx, rax, false);
+ // Tail call exception on protection domain mismatch
+ __ bind(protection_domain_mismatch_cont);
++ __ pop(rbx);
+ __ pop(rcx);
+ __ pop(rdx);
+ __ pop(rax);
@@ -1531,7 +2089,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
void TemplateTable::fast_invokevfinal(int byte_no) {
transition(vtos, vtos);
-@@ -3027,8 +3277,23 @@
+@@ -3027,8 +3287,23 @@ void TemplateTable::fast_invokevfinal(in
void TemplateTable::invokeinterface(int byte_no) {
@@ -1556,7 +2114,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
// rax,: Interface
// rbx,: index
-@@ -3044,7 +3309,7 @@
+@@ -3044,7 +3319,7 @@ void TemplateTable::invokeinterface(int
__ andl(rdi, (1 << ConstantPoolCacheEntry::methodInterface));
__ jcc(Assembler::zero, notMethod);
@@ -1565,18 +2123,22 @@ diff --git a/src/cpu/x86/vm/templateTabl
__ bind(notMethod);
// Get receiver klass into rdx - also a null check
-@@ -3123,10 +3388,35 @@
+@@ -3123,10 +3398,42 @@ void TemplateTable::invokeinterface(int
__ bind(L);
}
+ Label regular_call_continuation;
++ Label regular_call_continuation_pd_mismatch;
+ Label protection_domain_mismatch_cont;
+ // If tail calling pop stack and move paramters.
+ if (is_tail_call) {
+ // rax, rdx are clobbered by jcc_protection_domain_mismatch
+ __ push(rax);
+ __ push(rdx);
-+ jcc_protection_domain_mismatch(rax, rdx, rcx, protection_domain_mismatch_cont, false);
++ if (TailCallsStackCompression)
++ jcc_protection_domain_mismatch(rax, rdx, rbx, regular_call_continuation_pd_mismatch);
++ else
++ jcc_protection_domain_mismatch(rax, rdx, rbx, protection_domain_mismatch_cont);
+ __ pop(rdx);
+ __ pop(rax);
+ // The bcp in rsi has been clobbered but is needed in tail_call.
@@ -1590,6 +2152,9 @@ diff --git a/src/cpu/x86/vm/templateTabl
- __ jump_from_interpreted(rbx, rdx);
+ __ jump_from_interpreted(rbx, rdx, is_tail_call);
+ // not a tail call
++ __ bind (regular_call_continuation_pd_mismatch);
++ __ pop(rdx);
++ __ pop(rax);
+ __ bind (regular_call_continuation);
+ __ jump_from_interpreted(rbx, rax, false);
+ // Tail call exception on protection domain mismatch
@@ -1602,9 +2167,9 @@ diff --git a/src/cpu/x86/vm/templateTabl
}
//----------------------------------------------------------------------------------------------------
-diff --git a/src/cpu/x86/vm/templateTable_x86_32.hpp b/src/cpu/x86/vm/templateTable_x86_32.hpp
---- a/src/cpu/x86/vm/templateTable_x86_32.hpp
-+++ b/src/cpu/x86/vm/templateTable_x86_32.hpp
+diff -r ce2272390558 src/cpu/x86/vm/templateTable_x86_32.hpp
+--- a/src/cpu/x86/vm/templateTable_x86_32.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/templateTable_x86_32.hpp Mon Mar 16 11:44:02 2009 +0100
@@ -22,10 +22,21 @@
*
*/
@@ -1620,7 +2185,7 @@ diff --git a/src/cpu/x86/vm/templateTabl
+ static void invokeinterface_helper(int byte_no, bool is_tail_call = false);
+
+ static void load_pool_holder_of_method(Register method, Register klass);
-+ static void jcc_protection_domain_mismatch(Register temp, Register temp2, Register recv, Label& mismatch_cont, bool receiver_holds_klass);
++ static void jcc_protection_domain_mismatch(Register temp, Register temp2, Register recv, Label& mismatch_cont);
+
+ static void tail_call(int byte_no, Label& regular_call_continuation);
+ // Tail call helper.
@@ -1630,10 +2195,10 @@ diff --git a/src/cpu/x86/vm/templateTabl
static void volatile_barrier(Assembler::Membar_mask_bits order_constraint );
// Helpers
-diff --git a/src/cpu/x86/vm/vtableStubs_x86_32.cpp b/src/cpu/x86/vm/vtableStubs_x86_32.cpp
---- a/src/cpu/x86/vm/vtableStubs_x86_32.cpp
-+++ b/src/cpu/x86/vm/vtableStubs_x86_32.cpp
-@@ -39,9 +39,9 @@
+diff -r ce2272390558 src/cpu/x86/vm/vtableStubs_x86_32.cpp
+--- a/src/cpu/x86/vm/vtableStubs_x86_32.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/vtableStubs_x86_32.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -39,9 +39,9 @@ extern "C" void bad_compiled_vtable_inde
// Leave receiver in rcx; required behavior when +OptoArgsInRegisters
// is modifed to put first oop in rcx.
//
@@ -1645,16 +2210,44 @@ diff --git a/src/cpu/x86/vm/vtableStubs_
ResourceMark rm;
CodeBuffer cb(s->entry_point(), i486_code_length);
MacroAssembler* masm = new MacroAssembler(&cb);
-@@ -77,11 +77,21 @@
+@@ -58,9 +58,27 @@ VtableStub* VtableStubs::create_vtable_s
+
+ // get receiver klass
+ address npe_addr = __ pc();
++
+ __ movptr(rax, Address(rcx, oopDesc::klass_offset_in_bytes()));
++
+ // compute entry offset (in words)
+ int entry_offset = instanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size();
++
++ Label pd_mismatch;
++ // check protection domains match
++ if (is_tail_call) {
++ // Protection domain slot [esp+4] contains caller klass.
++ __ movl(rbx, Address(rsp, wordSize));
++ __ movl(rbx, Address(rbx, instanceKlass::protection_domain_offset()*wordSize));
++ // Get method_holder's pd. First get methodOop. Then do
++ // methodOop.constant_pool.class.protection_domain.
++ __ movptr(rdi, Address(rax, entry_offset*wordSize + vtableEntry::method_offset_in_bytes()));
++ __ movptr(rdi, Address(rdi, methodOopDesc::constants_offset()));
++ __ movptr(rdi, Address(rdi, constantPoolOopDesc::pool_holder_offset_in_bytes()));
++ __ cmpl(rbx, Address(rdi, instanceKlass::protection_domain_offset()*wordSize));
++ __ jcc(Assembler::notEqual, pd_mismatch);
++ }
++
+ #ifndef PRODUCT
+ if (DebugVtables) {
+ Label L;
+@@ -77,11 +95,21 @@ VtableStub* VtableStubs::create_vtable_s
// load methodOop and target address
__ movptr(method, Address(rax, entry_offset*wordSize + vtableEntry::method_offset_in_bytes()));
+
+ ByteSize method_entry_offset = in_ByteSize(0);
+ if (is_tail_call && is_sibling) {
-+ method_entry_offset = methodOopDesc::from_compiled_static_tail_call_offset();
++ method_entry_offset = methodOopDesc::from_compiled_tail_call_offset();
+ } else if (is_tail_call) {
-+ method_entry_offset = methodOopDesc::from_compiled_not_sibling_static_tail_call_offset();
++ method_entry_offset = methodOopDesc::from_compiled_not_sibling_tail_call_offset();
+ } else {
+ method_entry_offset = methodOopDesc::from_compiled_offset();
+ }
@@ -1668,16 +2261,29 @@ diff --git a/src/cpu/x86/vm/vtableStubs_
__ jcc(Assembler::notZero, L);
__ stop("Vtable entry is NULL");
__ bind(L);
-@@ -91,7 +101,7 @@
+@@ -91,7 +119,20 @@ VtableStub* VtableStubs::create_vtable_s
// method (rbx): methodOop
// rcx: receiver
address ame_addr = __ pc();
- __ jmp( Address(method, methodOopDesc::from_compiled_offset()));
+ __ jmp( Address(method, method_entry_offset));
++
++ if (is_tail_call) {
++ __ bind(pd_mismatch); // Protection domain mismatch.
++ if (TraceTailCalls) __ warn ("vtable tail call pd mismatch");
++ if (TailCallsStackCompression) {
++ // Jump to normal method entry. TODO: Need new exception point.
++ __ movptr(rax, Address(rcx, oopDesc::klass_offset_in_bytes()));
++ __ movptr(method, Address(rax, entry_offset*wordSize + vtableEntry::method_offset_in_bytes()));
++ __ jmp(Address(method, methodOopDesc::from_compiled_offset()));
++ } else {
++ __ jump(RuntimeAddress(StubRoutines::throw_TailCallException_entry()));
++ }
++ }
masm->flush();
s->set_exception_points(npe_addr, ame_addr);
-@@ -99,11 +109,11 @@
+@@ -99,11 +140,11 @@ VtableStub* VtableStubs::create_vtable_s
}
@@ -1691,15 +2297,31 @@ diff --git a/src/cpu/x86/vm/vtableStubs_
ResourceMark rm;
CodeBuffer cb(s->entry_point(), i486_code_length);
MacroAssembler* masm = new MacroAssembler(&cb);
-@@ -170,13 +180,21 @@
+@@ -120,9 +161,15 @@ VtableStub* VtableStubs::create_itable_s
+ // get receiver (need to skip return address on top of stack)
+
+ assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx");
++#ifdef COMPILER2
++ if (is_tail_call) {
++ __ movl(rdi, rsi); // Opto tail calls store the base pointer in rsi.
++ }
++#endif
+
+ // get receiver klass (also an implicit null-check)
+ address npe_addr = __ pc();
++
+ __ movptr(rbx, Address(rcx, oopDesc::klass_offset_in_bytes()));
+
+ __ mov(rsi, rbx); // Save klass in free register
+@@ -170,21 +217,49 @@ VtableStub* VtableStubs::create_itable_s
// method (rbx): methodOop
// rcx: receiver
+ ByteSize method_entry_offset = in_ByteSize(0);
+ if (is_tail_call && is_sibling) {
-+ method_entry_offset = methodOopDesc::from_compiled_static_tail_call_offset();
++ method_entry_offset = methodOopDesc::from_compiled_tail_call_offset();
+ } else if (is_tail_call) {
-+ method_entry_offset = methodOopDesc::from_compiled_not_sibling_static_tail_call_offset();
++ method_entry_offset = methodOopDesc::from_compiled_not_sibling_tail_call_offset();
+ } else {
+ method_entry_offset = methodOopDesc::from_compiled_offset();
+ }
@@ -1714,19 +2336,584 @@ diff --git a/src/cpu/x86/vm/vtableStubs_
__ jcc(Assembler::notZero, L1);
__ stop("methodOop is null");
__ bind(L1);
-@@ -184,7 +202,7 @@
+ }
#endif // ASSERT
++#ifdef COMPILER2
++ if (is_tail_call) {
++ // restore rsi (contains base pointer for tail calls).
++ __ movl (rsi, rdi);
++ }
++#endif
++
++ Label pd_mismatch;
++ // Check protection domains match. Clobbers: rdi, rax
++ if (is_tail_call) {
++ // Protection domain slot [esp+4] contains caller klass.
++ __ movl(rdi, Address(rsp, wordSize));
++ __ movl(rdi, Address(rdi, instanceKlass::protection_domain_offset()*wordSize));
++ // Get receiver klass.
++ __ movptr(rax, Address(method, methodOopDesc::constants_offset()));
++ __ movptr(rax, Address(rax, constantPoolOopDesc::pool_holder_offset_in_bytes()));
++ __ cmpl(rdi, Address(rax, instanceKlass::protection_domain_offset()*wordSize));
++ __ jcc(Assembler::notEqual, pd_mismatch);
++ }
++
address ame_addr = __ pc();
- __ jmp(Address(method, methodOopDesc::from_compiled_offset()));
+ __ jmp(Address(method, method_entry_offset));
__ bind(throw_icce);
// Restore saved register
-diff --git a/src/share/tools/hsdis/Makefile b/src/share/tools/hsdis/Makefile
---- a/src/share/tools/hsdis/Makefile
-+++ b/src/share/tools/hsdis/Makefile
-@@ -65,6 +65,7 @@
+@@ -192,7 +267,16 @@ VtableStub* VtableStubs::create_itable_s
+ __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
+
+ masm->flush();
+-
++
++ if (is_tail_call) {
++ __ bind(pd_mismatch); // Protection domain mismatch.
++ if (TraceTailCalls) __ warn("itable tail call pd mismatch");
++ if (TailCallsStackCompression) {
++ __ jmp(Address(method, methodOopDesc::from_compiled_offset()));
++ } else {
++ __ jump(RuntimeAddress(StubRoutines::throw_TailCallException_entry()));
++ }
++ }
+ guarantee(__ pc() <= s->code_end(), "overflowed buffer");
+
+ s->set_exception_points(npe_addr, ame_addr);
+@@ -204,10 +288,12 @@ int VtableStub::pd_code_size_limit(bool
+ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
+ if (is_vtable_stub) {
+ // Vtable stub size
+- return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0);
++ // Tail calls check that protection domains match.
++ // TODO: get the size right!
++ return (TailCalls ? 256 : 0) + (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0);
+ } else {
+ // Itable stub size
+- return (DebugVtables ? 144 : 64) + (CountCompiledCalls ? 6 : 0);
++ return (TailCalls ? 256 : 0) +(DebugVtables ? 144 : 64) + (CountCompiledCalls ? 6 : 0);
+ }
+ }
+
+diff -r ce2272390558 src/cpu/x86/vm/x86_32.ad
+--- a/src/cpu/x86/vm/x86_32.ad Mon Mar 09 13:34:00 2009 -0700
++++ b/src/cpu/x86/vm/x86_32.ad Mon Mar 16 11:44:02 2009 +0100
+@@ -272,11 +272,11 @@ static jlong *double_signflip_pool = dou
+ // from the start of the call to the point where the return address
+ // will point.
+ int MachCallStaticJavaNode::ret_addr_offset() {
+- return 5 + (Compile::current()->in_24_bit_fp_mode() ? 6 : 0); // 5 bytes from start of call to where return address points
++ return 5 + (Compile::current()->in_24_bit_fp_mode() ? 6 : 0) + (_is_tail_call ? 7+11 : 0); // 5 bytes from start of call to where return address points
+ }
+
+ int MachCallDynamicJavaNode::ret_addr_offset() {
+- return 10 + (Compile::current()->in_24_bit_fp_mode() ? 6 : 0); // 10 bytes from start of call to where return address points
++ return 10 + (Compile::current()->in_24_bit_fp_mode() ? 6 : 0) + (_is_tail_call ? 14+11 : 0); // 10 bytes from start of call to where return address points
+ }
+
+ static int sizeof_FFree_Float_Stack_All = -1;
+@@ -299,6 +299,12 @@ bool SafePointNode::needs_polling_addres
+ // The address of the call instruction needs to be 4-byte aligned to
+ // ensure that it does not span a cache line so that it can be patched.
+ int CallStaticJavaDirectNode::compute_padding(int current_offset) const {
++ if (_is_tail_call) {
++ // emit lea ebp [esp-framesize] before every call
++ current_offset += 7;
++ // mov [esp-4] ret_addr; subptr 4 esp
++ current_offset += 11;
++ }
+ if (Compile::current()->in_24_bit_fp_mode())
+ current_offset += 6; // skip fldcw in pre_call_FPU, if any
+ current_offset += 1; // skip call opcode byte
+@@ -308,6 +314,14 @@ int CallStaticJavaDirectNode::compute_pa
+ // The address of the call instruction needs to be 4-byte aligned to
+ // ensure that it does not span a cache line so that it can be patched.
+ int CallDynamicJavaDirectNode::compute_padding(int current_offset) const {
++ if (_is_tail_call) {
++ // emit lea ebp [esp-framesize] before every call
++ current_offset += 7;
++ // mov [esp+0] noop
++ current_offset += 7;
++ // mov [esp-4] ret_addr; subptr 4 esp
++ current_offset += 11;
++ }
+ if (Compile::current()->in_24_bit_fp_mode())
+ current_offset += 6; // skip fldcw in pre_call_FPU, if any
+ current_offset += 5; // skip MOV instruction
+@@ -1158,12 +1172,36 @@ void emit_java_to_interp(CodeBuffer &cbu
+ __ end_a_stub();
+ // Update current stubs pointer and restore code_end.
+ }
++void emit_java_to_interp_tail_call(CodeBuffer &cbuf ) {
++ // Stub is fixed up when the corresponding call is converted from calling
++ // compiled code to calling interpreted code.
++ // mov rbx,0
++ // jmp -1
++ // Note that the code buffer's inst_mark is always relative to insts.
++ // That's why we must use the macroassembler to generate a stub.
++ MacroAssembler _masm(&cbuf);
++ address call_pc = __ pc()-5;
++ address base =
++ __ start_a_stub(Compile::MAX_stubs_size);
++ if (base == NULL) return; // CodeBuffer::expand failed
++ // static stub relocation stores the instruction address of the call
++ __ relocate(static_stub_Relocation::spec(call_pc), RELOC_IMM32);
++ // static stub relocation also tags the methodOop in the code-stream.
++ __ movoop(rbx, (jobject)NULL); // method is zapped till fixup time
++ // This is recognized as unresolved by relocs/nativeInst/ic code
++ __ jump(RuntimeAddress(__ pc()));
++
++ __ end_a_stub();
++ // Update current stubs pointer and restore code_end.
++}
++
+ // size of call stub, compiled java to interpretor
+ uint size_java_to_interp() {
+ return 10; // movl; jmp
+ }
+ // relocation entries for call stub, compiled java to interpretor
+ uint reloc_java_to_interp() {
++ if (TailCalls) return 4 + 4;
+ return 4; // 3 in emit_java_to_interp + 1 in Java_Static_Call
+ }
+
+@@ -1236,6 +1274,283 @@ uint size_deopt_handler() {
+ // Note that this value is also credited (in output.cpp) to
+ // the size of the code section.
+ return 5 + NativeJump::instruction_size; // pushl(); jmp;
++}
++
++relocInfo::tailCallType tail_call_type_for_call(bool is_tail_call, bool is_sibling) {
++ if(!is_tail_call) return relocInfo::not_tail_call;
++ else if (is_tail_call && is_sibling) return relocInfo::sibling_tail_call_type;
++ else {
++ assert (is_tail_call && !is_sibling, "oops");
++ return relocInfo::not_sibling_tail_call_type;
++ }
++}
++
++void emit_tail_call_argument_move(MacroAssembler & _masm, int arg_slots) {
++ // Copy the args to tail call position using register rbx.
++ Register tmp = rbx;
++ // Don't need to move the protection domain slot.
++ for (int slot = 1+SharedRuntime::tail_call_protection_domain_slots(); slot <= arg_slots; slot++) {
++ Address src (rsp, VMRegImpl::stack_slot_size * (SharedRuntime::out_preserve_stack_slots()+slot));
++ // Need to add safed eip slot so slot+1 VVV
++ Address dest(rsi, VMRegImpl::stack_slot_size * (SharedRuntime::out_preserve_stack_slots()+slot+1));
++ __ movl(tmp, src);
++ __ movl(dest, tmp);
++ }
++}
++
++void tail_call_leave(MacroAssembler & _masm) {
++ // Rsi holds rbp in opto tail calls.
++ __ mov(rsp, rsi);
++ __ pop(rbp);
++}
++
++uint size_verified_not_sib_tail_call_stub(int arg_slots) {
++ // TODO: get real size.
++ return (8 * arg_slots) + 512;
++}
++
++uint size_verified_tail_call_stub(int arg_slots) {
++ // TODO: get real size.
++ return (8 * arg_slots) + 256;
++}
++
++void emit_verified_not_sib_tail_call_stub(CodeBuffer& cbuf, int arg_slots, int VEP_offset, CodeOffsets & code_offsets) {
++ MacroAssembler _masm(&cbuf);
++ Label call_to_interpreter;
++ int stub_size = size_verified_not_sib_tail_call_stub(arg_slots);
++ // Generate code for static tail call (we know that klass and protection
++ // domain is correct).
++ address handler_base = __ start_a_stub(stub_size);
++ if (handler_base == NULL) {
++ assert(false, "static tail call stub overflow");
++ // not enough space left for the handler
++ return;
++ }
++#ifdef ASSERT
++ int offset = __ offset();
++#endif // ASSERT
++ __ align(CodeEntryAlignment);
++ code_offsets.set_value(CodeOffsets::Verified_Not_Sibling_Tail_Call_Entry, __ offset());
++
++ if (TraceTailCalls) __ warn("Opto Compiled entry point: Verified_Not_Sibling_Tail_Call_Entry");
++ // Fast case: parent is interpreter. This means we can extend its stack frame.
++ // Assume: rax, rbx are scratch. rbx would hold methodOop, rax the IC_klass token
++ Register tmp = rax; // scratch
++ Register last_sp = rbx; // scratch
++ Register base_pointer = rsi; // opto specific
++ __ parent_is_not_interpreter_jcc(base_pointer, rbx, call_to_interpreter);
++ // Store old rbp
++ __ movl(tmp, Address(base_pointer, frame::link_offset*wordSize));
++ __ push(tmp);
++ // Store ret address.
++ __ movl(tmp, Address(base_pointer, frame::return_addr_offset * wordSize));
++ __ push(tmp);
++
++
++ // Get last_sp from parent frame.
++ __ movl(tmp, Address(base_pointer, frame::link_offset * wordSize)); // old rbp
++ __ movl(last_sp, Address(tmp, frame::interpreter_frame_last_sp_offset * wordSize));
++ // Shuffle arguments
++ for (int src_slot = arg_slots, dest_slot=-1; src_slot > 0; src_slot--, dest_slot--) {
++ // saved old_rbp, old_retaddr on top of stack => +2
++ Address src(rsp, VMRegImpl::stack_slot_size * (2+src_slot));
++ Address dest(last_sp, VMRegImpl::stack_slot_size * (dest_slot));
++ __ movl(tmp, src);
++ __ movl(dest, tmp);
++ }
++ // Set return address.
++ __ subl(last_sp, (1+arg_slots)*wordSize);
++ __ pop(tmp);
++ __ movl(Address(last_sp, 0), tmp);
++ // Set new rbp
++ __ pop(rbp);
++ // Set new rsp. Need to do this after the pop!
++ __ movl(rsp, last_sp);
++ // jump to VEP
++ address vep_entry = cbuf.insts()->start() + VEP_offset;
++ RelocationHolder rh = section_call_Relocation::spec(vep_entry, CodeBuffer::SECT_INSTS);
++ // Jump to vep.
++ __ jump(AddressLiteral((address)vep_entry, rh));
++ // Slow case: parent is not interpreted. Jump to interpreter entry of called
++ // function in order to lazily create an interpreted frame on the stack.
++ __ bind(call_to_interpreter);
++ code_offsets.set_value(CodeOffsets::Verified_Not_Sibling_Tail_Call_Set_Data_Entry, __ offset());
++ // Set methodoop.
++ __ movoop(rbx, (jobject)Universe::non_oop_word());
++ // Jump to C2I Entry Point
++ __ jump(RuntimeAddress((address)-1));
++ // TODO: adapt static_tail_call_stub_size
++ assert(__ offset() - offset <= stub_size, "overflow");
++ __ end_a_stub();
++}
++
++void emit_verified_tail_call_stub(Compile * C, CodeBuffer& cbuf, int arg_slots, int frame_size, CodeOffsets & code_offsets) {
++ MacroAssembler _masm(&cbuf);
++ int stub_size = size_verified_tail_call_stub(arg_slots);
++ // Generate code for static tail call (we know that klass and protection
++ // domain is correct).
++ address handler_base = __ start_a_stub(stub_size);
++ if (handler_base == NULL) {
++ // not enough space left for the handler
++ return;
++ }
++#ifdef ASSERT
++ int offset = __ offset();
++#endif // ASSERT
++
++ __ align(CodeEntryAlignment);
++ code_offsets.set_value(CodeOffsets::Verified_Tail_Call_Entry, __ offset());
++ if (TraceTailCalls) __ warn("Opto Compiled entry point: Verified_Tail_Call_Entry");
++ // Check that there is enough space on the stack.
++ if (C->need_stack_bang(frame_size)) {
++ MacroAssembler masm(&cbuf);
++ masm.generate_stack_overflow_check(frame_size);
++ }
++ // Move arguments.
++ emit_tail_call_argument_move(_masm, arg_slots);
++ // Remove tail calling caller's stack frame.
++ //tail_call_leave(_masm);
++ __ leal(rsp, Address(rsi, -frame_size));
++ // Compute target of jump. Verified entry point of current method.
++ address vep_entry = cbuf.insts()->start() +
++ code_offsets.value(CodeOffsets::Frame_Complete);
++ RelocationHolder rh = section_call_Relocation::spec(vep_entry, CodeBuffer::SECT_INSTS);
++ // Jump to vep.
++ __ jump(AddressLiteral((address)vep_entry, rh));
++
++ // TODO: adapt static_tail_call_stub_size
++ assert(__ offset() - offset <= stub_size, "opto overflow");
++ __ end_a_stub();
++}
++
++uint size_not_sib_tail_call_stub(int arg_slots) {
++ // TODO: get real size.
++ return 8*arg_slots + 512;
++}
++
++uint size_tail_call_stub(int arg_slots) {
++ // TODO: get real size.
++ return 8*arg_slots + 256;
++}
++
++void emit_not_sib_tail_call_stub(CodeBuffer& cbuf, int arg_slots, int VEP_offset, CodeOffsets& code_offsets) {
++ MacroAssembler _masm(&cbuf);
++ Label call_to_interpreter;
++ int stub_size = size_not_sib_tail_call_stub(arg_slots);
++ address handler_base = __ start_a_stub(stub_size);
++ if (handler_base == NULL) {
++ // not enough space left for the handler
++ assert(false, "static tail call stub overflow");
++ return;
++ }
++#ifdef ASSERT
++ int offset = __ offset();
++#endif // ASSERT
++ __ align(CodeEntryAlignment);
++ code_offsets.set_value(CodeOffsets::Not_Sibling_Tail_Call_Entry, __ offset());
++ if (TraceTailCalls) __ warn("Opto Compiled entry point: Not_Sibling_Tail_Call_Entry");
++ // Check icache
++ __ cmpptr(rax, Address(rcx, oopDesc::klass_offset_in_bytes()));
++ __ jump_cc(Assembler::notEqual,
++ RuntimeAddress(SharedRuntime::get_ic_miss_stub()));
++ // Fast case: parent is interpreter. This means we can extend its stack frame.
++ // Assume: rax, rbx are scratch here since rax is needed only for
++ // check_icache. rbx would hold methodOop, rax the IC_klass token
++ Register tmp = rax; // scratch
++ Register last_sp = rbx; // scratch
++ Register base_pointer = rsi;
++ __ parent_is_not_interpreter_jcc(base_pointer, tmp, call_to_interpreter);
++ // Store old rbp
++ __ movl(tmp, Address(base_pointer, frame::link_offset*wordSize));
++ __ push(tmp);
++ // Store ret address.
++ __ movl(tmp, Address(base_pointer, frame::return_addr_offset * wordSize));
++ __ push(tmp);
++
++ // when debugging the return addr pointer remove the 2 __ a_long() lines in
++ // templateInterpreter_x86_32.cpp to get a sensible assembler output
++ //__ stop("static_not_sibling_call, parent is interpreted rax contains ret_entry");
++
++ // Get last_sp from parent frame.
++ __ movl(tmp, Address(base_pointer, frame::link_offset * wordSize)); // old rbp
++ __ movl(last_sp, Address(tmp, frame::interpreter_frame_last_sp_offset * wordSize));
++ // Shuffle arguments
++ for (int src_slot = arg_slots, dest_slot=-1; src_slot > 0; src_slot--, dest_slot--) {
++ // saved old_rbp, old_retaddr on top of stack => +2
++ Address src(rsp, VMRegImpl::stack_slot_size * (2+src_slot));
++ Address dest(last_sp, VMRegImpl::stack_slot_size * (dest_slot));
++ __ movl(tmp, src);
++ __ movl(dest, tmp);
++ }
++ // Set return address.
++ __ subl(last_sp, (1+arg_slots)*wordSize);
++ __ pop(tmp);
++ __ movl(Address(last_sp, 0), tmp);
++ // Set new rbp
++ __ pop(rbp);
++ // Set new rsp. Need to do this after the pop!
++ __ movl(rsp, last_sp);
++ // jump to VEP
++ address vep_entry = cbuf.insts()->start() + VEP_offset;
++ RelocationHolder rh = section_call_Relocation::spec(vep_entry, CodeBuffer::SECT_INSTS);
++ // Jump to vep.
++ __ jump(AddressLiteral((address)vep_entry, rh));
++ // Slow case: parent is not interpreted. Jump to interpreter entry of called
++ // function in order to lazily create an interpreted frame on the stack.
++ __ bind(call_to_interpreter);
++ code_offsets.set_value(CodeOffsets::Not_Sibling_Tail_Call_Set_Data_Entry, __ offset());
++ // Set methodoop.
++ __ movoop(rbx, (jobject)Universe::non_oop_word());
++ // Jump to C2I Entry Point
++ __ jump(RuntimeAddress((address)-1));
++ // TODO: adapt static_tail_call_stub_size
++ assert(__ offset() - offset <= stub_size, "overflow");
++ __ end_a_stub();
++}
++
++void emit_tail_call_stub(Compile * C, CodeBuffer& cbuf, int arg_slots, int frame_size, CodeOffsets & code_offsets) {
++ MacroAssembler _masm(&cbuf);
++ int stub_size = size_tail_call_stub(arg_slots);
++ // Generate code for tail call, check klass token.
++ address handler_base = __ start_a_stub(stub_size);
++ if (handler_base == NULL) {
++ assert(false, "not enough space in tail call stub");
++ // not enough space left for the handler
++ return;
++ }
++#ifdef ASSERT
++ int offset = __ offset();
++#endif // ASSERT
++
++ __ align(CodeEntryAlignment);
++ code_offsets.set_value(CodeOffsets::Tail_Call_Entry, __ offset());
++ if (TraceTailCalls) __ warn("Opto Compiled entry point: Tail_Call_Entry");
++
++ // Check icache
++ __ cmpptr(rax, Address(rcx, oopDesc::klass_offset_in_bytes()));
++ __ jump_cc(Assembler::notEqual,
++ RuntimeAddress(SharedRuntime::get_ic_miss_stub()));
++ // Check for enough stack space.
++ if (C->need_stack_bang(frame_size)) {
++ MacroAssembler masm(&cbuf);
++ masm.generate_stack_overflow_check(frame_size);
++ }
++ // Move arguments.
++ emit_tail_call_argument_move(_masm, arg_slots);
++ // Remove tail calling caller's stack frame.
++ //tail_call_leave(_masm);
++ __ leal(rsp, Address(rsi, -frame_size));
++
++ // Compute target of jump. Verified entry point of current method.
++ address vep_entry = cbuf.insts()->start()
++ + code_offsets.value(CodeOffsets::Frame_Complete);
++ RelocationHolder rh = section_call_Relocation::spec(vep_entry, CodeBuffer::SECT_INSTS);
++ // Jump to vep.
++ __ jump(AddressLiteral((address)vep_entry, rh));
++
++ // TODO: adapt static_tail_call_stub_size
++ assert(__ offset() - offset <= stub_size, "opto overflow");
++ __ end_a_stub();
+ }
+
+ // Emit deopt handler code.
+@@ -1789,37 +2104,94 @@ encode %{
+ enc_class Java_Static_Call (method meth) %{ // JAVA STATIC CALL
+ // CALL to fixup routine. Fixup routine uses ScopeDesc info to determine
+ // who we intended to call.
+- cbuf.set_inst_mark();
+- $$$emit8$primary;
+- if ( !_method ) {
+- emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.code_end()) - 4),
+- runtime_call_Relocation::spec(), RELOC_IMM32 );
+- } else if(_optimized_virtual) {
+- emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.code_end()) - 4),
+- opt_virtual_call_Relocation::spec(), RELOC_IMM32 );
+- } else {
+- emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.code_end()) - 4),
+- static_call_Relocation::spec(), RELOC_IMM32 );
+- }
+- if( _method ) { // Emit stub for static call
+- emit_java_to_interp(cbuf);
++ if(_is_tail_call) {
++ // load base pointer to rsi for tail calls.
++ Compile* C = ra_->C;
++ int framesize = C->frame_slots() << LogBytesPerInt;
++ framesize -= 2*wordSize; // EBP,RET
++
++ cbuf.set_inst_mark();
++ emit_opcode(cbuf, 0x8D); // LEA ESI,[SP-framesize] 1byte
++ emit_rm(cbuf, 0x2, ESI_enc, 0x04); // 1 byte
++ emit_rm(cbuf, 0x0, 0x04, ESP_enc); // 1 byte
++ emit_d32(cbuf, framesize);
++ }
++ relocInfo::tailCallType rtype = tail_call_type_for_call(_is_tail_call, _is_sibling);
++ if (_is_tail_call) {
++ MacroAssembler masm(&cbuf);
++ Label return_address;
++ RelocationHolder rh = _optimized_virtual ?
++ opt_virtual_call_Relocation::spec(rtype) :
++ static_call_Relocation::spec(rtype);
++ masm.mov_label(Address(rsp,-4), return_address);
++ masm.subl (rsp, wordSize); //jmp_literal
++ masm.tail_call_jmp_literal((address)_entry_point, rh);
++ masm.bind(return_address);
++ emit_java_to_interp_tail_call(cbuf);
++ } else {
++ cbuf.set_inst_mark();
++ $$$emit8$primary;
++ if ( !_method ) {
++ emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.code_end()) - 4),
++ runtime_call_Relocation::spec(), RELOC_IMM32 );
++ } else if(_optimized_virtual) {
++ emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.code_end()) - 4),
++ opt_virtual_call_Relocation::spec(rtype), RELOC_IMM32 );
++ } else {
++ emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.code_end()) - 4),
++ static_call_Relocation::spec(rtype), RELOC_IMM32 );
++ }
++ if( _method ) { // Emit stub for static call
++ emit_java_to_interp(cbuf);
++ }
+ }
+ %}
+
+ enc_class Java_Dynamic_Call (method meth) %{ // JAVA DYNAMIC CALL
++ if(_is_tail_call) {
++ // load base pointer to rsi for tail calls.
++ Compile* C = ra_->C;
++ int framesize = C->frame_slots() << LogBytesPerInt;
++ framesize -= 2*wordSize; // EBP,RET
++
++ cbuf.set_inst_mark();
++ emit_opcode(cbuf, 0x8D); // LEA ESI,[SP-framesize] 1byte
++ emit_rm(cbuf, 0x2, ESI_enc, 0x04); // 1 byte
++ emit_rm(cbuf, 0x0, 0x04, ESP_enc); // 1 byte
++ emit_d32(cbuf, framesize);
++ // protection domain token
++ {
++ MacroAssembler _masm(&cbuf);
++ // 7bytes
++ int before_offset = __ offset();
++ __ movoop(Address(rsp, 0), (jobject)Universe::non_oop_word());
++ assert (__ offset() - before_offset == 7, "Must have size 7.");
++ }
++ }
+ // !!!!!
+ // Generate "Mov EAX,0x00", placeholder instruction to load oop-info
+ // emit_call_dynamic_prologue( cbuf );
+ cbuf.set_inst_mark();
+ emit_opcode(cbuf, 0xB8 + EAX_enc); // mov EAX,-1
+ emit_d32_reloc(cbuf, (int)Universe::non_oop_word(), oop_Relocation::spec_for_immediate(), RELOC_IMM32);
++ relocInfo::tailCallType rtype = tail_call_type_for_call(_is_tail_call, _is_sibling);
+ address virtual_call_oop_addr = cbuf.inst_mark();
+ // CALL to fixup routine. Fixup routine uses ScopeDesc info to determine
+ // who we intended to call.
+- cbuf.set_inst_mark();
+- $$$emit8$primary;
+- emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.code_end()) - 4),
+- virtual_call_Relocation::spec(virtual_call_oop_addr), RELOC_IMM32 );
++ if (_is_tail_call) {
++ RelocationHolder rh = virtual_call_Relocation::spec(virtual_call_oop_addr, NULL, rtype);
++ MacroAssembler masm(&cbuf);
++ Label return_address;
++ masm.mov_label(Address(rsp,-4), return_address);
++ masm.subl (rsp, wordSize); //jmp_literal
++ masm.tail_call_jmp_literal((address)_entry_point, rh);
++ masm.bind(return_address);
++ } else {
++ cbuf.set_inst_mark();
++ $$$emit8$primary;
++ emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.code_end()) - 4),
++ virtual_call_Relocation::spec(virtual_call_oop_addr, NULL, rtype), RELOC_IMM32 );
++ }
+ %}
+
+ enc_class Java_Compiled_Call (method meth) %{ // JAVA COMPILED CALL
+@@ -4564,8 +4936,8 @@ frame %{
+ // a new frame. The PROLOG must add this many slots to the stack. The
+ // EPILOG must remove this many slots. Intel needs one slot for
+ // return address and one for rbp, (must save rbp)
++ //in_preserve_stack_slots(2+VerifyStackAtCalls);
+ in_preserve_stack_slots(2+VerifyStackAtCalls);
+-
+ // Number of outgoing stack slots killed above the out_preserve_stack_slots
+ // for calls to C. Supports the var-args backing area for register parms.
+ varargs_C_out_slots_killed(0);
+diff -r ce2272390558 src/os/solaris/vm/os_solaris.cpp
+--- a/src/os/solaris/vm/os_solaris.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/os/solaris/vm/os_solaris.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -3770,6 +3770,7 @@ int set_lwp_priority (int ThreadID,
+ int maxClamped = MIN2(iaLimits.maxPrio, (int)iaInfo->ia_uprilim);
+ iaInfo->ia_upri = scale_to_lwp_priority(iaLimits.minPrio, maxClamped, newPrio);
+ iaInfo->ia_uprilim = IA_NOCHANGE;
++ iaInfo->ia_nice = IA_NOCHANGE;
+ iaInfo->ia_mode = IA_NOCHANGE;
+ if (ThreadPriorityVerbose) {
+ tty->print_cr ("IA: [%d...%d] %d->%d\n",
+diff -r ce2272390558 src/os_cpu/linux_x86/vm/os_linux_x86.cpp
+--- a/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -261,7 +261,7 @@ JVM_handle_linux_signal(int sig,
+
+ // check if fault address is within thread stack
+ if (addr < thread->stack_base() &&
+- addr >= thread->stack_base() - thread->stack_size()) {
++ addr >= thread->stack_base() - thread->stack_size()) {
+ // stack overflow
+ if (thread->in_stack_yellow_zone(addr)) {
+ thread->disable_stack_yellow_zone();
+diff -r ce2272390558 src/share/tools/hsdis/Makefile
+--- a/src/share/tools/hsdis/Makefile Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/tools/hsdis/Makefile Mon Mar 16 11:44:02 2009 +0100
+@@ -65,6 +65,7 @@ OS = linux
OS = linux
CC = gcc
CCFLAGS += -O
@@ -1734,17 +2921,17 @@ diff --git a/src/share/tools/hsdis/Makef
DLDFLAGS += -shared
OUTFLAGS += -o $@
LIB_EXT = .so
-diff --git a/src/share/tools/hsdis/hsdis-demo.c b/src/share/tools/hsdis/hsdis-demo.c
---- a/src/share/tools/hsdis/hsdis-demo.c
-+++ b/src/share/tools/hsdis/hsdis-demo.c
-@@ -221,3 +221,4 @@
+diff -r ce2272390558 src/share/tools/hsdis/hsdis-demo.c
+--- a/src/share/tools/hsdis/hsdis-demo.c Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/tools/hsdis/hsdis-demo.c Mon Mar 16 11:44:02 2009 +0100
+@@ -221,3 +221,4 @@ void disassemble(void* from, void* to) {
if (res != to)
printf("*** Result was %p!\n", res);
}
+
-diff --git a/src/share/tools/hsdis/hsdis.c b/src/share/tools/hsdis/hsdis.c
---- a/src/share/tools/hsdis/hsdis.c
-+++ b/src/share/tools/hsdis/hsdis.c
+diff -r ce2272390558 src/share/tools/hsdis/hsdis.c
+--- a/src/share/tools/hsdis/hsdis.c Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/tools/hsdis/hsdis.c Mon Mar 16 11:44:02 2009 +0100
@@ -29,6 +29,7 @@
#include "hsdis.h"
@@ -1753,48 +2940,47 @@ diff --git a/src/share/tools/hsdis/hsdis
#include <sysdep.h>
#include <libiberty.h>
#include <bfd.h>
-diff --git a/src/share/tools/hsdis/hsdis.h b/src/share/tools/hsdis/hsdis.h
---- a/src/share/tools/hsdis/hsdis.h
-+++ b/src/share/tools/hsdis/hsdis.h
-@@ -65,3 +65,4 @@
+diff -r ce2272390558 src/share/tools/hsdis/hsdis.h
+--- a/src/share/tools/hsdis/hsdis.h Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/tools/hsdis/hsdis.h Mon Mar 16 11:44:02 2009 +0100
+@@ -65,3 +65,4 @@ typedef void* (*decode_instructions_ftyp
decode_instructions_printf_callback_ftype printf_callback,
void* printf_stream,
const char* options);
+
-diff --git a/src/share/vm/asm/codeBuffer.hpp b/src/share/vm/asm/codeBuffer.hpp
---- a/src/share/vm/asm/codeBuffer.hpp
-+++ b/src/share/vm/asm/codeBuffer.hpp
-@@ -39,6 +39,13 @@
+diff -r ce2272390558 src/share/vm/asm/codeBuffer.hpp
+--- a/src/share/vm/asm/codeBuffer.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/asm/codeBuffer.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -39,6 +39,12 @@ public:
Dtrace_trap = OSR_Entry, // dtrace probes can never have an OSR entry so reuse it
Exceptions, // Offset where exception handler lives
Deopt, // Offset where deopt handler lives
-+ Static_Tail_Call_Entry, // Offset for static tail calls.
-+ Static_Not_Sibling_Tail_Call_Entry,
-+ Monomorphic_Tail_Call_Entry, // Offset for monomorphic tail
-+ // calls.
-+ Monomorphic_Not_Sibling_Tail_Call_Entry,
-+ Static_Not_Sibling_Tail_Call_Set_Data_Entry,
-+ Monomorphic_Not_Sibling_Tail_Call_Set_Data_Entry,
++ Verified_Tail_Call_Entry, // Offset for verified tail calls.
++ Verified_Not_Sibling_Tail_Call_Entry,
++ Tail_Call_Entry, // Offset for monomorphic tail calls.
++ Not_Sibling_Tail_Call_Entry,
++ Verified_Not_Sibling_Tail_Call_Set_Data_Entry,
++ Not_Sibling_Tail_Call_Set_Data_Entry,
max_Entries };
// special value to note codeBlobs where profile (forte) stack walking is
-@@ -57,6 +64,12 @@
+@@ -57,6 +63,12 @@ public:
_values[OSR_Entry] = 0;
_values[Exceptions] = -1;
_values[Deopt] = -1;
-+ _values[Static_Tail_Call_Entry] = 0;
-+ _values[Monomorphic_Tail_Call_Entry] = 0;
-+ _values[Monomorphic_Not_Sibling_Tail_Call_Entry] = 0;
-+ _values[Static_Not_Sibling_Tail_Call_Entry] = 0;
-+ _values[Static_Not_Sibling_Tail_Call_Set_Data_Entry] = 0;
-+ _values[Monomorphic_Not_Sibling_Tail_Call_Set_Data_Entry] = 0;
++ _values[Verified_Tail_Call_Entry] = 0;
++ _values[Tail_Call_Entry] = 0;
++ _values[Not_Sibling_Tail_Call_Entry] = 0;
++ _values[Verified_Not_Sibling_Tail_Call_Entry] = 0;
++ _values[Verified_Not_Sibling_Tail_Call_Set_Data_Entry] = 0;
++ _values[Not_Sibling_Tail_Call_Set_Data_Entry] = 0;
}
int value(Entries e) { return _values[e]; }
-diff --git a/src/share/vm/c1/c1_Compilation.cpp b/src/share/vm/c1/c1_Compilation.cpp
---- a/src/share/vm/c1/c1_Compilation.cpp
-+++ b/src/share/vm/c1/c1_Compilation.cpp
-@@ -218,7 +218,14 @@
+diff -r ce2272390558 src/share/vm/c1/c1_Compilation.cpp
+--- a/src/share/vm/c1/c1_Compilation.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/c1/c1_Compilation.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -218,7 +218,14 @@ void Compilation::emit_code_epilog(LIR_A
CHECK_BAILOUT();
assembler->emit_deopt_handler();
CHECK_BAILOUT();
@@ -1810,7 +2996,7 @@ diff --git a/src/share/vm/c1/c1_Compilat
// done
masm()->flush();
}
-@@ -274,8 +281,13 @@
+@@ -274,8 +281,13 @@ int Compilation::compile_java_method() {
{
PhaseTraceTime timeit(_t_emit_lir);
@@ -1826,10 +3012,10 @@ diff --git a/src/share/vm/c1/c1_Compilat
emit_lir();
}
CHECK_BAILOUT_(no_frame_size);
-diff --git a/src/share/vm/c1/c1_FrameMap.cpp b/src/share/vm/c1/c1_FrameMap.cpp
---- a/src/share/vm/c1/c1_FrameMap.cpp
-+++ b/src/share/vm/c1/c1_FrameMap.cpp
-@@ -49,7 +49,7 @@
+diff -r ce2272390558 src/share/vm/c1/c1_FrameMap.cpp
+--- a/src/share/vm/c1/c1_FrameMap.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/c1/c1_FrameMap.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -49,7 +49,7 @@ BasicTypeArray* FrameMap::signature_type
}
@@ -1838,7 +3024,7 @@ diff --git a/src/share/vm/c1/c1_FrameMap
// compute the size of the arguments first. The signature array
// that java_calling_convention takes includes a T_VOID after double
// work items but our signatures do not.
-@@ -76,12 +76,14 @@
+@@ -76,12 +76,14 @@ CallingConvention* FrameMap::java_callin
BasicType t = sig_bt[i];
assert(t != T_VOID, "should be skipping these");
@@ -1854,7 +3040,7 @@ diff --git a/src/share/vm/c1/c1_FrameMap
}
i += type2size[t];
}
-@@ -90,7 +92,10 @@
+@@ -90,7 +92,10 @@ CallingConvention* FrameMap::java_callin
if (outgoing) {
// update the space reserved for arguments.
@@ -1866,10 +3052,20 @@ diff --git a/src/share/vm/c1/c1_FrameMap
}
return new CallingConvention(args, out_preserve);
}
-diff --git a/src/share/vm/c1/c1_FrameMap.hpp b/src/share/vm/c1/c1_FrameMap.hpp
---- a/src/share/vm/c1/c1_FrameMap.hpp
-+++ b/src/share/vm/c1/c1_FrameMap.hpp
-@@ -144,7 +144,7 @@
+@@ -161,7 +166,8 @@ FrameMap::FrameMap(ciMethod* method, int
+ assert(monitors >= 0, "not set");
+ _num_monitors = monitors;
+ assert(reserved_argument_area_size >= 0, "not set");
+- _reserved_argument_area_size = MAX2(4, reserved_argument_area_size) * BytesPerWord;
++ int min_ougoing_arg_size = MAX2(MinOutgoingArgStackSlotSize, 4);
++ _reserved_argument_area_size = MAX2(min_ougoing_arg_size, reserved_argument_area_size) * BytesPerWord;
+
+ _argcount = method->arg_size();
+ _argument_locations = new intArray(_argcount, -1);
+diff -r ce2272390558 src/share/vm/c1/c1_FrameMap.hpp
+--- a/src/share/vm/c1/c1_FrameMap.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/c1/c1_FrameMap.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -144,7 +144,7 @@ class FrameMap : public CompilationResou
// stack addresses are expressable in a simm13.
bool validate_frame();
@@ -1878,7 +3074,7 @@ diff --git a/src/share/vm/c1/c1_FrameMap
public:
// Opr representing the stack_pointer on this platform
-@@ -156,7 +156,7 @@
+@@ -156,7 +156,7 @@ class FrameMap : public CompilationResou
// for outgoing calls, these also update the reserved area to
// include space for arguments and any ABI area.
CallingConvention* c_calling_convention (const BasicTypeArray* signature);
@@ -1887,10 +3083,10 @@ diff --git a/src/share/vm/c1/c1_FrameMap
// deopt support
ByteSize sp_offset_for_orig_pc() { return sp_offset_for_monitor_base(_num_monitors); }
-diff --git a/src/share/vm/c1/c1_GraphBuilder.cpp b/src/share/vm/c1/c1_GraphBuilder.cpp
---- a/src/share/vm/c1/c1_GraphBuilder.cpp
-+++ b/src/share/vm/c1/c1_GraphBuilder.cpp
-@@ -1504,6 +1504,8 @@
+diff -r ce2272390558 src/share/vm/c1/c1_GraphBuilder.cpp
+--- a/src/share/vm/c1/c1_GraphBuilder.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/c1/c1_GraphBuilder.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -1504,6 +1504,8 @@ Dependencies* GraphBuilder::dependency_r
void GraphBuilder::invoke(Bytecodes::Code code) {
bool will_link;
@@ -1899,7 +3095,7 @@ diff --git a/src/share/vm/c1/c1_GraphBui
ciMethod* target = stream()->get_method(will_link);
// we have to make sure the argument size (incl. the receiver)
// is correct for compilation (the call would fail later during
-@@ -1718,7 +1720,7 @@
+@@ -1718,7 +1720,7 @@ void GraphBuilder::invoke(Bytecodes::Cod
profile_call(recv, target_klass);
}
@@ -1908,19 +3104,19 @@ diff --git a/src/share/vm/c1/c1_GraphBui
// push result
append_split(result);
-@@ -3332,7 +3334,7 @@
+@@ -3332,7 +3334,7 @@ bool GraphBuilder::try_inline_full(ciMet
!InlineSynchronizedMethods ) INLINE_BAILOUT("callee is synchronized");
if (!callee->holder()->is_initialized()) INLINE_BAILOUT("callee's klass not initialized yet");
if (!callee->has_balanced_monitors()) INLINE_BAILOUT("callee's monitors do not match");
-
-+ if (callee->contains_tail_call()) INLINE_BAILOUT("callee contains a tail call");
++ if (!stream()->is_wide() && callee->contains_tail_call()) INLINE_BAILOUT("callee contains a tail call but caller is no tail calling");
// Proper inlining of methods with jsrs requires a little more work.
if (callee->has_jsrs() ) INLINE_BAILOUT("jsrs not handled properly by inliner yet");
-diff --git a/src/share/vm/c1/c1_Instruction.cpp b/src/share/vm/c1/c1_Instruction.cpp
---- a/src/share/vm/c1/c1_Instruction.cpp
-+++ b/src/share/vm/c1/c1_Instruction.cpp
-@@ -334,7 +334,7 @@
+diff -r ce2272390558 src/share/vm/c1/c1_Instruction.cpp
+--- a/src/share/vm/c1/c1_Instruction.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/c1/c1_Instruction.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -334,7 +334,7 @@ void Intrinsic::state_values_do(void f(V
Invoke::Invoke(Bytecodes::Code code, ValueType* result_type, Value recv, Values* args,
@@ -1929,7 +3125,7 @@ diff --git a/src/share/vm/c1/c1_Instruct
: StateSplit(result_type)
, _code(code)
, _recv(recv)
-@@ -345,7 +345,7 @@
+@@ -345,7 +345,7 @@ Invoke::Invoke(Bytecodes::Code code, Val
set_flag(TargetIsLoadedFlag, target->is_loaded());
set_flag(TargetIsFinalFlag, target_is_loaded() && target->is_final_method());
set_flag(TargetIsStrictfpFlag, target_is_loaded() && target->is_strict());
@@ -1938,10 +3134,10 @@ diff --git a/src/share/vm/c1/c1_Instruct
assert(args != NULL, "args must exist");
#ifdef ASSERT
values_do(assert_value);
-diff --git a/src/share/vm/c1/c1_Instruction.hpp b/src/share/vm/c1/c1_Instruction.hpp
---- a/src/share/vm/c1/c1_Instruction.hpp
-+++ b/src/share/vm/c1/c1_Instruction.hpp
-@@ -312,7 +312,8 @@
+diff -r ce2272390558 src/share/vm/c1/c1_Instruction.hpp
+--- a/src/share/vm/c1/c1_Instruction.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/c1/c1_Instruction.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -312,7 +312,8 @@ class Instruction: public CompilationRes
NeedsPatchingFlag,
ThrowIncompatibleClassChangeErrorFlag,
ProfileMDOFlag,
@@ -1951,7 +3147,7 @@ diff --git a/src/share/vm/c1/c1_Instruct
};
public:
-@@ -1144,7 +1145,7 @@
+@@ -1144,7 +1145,7 @@ LEAF(Invoke, StateSplit)
public:
// creation
Invoke(Bytecodes::Code code, ValueType* result_type, Value recv, Values* args,
@@ -1960,20 +3156,20 @@ diff --git a/src/share/vm/c1/c1_Instruct
// accessors
Bytecodes::Code code() const { return _code; }
-@@ -1162,6 +1163,9 @@
+@@ -1161,6 +1162,9 @@ LEAF(Invoke, StateSplit)
+ bool target_is_loaded() const { return check_flag(TargetIsLoadedFlag); }
// Returns false if target is not loaded
bool target_is_strictfp() const { return check_flag(TargetIsStrictfpFlag); }
-
++
+ // Is this a tail call?
+ bool is_tail_call() const { return check_flag(TailCallFlag); }
-+
+
// generic
virtual bool can_trap() const { return true; }
- virtual void input_values_do(void f(Value*)) {
-diff --git a/src/share/vm/c1/c1_LIR.hpp b/src/share/vm/c1/c1_LIR.hpp
---- a/src/share/vm/c1/c1_LIR.hpp
-+++ b/src/share/vm/c1/c1_LIR.hpp
-@@ -1032,25 +1032,28 @@
+diff -r ce2272390558 src/share/vm/c1/c1_LIR.hpp
+--- a/src/share/vm/c1/c1_LIR.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/c1/c1_LIR.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -1032,25 +1032,28 @@ class LIR_OpJavaCall: public LIR_OpCall
private:
ciMethod* _method;
LIR_Opr _receiver;
@@ -2007,7 +3203,7 @@ diff --git a/src/share/vm/c1/c1_LIR.hpp
intptr_t vtable_offset() const {
assert(_code == lir_virtual_call, "only have vtable for real vcall");
-@@ -1751,20 +1754,20 @@
+@@ -1751,20 +1754,20 @@ class LIR_List: public CompilationResour
//---------- instructions -------------
void call_opt_virtual(ciMethod* method, LIR_Opr receiver, LIR_Opr result,
address dest, LIR_OprList* arguments,
@@ -2036,10 +3232,10 @@ diff --git a/src/share/vm/c1/c1_LIR.hpp
}
void get_thread(LIR_Opr result) { append(new LIR_Op0(lir_get_thread, result)); }
-diff --git a/src/share/vm/c1/c1_LIRAssembler.cpp b/src/share/vm/c1/c1_LIRAssembler.cpp
---- a/src/share/vm/c1/c1_LIRAssembler.cpp
-+++ b/src/share/vm/c1/c1_LIRAssembler.cpp
-@@ -411,10 +411,11 @@
+diff -r ce2272390558 src/share/vm/c1/c1_LIRAssembler.cpp
+--- a/src/share/vm/c1/c1_LIRAssembler.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/c1/c1_LIRAssembler.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -411,10 +411,11 @@ void LIR_Assembler::emit_rtcall(LIR_OpRT
void LIR_Assembler::emit_call(LIR_OpJavaCall* op) {
verify_oop_map(op->info());
@@ -2054,7 +3250,7 @@ diff --git a/src/share/vm/c1/c1_LIRAssem
}
// emit the static call stub stuff out of line
-@@ -428,7 +429,7 @@
+@@ -428,7 +429,7 @@ void LIR_Assembler::emit_call(LIR_OpJava
call(op->addr(), relocInfo::opt_virtual_call_type, op->info());
break;
case lir_icvirtual_call:
@@ -2063,7 +3259,7 @@ diff --git a/src/share/vm/c1/c1_LIRAssem
break;
case lir_virtual_call:
vtable_call(op->vtable_offset(), op->info());
-@@ -570,6 +571,7 @@
+@@ -570,6 +571,7 @@ void LIR_Assembler::emit_op0(LIR_Op0* op
case lir_std_entry:
// init offsets
@@ -2071,10 +3267,10 @@ diff --git a/src/share/vm/c1/c1_LIRAssem
offsets()->set_value(CodeOffsets::OSR_Entry, _masm->offset());
_masm->align(CodeEntryAlignment);
if (needs_icache(compilation()->method())) {
-diff --git a/src/share/vm/c1/c1_LIRAssembler.hpp b/src/share/vm/c1/c1_LIRAssembler.hpp
---- a/src/share/vm/c1/c1_LIRAssembler.hpp
-+++ b/src/share/vm/c1/c1_LIRAssembler.hpp
-@@ -129,6 +129,10 @@
+diff -r ce2272390558 src/share/vm/c1/c1_LIRAssembler.hpp
+--- a/src/share/vm/c1/c1_LIRAssembler.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/c1/c1_LIRAssembler.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -129,6 +129,10 @@ class LIR_Assembler: public CompilationR
// stubs
void emit_slow_case_stubs();
void emit_static_call_stub();
@@ -2085,18 +3281,19 @@ diff --git a/src/share/vm/c1/c1_LIRAssem
void emit_code_stub(CodeStub* op);
void add_call_info_here(CodeEmitInfo* info) { add_call_info(code_offset(), info); }
-@@ -205,7 +209,9 @@
+@@ -205,7 +209,10 @@ class LIR_Assembler: public CompilationR
void comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr result, LIR_Op2* op);
void cmove(LIR_Condition code, LIR_Opr left, LIR_Opr right, LIR_Opr result);
- void ic_call(address destination, CodeEmitInfo* info);
+ // Set protection domain token for virtual tail calls.
+ void set_protection_domain_token();
++ void tail_call(address destination, RelocationHolder & rh);
+ void ic_call(address destination, CodeEmitInfo* info, bool is_tail_call);
void vtable_call(int vtable_offset, CodeEmitInfo* info);
void call(address entry, relocInfo::relocType rtype, CodeEmitInfo* info);
-@@ -217,7 +223,7 @@
+@@ -217,7 +224,7 @@ class LIR_Assembler: public CompilationR
void monitor_address(int monitor_ix, LIR_Opr dst);
void align_backward_branch_target();
@@ -2105,10 +3302,10 @@ diff --git a/src/share/vm/c1/c1_LIRAssem
void negate(LIR_Opr left, LIR_Opr dest);
void leal(LIR_Opr left, LIR_Opr dest);
-diff --git a/src/share/vm/c1/c1_LIRGenerator.cpp b/src/share/vm/c1/c1_LIRGenerator.cpp
---- a/src/share/vm/c1/c1_LIRGenerator.cpp
-+++ b/src/share/vm/c1/c1_LIRGenerator.cpp
-@@ -2257,6 +2257,16 @@
+diff -r ce2272390558 src/share/vm/c1/c1_LIRGenerator.cpp
+--- a/src/share/vm/c1/c1_LIRGenerator.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/c1/c1_LIRGenerator.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -2257,6 +2257,18 @@ void LIRGenerator::do_OsrEntry(OsrEntry*
__ move(LIR_Assembler::osrBufferPointer(), result);
}
@@ -2119,13 +3316,15 @@ diff --git a/src/share/vm/c1/c1_LIRGener
+ //int incoming_args_slots = MAX2(4,
+ // frame_map()->incoming_arguments()->reserved_stack_slots());
+ int incoming_args_slots = frame_map()->incoming_arguments()->reserved_stack_slots();
++ int min_ougoing_arg_size = MAX2(MinOutgoingArgStackSlotSize, 4);
++ incoming_args_slots = MAX2(min_ougoing_arg_size, incoming_args_slots);
+ int outgoing_args_slots = callee_cc->reserved_stack_slots();
+ return outgoing_args_slots <= incoming_args_slots;
+}
void LIRGenerator::invoke_load_arguments(Invoke* x, LIRItemList* args, const LIR_OprList* arg_list) {
int i = x->has_receiver() ? 1 : 0;
-@@ -2291,7 +2301,7 @@
+@@ -2291,7 +2303,7 @@ void LIRGenerator::invoke_load_arguments
// Visits all arguments, returns appropriate items without loading them
@@ -2134,7 +3333,7 @@ diff --git a/src/share/vm/c1/c1_LIRGener
LIRItemList* argument_items = new LIRItemList();
if (x->has_receiver()) {
LIRItem* receiver = new LIRItem(x->receiver(), this);
-@@ -2300,6 +2310,16 @@
+@@ -2300,6 +2312,16 @@ LIRItemList* LIRGenerator::invoke_visit_
int idx = x->has_receiver() ? 1 : 0;
for (int i = 0; i < x->number_of_arguments(); i++) {
LIRItem* param = new LIRItem(x->argument_at(i), this);
@@ -2151,7 +3350,7 @@ diff --git a/src/share/vm/c1/c1_LIRGener
argument_items->append(param);
idx += (param->type()->is_double_word() ? 2 : 1);
}
-@@ -2331,11 +2351,15 @@
+@@ -2331,11 +2353,15 @@ LIRItemList* LIRGenerator::invoke_visit_
// - if we keep the receiver locked while doing spill-save,
// we cannot spill it as it is spill-locked
//
@@ -2169,7 +3368,7 @@ diff --git a/src/share/vm/c1/c1_LIRGener
LIR_Opr receiver = LIR_OprFact::illegalOpr;
// setup result register
-@@ -2359,9 +2383,19 @@
+@@ -2359,9 +2385,19 @@ void LIRGenerator::do_Invoke(Invoke* x)
switch (x->code()) {
case Bytecodes::_invokestatic:
@@ -2192,7 +3391,7 @@ diff --git a/src/share/vm/c1/c1_LIRGener
break;
case Bytecodes::_invokespecial:
case Bytecodes::_invokevirtual:
-@@ -2369,13 +2403,32 @@
+@@ -2369,13 +2405,32 @@ void LIRGenerator::do_Invoke(Invoke* x)
// for final target we still produce an inline cache, in order
// to be able to call mixed mode
if (x->code() == Bytecodes::_invokespecial || optimized) {
@@ -2200,19 +3399,16 @@ diff --git a/src/share/vm/c1/c1_LIRGener
+ if (is_tail && is_sibling) {
+ __ call_opt_virtual(x->target(), receiver, result_register,
+ SharedRuntime::get_resolve_opt_virtual_tail_call_stub(),
-+ arg_list, info);
++ arg_list, info, is_tail);
+ } else if (is_tail) {
+ __ call_opt_virtual(x->target(), receiver, result_register,
+ SharedRuntime::get_resolve_opt_not_sibling_virtual_tail_call_stub(),
-+ arg_list, info);
++ arg_list, info, is_tail);
+ } else
+ __ call_opt_virtual(x->target(), receiver, result_register,
SharedRuntime::get_resolve_opt_virtual_call_stub(),
- arg_list, info);
- } else if (x->vtable_index() < 0) {
-- __ call_icvirtual(x->target(), receiver, result_register,
-- SharedRuntime::get_resolve_virtual_call_stub(),
-- arg_list, info);
++ arg_list, info, is_tail);
++ } else if (x->vtable_index() < 0) {
+ if (is_tail && is_sibling) {
+ __ call_icvirtual(x->target(), receiver, result_register,
+ SharedRuntime::get_resolve_virtual_tail_call_stub(),
@@ -2224,15 +3420,19 @@ diff --git a/src/share/vm/c1/c1_LIRGener
+ } else {
+ __ call_icvirtual(x->target(), receiver, result_register,
+ SharedRuntime::get_resolve_virtual_call_stub(),
-+ arg_list, info);
+ arg_list, info);
+- } else if (x->vtable_index() < 0) {
+- __ call_icvirtual(x->target(), receiver, result_register,
+- SharedRuntime::get_resolve_virtual_call_stub(),
+- arg_list, info);
+ }
} else {
int entry_offset = instanceKlass::vtable_start_offset() + x->vtable_index() * vtableEntry::size();
int vtable_offset = entry_offset * wordSize + vtableEntry::method_offset_in_bytes();
-diff --git a/src/share/vm/c1/c1_LIRGenerator.hpp b/src/share/vm/c1/c1_LIRGenerator.hpp
---- a/src/share/vm/c1/c1_LIRGenerator.hpp
-+++ b/src/share/vm/c1/c1_LIRGenerator.hpp
-@@ -30,6 +30,7 @@
+diff -r ce2272390558 src/share/vm/c1/c1_LIRGenerator.hpp
+--- a/src/share/vm/c1/c1_LIRGenerator.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/c1/c1_LIRGenerator.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -30,6 +30,7 @@ class Invoke;
class Invoke;
class SwitchRange;
class LIRItem;
@@ -2240,7 +3440,7 @@ diff --git a/src/share/vm/c1/c1_LIRGener
define_array(LIRItemArray, LIRItem*)
define_stack(LIRItemList, LIRItemArray)
-@@ -269,8 +270,10 @@
+@@ -269,8 +270,10 @@ class LIRGenerator: public InstructionVi
ciObject* get_jobject_constant(Value value);
@@ -2248,14 +3448,14 @@ diff --git a/src/share/vm/c1/c1_LIRGener
+ LIRItemList* invoke_visit_arguments(Invoke* x, bool is_tail_call);
void invoke_load_arguments(Invoke* x, LIRItemList* args, const LIR_OprList* arg_list);
+ // Tail call optimization support
-+ bool is_sibling_call(CallingConvention* callee_cc);
++ bool is_sibling_call(CallingConvention * callee_cc);
void trace_block_entry(BlockBegin* block);
-diff --git a/src/share/vm/c1/c1_Runtime1.cpp b/src/share/vm/c1/c1_Runtime1.cpp
---- a/src/share/vm/c1/c1_Runtime1.cpp
-+++ b/src/share/vm/c1/c1_Runtime1.cpp
-@@ -140,9 +140,18 @@
+diff -r ce2272390558 src/share/vm/c1/c1_Runtime1.cpp
+--- a/src/share/vm/c1/c1_Runtime1.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/c1/c1_Runtime1.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -140,9 +140,18 @@ void Runtime1::setup_code_buffer(CodeBuf
locs_buffer_size / sizeof(relocInfo));
code->initialize_consts_size(desired_max_constant_size());
// Call stubs + deopt/exception handler
@@ -2275,10 +3475,10 @@ diff --git a/src/share/vm/c1/c1_Runtime1
}
-diff --git a/src/share/vm/ci/ciMethod.cpp b/src/share/vm/ci/ciMethod.cpp
---- a/src/share/vm/ci/ciMethod.cpp
-+++ b/src/share/vm/ci/ciMethod.cpp
-@@ -49,6 +49,9 @@
+diff -r ce2272390558 src/share/vm/ci/ciMethod.cpp
+--- a/src/share/vm/ci/ciMethod.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/ci/ciMethod.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -49,6 +49,9 @@ ciMethod::ciMethod(methodHandle h_m) : c
_handler_count = h_m()->exception_table()->length() / 4;
_uses_monitors = h_m()->access_flags().has_monitor_bytecodes();
_balanced_monitors = !_uses_monitors || h_m()->access_flags().is_monitor_matching();
@@ -2288,7 +3488,7 @@ diff --git a/src/share/vm/ci/ciMethod.cp
_is_compilable = !h_m()->is_not_compilable();
// Lazy fields, filled in on demand. Require allocation.
_code = NULL;
-@@ -124,6 +127,8 @@
+@@ -124,6 +127,8 @@ ciMethod::ciMethod(ciInstanceKlass* hold
_bcea = NULL;
_method_blocks = NULL;
_method_data = NULL;
@@ -2297,10 +3497,14 @@ diff --git a/src/share/vm/ci/ciMethod.cp
#ifdef COMPILER2
_flow = NULL;
#endif // COMPILER2
-@@ -290,6 +295,47 @@
- return true;
- }
-
+@@ -286,6 +291,47 @@ bool ciMethod::has_balanced_monitors() {
+ }
+ method->set_guaranteed_monitor_matching();
+ _balanced_monitors = true;
++ }
++ return true;
++}
++
+// ------------------------------------------------------------------
+// ciMethod::uses_balanced_monitors
+//
@@ -2338,17 +3542,13 @@ diff --git a/src/share/vm/ci/ciMethod.cp
+ }
+ method->set_contains_tail_call(true);
+ _contains_tail_call = true;
-+ }
-+ return true;
-+}
-+
-
- // ------------------------------------------------------------------
- // ciMethod::get_flow_analysis
-diff --git a/src/share/vm/ci/ciMethod.hpp b/src/share/vm/ci/ciMethod.hpp
---- a/src/share/vm/ci/ciMethod.hpp
-+++ b/src/share/vm/ci/ciMethod.hpp
-@@ -62,6 +62,8 @@
+ }
+ return true;
+ }
+diff -r ce2272390558 src/share/vm/ci/ciMethod.hpp
+--- a/src/share/vm/ci/ciMethod.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/ci/ciMethod.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -62,6 +62,8 @@ class ciMethod : public ciObject {
bool _balanced_monitors;
bool _is_compilable;
bool _can_be_statically_bound;
@@ -2357,7 +3557,7 @@ diff --git a/src/share/vm/ci/ciMethod.hp
// Lazy fields, filled in on demand
address _code;
-@@ -148,6 +150,7 @@
+@@ -148,6 +150,7 @@ class ciMethod : public ciObject {
bool uses_monitors() const { return _uses_monitors; } // this one should go away, it has a misleading name
bool has_monitor_bytecodes() const { return _uses_monitors; }
bool has_balanced_monitors();
@@ -2365,10 +3565,10 @@ diff --git a/src/share/vm/ci/ciMethod.hp
MethodLivenessResult liveness_at_bci(int bci);
-diff --git a/src/share/vm/ci/ciStreams.cpp b/src/share/vm/ci/ciStreams.cpp
---- a/src/share/vm/ci/ciStreams.cpp
-+++ b/src/share/vm/ci/ciStreams.cpp
-@@ -88,10 +88,9 @@
+diff -r ce2272390558 src/share/vm/ci/ciStreams.cpp
+--- a/src/share/vm/ci/ciStreams.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/ci/ciStreams.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -88,10 +88,9 @@ Bytecodes::Code ciBytecodeStream::wide()
{
// Get following bytecode; do not return wide
Bytecodes::Code bc = (Bytecodes::Code)_pc[1];
@@ -2382,7 +3582,7 @@ diff --git a/src/share/vm/ci/ciStreams.c
_was_wide = _pc; // Flag last wide bytecode found
return bc;
}
-@@ -303,11 +302,15 @@
+@@ -303,11 +302,15 @@ int ciBytecodeStream::get_method_index()
int ciBytecodeStream::get_method_index() {
switch (cur_bc()) {
case Bytecodes::_invokeinterface:
@@ -2399,10 +3599,41 @@ diff --git a/src/share/vm/ci/ciStreams.c
default:
ShouldNotReachHere();
return 0;
-diff --git a/src/share/vm/classfile/verifier.cpp b/src/share/vm/classfile/verifier.cpp
---- a/src/share/vm/classfile/verifier.cpp
-+++ b/src/share/vm/classfile/verifier.cpp
-@@ -323,6 +323,7 @@
+diff -r ce2272390558 src/share/vm/ci/ciStreams.hpp
+--- a/src/share/vm/ci/ciStreams.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/ci/ciStreams.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -121,7 +121,7 @@ public:
+ return check_java(_bc);
+ }
+
+- bool is_wide() { return ( _pc == _was_wide ); }
++ bool is_wide() const { return ( _pc == _was_wide ); }
+
+ // Get a byte index following this bytecode.
+ // If prefixed with a wide bytecode, get a wide index.
+@@ -141,7 +141,17 @@ public:
+ }
+
+ // Get 2-byte index (getfield/putstatic/etc)
+- int get_index_big() const { return Bytes::get_Java_u2(_bc_start+1); }
++ int get_index_big() const {
++ if (is_wide()) {
++ assert(_bc == Bytecodes::_invokestatic ||
++ _bc == Bytecodes::_invokespecial ||
++ _bc == Bytecodes::_invokevirtual ||
++ _bc == Bytecodes::_invokeinterface,
++ "Work without the is_wide() check previously so it is assumed that its only called for wide invokes."); // Just to check.
++ return Bytes::get_Java_u2(_bc_start+2);
++ }
++ return Bytes::get_Java_u2(_bc_start+1);
++ }
+
+ // Get dimensions byte (multinewarray)
+ int get_dimensions() const { return *(unsigned char*)(_pc-1); }
+diff -r ce2272390558 src/share/vm/classfile/verifier.cpp
+--- a/src/share/vm/classfile/verifier.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/classfile/verifier.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -323,6 +323,7 @@ void ClassVerifier::verify_method(method
bool no_control_flow = false; // Set to true when there is no direct control
// flow from current instruction to the next
// instruction in sequence
@@ -2410,16 +3641,16 @@ diff --git a/src/share/vm/classfile/veri
Bytecodes::Code opcode;
while (!bcs.is_last_bytecode()) {
opcode = bcs.raw_next();
-@@ -331,6 +332,8 @@
+@@ -330,6 +331,8 @@ void ClassVerifier::verify_method(method
+
// Set current frame's offset to bci
current_frame.set_offset(bci);
-
++
+ assert(handlers_prohibited == false, "should be set true only briefly");
-+
+
// Make sure every offset in stackmap table point to the beginning to
// an instruction. Match current_frame to stackmap_table entry with
- // the same offset if exists.
-@@ -350,22 +353,46 @@
+@@ -350,22 +353,46 @@ void ClassVerifier::verify_method(method
#ifndef PRODUCT
if (_verify_verbose) {
current_frame.print();
@@ -2462,7 +3693,7 @@ diff --git a/src/share/vm/classfile/veri
+ opcode != Bytecodes::_invokeinterface && opcode != Bytecodes::_invokestatic) {
+ assert(false, "should have seen Prefix_unknown");
+ }
-+ return;
++ break;
+ default:
+ ShouldNotReachHere();
}
@@ -2470,7 +3701,7 @@ diff --git a/src/share/vm/classfile/veri
switch (opcode) {
case Bytecodes::_nop :
-@@ -1169,14 +1196,15 @@
+@@ -1169,14 +1196,15 @@ void ClassVerifier::verify_method(method
case Bytecodes::_invokevirtual :
case Bytecodes::_invokespecial :
case Bytecodes::_invokestatic :
@@ -2490,7 +3721,7 @@ diff --git a/src/share/vm/classfile/veri
no_control_flow = false; break;
case Bytecodes::_new :
{
-@@ -1278,8 +1306,10 @@
+@@ -1278,8 +1306,10 @@ void ClassVerifier::verify_method(method
// matches current_frame
if (bci >= ex_min && bci < ex_max) {
verify_exception_handler_targets(
@@ -2502,7 +3733,7 @@ diff --git a/src/share/vm/classfile/veri
} // end while
// Make sure that control flow does not fall through end of the method
-@@ -1415,8 +1445,9 @@
+@@ -1415,8 +1445,9 @@ u2 ClassVerifier::verify_stackmap_table(
return stackmap_index;
}
@@ -2514,7 +3745,7 @@ diff --git a/src/share/vm/classfile/veri
constantPoolHandle cp (THREAD, _method->constants());
typeArrayHandle exhandlers (THREAD, _method->exception_table());
if (exhandlers() != NULL) {
-@@ -1426,6 +1457,13 @@
+@@ -1426,6 +1457,13 @@ void ClassVerifier::verify_exception_han
u2 handler_pc = exhandlers->int_at(i++);
int catch_type_index = exhandlers->int_at(i++);
if(bci >= start_pc && bci < end_pc) {
@@ -2528,7 +3759,7 @@ diff --git a/src/share/vm/classfile/veri
u1 flags = current_frame->flags();
if (this_uninit) { flags |= FLAG_THIS_UNINIT; }
-@@ -1723,8 +1761,9 @@
+@@ -1723,8 +1761,9 @@ void ClassVerifier::verify_field_instruc
}
// Get referenced class type
@@ -2540,7 +3771,7 @@ diff --git a/src/share/vm/classfile/veri
if (!ref_class_type.is_object()) {
verify_error(
"Expecting reference to class in class %s at constant pool index %d",
-@@ -1793,8 +1832,6 @@
+@@ -1793,8 +1832,6 @@ void ClassVerifier::verify_field_instruc
check_protected: {
if (_this_type == stack_object_type)
break; // stack_object_type must be assignable to _current_class_type
@@ -2549,7 +3780,7 @@ diff --git a/src/share/vm/classfile/veri
if (!name_in_supers(ref_class_name(), current_class()))
// stack_object_type must be assignable to _current_class_type since:
// 1. stack_object_type must be assignable to ref_class.
-@@ -1890,13 +1927,20 @@
+@@ -1890,13 +1927,20 @@ void ClassVerifier::verify_invoke_instru
RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
bool *this_uninit, VerificationType return_type,
constantPoolHandle cp, TRAPS) {
@@ -2574,7 +3805,16 @@ diff --git a/src/share/vm/classfile/veri
// Get method name and signature
symbolHandle method_name(THREAD, cp->name_ref_at(index));
-@@ -1973,6 +2017,7 @@
+@@ -1955,7 +1999,7 @@ void ClassVerifier::verify_invoke_instru
+ // Check instruction operands
+ u2 bci = bcs->bci();
+ if (opcode == Bytecodes::_invokeinterface) {
+- address bcp = bcs->bcp();
++ address bcp = bcs->bcp()+ (bcs->prefix()==Bytecodes::Prefix_tail_call ? 1 : 0);
+ // 4905268: count operand in invokeinterface should be nargs+1, not nargs.
+ // JSR202 spec: The count operand of an invokeinterface instruction is valid if it is
+ // the difference between the size of the operand stack before and after the instruction
+@@ -1973,6 +2017,7 @@ void ClassVerifier::verify_invoke_instru
if (method_name->byte_at(0) == '<') {
// Make sure <init> can only be invoked by invokespecial
if (opcode != Bytecodes::_invokespecial ||
@@ -2582,7 +3822,7 @@ diff --git a/src/share/vm/classfile/veri
method_name() != vmSymbols::object_initializer_name()) {
verify_error(bci, "Illegal call to internal method");
return;
-@@ -2007,8 +2052,8 @@
+@@ -2007,8 +2052,8 @@ void ClassVerifier::verify_invoke_instru
current_frame->pop_stack(ref_class_type, CHECK_VERIFY(this));
if (current_type() != stack_object_type) {
assert(cp->cache() == NULL, "not rewritten yet");
@@ -2593,10 +3833,13 @@ diff --git a/src/share/vm/classfile/veri
// See the comments in verify_field_instructions() for
// the rationale behind this.
if (name_in_supers(ref_class_name(), current_class())) {
-@@ -2056,6 +2101,43 @@
- }
- }
-
+@@ -2053,6 +2098,43 @@ void ClassVerifier::verify_invoke_instru
+ for (int i = 0; i < n; i++) {
+ current_frame->push_stack(return_type[i], CHECK_VERIFY(this)); // push types backwards
+ }
++ }
++}
++
+void ClassVerifier::verify_tail_call(
+ RawBytecodeStream* bcs, u2 bci, TRAPS) {
+ assert(TailCalls, "BCS will produce tailcalls only if feature is enabled");
@@ -2631,16 +3874,13 @@ diff --git a/src/share/vm/classfile/veri
+ // An implicit exception handler...
+ verify_error(bci, "Tail call from synchronized method");
+ return;
-+ }
-+}
-+
- VerificationType ClassVerifier::get_newarray_type(
- u2 index, u2 bci, TRAPS) {
- const char* from_bt[] = {
-diff --git a/src/share/vm/classfile/verifier.hpp b/src/share/vm/classfile/verifier.hpp
---- a/src/share/vm/classfile/verifier.hpp
-+++ b/src/share/vm/classfile/verifier.hpp
-@@ -107,7 +107,7 @@
+ }
+ }
+
+diff -r ce2272390558 src/share/vm/classfile/verifier.hpp
+--- a/src/share/vm/classfile/verifier.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/classfile/verifier.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -107,7 +107,7 @@ class ClassVerifier : public StackObj {
StackMapTable* stackmap_table, bool no_control_flow, TRAPS);
void verify_exception_handler_targets(
@@ -2649,19 +3889,19 @@ diff --git a/src/share/vm/classfile/veri
StackMapTable* stackmap_table, TRAPS);
void verify_ldc(
-@@ -132,6 +132,9 @@
+@@ -131,6 +131,9 @@ class ClassVerifier : public StackObj {
+ RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
bool* this_uninit, VerificationType return_type,
constantPoolHandle cp, TRAPS);
-
++
+ void verify_tail_call(
+ RawBytecodeStream* bcs, u2 bci, TRAPS);
-+
+
VerificationType get_newarray_type(u2 index, u2 bci, TRAPS);
void verify_anewarray(
- u2 index, constantPoolHandle cp, StackMapFrame* current_frame, TRAPS);
-diff --git a/src/share/vm/classfile/vmSymbols.hpp b/src/share/vm/classfile/vmSymbols.hpp
---- a/src/share/vm/classfile/vmSymbols.hpp
-+++ b/src/share/vm/classfile/vmSymbols.hpp
+diff -r ce2272390558 src/share/vm/classfile/vmSymbols.hpp
+--- a/src/share/vm/classfile/vmSymbols.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/classfile/vmSymbols.hpp Mon Mar 16 11:44:02 2009 +0100
@@ -151,6 +151,8 @@
template(java_lang_RuntimeException, "java/lang/RuntimeException") \
template(java_io_IOException, "java/io/IOException") \
@@ -2671,10 +3911,80 @@ diff --git a/src/share/vm/classfile/vmSy
\
/* error klasses: at least all errors thrown by the VM have entries here */ \
template(java_lang_AbstractMethodError, "java/lang/AbstractMethodError") \
-diff --git a/src/share/vm/code/compiledIC.cpp b/src/share/vm/code/compiledIC.cpp
---- a/src/share/vm/code/compiledIC.cpp
-+++ b/src/share/vm/code/compiledIC.cpp
-@@ -116,12 +116,37 @@
+diff -r ce2272390558 src/share/vm/code/codeBlob.cpp
+--- a/src/share/vm/code/codeBlob.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/code/codeBlob.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -375,6 +375,7 @@ DeoptimizationBlob::DeoptimizationBlob(
+ int unpack_offset,
+ int unpack_with_exception_offset,
+ int unpack_with_reexecution_offset,
++ int stack_compression_offset,
+ int frame_size
+ )
+ : SingletonBlob("DeoptimizationBlob", cb, sizeof(DeoptimizationBlob), size, frame_size, oop_maps)
+@@ -382,6 +383,7 @@ DeoptimizationBlob::DeoptimizationBlob(
+ _unpack_offset = unpack_offset;
+ _unpack_with_exception = unpack_with_exception_offset;
+ _unpack_with_reexecution = unpack_with_reexecution_offset;
++ _stack_compression_offset = stack_compression_offset;
+ #ifdef COMPILER1
+ _unpack_with_exception_in_tls = -1;
+ #endif
+@@ -394,6 +396,7 @@ DeoptimizationBlob* DeoptimizationBlob::
+ int unpack_offset,
+ int unpack_with_exception_offset,
+ int unpack_with_reexecution_offset,
++ int stack_compression_offset,
+ int frame_size)
+ {
+ DeoptimizationBlob* blob = NULL;
+@@ -407,6 +410,7 @@ DeoptimizationBlob* DeoptimizationBlob::
+ unpack_offset,
+ unpack_with_exception_offset,
+ unpack_with_reexecution_offset,
++ stack_compression_offset,
+ frame_size);
+ }
+
+diff -r ce2272390558 src/share/vm/code/codeBlob.hpp
+--- a/src/share/vm/code/codeBlob.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/code/codeBlob.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -339,6 +339,7 @@ class DeoptimizationBlob: public Singlet
+ int _unpack_offset;
+ int _unpack_with_exception;
+ int _unpack_with_reexecution;
++ int _stack_compression_offset;
+
+ int _unpack_with_exception_in_tls;
+
+@@ -350,6 +351,7 @@ class DeoptimizationBlob: public Singlet
+ int unpack_offset,
+ int unpack_with_exception_offset,
+ int unpack_with_reexecution_offset,
++ int stack_compression_offset,
+ int frame_size
+ );
+
+@@ -363,6 +365,7 @@ class DeoptimizationBlob: public Singlet
+ int unpack_offset,
+ int unpack_with_exception_offset,
+ int unpack_with_reexecution_offset,
++ int stack_compression_offset,
+ int frame_size
+ );
+
+@@ -389,6 +392,7 @@ class DeoptimizationBlob: public Singlet
+ address unpack() const { return instructions_begin() + _unpack_offset; }
+ address unpack_with_exception() const { return instructions_begin() + _unpack_with_exception; }
+ address unpack_with_reexecution() const { return instructions_begin() + _unpack_with_reexecution; }
++ address stack_compression() const { return instructions_begin() + _stack_compression_offset; }
+
+ // Alternate entry point for C1 where the exception and issuing pc
+ // are in JavaThread::_exception_oop and JavaThread::_exception_pc
+diff -r ce2272390558 src/share/vm/code/compiledIC.cpp
+--- a/src/share/vm/code/compiledIC.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/code/compiledIC.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -116,12 +116,37 @@ address CompiledIC::stub_address() const
return _ic_call->destination();
}
@@ -2713,7 +4023,7 @@ diff --git a/src/share/vm/code/compiledI
methodHandle method = call_info->selected_method();
bool is_invoke_interface = (bytecode == Bytecodes::_invokeinterface && !call_info->has_vtable_index());
assert(CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
-@@ -130,9 +155,13 @@
+@@ -130,9 +155,13 @@ void CompiledIC::set_to_megamorphic(Call
assert(is_call_to_compiled() || is_call_to_interpreted(), "going directly to megamorphic?");
address entry;
@@ -2728,7 +4038,7 @@ diff --git a/src/share/vm/code/compiledI
assert(entry != NULL, "entry not computed");
klassOop k = call_info->resolved_method()->method_holder();
assert(Klass::cast(k)->is_interface(), "sanity check");
-@@ -140,7 +169,7 @@
+@@ -140,7 +169,7 @@ void CompiledIC::set_to_megamorphic(Call
} else {
// Can be different than method->vtable_index(), due to package-private etc.
int vtable_index = call_info->vtable_index();
@@ -2737,7 +4047,7 @@ diff --git a/src/share/vm/code/compiledI
InlineCacheBuffer::create_transition_stub(this, method(), entry);
}
-@@ -238,9 +267,34 @@
+@@ -238,9 +267,34 @@ void CompiledIC::set_to_clean() {
address entry;
if (is_optimized()) {
@@ -2774,7 +4084,7 @@ diff --git a/src/share/vm/code/compiledI
}
// A zombie transition will always be safe, since the oop has already been set to NULL, so
-@@ -274,7 +328,11 @@
+@@ -274,13 +328,17 @@ bool CompiledIC::is_clean() const {
bool is_clean = false;
address dest = ic_destination();
is_clean = dest == SharedRuntime::get_resolve_opt_virtual_call_stub() ||
@@ -2787,7 +4097,23 @@ diff --git a/src/share/vm/code/compiledI
assert(!is_clean || is_optimized() || cached_oop() == NULL, "sanity check");
return is_clean;
}
-@@ -370,6 +428,8 @@
+
+
+-void CompiledIC::set_to_monomorphic(const CompiledICInfo& info) {
++void CompiledIC::set_to_monomorphic(const CompiledICInfo& info, bool is_tail_call) {
+ assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
+ // Updating a cache to the wrong entry can cause bugs that are very hard
+ // to track down - if cache entry gets invalid - we just clean it. In
+@@ -305,7 +363,7 @@ void CompiledIC::set_to_monomorphic(cons
+ // At code generation time, this call has been emitted as static call
+ // Call via stub
+ assert(info.cached_oop().not_null() && info.cached_oop()->is_method(), "sanity check");
+- CompiledStaticCall* csc = compiledStaticCall_at(instruction_address());
++ CompiledStaticCall* csc = compiledStaticCall_at(instruction_address(), is_tail_call);
+ methodHandle method (thread, (methodOop)info.cached_oop()());
+ csc->set_to_interpreted(method, info.entry());
+ if (TraceICs) {
+@@ -370,6 +428,8 @@ void CompiledIC::compute_monomorphic_ent
KlassHandle receiver_klass,
bool is_optimized,
bool static_bound,
@@ -2796,69 +4122,69 @@ diff --git a/src/share/vm/code/compiledI
CompiledICInfo& info,
TRAPS) {
info._is_optimized = is_optimized;
-@@ -379,9 +439,41 @@
+@@ -379,9 +439,41 @@ void CompiledIC::compute_monomorphic_ent
if (method_code != NULL) {
// Call to compiled code
if (static_bound || is_optimized) {
- entry = method_code->verified_entry_point();
+ if (is_tail_call && is_sibling) {
-+ if (TraceTailCalls) {
++ if (TraceTailCalls){
+ tty->print("CompiledIC::compute_monomorphic_entry():");
+ method->print_value_string();
-+ tty->print_cr(" to compiled: static_tail_call_entry_point");
++ tty->print_cr(" to compiled: verified_tail_call_entry_point");
+ }
-+ entry = method_code->static_tail_call_entry_point();
++ entry = method_code->verified_tail_call_entry_point();
+ } else if (is_tail_call) {
-+ if (TraceTailCalls) {
++ if (TraceTailCalls){
+ tty->print("CompiledIC::compute_monomorphic_entry():");
+ method->print_value_string();
-+ tty->print_cr(" to compiled: static_not_sibling_tail_call_entry_point");
++ tty->print_cr(" to compiled: verified_not_sibling_tail_call_entry_point");
+ }
-+ entry = method_code->static_not_sibling_tail_call_entry_point();
++ entry = method_code->verified_not_sibling_tail_call_entry_point();
+ } else {
+ entry = method_code->verified_entry_point();
+ }
} else {
- entry = method_code->entry_point();
+ if (is_tail_call && is_sibling) {
-+ if (TraceTailCalls) {
++ if (TraceTailCalls){
+ tty->print("CompiledIC::compute_monomorphic_entry():");
+ method->print_value_string();
+ tty->print_cr(" to compiled: monomorphic_tail_call_entry_point");
+ }
-+ entry = method_code->monomorphic_tail_call_entry_point();
++ entry = method_code->tail_call_entry_point();
+ } else if (is_tail_call) {
-+ if (TraceTailCalls) {
++ if (TraceTailCalls){
+ tty->print("CompiledIC::compute_monomorphic_entry():");
+ method->print_value_string();
+ tty->print_cr(" to compiled: monomorphic_not_sibling_call_entry_point");
+ }
-+ entry = method_code->monomorphic_not_sibling_tail_call_entry_point();
++ entry = method_code->not_sibling_tail_call_entry_point();
+ } else {
+ entry = method_code->entry_point();
+ }
}
}
if (entry != NULL) {
-@@ -429,35 +521,66 @@
+@@ -429,36 +521,74 @@ void CompiledIC::compute_monomorphic_ent
#endif // COMPILER2
if (is_optimized) {
// Use stub entry
- info._entry = method()->get_c2i_entry();
+ if (is_tail_call && is_sibling) {
-+ if (TraceTailCalls) {
++ if (TraceTailCalls){
+ tty->print("CompiledIC::compute_monomorphic_entry():");
+ method->print_value_string();
-+ tty->print_cr(" to interpreter: get_c2i_static_tail_call_entry_point");
++ tty->print_cr(" to interpreter: get_c2i_verified_tail_call_entry_point");
+ }
-+ info._entry = method()->get_c2i_static_tail_call_entry();
++ info._entry = method()->get_c2i_verified_tail_call_entry();
+ } else if(is_tail_call) {
-+ if (TraceTailCalls) {
++ if (TraceTailCalls){
+ tty->print("CompiledIC::compute_monomorphic_entry():");
+ method->print_value_string();
-+ tty->print_cr(" to interpreter: get_c2i_not_sibling_static_tail_call_entry_point");
++ tty->print_cr(" to interpreter: get_c2i_verified_not_sibling_tail_call_entry_point");
+ }
-+ info._entry = method()->get_c2i_static_not_sibling_tail_call_entry();
++ info._entry = method()->get_c2i_verified_not_sibling_tail_call_entry();
+ } else
+ info._entry = method()->get_c2i_entry();
info._cached_oop = method;
@@ -2868,14 +4194,14 @@ diff --git a/src/share/vm/code/compiledI
info._cached_oop = Handle(THREAD, holder);
- info._entry = method()->get_c2i_unverified_entry();
+ if (is_tail_call && is_sibling) {
-+ if (TraceTailCalls) {
++ if (TraceTailCalls){
+ tty->print("CompiledIC::compute_monomorphic_entry():");
+ method->print_value_string();
+ tty->print_cr(" to interpreter: get_c2i_unverified_tail_call_entry_point");
+ }
+ info._entry = method()->get_c2i_unverified_tail_call_entry();
+ } else if (is_tail_call) {
-+ if (TraceTailCalls) {
++ if (TraceTailCalls){
+ tty->print("CompiledIC::compute_monomorphic_entry():");
+ method->print_value_string();
+ tty->print_cr(" to interpreter: get_c2i_unverified_not_sibling_tail_call_entry_point");
@@ -2905,15 +4231,25 @@ diff --git a/src/share/vm/code/compiledI
{
}
-
- CompiledIC::CompiledIC(Relocation* ic_reloc)
- : _ic_call(nativeCall_at(ic_reloc->addr())),
++static NativeCall* nativeCallOrJump_at(address addr, bool is_tail_call) {
++ NativeCall * res = is_tail_call ?
++ (NativeCall*) nativeJump_at(addr) :
++ nativeCall_at(addr);
++ return res;
++}
+
+-CompiledIC::CompiledIC(Relocation* ic_reloc)
+- : _ic_call(nativeCall_at(ic_reloc->addr())),
- _oops(parse_ic(ic_reloc->code(), ic_reloc->addr(), _oop_addr, &_is_optimized))
++CompiledIC::CompiledIC(Relocation* ic_reloc, bool is_tail_call)
++ : _ic_call(nativeCallOrJump_at(ic_reloc->addr(), is_tail_call)),
+ _oops(parse_ic(ic_reloc->code(), ic_reloc->addr(), _oop_addr, &_is_optimized, &_tail_call_type, _first_set_oop_inst))
{
++
assert(ic_reloc->type() == relocInfo::virtual_call_type ||
ic_reloc->type() == relocInfo::opt_virtual_call_type, "wrong reloc. info");
-@@ -474,8 +597,17 @@
+ }
+@@ -474,8 +604,17 @@ void CompiledStaticCall::set_to_clean()
CodeBlob* cb = CodeCache::find_blob_unsafe(this);
assert(cb != NULL && cb->is_nmethod(), "must be nmethod");
#endif
@@ -2933,20 +4269,22 @@ diff --git a/src/share/vm/code/compiledI
// Do not reset stub here: It is too expensive to call find_stub.
// Instead, rely on caller (nmethod::clear_inline_caches) to clear
// both the call and its stub.
-@@ -486,6 +618,12 @@
+@@ -486,6 +625,14 @@ bool CompiledStaticCall::is_clean() cons
return destination() == SharedRuntime::get_resolve_static_call_stub();
}
+bool CompiledStaticCall::is_clean_static_tail_call() const {
+ return destination() == SharedRuntime::get_resolve_static_tail_call_stub() ||
-+ destination() == SharedRuntime::get_resolve_not_sibling_static_tail_call_stub();
++ destination() == SharedRuntime::get_resolve_not_sibling_static_tail_call_stub() ||
++ destination() == SharedRuntime::get_resolve_opt_virtual_tail_call_stub() ||
++ destination() == SharedRuntime::get_resolve_opt_not_sibling_virtual_tail_call_stub();
+}
+
+
bool CompiledStaticCall::is_call_to_compiled() const {
return CodeCache::contains(destination());
}
-@@ -495,7 +633,13 @@
+@@ -495,7 +642,13 @@ bool CompiledStaticCall::is_call_to_inte
// It is a call to interpreted, if it calls to a stub. Hence, the destination
// must be in the stub part of the nmethod that contains the call
nmethod* nm = CodeCache::find_nmethod(instruction_address());
@@ -2954,14 +4292,23 @@ diff --git a/src/share/vm/code/compiledI
+ // Change: Because of tail calls there is another stub destination. So we need
+ // to check that the destination is not the tail call stub.
+ address dest = destination();
-+ bool is_stub = nm->stub_contains(dest) && dest != nm->static_tail_call_entry_point() &&
-+ dest != nm->static_not_sibling_tail_call_entry_point();
++ bool is_stub = nm->stub_contains(dest) &&
++ dest != nm->verified_tail_call_entry_point() &&
++ dest != nm->verified_not_sibling_tail_call_entry_point();
+ return is_stub;
-+ //return nm->stub_contains(destination());
}
-@@ -550,20 +694,76 @@
+@@ -532,7 +685,7 @@ void CompiledStaticCall::set(const Stati
+ // to track down - if cache entry gets invalid - we just clean it. In
+ // this way it is always the same code path that is responsible for
+ // updating and resolving an inline cache
+- assert(is_clean(), "do not update a call entry - use clean");
++ assert(is_clean() || (TailCallsStackCompression && is_clean_static_tail_call()), "do not update a call entry - use clean");
+
+ if (info._to_interpreter) {
+ // Call to interpreted code
+@@ -550,20 +703,76 @@ void CompiledStaticCall::set(const Stati
}
}
@@ -3004,16 +4351,16 @@ diff --git a/src/share/vm/code/compiledI
+ if (TraceTailCalls) {
+ tty->print("CompiledStaticCall:compute_entry() ");
+ m->print_value_string();
-+ tty->print_cr(" to compiled: static_tail_call_entry_point");
++ tty->print_cr(" to compiled: verified_tail_call_entry_point");
+ }
-+ info._entry = m_code->static_tail_call_entry_point();
++ info._entry = m_code->verified_tail_call_entry_point();
+ } else if (is_tail_call) {
-+ if (TraceTailCalls) {
++ if (TraceTailCalls){
+ tty->print("CompiledStaticCall:compute_entry() ");
+ m->print_value_string();
-+ tty->print_cr(" to compiled: static_not_sibling_tail_call_entry_point");
++ tty->print_cr(" to compiled: verified_not_sibling_tail_call_entry_point");
+ }
-+ info._entry = m_code->static_not_sibling_tail_call_entry_point();
++ info._entry = m_code->verified_not_sibling_tail_call_entry_point();
+ } else {
+ info._entry = m_code->verified_entry_point();
+ }
@@ -3023,33 +4370,50 @@ diff --git a/src/share/vm/code/compiledI
info._to_interpreter = true;
- info._entry = m()->get_c2i_entry();
+ if (is_tail_call && is_sibling_call) {
-+ if (TraceTailCalls) {
++ if (TraceTailCalls){
+ tty->print("CompiledStaticCall:compute_entry() ");
+ m->print_value_string();
-+ tty->print_cr(" to interpreter: get_c2i_static_tail_call_entry");
++ tty->print_cr(" to interpreter: get_c2i_verified_tail_call_entry");
+ }
-+ info._entry = m()->get_c2i_static_tail_call_entry();
++ info._entry = m()->get_c2i_verified_tail_call_entry();
+ } else if (is_tail_call) {
-+ if (TraceTailCalls) {
++ if (TraceTailCalls){
+ tty->print("CompiledStaticCall:compute_entry() ");
+ m->print_value_string();
-+ tty->print_cr(" to interpreter: get_c2i_not_sibling_static_tail_call_entry");
++ tty->print_cr(" to interpreter: get_c2i_verified_not_sibling_tail_call_entry");
+ }
-+ info._entry = m()->get_c2i_static_not_sibling_tail_call_entry();
++ info._entry = m()->get_c2i_verified_not_sibling_tail_call_entry();
+ } else
+ info._entry = m()->get_c2i_entry();
}
}
-@@ -642,6 +842,22 @@
+@@ -607,9 +816,11 @@ address CompiledStaticCall::find_stub()
+ // Non-product mode code
+ #ifndef PRODUCT
+
+-void CompiledIC::verify() {
++void CompiledIC::verify(bool is_tail_call) {
+ // make sure code pattern is actually a call imm32 instruction
+- _ic_call->verify();
++ if (is_tail_call)
++ ((NativeJump*)_ic_call)->verify();
++ else _ic_call->verify();
+ if (os::is_MP()) {
+ _ic_call->verify_alignment();
+ }
+@@ -640,6 +851,23 @@ void CompiledStaticCall::print() {
+ tty->print("interpreted");
+ }
tty->cr();
- }
-
++}
++
+void CompiledStaticCall::verify_static_tail_call() {
+ // Verify call
-+ NativeCall::verify();
++ NativeJump* jmp = (NativeJump*) this;
++ jmp->verify();
+ if (os::is_MP()) {
-+ verify_alignment_static_tail_call();
++ verify_alignment();
+ }
+
+ // Verify stub
@@ -3058,13 +4422,11 @@ diff --git a/src/share/vm/code/compiledI
+ NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); // creation also verifies the object
+ NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
+ // Verify state
-+ assert(is_clean_static_tail_call(), "sanity check");
-+}
-+
++ assert(is_clean_static_tail_call() || is_call_to_compiled()|| is_call_to_interpreted(), "sanity check");
+ }
+
void CompiledStaticCall::verify() {
- // Verify call
- NativeCall::verify();
-@@ -654,7 +870,6 @@
+@@ -654,7 +882,6 @@ void CompiledStaticCall::verify() {
assert(stub != NULL, "no stub found for static call");
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); // creation also verifies the object
NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
@@ -3072,10 +4434,10 @@ diff --git a/src/share/vm/code/compiledI
// Verify state
assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check");
}
-diff --git a/src/share/vm/code/compiledIC.hpp b/src/share/vm/code/compiledIC.hpp
---- a/src/share/vm/code/compiledIC.hpp
-+++ b/src/share/vm/code/compiledIC.hpp
-@@ -76,6 +76,8 @@
+diff -r ce2272390558 src/share/vm/code/compiledIC.hpp
+--- a/src/share/vm/code/compiledIC.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/code/compiledIC.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -76,15 +76,20 @@ class CompiledIC: public ResourceObj {
oop* _oop_addr; // patchable oop cell for this IC
RelocIterator _oops; // iteration over any and all set-oop instructions
bool _is_optimized; // an optimized virtual call (i.e., no compiled IC)
@@ -3083,18 +4445,34 @@ diff --git a/src/share/vm/code/compiledI
+ address _first_set_oop_inst;
CompiledIC(NativeCall* ic_call);
- CompiledIC(Relocation* ic_reloc); // Must be of virtual_call_type/opt_virtual_call_type
-@@ -86,6 +88,9 @@
+- CompiledIC(Relocation* ic_reloc); // Must be of virtual_call_type/opt_virtual_call_type
++ CompiledIC(Relocation* ic_reloc, bool is_tail_call); // Must be of virtual_call_type/opt_virtual_call_type
+
+ // low-level inline-cache manipulation. Cannot be accessed directly, since it might not be MT-safe
+ // to change an inline-cache. These changes the underlying inline-cache directly. They *newer* make
+ // changes to a transition stub.
void set_ic_destination(address entry_point);
void set_cached_oop(oop cache);
-
++
+ // Megamorphic tail calls need to set the protection domain token.
+ void set_protection_domain_token(oop protection_domain);
-+
+
// Reads the location of the transition stub. This will fail with an assertion, if no transition stub is
// associated with the inline cache.
- address stub_address() const;
-@@ -103,6 +108,9 @@
+@@ -93,9 +98,9 @@ class CompiledIC: public ResourceObj {
+
+ public:
+ // conversion (machine PC to CompiledIC*)
+- friend CompiledIC* CompiledIC_before(address return_addr);
+- friend CompiledIC* CompiledIC_at(address call_site);
+- friend CompiledIC* CompiledIC_at(Relocation* call_site);
++ friend CompiledIC* CompiledIC_before(address return_addr, bool is_tail_call);
++ friend CompiledIC* CompiledIC_at(address call_site, bool is_tail_call);
++ friend CompiledIC* CompiledIC_at(Relocation* call_site, bool is_tail_call);
+
+ // Return the cached_oop/destination associated with this inline cache. If the cache currently points
+ // to a transition stub, it will read the values from the transition stub.
+@@ -103,6 +108,9 @@ class CompiledIC: public ResourceObj {
address ic_destination() const;
bool is_optimized() const { return _is_optimized; }
@@ -3104,11 +4482,13 @@ diff --git a/src/share/vm/code/compiledI
// State
bool is_clean() const;
-@@ -122,10 +130,11 @@
+@@ -121,11 +129,12 @@ class CompiledIC: public ResourceObj {
+ // They all takes a TRAP argument, since they can cause a GC if the inline-cache buffer is full.
//
void set_to_clean(); // Can only be called during a safepoint operation
- void set_to_monomorphic(const CompiledICInfo& info);
+- void set_to_monomorphic(const CompiledICInfo& info);
- void set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecode, TRAPS);
++ void set_to_monomorphic(const CompiledICInfo& info, bool is_tail_call);
+ void set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecode, oop protection_domain, TRAPS);
static void compute_monomorphic_entry(methodHandle method, KlassHandle receiver_klass,
@@ -3118,7 +4498,46 @@ diff --git a/src/share/vm/code/compiledI
// Location
address instruction_address() const { return _ic_call->instruction_address(); }
-@@ -191,7 +200,7 @@
+@@ -133,24 +142,28 @@ class CompiledIC: public ResourceObj {
+ // Misc
+ void print() PRODUCT_RETURN;
+ void print_compiled_ic() PRODUCT_RETURN;
+- void verify() PRODUCT_RETURN;
++ void verify(bool is_tail_call) PRODUCT_RETURN;
+ };
+
+-inline CompiledIC* CompiledIC_before(address return_addr) {
+- CompiledIC* c_ic = new CompiledIC(nativeCall_before(return_addr));
+- c_ic->verify();
++inline CompiledIC* CompiledIC_before(address return_addr, bool is_tail_call) {
++ CompiledIC* c_ic = is_tail_call ?
++ new CompiledIC((NativeCall*)nativeJump_before(return_addr)) :
++ new CompiledIC(nativeCall_before(return_addr));
++ c_ic->verify(is_tail_call);
+ return c_ic;
+ }
+
+-inline CompiledIC* CompiledIC_at(address call_site) {
+- CompiledIC* c_ic = new CompiledIC(nativeCall_at(call_site));
+- c_ic->verify();
++inline CompiledIC* CompiledIC_at(address call_site, bool is_tail_call) {
++ CompiledIC* c_ic = is_tail_call ?
++ new CompiledIC((NativeCall*)nativeJump_at(call_site)) :
++ new CompiledIC(nativeCall_at(call_site));
++ c_ic->verify(is_tail_call);
+ return c_ic;
+ }
+
+-inline CompiledIC* CompiledIC_at(Relocation* call_site) {
+- CompiledIC* c_ic = new CompiledIC(call_site);
+- c_ic->verify();
++inline CompiledIC* CompiledIC_at(Relocation* call_site, bool is_tail_call) {
++ CompiledIC* c_ic = new CompiledIC(call_site, is_tail_call);
++ c_ic->verify(is_tail_call);
+ return c_ic;
+ }
+
+@@ -191,7 +204,7 @@ class CompiledStaticCall: public NativeC
// Also used by CompiledIC
void set_to_interpreted(methodHandle callee, address entry);
@@ -3127,7 +4546,7 @@ diff --git a/src/share/vm/code/compiledI
public:
friend CompiledStaticCall* compiledStaticCall_before(address return_addr);
-@@ -200,6 +209,8 @@
+@@ -200,6 +213,8 @@ class CompiledStaticCall: public NativeC
// State
bool is_clean() const;
@@ -3136,7 +4555,7 @@ diff --git a/src/share/vm/code/compiledI
bool is_call_to_compiled() const;
bool is_call_to_interpreted() const;
-@@ -210,9 +221,11 @@
+@@ -210,9 +225,11 @@ class CompiledStaticCall: public NativeC
// Computation and setting is split up, since the actions are separate during
// a OptoRuntime::resolve_xxx.
void set(const StaticCallInfo& info);
@@ -3149,65 +4568,109 @@ diff --git a/src/share/vm/code/compiledI
// Stub support
address find_stub();
-@@ -221,6 +234,8 @@
+@@ -221,21 +238,31 @@ class CompiledStaticCall: public NativeC
// Misc.
void print() PRODUCT_RETURN;
void verify() PRODUCT_RETURN;
+ void verify_static_tail_call() PRODUCT_RETURN;
-+ void verify_alignment_static_tail_call() {assert((intptr_t)addr_at(instruction_offset) % BytesPerInt == 0, "must be aligned");}
};
-@@ -230,6 +245,12 @@
+-inline CompiledStaticCall* compiledStaticCall_before(address return_addr) {
+- CompiledStaticCall* st = (CompiledStaticCall*)nativeCall_before(return_addr);
+- st->verify();
++inline CompiledStaticCall* compiledStaticCall_before(address return_addr, bool is_tail_call) {
++ // Since a jmp and call instruction have the same prefix size we treat the
++ // jump instruction like a call instruction.
++ CompiledStaticCall* st = is_tail_call ?
++ (CompiledStaticCall*)nativeJump_before(return_addr) :
++ (CompiledStaticCall*)nativeCall_before(return_addr);
++ if (is_tail_call)
++ st->verify_static_tail_call();
++ else st->verify();
return st;
}
-+inline CompiledStaticCall* compiledStaticTailCall_before(address return_addr) {
-+ CompiledStaticCall* st = (CompiledStaticCall*)nativeCall_before(return_addr);
-+ st->verify_static_tail_call();
-+ return st;
-+}
-+
- inline CompiledStaticCall* compiledStaticCall_at(address native_call) {
+-inline CompiledStaticCall* compiledStaticCall_at(address native_call) {
++
++inline CompiledStaticCall* compiledStaticCall_at(address native_call, bool is_tail_call) {
CompiledStaticCall* st = (CompiledStaticCall*)native_call;
- st->verify();
-diff --git a/src/share/vm/code/nmethod.cpp b/src/share/vm/code/nmethod.cpp
---- a/src/share/vm/code/nmethod.cpp
-+++ b/src/share/vm/code/nmethod.cpp
-@@ -786,6 +786,12 @@
+- st->verify();
++ if (is_tail_call)
++ st->verify_static_tail_call();
++ else st->verify();
+ return st;
+ }
+
+-inline CompiledStaticCall* compiledStaticCall_at(Relocation* call_site) {
+- return compiledStaticCall_at(call_site->addr());
++inline CompiledStaticCall* compiledStaticCall_at(Relocation* call_site, bool is_tail_call) {
++ return compiledStaticCall_at(call_site->addr(), is_tail_call);
+ }
+diff -r ce2272390558 src/share/vm/code/icBuffer.cpp
+--- a/src/share/vm/code/icBuffer.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/code/icBuffer.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -35,7 +35,9 @@ void ICStub::finalize() {
+ void ICStub::finalize() {
+ if (!is_empty()) {
+ ResourceMark rm;
+- CompiledIC *ic = CompiledIC_at(ic_site());
++ // If it's a jump it's a tail call.
++ bool is_tail_call = NativeJump::is_jump_at(ic_site());
++ CompiledIC *ic = CompiledIC_at(ic_site(), is_tail_call);
+ assert(CodeCache::find_nmethod(ic->instruction_address()) != NULL, "inline cache in non-nmethod?");
+
+ assert(this == ICStub_from_destination_address(ic->stub_address()), "wrong owner of ic buffer");
+diff -r ce2272390558 src/share/vm/code/nmethod.cpp
+--- a/src/share/vm/code/nmethod.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/code/nmethod.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -1,3 +1,4 @@
++
+ /*
+ * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+@@ -653,6 +654,7 @@ nmethod::nmethod(
+
+ // For dtrace wrappers
+ #ifdef HAVE_DTRACE_H
++
+ nmethod::nmethod(
+ methodOop method,
+ int nmethod_size,
+@@ -786,6 +788,12 @@ nmethod::nmethod(
// Exception handler and deopt handler are in the stub section
_exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions);
_deoptimize_offset = _stub_offset + offsets->value(CodeOffsets::Deopt);
-+ _static_tail_call_offset = _stub_offset + offsets->value(CodeOffsets::Static_Tail_Call_Entry);
-+ _static_not_sibling_tail_call_offset = _stub_offset + offsets->value(CodeOffsets::Static_Not_Sibling_Tail_Call_Entry);
-+ _static_not_sibling_tail_call_set_data_offset = _stub_offset + offsets->value(CodeOffsets::Static_Not_Sibling_Tail_Call_Set_Data_Entry);
-+ _monomorphic_tail_call_offset = _stub_offset + offsets->value(CodeOffsets::Monomorphic_Tail_Call_Entry);
-+ _monomorphic_not_sibling_tail_call_offset = _stub_offset + offsets->value(CodeOffsets::Monomorphic_Not_Sibling_Tail_Call_Entry);
-+ _monomorphic_not_sibling_tail_call_set_data_offset = _stub_offset + offsets->value(CodeOffsets::Monomorphic_Not_Sibling_Tail_Call_Set_Data_Entry);
++ _verified_tail_call_offset = _stub_offset + offsets->value(CodeOffsets::Verified_Tail_Call_Entry);
++ _verified_not_sibling_tail_call_offset = _stub_offset + offsets->value(CodeOffsets::Verified_Not_Sibling_Tail_Call_Entry);
++ _verified_not_sibling_tail_call_set_data_offset = _stub_offset + offsets->value(CodeOffsets::Verified_Not_Sibling_Tail_Call_Set_Data_Entry);
++ _tail_call_offset = _stub_offset + offsets->value(CodeOffsets::Tail_Call_Entry);
++ _not_sibling_tail_call_offset = _stub_offset + offsets->value(CodeOffsets::Not_Sibling_Tail_Call_Entry);
++ _not_sibling_tail_call_set_data_offset = _stub_offset + offsets->value(CodeOffsets::Not_Sibling_Tail_Call_Set_Data_Entry);
_consts_offset = instructions_offset() + code_buffer->total_offset_of(code_buffer->consts()->start());
_scopes_data_offset = data_offset();
_scopes_pcs_offset = _scopes_data_offset + round_to(debug_info->data_size (), oopSize);
-@@ -797,6 +803,19 @@
+@@ -797,6 +805,19 @@ nmethod::nmethod(
_entry_point = instructions_begin();
_verified_entry_point = instructions_begin() + offsets->value(CodeOffsets::Verified_Entry);
_osr_entry_point = instructions_begin() + offsets->value(CodeOffsets::OSR_Entry);
-+ _static_tail_call_entry_point = static_tail_call_begin();
-+ _static_not_sibling_tail_call_entry_point = static_not_sibling_tail_call_begin();
-+ _monomorphic_tail_call_entry_point = monomorphic_tail_call_begin();
-+ _monomorphic_not_sibling_tail_call_entry_point = monomorphic_not_sibling_tail_call_begin();
++ _verified_tail_call_entry_point = verified_tail_call_begin();
++ _verified_not_sibling_tail_call_entry_point = verified_not_sibling_tail_call_begin();
++ _tail_call_entry_point = tail_call_begin();
++ _not_sibling_tail_call_entry_point = not_sibling_tail_call_begin();
+
+#if ASSERT
+ // Check entry point alignment: when making the nmethod not entrant or
+ // zombie the tail call entry points need to be aligned properly.
-+ NativeJump::check_verified_entry_alignment(0, _static_tail_call_entry_point);
-+ NativeJump::check_verified_entry_alignment(0, _static_not_sibling_tail_call_entry_point);
-+ NativeJump::check_verified_entry_alignment(0, _monomorphic_tail_call_entry_point);
-+ NativeJump::check_verified_entry_alignment(0, _monomorphic_not_sibling_tail_call_entry_point);
++ NativeJump::check_verified_entry_alignment(0, _verified_tail_call_entry_point);
++ NativeJump::check_verified_entry_alignment(0, _verified_not_sibling_tail_call_entry_point);
++ NativeJump::check_verified_entry_alignment(0, _tail_call_entry_point);
++ NativeJump::check_verified_entry_alignment(0, _not_sibling_tail_call_entry_point);
+#endif
_exception_cache = NULL;
_pc_desc_cache.reset_to(scopes_pcs_begin());
-@@ -970,6 +989,44 @@
+@@ -970,6 +991,43 @@ ScopeDesc* nmethod::scope_desc_at(addres
}
@@ -3239,20 +4702,39 @@ diff --git a/src/share/vm/code/nmethod.c
+
+void nmethod::set_adapter_info_in_tail_call_stubs(methodOop method, AdapterHandlerEntry* adapter) {
+ guarantee(is_java_method(), "only works for java methods");
-+ // Currently only c1 supports tail calls.
-+ guarantee(is_compiled_by_c1(), "currently only supported by c1");
-+
-+ // Static not sibling tail call entry.
-+ address move_addr = header_begin() + _static_not_sibling_tail_call_set_data_offset;
++
++ // Verified not sibling tail call entry.
++ address move_addr = header_begin() + _verified_not_sibling_tail_call_set_data_offset;
+ set_adapter_info_in_tail_call_stub_helper(this, method, move_addr, adapter);
-+ move_addr = header_begin() + _monomorphic_not_sibling_tail_call_set_data_offset;
++ // Not sibling tail call entry.
++ move_addr = header_begin() + _not_sibling_tail_call_set_data_offset;
+ set_adapter_info_in_tail_call_stub_helper(this, method, move_addr, adapter);
+}
+
void nmethod::clear_inline_caches() {
assert(SafepointSynchronize::is_at_safepoint(), "cleaning of IC's only allowed at safepoint");
if (is_zombie()) {
-@@ -1173,6 +1230,18 @@
+@@ -1009,7 +1067,8 @@ void nmethod::cleanup_inline_caches() {
+ switch(iter.type()) {
+ case relocInfo::virtual_call_type:
+ case relocInfo::opt_virtual_call_type: {
+- CompiledIC *ic = CompiledIC_at(iter.reloc());
++ bool is_tail_call = iter.tail_call_type() != relocInfo::not_tail_call;
++ CompiledIC *ic = CompiledIC_at(iter.reloc(), is_tail_call);
+ // Ok, to lookup references to zombies here
+ CodeBlob *cb = CodeCache::find_blob_unsafe(ic->ic_destination());
+ if( cb != NULL && cb->is_nmethod() ) {
+@@ -1020,7 +1079,8 @@ void nmethod::cleanup_inline_caches() {
+ break;
+ }
+ case relocInfo::static_call_type: {
+- CompiledStaticCall *csc = compiledStaticCall_at(iter.reloc());
++ bool is_tail_call = iter.tail_call_type() != relocInfo::not_tail_call;
++ CompiledStaticCall *csc = compiledStaticCall_at(iter.reloc(), is_tail_call);
+ CodeBlob *cb = CodeCache::find_blob_unsafe(csc->destination());
+ if( cb != NULL && cb->is_nmethod() ) {
+ nmethod* nm = (nmethod*)cb;
+@@ -1173,6 +1233,18 @@ void nmethod::make_not_entrant_or_zombie
// The caller can be calling the method statically or through an inline
// cache call.
if (!is_not_entrant()) {
@@ -3260,18 +4742,54 @@ diff --git a/src/share/vm/code/nmethod.c
+ // might get to a patched verified entry point with a popped frame and
+ // get_handle_wrong method_stub would see a wrong return address (of the
+ // parent frame).
-+ NativeJump::patch_verified_entry(0, static_tail_call_entry_point(),
++ NativeJump::patch_verified_entry(0, verified_tail_call_entry_point(),
+ SharedRuntime::get_handle_wrong_method_stub());
-+ NativeJump::patch_verified_entry(0, static_not_sibling_tail_call_entry_point(),
++ NativeJump::patch_verified_entry(0, verified_not_sibling_tail_call_entry_point(),
+ SharedRuntime::get_handle_wrong_method_stub());
-+ NativeJump::patch_verified_entry(0, monomorphic_tail_call_entry_point(),
++ NativeJump::patch_verified_entry(0, tail_call_entry_point(),
+ SharedRuntime::get_handle_wrong_method_stub());
-+ NativeJump::patch_verified_entry(0, monomorphic_not_sibling_tail_call_entry_point(),
++ NativeJump::patch_verified_entry(0, not_sibling_tail_call_entry_point(),
+ SharedRuntime::get_handle_wrong_method_stub());
NativeJump::patch_verified_entry(entry_point(), verified_entry_point(),
SharedRuntime::get_handle_wrong_method_stub());
assert (NativeJump::instruction_size == nmethod::_zombie_instruction_size, "");
-@@ -2171,6 +2240,7 @@
+@@ -1456,7 +1528,8 @@ void nmethod::do_unloading(BoolObjectClo
+ RelocIterator iter(this, low_boundary);
+ while(iter.next()) {
+ if (iter.type() == relocInfo::virtual_call_type) {
+- CompiledIC *ic = CompiledIC_at(iter.reloc());
++ bool is_tail_call = iter.tail_call_type() != relocInfo::not_tail_call;
++ CompiledIC *ic = CompiledIC_at(iter.reloc(), is_tail_call);
+ oop ic_oop = ic->cached_oop();
+ if (ic_oop != NULL && !is_alive->do_object_b(ic_oop)) {
+ // The only exception is compiledICHolder oops which may
+@@ -1510,7 +1583,8 @@ void nmethod::do_unloading(BoolObjectClo
+ RelocIterator iter(this, low_boundary);
+ while (iter.next()) {
+ if (iter.type() == relocInfo::virtual_call_type) {
+- CompiledIC *ic = CompiledIC_at(iter.reloc());
++ bool is_tail_call = iter.tail_call_type() != relocInfo::not_tail_call;
++ CompiledIC *ic = CompiledIC_at(iter.reloc(), is_tail_call);
+ oop ic_oop = ic->cached_oop();
+ assert(ic_oop == NULL || is_alive->do_object_b(ic_oop),
+ "Found unmarked ic_oop in reachable nmethod");
+@@ -1923,11 +1997,13 @@ void nmethod::verify_interrupt_point(add
+ if (CompiledIC_lock->owner() == cur ||
+ ((cur->is_VM_thread() || cur->is_ConcurrentGC_thread()) &&
+ SafepointSynchronize::is_at_safepoint())) {
+- ic = CompiledIC_at(call_site);
++ bool is_tail_call = NativeJump::is_jump_at(call_site);
++ ic = CompiledIC_at(call_site, is_tail_call);
+ CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
+ } else {
+ MutexLocker ml_verify (CompiledIC_lock);
+- ic = CompiledIC_at(call_site);
++ bool is_tail_call = NativeJump::is_jump_at(call_site);
++ ic = CompiledIC_at(call_site, is_tail_call);
+ }
+ PcDesc* pd = pc_desc_at(ic->end_of_call());
+ assert(pd != NULL, "PcDesc must exist");
+@@ -2171,6 +2247,7 @@ const char* nmethod::reloc_string_for(u_
case relocInfo::poll_type: return "poll";
case relocInfo::poll_return_type: return "poll_return";
case relocInfo::type_mask: return "type_bit_mask";
@@ -3279,7 +4797,7 @@ diff --git a/src/share/vm/code/nmethod.c
}
}
return have_one ? "other" : NULL;
-@@ -2220,8 +2290,9 @@
+@@ -2220,8 +2297,9 @@ void nmethod::print_code_comment_on(outp
st->print("method is native");
} else {
address bcp = sd->method()->bcp_from(sd->bci());
@@ -3291,65 +4809,79 @@ diff --git a/src/share/vm/code/nmethod.c
switch (bc) {
case Bytecodes::_invokevirtual:
case Bytecodes::_invokespecial:
-diff --git a/src/share/vm/code/nmethod.hpp b/src/share/vm/code/nmethod.hpp
---- a/src/share/vm/code/nmethod.hpp
-+++ b/src/share/vm/code/nmethod.hpp
-@@ -151,7 +151,12 @@
+@@ -2302,12 +2380,13 @@ void nmethod::print_calls(outputStream*
+ case relocInfo::virtual_call_type:
+ case relocInfo::opt_virtual_call_type: {
+ VerifyMutexLocker mc(CompiledIC_lock);
+- CompiledIC_at(iter.reloc())->print();
++ bool is_tail_call = iter.tail_call_type()!=relocInfo::not_tail_call;
++ CompiledIC_at(iter.reloc(), is_tail_call)->print();
+ break;
+ }
+ case relocInfo::static_call_type:
+ st->print_cr("Static call at " INTPTR_FORMAT, iter.reloc()->addr());
+- compiledStaticCall_at(iter.reloc())->print();
++ compiledStaticCall_at(iter.reloc(), iter.tail_call_type()!=relocInfo::not_tail_call)->print();
+ break;
+ }
+ }
+diff -r ce2272390558 src/share/vm/code/nmethod.hpp
+--- a/src/share/vm/code/nmethod.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/code/nmethod.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -151,7 +151,12 @@ class nmethod : public CodeBlob {
int _handler_table_offset;
int _nul_chk_table_offset;
int _nmethod_end_offset;
-
-+ int _static_tail_call_offset;
-+ int _static_not_sibling_tail_call_offset;
-+ int _static_not_sibling_tail_call_set_data_offset;
-+ int _monomorphic_tail_call_offset;
-+ int _monomorphic_not_sibling_tail_call_offset;
-+ int _monomorphic_not_sibling_tail_call_set_data_offset;
++ int _verified_tail_call_offset;
++ int _verified_not_sibling_tail_call_offset;
++ int _verified_not_sibling_tail_call_set_data_offset;
++ int _tail_call_offset;
++ int _not_sibling_tail_call_offset;
++ int _not_sibling_tail_call_set_data_offset;
// location in frame (offset for sp) that deopt can store the original
// pc during a deopt.
int _orig_pc_offset;
-@@ -163,7 +168,11 @@
+@@ -163,6 +168,14 @@ class nmethod : public CodeBlob {
address _entry_point; // entry point with class check
address _verified_entry_point; // entry point without class check
address _osr_entry_point; // entry point for on stack replacement
--
-+ address _static_tail_call_entry_point; // entry point without class and
-+ // protection domain check
-+ address _static_not_sibling_tail_call_entry_point;
-+ address _monomorphic_tail_call_entry_point; // with class, without pd check
-+ address _monomorphic_not_sibling_tail_call_entry_point;
++
++ // Tail call entry points:
++ // Without class and without protection domain check.
++ address _verified_tail_call_entry_point;
++ address _verified_not_sibling_tail_call_entry_point;
++ // With class, without protection domain check.
++ address _tail_call_entry_point;
++ address _not_sibling_tail_call_entry_point;
+
nmFlags flags; // various flags to keep track of nmethod state
bool _markedForDeoptimization; // Used for stack deoptimization
- enum { alive = 0,
-@@ -338,7 +347,10 @@
+@@ -338,7 +351,10 @@ class nmethod : public CodeBlob {
address handler_table_end () const { return header_begin() + _nul_chk_table_offset ; }
address nul_chk_table_begin() const { return header_begin() + _nul_chk_table_offset ; }
address nul_chk_table_end () const { return header_begin() + _nmethod_end_offset ; }
-
-+ address static_tail_call_begin() const { return header_begin() + _static_tail_call_offset; }
-+ address static_not_sibling_tail_call_begin() const { return header_begin() + _static_not_sibling_tail_call_offset; }
-+ address monomorphic_tail_call_begin() const { return header_begin() + _monomorphic_tail_call_offset; }
-+ address monomorphic_not_sibling_tail_call_begin() const { return header_begin() + _monomorphic_not_sibling_tail_call_offset; }
++ address verified_tail_call_begin() const { return header_begin() + _verified_tail_call_offset; }
++ address verified_not_sibling_tail_call_begin() const { return header_begin() + _verified_not_sibling_tail_call_offset; }
++ address tail_call_begin() const { return header_begin() + _tail_call_offset; }
++ address not_sibling_tail_call_begin() const { return header_begin() + _not_sibling_tail_call_offset; }
int code_size () const { return code_end () - code_begin (); }
int stub_size () const { return stub_end () - stub_begin (); }
int consts_size () const { return consts_end () - consts_begin (); }
-@@ -361,7 +373,14 @@
+@@ -361,7 +377,10 @@ class nmethod : public CodeBlob {
// entry points
address entry_point() const { return _entry_point; } // normal entry point
address verified_entry_point() const { return _verified_entry_point; } // if klass is correct
-
-+ address static_tail_call_entry_point() const { return _static_tail_call_entry_point; } // If klass and pd is korrect.
-+ address static_not_sibling_tail_call_entry_point() const { return _static_not_sibling_tail_call_entry_point; } // If klass and pd is korrect.
-+ address monomorphic_tail_call_entry_point() const { return _monomorphic_tail_call_entry_point; } // klass
-+ // check
-+ // (pd
-+ // is
-+ // correct)
-+ address monomorphic_not_sibling_tail_call_entry_point() const { return _monomorphic_not_sibling_tail_call_entry_point; }
++ address verified_tail_call_entry_point() const { return _verified_tail_call_entry_point; } // If klass and pd is korrect.
++ address verified_not_sibling_tail_call_entry_point() const { return _verified_not_sibling_tail_call_entry_point; } // If klass and pd is korrect.
++ address tail_call_entry_point() const { return _tail_call_entry_point; } // Klass check
++ address not_sibling_tail_call_entry_point() const { return _not_sibling_tail_call_entry_point; }
// flag accessing and manipulation
bool is_in_use() const { return flags.state == alive; }
bool is_alive() const { return flags.state == alive || flags.state == not_entrant; }
-@@ -432,6 +451,8 @@
+@@ -432,6 +451,8 @@ class nmethod : public CodeBlob {
// note: native wrappers cannot be deoptimized.
bool can_be_deoptimized() const { return is_java_method(); }
@@ -3358,22 +4890,24 @@ diff --git a/src/share/vm/code/nmethod.h
// Inline cache support
void clear_inline_caches();
void cleanup_inline_caches();
-@@ -581,7 +602,7 @@
+@@ -581,7 +602,7 @@ class nmethod : public CodeBlob {
static int verified_entry_point_offset() { return offset_of(nmethod, _verified_entry_point); }
static int osr_entry_point_offset() { return offset_of(nmethod, _osr_entry_point); }
static int entry_bci_offset() { return offset_of(nmethod, _entry_bci); }
-
-+ static int static_tail_call_entry_point_offset() { return offset_of(nmethod, _static_tail_call_entry_point); }
++ static int verified_tail_call_entry_point_offset() { return offset_of(nmethod, _verified_tail_call_entry_point); }
};
// Locks an nmethod so its code will not get removed, even if it is a zombie/not_entrant method
-diff --git a/src/share/vm/code/relocInfo.cpp b/src/share/vm/code/relocInfo.cpp
---- a/src/share/vm/code/relocInfo.cpp
-+++ b/src/share/vm/code/relocInfo.cpp
-@@ -106,6 +106,37 @@
+diff -r ce2272390558 src/share/vm/code/relocInfo.cpp
+--- a/src/share/vm/code/relocInfo.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/code/relocInfo.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -106,6 +106,39 @@ void relocInfo::change_reloc_info_for_ad
assert(found, "no relocInfo found for pc");
}
++// TODO: arnold remove dead code
++#if 0
+void relocInfo::change_reloc_info_for_address(RelocIterator *itr, address pc, relocType old_type, relocType new_type, address target, int section) {
+ bool found = false;
+ assert(old_type == relocInfo::static_call_type, "only works for static call");
@@ -3404,11 +4938,11 @@ diff --git a/src/share/vm/code/relocInfo
+ }
+ assert(found, "no relocInfo found for pc");
+}
-+
++#endif
void relocInfo::remove_reloc_info_for_address(RelocIterator *itr, address pc, relocType old_type) {
change_reloc_info_for_address(itr, pc, old_type, none);
-@@ -404,6 +435,31 @@
+@@ -404,6 +437,31 @@ Relocation* RelocIterator::reloc() {
}
@@ -3440,7 +4974,7 @@ diff --git a/src/share/vm/code/relocInfo
//////// Methods for flyweight Relocation types
-@@ -579,18 +635,43 @@
+@@ -579,18 +637,43 @@ void virtual_call_Relocation::pack_data_
normalize_address(_oop_limit, dest);
jint x0 = scaled_offset_null_special(_first_oop, point);
jint x1 = scaled_offset_null_special(_oop_limit, point);
@@ -3486,26 +5020,20 @@ diff --git a/src/share/vm/code/relocInfo
void static_stub_Relocation::pack_data_to(CodeSection* dest) {
short* p = (short*) dest->locs_end();
-@@ -702,6 +783,69 @@
+@@ -702,6 +785,62 @@ void section_word_Relocation::unpack_dat
_target = address_from_scaled_offset(offset, base);
}
+void static_call_Relocation::pack_data_to(CodeSection* dest) {
+ short* p = (short*) dest->locs_end();
-+ // Store dummy integer here.
-+ p = add_jint(p, 0);
+ p = add_short(p, (short)_tail_call_type);
+ dest->set_locs_end((relocInfo*) p);
+}
+
+void static_call_Relocation::unpack_data() {
-+ assert(datalen() == 3, "data length must be 3");
-+ // For symmetry.
+ short* p = data();
-+ jint dummy = relocInfo::jint_from_data(p);
-+ p+=2; // advance over int
++ assert(datalen() == 1, "data length must be 1");
+ _tail_call_type = (relocInfo::tailCallType)relocInfo::short_data_at(0, p, 1);
-+
+}
+
+void section_call_Relocation::pack_data_to(CodeSection* dest) {
@@ -3525,7 +5053,6 @@ diff --git a/src/share/vm/code/relocInfo
+ jint offset = scaled_offset(_target, base);
+ assert((uint)sindex < (uint)CodeBuffer::SECT_LIMIT, "sanity");
+ assert(CodeBuffer::SECT_LIMIT <= (1 << section_width), "section_width++");
-+ //p = pack_1_int_to(p, (offset << section_width) | sindex);
+ // Want fixed size.
+ p = add_jint(p, (offset << section_width) | sindex);
+
@@ -3556,7 +5083,7 @@ diff --git a/src/share/vm/code/relocInfo
void breakpoint_Relocation::pack_data_to(CodeSection* dest) {
short* p = (short*) dest->locs_end();
-@@ -775,9 +919,21 @@
+@@ -775,9 +914,21 @@ void oop_Relocation::fix_oop_relocation(
}
}
@@ -3580,7 +5107,7 @@ diff --git a/src/share/vm/code/relocInfo
assert(ic_call != NULL, "ic_call address must be set");
assert(ic_call != NULL || first_oop != NULL, "must supply a non-null input");
if (code == NULL) {
-@@ -803,12 +959,15 @@
+@@ -803,12 +954,15 @@ RelocIterator virtual_call_Relocation::p
virtual_call_Relocation* r = iter.virtual_call_reloc();
first_oop = r->first_oop();
oop_limit = r->oop_limit();
@@ -3596,7 +5123,7 @@ diff --git a/src/share/vm/code/relocInfo
return iter;
}
}
-@@ -865,7 +1024,9 @@
+@@ -865,22 +1019,27 @@ address virtual_call_Relocation::oop_lim
return _oop_limit;
}
@@ -3607,7 +5134,10 @@ diff --git a/src/share/vm/code/relocInfo
void virtual_call_Relocation::clear_inline_cache() {
// No stubs for ICs
-@@ -875,6 +1036,9 @@
+ // Clean IC
+ ResourceMark rm;
+- CompiledIC* icache = CompiledIC_at(this);
++ CompiledIC* icache = CompiledIC_at(this, _tail_call_type!=relocInfo::not_tail_call);
icache->set_to_clean();
}
@@ -3617,7 +5147,24 @@ diff --git a/src/share/vm/code/relocInfo
void opt_virtual_call_Relocation::clear_inline_cache() {
// No stubs for ICs
-@@ -900,6 +1064,10 @@
+ // Clean IC
+ ResourceMark rm;
+- CompiledIC* icache = CompiledIC_at(this);
++ CompiledIC* icache = CompiledIC_at(this, _tail_call_type!=relocInfo::not_tail_call);
+ icache->set_to_clean();
+ }
+
+@@ -893,6 +1052,9 @@ address opt_virtual_call_Relocation::sta
+ if (iter.type() == relocInfo::static_stub_type) {
+ if (iter.static_stub_reloc()->static_call() == static_call_addr) {
+ return iter.addr();
++ } else if (iter.static_stub_reloc()->static_call()+NativeJump::tail_call_push_ret_offset == static_call_addr) {
++ // Tail call via jump.
++ return iter.addr();
+ }
+ }
+ }
+@@ -900,9 +1062,14 @@ address opt_virtual_call_Relocation::sta
}
@@ -3627,11 +5174,26 @@ diff --git a/src/share/vm/code/relocInfo
+
void static_call_Relocation::clear_inline_cache() {
// Safe call site info
- CompiledStaticCall* handler = compiledStaticCall_at(this);
-diff --git a/src/share/vm/code/relocInfo.hpp b/src/share/vm/code/relocInfo.hpp
---- a/src/share/vm/code/relocInfo.hpp
-+++ b/src/share/vm/code/relocInfo.hpp
-@@ -261,12 +261,17 @@
+- CompiledStaticCall* handler = compiledStaticCall_at(this);
++ bool is_tail_call = _tail_call_type!=relocInfo::not_tail_call;
++ CompiledStaticCall* handler = compiledStaticCall_at(this, is_tail_call);
+ handler->set_to_clean();
+ }
+
+@@ -914,6 +1081,9 @@ address static_call_Relocation::static_s
+ while (iter.next()) {
+ if (iter.type() == relocInfo::static_stub_type) {
+ if (iter.static_stub_reloc()->static_call() == static_call_addr) {
++ return iter.addr();
++ } else if (iter.static_stub_reloc()->static_call()+NativeJump::tail_call_push_ret_offset == static_call_addr) {
++ // Tail call via jump.
+ return iter.addr();
+ }
+ }
+diff -r ce2272390558 src/share/vm/code/relocInfo.hpp
+--- a/src/share/vm/code/relocInfo.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/code/relocInfo.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -261,12 +261,17 @@ class relocInfo VALUE_OBJ_CLASS_SPEC {
poll_type = 10, // polling instruction for safepoints
poll_return_type = 11, // polling instruction for safepoints at return
breakpoint_type = 12, // an initialization barrier or safepoint
@@ -3651,7 +5213,7 @@ diff --git a/src/share/vm/code/relocInfo
protected:
unsigned short _value;
-@@ -302,7 +307,7 @@
+@@ -302,7 +307,7 @@ class relocInfo VALUE_OBJ_CLASS_SPEC {
visitor(poll_return) \
visitor(breakpoint) \
visitor(section_word) \
@@ -3660,15 +5222,7 @@ diff --git a/src/share/vm/code/relocInfo
public:
enum {
-@@ -412,6 +417,7 @@
- // (since code is dynamically patched, we also need to dynamically update the relocation info)
- // Both methods takes old_type, so it is able to performe sanity checks on the information removed.
- static void change_reloc_info_for_address(RelocIterator *itr, address pc, relocType old_type, relocType new_type);
-+ static void change_reloc_info_for_address(RelocIterator *itr, address pc, relocType old_type, relocType new_type, address target, int section);
- static void remove_reloc_info_for_address(RelocIterator *itr, address pc, relocType old_type);
-
- // Machine dependent stuff
-@@ -616,6 +622,8 @@
+@@ -616,6 +621,8 @@ class RelocIterator : public StackObj {
#undef EACH_TYPE
// generic relocation accessor; switches on type to call the above
Relocation* reloc();
@@ -3677,7 +5231,7 @@ diff --git a/src/share/vm/code/relocInfo
// CodeBlob's have relocation indexes for faster random access:
static int locs_and_index_size(int code_size, int locs_size);
-@@ -732,7 +740,7 @@
+@@ -732,7 +739,7 @@ class Relocation VALUE_OBJ_CLASS_SPEC {
}
return p;
}
@@ -3686,7 +5240,7 @@ diff --git a/src/share/vm/code/relocInfo
int dlen = datalen();
short* dp = data();
if (dlen <= 2) {
-@@ -743,6 +751,7 @@
+@@ -743,6 +750,7 @@ class Relocation VALUE_OBJ_CLASS_SPEC {
x0 = relocInfo::jint_data_at(0, dp, dlen);
x1 = relocInfo::jint_data_at(2, dp, dlen);
}
@@ -3694,7 +5248,7 @@ diff --git a/src/share/vm/code/relocInfo
}
protected:
-@@ -821,6 +830,8 @@
+@@ -821,6 +829,8 @@ class Relocation VALUE_OBJ_CLASS_SPEC {
virtual void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { }
void print();
@@ -3703,7 +5257,7 @@ diff --git a/src/share/vm/code/relocInfo
};
-@@ -948,20 +959,24 @@
+@@ -948,20 +958,24 @@ class virtual_call_Relocation : public C
// "first_oop" points to the first associated set-oop.
// The oop_limit helps find the last associated set-oop.
// (See comments at the top of this file.)
@@ -3731,7 +5285,7 @@ diff --git a/src/share/vm/code/relocInfo
friend class RelocIterator;
virtual_call_Relocation() { }
-@@ -970,6 +985,7 @@
+@@ -970,6 +984,7 @@ class virtual_call_Relocation : public C
public:
address first_oop();
address oop_limit();
@@ -3739,7 +5293,7 @@ diff --git a/src/share/vm/code/relocInfo
// data is packed as scaled offsets in "2_ints" format: [f l] or [Ff Ll]
// oop_limit is set to 0 if the limit falls somewhere within the call.
-@@ -987,7 +1003,7 @@
+@@ -987,7 +1002,7 @@ class virtual_call_Relocation : public C
// The returned iterator will enumerate over the oops and the ic_call,
// as well as any other relocations that happen to be in that span of code.
// Recognize relevant set_oops with: oop_reloc()->oop_addr() == oop_addr.
@@ -3748,7 +5302,7 @@ diff --git a/src/share/vm/code/relocInfo
};
-@@ -995,21 +1011,27 @@
+@@ -995,21 +1010,27 @@ class opt_virtual_call_Relocation : publ
relocInfo::relocType type() { return relocInfo::opt_virtual_call_type; }
public:
@@ -3781,7 +5335,7 @@ diff --git a/src/share/vm/code/relocInfo
};
-@@ -1017,21 +1039,28 @@
+@@ -1017,21 +1038,28 @@ class static_call_Relocation : public Ca
relocInfo::relocType type() { return relocInfo::static_call_type; }
public:
@@ -3815,7 +5369,7 @@ diff --git a/src/share/vm/code/relocInfo
};
class static_stub_Relocation : public Relocation {
-@@ -1197,6 +1226,41 @@
+@@ -1197,6 +1225,41 @@ class section_word_Relocation : public i
};
@@ -3857,10 +5411,10 @@ diff --git a/src/share/vm/code/relocInfo
class poll_Relocation : public Relocation {
bool is_data() { return true; }
relocInfo::relocType type() { return relocInfo::poll_type; }
-diff --git a/src/share/vm/code/vtableStubs.cpp b/src/share/vm/code/vtableStubs.cpp
---- a/src/share/vm/code/vtableStubs.cpp
-+++ b/src/share/vm/code/vtableStubs.cpp
-@@ -96,17 +96,17 @@
+diff -r ce2272390558 src/share/vm/code/vtableStubs.cpp
+--- a/src/share/vm/code/vtableStubs.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/code/vtableStubs.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -96,17 +96,17 @@ void VtableStubs::initialize() {
}
@@ -3883,12 +5437,12 @@ diff --git a/src/share/vm/code/vtableStu
#ifndef PRODUCT
if (PrintAdapterHandlers) {
tty->print_cr("Decoding VtableStub %s[%d]@%d",
-@@ -119,26 +119,28 @@
+@@ -119,26 +119,28 @@ address VtableStubs::create_stub(bool is
}
-inline uint VtableStubs::hash(bool is_vtable_stub, int vtable_index){
-+inline uint VtableStubs::hash(bool is_vtable_stub, int vtable_index, bool is_tail_call, bool is_sibling) {
++inline uint VtableStubs::hash(bool is_vtable_stub, int vtable_index, bool is_tail_call, bool is_sibling){
// Assumption: receiver_location < 4 in most cases.
int hash = ((vtable_index << 2) ^ VtableStub::receiver_location()->value()) + vtable_index;
return (is_vtable_stub ? ~hash : hash) & mask;
@@ -3919,7 +5473,7 @@ diff --git a/src/share/vm/code/vtableStu
// enter s at the beginning of the corresponding list
s->set_next(_table[h]);
_table[h] = s;
-@@ -149,7 +151,7 @@
+@@ -149,7 +151,7 @@ bool VtableStubs::is_entry_point(address
bool VtableStubs::is_entry_point(address pc) {
MutexLocker ml(VtableStubs_lock);
VtableStub* stub = (VtableStub*)(pc - VtableStub::entry_offset());
@@ -3928,10 +5482,10 @@ diff --git a/src/share/vm/code/vtableStu
VtableStub* s;
for (s = _table[hash]; s != NULL && s != stub; s = s->next()) {}
return s == stub;
-diff --git a/src/share/vm/code/vtableStubs.hpp b/src/share/vm/code/vtableStubs.hpp
---- a/src/share/vm/code/vtableStubs.hpp
-+++ b/src/share/vm/code/vtableStubs.hpp
-@@ -37,14 +37,18 @@
+diff -r ce2272390558 src/share/vm/code/vtableStubs.hpp
+--- a/src/share/vm/code/vtableStubs.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/code/vtableStubs.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -37,14 +37,18 @@ class VtableStub {
const short _index; // vtable index
short _ame_offset; // Where an AbstractMethodError might occur
short _npe_offset; // Where a NullPointerException might occur
@@ -3953,7 +5507,7 @@ diff --git a/src/share/vm/code/vtableStu
VtableStub* next() const { return _next; }
int index() const { return _index; }
static VMReg receiver_location() { return _receiver_location; }
-@@ -54,8 +58,9 @@
+@@ -54,8 +58,9 @@ class VtableStub {
address entry_point() const { return code_begin(); }
static int entry_offset() { return sizeof(class VtableStub); }
@@ -3965,7 +5519,7 @@ diff --git a/src/share/vm/code/vtableStu
}
bool contains(address pc) const { return code_begin() <= pc && pc < code_end(); }
-@@ -83,6 +88,8 @@
+@@ -83,6 +88,8 @@ class VtableStub {
// Query
bool is_itable_stub() { return !_is_vtable_stub; }
bool is_vtable_stub() { return _is_vtable_stub; }
@@ -3974,7 +5528,7 @@ diff --git a/src/share/vm/code/vtableStu
bool is_abstract_method_error(address epc) { return epc == code_begin()+_ame_offset; }
bool is_null_pointer_exception(address epc) { return epc == code_begin()+_npe_offset; }
-@@ -105,14 +112,14 @@
+@@ -105,14 +112,14 @@ class VtableStubs : AllStatic {
static VtableStub* _table[N]; // table of existing stubs
static int _number_of_vtable_stubs; // number of stubs created so far (for statistics)
@@ -3995,23 +5549,24 @@ diff --git a/src/share/vm/code/vtableStu
static bool is_entry_point(address pc); // is pc a vtable stub entry point?
static bool contains(address pc); // is pc within any stub?
static VtableStub* stub_containing(address pc); // stub containing pc or NULL
-diff --git a/src/share/vm/compiler/disassembler.cpp b/src/share/vm/compiler/disassembler.cpp
---- a/src/share/vm/compiler/disassembler.cpp
-+++ b/src/share/vm/compiler/disassembler.cpp
-@@ -293,6 +293,9 @@
+diff -r ce2272390558 src/share/vm/compiler/disassembler.cpp
+--- a/src/share/vm/compiler/disassembler.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/compiler/disassembler.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -293,6 +293,10 @@ void decode_env::print_insn_labels() {
if (p == nm->exception_begin()) st->print_cr("[Exception Handler]");
if (p == nm->stub_begin()) st->print_cr("[Stub Code]");
if (p == nm->consts_begin()) st->print_cr("[Constants]");
-+ if (p == nm->static_tail_call_begin()) st->print_cr("[Static Tail Call Entry Point] %x", nm->static_tail_call_entry_point());
-+ if (p == nm->monomorphic_tail_call_begin()) st->print_cr("[Monomorphic Tail Call Entry Point] %x", nm->monomorphic_tail_call_entry_point());
-+ if (p == nm->static_not_sibling_tail_call_begin()) st->print_cr("[Static Not Sibling Tail Call Entry Point] %x", nm->monomorphic_tail_call_entry_point());
++ if (p == nm->verified_tail_call_begin()) st->print_cr("[Verified Tail Call Entry Point]");
++ if (p == nm->tail_call_begin()) st->print_cr("[Tail Call Entry Point]");
++ if (p == nm->verified_not_sibling_tail_call_begin()) st->print_cr("[Verified Not Sibling Tail Call Entry Point]");
++ if (p == nm->not_sibling_tail_call_begin()) st->print_cr("[Not Sibling Tail Call Entry Point]");
}
CodeBlob* cb = _code;
if (cb != NULL) {
-diff --git a/src/share/vm/compiler/disassembler.hpp b/src/share/vm/compiler/disassembler.hpp
---- a/src/share/vm/compiler/disassembler.hpp
-+++ b/src/share/vm/compiler/disassembler.hpp
-@@ -29,7 +29,7 @@
+diff -r ce2272390558 src/share/vm/compiler/disassembler.hpp
+--- a/src/share/vm/compiler/disassembler.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/compiler/disassembler.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -29,7 +29,7 @@ class decode_env;
class Disassembler {
friend class decode_env;
@@ -4020,7 +5575,7 @@ diff --git a/src/share/vm/compiler/disas
// this is the type of the dll entry point:
typedef void* (*decode_func)(void* start, void* end,
void* (*event_callback)(void*, const char*, void*),
-@@ -37,6 +37,8 @@
+@@ -37,6 +37,8 @@ class Disassembler {
int (*printf_callback)(void*, const char*, ...),
void* printf_stream,
const char* options);
@@ -4029,10 +5584,44 @@ diff --git a/src/share/vm/compiler/disas
// points to the library.
static void* _library;
// bailout
-diff --git a/src/share/vm/interpreter/abstractInterpreter.hpp b/src/share/vm/interpreter/abstractInterpreter.hpp
---- a/src/share/vm/interpreter/abstractInterpreter.hpp
-+++ b/src/share/vm/interpreter/abstractInterpreter.hpp
-@@ -73,7 +73,9 @@
+diff -r ce2272390558 src/share/vm/includeDB_core
+--- a/src/share/vm/includeDB_core Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/includeDB_core Mon Mar 16 11:44:02 2009 +0100
+@@ -1123,11 +1123,14 @@ compiledIC.cpp
+ compiledIC.cpp systemDictionary.hpp
+ compiledIC.cpp vtableStubs.hpp
+
++compiledIC.hpp codeCache.hpp
+ compiledIC.hpp compiledICHolderKlass.hpp
+ compiledIC.hpp compiledICHolderOop.hpp
+ compiledIC.hpp klassOop.hpp
+ compiledIC.hpp linkResolver.hpp
+ compiledIC.hpp nativeInst_<arch>.hpp
++compiledIC.hpp nmethod.hpp
++compiledIC.hpp relocInfo.hpp
+
+ compiledICHolderKlass.cpp collectedHeap.hpp
+ compiledICHolderKlass.cpp collectedHeap.inline.hpp
+@@ -4415,6 +4418,7 @@ verifier.cpp
+ verifier.cpp typeArrayOop.hpp
+ verifier.cpp verifier.hpp
+ verifier.cpp vmSymbols.hpp
++verifier.cpp bytecodes.hpp
+
+ verifier.hpp exceptions.hpp
+ verifier.hpp gcLocker.hpp
+@@ -4472,6 +4476,7 @@ vframeArray.cpp
+ vframeArray.cpp vframeArray.hpp
+ vframeArray.cpp vframe_hp.hpp
+ vframeArray.cpp vmSymbols.hpp
++vframeArray.cpp objectMonitor.inline.hpp
+
+ vframeArray.hpp arrayOop.hpp
+ vframeArray.hpp deoptimization.hpp
+diff -r ce2272390558 src/share/vm/interpreter/abstractInterpreter.hpp
+--- a/src/share/vm/interpreter/abstractInterpreter.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/abstractInterpreter.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -73,7 +73,9 @@ class AbstractInterpreter: AllStatic {
};
enum SomeConstants {
@@ -4043,7 +5632,7 @@ diff --git a/src/share/vm/interpreter/ab
};
protected:
-@@ -91,7 +93,11 @@
+@@ -91,7 +93,11 @@ class AbstractInterpreter: AllStatic {
static address _rethrow_exception_entry; // rethrows an activation in previous frame
@@ -4056,7 +5645,7 @@ diff --git a/src/share/vm/interpreter/ab
friend class AbstractInterpreterGenerator;
friend class InterpreterGenerator;
-@@ -118,6 +124,10 @@
+@@ -118,6 +124,10 @@ class AbstractInterpreter: AllStatic {
static address rethrow_exception_entry() { return _rethrow_exception_entry; }
@@ -4067,10 +5656,10 @@ diff --git a/src/share/vm/interpreter/ab
// Activation size in words for a method that is just being called.
// Parameters haven't been pushed so count them too.
static int size_top_interpreter_activation(methodOop method);
-diff --git a/src/share/vm/interpreter/bytecode.hpp b/src/share/vm/interpreter/bytecode.hpp
---- a/src/share/vm/interpreter/bytecode.hpp
-+++ b/src/share/vm/interpreter/bytecode.hpp
-@@ -167,10 +167,20 @@
+diff -r ce2272390558 src/share/vm/interpreter/bytecode.hpp
+--- a/src/share/vm/interpreter/bytecode.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/bytecode.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -167,10 +167,20 @@ inline Bytecode_tableswitch* Bytecode_ta
class Bytecode_invoke: public ResourceObj {
protected:
@@ -4094,7 +5683,7 @@ diff --git a/src/share/vm/interpreter/by
public:
void verify() const;
-@@ -191,6 +201,7 @@
+@@ -191,6 +201,7 @@ class Bytecode_invoke: public ResourceOb
methodHandle static_target(TRAPS); // "specified" method (from constant pool)
// Testers
@@ -4102,10 +5691,10 @@ diff --git a/src/share/vm/interpreter/by
bool is_invokeinterface() const { return adjusted_invoke_code() == Bytecodes::_invokeinterface; }
bool is_invokevirtual() const { return adjusted_invoke_code() == Bytecodes::_invokevirtual; }
bool is_invokestatic() const { return adjusted_invoke_code() == Bytecodes::_invokestatic; }
-diff --git a/src/share/vm/interpreter/bytecodeStream.cpp b/src/share/vm/interpreter/bytecodeStream.cpp
---- a/src/share/vm/interpreter/bytecodeStream.cpp
-+++ b/src/share/vm/interpreter/bytecodeStream.cpp
-@@ -37,14 +37,24 @@
+diff -r ce2272390558 src/share/vm/interpreter/bytecodeStream.cpp
+--- a/src/share/vm/interpreter/bytecodeStream.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/bytecodeStream.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -37,14 +37,24 @@ Bytecodes::Code RawBytecodeStream::raw_n
_next_bci += l;
assert(_bci < _next_bci, "length must be > 0");
// set attributes
@@ -4132,10 +5721,10 @@ diff --git a/src/share/vm/interpreter/by
}
}
}
-diff --git a/src/share/vm/interpreter/bytecodeStream.hpp b/src/share/vm/interpreter/bytecodeStream.hpp
---- a/src/share/vm/interpreter/bytecodeStream.hpp
-+++ b/src/share/vm/interpreter/bytecodeStream.hpp
-@@ -47,16 +47,17 @@
+diff -r ce2272390558 src/share/vm/interpreter/bytecodeStream.hpp
+--- a/src/share/vm/interpreter/bytecodeStream.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/bytecodeStream.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -47,16 +47,17 @@ class RawBytecodeStream: StackObj {
int _bci; // bci if current bytecode
int _next_bci; // bci of next bytecode
int _end_bci; // bci after the current iteration interval
@@ -4155,7 +5744,7 @@ diff --git a/src/share/vm/interpreter/by
// Iteration control
void set_interval(int beg_bci, int end_bci) {
-@@ -84,12 +85,12 @@
+@@ -84,12 +85,12 @@ class RawBytecodeStream: StackObj {
code = Bytecodes::code_or_bp_at(bcp);
// set next bytecode position
@@ -4172,7 +5761,7 @@ diff --git a/src/share/vm/interpreter/by
_code = code;
return code;
} else if (code == Bytecodes::_wide && _bci + 1 >= _end_bci) {
-@@ -108,7 +109,11 @@
+@@ -108,7 +109,11 @@ class RawBytecodeStream: StackObj {
int end_bci() const { return _end_bci; }
Bytecodes::Code code() const { return _code; }
@@ -4185,7 +5774,7 @@ diff --git a/src/share/vm/interpreter/by
bool is_last_bytecode() const { return _next_bci >= _end_bci; }
address bcp() const { return method()->code_base() + _bci; }
-@@ -122,8 +127,8 @@
+@@ -122,8 +127,8 @@ class RawBytecodeStream: StackObj {
int dest_w() const { return bci() + (int )Bytes::get_Java_u4(bcp() + 1); }
// Unsigned indices, widening
@@ -4196,7 +5785,7 @@ diff --git a/src/share/vm/interpreter/by
};
// In BytecodeStream, non-java bytecodes will be translated into the
-@@ -151,18 +156,23 @@
+@@ -151,18 +156,23 @@ class BytecodeStream: public RawBytecode
// note that we cannot advance before having the
// tty bytecode otherwise the stepping is wrong!
// (carefull: length_for(...) must be used first!)
@@ -4211,7 +5800,7 @@ diff --git a/src/share/vm/interpreter/by
+ code = (Bytecodes::Code)bcp[1];
+ _prefix = Bytecodes::allowed_prefix(code);
+ assert(prefix_length() == 1, "");
-+ if (_prefix == Bytecodes::Prefix_illegal) {
++ if (_prefix == Bytecodes::Prefix_illegal){
+ code = Bytecodes::_illegal;
+ }
+ }
@@ -4231,10 +5820,10 @@ diff --git a/src/share/vm/interpreter/by
}
_code = code;
return _code;
-diff --git a/src/share/vm/interpreter/bytecodeTracer.cpp b/src/share/vm/interpreter/bytecodeTracer.cpp
---- a/src/share/vm/interpreter/bytecodeTracer.cpp
-+++ b/src/share/vm/interpreter/bytecodeTracer.cpp
-@@ -38,7 +38,7 @@
+diff -r ce2272390558 src/share/vm/interpreter/bytecodeTracer.cpp
+--- a/src/share/vm/interpreter/bytecodeTracer.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/bytecodeTracer.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -38,7 +38,7 @@ class BytecodePrinter: public BytecodeCl
// operations on the pointer, except within a critical section.
// (Also, ensure that occasional false positives are benign.)
methodOop _current_method;
@@ -4243,7 +5832,7 @@ diff --git a/src/share/vm/interpreter/by
address _next_pc; // current decoding position
void align() { _next_pc = (address)round_to((intptr_t)_next_pc, sizeof(jint)); }
-@@ -48,10 +48,11 @@
+@@ -48,10 +48,11 @@ class BytecodePrinter: public BytecodeCl
int get_index() { return *(address)_next_pc++; }
int get_big_index() { int i=Bytes::get_Java_u2(_next_pc); _next_pc+=2; return i; }
@@ -4258,7 +5847,7 @@ diff --git a/src/share/vm/interpreter/by
void print_constant(int i, outputStream* st = tty);
void print_attributes(Bytecodes::Code code, int bci, outputStream* st = tty);
-@@ -59,7 +60,7 @@
+@@ -59,7 +60,7 @@ class BytecodePrinter: public BytecodeCl
public:
BytecodePrinter() {
@@ -4267,7 +5856,7 @@ diff --git a/src/share/vm/interpreter/by
}
// This method is called while executing the raw bytecodes, so none of
-@@ -80,26 +81,32 @@
+@@ -80,26 +81,32 @@ class BytecodePrinter: public BytecodeCl
_current_method = method();
}
Bytecodes::Code code;
@@ -4309,7 +5898,7 @@ diff --git a/src/share/vm/interpreter/by
}
// Used for methodOop::print_codes(). The input bcp comes from
-@@ -108,19 +115,18 @@
+@@ -108,19 +115,18 @@ class BytecodePrinter: public BytecodeCl
_current_method = method();
ResourceMark rm;
Bytecodes::Code code = Bytecodes::code_at(bcp);
@@ -4337,7 +5926,7 @@ diff --git a/src/share/vm/interpreter/by
print_attributes(code, bci, st);
bytecode_epilog(bci, st);
}
-@@ -250,7 +256,7 @@
+@@ -250,7 +256,7 @@ void BytecodePrinter::print_attributes(B
case Bytecodes::_iinc:
{ int index = get_index_special();
@@ -4346,10 +5935,10 @@ diff --git a/src/share/vm/interpreter/by
st->print_cr(" #%d " INT32_FORMAT, index, offset);
}
break;
-diff --git a/src/share/vm/interpreter/bytecodes.cpp b/src/share/vm/interpreter/bytecodes.cpp
---- a/src/share/vm/interpreter/bytecodes.cpp
-+++ b/src/share/vm/interpreter/bytecodes.cpp
-@@ -40,6 +40,8 @@
+diff -r ce2272390558 src/share/vm/interpreter/bytecodes.cpp
+--- a/src/share/vm/interpreter/bytecodes.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/bytecodes.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -40,6 +40,8 @@ BasicType Bytecodes::_result_type
BasicType Bytecodes::_result_type [Bytecodes::number_of_codes];
s_char Bytecodes::_depth [Bytecodes::number_of_codes];
u_char Bytecodes::_length [Bytecodes::number_of_codes];
@@ -4358,7 +5947,7 @@ diff --git a/src/share/vm/interpreter/by
bool Bytecodes::_can_trap [Bytecodes::number_of_codes];
Bytecodes::Code Bytecodes::_java_code [Bytecodes::number_of_codes];
bool Bytecodes::_can_rewrite [Bytecodes::number_of_codes];
-@@ -61,7 +63,7 @@
+@@ -61,7 +63,7 @@ int Bytecodes::special_length_at(address
if (end != NULL && bcp + 1 >= end) {
return -1; // don't read past end of code buffer
}
@@ -4367,7 +5956,7 @@ diff --git a/src/share/vm/interpreter/by
case _tableswitch:
{ address aligned_bcp = (address)round_to((intptr_t)bcp + 1, jintSize);
if (end != NULL && aligned_bcp + 3*jintSize >= end) {
-@@ -92,6 +94,32 @@
+@@ -92,6 +94,32 @@ int Bytecodes::special_length_at(address
return 0;
}
@@ -4400,7 +5989,7 @@ diff --git a/src/share/vm/interpreter/by
// At a breakpoint instruction, this returns the breakpoint's length,
// otherwise, it's the same as special_length_at(). This is used by
// the RawByteCodeStream, which wants to see the actual bytecode
-@@ -114,7 +142,6 @@
+@@ -114,7 +142,6 @@ int Bytecodes::raw_special_length_at(add
}
@@ -4408,7 +5997,7 @@ diff --git a/src/share/vm/interpreter/by
void Bytecodes::def(Code code, const char* name, const char* format, const char* wide_format, BasicType result_type, int depth, bool can_trap) {
def(code, name, format, wide_format, result_type, depth, can_trap, code);
}
-@@ -122,13 +149,39 @@
+@@ -122,13 +149,39 @@ void Bytecodes::def(Code code, const cha
void Bytecodes::def(Code code, const char* name, const char* format, const char* wide_format, BasicType result_type, int depth, bool can_trap, Code java_code) {
assert(wide_format == NULL || format != NULL, "short form must exist if there's a wide form");
@@ -4450,17 +6039,17 @@ diff --git a/src/share/vm/interpreter/by
_java_code [code] = java_code;
if (java_code != code) _can_rewrite[java_code] = true;
}
-@@ -159,6 +212,9 @@
+@@ -158,6 +211,9 @@ void Bytecodes::initialize() {
+ void Bytecodes::initialize() {
if (_is_initialized) return;
assert(number_of_codes <= 256, "too many bytecodes");
-
++
+ assert(0 == strcmp("wide_index:", prefix_name(Prefix_wide_index)),
+ "_prefix_name initialized correctly"); // spot-check only
-+
+
// initialize bytecode tables - didn't use static array initializers
// (such as {}) so we can do additional consistency checks and init-
- // code is independent of actual bytecode numbering.
-@@ -353,10 +409,10 @@
+@@ -353,10 +409,10 @@ void Bytecodes::initialize() {
def(_putstatic , "putstatic" , "bjj" , NULL , T_ILLEGAL, -1, true );
def(_getfield , "getfield" , "bjj" , NULL , T_ILLEGAL, 0, true );
def(_putfield , "putfield" , "bjj" , NULL , T_ILLEGAL, -2, true );
@@ -4475,10 +6064,10 @@ diff --git a/src/share/vm/interpreter/by
def(_xxxunusedxxx , "xxxunusedxxx" , NULL , NULL , T_VOID , 0, false);
def(_new , "new" , "bii" , NULL , T_OBJECT , 1, true );
def(_newarray , "newarray" , "bc" , NULL , T_OBJECT , 0, true );
-diff --git a/src/share/vm/interpreter/bytecodes.hpp b/src/share/vm/interpreter/bytecodes.hpp
---- a/src/share/vm/interpreter/bytecodes.hpp
-+++ b/src/share/vm/interpreter/bytecodes.hpp
-@@ -280,6 +280,16 @@
+diff -r ce2272390558 src/share/vm/interpreter/bytecodes.hpp
+--- a/src/share/vm/interpreter/bytecodes.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/bytecodes.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -280,6 +280,16 @@ class Bytecodes: AllStatic {
number_of_codes
};
@@ -4495,7 +6084,7 @@ diff --git a/src/share/vm/interpreter/by
private:
static bool _is_initialized;
static const char* _name [number_of_codes];
-@@ -288,9 +298,12 @@
+@@ -288,9 +298,12 @@ class Bytecodes: AllStatic {
static BasicType _result_type [number_of_codes];
static s_char _depth [number_of_codes];
static u_char _length [number_of_codes];
@@ -4508,7 +6097,7 @@ diff --git a/src/share/vm/interpreter/by
static void def(Code code, const char* name, const char* format, const char* wide_format, BasicType result_type, int depth, bool can_trap);
static void def(Code code, const char* name, const char* format, const char* wide_format, BasicType result_type, int depth, bool can_trap, Code java_code);
-@@ -300,9 +313,9 @@
+@@ -300,9 +313,9 @@ class Bytecodes: AllStatic {
public:
// Conversion
static void check (Code code) { assert(is_defined(code), "illegal code"); }
@@ -4519,10 +6108,11 @@ diff --git a/src/share/vm/interpreter/by
// Fetch a bytecode, hiding breakpoints as necessary:
static Code code_at(address bcp, methodOop method = NULL) {
-@@ -311,6 +324,16 @@
+@@ -310,6 +323,16 @@ class Bytecodes: AllStatic {
+ }
static Code java_code_at(address bcp, methodOop method = NULL) {
return java_code(code_at(bcp, method));
- }
++ }
+ static Code java_code_at(address bcp, Prefix& prefix_return) {
+ Code code = java_code(code_at(bcp));
+ if (code != _wide) {
@@ -4532,11 +6122,10 @@ diff --git a/src/share/vm/interpreter/by
+ prefix_return = allowed_prefix(code);
+ }
+ return code;
-+ }
+ }
// Fetch a bytecode or a breakpoint:
- static Code code_or_bp_at(address bcp) { return (Code)cast(*bcp); }
-@@ -323,23 +346,28 @@
+@@ -323,27 +346,35 @@ class Bytecodes: AllStatic {
// Bytecode attributes
static bool is_defined (int code) { return 0 <= code && code < number_of_codes && _format[code] != NULL; }
@@ -4566,42 +6155,124 @@ diff --git a/src/share/vm/interpreter/by
- const char* wf = wide_format(code);
- return (wf == NULL) ? 0 : (int)strlen(wf);
}
++
+ static const char* prefix_name (Prefix pfx);
+ static const char* name_for (Prefix pfx, Code code); // may resource-allocate
++
// if 'end' is provided, it indicates the end of the code buffer which
// should not be read past when parsing.
static int special_length_at(address bcp, address end = NULL);
-diff --git a/src/share/vm/interpreter/interpreter.cpp b/src/share/vm/interpreter/interpreter.cpp
---- a/src/share/vm/interpreter/interpreter.cpp
-+++ b/src/share/vm/interpreter/interpreter.cpp
-@@ -131,6 +131,9 @@
+ static int raw_special_length_at(address bcp, address end = NULL);
++
+ static int length_at (address bcp) { int l = length_for(code_at(bcp)); return l > 0 ? l : special_length_at(bcp); }
+ static int java_length_at (address bcp) { int l = length_for(java_code_at(bcp)); return l > 0 ? l : special_length_at(bcp); }
+ static bool is_java_code (Code code) { return 0 <= code && code < number_of_java_codes; }
+diff -r ce2272390558 src/share/vm/interpreter/interpreter.cpp
+--- a/src/share/vm/interpreter/interpreter.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/interpreter.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -130,6 +130,9 @@ address AbstractInterpreter::_slow_si
+ address AbstractInterpreter::_slow_signature_handler;
address AbstractInterpreter::_entry_table [AbstractInterpreter::number_of_method_entries];
address AbstractInterpreter::_native_abi_to_tosca [AbstractInterpreter::number_of_result_handlers];
-
++
+address AbstractInterpreter::_interpreter_code_begin = NULL;
+address AbstractInterpreter::_interpreter_code_end = NULL;
-+
+
//------------------------------------------------------------------------------------------------------------------------
// Generation of complete interpreter
-
-diff --git a/src/share/vm/interpreter/interpreterRuntime.cpp b/src/share/vm/interpreter/interpreterRuntime.cpp
---- a/src/share/vm/interpreter/interpreterRuntime.cpp
-+++ b/src/share/vm/interpreter/interpreterRuntime.cpp
-@@ -432,6 +432,10 @@
+@@ -356,11 +359,13 @@ address AbstractInterpreter::continuatio
+ Thread *thread = Thread::current();
+ ResourceMark rm(thread);
+ methodHandle mh(thread, method);
+- type = Bytecode_invoke_at(mh, bci)->result_type(thread);
++ Bytecode_invoke * invoke = Bytecode_invoke_at(mh, bci);
++ type = invoke->result_type(thread);
+ // since the cache entry might not be initialized:
+ // (NOT needed for the old calling convension)
+ if (!is_top_frame) {
+- int index = Bytes::get_native_u2(bcp+1);
++ int index = -1;
++ index = Bytes::get_native_u2(bcp+1);
+ method->constants()->cache()->entry_at(index)->set_parameter_size(callee_parameters);
+ }
+ break;
+@@ -374,7 +379,33 @@ address AbstractInterpreter::continuatio
+ case Bytecodes::_ldc2_w:
+ type = constant_pool_type( method, Bytes::get_Java_u2(bcp+1) );
+ break;
+-
++
++ case Bytecodes::_wide: {
++ Bytecodes::Code next = Bytecodes::java_code_at(bcp+1);
++ if (next == Bytecodes::_invokestatic ||
++ next == Bytecodes::_invokevirtual ||
++ next == Bytecodes::_invokespecial ||
++ next == Bytecodes::_invokeinterface) {
++ Thread *thread = Thread::current();
++ ResourceMark rm(thread);
++ methodHandle mh(thread, method);
++ Bytecode_invoke * invoke = Bytecode_invoke_at(mh, bci);
++ type = invoke->result_type(thread);
++ // since the cache entry might not be initialized:
++ // (NOT needed for the old calling convension)
++ if (!is_top_frame) {
++ int index = -1;
++ if (invoke->is_tailcall()) {
++ index = Bytes::get_native_u2(bcp+2);
++ } else {
++ index = Bytes::get_native_u2(bcp+1);
++ }
++ method->constants()->cache()->entry_at(index)->set_parameter_size(callee_parameters);
++ }
++ } else
++ type = Bytecodes::result_type(code);
++ break;
++ }
+ default:
+ type = Bytecodes::result_type(code);
+ break;
+diff -r ce2272390558 src/share/vm/interpreter/interpreterRuntime.cpp
+--- a/src/share/vm/interpreter/interpreterRuntime.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/interpreterRuntime.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -235,6 +235,23 @@ IRT_ENTRY(void, InterpreterRuntime::thro
+ THROW_HANDLE(exception);
+ IRT_END
+
++
++IRT_ENTRY(void, InterpreterRuntime::tail_call_handle_stack_overflow(JavaThread * thread))
++{// to get emacs to indent correctly
++ // Try to compress the stack here.
++ // Look at stack.
++ {
++ ResourceMark rm(thread);
++ if (StackCompressor::can_compress(thread)) {
++ thread->set_tail_call_do_stack_compression((address)1);
++ return;
++ }
++ }
++ // Throwing of exception is handled in calling function. See
++ // TemplateInterpreterGenerator::generate_tail_call_handle_stack_overflow_handler.
++ thread->set_tail_call_do_stack_compression((address)0);
++}// to get emacs to indent correctly
++IRT_END
+
+ IRT_ENTRY(void, InterpreterRuntime::create_exception(JavaThread* thread, char* name, char* message))
+ // lookup exception klass
+@@ -430,6 +447,10 @@ IRT_END
+
+ IRT_ENTRY(void, InterpreterRuntime::throw_IncompatibleClassChangeError(JavaThread* thread))
THROW(vmSymbols::java_lang_IncompatibleClassChangeError());
- IRT_END
-
++IRT_END
++
+IRT_ENTRY(void, InterpreterRuntime::throw_TailCallException(JavaThread* thread))
+ THROW(vmSymbols::java_lang_TailCallException());
-+IRT_END
-+
-
- //------------------------------------------------------------------------------------------------------------------------
- // Fields
-diff --git a/src/share/vm/interpreter/interpreterRuntime.hpp b/src/share/vm/interpreter/interpreterRuntime.hpp
---- a/src/share/vm/interpreter/interpreterRuntime.hpp
-+++ b/src/share/vm/interpreter/interpreterRuntime.hpp
-@@ -33,7 +33,13 @@
+ IRT_END
+
+
+diff -r ce2272390558 src/share/vm/interpreter/interpreterRuntime.hpp
+--- a/src/share/vm/interpreter/interpreterRuntime.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/interpreterRuntime.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -33,7 +33,13 @@ class InterpreterRuntime: AllStatic {
// Helper functions to access current interpreter state
static frame last_frame(JavaThread *thread) { return thread->last_frame(); }
static methodOop method(JavaThread *thread) { return last_frame(thread).interpreter_frame_method(); }
@@ -4616,18 +6287,21 @@ diff --git a/src/share/vm/interpreter/in
static void set_bcp_and_mdp(address bcp, JavaThread*thread);
static Bytecodes::Code code(JavaThread *thread) {
// pass method to avoid calling unsafe bcp_to_method (partial fix 4926272)
-@@ -70,6 +76,7 @@
+@@ -70,7 +76,10 @@ class InterpreterRuntime: AllStatic {
static void create_klass_exception(JavaThread* thread, char* name, oopDesc* obj);
static address exception_handler_for_exception(JavaThread* thread, oopDesc* exception);
static void throw_pending_exception(JavaThread* thread);
+ static void throw_TailCallException(JavaThread* thread);
++ static void tail_call_handle_stack_overflow(JavaThread * thread);
++
// Statics & fields
static void resolve_get_put(JavaThread* thread, Bytecodes::Code bytecode);
-diff --git a/src/share/vm/interpreter/linkResolver.hpp b/src/share/vm/interpreter/linkResolver.hpp
---- a/src/share/vm/interpreter/linkResolver.hpp
-+++ b/src/share/vm/interpreter/linkResolver.hpp
-@@ -69,7 +69,7 @@
+
+diff -r ce2272390558 src/share/vm/interpreter/linkResolver.hpp
+--- a/src/share/vm/interpreter/linkResolver.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/linkResolver.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -69,7 +69,7 @@ class CallInfo: public LinkInfo {
methodHandle _resolved_method; // static target method
methodHandle _selected_method; // dynamic (actual) target method
int _vtable_index; // vtable index of selected method
@@ -4636,7 +6310,7 @@ diff --git a/src/share/vm/interpreter/li
void set_static( KlassHandle resolved_klass, methodHandle resolved_method , TRAPS);
void set_interface(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method , TRAPS);
void set_virtual( KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS);
-@@ -84,6 +84,8 @@
+@@ -84,6 +84,8 @@ class CallInfo: public LinkInfo {
methodHandle selected_method() const { return _selected_method; }
BasicType result_type() const { return selected_method()->result_type(); }
@@ -4645,10 +6319,108 @@ diff --git a/src/share/vm/interpreter/li
bool has_vtable_index() const { return _vtable_index >= 0; }
bool is_statically_bound() const { return _vtable_index == methodOopDesc::nonvirtual_vtable_index; }
int vtable_index() const {
-diff --git a/src/share/vm/interpreter/rewriter.cpp b/src/share/vm/interpreter/rewriter.cpp
---- a/src/share/vm/interpreter/rewriter.cpp
-+++ b/src/share/vm/interpreter/rewriter.cpp
-@@ -113,7 +113,7 @@
+diff -r ce2272390558 src/share/vm/interpreter/oopMapCache.cpp
+--- a/src/share/vm/interpreter/oopMapCache.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/oopMapCache.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -33,7 +33,7 @@ class OopMapCacheEntry: private Interpre
+
+ protected:
+ // Initialization
+- void fill(methodHandle method, int bci);
++ void fill(methodHandle method, int bci, bool report_parameter_exprs=false);
+ // fills the bit mask for native calls
+ void fill_for_native(methodHandle method);
+ void set_mask(CellTypeState* vars, CellTypeState* stack, int stack_top);
+@@ -77,7 +77,7 @@ class OopMapForCacheEntry: public Genera
+ OopMapForCacheEntry(methodHandle method, int bci, OopMapCacheEntry *entry);
+
+ // Computes stack map for (method,bci) and initialize entry
+- void compute_map(TRAPS);
++ void compute_map(bool report_parameter_exprs, TRAPS);
+ int size();
+ };
+
+@@ -89,14 +89,23 @@ OopMapForCacheEntry::OopMapForCacheEntry
+ }
+
+
+-void OopMapForCacheEntry::compute_map(TRAPS) {
++void OopMapForCacheEntry::compute_map(bool report_parameter_exprs, TRAPS) {
+ assert(!method()->is_native(), "cannot compute oop map for native methods");
+ // First check if it is a method where the stackmap is always empty
+ if (method()->code_size() == 0 || method()->max_locals() + method()->max_stack() == 0) {
+ _entry->set_mask_size(0);
+ } else {
+ ResourceMark rm;
+- GenerateOopMap::compute_map(CATCH);
++ //GenerateOopMap::compute_map(CATCH);
++ GenerateOopMap::compute_map(THREAD, report_parameter_exprs);
++ // Expanded CATCH macro to be able to append report_parameter_exprs
++ // parameter.
++ if (HAS_PENDING_EXCEPTION) {
++ oop ex = PENDING_EXCEPTION;
++ CLEAR_PENDING_EXCEPTION;
++ ex->print();
++ ShouldNotReachHere();
++ }
+ result_for_basicblock(_bci);
+ }
+ }
+@@ -368,7 +377,7 @@ void OopMapCacheEntry::fill_for_native(m
+ }
+
+
+-void OopMapCacheEntry::fill(methodHandle method, int bci) {
++void OopMapCacheEntry::fill(methodHandle method, int bci, bool report_parameter_exprs) {
+ HandleMark hm;
+ // Flush entry to deallocate an existing entry
+ flush();
+@@ -378,10 +387,14 @@ void OopMapCacheEntry::fill(methodHandle
+ // Native method activations have oops only among the parameters and one
+ // extra oop following the parameters (the mirror for static native methods).
+ fill_for_native(method);
++ // TODO: what to do?
++ if (report_parameter_exprs==true) ShouldNotReachHere();
+ } else {
+ EXCEPTION_MARK;
+ OopMapForCacheEntry gen(method, bci, this);
+- gen.compute_map(CATCH);
++ //gen.compute_map(CATCH);
++ gen.compute_map(report_parameter_exprs, CATCH);
++
+ }
+ #ifdef ASSERT
+ verify();
+@@ -633,11 +646,11 @@ void OopMapCache::lookup(methodHandle me
+ return;
+ }
+
+-void OopMapCache::compute_one_oop_map(methodHandle method, int bci, InterpreterOopMap* entry) {
++void OopMapCache::compute_one_oop_map(methodHandle method, int bci, InterpreterOopMap* entry, bool report_parameter_exprs) {
+ // Due to the invariants above it's tricky to allocate a temporary OopMapCacheEntry on the stack
+ OopMapCacheEntry* tmp = NEW_C_HEAP_ARRAY(OopMapCacheEntry, 1);
+ tmp->initialize();
+- tmp->fill(method, bci);
++ tmp->fill(method, bci, report_parameter_exprs);
+ entry->resource_copy(tmp);
+ FREE_C_HEAP_ARRAY(OopMapCacheEntry, tmp);
+ }
+diff -r ce2272390558 src/share/vm/interpreter/oopMapCache.hpp
+--- a/src/share/vm/interpreter/oopMapCache.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/oopMapCache.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -177,7 +177,7 @@ class OopMapCache : public CHeapObj {
+ void lookup(methodHandle method, int bci, InterpreterOopMap* entry);
+
+ // Compute an oop map without updating the cache or grabbing any locks (for debugging)
+- static void compute_one_oop_map(methodHandle method, int bci, InterpreterOopMap* entry);
++ static void compute_one_oop_map(methodHandle method, int bci, InterpreterOopMap* entry, bool report_parameter_exprs=false);
+
+ // Helpers
+ // Iterate over the entries in the cached OopMapCacheEntry's
+diff -r ce2272390558 src/share/vm/interpreter/rewriter.cpp
+--- a/src/share/vm/interpreter/rewriter.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/rewriter.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -113,7 +113,7 @@ methodHandle Rewriter::rewrite_method(me
// moves, the bytecodes will also move.
No_Safepoint_Verifier nsv;
Bytecodes::Code c;
@@ -4657,7 +6429,7 @@ diff --git a/src/share/vm/interpreter/re
// Bytecodes and their length
const address code_base = method->code_base();
const int code_length = method->code_size();
-@@ -122,6 +122,7 @@
+@@ -122,6 +122,7 @@ methodHandle Rewriter::rewrite_method(me
for (int bci = 0; bci < code_length; bci += bc_length) {
address bcp = code_base + bci;
c = (Bytecodes::Code)(*bcp);
@@ -4665,7 +6437,7 @@ diff --git a/src/share/vm/interpreter/re
// Since we have the code, see if we can get the length
// directly. Some more complicated bytecodes will report
-@@ -135,6 +136,7 @@
+@@ -135,6 +136,7 @@ methodHandle Rewriter::rewrite_method(me
// by 'wide'. We don't currently examine any of the bytecodes
// modified by wide, but in case we do in the future...
if (c == Bytecodes::_wide) {
@@ -4673,7 +6445,7 @@ diff --git a/src/share/vm/interpreter/re
c = (Bytecodes::Code)bcp[1];
}
}
-@@ -162,6 +164,8 @@
+@@ -162,6 +164,8 @@ methodHandle Rewriter::rewrite_method(me
case Bytecodes::_invokestatic : // fall through
case Bytecodes::_invokeinterface: {
address p = bcp + 1;
@@ -4682,10 +6454,10 @@ diff --git a/src/share/vm/interpreter/re
Bytes::put_native_u2(p, index_map[Bytes::get_Java_u2(p)]);
break;
}
-diff --git a/src/share/vm/interpreter/templateInterpreter.cpp b/src/share/vm/interpreter/templateInterpreter.cpp
---- a/src/share/vm/interpreter/templateInterpreter.cpp
-+++ b/src/share/vm/interpreter/templateInterpreter.cpp
-@@ -50,6 +50,10 @@
+diff -r ce2272390558 src/share/vm/interpreter/templateInterpreter.cpp
+--- a/src/share/vm/interpreter/templateInterpreter.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/templateInterpreter.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -50,6 +50,10 @@ void TemplateInterpreter::initialize() {
if (PrintInterpreter) print();
}
@@ -4696,7 +6468,16 @@ diff --git a/src/share/vm/interpreter/te
// initialize dispatch table
_active_table = _normal_table;
}
-@@ -181,8 +185,8 @@
+@@ -171,6 +175,8 @@ address TemplateInterpreter::_throw_N
+ address TemplateInterpreter::_throw_NullPointerException_entry = NULL;
+ address TemplateInterpreter::_throw_StackOverflowError_entry = NULL;
+ address TemplateInterpreter::_throw_exception_entry = NULL;
++address TemplateInterpreter::_tail_call_handle_stack_overflow_entry = NULL;
++address TemplateInterpreter::_tail_call_handle_stack_overflow_patch_address = NULL;
+
+ #ifndef PRODUCT
+ EntryPoint TemplateInterpreter::_trace_code;
+@@ -181,8 +187,8 @@ EntryPoint TemplateInterpreter::_continu
EntryPoint TemplateInterpreter::_continuation_entry;
EntryPoint TemplateInterpreter::_safept_entry;
@@ -4707,7 +6488,7 @@ diff --git a/src/share/vm/interpreter/te
DispatchTable TemplateInterpreter::_active_table;
DispatchTable TemplateInterpreter::_normal_table;
-@@ -297,8 +301,11 @@
+@@ -297,8 +303,11 @@ void TemplateInterpreterGenerator::gener
for (int j = 0; j < number_of_states; j++) {
const TosState states[] = {btos, ctos, stos, itos, ltos, ftos, dtos, atos, vtos};
@@ -4721,7 +6502,15 @@ diff --git a/src/share/vm/interpreter/te
}
{ CodeletMark cm(_masm, "continuation entry points");
-@@ -438,11 +445,13 @@
+@@ -343,6 +352,7 @@ void TemplateInterpreterGenerator::gener
+ Interpreter::_throw_ClassCastException_entry = generate_ClassCastException_handler();
+ Interpreter::_throw_NullPointerException_entry = generate_exception_handler("java/lang/NullPointerException" , NULL );
+ Interpreter::_throw_StackOverflowError_entry = generate_StackOverflowError_handler();
++ Interpreter::_tail_call_handle_stack_overflow_entry = generate_tail_call_stack_overflow_handler();
+ }
+
+
+@@ -438,11 +448,13 @@ void TemplateInterpreterGenerator::set_e
Template* t = TemplateTable::template_for(code);
assert(t->is_valid(), "just checking");
set_short_entry_points(t, bep, cep, sep, aep, iep, lep, fep, dep, vep);
@@ -4740,7 +6529,7 @@ diff --git a/src/share/vm/interpreter/te
}
// set entry points
EntryPoint entry(bep, cep, sep, aep, iep, lep, fep, dep, vep);
-@@ -489,7 +498,7 @@
+@@ -489,7 +501,7 @@ void TemplateInterpreterGenerator::gener
#endif // !PRODUCT
int step;
if (!t->does_dispatch()) {
@@ -4749,7 +6538,7 @@ diff --git a/src/share/vm/interpreter/te
if (tos_out == ilgl) tos_out = t->tos_out();
// compute bytecode size
assert(step > 0, "just checkin'");
-@@ -519,6 +528,12 @@
+@@ -519,6 +531,12 @@ void TemplateInterpreterGenerator::gener
address TemplateInterpreter::return_entry(TosState state, int length) {
guarantee(0 <= length && length < Interpreter::number_of_return_entries, "illegal length");
@@ -4762,10 +6551,10 @@ diff --git a/src/share/vm/interpreter/te
return _return_entry[length].entry(state);
}
-diff --git a/src/share/vm/interpreter/templateInterpreter.hpp b/src/share/vm/interpreter/templateInterpreter.hpp
---- a/src/share/vm/interpreter/templateInterpreter.hpp
-+++ b/src/share/vm/interpreter/templateInterpreter.hpp
-@@ -84,7 +84,8 @@
+diff -r ce2272390558 src/share/vm/interpreter/templateInterpreter.hpp
+--- a/src/share/vm/interpreter/templateInterpreter.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/templateInterpreter.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -84,7 +84,8 @@ class TemplateInterpreter: public Abstra
enum MoreConstants {
number_of_return_entries = 9, // number of return entry points
number_of_deopt_entries = 9, // number of deoptimization entry points
@@ -4775,7 +6564,17 @@ diff --git a/src/share/vm/interpreter/te
};
protected:
-@@ -112,8 +113,11 @@
+@@ -97,7 +98,8 @@ class TemplateInterpreter: public Abstra
+ static address _throw_exception_entry;
+
+ static address _throw_StackOverflowError_entry;
+-
++ static address _tail_call_handle_stack_overflow_entry; // Try to compress the stack, throw exception if not possible.
++ static address _tail_call_handle_stack_overflow_patch_address; // Patch with deopt compress_entry_point
+ static address _remove_activation_entry; // continuation address if an exception is not handled by current frame
+ #ifdef HOTSWAP
+ static address _remove_activation_preserving_args_entry; // continuation address when current frame is being popped
+@@ -112,8 +114,11 @@ class TemplateInterpreter: public Abstra
static EntryPoint _continuation_entry;
static EntryPoint _safept_entry;
@@ -4787,7 +6586,18 @@ diff --git a/src/share/vm/interpreter/te
static DispatchTable _active_table; // the active dispatch table (used by the interpreter for dispatch)
static DispatchTable _normal_table; // the normal dispatch table (used to set the active table in normal mode)
-@@ -152,14 +156,15 @@
+@@ -139,7 +144,9 @@ class TemplateInterpreter: public Abstra
+ static address throw_ArithmeticException_entry() { return _throw_ArithmeticException_entry; }
+ static address throw_NullPointerException_entry() { return _throw_NullPointerException_entry; }
+ static address throw_StackOverflowError_entry() { return _throw_StackOverflowError_entry; }
+-
++ static address tail_call_handle_stack_overflow_entry() { return _tail_call_handle_stack_overflow_entry; }
++ static address tail_call_handle_stack_overflow_patch_addr(){ return _tail_call_handle_stack_overflow_patch_address; }
++
+ // Code generation
+ #ifndef PRODUCT
+ static address trace_code (TosState state) { return _trace_code.entry(state); }
+@@ -152,14 +159,15 @@ class TemplateInterpreter: public Abstra
static address* normal_table() { return _normal_table.table_for(); }
// Support for invokes
@@ -4806,10 +6616,21 @@ diff --git a/src/share/vm/interpreter/te
static void notice_safepoints(); // stops the thread when reaching a safepoint
static void ignore_safepoints(); // ignores safepoints
-diff --git a/src/share/vm/interpreter/templateTable.cpp b/src/share/vm/interpreter/templateTable.cpp
---- a/src/share/vm/interpreter/templateTable.cpp
-+++ b/src/share/vm/interpreter/templateTable.cpp
-@@ -37,19 +37,21 @@
+diff -r ce2272390558 src/share/vm/interpreter/templateInterpreterGenerator.hpp
+--- a/src/share/vm/interpreter/templateInterpreterGenerator.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/templateInterpreterGenerator.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -40,6 +40,7 @@ class TemplateInterpreterGenerator: publ
+ address generate_slow_signature_handler();
+ address generate_error_exit(const char* msg);
+ address generate_StackOverflowError_handler();
++ address generate_tail_call_stack_overflow_handler();
+ address generate_exception_handler(const char* name, const char* message) {
+ return generate_exception_handler_common(name, message, false);
+ }
+diff -r ce2272390558 src/share/vm/interpreter/templateTable.cpp
+--- a/src/share/vm/interpreter/templateTable.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/templateTable.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -37,19 +37,21 @@ void templateTable_init() {
// Implementation of Template
@@ -4843,7 +6664,7 @@ diff --git a/src/share/vm/interpreter/te
}
-@@ -180,24 +182,30 @@
+@@ -180,24 +182,30 @@ void TemplateTable::def(Bytecodes::Code
def(code, flags, in, out, (Template::generator)gen, 0);
}
@@ -4878,7 +6699,7 @@ diff --git a/src/share/vm/interpreter/te
}
-@@ -253,9 +261,11 @@
+@@ -253,9 +261,11 @@ void TemplateTable::initialize() {
const int ubcp = 1 << Template::uses_bcp_bit;
const int disp = 1 << Template::does_dispatch_bit;
const int clvm = 1 << Template::calls_vm_bit;
@@ -4892,7 +6713,7 @@ diff --git a/src/share/vm/interpreter/te
def(Bytecodes::_nop , ____|____|____|____, vtos, vtos, nop , _ );
def(Bytecodes::_aconst_null , ____|____|____|____, vtos, atos, aconst_null , _ );
def(Bytecodes::_iconst_m1 , ____|____|____|____, vtos, itos, iconst , -1 );
-@@ -473,6 +483,13 @@
+@@ -473,6 +483,13 @@ void TemplateTable::initialize() {
def(Bytecodes::_ret , ubcp|disp|____|iswd, vtos, vtos, wide_ret , _ );
def(Bytecodes::_breakpoint , ubcp|disp|clvm|____, vtos, vtos, _breakpoint , _ );
@@ -4906,7 +6727,7 @@ diff --git a/src/share/vm/interpreter/te
// JVM bytecodes
def(Bytecodes::_fast_agetfield , ubcp|____|____|____, atos, atos, fast_accessfield , atos );
def(Bytecodes::_fast_bgetfield , ubcp|____|____|____, atos, itos, fast_accessfield , itos );
-@@ -536,6 +553,12 @@
+@@ -536,6 +553,12 @@ void templateTable_init() {
void TemplateTable::unimplemented_bc() {
@@ -4920,10 +6741,10 @@ diff --git a/src/share/vm/interpreter/te
+ _masm->unimplemented(buf);
}
#endif /* !CC_INTERP */
-diff --git a/src/share/vm/interpreter/templateTable.hpp b/src/share/vm/interpreter/templateTable.hpp
---- a/src/share/vm/interpreter/templateTable.hpp
-+++ b/src/share/vm/interpreter/templateTable.hpp
-@@ -47,14 +47,19 @@
+diff -r ce2272390558 src/share/vm/interpreter/templateTable.hpp
+--- a/src/share/vm/interpreter/templateTable.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/interpreter/templateTable.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -47,14 +47,19 @@ class Template VALUE_OBJ_CLASS_SPEC {
TosState _tos_in; // tos cache state before template execution
TosState _tos_out; // tos cache state after template execution
generator _gen; // template code generator
@@ -4947,7 +6768,7 @@ diff --git a/src/share/vm/interpreter/te
bool is_valid() const { return _gen != NULL; }
bool uses_bcp() const { return (_flags & (1 << uses_bcp_bit )) != 0; }
bool does_dispatch() const { return (_flags & (1 << does_dispatch_bit)) != 0; }
-@@ -244,8 +249,9 @@
+@@ -244,8 +249,9 @@ class TemplateTable: AllStatic {
static void _return(TosState state);
@@ -4958,7 +6779,7 @@ diff --git a/src/share/vm/interpreter/te
Register method,
Register itable_index,
Register flags,
-@@ -262,6 +268,15 @@
+@@ -262,6 +268,15 @@ class TemplateTable: AllStatic {
static void invokestatic(int byte_no);
static void invokeinterface(int byte_no);
static void fast_invokevfinal(int byte_no);
@@ -4974,16 +6795,17 @@ diff --git a/src/share/vm/interpreter/te
static void getfield_or_static(int byte_no, bool is_static);
static void putfield_or_static(int byte_no, bool is_static);
-@@ -322,7 +337,15 @@
+@@ -322,7 +337,16 @@ class TemplateTable: AllStatic {
// Templates
static Template* template_for (Bytecodes::Code code) { Bytecodes::check (code); return &_template_table [code]; }
- static Template* template_for_wide(Bytecodes::Code code) { Bytecodes::wide_check(code); return &_template_table_wide[code]; }
+ //static Template* template_for_wide(Bytecodes::Code code) {
+ //Bytecodes::wide_check(code); return &_template_table_wide[code]; }
-+ static Template* template_for_prefix(Bytecodes::Prefix pfx, Bytecodes::Code code) {
++ static Template* template_for_prefix(Bytecodes::Prefix pfx, Bytecodes::Code code) {
+ Bytecodes::prefix_check(pfx, code);
-+ assert((pfx & Bytecodes::Prefix_wide_index) || (pfx & Bytecodes::Prefix_tail_call),
++ assert(( 1 &&
++ ((pfx & Bytecodes::Prefix_wide_index) || (pfx & Bytecodes::Prefix_tail_call) )),
+ "Only support wide now");
+
+ return &_template_table_wide[code];
@@ -4991,10 +6813,23 @@ diff --git a/src/share/vm/interpreter/te
// Platform specifics
#include "incls/_templateTable_pd.hpp.incl"
-diff --git a/src/share/vm/oops/generateOopMap.cpp b/src/share/vm/oops/generateOopMap.cpp
---- a/src/share/vm/oops/generateOopMap.cpp
-+++ b/src/share/vm/oops/generateOopMap.cpp
-@@ -549,7 +549,7 @@
+diff -r ce2272390558 src/share/vm/memory/space.cpp
+--- a/src/share/vm/memory/space.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/memory/space.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -790,6 +790,9 @@ size_t ContiguousSpace::block_size(const
+ assert(MemRegion(bottom(), end()).contains(p), "p not in space");
+ HeapWord* current_top = top();
+ assert(p <= current_top, "p is not a block start");
++ if (oop(p)->is_oop()==false) {
++ tty->print_cr("oop( " INTPTR_FORMAT "/" INTPTR_FORMAT " ) is no oop.", p, oop(p));
++ }
+ assert(p == current_top || oop(p)->is_oop(), "p is not a block start");
+ if (p < current_top)
+ return oop(p)->size();
+diff -r ce2272390558 src/share/vm/oops/generateOopMap.cpp
+--- a/src/share/vm/oops/generateOopMap.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/oops/generateOopMap.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -549,7 +549,7 @@ bool GenerateOopMap::jump_targets_do(Byt
break;
}
case Bytecodes::_jsr:
@@ -5003,7 +6838,7 @@ diff --git a/src/share/vm/oops/generateO
(*jmpFct)(this, bcs->dest(), data);
-@@ -1319,7 +1319,14 @@
+@@ -1319,7 +1319,14 @@ void GenerateOopMap::interp1(BytecodeStr
break;
}
}
@@ -5019,7 +6854,44 @@ diff --git a/src/share/vm/oops/generateO
// abstract interpretation of current opcode
switch(itr->code()) {
case Bytecodes::_nop: break;
-@@ -2043,6 +2050,7 @@
+@@ -1921,6 +1928,13 @@ void GenerateOopMap::do_method(int is_st
+ int arg_length = cse.compute_for_parameters(is_static != 0, in);
+ assert(arg_length<=MAXARGSIZE, "too many locals");
+
++ // Report results include parameter expressions (Used in Deoptimization stack
++ // compression).
++ if (_report_parameter_exprs == true && _report_result_for_send == true) {
++ fill_stackmap_for_opcodes(_itr_send, vars(), stack(), _stack_top);
++ _report_result_for_send = false;
++ }
++
+ // Pop arguments
+ for (int i = arg_length - 1; i >= 0; i--) ppop1(in[i]);// Do args in reverse order.
+
+@@ -2007,7 +2021,7 @@ GenerateOopMap::GenerateOopMap(methodHan
+ _method = method;
+ _max_locals=0;
+ _init_vars = NULL;
+-
++ _report_parameter_exprs = false;
+ #ifndef PRODUCT
+ // If we are doing a detailed trace, include the regular trace information.
+ if (TraceNewOopMapGenerationDetailed) {
+@@ -2016,7 +2030,7 @@ GenerateOopMap::GenerateOopMap(methodHan
+ #endif
+ }
+
+-void GenerateOopMap::compute_map(TRAPS) {
++void GenerateOopMap::compute_map(TRAPS, bool report_parameter_exprs) {
+ #ifndef PRODUCT
+ if (TimeOopMap2) {
+ method()->print_short_name(tty);
+@@ -2039,10 +2053,12 @@ void GenerateOopMap::compute_map(TRAPS)
+ _init_vars = new GrowableArray<intptr_t>(5); // There are seldom more than 5 init_vars
+ _report_result = false;
+ _report_result_for_send = false;
++ _report_parameter_exprs = report_parameter_exprs;
+ _new_var_map = NULL;
_ret_adr_tos = new GrowableArray<intptr_t>(5); // 5 seems like a good number;
_did_rewriting = false;
_did_relocation = false;
@@ -5027,18 +6899,30 @@ diff --git a/src/share/vm/oops/generateO
if (TraceNewOopMapGeneration) {
tty->print("Method name: %s\n", method()->name()->as_C_string());
-diff --git a/src/share/vm/oops/generateOopMap.hpp b/src/share/vm/oops/generateOopMap.hpp
---- a/src/share/vm/oops/generateOopMap.hpp
-+++ b/src/share/vm/oops/generateOopMap.hpp
-@@ -298,6 +298,7 @@
+diff -r ce2272390558 src/share/vm/oops/generateOopMap.hpp
+--- a/src/share/vm/oops/generateOopMap.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/oops/generateOopMap.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -298,7 +298,9 @@ class GenerateOopMap VALUE_OBJ_CLASS_SPE
bool _did_relocation; // was relocation neccessary
bool _monitor_safe; // The monitors in this method have been determined
// to be safe.
+-
+ bool _contains_tail_call; // This method contains a tail call.
-
++ bool _report_parameter_exprs; // Report parameter expressions.
++ //(Stack compression deoptimzation.)
// Working Cell type state
int _state_len; // Size of states
-@@ -469,6 +470,8 @@
+ CellTypeState *_state; // list of states
+@@ -456,7 +458,7 @@ class GenerateOopMap VALUE_OBJ_CLASS_SPE
+ GenerateOopMap(methodHandle method);
+
+ // Compute the map.
+- void compute_map(TRAPS);
++ void compute_map(TRAPS, bool report_parameter_exprs=false);
+ void result_for_basicblock(int bci); // Do a callback on fill_stackmap_for_opcodes for basicblock containing bci
+
+ // Query
+@@ -469,6 +471,8 @@ class GenerateOopMap VALUE_OBJ_CLASS_SPE
static void print_time();
@@ -5047,7 +6931,7 @@ diff --git a/src/share/vm/oops/generateO
// Monitor query
bool monitor_safe() { return _monitor_safe; }
-@@ -557,3 +560,26 @@
+@@ -557,3 +561,26 @@ class GeneratePairingInfo: public Genera
// Call compute_map(CHECK) to generate info.
};
@@ -5074,10 +6958,10 @@ diff --git a/src/share/vm/oops/generateO
+
+ // Call compute_map(CHECK) to generate info.
+};
-diff --git a/src/share/vm/oops/instanceKlass.hpp b/src/share/vm/oops/instanceKlass.hpp
---- a/src/share/vm/oops/instanceKlass.hpp
-+++ b/src/share/vm/oops/instanceKlass.hpp
-@@ -578,6 +578,7 @@
+diff -r ce2272390558 src/share/vm/oops/instanceKlass.hpp
+--- a/src/share/vm/oops/instanceKlass.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/oops/instanceKlass.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -578,6 +578,7 @@ class instanceKlass: public Klass {
int object_size() const { return object_size(align_object_offset(vtable_length()) + align_object_offset(itable_length()) + static_field_size() + nonstatic_oop_map_size()); }
static int vtable_start_offset() { return header_size(); }
static int vtable_length_offset() { return oopDesc::header_size() + offset_of(instanceKlass, _vtable_len) / HeapWordSize; }
@@ -5085,10 +6969,10 @@ diff --git a/src/share/vm/oops/instanceK
static int object_size(int extra) { return align_object_size(header_size() + extra); }
intptr_t* start_of_vtable() const { return ((intptr_t*)as_klassOop()) + vtable_start_offset(); }
-diff --git a/src/share/vm/oops/methodKlass.cpp b/src/share/vm/oops/methodKlass.cpp
---- a/src/share/vm/oops/methodKlass.cpp
-+++ b/src/share/vm/oops/methodKlass.cpp
-@@ -72,6 +72,7 @@
+diff -r ce2272390558 src/share/vm/oops/methodKlass.cpp
+--- a/src/share/vm/oops/methodKlass.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/oops/methodKlass.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -72,6 +72,7 @@ methodOop methodKlass::allocate(constMet
m->set_method_data(NULL);
m->set_interpreter_throwout_count(0);
m->set_vtable_index(methodOopDesc::garbage_vtable_index);
@@ -5096,16 +6980,18 @@ diff --git a/src/share/vm/oops/methodKla
// Fix and bury in methodOop
m->set_interpreter_entry(NULL); // sets i2i entry and from_int
-diff --git a/src/share/vm/oops/methodOop.cpp b/src/share/vm/oops/methodOop.cpp
---- a/src/share/vm/oops/methodOop.cpp
-+++ b/src/share/vm/oops/methodOop.cpp
-@@ -43,6 +43,26 @@
+diff -r ce2272390558 src/share/vm/oops/methodOop.cpp
+--- a/src/share/vm/oops/methodOop.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/oops/methodOop.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -41,6 +41,26 @@ address methodOopDesc::get_c2i_unverifie
+ address methodOopDesc::get_c2i_unverified_entry() {
+ assert(_adapter != NULL, "must have");
return _adapter->get_c2i_unverified_entry();
- }
-
-+address methodOopDesc::get_c2i_static_tail_call_entry() {
++}
++
++address methodOopDesc::get_c2i_verified_tail_call_entry() {
+ assert(_adapter != NULL, "must have");
-+ return _adapter->get_c2i_static_tail_call_entry();
++ return _adapter->get_c2i_verified_tail_call_entry();
+}
+
+address methodOopDesc::get_c2i_unverified_tail_call_entry() {
@@ -5113,38 +6999,58 @@ diff --git a/src/share/vm/oops/methodOop
+ return _adapter->get_c2i_unverified_tail_call_entry();
+}
+
-+address methodOopDesc::get_c2i_static_not_sibling_tail_call_entry() {
++address methodOopDesc::get_c2i_verified_not_sibling_tail_call_entry() {
+ assert(_adapter != NULL, "must have");
-+ return _adapter->get_c2i_static_not_sibling_tail_call_entry();
++ return _adapter->get_c2i_verified_not_sibling_tail_call_entry();
+}
+
+address methodOopDesc::get_c2i_unverified_not_sibling_tail_call_entry() {
+ assert(_adapter != NULL, "must have");
+ return _adapter->get_c2i_unverified_not_sibling_tail_call_entry();
-+}
-+
+ }
+
char* methodOopDesc::name_and_sig_as_C_string() {
- return name_and_sig_as_C_string(Klass::cast(constants()->pool_holder()), name(), signature());
- }
-@@ -610,6 +630,8 @@
+@@ -143,7 +163,8 @@ void methodOopDesc::mask_for(int bci, In
+ bool has_capability = myThread->is_VM_thread() ||
+ myThread->is_ConcurrentGC_thread() ||
+ myThread->is_GC_task_thread();
+-
++// TODO: arnold turn back on.
++#if 0
+ if (!has_capability) {
+ if (!VerifyStack && !VerifyLastFrame) {
+ // verify stack calls this outside VM thread
+@@ -154,6 +175,7 @@ void methodOopDesc::mask_for(int bci, In
+ local_mask.print();
+ }
+ }
++#endif
+ #endif
+ instanceKlass::cast(method_holder())->mask_for(h_this, bci, mask);
+ return;
+@@ -608,8 +630,12 @@ void methodOopDesc::clear_code() {
+ // Only should happen at allocate time.
+ if (_adapter == NULL) {
_from_compiled_entry = NULL;
++ _from_compiled_tail_call_entry = NULL;
++ _from_compiled_not_sibling_tail_call_entry = NULL;
} else {
_from_compiled_entry = _adapter->get_c2i_entry();
-+ _from_compiled_static_tail_call_entry = _adapter->get_c2i_static_tail_call_entry();
-+ _from_compiled_not_sibling_static_tail_call_entry = _adapter->get_c2i_static_not_sibling_tail_call_entry();
++ _from_compiled_tail_call_entry = _adapter->get_c2i_verified_tail_call_entry();
++ _from_compiled_not_sibling_tail_call_entry = _adapter->get_c2i_verified_not_sibling_tail_call_entry();
}
OrderAccess::storestore();
_from_interpreted_entry = _i2i_entry;
-@@ -631,6 +653,8 @@
+@@ -631,6 +657,8 @@ void methodOopDesc::unlink_method() {
backedge_counter()->reset();
_adapter = NULL;
_from_compiled_entry = NULL;
-+ _from_compiled_static_tail_call_entry = NULL;
-+ _from_compiled_not_sibling_static_tail_call_entry = NULL;
++ _from_compiled_tail_call_entry = NULL;
++ _from_compiled_not_sibling_tail_call_entry = NULL;
assert(_method_data == NULL, "unexpected method data?");
set_method_data(NULL);
set_interpreter_throwout_count(0);
-@@ -671,7 +695,7 @@
+@@ -671,7 +699,7 @@ void methodOopDesc::link_method(methodHa
}
@@ -5153,51 +7059,51 @@ diff --git a/src/share/vm/oops/methodOop
// Adapters for compiled code are made eagerly here. They are fairly
// small (generally < 100 bytes) and quick to make (and cached and shared)
// so making them eagerly shouldn't be too expensive.
-@@ -682,6 +706,10 @@
+@@ -682,6 +710,10 @@ address methodOopDesc::make_adapters(met
mh->set_adapter_entry(adapter);
mh->_from_compiled_entry = adapter->get_c2i_entry();
-+ mh->_from_compiled_static_tail_call_entry = adapter->get_c2i_static_tail_call_entry();
-+ mh->_from_compiled_not_sibling_static_tail_call_entry =
-+ adapter->get_c2i_static_not_sibling_tail_call_entry();
++ mh->_from_compiled_tail_call_entry = adapter->get_c2i_verified_tail_call_entry();
++ mh->_from_compiled_not_sibling_tail_call_entry =
++ adapter->get_c2i_verified_not_sibling_tail_call_entry();
+
return adapter->get_c2i_entry();
}
-@@ -698,6 +726,19 @@
+@@ -696,6 +728,19 @@ address methodOopDesc::verified_code_ent
+ debug_only(No_Safepoint_Verifier nsv;)
+ assert(_from_compiled_entry != NULL, "must be set");
return _from_compiled_entry;
++}
++
++
++address methodOopDesc::verified_tail_call_code_entry() {
++ debug_only(No_Safepoint_Verifier nsv;)
++ assert(_from_compiled_tail_call_entry != NULL, "must be set");
++ return _from_compiled_tail_call_entry;
++}
++
++address methodOopDesc::verified_not_sibling_tail_call_code_entry() {
++ debug_only(No_Safepoint_Verifier nsv;)
++ assert(_from_compiled_not_sibling_tail_call_entry != NULL, "must be set");
++ return _from_compiled_not_sibling_tail_call_entry;
}
-+
-+address methodOopDesc::verified_static_tail_call_code_entry() {
-+ debug_only(No_Safepoint_Verifier nsv;)
-+ assert(_from_compiled_static_tail_call_entry != NULL, "must be set");
-+ return _from_compiled_static_tail_call_entry;
-+}
-+
-+address methodOopDesc::verified_not_sibling_static_tail_call_code_entry() {
-+ debug_only(No_Safepoint_Verifier nsv;)
-+ assert(_from_compiled_not_sibling_static_tail_call_entry != NULL, "must be set");
-+ return _from_compiled_not_sibling_static_tail_call_entry;
-+}
-+
// Check that if an nmethod ref exists, it has a backlink to this or no backlink at all
- // (could be racing a deopt).
- // Not inline to avoid circular ref.
-@@ -725,13 +766,19 @@
+@@ -725,13 +770,19 @@ void methodOopDesc::set_code(methodHandl
if (comp_level > highest_tier_compile()) {
set_highest_tier_compile(comp_level);
}
+ // Set methodoop and c2i entry point in tail call stubs.
-+ if ( code->is_java_method() && code->is_compiled_by_c1())
++ if ( code->is_java_method())
+ code->set_adapter_info_in_tail_call_stubs(mh(), mh->adapter());
OrderAccess::storestore();
mh->_from_compiled_entry = code->verified_entry_point();
OrderAccess::storestore();
-+ mh->_from_compiled_static_tail_call_entry = code->static_tail_call_entry_point();
++ mh->_from_compiled_tail_call_entry = code->verified_tail_call_entry_point();
+ OrderAccess::storestore();
-+ mh->_from_compiled_not_sibling_static_tail_call_entry = code->static_not_sibling_tail_call_entry_point();
++ mh->_from_compiled_not_sibling_tail_call_entry = code->verified_not_sibling_tail_call_entry_point();
// Instantly compiled code can execute.
mh->_from_interpreted_entry = mh->get_i2c_entry();
-
@@ -5205,56 +7111,56 @@ diff --git a/src/share/vm/oops/methodOop
}
-diff --git a/src/share/vm/oops/methodOop.hpp b/src/share/vm/oops/methodOop.hpp
---- a/src/share/vm/oops/methodOop.hpp
-+++ b/src/share/vm/oops/methodOop.hpp
-@@ -128,6 +128,12 @@
+diff -r ce2272390558 src/share/vm/oops/methodOop.hpp
+--- a/src/share/vm/oops/methodOop.hpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/oops/methodOop.hpp Mon Mar 16 11:44:02 2009 +0100
+@@ -128,6 +128,12 @@ class methodOopDesc : public oopDesc {
nmethod* volatile _code; // Points to the corresponding piece of native code
volatile address _from_interpreted_entry; // Cache of _code ? _adapter->i2c_entry() : _i2i_entry
-+ // Entry point for static tail calling from compiled code.
-+ volatile address _from_compiled_static_tail_call_entry;
-+ volatile address _from_compiled_not_sibling_static_tail_call_entry;
++ // Entry point for tail calling from compiled code.
++ volatile address _from_compiled_tail_call_entry;
++ volatile address _from_compiled_not_sibling_tail_call_entry;
+ // Probably should go in access flags but i am unsure whether there is a bit
+ // left.
+ bool _contains_tail_call;
public:
static const bool IsUnsafeConc = false;
-@@ -140,7 +146,10 @@
+@@ -140,7 +146,10 @@ class methodOopDesc : public oopDesc {
static address make_adapters(methodHandle mh, TRAPS);
volatile address from_compiled_entry() const { return (address)OrderAccess::load_ptr_acquire(&_from_compiled_entry); }
-+ volatile address from_compiled_static_tail_call_entry() const { return (address)OrderAccess::load_ptr_acquire(&_from_compiled_static_tail_call_entry); }
-+ volatile address from_compiled_not_sibling_static_tail_call_entry() const { return (address)OrderAccess::load_ptr_acquire(&_from_compiled_not_sibling_static_tail_call_entry); }
++ volatile address from_compiled_tail_call_entry() const { return (address)OrderAccess::load_ptr_acquire(&_from_compiled_tail_call_entry); }
++ volatile address from_compiled_not_sibling_tail_call_entry() const { return (address)OrderAccess::load_ptr_acquire(&_from_compiled_not_sibling_tail_call_entry); }
volatile address from_interpreted_entry() const{ return (address)OrderAccess::load_ptr_acquire(&_from_interpreted_entry); }
+
// access flag
AccessFlags access_flags() const { return _access_flags; }
-@@ -302,6 +311,9 @@
+@@ -302,6 +311,9 @@ class methodOopDesc : public oopDesc {
// nmethod/verified compiler entry
address verified_code_entry();
-+ address verified_static_tail_call_code_entry();
-+ address verified_not_sibling_static_tail_call_code_entry();
++ address verified_tail_call_code_entry();
++ address verified_not_sibling_tail_call_code_entry();
+
bool check_code() const; // Not inline to avoid circular ref
nmethod* volatile code() const { assert( check_code(), "" ); return (nmethod *)OrderAccess::load_ptr_acquire(&_code); }
void clear_code(); // Clear out any compiled code
-@@ -310,6 +322,11 @@
+@@ -310,6 +322,11 @@ class methodOopDesc : public oopDesc {
address get_i2c_entry();
address get_c2i_entry();
address get_c2i_unverified_entry();
-+ address get_c2i_static_tail_call_entry();
++ address get_c2i_verified_tail_call_entry();
+ address get_c2i_unverified_tail_call_entry();
-+ address get_c2i_static_not_sibling_tail_call_entry();
++ address get_c2i_verified_not_sibling_tail_call_entry();
+ address get_c2i_unverified_not_sibling_tail_call_entry();
+
AdapterHandlerEntry* adapter() { return _adapter; }
// setup entry points
void link_method(methodHandle method, TRAPS);
-@@ -458,6 +475,11 @@
+@@ -458,6 +475,11 @@ class methodOopDesc : public oopDesc {
bool guaranteed_monitor_matching() const { return access_flags().is_monitor_matching(); }
void set_guaranteed_monitor_matching() { _access_flags.set_monitor_matching(); }
@@ -5266,20 +7172,576 @@ diff --git a/src/share/vm/oops/methodOop
// returns true if the method is an accessor function (setter/getter).
bool is_accessor() const;
-@@ -486,6 +508,9 @@
+@@ -486,6 +508,9 @@ class methodOopDesc : public oopDesc {
static ByteSize size_of_locals_offset() { return byte_offset_of(methodOopDesc, _max_locals ); }
static ByteSize size_of_parameters_offset() { return byte_offset_of(methodOopDesc, _size_of_parameters); }
static ByteSize from_compiled_offset() { return byte_offset_of(methodOopDesc, _from_compiled_entry); }
-+ static ByteSize from_compiled_static_tail_call_offset() { return byte_offset_of(methodOopDesc, _from_compiled_static_tail_call_entry); }
-+ static ByteSize from_compiled_not_sibling_static_tail_call_offset() { return byte_offset_of(methodOopDesc, _from_compiled_not_sibling_static_tail_call_entry); }
++ static ByteSize from_compiled_tail_call_offset() { return byte_offset_of(methodOopDesc, _from_compiled_tail_call_entry); }
++ static ByteSize from_compiled_not_sibling_tail_call_offset() { return byte_offset_of(methodOopDesc, _from_compiled_not_sibling_tail_call_entry); }
+
static ByteSize code_offset() { return byte_offset_of(methodOopDesc, _code); }
static ByteSize invocation_counter_offset() { return byte_offset_of(methodOopDesc, _invocation_counter); }
static ByteSize backedge_counter_offset() { return byte_offset_of(methodOopDesc, _backedge_counter); }
-diff --git a/src/share/vm/prims/jvmtiClassFileReconstituter.cpp b/src/share/vm/prims/jvmtiClassFileReconstituter.cpp
---- a/src/share/vm/prims/jvmtiClassFileReconstituter.cpp
-+++ b/src/share/vm/prims/jvmtiClassFileReconstituter.cpp
-@@ -642,7 +642,7 @@
+diff -r ce2272390558 src/share/vm/opto/callGenerator.cpp
+--- a/src/share/vm/opto/callGenerator.cpp Mon Mar 09 13:34:00 2009 -0700
++++ b/src/share/vm/opto/callGenerator.cpp Mon Mar 16 11:44:02 2009 +0100
+@@ -25,8 +25,10 @@
+ #include "incls/_precompiled.incl"
+ #include "incls/_callGenerator.cpp.incl"
+
+-CallGenerator::CallGenerator(ciMethod* method) {
++CallGenerator::CallGenerator(ciMethod* method, bool is_tail_call, bool is_sibling) {
+ _method = method;
++ _is_tail_call = is_tail_call;
++ _is_sibling = is_sibling;
+ }
+
+ // Utility function.
+@@ -42,16 +44,16 @@ private:
+ float _expected_uses;
+
+ public:
+- ParseGenerator(ciMethod* method, float expected_uses, bool is_osr = false)
++ ParseGenerator(ciMethod* method, float expected_uses, bool is_osr = false, bool is_tail_call = false)
+ : InlineCallGenerator(method)
+ {
+ _is_osr = is_osr;
+ _expected_uses = expected_uses;
+- assert(can_parse(method, is_osr), "parse must be possible");
++ assert(can_parse(method, true, is_osr, is_tail_call), "parse must be possible");
+ }
+
+ // Can we build either an OSR or a regular parser for this method?
+- static bool can_parse(ciMethod* method, int is_osr = false);
++ static bool can_parse(ciMethod* method, bool is_root, int is_osr = false, bool is_tail_call = false);
+
+ virtual bool is_parse() const { return true; }
+ virtual JVMState* generate(JVMState* jvms);
+@@ -99,8 +101,8 @@ JVMState* ParseGenerator::generate(JVMSt
+ // Internal class which handles all out-of-line calls w/o receiver type checks.
+ class DirectCallGenerator : public CallGenerator {
+ public:
+- DirectCallGenerator(ciMethod* method)
+- : CallGenerator(method)
++ DirectCallGenerator(ciMethod* method, bool is_tail_call, bool is_sibling)
++ : CallGenerator(method, is_tail_call, is_sibling)
+ {
+ }
+ virtual JVMState* generate(JVMState* jvms);
+@@ -109,14 +111,28 @@ JVMState* DirectCallGenerator::generate(
+ JVMState* DirectCallGenerator::generate(JVMState* jvms) {
+ GraphKit kit(jvms);
+ bool is_static = method()->is_static();
+- address target = is_static ? SharedRuntime::get_resolve_static_call_stub()
+- : SharedRuntime::get_resolve_opt_virtual_call_stub();
++ // MachCallStaticJavaNode
++ address target = NULL;
++
++ if (! is_tail_call()) {
++ // Normal call
++ target = is_static ? SharedRuntime::get_resolve_static_call_stub()
++ : SharedRuntime::get_resolve_opt_virtual_call_stub();
++ } else if (is_tail_call() && is_sibling()) {
++ // Tail call (sibling)
++ target = is_static ? SharedRuntime::get_resolve_static_tail_call_stub()
++ : SharedRuntime::get_resolve_opt_virtual_tail_call_stub();
++ } else if (is_tail_call()) {
++ // Tail call (not sibling)
++ target = is_static ? SharedRuntime::get_resolve_not_sibling_static_tail_call_stub()
++ : SharedRuntime::get_resolve_opt_not_sibling_virtual_tail_call_stub();
++ }
+
+ if (kit.C->log() != NULL) {
+ kit.C->log()->elem("direct_call bci='%d'", jvms->bci());
+ }
+
+- CallStaticJavaNode *call = new (kit.C, tf()->domain()->cnt()) CallStaticJavaNode(tf(), target, method(), kit.bci());
++ CallStaticJavaNode *call = new (kit.C, tf()->domain()->cnt()) CallStaticJavaNode(tf(), target, method(), kit.bci(), is_tail_call(), is_sibling());
+ if (!is_static) {
+ // Make an explicit receiver null_check as part of this call.
+ // Since we share a map with the caller, his JVMS gets adjusted.
+@@ -139,8 +155,8 @@ private:
+ private:
+ int _vtable_index;
+ public:
+- VirtualCallGenerator(ciMethod* method, int vtable_index)
+- : CallGenerator(method), _vtable_index(vtable_index)
++ VirtualCallGenerator(ciMethod* method, int vtable_index, bool is_tail_call, bool is_sibling)
++ : CallGenerator(method, is_tail_call, is_sibling), _vtable_index(vtable_index)
+ {
+ assert(vtable_index == methodOopDesc::invalid_vtable_index ||
+ vtable_index >= 0, "either invalid or usable");
+@@ -196,9 +212,23 @@ JVMState* VirtualCallGenerator::generate
+ assert(!method()->is_private(), "virtual call should not be to private");
+ assert(_vtable_index == methodOopDesc::invalid_vtable_index || !UseInlineCaches,
+ "no vtable calls if +UseInlineCaches ");
+- address target = SharedRuntime::get_resolve_virtual_call_stub();
++
++ address target = NULL;
++ if (! is_tail_call()) {
++ // Normal virtual call.
++ target = SharedRuntime::get_resolve_virtual_call_stub();
++ } else if (is_tail_call() && is_sibling()) {
++ // Tail call (sibling)
++ target = SharedRuntime::get_resolve_virtual_tail_call_stub();
++ } else if (is_tail_call()) {
++ // Tail call (not sibling)
++ target = SharedRuntime::get_resolve_not_sibling_virtual_tail_call_stub();
++ }
++#ifdef ASSERT
++ assert(target != NULL, "oops");
++#endif
+ // Normal inline cache used for call
+- CallDynamicJavaNode *call = new (kit.C, tf()->domain()->cnt()) CallDynamicJavaNode(tf(), target, method(), _vtable_index, kit.bci());
++ CallDynamicJavaNode *call = new (kit.C, tf()->domain()->cnt()) CallDynamicJavaNode(tf(), target, method(), _vtable_index, kit.bci(), is_tail_call(), is_sibling());
+ kit.set_arguments_for_java_call(call);
+ kit.set_edges_for_java_call(call);
+ Node* ret = kit.set_results_for_java_call(call);
+@@ -211,10 +241,15 @@ JVMState* VirtualCallGenerator::generate
+ return kit.transfer_exceptions_into_jvms();
+ }
+
+-bool ParseGenerator::can_parse(ciMethod* m, int entry_bci) {
++bool ParseGenerator::can_parse(ciMethod* m, bool is_root, int entry_bci, bool is_tail_call) {
+ // Certain methods cannot be parsed at all:
+ if (!m->can_be_compiled()) return false;
+ if (!m->has_balanced_monitors()) return false;
++ // Can not inline calls to methods that contain tail calls except if the call
++ // itself is a tail call.
++ if (!is_tail_call &&
++ is_root == false &&
++ m->contains_tail_call()) return false;
+ if (m->get_flow_analysis()->failing()) return false;
+
+ // (Methods may bail out for other reasons, after the parser is run.
+@@ -223,9 +258,9 @@ bool ParseGenerator::can_parse(ciMethod*
+ return true;
+ }
+
+-CallGenerator* CallGenerator::for_inline(ciMethod* m, float expected_uses) {
+- if (!ParseGenerator::can_parse(m)) return NULL;
+- return new ParseGenerator(m, expected_uses);
++CallGenerator* CallGenerator::for_inline(ciMethod* m, float expected_uses, bool is_root, bool is_tail_call) {
++ if (!ParseGenerator::can_parse(m, is_root, is_root, is_tail_call)) return NULL;
++ return new ParseGenerator(m, expected_uses, false, is_tail_call);
+ }
+
+ // As a special case, the JVMS passed to this CallGenerator is
+@@ -238,14 +273,14 @@ CallGenerator* CallGenerator::for_osr(ci
+ return new ParseGenerator(m, expected_uses, true);
+ }
+
+-CallGenerator* CallGenerator::