Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/Java/Openjdk/src/hotspot/cpu/x86/   (Sun/Oracle ©)  Datei vom 29.11.2022 mit Größe 138 kB image not shown  

SSL stubGenerator_x86_64.cpp   Sprache: C

 
/*
 * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */


#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "classfile/vmIntrinsics.hpp"
#include "compiler/oopMap.hpp"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
#include "gc/shared/barrierSetNMethod.hpp"
#include "gc/shared/gc_globals.hpp"
#include "memory/universe.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/arguments.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "stubGenerator_x86_64.hpp"
#ifdef COMPILER2
#include "opto/runtime.hpp"
#include "opto/c2_globals.hpp"
#endif
#if INCLUDE_JVMCI
#include "jvmci/jvmci_globals.hpp"
#endif
#if INCLUDE_ZGC
#include "gc/z/zThreadLocalData.hpp"
#endif
#if INCLUDE_JFR
#include "jfr/support/jfrIntrinsics.hpp"
#endif

// For a more detailed description of the stub routine structure
// see the comment in stubRoutines.hpp

#define __ _masm->
#define TIMES_OOP (UseCompressedOops ? Address::times_4 : Address::times_8)

#ifdef PRODUCT
#define BLOCK_COMMENT(str) /* nothing */
#else
#define BLOCK_COMMENT(str) __ block_comment(str)
#endif // PRODUCT

#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")

//
// Linux Arguments:
//    c_rarg0:   call wrapper address                   address
//    c_rarg1:   result                                 address
//    c_rarg2:   result type                            BasicType
//    c_rarg3:   method                                 Method*
//    c_rarg4:   (interpreter) entry point              address
//    c_rarg5:   parameters                             intptr_t*
//    16(rbp): parameter size (in words)              int
//    24(rbp): thread                                 Thread*
//
//     [ return_from_Java     ] <--- rsp
//     [ argument word n      ]
//      ...
// -12 [ argument word 1      ]
// -11 [ saved r15            ] <--- rsp_after_call
// -10 [ saved r14            ]
//  -9 [ saved r13            ]
//  -8 [ saved r12            ]
//  -7 [ saved rbx            ]
//  -6 [ call wrapper         ]
//  -5 [ result               ]
//  -4 [ result type          ]
//  -3 [ method               ]
//  -2 [ entry point          ]
//  -1 [ parameters           ]
//   0 [ saved rbp            ] <--- rbp
//   1 [ return address       ]
//   2 [ parameter size       ]
//   3 [ thread               ]
//
// Windows Arguments:
//    c_rarg0:   call wrapper address                   address
//    c_rarg1:   result                                 address
//    c_rarg2:   result type                            BasicType
//    c_rarg3:   method                                 Method*
//    48(rbp): (interpreter) entry point              address
//    56(rbp): parameters                             intptr_t*
//    64(rbp): parameter size (in words)              int
//    72(rbp): thread                                 Thread*
//
//     [ return_from_Java     ] <--- rsp
//     [ argument word n      ]
//      ...
// -60 [ argument word 1      ]
// -59 [ saved xmm31          ] <--- rsp after_call
//     [ saved xmm16-xmm30    ] (EVEX enabled, else the space is blank)
// -27 [ saved xmm15          ]
//     [ saved xmm7-xmm14     ]
//  -9 [ saved xmm6           ] (each xmm register takes 2 slots)
//  -7 [ saved r15            ]
//  -6 [ saved r14            ]
//  -5 [ saved r13            ]
//  -4 [ saved r12            ]
//  -3 [ saved rdi            ]
//  -2 [ saved rsi            ]
//  -1 [ saved rbx            ]
//   0 [ saved rbp            ] <--- rbp
//   1 [ return address       ]
//   2 [ call wrapper         ]
//   3 [ result               ]
//   4 [ result type          ]
//   5 [ method               ]
//   6 [ entry point          ]
//   7 [ parameters           ]
//   8 [ parameter size       ]
//   9 [ thread               ]
//
//    Windows reserves the callers stack space for arguments 1-4.
//    We spill c_rarg0-c_rarg3 to this space.

// Call stub stack layout word offsets from rbp
#ifdef _WIN64
enum call_stub_layout {
  xmm_save_first     = 6,  // save from xmm6
  xmm_save_last      = 31, // to xmm31
  xmm_save_base      = -9,
  rsp_after_call_off = xmm_save_base - 2 * (xmm_save_last - xmm_save_first), // -27
  r15_off            = -7,
  r14_off            = -6,
  r13_off            = -5,
  r12_off            = -4,
  rdi_off            = -3,
  rsi_off            = -2,
  rbx_off            = -1,
  rbp_off            =  0,
  retaddr_off        =  1,
  call_wrapper_off   =  2,
  result_off         =  3,
  result_type_off    =  4,
  method_off         =  5,
  entry_point_off    =  6,
  parameters_off     =  7,
  parameter_size_off =  8,
  thread_off         =  9
};

static Address xmm_save(int reg) {
  assert(reg >= xmm_save_first && reg <= xmm_save_last, "XMM register number out of range");
  return Address(rbp, (xmm_save_base - (reg - xmm_save_first) * 2) * wordSize);
}
#else // !_WIN64
enum call_stub_layout {
  rsp_after_call_off = -12,
  mxcsr_off          = rsp_after_call_off,
  r15_off            = -11,
  r14_off            = -10,
  r13_off            = -9,
  r12_off            = -8,
  rbx_off            = -7,
  call_wrapper_off   = -6,
  result_off         = -5,
  result_type_off    = -4,
  method_off         = -3,
  entry_point_off    = -2,
  parameters_off     = -1,
  rbp_off            =  0,
  retaddr_off        =  1,
  parameter_size_off =  2,
  thread_off         =  3
};
#endif // _WIN64

address StubGenerator::generate_call_stub(address& return_address) {

  assert((int)frame::entry_frame_after_call_words == -(int)rsp_after_call_off + 1 &&
         (int)frame::entry_frame_call_wrapper_offset == (int)call_wrapper_off,
         "adjust this code");
  StubCodeMark mark(this"StubRoutines""call_stub");
  address start = __ pc();

  // same as in generate_catch_exception()!
  const Address rsp_after_call(rbp, rsp_after_call_off * wordSize);

  const Address call_wrapper  (rbp, call_wrapper_off   * wordSize);
  const Address result        (rbp, result_off         * wordSize);
  const Address result_type   (rbp, result_type_off    * wordSize);
  const Address method        (rbp, method_off         * wordSize);
  const Address entry_point   (rbp, entry_point_off    * wordSize);
  const Address parameters    (rbp, parameters_off     * wordSize);
  const Address parameter_size(rbp, parameter_size_off * wordSize);

  // same as in generate_catch_exception()!
  const Address thread        (rbp, thread_off         * wordSize);

  const Address r15_save(rbp, r15_off * wordSize);
  const Address r14_save(rbp, r14_off * wordSize);
  const Address r13_save(rbp, r13_off * wordSize);
  const Address r12_save(rbp, r12_off * wordSize);
  const Address rbx_save(rbp, rbx_off * wordSize);

  // stub code
  __ enter();
  __ subptr(rsp, -rsp_after_call_off * wordSize);

  // save register parameters
#ifndef _WIN64
  __ movptr(parameters,   c_rarg5); // parameters
  __ movptr(entry_point,  c_rarg4); // entry_point
#endif

  __ movptr(method,       c_rarg3); // method
  __ movl(result_type,  c_rarg2);   // result type
  __ movptr(result,       c_rarg1); // result
  __ movptr(call_wrapper, c_rarg0); // call wrapper

  // save regs belonging to calling function
  __ movptr(rbx_save, rbx);
  __ movptr(r12_save, r12);
  __ movptr(r13_save, r13);
  __ movptr(r14_save, r14);
  __ movptr(r15_save, r15);

#ifdef _WIN64
  int last_reg = 15;
  if (UseAVX > 2) {
    last_reg = 31;
  }
  if (VM_Version::supports_evex()) {
    for (int i = xmm_save_first; i <= last_reg; i++) {
      __ vextractf32x4(xmm_save(i), as_XMMRegister(i), 0);
    }
  } else {
    for (int i = xmm_save_first; i <= last_reg; i++) {
      __ movdqu(xmm_save(i), as_XMMRegister(i));
    }
  }

  const Address rdi_save(rbp, rdi_off * wordSize);
  const Address rsi_save(rbp, rsi_off * wordSize);

  __ movptr(rsi_save, rsi);
  __ movptr(rdi_save, rdi);
#else
  const Address mxcsr_save(rbp, mxcsr_off * wordSize);
  {
    Label skip_ldmx;
    __ stmxcsr(mxcsr_save);
    __ movl(rax, mxcsr_save);
    __ andl(rax, 0xFFC0); // Mask out any pending exceptions (only check control and mask bits)
    ExternalAddress mxcsr_std(StubRoutines::x86::addr_mxcsr_std());
    __ cmp32(rax, mxcsr_std, rscratch1);
    __ jcc(Assembler::equal, skip_ldmx);
    __ ldmxcsr(mxcsr_std, rscratch1);
    __ bind(skip_ldmx);
  }
#endif

  // Load up thread register
  __ movptr(r15_thread, thread);
  __ reinit_heapbase();

#ifdef ASSERT
  // make sure we have no pending exceptions
  {
    Label L;
    __ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), NULL_WORD);
    __ jcc(Assembler::equal, L);
    __ stop("StubRoutines::call_stub: entered with pending exception");
    __ bind(L);
  }
