< prev index next >

src/hotspot/cpu/x86/stubGenerator_x86_64.cpp

Print this page
rev 50307 : [mq]: cont

@@ -33,10 +33,11 @@
 #include "oops/instanceOop.hpp"
 #include "oops/method.hpp"
 #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"
 #include "runtime/stubCodeGenerator.hpp"
 #include "runtime/stubRoutines.hpp"

@@ -4786,10 +4787,225 @@
 
     return start;
 
   }
 
+void push_FrameInfo(MacroAssembler* _masm, 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(MacroAssembler* _masm, 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(MacroAssembler* _masm, 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() {
+    const char *name = "cont_doYield";
+
+    enum layout {
+      frameinfo_11  = frame::arg_reg_save_area_bytes/BytesPerInt,
+      frameinfo_12,
+      frameinfo_21,
+      frameinfo_22,
+      frameinfo_31,
+      frameinfo_32,
+      rbp_off,
+      rbpH_off,
+      return_off,
+      return_off2,
+      framesize // inclusive of return address
+    };
+    // assert(is_even(framesize/2), "sp not 16-byte aligned");
+    int insts_size = 512;
+    int locs_size  = 64;
+    CodeBuffer code(name, insts_size, locs_size);
+    OopMapSet* oop_maps  = new OopMapSet();
+    MacroAssembler* masm = new MacroAssembler(&code);
+    MacroAssembler* _masm = masm;
+
+    // MacroAssembler* masm = _masm;
+    // StubCodeMark mark(this, "StubRoutines", name);
+
+    address start = __ pc();
+
+    Register fi = c_rarg1;
+
+    __ movq(c_rarg2, c_rarg0);          // scopes argument
+    __ movptr(rax, Address(rsp, 0));    // use return address as the frame pc // __ lea(rax, InternalAddress(pcxxxx));
+    __ lea(fi, Address(rsp, wordSize)); // skip return address
+    __ movptr(c_rarg3, rbp);
+
+    __ enter();
+    
+    // // return address and rbp are already in place
+    // __ subptr(rsp, (framesize-4) << LogBytesPerInt); // prolog
+
+    push_FrameInfo(masm, fi, fi, c_rarg3, rax);
+
+    int frame_complete = __ pc() - start;
+    address the_pc = __ pc();
+
+    __ set_last_Java_frame(rsp, rbp, the_pc); // may be unnecessary. also, consider MacroAssembler::call_VM_leaf_base
+
+    __ 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
+
+    Label pinned;
+    __ pop(rax); // read the pc from the FrameInfo
+    __ testq(rax, rax);
+    __ jcc(Assembler::zero, pinned);
+    
+    __ pop(rbp); // not pinned -- jump to Continuation.run (the entry frame)
+    __ 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;
+
+    OopMap* map = new OopMap(framesize, 1);
+    // map->set_callee_saved(VMRegImpl::stack2reg(rbp_off), rbp->as_VMReg());
+    oop_maps->add_gc_map(the_pc - start, map);
+
+    RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
+      RuntimeStub::new_runtime_stub(name,
+                                    &code,
+                                    frame_complete,
+                                    (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+                                    oop_maps, false);
+    return stub->entry_point();
+  }
+
+  address generate_cont_thaw(bool return_barrier) {
+    address start = __ pc();
+
+    // TODO: Handle Valhalla return types. May require generating different return barriers.
+
+    Register fi = r11;
+
+    if (!return_barrier) {
+      __ pop(c_rarg3); // pop return address. if we don't do this, we get a drift, where the bottom-most frozen frame continuously grows
+      // __ lea(rsp, Address(rsp, wordSize)); // pop return address. if we don't do this, we get a drift, where the bottom-most frozen frame continuously grows
+    }
+
+    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, return_barrier);
+    push_FrameInfo(_masm, fi, fi, rbp, c_rarg3);
+    __ 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);
+
+    pop_FrameInfo(_masm, fi, rbp, c_rarg3); // c_rarg3 would still be our return address
+    __ 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, return_barrier);
+    push_FrameInfo(_masm, fi, fi, rbp, c_rarg3);
+    __ call_VM_leaf(CAST_FROM_FN_PTR(address, Continuation::thaw), fi, c_rarg2);
+
+    __ bind(thaw_fail);
+    pop_FrameInfo(_masm, fi, rbp, rdx);
+    // __ movl(rbp, 0);
+    __ 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_thaw() {
+    StubCodeMark mark(this, "StubRoutines", "Cont thaw");
+    address start = __ pc();
+    generate_cont_thaw(false);
+    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();
+
+    if (CONT_FULL_STACK)
+      __ stop("RETURN BARRIER -- UNREACHABLE 0");
+
+    generate_cont_thaw(true);
+
+    return start;
+  }
+
+  address generate_cont_getPC() {
+    StubCodeMark mark(this, "StubRoutines", "GetPC");
+    address start = __ pc();
+
+    __ movptr(rax, Address(rsp, 0));
+    __ ret(0);
+
+    return start;
+  }
+
+  address generate_cont_getSP() {
+    StubCodeMark mark(this, "StubRoutines", "getSP");
+    address start = __ pc();
+
+    __ lea(rax, Address(rsp, wordSize));
+    __ ret(0);
+
+    return start;
+  }
+
+  address generate_cont_getFP() {
+    StubCodeMark mark(this, "StubRoutines", "GetFP");
+    address start = __ pc();
+
+    __ stop("WHAT?");
+    __ lea(rax, Address(rsp, wordSize));
+    __ ret(0);
+
+    return start;
+  }
+
 #undef __
 #define __ masm->
 
   // Continuation point for throwing of implicit exceptions that are
   // not handled in the current activation. Fabricates an exception

@@ -5017,10 +5233,19 @@
         StubRoutines::_dtan = generate_libmTan();
       }
     }
   }
 
+  void generate_phase1() {
+    // Continuation stubs:
+    StubRoutines::_cont_thaw          = generate_cont_thaw();
+    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
 
     // These entry points require SharedInfo::stack0 to be set up in
     // non-core builds and need to be relocatable, so they each

@@ -5139,17 +5364,19 @@
       StubRoutines::_vectorizedMismatch = generate_vectorizedMismatch();
     }
   }
 
  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);
 }
< prev index next >