* src/vm/jit/codegen-common.cpp (codegen_emit): New generic version of the
[cacao.git] / src / vm / jit / alpha / emit.c
1 /* src/vm/jit/alpha/emit.c - Alpha code emitter functions
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27 #include "vm/types.h"
28
29 #include <assert.h>
30 #include <stdint.h>
31
32 #include "md-abi.h"
33
34 #include "vm/jit/alpha/codegen.h"
35
36 #include "mm/memory.hpp"
37
38 #include "threads/lock.hpp"
39
40 #include "vm/options.h"
41
42 #include "vm/jit/abi.h"
43 #include "vm/jit/abi-asm.h"
44 #include "vm/jit/asmpart.h"
45 #include "vm/jit/dseg.h"
46 #include "vm/jit/emit-common.hpp"
47 #include "vm/jit/jit.hpp"
48 #include "vm/jit/patcher-common.hpp"
49 #include "vm/jit/replace.hpp"
50 #include "vm/jit/trace.hpp"
51 #include "vm/jit/trap.hpp"
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 (IS_INMEMORY(src->flags)) {
71                 COUNT_SPILLS;
72
73                 disp = src->vv.regoff;
74
75                 switch (src->type) {
76                 case TYPE_INT:
77                 case TYPE_LNG:
78                 case TYPE_ADR:
79                         M_LLD(tempreg, REG_SP, disp);
80                         break;
81                 case TYPE_FLT:
82                 case TYPE_DBL:
83                         M_DLD(tempreg, REG_SP, disp);
84                         break;
85                 default:
86                         vm_abort("emit_load: unknown type %d", src->type);
87                 }
88
89                 reg = tempreg;
90         }
91         else
92                 reg = src->vv.regoff;
93
94         return reg;
95 }
96
97
98 /* emit_store ******************************************************************
99
100    Emit a possible store for the given variable.
101
102 *******************************************************************************/
103
104 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
105 {
106         codegendata  *cd;
107         s4            disp;
108
109         /* get required compiler data */
110
111         cd = jd->cd;
112
113         if (IS_INMEMORY(dst->flags)) {
114                 COUNT_SPILLS;
115
116                 disp = dst->vv.regoff;
117
118                 switch (dst->type) {
119                 case TYPE_INT:
120                 case TYPE_LNG:
121                 case TYPE_ADR:
122                         M_LST(d, REG_SP, disp);
123                         break;
124                 case TYPE_FLT:
125                 case TYPE_DBL:
126                         M_DST(d, REG_SP, disp);
127                         break;
128                 default:
129                         vm_abort("emit_store: unknown type %d", dst->type);
130                 }
131         }
132 }
133
134
135 /* emit_copy *******************************************************************
136
137    Generates a register/memory to register/memory copy.
138
139 *******************************************************************************/
140
141 void emit_copy(jitdata *jd, instruction *iptr)
142 {
143         codegendata *cd;
144         varinfo     *src;
145         varinfo     *dst;
146         s4           s1, d;
147
148         /* get required compiler data */
149
150         cd = jd->cd;
151
152         /* get source and destination variables */
153
154         src = VAROP(iptr->s1);
155         dst = VAROP(iptr->dst);
156
157         if ((src->vv.regoff != dst->vv.regoff) ||
158                 ((src->flags ^ dst->flags) & INMEMORY)) {
159
160                 if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
161                         /* emit nothing, as the value won't be used anyway */
162                         return;
163                 }
164
165                 /* If one of the variables resides in memory, we can eliminate
166                    the register move from/to the temporary register with the
167                    order of getting the destination register and the load. */
168
169                 if (IS_INMEMORY(src->flags)) {
170                         d  = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
171                         s1 = emit_load(jd, iptr, src, d);
172                 }
173                 else {
174                         s1 = emit_load(jd, iptr, src, REG_IFTMP);
175                         d  = codegen_reg_of_var(iptr->opc, dst, s1);
176                 }
177
178                 if (s1 != d) {
179                         switch (src->type) {
180                         case TYPE_INT:
181                         case TYPE_LNG:
182                         case TYPE_ADR:
183                                 M_MOV(s1, d);
184                                 break;
185                         case TYPE_FLT:
186                         case TYPE_DBL:
187                                 M_FMOV(s1, d);
188                                 break;
189                         default:
190                                 vm_abort("emit_copy: unknown type %d", src->type);
191                         }
192                 }
193
194                 emit_store(jd, iptr, dst, d);
195         }
196 }
197
198
199 /* emit_iconst *****************************************************************
200
201    XXX
202
203 *******************************************************************************/
204
205 void emit_iconst(codegendata *cd, s4 d, s4 value)
206 {
207         s4 disp;
208
209         if ((value >= -32768) && (value <= 32767))
210                 M_LDA_INTERN(d, REG_ZERO, value);
211         else {
212                 disp = dseg_add_s4(cd, value);
213                 M_ILD(d, REG_PV, disp);
214         }
215 }
216
217
218 /* emit_lconst *****************************************************************
219
220    XXX
221
222 *******************************************************************************/
223
224 void emit_lconst(codegendata *cd, s4 d, s8 value)
225 {
226         s4 disp;
227
228         if ((value >= -32768) && (value <= 32767))
229                 M_LDA_INTERN(d, REG_ZERO, value);
230         else {
231                 disp = dseg_add_s8(cd, value);
232                 M_LLD(d, REG_PV, disp);
233         }
234 }
235
236
237 /**
238  * Emits code comparing one integer register to an immediate value.
239  */
240 void emit_icmpeq_imm(codegendata* cd, int reg, int32_t value, int d)
241 {
242         int32_t disp;
243
244         if ((value >= 0) && (value <= 255)) {
245                 M_CMPEQ_IMM(reg, value, d);
246         } else {
247                 assert(reg != REG_ITMP2);
248                 if ((value >= -32768) && (value <= 32767)) {
249                         M_LDA(REG_ITMP2, REG_ZERO, value);
250                 } else {
251                         disp = dseg_add_s4(cd, value);
252                         M_ILD(REG_ITMP2, REG_PV, disp);
253                 }
254                 M_CMPEQ(reg, REG_ITMP2, d);
255         }
256 }
257
258
259 /* emit_branch *****************************************************************
260
261    Emits the code for conditional and unconditional branchs.
262
263 *******************************************************************************/
264
265 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
266 {
267         s4 checkdisp;
268         s4 branchdisp;
269
270         /* calculate the different displacements */
271
272         checkdisp  = (disp - 4);
273         branchdisp = (disp - 4) >> 2;
274
275         /* check which branch to generate */
276
277         if (condition == BRANCH_UNCONDITIONAL) {
278                 /* check displacement for overflow */
279
280                 if ((checkdisp < (s4) 0xffe00000) || (checkdisp > (s4) 0x001fffff)) {
281                         /* if the long-branches flag isn't set yet, do it */
282
283                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
284                                 log_println("setting error");
285                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
286                                                           CODEGENDATA_FLAG_LONGBRANCHES);
287                         }
288
289                         vm_abort("emit_branch: emit unconditional long-branch code");
290                 }
291                 else {
292                         M_BR(branchdisp);
293                 }
294         }
295         else {
296                 /* and displacement for overflow */
297
298                 if ((checkdisp < (s4) 0xffe00000) || (checkdisp > (s4) 0x001fffff)) {
299                         /* if the long-branches flag isn't set yet, do it */
300
301                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
302                                 log_println("setting error");
303                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
304                                                           CODEGENDATA_FLAG_LONGBRANCHES);
305                         }
306
307                         vm_abort("emit_branch: emit conditional long-branch code");
308                 }
309                 else {
310                         switch (condition) {
311                         case BRANCH_EQ:
312                                 M_BEQZ(reg, branchdisp);
313                                 break;
314                         case BRANCH_NE:
315                                 M_BNEZ(reg, branchdisp);
316                                 break;
317                         case BRANCH_LT:
318                                 M_BLTZ(reg, branchdisp);
319                                 break;
320                         case BRANCH_GE:
321                                 M_BGEZ(reg, branchdisp);
322                                 break;
323                         case BRANCH_GT:
324                                 M_BGTZ(reg, branchdisp);
325                                 break;
326                         case BRANCH_LE:
327                                 M_BLEZ(reg, branchdisp);
328                                 break;
329                         default:
330                                 vm_abort("emit_branch: unknown condition %d", condition);
331                         }
332                 }
333         }
334 }
335
336
337 /* emit_arithmetic_check *******************************************************
338
339    Emit an ArithmeticException check.
340
341 *******************************************************************************/
342
343 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
344 {
345         if (INSTRUCTION_MUST_CHECK(iptr)) {
346                 M_BNEZ(reg, 1);
347                 /* Destination register must not be REG_ZERO, because then no
348                    SIGSEGV is thrown. */
349                 M_ALD_INTERN(reg, REG_ZERO, TRAP_ArithmeticException);
350         }
351 }
352
353
354 /* emit_arrayindexoutofbounds_check ********************************************
355
356    Emit an ArrayIndexOutOfBoundsException check.
357
358 *******************************************************************************/
359
360 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
361 {
362         if (INSTRUCTION_MUST_CHECK(iptr)) {
363                 M_ILD(REG_ITMP3, s1, OFFSET(java_array_t, size));
364                 M_CMPULT(s2, REG_ITMP3, REG_ITMP3);
365                 M_BNEZ(REG_ITMP3, 1);
366                 M_ALD_INTERN(s2, REG_ZERO, TRAP_ArrayIndexOutOfBoundsException);
367         }
368 }
369
370
371 /* emit_arraystore_check *******************************************************
372
373    Emit an ArrayStoreException check.
374
375 *******************************************************************************/
376
377 void emit_arraystore_check(codegendata *cd, instruction *iptr)
378 {
379         if (INSTRUCTION_MUST_CHECK(iptr)) {
380                 M_BNEZ(REG_RESULT, 1);
381                 /* Destination register must not be REG_ZERO, because then no
382                    SIGSEGV is thrown. */
383                 M_ALD_INTERN(REG_RESULT, REG_ZERO, TRAP_ArrayStoreException);
384         }
385 }
386
387
388 /* emit_classcast_check ********************************************************
389
390    Emit a ClassCastException check.
391
392 *******************************************************************************/
393
394 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
395 {
396         if (INSTRUCTION_MUST_CHECK(iptr)) {
397                 switch (condition) {
398                 case BRANCH_EQ:
399                         M_BNEZ(reg, 1);
400                         break;
401                 case BRANCH_LE:
402                         M_BGTZ(reg, 1);
403                         break;
404                 default:
405                         vm_abort("emit_classcast_check: unknown condition %d", condition);
406                 }
407                 M_ALD_INTERN(s1, REG_ZERO, TRAP_ClassCastException);
408         }
409 }
410
411
412 /* emit_nullpointer_check ******************************************************
413
414    Emit a NullPointerException check.
415
416 *******************************************************************************/
417
418 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
419 {
420         if (INSTRUCTION_MUST_CHECK(iptr)) {
421                 M_BNEZ(reg, 1);
422                 /* Destination register must not be REG_ZERO, because then no
423                    SIGSEGV is thrown. */
424                 M_ALD_INTERN(reg, REG_ZERO, TRAP_NullPointerException);
425         }
426 }
427
428
429 /* emit_exception_check ********************************************************
430
431    Emit an Exception check.
432
433 *******************************************************************************/
434
435 void emit_exception_check(codegendata *cd, instruction *iptr)
436 {
437         if (INSTRUCTION_MUST_CHECK(iptr)) {
438                 M_BNEZ(REG_RESULT, 1);
439                 /* Destination register must not be REG_ZERO, because then no
440                    SIGSEGV is thrown. */
441                 M_ALD_INTERN(REG_RESULT, REG_ZERO, TRAP_CHECK_EXCEPTION);
442         }
443 }
444
445
446 /* emit_trap_compiler **********************************************************
447
448    Emit a trap instruction which calls the JIT compiler.
449
450 *******************************************************************************/
451
452 void emit_trap_compiler(codegendata *cd)
453 {
454         M_ALD_INTERN(REG_METHODPTR, REG_ZERO, TRAP_COMPILER);
455 }
456
457
458 /* emit_trap *******************************************************************
459
460    Emit a trap instruction and return the original machine code.
461
462 *******************************************************************************/
463
464 uint32_t emit_trap(codegendata *cd)
465 {
466         uint32_t mcode;
467
468         /* Get machine code which is patched back in later. The
469            trap is 1 instruction word long. */
470
471         mcode = *((uint32_t*) cd->mcodeptr);
472
473         // Generate a SIGILL.
474         M_UNDEFINED;
475
476         return mcode;
477 }
478
479
480 /**
481  * Emit code to recompute the procedure vector.
482  */
483 void emit_recompute_pv(codegendata *cd)
484 {
485         int32_t disp = (int32_t) (cd->mcodeptr - cd->mcodebase);
486
487         M_LDA(REG_PV, REG_RA, -disp);
488 }
489
490
491 /**
492  * Generates synchronization code to enter a monitor.
493  */
494 #if defined(ENABLE_THREADS)
495 void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset)
496 {
497         int32_t p;
498         int32_t disp;
499
500         // Get required compiler data.
501         methodinfo*  m  = jd->m;
502         codegendata* cd = jd->cd;
503
504 #if !defined(NDEBUG)
505         if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) {
506                 M_LDA(REG_SP, REG_SP, -(INT_ARG_CNT + FLT_ARG_CNT) * 8);
507
508                 for (p = 0; p < INT_ARG_CNT; p++)
509                         M_LST(abi_registers_integer_argument[p], REG_SP, p * 8);
510
511                 for (p = 0; p < FLT_ARG_CNT; p++)
512                         M_DST(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8);
513
514                 syncslot_offset += (INT_ARG_CNT + FLT_ARG_CNT) * 8;
515         }
516 #endif /* !defined(NDEBUG) */
517
518         /* decide which monitor enter function to call */
519
520         if (m->flags & ACC_STATIC) {
521                 disp = dseg_add_address(cd, &m->clazz->object.header);
522                 M_ALD(REG_A0, REG_PV, disp);
523         }
524         else {
525                 M_BNEZ(REG_A0, 1);
526                 M_ALD_INTERN(REG_ZERO, REG_ZERO, TRAP_NullPointerException);
527         }
528
529         M_AST(REG_A0, REG_SP, syncslot_offset);
530         disp = dseg_add_functionptr(cd, LOCK_monitor_enter);
531         M_ALD(REG_PV, REG_PV, disp);
532         M_JSR(REG_RA, REG_PV);
533         emit_recompute_pv(cd);
534
535 #if !defined(NDEBUG)
536         if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) {
537                 for (p = 0; p < INT_ARG_CNT; p++)
538                         M_LLD(abi_registers_integer_argument[p], REG_SP, p * 8);
539
540                 for (p = 0; p < FLT_ARG_CNT; p++)
541                         M_DLD(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8);
542
543                 M_LDA(REG_SP, REG_SP, (INT_ARG_CNT + FLT_ARG_CNT) * 8);
544         }
545 #endif
546 }
547 #endif
548
549
550 /**
551  * Generates synchronization code to leave a monitor.
552  */
553 #if defined(ENABLE_THREADS)
554 void emit_monitor_exit(jitdata* jd, int32_t syncslot_offset)
555 {
556         int32_t disp;
557
558         // Get required compiler data.
559         methodinfo*  m  = jd->m;
560         codegendata* cd = jd->cd;
561
562         M_ALD(REG_A0, REG_SP, syncslot_offset);
563
564         methoddesc* md = m->parseddesc;
565
566         switch (md->returntype.type) {
567         case TYPE_INT:
568         case TYPE_LNG:
569         case TYPE_ADR:
570                 M_LST(REG_RESULT, REG_SP, syncslot_offset);
571                 break;
572         case TYPE_FLT:
573         case TYPE_DBL:
574                 M_DST(REG_FRESULT, REG_SP, syncslot_offset);
575                 break;
576         }
577
578         disp = dseg_add_functionptr(cd, LOCK_monitor_exit);
579         M_ALD(REG_PV, REG_PV, disp);
580         M_JSR(REG_RA, REG_PV);
581         emit_recompute_pv(cd);
582
583         switch (md->returntype.type) {
584         case TYPE_INT:
585         case TYPE_LNG:
586         case TYPE_ADR:
587                 M_LLD(REG_RESULT, REG_SP, syncslot_offset);
588                 break;
589         case TYPE_FLT:
590         case TYPE_DBL:
591                 M_DLD(REG_FRESULT, REG_SP, syncslot_offset);
592                 break;
593         }
594 }
595 #endif
596
597
598 /* emit_verbosecall_enter ******************************************************
599
600    Generates the code for the call trace.
601
602 *******************************************************************************/
603
604 #if !defined(NDEBUG)
605 void emit_verbosecall_enter(jitdata *jd)
606 {
607         methodinfo   *m;
608         codeinfo     *code;
609         codegendata  *cd;
610         registerdata *rd;
611         methoddesc   *md;
612         int32_t       stackframesize;
613         s4            disp;
614         s4            i, j, s;
615
616         /* get required compiler data */
617
618         m    = jd->m;
619         code = jd->code;
620         cd   = jd->cd;
621         rd   = jd->rd;
622
623         md = m->parseddesc;
624
625         /* mark trace code */
626
627         M_NOP;
628
629         stackframesize = ARG_CNT + TMP_CNT + md->paramcount + 1;
630
631         M_LDA(REG_SP, REG_SP, -(stackframesize * 8));
632         M_AST(REG_RA, REG_SP, 0 * 8);
633
634         /* save all argument and temporary registers for leaf methods */
635
636         if (code_is_leafmethod(code)) {
637                 j = 1 + md->paramcount;
638
639                 for (i = 0; i < INT_ARG_CNT; i++, j++)
640                         M_LST(abi_registers_integer_argument[i], REG_SP, j * 8);
641
642                 for (i = 0; i < FLT_ARG_CNT; i++, j++)
643                         M_DST(abi_registers_float_argument[i], REG_SP, j * 8);
644
645                 for (i = 0; i < INT_TMP_CNT; i++, j++)
646                         M_LST(rd->tmpintregs[i], REG_SP, j * 8);
647
648                 for (i = 0; i < FLT_TMP_CNT; i++, j++)
649                         M_DST(rd->tmpfltregs[i], REG_SP, j * 8);
650         }
651
652         /* save argument registers */
653
654         for (i = 0; i < md->paramcount; i++) {
655                 if (!md->params[i].inmemory) {
656                         s = md->params[i].regoff;
657
658                         switch (md->paramtypes[i].type) {
659                         case TYPE_ADR:
660                         case TYPE_INT:
661                         case TYPE_LNG:
662                                 M_LST(s, REG_SP, (1 + i) * 8);
663                                 break;
664                         case TYPE_FLT:
665                         case TYPE_DBL:
666                                 M_DST(s, REG_SP, (1 + i) * 8);
667                                 break;
668                         }
669                 }
670         }
671
672         disp = dseg_add_address(cd, m);
673         M_ALD(REG_A0, REG_PV, disp);
674         M_AADD_IMM(REG_SP, 1 * 8, REG_A1);
675         M_LDA(REG_A2, REG_SP, stackframesize * 8 + cd->stackframesize * 8);
676
677         disp = dseg_add_functionptr(cd, trace_java_call_enter);
678         M_ALD(REG_PV, REG_PV, disp);
679         M_JSR(REG_RA, REG_PV);
680         disp = (s4) (cd->mcodeptr - cd->mcodebase);
681         M_LDA(REG_PV, REG_RA, -disp);
682         M_ALD(REG_RA, REG_SP, 0 * 8);
683
684         /* restore argument registers */
685
686         for (i = 0; i < md->paramcount; i++) {
687                 if (!md->params[i].inmemory) {
688                         s = md->params[i].regoff;
689
690                         switch (md->paramtypes[i].type) {
691                         case TYPE_ADR:
692                         case TYPE_INT:
693                         case TYPE_LNG:
694                                 M_LLD(s, REG_SP, (1 + i) * 8);
695                                 break;
696                         case TYPE_FLT:
697                         case TYPE_DBL:
698                                 M_DLD(s, REG_SP, (1 + i) * 8);
699                                 break;
700                         }
701                 }
702         }
703
704         /* restore all argument and temporary registers for leaf methods */
705
706         if (code_is_leafmethod(code)) {
707                 j = 1 + md->paramcount;
708
709                 for (i = 0; i < INT_ARG_CNT; i++, j++)
710                         M_LLD(abi_registers_integer_argument[i], REG_SP, j * 8);
711
712                 for (i = 0; i < FLT_ARG_CNT; i++, j++)
713                         M_DLD(abi_registers_float_argument[i], REG_SP, j * 8);
714
715                 for (i = 0; i < INT_TMP_CNT; i++, j++)
716                         M_LLD(rd->tmpintregs[i], REG_SP, j * 8);
717
718                 for (i = 0; i < FLT_TMP_CNT; i++, j++)
719                         M_DLD(rd->tmpfltregs[i], REG_SP, j * 8);
720         }
721
722         M_LDA(REG_SP, REG_SP, stackframesize * 8);
723
724         /* mark trace code */
725
726         M_NOP;
727 }
728 #endif /* !defined(NDEBUG) */
729
730
731 /* emit_verbosecall_exit *******************************************************
732
733    Generates the code for the call trace.
734
735 *******************************************************************************/
736
737 #if !defined(NDEBUG)
738 void emit_verbosecall_exit(jitdata *jd)
739 {
740         methodinfo   *m;
741         codegendata  *cd;
742         registerdata *rd;
743         methoddesc   *md;
744         s4            disp;
745
746         /* get required compiler data */
747
748         m  = jd->m;
749         cd = jd->cd;
750         rd = jd->rd;
751
752         md = m->parseddesc;
753
754         /* mark trace code */
755
756         M_NOP;
757
758         M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
759         M_AST(REG_RA, REG_SP, 0 * 8);
760
761         /* save return value */
762
763         switch (md->returntype.type) {
764         case TYPE_ADR:
765         case TYPE_INT:
766         case TYPE_LNG:
767                 M_LST(REG_RESULT, REG_SP, 1 * 8);
768                 break;
769         case TYPE_FLT:
770         case TYPE_DBL:
771                 M_DST(REG_FRESULT, REG_SP, 1 * 8);
772                 break;
773         }
774
775         disp = dseg_add_address(cd, m);
776         M_ALD(REG_A0, REG_PV, disp);
777         M_AADD_IMM(REG_SP, 1 * 8, REG_A1);
778
779         disp = dseg_add_functionptr(cd, trace_java_call_exit);
780         M_ALD(REG_PV, REG_PV, disp);
781         M_JSR(REG_RA, REG_PV);
782         disp = (cd->mcodeptr - cd->mcodebase);
783         M_LDA(REG_PV, REG_RA, -disp);
784
785         /* restore return value */
786
787         switch (md->returntype.type) {
788         case TYPE_ADR:
789         case TYPE_INT:
790         case TYPE_LNG:
791                 M_LLD(REG_RESULT, REG_SP, 1 * 8);
792                 break;
793         case TYPE_FLT:
794         case TYPE_DBL:
795                 M_DLD(REG_FRESULT, REG_SP, 1 * 8);
796                 break;
797         }
798
799         M_ALD(REG_RA, REG_SP, 0 * 8);
800         M_AADD_IMM(REG_SP, 2 * 8, REG_SP);
801
802         /* mark trace code */
803
804         M_NOP;
805 }
806 #endif /* !defined(NDEBUG) */
807
808
809 /*
810  * These are local overrides for various environment variables in Emacs.
811  * Please do not remove this and leave it at the end of the file, where
812  * Emacs will automagically detect them.
813  * ---------------------------------------------------------------------
814  * Local variables:
815  * mode: c
816  * indent-tabs-mode: t
817  * c-basic-offset: 4
818  * tab-width: 4
819  * End:
820  * vim:noexpandtab:sw=4:ts=4:
821  */