* configure.ac: Added option --enable-replacement.
[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: emitfuncs.c 4398 2006-01-31 23:43:08Z twisti $
32
33 */
34
35
36 #include "config.h"
37 #include "vm/types.h"
38
39 #include <assert.h>
40
41 #include "md-abi.h"
42
43 #include "vm/jit/mips/codegen.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                         M_LLD(tempreg, REG_SP, disp);
89
90                 reg = tempreg;
91         }
92         else
93                 reg = src->vv.regoff;
94
95         return reg;
96 }
97
98
99 /* emit_store ******************************************************************
100
101    Emits a possible store to variable.
102
103 *******************************************************************************/
104
105 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
106 {
107         codegendata  *cd;
108         s4            disp;
109
110         /* get required compiler data */
111
112         cd = jd->cd;
113
114         if (dst->flags & INMEMORY) {
115                 COUNT_SPILLS;
116
117                 disp = dst->vv.regoff * 8;
118
119                 if (IS_FLT_DBL_TYPE(dst->type)) {
120                         if (IS_2_WORD_TYPE(dst->type))
121                                 M_DST(d, REG_SP, disp);
122                         else
123                                 M_FST(d, REG_SP, disp);
124                 }
125                 else
126                         M_LST(d, REG_SP, disp);
127         }
128 }
129
130
131 /* emit_copy *******************************************************************
132
133    Generates a register/memory to register/memory copy.
134
135 *******************************************************************************/
136
137 void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
138 {
139         codegendata  *cd;
140         s4            s1, d;
141
142         /* get required compiler data */
143
144         cd = jd->cd;
145
146         if ((src->vv.regoff != dst->vv.regoff) ||
147                 ((src->flags ^ dst->flags) & INMEMORY)) {
148
149                 /* If one of the variables resides in memory, we can eliminate
150                    the register move from/to the temporary register with the
151                    order of getting the destination register and the load. */
152
153                 if (IS_INMEMORY(src->flags)) {
154                         d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
155                         s1 = emit_load(jd, iptr, src, d);
156                 }
157                 else {
158                         s1 = emit_load(jd, iptr, src, REG_IFTMP);
159                         d = codegen_reg_of_var(iptr->opc, dst, s1);
160                 }
161
162                 if (s1 != d) {
163                         if (IS_FLT_DBL_TYPE(src->type)) {
164                                 if (IS_2_WORD_TYPE(src->type))
165                                         M_DMOV(s1, d);
166                                 else
167                                         M_FMOV(s1, d);
168                         }
169                         else
170                                 M_MOV(s1, d);
171                 }
172
173                 emit_store(jd, iptr, dst, d);
174         }
175 }
176
177
178 /* emit_iconst *****************************************************************
179
180    XXX
181
182 *******************************************************************************/
183
184 void emit_iconst(codegendata *cd, s4 d, s4 value)
185 {
186         s4 disp;
187
188     if ((value >= -32768) && (value <= 32767))
189         M_IADD_IMM(REG_ZERO, value, d);
190         else if ((value >= 0) && (value <= 0xffff))
191         M_OR_IMM(REG_ZERO, value, d);
192         else {
193         disp = dseg_add_s4(cd, value);
194         M_ILD(d, REG_PV, disp);
195     }
196 }
197
198
199 /* emit_lconst *****************************************************************
200
201    XXX
202
203 *******************************************************************************/
204
205 void emit_lconst(codegendata *cd, s4 d, s8 value)
206 {
207         s4 disp;
208
209         if ((value >= -32768) && (value <= 32767))
210                 M_LADD_IMM(REG_ZERO, value, d);
211         else if ((value >= 0) && (value <= 0xffff))
212                 M_OR_IMM(REG_ZERO, value, d);
213         else {
214                 disp = dseg_add_s8(cd, value);
215                 M_LLD(d, REG_PV, disp);
216         }
217 }
218
219
220 /* emit_arithmetic_check *******************************************************
221
222    Emit an ArithmeticException check.
223
224 *******************************************************************************/
225
226 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
227 {
228         if (INSTRUCTION_MUST_CHECK(iptr)) {
229 #if 0
230                 M_BEQZ(reg, 0);
231                 codegen_add_arithmeticexception_ref(cd);
232                 M_NOP;
233 #else
234                 M_BNEZ(reg, 6);
235                 M_NOP;
236
237                 M_LUI(REG_ITMP3, 0);
238                 M_OR_IMM(REG_ITMP3, 0, REG_ITMP3);
239                 codegen_add_arithmeticexception_ref(cd);
240                 M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
241                 M_JMP(REG_ITMP3);
242                 M_NOP;
243 #endif
244         }
245 }
246
247
248 /* emit_arrayindexoutofbounds_check ********************************************
249
250    Emit an ArrayIndexOutOfBoundsException check.
251
252 *******************************************************************************/
253
254 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
255 {
256         if (INSTRUCTION_MUST_CHECK(iptr)) {
257                 M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
258                 M_CMPULT(s2, REG_ITMP3, REG_ITMP3);
259
260 #if 0
261                 M_BEQZ(REG_ITMP3, 0);
262                 codegen_add_arrayindexoutofboundsexception_ref(cd, s2);
263                 M_NOP;
264 #else
265                 M_BNEZ(REG_ITMP3, 6);
266                 M_NOP;
267
268                 M_LUI(REG_ITMP3, 0);
269                 M_OR_IMM(REG_ITMP3, 0, REG_ITMP3);
270                 codegen_add_arrayindexoutofboundsexception_ref(cd, s2);
271                 M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
272                 M_JMP(REG_ITMP3);
273                 M_NOP;
274 #endif
275         }
276 }
277
278
279 /* emit_arraystore_check *******************************************************
280
281    Emit an ArrayStoreException check.
282
283 *******************************************************************************/
284
285 void emit_arraystore_check(codegendata *cd, instruction *iptr, s4 reg)
286 {
287         if (INSTRUCTION_MUST_CHECK(iptr)) {
288 #if 0
289                 M_BEQZ(reg, 0);
290                 codegen_add_arraystoreexception_ref(cd);
291                 M_NOP;
292 #else
293                 M_BNEZ(reg, 6);
294                 M_NOP;
295
296                 M_LUI(REG_ITMP3, 0);
297                 M_OR_IMM(REG_ITMP3, 0, REG_ITMP3);
298                 codegen_add_arraystoreexception_ref(cd);
299                 M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
300                 M_JMP(REG_ITMP3);
301                 M_NOP;
302 #endif
303         }
304 }
305
306
307 /* emit_classcast_check ********************************************************
308
309    Emit a ClassCastException check.
310
311 *******************************************************************************/
312
313 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
314 {
315         if (INSTRUCTION_MUST_CHECK(iptr)) {
316 #if 0
317                 M_BNEZ(reg, 0);
318                 codegen_add_classcastexception_ref(cd, s1);
319                 M_NOP;
320 #else
321                 switch (condition) {
322                 case ICMD_IFEQ:
323                         M_BNEZ(reg, 6);
324                         break;
325
326                 case ICMD_IFNE:
327                         M_BEQZ(reg, 6);
328                         break;
329
330                 case ICMD_IFLE:
331                         M_BGTZ(reg, 6);
332                         break;
333
334                 default:
335                         vm_abort("emit_classcast_check: condition %d not found", condition);
336                 }
337
338                 M_NOP;
339
340                 M_LUI(REG_ITMP3, 0);
341                 M_OR_IMM(REG_ITMP3, 0, REG_ITMP3);
342                 codegen_add_classcastexception_ref(cd, s1);
343                 M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
344                 M_JMP(REG_ITMP3);
345                 M_NOP;
346 #endif
347         }
348 }
349
350
351 /* emit_nullpointer_check ******************************************************
352
353    Emit a NullPointerException check.
354
355 *******************************************************************************/
356
357 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
358 {
359         if (INSTRUCTION_MUST_CHECK(iptr)) {
360 #if 0
361                 M_BEQZ(reg, 0);
362                 codegen_add_nullpointerexception_ref(cd);
363                 M_NOP;
364 #else
365                 M_BNEZ(reg, 6);
366                 M_NOP;
367
368                 M_LUI(REG_ITMP3, 0);
369                 M_OR_IMM(REG_ITMP3, 0, REG_ITMP3);
370                 codegen_add_nullpointerexception_ref(cd);
371                 M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
372                 M_JMP(REG_ITMP3);
373                 M_NOP;
374 #endif
375         }
376 }
377
378
379 /* emit_exception_check ********************************************************
380
381    Emit an Exception check.
382
383 *******************************************************************************/
384
385 void emit_exception_check(codegendata *cd, instruction *iptr)
386 {
387         if (INSTRUCTION_MUST_CHECK(iptr)) {
388 #if 0
389                 M_BEQZ(REG_RESULT, 0);
390                 codegen_add_fillinstacktrace_ref(cd);
391                 M_NOP;
392 #else
393                 M_BNEZ(REG_RESULT, 6);
394                 M_NOP;
395
396                 M_LUI(REG_ITMP3, 0);
397                 M_OR_IMM(REG_ITMP3, 0, REG_ITMP3);
398                 codegen_add_fillinstacktrace_ref(cd);
399                 M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
400                 M_JMP(REG_ITMP3);
401                 M_NOP;
402 #endif
403         }
404 }
405
406
407 /* emit_exception_stubs ********************************************************
408
409    Generates the code for the exception stubs.
410
411 *******************************************************************************/
412
413 void emit_exception_stubs(jitdata *jd)
414 {
415         codegendata  *cd;
416         registerdata *rd;
417         exceptionref *er;
418         s4            branchmpc;
419         s4            targetmpc;
420         s4            targetdisp;
421         s4            disp;
422
423         /* get required compiler data */
424
425         cd = jd->cd;
426         rd = jd->rd;
427
428         /* generate exception stubs */
429
430         targetdisp = 0;
431
432         for (er = cd->exceptionrefs; er != NULL; er = er->next) {
433                 /* back-patch the branch to this exception code */
434
435                 branchmpc = er->branchpos;
436                 targetmpc = cd->mcodeptr - cd->mcodebase;
437
438                 md_codegen_patch_branch(cd, branchmpc, targetmpc);
439
440                 MCODECHECK(100);
441
442                 /* Check if the exception is an
443                    ArrayIndexOutOfBoundsException.  If so, move index register
444                    into REG_ITMP1. */
445
446                 if (er->reg != -1)
447                         M_MOV(er->reg, REG_ITMP1);
448
449                 /* calcuate exception address */
450
451                 M_LDA(REG_ITMP2_XPC, REG_PV, er->branchpos - 4);
452
453                 /* move function to call into REG_ITMP3 */
454
455                 disp = dseg_add_functionptr(cd, er->function);
456                 M_ALD(REG_ITMP3, REG_PV, disp);
457
458                 if (targetdisp == 0) {
459                         targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
460
461                         M_MOV(REG_PV, REG_A0);
462                         M_MOV(REG_SP, REG_A1);
463
464                         if (jd->isleafmethod)
465                                 M_MOV(REG_RA, REG_A2);
466                         else
467                                 M_ALD(REG_A2, REG_SP, (cd->stackframesize - 1) * 8);
468
469                         M_MOV(REG_ITMP2_XPC, REG_A3);
470                         M_MOV(REG_ITMP1, REG_A4);
471
472                         M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
473                         M_AST(REG_ITMP2_XPC, REG_SP, 0 * 8);
474
475                         if (jd->isleafmethod)
476                                 M_AST(REG_RA, REG_SP, 1 * 8);
477
478                         M_JSR(REG_RA, REG_ITMP3);
479                         M_NOP;
480                         M_MOV(REG_RESULT, REG_ITMP1_XPTR);
481
482                         if (jd->isleafmethod)
483                                 M_ALD(REG_RA, REG_SP, 1 * 8);
484
485                         M_ALD(REG_ITMP2_XPC, REG_SP, 0 * 8);
486                         M_AADD_IMM(REG_SP, 2 * 8, REG_SP);
487
488                         disp = dseg_add_functionptr(cd, asm_handle_exception);
489                         M_ALD(REG_ITMP3, REG_PV, disp);
490                         M_JMP(REG_ITMP3);
491                         M_NOP;
492                 }
493                 else {
494                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
495                                 (((u4 *) cd->mcodeptr) + 1);
496
497                         M_BR(disp);
498                         M_NOP;
499                 }
500         }
501 }
502
503
504 /* emit_patcher_stubs **********************************************************
505
506    Generates the code for the patcher stubs.
507
508 *******************************************************************************/
509
510 void emit_patcher_stubs(jitdata *jd)
511 {
512         codegendata *cd;
513         patchref    *pr;
514         u4           mcode[5];
515         u1          *savedmcodeptr;
516         u1          *tmpmcodeptr;
517         s4           targetdisp;
518         s4           disp;
519
520         /* get required compiler data */
521
522         cd = jd->cd;
523
524         /* generate code patching stub call code */
525
526         targetdisp = 0;
527
528 /*      for (pr = list_first_unsynced(cd->patchrefs); pr != NULL; */
529 /*               pr = list_next_unsynced(cd->patchrefs, pr)) { */
530         for (pr = cd->patchrefs; pr != NULL; pr = pr->next) {
531                 /* check code segment size */
532
533                 MCODECHECK(100);
534
535                 /* Get machine code which is patched back in later. The
536                    call is 2 instruction words long. */
537
538                 tmpmcodeptr = (u1 *) (cd->mcodebase + pr->branchpos);
539
540                 /* We use 2 loads here as an unaligned 8-byte read on 64-bit
541                    MIPS causes a SIGSEGV and using the same code for both
542                    architectures is much better. */
543
544                 mcode[0] = ((u4 *) tmpmcodeptr)[0];
545                 mcode[1] = ((u4 *) tmpmcodeptr)[1];
546
547                 mcode[2] = ((u4 *) tmpmcodeptr)[2];
548                 mcode[3] = ((u4 *) tmpmcodeptr)[3];
549                 mcode[4] = ((u4 *) tmpmcodeptr)[4];
550
551                 /* Patch in the call to call the following code (done at
552                    compile time). */
553
554                 savedmcodeptr = cd->mcodeptr;   /* save current mcodeptr              */
555                 cd->mcodeptr  = tmpmcodeptr;    /* set mcodeptr to patch position     */
556
557                 disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 1);
558
559 /*              if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) { */
560                         /* Recalculate the displacement to be relative to PV. */
561
562                         disp = savedmcodeptr - cd->mcodebase;
563
564                         M_LUI(REG_ITMP3, disp >> 16);
565                         M_OR_IMM(REG_ITMP3, disp, REG_ITMP3);
566                         M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
567                         M_JMP(REG_ITMP3);
568                         M_NOP;
569 /*              } */
570 /*              else { */
571 /*                      M_BR(disp); */
572 /*                      M_NOP; */
573 /*                      M_NOP; */
574 /*                      M_NOP; */
575 /*                      M_NOP; */
576 /*              } */
577
578                 cd->mcodeptr = savedmcodeptr;   /* restore the current mcodeptr   */
579
580                 /* create stack frame */
581
582                 M_ASUB_IMM(REG_SP, 8 * 8, REG_SP);
583
584                 /* calculate return address and move it onto the stack */
585
586                 M_LDA(REG_ITMP3, REG_PV, pr->branchpos);
587                 M_AST(REG_ITMP3, REG_SP, 7 * 8);
588
589                 /* move pointer to java_objectheader onto stack */
590
591 #if defined(ENABLE_THREADS)
592                 /* create a virtual java_objectheader */
593
594                 (void) dseg_add_unique_address(cd, NULL);                  /* flcword */
595                 (void) dseg_add_unique_address(cd, lock_get_initial_lock_word());
596                 disp = dseg_add_unique_address(cd, NULL);                  /* vftbl   */
597
598                 M_LDA(REG_ITMP3, REG_PV, disp);
599                 M_AST(REG_ITMP3, REG_SP, 6 * 8);
600 #else
601                 /* do nothing */
602 #endif
603
604                 /* move machine code onto stack */
605
606                 disp = dseg_add_s4(cd, mcode[0]);
607                 M_ILD(REG_ITMP3, REG_PV, disp);
608                 M_IST(REG_ITMP3, REG_SP, 3 * 8 + 0);
609
610                 disp = dseg_add_s4(cd, mcode[1]);
611                 M_ILD(REG_ITMP3, REG_PV, disp);
612                 M_IST(REG_ITMP3, REG_SP, 3 * 8 + 4);
613
614                 disp = dseg_add_s4(cd, mcode[2]);
615                 M_ILD(REG_ITMP3, REG_PV, disp);
616                 M_IST(REG_ITMP3, REG_SP, 4 * 8 + 0);
617
618                 disp = dseg_add_s4(cd, mcode[3]);
619                 M_ILD(REG_ITMP3, REG_PV, disp);
620                 M_IST(REG_ITMP3, REG_SP, 4 * 8 + 4);
621
622                 disp = dseg_add_s4(cd, mcode[4]);
623                 M_ILD(REG_ITMP3, REG_PV, disp);
624                 M_IST(REG_ITMP3, REG_SP, 5 * 8 + 0);
625
626                 /* move class/method/field reference onto stack */
627
628                 disp = dseg_add_address(cd, pr->ref);
629                 M_ALD(REG_ITMP3, REG_PV, disp);
630                 M_AST(REG_ITMP3, REG_SP, 2 * 8);
631
632                 /* move data segment displacement onto stack */
633
634                 disp = dseg_add_s4(cd, pr->disp);
635                 M_ILD(REG_ITMP3, REG_PV, disp);
636                 M_IST(REG_ITMP3, REG_SP, 1 * 8);
637
638                 /* move patcher function pointer onto stack */
639
640                 disp = dseg_add_address(cd, pr->patcher);
641                 M_ALD(REG_ITMP3, REG_PV, disp);
642                 M_AST(REG_ITMP3, REG_SP, 0 * 8);
643
644                 if (targetdisp == 0) {
645                         targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
646
647                         disp = dseg_add_functionptr(cd, asm_patcher_wrapper);
648                         M_ALD(REG_ITMP3, REG_PV, disp);
649                         M_JMP(REG_ITMP3);
650                         M_NOP;
651                 }
652                 else {
653                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
654                                 (((u4 *) cd->mcodeptr) + 1);
655
656                         M_BR(disp);
657                         M_NOP;
658                 }
659         }
660 }
661
662
663 /* emit_replacement_stubs ******************************************************
664
665    Generates the code for the replacement stubs.
666
667 *******************************************************************************/
668
669 #if defined(ENABLE_REPLACEMENT)
670 void emit_replacement_stubs(jitdata *jd)
671 {
672         codegendata *cd;
673         codeinfo    *code;
674         rplpoint    *rplp;
675         s4           disp;
676         s4           i;
677 #if !defined(NDEBUG)
678         u1          *savedmcodeptr;
679 #endif
680
681         /* get required compiler data */
682
683         cd   = jd->cd;
684         code = jd->code;
685
686         rplp = code->rplpoints;
687
688         /* store beginning of replacement stubs */
689
690         code->replacementstubs = (u1*) (cd->mcodeptr - cd->mcodebase);
691
692         for (i = 0; i < code->rplpointcount; ++i, ++rplp) {
693                 /* do not generate stubs for non-trappable points */
694
695                 if (rplp->flags & RPLPOINT_FLAG_NOTRAP)
696                         continue;
697
698                 /* check code segment size */
699
700                 MCODECHECK(100);
701
702 #if !defined(NDEBUG)
703                 savedmcodeptr = cd->mcodeptr;
704 #endif
705
706                 /* create stack frame - 16-byte aligned */
707
708                 M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
709
710                 /* push address of `rplpoint` struct */
711
712                 disp = dseg_add_address(cd, rplp);
713                 M_ALD(REG_ITMP3, REG_PV, disp);
714                 M_AST(REG_ITMP3, REG_SP, 0 * 8);
715
716                 /* jump to replacement function */
717
718                 disp = dseg_add_functionptr(cd, asm_replacement_out);
719                 M_ALD(REG_ITMP3, REG_PV, disp);
720                 M_JMP(REG_ITMP3);
721                 M_NOP; /* delay slot */
722
723                 assert((cd->mcodeptr - savedmcodeptr) == 4*REPLACEMENT_STUB_SIZE);
724         }
725 }
726 #endif /* defined(ENABLE_REPLACEMENT) */
727
728
729 /* emit_verbosecall_enter ******************************************************
730
731    Generates the code for the call trace.
732
733 *******************************************************************************/
734
735 #if !defined(NDEBUG)
736 void emit_verbosecall_enter(jitdata *jd)
737 {
738         methodinfo   *m;
739         codegendata  *cd;
740         registerdata *rd;
741         methoddesc   *md;
742         s4            disp;
743         s4            i, t;
744
745         /* get required compiler data */
746
747         m  = jd->m;
748         cd = jd->cd;
749         rd = jd->rd;
750
751         md = m->parseddesc;
752
753         /* mark trace code */
754
755         M_NOP;
756
757         M_LDA(REG_SP, REG_SP, -(2 + ARG_CNT + TMP_CNT) * 8);
758         M_AST(REG_RA, REG_SP, 1 * 8);
759
760         /* save argument registers */
761
762         for (i = 0; i < INT_ARG_CNT; i++)
763                 M_LST(rd->argintregs[i], REG_SP, (2 + i) * 8);
764
765         for (i = 0; i < FLT_ARG_CNT; i++)
766                 M_DST(rd->argfltregs[i], REG_SP, (2 + INT_ARG_CNT + i) * 8);
767
768         /* save temporary registers for leaf methods */
769
770         if (jd->isleafmethod) {
771                 for (i = 0; i < INT_TMP_CNT; i++)
772                         M_LST(rd->tmpintregs[i], REG_SP, (2 + ARG_CNT + i) * 8);
773
774                 for (i = 0; i < FLT_TMP_CNT; i++)
775                         M_DST(rd->tmpfltregs[i], REG_SP, (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
776         }
777
778         /* load float arguments into integer registers */
779
780         for (i = 0; i < md->paramcount && i < INT_ARG_CNT; i++) {
781                 t = md->paramtypes[i].type;
782
783                 if (IS_FLT_DBL_TYPE(t)) {
784                         if (IS_2_WORD_TYPE(t)) {
785                                 M_DST(rd->argfltregs[i], REG_SP, 0 * 8);
786                                 M_LLD(rd->argintregs[i], REG_SP, 0 * 8);
787                         }
788                         else {
789                                 M_FST(rd->argfltregs[i], REG_SP, 0 * 8);
790                                 M_ILD(rd->argintregs[i], REG_SP, 0 * 8);
791                         }
792                 }
793         }
794
795         disp = dseg_add_address(cd, m);
796         M_ALD(REG_ITMP1, REG_PV, disp);
797         M_AST(REG_ITMP1, REG_SP, 0 * 8);
798         disp = dseg_add_functionptr(cd, builtin_trace_args);
799         M_ALD(REG_ITMP3, REG_PV, disp);
800         M_JSR(REG_RA, REG_ITMP3);
801         M_NOP;
802
803         /* restore argument registers */
804
805         for (i = 0; i < INT_ARG_CNT; i++)
806                 M_LLD(rd->argintregs[i], REG_SP, (2 + i) * 8);
807
808         for (i = 0; i < FLT_ARG_CNT; i++)
809                 M_DLD(rd->argfltregs[i], REG_SP, (2 + INT_ARG_CNT + i) * 8);
810
811         /* restore temporary registers for leaf methods */
812
813         if (jd->isleafmethod) {
814                 for (i = 0; i < INT_TMP_CNT; i++)
815                         M_LLD(rd->tmpintregs[i], REG_SP, (2 + ARG_CNT + i) * 8);
816
817                 for (i = 0; i < FLT_TMP_CNT; i++)
818                         M_DLD(rd->tmpfltregs[i], REG_SP, (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
819         }
820
821         M_ALD(REG_RA, REG_SP, 1 * 8);
822         M_LDA(REG_SP, REG_SP, (2 + ARG_CNT + TMP_CNT) * 8);
823
824         /* mark trace code */
825
826         M_NOP;
827 }
828 #endif /* !defined(NDEBUG) */
829
830
831 /* emit_verbosecall_exit *******************************************************
832
833    Generates the code for the call trace.
834
835 *******************************************************************************/
836
837 #if !defined(NDEBUG)
838 void emit_verbosecall_exit(jitdata *jd)
839 {
840         methodinfo   *m;
841         codegendata  *cd;
842         registerdata *rd;
843         s4            disp;
844
845         /* get required compiler data */
846
847         m  = jd->m;
848         cd = jd->cd;
849         rd = jd->rd;
850
851         /* mark trace code */
852
853         M_NOP;
854
855         M_LDA(REG_SP, REG_SP, -4 * 8);              /* keep stack 16-byte aligned */
856         M_LST(REG_RA, REG_SP, 0 * 8);
857
858         M_LST(REG_RESULT, REG_SP, 1 * 8);
859         M_DST(REG_FRESULT, REG_SP, 2 * 8);
860
861         disp = dseg_add_address(cd, m);
862         M_ALD(rd->argintregs[0], REG_PV, disp);
863
864         M_MOV(REG_RESULT, rd->argintregs[1]);
865         M_DMOV(REG_FRESULT, rd->argfltregs[2]);
866         M_FMOV(REG_FRESULT, rd->argfltregs[3]);
867
868         disp = dseg_add_functionptr(cd, builtin_displaymethodstop);
869         M_ALD(REG_ITMP3, REG_PV, disp);
870         M_JSR(REG_RA, REG_ITMP3);
871         M_NOP;
872
873         M_DLD(REG_FRESULT, REG_SP, 2 * 8);
874         M_LLD(REG_RESULT, REG_SP, 1 * 8);
875
876         M_LLD(REG_RA, REG_SP, 0 * 8);
877         M_LDA(REG_SP, REG_SP, 4 * 8);
878
879         /* mark trace code */
880
881         M_NOP;
882 }
883 #endif /* !defined(NDEBUG) */
884
885
886 /*
887  * These are local overrides for various environment variables in Emacs.
888  * Please do not remove this and leave it at the end of the file, where
889  * Emacs will automagically detect them.
890  * ---------------------------------------------------------------------
891  * Local variables:
892  * mode: c
893  * indent-tabs-mode: t
894  * c-basic-offset: 4
895  * tab-width: 4
896  * End:
897  * vim:noexpandtab:sw=4:ts=4:
898  */