Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | /* |
| 18 | Art assembly interpreter notes: |
| 19 | |
| 20 | First validate assembly code by implementing ExecuteXXXImpl() style body (doesn't |
| 21 | handle invoke, allows higher-level code to create frame & shadow frame. |
| 22 | |
| 23 | Once that's working, support direct entry code & eliminate shadow frame (and |
| 24 | excess locals allocation. |
| 25 | |
| 26 | Some (hopefully) temporary ugliness. We'll treat rFP as pointing to the |
| 27 | base of the vreg array within the shadow frame. Access the other fields, |
| 28 | dex_pc_, method_ and number_of_vregs_ via negative offsets. For now, we'll continue |
| 29 | the shadow frame mechanism of double-storing object references - via rFP & |
| 30 | number_of_vregs_. |
| 31 | |
| 32 | */ |
| 33 | |
| 34 | /* |
| 35 | x86 ABI general notes: |
| 36 | |
| 37 | Caller save set: |
| 38 | eax, edx, ecx, st(0)-st(7) |
| 39 | Callee save set: |
| 40 | ebx, esi, edi, ebp |
| 41 | Return regs: |
| 42 | 32-bit in eax |
| 43 | 64-bit in edx:eax (low-order 32 in eax) |
| 44 | fp on top of fp stack st(0) |
| 45 | |
| 46 | Parameters passed on stack, pushed right-to-left. On entry to target, first |
| 47 | parm is at 4(%esp). Traditional entry code is: |
| 48 | |
| 49 | functEntry: |
| 50 | push %ebp # save old frame pointer |
| 51 | mov %ebp,%esp # establish new frame pointer |
| 52 | sub FrameSize,%esp # Allocate storage for spill, locals & outs |
| 53 | |
| 54 | Once past the prologue, arguments are referenced at ((argno + 2)*4)(%ebp) |
| 55 | |
| 56 | Stack must be 16-byte aligned to support SSE in native code. |
| 57 | |
| 58 | If we're not doing variable stack allocation (alloca), the frame pointer can be |
| 59 | eliminated and all arg references adjusted to be esp relative. |
| 60 | */ |
| 61 | |
| 62 | /* |
| 63 | Mterp and x86 notes: |
| 64 | |
| 65 | Some key interpreter variables will be assigned to registers. |
| 66 | |
| 67 | nick reg purpose |
| 68 | rPC esi interpreted program counter, used for fetching instructions |
| 69 | rFP edi interpreted frame pointer, used for accessing locals and args |
| 70 | rINSTw bx first 16-bit code of current instruction |
| 71 | rINSTbl bl opcode portion of instruction word |
| 72 | rINSTbh bh high byte of inst word, usually contains src/tgt reg names |
| 73 | rIBASE edx base of instruction handler table |
| 74 | rREFS ebp base of object references in shadow frame. |
| 75 | |
| 76 | Notes: |
| 77 | o High order 16 bits of ebx must be zero on entry to handler |
| 78 | o rPC, rFP, rINSTw/rINSTbl valid on handler entry and exit |
| 79 | o eax and ecx are scratch, rINSTw/ebx sometimes scratch |
| 80 | |
| 81 | Macros are provided for common operations. Each macro MUST emit only |
| 82 | one instruction to make instruction-counting easier. They MUST NOT alter |
| 83 | unspecified registers or condition codes. |
| 84 | */ |
| 85 | |
| 86 | /* |
| 87 | * This is a #include, not a %include, because we want the C pre-processor |
| 88 | * to expand the macros into assembler assignment statements. |
| 89 | */ |
| 90 | #include "asm_support.h" |
| 91 | |
Serguei Katkov | 05dfaaa | 2016-01-28 08:21:26 +0600 | [diff] [blame] | 92 | /* |
| 93 | * Handle mac compiler specific |
| 94 | */ |
| 95 | #if defined(__APPLE__) |
| 96 | #define MACRO_LITERAL(value) $$(value) |
| 97 | #define FUNCTION_TYPE(name) |
| 98 | #define SIZE(start,end) |
| 99 | // Mac OS' symbols have an _ prefix. |
| 100 | #define SYMBOL(name) _ ## name |
| 101 | #else |
| 102 | #define MACRO_LITERAL(value) $$value |
| 103 | #define FUNCTION_TYPE(name) .type name, @function |
| 104 | #define SIZE(start,end) .size start, .-end |
| 105 | #define SYMBOL(name) name |
| 106 | #endif |
| 107 | |
Serguei Katkov | 897338d | 2016-03-01 15:53:22 +0600 | [diff] [blame] | 108 | .macro PUSH _reg |
| 109 | pushl \_reg |
| 110 | .cfi_adjust_cfa_offset 4 |
| 111 | .cfi_rel_offset \_reg, 0 |
| 112 | .endm |
| 113 | |
| 114 | .macro POP _reg |
| 115 | popl \_reg |
| 116 | .cfi_adjust_cfa_offset -4 |
| 117 | .cfi_restore \_reg |
| 118 | .endm |
| 119 | |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 120 | /* Frame size must be 16-byte aligned. |
Serguei Katkov | 897338d | 2016-03-01 15:53:22 +0600 | [diff] [blame] | 121 | * Remember about 4 bytes for return address + 4 * 4 for spills |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 122 | */ |
Serguei Katkov | 897338d | 2016-03-01 15:53:22 +0600 | [diff] [blame] | 123 | #define FRAME_SIZE 28 |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 124 | |
| 125 | /* Frame diagram while executing ExecuteMterpImpl, high to low addresses */ |
Serguei Katkov | 897338d | 2016-03-01 15:53:22 +0600 | [diff] [blame] | 126 | #define IN_ARG3 (FRAME_SIZE + 16 + 16) |
| 127 | #define IN_ARG2 (FRAME_SIZE + 16 + 12) |
| 128 | #define IN_ARG1 (FRAME_SIZE + 16 + 8) |
| 129 | #define IN_ARG0 (FRAME_SIZE + 16 + 4) |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 130 | /* Spill offsets relative to %esp */ |
Serguei Katkov | 897338d | 2016-03-01 15:53:22 +0600 | [diff] [blame] | 131 | #define LOCAL0 (FRAME_SIZE - 4) |
| 132 | #define LOCAL1 (FRAME_SIZE - 8) |
| 133 | #define LOCAL2 (FRAME_SIZE - 12) |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 134 | /* Out Arg offsets, relative to %esp */ |
| 135 | #define OUT_ARG3 ( 12) |
| 136 | #define OUT_ARG2 ( 8) |
| 137 | #define OUT_ARG1 ( 4) |
| 138 | #define OUT_ARG0 ( 0) /* <- ExecuteMterpImpl esp + 0 */ |
| 139 | |
| 140 | /* During bringup, we'll use the shadow frame model instead of rFP */ |
| 141 | /* single-purpose registers, given names for clarity */ |
| 142 | #define rSELF IN_ARG0(%esp) |
| 143 | #define rPC %esi |
| 144 | #define rFP %edi |
| 145 | #define rINST %ebx |
| 146 | #define rINSTw %bx |
| 147 | #define rINSTbh %bh |
| 148 | #define rINSTbl %bl |
| 149 | #define rIBASE %edx |
| 150 | #define rREFS %ebp |
| 151 | |
| 152 | /* |
| 153 | * Instead of holding a pointer to the shadow frame, we keep rFP at the base of the vregs. So, |
| 154 | * to access other shadow frame fields, we need to use a backwards offset. Define those here. |
| 155 | */ |
| 156 | #define OFF_FP(a) (a - SHADOWFRAME_VREGS_OFFSET) |
| 157 | #define OFF_FP_NUMBER_OF_VREGS OFF_FP(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET) |
| 158 | #define OFF_FP_DEX_PC OFF_FP(SHADOWFRAME_DEX_PC_OFFSET) |
| 159 | #define OFF_FP_LINK OFF_FP(SHADOWFRAME_LINK_OFFSET) |
| 160 | #define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET) |
| 161 | #define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET) |
| 162 | #define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET) |
| 163 | #define OFF_FP_CODE_ITEM OFF_FP(SHADOWFRAME_CODE_ITEM_OFFSET) |
| 164 | #define OFF_FP_SHADOWFRAME (-SHADOWFRAME_VREGS_OFFSET) |
| 165 | |
buzbee | 2de973d | 2016-02-23 13:25:00 -0800 | [diff] [blame] | 166 | #define MTERP_PROFILE_BRANCHES 1 |
| 167 | #define MTERP_LOGGING 0 |
| 168 | |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 169 | /* |
buzbee | 2de973d | 2016-02-23 13:25:00 -0800 | [diff] [blame] | 170 | * Profile branch. rINST should contain the offset. %eax is scratch. |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 171 | */ |
buzbee | 2de973d | 2016-02-23 13:25:00 -0800 | [diff] [blame] | 172 | .macro MTERP_PROFILE_BRANCH |
| 173 | #ifdef MTERP_PROFILE_BRANCHES |
| 174 | EXPORT_PC |
| 175 | movl rSELF, %eax |
| 176 | movl %eax, OUT_ARG0(%esp) |
| 177 | leal OFF_FP_SHADOWFRAME(rFP), %eax |
| 178 | movl %eax, OUT_ARG1(%esp) |
| 179 | movl rINST, OUT_ARG2(%esp) |
| 180 | call SYMBOL(MterpProfileBranch) |
| 181 | testb %al, %al |
| 182 | jnz MterpOnStackReplacement |
| 183 | RESTORE_IBASE |
| 184 | #endif |
| 185 | .endm |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 186 | |
| 187 | /* |
| 188 | * "export" the PC to dex_pc field in the shadow frame, f/b/o future exception objects. Must |
| 189 | * be done *before* something throws. |
| 190 | * |
| 191 | * It's okay to do this more than once. |
| 192 | * |
| 193 | * NOTE: the fast interpreter keeps track of dex pc as a direct pointer to the mapped |
| 194 | * dex byte codes. However, the rest of the runtime expects dex pc to be an instruction |
| 195 | * offset into the code_items_[] array. For effiency, we will "export" the |
| 196 | * current dex pc as a direct pointer using the EXPORT_PC macro, and rely on GetDexPC |
| 197 | * to convert to a dex pc when needed. |
| 198 | */ |
| 199 | .macro EXPORT_PC |
| 200 | movl rPC, OFF_FP_DEX_PC_PTR(rFP) |
| 201 | .endm |
| 202 | |
| 203 | /* |
| 204 | * Refresh handler table. |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 205 | */ |
| 206 | .macro REFRESH_IBASE |
| 207 | movl rSELF, rIBASE |
| 208 | movl THREAD_CURRENT_IBASE_OFFSET(rIBASE), rIBASE |
| 209 | .endm |
| 210 | |
| 211 | /* |
Serguei Katkov | ff8579e | 2016-02-17 11:30:23 +0600 | [diff] [blame] | 212 | * Refresh handler table. |
| 213 | * IBase handles uses the caller save register so we must restore it after each call. |
| 214 | * Also it is used as a result of some 64-bit operations (like imul) and we should |
| 215 | * restore it in such cases also. |
| 216 | * |
| 217 | * TODO: Consider spilling the IBase instead of restoring it from Thread structure. |
| 218 | */ |
| 219 | .macro RESTORE_IBASE |
| 220 | movl rSELF, rIBASE |
| 221 | movl THREAD_CURRENT_IBASE_OFFSET(rIBASE), rIBASE |
| 222 | .endm |
| 223 | |
| 224 | /* |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 225 | * If rSELF is already loaded then we can use it from known reg. |
| 226 | */ |
Serguei Katkov | ff8579e | 2016-02-17 11:30:23 +0600 | [diff] [blame] | 227 | .macro RESTORE_IBASE_FROM_SELF _reg |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 228 | movl THREAD_CURRENT_IBASE_OFFSET(\_reg), rIBASE |
| 229 | .endm |
| 230 | |
| 231 | /* |
| 232 | * Refresh rINST. |
| 233 | * At enter to handler rINST does not contain the opcode number. |
| 234 | * However some utilities require the full value, so this macro |
| 235 | * restores the opcode number. |
| 236 | */ |
| 237 | .macro REFRESH_INST _opnum |
| 238 | movb rINSTbl, rINSTbh |
Serguei Katkov | 05dfaaa | 2016-01-28 08:21:26 +0600 | [diff] [blame] | 239 | movb MACRO_LITERAL(\_opnum), rINSTbl |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 240 | .endm |
| 241 | |
| 242 | /* |
| 243 | * Fetch the next instruction from rPC into rINSTw. Does not advance rPC. |
| 244 | */ |
| 245 | .macro FETCH_INST |
| 246 | movzwl (rPC), rINST |
| 247 | .endm |
| 248 | |
| 249 | /* |
| 250 | * Remove opcode from rINST, compute the address of handler and jump to it. |
| 251 | */ |
| 252 | .macro GOTO_NEXT |
| 253 | movzx rINSTbl,%eax |
| 254 | movzbl rINSTbh,rINST |
Serguei Katkov | 05dfaaa | 2016-01-28 08:21:26 +0600 | [diff] [blame] | 255 | shll MACRO_LITERAL(${handler_size_bits}), %eax |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 256 | addl rIBASE, %eax |
| 257 | jmp *%eax |
| 258 | .endm |
| 259 | |
| 260 | /* |
| 261 | * Advance rPC by instruction count. |
| 262 | */ |
| 263 | .macro ADVANCE_PC _count |
| 264 | leal 2*\_count(rPC), rPC |
| 265 | .endm |
| 266 | |
| 267 | /* |
| 268 | * Advance rPC by instruction count, fetch instruction and jump to handler. |
| 269 | */ |
| 270 | .macro ADVANCE_PC_FETCH_AND_GOTO_NEXT _count |
| 271 | ADVANCE_PC \_count |
| 272 | FETCH_INST |
| 273 | GOTO_NEXT |
| 274 | .endm |
| 275 | |
| 276 | /* |
| 277 | * Get/set the 32-bit value from a Dalvik register. |
| 278 | */ |
| 279 | #define VREG_ADDRESS(_vreg) (rFP,_vreg,4) |
| 280 | #define VREG_HIGH_ADDRESS(_vreg) 4(rFP,_vreg,4) |
| 281 | #define VREG_REF_ADDRESS(_vreg) (rREFS,_vreg,4) |
| 282 | #define VREG_REF_HIGH_ADDRESS(_vreg) 4(rREFS,_vreg,4) |
| 283 | |
| 284 | .macro GET_VREG _reg _vreg |
| 285 | movl (rFP,\_vreg,4), \_reg |
| 286 | .endm |
| 287 | |
| 288 | /* Read wide value to xmm. */ |
| 289 | .macro GET_WIDE_FP_VREG _reg _vreg |
| 290 | movq (rFP,\_vreg,4), \_reg |
| 291 | .endm |
| 292 | |
| 293 | .macro SET_VREG _reg _vreg |
| 294 | movl \_reg, (rFP,\_vreg,4) |
Serguei Katkov | 05dfaaa | 2016-01-28 08:21:26 +0600 | [diff] [blame] | 295 | movl MACRO_LITERAL(0), (rREFS,\_vreg,4) |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 296 | .endm |
| 297 | |
| 298 | /* Write wide value from xmm. xmm is clobbered. */ |
| 299 | .macro SET_WIDE_FP_VREG _reg _vreg |
| 300 | movq \_reg, (rFP,\_vreg,4) |
| 301 | pxor \_reg, \_reg |
| 302 | movq \_reg, (rREFS,\_vreg,4) |
| 303 | .endm |
| 304 | |
| 305 | .macro SET_VREG_OBJECT _reg _vreg |
| 306 | movl \_reg, (rFP,\_vreg,4) |
| 307 | movl \_reg, (rREFS,\_vreg,4) |
| 308 | .endm |
| 309 | |
| 310 | .macro GET_VREG_HIGH _reg _vreg |
| 311 | movl 4(rFP,\_vreg,4), \_reg |
| 312 | .endm |
| 313 | |
| 314 | .macro SET_VREG_HIGH _reg _vreg |
| 315 | movl \_reg, 4(rFP,\_vreg,4) |
Serguei Katkov | 05dfaaa | 2016-01-28 08:21:26 +0600 | [diff] [blame] | 316 | movl MACRO_LITERAL(0), 4(rREFS,\_vreg,4) |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 317 | .endm |
| 318 | |
| 319 | .macro CLEAR_REF _vreg |
Serguei Katkov | 05dfaaa | 2016-01-28 08:21:26 +0600 | [diff] [blame] | 320 | movl MACRO_LITERAL(0), (rREFS,\_vreg,4) |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 321 | .endm |
| 322 | |
| 323 | .macro CLEAR_WIDE_REF _vreg |
Serguei Katkov | 05dfaaa | 2016-01-28 08:21:26 +0600 | [diff] [blame] | 324 | movl MACRO_LITERAL(0), (rREFS,\_vreg,4) |
| 325 | movl MACRO_LITERAL(0), 4(rREFS,\_vreg,4) |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 326 | .endm |