Mercurial > hg > graal-compiler
changeset 5908:ce292d6c0385
Merge
author | never |
---|---|
date | Fri, 02 Mar 2012 09:13:13 -0800 |
parents | 031df0387c09 (diff) 205573af962c (current diff) |
children | 03cb7c836ef3 e5f73be4c7f1 |
files | |
diffstat | 24 files changed, 448 insertions(+), 104 deletions(-) [+] |
line wrap: on
line diff
--- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -47,6 +47,12 @@ assert(!(oop_result1->is_valid() || oop_result2->is_valid()) || oop_result1 != oop_result2, "registers must be different"); assert(oop_result1 != thread && oop_result2 != thread, "registers must be different"); assert(args_size >= 0, "illegal args_size"); + bool align_stack = false; +#ifdef _LP64 + // At a method handle call, the stack may not be properly aligned + // when returning with an exception. + align_stack = (stub_id() == Runtime1::handle_exception_from_callee_id); +#endif #ifdef _LP64 mov(c_rarg0, thread); @@ -59,11 +65,21 @@ push(thread); #endif // _LP64 - set_last_Java_frame(thread, noreg, rbp, NULL); + int call_offset; + if (!align_stack) { + set_last_Java_frame(thread, noreg, rbp, NULL); + } else { + address the_pc = pc(); + call_offset = offset(); + set_last_Java_frame(thread, noreg, rbp, the_pc); + andptr(rsp, -(StackAlignmentInBytes)); // Align stack + } // do the call call(RuntimeAddress(entry)); - int call_offset = offset(); + if (!align_stack) { + call_offset = offset(); + } // verify callee-saved register #ifdef ASSERT guarantee(thread != rax, "change this code"); @@ -78,7 +94,7 @@ } pop(rax); #endif - reset_last_Java_frame(thread, true, false); + reset_last_Java_frame(thread, true, align_stack); // discard thread and arguments NOT_LP64(addptr(rsp, num_rt_args()*BytesPerWord));
--- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -1181,14 +1181,13 @@ BasicType* in_sig_bt) { // if map is non-NULL then the code should store the values, // otherwise it should load them. - int handle_index = 0; + int slot = arg_save_area; // Save down double word first for ( int i = 0; i < total_in_args; i++) { if (in_regs[i].first()->is_XMMRegister() && in_sig_bt[i] == T_DOUBLE) { - int slot = handle_index * VMRegImpl::slots_per_word + arg_save_area; int offset = slot * VMRegImpl::stack_slot_size; - handle_index += 2; - assert(handle_index <= stack_slots, "overflow"); + slot += VMRegImpl::slots_per_word; + assert(slot <= stack_slots, "overflow"); if (map != NULL) { __ movdbl(Address(rsp, offset), in_regs[i].first()->as_XMMRegister()); } else { @@ -1197,10 +1196,7 @@ } if (in_regs[i].first()->is_Register() && (in_sig_bt[i] == T_LONG || in_sig_bt[i] == T_ARRAY)) { - int slot = handle_index * VMRegImpl::slots_per_word + arg_save_area; int offset = slot * VMRegImpl::stack_slot_size; - handle_index += 2; - assert(handle_index <= stack_slots, "overflow"); if (map != NULL) { __ movq(Address(rsp, offset), in_regs[i].first()->as_Register()); if (in_sig_bt[i] == T_ARRAY) { @@ -1209,14 +1205,15 @@ } else { __ movq(in_regs[i].first()->as_Register(), Address(rsp, offset)); } + slot += VMRegImpl::slots_per_word; } } // Save or restore single word registers for ( int i = 0; i < total_in_args; i++) { if (in_regs[i].first()->is_Register()) { - int slot = handle_index++ * VMRegImpl::slots_per_word + arg_save_area; int offset = slot * VMRegImpl::stack_slot_size; - assert(handle_index <= stack_slots, "overflow"); + slot++; + assert(slot <= stack_slots, "overflow"); // Value is in an input register pass we must flush it to the stack const Register reg = in_regs[i].first()->as_Register(); @@ -1241,9 +1238,9 @@ } } else if (in_regs[i].first()->is_XMMRegister()) { if (in_sig_bt[i] == T_FLOAT) { - int slot = handle_index++ * VMRegImpl::slots_per_word + arg_save_area; int offset = slot * VMRegImpl::stack_slot_size; - assert(handle_index <= stack_slots, "overflow"); + slot++; + assert(slot <= stack_slots, "overflow"); if (map != NULL) { __ movflt(Address(rsp, offset), in_regs[i].first()->as_XMMRegister()); } else { @@ -1368,6 +1365,174 @@ __ bind(done); } + +class ComputeMoveOrder: public StackObj { + class MoveOperation: public ResourceObj { + friend class ComputeMoveOrder; + private: + VMRegPair _src; + VMRegPair _dst; + int _src_index; + int _dst_index; + bool _processed; + MoveOperation* _next; + MoveOperation* _prev; + + static int get_id(VMRegPair r) { + return r.first()->value(); + } + + public: + MoveOperation(int src_index, VMRegPair src, int dst_index, VMRegPair dst): + _src(src) + , _src_index(src_index) + , _dst(dst) + , _dst_index(dst_index) + , _next(NULL) + , _prev(NULL) + , _processed(false) { + } + + VMRegPair src() const { return _src; } + int src_id() const { return get_id(src()); } + int src_index() const { return _src_index; } + VMRegPair dst() const { return _dst; } + void set_dst(int i, VMRegPair dst) { _dst_index = i, _dst = dst; } + int dst_index() const { return _dst_index; } + int dst_id() const { return get_id(dst()); } + MoveOperation* next() const { return _next; } + MoveOperation* prev() const { return _prev; } + void set_processed() { _processed = true; } + bool is_processed() const { return _processed; } + + // insert + void break_cycle(VMRegPair temp_register) { + // create a new store following the last store + // to move from the temp_register to the original + MoveOperation* new_store = new MoveOperation(-1, temp_register, dst_index(), dst()); + + // break the cycle of links and insert new_store at the end + // break the reverse link. + MoveOperation* p = prev(); + assert(p->next() == this, "must be"); + _prev = NULL; + p->_next = new_store; + new_store->_prev = p; + + // change the original store to save it's value in the temp. + set_dst(-1, temp_register); + } + + void link(GrowableArray<MoveOperation*>& killer) { + // link this store in front the store that it depends on + MoveOperation* n = killer.at_grow(src_id(), NULL); + if (n != NULL) { + assert(_next == NULL && n->_prev == NULL, "shouldn't have been set yet"); + _next = n; + n->_prev = this; + } + } + }; + + private: + GrowableArray<MoveOperation*> edges; + + public: + ComputeMoveOrder(int total_in_args, VMRegPair* in_regs, int total_c_args, VMRegPair* out_regs, + BasicType* in_sig_bt, GrowableArray<int>& arg_order, VMRegPair tmp_vmreg) { + // Move operations where the dest is the stack can all be + // scheduled first since they can't interfere with the other moves. + for (int i = total_in_args - 1, c_arg = total_c_args - 1; i >= 0; i--, c_arg--) { + if (in_sig_bt[i] == T_ARRAY) { + c_arg--; + if (out_regs[c_arg].first()->is_stack() && + out_regs[c_arg + 1].first()->is_stack()) { + arg_order.push(i); + arg_order.push(c_arg); + } else { + if (out_regs[c_arg].first()->is_stack() || + in_regs[i].first() == out_regs[c_arg].first()) { + add_edge(i, in_regs[i].first(), c_arg, out_regs[c_arg + 1]); + } else { + add_edge(i, in_regs[i].first(), c_arg, out_regs[c_arg]); + } + } + } else if (in_sig_bt[i] == T_VOID) { + arg_order.push(i); + arg_order.push(c_arg); + } else { + if (out_regs[c_arg].first()->is_stack() || + in_regs[i].first() == out_regs[c_arg].first()) { + arg_order.push(i); + arg_order.push(c_arg); + } else { + add_edge(i, in_regs[i].first(), c_arg, out_regs[c_arg]); + } + } + } + // Break any cycles in the register moves and emit the in the + // proper order. + GrowableArray<MoveOperation*>* stores = get_store_order(tmp_vmreg); + for (int i = 0; i < stores->length(); i++) { + arg_order.push(stores->at(i)->src_index()); + arg_order.push(stores->at(i)->dst_index()); + } + } + + // Collected all the move operations + void add_edge(int src_index, VMRegPair src, int dst_index, VMRegPair dst) { + if (src.first() == dst.first()) return; + edges.append(new MoveOperation(src_index, src, dst_index, dst)); + } + + // Walk the edges breaking cycles between moves. The result list + // can be walked in order to produce the proper set of loads + GrowableArray<MoveOperation*>* get_store_order(VMRegPair temp_register) { + // Record which moves kill which values + GrowableArray<MoveOperation*> killer; + for (int i = 0; i < edges.length(); i++) { + MoveOperation* s = edges.at(i); + assert(killer.at_grow(s->dst_id(), NULL) == NULL, "only one killer"); + killer.at_put_grow(s->dst_id(), s, NULL); + } + assert(killer.at_grow(MoveOperation::get_id(temp_register), NULL) == NULL, + "make sure temp isn't in the registers that are killed"); + + // create links between loads and stores + for (int i = 0; i < edges.length(); i++) { + edges.at(i)->link(killer); + } + + // at this point, all the move operations are chained together + // in a doubly linked list. Processing it backwards finds + // the beginning of the chain, forwards finds the end. If there's + // a cycle it can be broken at any point, so pick an edge and walk + // backward until the list ends or we end where we started. + GrowableArray<MoveOperation*>* stores = new GrowableArray<MoveOperation*>(); + for (int e = 0; e < edges.length(); e++) { + MoveOperation* s = edges.at(e); + if (!s->is_processed()) { + MoveOperation* start = s; + // search for the beginning of the chain or cycle + while (start->prev() != NULL && start->prev() != s) { + start = start->prev(); + } + if (start->prev() == s) { + start->break_cycle(temp_register); + } + // walk the chain forward inserting to store list + while (start != NULL) { + stores->append(start); + start->set_processed(); + start = start->next(); + } + } + } + return stores; + } +}; + + // --------------------------------------------------------------------------- // Generate a native wrapper for a given method. The method takes arguments // in the Java compiled code convention, marshals them to the native @@ -1488,12 +1653,12 @@ if (in_regs[i].first()->is_Register()) { const Register reg = in_regs[i].first()->as_Register(); switch (in_sig_bt[i]) { - case T_ARRAY: case T_BOOLEAN: case T_BYTE: case T_SHORT: case T_CHAR: case T_INT: single_slots++; break; + case T_ARRAY: case T_LONG: double_slots++; break; default: ShouldNotReachHere(); } @@ -1690,36 +1855,43 @@ #endif /* ASSERT */ - if (is_critical_native) { - // The mapping of Java and C arguments passed in registers are - // rotated by one, which helps when passing arguments to regular - // Java method but for critical natives that creates a cycle which - // can cause arguments to be killed before they are used. Break - // the cycle by moving the first argument into a temporary - // register. - for (int i = 0; i < total_c_args; i++) { - if (in_regs[i].first()->is_Register() && - in_regs[i].first()->as_Register() == rdi) { - __ mov(rbx, rdi); - in_regs[i].set1(rbx->as_VMReg()); - } - } - } - // This may iterate in two different directions depending on the // kind of native it is. The reason is that for regular JNI natives // the incoming and outgoing registers are offset upwards and for // critical natives they are offset down. - int c_arg = total_c_args - 1; - int stride = -1; - int init = total_in_args - 1; - if (is_critical_native) { - // stride forwards - c_arg = 0; - stride = 1; - init = 0; + GrowableArray<int> arg_order(2 * total_in_args); + VMRegPair tmp_vmreg; + tmp_vmreg.set1(rbx->as_VMReg()); + + if (!is_critical_native) { + for (int i = total_in_args - 1, c_arg = total_c_args - 1; i >= 0; i--, c_arg--) { + arg_order.push(i); + arg_order.push(c_arg); + } + } else { + // Compute a valid move order, using tmp_vmreg to break any cycles + ComputeMoveOrder cmo(total_in_args, in_regs, total_c_args, out_regs, in_sig_bt, arg_order, tmp_vmreg); } - for (int i = init, count = 0; count < total_in_args; i += stride, c_arg += stride, count++ ) { + + int temploc = -1; + for (int ai = 0; ai < arg_order.length(); ai += 2) { + int i = arg_order.at(ai); + int c_arg = arg_order.at(ai + 1); + __ block_comment(err_msg("move %d -> %d", i, c_arg)); + if (c_arg == -1) { + assert(is_critical_native, "should only be required for critical natives"); + // This arg needs to be moved to a temporary + __ mov(tmp_vmreg.first()->as_Register(), in_regs[i].first()->as_Register()); + in_regs[i] = tmp_vmreg; + temploc = i; + continue; + } else if (i == -1) { + assert(is_critical_native, "should only be required for critical natives"); + // Read from the temporary location + assert(temploc != -1, "must be valid"); + i = temploc; + temploc = -1; + } #ifdef ASSERT if (in_regs[i].first()->is_Register()) { assert(!reg_destroyed[in_regs[i].first()->as_Register()->encoding()], "destroyed reg!"); @@ -1779,7 +1951,7 @@ // point c_arg at the first arg that is already loaded in case we // need to spill before we call out - c_arg++; + int c_arg = total_c_args - total_in_args; // Pre-load a static method's oop into r14. Used both by locking code and // the normal JNI call code. @@ -3620,8 +3792,12 @@ // // address OptoRuntime::handle_exception_C(JavaThread* thread) - __ set_last_Java_frame(noreg, noreg, NULL); + // At a method handle call, the stack may not be properly aligned + // when returning with an exception. + address the_pc = __ pc(); + __ set_last_Java_frame(noreg, noreg, the_pc); __ mov(c_rarg0, r15_thread); + __ andptr(rsp, -(StackAlignmentInBytes)); // Align stack __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C))); // Set an oopmap for the call site. This oopmap will only be used if we @@ -3632,9 +3808,9 @@ OopMapSet* oop_maps = new OopMapSet(); - oop_maps->add_gc_map( __ pc()-start, new OopMap(SimpleRuntimeFrame::framesize, 0)); - - __ reset_last_Java_frame(false, false); + oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0)); + + __ reset_last_Java_frame(false, true); // Restore callee-saved registers
--- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -710,6 +710,21 @@ return start; } + // Support for intptr_t get_previous_sp() + // + // This routine is used to find the previous stack pointer for the + // caller. + address generate_get_previous_sp() { + StubCodeMark mark(this, "StubRoutines", "get_previous_sp"); + address start = __ pc(); + + __ movptr(rax, rsp); + __ addptr(rax, 8); // return address is at the top of the stack. + __ ret(0); + + return start; + } + //---------------------------------------------------------------------------------------------------- // Support for void verify_mxcsr() // @@ -3060,6 +3075,7 @@ // platform dependent StubRoutines::x86::_get_previous_fp_entry = generate_get_previous_fp(); + StubRoutines::x86::_get_previous_sp_entry = generate_get_previous_sp(); StubRoutines::x86::_verify_mxcsr_entry = generate_verify_mxcsr();
--- a/src/cpu/x86/vm/stubRoutines_x86_64.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/cpu/x86/vm/stubRoutines_x86_64.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -43,6 +43,7 @@ // a description of how to extend it, see the stubRoutines.hpp file. address StubRoutines::x86::_get_previous_fp_entry = NULL; +address StubRoutines::x86::_get_previous_sp_entry = NULL; address StubRoutines::x86::_verify_mxcsr_entry = NULL;
--- a/src/cpu/x86/vm/stubRoutines_x86_64.hpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/cpu/x86/vm/stubRoutines_x86_64.hpp Fri Mar 02 09:13:13 2012 -0800 @@ -41,6 +41,7 @@ private: static address _get_previous_fp_entry; + static address _get_previous_sp_entry; static address _verify_mxcsr_entry; static address _f2i_fixup; @@ -61,6 +62,11 @@ return _get_previous_fp_entry; } + static address get_previous_sp_entry() + { + return _get_previous_sp_entry; + } + static address verify_mxcsr_entry() { return _verify_mxcsr_entry;
--- a/src/os/solaris/vm/os_solaris.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/os/solaris/vm/os_solaris.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -1013,15 +1013,6 @@ // use debugger to set breakpoint here } -// Returns an estimate of the current stack pointer. Result must be guaranteed to -// point into the calling threads stack, and be no lower than the current stack -// pointer. -address os::current_stack_pointer() { - volatile int dummy; - address sp = (address)&dummy + 8; // %%%% need to confirm if this is right - return sp; -} - static thread_t main_thread; // Thread start routine for all new Java threads
--- a/src/os/windows/vm/os_windows.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/os/windows/vm/os_windows.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -324,16 +324,6 @@ os::breakpoint(); } -// Returns an estimate of the current stack pointer. Result must be guaranteed -// to point into the calling threads stack, and be no lower than the current -// stack pointer. - -address os::current_stack_pointer() { - int dummy; - address sp = (address)&dummy; - return sp; -} - // os::current_stack_base() // // Returns the base of the stack, which is the stack's
--- a/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -1126,3 +1126,8 @@ : "r" (fpu_cntrl) : "memory"); #endif // !AMD64 } + +#ifndef PRODUCT +void os::verify_stack_alignment() { +} +#endif
--- a/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -562,3 +562,8 @@ } }; #endif // !_LP64 + +#ifndef PRODUCT +void os::verify_stack_alignment() { +} +#endif
--- a/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -756,3 +756,8 @@ // guard page, only enable glibc guard page for non-Java threads. return (thr_type == java_thread ? 0 : page_size()); } + +#ifndef PRODUCT +void os::verify_stack_alignment() { +} +#endif
--- a/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -862,3 +862,11 @@ : "r" (fpu_cntrl) : "memory"); #endif // !AMD64 } + +#ifndef PRODUCT +void os::verify_stack_alignment() { +#ifdef AMD64 + assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment"); +#endif +} +#endif
--- a/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -506,3 +506,8 @@ } }; #endif // !_LP64 + +#ifndef PRODUCT +void os::verify_stack_alignment() { +} +#endif
--- a/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -251,6 +251,15 @@ return frame(fr->sender_sp(), frame::unpatchable, fr->sender_pc()); } +// Returns an estimate of the current stack pointer. Result must be guaranteed to +// point into the calling threads stack, and be no lower than the current stack +// pointer. +address os::current_stack_pointer() { + volatile int dummy; + address sp = (address)&dummy + 8; // %%%% need to confirm if this is right + return sp; +} + frame os::current_frame() { intptr_t* sp = StubRoutines::Sparc::flush_callers_register_windows_func()(); frame myframe(sp, frame::unpatchable, @@ -815,3 +824,8 @@ __asm__ __volatile__ ("wr %%g0, 0, %%fprs \n\t" : : :); } #endif //defined(__sparc) && defined(COMPILER2) + +#ifndef PRODUCT +void os::verify_stack_alignment() { +} +#endif
--- a/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -237,6 +237,12 @@ return frame(fr->sender_sp(), fr->link(), fr->sender_pc()); } +extern "C" intptr_t *_get_current_sp(); // in .il file + +address os::current_stack_pointer() { + return (address)_get_current_sp(); +} + extern "C" intptr_t *_get_current_fp(); // in .il file frame os::current_frame() { @@ -954,3 +960,11 @@ _solaris_raw_setup_fpu(fpu_cntrl); } #endif // AMD64 + +#ifndef PRODUCT +void os::verify_stack_alignment() { +#ifdef AMD64 + assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment"); +#endif +} +#endif
--- a/src/os_cpu/solaris_x86/vm/solaris_x86_32.il Tue Feb 28 07:58:43 2012 -0800 +++ b/src/os_cpu/solaris_x86/vm/solaris_x86_32.il Fri Mar 02 09:13:13 2012 -0800 @@ -37,6 +37,12 @@ movl %gs:0, %eax .end + // Get current sp + .inline _get_current_sp,0 + .volatile + movl %esp, %eax + .end + // Get current fp .inline _get_current_fp,0 .volatile
--- a/src/os_cpu/solaris_x86/vm/solaris_x86_64.il Tue Feb 28 07:58:43 2012 -0800 +++ b/src/os_cpu/solaris_x86/vm/solaris_x86_64.il Fri Mar 02 09:13:13 2012 -0800 @@ -30,6 +30,12 @@ movq %fs:0, %rax .end + // Get current sp + .inline _get_current_sp,0 + .volatile + movq %rsp, %rax + .end + // Get current fp .inline _get_current_fp,0 .volatile
--- a/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -370,6 +370,26 @@ return frame(fr->sender_sp(), fr->link(), fr->sender_pc()); } +#ifndef AMD64 +// Returns an estimate of the current stack pointer. Result must be guaranteed +// to point into the calling threads stack, and be no lower than the current +// stack pointer. +address os::current_stack_pointer() { + int dummy; + address sp = (address)&dummy; + return sp; +} +#else +// Returns the current stack pointer. Accurate value needed for +// os::verify_stack_alignment(). +address os::current_stack_pointer() { + typedef address get_sp_func(); + get_sp_func* func = CAST_TO_FN_PTR(get_sp_func*, + StubRoutines::x86::get_previous_sp_entry()); + return (*func)(); +} +#endif + #ifndef AMD64 intptr_t* _get_previous_fp() { @@ -546,3 +566,11 @@ __asm fldcw fpu_cntrl_word; #endif // !AMD64 } + +#ifndef PRODUCT +void os::verify_stack_alignment() { +#ifdef AMD64 + assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment"); +#endif +} +#endif
--- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Compilation.java Tue Feb 28 07:58:43 2012 -0800 +++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Compilation.java Fri Mar 02 09:13:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ private boolean osr; private Method method; private CallSite call = new CallSite(); + private CallSite lateInlineCall = new CallSite(); private int osrBci; private String icount; private String bcount; @@ -80,6 +81,13 @@ sb.append(site); sb.append("\n"); } + if (getLateInlineCall().getCalls() != null) { + sb.append("late inline:\n"); + for (CallSite site : getLateInlineCall().getCalls()) { + sb.append(site); + sb.append("\n"); + } + } return sb.toString(); } @@ -115,6 +123,12 @@ site.print(stream, indent + 2); } } + if (printInlining && lateInlineCall.getCalls() != null) { + stream.println("late inline:"); + for (CallSite site : lateInlineCall.getCalls()) { + site.print(stream, indent + 2); + } + } } } @@ -215,7 +229,11 @@ } public void setMethod(Method method) { - this.method = method; + // Don't change method if it is already set to avoid changing + // it by post parse inlining info. + if (getMethod() == null) { + this.method = method; + } } public CallSite getCall() { @@ -226,6 +244,10 @@ this.call = call; } + public CallSite getLateInlineCall() { + return lateInlineCall; + } + public double getElapsedTime() { return end - start; }
--- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java Tue Feb 28 07:58:43 2012 -0800 +++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java Fri Mar 02 09:13:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -146,6 +146,7 @@ private CallSite site; private Stack<Phase> phaseStack = new Stack<Phase>(); private UncommonTrapEvent currentTrap; + private Stack<CallSite> late_inline_scope; long parseLong(String l) { try { @@ -302,6 +303,7 @@ } events.add(compile); compiles.put(makeId(atts), compile); + site = compile.getCall(); } else if (qname.equals("type")) { type(search(atts, "id"), search(atts, "name")); } else if (qname.equals("bc")) { @@ -360,12 +362,22 @@ // uncommon trap inserted during parsing. // ignore for now } + } else if (qname.equals("late_inline")) { + late_inline_scope = new Stack<CallSite>(); + site = new CallSite(-999, method(search(atts, "method"))); + late_inline_scope.push(site); } else if (qname.equals("jvms")) { // <jvms bci='4' method='java/io/DataInputStream readChar ()C' bytes='40' count='5815' iicount='20815'/> if (currentTrap != null) { currentTrap.addJVMS(atts.getValue("method"), Integer.parseInt(atts.getValue("bci"))); + } else if (late_inline_scope != null) { + bci = Integer.parseInt(search(atts, "bci")); + site = new CallSite(bci, method(search(atts, "method"))); + late_inline_scope.push(site); } else { - // Ignore <eliminate_allocation type='667'> and <eliminate_lock lock='1'> + // Ignore <eliminate_allocation type='667'>, + // <eliminate_lock lock='1'>, + // <replace_string_concat arguments='2' string_alloc='0' multiple='0'> } } else if (qname.equals("nmethod")) { String id = makeId(atts); @@ -379,7 +391,7 @@ Method m = method(search(atts, "method")); if (scopes.size() == 0) { compile.setMethod(m); - scopes.push(compile.getCall()); + scopes.push(site); } else { if (site.getMethod() == m) { scopes.push(site); @@ -393,7 +405,7 @@ } } else if (qname.equals("parse_done")) { CallSite call = scopes.pop(); - call.setEndNodes(Integer.parseInt(search(atts, "nodes"))); + call.setEndNodes(Integer.parseInt(search(atts, "nodes", "1"))); call.setTimeStamp(Double.parseDouble(search(atts, "stamp"))); scopes.push(call); } @@ -408,6 +420,43 @@ scopes.pop(); } else if (qname.equals("uncommon_trap")) { currentTrap = null; + } else if (qname.equals("late_inline")) { + // Populate late inlining info. + + // late_inline scopes are specified in reverse order: + // compiled method should be on top of stack. + CallSite caller = late_inline_scope.pop(); + Method m = compile.getMethod(); + if (m != caller.getMethod()) { + System.out.println(m); + System.out.println(caller.getMethod() + " bci: " + bci); + throw new InternalError("call site and late_inline info don't match"); + } + + // late_inline contains caller+bci info, convert it + // to bci+callee info used by LogCompilation. + site = compile.getLateInlineCall(); + do { + bci = caller.getBci(); + // Next inlined call. + caller = late_inline_scope.pop(); + CallSite callee = new CallSite(bci, caller.getMethod()); + site.add(callee); + site = callee; + } while (!late_inline_scope.empty()); + + if (caller.getBci() != -999) { + System.out.println(caller.getMethod()); + throw new InternalError("broken late_inline info"); + } + if (site.getMethod() != caller.getMethod()) { + System.out.println(site.getMethod()); + System.out.println(caller.getMethod()); + throw new InternalError("call site and late_inline info don't match"); + } + // late_inline is followed by parse with scopes.size() == 0, + // 'site' will be pushed to scopes. + late_inline_scope = null; } else if (qname.equals("task")) { types.clear(); methods.clear();
--- a/src/share/vm/c1/c1_LinearScan.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/share/vm/c1/c1_LinearScan.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -1884,7 +1884,7 @@ if (move_resolver.has_mappings()) { // insert moves after first instruction - move_resolver.set_insert_position(block->lir(), 1); + move_resolver.set_insert_position(block->lir(), 0); move_resolver.resolve_and_append_moves(); } }
--- a/src/share/vm/opto/connode.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/share/vm/opto/connode.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1051,6 +1051,7 @@ //------------------------------Value------------------------------------------ const Type *CastX2PNode::Value( PhaseTransform *phase ) const { const Type* t = phase->type(in(1)); + if (t == Type::TOP) return Type::TOP; if (t->base() == Type_X && t->singleton()) { uintptr_t bits = (uintptr_t) t->is_intptr_t()->get_con(); if (bits == 0) return TypePtr::NULL_PTR; @@ -1121,6 +1122,7 @@ //------------------------------Value------------------------------------------ const Type *CastP2XNode::Value( PhaseTransform *phase ) const { const Type* t = phase->type(in(1)); + if (t == Type::TOP) return Type::TOP; if (t->base() == Type::RawPtr && t->singleton()) { uintptr_t bits = (uintptr_t) t->is_rawptr()->get_con(); return TypeX::make(bits);
--- a/src/share/vm/opto/escape.cpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/share/vm/opto/escape.cpp Fri Mar 02 09:13:13 2012 -0800 @@ -2035,40 +2035,14 @@ Node* store = ini->find_captured_store(offset, type2aelembytes(ft), phase); if (store != NULL && store->is_Store()) { value = store->in(MemNode::ValueIn); - } else if (ptn->edge_count() > 0) { // Are there oop stores? - // Check for a store which follows allocation without branches. + } else { + // There could be initializing stores which follow allocation. // For example, a volatile field store is not collected - // by Initialize node. TODO: it would be nice to use idom() here. - // - // Search all references to the same field which use different - // AddP nodes, for example, in the next case: - // - // Point p[] = new Point[1]; - // if ( x ) { p[0] = new Point(); p[0].x = x; } - // if ( p[0] != null ) { y = p[0].x; } // has CastPP + // by Initialize node. // - for (uint next = ei; (next < ae_cnt) && (value == NULL); next++) { - uint fpi = pta->edge_target(next); // Field (AddP) - PointsToNode *ptf = ptnode_adr(fpi); - if (ptf->offset() == offset) { - Node* nf = ptf->_node; - for (DUIterator_Fast imax, i = nf->fast_outs(imax); i < imax; i++) { - store = nf->fast_out(i); - if (store->is_Store() && store->in(0) != NULL) { - Node* ctrl = store->in(0); - while(!(ctrl == ini || ctrl == alloc || ctrl == NULL || - ctrl == C->root() || ctrl == C->top() || ctrl->is_Region() || - ctrl->is_IfTrue() || ctrl->is_IfFalse())) { - ctrl = ctrl->in(0); - } - if (ctrl == ini || ctrl == alloc) { - value = store->in(MemNode::ValueIn); - break; - } - } - } - } - } + // Need to check for dependent loads to separate such stores from + // stores which follow loads. For now, add initial value NULL so + // that compare pointers optimization works correctly. } } if (value == NULL || value != ptnode_adr(value->_idx)->_node) {
--- a/src/share/vm/runtime/interfaceSupport.hpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/share/vm/runtime/interfaceSupport.hpp Fri Mar 02 09:13:13 2012 -0800 @@ -436,6 +436,7 @@ #define VM_LEAF_BASE(result_type, header) \ TRACE_CALL(result_type, header) \ debug_only(NoHandleMark __hm;) \ + os::verify_stack_alignment(); \ /* begin of body */ @@ -445,6 +446,7 @@ TRACE_CALL(result_type, header) \ HandleMarkCleaner __hm(thread); \ Thread* THREAD = thread; \ + os::verify_stack_alignment(); \ /* begin of body */ @@ -454,6 +456,7 @@ TRACE_CALL(result_type, header) \ debug_only(NoHandleMark __hm;) \ Thread* THREAD = thread; \ + os::verify_stack_alignment(); \ /* begin of body */
--- a/src/share/vm/runtime/os.hpp Tue Feb 28 07:58:43 2012 -0800 +++ b/src/share/vm/runtime/os.hpp Fri Mar 02 09:13:13 2012 -0800 @@ -404,6 +404,8 @@ static address current_stack_base(); static size_t current_stack_size(); + static void verify_stack_alignment() PRODUCT_RETURN; + static int message_box(const char* title, const char* message); static char* do_you_want_to_debug(const char* message);