#endif

  // pass parameters if any
  BLOCK_COMMENT("pass parameters if any");
  Label parameters_done;
  __ movl(c_rarg3, parameter_size);
  __ testl(c_rarg3, c_rarg3);
  __ jcc(Assembler::zero, parameters_done);

  Label loop;
  __ movptr(c_rarg2, parameters);       // parameter pointer
  __ movl(c_rarg1, c_rarg3);            // parameter counter is in c_rarg1
  __ BIND(loop);
  __ movptr(rax, Address(c_rarg2, 0));// get parameter
  __ addptr(c_rarg2, wordSize);       // advance to next parameter
  __ decrementl(c_rarg1);             // decrement counter
  __ push(rax);                       // pass parameter
  __ jcc(Assembler::notZero, loop);

  // call Java function
  __ BIND(parameters_done);
  __ movptr(rbx, method);             // get Method*
  __ movptr(c_rarg1, entry_point);    // get entry_point
  __ mov(r13, rsp);                   // set sender sp
  BLOCK_COMMENT("call Java function");
  __ call(c_rarg1);

  BLOCK_COMMENT("call_stub_return_address:");
  return_address = __ pc();

  // store result depending on type (everything that is not
  // T_OBJECT, T_LONG, T_FLOAT or T_DOUBLE is treated as T_INT)
  __ movptr(c_rarg0, result);
  Label is_long, is_float, is_double, exit;
  __ movl(c_rarg1, result_type);
  __ cmpl(c_rarg1, T_OBJECT);
  __ jcc(Assembler::equal, is_long);
  __ cmpl(c_rarg1, T_LONG);
  __ jcc(Assembler::equal, is_long);
  __ cmpl(c_rarg1, T_FLOAT);
  __ jcc(Assembler::equal, is_float);
  __ cmpl(c_rarg1, T_DOUBLE);
  __ jcc(Assembler::equal, is_double);

  // handle T_INT case
  __ movl(Address(c_rarg0, 0), rax);

  __ BIND(exit);

  // pop parameters
  __ lea(rsp, rsp_after_call);

#ifdef ASSERT
  // verify that threads correspond
  {
   Label L1, L2, L3;
    __ cmpptr(r15_thread, thread);
    __ jcc(Assembler::equal, L1);
    __ stop("StubRoutines::call_stub: r15_thread is corrupted");
    __ bind(L1);
    __ get_thread(rbx);
    __ cmpptr(r15_thread, thread);
    __ jcc(Assembler::equal, L2);
    __ stop("StubRoutines::call_stub: r15_thread is modified by call");
    __ bind(L2);
    __ cmpptr(r15_thread, rbx);
    __ jcc(Assembler::equal, L3);
    __ stop("StubRoutines::call_stub: threads must correspond");
    __ bind(L3);
  }
#endif

  __ pop_cont_fastpath();

  // restore regs belonging to calling function
#ifdef _WIN64
  // emit the restores for xmm regs
  if (VM_Version::supports_evex()) {
    for (int i = xmm_save_first; i <= last_reg; i++) {
      __ vinsertf32x4(as_XMMRegister(i), as_XMMRegister(i), xmm_save(i), 0);
    }
  } else {
    for (int i = xmm_save_first; i <= last_reg; i++) {
      __ movdqu(as_XMMRegister(i), xmm_save(i));
    }
  }
#endif
  __ movptr(r15, r15_save);
  __ movptr(r14, r14_save);
  __ movptr(r13, r13_save);
  __ movptr(r12, r12_save);
  __ movptr(rbx, rbx_save);

#ifdef _WIN64
  __ movptr(rdi, rdi_save);
  __ movptr(rsi, rsi_save);
#else
  __ ldmxcsr(mxcsr_save);
#endif

  // restore rsp
  __ addptr(rsp, -rsp_after_call_off * wordSize);

  // return
  __ vzeroupper();
  __ pop(rbp);
  __ ret(0);

  // handle return types different from T_INT
  __ BIND(is_long);
  __ movq(Address(c_rarg0, 0), rax);
  __ jmp(exit);

  __ BIND(is_float);
  __ movflt(Address(c_rarg0, 0), xmm0);
  __ jmp(exit);

  __ BIND(is_double);
  __ movdbl(Address(c_rarg0, 0), xmm0);
  __ jmp(exit);

  return start;
}

// Return point for a Java call if there's an exception thrown in
// Java code.  The exception is caught and transformed into a
// pending exception stored in JavaThread that can be tested from
// within the VM.
//
// Note: Usually the parameters are removed by the callee. In case
// of an exception crossing an activation frame boundary, that is
// not the case if the callee is compiled code => need to setup the
// rsp.
//
// rax: exception oop

address StubGenerator::generate_catch_exception() {
  StubCodeMark mark(this"StubRoutines""catch_exception");
  address start = __ pc();

  // same as in generate_call_stub():
  const Address rsp_after_call(rbp, rsp_after_call_off * wordSize);
  const Address thread        (rbp, thread_off         * wordSize);

#ifdef ASSERT
  // verify that threads correspond
  {
    Label L1, L2, L3;
    __ cmpptr(r15_thread, thread);
    __ jcc(Assembler::equal, L1);
    __ stop("StubRoutines::catch_exception: r15_thread is corrupted");
    __ bind(L1);
    __ get_thread(rbx);
    __ cmpptr(r15_thread, thread);
    __ jcc(Assembler::equal, L2);
    __ stop("StubRoutines::catch_exception: r15_thread is modified by call");
    __ bind(L2);
    __ cmpptr(r15_thread, rbx);
    __ jcc(Assembler::equal, L3);
    __ stop("StubRoutines::catch_exception: threads must correspond");
    __ bind(L3);
  }
#endif

  // set pending exception
  __ verify_oop(rax);

  __ movptr(Address(r15_thread, Thread::pending_exception_offset()), rax);
  __ lea(rscratch1, ExternalAddress((address)__FILE__));
  __ movptr(Address(r15_thread, Thread::exception_file_offset()), rscratch1);
  __ movl(Address(r15_thread, Thread::exception_line_offset()), (int)  __LINE__);

  // complete return to VM
  assert(StubRoutines::_call_stub_return_address != NULL,
         "_call_stub_return_address must have been generated before");
  __ jump(RuntimeAddress(StubRoutines::_call_stub_return_address));

  return start;
}

// Continuation point for runtime calls returning with a pending
// exception.  The pending exception check happened in the runtime
// or native call stub.  The pending exception in Thread is
// converted into a Java-level exception.
//
// Contract with Java-level exception handlers:
// rax: exception
// rdx: throwing pc
//
// NOTE: At entry of this stub, exception-pc must be on stack !!

address StubGenerator::generate_forward_exception() {
  StubCodeMark mark(this"StubRoutines""forward exception");
  address start = __ pc();

  // Upon entry, the sp points to the return address returning into
  // Java (interpreted or compiled) code; i.e., the return address
  // becomes the throwing pc.
  //
  // Arguments pushed before the runtime call are still on the stack
  // but the exception handler will reset the stack pointer ->
  // ignore them.  A potential result in registers can be ignored as
  // well.

#ifdef ASSERT
  // make sure this code is only executed if there is a pending exception
  {
    Label L;
    __ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), NULL_WORD);
    __ jcc(Assembler::notEqual, L);
    __ stop("StubRoutines::forward exception: no pending exception (1)");
    __ bind(L);
  }
#endif

  // compute exception handler into rbx
  __ movptr(c_rarg0, Address(rsp, 0));
  BLOCK_COMMENT("call exception_handler_for_return_address");
  __ call_VM_leaf(CAST_FROM_FN_PTR(address,
                       SharedRuntime::exception_handler_for_return_address),
                  r15_thread, c_rarg0);
  __ mov(rbx, rax);

  // setup rax & rdx, remove return address & clear pending exception
  __ pop(rdx);
  __ movptr(rax, Address(r15_thread, Thread::pending_exception_offset()));
  __ movptr(Address(r15_thread, Thread::pending_exception_offset()), NULL_WORD);

#ifdef ASSERT
  // make sure exception is set
  {
    Label L;
    __ testptr(rax, rax);
    __ jcc(Assembler::notEqual, L);
    __ stop("StubRoutines::forward exception: no pending exception (2)");
    __ bind(L);
  }
#endif

  // continue at exception handler (return address removed)
  // rax: exception
  // rbx: exception handler
  // rdx: throwing pc
  __ verify_oop(rax);
  __ jmp(rbx);

  return start;
}

// Support for intptr_t OrderAccess::fence()
//
// Arguments :
//
// Result:
address StubGenerator::generate_orderaccess_fence() {
  StubCodeMark mark(this"StubRoutines""orderaccess_fence");
  address start = __ pc();

  __ membar(Assembler::StoreLoad);
  __ ret(0);

  return start;
}


// Support for intptr_t get_previous_sp()
//
// This routine is used to find the previous stack pointer for the
// caller.
address StubGenerator::generate_get_previous_sp() {
  StubCodeMark mark(this"StubRoutines""get_previous_sp");
  address start = __ pc();

  __ movptr(rax, rsp);
  __ addptr(rax, 8); // return address is at the top of the stack.
  __ ret(0);

  return start;
}

//----------------------------------------------------------------------------------------------------
// Support for void verify_mxcsr()
//
// This routine is used with -Xcheck:jni to verify that native
// JNI code does not return to Java code without restoring the
// MXCSR register to our expected state.

