summaryrefslogtreecommitdiffstats
path: root/runtime/arch/arm64/quick_entrypoints_arm64.S
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/arch/arm64/quick_entrypoints_arm64.S')
-rw-r--r--runtime/arch/arm64/quick_entrypoints_arm64.S1094
1 files changed, 1094 insertions, 0 deletions
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
new file mode 100644
index 0000000000..2d64e7f598
--- /dev/null
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -0,0 +1,1094 @@
+/*
+ * Copyright (C) 2014 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_arm64.S"
+
+#include "arch/quick_alloc_entrypoints.S"
+
+
+ /*
+ * Macro that sets up the callee save frame to conform with
+ * Runtime::CreateCalleeSaveMethod(kSaveAll)
+ */
+.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
+ adrp x9, :got:_ZN3art7Runtime9instance_E
+ ldr x9, [x9, #:got_lo12:_ZN3art7Runtime9instance_E]
+
+ // Our registers aren't intermixed - just spill in order.
+ ldr x9,[x9] // x9 = & (art::Runtime * art::Runtime.instance_) .
+
+ // x9 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs] .
+ ldr x9, [x9, RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET ]
+
+ sub sp, sp, #368
+ .cfi_adjust_cfa_offset 368
+
+ // FP args
+ stp d1, d2, [sp, #8]
+ stp d2, d3, [sp, #24]
+ stp d4, d5, [sp, #40]
+ stp d6, d7, [sp, #56]
+
+ // FP callee-saves
+ stp d8, d9, [sp, #72]
+ stp d10, d11, [sp, #88]
+ stp d12, d13, [sp, #104]
+ stp d14, d15, [sp, #120]
+
+ stp d16, d17, [sp, #136]
+ stp d18, d19, [sp, #152]
+ stp d20, d21, [sp, #168]
+ stp d22, d23, [sp, #184]
+ stp d24, d25, [sp, #200]
+ stp d26, d27, [sp, #216]
+ stp d28, d29, [sp, #232]
+ stp d30, d31, [sp, #248]
+
+
+ // Callee saved.
+ stp xSELF, x19, [sp, #264]
+ stp x20, x21, [sp, #280]
+ stp x22, x23, [sp, #296]
+ stp x24, x25, [sp, #312]
+ stp x26, x27, [sp, #328]
+ stp x28, xFP, [sp, #344] // Save FP.
+ str xLR, [sp, #360]
+
+ .cfi_offset x18,72
+ .cfi_offset x19,80
+ .cfi_offset x20,88
+ .cfi_offset x21,96
+ .cfi_offset x22,104
+ .cfi_offset x23,112
+ .cfi_offset x24,120
+ .cfi_offset x25,128
+ .cfi_offset x26,136
+ .cfi_offset x27,144
+ .cfi_offset x28,152
+ .cfi_offset x29,160
+ .cfi_offset x30,168
+
+ // Loads appropriate callee-save-method
+ str x9, [sp] // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs]
+
+.endm
+
+ /*
+ * Macro that sets up the callee save frame to conform with
+ * Runtime::CreateCalleeSaveMethod(kRefsOnly).
+ */
+.macro SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ brk 0
+.endm
+
+.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+ brk 0
+.endm
+
+.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
+ brk 0
+.endm
+
+
+.macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
+ sub sp, sp, #304
+ .cfi_adjust_cfa_offset 304
+
+ stp d0, d1, [sp, #16]
+ stp d2, d3, [sp, #32]
+ stp d4, d5, [sp, #48]
+ stp d6, d7, [sp, #64]
+ stp d8, d9, [sp, #80]
+ stp d10, d11, [sp, #96]
+ stp d12, d13, [sp, #112]
+ stp d14, d15, [sp, #128]
+
+ stp x1, x2, [sp, #144]
+ stp x3, x4, [sp, #160]
+ stp x5, x6, [sp, #176]
+ stp x7, xSELF, [sp, #192]
+ stp x19, x20, [sp, #208]
+ stp x21, x22, [sp, #224]
+ stp x23, x24, [sp, #240]
+ stp x25, x26, [sp, #256]
+ stp x27, x28, [sp, #272]
+ stp xFP, xLR, [sp, #288]
+
+ .cfi_offset x1,144
+ .cfi_offset x2,152
+ .cfi_offset x3,160
+ .cfi_offset x4,168
+ .cfi_offset x5,176
+ .cfi_offset x6,184
+ .cfi_offset x7,192
+ .cfi_offset x18,200
+ .cfi_offset x19,208
+ .cfi_offset x20,216
+ .cfi_offset x21,224
+ .cfi_offset x22,232
+ .cfi_offset x23,240
+ .cfi_offset x24,248
+ .cfi_offset x25,256
+ .cfi_offset x26,264
+ .cfi_offset x27,272
+ .cfi_offset x28,280
+ .cfi_offset x29,288
+ .cfi_offset x30,296
+.endm
+
+ /*
+ * Macro that sets up the callee save frame to conform with
+ * Runtime::CreateCalleeSaveMethod(kRefsAndArgs).
+ *
+ * TODO This is probably too conservative - saving FP & LR.
+ */
+.macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+ adrp x9, :got:_ZN3art7Runtime9instance_E
+ ldr x9, [x9, #:got_lo12:_ZN3art7Runtime9instance_E]
+
+ // Our registers aren't intermixed - just spill in order.
+ ldr x9,[x9] // x9 = & (art::Runtime * art::Runtime.instance_) .
+
+ // x9 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs] .
+ ldr x9, [x9, RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET ]
+
+ SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
+
+ str x9, [sp] // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs]
+.endm
+
+.macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+
+ ldp d0, d1, [sp, #16]
+ ldp d2, d3, [sp, #32]
+ ldp d4, d5, [sp, #48]
+ ldp d6, d7, [sp, #64]
+ ldp d8, d9, [sp, #80]
+ ldp d10, d11, [sp, #96]
+ ldp d12, d13, [sp, #112]
+ ldp d14, d15, [sp, #128]
+
+ // args.
+ ldp x1, x2, [sp, #144]
+ ldp x3, x4, [sp, #160]
+ ldp x5, x6, [sp, #176]
+ ldp x7, xSELF, [sp, #192]
+ ldp x19, x20, [sp, #208]
+ ldp x21, x22, [sp, #224]
+ ldp x23, x24, [sp, #240]
+ ldp x25, x26, [sp, #256]
+ ldp x27, x28, [sp, #272]
+ ldp xFP, xLR, [sp, #288]
+
+ add sp, sp, #304
+ .cfi_adjust_cfa_offset -304
+.endm
+
+.macro RETURN_IF_RESULT_IS_ZERO
+ brk 0
+.endm
+
+.macro RETURN_IF_RESULT_IS_NON_ZERO
+ brk 0
+.endm
+
+ /*
+ * Macro that set calls through to artDeliverPendingExceptionFromCode, where the pending
+ * exception is Thread::Current()->exception_
+ */
+.macro DELIVER_PENDING_EXCEPTION
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
+ mov x0, xSELF
+ mov x1, sp
+
+ // Point of no return.
+ b artDeliverPendingExceptionFromCode // artDeliverPendingExceptionFromCode(Thread*, SP)
+ brk 0 // Unreached
+.endm
+
+.macro RETURN_OR_DELIVER_PENDING_EXCEPTION
+ ldr x9, [xSELF, # THREAD_EXCEPTION_OFFSET] // Get exception field.
+ cbnz x9, 1f
+ ret
+1:
+ DELIVER_PENDING_EXCEPTION
+.endm
+
+.macro NO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
+ .extern \cxx_name
+ENTRY \c_name
+ brk 0
+END \c_name
+.endm
+
+.macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name
+ .extern \cxx_name
+ENTRY \c_name
+ brk 0
+END \c_name
+.endm
+
+.macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
+ .extern \cxx_name
+ENTRY \c_name
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
+ brk 0
+END \c_name
+.endm
+
+ /*
+ * Called by managed code, saves callee saves and then calls artThrowException
+ * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception.
+ */
+ONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception, artDeliverExceptionFromCode
+
+ /*
+ * Called by managed code to create and deliver a NullPointerException.
+ */
+NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode
+
+ /*
+ * Called by managed code to create and deliver an ArithmeticException.
+ */
+NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode
+
+ /*
+ * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds
+ * index, arg2 holds limit.
+ */
+TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds, artThrowArrayBoundsFromCode
+
+ /*
+ * Called by managed code to create and deliver a StackOverflowError.
+ */
+NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFromCode
+
+ /*
+ * Called by managed code to create and deliver a NoSuchMethodError.
+ */
+ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method, artThrowNoSuchMethodFromCode
+
+ /*
+ * TODO arm64 specifics need to be fleshed out.
+ * All generated callsites for interface invokes and invocation slow paths will load arguments
+ * as usual - except instead of loading x0 with the target Method*, x0 will contain
+ * the method_idx. This wrapper will save x1-x3, load the caller's Method*, align the
+ * stack and call the appropriate C helper.
+ * NOTE: "this" is first visible argument of the target, and so can be found in x1.
+ *
+ * The helper will attempt to locate the target and return a result in x0 consisting
+ * of the target Method* in x0 and method->code_ in x1.
+ *
+ * If unsuccessful, the helper will return NULL/NULL. There will be a pending exception in the
+ * thread and we branch to another stub to deliver it.
+ *
+ * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
+ * pointing back to the original caller.
+ */
+.macro INVOKE_TRAMPOLINE c_name, cxx_name
+ .extern \cxx_name
+ENTRY \c_name
+ brk 0
+END \c_name
+.endm
+
+INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline
+INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
+
+INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
+INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck
+INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
+INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
+
+/*
+ * extern"C" void art_quick_invoke_stub(ArtMethod *method, x0
+ * uint32_t *args, x1
+ * uint32_t argsize, w2
+ * Thread *self, x3
+ * JValue *result, x4
+ * char *shorty); x5
+ * +----------------------+
+ * | |
+ * | C/C++ frame |
+ * | LR'' |
+ * | FP'' | <- SP'
+ * +----------------------+
+ * +----------------------+
+ * | SP' |
+ * | X5 |
+ * | X4 | Saved registers
+ * | LR' |
+ * | FP' | <- FP
+ * +----------------------+
+ * | uint32_t out[n-1] |
+ * | : : | Outs
+ * | uint32_t out[0] |
+ * | ArtMethod* NULL | <- SP
+ * +----------------------+
+ *
+ * Outgoing registers:
+ * x0 - Method*
+ * x1-x7 - integer parameters.
+ * d0-d7 - Floating point parameters.
+ * xSELF = self
+ * SP = & of ArtMethod*
+ * x1 = "this" pointer.
+ *
+ */
+ENTRY art_quick_invoke_stub
+ // Spill registers as per AACPS64 calling convention.
+
+SAVE_SIZE=5*8 // x4, x5, LR & FP saved.
+SAVE_SIZE_AND_METHOD=SAVE_SIZE+8
+
+ mov x9, sp // Save stack pointer.
+
+ mov x10, xFP // Save frame pointer
+ .cfi_register x29,x10
+ add x11, x2, # SAVE_SIZE_AND_METHOD // calculate size of frame.
+
+ sub x11, sp, x11 // Calculate SP position - saves + ArtMethod* + args
+
+ and x11, x11, # ~0xf // Enforce 16 byte stack alignment.
+
+ sub xFP, x9, #SAVE_SIZE // Calculate new FP. Don't store here until SP moved.
+ .cfi_def_cfa_register x29
+
+ mov sp, x11 // set new SP.
+
+ str x9, [xFP, #32] // Save old stack pointer.
+
+ .cfi_offset x9, 32
+
+ stp x4, x5, [xFP, #16] // Save result and shorty addresses.
+
+ .cfi_offset x4, 16
+ .cfi_offset x5, 24
+
+ stp x10, xLR, [xFP] // Store lr & old fp @ fp
+
+ .cfi_offset x30, 0
+ .cfi_offset x10, 8
+
+ mov xSELF, x3 // Move thread pointer into SELF register.
+
+ // Copy arguments into stack frame.
+ // Use simple copy routine for now.
+ // 4 bytes per slot.
+ // X1 - source address
+ // W2 - args length
+ // X10 - destination address.
+ add x9, sp, #8 // Destination address is bottom of stack + NULL.
+
+ // w2 = argsize parameter.
+.LcopyParams:
+ cmp w2, #0
+ beq .LendCopyParams
+ sub w2, w2, #4 // Need 65536 bytes of range.
+ ldr w10, [x1, x2]
+ str w10, [x9, x2]
+
+ b .LcopyParams
+
+.LendCopyParams:
+
+ // Store NULL into Method* at bottom of frame.
+ str xzr, [sp]
+
+ // Fill registers x/w1 to x/w7 and s/d0 to s/d7 with parameters.
+ // Parse the passed shorty to determine which register to load.
+ // Load addresses for routines that load WXSD registers.
+ adr x11, .LstoreW2
+ adr x12, .LstoreX2
+ adr x13, .LstoreS0
+ adr x14, .LstoreD0
+
+ // Initialize routine offsets to 0 for integers and floats.
+ // x8 for integers, x15 for floating point.
+ mov x8, #0
+ mov x15, #0
+
+ add x10, x5, #1 // Load shorty address, plus one to skip return value.
+ ldr w1, [x9],#4 // Load "this" parameter, and increment arg pointer.
+
+ // Loop to fill registers.
+.LfillRegisters:
+ ldrb w17, [x10], #1 // Load next character in signature, and increment.
+ cbz w17, .LcallFunction // Exit at end of signature. Shorty 0 terminated.
+
+ cmp w17, #'F' // is this a float?
+ bne .LisDouble
+
+ cmp x15, # 8*12 // Skip this load if all registers full.
+ beq .LfillRegisters
+
+ add x17, x13, x15 // Calculate subroutine to jump to.
+ br x17
+
+.LisDouble:
+ cmp w17, #'D' // is this a double?
+ bne .LisLong
+
+ cmp x15, # 8*12 // Skip this load if all registers full.
+ beq .LfillRegisters
+
+
+ add x17, x14, x15 // Calculate subroutine to jump to.
+ br x17
+
+.LisLong:
+ cmp w17, #'J' // is this a long?
+ bne .LisOther
+
+ cmp x8, # 7*12 // Skip this load if all registers full.
+ beq .LfillRegisters
+
+ add x17, x12, x8 // Calculate subroutine to jump to.
+ br x17
+
+
+.LisOther: // Everything else takes one vReg.
+ cmp x8, # 7*12 // Skip this load if all registers full.
+ beq .LfillRegisters
+ add x17, x11, x8 // Calculate subroutine to jump to.
+ br x17
+
+// Macro for loading a parameter into a register.
+// counter - the register with offset into these tables
+// size - the size of the register - 4 or 8 bytes.
+// register - the name of the register to be loaded.
+.macro LOADREG counter size register return
+ ldr \register , [x9], #\size
+ add \counter, \counter, 12
+ b \return
+.endm
+
+// Store ints.
+.LstoreW2:
+ LOADREG x8 4 w2 .LfillRegisters
+ LOADREG x8 4 w3 .LfillRegisters
+ LOADREG x8 4 w4 .LfillRegisters
+ LOADREG x8 4 w5 .LfillRegisters
+ LOADREG x8 4 w6 .LfillRegisters
+ LOADREG x8 4 w7 .LfillRegisters
+
+// Store longs.
+.LstoreX2:
+ LOADREG x8 8 x2 .LfillRegisters
+ LOADREG x8 8 x3 .LfillRegisters
+ LOADREG x8 8 x4 .LfillRegisters
+ LOADREG x8 8 x5 .LfillRegisters
+ LOADREG x8 8 x6 .LfillRegisters
+ LOADREG x8 8 x7 .LfillRegisters
+
+// Store singles.
+.LstoreS0:
+ LOADREG x15 4 s0 .LfillRegisters
+ LOADREG x15 4 s1 .LfillRegisters
+ LOADREG x15 4 s2 .LfillRegisters
+ LOADREG x15 4 s3 .LfillRegisters
+ LOADREG x15 4 s4 .LfillRegisters
+ LOADREG x15 4 s5 .LfillRegisters
+ LOADREG x15 4 s6 .LfillRegisters
+ LOADREG x15 4 s7 .LfillRegisters
+
+// Store doubles.
+.LstoreD0:
+ LOADREG x15 8 d0 .LfillRegisters
+ LOADREG x15 8 d1 .LfillRegisters
+ LOADREG x15 8 d2 .LfillRegisters
+ LOADREG x15 8 d3 .LfillRegisters
+ LOADREG x15 8 d4 .LfillRegisters
+ LOADREG x15 8 d5 .LfillRegisters
+ LOADREG x15 8 d6 .LfillRegisters
+ LOADREG x15 8 d7 .LfillRegisters
+
+
+.LcallFunction:
+
+ // load method-> METHOD_QUICK_CODE_OFFSET
+ ldr x9, [x0 , #METHOD_QUICK_CODE_OFFSET]
+ // Branch to method.
+ blr x9
+
+ // Restore return value address and shorty address.
+ ldp x4,x5, [xFP, #16]
+ .cfi_restore x4
+ .cfi_restore x5
+
+ // Store result (w0/x0/s0/d0) appropriately, depending on resultType.
+ ldrb w10, [x5]
+
+ // Don't set anything for a void type.
+ cmp w10, #'V'
+ beq .Lexit_art_quick_invoke_stub
+
+ cmp w10, #'D'
+ bne .Lreturn_is_float
+ str d0, [x4]
+ b .Lexit_art_quick_invoke_stub
+
+.Lreturn_is_float:
+ cmp w10, #'F'
+ bne .Lreturn_is_int
+ str s0, [x4]
+ b .Lexit_art_quick_invoke_stub
+
+ // Just store x0. Doesn't matter if it is 64 or 32 bits.
+.Lreturn_is_int:
+ str x0, [x4]
+
+.Lexit_art_quick_invoke_stub:
+ ldr x2, [x29, #32] // Restore stack pointer.
+ mov sp, x2
+ .cfi_restore sp
+
+ ldp x29, x30, [x29] // Restore old frame pointer and link register.
+ .cfi_restore x29
+ .cfi_restore x30
+
+ ret
+END art_quick_invoke_stub
+
+/* extern"C"
+ * void art_quick_invoke_static_stub(ArtMethod *method, x0
+ * uint32_t *args, x1
+ * uint32_t argsize, w2
+ * Thread *self, x3
+ * JValue *result, x4
+ * char *shorty); x5
+ */
+ENTRY art_quick_invoke_static_stub
+ // Spill registers as per AACPS64 calling convention.
+
+SAVE_SIZE=5*8 // x4, x5, SP, LR & FP saved
+SAVE_SIZE_AND_METHOD=SAVE_SIZE+8
+
+ mov x9, sp // Save stack pointer.
+
+ mov x10, xFP // Save frame pointer
+ .cfi_register x29,x10
+ add x11, x2, # SAVE_SIZE_AND_METHOD // calculate size of frame.
+
+ sub x11, sp, x11 // Calculate SP position - saves + ArtMethod* + args
+
+ and x11, x11, # ~0xf // Enforce 16 byte stack alignment.
+
+ sub xFP, x9, #SAVE_SIZE // Calculate new FP. Don't store here until SP moved.
+
+ mov sp, x11 // set new SP.
+
+ .cfi_def_cfa_register 29
+
+ str x9, [xFP, #32] // Save old stack pointer.
+
+ .cfi_offset x9, 32
+
+ stp x4, x5, [xFP, #16] // Save result and shorty addresses.
+
+ .cfi_offset x4, 16
+ .cfi_offset x5, 24
+
+ stp x10, xLR, [x29] // Store lr & old fp @ fp
+
+ .cfi_offset x30, 0
+ .cfi_offset x10, 8
+
+ mov xSELF, x3 // Move thread pointer into SELF register.
+
+ // Copy arguments into stack frame.
+ // Use simple copy routine for now.
+ // 4 bytes per slot.
+ // X1 - source address
+ // W2 - args length
+ // X10 - destination address.
+ add x9, sp, #8 // Destination address is bottom of stack + NULL.
+
+ // w2 = argsize parameter.
+.LcopyParams2:
+ cmp w2, #0
+ beq .LendCopyParams2
+ sub w2, w2, #4 // Need 65536 bytes of range.
+ ldr w10, [x1, x2]
+ str w10, [x9, x2]
+
+ b .LcopyParams2
+
+.LendCopyParams2:
+
+ // Store NULL into Method* at bottom of frame.
+ str xzr, [sp]
+
+ // Fill registers x/w1 to x/w7 and s/d0 to s/d7 with parameters.
+ // Parse the passed shorty to determine which register to load.
+ // Load addresses for routines that load WXSD registers.
+ adr x11, .LstoreW1_2
+ adr x12, .LstoreX1_2
+ adr x13, .LstoreS0_2
+ adr x14, .LstoreD0_2
+
+ // Initialize routine offsets to 0 for integers and floats.
+ // x8 for integers, x15 for floating point.
+ mov x8, #0
+ mov x15, #0
+
+ add x10, x5, #1 // Load shorty address, plus one to skip return value.
+
+ // Loop to fill registers.
+.LfillRegisters2:
+ ldrb w17, [x10], #1 // Load next character in signature, and increment.
+ cbz w17, .LcallFunction2 // Exit at end of signature. Shorty 0 terminated.
+
+ cmp w17, #'F' // is this a float?
+ bne .LisDouble2
+
+ cmp x15, # 8*12 // Skip this load if all registers full.
+ beq .LfillRegisters2
+
+ add x17, x13, x15 // Calculate subroutine to jump to.
+ br x17
+
+.LisDouble2:
+ cmp w17, #'D' // is this a double?
+ bne .LisLong2
+
+ cmp x15, # 8*12 // Skip this load if all registers full.
+ beq .LfillRegisters2
+
+
+ add x17, x14, x15 // Calculate subroutine to jump to.
+ br x17
+
+.LisLong2:
+ cmp w17, #'J' // is this a long?
+ bne .LisOther2
+
+ cmp x8, # 7*12 // Skip this load if all registers full.
+ beq .LfillRegisters2
+
+ add x17, x12, x8 // Calculate subroutine to jump to.
+ br x17
+
+
+.LisOther2: // Everything else takes one vReg.
+ cmp x8, # 7*12 // Skip this load if all registers full.
+ beq .LfillRegisters2
+ add x17, x11, x8 // Calculate subroutine to jump to.
+ br x17
+
+// Store ints.
+.LstoreW1_2:
+ LOADREG x8 4 w1 .LfillRegisters2
+ LOADREG x8 4 w2 .LfillRegisters2
+ LOADREG x8 4 w3 .LfillRegisters2
+ LOADREG x8 4 w4 .LfillRegisters2
+ LOADREG x8 4 w5 .LfillRegisters2
+ LOADREG x8 4 w6 .LfillRegisters2
+ LOADREG x8 4 w7 .LfillRegisters2
+
+// Store longs.
+.LstoreX1_2:
+ LOADREG x8 8 x1 .LfillRegisters2
+ LOADREG x8 8 x2 .LfillRegisters2
+ LOADREG x8 8 x3 .LfillRegisters2
+ LOADREG x8 8 x4 .LfillRegisters2
+ LOADREG x8 8 x5 .LfillRegisters2
+ LOADREG x8 8 x6 .LfillRegisters2
+ LOADREG x8 8 x7 .LfillRegisters2
+
+// Store singles.
+.LstoreS0_2:
+ LOADREG x15 4 s0 .LfillRegisters2
+ LOADREG x15 4 s1 .LfillRegisters2
+ LOADREG x15 4 s2 .LfillRegisters2
+ LOADREG x15 4 s3 .LfillRegisters2
+ LOADREG x15 4 s4 .LfillRegisters2
+ LOADREG x15 4 s5 .LfillRegisters2
+ LOADREG x15 4 s6 .LfillRegisters2
+ LOADREG x15 4 s7 .LfillRegisters2
+
+// Store doubles.
+.LstoreD0_2:
+ LOADREG x15 8 d0 .LfillRegisters2
+ LOADREG x15 8 d1 .LfillRegisters2
+ LOADREG x15 8 d2 .LfillRegisters2
+ LOADREG x15 8 d3 .LfillRegisters2
+ LOADREG x15 8 d4 .LfillRegisters2
+ LOADREG x15 8 d5 .LfillRegisters2
+ LOADREG x15 8 d6 .LfillRegisters2
+ LOADREG x15 8 d7 .LfillRegisters2
+
+
+.LcallFunction2:
+
+ // load method-> METHOD_QUICK_CODE_OFFSET.
+ ldr x9, [x0 , #METHOD_QUICK_CODE_OFFSET]
+ // Branch to method.
+ blr x9
+
+ // Restore return value address and shorty address.
+ ldp x4, x5, [xFP, #16]
+ .cfi_restore x4
+ .cfi_restore x5
+
+ // Store result (w0/x0/s0/d0) appropriately, depending on resultType.
+ ldrb w10, [x5]
+
+ // Don't set anything for a void type.
+ cmp w10, #'V'
+ beq .Lexit_art_quick_invoke_stub2
+
+ cmp w10, #'D'
+ bne .Lreturn_is_float2
+ str d0, [x4]
+ b .Lexit_art_quick_invoke_stub2
+
+.Lreturn_is_float2:
+ cmp w10, #'F'
+ bne .Lreturn_is_int2
+ str s0, [x4]
+ b .Lexit_art_quick_invoke_stub2
+
+ // Just store x0. Doesn't matter if it is 64 or 32 bits.
+.Lreturn_is_int2:
+ str x0, [x4]
+
+.Lexit_art_quick_invoke_stub2:
+
+ ldr x2, [xFP, #32] // Restore stack pointer.
+ mov sp, x2
+ .cfi_restore sp
+
+ ldp xFP, xLR, [xFP] // Restore old frame pointer and link register.
+ .cfi_restore x29
+ .cfi_restore x30
+
+ ret
+END art_quick_invoke_static_stub
+
+// UNIMPLEMENTED art_quick_do_long_jump
+
+ /*
+ * On entry x0 is uintptr_t* gprs_ and x1 is uint64_t* fprs_
+ */
+
+ENTRY art_quick_do_long_jump
+ // Load FPRs
+ ldp d0, d1, [x1], #16
+ ldp d2, d3, [x1], #16
+ ldp d4, d5, [x1], #16
+ ldp d6, d7, [x1], #16
+ ldp d8, d9, [x1], #16
+ ldp d10, d11, [x1], #16
+ ldp d12, d13, [x1], #16
+ ldp d14, d15, [x1], #16
+ ldp d16, d17, [x1], #16
+ ldp d18, d19, [x1], #16
+ ldp d20, d21, [x1], #16
+ ldp d22, d23, [x1], #16
+ ldp d24, d25, [x1], #16
+ ldp d26, d27, [x1], #16
+ ldp d28, d29, [x1], #16
+ ldp d30, d31, [x1]
+
+ // Load GPRs
+ // TODO: lots of those are smashed, could optimize.
+ add x0, x0, #30*8
+ ldp x30, x1, [x0], #-16
+ ldp x28, x29, [x0], #-16
+ ldp x26, x27, [x0], #-16
+ ldp x24, x25, [x0], #-16
+ ldp x22, x23, [x0], #-16
+ ldp x20, x21, [x0], #-16
+ ldp x18, x19, [x0], #-16
+ ldp x16, x17, [x0], #-16
+ ldp x14, x15, [x0], #-16
+ ldp x12, x13, [x0], #-16
+ ldp x10, x11, [x0], #-16
+ ldp x8, x9, [x0], #-16
+ ldp x6, x7, [x0], #-16
+ ldp x4, x5, [x0], #-16
+ ldp x2, x3, [x0], #-16
+ mov sp, x1
+
+ // TODO: Is it really OK to use LR for the target PC?
+ mov x0, #0
+ mov x1, #0
+ br xLR
+END art_quick_do_long_jump
+
+UNIMPLEMENTED art_quick_handle_fill_data
+
+UNIMPLEMENTED art_quick_lock_object
+UNIMPLEMENTED art_quick_unlock_object
+UNIMPLEMENTED art_quick_check_cast
+UNIMPLEMENTED art_quick_aput_obj_with_null_and_bound_check
+UNIMPLEMENTED art_quick_aput_obj_with_bound_check
+UNIMPLEMENTED art_quick_aput_obj
+UNIMPLEMENTED art_quick_initialize_static_storage
+UNIMPLEMENTED art_quick_initialize_type
+UNIMPLEMENTED art_quick_initialize_type_and_verify_access
+UNIMPLEMENTED art_quick_get32_static
+UNIMPLEMENTED art_quick_get64_static
+UNIMPLEMENTED art_quick_get_obj_static
+UNIMPLEMENTED art_quick_get32_instance
+UNIMPLEMENTED art_quick_get64_instance
+UNIMPLEMENTED art_quick_get_obj_instance
+UNIMPLEMENTED art_quick_set32_static
+UNIMPLEMENTED art_quick_set64_static
+UNIMPLEMENTED art_quick_set_obj_static
+UNIMPLEMENTED art_quick_set32_instance
+UNIMPLEMENTED art_quick_set64_instance
+UNIMPLEMENTED art_quick_set_obj_instance
+UNIMPLEMENTED art_quick_resolve_string
+
+// Macro to facilitate adding new allocation entrypoints.
+.macro TWO_ARG_DOWNCALL name, entrypoint, return
+ .extern \entrypoint
+ENTRY \name
+ brk 0
+END \name
+.endm
+
+// Macro to facilitate adding new array allocation entrypoints.
+.macro THREE_ARG_DOWNCALL name, entrypoint, return
+ .extern \entrypoint
+ENTRY \name
+ brk 0
+END \name
+.endm
+
+// Generate the allocation entrypoints for each allocator.
+GENERATE_ALL_ALLOC_ENTRYPOINTS
+
+UNIMPLEMENTED art_quick_test_suspend
+
+/**
+ * Returned by ClassLinker::GetOatCodeFor
+ *
+ */
+UNIMPLEMENTED art_quick_proxy_invoke_handler
+
+UNIMPLEMENTED art_quick_imt_conflict_trampoline
+
+
+ENTRY art_quick_resolution_trampoline
+ SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+ mov x2, xSELF
+ mov x3, sp
+ bl artQuickResolutionTrampoline // (called, receiver, Thread*, SP)
+ mov x9, x0 // Remember returned code pointer in x9.
+ RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+ cbz x9, 1f
+ br x0
+1:
+ RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+ DELIVER_PENDING_EXCEPTION
+END art_quick_resolution_trampoline
+
+/*
+ * Generic JNI frame layout:
+ *
+ * #-------------------#
+ * | |
+ * | caller method... |
+ * #-------------------# <--- SP on entry
+ * | Return X30/LR |
+ * | X29/FP | callee save
+ * | X28 | callee save
+ * | X27 | callee save
+ * | X26 | callee save
+ * | X25 | callee save
+ * | X24 | callee save
+ * | X23 | callee save
+ * | X22 | callee save
+ * | X21 | callee save
+ * | X20 | callee save
+ * | X19 | callee save
+ * | X7 | arg7
+ * | X6 | arg6
+ * | X5 | arg5
+ * | X4 | arg4
+ * | X3 | arg3
+ * | X2 | arg2
+ * | X1 | arg1
+ * | D15 | float arg 8
+ * | D14 | float arg 8
+ * | D13 | float arg 8
+ * | D12 | callee save
+ * | D11 | callee save
+ * | D10 | callee save
+ * | D9 | callee save
+ * | D8 | callee save
+ * | D7 | float arg 8
+ * | D6 | float arg 7
+ * | D5 | float arg 6
+ * | D4 | float arg 5
+ * | D3 | float arg 4
+ * | D2 | float arg 3
+ * | D1 | float arg 2
+ * | D0 | float arg 1
+ * | RDI/Method* | <- X0
+ * #-------------------#
+ * | local ref cookie | // 4B
+ * | SIRT size | // 4B
+ * #-------------------#
+ * | JNI Call Stack |
+ * #-------------------# <--- SP on native call
+ * | |
+ * | Stack for Regs | The trampoline assembly will pop these values
+ * | | into registers for native call
+ * #-------------------#
+ * | Native code ptr |
+ * #-------------------#
+ * | Free scratch |
+ * #-------------------#
+ * | Ptr to (1) | <--- SP
+ * #-------------------#
+ */
+ /*
+ * Called to do a generic JNI down-call
+ */
+ENTRY art_quick_generic_jni_trampoline
+ SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
+ str x0, [sp, #0] // Store native ArtMethod* to bottom of stack.
+
+ // Save SP , so we can have static CFI info.
+ mov x28, sp
+ .cfi_def_cfa_register x28
+
+ // This looks the same, but is different: this will be updated to point to the bottom
+ // of the frame when the SIRT is inserted.
+ mov xFP, sp
+
+ mov x8, #5120
+ sub sp, sp, x8
+
+ // prepare for artQuickGenericJniTrampoline call
+ // (Thread*, SP)
+ // x0 x1 <= C calling convention
+ // xSELF xFP <= where they are
+
+ mov x0, xSELF // Thread*
+ mov x1, xFP
+ bl artQuickGenericJniTrampoline // (Thread*, sp)
+
+ // Get the updated pointer. This is the bottom of the frame _with_ SIRT.
+ ldr xFP, [sp]
+ add x9, sp, #8
+
+ cmp x0, #0
+ b.mi .Lentry_error // Check for error, negative value.
+
+ // release part of the alloca.
+ add x9, x9, x0
+
+ // Get the code pointer
+ ldr xIP0, [x9, #0]
+
+ // Load parameters from frame into registers.
+ // TODO Check with artQuickGenericJniTrampoline.
+ // Also, check again APPCS64 - the stack arguments are interleaved.
+ ldp x0, x1, [x9, #8]
+ ldp x2, x3, [x9, #24]
+ ldp x4, x5, [x9, #40]
+ ldp x6, x7, [x9, #56]
+
+ ldp d0, d1, [x9, #72]
+ ldp d2, d3, [x9, #88]
+ ldp d4, d5, [x9, #104]
+ ldp d6, d7, [x9, #120]
+
+ add sp, x9, #136
+
+ blr xIP0 // native call.
+
+ // Restore self pointer.
+ ldr xSELF, [x28, #200]
+
+ // result sign extension is handled in C code
+ // prepare for artQuickGenericJniEndTrampoline call
+ // (Thread*, SP, result, result_f)
+ // x0 x1 x2 x3 <= C calling convention
+ mov x5, x0 // Save return value
+ mov x0, xSELF // Thread register
+ mov x1, xFP // Stack pointer
+ mov x2, x5 // Result (from saved)
+ fmov x3, d0 // d0 will contain floating point result, but needs to go into x3
+
+ bl artQuickGenericJniEndTrampoline
+
+ // Tear down the alloca.
+ mov sp, x28
+ .cfi_def_cfa_register sp
+
+ // Restore self pointer.
+ ldr xSELF, [x28, #200]
+
+ // Pending exceptions possible.
+ ldr x1, [xSELF, THREAD_EXCEPTION_OFFSET]
+ cbnz x1, .Lexception_in_native
+
+ // Tear down the callee-save frame.
+ RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+
+ // store into fpr, for when it's a fpr return...
+ fmov d0, x0
+ ret
+
+.Lentry_error:
+ mov sp, x28
+ .cfi_def_cfa_register sp
+ ldr xSELF, [x28, #200]
+.Lexception_in_native:
+ RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+ DELIVER_PENDING_EXCEPTION
+
+END art_quick_generic_jni_trampoline
+
+/*
+ * Called to bridge from the quick to interpreter ABI. On entry the arguments match those
+ * of a quick call:
+ * x0 = method being called/to bridge to.
+ * x1..x7, d0..d7 = arguments to that method.
+ */
+ENTRY art_quick_to_interpreter_bridge
+ SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME // Set up frame and save arguments.
+
+ // x0 will contain mirror::ArtMethod* method.
+ mov x1, xSELF // How to get Thread::Current() ???
+ mov x2, sp
+
+ // uint64_t artQuickToInterpreterBridge(mirror::ArtMethod* method, Thread* self,
+ // mirror::ArtMethod** sp)
+ bl artQuickToInterpreterBridge
+
+ RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME // TODO: no need to restore arguments in this case.
+
+ fmov d0, x0
+
+ RETURN_OR_DELIVER_PENDING_EXCEPTION
+END art_quick_to_interpreter_bridge
+
+UNIMPLEMENTED art_quick_instrumentation_entry
+UNIMPLEMENTED art_quick_instrumentation_exit
+UNIMPLEMENTED art_quick_deoptimize
+UNIMPLEMENTED art_quick_mul_long
+UNIMPLEMENTED art_quick_shl_long
+UNIMPLEMENTED art_quick_shr_long
+UNIMPLEMENTED art_quick_ushr_long
+UNIMPLEMENTED art_quick_indexof
+UNIMPLEMENTED art_quick_string_compareto