// 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
//
// [1] https://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
// 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
// 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
/* *ArtMethodentrypoint. * *Onentry: *a0ArtMethod*callee *a1-a7methodparameters
*/
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
// 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
.Lentry_go:
la xIBASE, artNterpAsmInstructionStart
START_EXECUTING_INSTRUCTIONS
// NOTE: no fallthrough
// cfi info continues, and covers the whole nterp implementation. SIZE ExecuteNterpImpl
// 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).
// 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:
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
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.