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