Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  main.S

  Sprache: Sparc
 

/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


/*
 * This is a #include, not a %include, because we want the C pre-processor
 * to expand the macros into assembler assignment statements.
 */

#include "asm_support.h"
#include "arch/riscv64/asm_support_riscv64.S"

/**
 * RISC-V 64 ABI general notes
 *
 * References
 * - https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc
 * - runtime/arch/riscv64/registers_riscv64.h
 *
 * 32 general purposes registers
 * - fixed purpose: zero, ra, sp, gp, tp, s1
 *     gp/scs: shadow call stack - do not clobber!
 *     s1/tr: ART thread register - do not clobber!
 * - temporaries: t0-t6
 * - arguments: a0-a7
 * - callee saved: ra, s0/fp, s2-s11
 *     s0 is flexible, available to use as a frame pointer if needed.
 *
 * 32 floating point registers
 * - temporaries: ft0-ft11
 * - arguments: fa0-fa7
 * - callee saved: fs0-fs11
 */


// Android references
//   Bytecodes: https://source.android.com/docs/core/runtime/dalvik-bytecode
//   Instruction formats: https://source.android.com/docs/core/runtime/instruction-formats
//   Shorty: https://source.android.com/docs/core/runtime/dex-format#shortydescriptor

// Fixed register usages in Nterp.
//    nickname  ABI    reg   purpose
#define xSELF    s1  // x9,   Thread* self pointer
#define xFP      s2  // x18,  interpreted frame pointer: to access locals and args
#define xPC      s3  // x19,  interpreted program counter: to fetch instructions
#define xINST    s4  // x20,  first 16-bit code unit of current instruction
#define xIBASE   s5  // x21,  interpreted instruction base pointer: for computed goto
#define xREFS    s6  // x22,  base of object references of dex registers

// DWARF registers reference
// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-dwarf.adoc
#define CFI_TMP  10  // DWARF register number for       a0/x10
#define CFI_DEX  19  // DWARF register number for xPC  /s3/x19
#define CFI_REFS 22  // DWARF register number for xREFS/s6/x22

// Synchronization
// This code follows the RISC-V atomics ABI specification [1].
//
// Object publication.
// new-instance and new-array operations must first perform a `fence w,w` "constructor fence" to
// ensure their new object references are correctly published with a subsequent SET_VREG_OBJECT.
//
// Volatile load/store.
// A volatile load is implemented as: fence rw,rw ; load ; fence r,rw.
// A 32-bit or 64-bit volatile store is implemented as: amoswap.{w,d}.rl
// A volatile store for a narrower type is implemented as: fence rw,w ; store ; fence rw,rw
//
// [1https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-atomic.adoc

// An assembly entry for nterp.
.macro OAT_ENTRY name
    .type \name, @function
    .hidden \name
    .global \name
    .balign 16
\name:
%   pass
.endm

.macro SIZE name
    .size \name, .-\name
.endm

// Similar to ENTRY but without the CFI directives.
.macro NAME_START name
    .type \name, @function
    .hidden \name  // Hide this as a global symbol, so we do not incur plt calls.
    .global \name
    /* Cache alignment for function entry */
    .balign 16
\name:
%   pass
.endm

.macro NAME_END name
  SIZE \name
.endm

// Macro for defining entrypoints into runtime. We don't need to save registers (we're not holding
// references there), but there is no kDontSave runtime method. So just use the kSaveRefsOnly
// runtime method.
.macro NTERP_TRAMPOLINE name, helper
  ENTRY \name
    SETUP_SAVE_REFS_ONLY_FRAME
    call \helper
    RESTORE_SAVE_REFS_ONLY_FRAME
    ld t0, THREAD_EXCEPTION_OFFSET(xSELF)
    bnez t0, nterp_deliver_pending_exception
    ret
  END \name
.endm

// Unpack code items from dex format.
// Input: \code_item
// Output:
//   - \regs: register count
//   - \outs: out count
//   - \ins: in count. If set to register "zero" (x0), load is skipped.
//   - \code_item: holds instruction array on exit
.macro FETCH_CODE_ITEM_INFO code_item, regs, outs, ins
    // Unpack values from regular dex format.
    lhu \regs, CODE_ITEM_REGISTERS_SIZE_OFFSET(\code_item)
    lhu \outs, CODE_ITEM_OUTS_SIZE_OFFSET(\code_item)
    .ifnc \ins, zero
      lhu \ins, CODE_ITEM_INS_SIZE_OFFSET(\code_item)
    .endif
    addi \code_item, \code_item, CODE_ITEM_INSNS_OFFSET
