< 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"

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




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

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

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




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

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

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




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

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

3143 
3144 /**
3145  *  Arguments:
3146  *
3147  *  Input:
3148  *    c_rarg0   - x address
3149  *    c_rarg1   - x length
3150  *    c_rarg2   - y address
3151  *    c_rarg3   - y length
3152  * not Win64
3153  *    c_rarg4   - z address
3154  * Win64
3155  *    rsp+40    - z address
3156  */
3157 address StubGenerator::generate_multiplyToLen() {
3158   __ align(CodeEntryAlignment);
3159   StubGenStubId stub_id = StubGenStubId::multiplyToLen_id;
3160   StubCodeMark mark(this, stub_id);
3161   address start = __ pc();
3162 
3163   if (SCCache::load_stub(this, vmIntrinsics::_multiplyToLen, "multiplyToLen", start)) {
3164     return start;
3165   }
3166 
3167   // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...)
3168   // Unix:  rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...)
3169   const Register x     = rdi;
3170   const Register xlen  = rax;
3171   const Register y     = rsi;
3172   const Register ylen  = rcx;
3173   const Register z     = r8;
3174 
3175   // Next registers will be saved on stack in multiply_to_len().
3176   const Register tmp0  = r11;
3177   const Register tmp1  = r12;
3178   const Register tmp2  = r13;
3179   const Register tmp3  = r14;
3180   const Register tmp4  = r15;
3181   const Register tmp5  = rbx;
3182 
3183   BLOCK_COMMENT("Entry:");
3184   __ enter(); // required for proper stackwalking of RuntimeStub frame
3185 
3186   setup_arg_regs(4); // x => rdi, xlen => rsi, y => rdx
3187                      // ylen => rcx, z => r8
3188                      // r9 and r10 may be used to save non-volatile registers
3189 #ifdef _WIN64
3190   // last argument (#4) is on stack on Win64
3191   __ movptr(z, Address(rsp, 6 * wordSize));
3192 #endif
3193 
3194   __ movptr(xlen, rsi);
3195   __ movptr(y,    rdx);
3196   __ multiply_to_len(x, xlen, y, ylen, z, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
3197 
3198   restore_arg_regs();
3199 
3200   __ leave(); // required for proper stackwalking of RuntimeStub frame
3201   __ ret(0);
3202 
3203   SCCache::store_stub(this, vmIntrinsics::_multiplyToLen, "multiplyToLen", start);
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   if (SCCache::load_stub(this, vmIntrinsics::_squareToLen, "squareToLen", start)) {
3278     return start;
3279   }
3280 
3281   // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...)
3282   // Unix:  rdi, rsi, rdx, rcx (c_rarg0, c_rarg1, ...)
3283   const Register x      = rdi;
3284   const Register len    = rsi;
3285   const Register z      = r8;
3286   const Register zlen   = rcx;
3287 
3288  const Register tmp1      = r12;
3289  const Register tmp2      = r13;
3290  const Register tmp3      = r14;
3291  const Register tmp4      = r15;
3292  const Register tmp5      = rbx;
3293 
3294   BLOCK_COMMENT("Entry:");
3295   __ enter(); // required for proper stackwalking of RuntimeStub frame
3296 
3297   setup_arg_regs(4); // x => rdi, len => rsi, z => rdx
3298                      // zlen => rcx
3299                      // r9 and r10 may be used to save non-volatile registers
3300   __ movptr(r8, rdx);
3301   __ square_to_len(x, len, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, rdx, rax);
3302 
3303   restore_arg_regs();
3304 
3305   __ leave(); // required for proper stackwalking of RuntimeStub frame
3306   __ ret(0);
3307 
3308   SCCache::store_stub(this, vmIntrinsics::_squareToLen, "squareToLen", start);
3309   return start;
3310 }
3311 
3312 address StubGenerator::generate_method_entry_barrier() {
3313   __ align(CodeEntryAlignment);
3314   StubGenStubId stub_id = StubGenStubId::method_entry_barrier_id;
3315   StubCodeMark mark(this, stub_id);
3316   address start = __ pc();
3317 
3318   Label deoptimize_label;
3319 
3320   __ push(-1); // cookie, this is used for writing the new rsp when deoptimizing
3321 
3322   BLOCK_COMMENT("Entry:");
3323   __ enter(); // save rbp
3324 
3325   // save c_rarg0, because we want to use that value.
3326   // We could do without it but then we depend on the number of slots used by pusha
3327   __ push(c_rarg0);
3328 

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