Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/Java/Openjdk/src/hotspot/cpu/riscv/   (Sun/Oracle ©)  Datei vom 13.11.2022 mit Größe 115 kB image not shown  

Quelle  templateTable_riscv.cpp   Sprache: C

 
/*
 * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 2014, Red Hat Inc. All rights reserved.
 * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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.inline.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/tlab_globals.hpp"
#include "interpreter/interp_masm.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "interpreter/templateTable.hpp"
#include "memory/universe.hpp"
#include "oops/method.hpp"
#include "oops/methodData.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/synchronizer.hpp"
#include "utilities/powerOfTwo.hpp"

#define __ _masm->

// Address computation: local variables

static inline Address iaddress(int n) {
  return Address(xlocals, Interpreter::local_offset_in_bytes(n));
}

static inline Address laddress(int n) {
  return iaddress(n + 1);
}

static inline Address faddress(int n) {
  return iaddress(n);
}

static inline Address daddress(int n) {
  return laddress(n);
}

static inline Address aaddress(int n) {
  return iaddress(n);
}

static inline Address iaddress(Register r, Register temp, InterpreterMacroAssembler* _masm) {
  _masm->shadd(temp, r, xlocals, temp, 3);
  return Address(temp, 0);
}

static inline Address laddress(Register r, Register temp, InterpreterMacroAssembler* _masm) {
  _masm->shadd(temp, r, xlocals, temp, 3);
  return Address(temp, Interpreter::local_offset_in_bytes(1));;
}

static inline Address faddress(Register r, Register temp, InterpreterMacroAssembler* _masm) {
  return iaddress(r, temp, _masm);
}

static inline Address daddress(Register r, Register temp, InterpreterMacroAssembler* _masm) {
  return laddress(r, temp, _masm);
}

static inline Address aaddress(Register r, Register temp, InterpreterMacroAssembler* _masm) {
  return iaddress(r, temp, _masm);
}

static inline Address at_rsp() {
  return Address(esp, 0);
}

// At top of Java expression stack which may be different than esp().  It
// isn't for category 1 objects.
static inline Address at_tos   () {
  return Address(esp,  Interpreter::expr_offset_in_bytes(0));
}

static inline Address at_tos_p1() {
  return Address(esp, Interpreter::expr_offset_in_bytes(1));
}

static inline Address at_tos_p2() {
  return Address(esp, Interpreter::expr_offset_in_bytes(2));
}

static inline Address at_tos_p3() {
  return Address(esp, Interpreter::expr_offset_in_bytes(3));
}

static inline Address at_tos_p4() {
  return Address(esp, Interpreter::expr_offset_in_bytes(4));
}

static inline Address at_tos_p5() {
  return Address(esp, Interpreter::expr_offset_in_bytes(5));
}

// Miscellaneous helper routines
// Store an oop (or NULL) at the Address described by obj.
// If val == noreg this means store a NULL
static void do_oop_store(InterpreterMacroAssembler* _masm,
                         Address dst,
                         Register val,
                         DecoratorSet decorators) {
  assert(val == noreg || val == x10, "parameter is just for looks");
  __ store_heap_oop(dst, val, x28, x29, x13, decorators);
}

static void do_oop_load(InterpreterMacroAssembler* _masm,
                        Address src,
                        Register dst,
                        DecoratorSet decorators) {
  __ load_heap_oop(dst, src, x28, x29, decorators);
}

Address TemplateTable::at_bcp(int offset) {
  assert(_desc->uses_bcp(), "inconsistent uses_bcp information");
  return Address(xbcp, offset);
}

void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg,
                                   Register temp_reg, bool load_bc_into_bc_reg /*=true*/,
                                   int byte_no) {
  if (!RewriteBytecodes) { return; }
  Label L_patch_done;

  switch (bc) {
    case Bytecodes::_fast_aputfield:  // fall through
    case Bytecodes::_fast_bputfield:  // fall through
    case Bytecodes::_fast_zputfield:  // fall through
    case Bytecodes::_fast_cputfield:  // fall through
    case Bytecodes::_fast_dputfield:  // fall through
    case Bytecodes::_fast_fputfield:  // fall through
    case Bytecodes::_fast_iputfield:  // fall through
    case Bytecodes::_fast_lputfield:  // fall through
    case Bytecodes::_fast_sputfield: {
      // We skip bytecode quickening for putfield instructions when
      // the put_code written to the constant pool cache is zero.
      // This is required so that every execution of this instruction
      // calls out to InterpreterRuntime::resolve_get_put to do
      // additional, required work.
      assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
      assert(load_bc_into_bc_reg, "we use bc_reg as temp");
      __ get_cache_and_index_and_bytecode_at_bcp(temp_reg, bc_reg, temp_reg, byte_no, 1);
      __ mv(bc_reg, bc);
      __ beqz(temp_reg, L_patch_done);
      break;
    }
    default:
      assert(byte_no == -1, "sanity");
      // the pair bytecodes have already done the load.
      if (load_bc_into_bc_reg) {
        __ mv(bc_reg, bc);
      }
  }

  if (JvmtiExport::can_post_breakpoint()) {
    Label L_fast_patch;
    // if a breakpoint is present we can't rewrite the stream directly
    __ load_unsigned_byte(temp_reg, at_bcp(0));
    __ addi(temp_reg, temp_reg, -Bytecodes::_breakpoint); // temp_reg is temporary register.
    __ bnez(temp_reg, L_fast_patch);
    // Let breakpoint table handling rewrite to quicker bytecode
    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::set_original_bytecode_at), xmethod, xbcp, bc_reg);
    __ j(L_patch_done);
    __ bind(L_fast_patch);
  }

#ifdef ASSERT
  Label L_okay;
  __ load_unsigned_byte(temp_reg, at_bcp(0));
  __ beq(temp_reg, bc_reg, L_okay);
  __ addi(temp_reg, temp_reg, -(int) Bytecodes::java_code(bc));
  __ beqz(temp_reg, L_okay);
  __ stop("patching the wrong bytecode");
  __ bind(L_okay);
#endif

  // patch bytecode
  __ sb(bc_reg, at_bcp(0));
  __ bind(L_patch_done);
}

// Individual instructions

void TemplateTable::nop() {
  transition(vtos, vtos);
  // nothing to do
}

void TemplateTable::shouldnotreachhere() {
  transition(vtos, vtos);
  __ stop("should not reach here bytecode");
}

void TemplateTable::aconst_null() {
  transition(vtos, atos);
  __ mv(x10, zr);
}

void TemplateTable::iconst(int value) {
  transition(vtos, itos);
  __ mv(x10, value);
}

void TemplateTable::lconst(int value) {
  transition(vtos, ltos);
  __ mv(x10, value);
}

void TemplateTable::fconst(int value) {
  transition(vtos, ftos);
  static float fBuf[2] = {1.0, 2.0};
  __ mv(t0, (intptr_t)fBuf);
  switch (value) {
    case 0:
      __ fmv_w_x(f10, zr);
      break;
    case 1:
      __ flw(f10, Address(t0, 0));
      break;
    case 2:
      __ flw(f10, Address(t0, sizeof(float)));
      break;
    default:
      ShouldNotReachHere();
  }
}

void TemplateTable::dconst(int value) {
  transition(vtos, dtos);
  static double dBuf[2] = {1.0, 2.0};
  __ mv(t0, (intptr_t)dBuf);
  switch (value) {
    case 0:
      __ fmv_d_x(f10, zr);
      break;
    case 1:
      __ fld(f10, Address(t0, 0));
      break;
    case 2:
      __ fld(f10, Address(t0, sizeof(double)));
      break;
    default:
      ShouldNotReachHere();
  }
}

void TemplateTable::bipush() {
  transition(vtos, itos);
  __ load_signed_byte(x10, at_bcp(1));
}

void TemplateTable::sipush() {
  transition(vtos, itos);
  __ load_unsigned_short(x10, at_bcp(1));
  __ revb_w_w(x10, x10);
  __ sraiw(x10, x10, 16);
}

void TemplateTable::ldc(LdcType type) {
  transition(vtos, vtos);
  Label call_ldc, notFloat, notClass, notInt, Done;

  if (is_ldc_wide(type)) {
   __ get_unsigned_2_byte_index_at_bcp(x11, 1);
  } else {
   __ load_unsigned_byte(x11, at_bcp(1));
  }
  __ get_cpool_and_tags(x12, x10);

  const int base_offset = ConstantPool::header_size() * wordSize;
  const int tags_offset = Array<u1>::base_offset_in_bytes();

  // get type
  __ addi(x13, x11, tags_offset);
  __ add(x13, x10, x13);
  __ membar(MacroAssembler::AnyAny);
  __ lbu(x13, Address(x13, 0));
  __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore);

  // unresolved class - get the resolved class
  __ mv(t1, (u1)JVM_CONSTANT_UnresolvedClass);
  __ beq(x13, t1, call_ldc);

  // unresolved class in error state - call into runtime to throw the error
  // from the first resolution attempt
  __ mv(t1, (u1)JVM_CONSTANT_UnresolvedClassInError);
  __ beq(x13, t1, call_ldc);

  // resolved class - need to call vm to get java mirror of the class
  __ mv(t1, (u1)JVM_CONSTANT_Class);
  __ bne(x13, t1, notClass);

  __ bind(call_ldc);
  __ mv(c_rarg1, is_ldc_wide(type) ? 1 : 0);
  call_VM(x10, CAST_FROM_FN_PTR(address, InterpreterRuntime::ldc), c_rarg1);
  __ push_ptr(x10);
  __ verify_oop(x10);
  __ j(Done);

  __ bind(notClass);
  __ mv(t1, (u1)JVM_CONSTANT_Float);
  __ bne(x13, t1, notFloat);

  // ftos
  __ shadd(x11, x11, x12, x11, 3);
  __ flw(f10, Address(x11, base_offset));
  __ push_f(f10);
  __ j(Done);

  __ bind(notFloat);

  __ mv(t1, (u1)JVM_CONSTANT_Integer);
  __ bne(x13, t1, notInt);

  // itos
  __ shadd(x11, x11, x12, x11, 3);
  __ lw(x10, Address(x11, base_offset));
  __ push_i(x10);
  __ j(Done);

  __ bind(notInt);
  condy_helper(Done);

  __ bind(Done);
}

