1 /* Copyright (C) 2008 The Android Open Source Project 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 /* 17 * File: header.S 18 */ 19 20 /* 21 * IA32 calling convention and general notes: 22 * 23 * EAX, ECX, EDX - general purpose scratch registers (caller-saved); 24 * 25 * The stack (%esp) - used to pass arguments to functions 26 * 27 * EAX - holds the first 4 bytes of a return 28 * EDX - holds the second 4 bytes of a return 29 * 30 * EBX, ESI, EDI, EBP - are callee saved 31 * 32 * CS, DS, SS - are segment registers 33 * ES, FS, GS - are segment registers. We will try to avoid using these registers 34 * 35 * The stack is "full descending". Only the arguments that do not fit * in the first two arg registers are placed on the stack. 36 * "%esp" points to the first stacked argument (i.e. the 3rd arg). 37 */ 38 39 /* 40 * Mterp and IA32 notes 41 * 42 * mem nick purpose 43 * (%ebp) rGLUE InterpState base pointer (A.K.A. MterpGlue Pointer) 44 * %esi rPC interpreted program counter, used for fetching 45 * instructions 46 * %ebx rINST first 16-bit code unit of current instruction 47 * %edi rFP interpreted frame pointer, used for accessing 48 * locals and args 49 */ 50 51 /* 52 * Includes 53 */ 54 55 #include "../common/asm-constants.h" 56 57 /* 58 * Reserved registers 59 */ 60 61 #define rGLUE (%ebp) 62 #define rINST %ebx 63 #define rINSTbl %bl 64 #define rINSTbh %bh 65 #define rINSTw %bx 66 #define rPC %esi 67 #define rFP %edi 68 69 /* 70 * Temporary register used when finishing an opcode 71 */ 72 73 #define rFinish %edx 74 75 /* 76 * Stack locations used for temporary data. For convenience. 77 */ 78 79 #define sReg0 4(%ebp) 80 #define sReg1 8(%ebp) 81 #define sReg2 12(%ebp) 82 #define sReg3 16(%ebp) 83 84 /* 85 * Save the PC and FP to the glue struct 86 */ 87 88 .macro SAVE_PC_FP_TO_GLUE _reg 89 movl rGLUE, \_reg 90 movl rPC, offGlue_pc(\_reg) 91 movl rFP, offGlue_fp(\_reg) 92 .endm 93 94 /* 95 * Restore the PC and FP from the glue struct 96 */ 97 98 .macro LOAD_PC_FP_FROM_GLUE 99 movl rGLUE, rFP 100 movl offGlue_pc(rFP), rPC 101 movl offGlue_fp(rFP), rFP 102 .endm 103 104 /* 105 * "Export" the PC to the stack frame, f/b/o future exception objects. This must 106 * be done *before* something calls dvmThrowException. 107 * 108 * In C this is "SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc", i.e. 109 * fp - sizeof(StackSaveArea) + offsetof(SaveArea, xtra.currentPc) 110 * 111 * It's okay to do this more than once. 112 */ 113 114 .macro EXPORT_PC 115 movl rPC, (-sizeofStackSaveArea + offStackSaveArea_currentPc)(rFP) 116 .endm 117 118 /* 119 * Given a frame pointer, find the stack save area. 120 * In C this is "((StackSaveArea*)(_fp) -1)". 121 */ 122 123 .macro SAVEAREA_FROM_FP _reg 124 lea -sizeofStackSaveArea(rFP), \_reg 125 .endm 126 127 /* 128 * Get the 32-bit value from a dalvik register. 129 */ 130 131 .macro GET_VREG _vreg 132 movl (rFP,\_vreg, 4), \_vreg 133 .endm 134 135 /* 136 * Set the 32-bit value from a dalvik register. 137 */ 138 139 .macro SET_VREG _reg _vreg 140 movl \_reg, (rFP,\_vreg, 4) 141 .endm 142 143 /* 144 * Fetch the next instruction from rPC into rINST. Does not advance rPC. 145 */ 146 147 .macro FETCH_INST 148 movzwl (rPC), rINST 149 .endm 150 151 /* 152 * Fetch the next instruction from the specified offset. Advances rPC 153 * to point to the next instruction. "_count" is in 16-bit code units. 154 * 155 * This must come AFTER anything that can throw an exception, or the 156 * exception catch may miss. (This also implies that it must come after 157 * EXPORT_PC()) 158 */ 159 160 .macro FETCH_ADVANCE_INST _count 161 add $$(\_count*2), rPC 162 movzwl (rPC), rINST 163 .endm 164 165 /* 166 * Fetch the next instruction from an offset specified by _reg. Updates 167 * rPC to point to the next instruction. "_reg" must specify the distance 168 * in bytes, *not* 16-bit code units, and may be a signed value. 169 */ 170 171 .macro FETCH_ADVANCE_INST_RB _reg 172 addl \_reg, rPC 173 movzwl (rPC), rINST 174 .endm 175 176 /* 177 * Fetch a half-word code unit from an offset past the current PC. The 178 * "_count" value is in 16-bit code units. Does not advance rPC. 179 * For example, given instruction of format: AA|op BBBB, it 180 * fetches BBBB. 181 */ 182 183 .macro FETCH _count _reg 184 movzwl (\_count*2)(rPC), \_reg 185 .endm 186 187 /* 188 * Fetch a half-word code unit from an offset past the current PC. The 189 * "_count" value is in 16-bit code units. Does not advance rPC. 190 * This variant treats the value as signed. 191 */ 192 193 .macro FETCHs _count _reg 194 movswl (\_count*2)(rPC), \_reg 195 .endm 196 197 /* 198 * Fetch the first byte from an offset past the current PC. The 199 * "_count" value is in 16-bit code units. Does not advance rPC. 200 * For example, given instruction of format: AA|op CC|BB, it 201 * fetches BB. 202 */ 203 204 .macro FETCH_BB _count _reg 205 movzbl (\_count*2)(rPC), \_reg 206 .endm 207 208 /* 209 * Fetch the second byte from an offset past the current PC. The 210 * "_count" value is in 16-bit code units. Does not advance rPC. 211 * For example, given instruction of format: AA|op CC|BB, it 212 * fetches CC. 213 */ 214 215 .macro FETCH_CC _count _reg 216 movzbl (\_count*2 + 1)(rPC), \_reg 217 .endm 218 219 /* 220 * Fetch the second byte from an offset past the current PC. The 221 * "_count" value is in 16-bit code units. Does not advance rPC. 222 * This variant treats the value as signed. 223 */ 224 225 .macro FETCH_CCs _count _reg 226 movsbl (\_count*2 + 1)(rPC), \_reg 227 .endm 228 229 230 /* 231 * Fetch one byte from an offset past the current PC. Pass in the same 232 * "_count" as you would for FETCH, and an additional 0/1 indicating which 233 * byte of the halfword you want (lo/hi). 234 */ 235 236 .macro FETCH_B _reg _count _byte 237 movzbl (\_count*2+\_byte)(rPC), \_reg 238 .endm 239 240 /* 241 * Put the instruction's opcode field into the specified register. 242 */ 243 244 .macro GET_INST_OPCODE _reg 245 movzbl rINSTbl, \_reg 246 .endm 247 248 /* 249 * Begin executing the opcode in _reg. 250 */ 251 252 .macro GOTO_OPCODE _reg 253 shl $$${handler_size_bits}, \_reg 254 addl $$dvmAsmInstructionStart,\_reg 255 jmp *\_reg 256 .endm 257 258 259 260 /* 261 * Macros pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE 262 * by using a jump table. _rFinish should must be the same register for 263 * both macros. 264 */ 265 266 .macro FFETCH _rFinish 267 movzbl (rPC), \_rFinish 268 .endm 269 270 .macro FGETOP_JMPa _rFinish 271 movzbl 1(rPC), rINST 272 jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4) 273 .endm 274 275 /* 276 * Macro pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE 277 * by using a jump table. _rFinish and _count should must be the same register for 278 * both macros. 279 */ 280 281 .macro FFETCH_ADV _count _rFinish 282 movzbl (\_count*2)(rPC), \_rFinish 283 .endm 284 285 .macro FGETOP_JMP _count _rFinish 286 movzbl (\_count*2 + 1)(rPC), rINST 287 addl $$(\_count*2), rPC 288 jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4) 289 .endm 290 291 /* 292 * Macro pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE 293 * by using a jump table. _rFinish and _reg should must be the same register for 294 * both macros. 295 */ 296 297 .macro FFETCH_ADV_RB _reg _rFinish 298 movzbl (\_reg, rPC), \_rFinish 299 .endm 300 301 .macro FGETOP_RB_JMP _reg _rFinish 302 movzbl 1(\_reg, rPC), rINST 303 addl \_reg, rPC 304 jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4) 305 .endm 306 307 /* 308 * Attempts to speed up FETCH_INST, GET_INST_OPCODE using 309 * a jump table. This macro should be called before FINISH_JMP where 310 * rFinish should be the same register containing the opcode value. 311 * This is an attempt to split up FINISH in order to reduce or remove 312 * potential stalls due to the wait for rFINISH. 313 */ 314 315 .macro FINISH_FETCH _rFinish 316 movzbl (rPC), \_rFinish 317 movzbl 1(rPC), rINST 318 .endm 319 320 321 /* 322 * Attempts to speed up FETCH_ADVANCE_INST, GET_INST_OPCODE using 323 * a jump table. This macro should be called before FINISH_JMP where 324 * rFinish should be the same register containing the opcode value. 325 * This is an attempt to split up FINISH in order to reduce or remove 326 * potential stalls due to the wait for rFINISH. 327 */ 328 329 .macro FINISH_FETCH_ADVANCE _count _rFinish 330 movzbl (\_count*2)(rPC), \_rFinish 331 movzbl (\_count*2 + 1)(rPC), rINST 332 addl $$(\_count*2), rPC 333 .endm 334 335 /* 336 * Attempts to speed up FETCH_ADVANCE_INST_RB, GET_INST_OPCODE using 337 * a jump table. This macro should be called before FINISH_JMP where 338 * rFinish should be the same register containing the opcode value. 339 * This is an attempt to split up FINISH in order to reduce or remove 340 * potential stalls due to the wait for rFINISH. 341 */ 342 343 .macro FINISH_FETCH_ADVANCE_RB _reg _rFinish 344 movzbl (\_reg, rPC), \_rFinish 345 movzbl 1(\_reg, rPC), rINST 346 addl \_reg, rPC 347 .endm 348 349 /* 350 * Attempts to speed up GOTO_OPCODE using a jump table. This macro should 351 * be called after a FINISH_FETCH* instruction where rFinish should be the 352 * same register containing the opcode value. This is an attempt to split up 353 * FINISH in order to reduce or remove potential stalls due to the wait for rFINISH. 354 */ 355 356 .macro FINISH_JMP _rFinish 357 jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4) 358 .endm 359 360 /* 361 * Attempts to speed up FETCH_INST, GET_INST_OPCODE, GOTO_OPCODE by using 362 * a jump table. Uses a single macro - but it should be faster if we 363 * split up the fetch for rFinish and the jump using rFinish. 364 */ 365 366 .macro FINISH_A 367 movzbl (rPC), rFinish 368 movzbl 1(rPC), rINST 369 jmp *dvmAsmInstructionJmpTable(,rFinish, 4) 370 .endm 371 372 /* 373 * Attempts to speed up FETCH_ADVANCE_INST, GET_INST_OPCODE, 374 * GOTO_OPCODE by using a jump table. Uses a single macro - 375 * but it should be faster if we split up the fetch for rFinish 376 * and the jump using rFinish. 377 */ 378 379 .macro FINISH _count 380 movzbl (\_count*2)(rPC), rFinish 381 movzbl (\_count*2 + 1)(rPC), rINST 382 addl $$(\_count*2), rPC 383 jmp *dvmAsmInstructionJmpTable(,rFinish, 4) 384 .endm 385 386 /* 387 * Attempts to speed up FETCH_ADVANCE_INST_RB, GET_INST_OPCODE, 388 * GOTO_OPCODE by using a jump table. Uses a single macro - 389 * but it should be faster if we split up the fetch for rFinish 390 * and the jump using rFinish. 391 */ 392 393 .macro FINISH_RB _reg _rFinish 394 movzbl (\_reg, rPC), \_rFinish 395 movzbl 1(\_reg, rPC), rINST 396 addl \_reg, rPC 397 jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4) 398 .endm 399 400 /* 401 * Hard coded helper values. 402 */ 403 404 .balign 16 405 406 .LdoubNeg: 407 .quad 0x8000000000000000 408 409 .L64bits: 410 .quad 0xFFFFFFFFFFFFFFFF 411 412 .LshiftMask2: 413 .quad 0x0000000000000000 414 .LshiftMask: 415 .quad 0x000000000000003F 416 417 .Lvalue64: 418 .quad 0x0000000000000040 419 420 .LvaluePosInfLong: 421 .quad 0x7FFFFFFFFFFFFFFF 422 423 .LvalueNegInfLong: 424 .quad 0x8000000000000000 425 426 .LvalueNanLong: 427 .quad 0x0000000000000000 428 429 .LintMin: 430 .long 0x80000000 431 432 .LintMax: 433 .long 0x7FFFFFFF 434