address StubGenerator::generate_verify_mxcsr() {
  StubCodeMark mark(this"StubRoutines""verify_mxcsr");
  address start = __ pc();

  const Address mxcsr_save(rsp, 0);

  if (CheckJNICalls) {
    Label ok_ret;
    ExternalAddress mxcsr_std(StubRoutines::x86::addr_mxcsr_std());
    __ push(rax);
    __ subptr(rsp, wordSize);      // allocate a temp location
    __ stmxcsr(mxcsr_save);
    __ movl(rax, mxcsr_save);
    __ andl(rax, 0xFFC0); // Mask out any pending exceptions (only check control and mask bits)
    __ cmp32(rax, mxcsr_std, rscratch1);
    __ jcc(Assembler::equal, ok_ret);

    __ warn("MXCSR changed by native JNI code, use -XX:+RestoreMXCSROnJNICall");

    __ ldmxcsr(mxcsr_std, rscratch1);

    __ bind(ok_ret);
    __ addptr(rsp, wordSize);
    __ pop(rax);
  }

  __ ret(0);

  return start;
}

address StubGenerator::generate_f2i_fixup() {
  StubCodeMark mark(this"StubRoutines""f2i_fixup");
  Address inout(rsp, 5 * wordSize); // return address + 4 saves

  address start = __ pc();

  Label L;

  __ push(rax);
  __ push(c_rarg3);
  __ push(c_rarg2);
  __ push(c_rarg1);

  __ movl(rax, 0x7f800000);
  __ xorl(c_rarg3, c_rarg3);
  __ movl(c_rarg2, inout);
  __ movl(c_rarg1, c_rarg2);
  __ andl(c_rarg1, 0x7fffffff);
  __ cmpl(rax, c_rarg1); // NaN? -> 0
  __ jcc(Assembler::negative, L);
  __ testl(c_rarg2, c_rarg2); // signed ? min_jint : max_jint
  __ movl(c_rarg3, 0x80000000);
  __ movl(rax, 0x7fffffff);
  __ cmovl(Assembler::positive, c_rarg3, rax);

  __ bind(L);
  __ movptr(inout, c_rarg3);

  __ pop(c_rarg1);
  __ pop(c_rarg2);
  __ pop(c_rarg3);
  __ pop(rax);

  __ ret(0);

  return start;
}

address StubGenerator::generate_f2l_fixup() {
  StubCodeMark mark(this"StubRoutines""f2l_fixup");
  Address inout(rsp, 5 * wordSize); // return address + 4 saves
  address start = __ pc();

  Label L;

  __ push(rax);
  __ push(c_rarg3);
  __ push(c_rarg2);
  __ push(c_rarg1);

  __ movl(rax, 0x7f800000);
  __ xorl(c_rarg3, c_rarg3);
  __ movl(c_rarg2, inout);
  __ movl(c_rarg1, c_rarg2);
  __ andl(c_rarg1, 0x7fffffff);
  __ cmpl(rax, c_rarg1); // NaN? -> 0
  __ jcc(Assembler::negative, L);
  __ testl(c_rarg2, c_rarg2); // signed ? min_jlong : max_jlong
  __ mov64(c_rarg3, 0x8000000000000000);
  __ mov64(rax, 0x7fffffffffffffff);
  __ cmov(Assembler::positive, c_rarg3, rax);

  __ bind(L);
  __ movptr(inout, c_rarg3);

  __ pop(c_rarg1);
  __ pop(c_rarg2);
  __ pop(c_rarg3);
  __ pop(rax);

  __ ret(0);

  return start;
}

address StubGenerator::generate_d2i_fixup() {
  StubCodeMark mark(this"StubRoutines""d2i_fixup");
  Address inout(rsp, 6 * wordSize); // return address + 5 saves

  address start = __ pc();

  Label L;

  __ push(rax);
  __ push(c_rarg3);
  __ push(c_rarg2);
  __ push(c_rarg1);
  __ push(c_rarg0);

  __ movl(rax, 0x7ff00000);
  __ movq(c_rarg2, inout);
  __ movl(c_rarg3, c_rarg2);
  __ mov(c_rarg1, c_rarg2);
  __ mov(c_rarg0, c_rarg2);
  __ negl(c_rarg3);
  __ shrptr(c_rarg1, 0x20);
  __ orl(c_rarg3, c_rarg2);
  __ andl(c_rarg1, 0x7fffffff);
  __ xorl(c_rarg2, c_rarg2);
  __ shrl(c_rarg3, 0x1f);
  __ orl(c_rarg1, c_rarg3);
  __ cmpl(rax, c_rarg1);
  __ jcc(Assembler::negative, L); // NaN -> 0
  __ testptr(c_rarg0, c_rarg0); // signed ? min_jint : max_jint
  __ movl(c_rarg2, 0x80000000);
  __ movl(rax, 0x7fffffff);
  __ cmov(Assembler::positive, c_rarg2, rax);

  __ bind(L);
  __ movptr(inout, c_rarg2);

  __ pop(c_rarg0);
  __ pop(c_rarg1);
  __ pop(c_rarg2);
  __ pop(c_rarg3);
  __ pop(rax);

  __ ret(0);

  return start;
}

address StubGenerator::generate_d2l_fixup() {
  StubCodeMark mark(this"StubRoutines""d2l_fixup");
  Address inout(rsp, 6 * wordSize); // return address + 5 saves

  address start = __ pc();

  Label L;

  __ push(rax);
  __ push(c_rarg3);
  __ push(c_rarg2);
  __ push(c_rarg1);
  __ push(c_rarg0);

  __ movl(rax, 0x7ff00000);
  __ movq(c_rarg2, inout);
  __ movl(c_rarg3, c_rarg2);
  __ mov(c_rarg1, c_rarg2);
  __ mov(c_rarg0, c_rarg2);
  __ negl(c_rarg3);
  __ shrptr(c_rarg1, 0x20);
  __ orl(c_rarg3, c_rarg2);
  __ andl(c_rarg1, 0x7fffffff);
  __ xorl(c_rarg2, c_rarg2);
  __ shrl(c_rarg3, 0x1f);
  __ orl(c_rarg1, c_rarg3);
  __ cmpl(rax, c_rarg1);
  __ jcc(Assembler::negative, L); // NaN -> 0
  __ testq(c_rarg0, c_rarg0); // signed ? min_jlong : max_jlong
  __ mov64(c_rarg2, 0x8000000000000000);
  __ mov64(rax, 0x7fffffffffffffff);
  __ cmovq(Assembler::positive, c_rarg2, rax);

  __ bind(L);
  __ movq(inout, c_rarg2);

  __ pop(c_rarg0);
  __ pop(c_rarg1);
  __ pop(c_rarg2);
  __ pop(c_rarg3);
  __ pop(rax);

  __ ret(0);

  return start;
}

address StubGenerator::generate_count_leading_zeros_lut(const char *stub_name) {
  __ align64();
  StubCodeMark mark(this"StubRoutines", stub_name);
  address start = __ pc();

  __ emit_data64(0x0101010102020304, relocInfo::none);
  __ emit_data64(0x0000000000000000, relocInfo::none);
  __ emit_data64(0x0101010102020304, relocInfo::none);
  __ emit_data64(0x0000000000000000, relocInfo::none);
  __ emit_data64(0x0101010102020304, relocInfo::none);
  __ emit_data64(0x0000000000000000, relocInfo::none);
  __ emit_data64(0x0101010102020304, relocInfo::none);
  __ emit_data64(0x0000000000000000, relocInfo::none);

  return start;
}

address StubGenerator::generate_popcount_avx_lut(const char *stub_name) {
  __ align64();
  StubCodeMark mark(this"StubRoutines", stub_name);
  address start = __ pc();

  __ emit_data64(0x0302020102010100, relocInfo::none);
  __ emit_data64(0x0403030203020201, relocInfo::none);
  __ emit_data64(0x0302020102010100, relocInfo::none);
  __ emit_data64(0x0403030203020201, relocInfo::none);
  __ emit_data64(0x0302020102010100, relocInfo::none);
  __ emit_data64(0x0403030203020201, relocInfo::none);
  __ emit_data64(0x0302020102010100, relocInfo::none);
  __ emit_data64(0x0403030203020201, relocInfo::none);

  return start;
}

