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

Quelle  templateTable_ppc_64.cpp   Sprache: C

 
/*
 * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 2013, 2022 SAP SE. 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/tlab_globals.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "interpreter/interp_masm.hpp"
#include "interpreter/templateInterpreter.hpp"
#include "interpreter/templateTable.hpp"
#include "memory/universe.hpp"
#include "oops/klass.inline.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/safepointMechanism.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/vm_version.hpp"
#include "utilities/macros.hpp"
#include "utilities/powerOfTwo.hpp"

#undef __
#define __ _masm->

// ============================================================================
// Misc helpers

// Do an oop store like *(base + index) = val OR *(base + offset) = val
// (only one of both variants is possible at the same time).
// Index can be noreg.
// Kills:
//   Rbase, Rtmp
static void do_oop_store(InterpreterMacroAssembler* _masm,
                         Register           base,
                         RegisterOrConstant offset,
                         Register           val,         // Noreg means always null.
                         Register           tmp1,
                         Register           tmp2,
                         Register           tmp3,
                         DecoratorSet       decorators) {
  assert_different_registers(tmp1, tmp2, tmp3, val, base);
  __ store_heap_oop(val, offset, base, tmp1, tmp2, tmp3, MacroAssembler::PRESERVATION_NONE, decorators);
}

static void do_oop_load(InterpreterMacroAssembler* _masm,
                        Register base,
                        RegisterOrConstant offset,
                        Register dst,
                        Register tmp1,
                        Register tmp2,
                        DecoratorSet decorators) {
  assert_different_registers(base, tmp1, tmp2);
  assert_different_registers(dst, tmp1, tmp2);
  __ load_heap_oop(dst, offset, base, tmp1, tmp2, MacroAssembler::PRESERVATION_NONE, decorators);
}

Address TemplateTable::at_bcp(int offset) {
  // Not used on ppc.
  ShouldNotReachHere();
  return Address();
}

// Patches the current bytecode (ptr to it located in bcp)
// in the bytecode stream with a new one.
void TemplateTable::patch_bytecode(Bytecodes::Code new_bc, Register Rnew_bc, Register Rtemp, bool load_bc_into_bc_reg /*=true*/, int byte_no) {
  // With sharing on, may need to test method flag.
  if (!RewriteBytecodes) return;
  Label L_patch_done;

  switch (new_bc) {
    case Bytecodes::_fast_aputfield:
    case Bytecodes::_fast_bputfield:
    case Bytecodes::_fast_zputfield:
    case Bytecodes::_fast_cputfield:
    case Bytecodes::_fast_dputfield:
    case Bytecodes::_fast_fputfield:
    case Bytecodes::_fast_iputfield:
    case Bytecodes::_fast_lputfield:
    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_at_bcp(Rtemp /* dst = cache */, 1);
      // ((*(cache+indices))>>((1+byte_no)*8))&0xFF:
#if defined(VM_LITTLE_ENDIAN)
      __ lbz(Rnew_bc, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 1 + byte_no, Rtemp);
#else
      __ lbz(Rnew_bc, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 7 - (1 + byte_no), Rtemp);
#endif
      __ cmpwi(CCR0, Rnew_bc, 0);
      __ li(Rnew_bc, (unsigned int)(unsigned char)new_bc);
      __ beq(CCR0, L_patch_done);
      // __ isync(); // acquire not needed
      break;
    }

    default:
      assert(byte_no == -1, "sanity");
      if (load_bc_into_bc_reg) {
        __ li(Rnew_bc, (unsigned int)(unsigned char)new_bc);
      }
  }

  if (JvmtiExport::can_post_breakpoint()) {
    Label L_fast_patch;
    __ lbz(Rtemp, 0, R14_bcp);
    __ cmpwi(CCR0, Rtemp, (unsigned int)(unsigned char)Bytecodes::_breakpoint);
    __ bne(CCR0, L_fast_patch);
    // Perform the quickening, slowly, in the bowels of the breakpoint table.
    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::set_original_bytecode_at), R19_method, R14_bcp, Rnew_bc);
    __ b(L_patch_done);
    __ bind(L_fast_patch);
  }

  // Patch bytecode.
  __ stb(Rnew_bc, 0, R14_bcp);

  __ bind(L_patch_done);
}

// ============================================================================
// Individual instructions

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

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

void TemplateTable::aconst_null() {
  transition(vtos, atos);
  __ li(R17_tos, 0);
}

void TemplateTable::iconst(int value) {
  transition(vtos, itos);
  assert(value >= -1 && value <= 5, "");
  __ li(R17_tos, value);
}

void TemplateTable::lconst(int value) {
  transition(vtos, ltos);
  assert(value >= -1 && value <= 5, "");
  __ li(R17_tos, value);
}

void TemplateTable::fconst(int value) {
  transition(vtos, ftos);
  static float zero = 0.0;
  static float one  = 1.0;
  static float two  = 2.0;
  switch (value) {
    default: ShouldNotReachHere();
    case 0: {
      int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&zero, R0, true);
      __ lfs(F15_ftos, simm16_offset, R11_scratch1);
      break;
    }
    case 1: {
      int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&one, R0, true);
      __ lfs(F15_ftos, simm16_offset, R11_scratch1);
      break;
    }
    case 2: {
      int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&two, R0, true);
      __ lfs(F15_ftos, simm16_offset, R11_scratch1);
      break;
    }
  }
}

void TemplateTable::dconst(int value) {
  transition(vtos, dtos);
  static double zero = 0.0;
  static double one  = 1.0;
  switch (value) {
    case 0: {
      int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&zero, R0, true);
      __ lfd(F15_ftos, simm16_offset, R11_scratch1);
      break;
    }
    case 1: {
      int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&one, R0, true);
      __ lfd(F15_ftos, simm16_offset, R11_scratch1);
      break;
    }
    default: ShouldNotReachHere();
  }
}

void TemplateTable::bipush() {
  transition(vtos, itos);
  __ lbz(R17_tos, 1, R14_bcp);
  __ extsb(R17_tos, R17_tos);
}

void TemplateTable::sipush() {
  transition(vtos, itos);
  __ get_2_byte_integer_at_bcp(1, R17_tos, InterpreterMacroAssembler::Signed);
}

void TemplateTable::ldc(LdcType type) {
  Register Rscratch1 = R11_scratch1,
           Rscratch2 = R12_scratch2,
           Rcpool    = R3_ARG1;

  transition(vtos, vtos);
  Label notInt, notFloat, notClass, exit;

  __ get_cpool_and_tags(Rcpool, Rscratch2); // Set Rscratch2 = &tags.
  if (is_ldc_wide(type)) { // Read index.
    __ get_2_byte_integer_at_bcp(1, Rscratch1, InterpreterMacroAssembler::Unsigned);
  } else {
    __ lbz(Rscratch1, 1, R14_bcp);
  }

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

  // Get type from tags.
  __ addi(Rscratch2, Rscratch2, tags_offset);
  __ lbzx(Rscratch2, Rscratch2, Rscratch1);

  __ cmpwi(CCR0, Rscratch2, JVM_CONSTANT_UnresolvedClass); // Unresolved class?
  __ cmpwi(CCR1, Rscratch2, JVM_CONSTANT_UnresolvedClassInError); // Unresolved class in error state?
  __ cror(CCR0, Assembler::equal, CCR1, Assembler::equal);

  // Resolved class - need to call vm to get java mirror of the class.
  __ cmpwi(CCR1, Rscratch2, JVM_CONSTANT_Class);
  __ crnor(CCR0, Assembler::equal, CCR1, Assembler::equal); // Neither resolved class nor unresolved case from above?
  __ beq(CCR0, notClass);

  __ li(R4, is_ldc_wide(type) ? 1 : 0);
  call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::ldc), R4);
  __ push(atos);
  __ b(exit);

  __ align(32, 12);
  __ bind(notClass);
  __ addi(Rcpool, Rcpool, base_offset);
  __ sldi(Rscratch1, Rscratch1, LogBytesPerWord);
  __ cmpdi(CCR0, Rscratch2, JVM_CONSTANT_Integer);
  __ bne(CCR0, notInt);
  __ lwax(R17_tos, Rcpool, Rscratch1);
  __ push(itos);
  __ b(exit);

  __ align(32, 12);
  __ bind(notInt);
  __ cmpdi(CCR0, Rscratch2, JVM_CONSTANT_Float);
  __ bne(CCR0, notFloat);
  __ lfsx(F15_ftos, Rcpool, Rscratch1);
  __ push(ftos);
  __ b(exit);

  __ align(32, 12);
  // assume the tag is for condy; if not, the VM runtime will tell us
  __ bind(notFloat);
  condy_helper(exit);

  __ align(32, 12);
  __ bind(exit);
}

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

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

  // We are resolved if the resolved reference cache entry contains a
  // non-null object (CallSite, etc.)
  __ get_cache_index_at_bcp(R31, 1, index_size);  // Load index.
  __ load_resolved_reference_at_index(R17_tos, R31, R11_scratch1, R12_scratch2, &is_null);

  // Convert null sentinel to NULL
  int simm16_rest = __ load_const_optimized(R11_scratch1, Universe::the_null_sentinel_addr(), R0, true);
  __ ld(R31, simm16_rest, R11_scratch1);
  __ resolve_oop_handle(R31, R11_scratch1, R12_scratch2, MacroAssembler::PRESERVATION_NONE);
  __ cmpld(CCR0, R17_tos, R31);
  if (VM_Version::has_isel()) {
    __ isel_0(R17_tos, CCR0, Assembler::equal);
  } else {
    Label not_sentinel;
    __ bne(CCR0, not_sentinel);
    __ li(R17_tos, 0);
    __ bind(not_sentinel);
  }
  __ verify_oop(R17_tos);
  __ dispatch_epilog(atos, Bytecodes::length_for(bytecode()));

  __ bind(is_null);
  __ load_const_optimized(R3_ARG1, (int)bytecode());

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

  // First time invocation - must resolve first.
  __ call_VM(R17_tos, entry, R3_ARG1);
  __ verify_oop(R17_tos);
}