.endm

.macro EXPORT_PC
    sd xPC, -16(xREFS)
.endm

.macro TEST_IF_MARKING reg, label
    lb \reg, THREAD_IS_GC_MARKING_OFFSET(xSELF)
    bnez \reg, \label
.endm

.macro DO_SUSPEND_CHECK continue
    lwu t0, THREAD_FLAGS_OFFSET(xSELF)
    andi t0, t0, THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
    beqz t0, \continue
    EXPORT_PC
    call art_quick_test_suspend
.endm

// Fetch one or more half-word units from an offset past the current PC.
// The offset is specified in 16-bit code units.
//
// A \width flag allows reading 32 bits (2 units) or 64 bits (4 units) from the offset.
// The RISC-V ISA supports unaligned accesses for these wider loads.
//
// If \width=8, \byte={0,1} indexes into the code unit at the offset.
//
// Default behavior loads one code unit with unsigned zext.
// The \signed flag is for signed sext, for shorter loads.
//
// Does not advance xPC.
.macro FETCH reg, count, signed=0, width=16, byte=0
    .if \width == 8
      .if \signed
        lb  \reg, (\count*2 + \byte)(xPC)
      .else
        lbu \reg, (\count*2 + \byte)(xPC)
      .endif
    .elseif \width == 16
      .if \signed
        lh  \reg, (\count*2)(xPC)
      .else
        lhu \reg, (\count*2)(xPC)
      .endif
    .elseif \width == 32
      .if \signed
        lw  \reg, (\count*2)(xPC)
      .else
        lwu \reg, (\count*2)(xPC)
      .endif
    .elseif \width == 64
      ld  \reg, (\count*2)(xPC)
    .else
      unimp  // impossible
    .endif
.endm

// Fetch the next instruction, from xPC into xINST.
// Does not advance xPC.
.macro FETCH_INST
    lhu xINST, (xPC)  // zero in upper 48 bits
.endm

// Fetch the next instruction, from xPC into xINST. Advance xPC by \count units, each 2 bytes.
//
// Immediates have a 12-bit offset range from xPC. Thus, \count can range from -1024 to 1023.
//
// Note: Must be placed AFTER anything that can throw an exception, or the exception catch may miss.
// Thus, this macro must be placed after EXPORT_PC.
.macro FETCH_ADVANCE_INST count
    lhu xINST, (\count*2)(xPC)  // zero in upper 48 bits
    addi xPC, xPC, (\count*2)
.endm

// Clobbers: \reg
.macro GET_INST_OPCODE reg
    and \reg, xINST, 0xFF
.endm

// Clobbers: \reg
.macro GOTO_OPCODE reg
    slliw \reg, \reg, ${handler_size_bits}
    add \reg, xIBASE, \reg
    jr \reg
.endm

// Inputs:
//   - a0
//   - xSELF
// Clobbers: t0
.macro CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot, if_not_hot
    // TODO(solanes): Figure out if there's a way to load t0 only once.
    lwu t0, ART_METHOD_ACCESS_FLAGS_OFFSET(a0)
    BRANCH_IF_BIT_CLEAR t0, t0, ART_METHOD_IS_MEMORY_SHARED_FLAG_BIT, \if_hot
    lwu t0, ART_METHOD_ACCESS_FLAGS_OFFSET(a0)
    // Intrinsics are always in the boot image and considered hot.
    BRANCH_IF_BIT_SET t0, t0, ART_METHOD_IS_INTRINSIC_FLAG_BIT, \if_hot
    lwu t0, THREAD_SHARED_METHOD_HOTNESS_OFFSET(xSELF)  // t0 := hotness
    beqz t0, \if_hot

    addi t0, t0, -1  // increase hotness
    sw t0,  THREAD_SHARED_METHOD_HOTNESS_OFFSET(xSELF)
    j \if_not_hot
.endm

