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