void TemplateTable::ldc2_w() {
  transition(vtos, vtos);
  Label not_double, not_long, exit;

  Register Rindex = R11_scratch1,
           Rcpool = R12_scratch2,
           Rtag   = R3_ARG1;
  __ get_cpool_and_tags(Rcpool, Rtag);
  __ get_2_byte_integer_at_bcp(1, Rindex, InterpreterMacroAssembler::Unsigned);

  const int base_offset = ConstantPool::header_size() * wordSize;
  const int tags_offset = Array<u1>::base_offset_in_bytes();
  // Get type from tags.
  __ addi(Rcpool, Rcpool, base_offset);
  __ addi(Rtag, Rtag, tags_offset);

  __ lbzx(Rtag, Rtag, Rindex);
  __ sldi(Rindex, Rindex, LogBytesPerWord);

  __ cmpdi(CCR0, Rtag, JVM_CONSTANT_Double);
  __ bne(CCR0, not_double);
  __ lfdx(F15_ftos, Rcpool, Rindex);
  __ push(dtos);
  __ b(exit);

  __ bind(not_double);
  __ cmpdi(CCR0, Rtag, JVM_CONSTANT_Long);
  __ bne(CCR0, not_long);
  __ ldx(R17_tos, Rcpool, Rindex);
  __ push(ltos);
  __ b(exit);

  __ bind(not_long);
  condy_helper(exit);

  __ align(32, 12);
  __ bind(exit);
}

void TemplateTable::condy_helper(Label& Done) {
  const Register obj   = R31;
  const Register off   = R11_scratch1;
  const Register flags = R12_scratch2;
  const Register rarg  = R4_ARG2;
  __ li(rarg, (int)bytecode());
  call_VM(obj, CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc), rarg);
  __ get_vm_result_2(flags);

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

  // What sort of thing are we loading?
  __ rldicl(flags, flags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits);

  switch (bytecode()) {
  case Bytecodes::_ldc:
  case Bytecodes::_ldc_w:
    {
      // tos in (itos, ftos, stos, btos, ctos, ztos)
      Label notInt, notFloat, notShort, notByte, notChar, notBool;
      __ cmplwi(CCR0, flags, itos);
      __ bne(CCR0, notInt);
      // itos
      __ lwax(R17_tos, obj, off);
      __ push(itos);
      __ b(Done);

      __ bind(notInt);
      __ cmplwi(CCR0, flags, ftos);
      __ bne(CCR0, notFloat);
      // ftos
      __ lfsx(F15_ftos, obj, off);
      __ push(ftos);
      __ b(Done);

      __ bind(notFloat);
      __ cmplwi(CCR0, flags, stos);
      __ bne(CCR0, notShort);
      // stos
      __ lhax(R17_tos, obj, off);
      __ push(stos);
      __ b(Done);

      __ bind(notShort);
      __ cmplwi(CCR0, flags, btos);
      __ bne(CCR0, notByte);
      // btos
      __ lbzx(R17_tos, obj, off);
      __ extsb(R17_tos, R17_tos);
      __ push(btos);
      __ b(Done);

      __ bind(notByte);
      __ cmplwi(CCR0, flags, ctos);
      __ bne(CCR0, notChar);
      // ctos
      __ lhzx(R17_tos, obj, off);
      __ push(ctos);
      __ b(Done);

      __ bind(notChar);
      __ cmplwi(CCR0, flags, ztos);
      __ bne(CCR0, notBool);
      // ztos
      __ lbzx(R17_tos, obj, off);
      __ push(ztos);
      __ b(Done);

      __ bind(notBool);
      break;
    }

  case Bytecodes::_ldc2_w:
    {
      Label notLong, notDouble;
      __ cmplwi(CCR0, flags, ltos);
      __ bne(CCR0, notLong);
      // ltos
      __ ldx(R17_tos, obj, off);
      __ push(ltos);
      __ b(Done);

      __ bind(notLong);
      __ cmplwi(CCR0, flags, dtos);
      __ bne(CCR0, notDouble);
      // dtos
      __ lfdx(F15_ftos, obj, off);
      __ push(dtos);
      __ b(Done);

      __ bind(notDouble);
      break;
    }

  default:
    ShouldNotReachHere();
  }

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

// Get the locals index located in the bytecode stream at bcp + offset.
void TemplateTable::locals_index(Register Rdst, int offset) {
  __ lbz(Rdst, offset, R14_bcp);
}

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

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

void TemplateTable::iload_internal(RewriteControl rc) {
  transition(vtos, itos);

  // Get the local value into tos
  const Register Rindex = R22_tmp2;
  locals_index(Rindex);

  // Rewrite iload,iload  pair into fast_iload2
  //         iload,caload pair into fast_icaload
  if (RewriteFrequentPairs && rc == may_rewrite) {
    Label Lrewrite, Ldone;
    Register Rnext_byte  = R3_ARG1,
             Rrewrite_to = R6_ARG4,
             Rscratch    = R11_scratch1;

    // get next byte
    __ lbz(Rnext_byte, Bytecodes::length_for(Bytecodes::_iload), R14_bcp);

    // 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.
    __ cmpwi(CCR0, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_iload);
    __ beq(CCR0, Ldone);

    __ cmpwi(CCR1, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_fast_iload);
    __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_iload2);
    __ beq(CCR1, Lrewrite);

    __ cmpwi(CCR0, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_caload);
    __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_icaload);
    __ beq(CCR0, Lrewrite);

    __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_iload);

    __ bind(Lrewrite);
    patch_bytecode(Bytecodes::_iload, Rrewrite_to, Rscratch, false);
    __ bind(Ldone);
  }

  __ load_local_int(R17_tos, Rindex, Rindex);
}

// Load 2 integers in a row without dispatching
void TemplateTable::fast_iload2() {
  transition(vtos, itos);

  __ lbz(R3_ARG1, 1, R14_bcp);
  __ lbz(R17_tos, Bytecodes::length_for(Bytecodes::_iload) + 1, R14_bcp);

  __ load_local_int(R3_ARG1, R11_scratch1, R3_ARG1);
  __ load_local_int(R17_tos, R12_scratch2, R17_tos);
  __ push_i(R3_ARG1);
}

void TemplateTable::fast_iload() {
  transition(vtos, itos);
  // Get the local value into tos

  const Register Rindex = R11_scratch1;
  locals_index(Rindex);
  __ load_local_int(R17_tos, Rindex, Rindex);
}

// Load a local variable type long from locals area to TOS cache register.
// Local index resides in bytecodestream.
void TemplateTable::lload() {
  transition(vtos, ltos);

  const Register Rindex = R11_scratch1;
  locals_index(Rindex);
  __ load_local_long(R17_tos, Rindex, Rindex);
}

void TemplateTable::fload() {
  transition(vtos, ftos);

  const Register Rindex = R11_scratch1;
  locals_index(Rindex);
  __ load_local_float(F15_ftos, Rindex, Rindex);
}

void TemplateTable::dload() {
  transition(vtos, dtos);

  const Register Rindex = R11_scratch1;
  locals_index(Rindex);
  __ load_local_double(F15_ftos, Rindex, Rindex);
}

void TemplateTable::aload() {
  transition(vtos, atos);

  const Register Rindex = R11_scratch1;
  locals_index(Rindex);
  __ load_local_ptr(R17_tos, Rindex, Rindex);
}

void TemplateTable::locals_index_wide(Register Rdst) {
  // Offset is 2, not 1, because Lbcp points to wide prefix code.
  __ get_2_byte_integer_at_bcp(2, Rdst, InterpreterMacroAssembler::Unsigned);
}

void TemplateTable::wide_iload() {
  // Get the local value into tos.

  const Register Rindex = R11_scratch1;
  locals_index_wide(Rindex);
  __ load_local_int(R17_tos, Rindex, Rindex);
}