// Update xPC by \units code units. On back edges, perform hotness and suspend.
.macro BRANCH units
    sh1add xPC, \units, xPC
    blez \units, 1f  // If branch is <= 0, increase hotness and do a suspend check.
    FETCH_INST
    GET_INST_OPCODE t0
    GOTO_OPCODE t0
1:
    tail NterpHotnessCheck
.endm

// Increase method hotness before starting the method.
// Hardcoded:
// - a0: ArtMethod*
// Clobbers: t0
.macro START_EXECUTING_INSTRUCTIONS
    ld a0, (sp)
    lhu t0, ART_METHOD_HOTNESS_COUNT_OFFSET(a0)  // t0 := hotness
#if (NTERP_HOTNESS_VALUE != 0)
#error Expected 0 for hotness value
#endif
    // If the counter is at zero (hot), handle it in the runtime.
    beqz t0, 3f
    addi t0, t0, -1  // increase hotness
    sh t0, ART_METHOD_HOTNESS_COUNT_OFFSET(a0)
1:
    DO_SUSPEND_CHECK continue=2f
2:
    FETCH_INST
    GET_INST_OPCODE t0
    GOTO_OPCODE t0
3:
    CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot=4f, if_not_hot=1b
4:
    mv a1, zero  // dex_pc_ptr=nullptr
    mv a2, zero  // vergs=nullptr
    call nterp_hot_method
    j 2b
.endm

// 64 bit read
// Clobbers: \reg
// Safe if \reg == \vreg.
.macro GET_VREG_WIDE reg, vreg
    sh2add \reg, \vreg, xFP  // vreg addr in register array
    ld \reg, (\reg)          // reg := fp[vreg](lo) | fp[vreg+1](hi)
.endm

// 64 bit write
// Clobbers: z0
.macro SET_VREG_WIDE reg, vreg, z0
    sh2add \z0, \vreg, xFP    // vreg addr in register array
    sd \reg, (\z0)            // fp[vreg] := reg(lo) ; fp[vreg+1] := reg(hi)
    sh2add \z0, \vreg, xREFS  // vreg addr in reference array
    sd zero, (\z0)            // refs[vreg] := null ; refs[vreg+1] := null
.endm

// Object read
// Clobbers: \reg
// Safe if \reg == \vreg.
.macro GET_VREG_OBJECT reg, vreg
    sh2add \reg, \vreg, xREFS  // vreg addr in reference array
    lwu \reg, (\reg)           // reg := refs[vreg]
.endm

// Object write
// Clobbers: z0
.macro SET_VREG_OBJECT reg, vreg, z0
    sh2add \z0, \vreg, xFP    // vreg addr in register array
    sw \reg, (\z0)            // fp[vreg] := reg
    sh2add \z0, \vreg, xREFS  // vreg addr in reference array
    sw \reg, (\z0)            // refs[vreg] := reg
.endm

// Floating-point 64 bit read
// Clobbers: \reg, \vreg
.macro GET_VREG_DOUBLE reg, vreg
    sh2add \vreg, \vreg, xFP  // vreg addr in register array
    fld \reg, (\vreg)         // reg := fp[vreg](lo) | fp[vreg+1](hi)
.endm

// Floating-point 64 bit write
// Clobbers: \reg, z0
.macro SET_VREG_DOUBLE reg, vreg, z0
    sh2add \z0, \vreg, xFP    // vreg addr in register array
    fsd \reg, (\z0)           // fp[vreg] := reg(lo) ; fp[vreg+1] := reg(hi)
    sh2add \z0, \vreg, xREFS  // vreg addr in reference array
    sd zero, (\z0)            // refs[vreg] := null ; refs[vreg+1] := null
.endm

// Put "%def" definitions after ".macro" definitions for proper expansion. %def is greedy.

// Typed read, defaults to 32-bit read
// Note: An object ref requires LWU, or LW;ZEXT.W.
// Clobbers: \reg
// Safe if \reg == \vreg.
%def get_vreg(reg, vreg, width=32, is_wide=False, is_unsigned=False):
%  if is_wide or width == 64:
     GET_VREG_WIDE $reg, $vreg
