quick_entrypoints_arm64.S revision 63206f3038d3d6e1cb24166726613808a4b0ad8c
136836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com/* 236836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * Copyright (C) 2014 The Android Open Source Project 300fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * 436836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * Licensed under the Apache License, Version 2.0 (the "License"); 536836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * you may not use this file except in compliance with the License. 636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * You may obtain a copy of the License at 736836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * 836836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * http://www.apache.org/licenses/LICENSE-2.0 936836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * 1036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * Unless required by applicable law or agreed to in writing, software 1136836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * distributed under the License is distributed on an "AS IS" BASIS, 1236836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1336836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * See the License for the specific language governing permissions and 1436836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * limitations under the License. 1536836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com */ 1636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com 1736836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com#include "asm_support_arm64.S" 1836836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com 1936836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com#include "arch/quick_alloc_entrypoints.S" 2036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com 2136836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com 2236836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com /* 2336836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * Macro that sets up the callee save frame to conform with 2436836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * Runtime::CreateCalleeSaveMethod(kSaveAll) 2536836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com */ 2636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME 2736836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com adrp x9, :got:_ZN3art7Runtime9instance_E 2836836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com ldr x9, [x9, #:got_lo12:_ZN3art7Runtime9instance_E] 2936836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com 3036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com // Our registers aren't intermixed - just spill in order. 317e25c35df7786c98bc6fa96958e93146ca73367aBen Gruver ldr x9,[x9] // x9 = & (art::Runtime * art::Runtime.instance_) . 3213705697c23cb2d72bea75d661390be26fea50a4Ben Gruver 336ef13753e78bb7abc7e7683d5e533c3395d4a9b6JesusFreke@JesusFreke.com // x9 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs] . 348b1508ee58f4918835d8c01483725b508d21be29Ben Gruver ldr x9, [x9, RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET ] 358b1508ee58f4918835d8c01483725b508d21be29Ben Gruver 36bbf4dbba6127ef96e316060b2b4ec292627a4078JesusFreke@JesusFreke.com sub sp, sp, #368 374b72225e9d81201838f387171a68a832486903f9JesusFreke@JesusFreke.com .cfi_adjust_cfa_offset 368 3836836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com 3922e85fc3ff3d85e8a30fc42438ccb942fc5d80dfBen Gruver // Ugly compile-time check, but we only have the preprocessor. 40e9ee92dc4c0848146e00d5607eb4baa5750361c8JesusFreke@JesusFreke.com#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 368) 4122e85fc3ff3d85e8a30fc42438ccb942fc5d80dfBen Gruver#error "SAVE_ALL_CALLEE_SAVE_FRAME(ARM64) size not as expected." 4213705697c23cb2d72bea75d661390be26fea50a4Ben Gruver#endif 4322e85fc3ff3d85e8a30fc42438ccb942fc5d80dfBen Gruver 447e25c35df7786c98bc6fa96958e93146ca73367aBen Gruver // FP args 4536836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com stp d1, d2, [sp, #8] 465a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver stp d2, d3, [sp, #24] 475a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver stp d4, d5, [sp, #40] 4822e85fc3ff3d85e8a30fc42438ccb942fc5d80dfBen Gruver stp d6, d7, [sp, #56] 4922e85fc3ff3d85e8a30fc42438ccb942fc5d80dfBen Gruver 5022e85fc3ff3d85e8a30fc42438ccb942fc5d80dfBen Gruver // FP callee-saves 5122e85fc3ff3d85e8a30fc42438ccb942fc5d80dfBen Gruver stp d8, d9, [sp, #72] 5222e85fc3ff3d85e8a30fc42438ccb942fc5d80dfBen Gruver stp d10, d11, [sp, #88] 53e9ee92dc4c0848146e00d5607eb4baa5750361c8JesusFreke@JesusFreke.com stp d12, d13, [sp, #104] 54a6e5671a627284347484db96f40a29a45e4e4ed1JesusFreke@JesusFreke.com stp d14, d15, [sp, #120] 55a6e5671a627284347484db96f40a29a45e4e4ed1JesusFreke@JesusFreke.com 56a6e5671a627284347484db96f40a29a45e4e4ed1JesusFreke@JesusFreke.com stp d16, d17, [sp, #136] 57a6e5671a627284347484db96f40a29a45e4e4ed1JesusFreke@JesusFreke.com stp d18, d19, [sp, #152] 5813705697c23cb2d72bea75d661390be26fea50a4Ben Gruver stp d20, d21, [sp, #168] 59987cdc3e0e1ee99c104837192ea1f63e4fa5565aBen Gruver stp d22, d23, [sp, #184] 605a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver stp d24, d25, [sp, #200] 61a6e5671a627284347484db96f40a29a45e4e4ed1JesusFreke@JesusFreke.com stp d26, d27, [sp, #216] 625a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver stp d28, d29, [sp, #232] 63dea5f8d544040e506b550116bd7874d27436b99bBen Gruver stp d30, d31, [sp, #248] 647e25c35df7786c98bc6fa96958e93146ca73367aBen Gruver 6522e85fc3ff3d85e8a30fc42438ccb942fc5d80dfBen Gruver 6622e85fc3ff3d85e8a30fc42438ccb942fc5d80dfBen Gruver // Callee saved. 6722e85fc3ff3d85e8a30fc42438ccb942fc5d80dfBen Gruver stp xSELF, x19, [sp, #264] 6822e85fc3ff3d85e8a30fc42438ccb942fc5d80dfBen Gruver .cfi_rel_offset x18, 264 6922e85fc3ff3d85e8a30fc42438ccb942fc5d80dfBen Gruver .cfi_rel_offset x19, 272 707e25c35df7786c98bc6fa96958e93146ca73367aBen Gruver 7122e85fc3ff3d85e8a30fc42438ccb942fc5d80dfBen Gruver stp x20, x21, [sp, #280] 7222e85fc3ff3d85e8a30fc42438ccb942fc5d80dfBen Gruver .cfi_rel_offset x20, 280 7322e85fc3ff3d85e8a30fc42438ccb942fc5d80dfBen Gruver .cfi_rel_offset x21, 288 74dea5f8d544040e506b550116bd7874d27436b99bBen Gruver 75dea5f8d544040e506b550116bd7874d27436b99bBen Gruver stp x22, x23, [sp, #296] 76dea5f8d544040e506b550116bd7874d27436b99bBen Gruver .cfi_rel_offset x22, 296 777e25c35df7786c98bc6fa96958e93146ca73367aBen Gruver .cfi_rel_offset x23, 304 787e25c35df7786c98bc6fa96958e93146ca73367aBen Gruver 797e25c35df7786c98bc6fa96958e93146ca73367aBen Gruver stp x24, x25, [sp, #312] 807e25c35df7786c98bc6fa96958e93146ca73367aBen Gruver .cfi_rel_offset x24, 312 81dea5f8d544040e506b550116bd7874d27436b99bBen Gruver .cfi_rel_offset x25, 320 82eae0b0edbf3f0feedc289655144c54d27cb2ddccBen Gruver 83eae0b0edbf3f0feedc289655144c54d27cb2ddccBen Gruver stp x26, x27, [sp, #328] 84eae0b0edbf3f0feedc289655144c54d27cb2ddccBen Gruver .cfi_rel_offset x26, 328 85eae0b0edbf3f0feedc289655144c54d27cb2ddccBen Gruver .cfi_rel_offset x27, 336 86eae0b0edbf3f0feedc289655144c54d27cb2ddccBen Gruver 87eae0b0edbf3f0feedc289655144c54d27cb2ddccBen Gruver stp x28, xFP, [sp, #344] // Save FP. 88eae0b0edbf3f0feedc289655144c54d27cb2ddccBen Gruver .cfi_rel_offset x28, 344 89eae0b0edbf3f0feedc289655144c54d27cb2ddccBen Gruver .cfi_rel_offset x29, 352 90eae0b0edbf3f0feedc289655144c54d27cb2ddccBen Gruver 91eae0b0edbf3f0feedc289655144c54d27cb2ddccBen Gruver str xLR, [sp, #360] 92eae0b0edbf3f0feedc289655144c54d27cb2ddccBen Gruver .cfi_rel_offset x30, 360 93dea5f8d544040e506b550116bd7874d27436b99bBen Gruver 94eae0b0edbf3f0feedc289655144c54d27cb2ddccBen Gruver // Loads appropriate callee-save-method 957e25c35df7786c98bc6fa96958e93146ca73367aBen Gruver str x9, [sp] // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs] 967e25c35df7786c98bc6fa96958e93146ca73367aBen Gruver 97eae0b0edbf3f0feedc289655144c54d27cb2ddccBen Gruver.endm 98eae0b0edbf3f0feedc289655144c54d27cb2ddccBen Gruver 994b171afedb983fb811990beeec6a15e30a90b455Ben Gruver /* 100dea5f8d544040e506b550116bd7874d27436b99bBen Gruver * Macro that sets up the callee save frame to conform with 1014b171afedb983fb811990beeec6a15e30a90b455Ben Gruver * Runtime::CreateCalleeSaveMethod(kRefsOnly). 10281014659d928284a14fafc23bc239e39de836d83JesusFreke@JesusFreke.com */ 103dea5f8d544040e506b550116bd7874d27436b99bBen Gruver// WIP. 1045a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver.macro SETUP_REF_ONLY_CALLEE_SAVE_FRAME 1054b171afedb983fb811990beeec6a15e30a90b455Ben Gruver adrp x9, :got:_ZN3art7Runtime9instance_E 1064b171afedb983fb811990beeec6a15e30a90b455Ben Gruver ldr x9, [x9, #:got_lo12:_ZN3art7Runtime9instance_E] 1074b171afedb983fb811990beeec6a15e30a90b455Ben Gruver 1084b171afedb983fb811990beeec6a15e30a90b455Ben Gruver // Our registers aren't intermixed - just spill in order. 1094b171afedb983fb811990beeec6a15e30a90b455Ben Gruver ldr x9,[x9] // x9 = & (art::Runtime * art::Runtime.instance_) . 1104b171afedb983fb811990beeec6a15e30a90b455Ben Gruver 1114b171afedb983fb811990beeec6a15e30a90b455Ben Gruver // x9 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs] . 1124b171afedb983fb811990beeec6a15e30a90b455Ben Gruver ldr x9, [x9, RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET ] 1134b171afedb983fb811990beeec6a15e30a90b455Ben Gruver 1144b171afedb983fb811990beeec6a15e30a90b455Ben Gruver sub sp, sp, #176 1154b171afedb983fb811990beeec6a15e30a90b455Ben Gruver .cfi_adjust_cfa_offset 176 1164b171afedb983fb811990beeec6a15e30a90b455Ben Gruver 1174b171afedb983fb811990beeec6a15e30a90b455Ben Gruver // Ugly compile-time check, but we only have the preprocessor. 118dea5f8d544040e506b550116bd7874d27436b99bBen Gruver#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 176) 1194b171afedb983fb811990beeec6a15e30a90b455Ben Gruver#error "REFS_ONLY_CALLEE_SAVE_FRAME(ARM64) size not as expected." 12081014659d928284a14fafc23bc239e39de836d83JesusFreke@JesusFreke.com#endif 1214b171afedb983fb811990beeec6a15e30a90b455Ben Gruver 12236836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com // FP callee-saves 1234b171afedb983fb811990beeec6a15e30a90b455Ben Gruver stp d8, d9, [sp, #8] 1244b171afedb983fb811990beeec6a15e30a90b455Ben Gruver stp d10, d11, [sp, #24] 1256eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com stp d12, d13, [sp, #40] 1264b171afedb983fb811990beeec6a15e30a90b455Ben Gruver stp d14, d15, [sp, #56] 1274b171afedb983fb811990beeec6a15e30a90b455Ben Gruver 1284b171afedb983fb811990beeec6a15e30a90b455Ben Gruver // Callee saved. 1294b171afedb983fb811990beeec6a15e30a90b455Ben Gruver stp xSELF, x19, [sp, #72] 1304b171afedb983fb811990beeec6a15e30a90b455Ben Gruver .cfi_rel_offset x18, 72 1314b171afedb983fb811990beeec6a15e30a90b455Ben Gruver .cfi_rel_offset x19, 80 1324b171afedb983fb811990beeec6a15e30a90b455Ben Gruver 1337e25c35df7786c98bc6fa96958e93146ca73367aBen Gruver stp x20, x21, [sp, #88] 1347e25c35df7786c98bc6fa96958e93146ca73367aBen Gruver .cfi_rel_offset x20, 88 1357e25c35df7786c98bc6fa96958e93146ca73367aBen Gruver .cfi_rel_offset x21, 96 136dea5f8d544040e506b550116bd7874d27436b99bBen Gruver 1377e25c35df7786c98bc6fa96958e93146ca73367aBen Gruver stp x22, x23, [sp, #104] 1384b171afedb983fb811990beeec6a15e30a90b455Ben Gruver .cfi_rel_offset x22, 104 13981014659d928284a14fafc23bc239e39de836d83JesusFreke@JesusFreke.com .cfi_rel_offset x23, 112 1404b171afedb983fb811990beeec6a15e30a90b455Ben Gruver 1414b171afedb983fb811990beeec6a15e30a90b455Ben Gruver stp x24, x25, [sp, #120] 1424b171afedb983fb811990beeec6a15e30a90b455Ben Gruver .cfi_rel_offset x24, 120 1434b171afedb983fb811990beeec6a15e30a90b455Ben Gruver .cfi_rel_offset x25, 128 144dea5f8d544040e506b550116bd7874d27436b99bBen Gruver 14581014659d928284a14fafc23bc239e39de836d83JesusFreke@JesusFreke.com stp x26, x27, [sp, #136] 146e9ee92dc4c0848146e00d5607eb4baa5750361c8JesusFreke@JesusFreke.com .cfi_rel_offset x26, 136 1472371e35aaeaf2ed4d7c571fb3286090eb01b717dJesusFreke@JesusFreke.com .cfi_rel_offset x27, 144 1484b171afedb983fb811990beeec6a15e30a90b455Ben Gruver 1494b171afedb983fb811990beeec6a15e30a90b455Ben Gruver stp x28, xFP, [sp, #152] // Save FP. 1504b171afedb983fb811990beeec6a15e30a90b455Ben Gruver .cfi_rel_offset x28, 152 1514b171afedb983fb811990beeec6a15e30a90b455Ben Gruver .cfi_rel_offset x29, 160 1524b171afedb983fb811990beeec6a15e30a90b455Ben Gruver 1534b171afedb983fb811990beeec6a15e30a90b455Ben Gruver str xLR, [sp, #168] 15468564258a316e41cb014f98d2777b5944bf37de3Ben Gruver .cfi_rel_offset x30, 168 1554b171afedb983fb811990beeec6a15e30a90b455Ben Gruver 1564b171afedb983fb811990beeec6a15e30a90b455Ben Gruver // Loads appropriate callee-save-method 1574b171afedb983fb811990beeec6a15e30a90b455Ben Gruver str x9, [sp] // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs] 158dea5f8d544040e506b550116bd7874d27436b99bBen Gruver.endm 1594b171afedb983fb811990beeec6a15e30a90b455Ben Gruver 1604b171afedb983fb811990beeec6a15e30a90b455Ben Gruver.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 1614b171afedb983fb811990beeec6a15e30a90b455Ben Gruver // FP callee saves 1624b171afedb983fb811990beeec6a15e30a90b455Ben Gruver ldp d8, d9, [sp, #8] 1634b171afedb983fb811990beeec6a15e30a90b455Ben Gruver ldp d10, d11, [sp, #24] 1644b171afedb983fb811990beeec6a15e30a90b455Ben Gruver ldp d12, d13, [sp, #40] 1654b171afedb983fb811990beeec6a15e30a90b455Ben Gruver ldp d14, d15, [sp, #56] 16668564258a316e41cb014f98d2777b5944bf37de3Ben Gruver 1674b171afedb983fb811990beeec6a15e30a90b455Ben Gruver // Callee saved. 1684b171afedb983fb811990beeec6a15e30a90b455Ben Gruver ldp xSELF, x19, [sp, #72] 1692371e35aaeaf2ed4d7c571fb3286090eb01b717dJesusFreke@JesusFreke.com .cfi_restore x18 170e9ee92dc4c0848146e00d5607eb4baa5750361c8JesusFreke@JesusFreke.com .cfi_restore x19 171dea5f8d544040e506b550116bd7874d27436b99bBen Gruver 17278bde01ad4bf31ad44ad7bd0279b07fd2696b53cJesusFreke@JesusFreke.com ldp x20, x21, [sp, #88] 17336836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com .cfi_restore x20 174 .cfi_restore x21 175 176 ldp x22, x23, [sp, #104] 177 .cfi_restore x22 178 .cfi_restore x23 179 180 ldp x24, x25, [sp, #120] 181 .cfi_restore x24 182 .cfi_restore x25 183 184 ldp x26, x27, [sp, #136] 185 .cfi_restore x26 186 .cfi_restore x27 187 188 ldp x28, xFP, [sp, #152] // Save FP. 189 .cfi_restore x28 190 .cfi_restore x29 191 192 ldr xLR, [sp, #168] 193 .cfi_restore x30 194 195 add sp, sp, #176 196 .cfi_adjust_cfa_offset -176 197.endm 198 199.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN 200 brk 0 201.endm 202 203 204.macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL 205 sub sp, sp, #304 206 .cfi_adjust_cfa_offset 304 207 208 // Ugly compile-time check, but we only have the preprocessor. 209#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 304) 210#error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(ARM64) size not as expected." 211#endif 212 213 stp d0, d1, [sp, #16] 214 stp d2, d3, [sp, #32] 215 stp d4, d5, [sp, #48] 216 stp d6, d7, [sp, #64] 217 stp d8, d9, [sp, #80] 218 stp d10, d11, [sp, #96] 219 stp d12, d13, [sp, #112] 220 stp d14, d15, [sp, #128] 221 222 stp x1, x2, [sp, #144] 223 .cfi_rel_offset x1, 144 224 .cfi_rel_offset x2, 152 225 226 stp x3, x4, [sp, #160] 227 .cfi_rel_offset x3, 160 228 .cfi_rel_offset x4, 168 229 230 stp x5, x6, [sp, #176] 231 .cfi_rel_offset x5, 176 232 .cfi_rel_offset x6, 184 233 234 stp x7, xSELF, [sp, #192] 235 .cfi_rel_offset x7, 192 236 .cfi_rel_offset x18, 200 237 238 stp x19, x20, [sp, #208] 239 .cfi_rel_offset x19, 208 240 .cfi_rel_offset x20, 216 241 242 stp x21, x22, [sp, #224] 243 .cfi_rel_offset x21, 224 244 .cfi_rel_offset x22, 232 245 246 stp x23, x24, [sp, #240] 247 .cfi_rel_offset x23, 240 248 .cfi_rel_offset x24, 248 249 250 stp x25, x26, [sp, #256] 251 .cfi_rel_offset x25, 256 252 .cfi_rel_offset x26, 264 253 254 stp x27, x28, [sp, #272] 255 .cfi_rel_offset x27, 272 256 .cfi_rel_offset x28, 280 257 258 stp xFP, xLR, [sp, #288] 259 .cfi_rel_offset x29, 288 260 .cfi_rel_offset x30, 296 261.endm 262 263 /* 264 * Macro that sets up the callee save frame to conform with 265 * Runtime::CreateCalleeSaveMethod(kRefsAndArgs). 266 * 267 * TODO This is probably too conservative - saving FP & LR. 268 */ 269.macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME 270 adrp x9, :got:_ZN3art7Runtime9instance_E 271 ldr x9, [x9, #:got_lo12:_ZN3art7Runtime9instance_E] 272 273 // Our registers aren't intermixed - just spill in order. 274 ldr x9,[x9] // x9 = & (art::Runtime * art::Runtime.instance_) . 275 276 // x9 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs] . 277 ldr x9, [x9, RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET ] 278 279 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL 280 281 str x9, [sp] // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs] 282.endm 283 284.macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 285 286 ldp d0, d1, [sp, #16] 287 ldp d2, d3, [sp, #32] 288 ldp d4, d5, [sp, #48] 289 ldp d6, d7, [sp, #64] 290 ldp d8, d9, [sp, #80] 291 ldp d10, d11, [sp, #96] 292 ldp d12, d13, [sp, #112] 293 ldp d14, d15, [sp, #128] 294 295 // args. 296 ldp x1, x2, [sp, #144] 297 .cfi_restore x1 298 .cfi_restore x2 299 300 ldp x3, x4, [sp, #160] 301 .cfi_restore x3 302 .cfi_restore x4 303 304 ldp x5, x6, [sp, #176] 305 .cfi_restore x5 306 .cfi_restore x6 307 308 ldp x7, xSELF, [sp, #192] 309 .cfi_restore x7 310 .cfi_restore x18 311 312 ldp x19, x20, [sp, #208] 313 .cfi_restore x19 314 .cfi_restore x20 315 316 ldp x21, x22, [sp, #224] 317 .cfi_restore x21 318 .cfi_restore x22 319 320 ldp x23, x24, [sp, #240] 321 .cfi_restore x23 322 .cfi_restore x24 323 324 ldp x25, x26, [sp, #256] 325 .cfi_restore x25 326 .cfi_restore x26 327 328 ldp x27, x28, [sp, #272] 329 .cfi_restore x27 330 .cfi_restore x28 331 332 ldp xFP, xLR, [sp, #288] 333 .cfi_restore x29 334 .cfi_restore x30 335 336 add sp, sp, #304 337 .cfi_adjust_cfa_offset -304 338.endm 339 340.macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME_NO_D0 341 342 ldr d1, [sp, #24] 343 ldp d2, d3, [sp, #32] 344 ldp d4, d5, [sp, #48] 345 ldp d6, d7, [sp, #64] 346 ldp d8, d9, [sp, #80] 347 ldp d10, d11, [sp, #96] 348 ldp d12, d13, [sp, #112] 349 ldp d14, d15, [sp, #128] 350 351 // args. 352 ldp x1, x2, [sp, #144] 353 .cfi_restore x1 354 .cfi_restore x2 355 356 ldp x3, x4, [sp, #160] 357 .cfi_restore x3 358 .cfi_restore x4 359 360 ldp x5, x6, [sp, #176] 361 .cfi_restore x5 362 .cfi_restore x6 363 364 ldp x7, xSELF, [sp, #192] 365 .cfi_restore x7 366 .cfi_restore x18 367 368 ldp x19, x20, [sp, #208] 369 .cfi_restore x19 370 .cfi_restore x20 371 372 ldp x21, x22, [sp, #224] 373 .cfi_restore x21 374 .cfi_restore x22 375 376 ldp x23, x24, [sp, #240] 377 .cfi_restore x23 378 .cfi_restore x24 379 380 ldp x25, x26, [sp, #256] 381 .cfi_restore x25 382 .cfi_restore x26 383 384 ldp x27, x28, [sp, #272] 385 .cfi_restore x27 386 .cfi_restore x28 387 388 ldp xFP, xLR, [sp, #288] 389 .cfi_restore x29 390 .cfi_restore x30 391 392 add sp, sp, #304 393 .cfi_adjust_cfa_offset -304 394.endm 395 396.macro RETURN_IF_RESULT_IS_ZERO 397 cbnz x0, 1f // result non-zero branch over 398 ret // return 3991: 400.endm 401 402.macro RETURN_IF_RESULT_IS_NON_ZERO 403 cbz x0, 1f // result zero branch over 404 ret // return 4051: 406.endm 407 408 /* 409 * Macro that set calls through to artDeliverPendingExceptionFromCode, where the pending 410 * exception is Thread::Current()->exception_ 411 */ 412.macro DELIVER_PENDING_EXCEPTION 413 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME 414 mov x0, xSELF 415 mov x1, sp 416 417 // Point of no return. 418 b artDeliverPendingExceptionFromCode // artDeliverPendingExceptionFromCode(Thread*, SP) 419 brk 0 // Unreached 420.endm 421 422.macro RETURN_OR_DELIVER_PENDING_EXCEPTION_REG reg 423 ldr \reg, [xSELF, # THREAD_EXCEPTION_OFFSET] // Get exception field. 424 cbnz \reg, 1f 425 ret 4261: 427 DELIVER_PENDING_EXCEPTION 428.endm 429 430.macro RETURN_OR_DELIVER_PENDING_EXCEPTION 431 RETURN_OR_DELIVER_PENDING_EXCEPTION_REG x9 432.endm 433 434// Same as above with x1. This is helpful in stubs that want to avoid clobbering another register. 435.macro RETURN_OR_DELIVER_PENDING_EXCEPTION_X1 436 RETURN_OR_DELIVER_PENDING_EXCEPTION_REG x1 437.endm 438 439.macro RETURN_IF_W0_IS_ZERO_OR_DELIVER 440 cbnz w0, 1f // result non-zero branch over 441 ret // return 4421: 443 DELIVER_PENDING_EXCEPTION 444.endm 445 446.macro NO_ARG_RUNTIME_EXCEPTION c_name, cxx_name 447 .extern \cxx_name 448ENTRY \c_name 449 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context 450 mov x0, xSELF // pass Thread::Current 451 mov x1, sp // pass SP 452 b \cxx_name // \cxx_name(Thread*, SP) 453END \c_name 454.endm 455 456.macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name 457 .extern \cxx_name 458ENTRY \c_name 459 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context. 460 mov x1, xSELF // pass Thread::Current. 461 mov x2, sp // pass SP. 462 b \cxx_name // \cxx_name(arg, Thread*, SP). 463 brk 0 464END \c_name 465.endm 466 467.macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name 468 .extern \cxx_name 469ENTRY \c_name 470 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context 471 mov x2, xSELF // pass Thread::Current 472 mov x3, sp // pass SP 473 b \cxx_name // \cxx_name(arg1, arg2, Thread*, SP) 474 brk 0 475END \c_name 476.endm 477 478 /* 479 * Called by managed code, saves callee saves and then calls artThrowException 480 * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception. 481 */ 482ONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception, artDeliverExceptionFromCode 483 484 /* 485 * Called by managed code to create and deliver a NullPointerException. 486 */ 487NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode 488 489 /* 490 * Called by managed code to create and deliver an ArithmeticException. 491 */ 492NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode 493 494 /* 495 * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds 496 * index, arg2 holds limit. 497 */ 498TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds, artThrowArrayBoundsFromCode 499 500 /* 501 * Called by managed code to create and deliver a StackOverflowError. 502 */ 503NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFromCode 504 505 /* 506 * Called by managed code to create and deliver a NoSuchMethodError. 507 */ 508ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method, artThrowNoSuchMethodFromCode 509 510 /* 511 * TODO arm64 specifics need to be fleshed out. 512 * All generated callsites for interface invokes and invocation slow paths will load arguments 513 * as usual - except instead of loading x0 with the target Method*, x0 will contain 514 * the method_idx. This wrapper will save x1-x3, load the caller's Method*, align the 515 * stack and call the appropriate C helper. 516 * NOTE: "this" is first visible argument of the target, and so can be found in x1. 517 * 518 * The helper will attempt to locate the target and return a result in x0 consisting 519 * of the target Method* in x0 and method->code_ in x1. 520 * 521 * If unsuccessful, the helper will return NULL/NULL. There will be a pending exception in the 522 * thread and we branch to another stub to deliver it. 523 * 524 * On success this wrapper will restore arguments and *jump* to the target, leaving the lr 525 * pointing back to the original caller. 526 */ 527.macro INVOKE_TRAMPOLINE c_name, cxx_name 528 .extern \cxx_name 529ENTRY \c_name 530 brk 0 531END \c_name 532.endm 533 534INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline 535INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck 536 537INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck 538INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck 539INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck 540INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck 541 542 543.macro INVOKE_STUB_CREATE_FRAME 544 545SAVE_SIZE=5*8 // x4, x5, SP, LR & FP saved. 546SAVE_SIZE_AND_METHOD=SAVE_SIZE+8 547 548 mov x9, sp // Save stack pointer. 549 .cfi_register sp,x9 550 551 add x10, x2, # SAVE_SIZE_AND_METHOD // calculate size of frame. 552 sub x10, sp, x10 // Calculate SP position - saves + ArtMethod* + args 553 and x10, x10, # ~0xf // Enforce 16 byte stack alignment. 554 mov sp, x10 // Set new SP. 555 556 sub x10, x9, #SAVE_SIZE // Calculate new FP (later). Done here as we must move SP 557 .cfi_def_cfa_register x10 // before this. 558 .cfi_adjust_cfa_offset SAVE_SIZE 559 560 str x9, [x10, #32] // Save old stack pointer. 561 .cfi_rel_offset sp, 32 562 563 stp x4, x5, [x10, #16] // Save result and shorty addresses. 564 .cfi_rel_offset x4, 16 565 .cfi_rel_offset x5, 24 566 567 stp xFP, xLR, [x10] // Store LR & FP. 568 .cfi_rel_offset x29, 0 569 .cfi_rel_offset x30, 8 570 571 mov xFP, x10 // Use xFP now, as it's callee-saved. 572 .cfi_def_cfa_register x29 573 mov xSELF, x3 // Move thread pointer into SELF register. 574 575 // Copy arguments into stack frame. 576 // Use simple copy routine for now. 577 // 4 bytes per slot. 578 // X1 - source address 579 // W2 - args length 580 // X9 - destination address. 581 // W10 - temporary 582 add x9, sp, #8 // Destination address is bottom of stack + NULL. 583 584 // Use \@ to differentiate between macro invocations. 585.LcopyParams\@: 586 cmp w2, #0 587 beq .LendCopyParams\@ 588 sub w2, w2, #4 // Need 65536 bytes of range. 589 ldr w10, [x1, x2] 590 str w10, [x9, x2] 591 592 b .LcopyParams\@ 593 594.LendCopyParams\@: 595 596 // Store NULL into Method* at bottom of frame. 597 str xzr, [sp] 598 599.endm 600 601.macro INVOKE_STUB_CALL_AND_RETURN 602 603 // load method-> METHOD_QUICK_CODE_OFFSET 604 ldr x9, [x0 , #METHOD_QUICK_CODE_OFFSET] 605 // Branch to method. 606 blr x9 607 608 // Restore return value address and shorty address. 609 ldp x4,x5, [xFP, #16] 610 .cfi_restore x4 611 .cfi_restore x5 612 613 // Store result (w0/x0/s0/d0) appropriately, depending on resultType. 614 ldrb w10, [x5] 615 616 // Don't set anything for a void type. 617 cmp w10, #'V' 618 beq .Lexit_art_quick_invoke_stub\@ 619 620 cmp w10, #'D' 621 bne .Lreturn_is_float\@ 622 str d0, [x4] 623 b .Lexit_art_quick_invoke_stub\@ 624 625.Lreturn_is_float\@: 626 cmp w10, #'F' 627 bne .Lreturn_is_int\@ 628 str s0, [x4] 629 b .Lexit_art_quick_invoke_stub\@ 630 631 // Just store x0. Doesn't matter if it is 64 or 32 bits. 632.Lreturn_is_int\@: 633 str x0, [x4] 634 635.Lexit_art_quick_invoke_stub\@: 636 ldr x2, [x29, #32] // Restore stack pointer. 637 mov sp, x2 638 .cfi_restore sp 639 640 ldp x29, x30, [x29] // Restore old frame pointer and link register. 641 .cfi_restore x29 642 .cfi_restore x30 643 644 ret 645 646.endm 647 648 649/* 650 * extern"C" void art_quick_invoke_stub(ArtMethod *method, x0 651 * uint32_t *args, x1 652 * uint32_t argsize, w2 653 * Thread *self, x3 654 * JValue *result, x4 655 * char *shorty); x5 656 * +----------------------+ 657 * | | 658 * | C/C++ frame | 659 * | LR'' | 660 * | FP'' | <- SP' 661 * +----------------------+ 662 * +----------------------+ 663 * | SP' | 664 * | X5 | 665 * | X4 | Saved registers 666 * | LR' | 667 * | FP' | <- FP 668 * +----------------------+ 669 * | uint32_t out[n-1] | 670 * | : : | Outs 671 * | uint32_t out[0] | 672 * | ArtMethod* NULL | <- SP 673 * +----------------------+ 674 * 675 * Outgoing registers: 676 * x0 - Method* 677 * x1-x7 - integer parameters. 678 * d0-d7 - Floating point parameters. 679 * xSELF = self 680 * SP = & of ArtMethod* 681 * x1 = "this" pointer. 682 * 683 */ 684ENTRY art_quick_invoke_stub 685 // Spill registers as per AACPS64 calling convention. 686 INVOKE_STUB_CREATE_FRAME 687 688 // Fill registers x/w1 to x/w7 and s/d0 to s/d7 with parameters. 689 // Parse the passed shorty to determine which register to load. 690 // Load addresses for routines that load WXSD registers. 691 adr x11, .LstoreW2 692 adr x12, .LstoreX2 693 adr x13, .LstoreS0 694 adr x14, .LstoreD0 695 696 // Initialize routine offsets to 0 for integers and floats. 697 // x8 for integers, x15 for floating point. 698 mov x8, #0 699 mov x15, #0 700 701 add x10, x5, #1 // Load shorty address, plus one to skip return value. 702 ldr w1, [x9],#4 // Load "this" parameter, and increment arg pointer. 703 704 // Loop to fill registers. 705.LfillRegisters: 706 ldrb w17, [x10], #1 // Load next character in signature, and increment. 707 cbz w17, .LcallFunction // Exit at end of signature. Shorty 0 terminated. 708 709 cmp w17, #'F' // is this a float? 710 bne .LisDouble 711 712 cmp x15, # 8*12 // Skip this load if all registers full. 713 beq .Ladvance4 714 715 add x17, x13, x15 // Calculate subroutine to jump to. 716 br x17 717 718.LisDouble: 719 cmp w17, #'D' // is this a double? 720 bne .LisLong 721 722 cmp x15, # 8*12 // Skip this load if all registers full. 723 beq .Ladvance8 724 725 add x17, x14, x15 // Calculate subroutine to jump to. 726 br x17 727 728.LisLong: 729 cmp w17, #'J' // is this a long? 730 bne .LisOther 731 732 cmp x8, # 6*12 // Skip this load if all registers full. 733 beq .Ladvance8 734 735 add x17, x12, x8 // Calculate subroutine to jump to. 736 br x17 737 738.LisOther: // Everything else takes one vReg. 739 cmp x8, # 6*12 // Skip this load if all registers full. 740 beq .Ladvance4 741 742 add x17, x11, x8 // Calculate subroutine to jump to. 743 br x17 744 745.Ladvance4: 746 add x9, x9, #4 747 b .LfillRegisters 748 749.Ladvance8: 750 add x9, x9, #8 751 b .LfillRegisters 752 753// Macro for loading a parameter into a register. 754// counter - the register with offset into these tables 755// size - the size of the register - 4 or 8 bytes. 756// register - the name of the register to be loaded. 757.macro LOADREG counter size register return 758 ldr \register , [x9], #\size 759 add \counter, \counter, 12 760 b \return 761.endm 762 763// Store ints. 764.LstoreW2: 765 LOADREG x8 4 w2 .LfillRegisters 766 LOADREG x8 4 w3 .LfillRegisters 767 LOADREG x8 4 w4 .LfillRegisters 768 LOADREG x8 4 w5 .LfillRegisters 769 LOADREG x8 4 w6 .LfillRegisters 770 LOADREG x8 4 w7 .LfillRegisters 771 772// Store longs. 773.LstoreX2: 774 LOADREG x8 8 x2 .LfillRegisters 775 LOADREG x8 8 x3 .LfillRegisters 776 LOADREG x8 8 x4 .LfillRegisters 777 LOADREG x8 8 x5 .LfillRegisters 778 LOADREG x8 8 x6 .LfillRegisters 779 LOADREG x8 8 x7 .LfillRegisters 780 781// Store singles. 782.LstoreS0: 783 LOADREG x15 4 s0 .LfillRegisters 784 LOADREG x15 4 s1 .LfillRegisters 785 LOADREG x15 4 s2 .LfillRegisters 786 LOADREG x15 4 s3 .LfillRegisters 787 LOADREG x15 4 s4 .LfillRegisters 788 LOADREG x15 4 s5 .LfillRegisters 789 LOADREG x15 4 s6 .LfillRegisters 790 LOADREG x15 4 s7 .LfillRegisters 791 792// Store doubles. 793.LstoreD0: 794 LOADREG x15 8 d0 .LfillRegisters 795 LOADREG x15 8 d1 .LfillRegisters 796 LOADREG x15 8 d2 .LfillRegisters 797 LOADREG x15 8 d3 .LfillRegisters 798 LOADREG x15 8 d4 .LfillRegisters 799 LOADREG x15 8 d5 .LfillRegisters 800 LOADREG x15 8 d6 .LfillRegisters 801 LOADREG x15 8 d7 .LfillRegisters 802 803 804.LcallFunction: 805 806 INVOKE_STUB_CALL_AND_RETURN 807 808END art_quick_invoke_stub 809 810/* extern"C" 811 * void art_quick_invoke_static_stub(ArtMethod *method, x0 812 * uint32_t *args, x1 813 * uint32_t argsize, w2 814 * Thread *self, x3 815 * JValue *result, x4 816 * char *shorty); x5 817 */ 818ENTRY art_quick_invoke_static_stub 819 // Spill registers as per AACPS64 calling convention. 820 INVOKE_STUB_CREATE_FRAME 821 822 // Fill registers x/w1 to x/w7 and s/d0 to s/d7 with parameters. 823 // Parse the passed shorty to determine which register to load. 824 // Load addresses for routines that load WXSD registers. 825 adr x11, .LstoreW1_2 826 adr x12, .LstoreX1_2 827 adr x13, .LstoreS0_2 828 adr x14, .LstoreD0_2 829 830 // Initialize routine offsets to 0 for integers and floats. 831 // x8 for integers, x15 for floating point. 832 mov x8, #0 833 mov x15, #0 834 835 add x10, x5, #1 // Load shorty address, plus one to skip return value. 836 837 // Loop to fill registers. 838.LfillRegisters2: 839 ldrb w17, [x10], #1 // Load next character in signature, and increment. 840 cbz w17, .LcallFunction2 // Exit at end of signature. Shorty 0 terminated. 841 842 cmp w17, #'F' // is this a float? 843 bne .LisDouble2 844 845 cmp x15, # 8*12 // Skip this load if all registers full. 846 beq .Ladvance4_2 847 848 add x17, x13, x15 // Calculate subroutine to jump to. 849 br x17 850 851.LisDouble2: 852 cmp w17, #'D' // is this a double? 853 bne .LisLong2 854 855 cmp x15, # 8*12 // Skip this load if all registers full. 856 beq .Ladvance8_2 857 858 add x17, x14, x15 // Calculate subroutine to jump to. 859 br x17 860 861.LisLong2: 862 cmp w17, #'J' // is this a long? 863 bne .LisOther2 864 865 cmp x8, # 7*12 // Skip this load if all registers full. 866 beq .Ladvance8_2 867 868 add x17, x12, x8 // Calculate subroutine to jump to. 869 br x17 870 871.LisOther2: // Everything else takes one vReg. 872 cmp x8, # 7*12 // Skip this load if all registers full. 873 beq .Ladvance4_2 874 875 add x17, x11, x8 // Calculate subroutine to jump to. 876 br x17 877 878.Ladvance4_2: 879 add x9, x9, #4 880 b .LfillRegisters2 881 882.Ladvance8_2: 883 add x9, x9, #8 884 b .LfillRegisters2 885 886// Store ints. 887.LstoreW1_2: 888 LOADREG x8 4 w1 .LfillRegisters2 889 LOADREG x8 4 w2 .LfillRegisters2 890 LOADREG x8 4 w3 .LfillRegisters2 891 LOADREG x8 4 w4 .LfillRegisters2 892 LOADREG x8 4 w5 .LfillRegisters2 893 LOADREG x8 4 w6 .LfillRegisters2 894 LOADREG x8 4 w7 .LfillRegisters2 895 896// Store longs. 897.LstoreX1_2: 898 LOADREG x8 8 x1 .LfillRegisters2 899 LOADREG x8 8 x2 .LfillRegisters2 900 LOADREG x8 8 x3 .LfillRegisters2 901 LOADREG x8 8 x4 .LfillRegisters2 902 LOADREG x8 8 x5 .LfillRegisters2 903 LOADREG x8 8 x6 .LfillRegisters2 904 LOADREG x8 8 x7 .LfillRegisters2 905 906// Store singles. 907.LstoreS0_2: 908 LOADREG x15 4 s0 .LfillRegisters2 909 LOADREG x15 4 s1 .LfillRegisters2 910 LOADREG x15 4 s2 .LfillRegisters2 911 LOADREG x15 4 s3 .LfillRegisters2 912 LOADREG x15 4 s4 .LfillRegisters2 913 LOADREG x15 4 s5 .LfillRegisters2 914 LOADREG x15 4 s6 .LfillRegisters2 915 LOADREG x15 4 s7 .LfillRegisters2 916 917// Store doubles. 918.LstoreD0_2: 919 LOADREG x15 8 d0 .LfillRegisters2 920 LOADREG x15 8 d1 .LfillRegisters2 921 LOADREG x15 8 d2 .LfillRegisters2 922 LOADREG x15 8 d3 .LfillRegisters2 923 LOADREG x15 8 d4 .LfillRegisters2 924 LOADREG x15 8 d5 .LfillRegisters2 925 LOADREG x15 8 d6 .LfillRegisters2 926 LOADREG x15 8 d7 .LfillRegisters2 927 928 929.LcallFunction2: 930 931 INVOKE_STUB_CALL_AND_RETURN 932 933END art_quick_invoke_static_stub 934 935 936 937 /* 938 * On entry x0 is uintptr_t* gprs_ and x1 is uint64_t* fprs_ 939 */ 940 941ENTRY art_quick_do_long_jump 942 // Load FPRs 943 ldp d0, d1, [x1], #16 944 ldp d2, d3, [x1], #16 945 ldp d4, d5, [x1], #16 946 ldp d6, d7, [x1], #16 947 ldp d8, d9, [x1], #16 948 ldp d10, d11, [x1], #16 949 ldp d12, d13, [x1], #16 950 ldp d14, d15, [x1], #16 951 ldp d16, d17, [x1], #16 952 ldp d18, d19, [x1], #16 953 ldp d20, d21, [x1], #16 954 ldp d22, d23, [x1], #16 955 ldp d24, d25, [x1], #16 956 ldp d26, d27, [x1], #16 957 ldp d28, d29, [x1], #16 958 ldp d30, d31, [x1] 959 960 // Load GPRs 961 // TODO: lots of those are smashed, could optimize. 962 add x0, x0, #30*8 963 ldp x30, x1, [x0], #-16 964 ldp x28, x29, [x0], #-16 965 ldp x26, x27, [x0], #-16 966 ldp x24, x25, [x0], #-16 967 ldp x22, x23, [x0], #-16 968 ldp x20, x21, [x0], #-16 969 ldp x18, x19, [x0], #-16 970 ldp x16, x17, [x0], #-16 971 ldp x14, x15, [x0], #-16 972 ldp x12, x13, [x0], #-16 973 ldp x10, x11, [x0], #-16 974 ldp x8, x9, [x0], #-16 975 ldp x6, x7, [x0], #-16 976 ldp x4, x5, [x0], #-16 977 ldp x2, x3, [x0], #-16 978 mov sp, x1 979 980 // TODO: Is it really OK to use LR for the target PC? 981 mov x0, #0 982 mov x1, #0 983 br xLR 984END art_quick_do_long_jump 985 986 /* 987 * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on 988 * failure. 989 */ 990 .extern artHandleFillArrayDataFromCode 991ENTRY art_quick_handle_fill_data 992 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // Save callee saves in case exception allocation triggers GC. 993 mov x2, xSELF // Pass Thread::Current. 994 mov x3, sp // Pass SP. 995 bl artHandleFillArrayDataFromCode // (Array*, const DexFile::Payload*, Thread*, SP) 996 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 997 RETURN_IF_RESULT_IS_ZERO 998 DELIVER_PENDING_EXCEPTION 999END art_quick_handle_fill_data 1000 1001UNIMPLEMENTED art_quick_lock_object 1002UNIMPLEMENTED art_quick_unlock_object 1003 1004 /* 1005 * Entry from managed code that calls artIsAssignableFromCode and on failure calls 1006 * artThrowClassCastException. 1007 */ 1008 .extern artThrowClassCastException 1009ENTRY art_quick_check_cast 1010 // Store arguments and link register 1011 sub sp, sp, #32 // Stack needs to be 16b aligned on calls 1012 .cfi_adjust_cfa_offset 32 1013 stp x0, x1, [sp] 1014 .cfi_rel_offset x0, 0 1015 .cfi_rel_offset x1, 8 1016 stp xSELF, xLR, [sp, #16] 1017 .cfi_rel_offset x18, 16 1018 .cfi_rel_offset x30, 24 1019 1020 // Call runtime code 1021 bl artIsAssignableFromCode 1022 1023 // Check for exception 1024 cbz x0, .Lthrow_class_cast_exception 1025 1026 // Restore and return 1027 ldp x0, x1, [sp] 1028 .cfi_restore x0 1029 .cfi_restore x1 1030 ldp xSELF, xLR, [sp, #16] 1031 .cfi_restore x18 1032 .cfi_restore x30 1033 add sp, sp, #32 1034 .cfi_adjust_cfa_offset -32 1035 ret 1036 1037.Lthrow_class_cast_exception: 1038 // Restore 1039 ldp x0, x1, [sp] 1040 .cfi_restore x0 1041 .cfi_restore x1 1042 ldp xSELF, xLR, [sp, #16] 1043 .cfi_restore x18 1044 .cfi_restore x30 1045 add sp, sp, #32 1046 .cfi_adjust_cfa_offset -32 1047 1048 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context 1049 mov x2, xSELF // pass Thread::Current 1050 mov x3, sp // pass SP 1051 b artThrowClassCastException // (Class*, Class*, Thread*, SP) 1052 brk 0 // We should not return here... 1053END art_quick_check_cast 1054 1055 /* 1056 * Entry from managed code for array put operations of objects where the value being stored 1057 * needs to be checked for compatibility. 1058 * x0 = array, x1 = index, x2 = value 1059 * 1060 * Currently all values should fit into w0/w1/w2, and w1 always will as indices are 32b. We 1061 * assume, though, that the upper 32b are zeroed out. At least for x1/w1 we can do better by 1062 * using index-zero-extension in load/stores. 1063 * 1064 * Temporaries: x3, x4 1065 * TODO: x4 OK? ip seems wrong here. 1066 */ 1067ENTRY art_quick_aput_obj_with_null_and_bound_check 1068 tst x0, x0 1069 bne art_quick_aput_obj_with_bound_check 1070 b art_quick_throw_null_pointer_exception 1071END art_quick_aput_obj_with_null_and_bound_check 1072 1073ENTRY art_quick_aput_obj_with_bound_check 1074 ldr w3, [x0, #ARRAY_LENGTH_OFFSET] 1075 cmp w3, w1 1076 bhi art_quick_aput_obj 1077 mov x0, x1 1078 mov x1, x3 1079 b art_quick_throw_array_bounds 1080END art_quick_aput_obj_with_bound_check 1081 1082ENTRY art_quick_aput_obj 1083 cbz x2, .Ldo_aput_null 1084 ldr w3, [x0, #CLASS_OFFSET] // Heap reference = 32b 1085 // This also zero-extends to x3 1086 ldr w4, [x2, #CLASS_OFFSET] // Heap reference = 32b 1087 // This also zero-extends to x4 1088 ldr w3, [x3, #CLASS_COMPONENT_TYPE_OFFSET] // Heap reference = 32b 1089 // This also zero-extends to x3 1090 cmp w3, w4 // value's type == array's component type - trivial assignability 1091 bne .Lcheck_assignability 1092.Ldo_aput: 1093 add x3, x0, #OBJECT_ARRAY_DATA_OFFSET 1094 // "Compress" = do nothing 1095 str w2, [x3, x1, lsl #2] // Heap reference = 32b 1096 ldr x3, [xSELF, #THREAD_CARD_TABLE_OFFSET] 1097 lsr x0, x0, #7 1098 strb w3, [x3, x0] 1099 ret 1100.Ldo_aput_null: 1101 add x3, x0, #OBJECT_ARRAY_DATA_OFFSET 1102 // "Compress" = do nothing 1103 str w2, [x3, x1, lsl #2] // Heap reference = 32b 1104 ret 1105.Lcheck_assignability: 1106 // Store arguments and link register 1107 sub sp, sp, #48 // Stack needs to be 16b aligned on calls 1108 .cfi_adjust_cfa_offset 48 1109 stp x0, x1, [sp] 1110 .cfi_rel_offset x0, 0 1111 .cfi_rel_offset x1, 8 1112 stp x2, xSELF, [sp, #16] 1113 .cfi_rel_offset x2, 16 1114 .cfi_rel_offset x18, 24 1115 str xLR, [sp, #32] 1116 .cfi_rel_offset x30, 32 1117 1118 // Call runtime code 1119 mov x0, x3 // Heap reference, 32b, "uncompress" = do nothing, already zero-extended 1120 mov x1, x4 // Heap reference, 32b, "uncompress" = do nothing, already zero-extended 1121 bl artIsAssignableFromCode 1122 1123 // Check for exception 1124 cbz x0, .Lthrow_array_store_exception 1125 1126 // Restore 1127 ldp x0, x1, [sp] 1128 .cfi_restore x0 1129 .cfi_restore x1 1130 ldp x2, xSELF, [sp, #16] 1131 .cfi_restore x2 1132 .cfi_restore x18 1133 ldr xLR, [sp, #32] 1134 .cfi_restore x30 1135 add sp, sp, #48 1136 .cfi_adjust_cfa_offset -48 1137 1138 add x3, x0, #OBJECT_ARRAY_DATA_OFFSET 1139 // "Compress" = do nothing 1140 str w2, [x3, x1, lsl #2] // Heap reference = 32b 1141 ldr x3, [xSELF, #THREAD_CARD_TABLE_OFFSET] 1142 lsr x0, x0, #7 1143 strb w3, [x3, x0] 1144 ret 1145.Lthrow_array_store_exception: 1146 ldp x0, x1, [sp] 1147 .cfi_restore x0 1148 .cfi_restore x1 1149 ldp x2, xSELF, [sp, #16] 1150 .cfi_restore x2 1151 .cfi_restore x18 1152 ldr xLR, [sp, #32] 1153 .cfi_restore x30 1154 add sp, sp, #48 1155 .cfi_adjust_cfa_offset -48 1156 1157 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME 1158 mov x1, x2 // Pass value. 1159 mov x2, xSELF // Pass Thread::Current. 1160 mov x3, sp // Pass SP. 1161 b artThrowArrayStoreException // (Object*, Object*, Thread*, SP). 1162 brk 0 // Unreached. 1163END art_quick_aput_obj 1164 1165UNIMPLEMENTED art_quick_initialize_static_storage 1166UNIMPLEMENTED art_quick_initialize_type 1167UNIMPLEMENTED art_quick_initialize_type_and_verify_access 1168 1169// Macro to facilitate adding new allocation entrypoints. 1170.macro TWO_ARG_DOWNCALL name, entrypoint, return 1171 .extern \entrypoint 1172ENTRY \name 1173 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC 1174 mov x2, xSELF // pass Thread::Current 1175 mov x3, sp // pass SP 1176 bl \entrypoint // (uint32_t type_idx, Method* method, Thread*, SP) 1177 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 1178 \return 1179 DELIVER_PENDING_EXCEPTION 1180END \name 1181.endm 1182 1183// Macro to facilitate adding new array allocation entrypoints. 1184.macro THREE_ARG_DOWNCALL name, entrypoint, return 1185 .extern \entrypoint 1186ENTRY \name 1187 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC 1188 mov x3, xSELF // pass Thread::Current 1189 mov x4, sp // pass SP 1190 bl \entrypoint 1191 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 1192 \return 1193 DELIVER_PENDING_EXCEPTION 1194END \name 1195.endm 1196 1197// Macros taking opportunity of code similarities for downcalls with referrer. 1198 1199// TODO: xSELF -> x19. Temporarily rely on xSELF being saved in REF_ONLY 1200.macro ONE_ARG_REF_DOWNCALL name, entrypoint, return 1201 .extern \entrypoint 1202ENTRY \name 1203 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC 1204 ldr x1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer 1205 mov x2, xSELF // pass Thread::Current 1206 mov x3, sp // pass SP 1207 bl \entrypoint // (uint32_t type_idx, Method* method, Thread*, SP) 1208 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 1209 \return 1210END \name 1211.endm 1212 1213// TODO: xSELF -> x19. Temporarily rely on xSELF being saved in REF_ONLY 1214.macro TWO_ARG_REF_DOWNCALL name, entrypoint, return 1215 .extern \entrypoint 1216ENTRY \name 1217 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC 1218 ldr x2, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer 1219 mov x3, xSELF // pass Thread::Current 1220 mov x4, sp // pass SP 1221 bl \entrypoint 1222 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 1223 \return 1224END \name 1225.endm 1226 1227// TODO: xSELF -> x19. Temporarily rely on xSELF being saved in REF_ONLY 1228.macro THREE_ARG_REF_DOWNCALL name, entrypoint, return 1229 .extern \entrypoint 1230ENTRY \name 1231 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC 1232 ldr x3, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer 1233 mov x4, xSELF // pass Thread::Current 1234 mov x5, sp // pass SP 1235 bl \entrypoint 1236 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 1237 \return 1238END \name 1239.endm 1240 1241ONE_ARG_REF_DOWNCALL art_quick_get32_static, artGet32StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1 1242ONE_ARG_REF_DOWNCALL art_quick_get64_static, artGet64StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1 1243ONE_ARG_REF_DOWNCALL art_quick_get_obj_static, artGetObjStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1 1244 1245TWO_ARG_REF_DOWNCALL art_quick_get32_instance, artGet32InstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1 1246TWO_ARG_REF_DOWNCALL art_quick_get64_instance, artGet64InstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1 1247TWO_ARG_REF_DOWNCALL art_quick_get_obj_instance, artGetObjInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1 1248 1249TWO_ARG_REF_DOWNCALL art_quick_set32_static, artSet32StaticFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER 1250TWO_ARG_REF_DOWNCALL art_quick_set_obj_static, artSetObjStaticFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER 1251 1252THREE_ARG_REF_DOWNCALL art_quick_set32_instance, artSet32InstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER 1253THREE_ARG_DOWNCALL art_quick_set64_instance, artSet64InstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER 1254THREE_ARG_REF_DOWNCALL art_quick_set_obj_instance, artSetObjInstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER 1255 1256// This is separated out as the argument order is different. 1257 .extern artSet64StaticFromCode 1258ENTRY art_quick_set64_static 1259 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC 1260 mov x3, x1 // Store value 1261 ldr x1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer 1262 mov x2, x3 // Put value param 1263 mov x3, xSELF // pass Thread::Current 1264 mov x4, sp // pass SP 1265 bl artSet64StaticFromCode 1266 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 1267 RETURN_IF_W0_IS_ZERO_OR_DELIVER 1268END art_quick_set64_static 1269 1270 1271UNIMPLEMENTED art_quick_resolve_string 1272 1273// Generate the allocation entrypoints for each allocator. 1274GENERATE_ALL_ALLOC_ENTRYPOINTS 1275 1276UNIMPLEMENTED art_quick_test_suspend 1277 1278 /* 1279 * Called by managed code that is attempting to call a method on a proxy class. On entry 1280 * x0 holds the proxy method and x1 holds the receiver; The frame size of the invoked proxy 1281 * method agrees with a ref and args callee save frame. 1282 */ 1283 .extern artQuickProxyInvokeHandler 1284ENTRY art_quick_proxy_invoke_handler 1285 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME 1286 str x0, [sp, #0] // place proxy method at bottom of frame 1287 mov x2, xSELF // pass Thread::Current 1288 mov x3, sp // pass SP 1289 bl artQuickProxyInvokeHandler // (Method* proxy method, receiver, Thread*, SP) 1290 ldr xSELF, [sp, #200] // Restore self pointer. 1291 ldr x2, [xSELF, THREAD_EXCEPTION_OFFSET] 1292 cbnz x2, .Lexception_in_proxy // success if no exception is pending 1293 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME_NO_D0 // keep d0 1294 ret // return on success 1295.Lexception_in_proxy: 1296 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 1297 DELIVER_PENDING_EXCEPTION 1298END art_quick_proxy_invoke_handler 1299 1300UNIMPLEMENTED art_quick_imt_conflict_trampoline 1301 1302 1303ENTRY art_quick_resolution_trampoline 1304 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME 1305 mov x19, x0 // save the called method 1306 mov x2, xSELF 1307 mov x3, sp 1308 bl artQuickResolutionTrampoline // (called, receiver, Thread*, SP) 1309 mov x9, x0 // Remember returned code pointer in x9. 1310 mov x0, x19 // Restore the method, before x19 is restored to on-call value 1311 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 1312 cbz x9, 1f 1313 br x9 13141: 1315 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 1316 DELIVER_PENDING_EXCEPTION 1317END art_quick_resolution_trampoline 1318 1319/* 1320 * Generic JNI frame layout: 1321 * 1322 * #-------------------# 1323 * | | 1324 * | caller method... | 1325 * #-------------------# <--- SP on entry 1326 * | Return X30/LR | 1327 * | X29/FP | callee save 1328 * | X28 | callee save 1329 * | X27 | callee save 1330 * | X26 | callee save 1331 * | X25 | callee save 1332 * | X24 | callee save 1333 * | X23 | callee save 1334 * | X22 | callee save 1335 * | X21 | callee save 1336 * | X20 | callee save 1337 * | X19 | callee save 1338 * | X7 | arg7 1339 * | X6 | arg6 1340 * | X5 | arg5 1341 * | X4 | arg4 1342 * | X3 | arg3 1343 * | X2 | arg2 1344 * | X1 | arg1 1345 * | D15 | float arg 8 1346 * | D14 | float arg 8 1347 * | D13 | float arg 8 1348 * | D12 | callee save 1349 * | D11 | callee save 1350 * | D10 | callee save 1351 * | D9 | callee save 1352 * | D8 | callee save 1353 * | D7 | float arg 8 1354 * | D6 | float arg 7 1355 * | D5 | float arg 6 1356 * | D4 | float arg 5 1357 * | D3 | float arg 4 1358 * | D2 | float arg 3 1359 * | D1 | float arg 2 1360 * | D0 | float arg 1 1361 * | RDI/Method* | <- X0 1362 * #-------------------# 1363 * | local ref cookie | // 4B 1364 * | SIRT size | // 4B 1365 * #-------------------# 1366 * | JNI Call Stack | 1367 * #-------------------# <--- SP on native call 1368 * | | 1369 * | Stack for Regs | The trampoline assembly will pop these values 1370 * | | into registers for native call 1371 * #-------------------# 1372 * | Native code ptr | 1373 * #-------------------# 1374 * | Free scratch | 1375 * #-------------------# 1376 * | Ptr to (1) | <--- SP 1377 * #-------------------# 1378 */ 1379 /* 1380 * Called to do a generic JNI down-call 1381 */ 1382ENTRY art_quick_generic_jni_trampoline 1383 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL 1384 str x0, [sp, #0] // Store native ArtMethod* to bottom of stack. 1385 1386 // Save SP , so we can have static CFI info. 1387 mov x28, sp 1388 .cfi_def_cfa_register x28 1389 1390 // This looks the same, but is different: this will be updated to point to the bottom 1391 // of the frame when the SIRT is inserted. 1392 mov xFP, sp 1393 1394 mov x8, #5120 1395 sub sp, sp, x8 1396 1397 // prepare for artQuickGenericJniTrampoline call 1398 // (Thread*, SP) 1399 // x0 x1 <= C calling convention 1400 // xSELF xFP <= where they are 1401 1402 mov x0, xSELF // Thread* 1403 mov x1, xFP 1404 bl artQuickGenericJniTrampoline // (Thread*, sp) 1405 1406 // Get the updated pointer. This is the bottom of the frame _with_ SIRT. 1407 ldr xFP, [sp] 1408 add x9, sp, #8 1409 1410 cmp x0, #0 1411 b.mi .Lentry_error // Check for error, negative value. 1412 1413 // release part of the alloca. 1414 add x9, x9, x0 1415 1416 // Get the code pointer 1417 ldr xIP0, [x9, #0] 1418 1419 // Load parameters from frame into registers. 1420 // TODO Check with artQuickGenericJniTrampoline. 1421 // Also, check again APPCS64 - the stack arguments are interleaved. 1422 ldp x0, x1, [x9, #8] 1423 ldp x2, x3, [x9, #24] 1424 ldp x4, x5, [x9, #40] 1425 ldp x6, x7, [x9, #56] 1426 1427 ldp d0, d1, [x9, #72] 1428 ldp d2, d3, [x9, #88] 1429 ldp d4, d5, [x9, #104] 1430 ldp d6, d7, [x9, #120] 1431 1432 add sp, x9, #136 1433 1434 blr xIP0 // native call. 1435 1436 // Restore self pointer. 1437 ldr xSELF, [x28, #200] 1438 1439 // result sign extension is handled in C code 1440 // prepare for artQuickGenericJniEndTrampoline call 1441 // (Thread*, SP, result, result_f) 1442 // x0 x1 x2 x3 <= C calling convention 1443 mov x5, x0 // Save return value 1444 mov x0, xSELF // Thread register 1445 mov x1, xFP // Stack pointer 1446 mov x2, x5 // Result (from saved) 1447 fmov x3, d0 // d0 will contain floating point result, but needs to go into x3 1448 1449 bl artQuickGenericJniEndTrampoline 1450 1451 // Tear down the alloca. 1452 mov sp, x28 1453 .cfi_def_cfa_register sp 1454 1455 // Restore self pointer. 1456 ldr xSELF, [x28, #200] 1457 1458 // Pending exceptions possible. 1459 ldr x1, [xSELF, THREAD_EXCEPTION_OFFSET] 1460 cbnz x1, .Lexception_in_native 1461 1462 // Tear down the callee-save frame. 1463 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 1464 1465 // store into fpr, for when it's a fpr return... 1466 fmov d0, x0 1467 ret 1468 1469.Lentry_error: 1470 mov sp, x28 1471 .cfi_def_cfa_register sp 1472 ldr xSELF, [x28, #200] 1473.Lexception_in_native: 1474 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 1475 DELIVER_PENDING_EXCEPTION 1476 1477END art_quick_generic_jni_trampoline 1478 1479/* 1480 * Called to bridge from the quick to interpreter ABI. On entry the arguments match those 1481 * of a quick call: 1482 * x0 = method being called/to bridge to. 1483 * x1..x7, d0..d7 = arguments to that method. 1484 */ 1485ENTRY art_quick_to_interpreter_bridge 1486 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME // Set up frame and save arguments. 1487 1488 // x0 will contain mirror::ArtMethod* method. 1489 mov x1, xSELF // How to get Thread::Current() ??? 1490 mov x2, sp 1491 1492 // uint64_t artQuickToInterpreterBridge(mirror::ArtMethod* method, Thread* self, 1493 // mirror::ArtMethod** sp) 1494 bl artQuickToInterpreterBridge 1495 1496 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME // TODO: no need to restore arguments in this case. 1497 1498 fmov d0, x0 1499 1500 RETURN_OR_DELIVER_PENDING_EXCEPTION 1501END art_quick_to_interpreter_bridge 1502 1503UNIMPLEMENTED art_quick_instrumentation_entry 1504UNIMPLEMENTED art_quick_instrumentation_exit 1505UNIMPLEMENTED art_quick_deoptimize 1506UNIMPLEMENTED art_quick_mul_long 1507UNIMPLEMENTED art_quick_shl_long 1508UNIMPLEMENTED art_quick_shr_long 1509UNIMPLEMENTED art_quick_ushr_long 1510UNIMPLEMENTED art_quick_indexof 1511 1512 /* 1513 * String's compareTo. 1514 * 1515 * TODO: Not very optimized. 1516 * 1517 * On entry: 1518 * x0: this object pointer 1519 * x1: comp object pointer 1520 * 1521 */ 1522 .extern __memcmp16 1523ENTRY art_quick_string_compareto 1524 mov x2, x0 // x0 is return, use x2 for first input. 1525 sub x0, x2, x1 // Same string object? 1526 cbnz x0,1f 1527 ret 15281: // Different string objects. 1529 1530 ldr w6, [x2, #STRING_OFFSET_OFFSET] 1531 ldr w5, [x1, #STRING_OFFSET_OFFSET] 1532 ldr w4, [x2, #STRING_COUNT_OFFSET] 1533 ldr w3, [x1, #STRING_COUNT_OFFSET] 1534 ldr w2, [x2, #STRING_VALUE_OFFSET] 1535 ldr w1, [x1, #STRING_VALUE_OFFSET] 1536 1537 /* 1538 * Now: CharArray* Offset Count 1539 * first arg x2 w6 w4 1540 * second arg x1 w5 w3 1541 */ 1542 1543 // x0 := str1.length(w4) - str2.length(w3). ldr zero-extended w3/w4 into x3/x4. 1544 subs x0, x4, x3 1545 // Min(count1, count2) into w3. 1546 csel x3, x3, x4, ge 1547 1548 // Build pointer into string data. 1549 1550 // Add offset in array (substr etc.) (sign extend and << 1). 1551 add x2, x2, w6, sxtw #1 1552 add x1, x1, w5, sxtw #1 1553 1554 // Add offset in CharArray to array. 1555 add x2, x2, #STRING_DATA_OFFSET 1556 add x1, x1, #STRING_DATA_OFFSET 1557 1558 // Check for long string, do memcmp16 for them. 1559 cmp w3, #28 // Constant from arm32. 1560 bgt .Ldo_memcmp16 1561 1562 /* 1563 * Now: 1564 * x2: *first string data 1565 * x1: *second string data 1566 * w3: iteration count 1567 * x0: return value if comparison equal 1568 * x4, x5, x6, x7: free 1569 */ 1570 1571 // Do a simple unrolled loop. 1572.Lloop: 1573 // At least two more elements? 1574 subs w3, w3, #2 1575 b.lt .Lremainder_or_done 1576 1577 ldrh w4, [x2], #2 1578 ldrh w5, [x1], #2 1579 1580 ldrh w6, [x2], #2 1581 ldrh w7, [x1], #2 1582 1583 subs w4, w4, w5 1584 b.ne .Lw4_result 1585 1586 subs w6, w6, w7 1587 b.ne .Lw6_result 1588 1589 b .Lloop 1590 1591.Lremainder_or_done: 1592 adds w3, w3, #1 1593 b.eq .Lremainder 1594 ret 1595 1596.Lremainder: 1597 ldrh w4, [x2], #2 1598 ldrh w5, [x1], #2 1599 subs w4, w4, w5 1600 b.ne .Lw4_result 1601 ret 1602 1603// Result is in w4 1604.Lw4_result: 1605 sxtw x0, w4 1606 ret 1607 1608// Result is in w6 1609.Lw6_result: 1610 sxtw x0, w6 1611 ret 1612 1613.Ldo_memcmp16: 1614 str x0, [sp,#-16]! // Save x0 1615 1616 mov x0, x2 1617 uxtw x2, w3 1618 bl __memcmp16 1619 1620 ldr x1, [sp], #16 // Restore old x0 = length diff 1621 1622 cmp x0, #0 // Check the memcmp difference 1623 csel x0, x0, x1, ne // x0 := x0 != 0 ? x0 : x1 1624 ret 1625END art_quick_string_compareto 1626