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 | |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 108 | /* Frame size must be 16-byte aligned. |
| 109 | * Remember about 4 bytes for return address |
| 110 | */ |
| 111 | #define FRAME_SIZE 44 |
| 112 | |
| 113 | /* Frame diagram while executing ExecuteMterpImpl, high to low addresses */ |
| 114 | #define IN_ARG3 (FRAME_SIZE + 16) |
| 115 | #define IN_ARG2 (FRAME_SIZE + 12) |
| 116 | #define IN_ARG1 (FRAME_SIZE + 8) |
| 117 | #define IN_ARG0 (FRAME_SIZE + 4) |
| 118 | #define CALLER_RP (FRAME_SIZE + 0) |
| 119 | /* Spill offsets relative to %esp */ |
| 120 | #define EBP_SPILL (FRAME_SIZE - 4) |
| 121 | #define EDI_SPILL (FRAME_SIZE - 8) |
| 122 | #define ESI_SPILL (FRAME_SIZE - 12) |
| 123 | #define EBX_SPILL (FRAME_SIZE - 16) |
| 124 | #define LOCAL0 (FRAME_SIZE - 20) |
| 125 | #define LOCAL1 (FRAME_SIZE - 24) |
| 126 | #define LOCAL2 (FRAME_SIZE - 28) |
| 127 | /* Out Arg offsets, relative to %esp */ |
| 128 | #define OUT_ARG3 ( 12) |
| 129 | #define OUT_ARG2 ( 8) |
| 130 | #define OUT_ARG1 ( 4) |
| 131 | #define OUT_ARG0 ( 0) /* <- ExecuteMterpImpl esp + 0 */ |
| 132 | |
| 133 | /* During bringup, we'll use the shadow frame model instead of rFP */ |
| 134 | /* single-purpose registers, given names for clarity */ |
| 135 | #define rSELF IN_ARG0(%esp) |
| 136 | #define rPC %esi |
| 137 | #define rFP %edi |
| 138 | #define rINST %ebx |
| 139 | #define rINSTw %bx |
| 140 | #define rINSTbh %bh |
| 141 | #define rINSTbl %bl |
| 142 | #define rIBASE %edx |
| 143 | #define rREFS %ebp |
| 144 | |
| 145 | /* |
| 146 | * Instead of holding a pointer to the shadow frame, we keep rFP at the base of the vregs. So, |
| 147 | * to access other shadow frame fields, we need to use a backwards offset. Define those here. |
| 148 | */ |
| 149 | #define OFF_FP(a) (a - SHADOWFRAME_VREGS_OFFSET) |
| 150 | #define OFF_FP_NUMBER_OF_VREGS OFF_FP(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET) |
| 151 | #define OFF_FP_DEX_PC OFF_FP(SHADOWFRAME_DEX_PC_OFFSET) |
| 152 | #define OFF_FP_LINK OFF_FP(SHADOWFRAME_LINK_OFFSET) |
| 153 | #define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET) |
| 154 | #define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET) |
| 155 | #define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET) |
| 156 | #define OFF_FP_CODE_ITEM OFF_FP(SHADOWFRAME_CODE_ITEM_OFFSET) |
| 157 | #define OFF_FP_SHADOWFRAME (-SHADOWFRAME_VREGS_OFFSET) |
| 158 | |
| 159 | /* |
| 160 | * |
| 161 | * The reference interpreter performs explicit suspect checks, which is somewhat wasteful. |
| 162 | * Dalvik's interpreter folded suspend checks into the jump table mechanism, and eventually |
| 163 | * mterp should do so as well. |
| 164 | */ |
| 165 | #define MTERP_SUSPEND 0 |
| 166 | |
| 167 | /* |
| 168 | * "export" the PC to dex_pc field in the shadow frame, f/b/o future exception objects. Must |
| 169 | * be done *before* something throws. |
| 170 | * |
| 171 | * It's okay to do this more than once. |
| 172 | * |
| 173 | * NOTE: the fast interpreter keeps track of dex pc as a direct pointer to the mapped |
| 174 | * dex byte codes. However, the rest of the runtime expects dex pc to be an instruction |
| 175 | * offset into the code_items_[] array. For effiency, we will "export" the |
| 176 | * current dex pc as a direct pointer using the EXPORT_PC macro, and rely on GetDexPC |
| 177 | * to convert to a dex pc when needed. |
| 178 | */ |
| 179 | .macro EXPORT_PC |
| 180 | movl rPC, OFF_FP_DEX_PC_PTR(rFP) |
| 181 | .endm |
| 182 | |
| 183 | /* |
| 184 | * Refresh handler table. |
| 185 | * IBase handles uses the caller save register so we must restore it after each call. |
| 186 | * Also it is used as a result of some 64-bit operations (like imul) and we should |
| 187 | * restore it in such cases also. |
| 188 | * |
| 189 | * TODO: Consider spilling the IBase instead of restoring it from Thread structure. |
| 190 | */ |
| 191 | .macro REFRESH_IBASE |
| 192 | movl rSELF, rIBASE |
| 193 | movl THREAD_CURRENT_IBASE_OFFSET(rIBASE), rIBASE |
| 194 | .endm |
| 195 | |
| 196 | /* |
| 197 | * If rSELF is already loaded then we can use it from known reg. |
| 198 | */ |
| 199 | .macro REFRESH_IBASE_FROM_SELF _reg |
| 200 | movl THREAD_CURRENT_IBASE_OFFSET(\_reg), rIBASE |
| 201 | .endm |
| 202 | |
| 203 | /* |
| 204 | * Refresh rINST. |
| 205 | * At enter to handler rINST does not contain the opcode number. |
| 206 | * However some utilities require the full value, so this macro |
| 207 | * restores the opcode number. |
| 208 | */ |
| 209 | .macro REFRESH_INST _opnum |
| 210 | movb rINSTbl, rINSTbh |
Serguei Katkov | 05dfaaa | 2016-01-28 08:21:26 +0600 | [diff] [blame] | 211 | movb MACRO_LITERAL(\_opnum), rINSTbl |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 212 | .endm |
| 213 | |
| 214 | /* |
| 215 | * Fetch the next instruction from rPC into rINSTw. Does not advance rPC. |
| 216 | */ |
| 217 | .macro FETCH_INST |
| 218 | movzwl (rPC), rINST |
| 219 | .endm |
| 220 | |
| 221 | /* |
| 222 | * Remove opcode from rINST, compute the address of handler and jump to it. |
| 223 | */ |
| 224 | .macro GOTO_NEXT |
| 225 | movzx rINSTbl,%eax |
| 226 | movzbl rINSTbh,rINST |
Serguei Katkov | 05dfaaa | 2016-01-28 08:21:26 +0600 | [diff] [blame] | 227 | shll MACRO_LITERAL(${handler_size_bits}), %eax |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 228 | addl rIBASE, %eax |
| 229 | jmp *%eax |
| 230 | .endm |
| 231 | |
| 232 | /* |
| 233 | * Advance rPC by instruction count. |
| 234 | */ |
| 235 | .macro ADVANCE_PC _count |
| 236 | leal 2*\_count(rPC), rPC |
| 237 | .endm |
| 238 | |
| 239 | /* |
| 240 | * Advance rPC by instruction count, fetch instruction and jump to handler. |
| 241 | */ |
| 242 | .macro ADVANCE_PC_FETCH_AND_GOTO_NEXT _count |
| 243 | ADVANCE_PC \_count |
| 244 | FETCH_INST |
| 245 | GOTO_NEXT |
| 246 | .endm |
| 247 | |
| 248 | /* |
| 249 | * Get/set the 32-bit value from a Dalvik register. |
| 250 | */ |
| 251 | #define VREG_ADDRESS(_vreg) (rFP,_vreg,4) |
| 252 | #define VREG_HIGH_ADDRESS(_vreg) 4(rFP,_vreg,4) |
| 253 | #define VREG_REF_ADDRESS(_vreg) (rREFS,_vreg,4) |
| 254 | #define VREG_REF_HIGH_ADDRESS(_vreg) 4(rREFS,_vreg,4) |
| 255 | |
| 256 | .macro GET_VREG _reg _vreg |
| 257 | movl (rFP,\_vreg,4), \_reg |
| 258 | .endm |
| 259 | |
| 260 | /* Read wide value to xmm. */ |
| 261 | .macro GET_WIDE_FP_VREG _reg _vreg |
| 262 | movq (rFP,\_vreg,4), \_reg |
| 263 | .endm |
| 264 | |
| 265 | .macro SET_VREG _reg _vreg |
| 266 | movl \_reg, (rFP,\_vreg,4) |
Serguei Katkov | 05dfaaa | 2016-01-28 08:21:26 +0600 | [diff] [blame] | 267 | movl MACRO_LITERAL(0), (rREFS,\_vreg,4) |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 268 | .endm |
| 269 | |
| 270 | /* Write wide value from xmm. xmm is clobbered. */ |
| 271 | .macro SET_WIDE_FP_VREG _reg _vreg |
| 272 | movq \_reg, (rFP,\_vreg,4) |
| 273 | pxor \_reg, \_reg |
| 274 | movq \_reg, (rREFS,\_vreg,4) |
| 275 | .endm |
| 276 | |
| 277 | .macro SET_VREG_OBJECT _reg _vreg |
| 278 | movl \_reg, (rFP,\_vreg,4) |
| 279 | movl \_reg, (rREFS,\_vreg,4) |
| 280 | .endm |
| 281 | |
| 282 | .macro GET_VREG_HIGH _reg _vreg |
| 283 | movl 4(rFP,\_vreg,4), \_reg |
| 284 | .endm |
| 285 | |
| 286 | .macro SET_VREG_HIGH _reg _vreg |
| 287 | movl \_reg, 4(rFP,\_vreg,4) |
Serguei Katkov | 05dfaaa | 2016-01-28 08:21:26 +0600 | [diff] [blame] | 288 | movl MACRO_LITERAL(0), 4(rREFS,\_vreg,4) |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 289 | .endm |
| 290 | |
| 291 | .macro CLEAR_REF _vreg |
Serguei Katkov | 05dfaaa | 2016-01-28 08:21:26 +0600 | [diff] [blame] | 292 | movl MACRO_LITERAL(0), (rREFS,\_vreg,4) |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 293 | .endm |
| 294 | |
| 295 | .macro CLEAR_WIDE_REF _vreg |
Serguei Katkov | 05dfaaa | 2016-01-28 08:21:26 +0600 | [diff] [blame] | 296 | movl MACRO_LITERAL(0), (rREFS,\_vreg,4) |
| 297 | movl MACRO_LITERAL(0), 4(rREFS,\_vreg,4) |
Bill Buzbee | 7c58bd4 | 2016-01-20 20:46:01 +0000 | [diff] [blame] | 298 | .endm |