* src/vm/jit/emit-common.h (emit_copy): Changed signature.
[cacao.git] / src / vm / jit / arm / emit.c
1 /* src/vm/jit/arm/emit.c - Arm code emitter functions
2
3    Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    $Id: emit.c 4398 2006-01-31 23:43:08Z twisti $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33
34 #include "vm/types.h"
35
36 #include "md-abi.h"
37
38 #include "vm/jit/arm/codegen.h"
39
40 #include "mm/memory.h"
41
42 #if defined(ENABLE_THREADS)
43 # include "threads/native/lock.h"
44 #endif
45
46 #include "vm/builtin.h"
47 #include "vm/exceptions.h"
48 #include "vm/global.h"
49
50 #include "vm/jit/abi.h"
51 #include "vm/jit/asmpart.h"
52 #include "vm/jit/emit-common.h"
53 #include "vm/jit/jit.h"
54 #include "vm/jit/replace.h"
55
56 #include "toolbox/logging.h" /* XXX for debugging only */
57
58
59 /* emit_load *******************************************************************
60
61    Emits a possible load of an operand.
62
63 *******************************************************************************/
64
65 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
66 {
67         codegendata  *cd;
68         s4            disp;
69         s4            reg;
70
71         /* get required compiler data */
72
73         cd = jd->cd;
74
75         if (src->flags & INMEMORY) {
76                 COUNT_SPILLS;
77
78                 disp = src->vv.regoff * 4;
79
80                 if (IS_FLT_DBL_TYPE(src->type)) {
81 #if defined(ENABLE_SOFTFLOAT)
82                         if (IS_2_WORD_TYPE(src->type))
83                                 M_LLD(tempreg, REG_SP, disp);
84                         else
85                                 M_ILD(tempreg, REG_SP, disp);
86 #else
87                         if (IS_2_WORD_TYPE(src->type))
88                                 M_DLD(tempreg, REG_SP, disp);
89                         else
90                                 M_FLD(tempreg, REG_SP, disp);
91 #endif
92                 }
93                 else {
94                         if (IS_2_WORD_TYPE(src->type))
95                                 M_LLD(tempreg, REG_SP, disp);
96                         else
97                                 M_ILD(tempreg, REG_SP, disp);
98                 }
99
100                 reg = tempreg;
101         }
102         else
103                 reg = src->vv.regoff;
104
105         return reg;
106 }
107
108
109 /* emit_load_low ***************************************************************
110
111    Emits a possible load of the low 32-bits of a long source operand.
112
113 *******************************************************************************/
114
115 s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
116 {
117         codegendata  *cd;
118         s4            disp;
119         s4            reg;
120
121         assert(src->type == TYPE_LNG);
122
123         /* get required compiler data */
124
125         cd = jd->cd;
126
127         if (src->flags & INMEMORY) {
128                 COUNT_SPILLS;
129
130                 disp = src->vv.regoff * 4;
131
132 #if defined(__ARMEL__)
133                 M_ILD(tempreg, REG_SP, disp);
134 #else
135                 M_ILD(tempreg, REG_SP, disp + 4);
136 #endif
137
138                 reg = tempreg;
139         }
140         else
141                 reg = GET_LOW_REG(src->vv.regoff);
142
143         return reg;
144 }
145
146
147 /* emit_load_high **************************************************************
148
149    Emits a possible load of the high 32-bits of a long source operand.
150
151 *******************************************************************************/
152
153 s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
154 {
155         codegendata  *cd;
156         s4            disp;
157         s4            reg;
158
159         assert(src->type == TYPE_LNG);
160
161         /* get required compiler data */
162
163         cd = jd->cd;
164
165         if (src->flags & INMEMORY) {
166                 COUNT_SPILLS;
167
168                 disp = src->vv.regoff * 4;
169
170 #if defined(__ARMEL__)
171                 M_ILD(tempreg, REG_SP, disp + 4);
172 #else
173                 M_ILD(tempreg, REG_SP, disp);
174 #endif
175
176                 reg = tempreg;
177         }
178         else
179                 reg = GET_HIGH_REG(src->vv.regoff);
180
181         return reg;
182 }
183
184
185 /* emit_store ******************************************************************
186
187    Emits a possible store to a variable.
188
189 *******************************************************************************/
190
191 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
192 {
193         codegendata  *cd;
194         s4            disp;
195
196         /* get required compiler data */
197
198         cd = jd->cd;
199
200         if (dst->flags & INMEMORY) {
201                 COUNT_SPILLS;
202
203                 disp = dst->vv.regoff * 4;
204
205                 if (IS_FLT_DBL_TYPE(dst->type)) {
206 #if defined(ENABLE_SOFTFLOAT)
207                         if (IS_2_WORD_TYPE(dst->type))
208                                 M_LST(d, REG_SP, disp);
209                         else
210                                 M_IST(d, REG_SP, disp);
211 #else
212                         if (IS_2_WORD_TYPE(dst->type))
213                                 M_DST(d, REG_SP, disp);
214                         else
215                                 M_FST(d, REG_SP, disp);
216 #endif
217                 }
218                 else {
219                         if (IS_2_WORD_TYPE(dst->type))
220                                 M_LST(d, REG_SP, disp);
221                         else
222                                 M_IST(d, REG_SP, disp);
223                 }
224         }
225         else if (IS_LNG_TYPE(dst->type)) {
226 #if defined(__ARMEL__)
227                 if (GET_HIGH_REG(dst->vv.regoff) == REG_SPLIT)
228                         M_IST_INTERN(GET_HIGH_REG(d), REG_SP, 0 * 4);
229 #else
230                 if (GET_LOW_REG(dst->vv.regoff) == REG_SPLIT)
231                         M_IST_INTERN(GET_LOW_REG(d), REG_SP, 0 * 4);
232 #endif
233         }
234 }
235
236
237 /* emit_copy *******************************************************************
238
239    Generates a register/memory to register/memory copy.
240
241 *******************************************************************************/
242
243 void emit_copy(jitdata *jd, instruction *iptr)
244 {
245         codegendata *cd;
246         varinfo     *src;
247         varinfo     *dst;
248         s4           s1, d;
249
250         /* get required compiler data */
251
252         cd = jd->cd;
253
254         /* get source and destination variables */
255
256         src = VAROP(iptr->s1);
257         dst = VAROP(iptr->dst);
258
259         /* XXX dummy call, removed me!!! */
260         d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP1);
261
262         if ((src->vv.regoff != dst->vv.regoff) ||
263                 ((src->flags ^ dst->flags) & INMEMORY)) {
264
265                 if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
266                         /* emit nothing, as the value won't be used anyway */
267                         return;
268                 }
269
270                 /* If one of the variables resides in memory, we can eliminate
271                    the register move from/to the temporary register with the
272                    order of getting the destination register and the load. */
273
274                 if (IS_INMEMORY(src->flags)) {
275 #if !defined(ENABLE_SOFTFLOAT)
276                         if (IS_FLT_DBL_TYPE(src->type))
277                                 d = codegen_reg_of_var(iptr->opc, dst, REG_FTMP1);
278                         else
279 #endif
280                         {
281                                 if (IS_2_WORD_TYPE(src->type))
282                                         d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
283                                 else
284                                         d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP1);
285                         }
286
287                         s1 = emit_load(jd, iptr, src, d);
288                 }
289                 else {
290 #if !defined(ENABLE_SOFTFLOAT)
291                         if (IS_FLT_DBL_TYPE(src->type))
292                                 s1 = emit_load(jd, iptr, src, REG_FTMP1);
293                         else
294 #endif
295                         {
296                                 if (IS_2_WORD_TYPE(src->type))
297                                         s1 = emit_load(jd, iptr, src, REG_ITMP12_PACKED);
298                                 else
299                                         s1 = emit_load(jd, iptr, src, REG_ITMP1);
300                         }
301
302                         d = codegen_reg_of_var(iptr->opc, dst, s1);
303                 }
304
305                 if (s1 != d) {
306                         if (IS_FLT_DBL_TYPE(src->type)) {
307 #if defined(ENABLE_SOFTFLOAT)
308                                 if (IS_2_WORD_TYPE(src->type))
309                                         M_LNGMOVE(s1, d);
310                                 else
311                                         /* XXX grrrr, wrong direction! */
312                                         M_MOV(d, s1);
313 #else
314                                 if (IS_2_WORD_TYPE(src->type))
315                                         M_DMOV(s1, d);
316                                 else
317                                         M_FMOV(s1, d);
318 #endif
319                         }
320                         else {
321                                 if (IS_2_WORD_TYPE(src->type))
322                                         M_LNGMOVE(s1, d);
323                                 else
324                                         /* XXX grrrr, wrong direction! */
325                                         M_MOV(d, s1);
326                         }
327                 }
328
329                 emit_store(jd, iptr, dst, d);
330         }
331 }
332
333
334 /* emit_iconst *****************************************************************
335
336    XXX
337
338 *******************************************************************************/
339
340 void emit_iconst(codegendata *cd, s4 d, s4 value)
341 {
342         s4 disp;
343
344         if (IS_IMM(value))
345                 M_MOV_IMM(d, value);
346         else {
347                 disp = dseg_add_s4(cd, value);
348                 M_DSEG_LOAD(d, disp);
349         }
350 }
351
352
353 /* emit_branch *****************************************************************
354
355    Emits the code for conditional and unconditional branchs.
356
357 *******************************************************************************/
358
359 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
360 {
361         s4 checkdisp;
362         s4 branchdisp;
363
364         /* calculate the different displacements */
365
366         checkdisp  = (disp - 8);
367         branchdisp = (disp - 8) >> 2;
368
369         /* check which branch to generate */
370
371         if (condition == BRANCH_UNCONDITIONAL) {
372                 /* check displacement for overflow */
373
374                 if ((checkdisp < (s4) 0xff000000) || (checkdisp > (s4) 0x00ffffff)) {
375                         /* if the long-branches flag isn't set yet, do it */
376
377                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
378                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
379                                                           CODEGENDATA_FLAG_LONGBRANCHES);
380                         }
381
382                         vm_abort("emit_branch: emit unconditional long-branch code");
383                 }
384                 else {
385                         M_B(branchdisp);
386                 }
387         }
388         else {
389                 /* and displacement for overflow */
390
391                 if ((checkdisp < (s4) 0xff000000) || (checkdisp > (s4) 0x00ffffff)) {
392                         /* if the long-branches flag isn't set yet, do it */
393
394                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
395                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
396                                                           CODEGENDATA_FLAG_LONGBRANCHES);
397                         }
398
399                         vm_abort("emit_branch: emit conditional long-branch code");
400                 }
401                 else {
402                         switch (condition) {
403                         case BRANCH_EQ:
404                                 M_BEQ(branchdisp);
405                                 break;
406                         case BRANCH_NE:
407                                 M_BNE(branchdisp);
408                                 break;
409                         case BRANCH_LT:
410                                 M_BLT(branchdisp);
411                                 break;
412                         case BRANCH_GE:
413                                 M_BGE(branchdisp);
414                                 break;
415                         case BRANCH_GT:
416                                 M_BGT(branchdisp);
417                                 break;
418                         case BRANCH_LE:
419                                 M_BLE(branchdisp);
420                                 break;
421                         case BRANCH_UGT:
422                                 M_BHI(branchdisp);
423                                 break;
424                         default:
425                                 vm_abort("emit_branch: unknown condition %d", condition);
426                         }
427                 }
428         }
429 }
430
431
432 /* emit_arithmetic_check *******************************************************
433
434    Emit an ArithmeticException check.
435
436 *******************************************************************************/
437
438 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
439 {
440         if (INSTRUCTION_MUST_CHECK(iptr)) {
441                 CHECK_INT_REG(reg);
442                 M_TEQ_IMM(reg, 0);
443                 M_TRAPEQ(0, EXCEPTION_HARDWARE_ARITHMETIC);
444         }
445 }
446
447
448 /* emit_nullpointer_check ******************************************************
449
450    Emit a NullPointerException check.
451
452 *******************************************************************************/
453
454 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
455 {
456         if (INSTRUCTION_MUST_CHECK(iptr)) {
457                 M_TST(reg, reg);
458                 M_TRAPEQ(0, EXCEPTION_HARDWARE_NULLPOINTER);
459         }
460 }
461
462 void emit_nullpointer_check_force(codegendata *cd, instruction *iptr, s4 reg)
463 {
464         M_TST(reg, reg);
465         M_TRAPEQ(0, EXCEPTION_HARDWARE_NULLPOINTER);
466 }
467
468
469 /* emit_arrayindexoutofbounds_check ********************************************
470
471    Emit a ArrayIndexOutOfBoundsException check.
472
473 *******************************************************************************/
474
475 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
476 {
477         if (INSTRUCTION_MUST_CHECK(iptr)) {
478                 M_ILD_INTERN(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
479                 M_CMP(s2, REG_ITMP3);
480                 M_TRAPHS(s2, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
481         }
482 }
483
484
485 /* emit_classcast_check ********************************************************
486
487    Emit a ClassCastException check.
488
489 *******************************************************************************/
490
491 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
492 {
493         if (INSTRUCTION_MUST_CHECK(iptr)) {
494                 switch (condition) {
495                 case BRANCH_EQ:
496                         M_TRAPEQ(s1, EXCEPTION_HARDWARE_CLASSCAST);
497                         break;
498
499                 case BRANCH_LE:
500                         M_TRAPLE(s1, EXCEPTION_HARDWARE_CLASSCAST);
501                         break;
502
503                 case BRANCH_UGT:
504                         M_TRAPHI(s1, EXCEPTION_HARDWARE_CLASSCAST);
505                         break;
506
507                 default:
508                         vm_abort("emit_classcast_check: unknown condition %d", condition);
509                 }
510         }
511 }
512
513 /* emit_exception_check ********************************************************
514
515    Emit an Exception check.
516
517 *******************************************************************************/
518
519 void emit_exception_check(codegendata *cd, instruction *iptr)
520 {
521         if (INSTRUCTION_MUST_CHECK(iptr)) {
522                 M_TST(REG_RESULT, REG_RESULT);
523                 M_TRAPEQ(0, EXCEPTION_HARDWARE_EXCEPTION);
524         }
525 }
526
527
528 /* emit_patcher_stubs **********************************************************
529
530    Generates the code for the patcher stubs.
531
532 *******************************************************************************/
533
534 void emit_patcher_stubs(jitdata *jd)
535 {
536         codegendata *cd;
537         patchref    *pref;
538         u4           mcode;
539         u1          *savedmcodeptr;
540         u1          *tmpmcodeptr;
541         s4           targetdisp;
542         s4           disp;
543
544         /* get required compiler data */
545
546         cd = jd->cd;
547
548         /* generate patcher stub call code */
549
550         targetdisp = 0;
551
552         for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
553                 /* check code segment size */
554
555                 MCODECHECK(100);
556
557                 /* Get machine code which is patched back in later. The
558                    call is 1 instruction word long. */
559
560                 tmpmcodeptr = (u1 *) (cd->mcodebase + pref->branchpos);
561
562                 mcode = *((u4 *) tmpmcodeptr);
563
564                 /* Patch in the call to call the following code (done at
565                    compile time). */
566
567                 savedmcodeptr = cd->mcodeptr;   /* save current mcodeptr              */
568                 cd->mcodeptr  = tmpmcodeptr;    /* set mcodeptr to patch position     */
569
570                 disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 2);
571                 M_B(disp);
572
573                 cd->mcodeptr = savedmcodeptr;   /* restore the current mcodeptr       */
574
575                 /* create stack frame (align stack to 8-byte) */
576
577                 M_SUB_IMM(REG_SP, REG_SP, 8 * 4);
578
579                 /* save itmp3 onto stack */
580
581                 M_STR_INTERN(REG_ITMP3, REG_SP, 6 * 4);
582
583                 /* calculate return address and move it onto stack */
584                 /* ATTENTION: we can not use BL to branch to patcher stub,        */
585                 /* ATTENTION: because we need to preserve LR for leaf methods     */
586
587                 disp = (s4) (((u4 *) cd->mcodeptr) - (((u4 *) tmpmcodeptr) + 1) + 2);
588
589                 M_SUB_IMM_EXT_MUL4(REG_ITMP3, REG_PC, disp);
590                 M_STR_INTERN(REG_ITMP3, REG_SP, 4 * 4);
591
592                 /* move pointer to java_objectheader onto stack */
593
594 #if defined(ENABLE_THREADS)
595                 /* order reversed because of data segment layout */
596
597                 (void) dseg_add_unique_address(cd, NULL);           /* flcword    */
598                 (void) dseg_add_unique_address(cd, lock_get_initial_lock_word());
599                 disp = dseg_add_unique_address(cd, NULL);           /* vftbl      */
600
601                 M_SUB_IMM_EXT_MUL4(REG_ITMP3, REG_PV, -disp / 4);
602                 M_STR_INTERN(REG_ITMP3, REG_SP, 3 * 4);
603 #else
604                 M_EOR(REG_ITMP3, REG_ITMP3, REG_ITMP3);
605                 M_STR_INTERN(REG_ITMP3, REG_SP, 3 * 4);
606 #endif
607
608                 /* move machine code onto stack */
609
610                 disp = dseg_add_unique_s4(cd, mcode);
611                 M_DSEG_LOAD(REG_ITMP3, disp);
612                 M_STR_INTERN(REG_ITMP3, REG_SP, 2 * 4);
613
614                 /* move class/method/field reference onto stack */
615
616                 disp = dseg_add_unique_address(cd, pref->ref);
617                 M_DSEG_LOAD(REG_ITMP3, disp);
618                 M_STR_INTERN(REG_ITMP3, REG_SP, 1 * 4);
619
620                 /* move data segment displacement onto stack */
621
622                 disp = dseg_add_unique_s4(cd, pref->disp);
623                 M_DSEG_LOAD(REG_ITMP3, disp);
624                 M_STR_INTERN(REG_ITMP3, REG_SP, 5 * 4);
625
626                 /* move patcher function pointer onto stack */
627
628                 disp = dseg_add_functionptr(cd, pref->patcher);
629                 M_DSEG_LOAD(REG_ITMP3, disp);
630                 M_STR_INTERN(REG_ITMP3, REG_SP, 0 * 4);
631
632                 /* finally call the patcher via asm_patcher_wrapper */
633                 /* ATTENTION: don't use REG_PV here, because some patchers need it */
634
635                 if (targetdisp == 0) {
636                         targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
637
638                         disp = dseg_add_functionptr(cd, asm_patcher_wrapper);
639                         /*M_DSEG_BRANCH_NOLINK(REG_PC, REG_PV, a);*/
640                         /* TODO: this is only a hack */
641                         M_DSEG_LOAD(REG_ITMP3, disp);
642                         M_MOV(REG_PC, REG_ITMP3);
643                 }
644                 else {
645                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
646                                 (((u4 *) cd->mcodeptr) + 2);
647
648                         M_B(disp);
649                 }
650         }
651 }
652
653
654 /* emit_replacement_stubs ******************************************************
655
656    Generates the code for the replacement stubs.
657
658 *******************************************************************************/
659
660 #if defined(ENABLE_REPLACEMENT)
661 void emit_replacement_stubs(jitdata *jd)
662 {
663         codegendata *cd;
664         codeinfo    *code;
665         rplpoint    *rplp;
666         u1          *savedmcodeptr;
667         s4           disp;
668         s4           i;
669
670         /* get required compiler data */
671
672         cd   = jd->cd;
673         code = jd->code;
674 }
675 #endif /* defined(ENABLE_REPLACEMENT) */
676
677
678 /* emit_verbosecall_enter ******************************************************
679
680    Generates the code for the call trace.
681
682 *******************************************************************************/
683
684 #if !defined(NDEBUG)
685 void emit_verbosecall_enter(jitdata *jd)
686 {
687         methodinfo   *m;
688         codegendata  *cd;
689         registerdata *rd;
690         methoddesc   *md;
691         s4            stackframesize;
692         s4            disp;
693         s4            i, t, s1, s2;
694
695         /* get required compiler data */
696
697         m  = jd->m;
698         cd = jd->cd;
699         rd = jd->rd;
700
701         md = m->parseddesc;
702
703         /* stackframesize is changed below */
704
705         stackframesize = cd->stackframesize;
706
707         /* mark trace code */
708
709         M_NOP;
710
711         /* Save argument registers to stack (including LR and PV).  Keep
712            stack 8-byte aligned. */
713
714         M_STMFD(BITMASK_ARGS | (1<<REG_LR) | (1<<REG_PV), REG_SP);
715         M_SUB_IMM(REG_SP, REG_SP, (2 + 2 + 1 + 1) * 4); /* space for a3, a4 and m */
716
717         stackframesize += 6 + 2 + 2 + 1 + 1;
718
719         /* prepare args for tracer */
720
721         i = md->paramcount - 1;
722
723         if (i > 3)
724                 i = 3;
725
726         for (; i >= 0; i--) {
727                 t = md->paramtypes[i].type;
728
729                 /* load argument into register (s1) and make it of TYPE_LNG */
730
731                 if (!md->params[i].inmemory) {
732                         s1 = md->params[i].regoff;
733
734                         if (!IS_2_WORD_TYPE(t)) {
735                                 M_MOV_IMM(REG_ITMP1, 0);
736                                 s1 = PACK_REGS(s1, REG_ITMP1);
737                         }
738                         else {
739                                 SPLIT_OPEN(t, s1, REG_ITMP1);
740                                 SPLIT_LOAD(t, s1, stackframesize);
741                         }
742                 }
743                 else {
744                         s1 = REG_ITMP12_PACKED;
745                         s2 = md->params[i].regoff + stackframesize;
746
747                         if (IS_2_WORD_TYPE(t))
748                                 M_LLD(s1, REG_SP, s2 * 4);
749                         else {
750                                 M_ILD(GET_LOW_REG(s1), REG_SP, s2 * 4);
751                                 M_MOV_IMM(GET_HIGH_REG(s1), 0);
752                         }
753                 }
754
755                 /* place argument for tracer */
756
757                 if (i < 2) {
758 #if defined(__ARMEL__)
759                         s2 = PACK_REGS(abi_registers_integer_argument[i * 2],
760                                                    abi_registers_integer_argument[i * 2 + 1]);
761 #else /* defined(__ARMEB__) */
762                         s2 = PACK_REGS(abi_registers_integer_argument[i * 2 + 1],
763                                                    abi_registers_integer_argument[i * 2]);
764 #endif          
765                         M_LNGMOVE(s1, s2);
766                 }
767                 else {
768                         s2 = (i - 2) * 2;
769                         M_LST(s1, REG_SP, s2 * 4);
770                 }
771         }
772
773         /* prepare methodinfo pointer for tracer */
774
775         disp = dseg_add_address(cd, m);
776         M_DSEG_LOAD(REG_ITMP1, disp);
777         M_STR_INTERN(REG_ITMP1, REG_SP, 16);
778
779         /* call tracer here (we use a long branch) */
780
781         M_LONGBRANCH(builtin_verbosecall_enter);
782
783         /* Restore argument registers from stack.  Keep stack 8-byte
784            aligned. */
785
786         M_ADD_IMM(REG_SP, REG_SP, (2 + 2 + 1 + 1) * 4);    /* free argument stack */
787         M_LDMFD(BITMASK_ARGS | (1<<REG_LR) | (1<<REG_PV), REG_SP);
788
789         /* mark trace code */
790
791         M_NOP;
792 }
793 #endif /* !defined(NDEBUG) */
794
795
796 /* emit_verbosecall_exit *******************************************************
797
798    Generates the code for the call trace.
799
800    void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
801
802 *******************************************************************************/
803
804 #if !defined(NDEBUG)
805 void emit_verbosecall_exit(jitdata *jd)
806 {
807         methodinfo   *m;
808         codegendata  *cd;
809         registerdata *rd;
810         methoddesc   *md;
811         s4            disp;
812
813         /* get required compiler data */
814
815         m  = jd->m;
816         cd = jd->cd;
817         rd = jd->rd;
818
819         md = m->parseddesc;
820
821         /* mark trace code */
822
823         M_NOP;
824
825         /* Keep stack 8-byte aligned. */
826
827         M_STMFD(BITMASK_RESULT | (1<<REG_LR) | (1<<REG_PV), REG_SP);
828         M_SUB_IMM(REG_SP, REG_SP, (1 + 1) * 4);              /* space for f and m */
829
830         switch (md->returntype.type) {
831         case TYPE_ADR:
832         case TYPE_INT:
833                 M_INTMOVE(REG_RESULT, GET_LOW_REG(REG_A0_A1_PACKED));
834                 M_MOV_IMM(GET_HIGH_REG(REG_A0_A1_PACKED), 0);
835                 break;
836
837         case TYPE_LNG:
838                 M_LNGMOVE(REG_RESULT_PACKED, REG_A0_A1_PACKED);
839                 break;
840
841         case TYPE_FLT:
842                 M_IST(REG_RESULT, REG_SP, 0 * 4);
843                 break;
844
845         case TYPE_DBL:
846                 M_LNGMOVE(REG_RESULT_PACKED, REG_A2_A3_PACKED);
847                 break;
848         }
849
850         disp = dseg_add_address(cd, m);
851         M_DSEG_LOAD(REG_ITMP1, disp);
852         M_AST(REG_ITMP1, REG_SP, 1 * 4);
853         M_LONGBRANCH(builtin_verbosecall_exit);
854
855         /* Keep stack 8-byte aligned. */
856
857         M_ADD_IMM(REG_SP, REG_SP, (1 + 1) * 4);            /* free argument stack */
858         M_LDMFD(BITMASK_RESULT | (1<<REG_LR) | (1<<REG_PV), REG_SP);
859
860         /* mark trace code */
861
862         M_NOP;
863 }
864 #endif /* !defined(NDEBUG) */
865
866
867 /*
868  * These are local overrides for various environment variables in Emacs.
869  * Please do not remove this and leave it at the end of the file, where
870  * Emacs will automagically detect them.
871  * ---------------------------------------------------------------------
872  * Local variables:
873  * mode: c
874  * indent-tabs-mode: t
875  * c-basic-offset: 4
876  * tab-width: 4
877  * End:
878  * vim:noexpandtab:sw=4:ts=4:
879  */