address StubGenerator::generate_iota_indices(const char *stub_name) {
  __ align(CodeEntryAlignment);
  StubCodeMark mark(this"StubRoutines", stub_name);
  address start = __ pc();
  // B
  __ emit_data64(0x0706050403020100, relocInfo::none);
  __ emit_data64(0x0F0E0D0C0B0A0908, relocInfo::none);
  __ emit_data64(0x1716151413121110, relocInfo::none);
  __ emit_data64(0x1F1E1D1C1B1A1918, relocInfo::none);
  __ emit_data64(0x2726252423222120, relocInfo::none);
  __ emit_data64(0x2F2E2D2C2B2A2928, relocInfo::none);
  __ emit_data64(0x3736353433323130, relocInfo::none);
  __ emit_data64(0x3F3E3D3C3B3A3938, relocInfo::none);
  // W
  __ emit_data64(0x0003000200010000, relocInfo::none);
  __ emit_data64(0x0007000600050004, relocInfo::none);
  __ emit_data64(0x000B000A00090008, relocInfo::none);
  __ emit_data64(0x000F000E000D000C, relocInfo::none);
  __ emit_data64(0x0013001200110010, relocInfo::none);
  __ emit_data64(0x0017001600150014, relocInfo::none);
  __ emit_data64(0x001B001A00190018, relocInfo::none);
  __ emit_data64(0x001F001E001D001C, relocInfo::none);
  // D
  __ emit_data64(0x0000000100000000, relocInfo::none);
  __ emit_data64(0x0000000300000002, relocInfo::none);
  __ emit_data64(0x0000000500000004, relocInfo::none);
  __ emit_data64(0x0000000700000006, relocInfo::none);
  __ emit_data64(0x0000000900000008, relocInfo::none);
  __ emit_data64(0x0000000B0000000A, relocInfo::none);
  __ emit_data64(0x0000000D0000000C, relocInfo::none);
  __ emit_data64(0x0000000F0000000E, relocInfo::none);
  // Q
  __ emit_data64(0x0000000000000000, relocInfo::none);
  __ emit_data64(0x0000000000000001, relocInfo::none);
  __ emit_data64(0x0000000000000002, relocInfo::none);
  __ emit_data64(0x0000000000000003, relocInfo::none);
  __ emit_data64(0x0000000000000004, relocInfo::none);
  __ emit_data64(0x0000000000000005, relocInfo::none);
  __ emit_data64(0x0000000000000006, relocInfo::none);
  __ emit_data64(0x0000000000000007, relocInfo::none);
  // D - FP
  __ emit_data64(0x3F80000000000000, relocInfo::none); // 0.0f, 1.0f
  __ emit_data64(0x4040000040000000, relocInfo::none); // 2.0f, 3.0f
  __ emit_data64(0x40A0000040800000, relocInfo::none); // 4.0f, 5.0f
  __ emit_data64(0x40E0000040C00000, relocInfo::none); // 6.0f, 7.0f
  __ emit_data64(0x4110000041000000, relocInfo::none); // 8.0f, 9.0f
  __ emit_data64(0x4130000041200000, relocInfo::none); // 10.0f, 11.0f
  __ emit_data64(0x4150000041400000, relocInfo::none); // 12.0f, 13.0f
  __ emit_data64(0x4170000041600000, relocInfo::none); // 14.0f, 15.0f
  // Q - FP
  __ emit_data64(0x0000000000000000, relocInfo::none); // 0.0d
  __ emit_data64(0x3FF0000000000000, relocInfo::none); // 1.0d
  __ emit_data64(0x4000000000000000, relocInfo::none); // 2.0d
  __ emit_data64(0x4008000000000000, relocInfo::none); // 3.0d
  __ emit_data64(0x4010000000000000, relocInfo::none); // 4.0d
  __ emit_data64(0x4014000000000000, relocInfo::none); // 5.0d
  __ emit_data64(0x4018000000000000, relocInfo::none); // 6.0d
  __ emit_data64(0x401c000000000000, relocInfo::none); // 7.0d
  return start;
}

address StubGenerator::generate_vector_reverse_bit_lut(const char *stub_name) {
  __ align(CodeEntryAlignment);
  StubCodeMark mark(this"StubRoutines", stub_name);
  address start = __ pc();

  __ emit_data64(0x0E060A020C040800, relocInfo::none);
  __ emit_data64(0x0F070B030D050901, relocInfo::none);
  __ emit_data64(0x0E060A020C040800, relocInfo::none);
  __ emit_data64(0x0F070B030D050901, relocInfo::none);
  __ emit_data64(0x0E060A020C040800, relocInfo::none);
  __ emit_data64(0x0F070B030D050901, relocInfo::none);
  __ emit_data64(0x0E060A020C040800, relocInfo::none);
  __ emit_data64(0x0F070B030D050901, relocInfo::none);

  return start;
}

address StubGenerator::generate_vector_reverse_byte_perm_mask_long(const char *stub_name) {
  __ align(CodeEntryAlignment);
  StubCodeMark mark(this"StubRoutines", stub_name);
  address start = __ pc();

  __ emit_data64(0x0001020304050607, relocInfo::none);
  __ emit_data64(0x08090A0B0C0D0E0F, relocInfo::none);
  __ emit_data64(0x0001020304050607, relocInfo::none);
  __ emit_data64(0x08090A0B0C0D0E0F, relocInfo::none);
  __ emit_data64(0x0001020304050607, relocInfo::none);
  __ emit_data64(0x08090A0B0C0D0E0F, relocInfo::none);
  __ emit_data64(0x0001020304050607, relocInfo::none);
  __ emit_data64(0x08090A0B0C0D0E0F, relocInfo::none);

  return start;
}

address StubGenerator::generate_vector_reverse_byte_perm_mask_int(const char *stub_name) {
  __ align(CodeEntryAlignment);
  StubCodeMark mark(this"StubRoutines", stub_name);
  address start = __ pc();

  __ emit_data64(0x0405060700010203, relocInfo::none);
  __ emit_data64(0x0C0D0E0F08090A0B, relocInfo::none);
  __ emit_data64(0x0405060700010203, relocInfo::none);
  __ emit_data64(0x0C0D0E0F08090A0B, relocInfo::none);
  __ emit_data64(0x0405060700010203, relocInfo::none);
  __ emit_data64(0x0C0D0E0F08090A0B, relocInfo::none);
  __ emit_data64(0x0405060700010203, relocInfo::none);
  __ emit_data64(0x0C0D0E0F08090A0B, relocInfo::none);

  return start;
}

address StubGenerator::generate_vector_reverse_byte_perm_mask_short(const char *stub_name) {
  __ align(CodeEntryAlignment);
  StubCodeMark mark(this"StubRoutines", stub_name);
  address start = __ pc();

  __ emit_data64(0x0607040502030001, relocInfo::none);
  __ emit_data64(0x0E0F0C0D0A0B0809, relocInfo::none);
  __ emit_data64(0x0607040502030001, relocInfo::none);
  __ emit_data64(0x0E0F0C0D0A0B0809, relocInfo::none);
  __ emit_data64(0x0607040502030001, relocInfo::none);
  __ emit_data64(0x0E0F0C0D0A0B0809, relocInfo::none);
  __ emit_data64(0x0607040502030001, relocInfo::none);
  __ emit_data64(0x0E0F0C0D0A0B0809, relocInfo::none);

  return start;
}

address StubGenerator::generate_vector_byte_shuffle_mask(const char *stub_name) {
  __ align(CodeEntryAlignment);
  StubCodeMark mark(this"StubRoutines", stub_name);
  address start = __ pc();

  __ emit_data64(0x7070707070707070, relocInfo::none);
  __ emit_data64(0x7070707070707070, relocInfo::none);
  __ emit_data64(0xF0F0F0F0F0F0F0F0, relocInfo::none);
  __ emit_data64(0xF0F0F0F0F0F0F0F0, relocInfo::none);

  return start;
}

address StubGenerator::generate_fp_mask(const char *stub_name, int64_t mask) {
  __ align(CodeEntryAlignment);
  StubCodeMark mark(this"StubRoutines", stub_name);
  address start = __ pc();

  __ emit_data64( mask, relocInfo::none );
  __ emit_data64( mask, relocInfo::none );

  return start;
}

address StubGenerator::generate_vector_mask(const char *stub_name, int64_t mask) {
  __ align(CodeEntryAlignment);
  StubCodeMark mark(this"StubRoutines", stub_name);
  address start = __ pc();

  __ emit_data64(mask, relocInfo::none);
  __ emit_data64(mask, relocInfo::none);
  __ emit_data64(mask, relocInfo::none);
  __ emit_data64(mask, relocInfo::none);
  __ emit_data64(mask, relocInfo::none);
  __ emit_data64(mask, relocInfo::none);
  __ emit_data64(mask, relocInfo::none);
  __ emit_data64(mask, relocInfo::none);

  return start;
}

address StubGenerator::generate_vector_byte_perm_mask(const char *stub_name) {
  __ align(CodeEntryAlignment);
  StubCodeMark mark(this"StubRoutines", stub_name);
  address start = __ pc();

  __ emit_data64(0x0000000000000001, relocInfo::none);
  __ emit_data64(0x0000000000000003, relocInfo::none);
  __ emit_data64(0x0000000000000005, relocInfo::none);
  __ emit_data64(0x0000000000000007, relocInfo::none);
  __ emit_data64(0x0000000000000000, relocInfo::none);
  __ emit_data64(0x0000000000000002, relocInfo::none);
  __ emit_data64(0x0000000000000004, relocInfo::none);
  __ emit_data64(0x0000000000000006, relocInfo::none);

  return start;
}

address StubGenerator::generate_vector_fp_mask(const char *stub_name, int64_t mask) {
  __ align(CodeEntryAlignment);
  StubCodeMark mark(this"StubRoutines", stub_name);
  address start = __ pc();

  __ emit_data64(mask, relocInfo::none);
  __ emit_data64(mask, relocInfo::none);
  __ emit_data64(mask, relocInfo::none);
  __ emit_data64(mask, relocInfo::none);
  __ emit_data64(mask, relocInfo::none);
  __ emit_data64(mask, relocInfo::none);
  __ emit_data64(mask, relocInfo::none);
  __ emit_data64(mask, relocInfo::none);

  return start;
}

address StubGenerator::generate_vector_custom_i32(const char *stub_name, Assembler::AvxVectorLen len,
                                   int32_t val0, int32_t val1, int32_t val2, int32_t val3,
                                   int32_t val4, int32_t val5, int32_t val6, int32_t val7,
                                   int32_t val8, int32_t val9, int32_t val10, int32_t val11,
                                   int32_t val12, int32_t val13, int32_t val14, int32_t val15) {
  __ align(CodeEntryAlignment);
  StubCodeMark mark(this"StubRoutines", stub_name);
  address start = __ pc();

  assert(len != Assembler::AVX_NoVec, "vector len must be specified");
  __ emit_data(val0, relocInfo::none, 0);
  __ emit_data(val1, relocInfo::none, 0);
  __ emit_data(val2, relocInfo::none, 0);
  __ emit_data(val3, relocInfo::none, 0);
  if (len >= Assembler::AVX_256bit) {
    __ emit_data(val4, relocInfo::none, 0);
    __ emit_data(val5, relocInfo::none, 0);
    __ emit_data(val6, relocInfo::none, 0);
    __ emit_data(val7, relocInfo::none, 0);
    if (len >= Assembler::AVX_512bit) {
      __ emit_data(val8, relocInfo::none, 0);
      __ emit_data(val9, relocInfo::none, 0);
      __ emit_data(val10, relocInfo::none, 0);
      __ emit_data(val11, relocInfo::none, 0);
      __ emit_data(val12, relocInfo::none, 0);
      __ emit_data(val13, relocInfo::none, 0);
      __ emit_data(val14, relocInfo::none, 0);
      __ emit_data(val15, relocInfo::none, 0);
    }
  }
  return start;
}