void TemplateTable::wide_lload() {
  transition(vtos, ltos);

  const Register Rindex = R11_scratch1;
  locals_index_wide(Rindex);
  __ load_local_long(R17_tos, Rindex, Rindex);
}

void TemplateTable::wide_fload() {
  transition(vtos, ftos);

  const Register Rindex = R11_scratch1;
  locals_index_wide(Rindex);
  __ load_local_float(F15_ftos, Rindex, Rindex);
}

void TemplateTable::wide_dload() {
  transition(vtos, dtos);

  const Register Rindex = R11_scratch1;
  locals_index_wide(Rindex);
  __ load_local_double(F15_ftos, Rindex, Rindex);
}

void TemplateTable::wide_aload() {
  transition(vtos, atos);

  const Register Rindex = R11_scratch1;
  locals_index_wide(Rindex);
  __ load_local_ptr(R17_tos, Rindex, Rindex);
}

void TemplateTable::iaload() {
  transition(itos, itos);

  const Register Rload_addr = R3_ARG1,
                 Rarray     = R4_ARG2,
                 Rtemp      = R5_ARG3;
  __ index_check(Rarray, R17_tos /* index */, LogBytesPerInt, Rtemp, Rload_addr);
  __ lwa(R17_tos, arrayOopDesc::base_offset_in_bytes(T_INT), Rload_addr);
}

void TemplateTable::laload() {
  transition(itos, ltos);

  const Register Rload_addr = R3_ARG1,
                 Rarray     = R4_ARG2,
                 Rtemp      = R5_ARG3;
  __ index_check(Rarray, R17_tos /* index */, LogBytesPerLong, Rtemp, Rload_addr);
  __ ld(R17_tos, arrayOopDesc::base_offset_in_bytes(T_LONG), Rload_addr);
}

void TemplateTable::faload() {
  transition(itos, ftos);

  const Register Rload_addr = R3_ARG1,
                 Rarray     = R4_ARG2,
                 Rtemp      = R5_ARG3;
  __ index_check(Rarray, R17_tos /* index */, LogBytesPerInt, Rtemp, Rload_addr);
  __ lfs(F15_ftos, arrayOopDesc::base_offset_in_bytes(T_FLOAT), Rload_addr);
}

void TemplateTable::daload() {
  transition(itos, dtos);

  const Register Rload_addr = R3_ARG1,
                 Rarray     = R4_ARG2,
                 Rtemp      = R5_ARG3;
  __ index_check(Rarray, R17_tos /* index */, LogBytesPerLong, Rtemp, Rload_addr);
  __ lfd(F15_ftos, arrayOopDesc::base_offset_in_bytes(T_DOUBLE), Rload_addr);
}

void TemplateTable::aaload() {
  transition(itos, atos);

  // tos: index
  // result tos: array
  const Register Rload_addr = R3_ARG1,
                 Rarray     = R4_ARG2,
                 Rtemp      = R5_ARG3,
                 Rtemp2     = R31;
  __ index_check(Rarray, R17_tos /* index */, UseCompressedOops ? 2 : LogBytesPerWord, Rtemp, Rload_addr);
  do_oop_load(_masm, Rload_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), R17_tos, Rtemp, Rtemp2,
              IS_ARRAY);
  __ verify_oop(R17_tos);
  //__ dcbt(R17_tos); // prefetch
}

void TemplateTable::baload() {
  transition(itos, itos);

  const Register Rload_addr = R3_ARG1,
                 Rarray     = R4_ARG2,
                 Rtemp      = R5_ARG3;
  __ index_check(Rarray, R17_tos /* index */, 0, Rtemp, Rload_addr);
  __ lbz(R17_tos, arrayOopDesc::base_offset_in_bytes(T_BYTE), Rload_addr);
  __ extsb(R17_tos, R17_tos);
}

void TemplateTable::caload() {
  transition(itos, itos);

  const Register Rload_addr = R3_ARG1,
                 Rarray     = R4_ARG2,
                 Rtemp      = R5_ARG3;
  __ index_check(Rarray, R17_tos /* index */, LogBytesPerShort, Rtemp, Rload_addr);
  __ lhz(R17_tos, arrayOopDesc::base_offset_in_bytes(T_CHAR), Rload_addr);
}

// Iload followed by caload frequent pair.
void TemplateTable::fast_icaload() {
  transition(vtos, itos);

  const Register Rload_addr = R3_ARG1,
                 Rarray     = R4_ARG2,
                 Rtemp      = R11_scratch1;

  locals_index(R17_tos);
  __ load_local_int(R17_tos, Rtemp, R17_tos);
  __ index_check(Rarray, R17_tos /* index */, LogBytesPerShort, Rtemp, Rload_addr);
  __ lhz(R17_tos, arrayOopDesc::base_offset_in_bytes(T_CHAR), Rload_addr);
}

void TemplateTable::saload() {
  transition(itos, itos);

  const Register Rload_addr = R11_scratch1,
                 Rarray     = R12_scratch2,
                 Rtemp      = R3_ARG1;
  __ index_check(Rarray, R17_tos /* index */, LogBytesPerShort, Rtemp, Rload_addr);
  __ lha(R17_tos, arrayOopDesc::base_offset_in_bytes(T_SHORT), Rload_addr);
}

void TemplateTable::iload(int n) {
  transition(vtos, itos);

  __ lwz(R17_tos, Interpreter::local_offset_in_bytes(n), R18_locals);
}

void TemplateTable::lload(int n) {
  transition(vtos, ltos);

  __ ld(R17_tos, Interpreter::local_offset_in_bytes(n + 1), R18_locals);
}

void TemplateTable::fload(int n) {
  transition(vtos, ftos);

  __ lfs(F15_ftos, Interpreter::local_offset_in_bytes(n), R18_locals);
}

void TemplateTable::dload(int n) {
  transition(vtos, dtos);

  __ lfd(F15_ftos, Interpreter::local_offset_in_bytes(n + 1), R18_locals);
}

void TemplateTable::aload(int n) {
  transition(vtos, atos);

  __ ld(R17_tos, Interpreter::local_offset_in_bytes(n), R18_locals);
}

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) {
  transition(vtos, atos);
  // 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 _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 Lrewrite, Ldont_rewrite;
    Register Rnext_byte  = R3_ARG1,
             Rrewrite_to = R6_ARG4,
             Rscratch    = R11_scratch1;

    // Get next byte.
    __ lbz(Rnext_byte, Bytecodes::length_for(Bytecodes::_aload_0), R14_bcp);

    // If _getfield, wait to rewrite. We only want to rewrite the last two bytecodes in a pair.
    __ cmpwi(CCR0, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_getfield);
    __ beq(CCR0, Ldont_rewrite);

    __ cmpwi(CCR1, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_fast_igetfield);
    __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_iaccess_0);
    __ beq(CCR1, Lrewrite);

    __ cmpwi(CCR0, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_fast_agetfield);
    __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_aaccess_0);
    __ beq(CCR0, Lrewrite);

    __ cmpwi(CCR1, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_fast_fgetfield);
    __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_faccess_0);
    __ beq(CCR1, Lrewrite);

    __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_aload_0);

    __ bind(Lrewrite);
    patch_bytecode(Bytecodes::_aload_0, Rrewrite_to, Rscratch, false);
    __ bind(Ldont_rewrite);
  }

  // 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);

  const Register Rindex = R11_scratch1;
  locals_index(Rindex);
  __ store_local_int(R17_tos, Rindex);
}

void TemplateTable::lstore() {
  transition(ltos, vtos);
  const Register Rindex = R11_scratch1;
  locals_index(Rindex);
  __ store_local_long(R17_tos, Rindex);
}

void TemplateTable::fstore() {
  transition(ftos, vtos);

  const Register Rindex = R11_scratch1;
  locals_index(Rindex);
  __ store_local_float(F15_ftos, Rindex);
}

void TemplateTable::dstore() {
  transition(dtos, vtos);

  const Register Rindex = R11_scratch1;
  locals_index(Rindex);
  __ store_local_double(F15_ftos, Rindex);
}

void TemplateTable::astore() {
  transition(vtos, vtos);

  const Register Rindex = R11_scratch1;
  __ pop_ptr();
  __ verify_oop_or_return_address(R17_tos, Rindex);
  locals_index(Rindex);
  __ store_local_ptr(R17_tos, Rindex);
}

void TemplateTable::wide_istore() {
  transition(vtos, vtos);

  const Register Rindex = R11_scratch1;
  __ pop_i();
  locals_index_wide(Rindex);
  __ store_local_int(R17_tos, Rindex);
}

void TemplateTable::wide_lstore() {
  transition(vtos, vtos);

  const Register Rindex = R11_scratch1;
  __ pop_l();
  locals_index_wide(Rindex);
  __ store_local_long(R17_tos, Rindex);
}

void TemplateTable::wide_fstore() {
  transition(vtos, vtos);

  const Register Rindex = R11_scratch1;
  __ pop_f();
  locals_index_wide(Rindex);
  __ store_local_float(F15_ftos, Rindex);
}

