src/hotspot/cpu/aarch64/aarch64_call.cpp
changeset 57565 01bca26734bb
parent 57564 0a8436eda2fa
child 57566 ad84ae073248
equal deleted inserted replaced
57564:0a8436eda2fa 57565:01bca26734bb
     1 /*
       
     2  * Copyright (c) 2014, Red Hat Inc. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  *
       
    23  */
       
    24 
       
    25 #ifdef BUILTIN_SIM
       
    26 
       
    27 #include <stdio.h>
       
    28 #include <sys/types.h>
       
    29 #include "asm/macroAssembler.hpp"
       
    30 #include "asm/macroAssembler.inline.hpp"
       
    31 #include "runtime/sharedRuntime.hpp"
       
    32 #include "../../../../../../simulator/cpustate.hpp"
       
    33 #include "../../../../../../simulator/simulator.hpp"
       
    34 
       
    35 /*
       
    36  * a routine to initialise and enter ARM simulator execution when
       
    37  * calling into ARM code from x86 code.
       
    38  *
       
    39  * we maintain a simulator per-thread and provide it with 8 Mb of
       
    40  * stack space
       
    41  */
       
    42 #define SIM_STACK_SIZE (1024 * 1024) // in units of u_int64_t
       
    43 
       
    44 extern "C" u_int64_t get_alt_stack()
       
    45 {
       
    46   return AArch64Simulator::altStack();
       
    47 }
       
    48 
       
    49 extern "C" void setup_arm_sim(void *sp, u_int64_t calltype)
       
    50 {
       
    51   // n.b. this function runs on the simulator stack so as to avoid
       
    52   // simulator frames appearing in between VM x86 and ARM frames. note
       
    53   // that arfgument sp points to the old (VM) stack from which the
       
    54   // call into the sim was made. The stack switch and entry into this
       
    55   // routine is handled by x86 prolog code planted in the head of the
       
    56   // ARM code buffer which the sim is about to start executing (see
       
    57   // aarch64_linkage.S).
       
    58   //
       
    59   // The first ARM instruction in the buffer is identified by fnptr
       
    60   // stored at the top of the old stack. x86 register contents precede
       
    61   // fnptr. preceding that are the fp and return address of the VM
       
    62   // caller into ARM code. any extra, non-register arguments passed to
       
    63   // the linkage routine precede the fp (this is as per any normal x86
       
    64   // call wirth extra args).
       
    65   //
       
    66   // note that the sim creates Java frames on the Java stack just
       
    67   // above sp (i.e. directly above fnptr). it sets the sim FP register
       
    68   // to the pushed fp for the caller effectively eliding the register
       
    69   // data saved by the linkage routine.
       
    70   //
       
    71   // x86 register call arguments are loaded from the stack into ARM
       
    72   // call registers. if extra arguments occur preceding the x86
       
    73   // caller's fp then they are copied either into extra ARM registers
       
    74   // (ARM has 8 rather than 6 gp call registers) or up the stack
       
    75   // beyond the saved x86 registers so that they immediately precede
       
    76   // the ARM frame where the ARM calling convention expects them to
       
    77   // be.
       
    78   //
       
    79   // n.b. the number of register/stack values passed to the ARM code
       
    80   // is determined by calltype
       
    81   //
       
    82   // +--------+
       
    83   // | fnptr  |  <--- argument sp points here
       
    84   // +--------+  |
       
    85   // | rax    |  | return slot if we need to return a value
       
    86   // +--------+  |
       
    87   // | rdi    |  increasing
       
    88   // +--------+  address
       
    89   // | rsi    |  |
       
    90   // +--------+  V
       
    91   // | rdx    |
       
    92   // +--------+
       
    93   // | rcx    |
       
    94   // +--------+
       
    95   // | r8     |
       
    96   // +--------+
       
    97   // | r9     |
       
    98   // +--------+
       
    99   // | xmm0   |
       
   100   // +--------+
       
   101   // | xmm1   |
       
   102   // +--------+
       
   103   // | xmm2   |
       
   104   // +--------+
       
   105   // | xmm3   |
       
   106   // +--------+
       
   107   // | xmm4   |
       
   108   // +--------+
       
   109   // | xmm5   |
       
   110   // +--------+
       
   111   // | xmm6   |
       
   112   // +--------+
       
   113   // | xmm7   |
       
   114   // +--------+
       
   115   // | fp     |
       
   116   // +--------+
       
   117   // | caller |
       
   118   // | ret ip |
       
   119   // +--------+
       
   120   // | arg0   | <-- any extra call args start here
       
   121   // +--------+     offset = 18 * wordSize
       
   122   // | . . .  |     (i.e. 1 * calladdr + 1 * rax  + 6 * gp call regs
       
   123   //                      + 8 * fp call regs + 2 * frame words)
       
   124   //
       
   125   // we use a unique sim/stack per thread
       
   126   const int cursor2_offset = 18;
       
   127   const int fp_offset = 16;
       
   128   u_int64_t *cursor = (u_int64_t *)sp;
       
   129   u_int64_t *cursor2 = ((u_int64_t *)sp) + cursor2_offset;
       
   130   u_int64_t *fp = ((u_int64_t *)sp) + fp_offset;
       
   131   int gp_arg_count = calltype & 0xf;
       
   132   int fp_arg_count = (calltype >> 4) & 0xf;
       
   133   int return_type = (calltype >> 8) & 0x3;
       
   134   AArch64Simulator *sim = AArch64Simulator::get_current(UseSimulatorCache, DisableBCCheck);
       
   135   // save previous cpu state in case this is a recursive entry
       
   136   CPUState saveState = sim->getCPUState();
       
   137   // set up initial sim pc, sp and fp registers
       
   138   sim->init(*cursor++, (u_int64_t)sp, (u_int64_t)fp);
       
   139   u_int64_t *return_slot = cursor++;
       
   140 
       
   141   // if we need to pass the sim extra args on the stack then bump
       
   142   // the stack pointer now
       
   143   u_int64_t *cursor3 = (u_int64_t *)sim->getCPUState().xreg(SP, 1);
       
   144   if (gp_arg_count > 8) {
       
   145     cursor3 -= gp_arg_count - 8;
       
   146   }
       
   147   if (fp_arg_count > 8) {
       
   148     cursor3 -= fp_arg_count - 8;
       
   149   }
       
   150   sim->getCPUState().xreg(SP, 1) = (u_int64_t)(cursor3++);
       
   151 
       
   152   for (int i = 0; i < gp_arg_count; i++) {
       
   153     if (i < 6) {
       
   154       // copy saved register to sim register
       
   155       GReg reg = (GReg)i;
       
   156       sim->getCPUState().xreg(reg, 0) = *cursor++;
       
   157     } else if (i < 8) {
       
   158       // copy extra int arg to sim register
       
   159       GReg reg = (GReg)i;
       
   160       sim->getCPUState().xreg(reg, 0) = *cursor2++;
       
   161     } else {
       
   162       // copy extra fp arg to sim stack
       
   163       *cursor3++ = *cursor2++;
       
   164     }
       
   165   }
       
   166   for (int i = 0; i < fp_arg_count; i++) {
       
   167     if (i < 8) {
       
   168       // copy saved register to sim register
       
   169       GReg reg = (GReg)i;
       
   170       sim->getCPUState().xreg(reg, 0) = *cursor++;
       
   171     } else {
       
   172       // copy extra arg to sim stack
       
   173       *cursor3++ = *cursor2++;
       
   174     }
       
   175   }
       
   176   AArch64Simulator::status_t return_status = sim->run();
       
   177   if (return_status != AArch64Simulator::STATUS_RETURN){
       
   178     sim->simPrint0();
       
   179     fatal("invalid status returned from simulator.run()\n");
       
   180   }
       
   181   switch (return_type) {
       
   182   case MacroAssembler::ret_type_void:
       
   183   default:
       
   184     break;
       
   185   case MacroAssembler::ret_type_integral:
       
   186   // this overwrites the saved r0
       
   187     *return_slot = sim->getCPUState().xreg(R0, 0);
       
   188     break;
       
   189   case MacroAssembler::ret_type_float:
       
   190     *(float *)return_slot = sim->getCPUState().sreg(V0);
       
   191     break;
       
   192   case MacroAssembler::ret_type_double:
       
   193     *(double *)return_slot = sim->getCPUState().dreg(V0);
       
   194     break;
       
   195   }
       
   196   // restore incoimng cpu state
       
   197   sim->getCPUState() = saveState;
       
   198 }
       
   199 
       
   200 #endif