%  elif is_unsigned:
     sh2add $reg, $vreg, xFP  // vreg addr in register array
     lwu $reg, ($reg)         // reg := fp[vreg], zext
%  else:
     sh2add $reg, $vreg, xFP  // vreg addr in register array
     lw $reg, ($reg)          // reg := fp[vreg]

// Typed write, defaults to 32-bit write.
// Note: Incorrect for an object ref; it requires 2nd SW into xREFS.
// Clobbers: z0
%def set_vreg(reg, vreg, z0, width=32, is_wide=False):
%  if is_wide or width == 64:
     SET_VREG_WIDE $reg, $vreg, $z0
%  else:
     sh2add $z0, $vreg, xFP    // vreg addr in register array
     sw $reg, ($z0)            // fp[vreg] := reg
     sh2add $z0, $vreg, xREFS  // vreg addr in reference array
     sw zero, ($z0)            // refs[vreg] := null

// Floating-point read, defaults to 32-bit read.
// Clobbers: reg, vreg
%def get_vreg_float(reg, vreg, is_double=False):
%  if is_double:
     GET_VREG_DOUBLE $reg, $vreg
%  else:
     sh2add $vreg, $vreg, xFP  // vreg addr in register array
     flw $reg, ($vreg)         // reg := fp[vreg]

// Floating-point write, defaults to 32-bit write.
// Clobbers: reg, z0
%def set_vreg_float(reg, vreg, z0, is_double=False):
%  if is_double:
     SET_VREG_DOUBLE $reg, $vreg, $z0
%  else:
     sh2add $z0, $vreg, xFP    // vreg addr in register array
     fsw $reg, ($z0)           // fp[vreg] := reg
     sh2add $z0, $vreg, xREFS  // vreg addr in reference array
     sw zero, ($z0)            // refs[vreg] := null

/*
 * ArtMethod entry point.
 *
 * On entry:
 *  a0     ArtMethod* callee
 *  a1-a7  method parameters
 */

OAT_ENTRY ExecuteNterpWithClinitImpl
#if MIRROR_CLASS_STATUS_SHIFT < 12
#error mirror class status bits cannot use LUI load technique
#endif
    .cfi_startproc
    // For simplicity, we don't do a read barrier here, but instead rely
    // on art_quick_resolution_trampoline to always have a suspend point before
    // calling back here.
    lwu t0, ART_METHOD_DECLARING_CLASS_OFFSET(a0)
    lw t1, MIRROR_CLASS_STATUS_OFFSET(t0)  // t1 := status word, sext
    lui t2, MIRROR_CLASS_STATUS_VISIBLY_INITIALIZED << (MIRROR_CLASS_STATUS_SHIFT - 12)
    // The unsigned comparison works in tandem with the 64-bit sign-extension of
    // the status bits at the top of the 32-bit word. The order of the status
    // constants (sign extended from LUI) is unchanged with unsigned comparison.
    bgeu t1, t2, ExecuteNterpImpl
    lui t2, MIRROR_CLASS_STATUS_INITIALIZED << (MIRROR_CLASS_STATUS_SHIFT - 12)
    bltu t1, t2, .Linitializing_check
    fence w, w
    j ExecuteNterpImpl
.Linitializing_check:
    lui t2, MIRROR_CLASS_STATUS_INITIALIZING << (MIRROR_CLASS_STATUS_SHIFT - 12)
    bltu t1, t2, .Lresolution_trampoline
    lwu t1, MIRROR_CLASS_CLINIT_THREAD_ID_OFFSET(t0)
    lwu t0, THREAD_TID_OFFSET(xSELF)
    beq t0, t1, ExecuteNterpImpl
.Lresolution_trampoline:
    tail art_quick_resolution_trampoline
    .cfi_endproc
    .type EndExecuteNterpWithClinitImpl, @function
    .hidden EndExecuteNterpWithClinitImpl
    .global EndExecuteNterpWithClinitImpl
EndExecuteNterpWithClinitImpl:
%   pass

OAT_ENTRY ExecuteNterpImpl
   .cfi_startproc