void TemplateTable::wide_dstore() {
  transition(vtos, vtos);

  const Register Rindex = R11_scratch1;
  __ pop_d();
  locals_index_wide(Rindex);
  __ store_local_double(F15_ftos, Rindex);
}

void TemplateTable::wide_astore() {
  transition(vtos, vtos);

  const Register Rindex = R11_scratch1;
  __ pop_ptr();
  __ verify_oop_or_return_address(R17_tos, Rindex);
  locals_index_wide(Rindex);
  __ store_local_ptr(R17_tos, Rindex);
}

void TemplateTable::iastore() {
  transition(itos, vtos);

  const Register Rindex      = R3_ARG1,
                 Rstore_addr = R4_ARG2,
                 Rarray      = R5_ARG3,
                 Rtemp       = R6_ARG4;
  __ pop_i(Rindex);
  __ index_check(Rarray, Rindex, LogBytesPerInt, Rtemp, Rstore_addr);
  __ stw(R17_tos, arrayOopDesc::base_offset_in_bytes(T_INT), Rstore_addr);
  }

void TemplateTable::lastore() {
  transition(ltos, vtos);

  const Register Rindex      = R3_ARG1,
                 Rstore_addr = R4_ARG2,
                 Rarray      = R5_ARG3,
                 Rtemp       = R6_ARG4;
  __ pop_i(Rindex);
  __ index_check(Rarray, Rindex, LogBytesPerLong, Rtemp, Rstore_addr);
  __ std(R17_tos, arrayOopDesc::base_offset_in_bytes(T_LONG), Rstore_addr);
  }

void TemplateTable::fastore() {
  transition(ftos, vtos);

  const Register Rindex      = R3_ARG1,
                 Rstore_addr = R4_ARG2,
                 Rarray      = R5_ARG3,
                 Rtemp       = R6_ARG4;
  __ pop_i(Rindex);
  __ index_check(Rarray, Rindex, LogBytesPerInt, Rtemp, Rstore_addr);
  __ stfs(F15_ftos, arrayOopDesc::base_offset_in_bytes(T_FLOAT), Rstore_addr);
  }

void TemplateTable::dastore() {
  transition(dtos, vtos);

  const Register Rindex      = R3_ARG1,
                 Rstore_addr = R4_ARG2,
                 Rarray      = R5_ARG3,
                 Rtemp       = R6_ARG4;
  __ pop_i(Rindex);
  __ index_check(Rarray, Rindex, LogBytesPerLong, Rtemp, Rstore_addr);
  __ stfd(F15_ftos, arrayOopDesc::base_offset_in_bytes(T_DOUBLE), Rstore_addr);
  }

// Pop 3 values from the stack and...
void TemplateTable::aastore() {
  transition(vtos, vtos);

  Label Lstore_ok, Lis_null, Ldone;
  const Register Rindex    = R3_ARG1,
                 Rarray    = R4_ARG2,
                 Rscratch  = R11_scratch1,
                 Rscratch2 = R12_scratch2,
                 Rarray_klass = R5_ARG3,
                 Rarray_element_klass = Rarray_klass,
                 Rvalue_klass = R6_ARG4,
                 Rstore_addr = R31;    // Use register which survives VM call.

  __ ld(R17_tos, Interpreter::expr_offset_in_bytes(0), R15_esp); // Get value to store.
  __ lwz(Rindex, Interpreter::expr_offset_in_bytes(1), R15_esp); // Get index.
  __ ld(Rarray, Interpreter::expr_offset_in_bytes(2), R15_esp);  // Get array.

  __ verify_oop(R17_tos);
  __ index_check_without_pop(Rarray, Rindex, UseCompressedOops ? 2 : LogBytesPerWord, Rscratch, Rstore_addr);
  // Rindex is dead!
  Register Rscratch3 = Rindex;

  // Do array store check - check for NULL value first.
  __ cmpdi(CCR0, R17_tos, 0);
  __ beq(CCR0, Lis_null);

  __ load_klass(Rarray_klass, Rarray);
  __ load_klass(Rvalue_klass, R17_tos);

  // Do fast instanceof cache test.
  __ ld(Rarray_element_klass, in_bytes(ObjArrayKlass::element_klass_offset()), Rarray_klass);

  // Generate a fast subtype check. Branch to store_ok if no failure. Throw if failure.
  __ gen_subtype_check(Rvalue_klass /*subklass*/, Rarray_element_klass /*superklass*/, Rscratch, Rscratch2, Rscratch3, Lstore_ok);

  // Fell through: subtype check failed => throw an exception.
  __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ArrayStoreException_entry);
  __ mtctr(R11_scratch1);
  __ bctr();

  __ bind(Lis_null);
  do_oop_store(_masm, Rstore_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), nore/* 0 */,
               Rscratch, Rscratch2, Rscratch3, IS_ARRAY);
  __ profile_null_seen(Rscratch, Rscratch2);
  __ b(Ldone);

  // Store is OK.
  __ bind(Lstore_ok);
  do_oop_store(_masm, Rstore_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), R17_tos /* value */,
               Rscratch, Rscratch2, Rscratch3, IS_ARRAY | IS_NOT_NULL);

  __ bind(Ldone);
  // Adjust sp (pops array, index and value).
  __ addi(R15_esp, R15_esp, 3 * Interpreter::stackElementSize);
}

void TemplateTable::bastore() {
  transition(itos, vtos);

  const Register Rindex   = R11_scratch1,
                 Rarray   = R12_scratch2,
                 Rscratch = R3_ARG1;
  __ pop_i(Rindex);
  __ pop_ptr(Rarray);
  // tos: val

  // Need to check whether array is boolean or byte
  // since both types share the bastore bytecode.
  __ load_klass(Rscratch, Rarray);
  __ lwz(Rscratch, in_bytes(Klass::layout_helper_offset()), Rscratch);
  int diffbit = exact_log2(Klass::layout_helper_boolean_diffbit());
  __ testbitdi(CCR0, R0, Rscratch, diffbit);
  Label L_skip;
  __ bfalse(CCR0, L_skip);
  __ andi(R17_tos, R17_tos, 1);  // if it is a T_BOOLEAN array, mask the stored value to 0/1
  __ bind(L_skip);

  __ index_check_without_pop(Rarray, Rindex, 0, Rscratch, Rarray);
  __ stb(R17_tos, arrayOopDesc::base_offset_in_bytes(T_BYTE), Rarray);
}

void TemplateTable::castore() {
  transition(itos, vtos);

  const Register Rindex   = R11_scratch1,
                 Rarray   = R12_scratch2,
                 Rscratch = R3_ARG1;
  __ pop_i(Rindex);
  // tos: val
  // Rarray: array ptr (popped by index_check)
  __ index_check(Rarray, Rindex, LogBytesPerShort, Rscratch, Rarray);
  __ sth(R17_tos, arrayOopDesc::base_offset_in_bytes(T_CHAR), Rarray);
}

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

void TemplateTable::istore(int n) {
  transition(itos, vtos);
  __ stw(R17_tos, Interpreter::local_offset_in_bytes(n), R18_locals);
}

void TemplateTable::lstore(int n) {
  transition(ltos, vtos);
  __ std(R17_tos, Interpreter::local_offset_in_bytes(n + 1), R18_locals);
}

void TemplateTable::fstore(int n) {
  transition(ftos, vtos);
  __ stfs(F15_ftos, Interpreter::local_offset_in_bytes(n), R18_locals);
}

void TemplateTable::dstore(int n) {
  transition(dtos, vtos);
  __ stfd(F15_ftos, Interpreter::local_offset_in_bytes(n + 1), R18_locals);
}

void TemplateTable::astore(int n) {
  transition(vtos, vtos);

  __ pop_ptr();
  __ verify_oop_or_return_address(R17_tos, R11_scratch1);
  __ std(R17_tos, Interpreter::local_offset_in_bytes(n), R18_locals);
}

void TemplateTable::pop() {
  transition(vtos, vtos);

  __ addi(R15_esp, R15_esp, Interpreter::stackElementSize);
}

void TemplateTable::pop2() {
  transition(vtos, vtos);

  __ addi(R15_esp, R15_esp, Interpreter::stackElementSize * 2);
}

void TemplateTable::dup() {
  transition(vtos, vtos);

  __ ld(R11_scratch1, Interpreter::stackElementSize, R15_esp);
  __ push_ptr(R11_scratch1);
}

void TemplateTable::dup_x1() {
  transition(vtos, vtos);

  Register Ra = R11_scratch1,
           Rb = R12_scratch2;
  // stack: ..., a, b
  __ ld(Rb, Interpreter::stackElementSize,     R15_esp);
  __ ld(Ra, Interpreter::stackElementSize * 2, R15_esp);
  __ std(Rb, Interpreter::stackElementSize * 2, R15_esp);
  __ std(Ra, Interpreter::stackElementSize,     R15_esp);
  __ push_ptr(Rb);
  // stack: ..., b, a, b
}

void TemplateTable::dup_x2() {
  transition(vtos, vtos);

  Register Ra = R11_scratch1,
           Rb = R12_scratch2,
           Rc = R3_ARG1;

  // stack: ..., a, b, c
  __ ld(Rc, Interpreter::stackElementSize,     R15_esp);  // load c
  __ ld(Ra, Interpreter::stackElementSize * 3, R15_esp);  // load a
  __ std(Rc, Interpreter::stackElementSize * 3, R15_esp); // store c in a
  __ ld(Rb, Interpreter::stackElementSize * 2, R15_esp);  // load b
  // stack: ..., c, b, c
  __ std(Ra, Interpreter::stackElementSize * 2, R15_esp); // store a in b
  // stack: ..., c, a, c
  __ std(Rb, Interpreter::stackElementSize,     R15_esp); // store b in c
  __ push_ptr(Rc);                                        // push c
  // stack: ..., c, a, b, c
}

void TemplateTable::dup2() {
  transition(vtos, vtos);

  Register Ra = R11_scratch1,
           Rb = R12_scratch2;
  // stack: ..., a, b
  __ ld(Rb, Interpreter::stackElementSize,     R15_esp);
  __ ld(Ra, Interpreter::stackElementSize * 2, R15_esp);
  __ push_2ptrs(Ra, Rb);
  // stack: ..., a, b, a, b
}

void TemplateTable::dup2_x1() {
  transition(vtos, vtos);

  Register Ra = R11_scratch1,
           Rb = R12_scratch2,
           Rc = R3_ARG1;
  // stack: ..., a, b, c
  __ ld(Rc, Interpreter::stackElementSize,     R15_esp);
  __ ld(Rb, Interpreter::stackElementSize * 2, R15_esp);
  __ std(Rc, Interpreter::stackElementSize * 2, R15_esp);
  __ ld(Ra, Interpreter::stackElementSize * 3, R15_esp);
  __ std(Ra, Interpreter::stackElementSize,     R15_esp);
  __ std(Rb, Interpreter::stackElementSize * 3, R15_esp);
  // stack: ..., b, c, a
  __ push_2ptrs(Rb, Rc);
  // stack: ..., b, c, a, b, c
}

void TemplateTable::dup2_x2() {
  transition(vtos, vtos);

  Register Ra = R11_scratch1,
           Rb = R12_scratch2,
           Rc = R3_ARG1,
           Rd = R4_ARG2;
  // stack: ..., a, b, c, d
  __ ld(Rb, Interpreter::stackElementSize * 3, R15_esp);
  __ ld(Rd, Interpreter::stackElementSize,     R15_esp);
  __ std(Rb, Interpreter::stackElementSize,     R15_esp);  // store b in d
  __ std(Rd, Interpreter::stackElementSize * 3, R15_esp);  // store d in b
  __ ld(Ra, Interpreter::stackElementSize * 4, R15_esp);
  __ ld(Rc, Interpreter::stackElementSize * 2, R15_esp);
  __ std(Ra, Interpreter::stackElementSize * 2, R15_esp);  // store a in c
  __ std(Rc, Interpreter::stackElementSize * 4, R15_esp);  // store c in a
  // stack: ..., c, d, a, b
  __ push_2ptrs(Rc, Rd);
  // stack: ..., c, d, a, b, c, d
}

void TemplateTable::swap() {
  transition(vtos, vtos);
  // stack: ..., a, b

  Register Ra = R11_scratch1,
           Rb = R12_scratch2;
  // stack: ..., a, b
  __ ld(Rb, Interpreter::stackElementSize,     R15_esp);
  __ ld(Ra, Interpreter::stackElementSize * 2, R15_esp);
  __ std(Rb, Interpreter::stackElementSize * 2, R15_esp);
  __ std(Ra, Interpreter::stackElementSize,     R15_esp);
  // stack: ..., b, a
}

void TemplateTable::iop2(Operation op) {
  transition(itos, itos);

  Register Rscratch = R11_scratch1;

  __ pop_i(Rscratch);
  // tos  = number of bits to shift
  // Rscratch = value to shift
  switch (op) {
    case  add:   __ add(R17_tos, Rscratch, R17_tos); break;
    case  sub:   __ sub(R17_tos, Rscratch, R17_tos); break;
    case  mul:   __ mullw(R17_tos, Rscratch, R17_tos); break;
    case  _and:  __ andr(R17_tos, Rscratch, R17_tos); break;
    case  _or:   __ orr(R17_tos, Rscratch, R17_tos); break;
    case  _xor:  __ xorr(R17_tos, Rscratch, R17_tos); break;
    case  shl:   __ rldicl(R17_tos, R17_tos, 0, 64-5); __ slw(R17_tos, Rscratch, R17_tos); break;
    case  shr:   __ rldicl(R17_tos, R17_tos, 0, 64-5); __ sraw(R17_tos, Rscratch, R17_tos); break;
    case  ushr:  __ rldicl(R17_tos, R17_tos, 0, 64-5); __ srw(R17_tos, Rscratch, R17_tos); break;
    default:     ShouldNotReachHere();
  }
}

void TemplateTable::lop2(Operation op) {
  transition(ltos, ltos);

  Register Rscratch = R11_scratch1;
  __ pop_l(Rscratch);
  switch (op) {
    case  add:   __ add(R17_tos, Rscratch, R17_tos); break;
    case  sub:   __ sub(R17_tos, Rscratch, R17_tos); break;
    case  _and:  __ andr(R17_tos, Rscratch, R17_tos); break;
    case  _or:   __ orr(R17_tos, Rscratch, R17_tos); break;
    case  _xor:  __ xorr(R17_tos, Rscratch, R17_tos); break;
    default:     ShouldNotReachHere();
  }
}

void TemplateTable::idiv() {
  transition(itos, itos);

  Label Lnormal, Lexception, Ldone;
  Register Rdividend = R11_scratch1; // Used by irem.

  __ addi(R0, R17_tos, 1);
  __ cmplwi(CCR0, R0, 2);
  __ bgt(CCR0, Lnormal); // divisor <-1 or >1

  __ cmpwi(CCR1, R17_tos, 0);
  __ beq(CCR1, Lexception); // divisor == 0

  __ pop_i(Rdividend);
  __ mullw(R17_tos, Rdividend, R17_tos); // div by +/-1
  __ b(Ldone);

  __ bind(Lexception);
  __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ArithmeticException_entry);
  __ mtctr(R11_scratch1);
  __ bctr();

  __ align(32, 12);
  __ bind(Lnormal);
  __ pop_i(Rdividend);
  __ divw(R17_tos, Rdividend, R17_tos); // Can't divide minint/-1.
  __ bind(Ldone);
}

void TemplateTable::irem() {
  transition(itos, itos);

  __ mr(R12_scratch2, R17_tos);
  idiv();
  __ mullw(R17_tos, R17_tos, R12_scratch2);
  __ subf(R17_tos, R17_tos, R11_scratch1); // Dividend set by idiv.
}

void TemplateTable::lmul() {
  transition(ltos, ltos);

  __ pop_l(R11_scratch1);
  __ mulld(R17_tos, R11_scratch1, R17_tos);
}

void TemplateTable::ldiv() {
  transition(ltos, ltos);

  Label Lnormal, Lexception, Ldone;
  Register Rdividend = R11_scratch1; // Used by lrem.

  __ addi(R0, R17_tos, 1);
  __ cmpldi(CCR0, R0, 2);
  __ bgt(CCR0, Lnormal); // divisor <-1 or >1

  __ cmpdi(CCR1, R17_tos, 0);
  __ beq(CCR1, Lexception); // divisor == 0

  __ pop_l(Rdividend);
  __ mulld(R17_tos, Rdividend, R17_tos); // div by +/-1
  __ b(Ldone);

  __ bind(Lexception);
  __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ArithmeticException_entry);
  __ mtctr(R11_scratch1);
  __ bctr();

  __ align(32, 12);
  __ bind(Lnormal);
  __ pop_l(Rdividend);
  __ divd(R17_tos, Rdividend, R17_tos); // Can't divide minint/-1.
  __ bind(Ldone);
}

void TemplateTable::lrem() {
  transition(ltos, ltos);

  __ mr(R12_scratch2, R17_tos);
  ldiv();
  __ mulld(R17_tos, R17_tos, R12_scratch2);
  __ subf(R17_tos, R17_tos, R11_scratch1); // Dividend set by ldiv.
}

void TemplateTable::lshl() {
  transition(itos, ltos);

  __ rldicl(R17_tos, R17_tos, 0, 64-6); // Extract least significant bits.
  __ pop_l(R11_scratch1);
  __ sld(R17_tos, R11_scratch1, R17_tos);
}

void TemplateTable::lshr() {
  transition(itos, ltos);

  __ rldicl(R17_tos, R17_tos, 0, 64-6); // Extract least significant bits.
  __ pop_l(R11_scratch1);
  __ srad(R17_tos, R11_scratch1, R17_tos);
}

void TemplateTable::lushr() {
  transition(itos, ltos);

  __ rldicl(R17_tos, R17_tos, 0, 64-6); // Extract least significant bits.
  __ pop_l(R11_scratch1);
  __ srd(R17_tos, R11_scratch1, R17_tos);
}

void TemplateTable::fop2(Operation op) {
  transition(ftos, ftos);

  switch (op) {
    case add: __ pop_f(F0_SCRATCH); __ fadds(F15_ftos, F0_SCRATCH, F15_ftos); break;
    case sub: __ pop_f(F0_SCRATCH); __ fsubs(F15_ftos, F0_SCRATCH, F15_ftos); break;
    case mul: __ pop_f(F0_SCRATCH); __ fmuls(F15_ftos, F0_SCRATCH, F15_ftos); break;
    case div: __ pop_f(F0_SCRATCH); __ fdivs(F15_ftos, F0_SCRATCH, F15_ftos); break;
    case rem:
      __ pop_f(F1_ARG1);
      __ fmr(F2_ARG2, F15_ftos);
      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::frem));
      __ fmr(F15_ftos, F1_RET);
      break;

    default: ShouldNotReachHere();
  }
}

void TemplateTable::dop2(Operation op) {
  transition(dtos, dtos);

  switch (op) {
    case add: __ pop_d(F0_SCRATCH); __ fadd(F15_ftos, F0_SCRATCH, F15_ftos); break;
    case sub: __ pop_d(F0_SCRATCH); __ fsub(F15_ftos, F0_SCRATCH, F15_ftos); break;
    case mul: __ pop_d(F0_SCRATCH); __ fmul(F15_ftos, F0_SCRATCH, F15_ftos); break;
    case div: __ pop_d(F0_SCRATCH); __ fdiv(F15_ftos, F0_SCRATCH, F15_ftos); break;
    case rem:
      __ pop_d(F1_ARG1);
      __ fmr(F2_ARG2, F15_ftos);
      __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::drem));
      __ fmr(F15_ftos, F1_RET);
      break;

    default: ShouldNotReachHere();
  }
}

// Negate the value in the TOS cache.
void TemplateTable::ineg() {
  transition(itos, itos);

  __ neg(R17_tos, R17_tos);
}

// Negate the value in the TOS cache.
void TemplateTable::lneg() {
  transition(ltos, ltos);

  __ neg(R17_tos, R17_tos);
}

void TemplateTable::fneg() {
  transition(ftos, ftos);

  __ fneg(F15_ftos, F15_ftos);
}

void TemplateTable::dneg() {
  transition(dtos, dtos);

  __ fneg(F15_ftos, F15_ftos);
}

// Increments a local variable in place.
void TemplateTable::iinc() {
  transition(vtos, vtos);

  const Register Rindex     = R11_scratch1,
                 Rincrement = R0,
                 Rvalue     = R12_scratch2;

  locals_index(Rindex);              // Load locals index from bytecode stream.
  __ lbz(Rincrement, 2, R14_bcp);    // Load increment from the bytecode stream.
  __ extsb(Rincrement, Rincrement);

  __ load_local_int(Rvalue, Rindex, Rindex); // Puts address of local into Rindex.

  __ add(Rvalue, Rincrement, Rvalue);
  __ stw(Rvalue, 0, Rindex);
}

void TemplateTable::wide_iinc() {
  transition(vtos, vtos);

  Register Rindex       = R11_scratch1,
           Rlocals_addr = Rindex,
           Rincr        = R12_scratch2;
  locals_index_wide(Rindex);
  __ get_2_byte_integer_at_bcp(4, Rincr, InterpreterMacroAssembler::Signed);
  __ load_local_int(R17_tos, Rlocals_addr, Rindex);
  __ add(R17_tos, Rincr, R17_tos);
  __ stw(R17_tos, 0, Rlocals_addr);
}

void TemplateTable::convert() {
  // %%%%% Factor this first part across platforms
#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

  // Conversion
  Label done;
  switch (bytecode()) {
    case Bytecodes::_i2l:
      __ extsw(R17_tos, R17_tos);
      break;

    case Bytecodes::_l2i:
      // Nothing to do, we'll continue to work with the lower bits.
      break;

    case Bytecodes::_i2b:
      __ extsb(R17_tos, R17_tos);
      break;

    case Bytecodes::_i2c:
      __ rldicl(R17_tos, R17_tos, 0, 64-2*8);
      break;

    case Bytecodes::_i2s:
      __ extsh(R17_tos, R17_tos);
      break;

    case Bytecodes::_i2d:
      __ extsw(R17_tos, R17_tos);
    case Bytecodes::_l2d:
      __ move_l_to_d();
      __ fcfid(F15_ftos, F15_ftos);
      break;

    case Bytecodes::_i2f:
      __ extsw(R17_tos, R17_tos);
      __ move_l_to_d();
      if (VM_Version::has_fcfids()) { // fcfids is >= Power7 only
        // Comment: alternatively, load with sign extend could be done by lfiwax.
        __ fcfids(F15_ftos, F15_ftos);
      } else {
        __ fcfid(F15_ftos, F15_ftos);
        __ frsp(F15_ftos, F15_ftos);
      }
      break;

    case Bytecodes::_l2f:
      if (VM_Version::has_fcfids()) { // fcfids is >= Power7 only
        __ move_l_to_d();
        __ fcfids(F15_ftos, F15_ftos);
      } else {
        // Avoid rounding problem when result should be 0x3f800001: need fixup code before fcfid+frsp.
        __ mr(R3_ARG1, R17_tos);
        __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::l2f));
        __ fmr(F15_ftos, F1_RET);
      }
      break;

    case Bytecodes::_f2d:
      // empty
      break;

    case Bytecodes::_d2f:
      __ frsp(F15_ftos, F15_ftos);
      break;

    case Bytecodes::_d2i:
    case Bytecodes::_f2i:
      __ fcmpu(CCR0, F15_ftos, F15_ftos);
      __ li(R17_tos, 0); // 0 in case of NAN
      __ bso(CCR0, done);
      __ fctiwz(F15_ftos, F15_ftos);
      __ move_d_to_l();
      break;

    case Bytecodes::_d2l:
    case Bytecodes::_f2l:
      __ fcmpu(CCR0, F15_ftos, F15_ftos);
      __ li(R17_tos, 0); // 0 in case of NAN
      __ bso(CCR0, done);
      __ fctidz(F15_ftos, F15_ftos);
      __ move_d_to_l();
      break;

    default: ShouldNotReachHere();
  }
  __ bind(done);
}

// Long compare
void TemplateTable::lcmp() {
  transition(ltos, itos);

  const Register Rscratch = R11_scratch1;
  __ pop_l(Rscratch); // first operand, deeper in stack

  __ cmpd(CCR0, Rscratch, R17_tos); // compare
  __ set_cmp3(R17_tos); // set result as follows: <: -1, =: 0, >: 1
}

// fcmpl/fcmpg and dcmpl/dcmpg bytecodes
// unordered_result == -1 => fcmpl or dcmpl
// unordered_result ==  1 => fcmpg or dcmpg
void TemplateTable::float_cmp(bool is_float, int unordered_result) {
  const FloatRegister Rfirst  = F0_SCRATCH,
                      Rsecond = F15_ftos;
  const Register Rscratch = R11_scratch1;

  if (is_float) {
    __ pop_f(Rfirst);
  } else {
    __ pop_d(Rfirst);
  }

  __ fcmpu(CCR0, Rfirst, Rsecond); // compare
  // if unordered_result is 1, treat unordered_result like 'greater than'
  assert(unordered_result == 1 || unordered_result == -1, "unordered_result can be either 1 or -1");
  __ set_cmpu3(R17_tos, unordered_result != 1);
}

// Branch_conditional which takes TemplateTable::Condition.
void TemplateTable::branch_conditional(ConditionRegister crx, TemplateTable::Condition cc, Label& L, bool invert) {
  bool positive = false;
  Assembler::Condition cond = Assembler::equal;
  switch (cc) {
    case TemplateTable::equal:         positive = true ; cond = Assembler::equal  ; break;
    case TemplateTable::not_equal:     positive = false; cond = Assembler::equal  ; break;
    case TemplateTable::less:          positive = true ; cond = Assembler::less   ; break;
    case TemplateTable::less_equal:    positive = false; cond = Assembler::greater; break;
    case TemplateTable::greater:       positive = true ; cond = Assembler::greater; break;
    case TemplateTable::greater_equal: positive = false; cond = Assembler::less   ; break;
    default: ShouldNotReachHere();
  }
  int bo = (positive != invert) ? Assembler::bcondCRbiIs1 : Assembler::bcondCRbiIs0;
  int bi = Assembler::bi0(crx, cond);
  __ bc(bo, bi, L);
}

void TemplateTable::branch(bool is_jsr, bool is_wide) {

  // Note: on SPARC, we use InterpreterMacroAssembler::if_cmp also.
  __ verify_thread();

  const Register Rscratch1    = R11_scratch1,
                 Rscratch2    = R12_scratch2,
                 Rscratch3    = R3_ARG1,
                 R4_counters  = R4_ARG2,
                 bumped_count = R31,
                 Rdisp        = R22_tmp2;

  __ profile_taken_branch(Rscratch1, bumped_count);

  // Get (wide) offset.
  if (is_wide) {
    __ get_4_byte_integer_at_bcp(1, Rdisp, InterpreterMacroAssembler::Signed);
  } else {
    __ get_2_byte_integer_at_bcp(1, Rdisp, InterpreterMacroAssembler::Signed);
  }

  // --------------------------------------------------------------------------
  // 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 in Otos_i.
    __ ld(Rscratch1, in_bytes(Method::const_offset()), R19_method);
    __ addi(Rscratch2, R14_bcp, -in_bytes(ConstMethod::codes_offset()) + (is_wide ? 5 : 3));
    __ subf(R17_tos, Rscratch1, Rscratch2);

    // Bump bcp to target of JSR.
    __ add(R14_bcp, Rdisp, R14_bcp);
    // Push returnAddress for "ret" on stack.
    __ push_ptr(R17_tos);
    // And away we go!
    __ dispatch_next(vtos, 0 ,true);
    return;
  }

  // --------------------------------------------------------------------------
  // Normal (non-jsr) branch handling

  // Bump bytecode pointer by displacement (take the branch).
  __ add(R14_bcp, Rdisp, R14_bcp); // Add to bc addr.

  const bool increment_invocation_counter_for_backward_branches = UseCompiler && UseLoopCounter;
  if (increment_invocation_counter_for_backward_branches) {
    Label Lforward;

    // Check branch direction.
    __ cmpdi(CCR0, Rdisp, 0);
    __ bgt(CCR0, Lforward);

    __ get_method_counters(R19_method, R4_counters, Lforward);

    Label Lno_mdo, Loverflow;
    const int increment = InvocationCounter::count_increment;
    if (ProfileInterpreter) {
      Register Rmdo = Rscratch1;

      // If no method data exists, go to profile_continue.
      __ ld(Rmdo, in_bytes(Method::method_data_offset()), R19_method);
      __ cmpdi(CCR0, Rmdo, 0);
      __ beq(CCR0, Lno_mdo);

      // Increment backedge counter in the MDO.
      const int mdo_bc_offs = in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
      __ lwz(Rscratch2, mdo_bc_offs, Rmdo);
      __ lwz(Rscratch3, in_bytes(MethodData::backedge_mask_offset()), Rmdo);
      __ addi(Rscratch2, Rscratch2, increment);
      __ stw(Rscratch2, mdo_bc_offs, Rmdo);
      if (UseOnStackReplacement) {
        __ and_(Rscratch3, Rscratch2, Rscratch3);
        __ bne(CCR0, Lforward);
        __ b(Loverflow);
      } else {
        __ b(Lforward);
      }
    }

    // If there's no MDO, increment counter in method.
    const int mo_bc_offs = in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
    __ bind(Lno_mdo);
    __ lwz(Rscratch2, mo_bc_offs, R4_counters);
    __ lwz(Rscratch3, in_bytes(MethodCounters::backedge_mask_offset()), R4_counters);
    __ addi(Rscratch2, Rscratch2, increment);
    __ stw(Rscratch2, mo_bc_offs, R4_counters);
    if (UseOnStackReplacement) {
      __ and_(Rscratch3, Rscratch2, Rscratch3);
      __ bne(CCR0, Lforward);
    } else {
      __ b(Lforward);
    }
    __ bind(Loverflow);

    // Notify point for loop, pass branch bytecode.
    __ subf(R4_ARG2, Rdisp, R14_bcp); // Compute branch bytecode (previous bcp).
    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R4_ARG2, true);

    // Was an OSR adapter generated?
    __ cmpdi(CCR0, R3_RET, 0);
    __ beq(CCR0, Lforward);

    // Has the nmethod been invalidated already?
    __ lbz(R0, nmethod::state_offset(), R3_RET);
    __ cmpwi(CCR0, R0, nmethod::in_use);
    __ bne(CCR0, Lforward);

    // Migrate the interpreter frame off of the stack.
    // We can use all registers because we will not return to interpreter from this point.

    // Save nmethod.
    const Register osr_nmethod = R31;
    __ mr(osr_nmethod, R3_RET);
    __ set_top_ijava_frame_at_SP_as_last_Java_frame(R1_SP, R11_scratch1);
    __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin), R16_thread);
    __ reset_last_Java_frame();
    // OSR buffer is in ARG1.

    // Remove the interpreter frame.
    __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2);

    // Jump to the osr code.
    __ ld(R11_scratch1, nmethod::osr_entry_point_offset(), osr_nmethod);
    __ mtlr(R0);
    __ mtctr(R11_scratch1);
    __ bctr();

    __ bind(Lforward);
  }
  __ dispatch_next(vtos, 0, true);
}

// Helper function for if_cmp* methods below.
// Factored out common compare and branch code.
void TemplateTable::if_cmp_common(Register Rfirst, Register Rsecond, Register Rscratch1, Register Rscratch2, Condition cc, bool is_jint, bool cmp0) {
  Label Lnot_taken;
  // Note: The condition code we get is the condition under which we
  // *fall through*! So we have to inverse the CC here.

  if (is_jint) {
    if (cmp0) {
      __ cmpwi(CCR0, Rfirst, 0);
    } else {
      __ cmpw(CCR0, Rfirst, Rsecond);
    }
  } else {
    if (cmp0) {
      __ cmpdi(CCR0, Rfirst, 0);
    } else {
      __ cmpd(CCR0, Rfirst, Rsecond);
    }
  }
  branch_conditional(CCR0, cc, Lnot_taken, /*invert*/ true);

  // Conition is false => Jump!
  branch(falsefalse);

  // Condition is not true => Continue.
  __ align(32, 12);
  __ bind(Lnot_taken);
  __ profile_not_taken_branch(Rscratch1, Rscratch2);
}

// Compare integer values with zero and fall through if CC holds, branch away otherwise.
void TemplateTable::if_0cmp(Condition cc) {
  transition(itos, vtos);

  if_cmp_common(R17_tos, noreg, R11_scratch1, R12_scratch2, cc, truetrue);
}

// Compare integer values and fall through if CC holds, branch away otherwise.
//
// Interface:
//  - Rfirst: First operand  (older stack value)
//  - tos:    Second operand (younger stack value)
void TemplateTable::if_icmp(Condition cc) {
  transition(itos, vtos);

  const Register Rfirst  = R0,
                 Rsecond = R17_tos;

  __ pop_i(Rfirst);
  if_cmp_common(Rfirst, Rsecond, R11_scratch1, R12_scratch2, cc, truefalse);
}

void TemplateTable::if_nullcmp(Condition cc) {
  transition(atos, vtos);

  if_cmp_common(R17_tos, noreg, R11_scratch1, R12_scratch2, cc, falsetrue);
}

void TemplateTable::if_acmp(Condition cc) {
  transition(atos, vtos);

  const Register Rfirst  = R0,
                 Rsecond = R17_tos;

  __ pop_ptr(Rfirst);
  if_cmp_common(Rfirst, Rsecond, R11_scratch1, R12_scratch2, cc, falsefalse);
}

void TemplateTable::ret() {
  locals_index(R11_scratch1);
  __ load_local_ptr(R17_tos, R11_scratch1, R11_scratch1);

  __ profile_ret(vtos, R17_tos, R11_scratch1, R12_scratch2);

  __ ld(R11_scratch1, in_bytes(Method::const_offset()), R19_method);
  __ add(R11_scratch1, R17_tos, R11_scratch1);
  __ addi(R14_bcp, R11_scratch1, in_bytes(ConstMethod::codes_offset()));
  __ dispatch_next(vtos, 0, true);
}

void TemplateTable::wide_ret() {
  transition(vtos, vtos);

  const Register Rindex = R3_ARG1,
                 Rscratch1 = R11_scratch1,
                 Rscratch2 = R12_scratch2;

  locals_index_wide(Rindex);
  __ load_local_ptr(R17_tos, R17_tos, Rindex);
  __ profile_ret(vtos, R17_tos, Rscratch1, R12_scratch2);
  // Tos now contains the bci, compute the bcp from that.
  __ ld(Rscratch1, in_bytes(Method::const_offset()), R19_method);
  __ addi(Rscratch2, R17_tos, in_bytes(ConstMethod::codes_offset()));
  __ add(R14_bcp, Rscratch1, Rscratch2);
  __ dispatch_next(vtos, 0, true);
}

