< prev index next >

src/hotspot/cpu/x86/stubGenerator_x86_64.cpp

Print this page

   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 #include "asm/macroAssembler.hpp"
  26 #include "classfile/javaClasses.hpp"
  27 #include "classfile/vmIntrinsics.hpp"

  28 #include "compiler/oopMap.hpp"
  29 #include "gc/shared/barrierSet.hpp"
  30 #include "gc/shared/barrierSetAssembler.hpp"
  31 #include "gc/shared/barrierSetNMethod.hpp"
  32 #include "gc/shared/gc_globals.hpp"
  33 #include "memory/universe.hpp"
  34 #include "prims/jvmtiExport.hpp"
  35 #include "prims/upcallLinker.hpp"
  36 #include "runtime/arguments.hpp"
  37 #include "runtime/continuationEntry.hpp"
  38 #include "runtime/javaThread.hpp"
  39 #include "runtime/sharedRuntime.hpp"
  40 #include "runtime/stubRoutines.hpp"
  41 #include "stubGenerator_x86_64.hpp"
  42 #ifdef COMPILER2
  43 #include "opto/runtime.hpp"
  44 #include "opto/c2_globals.hpp"
  45 #endif
  46 #if INCLUDE_JVMCI
  47 #include "jvmci/jvmci_globals.hpp"