// Fast path for caching oop constants.
void TemplateTable::fast_aldc(LdcType type) {
  transition(vtos, atos);

  const Register result = x10;
  const Register tmp = x11;
  const Register rarg = x12;

  const int index_size = is_ldc_wide(type) ? sizeof(u2) : sizeof(u1);

  Label resolved;

  // We are resolved if the resolved reference cache entry contains a
  // non-null object (String, MethodType, etc.)
  assert_different_registers(result, tmp);
  __ get_cache_index_at_bcp(tmp, 1, index_size);
  __ load_resolved_reference_at_index(result, tmp);
  __ bnez(result, resolved);

  const address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc);

  // first time invocation - must resolve first
  __ mv(rarg, (int)bytecode());
  __ call_VM(result, entry, rarg);

  __ bind(resolved);

  { // Check for the null sentinel.
    // If we just called the VM, it already did the mapping for us,
    // but it's harmless to retry.
    Label notNull;

    // Stash null_sentinel address to get its value later
    int32_t offset = 0;
    __ mv(rarg, Universe::the_null_sentinel_addr(), offset);
    __ ld(tmp, Address(rarg, offset));
    __ resolve_oop_handle(tmp, x15, t1);
    __ bne(result, tmp, notNull);
    __ mv(result, zr);  // NULL object reference
    __ bind(notNull);
  }

  if (VerifyOops) {
    // Safe to call with 0 result
    __ verify_oop(result);
  }
}

void TemplateTable::ldc2_w() {
    transition(vtos, vtos);
    Label notDouble, notLong, Done;
    __ get_unsigned_2_byte_index_at_bcp(x10, 1);

    __ get_cpool_and_tags(x11, x12);
    const int base_offset = ConstantPool::header_size() * wordSize;
    const int tags_offset = Array<u1>::base_offset_in_bytes();

    // get type
    __ add(x12, x12, x10);
    __ load_unsigned_byte(x12, Address(x12, tags_offset));
    __ mv(t1, JVM_CONSTANT_Double);
    __ bne(x12, t1, notDouble);

    // dtos
    __ shadd(x12, x10, x11, x12, 3);
    __ fld(f10, Address(x12, base_offset));
    __ push_d(f10);
    __ j(Done);

    __ bind(notDouble);
    __ mv(t1, (int)JVM_CONSTANT_Long);
    __ bne(x12, t1, notLong);

    // ltos
    __ shadd(x10, x10, x11, x10, 3);
    __ ld(x10, Address(x10, base_offset));
    __ push_l(x10);
    __ j(Done);

    __ bind(notLong);
    condy_helper(Done);
    __ bind(Done);
}

void TemplateTable::condy_helper(Label& Done) {
  const Register obj = x10;
  const Register rarg = x11;
  const Register flags = x12;
  const Register off = x13;

  const address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc);

  __ mv(rarg, (int) bytecode());
  __ call_VM(obj, entry, rarg);

  __ get_vm_result_2(flags, xthread);

  // VMr = obj = base address to find primitive value to push
  // VMr2 = flags = (tos, off) using format of CPCE::_flags
  __ mv(off, flags);
  __ mv(t0, ConstantPoolCacheEntry::field_index_mask);
  __ andrw(off, off, t0);

  __ add(off, obj, off);
  const Address field(off, 0); // base + R---->base + offset

  __ slli(flags, flags, XLEN - (ConstantPoolCacheEntry::tos_state_shift + ConstantPoolCacheEntry::tos_state_bits));
  __ srli(flags, flags, XLEN - ConstantPoolCacheEntry::tos_state_bits); // (1 << 5) - 4 --> 28~31==> flags:0~3

  switch (bytecode()) {
    case Bytecodes::_ldc:   // fall through
    case Bytecodes::_ldc_w: {
      // tos in (itos, ftos, stos, btos, ctos, ztos)
      Label notInt, notFloat, notShort, notByte, notChar, notBool;
      __ mv(t1, itos);
      __ bne(flags, t1, notInt);
      // itos
      __ lw(x10, field);
      __ push(itos);
      __ j(Done);

      __ bind(notInt);
      __ mv(t1, ftos);
      __ bne(flags, t1, notFloat);
      // ftos
      __ load_float(field);
      __ push(ftos);
      __ j(Done);

      __ bind(notFloat);
      __ mv(t1, stos);
      __ bne(flags, t1, notShort);
      // stos
      __ load_signed_short(x10, field);
      __ push(stos);
      __ j(Done);

      __ bind(notShort);
      __ mv(t1, btos);
      __ bne(flags, t1, notByte);
      // btos
      __ load_signed_byte(x10, field);
      __ push(btos);
      __ j(Done);

      __ bind(notByte);
      __ mv(t1, ctos);
      __ bne(flags, t1, notChar);
      // ctos
      __ load_unsigned_short(x10, field);
      __ push(ctos);
      __ j(Done);

      __ bind(notChar);
      __ mv(t1, ztos);
      __ bne(flags, t1, notBool);
      // ztos
      __ load_signed_byte(x10, field);
      __ push(ztos);
      __ j(Done);

      __ bind(notBool);
      break;
    }

    case Bytecodes::_ldc2_w: {
      Label notLong, notDouble;
      __ mv(t1, ltos);
      __ bne(flags, t1, notLong);
      // ltos
      __ ld(x10, field);
      __ push(ltos);
      __ j(Done);

      __ bind(notLong);
      __ mv(t1, dtos);
      __ bne(flags, t1, notDouble);
      // dtos
      __ load_double(field);
      __ push(dtos);
      __ j(Done);

      __ bind(notDouble);
      break;
    }

    default:
      ShouldNotReachHere();
  }

  __ stop("bad ldc/condy");
}

void TemplateTable::locals_index(Register reg, int offset) {
  __ lbu(reg, at_bcp(offset));
  __ neg(reg, reg);
}

void TemplateTable::iload() {
  iload_internal();
}

void TemplateTable::nofast_iload() {
  iload_internal(may_not_rewrite);
}

void TemplateTable::iload_internal(RewriteControl rc) {
  transition(vtos, itos);
  if (RewriteFrequentPairs && rc == may_rewrite) {
    Label rewrite, done;
    const Register bc = x14;

    // get next bytecode
    __ load_unsigned_byte(x11, at_bcp(Bytecodes::length_for(Bytecodes::_iload)));

    // if _iload, wait to rewrite to iload2.  We only want to rewrite the
    // last two iloads in a pair.  Comparing against fast_iload means that
    // the next bytecode is neither an iload or a caload, and therefore
    // an iload pair.
    __ mv(t1, Bytecodes::_iload);
    __ beq(x11, t1, done);

    // if _fast_iload rewrite to _fast_iload2
    __ mv(t1, Bytecodes::_fast_iload);
    __ mv(bc, Bytecodes::_fast_iload2);
    __ beq(x11, t1, rewrite);

    // if _caload rewrite to _fast_icaload
    __ mv(t1, Bytecodes::_caload);
    __ mv(bc, Bytecodes::_fast_icaload);
    __ beq(x11, t1, rewrite);

    // else rewrite to _fast_iload
    __ mv(bc, Bytecodes::_fast_iload);

    // rewrite
    // bc: new bytecode
    __ bind(rewrite);
    patch_bytecode(Bytecodes::_iload, bc, x11, false);
    __ bind(done);

  }

  // do iload, get the local value into tos
  locals_index(x11);
  __ lw(x10, iaddress(x11, x10, _masm));
}

void TemplateTable::fast_iload2() {
  transition(vtos, itos);
  locals_index(x11);
  __ lw(x10, iaddress(x11, x10, _masm));
  __ push(itos);
  locals_index(x11, 3);
  __ lw(x10, iaddress(x11, x10, _masm));
}

void TemplateTable::fast_iload() {
  transition(vtos, itos);
  locals_index(x11);
  __ lw(x10, iaddress(x11, x10, _masm));
}

void TemplateTable::lload() {
  transition(vtos, ltos);
  __ lbu(x11, at_bcp(1));
  __ slli(x11, x11, LogBytesPerWord);
  __ sub(x11, xlocals, x11);
  __ ld(x10, Address(x11, Interpreter::local_offset_in_bytes(1)));
}

