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