// Non-destructive plausibility checks for oops
//
// Arguments:
//    all args on stack!
//
// Stack after saving c_rarg3:
//    [tos + 0]: saved c_rarg3
//    [tos + 1]: saved c_rarg2
//    [tos + 2]: saved r12 (several TemplateTable methods use it)
//    [tos + 3]: saved flags
//    [tos + 4]: return address
//  * [tos + 5]: error message (char*)
//  * [tos + 6]: object to verify (oop)
//  * [tos + 7]: saved rax - saved by caller and bashed
//  * [tos + 8]: saved r10 (rscratch1) - saved by caller
//  * = popped on exit
address StubGenerator::generate_verify_oop() {
  StubCodeMark mark(this"StubRoutines""verify_oop");
  address start = __ pc();

  Label exit, error;

  __ pushf();
  __ incrementl(ExternalAddress((address) StubRoutines::verify_oop_count_addr()), rscratch1);

  __ push(r12);

  // save c_rarg2 and c_rarg3
  __ push(c_rarg2);
  __ push(c_rarg3);

  enum {
    // After previous pushes.
    oop_to_verify = 6 * wordSize,
    saved_rax     = 7 * wordSize,
    saved_r10     = 8 * wordSize,

    // Before the call to MacroAssembler::debug(), see below.
    return_addr   = 16 * wordSize,
    error_msg     = 17 * wordSize
  };

  // get object
  __ movptr(rax, Address(rsp, oop_to_verify));

  // make sure object is 'reasonable'
  __ testptr(rax, rax);
  __ jcc(Assembler::zero, exit); // if obj is NULL it is OK

#if INCLUDE_ZGC
  if (UseZGC) {
    // Check if metadata bits indicate a bad oop
    __ testptr(rax, Address(r15_thread, ZThreadLocalData::address_bad_mask_offset()));
    __ jcc(Assembler::notZero, error);
  }
#endif

  // Check if the oop is in the right area of memory
  __ movptr(c_rarg2, rax);
  __ movptr(c_rarg3, (intptr_t) Universe::verify_oop_mask());
  __ andptr(c_rarg2, c_rarg3);
  __ movptr(c_rarg3, (intptr_t) Universe::verify_oop_bits());
  __ cmpptr(c_rarg2, c_rarg3);
  __ jcc(Assembler::notZero, error);

  // make sure klass is 'reasonable', which is not zero.
  __ load_klass(rax, rax, rscratch1);  // get klass
  __ testptr(rax, rax);
  __ jcc(Assembler::zero, error); // if klass is NULL it is broken

  // return if everything seems ok
  __ bind(exit);
  __ movptr(rax, Address(rsp, saved_rax));     // get saved rax back
  __ movptr(rscratch1, Address(rsp, saved_r10)); // get saved r10 back
  __ pop(c_rarg3);                             // restore c_rarg3
  __ pop(c_rarg2);                             // restore c_rarg2
  __ pop(r12);                                 // restore r12
  __ popf();                                   // restore flags
  __ ret(4 * wordSize);                        // pop caller saved stuff

  // handle errors
  __ bind(error);
  __ movptr(rax, Address(rsp, saved_rax));     // get saved rax back
  __ movptr(rscratch1, Address(rsp, saved_r10)); // get saved r10 back
  __ pop(c_rarg3);                             // get saved c_rarg3 back
  __ pop(c_rarg2);                             // get saved c_rarg2 back
  __ pop(r12);                                 // get saved r12 back
  __ popf();                                   // get saved flags off stack --
                                               // will be ignored

  __ pusha();                                  // push registers
                                               // (rip is already
                                               // already pushed)
  // debug(char* msg, int64_t pc, int64_t regs[])
  // We've popped the registers we'd saved (c_rarg3, c_rarg2 and flags), and
  // pushed all the registers, so now the stack looks like:
  //     [tos +  0] 16 saved registers
  //     [tos + 16] return address
  //   * [tos + 17] error message (char*)
  //   * [tos + 18] object to verify (oop)
  //   * [tos + 19] saved rax - saved by caller and bashed
  //   * [tos + 20] saved r10 (rscratch1) - saved by caller
  //   * = popped on exit

  __ movptr(c_rarg0, Address(rsp, error_msg));    // pass address of error message
  __ movptr(c_rarg1, Address(rsp, return_addr));  // pass return address
  __ movq(c_rarg2, rsp);                          // pass address of regs on stack
  __ mov(r12, rsp);                               // remember rsp
  __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
  __ andptr(rsp, -16);                            // align stack as required by ABI
  BLOCK_COMMENT("call MacroAssembler::debug");
  __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug64)));
  __ hlt();

  return start;
}


// Shuffle first three arg regs on Windows into Linux/Solaris locations.
//
// Outputs:
//    rdi - rcx
//    rsi - rdx
//    rdx - r8
//    rcx - r9
//
// Registers r9 and r10 are used to save rdi and rsi on Windows, which latter
// are non-volatile.  r9 and r10 should not be used by the caller.
//
void StubGenerator::setup_arg_regs(int nargs) {
  const Register saved_rdi = r9;
  const Register saved_rsi = r10;
  assert(nargs == 3 || nargs == 4, "else fix");
#ifdef _WIN64
  assert(c_rarg0 == rcx && c_rarg1 == rdx && c_rarg2 == r8 && c_rarg3 == r9,
         "unexpected argument registers");
  if (nargs >= 4)
    __ mov(rax, r9);  // r9 is also saved_rdi
  __ movptr(saved_rdi, rdi);
  __ movptr(saved_rsi, rsi);
  __ mov(rdi, rcx); // c_rarg0
  __ mov(rsi, rdx); // c_rarg1
  __ mov(rdx, r8);  // c_rarg2
  if (nargs >= 4)
    __ mov(rcx, rax); // c_rarg3 (via rax)
#else
  assert(c_rarg0 == rdi && c_rarg1 == rsi && c_rarg2 == rdx && c_rarg3 == rcx,
         "unexpected argument registers");
#endif
  DEBUG_ONLY(_regs_in_thread = false;)
}


void StubGenerator::restore_arg_regs() {
  assert(!_regs_in_thread, "wrong call to restore_arg_regs");
  const Register saved_rdi = r9;
  const Register saved_rsi = r10;
#ifdef _WIN64
  __ movptr(rdi, saved_rdi);
  __ movptr(rsi, saved_rsi);
#endif
}


// This is used in places where r10 is a scratch register, and can
// be adapted if r9 is needed also.
void StubGenerator::setup_arg_regs_using_thread() {
  const Register saved_r15 = r9;
#ifdef _WIN64
  __ mov(saved_r15, r15);  // r15 is callee saved and needs to be restored
  __ get_thread(r15_thread);
  assert(c_rarg0 == rcx && c_rarg1 == rdx && c_rarg2 == r8 && c_rarg3 == r9,
         "unexpected argument registers");
  __ movptr(Address(r15_thread, in_bytes(JavaThread::windows_saved_rdi_offset())), rdi);
  __ movptr(Address(r15_thread, in_bytes(JavaThread::windows_saved_rsi_offset())), rsi);

  __ mov(rdi, rcx); // c_rarg0
  __ mov(rsi, rdx); // c_rarg1
  __ mov(rdx, r8);  // c_rarg2
#else
  assert(c_rarg0 == rdi && c_rarg1 == rsi && c_rarg2 == rdx && c_rarg3 == rcx,
         "unexpected argument registers");
#endif
  DEBUG_ONLY(_regs_in_thread = true;)
}


void StubGenerator::restore_arg_regs_using_thread() {
  assert(_regs_in_thread, "wrong call to restore_arg_regs");
  const Register saved_r15 = r9;
#ifdef _WIN64
  __ get_thread(r15_thread);
  __ movptr(rsi, Address(r15_thread, in_bytes(JavaThread::windows_saved_rsi_offset())));
  __ movptr(rdi, Address(r15_thread, in_bytes(JavaThread::windows_saved_rdi_offset())));
  __ mov(r15, saved_r15);  // r15 is callee saved and needs to be restored
#endif
}


void StubGenerator::setup_argument_regs(BasicType type) {
  if (type == T_BYTE || type == T_SHORT) {
    setup_arg_regs(); // from => rdi, to => rsi, count => rdx
                      // r9 and r10 may be used to save non-volatile registers
  } else {
    setup_arg_regs_using_thread(); // from => rdi, to => rsi, count => rdx
                                   // r9 is used to save r15_thread
  }
}


void StubGenerator::restore_argument_regs(BasicType type) {
  if (type == T_BYTE || type == T_SHORT) {
    restore_arg_regs();
  } else {
    restore_arg_regs_using_thread();
  }
}