void TemplateTable::fload() {
  transition(vtos, ftos);
  locals_index(x11);
  __ flw(f10, faddress(x11, t0, _masm));
}

void TemplateTable::dload() {
  transition(vtos, dtos);
  __ lbu(x11, at_bcp(1));
  __ slli(x11, x11, LogBytesPerWord);
  __ sub(x11, xlocals, x11);
  __ fld(f10, Address(x11, Interpreter::local_offset_in_bytes(1)));
}

void TemplateTable::aload() {
  transition(vtos, atos);
  locals_index(x11);
  __ ld(x10, iaddress(x11, x10, _masm));
}

void TemplateTable::locals_index_wide(Register reg) {
  __ lhu(reg, at_bcp(2));
  __ revb_h_h_u(reg, reg); // reverse bytes in half-word and zero-extend
  __ neg(reg, reg);
}

void TemplateTable::wide_iload() {
  transition(vtos, itos);
  locals_index_wide(x11);
  __ lw(x10, iaddress(x11, t0, _masm));
}

void TemplateTable::wide_lload() {
  transition(vtos, ltos);
  __ lhu(x11, at_bcp(2));
  __ revb_h_h_u(x11, x11); // reverse bytes in half-word and zero-extend
  __ slli(x11, x11, LogBytesPerWord);
  __ sub(x11, xlocals, x11);
  __ ld(x10, Address(x11, Interpreter::local_offset_in_bytes(1)));
}

void TemplateTable::wide_fload() {
  transition(vtos, ftos);
  locals_index_wide(x11);
  __ flw(f10, faddress(x11, t0, _masm));
}

void TemplateTable::wide_dload() {
  transition(vtos, dtos);
  __ lhu(x11, at_bcp(2));
  __ revb_h_h_u(x11, x11); // reverse bytes in half-word and zero-extend
  __ slli(x11, x11, LogBytesPerWord);
  __ sub(x11, xlocals, x11);
  __ fld(f10, Address(x11, Interpreter::local_offset_in_bytes(1)));
}

void TemplateTable::wide_aload() {
  transition(vtos, atos);
  locals_index_wide(x11);
  __ ld(x10, aaddress(x11, t0, _masm));
}

void TemplateTable::index_check(Register array, Register index) {
  // destroys x11, t0
  // check array
  __ null_check(array, arrayOopDesc::length_offset_in_bytes());
  // sign extend index for use by indexed load
  // check index
  const Register length = t0;
  __ lwu(length, Address(array, arrayOopDesc::length_offset_in_bytes()));
  if (index != x11) {
    assert(x11 != array, "different registers");
    __ mv(x11, index);
  }
  Label ok;
  __ addw(index, index, zr);
  __ bltu(index, length, ok);
  __ mv(x13, array);
  __ mv(t0, Interpreter::_throw_ArrayIndexOutOfBoundsException_entry);
  __ jr(t0);
  __ bind(ok);
}

void TemplateTable::iaload() {
  transition(itos, itos);
  __ mv(x11, x10);
  __ pop_ptr(x10);
  // x10: array
  // x11: index
  index_check(x10, x11); // leaves index in x11
  __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_INT) >> 2);
  __ shadd(x10, x11, x10, t0, 2);
  __ access_load_at(T_INT, IN_HEAP | IS_ARRAY, x10, Address(x10), noreg, noreg);
  __ addw(x10, x10, zr); // signed extended
}

void TemplateTable::laload() {
  transition(itos, ltos);
  __ mv(x11, x10);
  __ pop_ptr(x10);
  // x10: array
  // x11: index
  index_check(x10, x11); // leaves index in x11
  __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_LONG) >> 3);
  __ shadd(x10, x11, x10, t0, 3);
  __ access_load_at(T_LONG, IN_HEAP | IS_ARRAY, x10, Address(x10), noreg, noreg);
}

void TemplateTable::faload() {
  transition(itos, ftos);
  __ mv(x11, x10);
  __ pop_ptr(x10);
  // x10: array
  // x11: index
  index_check(x10, x11); // leaves index in x11
  __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_FLOAT) >> 2);
  __ shadd(x10, x11, x10, t0, 2);
  __ access_load_at(T_FLOAT, IN_HEAP | IS_ARRAY, x10, Address(x10), noreg, noreg);
}

void TemplateTable::daload() {
  transition(itos, dtos);
  __ mv(x11, x10);
  __ pop_ptr(x10);
  // x10: array
  // x11: index
  index_check(x10, x11); // leaves index in x11
  __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_DOUBLE) >> 3);
  __ shadd(x10, x11, x10, t0, 3);
  __ access_load_at(T_DOUBLE, IN_HEAP | IS_ARRAY, x10, Address(x10), noreg, noreg);
}

void TemplateTable::aaload() {
  transition(itos, atos);
  __ mv(x11, x10);
  __ pop_ptr(x10);
  // x10: array
  // x11: index
  index_check(x10, x11); // leaves index in x11
  __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_OBJECT) >> LogBytesPerHeapOop);
  __ shadd(x10, x11, x10, t0, LogBytesPerHeapOop);
  do_oop_load(_masm, Address(x10), x10, IS_ARRAY);
}

void TemplateTable::baload() {
  transition(itos, itos);
  __ mv(x11, x10);
  __ pop_ptr(x10);
  // x10: array
  // x11: index
  index_check(x10, x11); // leaves index in x11
  __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_BYTE) >> 0);
  __ shadd(x10, x11, x10, t0, 0);
  __ access_load_at(T_BYTE, IN_HEAP | IS_ARRAY, x10, Address(x10), noreg, noreg);
}

void TemplateTable::caload() {
  transition(itos, itos);
  __ mv(x11, x10);
  __ pop_ptr(x10);
  // x10: array
  // x11: index
  index_check(x10, x11); // leaves index in x11
  __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_CHAR) >> 1);
  __ shadd(x10, x11, x10, t0, 1);
  __ access_load_at(T_CHAR, IN_HEAP | IS_ARRAY, x10, Address(x10), noreg, noreg);
}

// iload followed by caload frequent pair
void TemplateTable::fast_icaload() {
  transition(vtos, itos);
  // load index out of locals
  locals_index(x12);
  __ lw(x11, iaddress(x12, x11, _masm));
  __ pop_ptr(x10);

  // x10: array
  // x11: index
  index_check(x10, x11); // leaves index in x11, kills t0
  __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_CHAR) >> 1); // addi, max imm is 2^11
  __ shadd(x10, x11, x10, t0, 1);
  __ access_load_at(T_CHAR, IN_HEAP | IS_ARRAY, x10, Address(x10), noreg, noreg);
}

void TemplateTable::saload() {
  transition(itos, itos);
  __ mv(x11, x10);
  __ pop_ptr(x10);
  // x10: array
  // x11: index
  index_check(x10, x11); // leaves index in x11, kills t0
  __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_SHORT) >> 1);
  __ shadd(x10, x11, x10, t0, 1);
  __ access_load_at(T_SHORT, IN_HEAP | IS_ARRAY, x10, Address(x10), noreg, noreg);
}

void TemplateTable::iload(int n) {
  transition(vtos, itos);
  __ lw(x10, iaddress(n));
}

void TemplateTable::lload(int n) {
  transition(vtos, ltos);
  __ ld(x10, laddress(n));
}

void TemplateTable::fload(int n) {
  transition(vtos, ftos);
  __ flw(f10, faddress(n));
}

void TemplateTable::dload(int n) {
  transition(vtos, dtos);
  __ fld(f10, daddress(n));
}

void TemplateTable::aload(int n) {
  transition(vtos, atos);
  __ ld(x10, iaddress(n));
}

void TemplateTable::aload_0() {
  aload_0_internal();
}

void TemplateTable::nofast_aload_0() {
  aload_0_internal(may_not_rewrite);
}

