790 lines
32 KiB
ArmAsm
790 lines
32 KiB
ArmAsm
/*
|
|
* 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.
|
|
*/
|
|
|
|
#include "asm_support_riscv64.S"
|
|
#include "interpreter/cfi_asm_support.h"
|
|
|
|
|
|
// Wrap ExecuteSwitchImpl in assembly method which specifies DEX PC for unwinding.
|
|
// Argument 0: a0: The context pointer for ExecuteSwitchImpl.
|
|
// Argument 1: a1: Pointer to the templated ExecuteSwitchImpl to call.
|
|
// Argument 2: a2: The value of DEX PC (memory address of the methods bytecode).
|
|
ENTRY ExecuteSwitchImplAsm
|
|
INCREASE_FRAME 16
|
|
SAVE_GPR s1, 0
|
|
SAVE_GPR ra, 8
|
|
|
|
mv s1, a2 // s1 = DEX PC
|
|
CFI_DEFINE_DEX_PC_WITH_OFFSET(0 /* a0 */, 9 /* s1, a.k.a. x9 */, 0)
|
|
jalr a1 // Call the wrapped method.
|
|
|
|
RESTORE_GPR s1, 0
|
|
RESTORE_GPR ra, 8
|
|
DECREASE_FRAME 16
|
|
ret
|
|
END ExecuteSwitchImplAsm
|
|
|
|
|
|
.macro INVOKE_STUB_CREATE_FRAME
|
|
// Save ra, fp, xSELF (current thread) a4, a5 (they will be needed in the invoke stub return)
|
|
// and callee-save regs s3 - s5 that are clobbered here and in art_quick_invoke_(static_)_stub.
|
|
INCREASE_FRAME 48
|
|
SAVE_GPR fp, (8*0)
|
|
SAVE_GPR xSELF, (8*1)
|
|
SAVE_GPR a4, (8*2)
|
|
SAVE_GPR a5, (8*3)
|
|
SAVE_GPR s3, (8*4)
|
|
SAVE_GPR ra, (8*5)
|
|
|
|
mv fp, sp // save frame pointer
|
|
.cfi_def_cfa_register fp
|
|
|
|
addi t0, a2, (__SIZEOF_POINTER__ + 0xf) // Reserve space for ArtMethod*, arguments and
|
|
andi t0, t0, ~0xf // round up for 16-byte stack alignment.
|
|
sub sp, sp, t0
|
|
|
|
mv xSELF, a3
|
|
|
|
// Copy arguments on stack (4 bytes per slot):
|
|
// a1: source address
|
|
// a2: arguments length
|
|
// s3: destination address.
|
|
|
|
add s3, sp, 8 // destination address is bottom of the stack + 8 bytes for ArtMethod* (null)
|
|
|
|
beqz a2, 2f // loop through 4-byte arguments from the last to the first
|
|
1:
|
|
addi a2, a2, -4
|
|
add t0, a1, a2 // t0 is the source address of the next copied argument
|
|
lw t1, (t0) // t1 is the 4 bytes at address t0
|
|
add t0, s3, a2 // t0 is the destination address of the next copied argument
|
|
sw t1, (t0) // save t1 at the destination address t0
|
|
bnez a2, 1b
|
|
2:
|
|
sd zero, (sp) // Store null into ArtMethod* at bottom of frame.
|
|
.endm
|
|
|
|
|
|
.macro INVOKE_STUB_CALL_AND_RETURN
|
|
// Call the method.
|
|
ld t0, ART_METHOD_QUICK_CODE_OFFSET_64(a0)
|
|
jalr t0
|
|
|
|
mv sp, fp // restore frame pointer
|
|
.cfi_def_cfa_register sp
|
|
|
|
// Restore ra, fp, xSELF (current thread) a4 (shorty), a5 (result pointer) and callee-save
|
|
// regs s3 - s5 from stack.
|
|
RESTORE_GPR fp, (8*0)
|
|
RESTORE_GPR xSELF, (8*1)
|
|
RESTORE_GPR a4, (8*2)
|
|
RESTORE_GPR a5, (8*3)
|
|
RESTORE_GPR s3, (8*4)
|
|
RESTORE_GPR ra, (8*5)
|
|
DECREASE_FRAME 48
|
|
|
|
// Load result type (1-byte symbol) from a5.
|
|
// Check result type and store the correct register into the jvalue in memory at a4 address.
|
|
lbu t0, (a5)
|
|
|
|
li t1, 'V' // void (do not store result at all)
|
|
beq t1, t0, 1f
|
|
|
|
li t1, 'D' // double
|
|
beq t1, t0, 2f
|
|
|
|
li t1, 'F' // float
|
|
beq t1, t0, 3f
|
|
|
|
// Otherwise, result is in a0 (either 8 or 4 bytes, but it is fine to store 8 bytes as the
|
|
// upper bytes in a0 in that case are zero, and jvalue has enough space).
|
|
sd a0, (a4)
|
|
1:
|
|
ret
|
|
|
|
2: // double: result in fa0 (8 bytes)
|
|
fsd fa0, (a4)
|
|
ret
|
|
|
|
3: // float: result in fa0 (4 bytes)
|
|
fsw fa0, (a4)
|
|
ret
|
|
.endm
|
|
|
|
|
|
ENTRY art_deliver_pending_exception
|
|
DELIVER_PENDING_EXCEPTION
|
|
END art_deliver_pending_exception
|
|
|
|
|
|
// Macros for loading an argument into a register.
|
|
// label - the base name of the label of the load routine,
|
|
// reg - the register to load,
|
|
// args - pointer to current argument, incremented by size,
|
|
// size - the size of the register - 4 or 8 bytes,
|
|
// load - instruction used for loading,
|
|
// nh4_reg - the register to fill with the address of the next handler for 4-byte values,
|
|
// nh4_l - the base name of the label of the next handler for 4-byte values,
|
|
// nh8_reg - the register to fill with the address of the next handler for 8-byte values,
|
|
// nh8_l - the base name of the label of the next handler for 8-byte values,
|
|
// cont - the base name of the label for continuing the shorty processing loop,
|
|
// sfx - suffix added to all labels to make labels unique for different users.
|
|
.macro INVOKE_STUB_LOAD_REG label, reg, args, size, load, nh4_reg, nh4_l, nh8_reg, nh8_l, cont, sfx
|
|
\label\sfx:
|
|
\load \reg, (\args)
|
|
addi \args, \args, \size
|
|
la \nh4_reg, \nh4_l\sfx
|
|
la \nh8_reg, \nh8_l\sfx
|
|
j \cont\sfx
|
|
.endm
|
|
|
|
|
|
// Macro for skipping an argument that does not fit into argument registers.
|
|
// label - the base name of the label of the skip routine,
|
|
// args - pointer to current argument, incremented by size,
|
|
// size - the size of the argument - 4 or 8 bytes,
|
|
// cont - the base name of the label for continuing the shorty processing loop,
|
|
// sfx - suffix added to all labels to make labels unique for different users.
|
|
.macro INVOKE_STUB_SKIP_ARG label, args, size, cont, sfx
|
|
\label\sfx:
|
|
addi \args, \args, \size
|
|
j \cont\sfx
|
|
.endm
|
|
|
|
|
|
// Fill registers a1 to a7 and fa0 to fa7 with parameters.
|
|
// Parse the passed shorty to determine which register to load.
|
|
// a5 - shorty,
|
|
// s3 - points to arguments on the stack,
|
|
// sfx - suffix added to all labels to make labels unique for different users.
|
|
.macro INVOKE_STUB_LOAD_ALL_ARGS sfx
|
|
mv t0, a5 // Load shorty address,
|
|
addi t0, t0, 1 // plus one to skip the return type.
|
|
|
|
// Load this (if instance method) and addresses for routines that load argument GPRs and FPRs.
|
|
.ifc \sfx, _instance
|
|
lw a1, (s3) // Load "this" parameter,
|
|
addi s3, s3, 4 // and increment arg pointer.
|
|
la t3, .Lload4i2\sfx
|
|
la t4, .Lload8i2\sfx
|
|
.else
|
|
la t3, .Lload4i1\sfx
|
|
la t4, .Lload8i1\sfx
|
|
.endif
|
|
la t5, .Lload4f0\sfx
|
|
la t6, .Lload8f0\sfx
|
|
|
|
// Loop to fill registers.
|
|
.Lfill_regs\sfx:
|
|
lb t1, (t0) // Load next character in signature, and increment.
|
|
addi t0, t0, 1 // and increment.
|
|
beqz t1, .Lcall_method\sfx // Exit at end of signature. Shorty 0 terminated.
|
|
|
|
li t2, 'J'
|
|
beq t1, t2, .Lload_long\sfx // Is this a long?
|
|
|
|
li t2, 'F'
|
|
beq t1, t2, .Lload_float\sfx // Is this a float?
|
|
|
|
li t2, 'D'
|
|
beq t1, t2, .Lload_double\sfx // Is this a double?
|
|
|
|
// Everything else uses a 4-byte GPR.
|
|
jr t3
|
|
|
|
.Lload_long\sfx:
|
|
jr t4
|
|
|
|
.Lload_float\sfx:
|
|
jr t5
|
|
|
|
.Lload_double\sfx:
|
|
jr t6
|
|
|
|
// Handlers for loading other args (not float/double/long) into 4-byte GPRs.
|
|
.ifnc \sfx, _instance
|
|
INVOKE_STUB_LOAD_REG \
|
|
.Lload4i1, a1, s3, 4, lw, t3, .Lload4i2, t4, .Lload8i2, .Lfill_regs, \sfx
|
|
.endif
|
|
INVOKE_STUB_LOAD_REG .Lload4i2, a2, s3, 4, lw, t3, .Lload4i3, t4, .Lload8i3, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload4i3, a3, s3, 4, lw, t3, .Lload4i4, t4, .Lload8i4, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload4i4, a4, s3, 4, lw, t3, .Lload4i5, t4, .Lload8i5, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload4i5, a5, s3, 4, lw, t3, .Lload4i6, t4, .Lload8i6, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload4i6, a6, s3, 4, lw, t3, .Lload4i7, t4, .Lload8i7, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload4i7, a7, s3, 4, lw, t3, .Lskip4, t4, .Lskip8, .Lfill_regs, \sfx
|
|
|
|
// Handlers for loading longs into 8-byte GPRs.
|
|
.ifnc \sfx, _instance
|
|
INVOKE_STUB_LOAD_REG \
|
|
.Lload8i1, a1, s3, 8, ld, t3, .Lload4i2, t4, .Lload8i2, .Lfill_regs, \sfx
|
|
.endif
|
|
INVOKE_STUB_LOAD_REG .Lload8i2, a2, s3, 8, ld, t3, .Lload4i3, t4, .Lload8i3, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload8i3, a3, s3, 8, ld, t3, .Lload4i4, t4, .Lload8i4, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload8i4, a4, s3, 8, ld, t3, .Lload4i5, t4, .Lload8i5, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload8i5, a5, s3, 8, ld, t3, .Lload4i6, t4, .Lload8i6, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload8i6, a6, s3, 8, ld, t3, .Lload4i7, t4, .Lload8i7, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload8i7, a7, s3, 8, ld, t3, .Lskip4, t4, .Lskip8, .Lfill_regs, \sfx
|
|
|
|
// Handlers for loading floats into FPRs.
|
|
INVOKE_STUB_LOAD_REG .Lload4f0, fa0, s3, 4, flw, t5, .Lload4f1, t6, .Lload8f1, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload4f1, fa1, s3, 4, flw, t5, .Lload4f2, t6, .Lload8f2, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload4f2, fa2, s3, 4, flw, t5, .Lload4f3, t6, .Lload8f3, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload4f3, fa3, s3, 4, flw, t5, .Lload4f4, t6, .Lload8f4, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload4f4, fa4, s3, 4, flw, t5, .Lload4f5, t6, .Lload8f5, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload4f5, fa5, s3, 4, flw, t5, .Lload4f6, t6, .Lload8f6, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload4f6, fa6, s3, 4, flw, t5, .Lload4f7, t6, .Lload8f7, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload4f7, fa7, s3, 4, flw, t5, .Lskip4, t6, .Lskip8, .Lfill_regs, \sfx
|
|
|
|
// Handlers for loading doubles into FPRs.
|
|
INVOKE_STUB_LOAD_REG .Lload8f0, fa0, s3, 8, fld, t5, .Lload4f1, t6, .Lload8f1, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload8f1, fa1, s3, 8, fld, t5, .Lload4f2, t6, .Lload8f2, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload8f2, fa2, s3, 8, fld, t5, .Lload4f3, t6, .Lload8f3, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload8f3, fa3, s3, 8, fld, t5, .Lload4f4, t6, .Lload8f4, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload8f4, fa4, s3, 8, fld, t5, .Lload4f5, t6, .Lload8f5, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload8f5, fa5, s3, 8, fld, t5, .Lload4f6, t6, .Lload8f6, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload8f6, fa6, s3, 8, fld, t5, .Lload4f7, t6, .Lload8f7, .Lfill_regs, \sfx
|
|
INVOKE_STUB_LOAD_REG .Lload8f7, fa7, s3, 8, fld, t5, .Lskip4, t6, .Lskip8, .Lfill_regs, \sfx
|
|
|
|
// Handlers for skipping arguments that do not fit into registers.
|
|
INVOKE_STUB_SKIP_ARG .Lskip4, s3, 4, .Lfill_regs, \sfx
|
|
INVOKE_STUB_SKIP_ARG .Lskip8, s3, 8, .Lfill_regs, \sfx
|
|
|
|
.Lcall_method\sfx:
|
|
.endm
|
|
|
|
|
|
// void art_quick_invoke_stub(ArtMethod* method, // a0
|
|
// uint32_t* args, // a1
|
|
// uint32_t argsize, // a2
|
|
// Thread* self, // a3
|
|
// JValue* result, // a4
|
|
// char* shorty) // a5
|
|
ENTRY art_quick_invoke_stub
|
|
INVOKE_STUB_CREATE_FRAME
|
|
|
|
// Load args into registers.
|
|
INVOKE_STUB_LOAD_ALL_ARGS _instance
|
|
|
|
// Call the method and return.
|
|
INVOKE_STUB_CALL_AND_RETURN
|
|
END art_quick_invoke_stub
|
|
|
|
|
|
// void art_quick_invoke_static_stub(ArtMethod* method, // a0
|
|
// uint32_t* args, // a1
|
|
// uint32_t argsize, // a2
|
|
// Thread* self, // a3
|
|
// JValue* result, // a4
|
|
// char* shorty) // a5
|
|
ENTRY art_quick_invoke_static_stub
|
|
INVOKE_STUB_CREATE_FRAME
|
|
|
|
// Load args into registers.
|
|
INVOKE_STUB_LOAD_ALL_ARGS _static
|
|
|
|
// Call the method and return.
|
|
INVOKE_STUB_CALL_AND_RETURN
|
|
END art_quick_invoke_static_stub
|
|
|
|
|
|
ENTRY art_quick_generic_jni_trampoline
|
|
SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_A0
|
|
|
|
// Save sp, so we can have static CFI info.
|
|
mv fp, sp
|
|
.cfi_def_cfa_register fp
|
|
|
|
li t0, GENERIC_JNI_TRAMPOLINE_RESERVED_AREA
|
|
sub sp, sp, t0
|
|
|
|
mv a0, xSELF // Thread*
|
|
mv a1, fp // SP for the managed frame.
|
|
mv a2, sp // reserved area for arguments and other saved data (up to managed frame)
|
|
call artQuickGenericJniTrampoline
|
|
|
|
// Check for error (class init check or locking for synchronized native method can throw).
|
|
beqz a0, .Lexception_in_native
|
|
|
|
mv t0, a0 // save pointer to native method code into temporary
|
|
|
|
// Load argument GPRs from stack (saved there by artQuickGenericJniTrampoline).
|
|
ld a0, 8*0(sp) // JniEnv* for the native method
|
|
ld a1, 8*1(sp)
|
|
ld a2, 8*2(sp)
|
|
ld a3, 8*3(sp)
|
|
ld a4, 8*4(sp)
|
|
ld a5, 8*5(sp)
|
|
ld a6, 8*6(sp)
|
|
ld a7, 8*7(sp)
|
|
|
|
// Load argument FPRs from stack (saved there by artQuickGenericJniTrampoline).
|
|
fld fa0, 8*8(sp)
|
|
fld fa1, 8*9(sp)
|
|
fld fa2, 8*10(sp)
|
|
fld fa3, 8*11(sp)
|
|
fld fa4, 8*12(sp)
|
|
fld fa5, 8*13(sp)
|
|
fld fa6, 8*14(sp)
|
|
fld fa7, 8*15(sp)
|
|
|
|
ld t6, 8*16(sp) // @CriticalNative arg, used by art_jni_dlsym_lookup_critical_stub
|
|
|
|
ld t1, 8*17(sp) // restore stack
|
|
mv sp, t1
|
|
|
|
jalr t0 // call native method
|
|
|
|
// result sign extension is handled in C code, prepare for artQuickGenericJniEndTrampoline call:
|
|
// uint64_t artQuickGenericJniEndTrampoline(Thread* self, // a0
|
|
// jvalue result, // a1 (need to move from a0)
|
|
// uint64_t result_f) // a2 (need to move from fa0)
|
|
mv a1, a0
|
|
mv a0, xSELF
|
|
fmv.x.d a2, fa0
|
|
call artQuickGenericJniEndTrampoline
|
|
|
|
// Pending exceptions possible.
|
|
ld t0, THREAD_EXCEPTION_OFFSET(xSELF)
|
|
bnez t0, .Lexception_in_native
|
|
|
|
// Tear down the alloca.
|
|
mv sp, fp
|
|
.cfi_remember_state
|
|
.cfi_def_cfa_register sp
|
|
|
|
LOAD_RUNTIME_INSTANCE a1
|
|
lb a1, RUN_EXIT_HOOKS_OFFSET_FROM_RUNTIME_INSTANCE(a1)
|
|
bnez a1, .Lcall_method_exit_hook
|
|
|
|
.Lcall_method_exit_hook_done:
|
|
// This does not clobber the result register a0. a1 is not used for result as the managed code
|
|
// does not have a 128-bit type. Alternatively we could restore a subset of these registers.
|
|
RESTORE_SAVE_REFS_AND_ARGS_FRAME
|
|
fmv.d.x fa0, a0
|
|
ret
|
|
CFI_RESTORE_STATE_AND_DEF_CFA sp, FRAME_SIZE_SAVE_REFS_AND_ARGS
|
|
|
|
.Lcall_method_exit_hook:
|
|
fmv.d.x fa0, a0
|
|
li a4, FRAME_SIZE_SAVE_REFS_AND_ARGS
|
|
jal art_quick_method_exit_hook
|
|
j .Lcall_method_exit_hook_done
|
|
|
|
.Lexception_in_native:
|
|
// Move to a1 then sp to please assembler.
|
|
ld a1, THREAD_TOP_QUICK_FRAME_OFFSET(xSELF)
|
|
addi sp, a1, -1 // Remove the GenericJNI tag.
|
|
call art_deliver_pending_exception
|
|
END art_quick_generic_jni_trampoline
|
|
|
|
|
|
ENTRY art_quick_to_interpreter_bridge
|
|
SETUP_SAVE_REFS_AND_ARGS_FRAME
|
|
|
|
// uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self, ArtMethod** sp)
|
|
// a0 will contain ArtMethod*
|
|
mv a1, xSELF
|
|
mv a2, sp
|
|
call artQuickToInterpreterBridge
|
|
|
|
// TODO: no need to restore arguments in this case.
|
|
RESTORE_SAVE_REFS_AND_ARGS_FRAME
|
|
|
|
fmv.d.x fa0, a0 // copy the result to FP result register
|
|
|
|
RETURN_OR_DELIVER_PENDING_EXCEPTION_REG t0
|
|
END art_quick_to_interpreter_bridge
|
|
|
|
|
|
.extern artMethodExitHook
|
|
ENTRY art_quick_method_exit_hook
|
|
SETUP_SAVE_EVERYTHING_FRAME
|
|
|
|
addi a3, sp, SAVE_EVERYTHING_FRAME_OFFSET_FA0 // FP result ptr in kSaveEverything frame
|
|
addi a2, sp, SAVE_EVERYTHING_FRAME_OFFSET_A0 // integer result ptr in kSaveEverything frame
|
|
addi a1, sp, FRAME_SIZE_SAVE_EVERYTHING // ArtMethod**
|
|
mv a0, xSELF // Thread::Current
|
|
call artMethodExitHook // (Thread*, ArtMethod**, gpr_res*, fpr_res*,
|
|
// frame_size)
|
|
|
|
// Normal return.
|
|
RESTORE_SAVE_EVERYTHING_FRAME
|
|
ret
|
|
END art_quick_method_exit_hook
|
|
|
|
|
|
// On entry a0 is uintptr_t* gprs_ and a1 is uint64_t* fprs_.
|
|
// Both must reside on the stack, between current sp and target sp.
|
|
ENTRY art_quick_do_long_jump
|
|
// Load FPRs
|
|
fld ft0, 8*0(a1) // f0
|
|
fld ft1, 8*1(a1) // f1
|
|
fld ft2, 8*2(a1) // f2
|
|
fld ft3, 8*3(a1) // f3
|
|
fld ft4, 8*4(a1) // f4
|
|
fld ft5, 8*5(a1) // f5
|
|
fld ft6, 8*6(a1) // f6
|
|
fld ft7, 8*7(a1) // f7
|
|
fld fs0, 8*8(a1) // f8
|
|
fld fs1, 8*9(a1) // f9
|
|
fld fa0, 8*10(a1) // f10
|
|
fld fa1, 8*11(a1) // f11
|
|
fld fa2, 8*12(a1) // f12
|
|
fld fa3, 8*13(a1) // f13
|
|
fld fa4, 8*14(a1) // f14
|
|
fld fa5, 8*15(a1) // f15
|
|
fld fa6, 8*16(a1) // f16
|
|
fld fa7, 8*17(a1) // f17
|
|
fld fs2, 8*18(a1) // f18
|
|
fld fs3, 8*19(a1) // f19
|
|
fld fs4, 8*20(a1) // f20
|
|
fld fs5, 8*21(a1) // f21
|
|
fld fs6, 8*22(a1) // f22
|
|
fld fs7, 8*23(a1) // f23
|
|
fld fs8, 8*24(a1) // f24
|
|
fld fs9, 8*25(a1) // f25
|
|
fld fs10, 8*26(a1) // f26
|
|
fld fs11, 8*27(a1) // f27
|
|
fld ft8, 8*28(a1) // f28
|
|
fld ft9, 8*29(a1) // f29
|
|
fld ft10, 8*30(a1) // f30
|
|
fld ft11, 8*31(a1) // f31
|
|
|
|
// Load GPRs.
|
|
// Skip slot 8*0(a0) for zero/x0 as it is hard-wired zero.
|
|
ld ra, 8*1(a0) // x1
|
|
// Skip slot 8*2(a0) for sp/x2 as it is set below.
|
|
// Skip slot 8*3(a0) for platform-specific thread pointer gp/x3.
|
|
// Skip slot 8*4(a0) for platform-specific global pointer tp/x4.
|
|
// Skip slot 8*5(a0) for t0/x5 as it is clobbered below.
|
|
// Skip slot 8*6(a0) for t1/x6 as it is clobbered below.
|
|
ld t2, 8*7(a0) // x7
|
|
ld s0, 8*8(a0) // x8
|
|
ld s1, 8*9(a0) // x9
|
|
// Delay loading a0 as the base is in a0.
|
|
ld a1, 8*11(a0) // x11
|
|
ld a2, 8*12(a0) // x12
|
|
ld a3, 8*13(a0) // x13
|
|
ld a4, 8*14(a0) // x14
|
|
ld a5, 8*15(a0) // x15
|
|
ld a6, 8*16(a0) // x16
|
|
ld a7, 8*17(a0) // x17
|
|
ld s2, 8*18(a0) // x18
|
|
ld s3, 8*19(a0) // x19
|
|
ld s4, 8*20(a0) // x20
|
|
ld s5, 8*21(a0) // x21
|
|
ld s6, 8*22(a0) // x22
|
|
ld s7, 8*23(a0) // x23
|
|
ld s8, 8*24(a0) // x24
|
|
ld s9, 8*25(a0) // x25
|
|
ld s10, 8*26(a0) // x26
|
|
ld s11, 8*27(a0) // x27
|
|
ld t3, 8*28(a0) // x28
|
|
ld t4, 8*29(a0) // x29
|
|
ld t5, 8*30(a0) // x30
|
|
ld t6, 8*31(a0) // x31
|
|
|
|
// Load sp to t0.
|
|
ld t0, 8*2(a0)
|
|
|
|
// Load PC to t1, it is in the last stack slot.
|
|
ld t1, 8*32(a0)
|
|
|
|
// Now load a0.
|
|
ld a0, 8*10(a0) // x10
|
|
|
|
// Set sp. Do not access fprs_ and gprs_ from now, they are below sp.
|
|
mv sp, t0
|
|
|
|
jr t1
|
|
END art_quick_do_long_jump
|
|
|
|
|
|
// Called by managed code that is attempting to call a method on a proxy class. On entry a0 holds
|
|
// the proxy method and a1 holds the receiver. The frame size of the invoked proxy method agrees
|
|
// with kSaveRefsAndArgs frame.
|
|
.extern artQuickProxyInvokeHandler
|
|
ENTRY art_quick_proxy_invoke_handler
|
|
SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_A0
|
|
|
|
// uint64_t artQuickProxyInvokeHandler(ArtMethod* proxy_method, // a0
|
|
// mirror::Object* receiver, // a1
|
|
// Thread* self, // a2
|
|
// ArtMethod** sp) // a3
|
|
mv a2, xSELF // pass Thread::Current
|
|
mv a3, sp // pass sp
|
|
call artQuickProxyInvokeHandler // (Method* proxy method, receiver, Thread*, sp)
|
|
|
|
ld a2, THREAD_EXCEPTION_OFFSET(xSELF)
|
|
bnez a2, .Lexception_in_proxy // success if no exception is pending
|
|
.cfi_remember_state
|
|
RESTORE_SAVE_REFS_AND_ARGS_FRAME // Restore frame
|
|
fmv.d.x fa0, a0 // Store result in fa0 in case it was float or double
|
|
ret // return on success
|
|
|
|
.Lexception_in_proxy:
|
|
CFI_RESTORE_STATE_AND_DEF_CFA sp, FRAME_SIZE_SAVE_REFS_AND_ARGS
|
|
RESTORE_SAVE_REFS_AND_ARGS_FRAME
|
|
DELIVER_PENDING_EXCEPTION
|
|
END art_quick_proxy_invoke_handler
|
|
|
|
|
|
.macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name
|
|
.extern \cxx_name
|
|
ENTRY \c_name
|
|
SETUP_SAVE_ALL_CALLEE_SAVES_FRAME // save all registers as basis for long jump context.
|
|
mv a1, xSELF // pass Thread::Current.
|
|
jal \cxx_name // \cxx_name(arg, Thread*).
|
|
ebreak
|
|
END \c_name
|
|
.endm
|
|
|
|
|
|
// Called to attempt to execute an obsolete method.
|
|
ONE_ARG_RUNTIME_EXCEPTION art_invoke_obsolete_method_stub, artInvokeObsoleteMethod
|
|
|
|
|
|
ENTRY art_quick_resolution_trampoline
|
|
SETUP_SAVE_REFS_AND_ARGS_FRAME
|
|
|
|
// const void* artQuickResolutionTrampoline(ArtMethod* called, // a0
|
|
// mirror::Object* receiver, // a1
|
|
// Thread* self, // a2
|
|
// ArtMethod** sp) // a3
|
|
mv a2, xSELF
|
|
mv a3, sp
|
|
call artQuickResolutionTrampoline
|
|
|
|
beqz a0, 1f
|
|
.cfi_remember_state
|
|
mv t0, a0 // Remember returned code pointer in t0.
|
|
ld a0, (sp) // artQuickResolutionTrampoline puts called method in *sp.
|
|
|
|
RESTORE_SAVE_REFS_AND_ARGS_FRAME
|
|
jr t0
|
|
1:
|
|
CFI_RESTORE_STATE_AND_DEF_CFA sp, FRAME_SIZE_SAVE_REFS_AND_ARGS
|
|
RESTORE_SAVE_REFS_AND_ARGS_FRAME
|
|
DELIVER_PENDING_EXCEPTION
|
|
END art_quick_resolution_trampoline
|
|
|
|
|
|
UNDEFINED art_quick_imt_conflict_trampoline
|
|
UNDEFINED art_quick_deoptimize_from_compiled_code
|
|
UNDEFINED art_quick_string_builder_append
|
|
UNDEFINED art_quick_compile_optimized
|
|
UNDEFINED art_quick_method_entry_hook
|
|
UNDEFINED art_quick_check_instance_of
|
|
UNDEFINED art_quick_osr_stub
|
|
|
|
UNDEFINED art_quick_alloc_array_resolved_dlmalloc
|
|
UNDEFINED art_quick_alloc_array_resolved_dlmalloc_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved8_dlmalloc
|
|
UNDEFINED art_quick_alloc_array_resolved8_dlmalloc_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved16_dlmalloc
|
|
UNDEFINED art_quick_alloc_array_resolved16_dlmalloc_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved32_dlmalloc
|
|
UNDEFINED art_quick_alloc_array_resolved32_dlmalloc_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved64_dlmalloc
|
|
UNDEFINED art_quick_alloc_array_resolved64_dlmalloc_instrumented
|
|
UNDEFINED art_quick_alloc_object_resolved_dlmalloc
|
|
UNDEFINED art_quick_alloc_object_resolved_dlmalloc_instrumented
|
|
UNDEFINED art_quick_alloc_object_initialized_dlmalloc
|
|
UNDEFINED art_quick_alloc_object_initialized_dlmalloc_instrumented
|
|
UNDEFINED art_quick_alloc_object_with_checks_dlmalloc
|
|
UNDEFINED art_quick_alloc_object_with_checks_dlmalloc_instrumented
|
|
UNDEFINED art_quick_alloc_string_object_dlmalloc
|
|
UNDEFINED art_quick_alloc_string_object_dlmalloc_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_bytes_dlmalloc
|
|
UNDEFINED art_quick_alloc_string_from_bytes_dlmalloc_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_chars_dlmalloc
|
|
UNDEFINED art_quick_alloc_string_from_chars_dlmalloc_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_string_dlmalloc
|
|
UNDEFINED art_quick_alloc_string_from_string_dlmalloc_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved_rosalloc
|
|
UNDEFINED art_quick_alloc_array_resolved_rosalloc_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved8_rosalloc
|
|
UNDEFINED art_quick_alloc_array_resolved8_rosalloc_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved16_rosalloc
|
|
UNDEFINED art_quick_alloc_array_resolved16_rosalloc_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved32_rosalloc
|
|
UNDEFINED art_quick_alloc_array_resolved32_rosalloc_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved64_rosalloc
|
|
UNDEFINED art_quick_alloc_array_resolved64_rosalloc_instrumented
|
|
UNDEFINED art_quick_alloc_object_resolved_rosalloc
|
|
UNDEFINED art_quick_alloc_object_resolved_rosalloc_instrumented
|
|
UNDEFINED art_quick_alloc_object_initialized_rosalloc
|
|
UNDEFINED art_quick_alloc_object_initialized_rosalloc_instrumented
|
|
UNDEFINED art_quick_alloc_object_with_checks_rosalloc
|
|
UNDEFINED art_quick_alloc_object_with_checks_rosalloc_instrumented
|
|
UNDEFINED art_quick_alloc_string_object_rosalloc
|
|
UNDEFINED art_quick_alloc_string_object_rosalloc_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_bytes_rosalloc
|
|
UNDEFINED art_quick_alloc_string_from_bytes_rosalloc_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_chars_rosalloc
|
|
UNDEFINED art_quick_alloc_string_from_chars_rosalloc_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_string_rosalloc
|
|
UNDEFINED art_quick_alloc_string_from_string_rosalloc_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved_bump_pointer
|
|
UNDEFINED art_quick_alloc_array_resolved_bump_pointer_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved8_bump_pointer
|
|
UNDEFINED art_quick_alloc_array_resolved8_bump_pointer_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved16_bump_pointer
|
|
UNDEFINED art_quick_alloc_array_resolved16_bump_pointer_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved32_bump_pointer
|
|
UNDEFINED art_quick_alloc_array_resolved32_bump_pointer_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved64_bump_pointer
|
|
UNDEFINED art_quick_alloc_array_resolved64_bump_pointer_instrumented
|
|
UNDEFINED art_quick_alloc_object_resolved_bump_pointer
|
|
UNDEFINED art_quick_alloc_object_resolved_bump_pointer_instrumented
|
|
UNDEFINED art_quick_alloc_object_initialized_bump_pointer
|
|
UNDEFINED art_quick_alloc_object_initialized_bump_pointer_instrumented
|
|
UNDEFINED art_quick_alloc_object_with_checks_bump_pointer
|
|
UNDEFINED art_quick_alloc_object_with_checks_bump_pointer_instrumented
|
|
UNDEFINED art_quick_alloc_string_object_bump_pointer
|
|
UNDEFINED art_quick_alloc_string_object_bump_pointer_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_bytes_bump_pointer
|
|
UNDEFINED art_quick_alloc_string_from_bytes_bump_pointer_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_chars_bump_pointer
|
|
UNDEFINED art_quick_alloc_string_from_chars_bump_pointer_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_string_bump_pointer
|
|
UNDEFINED art_quick_alloc_string_from_string_bump_pointer_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved_tlab
|
|
UNDEFINED art_quick_alloc_array_resolved_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved8_tlab
|
|
UNDEFINED art_quick_alloc_array_resolved8_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved16_tlab
|
|
UNDEFINED art_quick_alloc_array_resolved16_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved32_tlab
|
|
UNDEFINED art_quick_alloc_array_resolved32_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved64_tlab
|
|
UNDEFINED art_quick_alloc_array_resolved64_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_object_resolved_tlab
|
|
UNDEFINED art_quick_alloc_object_resolved_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_object_initialized_tlab
|
|
UNDEFINED art_quick_alloc_object_initialized_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_object_with_checks_tlab
|
|
UNDEFINED art_quick_alloc_object_with_checks_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_string_object_tlab
|
|
UNDEFINED art_quick_alloc_string_object_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_bytes_tlab
|
|
UNDEFINED art_quick_alloc_string_from_bytes_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_chars_tlab
|
|
UNDEFINED art_quick_alloc_string_from_chars_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_string_tlab
|
|
UNDEFINED art_quick_alloc_string_from_string_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved_region
|
|
UNDEFINED art_quick_alloc_array_resolved_region_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved8_region
|
|
UNDEFINED art_quick_alloc_array_resolved8_region_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved16_region
|
|
UNDEFINED art_quick_alloc_array_resolved16_region_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved32_region
|
|
UNDEFINED art_quick_alloc_array_resolved32_region_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved64_region
|
|
UNDEFINED art_quick_alloc_array_resolved64_region_instrumented
|
|
UNDEFINED art_quick_alloc_object_resolved_region
|
|
UNDEFINED art_quick_alloc_object_resolved_region_instrumented
|
|
UNDEFINED art_quick_alloc_object_initialized_region
|
|
UNDEFINED art_quick_alloc_object_initialized_region_instrumented
|
|
UNDEFINED art_quick_alloc_object_with_checks_region
|
|
UNDEFINED art_quick_alloc_object_with_checks_region_instrumented
|
|
UNDEFINED art_quick_alloc_string_object_region
|
|
UNDEFINED art_quick_alloc_string_object_region_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_bytes_region
|
|
UNDEFINED art_quick_alloc_string_from_bytes_region_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_chars_region
|
|
UNDEFINED art_quick_alloc_string_from_chars_region_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_string_region
|
|
UNDEFINED art_quick_alloc_string_from_string_region_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved_region_tlab
|
|
UNDEFINED art_quick_alloc_array_resolved_region_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved8_region_tlab
|
|
UNDEFINED art_quick_alloc_array_resolved8_region_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved16_region_tlab
|
|
UNDEFINED art_quick_alloc_array_resolved16_region_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved32_region_tlab
|
|
UNDEFINED art_quick_alloc_array_resolved32_region_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_array_resolved64_region_tlab
|
|
UNDEFINED art_quick_alloc_array_resolved64_region_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_object_resolved_region_tlab
|
|
UNDEFINED art_quick_alloc_object_resolved_region_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_object_initialized_region_tlab
|
|
UNDEFINED art_quick_alloc_object_initialized_region_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_object_with_checks_region_tlab
|
|
UNDEFINED art_quick_alloc_object_with_checks_region_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_string_object_region_tlab
|
|
UNDEFINED art_quick_alloc_string_object_region_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_bytes_region_tlab
|
|
UNDEFINED art_quick_alloc_string_from_bytes_region_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_chars_region_tlab
|
|
UNDEFINED art_quick_alloc_string_from_chars_region_tlab_instrumented
|
|
UNDEFINED art_quick_alloc_string_from_string_region_tlab
|
|
UNDEFINED art_quick_alloc_string_from_string_region_tlab_instrumented
|
|
UNDEFINED art_quick_initialize_static_storage
|
|
UNDEFINED art_quick_resolve_type_and_verify_access
|
|
UNDEFINED art_quick_resolve_type
|
|
UNDEFINED art_quick_resolve_method_handle
|
|
UNDEFINED art_quick_resolve_method_type
|
|
UNDEFINED art_quick_resolve_string
|
|
UNDEFINED art_quick_set8_instance
|
|
UNDEFINED art_quick_set8_static
|
|
UNDEFINED art_quick_set16_instance
|
|
UNDEFINED art_quick_set16_static
|
|
UNDEFINED art_quick_set32_instance
|
|
UNDEFINED art_quick_set32_static
|
|
UNDEFINED art_quick_set64_instance
|
|
UNDEFINED art_quick_set64_static
|
|
UNDEFINED art_quick_set_obj_instance
|
|
UNDEFINED art_quick_set_obj_static
|
|
UNDEFINED art_quick_get_byte_instance
|
|
UNDEFINED art_quick_get_boolean_instance
|
|
UNDEFINED art_quick_get_short_instance
|
|
UNDEFINED art_quick_get_char_instance
|
|
UNDEFINED art_quick_get32_instance
|
|
UNDEFINED art_quick_get64_instance
|
|
UNDEFINED art_quick_get_obj_instance
|
|
UNDEFINED art_quick_get_byte_static
|
|
UNDEFINED art_quick_get_boolean_static
|
|
UNDEFINED art_quick_get_short_static
|
|
UNDEFINED art_quick_get_char_static
|
|
UNDEFINED art_quick_get32_static
|
|
UNDEFINED art_quick_get64_static
|
|
UNDEFINED art_quick_get_obj_static
|
|
UNDEFINED art_quick_aput_obj
|
|
UNDEFINED art_quick_lock_object_no_inline
|
|
UNDEFINED art_quick_lock_object
|
|
UNDEFINED art_quick_unlock_object_no_inline
|
|
UNDEFINED art_quick_unlock_object
|
|
UNDEFINED art_quick_invoke_direct_trampoline_with_access_check
|
|
UNDEFINED art_quick_invoke_interface_trampoline_with_access_check
|
|
UNDEFINED art_quick_invoke_static_trampoline_with_access_check
|
|
UNDEFINED art_quick_invoke_super_trampoline_with_access_check
|
|
UNDEFINED art_quick_invoke_virtual_trampoline_with_access_check
|
|
UNDEFINED art_quick_invoke_polymorphic
|
|
UNDEFINED art_quick_invoke_custom
|
|
UNDEFINED art_quick_test_suspend
|
|
UNDEFINED art_quick_deliver_exception
|
|
UNDEFINED art_quick_throw_array_bounds
|
|
UNDEFINED art_quick_throw_div_zero
|
|
UNDEFINED art_quick_throw_null_pointer_exception
|
|
UNDEFINED art_quick_throw_stack_overflow
|
|
UNDEFINED art_quick_throw_string_bounds
|
|
UNDEFINED art_quick_update_inline_cache
|
|
UNDEFINED art_jni_monitored_method_start
|
|
UNDEFINED art_jni_monitored_method_end
|
|
UNDEFINED art_quick_indexof
|