address StubGenerator::generate_data_cache_writeback() {
  const Register src        = c_rarg0;  // source address

  __ align(CodeEntryAlignment);

  StubCodeMark mark(this"StubRoutines""_data_cache_writeback");

  address start = __ pc();

  __ enter();
  __ cache_wb(Address(src, 0));
  __ leave();
  __ ret(0);

  return start;
}

address StubGenerator::generate_data_cache_writeback_sync() {
  const Register is_pre    = c_rarg0;  // pre or post sync

  __ align(CodeEntryAlignment);

  StubCodeMark mark(this"StubRoutines""_data_cache_writeback_sync");

  // pre wbsync is a no-op
  // post wbsync translates to an sfence

  Label skip;
  address start = __ pc();

  __ enter();
  __ cmpl(is_pre, 0);
  __ jcc(Assembler::notEqual, skip);
  __ cache_wbsync(false);
  __ bind(skip);
  __ leave();
  __ ret(0);

  return start;
}

// ofs and limit are use for multi-block byte array.
// int com.sun.security.provider.MD5.implCompress(byte[] b, int ofs)
address StubGenerator::generate_md5_implCompress(bool multi_block, const char *name) {
  __ align(CodeEntryAlignment);
  StubCodeMark mark(this"StubRoutines", name);
  address start = __ pc();

  const Register buf_param = r15;
  const Address state_param(rsp, 0 * wordSize);
  const Address ofs_param  (rsp, 1 * wordSize    );
  const Address limit_param(rsp, 1 * wordSize + 4);

  __ enter();
  __ push(rbx);
  __ push(rdi);
  __ push(rsi);
  __ push(r15);
  __ subptr(rsp, 2 * wordSize);

  __ movptr(buf_param, c_rarg0);
  __ movptr(state_param, c_rarg1);
  if (multi_block) {
    __ movl(ofs_param, c_rarg2);
    __ movl(limit_param, c_rarg3);
  }
  __ fast_md5(buf_param, state_param, ofs_param, limit_param, multi_block);

  __ addptr(rsp, 2 * wordSize);
  __ pop(r15);
  __ pop(rsi);
  __ pop(rdi);
  __ pop(rbx);
  __ leave();
  __ ret(0);

  return start;
}

address StubGenerator::generate_upper_word_mask() {
  __ align64();
  StubCodeMark mark(this"StubRoutines""upper_word_mask");
  address start = __ pc();

  __ emit_data64(0x0000000000000000, relocInfo::none);
  __ emit_data64(0xFFFFFFFF00000000, relocInfo::none);

  return start;
}

address StubGenerator::generate_shuffle_byte_flip_mask() {
  __ align64();
  StubCodeMark mark(this"StubRoutines""shuffle_byte_flip_mask");
  address start = __ pc();

  __ emit_data64(0x08090a0b0c0d0e0f, relocInfo::none);
  __ emit_data64(0x0001020304050607, relocInfo::none);

  return start;
}

// ofs and limit are use for multi-block byte array.
// int com.sun.security.provider.DigestBase.implCompressMultiBlock(byte[] b, int ofs, int limit)
address StubGenerator::generate_sha1_implCompress(bool multi_block, const char *name) {
  __ align(CodeEntryAlignment);
  StubCodeMark mark(this"StubRoutines", name);
  address start = __ pc();

  Register buf = c_rarg0;
  Register state = c_rarg1;
  Register ofs = c_rarg2;
  Register limit = c_rarg3;

  const XMMRegister abcd = xmm0;
  const XMMRegister e0 = xmm1;
  const XMMRegister e1 = xmm2;
  const XMMRegister msg0 = xmm3;

  const XMMRegister msg1 = xmm4;
  const XMMRegister msg2 = xmm5;
  const XMMRegister msg3 = xmm6;
  const XMMRegister shuf_mask = xmm7;

  __ enter();

  __ subptr(rsp, 4 * wordSize);

  __ fast_sha1(abcd, e0, e1, msg0, msg1, msg2, msg3, shuf_mask,
    buf, state, ofs, limit, rsp, multi_block);

  __ addptr(rsp, 4 * wordSize);

  __ leave();
  __ ret(0);

  return start;
}

address StubGenerator::generate_pshuffle_byte_flip_mask() {
  __ align64();
  StubCodeMark mark(this"StubRoutines""pshuffle_byte_flip_mask");
  address start = __ pc();

  __ emit_data64(0x0405060700010203, relocInfo::none);
  __ emit_data64(0x0c0d0e0f08090a0b, relocInfo::none);

  if (VM_Version::supports_avx2()) {
    __ emit_data64(0x0405060700010203, relocInfo::none); // second copy
    __ emit_data64(0x0c0d0e0f08090a0b, relocInfo::none);
    // _SHUF_00BA
    __ emit_data64(0x0b0a090803020100, relocInfo::none);
    __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none);
    __ emit_data64(0x0b0a090803020100, relocInfo::none);
    __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none);
    // _SHUF_DC00
    __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none);
    __ emit_data64(0x0b0a090803020100, relocInfo::none);
    __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none);
    __ emit_data64(0x0b0a090803020100, relocInfo::none);
  }

  return start;
}

//Mask for byte-swapping a couple of qwords in an XMM register using (v)pshufb.
address StubGenerator::generate_pshuffle_byte_flip_mask_sha512() {
  __ align32();
  StubCodeMark mark(this"StubRoutines""pshuffle_byte_flip_mask_sha512");
  address start = __ pc();

  if (VM_Version::supports_avx2()) {
    __ emit_data64(0x0001020304050607, relocInfo::none); // PSHUFFLE_BYTE_FLIP_MASK
    __ emit_data64(0x08090a0b0c0d0e0f, relocInfo::none);
    __ emit_data64(0x1011121314151617, relocInfo::none);
    __ emit_data64(0x18191a1b1c1d1e1f, relocInfo::none);
    __ emit_data64(0x0000000000000000, relocInfo::none); //MASK_YMM_LO
    __ emit_data64(0x0000000000000000, relocInfo::none);
    __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none);
    __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none);
  }

  return start;
}

// ofs and limit are use for multi-block byte array.
// int com.sun.security.provider.DigestBase.implCompressMultiBlock(byte[] b, int ofs, int limit)
address StubGenerator::generate_sha256_implCompress(bool multi_block, const char *name) {
  assert(VM_Version::supports_sha() || VM_Version::supports_avx2(), "");
  __ align(CodeEntryAlignment);
  StubCodeMark mark(this"StubRoutines", name);
  address start = __ pc();

  Register buf = c_rarg0;
  Register state = c_rarg1;
  Register ofs = c_rarg2;
  Register limit = c_rarg3;

  const XMMRegister msg = xmm0;
  const XMMRegister state0 = xmm1;
  const XMMRegister state1 = xmm2;
  const XMMRegister msgtmp0 = xmm3;

  const XMMRegister msgtmp1 = xmm4;
  const XMMRegister msgtmp2 = xmm5;
  const XMMRegister msgtmp3 = xmm6;
  const XMMRegister msgtmp4 = xmm7;

  const XMMRegister shuf_mask = xmm8;

  __ enter();

  __ subptr(rsp, 4 * wordSize);

  if (VM_Version::supports_sha()) {
    __ fast_sha256(msg, state0, state1, msgtmp0, msgtmp1, msgtmp2, msgtmp3, msgtmp4,
      buf, state, ofs, limit, rsp, multi_block, shuf_mask);
  } else if (VM_Version::supports_avx2()) {
    __ sha256_AVX2(msg, state0, state1, msgtmp0, msgtmp1, msgtmp2, msgtmp3, msgtmp4,
      buf, state, ofs, limit, rsp, multi_block, shuf_mask);
  }
  __ addptr(rsp, 4 * wordSize);
  __ vzeroupper();
  __ leave();
  __ ret(0);

  return start;
}

address StubGenerator::generate_sha512_implCompress(bool multi_block, const char *name) {
  assert(VM_Version::supports_avx2(), "");
  assert(VM_Version::supports_bmi2(), "");
  __ align(CodeEntryAlignment);
  StubCodeMark mark(this"StubRoutines", name);
  address start = __ pc();

  Register buf = c_rarg0;
  Register state = c_rarg1;
  Register ofs = c_rarg2;
  Register limit = c_rarg3;

  const XMMRegister msg = xmm0;
  const XMMRegister state0 = xmm1;
  const XMMRegister state1 = xmm2;
  const XMMRegister msgtmp0 = xmm3;
  const XMMRegister msgtmp1 = xmm4;
  const XMMRegister msgtmp2 = xmm5;
  const XMMRegister msgtmp3 = xmm6;
  const XMMRegister msgtmp4 = xmm7;

  const XMMRegister shuf_mask = xmm8;

  __ enter();

  __ sha512_AVX2(msg, state0, state1, msgtmp0, msgtmp1, msgtmp2, msgtmp3, msgtmp4,
  buf, state, ofs, limit, rsp, multi_block, shuf_mask);

  __ vzeroupper();
  __ leave();
  __ ret(0);

  return start;
}

address StubGenerator::base64_shuffle_addr() {
  __ align64();
  StubCodeMark mark(this"StubRoutines""shuffle_base64");
  address start = __ pc();

  assert(((unsigned long long)start & 0x3f) == 0,
         "Alignment problem (0x%08llx)", (unsigned long long)start);
  __ emit_data64(0x0405030401020001, relocInfo::none);
  __ emit_data64(0x0a0b090a07080607, relocInfo::none);
  __ emit_data64(0x10110f100d0e0c0d, relocInfo::none);
  __ emit_data64(0x1617151613141213, relocInfo::none);
  __ emit_data64(0x1c1d1b1c191a1819, relocInfo::none);
  __ emit_data64(0x222321221f201e1f, relocInfo::none);
  __ emit_data64(0x2829272825262425, relocInfo::none);
  __ emit_data64(0x2e2f2d2e2b2c2a2b, relocInfo::none);

  return start;
}