3148 
3149 /**
3150  *  Arguments:
3151  *
3152  *  Input:
3153  *    c_rarg0   - x address
3154  *    c_rarg1   - x length
3155  *    c_rarg2   - y address
3156  *    c_rarg3   - y length
3157  * not Win64
3158  *    c_rarg4   - z address
3159  * Win64
3160  *    rsp+40    - z address
3161  */
3162 address StubGenerator::generate_multiplyToLen() {
3163   __ align(CodeEntryAlignment);
3164   StubGenStubId stub_id = StubGenStubId::multiplyToLen_id;
3165   StubCodeMark mark(this, stub_id);
3166   address start = __ pc();
3167 




3168   // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...)
3169   // Unix:  rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...)
3170   const Register x     = rdi;
3171   const Register xlen  = rax;
3172   const Register y     = rsi;
3173   const Register ylen  = rcx;
3174   const Register z     = r8;
3175 
3176   // Next registers will be saved on stack in multiply_to_len().
3177   const Register tmp0  = r11;
3178   const Register tmp1  = r12;
3179   const Register tmp2  = r13;
3180   const Register tmp3  = r14;
3181   const Register tmp4  = r15;
3182   const Register tmp5  = rbx;
3183 
3184   BLOCK_COMMENT("Entry:");
3185   __ enter(); // required for proper stackwalking of RuntimeStub frame
3186 
3187   setup_arg_regs(4); // x => rdi, xlen => rsi, y => rdx
3188                      // ylen => rcx, z => r8
3189                      // r9 and r10 may be used to save non-volatile registers
3190 #ifdef _WIN64
3191   // last argument (#4) is on stack on Win64
3192   __ movptr(z, Address(rsp, 6 * wordSize));
3193 #endif
3194 
3195   __ movptr(xlen, rsi);
3196   __ movptr(y,    rdx);
3197   __ multiply_to_len(x, xlen, y, ylen, z, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
3198 
3199   restore_arg_regs();
3200 
3201   __ leave(); // required for proper stackwalking of RuntimeStub frame
3202   __ ret(0);
3203 

3204   return start;
3205 }
3206 
3207 /**
3208 *  Arguments:
3209 *
3210 *  Input:
3211 *    c_rarg0   - obja     address
3212 *    c_rarg1   - objb     address
3213 *    c_rarg3   - length   length
3214 *    c_rarg4   - scale    log2_array_indxscale
3215 *
3216 *  Output:
3217 *        rax   - int >= mismatched index, < 0 bitwise complement of tail
3218 */
3219 address StubGenerator::generate_vectorizedMismatch() {
3220   __ align(CodeEntryAlignment);
3221   StubGenStubId stub_id = StubGenStubId::vectorizedMismatch_id;
3222   StubCodeMark mark(this, stub_id);
3223   address start = __ pc();

3257   return start;
3258 }
3259 
3260 /**
3261  *  Arguments:
3262  *
3263 //  Input:
3264 //    c_rarg0   - x address
3265 //    c_rarg1   - x length
3266 //    c_rarg2   - z address
3267 //    c_rarg3   - z length
3268  *
3269  */
3270 address StubGenerator::generate_squareToLen() {
3271 
3272   __ align(CodeEntryAlignment);
3273   StubGenStubId stub_id = StubGenStubId::squareToLen_id;
3274   StubCodeMark mark(this, stub_id);
3275   address start = __ pc();
3276 




3277   // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...)
3278   // Unix:  rdi, rsi, rdx, rcx (c_rarg0, c_rarg1, ...)
3279   const Register x      = rdi;
3280   const Register len    = rsi;
3281   const Register z      = r8;
3282   const Register zlen   = rcx;
3283 
3284  const Register tmp1      = r12;
3285  const Register tmp2      = r13;
3286  const Register tmp3      = r14;
3287  const Register tmp4      = r15;
3288  const Register tmp5      = rbx;
3289 
3290   BLOCK_COMMENT("Entry:");
3291   __ enter(); // required for proper stackwalking of RuntimeStub frame
3292 
3293   setup_arg_regs(4); // x => rdi, len => rsi, z => rdx
3294                      // zlen => rcx
3295                      // r9 and r10 may be used to save non-volatile registers
3296   __ movptr(r8, rdx);
3297   __ square_to_len(x, len, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, rdx, rax);
3298 
3299   restore_arg_regs();
3300 
3301   __ leave(); // required for proper stackwalking of RuntimeStub frame
3302   __ ret(0);
3303 

3304   return start;
3305 }
3306 
3307 address StubGenerator::generate_method_entry_barrier() {
3308   __ align(CodeEntryAlignment);
3309   StubGenStubId stub_id = StubGenStubId::method_entry_barrier_id;
3310   StubCodeMark mark(this, stub_id);
3311   address start = __ pc();
3312 
3313   Label deoptimize_label;
3314 
3315   __ push(-1); // cookie, this is used for writing the new rsp when deoptimizing
3316 
3317   BLOCK_COMMENT("Entry:");
3318   __ enter(); // save rbp
3319 
3320   // save c_rarg0, because we want to use that value.
3321   // We could do without it but then we depend on the number of slots used by pusha
3322   __ push(c_rarg0);
3323 

3383 
3384  /**
3385  *  Arguments:
3386  *
3387  *  Input:
3388  *    c_rarg0   - out address
3389  *    c_rarg1   - in address
3390  *    c_rarg2   - offset
3391  *    c_rarg3   - len
3392  * not Win64
3393  *    c_rarg4   - k
3394  * Win64
3395  *    rsp+40    - k
3396  */
3397 address StubGenerator::generate_mulAdd() {
3398   __ align(CodeEntryAlignment);
3399   StubGenStubId stub_id = StubGenStubId::mulAdd_id;
3400   StubCodeMark mark(this, stub_id);
3401   address start = __ pc();
3402 




3403   // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...)
3404   // Unix:  rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...)
3405   const Register out     = rdi;
3406   const Register in      = rsi;
3407   const Register offset  = r11;
3408   const Register len     = rcx;
3409   const Register k       = r8;
3410 
3411   // Next registers will be saved on stack in mul_add().
3412   const Register tmp1  = r12;
3413   const Register tmp2  = r13;
3414   const Register tmp3  = r14;
3415   const Register tmp4  = r15;
3416   const Register tmp5  = rbx;
3417 
3418   BLOCK_COMMENT("Entry:");
3419   __ enter(); // required for proper stackwalking of RuntimeStub frame
3420 
3421   setup_arg_regs(4); // out => rdi, in => rsi, offset => rdx
3422                      // len => rcx, k => r8
3423                      // r9 and r10 may be used to save non-volatile registers
3424 #ifdef _WIN64
3425   // last argument is on stack on Win64
3426   __ movl(k, Address(rsp, 6 * wordSize));
3427 #endif
3428   __ movptr(r11, rdx);  // move offset in rdx to offset(r11)
3429   __ mul_add(out, in, offset, len, k, tmp1, tmp2, tmp3, tmp4, tmp5, rdx, rax);
3430 
3431   restore_arg_regs();
3432 
3433   __ leave(); // required for proper stackwalking of RuntimeStub frame
3434   __ ret(0);
3435 

3436   return start;
3437 }
3438 
3439 address StubGenerator::generate_bigIntegerRightShift() {
3440   __ align(CodeEntryAlignment);
3441   StubGenStubId stub_id = StubGenStubId::bigIntegerRightShiftWorker_id;
3442   StubCodeMark mark(this, stub_id);
3443   address start = __ pc();
3444 
3445   Label Shift512Loop, ShiftTwo, ShiftTwoLoop, ShiftOne, Exit;
3446   // For Unix, the arguments are as follows: rdi, rsi, rdx, rcx, r8.
3447   const Register newArr = rdi;
3448   const Register oldArr = rsi;
3449   const Register newIdx = rdx;
3450   const Register shiftCount = rcx;  // It was intentional to have shiftCount in rcx since it is used implicitly for shift.
3451   const Register totalNumIter = r8;
3452 
3453   // For windows, we use r9 and r10 as temps to save rdi and rsi. Thus we cannot allocate them for our temps.
3454   // For everything else, we prefer using r9 and r10 since we do not have to save them before use.
3455   const Register tmp1 = r11;                    // Caller save.

   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 #include "asm/macroAssembler.hpp"
  26 #include "classfile/javaClasses.hpp"
  27 #include "classfile/vmIntrinsics.hpp"
  28 #include "code/SCCache.hpp"
  29 #include "compiler/oopMap.hpp"
  30 #include "gc/shared/barrierSet.hpp"
  31 #include "gc/shared/barrierSetAssembler.hpp"
  32 #include "gc/shared/barrierSetNMethod.hpp"
  33 #include "gc/shared/gc_globals.hpp"
  34 #include "memory/universe.hpp"
  35 #include "prims/jvmtiExport.hpp"
  36 #include "prims/upcallLinker.hpp"
  37 #include "runtime/arguments.hpp"
  38 #include "runtime/continuationEntry.hpp"
  39 #include "runtime/javaThread.hpp"
  40 #include "runtime/sharedRuntime.hpp"
  41 #include "runtime/stubRoutines.hpp"
  42 #include "stubGenerator_x86_64.hpp"
  43 #ifdef COMPILER2
  44 #include "opto/runtime.hpp"
  45 #include "opto/c2_globals.hpp"
  46 #endif
  47 #if INCLUDE_JVMCI
  48 #include "jvmci/jvmci_globals.hpp"

3149 
3150 /**
3151  *  Arguments:
3152  *
3153  *  Input:
3154  *    c_rarg0   - x address
3155  *    c_rarg1   - x length
3156  *    c_rarg2   - y address
3157  *    c_rarg3   - y length
3158  * not Win64
3159  *    c_rarg4   - z address
3160  * Win64
3161  *    rsp+40    - z address
3162  */
3163 address StubGenerator::generate_multiplyToLen() {
3164   __ align(CodeEntryAlignment);
3165   StubGenStubId stub_id = StubGenStubId::multiplyToLen_id;
3166   StubCodeMark mark(this, stub_id);
3167   address start = __ pc();
3168 
3169   if (SCCache::load_stub(this, vmIntrinsics::_multiplyToLen, "multiplyToLen", start)) {
3170     return start;
3171   }
3172 
3173   // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...)
3174   // Unix:  rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...)
3175   const Register x     = rdi;
3176   const Register xlen  = rax;
3177   const Register y     = rsi;
3178   const Register ylen  = rcx;
3179   const Register z     = r8;
3180 
3181   // Next registers will be saved on stack in multiply_to_len().
3182   const Register tmp0  = r11;
3183   const Register tmp1  = r12;
3184   const Register tmp2  = r13;
3185   const Register tmp3  = r14;
3186   const Register tmp4  = r15;
3187   const Register tmp5  = rbx;
3188 
3189   BLOCK_COMMENT("Entry:");
3190   __ enter(); // required for proper stackwalking of RuntimeStub frame
3191 
3192   setup_arg_regs(4); // x => rdi, xlen => rsi, y => rdx
3193                      // ylen => rcx, z => r8
3194                      // r9 and r10 may be used to save non-volatile registers
3195 #ifdef _WIN64
3196   // last argument (#4) is on stack on Win64
3197   __ movptr(z, Address(rsp, 6 * wordSize));
3198 #endif
3199 
3200   __ movptr(xlen, rsi);
3201   __ movptr(y,    rdx);
3202   __ multiply_to_len(x, xlen, y, ylen, z, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
3203 
3204   restore_arg_regs();
3205 
3206   __ leave(); // required for proper stackwalking of RuntimeStub frame
3207   __ ret(0);
3208 
3209   SCCache::store_stub(this, vmIntrinsics::_multiplyToLen, "multiplyToLen", start);
3210   return start;
3211 }
3212 
3213 /**
3214 *  Arguments:
3215 *
3216 *  Input:
3217 *    c_rarg0   - obja     address
3218 *    c_rarg1   - objb     address
3219 *    c_rarg3   - length   length
3220 *    c_rarg4   - scale    log2_array_indxscale
3221 *
3222 *  Output:
3223 *        rax   - int >= mismatched index, < 0 bitwise complement of tail
3224 */
3225 address StubGenerator::generate_vectorizedMismatch() {
3226   __ align(CodeEntryAlignment);
3227   StubGenStubId stub_id = StubGenStubId::vectorizedMismatch_id;
3228   StubCodeMark mark(this, stub_id);
3229   address start = __ pc();

3263   return start;
3264 }
3265 
3266 /**
3267  *  Arguments:
3268  *
3269 //  Input:
3270 //    c_rarg0   - x address
3271 //    c_rarg1   - x length
3272 //    c_rarg2   - z address
3273 //    c_rarg3   - z length
3274  *
3275  */
3276 address StubGenerator::generate_squareToLen() {
3277 
3278   __ align(CodeEntryAlignment);
3279   StubGenStubId stub_id = StubGenStubId::squareToLen_id;
3280   StubCodeMark mark(this, stub_id);
3281   address start = __ pc();
3282 
3283   if (SCCache::load_stub(this, vmIntrinsics::_squareToLen, "squareToLen", start)) {
3284     return start;
3285   }
3286 
3287   // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...)
3288   // Unix:  rdi, rsi, rdx, rcx (c_rarg0, c_rarg1, ...)
3289   const Register x      = rdi;
3290   const Register len    = rsi;
3291   const Register z      = r8;
3292   const Register zlen   = rcx;
3293 
3294  const Register tmp1      = r12;
3295  const Register tmp2      = r13;
3296  const Register tmp3      = r14;
3297  const Register tmp4      = r15;
3298  const Register tmp5      = rbx;
3299 
3300   BLOCK_COMMENT("Entry:");
3301   __ enter(); // required for proper stackwalking of RuntimeStub frame
3302 
3303   setup_arg_regs(4); // x => rdi, len => rsi, z => rdx
3304                      // zlen => rcx
3305                      // r9 and r10 may be used to save non-volatile registers
3306   __ movptr(r8, rdx);
3307   __ square_to_len(x, len, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, rdx, rax);
3308 
3309   restore_arg_regs();
3310 
3311   __ leave(); // required for proper stackwalking of RuntimeStub frame
3312   __ ret(0);
3313 
3314   SCCache::store_stub(this, vmIntrinsics::_squareToLen, "squareToLen", start);
3315   return start;
3316 }
3317 
3318 address StubGenerator::generate_method_entry_barrier() {
3319   __ align(CodeEntryAlignment);
3320   StubGenStubId stub_id = StubGenStubId::method_entry_barrier_id;
3321   StubCodeMark mark(this, stub_id);
3322   address start = __ pc();
3323 
3324   Label deoptimize_label;
3325 
3326   __ push(-1); // cookie, this is used for writing the new rsp when deoptimizing
3327 
3328   BLOCK_COMMENT("Entry:");
3329   __ enter(); // save rbp
3330 
3331   // save c_rarg0, because we want to use that value.
3332   // We could do without it but then we depend on the number of slots used by pusha
3333   __ push(c_rarg0);
3334 

3394 
3395  /**
3396  *  Arguments:
3397  *
3398  *  Input:
3399  *    c_rarg0   - out address
3400  *    c_rarg1   - in address
3401  *    c_rarg2   - offset
3402  *    c_rarg3   - len
3403  * not Win64
3404  *    c_rarg4   - k
3405  * Win64
3406  *    rsp+40    - k
3407  */
3408 address StubGenerator::generate_mulAdd() {
3409   __ align(CodeEntryAlignment);
3410   StubGenStubId stub_id = StubGenStubId::mulAdd_id;
3411   StubCodeMark mark(this, stub_id);
3412   address start = __ pc();
3413 
3414   if (SCCache::load_stub(this, vmIntrinsics::_mulAdd, "mulAdd", start)) {
3415     return start;
3416   }
3417 
3418   // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...)
3419   // Unix:  rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...)
3420   const Register out     = rdi;
3421   const Register in      = rsi;
3422   const Register offset  = r11;
3423   const Register len     = rcx;
3424   const Register k       = r8;
3425 
3426   // Next registers will be saved on stack in mul_add().
3427   const Register tmp1  = r12;
3428   const Register tmp2  = r13;
3429   const Register tmp3  = r14;
3430   const Register tmp4  = r15;
3431   const Register tmp5  = rbx;
3432 
3433   BLOCK_COMMENT("Entry:");
3434   __ enter(); // required for proper stackwalking of RuntimeStub frame
3435 
3436   setup_arg_regs(4); // out => rdi, in => rsi, offset => rdx
3437                      // len => rcx, k => r8
3438                      // r9 and r10 may be used to save non-volatile registers
3439 #ifdef _WIN64
3440   // last argument is on stack on Win64
3441   __ movl(k, Address(rsp, 6 * wordSize));
3442 #endif
3443   __ movptr(r11, rdx);  // move offset in rdx to offset(r11)
3444   __ mul_add(out, in, offset, len, k, tmp1, tmp2, tmp3, tmp4, tmp5, rdx, rax);
3445 
3446   restore_arg_regs();
3447 
3448   __ leave(); // required for proper stackwalking of RuntimeStub frame
3449   __ ret(0);
3450 
3451   SCCache::store_stub(this, vmIntrinsics::_mulAdd, "mulAdd", start);
3452   return start;
3453 }
3454 
3455 address StubGenerator::generate_bigIntegerRightShift() {
3456   __ align(CodeEntryAlignment);
3457   StubGenStubId stub_id = StubGenStubId::bigIntegerRightShiftWorker_id;
3458   StubCodeMark mark(this, stub_id);
3459   address start = __ pc();
3460 
3461   Label Shift512Loop, ShiftTwo, ShiftTwoLoop, ShiftOne, Exit;
3462   // For Unix, the arguments are as follows: rdi, rsi, rdx, rcx, r8.
3463   const Register newArr = rdi;
3464   const Register oldArr = rsi;
3465   const Register newIdx = rdx;
3466   const Register shiftCount = rcx;  // It was intentional to have shiftCount in rcx since it is used implicitly for shift.
3467   const Register totalNumIter = r8;
3468 
3469   // For windows, we use r9 and r10 as temps to save rdi and rsi. Thus we cannot allocate them for our temps.
3470   // For everything else, we prefer using r9 and r10 since we do not have to save them before use.
3471   const Register tmp1 = r11;                    // Caller save.
< prev index next >