%  setup_nterp_frame(cfi_refs="CFI_REFS", refs="xREFS", fp="xFP", pc="xPC", regs="s7"ins="s8", spills_sp="s9", z0="t0", z1="t1", z2="t2", z3="t3", uniq="entry")
                            // xREFS := callee refs array
                            // xFP   := callee fp array
                            // xPC   := callee dex array
                            // s7    := refs/fp vreg count
                            // s8    := ins count
                            // s9    := post-spills pre-frame sp
                            // sp    := post-frame sp
   CFI_DEFINE_DEX_PC_WITH_OFFSET(/*tmpReg*/CFI_TMP, /*dexReg*/CFI_DEX, /*dexOffset*/0)

   // Fast path: zero args.
   beqz s8, .Lentry_go

   sub s7, s7, s8           // s7 := a1 index in fp/refs
   lwu s10, ART_METHOD_ACCESS_FLAGS_OFFSET(a0)
                            // s10 := method flags

   // Fast path: all reference args.
   sh2add t0, s7, xFP       // t0 := &xFP[a1]
   sh2add t1, s7, xREFS     // t1 := &xREFS[a1]
   BRANCH_IF_BIT_CLEAR t2, s10, ART_METHOD_NTERP_ENTRY_POINT_FAST_PATH_FLAG_BIT, .Lentry_a1
%  setup_ref_args_and_go(fp="t0", refs="t1", refs_end="xFP", spills_sp="s9", z0="t2", z1="t3", done=".Lentry_go")

   // Fast path: instance with zero args.
.Lentry_a1:
   bexti s10, s10, ART_METHOD_IS_STATIC_FLAG_BIT
                            // s10 := 1 if static, 0 if instance
   bnez s10, .Lentry_shorty
   sw a1, (t0)
   sw a1, (t1)
   li t2, 1
   beq s8, t2, .Lentry_go

   // Slow path: runtime call to obtain shorty, full setup from managed ABI.
.Lentry_shorty:
   SPILL_ALL_ARGUMENTS
   // TODO: Better way to get shorty
   call NterpGetShorty      // arg a0
   mv s11, a0               // s11 := shorty
   RESTORE_ALL_ARGUMENTS

   // temporaries are trashed, recompute some values
   sh2add t0, s7, xFP       // t0 := &xFP[a1]
   sh2add t1, s7, xREFS     // t1 := &xREFS[a1]
   addi t2, s11, 1          // t2 := shorty arg (skip return type)
   xori s10, s10, 1         // s10 := 0 if static, 1 if instance
   slliw t3, s10, 2         // t3 := (static) 0, (instance) 4: fp/refs/outs byte offset
   // constant setup for gpr/fpr shorty comparisons
   li s0, 'D'               // s0 := double char (unused fp)
   li s4, 'F'               // s4 := float char (unused xINST)
   li s5, 'J'               // s5 := long char (unused xIBASE)
   li s8, 'L'               // s8 := ref char (unused ins count)
   bnez s10, .Lentry_args   // instance a1 already stored into callee's xFP and xREFS

%  store_gpr_to_vreg(gpr="a1", offset="t3", shorty="t2", fp="t0", refs="t1", z0="t4", z1="t5", D="s0", F="s4", J="s5", L="s8", next=".Lentry_fargs")

.Lentry_args:
   // linear scan through shorty: extract non-float args
%  store_gpr_to_vreg(gpr="a2", offset="t3", shorty="t2", fp="t0", refs="t1", z0="t4", z1="t5", D="s0", F="s4", J="s5", L="s8", next=".Lentry_fargs")
%  store_gpr_to_vreg(gpr="a3", offset="t3", shorty="t2", fp="t0", refs="t1", z0="t4", z1="t5", D="s0", F="s4", J="s5", L="s8", next=".Lentry_fargs")
%  store_gpr_to_vreg(gpr="a4", offset="t3", shorty="t2", fp="t0", refs="t1", z0="t4", z1="t5", D="s0", F="s4", J="s5", L="s8", next=".Lentry_fargs")
%  store_gpr_to_vreg(gpr="a5", offset="t3", shorty="t2", fp="t0", refs="t1", z0="t4", z1="t5", D="s0", F="s4", J="s5", L="s8", next=".Lentry_fargs")
%  store_gpr_to_vreg(gpr="a6", offset="t3", shorty="t2", fp="t0", refs="t1", z0="t4", z1="t5", D="s0", F="s4", J="s5", L="s8", next=".Lentry_fargs")
%  store_gpr_to_vreg(gpr="a7", offset="t3", shorty="t2", fp="t0", refs="t1", z0="t4", z1="t5", D="s0", F="s4", J="s5", L="s8", next=".Lentry_fargs")
   // We drained arg registers, so continue from caller stack's out array. Unlike the reference-only
   // fast-path, the continuation offset in the out array can vary, depending on the presence of
   // 64-bit values in the arg registers. \offset tracks this value as a byte offset.
   addi t5, s9, (NTERP_SIZE_SAVE_CALLEE_SAVES + 8)
                            // t5 := (caller) outs array base address
   add t4, t3, t0           // t4 := (callee) &FP[next]
   add t1, t3, t1           // t1 := (callee) &REFS[next]
   add t3, t3, t5           // t3 := (caller) &OUTS[next]