void TemplateTable::aload_0_internal(RewriteControl rc) {
  // According to bytecode histograms, the pairs:
  //
  // _aload_0, _fast_igetfield
  // _aload_0, _fast_agetfield
  // _aload_0, _fast_fgetfield
  //
  // occur frequently. If RewriteFrequentPairs is set, the (slow)
  // _aload_0 bytecode checks if the next bytecode is either
  // _fast_igetfield, _fast_agetfield or _fast_fgetfield and then
  // rewrites the current bytecode into a pair bytecode; otherwise it
  // rewrites the current bytecode into _fast_aload_0 that doesn't do
  // the pair check anymore.
  //
  // Note: If the next bytecode is _getfield, the rewrite must be
  //       delayed, otherwise we may miss an opportunity for a pair.
  //
  // Also rewrite frequent pairs
  //   aload_0, aload_1
  //   aload_0, iload_1
  // These bytecodes with a small amount of code are most profitable
  // to rewrite
  if (RewriteFrequentPairs && rc == may_rewrite) {
    Label rewrite, done;
    const Register bc = x14;

    // get next bytecode
    __ load_unsigned_byte(x11, at_bcp(Bytecodes::length_for(Bytecodes::_aload_0)));

    // if _getfield then wait with rewrite
    __ mv(t1, Bytecodes::Bytecodes::_getfield);
    __ beq(x11, t1, done);

    // if _igetfield then rewrite to _fast_iaccess_0
    assert(Bytecodes::java_code(Bytecodes::_fast_iaccess_0) == Bytecodes::_aload_0, "fix bytecode definition");
    __ mv(t1, Bytecodes::_fast_igetfield);
    __ mv(bc, Bytecodes::_fast_iaccess_0);
    __ beq(x11, t1, rewrite);

    // if _agetfield then rewrite to _fast_aaccess_0
    assert(Bytecodes::java_code(Bytecodes::_fast_aaccess_0) == Bytecodes::_aload_0, "fix bytecode definition");
    __ mv(t1, Bytecodes::_fast_agetfield);
    __ mv(bc, Bytecodes::_fast_aaccess_0);
    __ beq(x11, t1, rewrite);

    // if _fgetfield then rewrite to _fast_faccess_0
    assert(Bytecodes::java_code(Bytecodes::_fast_faccess_0) == Bytecodes::_aload_0, "fix bytecode definition");
    __ mv(t1, Bytecodes::_fast_fgetfield);
    __ mv(bc, Bytecodes::_fast_faccess_0);
    __ beq(x11, t1, rewrite);

    // else rewrite to _fast_aload0
    assert(Bytecodes::java_code(Bytecodes::_fast_aload_0) == Bytecodes::_aload_0, "fix bytecode definition");
    __ mv(bc, Bytecodes::Bytecodes::_fast_aload_0);

    // rewrite
    // bc: new bytecode
    __ bind(rewrite);
    patch_bytecode(Bytecodes::_aload_0, bc, x11, false);

    __ bind(done);
  }

  // Do actual aload_0 (must do this after patch_bytecode which might call VM and GC might change oop).
  aload(0);
}

void TemplateTable::istore() {
  transition(itos, vtos);
  locals_index(x11);
  __ sw(x10, iaddress(x11, t0, _masm));
}

void TemplateTable::lstore() {
  transition(ltos, vtos);
  locals_index(x11);
  __ sd(x10, laddress(x11, t0, _masm));
}

void TemplateTable::fstore() {
  transition(ftos, vtos);
  locals_index(x11);
  __ fsw(f10, iaddress(x11, t0, _masm));
}

void TemplateTable::dstore() {
  transition(dtos, vtos);
  locals_index(x11);
  __ fsd(f10, daddress(x11, t0, _masm));
}

void TemplateTable::astore() {
  transition(vtos, vtos);
  __ pop_ptr(x10);
  locals_index(x11);
  __ sd(x10, aaddress(x11, t0, _masm));
}

void TemplateTable::wide_istore() {
  transition(vtos, vtos);
  __ pop_i();
  locals_index_wide(x11);
  __ sw(x10, iaddress(x11, t0, _masm));
}

void TemplateTable::wide_lstore() {
  transition(vtos, vtos);
  __ pop_l();
  locals_index_wide(x11);
  __ sd(x10, laddress(x11, t0, _masm));
}

void TemplateTable::wide_fstore() {
  transition(vtos, vtos);
  __ pop_f();
  locals_index_wide(x11);
  __ fsw(f10, faddress(x11, t0, _masm));
}

void TemplateTable::wide_dstore() {
  transition(vtos, vtos);
  __ pop_d();
  locals_index_wide(x11);
  __ fsd(f10, daddress(x11, t0, _masm));
}

void TemplateTable::wide_astore() {
  transition(vtos, vtos);
  __ pop_ptr(x10);
  locals_index_wide(x11);
  __ sd(x10, aaddress(x11, t0, _masm));
}

void TemplateTable::iastore() {
  transition(itos, vtos);
  __ pop_i(x11);
  __ pop_ptr(x13);
  // x10: value
  // x11: index
  // x13: array
  index_check(x13, x11); // prefer index in x11
  __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_INT) >> 2);
  __ shadd(t0, x11, x13, t0, 2);
  __ access_store_at(T_INT, IN_HEAP | IS_ARRAY, Address(t0, 0), x10, noreg, noreg, noreg);
}

void TemplateTable::lastore() {
  transition(ltos, vtos);
  __ pop_i(x11);
  __ pop_ptr(x13);
  // x10: value
  // x11: index
  // x13: array
  index_check(x13, x11); // prefer index in x11
  __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_LONG) >> 3);
  __ shadd(t0, x11, x13, t0, 3);
  __ access_store_at(T_LONG, IN_HEAP | IS_ARRAY, Address(t0, 0), x10, noreg, noreg, noreg);
}

void TemplateTable::fastore() {
  transition(ftos, vtos);
  __ pop_i(x11);
  __ pop_ptr(x13);
  // f10: value
  // x11:  index
  // x13:  array
  index_check(x13, x11); // prefer index in x11
  __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_FLOAT) >> 2);
  __ shadd(t0, x11, x13, t0, 2);
  __ access_store_at(T_FLOAT, IN_HEAP | IS_ARRAY, Address(t0, 0), noreg /* ftos */, noreg, noreg, noreg);
}

void TemplateTable::dastore() {
  transition(dtos, vtos);
  __ pop_i(x11);
  __ pop_ptr(x13);
  // f10: value
  // x11:  index
  // x13:  array
  index_check(x13, x11); // prefer index in x11
  __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_DOUBLE) >> 3);
  __ shadd(t0, x11, x13, t0, 3);
  __ access_store_at(T_DOUBLE, IN_HEAP | IS_ARRAY, Address(t0, 0), noreg /* dtos */, noreg, noreg, noreg);
}

void TemplateTable::aastore() {
  Label is_null, ok_is_subtype, done;
  transition(vtos, vtos);
  // stack: ..., array, index, value
  __ ld(x10, at_tos());    // value
  __ ld(x12, at_tos_p1()); // index
  __ ld(x13, at_tos_p2()); // array

  index_check(x13, x12);     // kills x11
  __ add(x14, x12, arrayOopDesc::base_offset_in_bytes(T_OBJECT) >> LogBytesPerHeapOop);
  __ shadd(x14, x14, x13, x14, LogBytesPerHeapOop);

  Address element_address(x14, 0);

  // do array store check - check for NULL value first
  __ beqz(x10, is_null);

  // Move subklass into x11
  __ load_klass(x11, x10);
  // Move superklass into x10
  __ load_klass(x10, x13);
  __ ld(x10, Address(x10,
                     ObjArrayKlass::element_klass_offset()));
  // Compress array + index * oopSize + 12 into a single register.  Frees x12.

  // Generate subtype check.  Blows x12, x15
  // Superklass in x10.  Subklass in x11.
  __ gen_subtype_check(x11, ok_is_subtype);

  // Come here on failure
  // object is at TOS
  __ j(Interpreter::_throw_ArrayStoreException_entry);

  // Come here on success
  __ bind(ok_is_subtype);

  // Get the value we will store
  __ ld(x10, at_tos());
  // Now store using the appropriate barrier
  do_oop_store(_masm, element_address, x10, IS_ARRAY);
  __ j(done);

  // Have a NULL in x10, x13=array, x12=index.  Store NULL at ary[idx]
  __ bind(is_null);
  __ profile_null_seen(x12);

  // Store a NULL
  do_oop_store(_masm, element_address, noreg, IS_ARRAY);

  // Pop stack arguments
  __ bind(done);
  __ add(esp, esp, 3 * Interpreter::stackElementSize);
}

void TemplateTable::bastore() {
  transition(itos, vtos);
  __ pop_i(x11);
  __ pop_ptr(x13);
  // x10: value
  // x11: index
  // x13: array
  index_check(x13, x11); // prefer index in x11

  // Need to check whether array is boolean or byte
  // since both types share the bastore bytecode.
  __ load_klass(x12, x13);
  __ lwu(x12, Address(x12, Klass::layout_helper_offset()));
  Label L_skip;
  __ andi(t0, x12, Klass::layout_helper_boolean_diffbit());
  __ beqz(t0, L_skip);
  __ andi(x10, x10, 1);  // if it is a T_BOOLEAN array, mask the stored value to 0/1
  __ bind(L_skip);

  __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_BYTE) >> 0);

  __ add(x11, x13, x11);
  __ access_store_at(T_BYTE, IN_HEAP | IS_ARRAY, Address(x11, 0), x10, noreg, noreg, noreg);
}

void TemplateTable::castore() {
  transition(itos, vtos);
  __ pop_i(x11);
  __ pop_ptr(x13);
  // x10: value
  // x11: index
  // x13: array
  index_check(x13, x11); // prefer index in x11
  __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_CHAR) >> 1);
  __ shadd(t0, x11, x13, t0, 1);
  __ access_store_at(T_CHAR, IN_HEAP | IS_ARRAY, Address(t0, 0), x10, noreg, noreg, noreg);
}

void TemplateTable::sastore() {
  castore();
}

void TemplateTable::istore(int n) {
  transition(itos, vtos);
  __ sd(x10, iaddress(n));
}

void TemplateTable::lstore(int n) {
  transition(ltos, vtos);
  __ sd(x10, laddress(n));
}

void TemplateTable::fstore(int n) {
  transition(ftos, vtos);
  __ fsw(f10, faddress(n));
}

void TemplateTable::dstore(int n) {
  transition(dtos, vtos);
  __ fsd(f10, daddress(n));
}

void TemplateTable::astore(int n) {
  transition(vtos, vtos);
  __ pop_ptr(x10);
  __ sd(x10, iaddress(n));
}