address StubGenerator::base64_avx2_shuffle_addr() {
  __ align32();
  StubCodeMark mark(this"StubRoutines""avx2_shuffle_base64");
  address start = __ pc();

  __ emit_data64(0x0809070805060405, relocInfo::none);
  __ emit_data64(0x0e0f0d0e0b0c0a0b, relocInfo::none);
  __ emit_data64(0x0405030401020001, relocInfo::none);
  __ emit_data64(0x0a0b090a07080607, relocInfo::none);

  return start;
}

address StubGenerator::base64_avx2_input_mask_addr() {
  __ align32();
  StubCodeMark mark(this"StubRoutines""avx2_input_mask_base64");
  address start = __ pc();

  __ emit_data64(0x8000000000000000, relocInfo::none);
  __ emit_data64(0x8000000080000000, relocInfo::none);
  __ emit_data64(0x8000000080000000, relocInfo::none);
  __ emit_data64(0x8000000080000000, relocInfo::none);

  return start;
}

address StubGenerator::base64_avx2_lut_addr() {
  __ align32();
  StubCodeMark mark(this"StubRoutines""avx2_lut_base64");
  address start = __ pc();

  __ emit_data64(0xfcfcfcfcfcfc4741, relocInfo::none);
  __ emit_data64(0x0000f0edfcfcfcfc, relocInfo::none);
  __ emit_data64(0xfcfcfcfcfcfc4741, relocInfo::none);
  __ emit_data64(0x0000f0edfcfcfcfc, relocInfo::none);

  // URL LUT
  __ emit_data64(0xfcfcfcfcfcfc4741, relocInfo::none);
  __ emit_data64(0x000020effcfcfcfc, relocInfo::none);
  __ emit_data64(0xfcfcfcfcfcfc4741, relocInfo::none);
  __ emit_data64(0x000020effcfcfcfc, relocInfo::none);

  return start;
}

address StubGenerator::base64_encoding_table_addr() {
  __ align64();
  StubCodeMark mark(this"StubRoutines""encoding_table_base64");
  address start = __ pc();

  assert(((unsigned long long)start & 0x3f) == 0, "Alignment problem (0x%08llx)", (unsigned long long)start);
  __ emit_data64(0x4847464544434241, relocInfo::none);
  __ emit_data64(0x504f4e4d4c4b4a49, relocInfo::none);
  __ emit_data64(0x5857565554535251, relocInfo::none);
  __ emit_data64(0x6665646362615a59, relocInfo::none);
  __ emit_data64(0x6e6d6c6b6a696867, relocInfo::none);
  __ emit_data64(0x767574737271706f, relocInfo::none);
  __ emit_data64(0x333231307a797877, relocInfo::none);
  __ emit_data64(0x2f2b393837363534, relocInfo::none);

  // URL table
  __ emit_data64(0x4847464544434241, relocInfo::none);
  __ emit_data64(0x504f4e4d4c4b4a49, relocInfo::none);
  __ emit_data64(0x5857565554535251, relocInfo::none);
  __ emit_data64(0x6665646362615a59, relocInfo::none);
  __ emit_data64(0x6e6d6c6b6a696867, relocInfo::none);
  __ emit_data64(0x767574737271706f, relocInfo::none);
  __ emit_data64(0x333231307a797877, relocInfo::none);
  __ emit_data64(0x5f2d393837363534, relocInfo::none);

  return start;
}