%  store_outs_to_vregs(outs="t3", shorty="t2", fp="t4", refs="t1", z0="t5", z1="t6", D="s0", F="s4", J="s5", L="s8", next=".Lentry_fargs")
                            // t0 = &xFP[a1], unclobbered
.Lentry_fargs:
   addi t1, s11, 1          // t1 := shorty arg (skip return type)
   slliw t2, s10, 2         // t2 := starting byte offset for fp/outs, static and instance
   // linear scan through shorty: extract float args
%  store_fpr_to_vreg(fpr="fa0", offset="t2", shorty="t1", fp="t0", z0="t3", z1="t4", D="s0", F="s4", J="s5", next=".Lentry_go")
%  store_fpr_to_vreg(fpr="fa1", offset="t2", shorty="t1", fp="t0", z0="t3", z1="t4", D="s0", F="s4", J="s5", next=".Lentry_go")
%  store_fpr_to_vreg(fpr="fa2", offset="t2", shorty="t1", fp="t0", z0="t3", z1="t4", D="s0", F="s4", J="s5", next=".Lentry_go")
%  store_fpr_to_vreg(fpr="fa3", offset="t2", shorty="t1", fp="t0", z0="t3", z1="t4", D="s0", F="s4", J="s5", next=".Lentry_go")
%  store_fpr_to_vreg(fpr="fa4", offset="t2", shorty="t1", fp="t0", z0="t3", z1="t4", D="s0", F="s4", J="s5", next=".Lentry_go")
%  store_fpr_to_vreg(fpr="fa5", offset="t2", shorty="t1", fp="t0", z0="t3", z1="t4", D="s0", F="s4", J="s5", next=".Lentry_go")
%  store_fpr_to_vreg(fpr="fa6", offset="t2", shorty="t1", fp="t0", z0="t3", z1="t4", D="s0", F="s4", J="s5", next=".Lentry_go")
%  store_fpr_to_vreg(fpr="fa7", offset="t2", shorty="t1", fp="t0", z0="t3", z1="t4", D="s0", F="s4", J="s5", next=".Lentry_go")
   addi t3, s9, (NTERP_SIZE_SAVE_CALLEE_SAVES + 8)
                            // t3 := (caller) outs array base address
   add t0, t2, t0           // t0 := (callee) &FP[next]
   add t2, t2, t3           // t2 := (caller) &OUTS[next]
%  store_float_outs_to_vregs(outs="t2", shorty="t1", fp="t0", z0="t3", D="s0", F="s4", J="s5", next=".Lentry_go")

.Lentry_go:
   la xIBASE, artNterpAsmInstructionStart
   START_EXECUTING_INSTRUCTIONS
   // NOTE: no fallthrough
   // cfi info continues, and covers the whole nterp implementation.
   SIZE ExecuteNterpImpl

%def footer():
/*
 * ===========================================================================
 *  Common subroutines and data
 * ===========================================================================
 */


  .text
  .align  2


  // Enclose all code below in a symbol (which gets printed in backtraces).
  NAME_START nterp_helper

common_errArrayIndex:
    EXPORT_PC
    // CALL preserves RA for stack walking.
    call art_quick_throw_array_bounds  // args a0 (index), a1 (length)

common_errDivideByZero:
    EXPORT_PC
    // CALL preserves RA for stack walking.
    call art_quick_throw_div_zero