void TemplateTable::pop() {
  transition(vtos, vtos);
  __ addi(esp, esp, Interpreter::stackElementSize);
}

void TemplateTable::pop2() {
  transition(vtos, vtos);
  __ addi(esp, esp, 2 * Interpreter::stackElementSize);
}

void TemplateTable::dup() {
  transition(vtos, vtos);
  __ ld(x10, Address(esp, 0));
  __ push_reg(x10);
  // stack: ..., a, a
}

void TemplateTable::dup_x1() {
  transition(vtos, vtos);
  // stack: ..., a, b
  __ ld(x10, at_tos());  // load b
  __ ld(x12, at_tos_p1());  // load a
  __ sd(x10, at_tos_p1());  // store b
  __ sd(x12, at_tos());  // store a
  __ push_reg(x10);                  // push b
  // stack: ..., b, a, b
}

void TemplateTable::dup_x2() {
  transition(vtos, vtos);
  // stack: ..., a, b, c
  __ ld(x10, at_tos());  // load c
  __ ld(x12, at_tos_p2());  // load a
  __ sd(x10, at_tos_p2());  // store c in a
  __ push_reg(x10);      // push c
  // stack: ..., c, b, c, c
  __ ld(x10, at_tos_p2());  // load b
  __ sd(x12, at_tos_p2());  // store a in b
  // stack: ..., c, a, c, c
  __ sd(x10, at_tos_p1());  // store b in c
  // stack: ..., c, a, b, c
}

void TemplateTable::dup2() {
  transition(vtos, vtos);
  // stack: ..., a, b
  __ ld(x10, at_tos_p1());  // load a
  __ push_reg(x10);                  // push a
  __ ld(x10, at_tos_p1());  // load b
  __ push_reg(x10);                  // push b
  // stack: ..., a, b, a, b
}

void TemplateTable::dup2_x1() {
  transition(vtos, vtos);
  // stack: ..., a, b, c
  __ ld(x12, at_tos());     // load c
  __ ld(x10, at_tos_p1());  // load b
  __ push_reg(x10);             // push b
  __ push_reg(x12);             // push c
  // stack: ..., a, b, c, b, c
  __ sd(x12, at_tos_p3());  // store c in b
  // stack: ..., a, c, c, b, c
  __ ld(x12, at_tos_p4());  // load a
  __ sd(x12, at_tos_p2());  // store a in 2nd c
  // stack: ..., a, c, a, b, c
  __ sd(x10, at_tos_p4());  // store b in a
  // stack: ..., b, c, a, b, c
}

void TemplateTable::dup2_x2() {
  transition(vtos, vtos);
  // stack: ..., a, b, c, d
  __ ld(x12, at_tos());     // load d
  __ ld(x10, at_tos_p1());  // load c
  __ push_reg(x10);             // push c
  __ push_reg(x12);             // push d
  // stack: ..., a, b, c, d, c, d
  __ ld(x10, at_tos_p4());  // load b
  __ sd(x10, at_tos_p2());  // store b in d
  __ sd(x12, at_tos_p4());  // store d in b
  // stack: ..., a, d, c, b, c, d
  __ ld(x12, at_tos_p5());  // load a
  __ ld(x10, at_tos_p3());  // load c
  __ sd(x12, at_tos_p3());  // store a in c
  __ sd(x10, at_tos_p5());  // store c in a
  // stack: ..., c, d, a, b, c, d
}

void TemplateTable::swap() {
  transition(vtos, vtos);
  // stack: ..., a, b
  __ ld(x12, at_tos_p1());  // load a
  __ ld(x10, at_tos());     // load b
  __ sd(x12, at_tos());     // store a in b
  __ sd(x10, at_tos_p1());  // store b in a
  // stack: ..., b, a
}

void TemplateTable::iop2(Operation op) {
  transition(itos, itos);
  // x10 <== x11 op x10
  __ pop_i(x11);
  switch (op) {
    case add  : __ addw(x10, x11, x10);  break;
    case sub  : __ subw(x10, x11, x10);  break;
    case mul  : __ mulw(x10, x11, x10);  break;
    case _and : __ andrw(x10, x11, x10); break;
    case _or  : __ orrw(x10, x11, x10);  break;
    case _xor : __ xorrw(x10, x11, x10); break;
    case shl  : __ sllw(x10, x11, x10);  break;
    case shr  : __ sraw(x10, x11, x10);  break;
    case ushr : __ srlw(x10, x11, x10);  break;
    default   : ShouldNotReachHere();
  }
}

void TemplateTable::lop2(Operation op) {
  transition(ltos, ltos);
  // x10 <== x11 op x10
  __ pop_l(x11);
  switch (op) {
    case add  : __ add(x10, x11, x10);  break;
    case sub  : __ sub(x10, x11, x10);  break;
    case mul  : __ mul(x10, x11, x10);  break;
    case _and : __ andr(x10, x11, x10); break;
    case _or  : __ orr(x10, x11, x10);  break;
    case _xor : __ xorr(x10, x11, x10); break;
    default   : ShouldNotReachHere();
  }
}

void TemplateTable::idiv() {
  transition(itos, itos);
  // explicitly check for div0
  Label no_div0;
  __ bnez(x10, no_div0);
  __ mv(t0, Interpreter::_throw_ArithmeticException_entry);
  __ jr(t0);
  __ bind(no_div0);
  __ pop_i(x11);
  // x10 <== x11 idiv x10
  __ corrected_idivl(x10, x11, x10, /* want_remainder */ false);
}

void TemplateTable::irem() {
  transition(itos, itos);
  // explicitly check for div0
  Label no_div0;
  __ bnez(x10, no_div0);
  __ mv(t0, Interpreter::_throw_ArithmeticException_entry);
  __ jr(t0);
  __ bind(no_div0);
  __ pop_i(x11);
  // x10 <== x11 irem x10
  __ corrected_idivl(x10, x11, x10, /* want_remainder */ true);
}

void TemplateTable::lmul() {
  transition(ltos, ltos);
  __ pop_l(x11);
  __ mul(x10, x10, x11);
}

void TemplateTable::ldiv() {
  transition(ltos, ltos);
  // explicitly check for div0
  Label no_div0;
  __ bnez(x10, no_div0);
  __ mv(t0, Interpreter::_throw_ArithmeticException_entry);
  __ jr(t0);
  __ bind(no_div0);
  __ pop_l(x11);
  // x10 <== x11 ldiv x10
  __ corrected_idivq(x10, x11, x10, /* want_remainder */ false);
}

void TemplateTable::lrem() {
  transition(ltos, ltos);
  // explicitly check for div0
  Label no_div0;
  __ bnez(x10, no_div0);
  __ mv(t0, Interpreter::_throw_ArithmeticException_entry);
  __ jr(t0);
  __ bind(no_div0);
  __ pop_l(x11);
  // x10 <== x11 lrem x10
  __ corrected_idivq(x10, x11, x10, /* want_remainder */ true);
}

void TemplateTable::lshl() {
  transition(itos, ltos);
  // shift count is in x10
  __ pop_l(x11);
  __ sll(x10, x11, x10);
}

void TemplateTable::lshr() {
  transition(itos, ltos);
  // shift count is in x10
  __ pop_l(x11);
  __ sra(x10, x11, x10);
}

void TemplateTable::lushr() {
  transition(itos, ltos);
  // shift count is in x10
  __ pop_l(x11);
  __ srl(x10, x11, x10);
}

void TemplateTable::fop2(Operation op) {
  transition(ftos, ftos);
  switch (op) {
    case add:
      __ pop_f(f11);
      __ fadd_s(f10, f11, f10);
      break;
    case sub:
      __ pop_f(f11);
      __ fsub_s(f10, f11, f10);
      break;
    case mul:
      __ pop_f(f11);
      __ fmul_s(f10, f11, f10);
      break;
    case div:
      __ pop_f(f11);
      __ fdiv_s(f10, f11, f10);
      break;
    case rem:
      __ fmv_s(f11, f10);
      __ pop_f(f10);
      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::frem));
      break;
    default:
      ShouldNotReachHere();
  }
}

void TemplateTable::dop2(Operation op) {
  transition(dtos, dtos);
  switch (op) {
    case add:
      __ pop_d(f11);
      __ fadd_d(f10, f11, f10);
      break;
    case sub:
      __ pop_d(f11);
      __ fsub_d(f10, f11, f10);
      break;
    case mul:
      __ pop_d(f11);
      __ fmul_d(f10, f11, f10);
      break;
    case div:
      __ pop_d(f11);
      __ fdiv_d(f10, f11, f10);
      break;
    case rem:
      __ fmv_d(f11, f10);
      __ pop_d(f10);
      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::drem));
      break;
    default:
      ShouldNotReachHere();
  }
}

void TemplateTable::ineg() {
  transition(itos, itos);
  __ negw(x10, x10);
}

void TemplateTable::lneg() {
  transition(ltos, ltos);
  __ neg(x10, x10);
}

void TemplateTable::fneg() {
  transition(ftos, ftos);
  __ fneg_s(f10, f10);
}

void TemplateTable::dneg() {
  transition(dtos, dtos);
  __ fneg_d(f10, f10);
}

