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