c1_Runtime1_x86.cpp revision 0:a61af66fc99e
155682Smarkm/*
2233294Sstas * Copyright 1999-2007 Sun Microsystems, Inc.  All Rights Reserved.
3233294Sstas * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4233294Sstas *
555682Smarkm * This code is free software; you can redistribute it and/or modify it
6233294Sstas * under the terms of the GNU General Public License version 2 only, as
7233294Sstas * published by the Free Software Foundation.
8233294Sstas *
955682Smarkm * This code is distributed in the hope that it will be useful, but WITHOUT
10233294Sstas * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11233294Sstas * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1255682Smarkm * version 2 for more details (a copy is included in the LICENSE file that
13233294Sstas * accompanied this code).
14233294Sstas *
15233294Sstas * You should have received a copy of the GNU General Public License version
1655682Smarkm * 2 along with this work; if not, write to the Free Software Foundation,
17233294Sstas * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18233294Sstas *
19233294Sstas * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
2055682Smarkm * CA 95054 USA or visit www.sun.com if you need additional information or
21233294Sstas * have any questions.
22233294Sstas *
23233294Sstas */
24233294Sstas
25233294Sstas#include "incls/_precompiled.incl"
26233294Sstas#include "incls/_c1_Runtime1_x86.cpp.incl"
27233294Sstas
28233294Sstas
29233294Sstas// Implementation of StubAssembler
30233294Sstas
31233294Sstasint StubAssembler::call_RT(Register oop_result1, Register oop_result2, address entry, int args_size) {
3255682Smarkm  // setup registers
3355682Smarkm  const Register thread = rdi; // is callee-saved register (Visual C++ calling conventions)
3455682Smarkm  assert(!(oop_result1->is_valid() || oop_result2->is_valid()) || oop_result1 != oop_result2, "registers must be different");
35178825Sdfr  assert(oop_result1 != thread && oop_result2 != thread, "registers must be different");
3655682Smarkm  assert(args_size >= 0, "illegal args_size");
37233294Sstas
3855682Smarkm  set_num_rt_args(1 + args_size);
3955682Smarkm
4055682Smarkm  // push java thread (becomes first argument of C function)
4155682Smarkm  get_thread(thread);
4255682Smarkm  pushl(thread);
4355682Smarkm
4455682Smarkm  set_last_Java_frame(thread, noreg, rbp, NULL);
4555682Smarkm  // do the call
4655682Smarkm  call(RuntimeAddress(entry));
4755682Smarkm  int call_offset = offset();
4855682Smarkm  // verify callee-saved register
4955682Smarkm#ifdef ASSERT
5055682Smarkm  guarantee(thread != rax, "change this code");
5155682Smarkm  pushl(rax);
5255682Smarkm  { Label L;
5372445Sassar    get_thread(rax);
54178825Sdfr    cmpl(thread, rax);
5555682Smarkm    jcc(Assembler::equal, L);
5655682Smarkm    int3();
5755682Smarkm    stop("StubAssembler::call_RT: rdi not callee saved?");
5855682Smarkm    bind(L);
5955682Smarkm  }
6055682Smarkm  popl(rax);
6155682Smarkm#endif
6255682Smarkm  reset_last_Java_frame(thread, true, false);
6355682Smarkm
6455682Smarkm  // discard thread and arguments
6555682Smarkm  addl(rsp, (1 + args_size)*BytesPerWord);
6655682Smarkm
6755682Smarkm  // check for pending exceptions
68102644Snectar  { Label L;
6955682Smarkm    cmpl(Address(thread, Thread::pending_exception_offset()), NULL_WORD);
7055682Smarkm    jcc(Assembler::equal, L);
7155682Smarkm    // exception pending => remove activation and forward to exception handler
7255682Smarkm    movl(rax, Address(thread, Thread::pending_exception_offset()));
7355682Smarkm    // make sure that the vm_results are cleared
7455682Smarkm    if (oop_result1->is_valid()) {
7555682Smarkm      movl(Address(thread, JavaThread::vm_result_offset()), NULL_WORD);
7655682Smarkm    }
77178825Sdfr    if (oop_result2->is_valid()) {
7872445Sassar      movl(Address(thread, JavaThread::vm_result_2_offset()), NULL_WORD);
7972445Sassar    }
8072445Sassar    if (frame_size() == no_frame_size) {
8172445Sassar      leave();
8272445Sassar      jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
83178825Sdfr    } else if (_stub_id == Runtime1::forward_exception_id) {
8472445Sassar      should_not_reach_here();
8572445Sassar    } else {
8672445Sassar      jump(RuntimeAddress(Runtime1::entry_for(Runtime1::forward_exception_id)));
8772445Sassar    }
8872445Sassar    bind(L);
8972445Sassar  }
9072445Sassar  // get oop results if there are any and reset the values in the thread
9172445Sassar  if (oop_result1->is_valid()) {
9255682Smarkm    movl(oop_result1, Address(thread, JavaThread::vm_result_offset()));
9355682Smarkm    movl(Address(thread, JavaThread::vm_result_offset()), NULL_WORD);
9455682Smarkm    verify_oop(oop_result1);
9555682Smarkm  }
9655682Smarkm  if (oop_result2->is_valid()) {
9755682Smarkm    movl(oop_result2, Address(thread, JavaThread::vm_result_2_offset()));
9855682Smarkm    movl(Address(thread, JavaThread::vm_result_2_offset()), NULL_WORD);
9955682Smarkm    verify_oop(oop_result2);
10055682Smarkm  }
101178825Sdfr  return call_offset;
102233294Sstas}
103233294Sstas
104178825Sdfr
105233294Sstasint StubAssembler::call_RT(Register oop_result1, Register oop_result2, address entry, Register arg1) {
106178825Sdfr  pushl(arg1);
10755682Smarkm  return call_RT(oop_result1, oop_result2, entry, 1);
108233294Sstas}
109233294Sstas
110233294Sstas
11155682Smarkmint StubAssembler::call_RT(Register oop_result1, Register oop_result2, address entry, Register arg1, Register arg2) {
11255682Smarkm  pushl(arg2);
11355682Smarkm  pushl(arg1);
11455682Smarkm  return call_RT(oop_result1, oop_result2, entry, 2);
11572445Sassar}
11655682Smarkm
11755682Smarkm
11855682Smarkmint StubAssembler::call_RT(Register oop_result1, Register oop_result2, address entry, Register arg1, Register arg2, Register arg3) {
11955682Smarkm  pushl(arg3);
12055682Smarkm  pushl(arg2);
12155682Smarkm  pushl(arg1);
12255682Smarkm  return call_RT(oop_result1, oop_result2, entry, 3);
12355682Smarkm}
12472445Sassar
12572445Sassar
12672445Sassar// Implementation of StubFrame
12772445Sassar
12872445Sassarclass StubFrame: public StackObj {
12972445Sassar private:
130178825Sdfr  StubAssembler* _sasm;
13172445Sassar
13272445Sassar public:
13372445Sassar  StubFrame(StubAssembler* sasm, const char* name, bool must_gc_arguments);
13472445Sassar  void load_argument(int offset_in_words, Register reg);
13572445Sassar
13672445Sassar  ~StubFrame();
13772445Sassar};
13872445Sassar
13972445Sassar
14072445Sassar#define __ _sasm->
14172445Sassar
14272445SassarStubFrame::StubFrame(StubAssembler* sasm, const char* name, bool must_gc_arguments) {
14372445Sassar  _sasm = sasm;
14472445Sassar  __ set_info(name, must_gc_arguments);
14572445Sassar  __ enter();
14672445Sassar}
14772445Sassar
14872445Sassar// load parameters that were stored with LIR_Assembler::store_parameter
14955682Smarkm// Note: offsets for store_parameter and load_argument must match
15055682Smarkmvoid StubFrame::load_argument(int offset_in_words, Register reg) {
15155682Smarkm  // rbp, + 0: link
15255682Smarkm  //     + 1: return address
15355682Smarkm  //     + 2: argument with offset 0
15455682Smarkm  //     + 3: argument with offset 1
15555682Smarkm  //     + 4: ...
15655682Smarkm
15755682Smarkm  __ movl(reg, Address(rbp, (offset_in_words + 2) * BytesPerWord));
15855682Smarkm}
15955682Smarkm
16055682Smarkm
16155682SmarkmStubFrame::~StubFrame() {
16255682Smarkm  __ leave();
16355682Smarkm  __ ret(0);
16455682Smarkm}
16555682Smarkm
16655682Smarkm#undef __
16755682Smarkm
16855682Smarkm
16955682Smarkm// Implementation of Runtime1
17055682Smarkm
17155682Smarkm#define __ sasm->
17255682Smarkm
17355682Smarkmconst int float_regs_as_doubles_size_in_words = 16;
17455682Smarkmconst int xmm_regs_as_doubles_size_in_words = 16;
17555682Smarkm
17655682Smarkm// Stack layout for saving/restoring  all the registers needed during a runtime
17755682Smarkm// call (this includes deoptimization)
17855682Smarkm// Note: note that users of this frame may well have arguments to some runtime
17955682Smarkm// while these values are on the stack. These positions neglect those arguments
18055682Smarkm// but the code in save_live_registers will take the argument count into
18155682Smarkm// account.
18255682Smarkm//
18355682Smarkmenum reg_save_layout {
18455682Smarkm  dummy1,
18555682Smarkm  dummy2,
18655682Smarkm  // Two temps to be used as needed by users of save/restore callee registers
18755682Smarkm  temp_2_off,
18855682Smarkm  temp_1_off,
18955682Smarkm  xmm_regs_as_doubles_off,
19055682Smarkm  float_regs_as_doubles_off = xmm_regs_as_doubles_off + xmm_regs_as_doubles_size_in_words,
19155682Smarkm  fpu_state_off = float_regs_as_doubles_off + float_regs_as_doubles_size_in_words,
19255682Smarkm  fpu_state_end_off = fpu_state_off + FPUStateSizeInWords,
19355682Smarkm  marker = fpu_state_end_off,
19455682Smarkm  extra_space_offset,
19555682Smarkm  rdi_off = extra_space_offset,
196233294Sstas  rsi_off,
19755682Smarkm  rbp_off,
19855682Smarkm  rsp_off,
19955682Smarkm  rbx_off,
20055682Smarkm  rdx_off,
201233294Sstas  rcx_off,
20255682Smarkm  rax_off,
20355682Smarkm  saved_rbp_off,
20455682Smarkm  return_off,
20555682Smarkm  reg_save_frame_size,  // As noted: neglects any parameters to runtime
20655682Smarkm
20755682Smarkm  // equates
20855682Smarkm
209233294Sstas  // illegal instruction handler
21055682Smarkm  continue_dest_off = temp_1_off,
21155682Smarkm
21255682Smarkm  // deoptimization equates
213233294Sstas  fp0_off = float_regs_as_doubles_off, // slot for java float/double return value
21455682Smarkm  xmm0_off = xmm_regs_as_doubles_off,  // slot for java float/double return value
21555682Smarkm  deopt_type = temp_2_off,             // slot for type of deopt in progress
21655682Smarkm  ret_type = temp_1_off                // slot for return type
21755682Smarkm};
21855682Smarkm
21955682Smarkm
220233294Sstas
221233294Sstas// Save off registers which might be killed by calls into the runtime.
222233294Sstas// Tries to smart of about FP registers.  In particular we separate
223233294Sstas// saving and describing the FPU registers for deoptimization since we
224233294Sstas// have to save the FPU registers twice if we describe them and on P4
225233294Sstas// saving FPU registers which don't contain anything appears
226233294Sstas// expensive.  The deopt blob is the only thing which needs to
227233294Sstas// describe FPU registers.  In all other cases it should be sufficient
22855682Smarkm// to simply save their current value.
22955682Smarkm
23055682Smarkmstatic OopMap* generate_oop_map(StubAssembler* sasm, int num_rt_args,
23155682Smarkm                                bool save_fpu_registers = true) {
23255682Smarkm  int frame_size = reg_save_frame_size + num_rt_args; // args + thread
23355682Smarkm  sasm->set_frame_size(frame_size);
23455682Smarkm
23555682Smarkm  // record saved value locations in an OopMap
23655682Smarkm  // locations are offsets from sp after runtime call; num_rt_args is number of arguments in call, including thread
23755682Smarkm  OopMap* map = new OopMap(frame_size, 0);
23855682Smarkm  map->set_callee_saved(VMRegImpl::stack2reg(rax_off + num_rt_args), rax->as_VMReg());
23955682Smarkm  map->set_callee_saved(VMRegImpl::stack2reg(rcx_off + num_rt_args), rcx->as_VMReg());
24055682Smarkm  map->set_callee_saved(VMRegImpl::stack2reg(rdx_off + num_rt_args), rdx->as_VMReg());
24155682Smarkm  map->set_callee_saved(VMRegImpl::stack2reg(rbx_off + num_rt_args), rbx->as_VMReg());
24255682Smarkm  map->set_callee_saved(VMRegImpl::stack2reg(rsi_off + num_rt_args), rsi->as_VMReg());
24355682Smarkm  map->set_callee_saved(VMRegImpl::stack2reg(rdi_off + num_rt_args), rdi->as_VMReg());
24455682Smarkm
24555682Smarkm  if (save_fpu_registers) {
24655682Smarkm    if (UseSSE < 2) {
24755682Smarkm      int fpu_off = float_regs_as_doubles_off;
24855682Smarkm      for (int n = 0; n < FrameMap::nof_fpu_regs; n++) {
24955682Smarkm        VMReg fpu_name_0 = FrameMap::fpu_regname(n);
25055682Smarkm        map->set_callee_saved(VMRegImpl::stack2reg(fpu_off +     num_rt_args), fpu_name_0);
25155682Smarkm        // %%% This is really a waste but we'll keep things as they were for now
25255682Smarkm        if (true) {
25355682Smarkm          map->set_callee_saved(VMRegImpl::stack2reg(fpu_off + 1 + num_rt_args), fpu_name_0->next());
25455682Smarkm        }
25555682Smarkm        fpu_off += 2;
25655682Smarkm      }
25755682Smarkm      assert(fpu_off == fpu_state_off, "incorrect number of fpu stack slots");
25855682Smarkm    }
259102644Snectar
26055682Smarkm    if (UseSSE >= 2) {
26155682Smarkm      int xmm_off = xmm_regs_as_doubles_off;
26255682Smarkm      for (int n = 0; n < FrameMap::nof_xmm_regs; n++) {
26355682Smarkm        VMReg xmm_name_0 = as_XMMRegister(n)->as_VMReg();
26455682Smarkm        map->set_callee_saved(VMRegImpl::stack2reg(xmm_off +     num_rt_args), xmm_name_0);
26555682Smarkm        // %%% This is really a waste but we'll keep things as they were for now
26655682Smarkm        if (true) {
26755682Smarkm          map->set_callee_saved(VMRegImpl::stack2reg(xmm_off + 1 + num_rt_args), xmm_name_0->next());
26855682Smarkm        }
26955682Smarkm        xmm_off += 2;
27055682Smarkm      }
27155682Smarkm      assert(xmm_off == float_regs_as_doubles_off, "incorrect number of xmm registers");
27255682Smarkm
27355682Smarkm    } else if (UseSSE == 1) {
27455682Smarkm      int xmm_off = xmm_regs_as_doubles_off;
27555682Smarkm      for (int n = 0; n < FrameMap::nof_xmm_regs; n++) {
27655682Smarkm        VMReg xmm_name_0 = as_XMMRegister(n)->as_VMReg();
27755682Smarkm        map->set_callee_saved(VMRegImpl::stack2reg(xmm_off +     num_rt_args), xmm_name_0);
27855682Smarkm        xmm_off += 2;
27955682Smarkm      }
280178825Sdfr      assert(xmm_off == float_regs_as_doubles_off, "incorrect number of xmm registers");
28155682Smarkm    }
282178825Sdfr  }
283178825Sdfr
28455682Smarkm  return map;
28555682Smarkm}
28655682Smarkm
28755682Smarkmstatic OopMap* save_live_registers(StubAssembler* sasm, int num_rt_args,
288178825Sdfr                                   bool save_fpu_registers = true) {
28955682Smarkm  __ block_comment("save_live_registers");
290178825Sdfr
291178825Sdfr  int frame_size = reg_save_frame_size + num_rt_args; // args + thread
292120945Snectar  // frame_size = round_to(frame_size, 4);
293178825Sdfr  sasm->set_frame_size(frame_size);
294233294Sstas
295120945Snectar  __ pushad();         // integer registers
296178825Sdfr
297102644Snectar  // assert(float_regs_as_doubles_off % 2 == 0, "misaligned offset");
298178825Sdfr  // assert(xmm_regs_as_doubles_off % 2 == 0, "misaligned offset");
29955682Smarkm
300178825Sdfr  __ subl(rsp, extra_space_offset * wordSize);
301233294Sstas
302233294Sstas#ifdef ASSERT
30355682Smarkm  __ movl(Address(rsp, marker * wordSize), 0xfeedbeef);
304178825Sdfr#endif
305178825Sdfr
30655682Smarkm  if (save_fpu_registers) {
30755682Smarkm    if (UseSSE < 2) {
30855682Smarkm      // save FPU stack
30955682Smarkm      __ fnsave(Address(rsp, fpu_state_off * wordSize));
31055682Smarkm      __ fwait();
31155682Smarkm
31255682Smarkm#ifdef ASSERT
31355682Smarkm      Label ok;
31455682Smarkm      __ cmpw(Address(rsp, fpu_state_off * wordSize), StubRoutines::fpu_cntrl_wrd_std());
31555682Smarkm      __ jccb(Assembler::equal, ok);
31655682Smarkm      __ stop("corrupted control word detected");
31755682Smarkm      __ bind(ok);
31855682Smarkm#endif
31955682Smarkm
32055682Smarkm      // Reset the control word to guard against exceptions being unmasked
32155682Smarkm      // since fstp_d can cause FPU stack underflow exceptions.  Write it
32255682Smarkm      // into the on stack copy and then reload that to make sure that the
32355682Smarkm      // current and future values are correct.
32455682Smarkm      __ movw(Address(rsp, fpu_state_off * wordSize), StubRoutines::fpu_cntrl_wrd_std());
325178825Sdfr      __ frstor(Address(rsp, fpu_state_off * wordSize));
326178825Sdfr
32755682Smarkm      // Save the FPU registers in de-opt-able form
328178825Sdfr      __ fstp_d(Address(rsp, float_regs_as_doubles_off * BytesPerWord +  0));
329178825Sdfr      __ fstp_d(Address(rsp, float_regs_as_doubles_off * BytesPerWord +  8));
330178825Sdfr      __ fstp_d(Address(rsp, float_regs_as_doubles_off * BytesPerWord + 16));
331178825Sdfr      __ fstp_d(Address(rsp, float_regs_as_doubles_off * BytesPerWord + 24));
332178825Sdfr      __ fstp_d(Address(rsp, float_regs_as_doubles_off * BytesPerWord + 32));
333102644Snectar      __ fstp_d(Address(rsp, float_regs_as_doubles_off * BytesPerWord + 40));
334178825Sdfr      __ fstp_d(Address(rsp, float_regs_as_doubles_off * BytesPerWord + 48));
335178825Sdfr      __ fstp_d(Address(rsp, float_regs_as_doubles_off * BytesPerWord + 56));
336178825Sdfr    }
337102644Snectar
338102644Snectar    if (UseSSE >= 2) {
339178825Sdfr      // save XMM registers
340178825Sdfr      // XMM registers can contain float or double values, but this is not known here,
341178825Sdfr      // so always save them as doubles.
342102644Snectar      // note that float values are _not_ converted automatically, so for float values
343178825Sdfr      // the second word contains only garbage data.
344178825Sdfr      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * wordSize +  0), xmm0);
345178825Sdfr      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * wordSize +  8), xmm1);
34655682Smarkm      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * wordSize + 16), xmm2);
347178825Sdfr      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * wordSize + 24), xmm3);
348178825Sdfr      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * wordSize + 32), xmm4);
34955682Smarkm      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * wordSize + 40), xmm5);
35055682Smarkm      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * wordSize + 48), xmm6);
351178825Sdfr      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * wordSize + 56), xmm7);
35255682Smarkm    } else if (UseSSE == 1) {
353178825Sdfr      // save XMM registers as float because double not supported without SSE2
354178825Sdfr      __ movflt(Address(rsp, xmm_regs_as_doubles_off * wordSize +  0), xmm0);
35555682Smarkm      __ movflt(Address(rsp, xmm_regs_as_doubles_off * wordSize +  8), xmm1);
35655682Smarkm      __ movflt(Address(rsp, xmm_regs_as_doubles_off * wordSize + 16), xmm2);
35755682Smarkm      __ movflt(Address(rsp, xmm_regs_as_doubles_off * wordSize + 24), xmm3);
35855682Smarkm      __ movflt(Address(rsp, xmm_regs_as_doubles_off * wordSize + 32), xmm4);
35955682Smarkm      __ movflt(Address(rsp, xmm_regs_as_doubles_off * wordSize + 40), xmm5);
36055682Smarkm      __ movflt(Address(rsp, xmm_regs_as_doubles_off * wordSize + 48), xmm6);
36155682Smarkm      __ movflt(Address(rsp, xmm_regs_as_doubles_off * wordSize + 56), xmm7);
362178825Sdfr    }
36355682Smarkm  }
364178825Sdfr
365178825Sdfr  // FPU stack must be empty now
36655682Smarkm  __ verify_FPU(0, "save_live_registers");
36755682Smarkm
36855682Smarkm  return generate_oop_map(sasm, num_rt_args, save_fpu_registers);
369178825Sdfr}
37055682Smarkm
371178825Sdfr
372178825Sdfrstatic void restore_fpu(StubAssembler* sasm, bool restore_fpu_registers = true) {
373233294Sstas  if (restore_fpu_registers) {
374233294Sstas    if (UseSSE >= 2) {
375178825Sdfr      // restore XMM registers
376178825Sdfr      __ movdbl(xmm0, Address(rsp, xmm_regs_as_doubles_off * wordSize +  0));
37755682Smarkm      __ movdbl(xmm1, Address(rsp, xmm_regs_as_doubles_off * wordSize +  8));
378178825Sdfr      __ movdbl(xmm2, Address(rsp, xmm_regs_as_doubles_off * wordSize + 16));
379178825Sdfr      __ movdbl(xmm3, Address(rsp, xmm_regs_as_doubles_off * wordSize + 24));
38055682Smarkm      __ movdbl(xmm4, Address(rsp, xmm_regs_as_doubles_off * wordSize + 32));
38155682Smarkm      __ movdbl(xmm5, Address(rsp, xmm_regs_as_doubles_off * wordSize + 40));
38255682Smarkm      __ movdbl(xmm6, Address(rsp, xmm_regs_as_doubles_off * wordSize + 48));
38355682Smarkm      __ movdbl(xmm7, Address(rsp, xmm_regs_as_doubles_off * wordSize + 56));
38455682Smarkm    } else if (UseSSE == 1) {
38555682Smarkm      // restore XMM registers
38655682Smarkm      __ movflt(xmm0, Address(rsp, xmm_regs_as_doubles_off * wordSize +  0));
38755682Smarkm      __ movflt(xmm1, Address(rsp, xmm_regs_as_doubles_off * wordSize +  8));
38855682Smarkm      __ movflt(xmm2, Address(rsp, xmm_regs_as_doubles_off * wordSize + 16));
38955682Smarkm      __ movflt(xmm3, Address(rsp, xmm_regs_as_doubles_off * wordSize + 24));
39055682Smarkm      __ movflt(xmm4, Address(rsp, xmm_regs_as_doubles_off * wordSize + 32));
39155682Smarkm      __ movflt(xmm5, Address(rsp, xmm_regs_as_doubles_off * wordSize + 40));
39255682Smarkm      __ movflt(xmm6, Address(rsp, xmm_regs_as_doubles_off * wordSize + 48));
39355682Smarkm      __ movflt(xmm7, Address(rsp, xmm_regs_as_doubles_off * wordSize + 56));
39455682Smarkm    }
39555682Smarkm
39655682Smarkm    if (UseSSE < 2) {
39755682Smarkm      __ frstor(Address(rsp, fpu_state_off * wordSize));
39855682Smarkm    } else {
399178825Sdfr      // check that FPU stack is really empty
400178825Sdfr      __ verify_FPU(0, "restore_live_registers");
40155682Smarkm    }
40255682Smarkm
403178825Sdfr  } else {
404178825Sdfr    // check that FPU stack is really empty
405178825Sdfr    __ verify_FPU(0, "restore_live_registers");
40655682Smarkm  }
407178825Sdfr
408178825Sdfr#ifdef ASSERT
409178825Sdfr  {
410178825Sdfr    Label ok;
411178825Sdfr    __ cmpl(Address(rsp, marker * wordSize), 0xfeedbeef);
412178825Sdfr    __ jcc(Assembler::equal, ok);
413102644Snectar    __ stop("bad offsets in frame");
414178825Sdfr    __ bind(ok);
415178825Sdfr  }
416178825Sdfr#endif
417178825Sdfr
418102644Snectar  __ addl(rsp, extra_space_offset * wordSize);
419102644Snectar}
42055682Smarkm
421102644Snectar
422178825Sdfrstatic void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) {
423178825Sdfr  __ block_comment("restore_live_registers");
424178825Sdfr
425178825Sdfr  restore_fpu(sasm, restore_fpu_registers);
426102644Snectar  __ popad();
427178825Sdfr}
428178825Sdfr
429178825Sdfr
430178825Sdfrstatic void restore_live_registers_except_rax(StubAssembler* sasm, bool restore_fpu_registers = true) {
43155682Smarkm  __ block_comment("restore_live_registers_except_rax");
432178825Sdfr
433178825Sdfr  restore_fpu(sasm, restore_fpu_registers);
434178825Sdfr
43555682Smarkm  __ popl(rdi);
436178825Sdfr  __ popl(rsi);
437178825Sdfr  __ popl(rbp);
43855682Smarkm  __ popl(rbx); // skip this value
439178825Sdfr  __ popl(rbx);
440178825Sdfr  __ popl(rdx);
441178825Sdfr  __ popl(rcx);
442178825Sdfr  __ addl(rsp, 4);
443178825Sdfr}
444178825Sdfr
445178825Sdfr
44655682Smarkmvoid Runtime1::initialize_pd() {
44755682Smarkm  // nothing to do
44855682Smarkm}
44955682Smarkm
45055682Smarkm
45155682Smarkm// target: the entry point of the method that creates and posts the exception oop
45255682Smarkm// has_argument: true if the exception needs an argument (passed on stack because registers must be preserved)
453178825Sdfr
45455682SmarkmOopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address target, bool has_argument) {
455178825Sdfr  // preserve all registers
456178825Sdfr  int num_rt_args = has_argument ? 2 : 1;
45755682Smarkm  OopMap* oop_map = save_live_registers(sasm, num_rt_args);
45855682Smarkm
45955682Smarkm  // now all registers are saved and can be used freely
46055682Smarkm  // verify that no old value is used accidentally
461178825Sdfr  __ invalidate_registers(true, true, true, true, true, true);
46255682Smarkm
46355682Smarkm  // registers used by this stub
46455682Smarkm  const Register temp_reg = rbx;
46555682Smarkm
466178825Sdfr  // load argument for exception that is passed as an argument into the stub
467178825Sdfr  if (has_argument) {
468102644Snectar    __ movl(temp_reg, Address(rbp, 2*BytesPerWord));
469178825Sdfr    __ pushl(temp_reg);
470178825Sdfr  }
471233294Sstas
472233294Sstas  int call_offset = __ call_RT(noreg, noreg, target, num_rt_args - 1);
473178825Sdfr
474178825Sdfr  OopMapSet* oop_maps = new OopMapSet();
475102644Snectar  oop_maps->add_gc_map(call_offset, oop_map);
47655682Smarkm
477120945Snectar  __ stop("should not reach here");
478120945Snectar
479120945Snectar  return oop_maps;
480120945Snectar}
481120945Snectar
482102644Snectar
483178825Sdfrvoid Runtime1::generate_handle_exception(StubAssembler *sasm, OopMapSet* oop_maps, OopMap* oop_map, bool save_fpu_registers) {
48455682Smarkm  // incoming parameters
48555682Smarkm  const Register exception_oop = rax;
48655682Smarkm  const Register exception_pc = rdx;
48755682Smarkm  // other registers used in this stub
48855682Smarkm  const Register real_return_addr = rbx;
489233294Sstas  const Register thread = rdi;
490178825Sdfr
49155682Smarkm  __ block_comment("generate_handle_exception");
49255682Smarkm
49355682Smarkm#ifdef TIERED
49455682Smarkm  // C2 can leave the fpu stack dirty
49555682Smarkm  if (UseSSE < 2 ) {
496178825Sdfr    __ empty_FPU_stack();
49755682Smarkm  }
49855682Smarkm#endif // TIERED
49955682Smarkm
50055682Smarkm  // verify that only rax, and rdx is valid at this time
50155682Smarkm  __ invalidate_registers(false, true, true, false, true, true);
50255682Smarkm  // verify that rax, contains a valid exception
50355682Smarkm  __ verify_not_null_oop(exception_oop);
50455682Smarkm
50555682Smarkm  // load address of JavaThread object for thread-local data
50655682Smarkm  __ get_thread(thread);
50755682Smarkm
50855682Smarkm#ifdef ASSERT
509178825Sdfr  // check that fields in JavaThread for exception oop and issuing pc are
51055682Smarkm  // empty before writing to them
51155682Smarkm  Label oop_empty;
51255682Smarkm  __ cmpl(Address(thread, JavaThread::exception_oop_offset()), 0);
51355682Smarkm  __ jcc(Assembler::equal, oop_empty);
514178825Sdfr  __ stop("exception oop already set");
51555682Smarkm  __ bind(oop_empty);
51655682Smarkm
517178825Sdfr  Label pc_empty;
518178825Sdfr  __ cmpl(Address(thread, JavaThread::exception_pc_offset()), 0);
51955682Smarkm  __ jcc(Assembler::equal, pc_empty);
52055682Smarkm  __ stop("exception pc already set");
521178825Sdfr  __ bind(pc_empty);
522178825Sdfr#endif
523178825Sdfr
52455682Smarkm  // save exception oop and issuing pc into JavaThread
525178825Sdfr  // (exception handler will load it from here)
526178825Sdfr  __ movl(Address(thread, JavaThread::exception_oop_offset()), exception_oop);
527178825Sdfr  __ movl(Address(thread, JavaThread::exception_pc_offset()), exception_pc);
52855682Smarkm
529178825Sdfr  // save real return address (pc that called this stub)
530178825Sdfr  __ movl(real_return_addr, Address(rbp, 1*BytesPerWord));
531178825Sdfr  __ movl(Address(rsp, temp_1_off * BytesPerWord), real_return_addr);
532178825Sdfr
533178825Sdfr  // patch throwing pc into return address (has bci & oop map)
534178825Sdfr  __ movl(Address(rbp, 1*BytesPerWord), exception_pc);
535102644Snectar
536178825Sdfr  // compute the exception handler.
537178825Sdfr  // the exception oop and the throwing pc are read from the fields in JavaThread
538178825Sdfr  int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc));
539178825Sdfr  oop_maps->add_gc_map(call_offset, oop_map);
54055682Smarkm
541178825Sdfr  // rax,: handler address or NULL if no handler exists
542178825Sdfr  //      will be the deopt blob if nmethod was deoptimized while we looked up
54355682Smarkm  //      handler regardless of whether handler existed in the nmethod.
544178825Sdfr
545178825Sdfr  // only rax, is valid at this time, all other registers have been destroyed by the runtime call
546178825Sdfr  __ invalidate_registers(false, true, true, true, true, true);
54755682Smarkm
548178825Sdfr  // Do we have an exception handler in the nmethod?
549178825Sdfr  Label no_handler;
550178825Sdfr  Label done;
551178825Sdfr  __ testl(rax, rax);
55255682Smarkm  __ jcc(Assembler::zero, no_handler);
55355682Smarkm
55455682Smarkm  // exception handler found
55555682Smarkm  // patch the return address -> the stub will directly return to the exception handler
55655682Smarkm  __ movl(Address(rbp, 1*BytesPerWord), rax);
55755682Smarkm
55855682Smarkm  // restore registers
559178825Sdfr  restore_live_registers(sasm, save_fpu_registers);
56055682Smarkm
561178825Sdfr  // return to exception handler
562178825Sdfr  __ leave();
56355682Smarkm  __ ret(0);
56455682Smarkm
56555682Smarkm  __ bind(no_handler);
56655682Smarkm  // no exception handler found in this method, so the exception is
56755682Smarkm  // forwarded to the caller (using the unwind code of the nmethod)
568178825Sdfr  // there is no need to restore the registers
56955682Smarkm
570178825Sdfr  // restore the real return address that was saved before the RT-call
571178825Sdfr  __ movl(real_return_addr, Address(rsp, temp_1_off * BytesPerWord));
57255682Smarkm  __ movl(Address(rbp, 1*BytesPerWord), real_return_addr);
57355682Smarkm
574120945Snectar  // load address of JavaThread object for thread-local data
575178825Sdfr  __ get_thread(thread);
576233294Sstas  // restore exception oop into rax, (convention for unwind code)
577120945Snectar  __ movl(exception_oop, Address(thread, JavaThread::exception_oop_offset()));
578178825Sdfr
579102644Snectar  // clear exception fields in JavaThread because they are no longer needed
580178825Sdfr  // (fields must be cleared because they are processed by GC otherwise)
58155682Smarkm  __ movl(Address(thread, JavaThread::exception_oop_offset()), NULL_WORD);
58255682Smarkm  __ movl(Address(thread, JavaThread::exception_pc_offset()), NULL_WORD);
58355682Smarkm
584178825Sdfr  // pop the stub frame off
585178825Sdfr  __ leave();
586233294Sstas
587233294Sstas  generate_unwind_exception(sasm);
588233294Sstas  __ stop("should not reach here");
58955682Smarkm}
590178825Sdfr
59155682Smarkm
592178825Sdfrvoid Runtime1::generate_unwind_exception(StubAssembler *sasm) {
593178825Sdfr  // incoming parameters
59472445Sassar  const Register exception_oop = rax;
595178825Sdfr  // other registers used in this stub
596178825Sdfr  const Register exception_pc = rdx;
597178825Sdfr  const Register handler_addr = rbx;
598178825Sdfr  const Register thread = rdi;
599233294Sstas
600178825Sdfr  // verify that only rax, is valid at this time
601178825Sdfr  __ invalidate_registers(false, true, true, true, true, true);
602178825Sdfr
603178825Sdfr#ifdef ASSERT
60472445Sassar  // check that fields in JavaThread for exception oop and issuing pc are empty
60555682Smarkm  __ get_thread(thread);
60655682Smarkm  Label oop_empty;
607178825Sdfr  __ cmpl(Address(thread, JavaThread::exception_oop_offset()), 0);
608178825Sdfr  __ jcc(Assembler::equal, oop_empty);
60972445Sassar  __ stop("exception oop must be empty");
610178825Sdfr  __ bind(oop_empty);
611178825Sdfr
612178825Sdfr  Label pc_empty;
613178825Sdfr  __ cmpl(Address(thread, JavaThread::exception_pc_offset()), 0);
614233294Sstas  __ jcc(Assembler::equal, pc_empty);
615178825Sdfr  __ stop("exception pc must be empty");
616178825Sdfr  __ bind(pc_empty);
617178825Sdfr#endif
618178825Sdfr
61972445Sassar  // clear the FPU stack in case any FPU results are left behind
62055682Smarkm  __ empty_FPU_stack();
62155682Smarkm
62255682Smarkm  // leave activation of nmethod
62355682Smarkm  __ leave();
62455682Smarkm  // store return address (is on top of stack after leave)
625178825Sdfr  __ movl(exception_pc, Address(rsp, 0));
62655682Smarkm
62755682Smarkm  __ verify_oop(exception_oop);
628178825Sdfr
629178825Sdfr  // save exception oop from rax, to stack before call
63072445Sassar  __ pushl(exception_oop);
631178825Sdfr
632178825Sdfr  // search the exception handler address of the caller (using the return address)
633178825Sdfr  __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), exception_pc);
634178825Sdfr  // rax,: exception handler address of the caller
635233294Sstas
636178825Sdfr  // only rax, is valid at this time, all other registers have been destroyed by the call
637178825Sdfr  __ invalidate_registers(false, true, true, true, true, true);
638178825Sdfr
639178825Sdfr  // move result of call into correct register
64072445Sassar  __ movl(handler_addr, rax);
64155682Smarkm
64255682Smarkm  // restore exception oop in rax, (required convention of exception handler)
643178825Sdfr  __ popl(exception_oop);
644178825Sdfr
645178825Sdfr  __ verify_oop(exception_oop);
646178825Sdfr
647233294Sstas  // get throwing pc (= return address).
648178825Sdfr  // rdx has been destroyed by the call, so it must be set again
649178825Sdfr  // the pop is also necessary to simulate the effect of a ret(0)
65055682Smarkm  __ popl(exception_pc);
651178825Sdfr
652178825Sdfr  // verify that that there is really a valid exception in rax,
653178825Sdfr  __ verify_not_null_oop(exception_oop);
654233294Sstas
655178825Sdfr  // continue at exception handler (return address removed)
656178825Sdfr  // note: do *not* remove arguments when unwinding the
65755682Smarkm  //       activation since the caller assumes having
65855682Smarkm  //       all arguments on the stack when entering the
659178825Sdfr  //       runtime to determine the exception handler
66055682Smarkm  //       (GC happens at call site with arguments!)
66155682Smarkm  // rax,: exception oop
66255682Smarkm  // rdx: throwing pc
66355682Smarkm  // rbx,: exception handler
66455682Smarkm  __ jmp(handler_addr);
66555682Smarkm}
66655682Smarkm
66755682Smarkm
66855682SmarkmOopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) {
66955682Smarkm  // use the maximum number of runtime-arguments here because it is difficult to
67055682Smarkm  // distinguish each RT-Call.
67155682Smarkm  // Note: This number affects also the RT-Call in generate_handle_exception because
67255682Smarkm  //       the oop-map is shared for all calls.
67355682Smarkm  const int num_rt_args = 2;  // thread + dummy
674178825Sdfr
675178825Sdfr  DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob();
67672445Sassar  assert(deopt_blob != NULL, "deoptimization blob must have been created");
677178825Sdfr
678178825Sdfr  OopMap* oop_map = save_live_registers(sasm, num_rt_args);
679178825Sdfr
680178825Sdfr  __ pushl(rax); // push dummy
681233294Sstas
682178825Sdfr  const Register thread = rdi; // is callee-saved register (Visual C++ calling conventions)
683178825Sdfr  // push java thread (becomes first argument of C function)
684178825Sdfr  __ get_thread(thread);
685178825Sdfr  __ pushl(thread);
68672445Sassar  __ set_last_Java_frame(thread, noreg, rbp, NULL);
68755682Smarkm  // do the call
68855682Smarkm  __ call(RuntimeAddress(target));
68955682Smarkm  OopMapSet* oop_maps = new OopMapSet();
69055682Smarkm  oop_maps->add_gc_map(__ offset(), oop_map);
69155682Smarkm  // verify callee-saved register
69255682Smarkm#ifdef ASSERT
69355682Smarkm  guarantee(thread != rax, "change this code");
69455682Smarkm  __ pushl(rax);
69555682Smarkm  { Label L;
69655682Smarkm    __ get_thread(rax);
69755682Smarkm    __ cmpl(thread, rax);
698178825Sdfr    __ jcc(Assembler::equal, L);
699233294Sstas    __ stop("StubAssembler::call_RT: rdi not callee saved?");
70055682Smarkm    __ bind(L);
701178825Sdfr  }
702178825Sdfr  __ popl(rax);
703178825Sdfr#endif
70455682Smarkm  __ reset_last_Java_frame(thread, true, false);
705178825Sdfr  __ popl(rcx); // discard thread arg
70655682Smarkm  __ popl(rcx); // discard dummy
707178825Sdfr
708178825Sdfr  // check for pending exceptions
709178825Sdfr  { Label L;
710233294Sstas    __ cmpl(Address(thread, Thread::pending_exception_offset()), NULL_WORD);
711178825Sdfr    __ jcc(Assembler::equal, L);
712178825Sdfr    // exception pending => remove activation and forward to exception handler
713178825Sdfr
714178825Sdfr    __ testl(rax, rax);                                   // have we deoptimized?
715178825Sdfr    __ jump_cc(Assembler::equal,
716178825Sdfr               RuntimeAddress(Runtime1::entry_for(Runtime1::forward_exception_id)));
717233294Sstas
718178825Sdfr    // the deopt blob expects exceptions in the special fields of
719178825Sdfr    // JavaThread, so copy and clear pending exception.
720178825Sdfr
72155682Smarkm    // load and clear pending exception
722178825Sdfr    __ movl(rax, Address(thread, Thread::pending_exception_offset()));
723178825Sdfr    __ movl(Address(thread, Thread::pending_exception_offset()), NULL_WORD);
724178825Sdfr
725178825Sdfr    // check that there is really a valid exception
726178825Sdfr    __ verify_not_null_oop(rax);
727178825Sdfr
728178825Sdfr    // load throwing pc: this is the return address of the stub
729178825Sdfr    __ movl(rdx, Address(rsp, return_off * BytesPerWord));
730178825Sdfr
731178825Sdfr#ifdef ASSERT
732233294Sstas    // check that fields in JavaThread for exception oop and issuing pc are empty
733178825Sdfr    Label oop_empty;
734178825Sdfr    __ cmpoop(Address(thread, JavaThread::exception_oop_offset()), 0);
735178825Sdfr    __ jcc(Assembler::equal, oop_empty);
736178825Sdfr    __ stop("exception oop must be empty");
737178825Sdfr    __ bind(oop_empty);
738178825Sdfr
739178825Sdfr    Label pc_empty;
740178825Sdfr    __ cmpl(Address(thread, JavaThread::exception_pc_offset()), 0);
741178825Sdfr    __ jcc(Assembler::equal, pc_empty);
742233294Sstas    __ stop("exception pc must be empty");
743178825Sdfr    __ bind(pc_empty);
744178825Sdfr#endif
74555682Smarkm
74655682Smarkm    // store exception oop and throwing pc to JavaThread
74755682Smarkm    __ movl(Address(thread, JavaThread::exception_oop_offset()), rax);
74855682Smarkm    __ movl(Address(thread, JavaThread::exception_pc_offset()), rdx);
74955682Smarkm
75055682Smarkm    restore_live_registers(sasm);
751178825Sdfr
75272445Sassar    __ leave();
75372445Sassar    __ addl(rsp, 4);  // remove return address from stack
75472445Sassar
75572445Sassar    // Forward the exception directly to deopt blob. We can blow no
75672445Sassar    // registers and must leave throwing pc on the stack.  A patch may
75772445Sassar    // have values live in registers so the entry point with the
75872445Sassar    // exception in tls.
75972445Sassar    __ jump(RuntimeAddress(deopt_blob->unpack_with_exception_in_tls()));
76072445Sassar
76172445Sassar    __ bind(L);
76272445Sassar  }
76372445Sassar
76472445Sassar
76572445Sassar  // Runtime will return true if the nmethod has been deoptimized during
76672445Sassar  // the patching process. In that case we must do a deopt reexecute instead.
76772445Sassar
76872445Sassar  Label reexecuteEntry, cont;
76972445Sassar
77072445Sassar  __ testl(rax, rax);                                   // have we deoptimized?
77172445Sassar  __ jcc(Assembler::equal, cont);                       // no
77272445Sassar
77372445Sassar  // Will reexecute. Proper return address is already on the stack we just restore
77472445Sassar  // registers, pop all of our frame but the return address and jump to the deopt blob
77572445Sassar  restore_live_registers(sasm);
776178825Sdfr  __ leave();
77772445Sassar  __ jump(RuntimeAddress(deopt_blob->unpack_with_reexecution()));
77872445Sassar
77972445Sassar  __ bind(cont);
78072445Sassar  restore_live_registers(sasm);
78172445Sassar  __ leave();
78272445Sassar  __ ret(0);
78372445Sassar
784178825Sdfr  return oop_maps;
78572445Sassar
786178825Sdfr}
787178825Sdfr
78872445Sassar
78972445SassarOopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
79072445Sassar
79172445Sassar  // for better readability
79272445Sassar  const bool must_gc_arguments = true;
79372445Sassar  const bool dont_gc_arguments = false;
79455682Smarkm
79555682Smarkm  // default value; overwritten for some optimized stubs that are called from methods that do not use the fpu
79655682Smarkm  bool save_fpu_registers = true;
79755682Smarkm
79855682Smarkm  // stub code & info for the different stubs
79955682Smarkm  OopMapSet* oop_maps = NULL;
800178825Sdfr  switch (id) {
80155682Smarkm    case forward_exception_id:
80255682Smarkm      {
803178825Sdfr        // we're handling an exception in the context of a compiled
804178825Sdfr        // frame.  The registers have been saved in the standard
805178825Sdfr        // places.  Perform an exception lookup in the caller and
806178825Sdfr        // dispatch to the handler if found.  Otherwise unwind and
80755682Smarkm        // dispatch to the callers exception handler.
80855682Smarkm
80955682Smarkm        const Register thread = rdi;
81055682Smarkm        const Register exception_oop = rax;
81155682Smarkm        const Register exception_pc = rdx;
81255682Smarkm
81355682Smarkm        // load pending exception oop into rax,
814178825Sdfr        __ movl(exception_oop, Address(thread, Thread::pending_exception_offset()));
81555682Smarkm        // clear pending exception
81655682Smarkm        __ movl(Address(thread, Thread::pending_exception_offset()), NULL_WORD);
81755682Smarkm
81855682Smarkm        // load issuing PC (the return address for this stub) into rdx
81955682Smarkm        __ movl(exception_pc, Address(rbp, 1*BytesPerWord));
82055682Smarkm
821178825Sdfr        // make sure that the vm_results are cleared (may be unnecessary)
822178825Sdfr        __ movl(Address(thread, JavaThread::vm_result_offset()), NULL_WORD);
823178825Sdfr        __ movl(Address(thread, JavaThread::vm_result_2_offset()), NULL_WORD);
824178825Sdfr
825178825Sdfr        // verify that that there is really a valid exception in rax,
826178825Sdfr        __ verify_not_null_oop(exception_oop);
827178825Sdfr
82855682Smarkm
829178825Sdfr        oop_maps = new OopMapSet();
83055682Smarkm        OopMap* oop_map = generate_oop_map(sasm, 1);
83155682Smarkm        generate_handle_exception(sasm, oop_maps, oop_map);
83255682Smarkm        __ stop("should not reach here");
83355682Smarkm      }
83455682Smarkm      break;
83555682Smarkm
83655682Smarkm    case new_instance_id:
83755682Smarkm    case fast_new_instance_id:
83855682Smarkm    case fast_new_instance_init_check_id:
83955682Smarkm      {
84055682Smarkm        Register klass = rdx; // Incoming
84155682Smarkm        Register obj   = rax; // Result
84255682Smarkm
843102644Snectar        if (id == new_instance_id) {
84455682Smarkm          __ set_info("new_instance", dont_gc_arguments);
84555682Smarkm        } else if (id == fast_new_instance_id) {
84655682Smarkm          __ set_info("fast new_instance", dont_gc_arguments);
84755682Smarkm        } else {
84855682Smarkm          assert(id == fast_new_instance_init_check_id, "bad StubID");
849233294Sstas          __ set_info("fast new_instance init check", dont_gc_arguments);
850233294Sstas        }
851233294Sstas
852178825Sdfr        if ((id == fast_new_instance_id || id == fast_new_instance_init_check_id) &&
85355682Smarkm            UseTLAB && FastTLABRefill) {
85455682Smarkm          Label slow_path;
85555682Smarkm          Register obj_size = rcx;
856178825Sdfr          Register t1       = rbx;
857178825Sdfr          Register t2       = rsi;
858178825Sdfr          assert_different_registers(klass, obj, obj_size, t1, t2);
85955682Smarkm
86055682Smarkm          __ pushl(rdi);
861178825Sdfr          __ pushl(rbx);
86255682Smarkm
863178825Sdfr          if (id == fast_new_instance_init_check_id) {
864178825Sdfr            // make sure the klass is initialized
86555682Smarkm            __ cmpl(Address(klass, instanceKlass::init_state_offset_in_bytes() + sizeof(oopDesc)), instanceKlass::fully_initialized);
86655682Smarkm            __ jcc(Assembler::notEqual, slow_path);
867178825Sdfr          }
868178825Sdfr
869102644Snectar#ifdef ASSERT
870178825Sdfr          // assert object can be fast path allocated
871178825Sdfr          {
872178825Sdfr            Label ok, not_ok;
87355682Smarkm            __ movl(obj_size, Address(klass, Klass::layout_helper_offset_in_bytes() + sizeof(oopDesc)));
874178825Sdfr            __ cmpl(obj_size, 0);  // make sure it's an instance (LH > 0)
875233294Sstas            __ jcc(Assembler::lessEqual, not_ok);
876233294Sstas            __ testl(obj_size, Klass::_lh_instance_slow_path_bit);
87755682Smarkm            __ jcc(Assembler::zero, ok);
87855682Smarkm            __ bind(not_ok);
879102644Snectar            __ stop("assert(can be fast path allocated)");
880178825Sdfr            __ should_not_reach_here();
881178825Sdfr            __ bind(ok);
882178825Sdfr          }
883233294Sstas#endif // ASSERT
884178825Sdfr
885233294Sstas          // if we got here then the TLAB allocation failed, so try
886233294Sstas          // refilling the TLAB or allocating directly from eden.
887233294Sstas          Label retry_tlab, try_eden;
888233294Sstas          __ tlab_refill(retry_tlab, try_eden, slow_path); // does not destroy rdx (klass)
889233294Sstas
890233294Sstas          __ bind(retry_tlab);
891178825Sdfr
892178825Sdfr          // get the instance size
893178825Sdfr          __ movl(obj_size, Address(klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes()));
894178825Sdfr          __ tlab_allocate(obj, obj_size, 0, t1, t2, slow_path);
895178825Sdfr          __ initialize_object(obj, klass, obj_size, 0, t1, t2);
89655682Smarkm          __ verify_oop(obj);
897178825Sdfr          __ popl(rbx);
898233294Sstas          __ popl(rdi);
899233294Sstas          __ ret(0);
90055682Smarkm
901178825Sdfr          __ bind(try_eden);
902178825Sdfr          // get the instance size
903178825Sdfr          __ movl(obj_size, Address(klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes()));
904233294Sstas          __ eden_allocate(obj, obj_size, 0, t1, slow_path);
905178825Sdfr          __ initialize_object(obj, klass, obj_size, 0, t1, t2);
906233294Sstas          __ verify_oop(obj);
907233294Sstas          __ popl(rbx);
908233294Sstas          __ popl(rdi);
909178825Sdfr          __ ret(0);
910178825Sdfr
91155682Smarkm          __ bind(slow_path);
912178825Sdfr          __ popl(rbx);
913178825Sdfr          __ popl(rdi);
914178825Sdfr        }
915233294Sstas
916233294Sstas        __ enter();
917178825Sdfr        OopMap* map = save_live_registers(sasm, 2);
91855682Smarkm        int call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_instance), klass);
91955682Smarkm        oop_maps = new OopMapSet();
92055682Smarkm        oop_maps->add_gc_map(call_offset, map);
92155682Smarkm        restore_live_registers_except_rax(sasm);
92255682Smarkm        __ verify_oop(obj);
92355682Smarkm        __ leave();
92455682Smarkm        __ ret(0);
92555682Smarkm
92655682Smarkm        // rax,: new instance
927178825Sdfr      }
928178825Sdfr
92955682Smarkm      break;
93055682Smarkm
93155682Smarkm#ifdef TIERED
93255682Smarkm    case counter_overflow_id:
93355682Smarkm      {
93455682Smarkm        Register bci = rax;
93555682Smarkm        __ enter();
93655682Smarkm        OopMap* map = save_live_registers(sasm, 2);
93755682Smarkm        // Retrieve bci
93855682Smarkm        __ movl(bci, Address(rbp, 2*BytesPerWord));
93955682Smarkm        int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, counter_overflow), bci);
94072445Sassar        oop_maps = new OopMapSet();
94172445Sassar        oop_maps->add_gc_map(call_offset, map);
94255682Smarkm        restore_live_registers(sasm);
943233294Sstas        __ leave();
944233294Sstas        __ ret(0);
94555682Smarkm      }
94655682Smarkm      break;
94755682Smarkm#endif // TIERED
94872445Sassar
94972445Sassar    case new_type_array_id:
95072445Sassar    case new_object_array_id:
95172445Sassar      {
95272445Sassar        Register length   = rbx; // Incoming
95372445Sassar        Register klass    = rdx; // Incoming
95472445Sassar        Register obj      = rax; // Result
95572445Sassar
95672445Sassar        if (id == new_type_array_id) {
957178825Sdfr          __ set_info("new_type_array", dont_gc_arguments);
95872445Sassar        } else {
95972445Sassar          __ set_info("new_object_array", dont_gc_arguments);
96072445Sassar        }
96172445Sassar
96272445Sassar#ifdef ASSERT
96372445Sassar        // assert object type is really an array of the proper kind
96472445Sassar        {
96572445Sassar          Label ok;
96672445Sassar          Register t0 = obj;
96772445Sassar          __ movl(t0, Address(klass, Klass::layout_helper_offset_in_bytes() + sizeof(oopDesc)));
96872445Sassar          __ sarl(t0, Klass::_lh_array_tag_shift);
96972445Sassar          int tag = ((id == new_type_array_id)
97072445Sassar                     ? Klass::_lh_array_tag_type_value
971178825Sdfr                     : Klass::_lh_array_tag_obj_value);
97272445Sassar          __ cmpl(t0, tag);
97372445Sassar          __ jcc(Assembler::equal, ok);
97472445Sassar          __ stop("assert(is an array klass)");
97572445Sassar          __ should_not_reach_here();
97672445Sassar          __ bind(ok);
97772445Sassar        }
97872445Sassar#endif // ASSERT
97972445Sassar
98072445Sassar        if (UseTLAB && FastTLABRefill) {
98172445Sassar          Register arr_size = rsi;
98272445Sassar          Register t1       = rcx;  // must be rcx for use as shift count
98372445Sassar          Register t2       = rdi;
98472445Sassar          Label slow_path;
985178825Sdfr          assert_different_registers(length, klass, obj, arr_size, t1, t2);
986233294Sstas
987233294Sstas          // check that array length is small enough for fast path.
988178825Sdfr          __ cmpl(length, C1_MacroAssembler::max_array_allocation_length);
989178825Sdfr          __ jcc(Assembler::above, slow_path);
990178825Sdfr
991178825Sdfr          // if we got here then the TLAB allocation failed, so try
992178825Sdfr          // refilling the TLAB or allocating directly from eden.
993178825Sdfr          Label retry_tlab, try_eden;
994178825Sdfr          __ tlab_refill(retry_tlab, try_eden, slow_path); // preserves rbx, & rdx
995178825Sdfr
996178825Sdfr          __ bind(retry_tlab);
997178825Sdfr
998178825Sdfr          // get the allocation size: round_up(hdr + length << (layout_helper & 0x1F))
999178825Sdfr          __ movl(t1, Address(klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes()));
1000178825Sdfr          __ movl(arr_size, length);
1001178825Sdfr          assert(t1 == rcx, "fixed register usage");
1002178825Sdfr          __ shll(arr_size /* by t1=rcx, mod 32 */);
1003178825Sdfr          __ shrl(t1, Klass::_lh_header_size_shift);
1004178825Sdfr          __ andl(t1, Klass::_lh_header_size_mask);
1005178825Sdfr          __ addl(arr_size, t1);
1006233294Sstas          __ addl(arr_size, MinObjAlignmentInBytesMask); // align up
1007233294Sstas          __ andl(arr_size, ~MinObjAlignmentInBytesMask);
1008233294Sstas
1009233294Sstas          __ tlab_allocate(obj, arr_size, 0, t1, t2, slow_path);  // preserves arr_size
1010233294Sstas
1011233294Sstas          __ initialize_header(obj, klass, length, t1, t2);
1012233294Sstas          __ movb(t1, Address(klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes() + (Klass::_lh_header_size_shift / BitsPerByte)));
1013233294Sstas          assert(Klass::_lh_header_size_shift % BitsPerByte == 0, "bytewise");
1014233294Sstas          assert(Klass::_lh_header_size_mask <= 0xFF, "bytewise");
1015233294Sstas          __ andl(t1, Klass::_lh_header_size_mask);
1016233294Sstas          __ subl(arr_size, t1);  // body length
1017233294Sstas          __ addl(t1, obj);       // body start
1018233294Sstas          __ initialize_body(t1, arr_size, 0, t2);
1019233294Sstas          __ verify_oop(obj);
1020233294Sstas          __ ret(0);
1021233294Sstas
1022233294Sstas          __ bind(try_eden);
1023233294Sstas          // get the allocation size: round_up(hdr + length << (layout_helper & 0x1F))
1024233294Sstas          __ movl(t1, Address(klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes()));
1025233294Sstas          __ movl(arr_size, length);
1026233294Sstas          assert(t1 == rcx, "fixed register usage");
1027233294Sstas          __ shll(arr_size /* by t1=rcx, mod 32 */);
1028233294Sstas          __ shrl(t1, Klass::_lh_header_size_shift);
1029233294Sstas          __ andl(t1, Klass::_lh_header_size_mask);
1030233294Sstas          __ addl(arr_size, t1);
1031233294Sstas          __ addl(arr_size, MinObjAlignmentInBytesMask); // align up
1032233294Sstas          __ andl(arr_size, ~MinObjAlignmentInBytesMask);
1033233294Sstas
1034233294Sstas          __ eden_allocate(obj, arr_size, 0, t1, slow_path);  // preserves arr_size
1035233294Sstas
1036233294Sstas          __ initialize_header(obj, klass, length, t1, t2);
1037233294Sstas          __ movb(t1, Address(klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes() + (Klass::_lh_header_size_shift / BitsPerByte)));
1038233294Sstas          assert(Klass::_lh_header_size_shift % BitsPerByte == 0, "bytewise");
1039233294Sstas          assert(Klass::_lh_header_size_mask <= 0xFF, "bytewise");
1040233294Sstas          __ andl(t1, Klass::_lh_header_size_mask);
1041233294Sstas          __ subl(arr_size, t1);  // body length
1042233294Sstas          __ addl(t1, obj);       // body start
1043233294Sstas          __ initialize_body(t1, arr_size, 0, t2);
1044233294Sstas          __ verify_oop(obj);
1045233294Sstas          __ ret(0);
1046233294Sstas
1047233294Sstas          __ bind(slow_path);
1048233294Sstas        }
1049233294Sstas
1050233294Sstas        __ enter();
1051233294Sstas        OopMap* map = save_live_registers(sasm, 3);
1052233294Sstas        int call_offset;
1053233294Sstas        if (id == new_type_array_id) {
1054233294Sstas          call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_type_array), klass, length);
1055233294Sstas        } else {
1056233294Sstas          call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_object_array), klass, length);
1057233294Sstas        }
1058
1059        oop_maps = new OopMapSet();
1060        oop_maps->add_gc_map(call_offset, map);
1061        restore_live_registers_except_rax(sasm);
1062
1063        __ verify_oop(obj);
1064        __ leave();
1065        __ ret(0);
1066
1067        // rax,: new array
1068      }
1069      break;
1070
1071    case new_multi_array_id:
1072      { StubFrame f(sasm, "new_multi_array", dont_gc_arguments);
1073        // rax,: klass
1074        // rbx,: rank
1075        // rcx: address of 1st dimension
1076        OopMap* map = save_live_registers(sasm, 4);
1077        int call_offset = __ call_RT(rax, noreg, CAST_FROM_FN_PTR(address, new_multi_array), rax, rbx, rcx);
1078
1079        oop_maps = new OopMapSet();
1080        oop_maps->add_gc_map(call_offset, map);
1081        restore_live_registers_except_rax(sasm);
1082
1083        // rax,: new multi array
1084        __ verify_oop(rax);
1085      }
1086      break;
1087
1088    case register_finalizer_id:
1089      {
1090        __ set_info("register_finalizer", dont_gc_arguments);
1091
1092        // The object is passed on the stack and we haven't pushed a
1093        // frame yet so it's one work away from top of stack.
1094        __ movl(rax, Address(rsp, 1 * BytesPerWord));
1095        __ verify_oop(rax);
1096
1097        // load the klass and check the has finalizer flag
1098        Label register_finalizer;
1099        Register t = rsi;
1100        __ movl(t, Address(rax, oopDesc::klass_offset_in_bytes()));
1101        __ movl(t, Address(t, Klass::access_flags_offset_in_bytes() + sizeof(oopDesc)));
1102        __ testl(t, JVM_ACC_HAS_FINALIZER);
1103        __ jcc(Assembler::notZero, register_finalizer);
1104        __ ret(0);
1105
1106        __ bind(register_finalizer);
1107        __ enter();
1108        OopMap* oop_map = save_live_registers(sasm, 2 /*num_rt_args */);
1109        int call_offset = __ call_RT(noreg, noreg,
1110                                     CAST_FROM_FN_PTR(address, SharedRuntime::register_finalizer), rax);
1111        oop_maps = new OopMapSet();
1112        oop_maps->add_gc_map(call_offset, oop_map);
1113
1114        // Now restore all the live registers
1115        restore_live_registers(sasm);
1116
1117        __ leave();
1118        __ ret(0);
1119      }
1120      break;
1121
1122    case throw_range_check_failed_id:
1123      { StubFrame f(sasm, "range_check_failed", dont_gc_arguments);
1124        oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), true);
1125      }
1126      break;
1127
1128    case throw_index_exception_id:
1129      { StubFrame f(sasm, "index_range_check_failed", dont_gc_arguments);
1130        oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception), true);
1131      }
1132      break;
1133
1134    case throw_div0_exception_id:
1135      { StubFrame f(sasm, "throw_div0_exception", dont_gc_arguments);
1136        oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false);
1137      }
1138      break;
1139
1140    case throw_null_pointer_exception_id:
1141      { StubFrame f(sasm, "throw_null_pointer_exception", dont_gc_arguments);
1142        oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false);
1143      }
1144      break;
1145
1146    case handle_exception_nofpu_id:
1147      save_fpu_registers = false;
1148      // fall through
1149    case handle_exception_id:
1150      { StubFrame f(sasm, "handle_exception", dont_gc_arguments);
1151        oop_maps = new OopMapSet();
1152        OopMap* oop_map = save_live_registers(sasm, 1, save_fpu_registers);
1153        generate_handle_exception(sasm, oop_maps, oop_map, save_fpu_registers);
1154      }
1155      break;
1156
1157    case unwind_exception_id:
1158      { __ set_info("unwind_exception", dont_gc_arguments);
1159        // note: no stubframe since we are about to leave the current
1160        //       activation and we are calling a leaf VM function only.
1161        generate_unwind_exception(sasm);
1162      }
1163      break;
1164
1165    case throw_array_store_exception_id:
1166      { StubFrame f(sasm, "throw_array_store_exception", dont_gc_arguments);
1167        // tos + 0: link
1168        //     + 1: return address
1169        oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_array_store_exception), false);
1170      }
1171      break;
1172
1173    case throw_class_cast_exception_id:
1174      { StubFrame f(sasm, "throw_class_cast_exception", dont_gc_arguments);
1175        oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true);
1176      }
1177      break;
1178
1179    case throw_incompatible_class_change_error_id:
1180      { StubFrame f(sasm, "throw_incompatible_class_cast_exception", dont_gc_arguments);
1181        oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false);
1182      }
1183      break;
1184
1185    case slow_subtype_check_id:
1186      {
1187        enum layout {
1188          rax_off,
1189          rcx_off,
1190          rsi_off,
1191          rdi_off,
1192          saved_rbp_off,
1193          return_off,
1194          sub_off,
1195          super_off,
1196          framesize
1197        };
1198
1199        __ set_info("slow_subtype_check", dont_gc_arguments);
1200        __ pushl(rdi);
1201        __ pushl(rsi);
1202        __ pushl(rcx);
1203        __ pushl(rax);
1204        __ movl(rsi, Address(rsp, (super_off - 1) * BytesPerWord)); // super
1205        __ movl(rax, Address(rsp, (sub_off   - 1) * BytesPerWord)); // sub
1206
1207        __ movl(rdi,Address(rsi,sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes()));
1208        __ movl(rcx,Address(rdi,arrayOopDesc::length_offset_in_bytes()));
1209        __ addl(rdi,arrayOopDesc::base_offset_in_bytes(T_OBJECT));
1210
1211        Label miss;
1212        __ repne_scan();
1213        __ jcc(Assembler::notEqual, miss);
1214        __ movl(Address(rsi,sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()), rax);
1215        __ movl(Address(rsp, (super_off   - 1) * BytesPerWord), 1); // result
1216        __ popl(rax);
1217        __ popl(rcx);
1218        __ popl(rsi);
1219        __ popl(rdi);
1220        __ ret(0);
1221
1222        __ bind(miss);
1223        __ movl(Address(rsp, (super_off   - 1) * BytesPerWord), 0); // result
1224        __ popl(rax);
1225        __ popl(rcx);
1226        __ popl(rsi);
1227        __ popl(rdi);
1228        __ ret(0);
1229      }
1230      break;
1231
1232    case monitorenter_nofpu_id:
1233      save_fpu_registers = false;
1234      // fall through
1235    case monitorenter_id:
1236      {
1237        StubFrame f(sasm, "monitorenter", dont_gc_arguments);
1238        OopMap* map = save_live_registers(sasm, 3, save_fpu_registers);
1239
1240        f.load_argument(1, rax); // rax,: object
1241        f.load_argument(0, rbx); // rbx,: lock address
1242
1243        int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorenter), rax, rbx);
1244
1245        oop_maps = new OopMapSet();
1246        oop_maps->add_gc_map(call_offset, map);
1247        restore_live_registers(sasm, save_fpu_registers);
1248      }
1249      break;
1250
1251    case monitorexit_nofpu_id:
1252      save_fpu_registers = false;
1253      // fall through
1254    case monitorexit_id:
1255      {
1256        StubFrame f(sasm, "monitorexit", dont_gc_arguments);
1257        OopMap* map = save_live_registers(sasm, 2, save_fpu_registers);
1258
1259        f.load_argument(0, rax); // rax,: lock address
1260
1261        // note: really a leaf routine but must setup last java sp
1262        //       => use call_RT for now (speed can be improved by
1263        //       doing last java sp setup manually)
1264        int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorexit), rax);
1265
1266        oop_maps = new OopMapSet();
1267        oop_maps->add_gc_map(call_offset, map);
1268        restore_live_registers(sasm, save_fpu_registers);
1269
1270      }
1271      break;
1272
1273    case access_field_patching_id:
1274      { StubFrame f(sasm, "access_field_patching", dont_gc_arguments);
1275        // we should set up register map
1276        oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching));
1277      }
1278      break;
1279
1280    case load_klass_patching_id:
1281      { StubFrame f(sasm, "load_klass_patching", dont_gc_arguments);
1282        // we should set up register map
1283        oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_klass_patching));
1284      }
1285      break;
1286
1287    case jvmti_exception_throw_id:
1288      { // rax,: exception oop
1289        StubFrame f(sasm, "jvmti_exception_throw", dont_gc_arguments);
1290        // Preserve all registers across this potentially blocking call
1291        const int num_rt_args = 2;  // thread, exception oop
1292        OopMap* map = save_live_registers(sasm, num_rt_args);
1293        int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, Runtime1::post_jvmti_exception_throw), rax);
1294        oop_maps = new OopMapSet();
1295        oop_maps->add_gc_map(call_offset, map);
1296        restore_live_registers(sasm);
1297      }
1298      break;
1299
1300    case dtrace_object_alloc_id:
1301      { // rax,: object
1302        StubFrame f(sasm, "dtrace_object_alloc", dont_gc_arguments);
1303        // we can't gc here so skip the oopmap but make sure that all
1304        // the live registers get saved.
1305        save_live_registers(sasm, 1);
1306
1307        __ pushl(rax);
1308        __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc)));
1309        __ popl(rax);
1310
1311        restore_live_registers(sasm);
1312      }
1313      break;
1314
1315    case fpu2long_stub_id:
1316      {
1317        // rax, and rdx are destroyed, but should be free since the result is returned there
1318        // preserve rsi,ecx
1319        __ pushl(rsi);
1320        __ pushl(rcx);
1321
1322        // check for NaN
1323        Label return0, do_return, return_min_jlong, do_convert;
1324
1325        Address value_high_word(rsp, 8);
1326        Address value_low_word(rsp, 4);
1327        Address result_high_word(rsp, 16);
1328        Address result_low_word(rsp, 12);
1329
1330        __ subl(rsp, 20);
1331        __ fst_d(value_low_word);
1332        __ movl(rax, value_high_word);
1333        __ andl(rax, 0x7ff00000);
1334        __ cmpl(rax, 0x7ff00000);
1335        __ jcc(Assembler::notEqual, do_convert);
1336        __ movl(rax, value_high_word);
1337        __ andl(rax, 0xfffff);
1338        __ orl(rax, value_low_word);
1339        __ jcc(Assembler::notZero, return0);
1340
1341        __ bind(do_convert);
1342        __ fnstcw(Address(rsp, 0));
1343        __ movzxw(rax, Address(rsp, 0));
1344        __ orl(rax, 0xc00);
1345        __ movw(Address(rsp, 2), rax);
1346        __ fldcw(Address(rsp, 2));
1347        __ fwait();
1348        __ fistp_d(result_low_word);
1349        __ fldcw(Address(rsp, 0));
1350        __ fwait();
1351        __ movl(rax, result_low_word);
1352        __ movl(rdx, result_high_word);
1353        __ movl(rcx, rax);
1354        // What the heck is the point of the next instruction???
1355        __ xorl(rcx, 0x0);
1356        __ movl(rsi, 0x80000000);
1357        __ xorl(rsi, rdx);
1358        __ orl(rcx, rsi);
1359        __ jcc(Assembler::notEqual, do_return);
1360        __ fldz();
1361        __ fcomp_d(value_low_word);
1362        __ fnstsw_ax();
1363        __ sahf();
1364        __ jcc(Assembler::above, return_min_jlong);
1365        // return max_jlong
1366        __ movl(rdx, 0x7fffffff);
1367        __ movl(rax, 0xffffffff);
1368        __ jmp(do_return);
1369
1370        __ bind(return_min_jlong);
1371        __ movl(rdx, 0x80000000);
1372        __ xorl(rax, rax);
1373        __ jmp(do_return);
1374
1375        __ bind(return0);
1376        __ fpop();
1377        __ xorl(rdx,rdx);
1378        __ xorl(rax,rax);
1379
1380        __ bind(do_return);
1381        __ addl(rsp, 20);
1382        __ popl(rcx);
1383        __ popl(rsi);
1384        __ ret(0);
1385      }
1386      break;
1387
1388    default:
1389      { StubFrame f(sasm, "unimplemented entry", dont_gc_arguments);
1390        __ movl(rax, (int)id);
1391        __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), rax);
1392        __ should_not_reach_here();
1393      }
1394      break;
1395  }
1396  return oop_maps;
1397}
1398
1399#undef __
1400