1*795d594fSAndroid Build Coastguard Worker// Theory of operation. These invoke-X opcodes bounce to code labels in main.S which attempt a 2*795d594fSAndroid Build Coastguard Worker// variety of fast paths; the full asm doesn't fit in the per-opcode handler's size limit. 3*795d594fSAndroid Build Coastguard Worker// 4*795d594fSAndroid Build Coastguard Worker// Calling convention. There are three argument transfer types. 5*795d594fSAndroid Build Coastguard Worker// (A) Managed ABI -> Nterp. The ExecuteNterpImpl handles this case. We set up a fresh nterp frame 6*795d594fSAndroid Build Coastguard Worker// and move arguments from machine arg registers (and sometimes stack) into the frame. 7*795d594fSAndroid Build Coastguard Worker// (B) Nterp -> Nterp. An invoke op's fast path handles this case. If we can stay in nterp, then 8*795d594fSAndroid Build Coastguard Worker// we set up a fresh nterp frame, and copy the register slots from caller to callee. 9*795d594fSAndroid Build Coastguard Worker// (C) Nterp -> Managed ABI. Invoke op's remaining cases. To leave nterp, we read out arguments from 10*795d594fSAndroid Build Coastguard Worker// the caller's nterp frame and place them into machine arg registers (and sometimes stack). 11*795d594fSAndroid Build Coastguard Worker// Doing so requires obtaining and deciphering the method's shorty for arg type, width, and 12*795d594fSAndroid Build Coastguard Worker// order info. 13*795d594fSAndroid Build Coastguard Worker// 14*795d594fSAndroid Build Coastguard Worker// Fast path structure. 15*795d594fSAndroid Build Coastguard Worker// (0) If the next method's "quick code" is nterp, then set up a fresh nterp frame and perform a 16*795d594fSAndroid Build Coastguard Worker// vreg->vreg transfer. Jump to handler for the next method's first opcode. 17*795d594fSAndroid Build Coastguard Worker// - The following paths leave nterp. - 18*795d594fSAndroid Build Coastguard Worker// (1) If the next method is guaranteed to be only object refs, then the managed ABI is very simple: 19*795d594fSAndroid Build Coastguard Worker// just place all arguments in the native arg registers using LWU. Call the quick code. 20*795d594fSAndroid Build Coastguard Worker// (2) The next method might have an arg/return shape that can avoid the shorty, or at least avoid 21*795d594fSAndroid Build Coastguard Worker// most complications of the managed ABI arg setup. 22*795d594fSAndroid Build Coastguard Worker// (2.1) If the next method has 0 args, then peek ahead in dex: if no scalar return, then call the 23*795d594fSAndroid Build Coastguard Worker// quick code. (Even when the next opcode is move-result-object, nterp will expect the 24*795d594fSAndroid Build Coastguard Worker// reference at a0, matching where the managed ABI leaves it after the call.) 25*795d594fSAndroid Build Coastguard Worker// (2.2) If the next method has 0 args and scalar return, or has 1 arg, then obtain the shorty. 26*795d594fSAndroid Build Coastguard Worker// (2.2.1) Post-shorty: if 0 args, call the quick code. (After the call, a returned float must be 27*795d594fSAndroid Build Coastguard Worker// copied from fa0 into a0.) 28*795d594fSAndroid Build Coastguard Worker// (2.2.2) Post-shorty: check the arg's shorty type. If 'L', we must load it with LWU. Otherwise, we 29*795d594fSAndroid Build Coastguard Worker// load it with LW and store a copy into FA0 (to avoid another branch). Call the quick code. 30*795d594fSAndroid Build Coastguard Worker// - The fully pessimistic case. - 31*795d594fSAndroid Build Coastguard Worker// (3) The next method has 2+ arguments with a mix of float/double/long, OR it is polymorphic OR 32*795d594fSAndroid Build Coastguard Worker// custom. Obtain the shorty and perform the full setup for managed ABI. Polymorphic and 33*795d594fSAndroid Build Coastguard Worker// custom invokes are specially shunted to the runtime. Otherwise we call the quick code. 34*795d594fSAndroid Build Coastguard Worker// 35*795d594fSAndroid Build Coastguard Worker// Code organization. These functions are organized in a three tier structure to aid readability. 36*795d594fSAndroid Build Coastguard Worker// (P) The "front end" is an opcode handler, such as op_invoke_virtual(). They are defined in 37*795d594fSAndroid Build Coastguard Worker// invoke.S. Since all the invoke code cannot fit in the allotted handler region, every invoke 38*795d594fSAndroid Build Coastguard Worker// handler has code extending into a "back end". 39*795d594fSAndroid Build Coastguard Worker// (Q) The opcode handler calls a "back end" label that is located in main.S. The code for that 40*795d594fSAndroid Build Coastguard Worker// label is defined in invoke.S. As a convention, the label in main.S is NterpInvokeVirtual. The 41*795d594fSAndroid Build Coastguard Worker// code in invoke.S is nterp_invoke_virtual(). 42*795d594fSAndroid Build Coastguard Worker// (R) For the Nterp to Nterp fast path case, the back end calls a label located in main.S, the code 43*795d594fSAndroid Build Coastguard Worker// for which is defined in invoke.S. As a convention, the label in main.S is 44*795d594fSAndroid Build Coastguard Worker// NterpToNterpInstance, and the code in invoke.S is nterp_to_nterp_instance(). 45*795d594fSAndroid Build Coastguard Worker// Helpers for each tier are placed just after the functions of each tier. 46*795d594fSAndroid Build Coastguard Worker 47*795d594fSAndroid Build Coastguard Worker// 48*795d594fSAndroid Build Coastguard Worker// invoke-kind {vC, vD, vE, vF, vG}, meth@BBBB 49*795d594fSAndroid Build Coastguard Worker// Format 35c: A|G|op BBBB F|E|D|C 50*795d594fSAndroid Build Coastguard Worker// 51*795d594fSAndroid Build Coastguard Worker 52*795d594fSAndroid Build Coastguard Worker// invoke-virtual {vC, vD, vE, vF, vG}, meth@BBBB 53*795d594fSAndroid Build Coastguard Worker// Format 35c: A|G|6e BBBB F|E|D|C 54*795d594fSAndroid Build Coastguard Worker// 55*795d594fSAndroid Build Coastguard Worker// Note: invoke-virtual is used to invoke a normal virtual method (a method that is not private, 56*795d594fSAndroid Build Coastguard Worker// static, or final, and is also not a constructor). 57*795d594fSAndroid Build Coastguard Worker%def op_invoke_virtual(range=""): 58*795d594fSAndroid Build Coastguard Worker EXPORT_PC 59*795d594fSAndroid Build Coastguard Worker FETCH s7, count=2 // s7 := F|E|D|C or CCCC (range) 60*795d594fSAndroid Build Coastguard Worker FETCH_FROM_THREAD_CACHE a0, /*slow path*/2f, t0, t1 61*795d594fSAndroid Build Coastguard Worker // a0 := method idx of resolved virtual method 62*795d594fSAndroid Build Coastguard Worker1: 63*795d594fSAndroid Build Coastguard Worker% fetch_receiver(reg="a1", vreg="s7", range=range) 64*795d594fSAndroid Build Coastguard Worker // a1 := fp[C] (this) 65*795d594fSAndroid Build Coastguard Worker // Note: null case handled by SEGV handler. 66*795d594fSAndroid Build Coastguard Worker lwu t0, MIRROR_OBJECT_CLASS_OFFSET(a1) 67*795d594fSAndroid Build Coastguard Worker // t0 := klass object (32-bit addr) 68*795d594fSAndroid Build Coastguard Worker UNPOISON_HEAP_REF t0 69*795d594fSAndroid Build Coastguard Worker // Entry address = entry's byte offset in vtable + vtable's byte offset in klass object. 70*795d594fSAndroid Build Coastguard Worker sh3add a0, a0, t0 // a0 := entry's byte offset 71*795d594fSAndroid Build Coastguard Worker ld a0, MIRROR_CLASS_VTABLE_OFFSET_64(a0) 72*795d594fSAndroid Build Coastguard Worker // a0 := ArtMethod* 73*795d594fSAndroid Build Coastguard Worker tail NterpInvokeVirtual${range} // args a0, a1, s7 74*795d594fSAndroid Build Coastguard Worker2: 75*795d594fSAndroid Build Coastguard Worker% resolve_method_into_a0() 76*795d594fSAndroid Build Coastguard Worker j 1b 77*795d594fSAndroid Build Coastguard Worker 78*795d594fSAndroid Build Coastguard Worker 79*795d594fSAndroid Build Coastguard Worker// invoke-super {vC, vD, vE, vF, vG}, meth@BBBB 80*795d594fSAndroid Build Coastguard Worker// Format 35c: A|G|6f BBBB F|E|D|C 81*795d594fSAndroid Build Coastguard Worker// 82*795d594fSAndroid Build Coastguard Worker// Note: When the method_id references a method of a non-interface class, invoke-super is used to 83*795d594fSAndroid Build Coastguard Worker// invoke the closest superclass's virtual method (as opposed to the one with the same method_id in 84*795d594fSAndroid Build Coastguard Worker// the calling class). 85*795d594fSAndroid Build Coastguard Worker// Note: In Dex files version 037 or later, if the method_id refers to an interface method, 86*795d594fSAndroid Build Coastguard Worker// invoke-super is used to invoke the most specific, non-overridden version of that method defined 87*795d594fSAndroid Build Coastguard Worker// on that interface. The same method restrictions hold as for invoke-virtual. In Dex files prior to 88*795d594fSAndroid Build Coastguard Worker// version 037, having an interface method_id is illegal and undefined. 89*795d594fSAndroid Build Coastguard Worker%def op_invoke_super(range=""): 90*795d594fSAndroid Build Coastguard Worker EXPORT_PC 91*795d594fSAndroid Build Coastguard Worker FETCH s7, count=2 // s7 := F|E|D|C or CCCC (range) 92*795d594fSAndroid Build Coastguard Worker FETCH_FROM_THREAD_CACHE a0, /*slow path*/2f, t0, t1 93*795d594fSAndroid Build Coastguard Worker // a0 := ArtMethod* 94*795d594fSAndroid Build Coastguard Worker1: 95*795d594fSAndroid Build Coastguard Worker% fetch_receiver(reg="a1", vreg="s7", range=range) 96*795d594fSAndroid Build Coastguard Worker // a1 := fp[C] (this) 97*795d594fSAndroid Build Coastguard Worker beqz a1, 3f // throw if null 98*795d594fSAndroid Build Coastguard Worker tail NterpInvokeSuper${range} // args a0, a1, s7 99*795d594fSAndroid Build Coastguard Worker2: 100*795d594fSAndroid Build Coastguard Worker% resolve_method_into_a0() 101*795d594fSAndroid Build Coastguard Worker j 1b 102*795d594fSAndroid Build Coastguard Worker3: 103*795d594fSAndroid Build Coastguard Worker tail common_errNullObject 104*795d594fSAndroid Build Coastguard Worker 105*795d594fSAndroid Build Coastguard Worker 106*795d594fSAndroid Build Coastguard Worker// invoke-direct {vC, vD, vE, vF, vG}, meth@BBBB 107*795d594fSAndroid Build Coastguard Worker// Format 35c: A|G|70 BBBB F|E|D|C 108*795d594fSAndroid Build Coastguard Worker// 109*795d594fSAndroid Build Coastguard Worker// Note: invoke-direct is used to invoke a non-static direct method (that is, an instance method 110*795d594fSAndroid Build Coastguard Worker// that is by its nature non-overridable, namely either a private instance method or a constructor). 111*795d594fSAndroid Build Coastguard Worker// 112*795d594fSAndroid Build Coastguard Worker// For additional context on string init, see b/28555675. The object reference is replaced after 113*795d594fSAndroid Build Coastguard Worker// the string factory call, so we disable thread-caching the resolution of string init, and skip 114*795d594fSAndroid Build Coastguard Worker// fast paths out to managed ABI calls. 115*795d594fSAndroid Build Coastguard Worker%def op_invoke_direct(range=""): 116*795d594fSAndroid Build Coastguard Worker EXPORT_PC 117*795d594fSAndroid Build Coastguard Worker FETCH s7, count=2 // s7 := F|E|D|C or CCCC (range) 118*795d594fSAndroid Build Coastguard Worker FETCH_FROM_THREAD_CACHE a0, /*slow path*/2f, t0, t1 119*795d594fSAndroid Build Coastguard Worker // a0 := ArtMethod*, never String.<init> 120*795d594fSAndroid Build Coastguard Worker1: 121*795d594fSAndroid Build Coastguard Worker% fetch_receiver(reg="a1", vreg="s7", range=range) 122*795d594fSAndroid Build Coastguard Worker // a1 := fp[C] (this) 123*795d594fSAndroid Build Coastguard Worker beqz a1, 3f // throw if null 124*795d594fSAndroid Build Coastguard Worker tail NterpInvokeDirect${range} // args a0, a1, s7 125*795d594fSAndroid Build Coastguard Worker2: 126*795d594fSAndroid Build Coastguard Worker% resolve_method_into_a0() # a0 := ArtMethod* or String.<init> 127*795d594fSAndroid Build Coastguard Worker and t0, a0, 0x1 // t0 := string-init bit 128*795d594fSAndroid Build Coastguard Worker beqz t0, 1b // not string init 129*795d594fSAndroid Build Coastguard Worker and a0, a0, ~0x1 // clear string-init bit 130*795d594fSAndroid Build Coastguard Worker tail NterpInvokeStringInit${range} // args a0, s7 131*795d594fSAndroid Build Coastguard Worker3: 132*795d594fSAndroid Build Coastguard Worker tail common_errNullObject 133*795d594fSAndroid Build Coastguard Worker 134*795d594fSAndroid Build Coastguard Worker 135*795d594fSAndroid Build Coastguard Worker// invoke-static {vC, vD, vE, vF, vG}, meth@BBBB 136*795d594fSAndroid Build Coastguard Worker// Format 35c: A|G|71 BBBB F|E|D|C 137*795d594fSAndroid Build Coastguard Worker// 138*795d594fSAndroid Build Coastguard Worker// Note: invoke-static is used to invoke a static method (which is always considered a direct 139*795d594fSAndroid Build Coastguard Worker// method). 140*795d594fSAndroid Build Coastguard Worker%def op_invoke_static(range=""): 141*795d594fSAndroid Build Coastguard Worker EXPORT_PC 142*795d594fSAndroid Build Coastguard Worker // TODO: Unnecessary if A=0, and unnecessary if nterp-to-nterp. 143*795d594fSAndroid Build Coastguard Worker FETCH s7, count=2 // s7 := F|E|D|C or CCCC (range) 144*795d594fSAndroid Build Coastguard Worker FETCH_FROM_THREAD_CACHE a0, /*slow path*/1f, t0, t1 145*795d594fSAndroid Build Coastguard Worker // a0 := ArtMethod* 146*795d594fSAndroid Build Coastguard Worker tail NterpInvokeStatic${range} // arg a0, s7 147*795d594fSAndroid Build Coastguard Worker1: 148*795d594fSAndroid Build Coastguard Worker% resolve_method_into_a0() 149*795d594fSAndroid Build Coastguard Worker tail NterpInvokeStatic${range} // arg a0, s7 150*795d594fSAndroid Build Coastguard Worker 151*795d594fSAndroid Build Coastguard Worker 152*795d594fSAndroid Build Coastguard Worker// invoke-interface {vC, vD, vE, vF, vG}, meth@BBBB 153*795d594fSAndroid Build Coastguard Worker// Format 35c: A|G|72 BBBB F|E|D|C 154*795d594fSAndroid Build Coastguard Worker// 155*795d594fSAndroid Build Coastguard Worker// Note: invoke-interface is used to invoke an interface method, that is, on an object whose 156*795d594fSAndroid Build Coastguard Worker// concrete class isn't known, using a method_id that refers to an interface. 157*795d594fSAndroid Build Coastguard Worker%def op_invoke_interface(range=""): 158*795d594fSAndroid Build Coastguard Worker EXPORT_PC 159*795d594fSAndroid Build Coastguard Worker FETCH s7, count=2 // s7 := F|E|D|C or CCCC (range) 160*795d594fSAndroid Build Coastguard Worker // T0 is eventually used to carry the "hidden argument" in the managed ABI. 161*795d594fSAndroid Build Coastguard Worker // This handler is tight on space, so we cache this arg in A0 and move it to T0 later. 162*795d594fSAndroid Build Coastguard Worker // Here, A0 is one of 163*795d594fSAndroid Build Coastguard Worker // (1) ArtMethod* 164*795d594fSAndroid Build Coastguard Worker // (2) ArtMethod* with LSB #1 set (default method) 165*795d594fSAndroid Build Coastguard Worker // (3) method index << 16 with LSB #0 set (j.l.Object method) 166*795d594fSAndroid Build Coastguard Worker FETCH_FROM_THREAD_CACHE a0, /*slow path*/5f, t0, t1 167*795d594fSAndroid Build Coastguard Worker1: 168*795d594fSAndroid Build Coastguard Worker% fetch_receiver(reg="a1", vreg="s7", range=range) 169*795d594fSAndroid Build Coastguard Worker // a1 := fp[C] (this) 170*795d594fSAndroid Build Coastguard Worker // Note: null case handled by SEGV handler. 171*795d594fSAndroid Build Coastguard Worker lwu t0, MIRROR_OBJECT_CLASS_OFFSET(a1) 172*795d594fSAndroid Build Coastguard Worker // t0 := klass object (32-bit addr) 173*795d594fSAndroid Build Coastguard Worker UNPOISON_HEAP_REF t0 174*795d594fSAndroid Build Coastguard Worker slliw t1, a0, 30 // test LSB #0 and #1 175*795d594fSAndroid Build Coastguard Worker bltz t1, 3f // LSB #1 is set; handle default method 176*795d594fSAndroid Build Coastguard Worker bgtz t1, 4f // LSB #0 is set; handle object method 177*795d594fSAndroid Build Coastguard Worker // no signal bits; it is a clean ArtMethod* 178*795d594fSAndroid Build Coastguard Worker lhu t1, ART_METHOD_IMT_INDEX_OFFSET(a0) 179*795d594fSAndroid Build Coastguard Worker // t1 := idx into interface method table (16-bit value) 180*795d594fSAndroid Build Coastguard Worker2: 181*795d594fSAndroid Build Coastguard Worker ld t0, MIRROR_CLASS_IMT_PTR_OFFSET_64(t0) 182*795d594fSAndroid Build Coastguard Worker // t0 := base address of imt 183*795d594fSAndroid Build Coastguard Worker sh3add t0, t1, t0 // t0 := entry's address in imt 184*795d594fSAndroid Build Coastguard Worker ld a2, (t0) // a2 := ArtMethod* 185*795d594fSAndroid Build Coastguard Worker tail NterpInvokeInterface${range} // a0 (hidden arg), a1 (this), a2 (ArtMethod*), s7 (vregs) 186*795d594fSAndroid Build Coastguard Worker3: 187*795d594fSAndroid Build Coastguard Worker andi a0, a0, ~2 // a0 := default ArtMethod*, LSB #1 cleared 188*795d594fSAndroid Build Coastguard Worker lhu t1, ART_METHOD_METHOD_INDEX_OFFSET(a0) 189*795d594fSAndroid Build Coastguard Worker // t1 := method_index_ (16-bit value) 190*795d594fSAndroid Build Coastguard Worker // Default methods have a contract with art::IMTable. 191*795d594fSAndroid Build Coastguard Worker andi t1, t1, ART_METHOD_IMT_MASK 192*795d594fSAndroid Build Coastguard Worker // t1 := idx into interface method table 193*795d594fSAndroid Build Coastguard Worker j 2b 194*795d594fSAndroid Build Coastguard Worker4: 195*795d594fSAndroid Build Coastguard Worker // Interface methods on j.l.Object have a contract with NterpGetMethod. 196*795d594fSAndroid Build Coastguard Worker srliw t1, a0, 16 // t3 := method index 197*795d594fSAndroid Build Coastguard Worker sh3add t0, t1, t0 // t0 := entry's byte offset, before vtable offset adjustment 198*795d594fSAndroid Build Coastguard Worker ld a0, MIRROR_CLASS_VTABLE_OFFSET_64(t0) 199*795d594fSAndroid Build Coastguard Worker tail NterpInvokeDirect${range} // args a0, a1, s7 200*795d594fSAndroid Build Coastguard Worker5: 201*795d594fSAndroid Build Coastguard Worker% resolve_method_into_a0() 202*795d594fSAndroid Build Coastguard Worker j 1b 203*795d594fSAndroid Build Coastguard Worker 204*795d594fSAndroid Build Coastguard Worker 205*795d594fSAndroid Build Coastguard Worker// 206*795d594fSAndroid Build Coastguard Worker// invoke-kind/range {vCCCC .. vNNNN}, meth@BBBB 207*795d594fSAndroid Build Coastguard Worker// Format 3rc: AA|op BBBB CCCC 208*795d594fSAndroid Build Coastguard Worker// where NNNN = CCCC + AA - 1, that is A determines the count 0..255, and C determines the first 209*795d594fSAndroid Build Coastguard Worker// register. 210*795d594fSAndroid Build Coastguard Worker// 211*795d594fSAndroid Build Coastguard Worker 212*795d594fSAndroid Build Coastguard Worker// invoke-virtual/range {vCCCC .. vNNNN}, meth@BBBB 213*795d594fSAndroid Build Coastguard Worker// Format 3rc: AA|74 BBBB CCCC 214*795d594fSAndroid Build Coastguard Worker// 215*795d594fSAndroid Build Coastguard Worker// Note: invoke-virtual/range is used to invoke a normal virtual method (a method that is not 216*795d594fSAndroid Build Coastguard Worker// private, static, or final, and is also not a constructor). 217*795d594fSAndroid Build Coastguard Worker%def op_invoke_virtual_range(): 218*795d594fSAndroid Build Coastguard Worker% op_invoke_virtual(range="Range") 219*795d594fSAndroid Build Coastguard Worker 220*795d594fSAndroid Build Coastguard Worker 221*795d594fSAndroid Build Coastguard Worker// invoke-super/range {vCCCC .. vNNNN}, meth@BBBB 222*795d594fSAndroid Build Coastguard Worker// Format 3rc: AA|75 BBBB CCCC 223*795d594fSAndroid Build Coastguard Worker// 224*795d594fSAndroid Build Coastguard Worker// Note: When the method_id references a method of a non-interface class, invoke-super/range is used 225*795d594fSAndroid Build Coastguard Worker// to invoke the closest superclass's virtual method (as opposed to the one with the same method_id 226*795d594fSAndroid Build Coastguard Worker// in the calling class). 227*795d594fSAndroid Build Coastguard Worker// Note: In Dex files version 037 or later, if the method_id refers to an interface method, 228*795d594fSAndroid Build Coastguard Worker// invoke-super/range is used to invoke the most specific, non-overridden version of that method 229*795d594fSAndroid Build Coastguard Worker// defined on that interface. In Dex files prior to version 037, having an interface method_id is 230*795d594fSAndroid Build Coastguard Worker// illegal and undefined. 231*795d594fSAndroid Build Coastguard Worker%def op_invoke_super_range(): 232*795d594fSAndroid Build Coastguard Worker% op_invoke_super(range="Range") 233*795d594fSAndroid Build Coastguard Worker 234*795d594fSAndroid Build Coastguard Worker 235*795d594fSAndroid Build Coastguard Worker// invoke-direct/range {vCCCC .. vNNNN}, meth@BBBB 236*795d594fSAndroid Build Coastguard Worker// Format 3rc: AA|76 BBBB CCCC 237*795d594fSAndroid Build Coastguard Worker// 238*795d594fSAndroid Build Coastguard Worker// Note: invoke-direct/range is used to invoke a non-static direct method (that is, an instance 239*795d594fSAndroid Build Coastguard Worker// method that is by its nature non-overridable, namely either a private instance method or a 240*795d594fSAndroid Build Coastguard Worker// constructor). 241*795d594fSAndroid Build Coastguard Worker%def op_invoke_direct_range(): 242*795d594fSAndroid Build Coastguard Worker% op_invoke_direct(range="Range") 243*795d594fSAndroid Build Coastguard Worker 244*795d594fSAndroid Build Coastguard Worker 245*795d594fSAndroid Build Coastguard Worker// invoke-static/range {vCCCC .. vNNNN}, meth@BBBB 246*795d594fSAndroid Build Coastguard Worker// Format 3rc: AA|77 BBBB CCCC 247*795d594fSAndroid Build Coastguard Worker// 248*795d594fSAndroid Build Coastguard Worker// Note: invoke-static/range is used to invoke a static method (which is always considered a direct 249*795d594fSAndroid Build Coastguard Worker// method). 250*795d594fSAndroid Build Coastguard Worker%def op_invoke_static_range(): 251*795d594fSAndroid Build Coastguard Worker% op_invoke_static(range="Range") 252*795d594fSAndroid Build Coastguard Worker 253*795d594fSAndroid Build Coastguard Worker 254*795d594fSAndroid Build Coastguard Worker// invoke-interface/range {vCCCC .. vNNNN}, meth@BBBB 255*795d594fSAndroid Build Coastguard Worker// Format 3rc: AA|78 BBBB CCCC 256*795d594fSAndroid Build Coastguard Worker// 257*795d594fSAndroid Build Coastguard Worker// Note: invoke-interface/range is used to invoke an interface method, that is, on an object whose 258*795d594fSAndroid Build Coastguard Worker// concrete class isn't known, using a method_id that refers to an interface. 259*795d594fSAndroid Build Coastguard Worker%def op_invoke_interface_range(): 260*795d594fSAndroid Build Coastguard Worker% op_invoke_interface(range="Range") 261*795d594fSAndroid Build Coastguard Worker 262*795d594fSAndroid Build Coastguard Worker 263*795d594fSAndroid Build Coastguard Worker// invoke-polymorphic {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH 264*795d594fSAndroid Build Coastguard Worker// Format 45cc: A|G|fa BBBB F|E|D|C HHHH 265*795d594fSAndroid Build Coastguard Worker// 266*795d594fSAndroid Build Coastguard Worker// Note: Invoke the indicated signature polymorphic method. The result (if any) may be stored with 267*795d594fSAndroid Build Coastguard Worker// an appropriate move-result* variant as the immediately subsequent instruction. 268*795d594fSAndroid Build Coastguard Worker// 269*795d594fSAndroid Build Coastguard Worker// The method reference must be to a signature polymorphic method, such as 270*795d594fSAndroid Build Coastguard Worker// java.lang.invoke.MethodHandle.invoke or java.lang.invoke.MethodHandle.invokeExact. 271*795d594fSAndroid Build Coastguard Worker// 272*795d594fSAndroid Build Coastguard Worker// The receiver must be an object supporting the signature polymorphic method being invoked. 273*795d594fSAndroid Build Coastguard Worker// 274*795d594fSAndroid Build Coastguard Worker// The prototype reference describes the argument types provided and the expected return type. 275*795d594fSAndroid Build Coastguard Worker// 276*795d594fSAndroid Build Coastguard Worker// The invoke-polymorphic bytecode may raise exceptions when it executes. The exceptions are 277*795d594fSAndroid Build Coastguard Worker// described in the API documentation for the signature polymorphic method being invoked. 278*795d594fSAndroid Build Coastguard Worker// 279*795d594fSAndroid Build Coastguard Worker// Present in Dex files from version 038 onwards. 280*795d594fSAndroid Build Coastguard Worker%def op_invoke_polymorphic(range=""): 281*795d594fSAndroid Build Coastguard Worker EXPORT_PC 282*795d594fSAndroid Build Coastguard Worker FETCH s7, count=2 // s7 := F|E|D|C or CCCC (range) 283*795d594fSAndroid Build Coastguard Worker // No need to fetch the target method; the runtime handles it. 284*795d594fSAndroid Build Coastguard Worker% fetch_receiver(reg="s8", vreg="s7", range=range) 285*795d594fSAndroid Build Coastguard Worker beqz s8, 1f // throw if null 286*795d594fSAndroid Build Coastguard Worker 287*795d594fSAndroid Build Coastguard Worker ld a0, (sp) // a0 := caller ArtMethod* 288*795d594fSAndroid Build Coastguard Worker mv a1, xPC 289*795d594fSAndroid Build Coastguard Worker call NterpGetShortyFromInvokePolymorphic // args a0, a1 290*795d594fSAndroid Build Coastguard Worker mv a1, s8 291*795d594fSAndroid Build Coastguard Worker tail NterpInvokePolymorphic${range} // args a0 (shorty), a1 (this), s7 (vregs) 292*795d594fSAndroid Build Coastguard Worker1: 293*795d594fSAndroid Build Coastguard Worker tail common_errNullObject 294*795d594fSAndroid Build Coastguard Worker 295*795d594fSAndroid Build Coastguard Worker 296*795d594fSAndroid Build Coastguard Worker// invoke-polymorphic/range {vCCCC .. vNNNN}, meth@BBBB, proto@HHHH 297*795d594fSAndroid Build Coastguard Worker// Format 4rcc: AA|fb BBBB CCCC HHHH 298*795d594fSAndroid Build Coastguard Worker// where NNNN = CCCC + AA - 1, that is A determines the count 0..255, and C determines the first 299*795d594fSAndroid Build Coastguard Worker// register. 300*795d594fSAndroid Build Coastguard Worker// 301*795d594fSAndroid Build Coastguard Worker// Note: Invoke the indicated method handle. See the invoke-polymorphic description above for 302*795d594fSAndroid Build Coastguard Worker// details. 303*795d594fSAndroid Build Coastguard Worker// 304*795d594fSAndroid Build Coastguard Worker// Present in Dex files from version 038 onwards. 305*795d594fSAndroid Build Coastguard Worker%def op_invoke_polymorphic_range(): 306*795d594fSAndroid Build Coastguard Worker% op_invoke_polymorphic(range="Range") 307*795d594fSAndroid Build Coastguard Worker 308*795d594fSAndroid Build Coastguard Worker 309*795d594fSAndroid Build Coastguard Worker// invoke-custom {vC, vD, vE, vF, vG}, call_site@BBBB 310*795d594fSAndroid Build Coastguard Worker// Format 35c: A|G|fc BBBB F|E|D|C 311*795d594fSAndroid Build Coastguard Worker// 312*795d594fSAndroid Build Coastguard Worker// Note: Resolves and invokes the indicated call site. The result from the invocation (if any) may 313*795d594fSAndroid Build Coastguard Worker// be stored with an appropriate move-result* variant as the immediately subsequent instruction. 314*795d594fSAndroid Build Coastguard Worker// 315*795d594fSAndroid Build Coastguard Worker// This instruction executes in two phases: call site resolution and call site invocation. 316*795d594fSAndroid Build Coastguard Worker// 317*795d594fSAndroid Build Coastguard Worker// Call site resolution checks whether the indicated call site has an associated 318*795d594fSAndroid Build Coastguard Worker// java.lang.invoke.CallSite instance. If not, the bootstrap linker method for the indicated call 319*795d594fSAndroid Build Coastguard Worker// site is invoked using arguments present in the DEX file (see call_site_item). The bootstrap 320*795d594fSAndroid Build Coastguard Worker// linker method returns a java.lang.invoke.CallSite instance that will then be associated with the 321*795d594fSAndroid Build Coastguard Worker// indicated call site if no association exists. Another thread may have already made the 322*795d594fSAndroid Build Coastguard Worker// association first, and if so execution of the instruction continues with the first associated 323*795d594fSAndroid Build Coastguard Worker// java.lang.invoke.CallSite instance. 324*795d594fSAndroid Build Coastguard Worker// 325*795d594fSAndroid Build Coastguard Worker// Call site invocation is made on the java.lang.invoke.MethodHandle target of the resolved 326*795d594fSAndroid Build Coastguard Worker// java.lang.invoke.CallSite instance. The target is invoked as if executing invoke-polymorphic 327*795d594fSAndroid Build Coastguard Worker// (described above) using the method handle and arguments to the invoke-custom instruction as the 328*795d594fSAndroid Build Coastguard Worker// arguments to an exact method handle invocation. 329*795d594fSAndroid Build Coastguard Worker// 330*795d594fSAndroid Build Coastguard Worker// Exceptions raised by the bootstrap linker method are wrapped in a java.lang.BootstrapMethodError. 331*795d594fSAndroid Build Coastguard Worker// A BootstrapMethodError is also raised if: 332*795d594fSAndroid Build Coastguard Worker// - the bootstrap linker method fails to return a java.lang.invoke.CallSite instance. 333*795d594fSAndroid Build Coastguard Worker// - the returned java.lang.invoke.CallSite has a null method handle target. 334*795d594fSAndroid Build Coastguard Worker// - the method handle target is not of the requested type. 335*795d594fSAndroid Build Coastguard Worker// 336*795d594fSAndroid Build Coastguard Worker// Present in Dex files from version 038 onwards. 337*795d594fSAndroid Build Coastguard Worker%def op_invoke_custom(range=""): 338*795d594fSAndroid Build Coastguard Worker EXPORT_PC 339*795d594fSAndroid Build Coastguard Worker ld a0, (sp) // a0 := caller ArtMethod* 340*795d594fSAndroid Build Coastguard Worker mv a1, xPC 341*795d594fSAndroid Build Coastguard Worker call NterpGetShortyFromInvokeCustom // args a0, a1 342*795d594fSAndroid Build Coastguard Worker mv s7, a0 // s7 := shorty 343*795d594fSAndroid Build Coastguard Worker FETCH a0, 1 // a0 := BBBB 344*795d594fSAndroid Build Coastguard Worker FETCH s8, 2 // s8 := F|E|D|C or CCCC (range) 345*795d594fSAndroid Build Coastguard Worker tail NterpInvokeCustom${range} // args a0 (BBBB), s7 (shorty), s8 (vregs) 346*795d594fSAndroid Build Coastguard Worker 347*795d594fSAndroid Build Coastguard Worker 348*795d594fSAndroid Build Coastguard Worker// invoke-custom/range {vCCCC .. vNNNN}, call_site@BBBB 349*795d594fSAndroid Build Coastguard Worker// Format 3rc: AA|fd BBBB CCCC 350*795d594fSAndroid Build Coastguard Worker// where NNNN = CCCC + AA - 1, that is A determines the count 0..255, and C determines the first 351*795d594fSAndroid Build Coastguard Worker// register. 352*795d594fSAndroid Build Coastguard Worker// 353*795d594fSAndroid Build Coastguard Worker// Note: Resolve and invoke a call site. See the invoke-custom description above for details. 354*795d594fSAndroid Build Coastguard Worker// 355*795d594fSAndroid Build Coastguard Worker// Present in Dex files from version 038 onwards. 356*795d594fSAndroid Build Coastguard Worker%def op_invoke_custom_range(): 357*795d594fSAndroid Build Coastguard Worker% op_invoke_custom(range="Range") 358*795d594fSAndroid Build Coastguard Worker 359*795d594fSAndroid Build Coastguard Worker 360*795d594fSAndroid Build Coastguard Worker// handler helpers 361*795d594fSAndroid Build Coastguard Worker 362*795d594fSAndroid Build Coastguard Worker%def resolve_method_into_a0(): 363*795d594fSAndroid Build Coastguard Worker mv a0, xSELF 364*795d594fSAndroid Build Coastguard Worker ld a1, (sp) // We can't always rely on a0 = ArtMethod*. 365*795d594fSAndroid Build Coastguard Worker mv a2, xPC 366*795d594fSAndroid Build Coastguard Worker call nterp_get_method 367*795d594fSAndroid Build Coastguard Worker 368*795d594fSAndroid Build Coastguard Worker 369*795d594fSAndroid Build Coastguard Worker%def fetch_receiver(reg="", vreg="", range=""): 370*795d594fSAndroid Build Coastguard Worker% if range == 'Range': 371*795d594fSAndroid Build Coastguard Worker GET_VREG_OBJECT $reg, $vreg // reg := refs[CCCC] 372*795d594fSAndroid Build Coastguard Worker% else: 373*795d594fSAndroid Build Coastguard Worker andi $reg, $vreg, 0xF // reg := C 374*795d594fSAndroid Build Coastguard Worker GET_VREG_OBJECT $reg, $reg // reg := refs[C] 375*795d594fSAndroid Build Coastguard Worker 376*795d594fSAndroid Build Coastguard Worker 377*795d594fSAndroid Build Coastguard Worker// 378*795d594fSAndroid Build Coastguard Worker// These asm blocks are positioned in main.S for visibility to stack walking. 379*795d594fSAndroid Build Coastguard Worker// 380*795d594fSAndroid Build Coastguard Worker 381*795d594fSAndroid Build Coastguard Worker 382*795d594fSAndroid Build Coastguard Worker// NterpInvokeVirtual 383*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod* 384*795d594fSAndroid Build Coastguard Worker// a1: this 385*795d594fSAndroid Build Coastguard Worker// s7: vreg ids F|E|D|C 386*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_virtual(): 387*795d594fSAndroid Build Coastguard Worker% nterp_invoke_direct(uniq="invoke_virtual") 388*795d594fSAndroid Build Coastguard Worker 389*795d594fSAndroid Build Coastguard Worker 390*795d594fSAndroid Build Coastguard Worker// NterpInvokeSuper 391*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod* 392*795d594fSAndroid Build Coastguard Worker// a1: this 393*795d594fSAndroid Build Coastguard Worker// s7: vreg ids F|E|D|C 394*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_super(): 395*795d594fSAndroid Build Coastguard Worker% nterp_invoke_direct(uniq="invoke_super") 396*795d594fSAndroid Build Coastguard Worker 397*795d594fSAndroid Build Coastguard Worker 398*795d594fSAndroid Build Coastguard Worker// NterpInvokeDirect 399*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod* 400*795d594fSAndroid Build Coastguard Worker// a1: this 401*795d594fSAndroid Build Coastguard Worker// s7: (regular) vreg ids F|E|D|C, (range) vreg id CCCC 402*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_direct(uniq="invoke_direct", range=""): 403*795d594fSAndroid Build Coastguard Worker ld s8, ART_METHOD_QUICK_CODE_OFFSET_64(a0) 404*795d594fSAndroid Build Coastguard Worker // s8 := quick code 405*795d594fSAndroid Build Coastguard Worker% try_nterp(quick="s8", z0="t0", skip=f".L{uniq}_simple") 406*795d594fSAndroid Build Coastguard Worker call NterpToNterpInstance${range} // args a0, a1 407*795d594fSAndroid Build Coastguard Worker j .L${uniq}_next_op 408*795d594fSAndroid Build Coastguard Worker 409*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple: 410*795d594fSAndroid Build Coastguard Worker% if range == 'Range': 411*795d594fSAndroid Build Coastguard Worker% try_simple_args_range(vC="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", skip=f".L{uniq}_01", uniq=uniq) 412*795d594fSAndroid Build Coastguard Worker% else: 413*795d594fSAndroid Build Coastguard Worker% try_simple_args(v_fedc="s7", z0="t0", z1="t1", skip=f".L{uniq}_01", uniq=uniq) 414*795d594fSAndroid Build Coastguard Worker%#: 415*795d594fSAndroid Build Coastguard Worker jalr s8 // (regular) args a0 - a5, (range) args a0 - a7 and stack 416*795d594fSAndroid Build Coastguard Worker j .L${uniq}_next_op 417*795d594fSAndroid Build Coastguard Worker 418*795d594fSAndroid Build Coastguard Worker.L${uniq}_01: 419*795d594fSAndroid Build Coastguard Worker mv s9, zero // initialize shorty reg 420*795d594fSAndroid Build Coastguard Worker% try_01_args(vreg="s7", shorty="s9", z0="t0", z1="t1", z2="t2", y0="s10", y1="s11", y2="s0", skip=f".L{uniq}_slow", call=f".L{uniq}_01_call", uniq=uniq, range=range) 421*795d594fSAndroid Build Coastguard Worker // if s9 := shorty, then maybe (a2, fa0) := fp[D] or fp[CCCC + 1] 422*795d594fSAndroid Build Coastguard Worker.L${uniq}_01_call: 423*795d594fSAndroid Build Coastguard Worker jalr s8 // args a0, a1, and maybe a2, fa0 424*795d594fSAndroid Build Coastguard Worker beqz s9, .L${uniq}_next_op // no shorty, no scalar return 425*795d594fSAndroid Build Coastguard Worker% maybe_float_returned(shorty="s9", z0="t0", z1="t1", uniq=f"{uniq}_0") 426*795d594fSAndroid Build Coastguard Worker // a0 := fa0 if float return 427*795d594fSAndroid Build Coastguard Worker j .L${uniq}_next_op 428*795d594fSAndroid Build Coastguard Worker 429*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow: 430*795d594fSAndroid Build Coastguard Worker% get_shorty_save_a0_a1(shorty="s9", y0="s10", y1="s11") 431*795d594fSAndroid Build Coastguard Worker% if range == 'Range': 432*795d594fSAndroid Build Coastguard Worker% slow_setup_args_range(shorty="s9", vC="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", z7="s10", uniq=uniq) 433*795d594fSAndroid Build Coastguard Worker% else: 434*795d594fSAndroid Build Coastguard Worker% slow_setup_args(shorty="s9", vregs="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", uniq=uniq) 435*795d594fSAndroid Build Coastguard Worker%#: 436*795d594fSAndroid Build Coastguard Worker jalr s8 // args in a0-a5, fa0-fa4 437*795d594fSAndroid Build Coastguard Worker% maybe_float_returned(shorty="s9", z0="t0", z1="t1", uniq=f"{uniq}_1") 438*795d594fSAndroid Build Coastguard Worker // a0 := fa0 if float return 439*795d594fSAndroid Build Coastguard Worker.L${uniq}_next_op: 440*795d594fSAndroid Build Coastguard Worker FETCH_ADVANCE_INST 3 441*795d594fSAndroid Build Coastguard Worker GET_INST_OPCODE t0 442*795d594fSAndroid Build Coastguard Worker GOTO_OPCODE t0 443*795d594fSAndroid Build Coastguard Worker 444*795d594fSAndroid Build Coastguard Worker 445*795d594fSAndroid Build Coastguard Worker// NterpInvokeStringInit 446*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod* 447*795d594fSAndroid Build Coastguard Worker// s7: (regular) vreg ids F|E|D|C, (range) vreg id CCCC 448*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_string_init(uniq="invoke_string_init", range=""): 449*795d594fSAndroid Build Coastguard Worker ld s8, ART_METHOD_QUICK_CODE_OFFSET_64(a0) 450*795d594fSAndroid Build Coastguard Worker // s8 := quick code 451*795d594fSAndroid Build Coastguard Worker% try_nterp(quick="s8", z0="t0", skip=f".L{uniq}_slow") 452*795d594fSAndroid Build Coastguard Worker call NterpToNterpStringInit${range} // arg a0 453*795d594fSAndroid Build Coastguard Worker j .L${uniq}_next_op 454*795d594fSAndroid Build Coastguard Worker 455*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow: 456*795d594fSAndroid Build Coastguard Worker% get_shorty_save_a0_a1(shorty="s9", y0="s10", y1="s11") 457*795d594fSAndroid Build Coastguard Worker% if range == 'Range': 458*795d594fSAndroid Build Coastguard Worker% slow_setup_args_string_init_range(shorty="s9", vC="s7", z0="t0", z1="t1", z2="t2", z3="t3", uniq=uniq) 459*795d594fSAndroid Build Coastguard Worker% else: 460*795d594fSAndroid Build Coastguard Worker% slow_setup_args_string_init(shorty="s9", v_fedc="s7", z0="t0", z1="t1", z2="t2", uniq=uniq) 461*795d594fSAndroid Build Coastguard Worker%#: 462*795d594fSAndroid Build Coastguard Worker jalr s8 // args (regular) a0 - a5, (range) a0 - a5 463*795d594fSAndroid Build Coastguard Worker 464*795d594fSAndroid Build Coastguard Worker.L${uniq}_next_op: 465*795d594fSAndroid Build Coastguard Worker% fetch_receiver(reg="t0", vreg="s7", range=range) 466*795d594fSAndroid Build Coastguard Worker // t0 := fp[C] (this) 467*795d594fSAndroid Build Coastguard Worker% subst_vreg_references(old="t0", new="a0", z0="t1", z1="t2", z2="t3", uniq=uniq) 468*795d594fSAndroid Build Coastguard Worker FETCH_ADVANCE_INST 3 469*795d594fSAndroid Build Coastguard Worker GET_INST_OPCODE t0 470*795d594fSAndroid Build Coastguard Worker GOTO_OPCODE t0 471*795d594fSAndroid Build Coastguard Worker 472*795d594fSAndroid Build Coastguard Worker 473*795d594fSAndroid Build Coastguard Worker// NterpInvokeStatic 474*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod* 475*795d594fSAndroid Build Coastguard Worker// s7: (regular) vreg ids F|E|D|C, (range) vreg id CCCC 476*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_static(uniq="invoke_static", range=""): 477*795d594fSAndroid Build Coastguard Worker ld s8, ART_METHOD_QUICK_CODE_OFFSET_64(a0) 478*795d594fSAndroid Build Coastguard Worker // s8 := quick code 479*795d594fSAndroid Build Coastguard Worker% try_nterp(quick="s8", z0="t0", skip=f".L{uniq}_simple") 480*795d594fSAndroid Build Coastguard Worker call NterpToNterpStatic${range} // arg a0 481*795d594fSAndroid Build Coastguard Worker j .L${uniq}_next_op 482*795d594fSAndroid Build Coastguard Worker 483*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple: 484*795d594fSAndroid Build Coastguard Worker% if range == 'Range': 485*795d594fSAndroid Build Coastguard Worker% try_simple_args_range(vC="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", arg_start="0", skip=f".L{uniq}_01", uniq=uniq) 486*795d594fSAndroid Build Coastguard Worker% else: 487*795d594fSAndroid Build Coastguard Worker% try_simple_args(v_fedc="s7", z0="t0", z1="t1", arg_start="0", skip=f".L{uniq}_01", uniq=uniq) 488*795d594fSAndroid Build Coastguard Worker%#: 489*795d594fSAndroid Build Coastguard Worker jalr s8 // args (regular) a0 - a5, (range) a0 - a7 and maybe stack 490*795d594fSAndroid Build Coastguard Worker j .L${uniq}_next_op 491*795d594fSAndroid Build Coastguard Worker 492*795d594fSAndroid Build Coastguard Worker.L${uniq}_01: 493*795d594fSAndroid Build Coastguard Worker mv s9, zero // initialize shorty reg 494*795d594fSAndroid Build Coastguard Worker% try_01_args_static(vreg="s7", shorty="s9", z0="t0", z1="t1", z2="t2", y0="s10", y1="s11", skip=f".L{uniq}_slow", call=f".L{uniq}_01_call", uniq=uniq, range=range) 495*795d594fSAndroid Build Coastguard Worker // if s9 := shorty, then maybe (a2, fa0) := fp[C] or fp[CCCC] 496*795d594fSAndroid Build Coastguard Worker.L${uniq}_01_call: 497*795d594fSAndroid Build Coastguard Worker jalr s8 // args a0, and maybe a1, fa0 498*795d594fSAndroid Build Coastguard Worker beqz s9, .L${uniq}_next_op // no shorty, no scalar return 499*795d594fSAndroid Build Coastguard Worker% maybe_float_returned(shorty="s9", z0="t0", z1="t1", uniq=f"{uniq}_0") 500*795d594fSAndroid Build Coastguard Worker // a0 := fa0 if float return 501*795d594fSAndroid Build Coastguard Worker j .L${uniq}_next_op 502*795d594fSAndroid Build Coastguard Worker 503*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow: 504*795d594fSAndroid Build Coastguard Worker% get_shorty_save_a0(shorty="s9", y0="s10") 505*795d594fSAndroid Build Coastguard Worker% if range == 'Range': 506*795d594fSAndroid Build Coastguard Worker% slow_setup_args_range(shorty="s9", vC="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", z7="s10", arg_start="0", uniq=uniq) 507*795d594fSAndroid Build Coastguard Worker% else: 508*795d594fSAndroid Build Coastguard Worker% slow_setup_args(shorty="s9", vregs="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", arg_start="0", uniq=uniq) 509*795d594fSAndroid Build Coastguard Worker%#: 510*795d594fSAndroid Build Coastguard Worker jalr s8 // args (regular) a0 - a5 and fa0 - fa4, (range) a0 - a7 and fa0 - fa7 and maybe stack 511*795d594fSAndroid Build Coastguard Worker% maybe_float_returned(shorty="s9", z0="t0", z1="t1", uniq=f"{uniq}_1") 512*795d594fSAndroid Build Coastguard Worker // a0 := fa0 if float return 513*795d594fSAndroid Build Coastguard Worker.L${uniq}_next_op: 514*795d594fSAndroid Build Coastguard Worker FETCH_ADVANCE_INST 3 515*795d594fSAndroid Build Coastguard Worker GET_INST_OPCODE t0 516*795d594fSAndroid Build Coastguard Worker GOTO_OPCODE t0 517*795d594fSAndroid Build Coastguard Worker 518*795d594fSAndroid Build Coastguard Worker 519*795d594fSAndroid Build Coastguard Worker// NterpInvokeInterface 520*795d594fSAndroid Build Coastguard Worker// a0: the target interface method 521*795d594fSAndroid Build Coastguard Worker// - ignored in nterp-to-nterp transfer 522*795d594fSAndroid Build Coastguard Worker// - preserved through shorty calls 523*795d594fSAndroid Build Coastguard Worker// - side-loaded in T0 as a "hidden argument" in managed ABI transfer 524*795d594fSAndroid Build Coastguard Worker// a1: this 525*795d594fSAndroid Build Coastguard Worker// a2: ArtMethod* 526*795d594fSAndroid Build Coastguard Worker// s7: vreg ids F|E|D|C 527*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_interface(uniq="invoke_interface", range=""): 528*795d594fSAndroid Build Coastguard Worker // We immediately adjust the incoming arguments to suit the rest of the invoke. 529*795d594fSAndroid Build Coastguard Worker mv t0, a0 // t0 := hidden arg, preserve until quick call 530*795d594fSAndroid Build Coastguard Worker mv a0, a2 // a0 := ArtMethod* 531*795d594fSAndroid Build Coastguard Worker 532*795d594fSAndroid Build Coastguard Worker ld s8, ART_METHOD_QUICK_CODE_OFFSET_64(a0) 533*795d594fSAndroid Build Coastguard Worker // s8 := quick code 534*795d594fSAndroid Build Coastguard Worker% try_nterp(quick="s8", z0="t1", skip=f".L{uniq}_simple") 535*795d594fSAndroid Build Coastguard Worker call NterpToNterpInstance${range} // args a0, a1 536*795d594fSAndroid Build Coastguard Worker j .L${uniq}_next_op 537*795d594fSAndroid Build Coastguard Worker 538*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple: 539*795d594fSAndroid Build Coastguard Worker% if range == 'Range': 540*795d594fSAndroid Build Coastguard Worker% try_simple_args_range(vC="s7", z0="t1", z1="t2", z2="t3", z3="t4", z4="t5", skip=f".L{uniq}_01", uniq=uniq) 541*795d594fSAndroid Build Coastguard Worker% else: 542*795d594fSAndroid Build Coastguard Worker% try_simple_args(v_fedc="s7", z0="t1", z1="t2", skip=f".L{uniq}_01", uniq=uniq) 543*795d594fSAndroid Build Coastguard Worker%#: 544*795d594fSAndroid Build Coastguard Worker jalr s8 // args (regular) a0 - a5 and t0, (range) a0 - a7 and t0 and maybe stack 545*795d594fSAndroid Build Coastguard Worker j .L${uniq}_next_op 546*795d594fSAndroid Build Coastguard Worker 547*795d594fSAndroid Build Coastguard Worker.L${uniq}_01: 548*795d594fSAndroid Build Coastguard Worker mv s9, zero // initialize shorty reg 549*795d594fSAndroid Build Coastguard Worker% try_01_args(vreg="s7", shorty="s9", z0="t1", z1="t2", z2="t3", y0="s10", y1="s11", y2="s0", interface=True, skip=f".L{uniq}_slow", call=f".L{uniq}_01_call", uniq=uniq, range=range) 550*795d594fSAndroid Build Coastguard Worker // if s9 := shorty, then maybe (a2, fa0) := fp[D] or fp[CCCC + 1] 551*795d594fSAndroid Build Coastguard Worker // (xINST clobbered, if taking this fast path) 552*795d594fSAndroid Build Coastguard Worker.L${uniq}_01_call: 553*795d594fSAndroid Build Coastguard Worker jalr s8 // args a0, a1, and t0, and maybe a2, fa0 554*795d594fSAndroid Build Coastguard Worker beqz s9, .L${uniq}_next_op // no shorty, no scalar return 555*795d594fSAndroid Build Coastguard Worker% maybe_float_returned(shorty="s9", z0="t0", z1="t1", uniq=f"{uniq}_0") 556*795d594fSAndroid Build Coastguard Worker // a0 := fa0 if float return 557*795d594fSAndroid Build Coastguard Worker j .L${uniq}_next_op 558*795d594fSAndroid Build Coastguard Worker 559*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow: 560*795d594fSAndroid Build Coastguard Worker% get_shorty_for_interface_save_a0_a1_t0(shorty="s9", y0="s10", y1="s11", y2="s0") 561*795d594fSAndroid Build Coastguard Worker% if range == 'Range': 562*795d594fSAndroid Build Coastguard Worker% slow_setup_args_range(shorty="s9", vC="s7", z0="s10", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", z7="s11", uniq=uniq) 563*795d594fSAndroid Build Coastguard Worker% else: 564*795d594fSAndroid Build Coastguard Worker% slow_setup_args(shorty="s9", vregs="s7", z0="s10", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", uniq=uniq) 565*795d594fSAndroid Build Coastguard Worker%#: 566*795d594fSAndroid Build Coastguard Worker jalr s8 // args (regular) a0 - a5, fa0 - fa4, t0, (range) a0 - a7, fa0 - fa7, t0 567*795d594fSAndroid Build Coastguard Worker% maybe_float_returned(shorty="s9", z0="t0", z1="t1", uniq=f"{uniq}_1") 568*795d594fSAndroid Build Coastguard Worker // a0 := fa0 if float return 569*795d594fSAndroid Build Coastguard Worker.L${uniq}_next_op: 570*795d594fSAndroid Build Coastguard Worker FETCH_ADVANCE_INST 3 571*795d594fSAndroid Build Coastguard Worker GET_INST_OPCODE t0 572*795d594fSAndroid Build Coastguard Worker GOTO_OPCODE t0 573*795d594fSAndroid Build Coastguard Worker 574*795d594fSAndroid Build Coastguard Worker 575*795d594fSAndroid Build Coastguard Worker// NterpInvokePolymorphic 576*795d594fSAndroid Build Coastguard Worker// a0: shorty 577*795d594fSAndroid Build Coastguard Worker// a1: receiver this 578*795d594fSAndroid Build Coastguard Worker// s7: (regular) vreg ids F|E|D|C, (range) vreg id CCCC 579*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_polymorphic(uniq="invoke_polymorphic", range=""): 580*795d594fSAndroid Build Coastguard Worker% if range == "Range": 581*795d594fSAndroid Build Coastguard Worker% slow_setup_args_range(shorty="a0", vC="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", z7="s8", uniq=uniq) 582*795d594fSAndroid Build Coastguard Worker% else: 583*795d594fSAndroid Build Coastguard Worker% slow_setup_args(shorty="a0", vregs="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", uniq=uniq) 584*795d594fSAndroid Build Coastguard Worker%#: 585*795d594fSAndroid Build Coastguard Worker // Managed ABI argument regs get spilled to stack and consumed by artInvokePolymorphic. 586*795d594fSAndroid Build Coastguard Worker call art_quick_invoke_polymorphic // args a1 - a7, fa0 - fa7, and maybe stack 587*795d594fSAndroid Build Coastguard Worker // Note: If float return, artInvokePolymorphic will place the value in A0, as Nterp expects. 588*795d594fSAndroid Build Coastguard Worker FETCH_ADVANCE_INST 4 589*795d594fSAndroid Build Coastguard Worker GET_INST_OPCODE t0 590*795d594fSAndroid Build Coastguard Worker GOTO_OPCODE t0 591*795d594fSAndroid Build Coastguard Worker 592*795d594fSAndroid Build Coastguard Worker 593*795d594fSAndroid Build Coastguard Worker// NterpInvokeCustom 594*795d594fSAndroid Build Coastguard Worker// a0: BBBB 595*795d594fSAndroid Build Coastguard Worker// s7: shorty 596*795d594fSAndroid Build Coastguard Worker// s8: (regular) vreg ids F|E|D|C, (range) vreg id CCCC 597*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_custom(uniq="invoke_custom", range=""): 598*795d594fSAndroid Build Coastguard Worker% if range == "Range": 599*795d594fSAndroid Build Coastguard Worker% slow_setup_args_range(shorty="s7", vC="s8", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", z7="s9", arg_start="0", uniq=uniq) 600*795d594fSAndroid Build Coastguard Worker% else: 601*795d594fSAndroid Build Coastguard Worker% slow_setup_args(shorty="s7", vregs="s8", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", arg_start="0", uniq=uniq) 602*795d594fSAndroid Build Coastguard Worker%#: 603*795d594fSAndroid Build Coastguard Worker // Managed ABI argument regs get spilled to stack and consumed by artInvokeCustom. 604*795d594fSAndroid Build Coastguard Worker call art_quick_invoke_custom // args a0 - a7, fa0 - fa7, and maybe stack 605*795d594fSAndroid Build Coastguard Worker // Note: If float return, artInvokeCustom will place the value in A0, as Nterp expects. 606*795d594fSAndroid Build Coastguard Worker FETCH_ADVANCE_INST 3 607*795d594fSAndroid Build Coastguard Worker GET_INST_OPCODE t0 608*795d594fSAndroid Build Coastguard Worker GOTO_OPCODE t0 609*795d594fSAndroid Build Coastguard Worker 610*795d594fSAndroid Build Coastguard Worker 611*795d594fSAndroid Build Coastguard Worker// NterpInvokeVirtualRange 612*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod* 613*795d594fSAndroid Build Coastguard Worker// a1: this 614*795d594fSAndroid Build Coastguard Worker// s7: vreg id CCCC 615*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_virtual_range(): 616*795d594fSAndroid Build Coastguard Worker% nterp_invoke_direct(uniq="invoke_virtual_range", range="Range") 617*795d594fSAndroid Build Coastguard Worker 618*795d594fSAndroid Build Coastguard Worker 619*795d594fSAndroid Build Coastguard Worker// NterpInvokeSuperRange 620*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod* 621*795d594fSAndroid Build Coastguard Worker// a1: this 622*795d594fSAndroid Build Coastguard Worker// s7: vreg id CCCC 623*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_super_range(): 624*795d594fSAndroid Build Coastguard Worker% nterp_invoke_direct(uniq="invoke_super_range", range="Range") 625*795d594fSAndroid Build Coastguard Worker 626*795d594fSAndroid Build Coastguard Worker 627*795d594fSAndroid Build Coastguard Worker// NterpInvokeDirectRange 628*795d594fSAndroid Build Coastguard Worker// Hardcoded: 629*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod* 630*795d594fSAndroid Build Coastguard Worker// a1: this 631*795d594fSAndroid Build Coastguard Worker// s7: vreg id CCCC 632*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_direct_range(): 633*795d594fSAndroid Build Coastguard Worker% nterp_invoke_direct(uniq="invoke_direct_range", range="Range") 634*795d594fSAndroid Build Coastguard Worker 635*795d594fSAndroid Build Coastguard Worker 636*795d594fSAndroid Build Coastguard Worker// NterpInvokeStringInitRange 637*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod* 638*795d594fSAndroid Build Coastguard Worker// s7: vreg id CCCC 639*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_string_init_range(): 640*795d594fSAndroid Build Coastguard Worker% nterp_invoke_string_init(uniq="invoke_string_init_range", range="Range") 641*795d594fSAndroid Build Coastguard Worker 642*795d594fSAndroid Build Coastguard Worker 643*795d594fSAndroid Build Coastguard Worker// NterpInvokeStaticRange 644*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod* 645*795d594fSAndroid Build Coastguard Worker// s7: vreg id CCCC 646*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_static_range(): 647*795d594fSAndroid Build Coastguard Worker% nterp_invoke_static(uniq="invoke_static_range", range="Range") 648*795d594fSAndroid Build Coastguard Worker 649*795d594fSAndroid Build Coastguard Worker 650*795d594fSAndroid Build Coastguard Worker// NterpInvokeInterfaceRange 651*795d594fSAndroid Build Coastguard Worker// a0: the target interface method 652*795d594fSAndroid Build Coastguard Worker// - ignored in nterp-to-nterp transfer 653*795d594fSAndroid Build Coastguard Worker// - preserved through shorty calls 654*795d594fSAndroid Build Coastguard Worker// - side-loaded in T0 as a "hidden argument" in managed ABI transfer 655*795d594fSAndroid Build Coastguard Worker// a1: this 656*795d594fSAndroid Build Coastguard Worker// a2: ArtMethod* 657*795d594fSAndroid Build Coastguard Worker// s7: vreg id CCCC 658*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_interface_range(): 659*795d594fSAndroid Build Coastguard Worker% nterp_invoke_interface(uniq="invoke_interface_range", range="Range") 660*795d594fSAndroid Build Coastguard Worker 661*795d594fSAndroid Build Coastguard Worker 662*795d594fSAndroid Build Coastguard Worker// NterpInvokePolymorphicRange 663*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_polymorphic_range(): 664*795d594fSAndroid Build Coastguard Worker% nterp_invoke_polymorphic(uniq="invoke_polymorphic_range", range="Range") 665*795d594fSAndroid Build Coastguard Worker 666*795d594fSAndroid Build Coastguard Worker 667*795d594fSAndroid Build Coastguard Worker// NterpInvokeCustomRange 668*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_custom_range(): 669*795d594fSAndroid Build Coastguard Worker% nterp_invoke_custom(uniq="invoke_custom_range", range="Range") 670*795d594fSAndroid Build Coastguard Worker 671*795d594fSAndroid Build Coastguard Worker 672*795d594fSAndroid Build Coastguard Worker// fast path and slow path helpers 673*795d594fSAndroid Build Coastguard Worker 674*795d594fSAndroid Build Coastguard Worker 675*795d594fSAndroid Build Coastguard Worker// Input 676*795d594fSAndroid Build Coastguard Worker// - quick: quick code ptr 677*795d594fSAndroid Build Coastguard Worker// Temporaries: z0 678*795d594fSAndroid Build Coastguard Worker%def try_nterp(quick="", z0="", skip=""): 679*795d594fSAndroid Build Coastguard Worker lla $z0, ExecuteNterpImpl 680*795d594fSAndroid Build Coastguard Worker bne $z0, $quick, $skip 681*795d594fSAndroid Build Coastguard Worker 682*795d594fSAndroid Build Coastguard Worker 683*795d594fSAndroid Build Coastguard Worker// Hardcoded 684*795d594fSAndroid Build Coastguard Worker// - a0: ArtMethod* 685*795d594fSAndroid Build Coastguard Worker// - xINST 686*795d594fSAndroid Build Coastguard Worker// Input 687*795d594fSAndroid Build Coastguard Worker// - v_fedc: vreg ids F|E|D|C 688*795d594fSAndroid Build Coastguard Worker// Temporaries: z0, z1 689*795d594fSAndroid Build Coastguard Worker%def try_simple_args(v_fedc="", z0="", z1="", arg_start="1", skip="", uniq=""): 690*795d594fSAndroid Build Coastguard Worker lwu $z0, ART_METHOD_ACCESS_FLAGS_OFFSET(a0) 691*795d594fSAndroid Build Coastguard Worker // The meaning of nterp-invoke-fast-path-flag for RISC-V diverges from other ISAs. 692*795d594fSAndroid Build Coastguard Worker BRANCH_IF_BIT_CLEAR $z0, $z0, ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG_BIT, $skip 693*795d594fSAndroid Build Coastguard Worker 694*795d594fSAndroid Build Coastguard Worker srliw $z0, xINST, 12 // z0 := A 695*795d594fSAndroid Build Coastguard Worker% if arg_start == "0": 696*795d594fSAndroid Build Coastguard Worker beqz $z0, .L${uniq}_simple_done // A = 0: no further args. 697*795d594fSAndroid Build Coastguard Worker%#: 698*795d594fSAndroid Build Coastguard Worker li $z1, 2 699*795d594fSAndroid Build Coastguard Worker blt $z0, $z1, .L${uniq}_simple_1 // A = 1 700*795d594fSAndroid Build Coastguard Worker beq $z0, $z1, .L${uniq}_simple_2 // A = 2 701*795d594fSAndroid Build Coastguard Worker li $z1, 4 702*795d594fSAndroid Build Coastguard Worker blt $z0, $z1, .L${uniq}_simple_3 // A = 3 703*795d594fSAndroid Build Coastguard Worker beq $z0, $z1, .L${uniq}_simple_4 // A = 4 704*795d594fSAndroid Build Coastguard Worker // A = 5 705*795d594fSAndroid Build Coastguard Worker srliw $z1, xINST, 8 // z1 := A|G 706*795d594fSAndroid Build Coastguard Worker andi $z1, $z1, 0xF // z1 := G 707*795d594fSAndroid Build Coastguard Worker GET_VREG_OBJECT a5, $z1 708*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_4: 709*795d594fSAndroid Build Coastguard Worker srliw $z1, $v_fedc, 12 // z1 := F 710*795d594fSAndroid Build Coastguard Worker GET_VREG_OBJECT a4, $z1 711*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_3: 712*795d594fSAndroid Build Coastguard Worker srliw $z1, $v_fedc, 8 // z1 := F|E 713*795d594fSAndroid Build Coastguard Worker andi $z1, $z1, 0xF // z1 := E 714*795d594fSAndroid Build Coastguard Worker GET_VREG_OBJECT a3, $z1 715*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_2: 716*795d594fSAndroid Build Coastguard Worker srliw $z1, $v_fedc, 4 // z1 := F|E|D 717*795d594fSAndroid Build Coastguard Worker andi $z1, $z1, 0xF // z1 := D 718*795d594fSAndroid Build Coastguard Worker GET_VREG_OBJECT a2, $z1 719*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_1: 720*795d594fSAndroid Build Coastguard Worker% if arg_start == "0": 721*795d594fSAndroid Build Coastguard Worker andi $z1, $v_fedc, 0xF // z1 := C 722*795d594fSAndroid Build Coastguard Worker GET_VREG_OBJECT a1, $z1 723*795d594fSAndroid Build Coastguard Worker // instance: a1 already set to "this" 724*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_done: 725*795d594fSAndroid Build Coastguard Worker 726*795d594fSAndroid Build Coastguard Worker 727*795d594fSAndroid Build Coastguard Worker// Range variant. 728*795d594fSAndroid Build Coastguard Worker%def try_simple_args_range(vC="", z0="", z1="", z2="", z3="", z4="", skip="", arg_start="1", uniq=""): 729*795d594fSAndroid Build Coastguard Worker lwu $z0, ART_METHOD_ACCESS_FLAGS_OFFSET(a0) 730*795d594fSAndroid Build Coastguard Worker // The meaning of nterp-invoke-fast-path-flag for RISC-V diverges from other ISAs. 731*795d594fSAndroid Build Coastguard Worker BRANCH_IF_BIT_CLEAR $z0, $z0, ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG_BIT, $skip 732*795d594fSAndroid Build Coastguard Worker 733*795d594fSAndroid Build Coastguard Worker srliw $z0, xINST, 8 // z0 := AA 734*795d594fSAndroid Build Coastguard Worker% if arg_start == "0": # static: 735*795d594fSAndroid Build Coastguard Worker beqz $z0, .L${uniq}_simple_done // AA = 0: no further args. 736*795d594fSAndroid Build Coastguard Worker sh2add $z1, $vC, xFP // z1 := &FP[CCCC] 737*795d594fSAndroid Build Coastguard Worker li $z2, 2 738*795d594fSAndroid Build Coastguard Worker blt $z0, $z2, .L${uniq}_simple_1 // AA = 1 739*795d594fSAndroid Build Coastguard Worker% else: # instance: 740*795d594fSAndroid Build Coastguard Worker li $z2, 2 741*795d594fSAndroid Build Coastguard Worker blt $z0, $z2, .L${uniq}_simple_done // AA = 1, and a1 already loaded. 742*795d594fSAndroid Build Coastguard Worker sh2add $z1, $vC, xFP // z1 := &FP[CCCC] 743*795d594fSAndroid Build Coastguard Worker%#: 744*795d594fSAndroid Build Coastguard Worker // Here: z0, z1, z2 same values for static vs instance. 745*795d594fSAndroid Build Coastguard Worker beq $z0, $z2, .L${uniq}_simple_2 // AA = 2 746*795d594fSAndroid Build Coastguard Worker li $z2, 4 747*795d594fSAndroid Build Coastguard Worker blt $z0, $z2, .L${uniq}_simple_3 // AA = 3 748*795d594fSAndroid Build Coastguard Worker beq $z0, $z2, .L${uniq}_simple_4 // AA = 4 749*795d594fSAndroid Build Coastguard Worker li $z2, 6 750*795d594fSAndroid Build Coastguard Worker blt $z0, $z2, .L${uniq}_simple_5 // AA = 5 751*795d594fSAndroid Build Coastguard Worker beq $z0, $z2, .L${uniq}_simple_6 // AA = 6 752*795d594fSAndroid Build Coastguard Worker li $z2, 7 753*795d594fSAndroid Build Coastguard Worker beq $z0, $z2, .L${uniq}_simple_7 // AA = 7 754*795d594fSAndroid Build Coastguard Worker 755*795d594fSAndroid Build Coastguard Worker // AA >= 8: store in stack. Load/store from FP[CCCC + 7] upwards. 756*795d594fSAndroid Build Coastguard Worker slli $z2, $z0, 63 // z2 := negative if z0 bit #0 is set (odd) 757*795d594fSAndroid Build Coastguard Worker sh2add $z0, $z0, $z1 // z0 := loop guard at top of stack 758*795d594fSAndroid Build Coastguard Worker addi $z3, $z1, 7*4 // z3 := &FP[CCCC + 7] 759*795d594fSAndroid Build Coastguard Worker addi $z4, sp, __SIZEOF_POINTER__ + 7*4 760*795d594fSAndroid Build Coastguard Worker // z4 := &OUT[CCCC + 7] 761*795d594fSAndroid Build Coastguard Worker bltz $z2, .L${uniq}_simple_loop_wide 762*795d594fSAndroid Build Coastguard Worker // if AA odd, branch to wide-copy 763*795d594fSAndroid Build Coastguard Worker lwu $z2, ($z3) 764*795d594fSAndroid Build Coastguard Worker sw $z2, ($z4) 765*795d594fSAndroid Build Coastguard Worker addi $z3, $z3, 4 766*795d594fSAndroid Build Coastguard Worker addi $z4, $z4, 4 767*795d594fSAndroid Build Coastguard Worker 768*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_loop_wide: 769*795d594fSAndroid Build Coastguard Worker // TODO: Consider ensuring 64-bit stores are aligned. 770*795d594fSAndroid Build Coastguard Worker beq $z3, $z0, .L${uniq}_simple_7 771*795d594fSAndroid Build Coastguard Worker ld $z2, ($z3) 772*795d594fSAndroid Build Coastguard Worker sd $z2, ($z4) 773*795d594fSAndroid Build Coastguard Worker addi $z3, $z3, 8 774*795d594fSAndroid Build Coastguard Worker addi $z4, $z4, 8 775*795d594fSAndroid Build Coastguard Worker j .L${uniq}_simple_loop_wide 776*795d594fSAndroid Build Coastguard Worker 777*795d594fSAndroid Build Coastguard Worker // Bottom 7 slots of OUT array never written; first args are passed with a1-a7. 778*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_7: 779*795d594fSAndroid Build Coastguard Worker lwu a7, 6*4($z1) 780*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_6: 781*795d594fSAndroid Build Coastguard Worker lwu a6, 5*4($z1) 782*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_5: 783*795d594fSAndroid Build Coastguard Worker lwu a5, 4*4($z1) 784*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_4: 785*795d594fSAndroid Build Coastguard Worker lwu a4, 3*4($z1) 786*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_3: 787*795d594fSAndroid Build Coastguard Worker lwu a3, 2*4($z1) 788*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_2: 789*795d594fSAndroid Build Coastguard Worker lwu a2, 1*4($z1) 790*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_1: 791*795d594fSAndroid Build Coastguard Worker% if arg_start == "0": # static: 792*795d594fSAndroid Build Coastguard Worker lwu a1, 0*4($z1) 793*795d594fSAndroid Build Coastguard Worker%#: 794*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_done: 795*795d594fSAndroid Build Coastguard Worker 796*795d594fSAndroid Build Coastguard Worker 797*795d594fSAndroid Build Coastguard Worker// Check if a 0/1 arg invoke form is possible, set up a2 and fa0 if needed. 798*795d594fSAndroid Build Coastguard Worker// If a return value expected, move possible float return to a0. 799*795d594fSAndroid Build Coastguard Worker// Hardcoded: xINST, xPC, xFP, a0, a1, t0, fa0 800*795d594fSAndroid Build Coastguard Worker// NOTE xINST clobbered if interface=True and we're taking the fast path. 801*795d594fSAndroid Build Coastguard Worker// zN are temporaries, yN are callee-save 802*795d594fSAndroid Build Coastguard Worker%def try_01_args(vreg="", shorty="", z0="", z1="", z2="", y0="", y1="", y2="", interface=False, skip="", call="", uniq="", range=""): 803*795d594fSAndroid Build Coastguard Worker% if range == 'Range': 804*795d594fSAndroid Build Coastguard Worker srliw $y0, xINST, 8 // y0 := AA 805*795d594fSAndroid Build Coastguard Worker% else: 806*795d594fSAndroid Build Coastguard Worker srliw $y0, xINST, 12 // y0 := A 807*795d594fSAndroid Build Coastguard Worker%#: 808*795d594fSAndroid Build Coastguard Worker addi $y0, $y0, -2 // y0 := A - 2 or (range) AA - 2 809*795d594fSAndroid Build Coastguard Worker bgtz $y0, $skip // 2+ args: slow path 810*795d594fSAndroid Build Coastguard Worker beqz $y0, .L${uniq}_01_shorty // this and 1 arg: determine arg type with shorty 811*795d594fSAndroid Build Coastguard Worker // 0 args 812*795d594fSAndroid Build Coastguard Worker% try_01_args_peek_next(z0=z0) # z0 is zero if invoke has scalar return 813*795d594fSAndroid Build Coastguard Worker bnez $z0, $call // Non-scalar return, 0 args: make the call. 814*795d594fSAndroid Build Coastguard Worker // Scalar return, 0 args: determine return type with shorty 815*795d594fSAndroid Build Coastguard Worker 816*795d594fSAndroid Build Coastguard Worker.L${uniq}_01_shorty: 817*795d594fSAndroid Build Coastguard Worker // Get shorty, stash in callee-save to be available on return. 818*795d594fSAndroid Build Coastguard Worker // When getting shorty, stash this fast path's A0 and A1, then restore. 819*795d594fSAndroid Build Coastguard Worker% if interface: 820*795d594fSAndroid Build Coastguard Worker // xINST is a regular callee save. Safe: orig xINST value unused before FETCH_ADVANCE_INST. 821*795d594fSAndroid Build Coastguard Worker% get_shorty_for_interface_save_a0_a1_t0(shorty=shorty, y0=y1, y1=y2, y2="xINST") 822*795d594fSAndroid Build Coastguard Worker% else: 823*795d594fSAndroid Build Coastguard Worker% get_shorty_save_a0_a1(shorty=shorty, y0=y1, y1=y2) 824*795d594fSAndroid Build Coastguard Worker%#: 825*795d594fSAndroid Build Coastguard Worker // shorty assigned 826*795d594fSAndroid Build Coastguard Worker bltz $y0, $call // Scalar return, 0 args: make the call. 827*795d594fSAndroid Build Coastguard Worker // ins = 2: this and 1 arg. Load arg type. 828*795d594fSAndroid Build Coastguard Worker lb $z0, 1($shorty) // z0 := first arg 829*795d594fSAndroid Build Coastguard Worker li $z1, 'L' // ref type 830*795d594fSAndroid Build Coastguard Worker% if range == 'Range': 831*795d594fSAndroid Build Coastguard Worker sh2add $z2, $vreg, xFP // z2 := &fp[CCCC] 832*795d594fSAndroid Build Coastguard Worker lwu a2, 4($z2) // a2 := fp[CCCC + 1], zext 833*795d594fSAndroid Build Coastguard Worker% else: 834*795d594fSAndroid Build Coastguard Worker srliw $z2, $vreg, 4 // z2 := F|E|D 835*795d594fSAndroid Build Coastguard Worker andi $z2, $z2, 0xF // z2 := D 836*795d594fSAndroid Build Coastguard Worker sh2add $z2, $z2, xFP // z2 := &fp[D] 837*795d594fSAndroid Build Coastguard Worker lwu a2, ($z2) // a2 := fp[D], zext 838*795d594fSAndroid Build Coastguard Worker%#: 839*795d594fSAndroid Build Coastguard Worker beq $z0, $z1, $call // ref type: LWU into a2 840*795d594fSAndroid Build Coastguard Worker // non-'L' type 841*795d594fSAndroid Build Coastguard Worker fmv.w.x fa0, a2 // overload of managed ABI, for one arg 842*795d594fSAndroid Build Coastguard Worker sext.w a2, a2 // scalar type: LW into a2 843*795d594fSAndroid Build Coastguard Worker // immediately followed by call 844*795d594fSAndroid Build Coastguard Worker 845*795d594fSAndroid Build Coastguard Worker 846*795d594fSAndroid Build Coastguard Worker// Static variant. 847*795d594fSAndroid Build Coastguard Worker%def try_01_args_static(vreg="", shorty="", z0="", z1="", z2="", y0="", y1="", skip="", call="", uniq="", range=""): 848*795d594fSAndroid Build Coastguard Worker% if range == 'Range': 849*795d594fSAndroid Build Coastguard Worker srliw $y0, xINST, 8 // y0 := AA 850*795d594fSAndroid Build Coastguard Worker% else: 851*795d594fSAndroid Build Coastguard Worker srliw $y0, xINST, 12 // y0 := A 852*795d594fSAndroid Build Coastguard Worker%#: 853*795d594fSAndroid Build Coastguard Worker addi $y0, $y0, -1 // y0 := A - 1 or (range) AA - 1 854*795d594fSAndroid Build Coastguard Worker bgtz $y0, $skip // 2+ args: slow path 855*795d594fSAndroid Build Coastguard Worker beqz $y0, .L${uniq}_01_shorty // 1 arg: determine arg type with shorty 856*795d594fSAndroid Build Coastguard Worker // 0 args 857*795d594fSAndroid Build Coastguard Worker% try_01_args_peek_next(z0=z0) # z0 is zero if invoke has scalar return 858*795d594fSAndroid Build Coastguard Worker bnez $z0, $call // Non-scalar return, 0 args: make the call. 859*795d594fSAndroid Build Coastguard Worker // Scalar return, 0 args: determine return type with shorty. 860*795d594fSAndroid Build Coastguard Worker 861*795d594fSAndroid Build Coastguard Worker.L${uniq}_01_shorty: 862*795d594fSAndroid Build Coastguard Worker // Get shorty, stash in callee-save to be available on return. 863*795d594fSAndroid Build Coastguard Worker // When getting shorty, stash this fast path's A0 then restore. 864*795d594fSAndroid Build Coastguard Worker% get_shorty_save_a0(shorty=shorty, y0=y1) 865*795d594fSAndroid Build Coastguard Worker // shorty assigned 866*795d594fSAndroid Build Coastguard Worker bltz $y0, $call // Scalar return, 0 args: make the call. 867*795d594fSAndroid Build Coastguard Worker // ins = 1: load arg type 868*795d594fSAndroid Build Coastguard Worker lb $z0, 1($shorty) // z0 := first arg 869*795d594fSAndroid Build Coastguard Worker li $z1, 'L' // ref type 870*795d594fSAndroid Build Coastguard Worker% if range == 'Range': 871*795d594fSAndroid Build Coastguard Worker sh2add $z2, $vreg, xFP // z2 := &fp[CCCC] 872*795d594fSAndroid Build Coastguard Worker% else: 873*795d594fSAndroid Build Coastguard Worker andi $z2, $vreg, 0xF // z2 := C 874*795d594fSAndroid Build Coastguard Worker sh2add $z2, $z2, xFP // z2 := &fp[C] 875*795d594fSAndroid Build Coastguard Worker%#: 876*795d594fSAndroid Build Coastguard Worker lwu a1, ($z2) // a1 := fp[C] or (range) fp[CCCC], zext 877*795d594fSAndroid Build Coastguard Worker beq $z0, $z1, $call // ref type: LWU into a1 878*795d594fSAndroid Build Coastguard Worker // non-'L' type 879*795d594fSAndroid Build Coastguard Worker fmv.w.x fa0, a1 // overload of managed ABI, for one arg 880*795d594fSAndroid Build Coastguard Worker sext.w a1, a1 // scalar type: LW into a1 881*795d594fSAndroid Build Coastguard Worker // immediately followed by call 882*795d594fSAndroid Build Coastguard Worker 883*795d594fSAndroid Build Coastguard Worker 884*795d594fSAndroid Build Coastguard Worker%def try_01_args_peek_next(z0=""): 885*795d594fSAndroid Build Coastguard Worker FETCH $z0, count=3, width=8, byte=0 886*795d594fSAndroid Build Coastguard Worker // z0 := next op 887*795d594fSAndroid Build Coastguard Worker andi $z0, $z0, ~1 // clear bit #0 888*795d594fSAndroid Build Coastguard Worker addi $z0, $z0, -0x0A // z0 := zero if op is 0x0A or 0x0B 889*795d594fSAndroid Build Coastguard Worker 890*795d594fSAndroid Build Coastguard Worker 891*795d594fSAndroid Build Coastguard Worker// The invoked method might return in FA0, via managed ABI. 892*795d594fSAndroid Build Coastguard Worker// The next opcode, MOVE-RESULT{-WIDE}, expects the value in A0. 893*795d594fSAndroid Build Coastguard Worker%def maybe_float_returned(shorty="", z0="", z1="", uniq=""): 894*795d594fSAndroid Build Coastguard Worker lb $z0, ($shorty) // z0 := first byte of shorty; type of return 895*795d594fSAndroid Build Coastguard Worker li $z1, 'F' // 896*795d594fSAndroid Build Coastguard Worker beq $z0, $z1, .L${uniq}_float_return_move 897*795d594fSAndroid Build Coastguard Worker li $z1, 'D' // 898*795d594fSAndroid Build Coastguard Worker bne $z0, $z1, .L${uniq}_float_return_done 899*795d594fSAndroid Build Coastguard Worker.L${uniq}_float_return_move: 900*795d594fSAndroid Build Coastguard Worker // If fa0 carries a 32-bit float, the hi bits of fa0 will contain all 1's (NaN boxing). 901*795d594fSAndroid Build Coastguard Worker // The use of fmv.x.d will transfer those hi bits into a0, and that's okay, because the next 902*795d594fSAndroid Build Coastguard Worker // opcode, move-result, will only read the lo 32-bits of a0 - the box bits are correctly ignored. 903*795d594fSAndroid Build Coastguard Worker // If fa0 carries a 64-bit float, then fmv.x.d works as expected. 904*795d594fSAndroid Build Coastguard Worker fmv.x.d a0, fa0 905*795d594fSAndroid Build Coastguard Worker.L${uniq}_float_return_done: 906*795d594fSAndroid Build Coastguard Worker 907*795d594fSAndroid Build Coastguard Worker 908*795d594fSAndroid Build Coastguard Worker// Hardcoded: 909*795d594fSAndroid Build Coastguard Worker// - a0: ArtMethod* 910*795d594fSAndroid Build Coastguard Worker// - a1: this 911*795d594fSAndroid Build Coastguard Worker// Callee-saves: y0, y1 912*795d594fSAndroid Build Coastguard Worker%def get_shorty_save_a0_a1(shorty="", y0="", y1=""): 913*795d594fSAndroid Build Coastguard Worker mv $y1, a1 914*795d594fSAndroid Build Coastguard Worker mv $y0, a0 915*795d594fSAndroid Build Coastguard Worker call NterpGetShorty // arg a0 916*795d594fSAndroid Build Coastguard Worker mv $shorty, a0 917*795d594fSAndroid Build Coastguard Worker mv a0, $y0 918*795d594fSAndroid Build Coastguard Worker mv a1, $y1 919*795d594fSAndroid Build Coastguard Worker 920*795d594fSAndroid Build Coastguard Worker 921*795d594fSAndroid Build Coastguard Worker// Static variant. 922*795d594fSAndroid Build Coastguard Worker// Hardcoded: 923*795d594fSAndroid Build Coastguard Worker// - a0: ArtMethod* 924*795d594fSAndroid Build Coastguard Worker// Callee-saves: y0 925*795d594fSAndroid Build Coastguard Worker%def get_shorty_save_a0(shorty="", y0=""): 926*795d594fSAndroid Build Coastguard Worker mv $y0, a0 927*795d594fSAndroid Build Coastguard Worker call NterpGetShorty // arg a0 928*795d594fSAndroid Build Coastguard Worker mv $shorty, a0 929*795d594fSAndroid Build Coastguard Worker mv a0, $y0 930*795d594fSAndroid Build Coastguard Worker 931*795d594fSAndroid Build Coastguard Worker 932*795d594fSAndroid Build Coastguard Worker// Interface variant. 933*795d594fSAndroid Build Coastguard Worker// Hardcoded: 934*795d594fSAndroid Build Coastguard Worker// - a0: ArtMethod* 935*795d594fSAndroid Build Coastguard Worker// - a1: this 936*795d594fSAndroid Build Coastguard Worker// - t0: "hidden argument" 937*795d594fSAndroid Build Coastguard Worker// Callee-saves: y0, y1, y2 938*795d594fSAndroid Build Coastguard Worker%def get_shorty_for_interface_save_a0_a1_t0(shorty="", y0="", y1="", y2=""): 939*795d594fSAndroid Build Coastguard Worker mv $y2, t0 940*795d594fSAndroid Build Coastguard Worker mv $y1, a1 941*795d594fSAndroid Build Coastguard Worker mv $y0, a0 942*795d594fSAndroid Build Coastguard Worker ld a0, (sp) // a0 := caller ArtMethod* 943*795d594fSAndroid Build Coastguard Worker FETCH reg=a1, count=1 // a1 := BBBB method idx 944*795d594fSAndroid Build Coastguard Worker call NterpGetShortyFromMethodId 945*795d594fSAndroid Build Coastguard Worker mv $shorty, a0 946*795d594fSAndroid Build Coastguard Worker mv a0, $y0 947*795d594fSAndroid Build Coastguard Worker mv a1, $y1 948*795d594fSAndroid Build Coastguard Worker mv t0, $y2 949*795d594fSAndroid Build Coastguard Worker 950*795d594fSAndroid Build Coastguard Worker 951*795d594fSAndroid Build Coastguard Worker// Hardcoded: xFP, xREFS 952*795d594fSAndroid Build Coastguard Worker// Starting with vreg index 0, replace any old reference with new reference. 953*795d594fSAndroid Build Coastguard Worker%def subst_vreg_references(old="", new="", z0="", z1="", z2="", uniq=""): 954*795d594fSAndroid Build Coastguard Worker mv $z0, xFP // z0 := &fp[0] 955*795d594fSAndroid Build Coastguard Worker mv $z1, xREFS // z1 := &refs[0] 956*795d594fSAndroid Build Coastguard Worker.L${uniq}_subst_try: 957*795d594fSAndroid Build Coastguard Worker lwu $z2, ($z1) 958*795d594fSAndroid Build Coastguard Worker bne $z2, $old, .L${uniq}_subst_next 959*795d594fSAndroid Build Coastguard Worker sw $new, ($z0) 960*795d594fSAndroid Build Coastguard Worker sw $new, ($z1) 961*795d594fSAndroid Build Coastguard Worker.L${uniq}_subst_next: 962*795d594fSAndroid Build Coastguard Worker addi $z0, $z0, 4 963*795d594fSAndroid Build Coastguard Worker addi $z1, $z1, 4 964*795d594fSAndroid Build Coastguard Worker bne $z1, xFP, .L${uniq}_subst_try 965*795d594fSAndroid Build Coastguard Worker 966*795d594fSAndroid Build Coastguard Worker 967*795d594fSAndroid Build Coastguard Worker// Hardcoded 968*795d594fSAndroid Build Coastguard Worker// - a0: ArtMethod* 969*795d594fSAndroid Build Coastguard Worker// - a1: this 970*795d594fSAndroid Build Coastguard Worker// Input 971*795d594fSAndroid Build Coastguard Worker// - vregs: F|E|D|C from dex 972*795d594fSAndroid Build Coastguard Worker%def slow_setup_args(shorty="", vregs="", z0="", z1="", z2="", z3="", z4="", z5="", z6="", arg_start="1", uniq=""): 973*795d594fSAndroid Build Coastguard Worker srliw $z0, xINST, 12 // z0 := A 974*795d594fSAndroid Build Coastguard Worker li $z1, 5 975*795d594fSAndroid Build Coastguard Worker blt $z0, $z1, .L${uniq}_slow_gpr 976*795d594fSAndroid Build Coastguard Worker // A = 5: need vreg G 977*795d594fSAndroid Build Coastguard Worker srliw $z1, xINST, 8 // z1 := A|G 978*795d594fSAndroid Build Coastguard Worker andi $z1, $z1, 0xF // z1 := G 979*795d594fSAndroid Build Coastguard Worker slliw $z1, $z1, 16 // z1 := G0000 980*795d594fSAndroid Build Coastguard Worker add $vregs, $z1, $vregs // vregs := G|F|E|D|C 981*795d594fSAndroid Build Coastguard Worker 982*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_gpr: 983*795d594fSAndroid Build Coastguard Worker addi $z0, $shorty, 1 // z0 := first arg of shorty 984*795d594fSAndroid Build Coastguard Worker srliw $z1, $vregs, 4*$arg_start 985*795d594fSAndroid Build Coastguard Worker // z1 := (instance) F|E|D or G|F|E|D, (static) F|E|D|C or G|F|E|D|C 986*795d594fSAndroid Build Coastguard Worker li $z2, 'D' // double 987*795d594fSAndroid Build Coastguard Worker li $z3, 'F' // float 988*795d594fSAndroid Build Coastguard Worker li $z4, 'J' // long 989*795d594fSAndroid Build Coastguard Worker li $z5, 'L' // ref 990*795d594fSAndroid Build Coastguard Worker // linear scan through shorty: extract non-float vregs 991*795d594fSAndroid Build Coastguard Worker% if arg_start == "0": # static can place vC into a1; instance already loaded "this" into a1. 992*795d594fSAndroid Build Coastguard Worker% load_vreg_in_gpr(gpr="a1", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, L=z5, z0=z6, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_0") 993*795d594fSAndroid Build Coastguard Worker% load_vreg_in_gpr(gpr="a2", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, L=z5, z0=z6, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_1") 994*795d594fSAndroid Build Coastguard Worker% load_vreg_in_gpr(gpr="a3", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, L=z5, z0=z6, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_2") 995*795d594fSAndroid Build Coastguard Worker% load_vreg_in_gpr(gpr="a4", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, L=z5, z0=z6, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_3") 996*795d594fSAndroid Build Coastguard Worker% load_vreg_in_gpr(gpr="a5", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, L=z5, z0=z6, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_4") 997*795d594fSAndroid Build Coastguard Worker 998*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_fpr: 999*795d594fSAndroid Build Coastguard Worker addi $z0, $shorty, 1 // z0 := first arg of shorty 1000*795d594fSAndroid Build Coastguard Worker srliw $z1, $vregs, 4*$arg_start 1001*795d594fSAndroid Build Coastguard Worker // z1 := (instance) F|E|D or G|F|E|D, (static) F|E|D|C or G|F|E|D|C 1002*795d594fSAndroid Build Coastguard Worker // linear scan through shorty: extract float/double vregs 1003*795d594fSAndroid Build Coastguard Worker% load_vreg_in_fpr(fpr="fa0", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, z0=z5, done=f".L{uniq}_slow_done", uniq=f"{uniq}_0") 1004*795d594fSAndroid Build Coastguard Worker% load_vreg_in_fpr(fpr="fa1", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, z0=z5, done=f".L{uniq}_slow_done", uniq=f"{uniq}_1") 1005*795d594fSAndroid Build Coastguard Worker% load_vreg_in_fpr(fpr="fa2", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, z0=z5, done=f".L{uniq}_slow_done", uniq=f"{uniq}_2") 1006*795d594fSAndroid Build Coastguard Worker% load_vreg_in_fpr(fpr="fa3", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, z0=z5, done=f".L{uniq}_slow_done", uniq=f"{uniq}_3") 1007*795d594fSAndroid Build Coastguard Worker% if arg_start == "0": # static can place G into fa4; instance has only 4 args. 1008*795d594fSAndroid Build Coastguard Worker% load_vreg_in_fpr(fpr="fa4", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, z0=z5, done=f".L{uniq}_slow_done", uniq=f"{uniq}_4") 1009*795d594fSAndroid Build Coastguard Worker%#: 1010*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_done: 1011*795d594fSAndroid Build Coastguard Worker 1012*795d594fSAndroid Build Coastguard Worker 1013*795d594fSAndroid Build Coastguard Worker// String-init variant: up to 4 args, no long/double/float args. 1014*795d594fSAndroid Build Coastguard Worker// Ref args ('L') loaded with LW *must* apply ZEXT.W to avoid subtle address bugs. 1015*795d594fSAndroid Build Coastguard Worker%def slow_setup_args_string_init(shorty="", v_fedc="", z0="", z1="", z2="", uniq=""): 1016*795d594fSAndroid Build Coastguard Worker srliw $z0, xINST, 12 // z0 := A; possible values 1-5 1017*795d594fSAndroid Build Coastguard Worker li $z1, 2 1018*795d594fSAndroid Build Coastguard Worker blt $z0, $z1, .L${uniq}_slow_1 // A = 1 1019*795d594fSAndroid Build Coastguard Worker li $z2, 'L' // z2 := ref type 1020*795d594fSAndroid Build Coastguard Worker beq $z0, $z1, .L${uniq}_slow_2 // A = 2 1021*795d594fSAndroid Build Coastguard Worker li $z1, 4 1022*795d594fSAndroid Build Coastguard Worker blt $z0, $z1, .L${uniq}_slow_3 // A = 3 1023*795d594fSAndroid Build Coastguard Worker beq $z0, $z1, .L${uniq}_slow_4 // A = 4 1024*795d594fSAndroid Build Coastguard Worker 1025*795d594fSAndroid Build Coastguard Worker // A = 5 1026*795d594fSAndroid Build Coastguard Worker srliw $z0, xINST, 8 // z0 := A|G 1027*795d594fSAndroid Build Coastguard Worker andi $z0, $z0, 0xF // z0 := G 1028*795d594fSAndroid Build Coastguard Worker% get_vreg("a4", z0) 1029*795d594fSAndroid Build Coastguard Worker lb $z1, 4($shorty) // shorty RDEFG 1030*795d594fSAndroid Build Coastguard Worker bne $z1, $z2, .L${uniq}_slow_4 1031*795d594fSAndroid Build Coastguard Worker zext.w a4, a4 1032*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_4: 1033*795d594fSAndroid Build Coastguard Worker srliw $z1, $v_fedc, 12 // z1 := F 1034*795d594fSAndroid Build Coastguard Worker% get_vreg("a3", z1) 1035*795d594fSAndroid Build Coastguard Worker lb $z1, 3($shorty) // shorty RDEF 1036*795d594fSAndroid Build Coastguard Worker bne $z1, $z2, .L${uniq}_slow_3 1037*795d594fSAndroid Build Coastguard Worker zext.w a3, a3 1038*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_3: 1039*795d594fSAndroid Build Coastguard Worker srliw $z1, $v_fedc, 8 // z1 := F|E 1040*795d594fSAndroid Build Coastguard Worker andi $z1, $z1, 0xF // z1 := E 1041*795d594fSAndroid Build Coastguard Worker% get_vreg("a2", z1) 1042*795d594fSAndroid Build Coastguard Worker lb $z1, 2($shorty) // shorty RDE 1043*795d594fSAndroid Build Coastguard Worker bne $z1, $z2, .L${uniq}_slow_2 1044*795d594fSAndroid Build Coastguard Worker zext.w a2, a2 1045*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_2: 1046*795d594fSAndroid Build Coastguard Worker srliw $z1, $v_fedc, 4 // z1 := F|E|D 1047*795d594fSAndroid Build Coastguard Worker andi $z1, $z1, 0xF // z1 := D 1048*795d594fSAndroid Build Coastguard Worker% get_vreg("a1", z1) 1049*795d594fSAndroid Build Coastguard Worker lb $z1, 1($shorty) // shorty RD 1050*795d594fSAndroid Build Coastguard Worker bne $z1, $z2, .L${uniq}_slow_1 1051*795d594fSAndroid Build Coastguard Worker zext.w a1, a1 1052*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_1: 1053*795d594fSAndroid Build Coastguard Worker // "this" never read in string-init 1054*795d594fSAndroid Build Coastguard Worker 1055*795d594fSAndroid Build Coastguard Worker 1056*795d594fSAndroid Build Coastguard Worker// Range and static-range variant. 1057*795d594fSAndroid Build Coastguard Worker// Hardcoded 1058*795d594fSAndroid Build Coastguard Worker// - (caller) xPC, xINST, xFP 1059*795d594fSAndroid Build Coastguard Worker// - (callee) sp 1060*795d594fSAndroid Build Coastguard Worker// Input 1061*795d594fSAndroid Build Coastguard Worker// - vC: CCCC from dex 1062*795d594fSAndroid Build Coastguard Worker%def slow_setup_args_range(shorty="", vC="", z0="", z1="", z2="", z3="", z4="", z5="", z6="", z7="", arg_start="1", uniq=""): 1063*795d594fSAndroid Build Coastguard Worker addi $z0, $shorty, 1 // z0 := first arg of shorty 1064*795d594fSAndroid Build Coastguard Worker addi $z1, $vC, $arg_start // z1 := (instance) CCCC+1, (static) CCCC 1065*795d594fSAndroid Build Coastguard Worker mv $z2, zero // z2 := is_out_stack_needed false 1066*795d594fSAndroid Build Coastguard Worker li $z3, 'D' // double 1067*795d594fSAndroid Build Coastguard Worker li $z4, 'F' // float 1068*795d594fSAndroid Build Coastguard Worker li $z5, 'J' // long 1069*795d594fSAndroid Build Coastguard Worker li $z6, 'L' // ref 1070*795d594fSAndroid Build Coastguard Worker 1071*795d594fSAndroid Build Coastguard Worker // linear scan through shorty: extract non-float vregs 1072*795d594fSAndroid Build Coastguard Worker% if arg_start == "0": # static can place vCCCC into a1; instance already loaded "this" into a1. 1073*795d594fSAndroid Build Coastguard Worker% load_vreg_in_gpr_range(gpr="a1", shorty=z0, idx=z1, D=z3, F=z4, J=z5, L=z6, z0=z7, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_1") 1074*795d594fSAndroid Build Coastguard Worker% load_vreg_in_gpr_range(gpr="a2", shorty=z0, idx=z1, D=z3, F=z4, J=z5, L=z6, z0=z7, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_2") 1075*795d594fSAndroid Build Coastguard Worker% load_vreg_in_gpr_range(gpr="a3", shorty=z0, idx=z1, D=z3, F=z4, J=z5, L=z6, z0=z7, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_3") 1076*795d594fSAndroid Build Coastguard Worker% load_vreg_in_gpr_range(gpr="a4", shorty=z0, idx=z1, D=z3, F=z4, J=z5, L=z6, z0=z7, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_4") 1077*795d594fSAndroid Build Coastguard Worker% load_vreg_in_gpr_range(gpr="a5", shorty=z0, idx=z1, D=z3, F=z4, J=z5, L=z6, z0=z7, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_5") 1078*795d594fSAndroid Build Coastguard Worker% load_vreg_in_gpr_range(gpr="a6", shorty=z0, idx=z1, D=z3, F=z4, J=z5, L=z6, z0=z7, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_6") 1079*795d594fSAndroid Build Coastguard Worker% load_vreg_in_gpr_range(gpr="a7", shorty=z0, idx=z1, D=z3, F=z4, J=z5, L=z6, z0=z7, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_7") 1080*795d594fSAndroid Build Coastguard Worker% is_out_stack_needed(needed=z2, shorty=z0, D=z3, F=z4, z0=z1, uniq=uniq) 1081*795d594fSAndroid Build Coastguard Worker 1082*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_fpr: 1083*795d594fSAndroid Build Coastguard Worker addi $z0, $shorty, 1 // z0 := first arg of shorty 1084*795d594fSAndroid Build Coastguard Worker addi $z1, $vC, $arg_start // z1 := (instance) CCCC+1, (static) CCCC 1085*795d594fSAndroid Build Coastguard Worker // linear scan through shorty: extract float/double vregs 1086*795d594fSAndroid Build Coastguard Worker% load_vreg_in_fpr_range(fpr="fa0", shorty=z0, idx=z1, D=z3, F=z4, J=z5, z0=z6, done=f".L{uniq}_slow_stack", uniq=f"{uniq}_0") 1087*795d594fSAndroid Build Coastguard Worker% load_vreg_in_fpr_range(fpr="fa1", shorty=z0, idx=z1, D=z3, F=z4, J=z5, z0=z6, done=f".L{uniq}_slow_stack", uniq=f"{uniq}_1") 1088*795d594fSAndroid Build Coastguard Worker% load_vreg_in_fpr_range(fpr="fa2", shorty=z0, idx=z1, D=z3, F=z4, J=z5, z0=z6, done=f".L{uniq}_slow_stack", uniq=f"{uniq}_2") 1089*795d594fSAndroid Build Coastguard Worker% load_vreg_in_fpr_range(fpr="fa3", shorty=z0, idx=z1, D=z3, F=z4, J=z5, z0=z6, done=f".L{uniq}_slow_stack", uniq=f"{uniq}_3") 1090*795d594fSAndroid Build Coastguard Worker% load_vreg_in_fpr_range(fpr="fa4", shorty=z0, idx=z1, D=z3, F=z4, J=z5, z0=z6, done=f".L{uniq}_slow_stack", uniq=f"{uniq}_4") 1091*795d594fSAndroid Build Coastguard Worker% load_vreg_in_fpr_range(fpr="fa5", shorty=z0, idx=z1, D=z3, F=z4, J=z5, z0=z6, done=f".L{uniq}_slow_stack", uniq=f"{uniq}_5") 1092*795d594fSAndroid Build Coastguard Worker% load_vreg_in_fpr_range(fpr="fa6", shorty=z0, idx=z1, D=z3, F=z4, J=z5, z0=z6, done=f".L{uniq}_slow_stack", uniq=f"{uniq}_6") 1093*795d594fSAndroid Build Coastguard Worker% load_vreg_in_fpr_range(fpr="fa7", shorty=z0, idx=z1, D=z3, F=z4, J=z5, z0=z6, done=f".L{uniq}_slow_stack", uniq=f"{uniq}_7") 1094*795d594fSAndroid Build Coastguard Worker% is_out_stack_needed_float(needed=z2, shorty=z0, D=z3, F=z4, z0=z1, uniq=uniq) 1095*795d594fSAndroid Build Coastguard Worker 1096*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_stack: 1097*795d594fSAndroid Build Coastguard Worker beqz $z2, .L${uniq}_slow_done // No stack needed, skip it. Otherwise copy-paste it all with LD/SD. 1098*795d594fSAndroid Build Coastguard Worker addi $z0, sp, 8 // z0 := base addr of out array 1099*795d594fSAndroid Build Coastguard Worker sh2add $z1, $vC, xFP // z1 := base addr of FP[CCCC] 1100*795d594fSAndroid Build Coastguard Worker srliw $z2, xINST, 8 // z2 := AA, vreg count 1101*795d594fSAndroid Build Coastguard Worker sh2add $z2, $z2, $z1 // z2 := loop guard, addr of one slot past top of xFP array 1102*795d594fSAndroid Build Coastguard Worker% copy_vregs_to_out(out=z0, fp=z1, fp_top=z2, z0=z3, uniq=uniq) 1103*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_done: 1104*795d594fSAndroid Build Coastguard Worker 1105*795d594fSAndroid Build Coastguard Worker 1106*795d594fSAndroid Build Coastguard Worker// String-init variant: up to 4 args, no long/float/double args. 1107*795d594fSAndroid Build Coastguard Worker// Ref args ('L') loaded with LW *must* apply ZEXT.W to avoid subtle address bugs. 1108*795d594fSAndroid Build Coastguard Worker%def slow_setup_args_string_init_range(shorty="", vC="", z0="", z1="", z2="", z3="", uniq=""): 1109*795d594fSAndroid Build Coastguard Worker srliw $z0, xINST, 8 // z0 := AA; possible values 1-5 1110*795d594fSAndroid Build Coastguard Worker li $z1, 2 1111*795d594fSAndroid Build Coastguard Worker blt $z0, $z1, .L${uniq}_slow_1 // A = 1 1112*795d594fSAndroid Build Coastguard Worker sh2add $z2, $vC, xFP // z2 := &fp[CCCC] 1113*795d594fSAndroid Build Coastguard Worker li $z3, 'L' // z3 := ref type 1114*795d594fSAndroid Build Coastguard Worker beq $z0, $z1, .L${uniq}_slow_2 // A = 2 1115*795d594fSAndroid Build Coastguard Worker li $z1, 4 1116*795d594fSAndroid Build Coastguard Worker blt $z0, $z1, .L${uniq}_slow_3 // A = 3 1117*795d594fSAndroid Build Coastguard Worker beq $z0, $z1, .L${uniq}_slow_4 // A = 4 1118*795d594fSAndroid Build Coastguard Worker // A = 5 1119*795d594fSAndroid Build Coastguard Worker lw a4, 4*4($z2) 1120*795d594fSAndroid Build Coastguard Worker lb $z1, 4($shorty) 1121*795d594fSAndroid Build Coastguard Worker bne $z1, $z3, .L${uniq}_slow_4 1122*795d594fSAndroid Build Coastguard Worker zext.w a4, a4 1123*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_4: 1124*795d594fSAndroid Build Coastguard Worker lw a3, 3*4($z2) 1125*795d594fSAndroid Build Coastguard Worker lb $z1, 3($shorty) 1126*795d594fSAndroid Build Coastguard Worker bne $z1, $z3, .L${uniq}_slow_3 1127*795d594fSAndroid Build Coastguard Worker zext.w a3, a3 1128*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_3: 1129*795d594fSAndroid Build Coastguard Worker lw a2, 2*4($z2) 1130*795d594fSAndroid Build Coastguard Worker lb $z1, 2($shorty) 1131*795d594fSAndroid Build Coastguard Worker bne $z1, $z3, .L${uniq}_slow_2 1132*795d594fSAndroid Build Coastguard Worker zext.w a2, a2 1133*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_2: 1134*795d594fSAndroid Build Coastguard Worker lw a1, 1*4($z2) 1135*795d594fSAndroid Build Coastguard Worker lb $z1, 1($shorty) 1136*795d594fSAndroid Build Coastguard Worker bne $z1, $z3, .L${uniq}_slow_1 1137*795d594fSAndroid Build Coastguard Worker zext.w a1, a1 1138*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_1: 1139*795d594fSAndroid Build Coastguard Worker // "this" never read in string-init 1140*795d594fSAndroid Build Coastguard Worker 1141*795d594fSAndroid Build Coastguard Worker 1142*795d594fSAndroid Build Coastguard Worker// Iterate through 4-bit vreg ids in the "vregs" register, load a non-FP value 1143*795d594fSAndroid Build Coastguard Worker// into one argument register. 1144*795d594fSAndroid Build Coastguard Worker%def load_vreg_in_gpr(gpr="", shorty="", vregs="", D="", F="", J="", L="", z0="", done="", uniq=""): 1145*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_find: 1146*795d594fSAndroid Build Coastguard Worker lb $z0, ($shorty) // z0 := next shorty arg spec 1147*795d594fSAndroid Build Coastguard Worker addi $shorty, $shorty, 1 // increment char ptr 1148*795d594fSAndroid Build Coastguard Worker beqz $z0, $done // z0 == \0 1149*795d594fSAndroid Build Coastguard Worker beq $z0, $F, .L${uniq}_gpr_skip_4_bytes 1150*795d594fSAndroid Build Coastguard Worker beq $z0, $D, .L${uniq}_gpr_skip_8_bytes 1151*795d594fSAndroid Build Coastguard Worker 1152*795d594fSAndroid Build Coastguard Worker andi $gpr, $vregs, 0xF // gpr := vreg id 1153*795d594fSAndroid Build Coastguard Worker beq $z0, $J, .L${uniq}_gpr_load_8_bytes 1154*795d594fSAndroid Build Coastguard Worker% get_vreg(gpr, gpr) # gpr := 32-bit load 1155*795d594fSAndroid Build Coastguard Worker bne $z0, $L, .L${uniq}_gpr_load_common 1156*795d594fSAndroid Build Coastguard Worker zext.w $gpr, $gpr 1157*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_load_common: 1158*795d594fSAndroid Build Coastguard Worker srliw $vregs, $vregs, 4 // shift out the processed arg, one vreg 1159*795d594fSAndroid Build Coastguard Worker j .L${uniq}_gpr_set // and exit 1160*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_load_8_bytes: 1161*795d594fSAndroid Build Coastguard Worker GET_VREG_WIDE $gpr, $gpr // gpr := 64-bit load 1162*795d594fSAndroid Build Coastguard Worker srliw $vregs, $vregs, 8 // shift out the processed arg, a vreg pair 1163*795d594fSAndroid Build Coastguard Worker j .L${uniq}_gpr_set // and exit 1164*795d594fSAndroid Build Coastguard Worker 1165*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_skip_8_bytes: 1166*795d594fSAndroid Build Coastguard Worker srliw $vregs, $vregs, 4 // shift out a skipped arg 1167*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_skip_4_bytes: 1168*795d594fSAndroid Build Coastguard Worker srliw $vregs, $vregs, 4 // shift out a skipped arg 1169*795d594fSAndroid Build Coastguard Worker j .L${uniq}_gpr_find 1170*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_set: 1171*795d594fSAndroid Build Coastguard Worker 1172*795d594fSAndroid Build Coastguard Worker 1173*795d594fSAndroid Build Coastguard Worker// Iterate through 4-bit vreg ids in the "vregs" register, load a float or double 1174*795d594fSAndroid Build Coastguard Worker// value into one floating point argument register. 1175*795d594fSAndroid Build Coastguard Worker%def load_vreg_in_fpr(fpr="", shorty="", vregs="", D="", F="", J="", z0="", done="", uniq=""): 1176*795d594fSAndroid Build Coastguard Worker.L${uniq}_fpr_find: 1177*795d594fSAndroid Build Coastguard Worker lb $z0, ($shorty) // z0 := next shorty arg spec 1178*795d594fSAndroid Build Coastguard Worker addi $shorty, $shorty, 1 // increment char ptr 1179*795d594fSAndroid Build Coastguard Worker beqz $z0, $done // z0 == \0 1180*795d594fSAndroid Build Coastguard Worker beq $z0, $F, .L${uniq}_fpr_load_4_bytes 1181*795d594fSAndroid Build Coastguard Worker beq $z0, $D, .L${uniq}_fpr_load_8_bytes 1182*795d594fSAndroid Build Coastguard Worker 1183*795d594fSAndroid Build Coastguard Worker srliw $vregs, $vregs, 4 // shift out a skipped arg, one vreg 1184*795d594fSAndroid Build Coastguard Worker bne $z0, $J, .L${uniq}_fpr_find 1185*795d594fSAndroid Build Coastguard Worker srliw $vregs, $vregs, 4 // shift out one more skipped arg, for J 1186*795d594fSAndroid Build Coastguard Worker j .L${uniq}_fpr_find 1187*795d594fSAndroid Build Coastguard Worker 1188*795d594fSAndroid Build Coastguard Worker.L${uniq}_fpr_load_4_bytes: 1189*795d594fSAndroid Build Coastguard Worker andi $z0, $vregs, 0xF 1190*795d594fSAndroid Build Coastguard Worker% get_vreg_float(fpr, z0) 1191*795d594fSAndroid Build Coastguard Worker srliw $vregs, $vregs, 4 // shift out the processed arg, one vreg 1192*795d594fSAndroid Build Coastguard Worker j .L${uniq}_fpr_set 1193*795d594fSAndroid Build Coastguard Worker.L${uniq}_fpr_load_8_bytes: 1194*795d594fSAndroid Build Coastguard Worker andi $z0, $vregs, 0xF 1195*795d594fSAndroid Build Coastguard Worker GET_VREG_DOUBLE $fpr, $z0 1196*795d594fSAndroid Build Coastguard Worker srliw $vregs, $vregs, 8 // shift out the processed arg, a vreg pair 1197*795d594fSAndroid Build Coastguard Worker.L${uniq}_fpr_set: 1198*795d594fSAndroid Build Coastguard Worker 1199*795d594fSAndroid Build Coastguard Worker 1200*795d594fSAndroid Build Coastguard Worker// Range variant 1201*795d594fSAndroid Build Coastguard Worker%def load_vreg_in_gpr_range(gpr="", shorty="", idx="", D="", F="", J="", L="", z0="", done="", uniq=""): 1202*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_range_find: 1203*795d594fSAndroid Build Coastguard Worker lb $z0, ($shorty) // z0 := next shorty arg 1204*795d594fSAndroid Build Coastguard Worker addi $shorty, $shorty, 1 // increment char ptr 1205*795d594fSAndroid Build Coastguard Worker beqz $z0, $done // z0 == \0 1206*795d594fSAndroid Build Coastguard Worker beq $z0, $F, .L${uniq}_gpr_range_skip_1_vreg 1207*795d594fSAndroid Build Coastguard Worker beq $z0, $D, .L${uniq}_gpr_range_skip_2_vreg 1208*795d594fSAndroid Build Coastguard Worker 1209*795d594fSAndroid Build Coastguard Worker beq $z0, $J, .L${uniq}_gpr_range_load_2_vreg 1210*795d594fSAndroid Build Coastguard Worker% get_vreg(gpr, idx) 1211*795d594fSAndroid Build Coastguard Worker bne $z0, $L, .L${uniq}_gpr_range_load_common 1212*795d594fSAndroid Build Coastguard Worker zext.w $gpr, $gpr 1213*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_range_load_common: 1214*795d594fSAndroid Build Coastguard Worker addi $idx, $idx, 1 1215*795d594fSAndroid Build Coastguard Worker j .L${uniq}_gpr_range_done 1216*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_range_load_2_vreg: 1217*795d594fSAndroid Build Coastguard Worker GET_VREG_WIDE $gpr, $idx 1218*795d594fSAndroid Build Coastguard Worker addi $idx, $idx, 2 1219*795d594fSAndroid Build Coastguard Worker j .L${uniq}_gpr_range_done 1220*795d594fSAndroid Build Coastguard Worker 1221*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_range_skip_2_vreg: 1222*795d594fSAndroid Build Coastguard Worker addi $idx, $idx, 1 1223*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_range_skip_1_vreg: 1224*795d594fSAndroid Build Coastguard Worker addi $idx, $idx, 1 1225*795d594fSAndroid Build Coastguard Worker j .L${uniq}_gpr_range_find 1226*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_range_done: 1227*795d594fSAndroid Build Coastguard Worker 1228*795d594fSAndroid Build Coastguard Worker 1229*795d594fSAndroid Build Coastguard Worker// Range variant. 1230*795d594fSAndroid Build Coastguard Worker%def load_vreg_in_fpr_range(fpr="", shorty="", idx="", D="", F="", J="", z0="", done="", uniq=""): 1231*795d594fSAndroid Build Coastguard Worker.L${uniq}_fpr_range_find: 1232*795d594fSAndroid Build Coastguard Worker lb $z0, ($shorty) // z0 := next shorty arg 1233*795d594fSAndroid Build Coastguard Worker addi $shorty, $shorty, 1 // increment char ptr 1234*795d594fSAndroid Build Coastguard Worker beqz $z0, $done // z0 == \0 1235*795d594fSAndroid Build Coastguard Worker beq $z0, $F, .L${uniq}_fpr_range_load_4_bytes 1236*795d594fSAndroid Build Coastguard Worker beq $z0, $D, .L${uniq}_fpr_range_load_8_bytes 1237*795d594fSAndroid Build Coastguard Worker 1238*795d594fSAndroid Build Coastguard Worker addi $idx, $idx, 1 // increment idx 1239*795d594fSAndroid Build Coastguard Worker bne $z0, $J, .L${uniq}_fpr_range_find 1240*795d594fSAndroid Build Coastguard Worker addi $idx, $idx, 1 // increment once more for J 1241*795d594fSAndroid Build Coastguard Worker j .L${uniq}_fpr_range_find 1242*795d594fSAndroid Build Coastguard Worker 1243*795d594fSAndroid Build Coastguard Worker.L${uniq}_fpr_range_load_4_bytes: 1244*795d594fSAndroid Build Coastguard Worker mv $z0, $idx 1245*795d594fSAndroid Build Coastguard Worker% get_vreg_float(fpr, z0) 1246*795d594fSAndroid Build Coastguard Worker addi $idx, $idx, 1 1247*795d594fSAndroid Build Coastguard Worker j .L${uniq}_fpr_range_set 1248*795d594fSAndroid Build Coastguard Worker.L${uniq}_fpr_range_load_8_bytes: 1249*795d594fSAndroid Build Coastguard Worker mv $z0, $idx 1250*795d594fSAndroid Build Coastguard Worker GET_VREG_DOUBLE $fpr, $z0 1251*795d594fSAndroid Build Coastguard Worker addi $idx, $idx, 2 1252*795d594fSAndroid Build Coastguard Worker.L${uniq}_fpr_range_set: 1253*795d594fSAndroid Build Coastguard Worker 1254*795d594fSAndroid Build Coastguard Worker 1255*795d594fSAndroid Build Coastguard Worker%def is_out_stack_needed(needed="", shorty="", D="", F="", z0="", uniq=""): 1256*795d594fSAndroid Build Coastguard Worker.L${uniq}_scan_arg: 1257*795d594fSAndroid Build Coastguard Worker lb $z0, ($shorty) 1258*795d594fSAndroid Build Coastguard Worker addi $shorty, $shorty, 1 1259*795d594fSAndroid Build Coastguard Worker beqz $z0, .L${uniq}_scan_done 1260*795d594fSAndroid Build Coastguard Worker beq $z0, $F, .L${uniq}_scan_arg 1261*795d594fSAndroid Build Coastguard Worker beq $z0, $D, .L${uniq}_scan_arg 1262*795d594fSAndroid Build Coastguard Worker li $needed, 1 1263*795d594fSAndroid Build Coastguard Worker.L${uniq}_scan_done: 1264*795d594fSAndroid Build Coastguard Worker 1265*795d594fSAndroid Build Coastguard Worker 1266*795d594fSAndroid Build Coastguard Worker%def is_out_stack_needed_float(needed="", shorty="", D="", F="", z0="", uniq=""): 1267*795d594fSAndroid Build Coastguard Worker bnez $needed, .L${uniq}_scan_float_done 1268*795d594fSAndroid Build Coastguard Worker.L${uniq}_scan_float_arg: 1269*795d594fSAndroid Build Coastguard Worker lb $z0, ($shorty) 1270*795d594fSAndroid Build Coastguard Worker addi $shorty, $shorty, 1 1271*795d594fSAndroid Build Coastguard Worker beqz $z0, .L${uniq}_scan_float_done 1272*795d594fSAndroid Build Coastguard Worker beq $z0, $F, .L${uniq}_scan_float_found 1273*795d594fSAndroid Build Coastguard Worker beq $z0, $D, .L${uniq}_scan_float_found 1274*795d594fSAndroid Build Coastguard Worker j .L${uniq}_scan_float_arg 1275*795d594fSAndroid Build Coastguard Worker.L${uniq}_scan_float_found: 1276*795d594fSAndroid Build Coastguard Worker li $needed, 1 1277*795d594fSAndroid Build Coastguard Worker.L${uniq}_scan_float_done: 1278*795d594fSAndroid Build Coastguard Worker 1279*795d594fSAndroid Build Coastguard Worker 1280*795d594fSAndroid Build Coastguard Worker%def copy_vregs_to_out(out="", fp="", fp_top="", z0="", uniq=""): 1281*795d594fSAndroid Build Coastguard Worker sub $z0, $fp_top, $fp // z0 := byte range 1282*795d594fSAndroid Build Coastguard Worker BRANCH_IF_BIT_CLEAR $z0, $z0, 2, .L${uniq}_copy_wide 1283*795d594fSAndroid Build Coastguard Worker // branch if odd count of slots 1284*795d594fSAndroid Build Coastguard Worker lwu $z0, ($fp) 1285*795d594fSAndroid Build Coastguard Worker sw $z0, ($out) 1286*795d594fSAndroid Build Coastguard Worker addi $fp, $fp, 4 1287*795d594fSAndroid Build Coastguard Worker addi $out, $out, 4 1288*795d594fSAndroid Build Coastguard Worker.L${uniq}_copy_wide: 1289*795d594fSAndroid Build Coastguard Worker beq $fp, $fp_top, .L${uniq}_copy_done 1290*795d594fSAndroid Build Coastguard Worker ld $z0, ($fp) 1291*795d594fSAndroid Build Coastguard Worker sd $z0, ($out) 1292*795d594fSAndroid Build Coastguard Worker addi $fp, $fp, 8 1293*795d594fSAndroid Build Coastguard Worker addi $out, $out, 8 1294*795d594fSAndroid Build Coastguard Worker j .L${uniq}_copy_wide 1295*795d594fSAndroid Build Coastguard Worker.L${uniq}_copy_done: 1296*795d594fSAndroid Build Coastguard Worker 1297*795d594fSAndroid Build Coastguard Worker 1298*795d594fSAndroid Build Coastguard Worker// NterpToNterpInstance 1299*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod* 1300*795d594fSAndroid Build Coastguard Worker// a1: this 1301*795d594fSAndroid Build Coastguard Worker%def nterp_to_nterp_instance(): 1302*795d594fSAndroid Build Coastguard Worker% nterp_to_nterp(how_vC="in_a1", uniq="n2n_instance") 1303*795d594fSAndroid Build Coastguard Worker 1304*795d594fSAndroid Build Coastguard Worker 1305*795d594fSAndroid Build Coastguard Worker// NterpToNterpStringInit 1306*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod* 1307*795d594fSAndroid Build Coastguard Worker%def nterp_to_nterp_string_init(): 1308*795d594fSAndroid Build Coastguard Worker% nterp_to_nterp(how_vC="skip", uniq="n2n_string_init") 1309*795d594fSAndroid Build Coastguard Worker 1310*795d594fSAndroid Build Coastguard Worker 1311*795d594fSAndroid Build Coastguard Worker// NterpToNterpStatic 1312*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod* 1313*795d594fSAndroid Build Coastguard Worker%def nterp_to_nterp_static(): 1314*795d594fSAndroid Build Coastguard Worker% nterp_to_nterp(a1_instance=False, how_vC="load", uniq="n2n_static") 1315*795d594fSAndroid Build Coastguard Worker 1316*795d594fSAndroid Build Coastguard Worker 1317*795d594fSAndroid Build Coastguard Worker// NterpToNterpInstanceRange 1318*795d594fSAndroid Build Coastguard Worker%def nterp_to_nterp_instance_range(): 1319*795d594fSAndroid Build Coastguard Worker% nterp_to_nterp(how_vC="in_a1", uniq="n2n_instance_range", range="Range") 1320*795d594fSAndroid Build Coastguard Worker 1321*795d594fSAndroid Build Coastguard Worker 1322*795d594fSAndroid Build Coastguard Worker// NterpToNterpStringInitRange 1323*795d594fSAndroid Build Coastguard Worker%def nterp_to_nterp_string_init_range(): 1324*795d594fSAndroid Build Coastguard Worker% nterp_to_nterp(how_vC="skip", uniq="n2n_string_init_range", range="Range") 1325*795d594fSAndroid Build Coastguard Worker 1326*795d594fSAndroid Build Coastguard Worker 1327*795d594fSAndroid Build Coastguard Worker// NterpToNterpStaticRange 1328*795d594fSAndroid Build Coastguard Worker%def nterp_to_nterp_static_range(): 1329*795d594fSAndroid Build Coastguard Worker% nterp_to_nterp(a1_instance=False, how_vC="load", uniq="n2n_static_range", range="Range") 1330*795d594fSAndroid Build Coastguard Worker 1331*795d594fSAndroid Build Coastguard Worker 1332*795d594fSAndroid Build Coastguard Worker// helpers 1333*795d594fSAndroid Build Coastguard Worker 1334*795d594fSAndroid Build Coastguard Worker 1335*795d594fSAndroid Build Coastguard Worker%def nterp_to_nterp(a1_instance=True, how_vC="", uniq="", range=""): 1336*795d594fSAndroid Build Coastguard Worker .cfi_startproc 1337*795d594fSAndroid Build Coastguard Worker% setup_nterp_frame(cfi_refs="23", refs="s8", fp="s9", pc="s10", regs="s11", spills_sp="t0", z0="t1", z1="t2", z2="t3", z3="t4", uniq=uniq) 1338*795d594fSAndroid Build Coastguard Worker // s8 := callee xREFS 1339*795d594fSAndroid Build Coastguard Worker // s9 := callee xFP 1340*795d594fSAndroid Build Coastguard Worker // s10 := callee xPC 1341*795d594fSAndroid Build Coastguard Worker // s11 := fp/refs vreg count 1342*795d594fSAndroid Build Coastguard Worker // t0 := post-spills pre-frame sp (unused here) 1343*795d594fSAndroid Build Coastguard Worker // sp := post-frame callee sp 1344*795d594fSAndroid Build Coastguard Worker% if range == 'Range': 1345*795d594fSAndroid Build Coastguard Worker% n2n_arg_move_range(refs="s8", fp="s9", regs="s11", vC="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", a1_instance=a1_instance, how_vC=how_vC, uniq=uniq) 1346*795d594fSAndroid Build Coastguard Worker% else: 1347*795d594fSAndroid Build Coastguard Worker% n2n_arg_move(refs="s8", fp="s9", pc="s10", regs="s11", v_fedc="s7", z0="t0", z1="t1", z2="t2", z3="t3", a1_instance=a1_instance, how_vC=how_vC, uniq=uniq) 1348*795d594fSAndroid Build Coastguard Worker%#: 1349*795d594fSAndroid Build Coastguard Worker mv xREFS, s8 1350*795d594fSAndroid Build Coastguard Worker mv xFP, s9 1351*795d594fSAndroid Build Coastguard Worker mv xPC, s10 1352*795d594fSAndroid Build Coastguard Worker CFI_DEFINE_DEX_PC_WITH_OFFSET(/*tmpReg*/CFI_TMP, /*dexReg*/CFI_DEX, /*dexOffset*/0) 1353*795d594fSAndroid Build Coastguard Worker 1354*795d594fSAndroid Build Coastguard Worker START_EXECUTING_INSTRUCTIONS 1355*795d594fSAndroid Build Coastguard Worker .cfi_endproc 1356*795d594fSAndroid Build Coastguard Worker 1357*795d594fSAndroid Build Coastguard Worker 1358*795d594fSAndroid Build Coastguard Worker// See runtime/nterp_helpers.cc for a diagram of the setup. 1359*795d594fSAndroid Build Coastguard Worker// Hardcoded 1360*795d594fSAndroid Build Coastguard Worker// - a0 - ArtMethod* 1361*795d594fSAndroid Build Coastguard Worker// Input 1362*795d594fSAndroid Build Coastguard Worker// - \cfi_refs: dwarf register number of \refs, for CFI 1363*795d594fSAndroid Build Coastguard Worker// - \uniq: string to ensure unique symbolic labels between instantiations 1364*795d594fSAndroid Build Coastguard Worker// Output 1365*795d594fSAndroid Build Coastguard Worker// - sp: adjusted downward for callee-saves and nterp frame 1366*795d594fSAndroid Build Coastguard Worker// - \refs: callee xREFS 1367*795d594fSAndroid Build Coastguard Worker// - \fp: callee xFP 1368*795d594fSAndroid Build Coastguard Worker// - \pc: callee xPC 1369*795d594fSAndroid Build Coastguard Worker// - \regs: register count in \refs 1370*795d594fSAndroid Build Coastguard Worker// - \ins: in count 1371*795d594fSAndroid Build Coastguard Worker// - \spills_sp: stack pointer after reg spills 1372*795d594fSAndroid Build Coastguard Worker%def setup_nterp_frame(cfi_refs="", refs="", fp="", pc="", regs="", ins="zero", spills_sp="", z0="", z1="", z2="", z3="", uniq=""): 1373*795d594fSAndroid Build Coastguard Worker // Check guard page for stack overflow. 1374*795d594fSAndroid Build Coastguard Worker li $z0, -STACK_OVERFLOW_RESERVED_BYTES 1375*795d594fSAndroid Build Coastguard Worker add $z0, $z0, sp 1376*795d594fSAndroid Build Coastguard Worker ld zero, ($z0) 1377*795d594fSAndroid Build Coastguard Worker 1378*795d594fSAndroid Build Coastguard Worker INCREASE_FRAME NTERP_SIZE_SAVE_CALLEE_SAVES 1379*795d594fSAndroid Build Coastguard Worker // sp := sp + callee-saves 1380*795d594fSAndroid Build Coastguard Worker SETUP_NTERP_SAVE_CALLEE_SAVES 1381*795d594fSAndroid Build Coastguard Worker 1382*795d594fSAndroid Build Coastguard Worker ld $pc, ART_METHOD_DATA_OFFSET_64(a0) 1383*795d594fSAndroid Build Coastguard Worker FETCH_CODE_ITEM_INFO code_item=$pc, regs=$regs, outs=$z0, ins=$ins 1384*795d594fSAndroid Build Coastguard Worker // pc := callee dex array 1385*795d594fSAndroid Build Coastguard Worker // regs := vreg count for fp array and refs array 1386*795d594fSAndroid Build Coastguard Worker // z0 := vreg count for outs array 1387*795d594fSAndroid Build Coastguard Worker // ins := vreg count for ins array 1388*795d594fSAndroid Build Coastguard Worker 1389*795d594fSAndroid Build Coastguard Worker // Compute required frame size: ((2 * \regs) + \z0) * 4 + 24 1390*795d594fSAndroid Build Coastguard Worker // - The register array and reference array each have \regs number of slots. 1391*795d594fSAndroid Build Coastguard Worker // - The out array has \z0 slots. 1392*795d594fSAndroid Build Coastguard Worker // - Each register slot is 4 bytes. 1393*795d594fSAndroid Build Coastguard Worker // - Additional 24 bytes for 3 fields: saved frame pointer, dex pc, and ArtMethod*. 1394*795d594fSAndroid Build Coastguard Worker sh1add $z1, $regs, $z0 1395*795d594fSAndroid Build Coastguard Worker slli $z1, $z1, 2 1396*795d594fSAndroid Build Coastguard Worker addi $z1, $z1, 24 // z1 := frame size, without alignment padding 1397*795d594fSAndroid Build Coastguard Worker 1398*795d594fSAndroid Build Coastguard Worker // compute new stack pointer 1399*795d594fSAndroid Build Coastguard Worker sub $z1, sp, $z1 1400*795d594fSAndroid Build Coastguard Worker // 16-byte alignment. 1401*795d594fSAndroid Build Coastguard Worker andi $z1, $z1, ~0xF // z1 := new sp 1402*795d594fSAndroid Build Coastguard Worker 1403*795d594fSAndroid Build Coastguard Worker // Set \refs to base of reference array. Align to pointer size for the frame pointer and dex pc 1404*795d594fSAndroid Build Coastguard Worker // pointer, below the reference array. 1405*795d594fSAndroid Build Coastguard Worker sh2add $z0, $z0, $z1 // z0 := out array size in bytes 1406*795d594fSAndroid Build Coastguard Worker addi $z0, $z0, 28 // + 24 bytes for 3 fields, plus 4 for alignment slack. 1407*795d594fSAndroid Build Coastguard Worker andi $refs, $z0, -__SIZEOF_POINTER__ 1408*795d594fSAndroid Build Coastguard Worker // refs := refs array base 1409*795d594fSAndroid Build Coastguard Worker 1410*795d594fSAndroid Build Coastguard Worker // Set \fp to base of register array, above the reference array. This region is already aligned. 1411*795d594fSAndroid Build Coastguard Worker sh2add $fp, $regs, $refs 1412*795d594fSAndroid Build Coastguard Worker // fp := fp array base 1413*795d594fSAndroid Build Coastguard Worker 1414*795d594fSAndroid Build Coastguard Worker // Set up the stack pointer. 1415*795d594fSAndroid Build Coastguard Worker mv $spills_sp, sp // spills_sp := old sp 1416*795d594fSAndroid Build Coastguard Worker .cfi_def_cfa_register $spills_sp 1417*795d594fSAndroid Build Coastguard Worker mv sp, $z1 // sp := new sp 1418*795d594fSAndroid Build Coastguard Worker sd $spills_sp, -8($refs) 1419*795d594fSAndroid Build Coastguard Worker // The CFA rule is now a dwarf expression, because the nterp frame offset for SP is a dynamic 1420*795d594fSAndroid Build Coastguard Worker // value, and thus SP cannot help compute CFA. For the duration of the nterp frame, CFI 1421*795d594fSAndroid Build Coastguard Worker // directives cannot adjust this CFA rule, but may still capture CFI for register spills as 1422*795d594fSAndroid Build Coastguard Worker // "register + offset" with a dwarf expression. 1423*795d594fSAndroid Build Coastguard Worker CFI_DEF_CFA_BREG_PLUS_UCONST $cfi_refs, -8, NTERP_SIZE_SAVE_CALLEE_SAVES 1424*795d594fSAndroid Build Coastguard Worker 1425*795d594fSAndroid Build Coastguard Worker // Put nulls in reference array. 1426*795d594fSAndroid Build Coastguard Worker beqz $regs, .L${uniq}_ref_zero_done 1427*795d594fSAndroid Build Coastguard Worker mv $z0, $refs // z0 := address iterator 1428*795d594fSAndroid Build Coastguard Worker.L${uniq}_ref_zero: 1429*795d594fSAndroid Build Coastguard Worker // Write in 8-byte increments, so fp[0] gets zero'ed too, if \regs is odd. 1430*795d594fSAndroid Build Coastguard Worker sd zero, ($z0) 1431*795d594fSAndroid Build Coastguard Worker addi $z0, $z0, 8 1432*795d594fSAndroid Build Coastguard Worker bltu $z0, $fp, .L${uniq}_ref_zero 1433*795d594fSAndroid Build Coastguard Worker.L${uniq}_ref_zero_done: 1434*795d594fSAndroid Build Coastguard Worker // Save the ArtMethod*. 1435*795d594fSAndroid Build Coastguard Worker sd a0, (sp) 1436*795d594fSAndroid Build Coastguard Worker 1437*795d594fSAndroid Build Coastguard Worker 1438*795d594fSAndroid Build Coastguard Worker// Hardcoded 1439*795d594fSAndroid Build Coastguard Worker// - (caller) xINST, xFP, xREFS, xPC 1440*795d594fSAndroid Build Coastguard Worker// - a0: ArtMethod* 1441*795d594fSAndroid Build Coastguard Worker// - a1: this, for instance invoke 1442*795d594fSAndroid Build Coastguard Worker%def n2n_arg_move(refs="", fp="", regs="", pc="", v_fedc="", z0="", z1="", z2="", z3="", a1_instance=True, how_vC="", uniq=""): 1443*795d594fSAndroid Build Coastguard Worker srliw $z0, xINST, 12 // z0 := A (arg count) 1444*795d594fSAndroid Build Coastguard Worker 1445*795d594fSAndroid Build Coastguard Worker% if not a1_instance: 1446*795d594fSAndroid Build Coastguard Worker beqz $z0, .L${uniq}_arg_done 1447*795d594fSAndroid Build Coastguard Worker%#: 1448*795d594fSAndroid Build Coastguard Worker // A >= 1, decide and branch 1449*795d594fSAndroid Build Coastguard Worker li $z1, 2 1450*795d594fSAndroid Build Coastguard Worker sub $z2, $regs, $z0 // z2 := regs - A; vC's index in fp 1451*795d594fSAndroid Build Coastguard Worker sh2add $z3, $z2, $fp // z3 := addr of fp[C] 1452*795d594fSAndroid Build Coastguard Worker sh2add $z2, $z2, $refs // z2 := addr of refs[C] 1453*795d594fSAndroid Build Coastguard Worker blt $z0, $z1, .L${uniq}_arg_1 1454*795d594fSAndroid Build Coastguard Worker beq $z0, $z1, .L${uniq}_arg_2 1455*795d594fSAndroid Build Coastguard Worker li $z1, 4 1456*795d594fSAndroid Build Coastguard Worker blt $z0, $z1, .L${uniq}_arg_3 1457*795d594fSAndroid Build Coastguard Worker beq $z0, $z1, .L${uniq}_arg_4 1458*795d594fSAndroid Build Coastguard Worker 1459*795d594fSAndroid Build Coastguard Worker // A = 5 1460*795d594fSAndroid Build Coastguard Worker srliw $z0, xINST, 8 1461*795d594fSAndroid Build Coastguard Worker andi $z0, $z0, 0xF // z0 := G 1462*795d594fSAndroid Build Coastguard Worker% get_vreg(z1, z0) # z1 := xFP[G] 1463*795d594fSAndroid Build Coastguard Worker sw $z1, (4*4)($z3) // fp[G] := z1 1464*795d594fSAndroid Build Coastguard Worker GET_VREG_OBJECT $z0, $z0 // z0 := xREFS[G] 1465*795d594fSAndroid Build Coastguard Worker sw $z0, (4*4)($z2) // refs[G] := z0 1466*795d594fSAndroid Build Coastguard Worker.L${uniq}_arg_4: 1467*795d594fSAndroid Build Coastguard Worker srliw $z0, $v_fedc, 12 // z0 := F 1468*795d594fSAndroid Build Coastguard Worker% get_vreg(z1, z0) # z1 := xFP[F] 1469*795d594fSAndroid Build Coastguard Worker sw $z1, (3*4)($z3) // fp[F] := z1 1470*795d594fSAndroid Build Coastguard Worker GET_VREG_OBJECT $z0, $z0 // z0 := xREFS[F] 1471*795d594fSAndroid Build Coastguard Worker sw $z0, (3*4)($z2) // refs[F] := z0 1472*795d594fSAndroid Build Coastguard Worker.L${uniq}_arg_3: 1473*795d594fSAndroid Build Coastguard Worker srliw $z0, $v_fedc, 8 // z0 := F|E 1474*795d594fSAndroid Build Coastguard Worker andi $z0, $z0, 0xF // z0 := E 1475*795d594fSAndroid Build Coastguard Worker% get_vreg(z1, z0) # z1 := xFP[E] 1476*795d594fSAndroid Build Coastguard Worker sw $z1, (2*4)($z3) // fp[E] := z1 1477*795d594fSAndroid Build Coastguard Worker GET_VREG_OBJECT $z0, $z0 // z0 := xREFS[E] 1478*795d594fSAndroid Build Coastguard Worker sw $z0, (2*4)($z2) // refs[E] := z0 1479*795d594fSAndroid Build Coastguard Worker.L${uniq}_arg_2: 1480*795d594fSAndroid Build Coastguard Worker srliw $z0, $v_fedc, 4 // z0 := F|E|D 1481*795d594fSAndroid Build Coastguard Worker andi $z0, $z0, 0xF // z0 := D 1482*795d594fSAndroid Build Coastguard Worker% get_vreg(z1, z0) # z1 := xFP[D] 1483*795d594fSAndroid Build Coastguard Worker sw $z1, (1*4)($z3) // fp[D] := z1 1484*795d594fSAndroid Build Coastguard Worker GET_VREG_OBJECT $z0, $z0 // z0 := xREFS[D] 1485*795d594fSAndroid Build Coastguard Worker sw $z0, (1*4)($z2) // refs[D] := z0 1486*795d594fSAndroid Build Coastguard Worker.L${uniq}_arg_1: 1487*795d594fSAndroid Build Coastguard Worker% if how_vC == "in_a1": 1488*795d594fSAndroid Build Coastguard Worker // a1 = xFP[C] from earlier stage of instance invoke 1489*795d594fSAndroid Build Coastguard Worker sw a1, (0*4)($z3) // fp[C] := a1 1490*795d594fSAndroid Build Coastguard Worker sw a1, (0*4)($z2) // refs[C] := a1 1491*795d594fSAndroid Build Coastguard Worker% elif how_vC == "skip": 1492*795d594fSAndroid Build Coastguard Worker // string init doesn't read "this" 1493*795d594fSAndroid Build Coastguard Worker% elif how_vC == "load": 1494*795d594fSAndroid Build Coastguard Worker // static method loads vC just like other vregs 1495*795d594fSAndroid Build Coastguard Worker andi $z0, $v_fedc, 0xF // z0 := C 1496*795d594fSAndroid Build Coastguard Worker% get_vreg(z1, z0) # z1 := xFP[C] 1497*795d594fSAndroid Build Coastguard Worker sw $z1, (0*4)($z3) // fp[C] := z1 1498*795d594fSAndroid Build Coastguard Worker GET_VREG_OBJECT $z0, $z0 // z0 := xREFS[C] 1499*795d594fSAndroid Build Coastguard Worker sw $z0, (0*4)($z2) // refs[C] := z0 1500*795d594fSAndroid Build Coastguard Worker%#: 1501*795d594fSAndroid Build Coastguard Worker.L${uniq}_arg_done: 1502*795d594fSAndroid Build Coastguard Worker 1503*795d594fSAndroid Build Coastguard Worker 1504*795d594fSAndroid Build Coastguard Worker%def n2n_arg_move_range(refs="", fp="", regs="", vC="", z0="", z1="", z2="", z3="", z4="", z5="", a1_instance=True, how_vC="", uniq=""): 1505*795d594fSAndroid Build Coastguard Worker srliw $z0, xINST, 8 // z0 := AA (arg count) 1506*795d594fSAndroid Build Coastguard Worker 1507*795d594fSAndroid Build Coastguard Worker% if not a1_instance: 1508*795d594fSAndroid Build Coastguard Worker beqz $z0, .L${uniq}_arg_range_done 1509*795d594fSAndroid Build Coastguard Worker%#: 1510*795d594fSAndroid Build Coastguard Worker // AA >= 1, iterator setup 1511*795d594fSAndroid Build Coastguard Worker sub $z4, $regs, $z0 // z4 := regs - AA; starting idx in fp and refs 1512*795d594fSAndroid Build Coastguard Worker sh2add $z1, $vC, xREFS // z1 := addr of xREFS[CCCC] 1513*795d594fSAndroid Build Coastguard Worker sh2add $z2, $vC, xFP // z2 := addr of xFP[CCCC] 1514*795d594fSAndroid Build Coastguard Worker sh2add $z3, $z4, $refs // z3 := addr of refs[z4] 1515*795d594fSAndroid Build Coastguard Worker sh2add $z4, $z4, $fp // z4 := addr of fp[z4] 1516*795d594fSAndroid Build Coastguard Worker 1517*795d594fSAndroid Build Coastguard Worker BRANCH_IF_BIT_CLEAR $z0, $z0, 0, .L${uniq}_arg_range_copy_wide 1518*795d594fSAndroid Build Coastguard Worker // branch if AA is even 1519*795d594fSAndroid Build Coastguard Worker // AA is odd, transfer one slot. Apply some optimizations. 1520*795d594fSAndroid Build Coastguard Worker% if how_vC == "in_a1": 1521*795d594fSAndroid Build Coastguard Worker sw a1, ($z3) 1522*795d594fSAndroid Build Coastguard Worker sw a1, ($z4) 1523*795d594fSAndroid Build Coastguard Worker% elif how_vC == "skip": 1524*795d594fSAndroid Build Coastguard Worker // string init doesn't read "this" 1525*795d594fSAndroid Build Coastguard Worker% elif how_vC == "load": 1526*795d594fSAndroid Build Coastguard Worker lw $z0, ($z1) 1527*795d594fSAndroid Build Coastguard Worker lw $z5, ($z2) 1528*795d594fSAndroid Build Coastguard Worker sw $z0, ($z3) 1529*795d594fSAndroid Build Coastguard Worker sw $z5, ($z4) 1530*795d594fSAndroid Build Coastguard Worker%#: 1531*795d594fSAndroid Build Coastguard Worker addi $z1, $z1, 4 1532*795d594fSAndroid Build Coastguard Worker addi $z2, $z2, 4 1533*795d594fSAndroid Build Coastguard Worker addi $z3, $z3, 4 1534*795d594fSAndroid Build Coastguard Worker addi $z4, $z4, 4 1535*795d594fSAndroid Build Coastguard Worker.L${uniq}_arg_range_copy_wide: 1536*795d594fSAndroid Build Coastguard Worker // Even count of vreg slots, apply LD/SD. 1537*795d594fSAndroid Build Coastguard Worker beq $z3, $fp, .L${uniq}_arg_range_done // terminate loop if refs[regs] == fp[0] 1538*795d594fSAndroid Build Coastguard Worker ld $z0, ($z1) 1539*795d594fSAndroid Build Coastguard Worker ld $z5, ($z2) 1540*795d594fSAndroid Build Coastguard Worker sd $z0, ($z3) 1541*795d594fSAndroid Build Coastguard Worker sd $z5, ($z4) 1542*795d594fSAndroid Build Coastguard Worker addi $z1, $z1, 8 1543*795d594fSAndroid Build Coastguard Worker addi $z2, $z2, 8 1544*795d594fSAndroid Build Coastguard Worker addi $z3, $z3, 8 1545*795d594fSAndroid Build Coastguard Worker addi $z4, $z4, 8 1546*795d594fSAndroid Build Coastguard Worker j .L${uniq}_arg_range_copy_wide 1547*795d594fSAndroid Build Coastguard Worker.L${uniq}_arg_range_done: 1548*795d594fSAndroid Build Coastguard Worker 1549*795d594fSAndroid Build Coastguard Worker 1550*795d594fSAndroid Build Coastguard Worker// 1551*795d594fSAndroid Build Coastguard Worker// Nterp entry point helpers 1552*795d594fSAndroid Build Coastguard Worker// 1553*795d594fSAndroid Build Coastguard Worker 1554*795d594fSAndroid Build Coastguard Worker 1555*795d594fSAndroid Build Coastguard Worker// Hardcoded: 1556*795d594fSAndroid Build Coastguard Worker// - a0: ArtMethod* 1557*795d594fSAndroid Build Coastguard Worker%def setup_ref_args_and_go(fp="", refs="", refs_end="", spills_sp="", z0="", z1="", done=""): 1558*795d594fSAndroid Build Coastguard Worker // Store managed-ABI register args into fp/refs arrays. 1559*795d594fSAndroid Build Coastguard Worker% store_ref_to_vreg(gpr="a1", fp=fp, refs=refs, refs_end=refs_end, done=done) 1560*795d594fSAndroid Build Coastguard Worker% store_ref_to_vreg(gpr="a2", fp=fp, refs=refs, refs_end=refs_end, done=done) 1561*795d594fSAndroid Build Coastguard Worker% store_ref_to_vreg(gpr="a3", fp=fp, refs=refs, refs_end=refs_end, done=done) 1562*795d594fSAndroid Build Coastguard Worker% store_ref_to_vreg(gpr="a4", fp=fp, refs=refs, refs_end=refs_end, done=done) 1563*795d594fSAndroid Build Coastguard Worker% store_ref_to_vreg(gpr="a5", fp=fp, refs=refs, refs_end=refs_end, done=done) 1564*795d594fSAndroid Build Coastguard Worker% store_ref_to_vreg(gpr="a6", fp=fp, refs=refs, refs_end=refs_end, done=done) 1565*795d594fSAndroid Build Coastguard Worker% store_ref_to_vreg(gpr="a7", fp=fp, refs=refs, refs_end=refs_end, done=done) 1566*795d594fSAndroid Build Coastguard Worker // We drained arg registers, so continue from caller's stack. 1567*795d594fSAndroid Build Coastguard Worker // A ref arg is 4 bytes, so the continuation offset is well known. 1568*795d594fSAndroid Build Coastguard Worker addi $z0, $spills_sp, (NTERP_SIZE_SAVE_CALLEE_SAVES + 8 + 7*4) 1569*795d594fSAndroid Build Coastguard Worker // z0 := out array base addr + 7 vreg slots 1570*795d594fSAndroid Build Coastguard Worker.Lentry_ref_stack: 1571*795d594fSAndroid Build Coastguard Worker lwu $z1, ($z0) 1572*795d594fSAndroid Build Coastguard Worker sw $z1, ($fp) 1573*795d594fSAndroid Build Coastguard Worker sw $z1, ($refs) 1574*795d594fSAndroid Build Coastguard Worker addi $z0, $z0, 4 1575*795d594fSAndroid Build Coastguard Worker addi $fp, $fp, 4 1576*795d594fSAndroid Build Coastguard Worker addi $refs, $refs, 4 1577*795d594fSAndroid Build Coastguard Worker bne $refs, $refs_end, .Lentry_ref_stack 1578*795d594fSAndroid Build Coastguard Worker 1579*795d594fSAndroid Build Coastguard Worker j $done 1580*795d594fSAndroid Build Coastguard Worker 1581*795d594fSAndroid Build Coastguard Worker 1582*795d594fSAndroid Build Coastguard Worker%def store_ref_to_vreg(gpr="", fp="", refs="", refs_end="", done=""): 1583*795d594fSAndroid Build Coastguard Worker sw $gpr, ($fp) 1584*795d594fSAndroid Build Coastguard Worker sw $gpr, ($refs) 1585*795d594fSAndroid Build Coastguard Worker addi $fp, $fp, 4 1586*795d594fSAndroid Build Coastguard Worker addi $refs, $refs, 4 1587*795d594fSAndroid Build Coastguard Worker beq $refs, $refs_end, $done 1588*795d594fSAndroid Build Coastguard Worker 1589*795d594fSAndroid Build Coastguard Worker 1590*795d594fSAndroid Build Coastguard Worker// \fp and \refs are used as array base addrs, unmodified. 1591*795d594fSAndroid Build Coastguard Worker%def store_gpr_to_vreg(gpr="", offset="", shorty="", fp="", refs="", z0="", z1="", D="", F="", J="", L="", next=""): 1592*795d594fSAndroid Build Coastguard Worker.Lentry_arg_${gpr}: 1593*795d594fSAndroid Build Coastguard Worker lb $z0, ($shorty) // z0 := shorty type 1594*795d594fSAndroid Build Coastguard Worker addi $shorty, $shorty, 1 // Increment char ptr. 1595*795d594fSAndroid Build Coastguard Worker beqz $z0, $next // z0 = \0: finished shorty pass 1596*795d594fSAndroid Build Coastguard Worker beq $z0, $D, .Lentry_arg_skip_double_${gpr} 1597*795d594fSAndroid Build Coastguard Worker beq $z0, $F, .Lentry_arg_skip_float_${gpr} 1598*795d594fSAndroid Build Coastguard Worker 1599*795d594fSAndroid Build Coastguard Worker add $z1, $offset, $fp 1600*795d594fSAndroid Build Coastguard Worker beq $z0, $J, .Lentry_arg_long_${gpr} 1601*795d594fSAndroid Build Coastguard Worker sw $gpr, ($z1) 1602*795d594fSAndroid Build Coastguard Worker bne $z0, $L, .Lentry_arg_finish_${gpr} 1603*795d594fSAndroid Build Coastguard Worker add $z1, $offset, $refs 1604*795d594fSAndroid Build Coastguard Worker sw $gpr, ($z1) 1605*795d594fSAndroid Build Coastguard Worker j .Lentry_arg_finish_${gpr} 1606*795d594fSAndroid Build Coastguard Worker.Lentry_arg_skip_double_${gpr}: 1607*795d594fSAndroid Build Coastguard Worker addi $offset, $offset, 4 1608*795d594fSAndroid Build Coastguard Worker.Lentry_arg_skip_float_${gpr}: 1609*795d594fSAndroid Build Coastguard Worker addi $offset, $offset, 4 1610*795d594fSAndroid Build Coastguard Worker j .Lentry_arg_${gpr} 1611*795d594fSAndroid Build Coastguard Worker.Lentry_arg_long_${gpr}: 1612*795d594fSAndroid Build Coastguard Worker sd $gpr, ($z1) 1613*795d594fSAndroid Build Coastguard Worker addi $offset, $offset, 4 1614*795d594fSAndroid Build Coastguard Worker.Lentry_arg_finish_${gpr}: 1615*795d594fSAndroid Build Coastguard Worker addi $offset, $offset, 4 1616*795d594fSAndroid Build Coastguard Worker 1617*795d594fSAndroid Build Coastguard Worker 1618*795d594fSAndroid Build Coastguard Worker// \fp is used as array base addr, unmodified. 1619*795d594fSAndroid Build Coastguard Worker%def store_fpr_to_vreg(fpr="", offset="", shorty="", fp="", z0="", z1="", D="", F="", J="", next=""): 1620*795d594fSAndroid Build Coastguard Worker.Lentry_farg_${fpr}: 1621*795d594fSAndroid Build Coastguard Worker lb $z0, ($shorty) // z0 := shorty type 1622*795d594fSAndroid Build Coastguard Worker addi $shorty, $shorty, 1 // Increment char ptr. 1623*795d594fSAndroid Build Coastguard Worker beqz $z0, $next // z0 = \0: finished shorty pass 1624*795d594fSAndroid Build Coastguard Worker beq $z0, $D, .Lentry_farg_double_${fpr} 1625*795d594fSAndroid Build Coastguard Worker beq $z0, $F, .Lentry_farg_float_${fpr} 1626*795d594fSAndroid Build Coastguard Worker addi $offset, $offset, 4 1627*795d594fSAndroid Build Coastguard Worker bne $z0, $J, .Lentry_farg_${fpr} 1628*795d594fSAndroid Build Coastguard Worker addi $offset, $offset, 4 1629*795d594fSAndroid Build Coastguard Worker j .Lentry_farg_${fpr} 1630*795d594fSAndroid Build Coastguard Worker 1631*795d594fSAndroid Build Coastguard Worker.Lentry_farg_float_${fpr}: 1632*795d594fSAndroid Build Coastguard Worker add $z1, $offset, $fp 1633*795d594fSAndroid Build Coastguard Worker fsw $fpr, ($z1) 1634*795d594fSAndroid Build Coastguard Worker j .Lentry_farg_finish_${fpr} 1635*795d594fSAndroid Build Coastguard Worker.Lentry_farg_double_${fpr}: 1636*795d594fSAndroid Build Coastguard Worker add $z1, $offset, $fp 1637*795d594fSAndroid Build Coastguard Worker fsd $fpr, ($z1) 1638*795d594fSAndroid Build Coastguard Worker addi $offset, $offset, 4 1639*795d594fSAndroid Build Coastguard Worker.Lentry_farg_finish_${fpr}: 1640*795d594fSAndroid Build Coastguard Worker addi $offset, $offset, 4 1641*795d594fSAndroid Build Coastguard Worker 1642*795d594fSAndroid Build Coastguard Worker 1643*795d594fSAndroid Build Coastguard Worker// \outs, \fp, \refs are used as iterators, modified. 1644*795d594fSAndroid Build Coastguard Worker%def store_outs_to_vregs(outs="", shorty="", fp="", refs="", z0="", z1="", D="", F="", J="", L="", next=""): 1645*795d594fSAndroid Build Coastguard Worker.Lentry_stack: 1646*795d594fSAndroid Build Coastguard Worker lb $z0, ($shorty) // z0 := next shorty arg spec 1647*795d594fSAndroid Build Coastguard Worker addi $shorty, $shorty, 1 // Increment char ptr. 1648*795d594fSAndroid Build Coastguard Worker beqz $z0, $next // z0 == \0 1649*795d594fSAndroid Build Coastguard Worker beq $z0, $F, .Lentry_stack_next_4 1650*795d594fSAndroid Build Coastguard Worker beq $z0, $D, .Lentry_stack_next_8 1651*795d594fSAndroid Build Coastguard Worker beq $z0, $J, .Lentry_stack_long 1652*795d594fSAndroid Build Coastguard Worker // 32-bit arg 1653*795d594fSAndroid Build Coastguard Worker lwu $z1, ($outs) 1654*795d594fSAndroid Build Coastguard Worker sw $z1, ($fp) 1655*795d594fSAndroid Build Coastguard Worker bne $z0, $L, .Lentry_stack_next_4 1656*795d594fSAndroid Build Coastguard Worker // and also a ref 1657*795d594fSAndroid Build Coastguard Worker sw $z1, ($refs) 1658*795d594fSAndroid Build Coastguard Worker.Lentry_stack_next_4: 1659*795d594fSAndroid Build Coastguard Worker addi $outs, $outs, 4 1660*795d594fSAndroid Build Coastguard Worker addi $fp, $fp, 4 1661*795d594fSAndroid Build Coastguard Worker addi $refs, $refs, 4 1662*795d594fSAndroid Build Coastguard Worker j .Lentry_stack 1663*795d594fSAndroid Build Coastguard Worker.Lentry_stack_long: 1664*795d594fSAndroid Build Coastguard Worker ld $z1, ($outs) 1665*795d594fSAndroid Build Coastguard Worker sd $z1, ($fp) 1666*795d594fSAndroid Build Coastguard Worker.Lentry_stack_next_8: 1667*795d594fSAndroid Build Coastguard Worker addi $outs, $outs, 8 1668*795d594fSAndroid Build Coastguard Worker addi $fp, $fp, 8 1669*795d594fSAndroid Build Coastguard Worker addi $refs, $refs, 8 1670*795d594fSAndroid Build Coastguard Worker j .Lentry_stack 1671*795d594fSAndroid Build Coastguard Worker 1672*795d594fSAndroid Build Coastguard Worker 1673*795d594fSAndroid Build Coastguard Worker// \outs, \fp are used as iterators, modified. 1674*795d594fSAndroid Build Coastguard Worker%def store_float_outs_to_vregs(outs="", shorty="", fp="", z0="", D="", F="", J="", next=""): 1675*795d594fSAndroid Build Coastguard Worker.Lentry_fstack: 1676*795d594fSAndroid Build Coastguard Worker lb $z0, ($shorty) // z0 := next shorty arg spec 1677*795d594fSAndroid Build Coastguard Worker addi $shorty, $shorty, 1 // Increment char ptr. 1678*795d594fSAndroid Build Coastguard Worker beqz $z0, $next // z0 == \0 1679*795d594fSAndroid Build Coastguard Worker beq $z0, $F, .Lentry_fstack_float 1680*795d594fSAndroid Build Coastguard Worker beq $z0, $D, .Lentry_fstack_double 1681*795d594fSAndroid Build Coastguard Worker beq $z0, $J, .Lentry_fstack_next_8 1682*795d594fSAndroid Build Coastguard Worker // 32-bit arg 1683*795d594fSAndroid Build Coastguard Worker addi $outs, $outs, 4 1684*795d594fSAndroid Build Coastguard Worker addi $fp, $fp, 4 1685*795d594fSAndroid Build Coastguard Worker j .Lentry_fstack 1686*795d594fSAndroid Build Coastguard Worker.Lentry_fstack_float: 1687*795d594fSAndroid Build Coastguard Worker lwu $z0, ($outs) 1688*795d594fSAndroid Build Coastguard Worker sw $z0, ($fp) 1689*795d594fSAndroid Build Coastguard Worker addi $outs, $outs, 4 1690*795d594fSAndroid Build Coastguard Worker addi $fp, $fp, 4 1691*795d594fSAndroid Build Coastguard Worker j .Lentry_fstack 1692*795d594fSAndroid Build Coastguard Worker.Lentry_fstack_double: 1693*795d594fSAndroid Build Coastguard Worker ld $z0, ($outs) 1694*795d594fSAndroid Build Coastguard Worker sd $z0, ($fp) 1695*795d594fSAndroid Build Coastguard Worker.Lentry_fstack_next_8: 1696*795d594fSAndroid Build Coastguard Worker addi $outs, $outs, 8 1697*795d594fSAndroid Build Coastguard Worker addi $fp, $fp, 8 1698*795d594fSAndroid Build Coastguard Worker j .Lentry_fstack 1699*795d594fSAndroid Build Coastguard Worker 1700