// Code for generating Base64 encoding.
// Intrinsic function prototype in Base64.java:
// private void encodeBlock(byte[] src, int sp, int sl, byte[] dst, int dp,
// boolean isURL) {
address StubGenerator::generate_base64_encodeBlock()
{
  __ align(CodeEntryAlignment);
  StubCodeMark mark(this"StubRoutines""implEncode");
  address start = __ pc();

  __ enter();

  // Save callee-saved registers before using them
  __ push(r12);
  __ push(r13);
  __ push(r14);
  __ push(r15);

  // arguments
  const Register source = c_rarg0;       // Source Array
  const Register start_offset = c_rarg1; // start offset
  const Register end_offset = c_rarg2;   // end offset
  const Register dest = c_rarg3;   // destination array

#ifndef _WIN64
  const Register dp = c_rarg4;    // Position for writing to dest array
  const Register isURL = c_rarg5; // Base64 or URL character set
#else
  const Address dp_mem(rbp, 6 * wordSize); // length is on stack on Win64
  const Address isURL_mem(rbp, 7 * wordSize);
  const Register isURL = r10; // pick the volatile windows register
  const Register dp = r12;
  __ movl(dp, dp_mem);
  __ movl(isURL, isURL_mem);
#endif

  const Register length = r14;
  const Register encode_table = r13;
  Label L_process3, L_exit, L_processdata, L_vbmiLoop, L_not512, L_32byteLoop;

  // calculate length from offsets
  __ movl(length, end_offset);
  __ subl(length, start_offset);
  __ cmpl(length, 0);
  __ jcc(Assembler::lessEqual, L_exit);

  // Code for 512-bit VBMI encoding.  Encodes 48 input bytes into 64
  // output bytes. We read 64 input bytes and ignore the last 16, so be
  // sure not to read past the end of the input buffer.
  if (VM_Version::supports_avx512_vbmi()) {
    __ cmpl(length, 64); // Do not overrun input buffer.
    __ jcc(Assembler::below, L_not512);

    __ shll(isURL, 6); // index into decode table based on isURL
    __ lea(encode_table, ExternalAddress(StubRoutines::x86::base64_encoding_table_addr()));
    __ addptr(encode_table, isURL);
    __ shrl(isURL, 6); // restore isURL

    __ mov64(rax, 0x3036242a1016040aull); // Shifts
    __ evmovdquq(xmm3, ExternalAddress(StubRoutines::x86::base64_shuffle_addr()), Assembler::AVX_512bit, r15);
    __ evmovdquq(xmm2, Address(encode_table, 0), Assembler::AVX_512bit);
    __ evpbroadcastq(xmm1, rax, Assembler::AVX_512bit);

    __ align32();
    __ BIND(L_vbmiLoop);

    __ vpermb(xmm0, xmm3, Address(source, start_offset), Assembler::AVX_512bit);
    __ subl(length, 48);

    // Put the input bytes into the proper lanes for writing, then
    // encode them.
    __ evpmultishiftqb(xmm0, xmm1, xmm0, Assembler::AVX_512bit);
    __ vpermb(xmm0, xmm0, xmm2, Assembler::AVX_512bit);

    // Write to destination
    __ evmovdquq(Address(dest, dp), xmm0, Assembler::AVX_512bit);

    __ addptr(dest, 64);
    __ addptr(source, 48);
    __ cmpl(length, 64);
    __ jcc(Assembler::aboveEqual, L_vbmiLoop);

    __ vzeroupper();
  }

  __ BIND(L_not512);
  if (VM_Version::supports_avx2()
      && VM_Version::supports_avx512vlbw()) {
    /*
    ** This AVX2 encoder is based off the paper at:
    **      https://dl.acm.org/doi/10.1145/3132709
    **
    ** We use AVX2 SIMD instructions to encode 24 bytes into 32
    ** output bytes.
    **
    */

    // Lengths under 32 bytes are done with scalar routine
    __ cmpl(length, 31);
    __ jcc(Assembler::belowEqual, L_process3);

    // Set up supporting constant table data
    __ vmovdqu(xmm9, ExternalAddress(StubRoutines::x86::base64_avx2_shuffle_addr()), rax);
    // 6-bit mask for 2nd and 4th (and multiples) 6-bit values
    __ movl(rax, 0x0fc0fc00);
    __ vmovdqu(xmm1, ExternalAddress(StubRoutines::x86::base64_avx2_input_mask_addr()), rax);
    __ evpbroadcastd(xmm8, rax, Assembler::AVX_256bit);

    // Multiplication constant for "shifting" right by 6 and 10
    // bits
    __ movl(rax, 0x04000040);

    __ subl(length, 24);
    __ evpbroadcastd(xmm7, rax, Assembler::AVX_256bit);

    // For the first load, we mask off reading of the first 4
    // bytes into the register. This is so we can get 4 3-byte
    // chunks into each lane of the register, avoiding having to
    // handle end conditions.  We then shuffle these bytes into a
    // specific order so that manipulation is easier.
    //
    // The initial read loads the XMM register like this:
    //
    // Lower 128-bit lane:
    // +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
    // | XX | XX | XX | XX | A0 | A1 | A2 | B0 | B1 | B2 | C0 | C1
    // | C2 | D0 | D1 | D2 |
    // +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
    //
    // Upper 128-bit lane:
    // +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
    // | E0 | E1 | E2 | F0 | F1 | F2 | G0 | G1 | G2 | H0 | H1 | H2
    // | XX | XX | XX | XX |
    // +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
    //
    // Where A0 is the first input byte, B0 is the fourth, etc.
    // The alphabetical significance denotes the 3 bytes to be
    // consumed and encoded into 4 bytes.
    //
    // We then shuffle the register so each 32-bit word contains
    // the sequence:
    //    A1 A0 A2 A1, B1, B0, B2, B1, etc.
    // Each of these byte sequences are then manipulated into 4
    // 6-bit values ready for encoding.
    //
    // If we focus on one set of 3-byte chunks, changing the
    // nomenclature such that A0 => a, A1 => b, and A2 => c, we
    // shuffle such that each 24-bit chunk contains:
    //
    // b7 b6 b5 b4 b3 b2 b1 b0 | a7 a6 a5 a4 a3 a2 a1 a0 | c7 c6
    // c5 c4 c3 c2 c1 c0 | b7 b6 b5 b4 b3 b2 b1 b0
    // Explain this step.
    // b3 b2 b1 b0 c5 c4 c3 c2 | c1 c0 d5 d4 d3 d2 d1 d0 | a5 a4
    // a3 a2 a1 a0 b5 b4 | b3 b2 b1 b0 c5 c4 c3 c2
    //
    // W first and off all but bits 4-9 and 16-21 (c5..c0 and
    // a5..a0) and shift them using a vector multiplication
    // operation (vpmulhuw) which effectively shifts c right by 6
    // bits and a right by 10 bits.  We similarly mask bits 10-15
    // (d5..d0) and 22-27 (b5..b0) and shift them left by 8 and 4
    // bits respectively.  This is done using vpmullw.  We end up
    // with 4 6-bit values, thus splitting the 3 input bytes,
    // ready for encoding:
    //    0 0 d5..d0 0 0 c5..c0 0 0 b5..b0 0 0 a5..a0
    //
    // For translation, we recognize that there are 5 distinct
    // ranges of legal Base64 characters as below:
    //
    //   +-------------+-------------+------------+
    //   | 6-bit value | ASCII range |   offset   |
    //   +-------------+-------------+------------+
    //   |    0..25    |    A..Z     |     65     |
    //   |   26..51    |    a..z     |     71     |
    //   |   52..61    |    0..9     |     -4     |
    //   |     62      |   + or -    | -19 or -17 |
    //   |     63      |   / or _    | -16 or 32  |
    //   +-------------+-------------+------------+
    //
    // We note that vpshufb does a parallel lookup in a
    // destination register using the lower 4 bits of bytes from a
    // source register.  If we use a saturated subtraction and
    // subtract 51 from each 6-bit value, bytes from [0,51]
    // saturate to 0, and [52,63] map to a range of [1,12].  We
    // distinguish the [0,25] and [26,51] ranges by assigning a
    // value of 13 for all 6-bit values less than 26.  We end up
    // with:
    //
    //   +-------------+-------------+------------+
    //   | 6-bit value |   Reduced   |   offset   |
    //   +-------------+-------------+------------+
    //   |    0..25    |     13      |     65     |
    //   |   26..51    |      0      |     71     |
    //   |   52..61    |    0..9     |     -4     |
    //   |     62      |     11      | -19 or -17 |
    //   |     63      |     12      | -16 or 32  |
    //   +-------------+-------------+------------+
    //
    // We then use a final vpshufb to add the appropriate offset,
    // translating the bytes.
    //
    // Load input bytes - only 28 bytes.  Mask the first load to
    // not load into the full register.
    __ vpmaskmovd(xmm1, xmm1, Address(source, start_offset, Address::times_1, -4), Assembler::AVX_256bit);

    // Move 3-byte chunks of input (12 bytes) into 16 bytes,
    // ordering by:
    //   1, 0, 2, 1; 4, 3, 5, 4; etc.  This groups 6-bit chunks
    //   for easy masking
    __ vpshufb(xmm1, xmm1, xmm9, Assembler::AVX_256bit);

    __ addl(start_offset, 24);

    // Load masking register for first and third (and multiples)
    // 6-bit values.
    __ movl(rax, 0x003f03f0);
    __ evpbroadcastd(xmm6, rax, Assembler::AVX_256bit);
    // Multiplication constant for "shifting" left by 4 and 8 bits
    __ movl(rax, 0x01000010);
    __ evpbroadcastd(xmm5, rax, Assembler::AVX_256bit);

    // Isolate 6-bit chunks of interest
    __ vpand(xmm0, xmm8, xmm1, Assembler::AVX_256bit);

    // Load constants for encoding
    __ movl(rax, 0x19191919);
    __ evpbroadcastd(xmm3, rax, Assembler::AVX_256bit);
    __ movl(rax, 0x33333333);
    __ evpbroadcastd(xmm4, rax, Assembler::AVX_256bit);

    // Shift output bytes 0 and 2 into proper lanes
    __ vpmulhuw(xmm2, xmm0, xmm7, Assembler::AVX_256bit);

    // Mask and shift output bytes 1 and 3 into proper lanes and
    // combine
    __ vpand(xmm0, xmm6, xmm1, Assembler::AVX_256bit);
    __ vpmullw(xmm0, xmm5, xmm0, Assembler::AVX_256bit);
    __ vpor(xmm0, xmm0, xmm2, Assembler::AVX_256bit);

    // Find out which are 0..25.  This indicates which input
    // values fall in the range of 'A'-'Z', which require an
    // additional offset (see comments above)
    __ vpcmpgtb(xmm2, xmm0, xmm3, Assembler::AVX_256bit);
    __ vpsubusb(xmm1, xmm0, xmm4, Assembler::AVX_256bit);
    __ vpsubb(xmm1, xmm1, xmm2, Assembler::AVX_256bit);

    // Load the proper lookup table
    __ lea(r11, ExternalAddress(StubRoutines::x86::base64_avx2_lut_addr()));
    __ movl(r15, isURL);
    __ shll(r15, 5);
    __ vmovdqu(xmm2, Address(r11, r15));

    // Shuffle the offsets based on the range calculation done
    // above. This allows us to add the correct offset to the
    // 6-bit value corresponding to the range documented above.
    __ vpshufb(xmm1, xmm2, xmm1, Assembler::AVX_256bit);
    __ vpaddb(xmm0, xmm1, xmm0, Assembler::AVX_256bit);

    // Store the encoded bytes
    __ vmovdqu(Address(dest, dp), xmm0);
    __ addl(dp, 32);

    __ cmpl(length, 31);
    __ jcc(Assembler::belowEqual, L_process3);

    __ align32();
    __ BIND(L_32byteLoop);

    // Get next 32 bytes
    __ vmovdqu(xmm1, Address(source, start_offset, Address::times_1, -4));

    __ subl(length, 24);
    __ addl(start_offset, 24);

    // This logic is identical to the above, with only constant
    // register loads removed.  Shuffle the input, mask off 6-bit
    // chunks, shift them into place, then add the offset to
    // encode.
    __ vpshufb(xmm1, xmm1, xmm9, Assembler::AVX_256bit);

    __ vpand(xmm0, xmm8, xmm1, Assembler::AVX_256bit);
    __ vpmulhuw(xmm10, xmm0, xmm7, Assembler::AVX_256bit);
    __ vpand(xmm0, xmm6, xmm1, Assembler::AVX_256bit);
    __ vpmullw(xmm0, xmm5, xmm0, Assembler::AVX_256bit);
    __ vpor(xmm0, xmm0, xmm10, Assembler::AVX_256bit);
    __ vpcmpgtb(xmm10, xmm0, xmm3, Assembler::AVX_256bit);
    __ vpsubusb(xmm1, xmm0, xmm4, Assembler::AVX_256bit);
    __ vpsubb(xmm1, xmm1, xmm10, Assembler::AVX_256bit);
    __ vpshufb(xmm1, xmm2, xmm1, Assembler::AVX_256bit);
    __ vpaddb(xmm0, xmm1, xmm0, Assembler::AVX_256bit);

    // Store the encoded bytes
    __ vmovdqu(Address(dest, dp), xmm0);
    __ addl(dp, 32);

    __ cmpl(length, 31);
    __ jcc(Assembler::above, L_32byteLoop);

    __ BIND(L_process3);
    __ vzeroupper();
  } else {
    __ BIND(L_process3);
  }

  __ cmpl(length, 3);
  __ jcc(Assembler::below, L_exit);

  // Load the encoding table based on isURL
  __ lea(r11, ExternalAddress(StubRoutines::x86::base64_encoding_table_addr()));
  __ movl(r15, isURL);
  __ shll(r15, 6);
  __ addptr(r11, r15);

  __ BIND(L_processdata);

  // Load 3 bytes
  __ load_unsigned_byte(r15, Address(source, start_offset));
  __ load_unsigned_byte(r10, Address(source, start_offset, Address::times_1, 1));
  __ load_unsigned_byte(r13, Address(source, start_offset, Address::times_1, 2));

  // Build a 32-bit word with bytes 1, 2, 0, 1
  __ movl(rax, r10);
  __ shll(r10, 24);
  __ orl(rax, r10);

  __ subl(length, 3);

  __ shll(r15, 8);
  __ shll(r13, 16);
  __ orl(rax, r15);

  __ addl(start_offset, 3);

  __ orl(rax, r13);
  // At this point, rax contains | byte1 | byte2 | byte0 | byte1
  // r13 has byte2 << 16 - need low-order 6 bits to translate.
  // This translated byte is the fourth output byte.
  __ shrl(r13, 16);
  __ andl(r13, 0x3f);

  // The high-order 6 bits of r15 (byte0) is translated.
  // The translated byte is the first output byte.
  __ shrl(r15, 10);

  __ load_unsigned_byte(r13, Address(r11, r13));
  __ load_unsigned_byte(r15, Address(r11, r15));

  __ movb(Address(dest, dp, Address::times_1, 3), r13);

  // Extract high-order 4 bits of byte1 and low-order 2 bits of byte0.
  // This translated byte is the second output byte.
  __ shrl(rax, 4);
  __ movl(r10, rax);
  __ andl(rax, 0x3f);

--> --------------------

--> maximum size reached

--> --------------------

94%


¤ Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.0.24Bemerkung:  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.