common_errNullObject:
    EXPORT_PC
    // CALL preserves RA for stack walking.
    call art_quick_throw_null_pointer_exception

NterpInvokeVirtual:
%   nterp_invoke_virtual()
NterpInvokeSuper:
%   nterp_invoke_super()
NterpInvokeDirect:
%   nterp_invoke_direct()
NterpInvokeStringInit:
%   nterp_invoke_string_init()
NterpInvokeStatic:
%   nterp_invoke_static()
NterpInvokeInterface:
%   nterp_invoke_interface()
NterpInvokePolymorphic:
%   nterp_invoke_polymorphic()
NterpInvokeCustom:
%   nterp_invoke_custom()
NterpInvokeVirtualRange:
%   nterp_invoke_virtual_range()
NterpInvokeSuperRange:
%   nterp_invoke_super_range()
NterpInvokeDirectRange:
%   nterp_invoke_direct_range()
NterpInvokeStringInitRange:
%   nterp_invoke_string_init_range()
NterpInvokeStaticRange:
%   nterp_invoke_static_range()
NterpInvokeInterfaceRange:
%   nterp_invoke_interface_range()
NterpInvokePolymorphicRange:
%   nterp_invoke_polymorphic_range()
NterpInvokeCustomRange:
%   nterp_invoke_custom_range()

NterpHotnessCheck:
    ld a0, (sp)
    lhu t0, ART_METHOD_HOTNESS_COUNT_OFFSET(a0)  // t0 := hotness
#if (NTERP_HOTNESS_VALUE != 0)
#error Expected 0 for hotness value
#endif
    // If the counter is at zero (hot), handle it in the runtime.
    beqz t0, 3f
    addi t0, t0, -1  // increase hotness
    sh t0, ART_METHOD_HOTNESS_COUNT_OFFSET(a0)
1:
    DO_SUSPEND_CHECK continue=2f
2:
    FETCH_INST
    GET_INST_OPCODE t0
    GOTO_OPCODE t0

3:
    CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot=4f, if_not_hot=1b
4:
    mv a1, xPC
    mv a2, xFP
    call nterp_hot_method  // args a0, a1, a2
    beqz a0, 2b

    // a0 = OsrData*
    // Drop most of the current nterp frame, but keep the callee-saves.
    // The nterp callee-saves (count and layout) match the OSR frame's callee-saves.
    ld sp, -8(xREFS)  // caller's interpreted frame pointer
    .cfi_def_cfa sp, NTERP_SIZE_SAVE_CALLEE_SAVES
    lwu t0, OSR_DATA_FRAME_SIZE(a0)
    addi t0, t0, -NTERP_SIZE_SAVE_CALLEE_SAVES  // t0 := osr frame - callee saves, in bytes
    mv s7, sp         // Remember CFA in a callee-save register.
    .cfi_def_cfa_register s7
    sub sp, sp, t0    // OSR size guaranteed to be stack aligned (16 bytes).

    addi t1, a0, OSR_DATA_MEMORY  // t1 := read start
    add t1, t1, t0                // t1 := read end (exclusive)
    mv t2, s7                     // t2 := write end (exclusive)
    // t0 >= 8 (OSR places ArtMethod* at bottom of frame), so loop will terminate.
.Lhotspill_osr_copy_loop:
    addi t1, t1, -8
    ld t3, (t1)
    addi t2, t2, -8
    sd t3, (t2)
    bne t2, sp, .Lhotspill_osr_copy_loop

    ld s8, OSR_DATA_NATIVE_PC(a0)  // s8 := native PC; jump after free
    call free  // arg a0; release OsrData*
    jr s8      // Jump to the compiled code.

    // This is the logical end of ExecuteNterpImpl, where the frame info applies.
    .cfi_endproc