void TemplateTable::tableswitch() {
  transition(itos, vtos);

  Label Ldispatch, Ldefault_case;
  Register Rlow_byte         = R3_ARG1,
           Rindex            = Rlow_byte,
           Rhigh_byte        = R4_ARG2,
           Rdef_offset_addr  = R5_ARG3, // is going to contain address of default offset
           Rscratch1         = R11_scratch1,
           Rscratch2         = R12_scratch2,
           Roffset           = R6_ARG4;

  // Align bcp.
  __ addi(Rdef_offset_addr, R14_bcp, BytesPerInt);
  __ clrrdi(Rdef_offset_addr, Rdef_offset_addr, LogBytesPerInt);

  // Load lo & hi.
  __ get_u4(Rlow_byte, Rdef_offset_addr, BytesPerInt, InterpreterMacroAssembler::Unsigned);
  __ get_u4(Rhigh_byte, Rdef_offset_addr, 2 *BytesPerInt, InterpreterMacroAssembler::Unsigned);

  // Check for default case (=index outside [low,high]).
  __ cmpw(CCR0, R17_tos, Rlow_byte);
  __ cmpw(CCR1, R17_tos, Rhigh_byte);
  __ blt(CCR0, Ldefault_case);
  __ bgt(CCR1, Ldefault_case);

  // Lookup dispatch offset.
  __ sub(Rindex, R17_tos, Rlow_byte);
  __ extsw(Rindex, Rindex);
  __ profile_switch_case(Rindex, Rhigh_byte /* scratch */, Rscratch1, Rscratch2);
  __ sldi(Rindex, Rindex, LogBytesPerInt);
  __ addi(Rindex, Rindex, 3 * BytesPerInt);
#if defined(VM_LITTLE_ENDIAN)
  __ lwbrx(Roffset, Rdef_offset_addr, Rindex);
  __ extsw(Roffset, Roffset);
#else
  __ lwax(Roffset, Rdef_offset_addr, Rindex);
#endif
  __ b(Ldispatch);

  __ bind(Ldefault_case);
  __ profile_switch_default(Rhigh_byte, Rscratch1);
  __ get_u4(Roffset, Rdef_offset_addr, 0, InterpreterMacroAssembler::Signed);

  __ bind(Ldispatch);

  __ add(R14_bcp, Roffset, R14_bcp);
  __ dispatch_next(vtos, 0, true);
}

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

// Table switch using linear search through cases.
// Bytecode stream format:
// Bytecode (1) | 4-byte padding | default offset (4) | count (4) | value/offset pair1 (8) | value/offset pair2 (8) | ...
// Note: Everything is big-endian format here.
void TemplateTable::fast_linearswitch() {
  transition(itos, vtos);

  Label Lloop_entry, Lsearch_loop, Lcontinue_execution, Ldefault_case;
  Register Rcount           = R3_ARG1,
           Rcurrent_pair    = R4_ARG2,
           Rdef_offset_addr = R5_ARG3, // Is going to contain address of default offset.
           Roffset          = R31,     // Might need to survive C call.
           Rvalue           = R12_scratch2,
           Rscratch         = R11_scratch1,
           Rcmp_value       = R17_tos;

  // Align bcp.
  __ addi(Rdef_offset_addr, R14_bcp, BytesPerInt);
  __ clrrdi(Rdef_offset_addr, Rdef_offset_addr, LogBytesPerInt);

  // Setup loop counter and limit.
  __ get_u4(Rcount, Rdef_offset_addr, BytesPerInt, InterpreterMacroAssembler::Unsigned);
  __ addi(Rcurrent_pair, Rdef_offset_addr, 2 * BytesPerInt); // Rcurrent_pair now points to first pair.

  __ mtctr(Rcount);
  __ cmpwi(CCR0, Rcount, 0);
  __ bne(CCR0, Lloop_entry);

  // Default case
  __ bind(Ldefault_case);
  __ get_u4(Roffset, Rdef_offset_addr, 0, InterpreterMacroAssembler::Signed);
  if (ProfileInterpreter) {
    __ profile_switch_default(Rdef_offset_addr, Rcount/* scratch */);
  }
  __ b(Lcontinue_execution);

  // Next iteration
  __ bind(Lsearch_loop);
  __ bdz(Ldefault_case);
  __ addi(Rcurrent_pair, Rcurrent_pair, 2 * BytesPerInt);
  __ bind(Lloop_entry);
  __ get_u4(Rvalue, Rcurrent_pair, 0, InterpreterMacroAssembler::Unsigned);
  __ cmpw(CCR0, Rvalue, Rcmp_value);
  __ bne(CCR0, Lsearch_loop);

  // Found, load offset.
  __ get_u4(Roffset, Rcurrent_pair, BytesPerInt, InterpreterMacroAssembler::Signed);
  // Calculate case index and profile
  __ mfctr(Rcurrent_pair);
  if (ProfileInterpreter) {
    __ sub(Rcurrent_pair, Rcount, Rcurrent_pair);
    __ profile_switch_case(Rcurrent_pair, Rcount /*scratch*/, Rdef_offset_addr/*scratch*/, Rscratch);
  }

  __ bind(Lcontinue_execution);
  __ add(R14_bcp, Roffset, R14_bcp);
  __ dispatch_next(vtos, 0, true);
}

// Table switch using binary search (value/offset pairs are ordered).
// Bytecode stream format:
// Bytecode (1) | 4-byte padding | default offset (4) | count (4) | value/offset pair1 (8) | value/offset pair2 (8) | ...
// Note: Everything is big-endian format here. So on little endian machines, we have to revers offset and count and cmp value.
void TemplateTable::fast_binaryswitch() {

  transition(itos, vtos);
  // Implementation using the following core algorithm: (copied from Intel)
  //
  // int binary_search(int key, LookupswitchPair* array, int n) {
  //   // 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) {
  //     // 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()) {
  //       j = h;
  //     } else {
  //       i = h;
  //     }
  //   }
  //   // R: a[i] <= key < a[i+1] or Q
  //   // (i.e., if key is within array, i is the correct index)
  //   return i;
  // }

  // register allocation
  const Register Rkey     = R17_tos;          // already set (tosca)
  const Register Rarray   = R3_ARG1;
  const Register Ri       = R4_ARG2;
  const Register Rj       = R5_ARG3;
  const Register Rh       = R6_ARG4;
  const Register Rscratch = R11_scratch1;

  const int log_entry_size = 3;
  const int entry_size = 1 << log_entry_size;

  Label found;

  // Find Array start,
  __ addi(Rarray, R14_bcp, 3 * BytesPerInt);
  __ clrrdi(Rarray, Rarray, LogBytesPerInt);

  // initialize i & j
  __ li(Ri,0);
  __ get_u4(Rj, Rarray, -BytesPerInt, InterpreterMacroAssembler::Unsigned);

  // and start.
  Label entry;
  __ b(entry);

  // binary search loop
  { Label loop;
    __ bind(loop);
    // int h = (i + j) >> 1;
    __ srdi(Rh, Rh, 1);
    // if (key < array[h].fast_match()) {
    //   j = h;
    // } else {
    //   i = h;
    // }
    __ sldi(Rscratch, Rh, log_entry_size);
#if defined(VM_LITTLE_ENDIAN)
    __ lwbrx(Rscratch, Rscratch, Rarray);
#else
    __ lwzx(Rscratch, Rscratch, Rarray);
#endif

    // if (key < current value)
    //   Rh = Rj
    // else
    //   Rh = Ri
    Label Lgreater;
    __ cmpw(CCR0, Rkey, Rscratch);
    __ bge(CCR0, Lgreater);
    __ mr(Rj, Rh);
    __ b(entry);
    __ bind(Lgreater);
    __ mr(Ri, Rh);

    // while (i+1 < j)
    __ bind(entry);
    __ addi(Rscratch, Ri, 1);
    __ cmpw(CCR0, Rscratch, Rj);
    __ add(Rh, Ri, Rj); // start h = i + j >> 1;

    __ blt(CCR0, loop);
  }

  // End of binary search, result index is i (must check again!).
  Label default_case;
  Label continue_execution;
  if (ProfileInterpreter) {
    __ mr(Rh, Ri);              // Save index in i for profiling.
  }
  // Ri = value offset
  __ sldi(Ri, Ri, log_entry_size);
  __ add(Ri, Ri, Rarray);
  __ get_u4(Rscratch, Ri, 0, InterpreterMacroAssembler::Unsigned);

  Label not_found;
  // Ri = offset offset
  __ cmpw(CCR0, Rkey, Rscratch);
  __ beq(CCR0, not_found);
  // entry not found -> j = default offset
  __ get_u4(Rj, Rarray, -2 * BytesPerInt, InterpreterMacroAssembler::Unsigned);
  __ b(default_case);

  __ bind(not_found);
  // entry found -> j = offset
  __ profile_switch_case(Rh, Rj, Rscratch, Rkey);
  __ get_u4(Rj, Ri, BytesPerInt, InterpreterMacroAssembler::Unsigned);

  if (ProfileInterpreter) {
    __ b(continue_execution);
  }

  __ bind(default_case); // fall through (if not profiling)
  __ profile_switch_default(Ri, Rscratch);

  __ bind(continue_execution);

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

--> maximum size reached

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

100%


¤ Dauer der Verarbeitung: 0.35 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.