cc06397e9a9901ac8214a059fd19a1c4e7fa83f3
[cacao.git] / src / vm / jit / mips / emit.c
1 /* src/vm/jit/mips/emit.c - MIPS 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 "vm/jit/mips/codegen.h"
37 #include "vm/jit/mips/md-abi.h"
38
39 #include "mm/memory.h"
40
41 #if defined(ENABLE_THREADS)
42 # include "threads/native/lock.h"
43 #endif
44
45 #include "vm/builtin.h"
46 #include "vm/exceptions.h"
47 #include "vm/stringlocal.h" /* XXX for gen_resolvebranch */
48
49 #include "vm/jit/abi-asm.h"
50 #include "vm/jit/asmpart.h"
51 #include "vm/jit/dseg.h"
52 #include "vm/jit/emit-common.h"
53 #include "vm/jit/jit.h"
54 #include "vm/jit/replace.h"
55
56 #include "vmcore/options.h"
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 * 8;
79
80                 if (IS_FLT_DBL_TYPE(src->type)) {
81                         if (IS_2_WORD_TYPE(src->type))
82                                 M_DLD(tempreg, REG_SP, disp);
83                         else
84                                 M_FLD(tempreg, REG_SP, disp);
85                 }
86                 else {
87 #if SIZEOF_VOID_P == 8
88                         M_LLD(tempreg, REG_SP, disp);
89 #else
90                         if (IS_2_WORD_TYPE(src->type))
91                                 M_LLD(tempreg, REG_SP, disp);
92                         else
93                                 M_ILD(tempreg, REG_SP, disp);
94 #endif
95                 }
96
97                 reg = tempreg;
98         }
99         else
100                 reg = src->vv.regoff;
101
102         return reg;
103 }
104
105
106 /* emit_load_low ***************************************************************
107
108    Emits a possible load of the low 32-bits of an operand.
109
110 *******************************************************************************/
111
112 #if SIZEOF_VOID_P == 4
113 s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
114 {
115         codegendata  *cd;
116         s4            disp;
117         s4            reg;
118
119         assert(src->type == TYPE_LNG);
120
121         /* get required compiler data */
122
123         cd = jd->cd;
124
125         if (src->flags & INMEMORY) {
126                 COUNT_SPILLS;
127
128                 disp = src->vv.regoff * 8;
129
130 #if WORDS_BIGENDIAN == 1
131                 M_ILD(tempreg, REG_SP, disp + 4);
132 #else
133                 M_ILD(tempreg, REG_SP, disp);
134 #endif
135
136                 reg = tempreg;
137         }
138         else
139                 reg = GET_LOW_REG(src->vv.regoff);
140
141         return reg;
142 }
143 #endif /* SIZEOF_VOID_P == 4 */
144
145
146 /* emit_load_high **************************************************************
147
148    Emits a possible load of the high 32-bits of an operand.
149
150 *******************************************************************************/
151
152 #if SIZEOF_VOID_P == 4
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 * 8;
169
170 #if WORDS_BIGENDIAN == 1
171                 M_ILD(tempreg, REG_SP, disp);
172 #else
173                 M_ILD(tempreg, REG_SP, disp + 4);
174 #endif
175
176                 reg = tempreg;
177         }
178         else
179                 reg = GET_HIGH_REG(src->vv.regoff);
180
181         return reg;
182 }
183 #endif /* SIZEOF_VOID_P == 4 */
184
185
186 /* emit_store ******************************************************************
187
188    Emits a possible store to variable.
189
190 *******************************************************************************/
191
192 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
193 {
194         codegendata  *cd;
195         s4            disp;
196
197         /* get required compiler data */
198
199         cd = jd->cd;
200
201         if (dst->flags & INMEMORY) {
202                 COUNT_SPILLS;
203
204                 disp = dst->vv.regoff * 8;
205
206                 if (IS_FLT_DBL_TYPE(dst->type)) {
207                         if (IS_2_WORD_TYPE(dst->type))
208                                 M_DST(d, REG_SP, disp);
209                         else
210                                 M_FST(d, REG_SP, disp);
211                 }
212                 else {
213 #if SIZEOF_VOID_P == 8
214                         M_LST(d, REG_SP, disp);
215 #else
216                         if (IS_2_WORD_TYPE(dst->type))
217                                 M_LST(d, REG_SP, disp);
218                         else
219                                 M_IST(d, REG_SP, disp);
220 #endif
221                 }
222         }
223 }
224
225
226 /* emit_copy *******************************************************************
227
228    Generates a register/memory to register/memory copy.
229
230 *******************************************************************************/
231
232 void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
233 {
234         codegendata  *cd;
235         s4            s1, d;
236
237         /* get required compiler data */
238
239         cd = jd->cd;
240
241         if ((src->vv.regoff != dst->vv.regoff) ||
242                 ((src->flags ^ dst->flags) & INMEMORY)) {
243                 /* If one of the variables resides in memory, we can eliminate
244                    the register move from/to the temporary register with the
245                    order of getting the destination register and the load. */
246
247                 if (IS_INMEMORY(src->flags)) {
248 #if SIZEOF_VOID_P == 4
249                         if (IS_2_WORD_TYPE(src->type))
250                                 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
251                         else
252 #endif
253                                 d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
254                         s1 = emit_load(jd, iptr, src, d);
255                 }
256                 else {
257                         s1 = emit_load(jd, iptr, src, REG_IFTMP);
258 #if SIZEOF_VOID_P == 4
259                         if (IS_2_WORD_TYPE(src->type))
260                                 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
261                         else
262 #endif
263                                 d = codegen_reg_of_var(iptr->opc, dst, s1);
264                 }
265
266                 if (s1 != d) {
267                         if (IS_FLT_DBL_TYPE(src->type)) {
268                                 if (IS_2_WORD_TYPE(src->type))
269                                         M_DMOV(s1, d);
270                                 else
271                                         M_FMOV(s1, d);
272                         }
273                         else {
274 #if SIZEOF_VOID_P == 8
275                                 M_MOV(s1, d);
276 #else
277                                 if (IS_2_WORD_TYPE(src->type))
278                                         M_LNGMOVE(s1, d);
279                                 else
280                                         M_MOV(s1, d);
281 #endif
282                         }
283                 }
284
285                 emit_store(jd, iptr, dst, d);
286         }
287 }
288
289
290 /* emit_iconst *****************************************************************
291
292    XXX
293
294 *******************************************************************************/
295
296 void emit_iconst(codegendata *cd, s4 d, s4 value)
297 {
298         s4 disp;
299
300     if ((value >= -32768) && (value <= 32767))
301         M_IADD_IMM(REG_ZERO, value, d);
302         else if ((value >= 0) && (value <= 0xffff))
303         M_OR_IMM(REG_ZERO, value, d);
304         else {
305         disp = dseg_add_s4(cd, value);
306         M_ILD(d, REG_PV, disp);
307     }
308 }
309
310
311 /* emit_lconst *****************************************************************
312
313    XXX
314
315 *******************************************************************************/
316
317 void emit_lconst(codegendata *cd, s4 d, s8 value)
318 {
319         s4 disp;
320
321 #if SIZEOF_VOID_P == 8
322         if ((value >= -32768) && (value <= 32767))
323                 M_LADD_IMM(REG_ZERO, value, d);
324         else if ((value >= 0) && (value <= 0xffff))
325                 M_OR_IMM(REG_ZERO, value, d);
326         else {
327                 disp = dseg_add_s8(cd, value);
328                 M_LLD(d, REG_PV, disp);
329         }
330 #else
331         disp = dseg_add_s8(cd, value);
332         M_LLD(d, REG_PV, disp);
333 #endif
334 }
335
336
337 /* emit_arithmetic_check *******************************************************
338
339    Emit an ArithmeticException check.
340
341 *******************************************************************************/
342
343 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
344 {
345         if (INSTRUCTION_MUST_CHECK(iptr)) {
346 #if 0
347                 M_BEQZ(reg, 0);
348                 codegen_add_arithmeticexception_ref(cd);
349                 M_NOP;
350 #else
351                 M_BNEZ(reg, 6);
352                 M_NOP;
353
354                 M_LUI(REG_ITMP3, 0);
355                 M_OR_IMM(REG_ITMP3, 0, REG_ITMP3);
356                 codegen_add_arithmeticexception_ref(cd);
357                 M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
358                 M_JMP(REG_ITMP3);
359                 M_NOP;
360 #endif
361         }
362 }
363
364
365 /* emit_arrayindexoutofbounds_check ********************************************
366
367    Emit an ArrayIndexOutOfBoundsException check.
368
369 *******************************************************************************/
370
371 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
372 {
373         if (INSTRUCTION_MUST_CHECK(iptr)) {
374                 M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
375                 M_CMPULT(s2, REG_ITMP3, REG_ITMP3);
376
377 #if 0
378                 M_BEQZ(REG_ITMP3, 0);
379                 codegen_add_arrayindexoutofboundsexception_ref(cd, s2);
380                 M_NOP;
381 #else
382                 M_BNEZ(REG_ITMP3, 6);
383                 M_NOP;
384
385                 M_LUI(REG_ITMP3, 0);
386                 M_OR_IMM(REG_ITMP3, 0, REG_ITMP3);
387                 codegen_add_arrayindexoutofboundsexception_ref(cd, s2);
388                 M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
389                 M_JMP(REG_ITMP3);
390                 M_NOP;
391 #endif
392         }
393 }
394
395
396 /* emit_arraystore_check *******************************************************
397
398    Emit an ArrayStoreException check.
399
400 *******************************************************************************/
401
402 void emit_arraystore_check(codegendata *cd, instruction *iptr, s4 reg)
403 {
404         if (INSTRUCTION_MUST_CHECK(iptr)) {
405 #if 0
406                 M_BEQZ(reg, 0);
407                 codegen_add_arraystoreexception_ref(cd);
408                 M_NOP;
409 #else
410                 M_BNEZ(reg, 6);
411                 M_NOP;
412
413                 M_LUI(REG_ITMP3, 0);
414                 M_OR_IMM(REG_ITMP3, 0, REG_ITMP3);
415                 codegen_add_arraystoreexception_ref(cd);
416                 M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
417                 M_JMP(REG_ITMP3);
418                 M_NOP;
419 #endif
420         }
421 }
422
423
424 /* emit_classcast_check ********************************************************
425
426    Emit a ClassCastException check.
427
428 *******************************************************************************/
429
430 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
431 {
432         if (INSTRUCTION_MUST_CHECK(iptr)) {
433 #if 0
434                 M_BNEZ(reg, 0);
435                 codegen_add_classcastexception_ref(cd, s1);
436                 M_NOP;
437 #else
438                 switch (condition) {
439                 case ICMD_IFEQ:
440                         M_BNEZ(reg, 6);
441                         break;
442
443                 case ICMD_IFNE:
444                         M_BEQZ(reg, 6);
445                         break;
446
447                 case ICMD_IFLE:
448                         M_BGTZ(reg, 6);
449                         break;
450
451                 default:
452                         vm_abort("emit_classcast_check: condition %d not found", condition);
453                 }
454
455                 M_NOP;
456
457                 M_LUI(REG_ITMP3, 0);
458                 M_OR_IMM(REG_ITMP3, 0, REG_ITMP3);
459                 codegen_add_classcastexception_ref(cd, s1);
460                 M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
461                 M_JMP(REG_ITMP3);
462                 M_NOP;
463 #endif
464         }
465 }
466
467
468 /* emit_nullpointer_check ******************************************************
469
470    Emit a NullPointerException check.
471
472 *******************************************************************************/
473
474 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
475 {
476         if (INSTRUCTION_MUST_CHECK(iptr)) {
477 #if 0
478                 M_BEQZ(reg, 0);
479                 codegen_add_nullpointerexception_ref(cd);
480                 M_NOP;
481 #else
482                 M_BNEZ(reg, 6);
483                 M_NOP;
484
485                 M_LUI(REG_ITMP3, 0);
486                 M_OR_IMM(REG_ITMP3, 0, REG_ITMP3);
487                 codegen_add_nullpointerexception_ref(cd);
488                 M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
489                 M_JMP(REG_ITMP3);
490                 M_NOP;
491 #endif
492         }
493 }
494
495
496 /* emit_exception_check ********************************************************
497
498    Emit an Exception check.
499
500 *******************************************************************************/
501
502 void emit_exception_check(codegendata *cd, instruction *iptr)
503 {
504         if (INSTRUCTION_MUST_CHECK(iptr)) {
505 #if 0
506                 M_BEQZ(REG_RESULT, 0);
507                 codegen_add_fillinstacktrace_ref(cd);
508                 M_NOP;
509 #else
510                 M_BNEZ(REG_RESULT, 6);
511                 M_NOP;
512
513                 M_LUI(REG_ITMP3, 0);
514                 M_OR_IMM(REG_ITMP3, 0, REG_ITMP3);
515                 codegen_add_fillinstacktrace_ref(cd);
516                 M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
517                 M_JMP(REG_ITMP3);
518                 M_NOP;
519 #endif
520         }
521 }
522
523
524 /* emit_exception_stubs ********************************************************
525
526    Generates the code for the exception stubs.
527
528 *******************************************************************************/
529
530 void emit_exception_stubs(jitdata *jd)
531 {
532         codegendata  *cd;
533         registerdata *rd;
534         exceptionref *er;
535         s4            branchmpc;
536         s4            targetmpc;
537         s4            targetdisp;
538         s4            disp;
539
540         /* get required compiler data */
541
542         cd = jd->cd;
543         rd = jd->rd;
544
545         /* generate exception stubs */
546
547         targetdisp = 0;
548
549         for (er = cd->exceptionrefs; er != NULL; er = er->next) {
550                 /* back-patch the branch to this exception code */
551
552                 branchmpc = er->branchpos;
553                 targetmpc = cd->mcodeptr - cd->mcodebase;
554
555                 md_codegen_patch_branch(cd, branchmpc, targetmpc);
556
557                 MCODECHECK(100);
558
559                 /* Check if the exception is an
560                    ArrayIndexOutOfBoundsException.  If so, move index register
561                    into REG_ITMP1. */
562
563                 if (er->reg != -1)
564                         M_MOV(er->reg, REG_ITMP1);
565
566                 /* calcuate exception address */
567
568                 M_LDA(REG_ITMP2_XPC, REG_PV, er->branchpos - 4);
569
570                 /* move function to call into REG_ITMP3 */
571
572                 disp = dseg_add_functionptr(cd, er->function);
573                 M_ALD(REG_ITMP3, REG_PV, disp);
574
575                 if (targetdisp == 0) {
576                         targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
577
578                         M_MOV(REG_PV, REG_A0);
579                         M_MOV(REG_SP, REG_A1);
580
581                         if (jd->isleafmethod)
582                                 M_MOV(REG_RA, REG_A2);
583                         else
584                                 M_ALD(REG_A2, REG_SP, (cd->stackframesize - 1) * 8);
585
586                         M_MOV(REG_ITMP2_XPC, REG_A3);
587
588 #if SIZEOF_VOID_P == 8
589                         /* XXX */
590                         M_MOV(REG_ITMP1, REG_A4);
591
592                         M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
593                         M_AST(REG_ITMP2_XPC, REG_SP, 0 * 8);
594
595                         if (jd->isleafmethod)
596                                 M_AST(REG_RA, REG_SP, 1 * 8);
597 #else
598                         M_ASUB_IMM(REG_SP, 5*4 + 2 * 8, REG_SP);
599                         M_AST(REG_ITMP2_XPC, REG_SP, 5*4 + 0 * 8);
600
601                         if (jd->isleafmethod)
602                                 M_AST(REG_RA, REG_SP, 5*4 + 1 * 8);
603
604                         M_AST(REG_ITMP1, REG_SP, 4 * 4);
605 #endif
606
607                         M_JSR(REG_RA, REG_ITMP3);
608                         M_NOP;
609                         M_MOV(REG_RESULT, REG_ITMP1_XPTR);
610
611 #if SIZEOF_VOID_P == 8
612                         if (jd->isleafmethod)
613                                 M_ALD(REG_RA, REG_SP, 1 * 8);
614
615                         M_ALD(REG_ITMP2_XPC, REG_SP, 0 * 8);
616                         M_AADD_IMM(REG_SP, 2 * 8, REG_SP);
617 #else
618                         if (jd->isleafmethod)
619                                 M_ALD(REG_RA, REG_SP, 5*4 + 1 * 8);
620
621                         M_ALD(REG_ITMP2_XPC, REG_SP, 5*4 + 0 * 8);
622                         M_AADD_IMM(REG_SP, 5*4 + 2 * 8, REG_SP);
623 #endif
624
625                         disp = dseg_add_functionptr(cd, asm_handle_exception);
626                         M_ALD(REG_ITMP3, REG_PV, disp);
627                         M_JMP(REG_ITMP3);
628                         M_NOP;
629                 }
630                 else {
631                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
632                                 (((u4 *) cd->mcodeptr) + 1);
633
634                         M_BR(disp);
635                         M_NOP;
636                 }
637         }
638 }
639
640
641 /* emit_patcher_stubs **********************************************************
642
643    Generates the code for the patcher stubs.
644
645 *******************************************************************************/
646
647 void emit_patcher_stubs(jitdata *jd)
648 {
649         codegendata *cd;
650         patchref    *pr;
651         u4           mcode[5];
652         u1          *savedmcodeptr;
653         u1          *tmpmcodeptr;
654         s4           targetdisp;
655         s4           disp;
656
657         /* get required compiler data */
658
659         cd = jd->cd;
660
661         /* generate code patching stub call code */
662
663         targetdisp = 0;
664
665 /*      for (pr = list_first_unsynced(cd->patchrefs); pr != NULL; */
666 /*               pr = list_next_unsynced(cd->patchrefs, pr)) { */
667         for (pr = cd->patchrefs; pr != NULL; pr = pr->next) {
668                 /* check code segment size */
669
670                 MCODECHECK(100);
671
672                 /* Get machine code which is patched back in later. The
673                    call is 2 instruction words long. */
674
675                 tmpmcodeptr = (u1 *) (cd->mcodebase + pr->branchpos);
676
677                 /* We use 2 loads here as an unaligned 8-byte read on 64-bit
678                    MIPS causes a SIGSEGV and using the same code for both
679                    architectures is much better. */
680
681                 mcode[0] = ((u4 *) tmpmcodeptr)[0];
682                 mcode[1] = ((u4 *) tmpmcodeptr)[1];
683
684                 mcode[2] = ((u4 *) tmpmcodeptr)[2];
685                 mcode[3] = ((u4 *) tmpmcodeptr)[3];
686                 mcode[4] = ((u4 *) tmpmcodeptr)[4];
687
688                 /* Patch in the call to call the following code (done at
689                    compile time). */
690
691                 savedmcodeptr = cd->mcodeptr;   /* save current mcodeptr              */
692                 cd->mcodeptr  = tmpmcodeptr;    /* set mcodeptr to patch position     */
693
694                 disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 1);
695
696 /*              if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) { */
697                         /* Recalculate the displacement to be relative to PV. */
698
699                         disp = savedmcodeptr - cd->mcodebase;
700
701                         M_LUI(REG_ITMP3, disp >> 16);
702                         M_OR_IMM(REG_ITMP3, disp, REG_ITMP3);
703                         M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
704                         M_JMP(REG_ITMP3);
705                         M_NOP;
706 /*              } */
707 /*              else { */
708 /*                      M_BR(disp); */
709 /*                      M_NOP; */
710 /*                      M_NOP; */
711 /*                      M_NOP; */
712 /*                      M_NOP; */
713 /*              } */
714
715                 cd->mcodeptr = savedmcodeptr;   /* restore the current mcodeptr   */
716
717                 /* create stack frame */
718
719                 M_ASUB_IMM(REG_SP, 8 * 8, REG_SP);
720
721                 /* calculate return address and move it onto the stack */
722
723                 M_LDA(REG_ITMP3, REG_PV, pr->branchpos);
724                 M_AST(REG_ITMP3, REG_SP, 7 * 8);
725
726                 /* move pointer to java_objectheader onto stack */
727
728 #if defined(ENABLE_THREADS)
729                 /* create a virtual java_objectheader */
730
731                 (void) dseg_add_unique_address(cd, NULL);                  /* flcword */
732                 (void) dseg_add_unique_address(cd, lock_get_initial_lock_word());
733                 disp = dseg_add_unique_address(cd, NULL);                  /* vftbl   */
734
735                 M_LDA(REG_ITMP3, REG_PV, disp);
736                 M_AST(REG_ITMP3, REG_SP, 6 * 8);
737 #else
738                 /* do nothing */
739 #endif
740
741                 /* move machine code onto stack */
742
743                 disp = dseg_add_s4(cd, mcode[0]);
744                 M_ILD(REG_ITMP3, REG_PV, disp);
745                 M_IST(REG_ITMP3, REG_SP, 3 * 8 + 0);
746
747                 disp = dseg_add_s4(cd, mcode[1]);
748                 M_ILD(REG_ITMP3, REG_PV, disp);
749                 M_IST(REG_ITMP3, REG_SP, 3 * 8 + 4);
750
751                 disp = dseg_add_s4(cd, mcode[2]);
752                 M_ILD(REG_ITMP3, REG_PV, disp);
753                 M_IST(REG_ITMP3, REG_SP, 4 * 8 + 0);
754
755                 disp = dseg_add_s4(cd, mcode[3]);
756                 M_ILD(REG_ITMP3, REG_PV, disp);
757                 M_IST(REG_ITMP3, REG_SP, 4 * 8 + 4);
758
759                 disp = dseg_add_s4(cd, mcode[4]);
760                 M_ILD(REG_ITMP3, REG_PV, disp);
761                 M_IST(REG_ITMP3, REG_SP, 5 * 8 + 0);
762
763                 /* move class/method/field reference onto stack */
764
765                 disp = dseg_add_address(cd, pr->ref);
766                 M_ALD(REG_ITMP3, REG_PV, disp);
767                 M_AST(REG_ITMP3, REG_SP, 2 * 8);
768
769                 /* move data segment displacement onto stack */
770
771                 disp = dseg_add_s4(cd, pr->disp);
772                 M_ILD(REG_ITMP3, REG_PV, disp);
773                 M_IST(REG_ITMP3, REG_SP, 1 * 8);
774
775                 /* move patcher function pointer onto stack */
776
777                 disp = dseg_add_functionptr(cd, pr->patcher);
778                 M_ALD(REG_ITMP3, REG_PV, disp);
779                 M_AST(REG_ITMP3, REG_SP, 0 * 8);
780
781                 if (targetdisp == 0) {
782                         targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
783
784                         disp = dseg_add_functionptr(cd, asm_patcher_wrapper);
785                         M_ALD(REG_ITMP3, REG_PV, disp);
786                         M_JMP(REG_ITMP3);
787                         M_NOP;
788                 }
789                 else {
790                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
791                                 (((u4 *) cd->mcodeptr) + 1);
792
793                         M_BR(disp);
794                         M_NOP;
795                 }
796         }
797 }
798
799
800 /* emit_replacement_stubs ******************************************************
801
802    Generates the code for the replacement stubs.
803
804 *******************************************************************************/
805
806 #if defined(ENABLE_REPLACEMENT)
807 void emit_replacement_stubs(jitdata *jd)
808 {
809         codegendata *cd;
810         codeinfo    *code;
811         rplpoint    *rplp;
812         s4           disp;
813         s4           i;
814 #if !defined(NDEBUG)
815         u1          *savedmcodeptr;
816 #endif
817
818         /* get required compiler data */
819
820         cd   = jd->cd;
821         code = jd->code;
822
823         rplp = code->rplpoints;
824
825         /* store beginning of replacement stubs */
826
827         code->replacementstubs = (u1*) (cd->mcodeptr - cd->mcodebase);
828
829         for (i = 0; i < code->rplpointcount; ++i, ++rplp) {
830                 /* do not generate stubs for non-trappable points */
831
832                 if (rplp->flags & RPLPOINT_FLAG_NOTRAP)
833                         continue;
834
835                 /* check code segment size */
836
837                 MCODECHECK(100);
838
839 #if !defined(NDEBUG)
840                 savedmcodeptr = cd->mcodeptr;
841 #endif
842
843                 /* create stack frame - 16-byte aligned */
844
845                 M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
846
847                 /* push address of `rplpoint` struct */
848
849                 disp = dseg_add_address(cd, rplp);
850                 M_ALD(REG_ITMP3, REG_PV, disp);
851                 M_AST(REG_ITMP3, REG_SP, 0 * 8);
852
853                 /* jump to replacement function */
854
855                 disp = dseg_add_functionptr(cd, asm_replacement_out);
856                 M_ALD(REG_ITMP3, REG_PV, disp);
857                 M_JMP(REG_ITMP3);
858                 M_NOP; /* delay slot */
859
860                 assert((cd->mcodeptr - savedmcodeptr) == 4*REPLACEMENT_STUB_SIZE);
861         }
862 }
863 #endif /* defined(ENABLE_REPLACEMENT) */
864
865
866 /* emit_verbosecall_enter ******************************************************
867
868    Generates the code for the call trace.
869
870 *******************************************************************************/
871
872 #if !defined(NDEBUG)
873 void emit_verbosecall_enter(jitdata *jd)
874 {
875         methodinfo   *m;
876         codegendata  *cd;
877         registerdata *rd;
878         methoddesc   *md;
879         s4            disp;
880         s4            i, j, t;
881
882         /* get required compiler data */
883
884         m  = jd->m;
885         cd = jd->cd;
886         rd = jd->rd;
887
888         md = m->parseddesc;
889
890         /* mark trace code */
891
892         M_NOP;
893
894         M_LDA(REG_SP, REG_SP, -(PA_SIZE + (2 + ARG_CNT + TMP_CNT) * 8));
895         M_AST(REG_RA, REG_SP, PA_SIZE + 1 * 8);
896
897         /* save argument registers (we store the registers as address
898            types, so it's correct for MIPS32 too) */
899
900         for (i = 0; i < INT_ARG_CNT; i++)
901                 M_AST(rd->argintregs[i], REG_SP, PA_SIZE + (2 + i) * 8);
902
903         for (i = 0; i < FLT_ARG_CNT; i++)
904                 M_DST(rd->argfltregs[i], REG_SP, PA_SIZE + (2 + INT_ARG_CNT + i) * 8);
905
906         /* save temporary registers for leaf methods */
907
908         if (jd->isleafmethod) {
909                 for (i = 0; i < INT_TMP_CNT; i++)
910                         M_AST(rd->tmpintregs[i], REG_SP, PA_SIZE + (2 + ARG_CNT + i) * 8);
911
912                 for (i = 0; i < FLT_TMP_CNT; i++)
913                         M_DST(rd->tmpfltregs[i], REG_SP, PA_SIZE + (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
914         }
915
916         /* Load float arguments into integer registers.  MIPS32 has less
917            float argument registers than integer ones, we need to check
918            that. */
919
920         for (i = 0; i < md->paramcount && i < INT_ARG_CNT && i < FLT_ARG_CNT; i++) {
921                 t = md->paramtypes[i].type;
922
923                 if (IS_FLT_DBL_TYPE(t)) {
924                         if (IS_2_WORD_TYPE(t)) {
925                                 M_DST(rd->argfltregs[i], REG_SP, 0 * 8);
926                                 M_LLD(rd->argintregs[i], REG_SP, 0 * 8);
927                         }
928                         else {
929                                 M_FST(rd->argfltregs[i], REG_SP, 0 * 8);
930                                 M_ILD(rd->argintregs[i], REG_SP, 0 * 8);
931                         }
932                 }
933         }
934
935 #if SIZEOF_VOID_P == 4
936                 for (i = 0, j = 0; i < md->paramcount && i < TRACE_ARGS_NUM; i++) {
937                         t = md->paramtypes[i].type;
938
939                         if (IS_INT_LNG_TYPE(t)) {
940                                 if (IS_2_WORD_TYPE(t)) {
941                                         M_ILD(rd->argintregs[j], REG_SP, PA_SIZE + (2 + i) * 8);
942                                         M_ILD(rd->argintregs[j + 1], REG_SP, PA_SIZE + (2 + i) * 8 + 4);
943                                 }
944                                 else {
945 # if WORDS_BIGENDIAN == 1
946                                         M_MOV(REG_ZERO, rd->argintregs[j]);
947                                         M_ILD(rd->argintregs[j + 1], REG_SP, PA_SIZE + (2 + i) * 8);
948 # else
949                                         M_ILD(rd->argintregs[j], REG_SP, PA_SIZE + (2 + i) * 8);
950                                         M_MOV(REG_ZERO, rd->argintregs[j + 1]);
951 # endif
952                                 }
953                                 j += 2;
954                         }
955                 }
956 #endif
957
958         disp = dseg_add_address(cd, m);
959         M_ALD(REG_ITMP1, REG_PV, disp);
960         M_AST(REG_ITMP1, REG_SP, PA_SIZE + 0 * 8);
961         disp = dseg_add_functionptr(cd, builtin_verbosecall_enter);
962         M_ALD(REG_ITMP3, REG_PV, disp);
963         M_JSR(REG_RA, REG_ITMP3);
964         M_NOP;
965
966         /* restore argument registers */
967
968         for (i = 0; i < INT_ARG_CNT; i++)
969                 M_ALD(rd->argintregs[i], REG_SP, PA_SIZE + (2 + i) * 8);
970
971         for (i = 0; i < FLT_ARG_CNT; i++)
972                 M_DLD(rd->argfltregs[i], REG_SP, PA_SIZE + (2 + INT_ARG_CNT + i) * 8);
973
974         /* restore temporary registers for leaf methods */
975
976         if (jd->isleafmethod) {
977                 for (i = 0; i < INT_TMP_CNT; i++)
978                         M_ALD(rd->tmpintregs[i], REG_SP, PA_SIZE + (2 + ARG_CNT + i) * 8);
979
980                 for (i = 0; i < FLT_TMP_CNT; i++)
981                         M_DLD(rd->tmpfltregs[i], REG_SP, PA_SIZE + (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
982         }
983
984         M_ALD(REG_RA, REG_SP, PA_SIZE + 1 * 8);
985         M_LDA(REG_SP, REG_SP, PA_SIZE + (2 + ARG_CNT + TMP_CNT) * 8);
986
987         /* mark trace code */
988
989         M_NOP;
990 }
991 #endif /* !defined(NDEBUG) */
992
993
994 /* emit_verbosecall_exit *******************************************************
995
996    Generates the code for the call trace.
997
998    void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
999
1000 *******************************************************************************/
1001
1002 #if !defined(NDEBUG)
1003 void emit_verbosecall_exit(jitdata *jd)
1004 {
1005         methodinfo   *m;
1006         codegendata  *cd;
1007         registerdata *rd;
1008         methoddesc   *md;
1009         s4            disp;
1010
1011         /* get required compiler data */
1012
1013         m  = jd->m;
1014         cd = jd->cd;
1015         rd = jd->rd;
1016
1017         md = m->parseddesc;
1018
1019         /* mark trace code */
1020
1021         M_NOP;
1022
1023 #if SIZEOF_VOID_P == 8
1024         M_ASUB_IMM(REG_SP, 4 * 8, REG_SP);          /* keep stack 16-byte aligned */
1025         M_AST(REG_RA, REG_SP, 0 * 8);
1026
1027         M_LST(REG_RESULT, REG_SP, 1 * 8);
1028         M_DST(REG_FRESULT, REG_SP, 2 * 8);
1029
1030         M_MOV(REG_RESULT, REG_A0);
1031         M_DMOV(REG_FRESULT, REG_FA1);
1032         M_FMOV(REG_FRESULT, REG_FA2);
1033
1034         disp = dseg_add_address(cd, m);
1035         M_ALD(REG_A4, REG_PV, disp);
1036 #else
1037         M_ASUB_IMM(REG_SP, (8*4 + 4 * 8), REG_SP);
1038         M_AST(REG_RA, REG_SP, 8*4 + 0 * 8);
1039
1040         M_LST(REG_RESULT_PACKED, REG_SP, 8*4 + 1 * 8);
1041         M_DST(REG_FRESULT, REG_SP, 8*4 + 2 * 8);
1042
1043         switch (md->returntype.type) {
1044         case TYPE_LNG:
1045                 M_LNGMOVE(REG_RESULT_PACKED, REG_A0_A1_PACKED);
1046                 break;
1047
1048         default:
1049 # if WORDS_BIGENDIAN == 1
1050                 M_MOV(REG_ZERO, REG_A0);
1051                 M_MOV(REG_RESULT, REG_A1);
1052 # else
1053                 M_MOV(REG_RESULT, REG_A0);
1054                 M_MOV(REG_ZERO, REG_A1);
1055 # endif
1056         }
1057
1058         M_LLD(REG_A2_A3_PACKED, REG_SP, 8*4 + 2 * 8);
1059         M_FST(REG_FRESULT, REG_SP, 4*4 + 0 * 4);
1060
1061         disp = dseg_add_address(cd, m);
1062         M_ALD(REG_ITMP1, REG_PV, disp);
1063         M_AST(REG_ITMP1, REG_SP, 4*4 + 1 * 4);
1064 #endif
1065
1066         disp = dseg_add_functionptr(cd, builtin_verbosecall_exit);
1067         M_ALD(REG_ITMP3, REG_PV, disp);
1068         M_JSR(REG_RA, REG_ITMP3);
1069         M_NOP;
1070
1071 #if SIZEOF_VOID_P == 8
1072         M_DLD(REG_FRESULT, REG_SP, 2 * 8);
1073         M_LLD(REG_RESULT, REG_SP, 1 * 8);
1074
1075         M_ALD(REG_RA, REG_SP, 0 * 8);
1076         M_AADD_IMM(REG_SP, 4 * 8, REG_SP);
1077 #else
1078         M_DLD(REG_FRESULT, REG_SP, 8*4 + 2 * 8);
1079         M_LLD(REG_RESULT_PACKED, REG_SP, 8*4 + 1 * 8);
1080
1081         M_ALD(REG_RA, REG_SP, 8*4 + 0 * 8);
1082         M_AADD_IMM(REG_SP, 8*4 + 4 * 8, REG_SP);
1083 #endif
1084
1085         /* mark trace code */
1086
1087         M_NOP;
1088 }
1089 #endif /* !defined(NDEBUG) */
1090
1091
1092 /*
1093  * These are local overrides for various environment variables in Emacs.
1094  * Please do not remove this and leave it at the end of the file, where
1095  * Emacs will automagically detect them.
1096  * ---------------------------------------------------------------------
1097  * Local variables:
1098  * mode: c
1099  * indent-tabs-mode: t
1100  * c-basic-offset: 4
1101  * tab-width: 4
1102  * End:
1103  * vim:noexpandtab:sw=4:ts=4:
1104  */