blob: b4b3283a54fc1d23810f39a2761d3e782f75c6a2 [file] [log] [blame]
Nicolas Geoffray4fc75692020-01-13 21:49:22 +00001%def header():
2/*
3 * Copyright (C) 2020 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * This is a #include, not a %include, because we want the C pre-processor
20 * to expand the macros into assembler assignment statements.
21 */
22#include "asm_support.h"
23#include "arch/arm64/asm_support_arm64.S"
Nicolas Geoffray4fc75692020-01-13 21:49:22 +000024
25/**
26 * ARM64 Runtime register usage conventions.
27 *
28 * r0 : w0 is 32-bit return register and x0 is 64-bit.
29 * r0-r7 : Argument registers.
30 * r8-r15 : Caller save registers (used as temporary registers).
31 * r16-r17: Also known as ip0-ip1, respectively. Used as scratch registers by
32 * the linker, by the trampolines and other stubs (the compiler uses
33 * these as temporary registers).
34 * r18 : Reserved for platform (SCS, shadow call stack)
35 * r19 : Pointer to thread-local storage.
36 * r20-r29: Callee save registers.
37 * r30 : (lr) is reserved (the link register).
38 * rsp : (sp) is reserved (the stack pointer).
39 * rzr : (zr) is reserved (the zero register).
40 *
41 * Floating-point registers
42 * v0-v31
43 *
44 * v0 : s0 is return register for singles (32-bit) and d0 for doubles (64-bit).
45 * This is analogous to the C/C++ (hard-float) calling convention.
46 * v0-v7 : Floating-point argument registers in both Dalvik and C/C++ conventions.
47 * Also used as temporary and codegen scratch registers.
48 *
49 * v0-v7 and v16-v31 : Caller save registers (used as temporary registers).
50 * v8-v15 : bottom 64-bits preserved across C calls (d8-d15 are preserved).
51 *
52 * v16-v31: Used as codegen temp/scratch.
53 * v8-v15 : Can be used for promotion.
54 *
55 * Must maintain 16-byte stack alignment.
56 *
57 * Nterp notes:
58 *
59 * The following registers have fixed assignments:
60 *
61 * reg nick purpose
62 * x19 xSELF self (Thread) pointer
63 * x20 wMR marking register
64 * x29 xFP interpreted frame pointer, used for accessing locals and args
65 * x22 xPC interpreted program counter, used for fetching instructions
66 * x23 xINST first 16-bit code unit of current instruction
67 * x24 xIBASE interpreted instruction base pointer, used for computed goto
68 * x25 xREFS base of object references of dex registers.
69 * x16 ip scratch reg
70 * x17 ip2 scratch reg (used by macros)
71 *
72 * Macros are provided for common operations. They MUST NOT alter unspecified registers or
73 * condition codes.
74*/
75
76/* single-purpose registers, given names for clarity */
77#define xSELF x19
78#define CFI_DEX 22 // DWARF register number of the register holding dex-pc (xPC).
79#define CFI_TMP 0 // DWARF register number of the first argument register (r0).
80#define xPC x22
81#define xINST x23
82#define wINST w23
83#define xIBASE x24
84#define xREFS x25
85#define CFI_REFS 25
86#define ip x16
87#define ip2 x17
88#define wip w16
89#define wip2 w17
90
91// To avoid putting ifdefs arond the use of wMR, make sure it's defined.
92// IsNterpSupported returns false for configurations that don't have wMR (typically CMS).
93#ifndef wMR
94#define wMR w20
95#endif
96
97// Temporary registers while setting up a frame.
98#define xNEW_FP x26
99#define xNEW_REFS x27
100#define CFI_NEW_REFS 27
101
102// +8 for the ArtMethod of the caller.
103#define OFFSET_TO_FIRST_ARGUMENT_IN_STACK (CALLEE_SAVES_SIZE + 8)
104
105/*
106 * Fetch the next instruction from xPC into wINST. Does not advance xPC.
107 */
108.macro FETCH_INST
109 ldrh wINST, [xPC]
110.endm
111
112/*
113 * Fetch the next instruction from the specified offset. Advances xPC
114 * to point to the next instruction. "count" is in 16-bit code units.
115 *
116 * Because of the limited size of immediate constants on ARM, this is only
117 * suitable for small forward movements (i.e. don't try to implement "goto"
118 * with this).
119 *
120 * This must come AFTER anything that can throw an exception, or the
121 * exception catch may miss. (This also implies that it must come after
122 * EXPORT_PC.)
123 */
124.macro FETCH_ADVANCE_INST count
125 ldrh wINST, [xPC, #((\count)*2)]!
126.endm
127
128/*
129 * Similar to FETCH_ADVANCE_INST, but does not update xPC. Used to load
130 * xINST ahead of possible exception point. Be sure to manually advance xPC
131 * later.
132 */
133.macro PREFETCH_INST count
134 ldrh wINST, [xPC, #((\count)*2)]
135.endm
136
137/* Advance xPC by some number of code units. */
138.macro ADVANCE count
139 add xPC, xPC, #((\count)*2)
140.endm
141
142/*
143 * Fetch the next instruction from an offset specified by "reg" and advance xPC.
144 * xPC to point to the next instruction. "reg" must specify the distance
145 * in bytes, *not* 16-bit code units, and may be a signed value.
146 *
147 */
148.macro FETCH_ADVANCE_INST_RB reg
149 add xPC, xPC, \reg, sxtw
150 ldrh wINST, [xPC]
151.endm
152
153/*
154 * Fetch a half-word code unit from an offset past the current PC. The
155 * "count" value is in 16-bit code units. Does not advance xPC.
156 *
157 * The "_S" variant works the same but treats the value as signed.
158 */
159.macro FETCH reg, count
160 ldrh \reg, [xPC, #((\count)*2)]
161.endm
162
163.macro FETCH_S reg, count
164 ldrsh \reg, [xPC, #((\count)*2)]
165.endm
166
167/*
168 * Fetch one byte from an offset past the current PC. Pass in the same
169 * "count" as you would for FETCH, and an additional 0/1 indicating which
170 * byte of the halfword you want (lo/hi).
171 */
172.macro FETCH_B reg, count, byte
173 ldrb \reg, [xPC, #((\count)*2+(\byte))]
174.endm
175
176/*
177 * Put the instruction's opcode field into the specified register.
178 */
179.macro GET_INST_OPCODE reg
180 and \reg, xINST, #255
181.endm
182
183/*
184 * Begin executing the opcode in _reg. Clobbers reg
185 */
186
187.macro GOTO_OPCODE reg
188 add \reg, xIBASE, \reg, lsl #${handler_size_bits}
189 br \reg
190.endm
191
192/*
193 * Get/set the 32-bit value from a Dalvik register.
194 */
195.macro GET_VREG reg, vreg
196 ldr \reg, [xFP, \vreg, uxtw #2]
197.endm
198.macro GET_VREG_OBJECT reg, vreg
199 ldr \reg, [xREFS, \vreg, uxtw #2]
200.endm
201.macro SET_VREG reg, vreg
202 str \reg, [xFP, \vreg, uxtw #2]
203 str wzr, [xREFS, \vreg, uxtw #2]
204.endm
205.macro SET_VREG_OBJECT reg, vreg, tmpreg
206 str \reg, [xFP, \vreg, uxtw #2]
207 str \reg, [xREFS, \vreg, uxtw #2]
208.endm
209.macro SET_VREG_FLOAT reg, vreg
210 str \reg, [xFP, \vreg, uxtw #2]
211 str wzr, [xREFS, \vreg, uxtw #2]
212.endm
213
214/*
215 * Get/set the 64-bit value from a Dalvik register.
216 */
217.macro GET_VREG_WIDE reg, vreg
218 add ip2, xFP, \vreg, uxtw #2
219 ldr \reg, [ip2]
220.endm
221.macro SET_VREG_WIDE reg, vreg
222 add ip2, xFP, \vreg, uxtw #2
223 str \reg, [ip2]
224 add ip2, xREFS, \vreg, uxtw #2
225 str xzr, [ip2]
226.endm
227.macro GET_VREG_DOUBLE reg, vreg
228 add ip2, xFP, \vreg, uxtw #2
229 ldr \reg, [ip2]
230.endm
231.macro SET_VREG_DOUBLE reg, vreg
232 add ip2, xFP, \vreg, uxtw #2
233 str \reg, [ip2]
234 add ip2, xREFS, \vreg, uxtw #2
235 str xzr, [ip2]
236.endm
237
238/*
239 * Get the 32-bit value from a Dalvik register and sign-extend to 64-bit.
240 * Used to avoid an extra instruction in int-to-long.
241 */
242.macro GET_VREG_S reg, vreg
243 ldrsw \reg, [xFP, \vreg, uxtw #2]
244.endm
245
246// An assembly entry that has a OatQuickMethodHeader prefix.
247.macro OAT_ENTRY name, end
248 .type \name, #function
249 .hidden \name
250 .global \name
251 .balign 16
252 // Padding of 8 bytes to get 16 bytes alignment of code entry.
253 .long 0
254 .long 0
255 // OatQuickMethodHeader.
256 .long 0
257 .long (\end - \name)
258\name:
259.endm
260
261.macro SIZE name
262 .size \name, .-\name
263.endm
264
265.macro NAME_START name
266 .type \name, #function
267 .hidden \name // Hide this as a global symbol, so we do not incur plt calls.
268 .global \name
269 /* Cache alignment for function entry */
270 .balign 16
271\name:
272.endm
273
274.macro NAME_END name
275 SIZE \name
276.endm
277
278// Macro for defining entrypoints into runtime. We don't need to save registers
279// (we're not holding references there), but there is no
280// kDontSave runtime method. So just use the kSaveRefsOnly runtime method.
281.macro NTERP_TRAMPOLINE name, helper
282ENTRY \name
283 SETUP_SAVE_REFS_ONLY_FRAME
284 bl \helper
285 RESTORE_SAVE_REFS_ONLY_FRAME
286 REFRESH_MARKING_REGISTER
287 RETURN_OR_DELIVER_PENDING_EXCEPTION
288END \name
289.endm
290
291.macro CLEAR_STATIC_VOLATILE_MARKER reg
292 and \reg, \reg, #-2
293.endm
294
295.macro CLEAR_INSTANCE_VOLATILE_MARKER reg
296 neg \reg, \reg
297.endm
298
299.macro EXPORT_PC
300 str xPC, [xREFS, #-16]
301.endm
302
303.macro BRANCH
304 // Update method counter and do a suspend check if the branch is negative.
305 tbnz wINST, #31, 2f
3061:
307 add w2, wINST, wINST // w2<- byte offset
308 FETCH_ADVANCE_INST_RB w2 // update xPC, load wINST
309 GET_INST_OPCODE ip // extract opcode from wINST
310 GOTO_OPCODE ip // jump to next instruction
3112:
312 ldr x0, [sp]
313 ldrh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
314 add x2, x2, #1
Nicolas Geoffray0315efa2020-06-26 11:42:39 +0100315 and w2, w2, #NTERP_HOTNESS_MASK
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000316 strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
317 // If the counter overflows, handle this in the runtime.
318 cbz w2, NterpHandleHotnessOverflow
319 // Otherwise, do a suspend check.
320 ldr x0, [xSELF, #THREAD_FLAGS_OFFSET]
321 ands x0, x0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
322 b.eq 1b
323 EXPORT_PC
324 bl art_quick_test_suspend
325 b 1b
326.endm
327
328// Setup the stack to start executing the method. Expects:
329// - x0 to contain the ArtMethod
330//
331// Outputs
332// - ip contains the dex registers size
333// - x13 contains the old stack pointer.
334//
335// Uses ip, ip2, x13, x14 as temporaries.
336.macro SETUP_STACK_FRAME code_item, refs, fp, cfi_refs
337 // Fetch dex register size.
338 ldrh wip, [\code_item, #CODE_ITEM_REGISTERS_SIZE_OFFSET]
339 // Fetch outs size.
340 ldrh wip2, [\code_item, #CODE_ITEM_OUTS_SIZE_OFFSET]
341
342 // Compute required frame size: ((2 * ip) + ip1) * 4 + 24
343 // 24 is for saving the previous frame, pc, and method being executed.
344 add x14, ip, ip
345 add x14, x14, ip2
346 lsl x14, x14, #2
347 add x14, x14, #24
348
349 // Compute new stack pointer in x14
350 sub x14, sp, x14
351 // Alignment
352 and x14, x14, #-16
353
354 // Set reference and dex registers, align to pointer size for previous frame and dex pc.
355 add \refs, x14, ip2, lsl #2
356 add \refs, \refs, 28
357 and \refs, \refs, #(-__SIZEOF_POINTER__)
358 add \fp, \refs, ip, lsl #2
359
360 // Now setup the stack pointer.
361 mov x13, sp
362 .cfi_def_cfa_register x13
363 mov sp, x14
364 str x13, [\refs, #-8]
Nicolas Geoffrayfaf5f3f2020-07-03 18:36:45 +0100365 CFI_DEF_CFA_BREG_PLUS_UCONST \cfi_refs, -8, CALLEE_SAVES_SIZE
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000366
367 // Put nulls in reference frame.
368 cbz ip, 2f
369 mov ip2, \refs
3701:
371 str xzr, [ip2], #8 // May clear vreg[0].
372 cmp ip2, \fp
373 b.lo 1b
3742:
375 // Save the ArtMethod.
376 str x0, [sp]
377.endm
378
379// Increase method hotness and do suspend check before starting executing the method.
380.macro START_EXECUTING_INSTRUCTIONS
381 ldr x0, [sp]
382 ldrh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
383 add x2, x2, #1
Nicolas Geoffray0315efa2020-06-26 11:42:39 +0100384 and w2, w2, #NTERP_HOTNESS_MASK
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000385 strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
386 // If the counter overflows, handle this in the runtime.
387 cbz w2, 2f
388 ldr x0, [xSELF, #THREAD_FLAGS_OFFSET]
389 tst x0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
390 b.ne 3f
3911:
392 FETCH_INST
393 GET_INST_OPCODE ip
394 GOTO_OPCODE ip
3952:
396 mov x1, xzr
397 mov x2, xFP
398 bl nterp_hot_method
399 b 1b
4003:
401 EXPORT_PC
402 bl art_quick_test_suspend
403 b 1b
404.endm
405
406.macro SPILL_ALL_CALLEE_SAVES
407 INCREASE_FRAME CALLEE_SAVES_SIZE
408 // Note: we technically don't need to save x19 and x20,
409 // but the runtime will expect those values to be there when unwinding
410 // (see Arm64Context::DoLongJump checking for the thread register).
411 SAVE_ALL_CALLEE_SAVES 0
412.endm
413
414.macro RESTORE_ALL_CALLEE_SAVES
415 // FP callee-saves
416 ldp d8, d9, [sp, #0]
417 ldp d10, d11, [sp, #16]
418 ldp d12, d13, [sp, #32]
419 ldp d14, d15, [sp, #48]
420
421 // GP callee-saves.
422 // No need to restore x19 (it's always the thread), and
423 // don't restore x20 (the marking register) as it may have been updated.
424 RESTORE_TWO_REGS x21, x22, 80
425 RESTORE_TWO_REGS x23, x24, 96
426 RESTORE_TWO_REGS x25, x26, 112
427 RESTORE_TWO_REGS x27, x28, 128
428 RESTORE_TWO_REGS x29, lr, 144
429
430 DECREASE_FRAME CALLEE_SAVES_SIZE
431.endm
432
433.macro SPILL_ALL_ARGUMENTS
434 INCREASE_FRAME 128
435 // GP arguments.
436 SAVE_TWO_REGS x0, x1, 0
437 SAVE_TWO_REGS x2, x3, 16
438 SAVE_TWO_REGS x4, x5, 32
439 SAVE_TWO_REGS x6, x7, 48
440
441 // FP arguments
442 stp d0, d1, [sp, #64]
443 stp d2, d3, [sp, #80]
444 stp d4, d5, [sp, #96]
445 stp d6, d7, [sp, #112]
446.endm
447
448.macro RESTORE_ALL_ARGUMENTS
449 // GP arguments.
450 RESTORE_TWO_REGS x0, x1, 0
451 RESTORE_TWO_REGS x2, x3, 16
452 RESTORE_TWO_REGS x4, x5, 32
453 RESTORE_TWO_REGS x6, x7, 48
454
455 // FP arguments
456 ldp d0, d1, [sp, #64]
457 ldp d2, d3, [sp, #80]
458 ldp d4, d5, [sp, #96]
459 ldp d6, d7, [sp, #112]
460 DECREASE_FRAME 128
461.endm
462
463// Helper to setup the stack after doing a nterp to nterp call. This will setup:
464// - xNEW_FP: the new pointer to dex registers
465// - xNEW_REFS: the new pointer to references
466// - xPC: the new PC pointer to execute
467// - x2: value in instruction to decode the number of arguments.
468// - x3: first dex register
469// - x4: top of dex register array
470//
471// The method expects:
472// - x0 to contain the ArtMethod
473// - x8 to contain the code item
474.macro SETUP_STACK_FOR_INVOKE
475 // We do the same stack overflow check as the compiler. See CanMethodUseNterp
476 // in how we limit the maximum nterp frame size.
477 sub x16, sp, #STACK_OVERFLOW_RESERVED_BYTES
478 ldr wzr, [x16]
479
480 // Spill all callee saves to have a consistent stack frame whether we
481 // are called by compiled code or nterp.
482 SPILL_ALL_CALLEE_SAVES
483
484 // Setup the frame.
485 SETUP_STACK_FRAME x8, xNEW_REFS, xNEW_FP, CFI_NEW_REFS
486 // Make x4 point to the top of the dex register array.
487 add x4, xNEW_FP, ip, uxtx #2
488
489 // Fetch instruction information before replacing xPC.
490 // TODO: move this down to the method that uses it, fetching it directly from wINST.
491 FETCH_B w2, 0, 1
492 // TODO: we could avoid this as instance invokes already fetch it.
493 FETCH w3, 2
494
495 // Set the dex pc pointer.
496 add xPC, x8, #CODE_ITEM_INSNS_OFFSET
497 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
498.endm
499
500// Setup arguments based on a non-range nterp to nterp call, and start executing
501// the method. We expect:
502// - xNEW_FP: the new pointer to dex registers
503// - xNEW_REFS: the new pointer to references
504// - xPC: the new PC pointer to execute
505// - x2: number of arguments (bits 4-7), 5th argument if any (bits 0-3)
506// - x3: first dex register
507// - x4: top of dex register array
508// - x1: receiver if non-static.
509.macro SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
510 // /* op vA, vB, {vC...vG} */
511 asr ip2, x2, #4
512 cbz ip2, 6f
513 mov ip, #-4
514 cmp ip2, #2
515 b.lt 1f
516 b.eq 2f
517 cmp ip2, #4
518 b.lt 3f
519 b.eq 4f
520
521 // We use a decrementing ip to store references relative
522 // to xNEW_FP and dex registers relative to x4
523 //
524 // TODO: We could set up ip as the number of registers (this can be an additional output from
525 // SETUP_STACK_FOR_INVOKE) and then just decrement it by one before copying each arg.
526 // Maybe even introduce macros NEW_VREG_ADDRESS/NEW_VREG_REF_ADDRESS.
5275:
528 and x2, x2, #15
529 GET_VREG_OBJECT w5, w2
530 str w5, [xNEW_FP, ip]
531 GET_VREG w5, w2
532 str w5, [x4, ip]
533 sub ip, ip, #4
5344:
535 asr x2, x3, #12
536 GET_VREG_OBJECT w5, w2
537 str w5, [xNEW_FP, ip]
538 GET_VREG w5, w2
539 str w5, [x4, ip]
540 sub ip, ip, #4
5413:
542 ubfx x2, x3, #8, #4
543 GET_VREG_OBJECT w5, w2
544 str w5, [xNEW_FP, ip]
545 GET_VREG w5, w2
546 str w5, [x4, ip]
547 sub ip, ip, #4
5482:
549 ubfx x2, x3, #4, #4
550 GET_VREG_OBJECT w5, w2
551 str w5, [xNEW_FP, ip]
552 GET_VREG w5, w2
553 str w5, [x4, ip]
554 .if !\is_string_init
555 sub ip, ip, #4
556 .endif
5571:
558 .if \is_string_init
559 // Ignore the first argument
560 .elseif \is_static
561 and x2, x3, #0xf
562 GET_VREG_OBJECT w5, w2
563 str w5, [xNEW_FP, ip]
564 GET_VREG w5, w2
565 str w5, [x4, ip]
566 .else
567 str w1, [xNEW_FP, ip]
568 str w1, [x4, ip]
569 .endif
570
5716:
572 // Start executing the method.
573 mov xFP, xNEW_FP
574 mov xREFS, xNEW_REFS
Nicolas Geoffrayfaf5f3f2020-07-03 18:36:45 +0100575 CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, CALLEE_SAVES_SIZE
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000576 START_EXECUTING_INSTRUCTIONS
577.endm
578
579// Setup arguments based on a range nterp to nterp call, and start executing
580// the method.
581// - xNEW_FP: the new pointer to dex registers
582// - xNEW_REFS: the new pointer to references
583// - xPC: the new PC pointer to execute
584// - x2: number of arguments
585// - x3: first dex register
586// - x4: top of dex register array
587// - x1: receiver if non-static.
588//
589// Uses ip, ip2, x5, x6 as temporaries.
590.macro SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
591 mov ip, #-4
592 .if \is_string_init
593 // Ignore the first argument
594 sub x2, x2, #1
595 add x3, x3, #1
596 .elseif !\is_static
597 sub x2, x2, #1
598 add x3, x3, #1
599 .endif
600
601 cbz x2, 2f
602 add ip2, xREFS, x3, lsl #2 // pointer to first argument in reference array
603 add ip2, ip2, x2, lsl #2 // pointer to last argument in reference array
604 add x5, xFP, x3, lsl #2 // pointer to first argument in register array
605 add x6, x5, x2, lsl #2 // pointer to last argument in register array
6061:
607 ldr w7, [ip2, #-4]!
608 str w7, [xNEW_FP, ip]
609 sub x2, x2, 1
610 ldr w7, [x6, #-4]!
611 str w7, [x4, ip]
612 sub ip, ip, 4
613 cbnz x2, 1b
6142:
615 .if \is_string_init
616 // Ignore first argument
617 .elseif !\is_static
618 str w1, [xNEW_FP, ip]
619 str w1, [x4, ip]
620 .endif
621 mov xFP, xNEW_FP
622 mov xREFS, xNEW_REFS
Nicolas Geoffrayfaf5f3f2020-07-03 18:36:45 +0100623 CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, CALLEE_SAVES_SIZE
Nicolas Geoffray4fc75692020-01-13 21:49:22 +0000624 START_EXECUTING_INSTRUCTIONS
625.endm
626
627.macro GET_SHORTY dest, is_interface, is_polymorphic, is_custom
628 stp x0, x1, [sp, #-16]!
629 .if \is_polymorphic
630 ldr x0, [sp, #16]
631 mov x1, xPC
632 bl NterpGetShortyFromInvokePolymorphic
633 .elseif \is_custom
634 ldr x0, [sp, #16]
635 mov x1, xPC
636 bl NterpGetShortyFromInvokeCustom
637 .elseif \is_interface
638 ldr x0, [sp, #16]
639 FETCH w1, 1
640 bl NterpGetShortyFromMethodId
641 .else
642 bl NterpGetShorty
643 .endif
644 mov \dest, x0
645 ldp x0, x1, [sp], #16
646.endm
647
648// Output: x8 contains the code item
649.macro GET_CODE_ITEM
650 // TODO: Get code item in a better way.
651 stp x0, x1, [sp, #-16]!
652 bl NterpGetCodeItem
653 mov x8, x0
654 ldp x0, x1, [sp], #16
655.endm
656
657.macro DO_ENTRY_POINT_CHECK call_compiled_code
658 // On entry, the method is x0, the instance is x1
659 adr x2, ExecuteNterpImpl
660 ldr x3, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
661 cmp x2, x3
662 b.ne \call_compiled_code
663.endm
664
665.macro UPDATE_REGISTERS_FOR_STRING_INIT old_value, new_value
666 mov wip, wzr
6671:
668 GET_VREG_OBJECT wip2, wip
669 cmp wip2, \old_value
670 b.ne 2f
671 SET_VREG_OBJECT \new_value, wip
6722:
673 add wip, wip, #1
674 add ip2, xREFS, wip, uxtw #2
675 cmp ip2, xFP
676 b.ne 1b
677.endm
678
679// Puts the next floating point argument into the expected register,
680// fetching values based on a non-range invoke.
681// Uses ip and ip2.
682.macro LOOP_OVER_SHORTY_LOADING_FPS dreg, sreg, inst, shorty, arg_index, finished
6831: // LOOP
684 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
685 cbz wip, \finished // if (wip == '\0') goto finished
686 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE
687 b.eq 2f
688 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT
689 b.eq 3f
690 lsr \inst, \inst, #4
691 add \arg_index, \arg_index, #1
692 // Handle extra argument in arg array taken by a long.
693 cmp wip, #74 // if (wip != 'J') goto LOOP
694 b.ne 1b
695 lsr \inst, \inst, #4
696 add \arg_index, \arg_index, #1
697 b 1b // goto LOOP
6982: // FOUND_DOUBLE
699 and ip, \inst, #0xf
700 GET_VREG wip, wip
701 lsr \inst, \inst, #4
702 add \arg_index, \arg_index, #1
703 cmp \arg_index, #4
704 b.eq 5f
705 and ip2, \inst, #0xf
706 lsr \inst, \inst, #4
707 add \arg_index, \arg_index, #1
708 b 6f
7095:
710 // TODO: Extract from wINST here and below? (Requires using a different register
711 // in the COMMON_INVOKE_NON_RANGE.)
712 FETCH_B wip2, 0, 1
713 and wip2, wip2, #0xf
7146:
715 GET_VREG wip2, wip2
716 add ip, ip, ip2, lsl #32
717 fmov \dreg, ip
718 b 4f
7193: // FOUND_FLOAT
720 cmp \arg_index, #4
721 b.eq 7f
722 and ip, \inst, #0xf
723 lsr \inst, \inst, #4
724 add \arg_index, \arg_index, #1
725 b 8f
7267:
727 FETCH_B wip, 0, 1
728 and wip, wip, #0xf
7298:
730 GET_VREG \sreg, wip
7314:
732.endm
733
734// Puts the next int/long/object argument in the expected register,
735// fetching values based on a non-range invoke.
736// Uses ip and ip2.
737.macro LOOP_OVER_SHORTY_LOADING_GPRS gpr_reg64, gpr_reg32, inst, shorty, arg_index, finished
7381: // LOOP
739 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
740 cbz wip, \finished // if (wip == '\0') goto finished
741 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG
742 b.eq 2f
743 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT
744 b.eq 3f
745 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE
746 b.eq 4f
747 cmp \arg_index, #4
748 b.eq 7f
749 and ip, \inst, #0xf
750 lsr \inst, \inst, #4
751 add \arg_index, \arg_index, #1
752 b 8f
7537:
754 FETCH_B wip, 0, 1
755 and wip, wip, #0xf
7568:
757 GET_VREG \gpr_reg32, wip
758 b 5f
7592: // FOUND_LONG
760 and ip, \inst, #0xf
761 GET_VREG wip, wip
762 lsr \inst, \inst, #4
763 add \arg_index, \arg_index, #1
764 cmp \arg_index, #4
765 b.eq 9f
766 and ip2, \inst, #0xf
767 lsr \inst, \inst, #4
768 add \arg_index, \arg_index, #1
769 b 10f
7709:
771 FETCH_B wip2, 0, 1
772 and wip2, wip2, #0xf
77310:
774 GET_VREG wip2, wip2
775 add \gpr_reg64, ip, ip2, lsl #32
776 b 5f
7773: // SKIP_FLOAT
778 lsr \inst, \inst, #4
779 add \arg_index, \arg_index, #1
780 b 1b
7814: // SKIP_DOUBLE
782 lsr \inst, \inst, #4
783 add \arg_index, \arg_index, #1
784 cmp \arg_index, #4
785 b.eq 1b
786 lsr \inst, \inst, #4
787 add \arg_index, \arg_index, #1
788 b 1b
7895:
790.endm
791
792.macro COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0
793 .if \is_polymorphic
794 // We always go to compiled code for polymorphic calls.
795 .elseif \is_custom
796 // We always go to compiled code for custom calls.
797 .else
798 DO_ENTRY_POINT_CHECK .Lcall_compiled_code_\suffix
799 GET_CODE_ITEM
800 .if \is_string_init
801 bl nterp_to_nterp_string_init_non_range
802 .elseif \is_static
803 bl nterp_to_nterp_static_non_range
804 .else
805 bl nterp_to_nterp_instance_non_range
806 .endif
807 b .Ldone_return_\suffix
808 .endif
809
810.Lcall_compiled_code_\suffix:
811 GET_SHORTY xINST, \is_interface, \is_polymorphic, \is_custom
812 // From this point:
813 // - xINST contains shorty (in callee-save to switch over return value after call).
814 // - x0 contains method
815 // - x1 contains 'this' pointer for instance method.
816 add x9, xINST, #1 // shorty + 1 ; ie skip return arg character
817 FETCH w11, 2 // arguments
818 .if \is_string_init
819 lsr x11, x11, #4
820 mov x10, #1 // ignore first argument
821 .elseif \is_static
822 mov x10, xzr // arg_index
823 .else
824 lsr x11, x11, #4
825 mov x10, #1 // ignore first argument
826 .endif
827 LOOP_OVER_SHORTY_LOADING_FPS d0, s0, x11, x9, x10, .Lxmm_setup_finished_\suffix
828 LOOP_OVER_SHORTY_LOADING_FPS d1, s1, x11, x9, x10, .Lxmm_setup_finished_\suffix
829 LOOP_OVER_SHORTY_LOADING_FPS d2, s2, x11, x9, x10, .Lxmm_setup_finished_\suffix
830 LOOP_OVER_SHORTY_LOADING_FPS d3, s3, x11, x9, x10, .Lxmm_setup_finished_\suffix
831 LOOP_OVER_SHORTY_LOADING_FPS d4, s4, x11, x9, x10, .Lxmm_setup_finished_\suffix
832.Lxmm_setup_finished_\suffix:
833 add x9, xINST, #1 // shorty + 1 ; ie skip return arg character
834 FETCH w11, 2 // arguments
835 .if \is_string_init
836 lsr x11, x11, #4
837 mov x10, #1 // ignore first argument
838 LOOP_OVER_SHORTY_LOADING_GPRS x1, w1, x11, x9, x10, .Lgpr_setup_finished_\suffix
839 .elseif \is_static
840 mov x10, xzr // arg_index
841 LOOP_OVER_SHORTY_LOADING_GPRS x1, w1, x11, x9, x10, .Lgpr_setup_finished_\suffix
842 .else
843 lsr x11, x11, #4
844 mov x10, #1 // ignore first argument
845 .endif
846 LOOP_OVER_SHORTY_LOADING_GPRS x2, w2, x11, x9, x10, .Lgpr_setup_finished_\suffix
847 LOOP_OVER_SHORTY_LOADING_GPRS x3, w3, x11, x9, x10, .Lgpr_setup_finished_\suffix
848 LOOP_OVER_SHORTY_LOADING_GPRS x4, w4, x11, x9, x10, .Lgpr_setup_finished_\suffix
849 LOOP_OVER_SHORTY_LOADING_GPRS x5, w5, x11, x9, x10, .Lgpr_setup_finished_\suffix
850.Lgpr_setup_finished_\suffix:
851 .if \is_polymorphic
852 bl art_quick_invoke_polymorphic
853 .elseif \is_custom
854 bl art_quick_invoke_custom
855 .else
856 .if \is_interface
857 // Setup hidden argument
858 FETCH wip2, 1
859 .endif
860 ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
861 blr lr
862 .endif
863 ldrb wip, [xINST]
864 cmp ip, #68 // Test if result type char == 'D'.
865 b.eq .Lreturn_double_\suffix
866 cmp ip, #70
867 b.ne .Ldone_return_\suffix
868.Lreturn_float_\suffix:
869 fmov w0, s0
870 b .Ldone_return_\suffix
871.Lreturn_double_\suffix:
872 fmov x0, d0
873.Ldone_return_\suffix:
874 /* resume execution of caller */
875 .if \is_string_init
876 FETCH w11, 2 // arguments
877 and x11, x11, #0xf
878 GET_VREG w1, w11
879 UPDATE_REGISTERS_FOR_STRING_INIT w1, w0
880 .endif
881
882 .if \is_polymorphic
883 FETCH_ADVANCE_INST 4
884 .else
885 FETCH_ADVANCE_INST 3
886 .endif
887 GET_INST_OPCODE ip
888 GOTO_OPCODE ip
889.endm
890
891// Puts the next floating point argument into the expected register,
892// fetching values based on a range invoke.
893// Uses ip as temporary.
894.macro LOOP_RANGE_OVER_SHORTY_LOADING_FPS dreg, sreg, shorty, arg_index, stack_index, finished
8951: // LOOP
896 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
897 cbz wip, \finished // if (wip == '\0') goto finished
898 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE
899 b.eq 2f
900 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT
901 b.eq 3f
902 add \arg_index, \arg_index, #1
903 add \stack_index, \stack_index, #1
904 // Handle extra argument in arg array taken by a long.
905 cmp wip, #74 // if (wip != 'J') goto LOOP
906 b.ne 1b
907 add \arg_index, \arg_index, #1
908 add \stack_index, \stack_index, #1
909 b 1b // goto LOOP
9102: // FOUND_DOUBLE
911 GET_VREG_DOUBLE \dreg, \arg_index
912 add \arg_index, \arg_index, #2
913 add \stack_index, \stack_index, #2
914 b 4f
9153: // FOUND_FLOAT
916 GET_VREG \sreg, \arg_index
917 add \arg_index, \arg_index, #1
918 add \stack_index, \stack_index, #1
9194:
920.endm
921
922// Puts the next floating point argument into the expected stack slot,
923// fetching values based on a range invoke.
924// Uses ip as temporary.
925//
926// TODO: We could just copy all the vregs to the stack slots in a simple loop
927// without looking at the shorty at all. (We could also drop
928// the "stack_index" from the macros for loading registers.) We could also do
929// that conditionally if argument word count > 6; otherwise we know that all
930// args fit into registers.
931.macro LOOP_RANGE_OVER_FPs shorty, arg_index, stack_index, finished
9321: // LOOP
933 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
934 cbz wip, \finished // if (wip == '\0') goto finished
935 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE
936 b.eq 2f
937 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT
938 b.eq 3f
939 add \arg_index, \arg_index, #1
940 add \stack_index, \stack_index, #1
941 // Handle extra argument in arg array taken by a long.
942 cmp wip, #74 // if (wip != 'J') goto LOOP
943 b.ne 1b
944 add \arg_index, \arg_index, #1
945 add \stack_index, \stack_index, #1
946 b 1b // goto LOOP
9472: // FOUND_DOUBLE
948 GET_VREG_WIDE ip, \arg_index
949 add ip2, sp, \stack_index, uxtw #2
950 str ip, [ip2]
951 add \arg_index, \arg_index, #2
952 add \stack_index, \stack_index, #2
953 b 1b
9543: // FOUND_FLOAT
955 GET_VREG wip, \arg_index
956 str wip, [sp, \stack_index, uxtw #2]
957 add \arg_index, \arg_index, #1
958 add \stack_index, \stack_index, #1
959 b 1b
960.endm
961
962// Puts the next int/long/object argument in the expected register,
963// fetching values based on a range invoke.
964// Uses ip as temporary.
965.macro LOOP_RANGE_OVER_SHORTY_LOADING_GPRS reg64, reg32, shorty, arg_index, stack_index, finished
9661: // LOOP
967 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
968 cbz wip, \finished // if (wip == '\0') goto finished
969 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG
970 b.eq 2f
971 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT
972 b.eq 3f
973 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE
974 b.eq 4f
975 GET_VREG \reg32, \arg_index
976 add \arg_index, \arg_index, #1
977 add \stack_index, \stack_index, #1
978 b 5f
9792: // FOUND_LONG
980 GET_VREG_WIDE \reg64, \arg_index
981 add \arg_index, \arg_index, #2
982 add \stack_index, \stack_index, #2
983 b 5f
9843: // SKIP_FLOAT
985 add \arg_index, \arg_index, #1
986 add \stack_index, \stack_index, #1
987 b 1b
9884: // SKIP_DOUBLE
989 add \arg_index, \arg_index, #2
990 add \stack_index, \stack_index, #2
991 b 1b
9925:
993.endm
994
995// Puts the next int/long/object argument in the expected stack slot,
996// fetching values based on a range invoke.
997// Uses ip as temporary.
998.macro LOOP_RANGE_OVER_INTs shorty, arg_index, stack_index, finished
9991: // LOOP
1000 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
1001 cbz wip, \finished // if (wip == '\0') goto finished
1002 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG
1003 b.eq 2f
1004 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT
1005 b.eq 3f
1006 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE
1007 b.eq 4f
1008 GET_VREG wip, \arg_index
1009 str wip, [sp, \stack_index, uxtw #2]
1010 add \arg_index, \arg_index, #1
1011 add \stack_index, \stack_index, #1
1012 b 1b
10132: // FOUND_LONG
1014 GET_VREG_WIDE ip, \arg_index
1015 add ip2, sp, \stack_index, uxtw #2
1016 str ip, [ip2]
1017 add \arg_index, \arg_index, #2
1018 add \stack_index, \stack_index, #2
1019 b 1b
10203: // SKIP_FLOAT
1021 add \arg_index, \arg_index, #1
1022 add \stack_index, \stack_index, #1
1023 b 1b
10244: // SKIP_DOUBLE
1025 add \arg_index, \arg_index, #2
1026 add \stack_index, \stack_index, #2
1027 b 1b
1028.endm
1029
1030.macro COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0
1031 .if \is_polymorphic
1032 // We always go to compiled code for polymorphic calls.
1033 .elseif \is_custom
1034 // We always go to compiled code for custom calls.
1035 .else
1036 DO_ENTRY_POINT_CHECK .Lcall_compiled_code_range_\suffix
1037 GET_CODE_ITEM
1038 .if \is_string_init
1039 bl nterp_to_nterp_string_init_range
1040 .elseif \is_static
1041 bl nterp_to_nterp_static_range
1042 .else
1043 bl nterp_to_nterp_instance_range
1044 .endif
1045 b .Ldone_return_range_\suffix
1046 .endif
1047
1048.Lcall_compiled_code_range_\suffix:
1049 GET_SHORTY xINST, \is_interface, \is_polymorphic, \is_custom
1050 // From this point:
1051 // - xINST contains shorty (in callee-save to switch over return value after call).
1052 // - x0 contains method
1053 // - x1 contains 'this' pointer for instance method.
1054 add x9, xINST, #1 // shorty + 1 ; ie skip return arg character
1055 FETCH w10, 2 // arguments
1056 .if \is_string_init
1057 add x10, x10, #1 // arg start index
1058 mov x11, #1 // index in stack
1059 .elseif \is_static
1060 mov x11, xzr // index in stack
1061 .else
1062 add x10, x10, #1 // arg start index
1063 mov x11, #1 // index in stack
1064 .endif
1065 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d0, s0, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1066 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d1, s1, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1067 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d2, s2, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1068 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d3, s3, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1069 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d4, s4, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1070 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d5, s5, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1071 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d6, s6, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1072 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d7, s7, x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1073 // Store in the outs array (stored above the ArtMethod in the stack)
1074 add x11, x11, #2 // Add two words for the ArtMethod stored before the outs.
1075 LOOP_RANGE_OVER_FPs x9, w10, w11, .Lxmm_setup_finished_range_\suffix
1076.Lxmm_setup_finished_range_\suffix:
1077 add x9, xINST, #1 // shorty + 1 ; ie skip return arg character
1078 FETCH w10, 2 // arguments
1079 .if \is_string_init
1080 add x10, x10, #1 // arg start index
1081 mov x11, #1 // index in stack
1082 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x1, w1, x9, w10, w11, .Lgpr_setup_finished_\suffix
1083 .elseif \is_static
1084 mov x11, xzr // index in stack
1085 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x1, w1, x9, w10, w11 .Lgpr_setup_finished_\suffix
1086 .else
1087 add x10, x10, #1 // arg start index
1088 mov x11, #1 // index in stack
1089 .endif
1090 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x2, w2, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1091 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x3, w3, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1092 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x4, w4, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1093 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x5, w5, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1094 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x6, w6, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1095 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x7, w7, x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1096 // Store in the outs array (stored above the ArtMethod in the stack)
1097 add x11, x11, #2 // Add two words for the ArtMethod stored before the outs.
1098 LOOP_RANGE_OVER_INTs x9, w10, w11, .Lgpr_setup_finished_range_\suffix
1099.Lgpr_setup_finished_range_\suffix:
1100 .if \is_polymorphic
1101 bl art_quick_invoke_polymorphic
1102 .elseif \is_custom
1103 bl art_quick_invoke_custom
1104 .else
1105 .if \is_interface
1106 // Setup hidden argument
1107 FETCH wip2, 1
1108 .endif
1109 ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64]
1110 blr lr
1111 .endif
1112 ldrb wip, [xINST]
1113 cmp ip, #68 // Test if result type char == 'D'.
1114 b.eq .Lreturn_double_range_\suffix
1115 cmp ip, #70
1116 b.ne .Ldone_return_\suffix
1117.Lreturn_float_range_\suffix:
1118 fmov w0, s0
1119 b .Ldone_return_range_\suffix
1120.Lreturn_double_range_\suffix:
1121 fmov x0, d0
1122.Ldone_return_range_\suffix:
1123 /* resume execution of caller */
1124 .if \is_string_init
1125 FETCH w11, 2 // arguments
1126 GET_VREG w1, w11
1127 UPDATE_REGISTERS_FOR_STRING_INIT w1, w0
1128 .endif
1129
1130 .if \is_polymorphic
1131 FETCH_ADVANCE_INST 4
1132 .else
1133 FETCH_ADVANCE_INST 3
1134 .endif
1135 GET_INST_OPCODE ip
1136 GOTO_OPCODE ip
1137.endm
1138
1139// Fetch some information from the thread cache.
1140// Uses ip and ip2 as temporaries.
1141.macro FETCH_FROM_THREAD_CACHE dest_reg, slow_path
1142 add ip, xSELF, #THREAD_INTERPRETER_CACHE_OFFSET // cache address
1143 ubfx ip2, xPC, #2, #THREAD_INTERPRETER_CACHE_SIZE_LOG2 // entry index
1144 add ip, ip, ip2, lsl #4 // entry address within the cache
1145 ldp ip, \dest_reg, [ip] // entry key (pc) and value (offset)
1146 cmp ip, xPC
1147 b.ne \slow_path
1148.endm
1149
1150// Helper for static field get.
1151.macro OP_SGET load="ldr", volatile_load="ldar", maybe_extend="", wide="0"
1152 // Fast-path which gets the field from thread-local cache.
1153 FETCH_FROM_THREAD_CACHE x0, 4f
11541:
1155 ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
1156 ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
1157 cbnz wMR, 3f
11582:
1159 lsr w2, wINST, #8 // w2 <- A
1160 .if \wide
1161 ldr x0, [x0, x1]
1162 SET_VREG_WIDE x0, w2 // fp[A] <- value
1163 .else
1164 \load w0, [x0, x1]
1165 SET_VREG w0, w2 // fp[A] <- value
1166 .endif
1167 FETCH_ADVANCE_INST 2
1168 GET_INST_OPCODE ip
1169 GOTO_OPCODE ip
11703:
1171 bl art_quick_read_barrier_mark_reg00
1172 b 2b
11734:
1174 mov x0, xSELF
1175 ldr x1, [sp]
1176 mov x2, xPC
1177 EXPORT_PC
1178 bl nterp_get_static_field
1179 tbz x0, #0, 1b
1180 CLEAR_STATIC_VOLATILE_MARKER x0
1181 ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
1182 ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
1183 cbnz wMR, 7f
11845:
1185 lsr w2, wINST, #8 // w2 <- A
1186 add x0, x0, x1
1187 .if \wide
1188 ldar x0, [x0]
1189 SET_VREG_WIDE x0, w2 // fp[A] <- value
1190 .else
1191 \volatile_load w0, [x0]
1192 \maybe_extend
1193 SET_VREG w0, w2 // fp[A] <- value
1194 .endif
1195 FETCH_ADVANCE_INST 2
1196 GET_INST_OPCODE ip
1197 GOTO_OPCODE ip
11987:
1199 bl art_quick_read_barrier_mark_reg00
1200 b 5b
1201.endm
1202
1203// Helper for static field put.
1204.macro OP_SPUT store="str", volatile_store="stlr", wide="0":
1205 // Fast-path which gets the field from thread-local cache.
1206 FETCH_FROM_THREAD_CACHE x0, 4f
12071:
1208 ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
1209 ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
1210 cbnz wMR, 3f
12112:
1212 lsr w2, wINST, #8 // w2 <- A
1213 .if \wide
1214 GET_VREG_WIDE x2, w2 // x2 <- v[A]
1215 \store x2, [x0, x1]
1216 .else
1217 GET_VREG w2, w2 // w2 <- v[A]
1218 \store w2, [x0, x1]
1219 .endif
1220 FETCH_ADVANCE_INST 2
1221 GET_INST_OPCODE ip
1222 GOTO_OPCODE ip
12233:
1224 bl art_quick_read_barrier_mark_reg00
1225 b 2b
12264:
1227 mov x0, xSELF
1228 ldr x1, [sp]
1229 mov x2, xPC
1230 EXPORT_PC
1231 bl nterp_get_static_field
1232 tbz x0, #0, 1b
1233 CLEAR_STATIC_VOLATILE_MARKER x0
1234 ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
1235 ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
1236 cbnz wMR, 6f
12375:
1238 lsr w2, wINST, #8 // w2 <- A
1239 add x0, x0, x1
1240 .if \wide
1241 GET_VREG_WIDE x2, w2 // x2 <- v[A]
1242 \volatile_store x2, [x0]
1243 .else
1244 GET_VREG w2, w2 // w2 <- v[A]
1245 \volatile_store w2, [x0]
1246 .endif
1247 FETCH_ADVANCE_INST 2
1248 GET_INST_OPCODE ip
1249 GOTO_OPCODE ip
12506:
1251 bl art_quick_read_barrier_mark_reg00
1252 b 5b
1253.endm
1254
1255
1256// Helper for instance field put.
1257.macro OP_IPUT store="str", volatile_store="stlr", wide="0":
1258 // Fast-path which gets the field from thread-local cache.
1259 FETCH_FROM_THREAD_CACHE x0, 2f
12601:
1261 ubfx w1, wINST, #8, #4 // w1<- A
1262 lsr w2, wINST, #12 // w2<- B
1263 GET_VREG w2, w2 // vB (object we're operating on)
1264 cbz w2, common_errNullObject
1265 .if \wide
1266 GET_VREG_WIDE x1, w1 // x1<- fp[A]/fp[A+1]
1267 \store x1, [x2, x0]
1268 .else
1269 GET_VREG w1, w1 // w1 <- v[A]
1270 \store w1, [x2, x0]
1271 .endif
1272 FETCH_ADVANCE_INST 2
1273 GET_INST_OPCODE ip
1274 GOTO_OPCODE ip
12752:
1276 mov x0, xSELF
1277 ldr x1, [sp]
1278 mov x2, xPC
1279 EXPORT_PC
1280 bl nterp_get_instance_field_offset
1281 tbz w0, #31, 1b
1282 CLEAR_INSTANCE_VOLATILE_MARKER w0
1283 ubfx w1, wINST, #8, #4 // w1<- A
1284 lsr w2, wINST, #12 // w2<- B
1285 GET_VREG w2, w2 // vB (object we're operating on)
1286 cbz w2, common_errNullObject
1287 add x2, x2, x0
1288 .if \wide
1289 GET_VREG_WIDE x1, w1 // x1<- fp[A]/fp[A+1]
1290 \volatile_store x1, [x2]
1291 .else
1292 GET_VREG w1, w1 // w1 <- v[A]
1293 \volatile_store w1, [x2]
1294 .endif
1295 FETCH_ADVANCE_INST 2
1296 GET_INST_OPCODE ip
1297 GOTO_OPCODE ip
1298.endm
1299
1300// Helper for instance field get.
1301.macro OP_IGET load="ldr", volatile_load="ldar", maybe_extend="", wide="0"
1302 // Fast-path which gets the field from thread-local cache.
1303 FETCH_FROM_THREAD_CACHE x0, 2f
13041:
1305 lsr w2, wINST, #12 // w2<- B
1306 GET_VREG w3, w2 // w3<- object we're operating on
1307 ubfx w2, wINST, #8, #4 // w2<- A
1308 cbz w3, common_errNullObject // object was null
1309 .if \wide
1310 \load x0, [x3, x0]
1311 SET_VREG_WIDE x0, w2 // fp[A] <- value
1312 .else
1313 \load w0, [x3, x0]
1314 SET_VREG w0, w2 // fp[A] <- value
1315 .endif
1316 FETCH_ADVANCE_INST 2
1317 GET_INST_OPCODE ip
1318 GOTO_OPCODE ip
13192:
1320 mov x0, xSELF
1321 ldr x1, [sp]
1322 mov x2, xPC
1323 EXPORT_PC
1324 bl nterp_get_instance_field_offset
1325 tbz w0, #31, 1b
1326 CLEAR_INSTANCE_VOLATILE_MARKER w0
1327 lsr w2, wINST, #12 // w2<- B
1328 GET_VREG w3, w2 // w3<- object we're operating on
1329 ubfx w2, wINST, #8, #4 // w2<- A
1330 cbz w3, common_errNullObject // object was null
1331 add x3, x3, x0
1332 .if \wide
1333 \volatile_load x0, [x3]
1334 SET_VREG_WIDE x0, w2 // fp[A] <- value
1335 .else
1336 \volatile_load w0, [x3]
1337 \maybe_extend
1338 SET_VREG w0, w2 // fp[A] <- value
1339 .endif
1340 FETCH_ADVANCE_INST 2
1341 GET_INST_OPCODE ip
1342 GOTO_OPCODE ip
1343.endm
1344
1345// Puts the next int/long/object parameter passed in physical register
1346// in the expected dex register array entry, and in case of object in the
1347// expected reference array entry.
1348.macro LOOP_OVER_SHORTY_STORING_GPRS gpr_64, gpr_32, shorty, arg_offset, regs, refs, finished
13491: // LOOP
1350 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
1351 cbz wip, \finished // if (wip == '\0') goto finished
1352 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG
1353 b.eq 2f
1354 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT
1355 b.eq 3f
1356 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE
1357 b.eq 4f
1358 str \gpr_32, [\regs, \arg_offset]
1359 cmp wip, #76 // if (wip != 'L') goto NOT_REFERENCE
1360 b.ne 6f
1361 str \gpr_32, [\refs, \arg_offset]
13626: // NOT_REFERENCE
1363 add \arg_offset, \arg_offset, #4
1364 b 5f
13652: // FOUND_LONG
1366 str \gpr_64, [\regs, \arg_offset]
1367 add \arg_offset, \arg_offset, #8
1368 b 5f
13693: // SKIP_FLOAT
1370 add \arg_offset, \arg_offset, #4
1371 b 1b
13724: // SKIP_DOUBLE
1373 add \arg_offset, \arg_offset, #8
1374 b 1b
13755:
1376.endm
1377
1378// Puts the next floating point parameter passed in physical register
1379// in the expected dex register array entry.
1380// Uses ip as temporary.
1381.macro LOOP_OVER_SHORTY_STORING_FPS dreg, sreg, shorty, arg_offset, fp, finished
13821: // LOOP
1383 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
1384 cbz wip, \finished // if (wip == '\0') goto finished
1385 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE
1386 b.eq 2f
1387 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT
1388 b.eq 3f
1389 add \arg_offset, \arg_offset, #4
1390 // Handle extra argument in arg array taken by a long.
1391 cmp wip, #74 // if (wip != 'J') goto LOOP
1392 b.ne 1b
1393 add \arg_offset, \arg_offset, #4
1394 b 1b // goto LOOP
13952: // FOUND_DOUBLE
1396 str \dreg, [\fp, \arg_offset]
1397 add \arg_offset, \arg_offset, #8
1398 b 4f
13993: // FOUND_FLOAT
1400 str \sreg, [\fp, \arg_offset]
1401 add \arg_offset, \arg_offset, #4
14024:
1403.endm
1404
1405// Puts the next floating point parameter passed in stack
1406// in the expected dex register array entry.
1407// Uses ip as temporary.
1408//
1409// TODO: Or we could just spill regs to the reserved slots in the caller's
1410// frame and copy all regs in a simple loop. This time, however, we would
1411// need to look at the shorty anyway to look for the references.
1412// (The trade-off is different for passing arguments and receiving them.)
1413.macro LOOP_OVER_FPs shorty, arg_offset, regs, stack_ptr, finished
14141: // LOOP
1415 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
1416 cbz wip, \finished // if (wip == '\0') goto finished
1417 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE
1418 b.eq 2f
1419 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT
1420 b.eq 3f
1421 add \arg_offset, \arg_offset, #4
1422 // Handle extra argument in arg array taken by a long.
1423 cmp wip, #74 // if (wip != 'J') goto LOOP
1424 b.ne 1b
1425 add \arg_offset, \arg_offset, #4
1426 b 1b // goto LOOP
14272: // FOUND_DOUBLE
1428 add ip, \stack_ptr, \arg_offset
1429 ldr ip, [ip, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1430 str ip, [\regs, \arg_offset]
1431 add \arg_offset, \arg_offset, #8
1432 b 1b
14333: // FOUND_FLOAT
1434 add ip, \stack_ptr, \arg_offset
1435 ldr wip, [ip, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1436 str wip, [\regs, \arg_offset]
1437 add \arg_offset, \arg_offset, #4
1438 b 1b
1439.endm
1440
1441// Puts the next int/long/object parameter passed in stack
1442// in the expected dex register array entry, and in case of object in the
1443// expected reference array entry.
1444// Uses ip and ip2 as temporary.
1445.macro LOOP_OVER_INTs shorty, arg_offset, regs, refs, stack_ptr, finished
14461: // LOOP
1447 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment.
1448 cbz wip, \finished // if (wip == '\0') goto finished
1449 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG
1450 b.eq 2f
1451 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT
1452 b.eq 3f
1453 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE
1454 b.eq 4f
1455 add ip2, \stack_ptr, \arg_offset
1456 ldr wip2, [ip2, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1457 str wip2, [\regs, \arg_offset]
1458 cmp wip, #76 // if (wip != 'L') goto loop
1459 b.ne 3f
1460 str wip2, [\refs, \arg_offset]
1461 add \arg_offset, \arg_offset, #4
1462 b 1b
14632: // FOUND_LONG
1464 add ip, \stack_ptr, \arg_offset
1465 ldr ip, [ip, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK]
1466 str ip, [\regs, \arg_offset]
1467 add \arg_offset, \arg_offset, #8
1468 b 1b
14693: // SKIP_FLOAT
1470 add \arg_offset, \arg_offset, #4
1471 b 1b
14724: // SKIP_DOUBLE
1473 add \arg_offset, \arg_offset, #8
1474 b 1b
1475.endm
1476
1477%def entry():
1478/*
1479 * ArtMethod entry point.
1480 *
1481 * On entry:
1482 * x0 ArtMethod* callee
1483 * rest method parameters
1484 */
1485
1486OAT_ENTRY ExecuteNterpImpl, EndExecuteNterpImpl
1487 .cfi_startproc
1488 sub x16, sp, #STACK_OVERFLOW_RESERVED_BYTES
1489 ldr wzr, [x16]
1490 /* Spill callee save regs */
1491 SPILL_ALL_CALLEE_SAVES
1492
1493 // TODO: Get shorty in a better way and remove below
1494 SPILL_ALL_ARGUMENTS
1495
1496 // Save method in callee-save xINST
1497 mov xINST, x0
1498 bl NterpGetShorty
1499 // Save shorty in callee-save xIBASE.
1500 mov xIBASE, x0
1501 mov x0, xINST
1502 bl NterpGetCodeItem
1503 mov xPC, x0
1504
1505 RESTORE_ALL_ARGUMENTS
1506
1507 // Setup the stack for executing the method.
1508 SETUP_STACK_FRAME xPC, xREFS, xFP, CFI_REFS
1509
1510 // Setup the parameters
1511 ldrh wip2, [xPC, #CODE_ITEM_INS_SIZE_OFFSET]
1512 cbz wip2, .Lxmm_setup_finished
1513
1514 sub ip2, ip, ip2
1515 lsl x8, ip2, #2 // x8 is now the offset for inputs into the registers array.
1516
1517 // Setup shorty, pointer to inputs in FP and pointer to inputs in REFS
1518 add x9, xIBASE, #1 // shorty + 1 ; ie skip return arg character
1519 add x10, xFP, x8
1520 add x11, xREFS, x8
1521
1522 ldr wip, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET]
1523 // TODO: could be TBNZ but we'd need a constant for log2(ART_METHOD_IS_STATIC_FLAG).
1524 tst wip, #ART_METHOD_IS_STATIC_FLAG
1525 b.ne .Lhandle_static_method
1526 str w1, [x10], #4
1527 str w1, [x11], #4
1528 add x13, x13, #4
1529 mov x12, #0
1530 b .Lcontinue_setup_gprs
1531.Lhandle_static_method:
1532 mov x12, #0
1533 LOOP_OVER_SHORTY_STORING_GPRS x1, w1, x9, x12, x10, x11, .Lgpr_setup_finished
1534.Lcontinue_setup_gprs:
1535 LOOP_OVER_SHORTY_STORING_GPRS x2, w2, x9, x12, x10, x11, .Lgpr_setup_finished
1536 LOOP_OVER_SHORTY_STORING_GPRS x3, w3, x9, x12, x10, x11, .Lgpr_setup_finished
1537 LOOP_OVER_SHORTY_STORING_GPRS x4, w4, x9, x12, x10, x11, .Lgpr_setup_finished
1538 LOOP_OVER_SHORTY_STORING_GPRS x5, w5, x9, x12, x10, x11, .Lgpr_setup_finished
1539 LOOP_OVER_SHORTY_STORING_GPRS x6, w6, x9, x12, x10, x11, .Lgpr_setup_finished
1540 LOOP_OVER_SHORTY_STORING_GPRS x7, w7, x9, x12, x10, x11, .Lgpr_setup_finished
1541 LOOP_OVER_INTs x9, x12, x10, x11, x13, .Lgpr_setup_finished
1542.Lgpr_setup_finished:
1543 add x9, xIBASE, #1 // shorty + 1 ; ie skip return arg character
1544 mov x12, #0 // reset counter
1545 LOOP_OVER_SHORTY_STORING_FPS d0, s0, x9, x12, x10, .Lxmm_setup_finished
1546 LOOP_OVER_SHORTY_STORING_FPS d1, s1, x9, x12, x10, .Lxmm_setup_finished
1547 LOOP_OVER_SHORTY_STORING_FPS d2, s2, x9, x12, x10, .Lxmm_setup_finished
1548 LOOP_OVER_SHORTY_STORING_FPS d3, s3, x9, x12, x10, .Lxmm_setup_finished
1549 LOOP_OVER_SHORTY_STORING_FPS d4, s4, x9, x12, x10, .Lxmm_setup_finished
1550 LOOP_OVER_SHORTY_STORING_FPS d5, s5, x9, x12, x10, .Lxmm_setup_finished
1551 LOOP_OVER_SHORTY_STORING_FPS d6, s6, x9, x12, x10, .Lxmm_setup_finished
1552 LOOP_OVER_SHORTY_STORING_FPS d7, s7, x9, x12, x10, .Lxmm_setup_finished
1553 LOOP_OVER_FPs x9, x12, x10, x13, .Lxmm_setup_finished
1554.Lxmm_setup_finished:
1555 // Set the dex pc pointer.
1556 add xPC, xPC, #CODE_ITEM_INSNS_OFFSET
1557 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
1558
1559 // Set rIBASE
1560 adr xIBASE, artNterpAsmInstructionStart
1561 /* start executing the instruction at xPC */
1562 START_EXECUTING_INSTRUCTIONS
1563 /* NOTE: no fallthrough */
1564 // cfi info continues, and covers the whole nterp implementation.
1565 SIZE ExecuteNterpImpl
1566
1567%def opcode_pre():
1568
1569%def helpers():
1570
1571%def footer():
1572/*
1573 * ===========================================================================
1574 * Common subroutines and data
1575 * ===========================================================================
1576 */
1577
1578 .text
1579 .align 2
1580
1581// Note: mterp also uses the common_* names below for helpers, but that's OK
1582// as the C compiler compiled each interpreter separately.
1583common_errDivideByZero:
1584 EXPORT_PC
1585 bl art_quick_throw_div_zero
1586
1587// Expect array in w0, index in w1, length in w2
1588common_errArrayIndex:
1589 EXPORT_PC
1590 mov x0, x1
1591 mov x1, x3
1592 bl art_quick_throw_array_bounds
1593
1594common_errNullObject:
1595 EXPORT_PC
1596 bl art_quick_throw_null_pointer_exception
1597
1598NterpCommonInvokeStatic:
1599 COMMON_INVOKE_NON_RANGE is_static=1, suffix="invokeStatic"
1600
1601NterpCommonInvokeStaticRange:
1602 COMMON_INVOKE_RANGE is_static=1, suffix="invokeStatic"
1603
1604NterpCommonInvokeInstance:
1605 COMMON_INVOKE_NON_RANGE suffix="invokeInstance"
1606
1607NterpCommonInvokeInstanceRange:
1608 COMMON_INVOKE_RANGE suffix="invokeInstance"
1609
1610NterpCommonInvokeInterface:
1611 COMMON_INVOKE_NON_RANGE is_interface=1, suffix="invokeInterface"
1612
1613NterpCommonInvokeInterfaceRange:
1614 COMMON_INVOKE_RANGE is_interface=1, suffix="invokeInterface"
1615
1616NterpCommonInvokePolymorphic:
1617 COMMON_INVOKE_NON_RANGE is_polymorphic=1, suffix="invokePolymorphic"
1618
1619NterpCommonInvokePolymorphicRange:
1620 COMMON_INVOKE_RANGE is_polymorphic=1, suffix="invokePolymorphic"
1621
1622NterpCommonInvokeCustom:
1623 COMMON_INVOKE_NON_RANGE is_static=1, is_custom=1, suffix="invokeCustom"
1624
1625NterpCommonInvokeCustomRange:
1626 COMMON_INVOKE_RANGE is_static=1, is_custom=1, suffix="invokeCustom"
1627
1628NterpHandleStringInit:
1629 COMMON_INVOKE_NON_RANGE is_string_init=1, suffix="stringInit"
1630
1631NterpHandleStringInitRange:
1632 COMMON_INVOKE_RANGE is_string_init=1, suffix="stringInit"
1633
1634NterpNewInstance:
1635 EXPORT_PC
1636 // Fast-path which gets the class from thread-local cache.
1637 FETCH_FROM_THREAD_CACHE x0, 2f
1638 cbnz wMR, 3f
16394:
1640 ldr lr, [xSELF, #THREAD_ALLOC_OBJECT_ENTRYPOINT_OFFSET]
1641 blr lr
16421:
1643 lsr w1, wINST, #8 // w1 <- A
1644 SET_VREG_OBJECT w0, w1 // fp[A] <- value
1645 FETCH_ADVANCE_INST 2
1646 GET_INST_OPCODE ip
1647 GOTO_OPCODE ip
16482:
1649 mov x0, xSELF
1650 ldr x1, [sp]
1651 mov x2, xPC
1652 bl nterp_get_class_or_allocate_object
1653 b 1b
16543:
1655 bl art_quick_read_barrier_mark_reg00
1656 b 4b
1657
1658NterpNewArray:
1659 /* new-array vA, vB, class@CCCC */
1660 EXPORT_PC
1661 // Fast-path which gets the class from thread-local cache.
1662 FETCH_FROM_THREAD_CACHE x0, 2f
1663 cbnz wMR, 3f
16641:
1665 lsr w1, wINST, #12 // w1<- B
1666 GET_VREG w1, w1 // w1<- vB (array length)
1667 ldr lr, [xSELF, #THREAD_ALLOC_ARRAY_ENTRYPOINT_OFFSET]
1668 blr lr
1669 ubfx w1, wINST, #8, #4 // w1<- A
1670 SET_VREG_OBJECT w0, w1
1671 FETCH_ADVANCE_INST 2
1672 GET_INST_OPCODE ip
1673 GOTO_OPCODE ip
16742:
1675 mov x0, xSELF
1676 ldr x1, [sp, 0]
1677 mov x2, xPC
1678 bl nterp_get_class_or_allocate_object
1679 b 1b
16803:
1681 bl art_quick_read_barrier_mark_reg00
1682 b 1b
1683
1684NterpPutObjectInstanceField:
1685 // Fast-path which gets the field from thread-local cache.
1686 FETCH_FROM_THREAD_CACHE x0, 3f
16871:
1688 ubfx w1, wINST, #8, #4 // w1<- A
1689 lsr w2, wINST, #12 // w2<- B
1690 GET_VREG w2, w2 // vB (object we're operating on)
1691 cbz w2, common_errNullObject // is object null?
1692 GET_VREG w1, w1 // w1 <- v[A]
1693 str w1, [x2, x0]
1694 cbz w1, 2f
1695 ldr x1, [xSELF, #THREAD_CARD_TABLE_OFFSET]
1696 lsr w3, w2, #CARD_TABLE_CARD_SHIFT
1697 strb w1, [x1, x3]
16982:
1699 FETCH_ADVANCE_INST 2
1700 GET_INST_OPCODE ip
1701 GOTO_OPCODE ip
17023:
1703 mov x0, xSELF
1704 ldr x1, [sp]
1705 mov x2, xPC
1706 EXPORT_PC
1707 bl nterp_get_instance_field_offset
1708 tbz w0, #31, 1b
1709 CLEAR_INSTANCE_VOLATILE_MARKER w0
1710 ubfx w1, wINST, #8, #4 // w1<- A
1711 lsr w2, wINST, #12 // w2<- B
1712 GET_VREG w2, w2 // vB (object we're operating on)
1713 cbz w2, common_errNullObject // is object null?
1714 GET_VREG w1, w1 // w1 <- v[A]
1715 add x3, x2, x0
1716 stlr w1, [x3]
1717 cbz w1, 2b
1718 ldr x1, [xSELF, #THREAD_CARD_TABLE_OFFSET]
1719 lsr w3, w2, #CARD_TABLE_CARD_SHIFT
1720 strb w1, [x1, x3]
1721 b 2b
1722
1723NterpGetObjectInstanceField:
1724 // Fast-path which gets the field from thread-local cache.
1725 FETCH_FROM_THREAD_CACHE x0, 4f
17261:
1727 ubfx w1, wINST, #8, #4 // w1<- A
1728 lsr w2, wINST, #12 // w2<- B
1729 GET_VREG w2, w2 // vB (object we're operating on)
1730 cbz w2, common_errNullObject
1731 ldr w0, [x2, x0]
1732 cbnz wMR, 3f
17332:
1734 SET_VREG_OBJECT w0, w1 // fp[A] <- value
1735 FETCH_ADVANCE_INST 2
1736 GET_INST_OPCODE ip
1737 GOTO_OPCODE ip
17383:
1739 bl art_quick_read_barrier_mark_reg00
1740 b 2b
17414:
1742 mov x0, xSELF
1743 ldr x1, [sp]
1744 mov x2, xPC
1745 EXPORT_PC
1746 bl nterp_get_instance_field_offset
1747 tbz w0, #31, 1b
1748 CLEAR_INSTANCE_VOLATILE_MARKER w0
1749 ubfx w1, wINST, #8, #4 // w1<- A
1750 lsr w2, wINST, #12 // w2<- B
1751 GET_VREG w2, w2 // vB (object we're operating on)
1752 cbz w2, common_errNullObject
1753 add x2, x2, x0
1754 ldar w0, [x2]
1755 cbnz wMR, 6f
17565:
1757 SET_VREG_OBJECT w0, w1 // fp[A] <- value
1758 FETCH_ADVANCE_INST 2
1759 GET_INST_OPCODE ip
1760 GOTO_OPCODE ip
17616:
1762 bl art_quick_read_barrier_mark_reg00
1763 b 5b
1764
1765NterpPutObjectStaticField:
1766 // Fast-path which gets the field from thread-local cache.
1767 FETCH_FROM_THREAD_CACHE x0, 5f
17681:
1769 ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
1770 ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
1771 cbnz wMR, 4f
17722:
1773 lsr w2, wINST, #8 // w2 <- A
1774 GET_VREG w2, w2
1775 str w2, [x0, x1]
1776 cbz w2, 3f
1777 ldr x1, [xSELF, #THREAD_CARD_TABLE_OFFSET]
1778 lsr w3, w0, #CARD_TABLE_CARD_SHIFT
1779 strb w1, [x1, x3]
17803:
1781 FETCH_ADVANCE_INST 2
1782 GET_INST_OPCODE ip
1783 GOTO_OPCODE ip
17844:
1785 bl art_quick_read_barrier_mark_reg00
1786 b 2b
17875:
1788 mov x0, xSELF
1789 ldr x1, [sp]
1790 mov x2, xPC
1791 EXPORT_PC
1792 bl nterp_get_static_field
1793 tbz x0, #0, 1b
1794 CLEAR_STATIC_VOLATILE_MARKER x0
1795 ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
1796 ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
1797 cbnz wMR, 7f
17986:
1799 lsr w2, wINST, #8 // w1 <- A
1800 GET_VREG w2, w2
1801 add ip, x0, x1
1802 stlr w2, [ip]
1803 cbz w2, 3b
1804 ldr x1, [xSELF, #THREAD_CARD_TABLE_OFFSET]
1805 lsr w3, w0, #CARD_TABLE_CARD_SHIFT
1806 strb w1, [x1, x3]
1807 b 3b
18087:
1809 bl art_quick_read_barrier_mark_reg00
1810 b 6b
1811
1812NterpGetObjectStaticField:
1813 // Fast-path which gets the field from thread-local cache.
1814 FETCH_FROM_THREAD_CACHE x0, 4f
18151:
1816 ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
1817 ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
1818 cbnz wMR, 3f
1819 ldr w0, [x0, x1]
1820 // No need to check the marking register, we know it's not set here.
18212:
1822 lsr w1, wINST, #8 // w1 <- A
1823 SET_VREG_OBJECT w0, w1 // fp[A] <- value
1824 FETCH_ADVANCE_INST 2
1825 GET_INST_OPCODE ip
1826 GOTO_OPCODE ip
18273:
1828 bl art_quick_read_barrier_mark_reg00
1829 ldr w0, [x0, x1]
1830 // Here, we know the marking register is set.
1831 bl art_quick_read_barrier_mark_reg00
1832 b 2b
18334:
1834 mov x0, xSELF
1835 ldr x1, [sp]
1836 mov x2, xPC
1837 EXPORT_PC
1838 bl nterp_get_static_field
1839 tbz x0, #0, 1b
1840 CLEAR_STATIC_VOLATILE_MARKER x0
1841 ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
1842 ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
1843 cbnz wMR, 7f
18445:
1845 add x0, x0, x1
1846 ldar w0, [x0]
1847 cbnz wMR, 8f
18486:
1849 lsr w1, wINST, #8 // w1 <- A
1850 SET_VREG_OBJECT w0, w1 // fp[A] <- value
1851 FETCH_ADVANCE_INST 2
1852 GET_INST_OPCODE ip
1853 GOTO_OPCODE ip
18547:
1855 bl art_quick_read_barrier_mark_reg00
1856 b 5b
18578:
1858 bl art_quick_read_barrier_mark_reg00
1859 b 6b
1860
1861NterpGetBooleanStaticField:
1862 OP_SGET load="ldrb", volatile_load="ldarb", maybe_extend="", wide=0
1863
1864NterpGetByteStaticField:
1865 OP_SGET load="ldrsb", volatile_load="ldarb", maybe_extend="sbfx w0, w0, #0, #8", wide=0
1866
1867NterpGetCharStaticField:
1868 OP_SGET load="ldrh", volatile_load="ldarh", maybe_extend="", wide=0
1869
1870NterpGetShortStaticField:
1871 OP_SGET load="ldrsh", volatile_load="ldarh", maybe_extend="sbfx w0, w0, #0, #16", wide=0
1872
1873NterpGetWideStaticField:
1874 OP_SGET load="ldr", volatile_load="ldar", maybe_extend="", wide=1
1875
1876NterpGetIntStaticField:
1877 OP_SGET load="ldr", volatile_load="ldar", maybe_extend="", wide=0
1878
1879NterpPutStaticField:
1880 OP_SPUT store="str", volatile_store="stlr", wide=0
1881
1882NterpPutBooleanStaticField:
1883NterpPutByteStaticField:
1884 OP_SPUT store="strb", volatile_store="stlrb", wide=0
1885
1886NterpPutCharStaticField:
1887NterpPutShortStaticField:
1888 OP_SPUT store="strh", volatile_store="stlrh", wide=0
1889
1890NterpPutWideStaticField:
1891 OP_SPUT store="str", volatile_store="stlr", wide=1
1892
1893NterpPutInstanceField:
1894 OP_IPUT store="str", volatile_store="stlr", wide=0
1895
1896NterpPutBooleanInstanceField:
1897NterpPutByteInstanceField:
1898 OP_IPUT store="strb", volatile_store="stlrb", wide=0
1899
1900NterpPutCharInstanceField:
1901NterpPutShortInstanceField:
1902 OP_IPUT store="strh", volatile_store="stlrh", wide=0
1903
1904NterpPutWideInstanceField:
1905 OP_IPUT store="str", volatile_store="stlr", wide=1
1906
1907NterpGetBooleanInstanceField:
1908 OP_IGET load="ldrb", volatile_load="ldarb", maybe_extend="", wide=0
1909
1910NterpGetByteInstanceField:
1911 OP_IGET load="ldrsb", volatile_load="ldarb", maybe_extend="sbfx w0, w0, #0, #8", wide=0
1912
1913NterpGetCharInstanceField:
1914 OP_IGET load="ldrh", volatile_load="ldarh", maybe_extend="", wide=0
1915
1916NterpGetShortInstanceField:
1917 OP_IGET load="ldrsh", volatile_load="ldarh", maybe_extend="sbfx w0, w0, #0, #16", wide=0
1918
1919NterpGetWideInstanceField:
1920 OP_IGET load="ldr", volatile_load="ldar", maybe_extend="", wide=1
1921
1922NterpGetInstanceField:
1923 OP_IGET load="ldr", volatile_load="ldar", maybe_extend="", wide=0
1924
1925NterpInstanceOf:
1926 /* instance-of vA, vB, class@CCCC */
1927 // Fast-path which gets the class from thread-local cache.
1928 EXPORT_PC
1929 FETCH_FROM_THREAD_CACHE x1, 3f
1930 cbnz wMR, 4f
19311:
1932 lsr w2, wINST, #12 // w2<- B
1933 GET_VREG w0, w2 // w0<- vB (object)
1934 cbz w0, 2f
1935 bl artInstanceOfFromCode
19362:
1937 ubfx w1, wINST, #8, #4 // w1<- A
1938 SET_VREG w0, w1
1939 FETCH_ADVANCE_INST 2
1940 GET_INST_OPCODE ip
1941 GOTO_OPCODE ip
19423:
1943 mov x0, xSELF
1944 ldr x1, [sp]
1945 mov x2, xPC
1946 bl nterp_get_class_or_allocate_object
1947 mov x1, x0
1948 b 1b
19494:
1950 bl art_quick_read_barrier_mark_reg01
1951 b 1b
1952
1953NterpCheckCast:
1954 // Fast-path which gets the class from thread-local cache.
1955 EXPORT_PC
1956 FETCH_FROM_THREAD_CACHE x1, 3f
1957 cbnz wMR, 4f
19581:
1959 lsr w2, wINST, #8 // w2<- A
1960 GET_VREG w0, w2 // w2<- vA (object)
1961 cbz w0, 2f
1962 bl art_quick_check_instance_of
19632:
1964 FETCH_ADVANCE_INST 2
1965 GET_INST_OPCODE ip
1966 GOTO_OPCODE ip
19673:
1968 mov x0, xSELF
1969 ldr x1, [sp]
1970 mov x2, xPC
1971 bl nterp_get_class_or_allocate_object
1972 mov x1, x0
1973 b 1b
19744:
1975 bl art_quick_read_barrier_mark_reg01
1976 b 1b
1977
1978NterpHandleHotnessOverflow:
1979 add x1, xPC, xINST, lsl #1
1980 mov x2, xFP
1981 bl nterp_hot_method
1982 cbnz x0, 1f
1983 add w2, wINST, wINST // w2<- byte offset
1984 FETCH_ADVANCE_INST_RB w2 // update xPC, load wINST
1985 GET_INST_OPCODE ip // extract opcode from wINST
1986 GOTO_OPCODE ip // jump to next instruction
19871:
1988 // Drop the current frame.
1989 ldr ip, [xREFS, #-8]
1990 mov sp, ip
1991 .cfi_def_cfa sp, CALLEE_SAVES_SIZE
1992
1993 // The transition frame of type SaveAllCalleeSaves saves x19 and x20,
1994 // but not managed ABI. So we need to restore callee-saves of the nterp frame,
1995 // and save managed ABI callee saves, which will be restored by the callee upon
1996 // return.
1997 RESTORE_ALL_CALLEE_SAVES
1998 INCREASE_FRAME ((CALLEE_SAVES_SIZE) - 16)
1999
2000 // FP callee-saves
2001 stp d8, d9, [sp, #0]
2002 stp d10, d11, [sp, #16]
2003 stp d12, d13, [sp, #32]
2004 stp d14, d15, [sp, #48]
2005
2006 // GP callee-saves.
2007 SAVE_TWO_REGS x21, x22, 64
2008 SAVE_TWO_REGS x23, x24, 80
2009 SAVE_TWO_REGS x25, x26, 96
2010 SAVE_TWO_REGS x27, x28, 112
2011 SAVE_TWO_REGS x29, lr, 128
2012
2013 // Setup the new frame
2014 ldr x1, [x0, #OSR_DATA_FRAME_SIZE]
2015 // Given stack size contains all callee saved registers, remove them.
2016 sub x1, x1, #(CALLEE_SAVES_SIZE - 16)
2017
2018 // We know x1 cannot be 0, as it at least contains the ArtMethod.
2019
2020 // Remember CFA in a callee-save register.
2021 mov xINST, sp
2022 .cfi_def_cfa_register xINST
2023
2024 sub sp, sp, x1
2025
2026 add x2, x0, #OSR_DATA_MEMORY
20272:
2028 sub x1, x1, #8
2029 ldr ip, [x2, x1]
2030 str ip, [sp, x1]
2031 cbnz x1, 2b
2032
2033 // Fetch the native PC to jump to and save it in a callee-save register.
2034 ldr xFP, [x0, #OSR_DATA_NATIVE_PC]
2035
2036 // Free the memory holding OSR Data.
2037 bl free
2038
2039 // Jump to the compiled code.
2040 br xFP
2041
2042NterpHandleInvokeInterfaceOnObjectMethodRange:
2043 // First argument is the 'this' pointer.
2044 FETCH w1, 2
2045 GET_VREG w1, w1
2046 // Note: x1 is null, this will be handled by our SIGSEGV handler.
2047 ldr w2, [x1, #MIRROR_OBJECT_CLASS_OFFSET]
2048 add w2, w2, #MIRROR_CLASS_VTABLE_OFFSET_64
2049 ldr x0, [x2, w0, sxtw #3]
2050 b NterpCommonInvokeInstanceRange
2051
2052NterpHandleInvokeInterfaceOnObjectMethod:
2053 // First argument is the 'this' pointer.
2054 FETCH w1, 2
2055 and w1, w1, #0xf
2056 GET_VREG w1, w1
2057 // Note: x1 is null, this will be handled by our SIGSEGV handler.
2058 ldr w2, [x1, #MIRROR_OBJECT_CLASS_OFFSET]
2059 add w2, w2, #MIRROR_CLASS_VTABLE_OFFSET_64
2060 ldr x0, [x2, w0, sxtw #3]
2061 b NterpCommonInvokeInstance
2062
2063// This is the logical end of ExecuteNterpImpl, where the frame info applies.
2064// EndExecuteNterpImpl includes the methods below as we want the runtime to
2065// see them as part of the Nterp PCs.
2066.cfi_endproc
2067
2068nterp_to_nterp_static_non_range:
2069 .cfi_startproc
2070 SETUP_STACK_FOR_INVOKE
2071 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=1, is_string_init=0
2072 .cfi_endproc
2073
2074nterp_to_nterp_string_init_non_range:
2075 .cfi_startproc
2076 SETUP_STACK_FOR_INVOKE
2077 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1
2078 .cfi_endproc
2079
2080nterp_to_nterp_instance_non_range:
2081 .cfi_startproc
2082 SETUP_STACK_FOR_INVOKE
2083 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0
2084 .cfi_endproc
2085
2086nterp_to_nterp_static_range:
2087 .cfi_startproc
2088 SETUP_STACK_FOR_INVOKE
2089 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=1
2090 .cfi_endproc
2091
2092nterp_to_nterp_instance_range:
2093 .cfi_startproc
2094 SETUP_STACK_FOR_INVOKE
2095 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0
2096 .cfi_endproc
2097
2098nterp_to_nterp_string_init_range:
2099 .cfi_startproc
2100 SETUP_STACK_FOR_INVOKE
2101 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1
2102 .cfi_endproc
2103
2104// This is the end of PCs contained by the OatQuickMethodHeader created for the interpreter
2105// entry point.
2106 .type EndExecuteNterpImpl, #function
2107 .hidden EndExecuteNterpImpl
2108 .global EndExecuteNterpImpl
2109EndExecuteNterpImpl:
2110
2111// Entrypoints into runtime.
2112NTERP_TRAMPOLINE nterp_get_static_field, NterpGetStaticField
2113NTERP_TRAMPOLINE nterp_get_instance_field_offset, NterpGetInstanceFieldOffset
2114NTERP_TRAMPOLINE nterp_filled_new_array, NterpFilledNewArray
2115NTERP_TRAMPOLINE nterp_filled_new_array_range, NterpFilledNewArrayRange
2116NTERP_TRAMPOLINE nterp_get_class_or_allocate_object, NterpGetClassOrAllocateObject
2117NTERP_TRAMPOLINE nterp_get_method, NterpGetMethod
2118NTERP_TRAMPOLINE nterp_hot_method, NterpHotMethod
2119NTERP_TRAMPOLINE nterp_load_object, NterpLoadObject
2120
2121// gen_mterp.py will inline the following definitions
2122// within [ExecuteNterpImpl, EndExecuteNterpImpl).
2123%def instruction_end():
2124
2125 .type artNterpAsmInstructionEnd, #function
2126 .hidden artNterpAsmInstructionEnd
2127 .global artNterpAsmInstructionEnd
2128artNterpAsmInstructionEnd:
2129 // artNterpAsmInstructionEnd is used as landing pad for exception handling.
2130 FETCH_INST
2131 GET_INST_OPCODE ip
2132 GOTO_OPCODE ip
2133
2134%def instruction_start():
2135
2136 .type artNterpAsmInstructionStart, #function
2137 .hidden artNterpAsmInstructionStart
2138 .global artNterpAsmInstructionStart
2139artNterpAsmInstructionStart = .L_op_nop
2140 .text
2141
2142%def opcode_start():
2143 NAME_START nterp_${opcode}
2144%def opcode_end():
2145 NAME_END nterp_${opcode}
2146%def helper_start(name):
2147 NAME_START ${name}
2148%def helper_end(name):
2149 NAME_END ${name}