void TemplateTable::iinc() {
  transition(vtos, vtos);
  __ load_signed_byte(x11, at_bcp(2)); // get constant
  locals_index(x12);
  __ ld(x10, iaddress(x12, x10, _masm));
  __ addw(x10, x10, x11);
  __ sd(x10, iaddress(x12, t0, _masm));
}

void TemplateTable::wide_iinc() {
  transition(vtos, vtos);
  __ lwu(x11, at_bcp(2)); // get constant and index
  __ revb_h_w_u(x11, x11); // reverse bytes in half-word (32bit) and zero-extend
  __ zero_extend(x12, x11, 16);
  __ neg(x12, x12);
  __ slli(x11, x11, 32);
  __ srai(x11, x11, 48);
  __ ld(x10, iaddress(x12, t0, _masm));
  __ addw(x10, x10, x11);
  __ sd(x10, iaddress(x12, t0, _masm));
}

void TemplateTable::convert() {
  // Checking
#ifdef ASSERT
  {
    TosState tos_in  = ilgl;
    TosState tos_out = ilgl;
    switch (bytecode()) {
      case Bytecodes::_i2l: // fall through
      case Bytecodes::_i2f: // fall through
      case Bytecodes::_i2d: // fall through
      case Bytecodes::_i2b: // fall through
      case Bytecodes::_i2c: // fall through
      case Bytecodes::_i2s: tos_in = itos; break;
      case Bytecodes::_l2i: // fall through
      case Bytecodes::_l2f: // fall through
      case Bytecodes::_l2d: tos_in = ltos; break;
      case Bytecodes::_f2i: // fall through
      case Bytecodes::_f2l: // fall through
      case Bytecodes::_f2d: tos_in = ftos; break;
      case Bytecodes::_d2i: // fall through
      case Bytecodes::_d2l: // fall through
      case Bytecodes::_d2f: tos_in = dtos; break;
      default             : ShouldNotReachHere();
    }
    switch (bytecode()) {
      case Bytecodes::_l2i: // fall through
      case Bytecodes::_f2i: // fall through
      case Bytecodes::_d2i: // fall through
      case Bytecodes::_i2b: // fall through
      case Bytecodes::_i2c: // fall through
      case Bytecodes::_i2s: tos_out = itos; break;
      case Bytecodes::_i2l: // fall through
      case Bytecodes::_f2l: // fall through
      case Bytecodes::_d2l: tos_out = ltos; break;
      case Bytecodes::_i2f: // fall through
      case Bytecodes::_l2f: // fall through
      case Bytecodes::_d2f: tos_out = ftos; break;
      case Bytecodes::_i2d: // fall through
      case Bytecodes::_l2d: // fall through
      case Bytecodes::_f2d: tos_out = dtos; break;
      default             : ShouldNotReachHere();
    }
    transition(tos_in, tos_out);
  }
#endif // ASSERT

  // Conversion
  switch (bytecode()) {
    case Bytecodes::_i2l:
      __ sign_extend(x10, x10, 32);
      break;
    case Bytecodes::_i2f:
      __ fcvt_s_w(f10, x10);
      break;
    case Bytecodes::_i2d:
      __ fcvt_d_w(f10, x10);
      break;
    case Bytecodes::_i2b:
      __ sign_extend(x10, x10, 8);
      break;
    case Bytecodes::_i2c:
      __ zero_extend(x10, x10, 16);
      break;
    case Bytecodes::_i2s:
      __ sign_extend(x10, x10, 16);
      break;
    case Bytecodes::_l2i:
      __ addw(x10, x10, zr);
      break;
    case Bytecodes::_l2f:
      __ fcvt_s_l(f10, x10);
      break;
    case Bytecodes::_l2d:
      __ fcvt_d_l(f10, x10);
      break;
    case Bytecodes::_f2i:
      __ fcvt_w_s_safe(x10, f10);
      break;
    case Bytecodes::_f2l:
      __ fcvt_l_s_safe(x10, f10);
      break;
    case Bytecodes::_f2d:
      __ fcvt_d_s(f10, f10);
      break;
    case Bytecodes::_d2i:
      __ fcvt_w_d_safe(x10, f10);
      break;
    case Bytecodes::_d2l:
      __ fcvt_l_d_safe(x10, f10);
      break;
    case Bytecodes::_d2f:
      __ fcvt_s_d(f10, f10);
      break;
    default:
      ShouldNotReachHere();
  }
}

void TemplateTable::lcmp() {
  transition(ltos, itos);
  __ pop_l(x11);
  __ cmp_l2i(t0, x11, x10);
  __ mv(x10, t0);
}

void TemplateTable::float_cmp(bool is_float, int unordered_result) {
  // For instruction feq, flt and fle, the result is 0 if either operand is NaN
  if (is_float) {
    __ pop_f(f11);
    // if unordered_result < 0:
    //   we want -1 for unordered or less than, 0 for equal and 1 for
    //   greater than.
    // else:
    //   we want -1 for less than, 0 for equal and 1 for unordered or
    //   greater than.
    // f11 primary, f10 secondary
    __ float_compare(x10, f11, f10, unordered_result);
  } else {
    __ pop_d(f11);
    // if unordered_result < 0:
    //   we want -1 for unordered or less than, 0 for equal and 1 for
    //   greater than.
    // else:
    //   we want -1 for less than, 0 for equal and 1 for unordered or
    //   greater than.
    // f11 primary, f10 secondary
    __ double_compare(x10, f11, f10, unordered_result);
  }
}

void TemplateTable::branch(bool is_jsr, bool is_wide) {
  // We might be moving to a safepoint.  The thread which calls
  // Interpreter::notice_safepoints() will effectively flush its cache
  // when it makes a system call, but we need to do something to
  // ensure that we see the changed dispatch table.
  __ membar(MacroAssembler::LoadLoad);

  __ profile_taken_branch(x10, x11);
  const ByteSize be_offset = MethodCounters::backedge_counter_offset() +
                             InvocationCounter::counter_offset();
  const ByteSize inv_offset = MethodCounters::invocation_counter_offset() +
                              InvocationCounter::counter_offset();

  // load branch displacement
  if (!is_wide) {
    __ lhu(x12, at_bcp(1));
    __ revb_h_h(x12, x12); // reverse bytes in half-word and sign-extend
  } else {
    __ lwu(x12, at_bcp(1));
    __ revb_w_w(x12, x12); // reverse bytes in word and sign-extend
  }

  // Handle all the JSR stuff here, then exit.
  // It's much shorter and cleaner than intermingling with the non-JSR
  // normal-branch stuff occurring below.

  if (is_jsr) {
    // compute return address as bci
    __ ld(t1, Address(xmethod, Method::const_offset()));
    __ add(t1, t1,
           in_bytes(ConstMethod::codes_offset()) - (is_wide ? 5 : 3));
    __ sub(x11, xbcp, t1);
    __ push_i(x11);
    // Adjust the bcp by the 16-bit displacement in x12
    __ add(xbcp, xbcp, x12);
    __ load_unsigned_byte(t0, Address(xbcp, 0));
    // load the next target bytecode into t0, it is the argument of dispatch_only
    __ dispatch_only(vtos, /*generate_poll*/true);
    return;
  }

  // Normal (non-jsr) branch handling

  // Adjust the bcp by the displacement in x12
  __ add(xbcp, xbcp, x12);

  assert(UseLoopCounter || !UseOnStackReplacement,
         "on-stack-replacement requires loop counters");
  Label backedge_counter_overflow;
  Label dispatch;
  if (UseLoopCounter) {
    // increment backedge counter for backward branches
    // x10: MDO
    // x11: MDO bumped taken-count
    // x12: target offset
    __ bgtz(x12, dispatch); // count only if backward branch

    // check if MethodCounters exists
    Label has_counters;
    __ ld(t0, Address(xmethod, Method::method_counters_offset()));
    __ bnez(t0, has_counters);
    __ push_reg(x10);
    __ push_reg(x11);
    __ push_reg(x12);
    __ call_VM(noreg, CAST_FROM_FN_PTR(address,
            InterpreterRuntime::build_method_counters), xmethod);
    __ pop_reg(x12);
    __ pop_reg(x11);
    __ pop_reg(x10);
    __ ld(t0, Address(xmethod, Method::method_counters_offset()));
    __ beqz(t0, dispatch); // No MethodCounters allocated, OutOfMemory
    __ bind(has_counters);

    Label no_mdo;
    int increment = InvocationCounter::count_increment;
    if (ProfileInterpreter) {
      // Are we profiling?
      __ ld(x11, Address(xmethod, in_bytes(Method::method_data_offset())));
      __ beqz(x11, no_mdo);
      // Increment the MDO backedge counter
      const Address mdo_backedge_counter(x11, in_bytes(MethodData::backedge_counter_offset()) +
                                         in_bytes(InvocationCounter::counter_offset()));
      const Address mask(x11, in_bytes(MethodData::backedge_mask_offset()));
      __ increment_mask_and_jump(mdo_backedge_counter, increment, mask,
                                 x10, t0, false,
                                 UseOnStackReplacement ? &backedge_counter_overflow : &dispatch);
      __ j(dispatch);
    }
    __ bind(no_mdo);
    // Increment backedge counter in MethodCounters*
    __ ld(t0, Address(xmethod, Method::method_counters_offset()));
    const Address mask(t0, in_bytes(MethodCounters::backedge_mask_offset()));
    __ increment_mask_and_jump(Address(t0, be_offset), increment, mask,
                               x10, t1, false,
                               UseOnStackReplacement ? &backedge_counter_overflow : &dispatch);
    __ bind(dispatch);
  }

  // Pre-load the next target bytecode into t0
  __ load_unsigned_byte(t0, Address(xbcp, 0));

  // continue with the bytecode @ target
  // t0: target bytecode
  // xbcp: target bcp
  __ dispatch_only(vtos, /*generate_poll*/true);

  if (UseLoopCounter && UseOnStackReplacement) {
    // invocation counter overflow
    __ bind(backedge_counter_overflow);
    __ neg(x12, x12);
    __ add(x12, x12, xbcp);     // branch xbcp
    // IcoResult frequency_counter_overflow([JavaThread*], address branch_bcp)
    __ call_VM(noreg,
               CAST_FROM_FN_PTR(address,
                                InterpreterRuntime::frequency_counter_overflow),
               x12);
    __ load_unsigned_byte(x11, Address(xbcp, 0));  // restore target bytecode

    // x10: osr nmethod (osr ok) or NULL (osr not possible)
    // w11: target bytecode
    // x12: temporary
    __ beqz(x10, dispatch);     // test result -- no osr if null
    // nmethod may have been invalidated (VM may block upon call_VM return)
    __ lbu(x12, Address(x10, nmethod::state_offset()));
    if (nmethod::in_use != 0) {
      __ sub(x12, x12, nmethod::in_use);
    }
    __ bnez(x12, dispatch);

    // We have the address of an on stack replacement routine in x10
    // We need to prepare to execute the OSR method. First we must
    // migrate the locals and monitors off of the stack.

    __ mv(x9, x10);                             // save the nmethod

    call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin));

    // x10 is OSR buffer, move it to expected parameter location
    __ mv(j_rarg0, x10);

    // remove activation
    // get sender esp
    __ ld(esp,
        Address(fp, frame::interpreter_frame_sender_sp_offset * wordSize));
    // remove frame anchor
    __ leave();
    // Ensure compiled code always sees stack at proper alignment
    __ andi(sp, esp, -16);

    // and begin the OSR nmethod
    __ ld(t0, Address(x9, nmethod::osr_entry_point_offset()));
    __ jr(t0);
  }
}

void TemplateTable::if_0cmp(Condition cc) {
  transition(itos, vtos);
  // assume branch is more often taken than not (loops use backward branches)
  Label not_taken;

  __ addw(x10, x10, zr);
  switch (cc) {
    case equal:
      __ bnez(x10, not_taken);
      break;
    case not_equal:
      __ beqz(x10, not_taken);
      break;
    case less:
      __ bgez(x10, not_taken);
      break;
    case less_equal:
      __ bgtz(x10, not_taken);
      break;
    case greater:
      __ blez(x10, not_taken);
      break;
    case greater_equal:
      __ bltz(x10, not_taken);
      break;
    default:
      break;
  }

  branch(falsefalse);
  __ bind(not_taken);
  __ profile_not_taken_branch(x10);
}

void TemplateTable::if_icmp(Condition cc) {
  transition(itos, vtos);
  // assume branch is more often taken than not (loops use backward branches)
  Label not_taken;
  __ pop_i(x11);
  __ addw(x10, x10, zr);
  switch (cc) {
    case equal:
      __ bne(x11, x10, not_taken);
      break;
    case not_equal:
      __ beq(x11, x10, not_taken);
      break;
    case less:
      __ bge(x11, x10, not_taken);
      break;
    case less_equal:
      __ bgt(x11, x10, not_taken);
      break;
    case greater:
      __ ble(x11, x10, not_taken);
      break;
    case greater_equal:
      __ blt(x11, x10, not_taken);
      break;
    default:
      break;
  }

  branch(falsefalse);
  __ bind(not_taken);
  __ profile_not_taken_branch(x10);
}

void TemplateTable::if_nullcmp(Condition cc) {
  transition(atos, vtos);
  // assume branch is more often taken than not (loops use backward branches)
  Label not_taken;
  if (cc == equal) {
    __ bnez(x10, not_taken);
  } else {
    __ beqz(x10, not_taken);
  }
  branch(falsefalse);
  __ bind(not_taken);
  __ profile_not_taken_branch(x10);
}

void TemplateTable::if_acmp(Condition cc) {
  transition(atos, vtos);
  // assume branch is more often taken than not (loops use backward branches)
  Label not_taken;
  __ pop_ptr(x11);

  if (cc == equal) {
    __ bne(x11, x10, not_taken);
  } else if (cc == not_equal) {
    __ beq(x11, x10, not_taken);
  }
  branch(falsefalse);
  __ bind(not_taken);
  __ profile_not_taken_branch(x10);
}

void TemplateTable::ret() {
  transition(vtos, vtos);
  // We might be moving to a safepoint.  The thread which calls
  // Interpreter::notice_safepoints() will effectively flush its cache
  // when it makes a system call, but we need to do something to
  // ensure that we see the changed dispatch table.
  __ membar(MacroAssembler::LoadLoad);

  locals_index(x11);
  __ ld(x11, aaddress(x11, t1, _masm)); // get return bci, compute return bcp
  __ profile_ret(x11, x12);
  __ ld(xbcp, Address(xmethod, Method::const_offset()));
  __ add(xbcp, xbcp, x11);
  __ addi(xbcp, xbcp, in_bytes(ConstMethod::codes_offset()));
  __ dispatch_next(vtos, 0, /*generate_poll*/true);
}

void TemplateTable::wide_ret() {
  transition(vtos, vtos);
  locals_index_wide(x11);
  __ ld(x11, aaddress(x11, t0, _masm)); // get return bci, compute return bcp
  __ profile_ret(x11, x12);
  __ ld(xbcp, Address(xmethod, Method::const_offset()));
  __ add(xbcp, xbcp, x11);
  __ add(xbcp, xbcp, in_bytes(ConstMethod::codes_offset()));
  __ dispatch_next(vtos, 0, /*generate_poll*/true);
}

void TemplateTable::tableswitch() {
  Label default_case, continue_execution;
  transition(itos, vtos);
  // align xbcp
  __ la(x11, at_bcp(BytesPerInt));
  __ andi(x11, x11, -BytesPerInt);
  // load lo & hi
  __ lwu(x12, Address(x11, BytesPerInt));
  __ lwu(x13, Address(x11, 2 * BytesPerInt));
  __ revb_w_w(x12, x12); // reverse bytes in word (32bit) and sign-extend
  __ revb_w_w(x13, x13); // reverse bytes in word (32bit) and sign-extend
  // check against lo & hi
  __ blt(x10, x12, default_case);
  __ bgt(x10, x13, default_case);
  // lookup dispatch offset
  __ subw(x10, x10, x12);
  __ shadd(x13, x10, x11, t0, 2);
  __ lwu(x13, Address(x13, 3 * BytesPerInt));
  __ profile_switch_case(x10, x11, x12);
  // continue execution
  __ bind(continue_execution);
  __ revb_w_w(x13, x13); // reverse bytes in word (32bit) and sign-extend
  __ add(xbcp, xbcp, x13);
  __ load_unsigned_byte(t0, Address(xbcp));
  __ dispatch_only(vtos, /*generate_poll*/true);
  // handle default
  __ bind(default_case);
  __ profile_switch_default(x10);
  __ lwu(x13, Address(x11, 0));
  __ j(continue_execution);
}

void TemplateTable::lookupswitch() {
  transition(itos, itos);
  __ stop("lookupswitch bytecode should have been rewritten");
}

void TemplateTable::fast_linearswitch() {
  transition(itos, vtos);
  Label loop_entry, loop, found, continue_execution;
  // bswap x10 so we can avoid bswapping the table entries
  __ revb_w_w(x10, x10); // reverse bytes in word (32bit) and sign-extend
  // align xbcp
  __ la(x9, at_bcp(BytesPerInt)); // btw: should be able to get rid of
                                    // this instruction (change offsets
                                    // below)
  __ andi(x9, x9, -BytesPerInt);
  // set counter
  __ lwu(x11, Address(x9, BytesPerInt));
  __ revb_w(x11, x11);
  __ j(loop_entry);
  // table search
  __ bind(loop);
  __ shadd(t0, x11, x9, t0, 3);
  __ lw(t0, Address(t0, 2 * BytesPerInt));
  __ beq(x10, t0, found);
  __ bind(loop_entry);
  __ addi(x11, x11, -1);
  __ bgez(x11, loop);
  // default case
  __ profile_switch_default(x10);
  __ lwu(x13, Address(x9, 0));
  __ j(continue_execution);
  // entry found -> get offset
  __ bind(found);
  __ shadd(t0, x11, x9, t0, 3);
  __ lwu(x13, Address(t0, 3 * BytesPerInt));
  __ profile_switch_case(x11, x10, x9);
  // continue execution
  __ bind(continue_execution);
  __ revb_w_w(x13, x13); // reverse bytes in word (32bit) and sign-extend
  __ add(xbcp, xbcp, x13);
  __ lbu(t0, Address(xbcp, 0));
  __ dispatch_only(vtos, /*generate_poll*/true);
}

void TemplateTable::fast_binaryswitch() {
  transition(itos, vtos);
  // Implementation using the following core algorithm:
  //
  // int binary_search(int key, LookupswitchPair* array, int n)
  //   binary_search start:
  //   #Binary search according to "Methodik des Programmierens" by
  //   # Edsger W. Dijkstra and W.H.J. Feijen, Addison Wesley Germany 1985.
  //   int i = 0;
  //   int j = n;
  //   while (i + 1 < j) do
  //     # invariant P: 0 <= i < j <= n and (a[i] <= key < a[j] or Q)
  //     # with      Q: for all i: 0 <= i < n: key < a[i]
  //     # where a stands for the array and assuming that the (inexisting)
  //     # element a[n] is infinitely big.
  //     int h = (i + j) >> 1
  //     # i < h < j
  //     if (key < array[h].fast_match())
  //     then [j = h]
  //     else [i = h]
  //   end
  //   # R: a[i] <= key < a[i+1] or Q
  //   # (i.e., if key is within array, i is the correct index)
  //   return i
  // binary_search end


  // Register allocation
  const Register key   = x10; // already set (tosca)
  const Register array = x11;
  const Register i     = x12;
  const Register j     = x13;
  const Register h     = x14;
  const Register temp  = x15;

  // Find array start
  __ la(array, at_bcp(3 * BytesPerInt));  // btw: should be able to
                                          // get rid of this
                                          // instruction (change
                                          // offsets below)
  __ andi(array, array, -BytesPerInt);

  // Initialize i & j
  __ mv(i, zr);                            // i = 0
  __ lwu(j, Address(array, -BytesPerInt)); // j = length(array)

  // Convert j into native byteordering
  __ revb_w(j, j);

  // And start
  Label entry;
  __ j(entry);

  // binary search loop
  {
    Label loop;
    __ bind(loop);
    __ addw(h, i, j);                           // h = i + j
    __ srliw(h, h, 1);                          // h = (i + j) >> 1
    // if [key < array[h].fast_match()]
    // then [j = h]
    // else [i = h]
    // Convert array[h].match to native byte-ordering before compare
    __ shadd(temp, h, array, temp, 3);
    __ ld(temp, Address(temp, 0));
    __ revb_w_w(temp, temp); // reverse bytes in word (32bit) and sign-extend

    Label L_done, L_greater;
    __ bge(key, temp, L_greater);
    // if [key < array[h].fast_match()] then j = h
    __ mv(j, h);
    __ j(L_done);
    __ bind(L_greater);
    // if [key >= array[h].fast_match()] then i = h
    __ mv(i, h);
    __ bind(L_done);

    // while [i + 1 < j]
    __ bind(entry);
    __ addiw(h, i, 1);         // i + 1
    __ blt(h, j, loop);        // i + 1 < j
  }

  // end of binary search, result index is i (must check again!)
  Label default_case;
  // Convert array[i].match to native byte-ordering before compare
  __ shadd(temp, i, array, temp, 3);
  __ ld(temp, Address(temp, 0));
  __ revb_w_w(temp, temp); // reverse bytes in word (32bit) and sign-extend
  __ bne(key, temp, default_case);

  // entry found -> j = offset
  __ shadd(temp, i, array, temp, 3);
  __ lwu(j, Address(temp, BytesPerInt));
  __ profile_switch_case(i, key, array);
  __ revb_w_w(j, j); // reverse bytes in word (32bit) and sign-extend

  __ add(temp, xbcp, j);
  __ load_unsigned_byte(t0, Address(temp, 0));

  __ add(xbcp, xbcp, j);
  __ la(xbcp, Address(xbcp, 0));
  __ dispatch_only(vtos, /*generate_poll*/true);

  // default case -> j = default offset
  __ bind(default_case);
  __ profile_switch_default(i);
  __ lwu(j, Address(array, -2 * BytesPerInt));
  __ revb_w_w(j, j); // reverse bytes in word (32bit) and sign-extend

  __ add(temp, xbcp, j);
  __ load_unsigned_byte(t0, Address(temp, 0));

  __ add(xbcp, xbcp, j);
  __ la(xbcp, Address(xbcp, 0));
  __ dispatch_only(vtos, /*generate_poll*/true);
}

void TemplateTable::_return(TosState state) {
  transition(state, state);
  assert(_desc->calls_vm(),
         "inconsistent calls_vm information"); // call in remove_activation

  if (_desc->bytecode() == Bytecodes::_return_register_finalizer) {
    assert(state == vtos, "only valid state");

    __ ld(c_rarg1, aaddress(0));
    __ load_klass(x13, c_rarg1);
    __ lwu(x13, Address(x13, Klass::access_flags_offset()));
    Label skip_register_finalizer;
    __ andi(t0, x13, JVM_ACC_HAS_FINALIZER);
    __ beqz(t0, skip_register_finalizer);

    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), c_rarg1);

    __ bind(skip_register_finalizer);
  }

  // Issue a StoreStore barrier after all stores but before return
  // from any constructor for any class with a final field. We don't
  // know if this is a finalizer, so we always do so.
  if (_desc->bytecode() == Bytecodes::_return) {
    __ membar(MacroAssembler::StoreStore);
  }

  // Narrow result if state is itos but result type is smaller.
  // Need to narrow in the return bytecode rather than in generate_return_entry
  // since compiled code callers expect the result to already be narrowed.
  if (state == itos) {
    __ narrow(x10);
  }

  __ remove_activation(state);
  __ ret();
}


// ----------------------------------------------------------------------------
// Volatile variables demand their effects be made known to all CPU's
// in order.  Store buffers on most chips allow reads & writes to
// reorder; the JMM's ReadAfterWrite.java test fails in -Xint mode
// without some kind of memory barrier (i.e., it's not sufficient that
// the interpreter does not reorder volatile references, the hardware
// also must not reorder them).
//
// According to the new Java Memory Model (JMM):
// (1) All volatiles are serialized wrt to each other.  ALSO reads &
//     writes act as acquire & release, so:
// (2) A read cannot let unrelated NON-volatile memory refs that
//     happen after the read float up to before the read.  It's OK for
//     non-volatile memory refs that happen before the volatile read to
//     float down below it.
// (3) Similar a volatile write cannot let unrelated NON-volatile
//     memory refs that happen BEFORE the write float down to after the
//     write.  It's OK for non-volatile memory refs that happen after the
//     volatile write to float up before it.
//
// We only put in barriers around volatile refs (they are expensive),
// not _between_ memory refs (that would require us to track the
// flavor of the previous memory refs).  Requirements (2) and (3)
// require some barriers before volatile stores and after volatile
// loads.  These nearly cover requirement (1) but miss the
// volatile-store-volatile-load case.  This final case is placed after
// volatile-stores although it could just as well go before
// volatile-loads.

void TemplateTable::resolve_cache_and_index(int byte_no,
                                            Register Rcache,
                                            Register index,
                                            size_t index_size) {
  const Register temp = x9;
  assert_different_registers(Rcache, index, temp);

  Label resolved, clinit_barrier_slow;

  Bytecodes::Code code = bytecode();
  switch (code) {
    case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break;
    case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break;
    defaultbreak;
  }

  assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
  __ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, temp, byte_no, 1, index_size);
  __ mv(t0, (int) code);
  __ beq(temp, t0, resolved);

  // resolve first time through
  // Class initialization barrier slow path lands here as well.
  __ bind(clinit_barrier_slow);

  address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
  __ mv(temp, (int) code);
  __ call_VM(noreg, entry, temp);

  // Update registers with resolved info
  __ get_cache_and_index_at_bcp(Rcache, index, 1, index_size);
  // n.b. unlike x86 Rcache is now rcpool plus the indexed offset
  // so all clients ofthis method must be modified accordingly
  __ bind(resolved);

  // Class initialization barrier for static methods
  if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) {
    __ load_resolved_method_at_index(byte_no, temp, Rcache);
    __ load_method_holder(temp, temp);
    __ clinit_barrier(temp, t0, NULL, &clinit_barrier_slow);
  }
}

// The Rcache and index registers must be set before call
// n.b unlike x86 cache already includes the index offset
void TemplateTable::load_field_cp_cache_entry(Register obj,
                                              Register cache,
                                              Register index,
                                              Register off,
                                              Register flags,
                                              bool is_static = false) {
  assert_different_registers(cache, index, flags, off);

  ByteSize cp_base_offset = ConstantPoolCache::base_offset();
  // Field offset
  __ ld(off, Address(cache, in_bytes(cp_base_offset +
                                     ConstantPoolCacheEntry::f2_offset())));
  // Flags
  __ lwu(flags, Address(cache, in_bytes(cp_base_offset +
                                        ConstantPoolCacheEntry::flags_offset())));

  // klass overwrite register
  if (is_static) {
    __ ld(obj, Address(cache, in_bytes(cp_base_offset +
                                       ConstantPoolCacheEntry::f1_offset())));
    const int mirror_offset = in_bytes(Klass::java_mirror_offset());
    __ ld(obj, Address(obj, mirror_offset));
--> --------------------

--> maximum size reached

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

91%


¤ Dauer der Verarbeitung: 0.26 Sekunden  (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.