--- old/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp 2018-04-20 00:46:37.000000000 +0100 +++ new/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp 2018-04-20 00:46:37.000000000 +0100 @@ -35,6 +35,7 @@ #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" #include "prims/methodHandles.hpp" +#include "runtime/continuation.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/sharedRuntime.hpp" @@ -4788,6 +4789,157 @@ } +void push_FrameInfo(Register fi, Register sp, Register fp, address pc) { + if(!sp->is_valid()) __ push(0); else { + if (sp == rsp) { + __ movptr(fi, rsp); + __ push(fi); + } else { + __ push(sp); + } + } + + if(!fp->is_valid()) __ push(0); else __ push(fp); + + __ lea(fi, ExternalAddress(pc)); + __ push(fi); + + __ movptr(fi, rsp); // make fi point to the beginning of FramInfo +} + +void push_FrameInfo(Register fi, Register sp, Register fp, Register pc) { + if(!sp->is_valid()) __ push(0); else { + if (sp == rsp) { + __ movptr(fi, rsp); + __ push(fi); + } else { + __ push(sp); + } + } + + if(!fp->is_valid()) __ push(0); else __ push(fp); + + if(!pc->is_valid()) __ push(0); else __ push(pc); + + __ movptr(fi, rsp); // make fi point to the beginning of FramInfo +} + +void pop_FrameInfo(Register sp, Register fp, Register pc) { + if(!pc->is_valid()) __ lea(rsp, Address(rsp, wordSize)); else __ pop(pc); + if(!fp->is_valid()) __ lea(rsp, Address(rsp, wordSize)); else __ pop(fp); + if(!sp->is_valid()) __ lea(rsp, Address(rsp, wordSize)); else __ pop(sp); +} + + // c_rarg1 ContinuationScope + address generate_cont_doYield() { + // try to use only caller-saved registers (see x86_64) + // c_rarg1 = rsi (rdx on WIN) + // c_rarg2 = rdx (r8 on WIN) + // c_rarg3 = rcx (r9 on WIN) + + StubCodeMark mark(this, "StubRoutines", "cont_doYield"); + address start = __ pc(); + + Register fi = c_rarg1; + + __ movptr(rax, Address(rsp, 0)); // use return address (in the intrinsic) as the frame pc + __ movq(c_rarg2, c_rarg1); // scope argument + + __ movptr(fi, rsp); + __ addq(fi, 1 * wordSize); // skip return address + + __ movptr(c_rarg3, rbp); + + __ enter(); + + push_FrameInfo(fi, fi, c_rarg3, rax); + //__ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); // __ reset_last_Java_frame(thread, true); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, Continuation::freeze), fi, c_rarg2, false); // do NOT check exceptions; they'll get forwarded to the caller + __ pop(rax); // return pc + + Label pinned; + __ testq(rax, rax); + __ jcc(Assembler::zero, pinned); + + __ pop(rbp); // not pinned -- return to Continuation.run + __ pop(fi); + __ movptr(rsp, fi); + __ jmp(rax); + + __ bind(pinned); // pinned -- return to caller + __ lea(rsp, Address(rsp, wordSize*2)); // "pop" the rest of the FrameInfo struct + + __ leave(); + __ ret(0); + + return start; + } + + // clobbers r11 + address generate_cont_thaw(const char *stub_name, int frames) { + StubCodeMark mark(this, "StubRoutines", stub_name); + address start = __ pc(); + + // TODO: Handle Valhalla return types. May require generating different return barriers. + + Register fi = r11; + + Label thaw_fail; + __ movptr(fi, rsp); + __ push(rax); __ push_d(xmm0); // preserve possible return value from a method returning to the return barrier + __ movl(c_rarg2, frames); + push_FrameInfo(fi, fi, noreg, noreg); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, Continuation::prepare_thaw), fi, c_rarg2); + __ testq(rax, rax); // rax contains the size of the frames to thaw, 0 if overflow or no more frames + __ jcc(Assembler::zero, thaw_fail); + + __ lea(rsp, Address(rsp, wordSize*3)); // "pop" FrameInfo + __ pop_d(xmm0); __ pop(rdx); // TEMPORARILY restore return value (we're going to push it again, but rsp is about to move) + __ subq(rsp, rax); // make room for the thawed frames + __ movptr(fi, rsp); // where we'll start copying frame (the lowest address) + __ push(rdx); __ push_d(xmm0); // save original return value -- again + __ movl(c_rarg2, frames); + push_FrameInfo(fi, fi, noreg, noreg); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, Continuation::thaw), fi, c_rarg2); + + __ bind(thaw_fail); + pop_FrameInfo(fi, rbp, rdx); + __ pop_d(xmm0); __ pop(rax); // restore return value (no safepoint in the call to thaw, so even an oop return value should be OK) + __ movptr(rsp, fi); // we're now on the yield frame (which is above us b/c rsp has been pushed down) + __ jmp(rdx); + + return start; + } + + address generate_cont_returnBarrier() { + // TODO: will probably need multiple return barriers depending on return type + StubCodeMark mark(this, "StubRoutines", "cont return barrier"); + address start = __ pc(); + + __ jump(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::cont_thaw(1)))); + __ stop("RETURN BARRIER -- UNREACHABLE"); // ret(0); + + return start; + } + + address generate_cont_getPC() { + StubCodeMark mark(this, "StubRoutines", "GetPC"); + address start = __ pc(); + //__ xorptr(rax, rax); // return 0 + __ movptr(rax, Address(rsp, 0)); + __ ret(0); + return start; + } + + address generate_cont_getSP() { + StubCodeMark mark(this, "StubRoutines", "GetSP"); + address start = __ pc(); + //__ xorptr(rax, rax); // return 0 + __ lea(rax, Address(rsp, wordSize)); + __ ret(0); + return start; + } + #undef __ #define __ masm-> @@ -5019,6 +5171,16 @@ } } + void generate_phase1() { + // Continuation stubs: + StubRoutines::_cont_thaw2 = generate_cont_thaw("Cont thaw 2", 2); + StubRoutines::_cont_thaw1 = generate_cont_thaw("Cont thaw 1", 1); + StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier(); + StubRoutines::_cont_doYield = generate_cont_doYield(); + StubRoutines::_cont_getSP = generate_cont_getSP(); + StubRoutines::_cont_getPC = generate_cont_getPC(); + } + void generate_all() { // Generates all stubs and initializes the entry points @@ -5141,15 +5303,17 @@ } public: - StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) { - if (all) { - generate_all(); - } else { + StubGenerator(CodeBuffer* code, int phase) : StubCodeGenerator(code) { + if (phase == 0) { generate_initial(); + } else if (phase == 1) { + generate_phase1(); + } else { + generate_all(); } } }; // end class declaration -void StubGenerator_generate(CodeBuffer* code, bool all) { - StubGenerator g(code, all); +void StubGenerator_generate(CodeBuffer* code, int phase) { + StubGenerator g(code, phase); }