NterpToNterpInstance:
%   nterp_to_nterp_instance()
NterpToNterpStringInit:
%   nterp_to_nterp_string_init()
NterpToNterpStatic:
%   nterp_to_nterp_static()
NterpToNterpInstanceRange:
%   nterp_to_nterp_instance_range()
NterpToNterpStringInitRange:
%   nterp_to_nterp_string_init_range()
NterpToNterpStaticRange:
%   nterp_to_nterp_static_range()

  NAME_END nterp_helper

  // EndExecuteNterpImpl includes the methods after .cfi_endproc, as we want the runtime to see them
  // as part of the Nterp PCs. This label marks the end of PCs contained by the OatQuickMethodHeader
  // created for the interpreter entry point.
  .type EndExecuteNterpImpl, @function
  .hidden EndExecuteNterpImpl
  .global EndExecuteNterpImpl
  EndExecuteNterpImpl:

  // Entrypoints into runtime.
  NTERP_TRAMPOLINE nterp_allocate_object, NterpAllocateObject
  NTERP_TRAMPOLINE nterp_filled_new_array, NterpFilledNewArray
  NTERP_TRAMPOLINE nterp_filled_new_array_range, NterpFilledNewArrayRange
  NTERP_TRAMPOLINE nterp_get_class, NterpGetClass
  NTERP_TRAMPOLINE nterp_get_instance_field_offset, NterpGetInstanceFieldOffset
  NTERP_TRAMPOLINE nterp_get_method, NterpGetMethod
  NTERP_TRAMPOLINE nterp_get_static_field, NterpGetStaticField
  NTERP_TRAMPOLINE nterp_hot_method, NterpHotMethod
  NTERP_TRAMPOLINE nterp_load_object, NterpLoadObject

  ENTRY nterp_deliver_pending_exception
      DELIVER_PENDING_EXCEPTION
  END nterp_deliver_pending_exception

// gen_mterp.py will inline the following definitions
// within [ExecuteNterpImpl, EndExecuteNterpImpl).
%def instruction_start():
    .type artNterpAsmInstructionStart, @function
    .hidden artNterpAsmInstructionStart
    .global artNterpAsmInstructionStart
    artNterpAsmInstructionStart = ${opcode_name_prefix}op_nop
    .text

%def instruction_end():
    .type artNterpAsmInstructionEnd, @function
    .hidden artNterpAsmInstructionEnd
    .global artNterpAsmInstructionEnd
artNterpAsmInstructionEnd:
    // artNterpAsmInstructionEnd is used as landing pad for exception handling.
    // xPC (S3) for the exception handler was set just prior to the long jump coming here.
    FETCH_INST
    GET_INST_OPCODE t0
    GOTO_OPCODE t0

%def fetch_from_thread_cache(reg, miss_label, z0, z1):
    // See art::InterpreterCache::IndexOf() for computing index of key within cache array.
    // Entry address:
    //   xSELF + OFFSET + ((xPC>>2 & xFF) << 4)
    // = xSELF + OFFSET + ((xPC & xFF<<2) << 2)
    // = xSELF + ((OFFSET>>2 + (xPC & xFF<<2)) << 2)
    // => ANDI, ADD, SH2ADD
#if (THREAD_INTERPRETER_CACHE_SIZE_LOG2 != 8)
#error Expected interpreter cache array size = 256 elements
#endif
#if (THREAD_INTERPRETER_CACHE_KEY_TO_ENTRY_SHIFT != 2)
#error Expected interpreter cache key to entry shift 2
#endif
#if ((THREAD_INTERPRETER_CACHE_OFFSET & 0x3) != 0)
#error Expected interpreter cache offset to be 4-byte aligned
#endif
    andi ${z0}, xPC, THREAD_INTERPRETER_CACHE_KEY_MASK
    addi ${z0}, ${z0}, THREAD_INTERPRETER_CACHE_OFFSET >> 2
    sh2add ${z0}, ${z0}, xSELF  // z0 := entry's address
    ld ${z1}, (${z0})           // z1 := dex PC
    bne xPC, ${z1}, ${miss_label}
    ld ${reg}, 8(${z0})         // value: depends on context; see call site

%def opcode_pre():
%   pass
%def opcode_name_prefixes():
%   return ["nterp_"]
%def opcode_start():
  NAME_START ${opcode}
%   pass
%def opcode_end():
  NAME_END ${opcode}
%def opcode_slow_path_start(name):
  NAME_START ${name}
%   pass
%def opcode_slow_path_end(name):
  NAME_END ${name}

Messung V0.5 in Prozent
C=92 H=98 G=94

¤ Dauer der Verarbeitung: 0.30 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

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 und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik