Merged revisions 7797-7917 via svnmerge from
[cacao.git] / src / vm / jit / powerpc64 / emit.c
1 /* src/vm/jit/powerpc64/emit.c - PowerPC64 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: emitfuncs.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 "mm/memory.h"
37
38 #include "md-abi.h"
39 #include "vm/jit/powerpc64/codegen.h"
40
41 #include "threads/lock-common.h"
42
43 #include "vm/builtin.h"
44 #include "vm/exceptions.h"
45 #include "vm/vm.h"
46
47 #include "vm/jit/abi.h"
48 #include "vm/jit/asmpart.h"
49 #include "vm/jit/emit-common.h"
50 #include "vm/jit/jit.h"
51
52 #include "vmcore/options.h"
53
54
55 /* emit_load *******************************************************************
56
57    Emits a possible load of an operand.
58
59 *******************************************************************************/
60
61 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
62 {
63         codegendata  *cd;
64         s4            disp;
65         s4            reg;
66
67         /* get required compiler data */
68
69         cd = jd->cd;
70
71         if (src->flags & INMEMORY) {
72                 COUNT_SPILLS;
73
74                 disp = src->vv.regoff * 8;
75
76                 if (IS_FLT_DBL_TYPE(src->type)) {
77                         M_DLD(tempreg, REG_SP, disp);
78                 }
79                 else {
80                         M_LLD(tempreg, REG_SP, disp);
81                 }
82
83                 reg = tempreg;
84         }
85         else
86                 reg = src->vv.regoff;
87
88         return reg;
89 }
90
91
92 /* emit_store ******************************************************************
93
94    Emits a possible store to a variable.
95
96 *******************************************************************************/
97
98 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
99 {
100         codegendata  *cd;
101
102         /* get required compiler data */
103
104         cd = jd->cd;
105
106         if (dst->flags & INMEMORY) {
107                 COUNT_SPILLS;
108
109                 if (IS_FLT_DBL_TYPE(dst->type)) {
110                         M_DST(d, REG_SP, dst->vv.regoff * 8);
111                 }
112                 else {
113                         M_LST(d, REG_SP, dst->vv.regoff * 8);
114                 }
115         }
116 }
117
118
119 /* emit_copy *******************************************************************
120
121    Generates a register/memory to register/memory copy.
122
123 *******************************************************************************/
124
125 void emit_copy(jitdata *jd, instruction *iptr)
126 {
127         codegendata *cd;
128         varinfo     *src;
129         varinfo     *dst;
130         s4           s1, d;
131
132         /* get required compiler data */
133
134         cd = jd->cd;
135
136         /* get source and destination variables */
137
138         src = VAROP(iptr->s1);
139         dst = VAROP(iptr->dst);
140
141         if ((src->vv.regoff != dst->vv.regoff) ||
142                 ((src->flags ^ dst->flags) & INMEMORY)) {
143
144                 if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
145                         /* emit nothing, as the value won't be used anyway */
146                         return;
147                 }
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                                 M_FMOV(s1, d);
165                         else
166                                 M_MOV(s1, d);
167                 }
168
169                 emit_store(jd, iptr, dst, d);
170         }
171 }
172
173
174 /* emit_iconst *****************************************************************
175
176    XXX
177
178 *******************************************************************************/
179
180 void emit_iconst(codegendata *cd, s4 d, s4 value)
181 {
182         s4 disp;
183
184         if ((value >= -32768) && (value <= 32767)) {
185                 M_LDA_INTERN(d, REG_ZERO, value);
186         } else {
187                 disp = dseg_add_s4(cd, value);
188                 M_ILD(d, REG_PV, disp);
189         }
190 }
191
192 void emit_lconst(codegendata *cd, s4 d, s8 value)
193 {
194         s4 disp;
195         if ((value >= -32768) && (value <= 32767)) {
196                 M_LDA_INTERN(d, REG_ZERO, value);
197         } else {
198                 disp = dseg_add_s8(cd, value);
199                 M_LLD(d, REG_PV, disp);
200         }
201 }
202
203
204 /* emit_verbosecall_enter ******************************************************
205
206    Generates the code for the call trace.
207
208 *******************************************************************************/
209
210 void emit_verbosecall_enter (jitdata *jd)
211 {
212         methodinfo   *m;
213         codegendata  *cd;
214         registerdata *rd;
215         s4 s1, p, t;
216         int stack_size;
217         methoddesc *md;
218
219         /* get required compiler data */
220
221         m  = jd->m;
222         cd = jd->cd;
223         rd = jd->rd;
224
225         md = m->parseddesc;
226         
227         /* Build up Stackframe for builtin_trace_args call (a multiple of 16) */
228         /* For Darwin:                                                        */
229         /* TODO                                                               */
230         /* For Linux:                                                         */
231         /* setup stack for TRACE_ARGS_NUM registers                           */
232         /* == LA_SIZE + PA_SIZE + 8 (methodinfo argument) + TRACE_ARGS_NUM*8 + 8 (itmp1)              */
233         
234         /* in nativestubs no Place to save the LR (Link Register) would be needed */
235         /* but since the stack frame has to be aligned the 4 Bytes would have to  */
236         /* be padded again */
237
238 #if defined(__DARWIN__)
239         stack_size = LA_SIZE + (TRACE_ARGS_NUM + 1) * 8;
240 #else
241         stack_size = LA_SIZE + PA_SIZE + 8 + TRACE_ARGS_NUM * 8 + 8;
242 #endif
243
244         /* mark trace code */
245         M_NOP;
246
247         M_MFLR(REG_ZERO);
248         M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
249         M_STDU(REG_SP, REG_SP, -stack_size);
250
251         for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++) {
252                 t = md->paramtypes[p].type;
253                 if (IS_INT_LNG_TYPE(t)) {
254                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
255                                 M_LST(md->params[p].regoff, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
256                         } else { /* Param on Stack */
257                                 s1 = (md->params[p].regoff + cd->stackframesize) * 8 + stack_size;
258                                 M_LLD(REG_ITMP2, REG_SP, s1);
259                                 M_LST(REG_ITMP2, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
260                         }
261                 } else { /* IS_FLT_DBL_TYPE(t) */
262                         if (!md->params[p].inmemory) { /* in Arg Reg */
263                                 s1 = md->params[p].regoff;
264                                 M_DST(s1, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
265                         } else { /* on Stack */
266                                 /* this should not happen */
267                                 assert(0);
268                         }
269                 }
270         }
271
272 #if defined(__DARWIN__)
273         #warning "emit_verbosecall_enter not implemented"
274 #else
275         /* LINUX */
276         /* Set integer and float argument registers for trace_args call */
277         /* offset to saved integer argument registers                   */
278         for (p = 0; (p < TRACE_ARGS_NUM) && (p < md->paramcount); p++) {
279                 t = md->paramtypes[p].type;
280                 if (IS_INT_LNG_TYPE(t)) {
281                         M_LLD(abi_registers_integer_argument[p], REG_SP,LA_SIZE + PA_SIZE + 8 + p * 8);
282                 } else { /* Float/Dbl */
283                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
284                                 /* use reserved Place on Stack (sp + 5 * 16) to copy  */
285                                 /* float/double arg reg to int reg                    */
286                                 s1 = md->params[p].regoff;
287                                 M_MOV(s1, abi_registers_integer_argument[p]);
288                         } else  {
289                                 assert(0);
290                         }
291                 }
292         }
293 #endif
294
295         /* put methodinfo pointer on Stackframe */
296         p = dseg_add_address(cd, m);
297         M_ALD(REG_ITMP1, REG_PV, p);
298 #if defined(__DARWIN__)
299         M_AST(REG_ITMP1, REG_SP, LA_SIZE + TRACE_ARGS_NUM * 8); 
300 #else
301         if (TRACE_ARGS_NUM == 8)        {
302                 /* need to pass via stack */
303                 M_AST(REG_ITMP1, REG_SP, LA_SIZE + PA_SIZE);
304         } else {
305                 /* pass via register, reg 3 is the first  */
306                 M_MOV(REG_ITMP1, 3 + TRACE_ARGS_NUM);
307         }
308 #endif
309         /* call via function descriptor */
310         /* XXX: what about TOC? */
311         p = dseg_add_functionptr(cd, builtin_verbosecall_enter);
312         M_ALD(REG_ITMP2, REG_PV, p);
313         M_ALD(REG_ITMP1, REG_ITMP2, 0);
314         M_MTCTR(REG_ITMP1);
315         M_JSR;
316
317 #if defined(__DARWIN__)
318         #warning "emit_verbosecall_enter not implemented"
319 #else
320         /* LINUX */
321         for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++) {
322                 t = md->paramtypes[p].type;
323                 if (IS_INT_LNG_TYPE(t)) {
324                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
325                                 /* restore integer argument registers */
326                                 M_LLD(abi_registers_integer_argument[p], REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
327                         } else {
328                                 assert(0);      /* TODO: implement this */
329                         }
330                 } else { /* FLT/DBL */
331                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
332                                 M_DLD(md->params[p].regoff, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
333                         } else {
334                                 assert(0); /* this shoudl never happen */
335                         }
336                         
337                 }
338         }
339 #endif
340         M_ALD(REG_ZERO, REG_SP, stack_size + LA_LR_OFFSET);
341         M_MTLR(REG_ZERO);
342         M_LDA(REG_SP, REG_SP, stack_size);
343
344         /* mark trace code */
345         M_NOP;
346 }
347
348
349 /* emit_verbosecall_exit ******************************************************
350
351    Generates the code for the call trace.
352
353    void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
354
355 *******************************************************************************/
356
357 void emit_verbosecall_exit(jitdata *jd)
358 {
359         methodinfo   *m;
360         codegendata  *cd;
361         s4            disp;
362
363         /* get required compiler data */
364
365         m  = jd->m;
366         cd = jd->cd;
367
368         /* mark trace code */
369
370         M_NOP;
371
372         M_MFLR(REG_ZERO);
373         M_LDA(REG_SP, REG_SP, -(LA_SIZE+PA_SIZE+10*8));
374         M_DST(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
375         M_LST(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+1*8);
376         M_AST(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+2*8);
377
378         M_MOV(REG_RESULT, REG_A0);
379
380         M_FLTMOVE(REG_FRESULT, REG_FA0);
381         M_FLTMOVE(REG_FRESULT, REG_FA1);
382
383         disp = dseg_add_address(cd, m);
384         M_ALD(REG_A3, REG_PV, disp);
385
386         disp = dseg_add_functionptr(cd, builtin_verbosecall_exit);
387         /* call via function descriptor, XXX: what about TOC ? */
388         M_ALD(REG_ITMP2, REG_PV, disp);
389         M_ALD(REG_ITMP2, REG_ITMP2, 0);
390         M_MTCTR(REG_ITMP2);
391         M_JSR;
392
393         M_DLD(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
394         M_LLD(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+1*8);
395         M_ALD(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+2*8);
396         M_LDA(REG_SP, REG_SP, LA_SIZE+PA_SIZE+10*8);
397         M_MTLR(REG_ZERO);
398
399         /* mark trace code */
400
401         M_NOP;
402 }
403
404 /* emit_branch *****************************************************************
405
406    Emits the code for conditional and unconditional branchs.
407
408 *******************************************************************************/
409
410 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
411 {
412         s4 checkdisp;
413         s4 branchdisp;
414
415         /* calculate the different displacements */
416
417         checkdisp  =  disp + 4;
418         branchdisp = (disp - 4) >> 2;
419
420         /* check which branch to generate */
421
422         if (condition == BRANCH_UNCONDITIONAL) {
423                 /* check displacement for overflow */
424
425                 if ((checkdisp < (s4) 0xfe000000) || (checkdisp > (s4) 0x01fffffc)) {
426                         /* if the long-branches flag isn't set yet, do it */
427
428                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
429                                 log_println("setting error");
430                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
431                                                           CODEGENDATA_FLAG_LONGBRANCHES);
432                         }
433
434                         vm_abort("emit_branch: emit unconditional long-branch code");
435                 }
436                 else {
437                         M_BR(branchdisp);
438                 }
439         }
440         else {
441                 /* and displacement for overflow */
442
443                 if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
444                         /* if the long-branches flag isn't set yet, do it */
445
446                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
447                                 log_println("setting error");
448                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
449                                                           CODEGENDATA_FLAG_LONGBRANCHES);
450                         }
451                         log_println("generating long-branch");
452
453                         branchdisp --;          /* we jump from the second instruction */
454                         switch (condition) {
455                         case BRANCH_EQ:
456                                 M_BNE(1);
457                                 M_BR(branchdisp);
458                                 break;
459                         case BRANCH_NE:
460                                 M_BEQ(1);
461                                 M_BR(branchdisp);
462                                 break;
463                         case BRANCH_LT:
464                                 M_BGE(1);
465                                 M_BR(branchdisp);
466                                 break;
467                         case BRANCH_GE:
468                                 M_BLT(1);
469                                 M_BR(branchdisp);
470                                 break;
471                         case BRANCH_GT:
472                                 M_BLE(1);
473                                 M_BR(branchdisp);
474                                 break;
475                         case BRANCH_LE:
476                                 M_BGT(1);
477                                 M_BR(branchdisp);
478                                 break;
479                         case BRANCH_NAN:
480                                 vm_abort("emit_branch: long BRANCH_NAN");
481                                 break;
482                         default:
483                                 vm_abort("emit_branch: unknown condition %d", condition);
484                         }
485
486                 }
487                 else {
488                         switch (condition) {
489                         case BRANCH_EQ:
490                                 M_BEQ(branchdisp);
491                                 break;
492                         case BRANCH_NE:
493                                 M_BNE(branchdisp);
494                                 break;
495                         case BRANCH_LT:
496                                 M_BLT(branchdisp);
497                                 break;
498                         case BRANCH_GE:
499                                 M_BGE(branchdisp);
500                                 break;
501                         case BRANCH_GT:
502                                 M_BGT(branchdisp);
503                                 break;
504                         case BRANCH_LE:
505                                 M_BLE(branchdisp);
506                                 break;
507                         case BRANCH_NAN:
508                                 M_BNAN(branchdisp);
509                                 break;
510                         default:
511                                 vm_abort("emit_branch: unknown condition %d", condition);
512                         }
513                 }
514         }
515 }
516
517 /* emit_arrayindexoutofbounds_check ********************************************
518
519    Emit a ArrayIndexOutOfBoundsException check.
520
521 *******************************************************************************/
522
523 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
524 {
525         if (checkbounds) {
526 #define SOFTEX 0
527 #if SOFTEX
528                 M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
529                 M_CMPU(s2, REG_ITMP3);
530                 codegen_add_arrayindexoutofboundsexception_ref(cd, s2);
531                 BRANCH_NOPS;
532 #else
533                 M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
534                 M_CMPU(s2, REG_ITMP3);
535                 M_BLT(1);
536                 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
537                 M_LWZ(s2, REG_ZERO, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
538 #endif
539         }
540 }
541
542
543 /* emit_arithmetic_check *******************************************************
544
545    Emit an ArithmeticException check.
546
547 *******************************************************************************/
548
549 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
550 {
551         if (INSTRUCTION_MUST_CHECK(iptr))       {
552         #if SOFTEX
553                 M_TST(reg);
554                 codegen_add_arithmeticexception_ref(cd);
555                 BRANCH_NOPS;
556         #else
557                 M_TST(reg);
558                 M_BNE(1);
559                 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
560                 M_LWZ(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_ARITHMETIC);
561         #endif
562         }
563 }
564
565 #if 0
566 /* emit_arraystore_check *******************************************************
567
568    Emit an ArrayStoreException check.
569
570 *******************************************************************************/
571
572 void emit_arraystore_check(codegendata *cd, instruction *iptr, s4 reg)
573 {
574         if (INSTRUCTION_MUST_CHECK(iptr))       {
575                 M_TST(REG_RESULT);
576                 codegen_add_arraystoreexception_ref(cd);
577                 BRANCH_NOPS;
578         }
579 }
580 #endif
581
582 /* emit_classcast_check ********************************************************
583
584    Emit a ClassCastException check.
585
586 *******************************************************************************/
587
588 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
589 {
590         if (INSTRUCTION_MUST_CHECK(iptr))       {
591         #if SOFTEX
592                 codegen_add_classcastexception_ref(cd, condition, s1);
593                 BRANCH_NOPS;
594                 M_NOP;
595         #else
596                 switch(condition)       {
597                         case BRANCH_LE:
598                                 M_BGT(1);
599                                 break;
600                         case BRANCH_EQ:
601                                 M_BNE(1);
602                                 break;
603                         case BRANCH_GT:
604                                 M_BLE(1);
605                                 break;
606                         default:
607                                 vm_abort("emit_classcast_check: unknown condition %d", condition);
608                 }
609                 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
610                 M_LWZ(s1, REG_ZERO, EXCEPTION_HARDWARE_CLASSCAST);
611         #endif
612         }
613 }
614
615
616 /* emit_nullpointer_check ******************************************************
617
618    Emit a NullPointerException check.
619
620 *******************************************************************************/
621
622 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
623 {
624         if (INSTRUCTION_MUST_CHECK(iptr))       {
625                 M_TST(reg);
626                 M_BNE(1);
627                 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
628                 M_LWZ(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_NULLPOINTER);
629         }
630 }
631
632 /* emit_exception_check ********************************************************
633
634    Emit an Exception check.
635
636 *******************************************************************************/
637
638 void emit_exception_check(codegendata *cd, instruction *iptr)
639 {
640         if (INSTRUCTION_MUST_CHECK(iptr))       {
641         #if SOFTEX
642                 M_CMPI(REG_RESULT, 0);
643                 codegen_add_fillinstacktrace_ref(cd);
644                 BRANCH_NOPS;
645         #else
646                 M_TST(REG_RESULT);
647                 M_BNE(1);
648                 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
649                 M_LWZ(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_EXCEPTION);
650         #endif
651         }
652 }
653
654
655 /* emit_patcher_stubs **********************************************************
656
657    Generates the code for the patcher stubs.
658
659 *******************************************************************************/
660 void emit_patcher_stubs(jitdata *jd)
661 {
662         codegendata *cd;
663         patchref    *pref;
664         u4           mcode;
665         u1          *savedmcodeptr;
666         u1          *tmpmcodeptr;
667         s4           targetdisp;
668         s4           disp;
669
670         cd = jd->cd;
671
672         /* generate code patching stub call code */
673
674         targetdisp = 0;
675
676         for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
677                 /* check code segment size */
678
679                 MCODECHECK(16);
680
681                 /* Get machine code which is patched back in later. The
682                    call is 1 instruction word long. */
683
684                 tmpmcodeptr = (u1 *) (cd->mcodebase + pref->branchpos);
685
686                 mcode = *((u4 *) tmpmcodeptr);
687
688                 /* Patch in the call to call the following code (done at
689                    compile time). */
690
691                 savedmcodeptr = cd->mcodeptr;   /* save current mcodeptr          */
692                 cd->mcodeptr  = tmpmcodeptr;    /* set mcodeptr to patch position */
693
694                 disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 1);
695                 M_BR(disp);
696
697                 cd->mcodeptr = savedmcodeptr;   /* restore the current mcodeptr   */
698
699                 /* create stack frame - keep stack 16-byte aligned */
700                 M_AADD_IMM(REG_SP, -8 * 8, REG_SP);
701
702                 /* calculate return address and move it onto the stack */
703                 M_LDA(REG_ITMP3, REG_PV, pref->branchpos);
704                 M_AST_INTERN(REG_ITMP3, REG_SP, 5 * 8);
705
706                 /* move pointer to java_objectheader onto stack */
707
708 #if defined(ENABLE_THREADS)
709                 /* order reversed because of data segment layout */
710
711                 (void) dseg_add_unique_address(cd, NULL);                         /* flcword    */
712                 (void) dseg_add_unique_address(cd, lock_get_initial_lock_word()); /* monitorPtr */
713                 disp = dseg_add_unique_address(cd, NULL);                         /* vftbl      */
714
715                 M_LDA(REG_ITMP3, REG_PV, disp);
716                 M_AST_INTERN(REG_ITMP3, REG_SP, 4 * 8);
717 #else
718                 /* do nothing */
719 #endif
720
721                 /* move machine code onto stack */
722                 disp = dseg_add_s4(cd, mcode);
723                 M_ILD(REG_ITMP3, REG_PV, disp);
724                 M_IST_INTERN(REG_ITMP3, REG_SP, 3 * 8);
725
726                 /* move class/method/field reference onto stack */
727                 disp = dseg_add_address(cd, pref->ref);
728                 M_ALD(REG_ITMP3, REG_PV, disp);
729                 M_AST_INTERN(REG_ITMP3, REG_SP, 2 * 8);
730
731                 /* move data segment displacement onto stack */
732                 disp = dseg_add_s4(cd, pref->disp);
733                 M_ILD(REG_ITMP3, REG_PV, disp);
734                 M_IST_INTERN(REG_ITMP3, REG_SP, 1 * 8);
735
736                 /* move patcher function pointer onto stack */
737                 disp = dseg_add_functionptr(cd, pref->patcher);
738                 M_ALD(REG_ITMP3, REG_PV, disp);
739                 M_AST_INTERN(REG_ITMP3, REG_SP, 0 * 8);
740
741                 if (targetdisp == 0) {
742                         targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
743
744                         disp = dseg_add_functionptr(cd, asm_patcher_wrapper);
745                         M_ALD(REG_ITMP3, REG_PV, disp);
746                         M_MTCTR(REG_ITMP3);
747                         M_RTS;
748                 }
749                 else {
750                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
751                                 (((u4 *) cd->mcodeptr) + 1);
752                         M_BR(disp);
753                 }
754         }
755 }
756
757
758 /* emit_replacement_stubs ******************************************************
759
760    Generates the code for the replacement stubs.
761
762 *******************************************************************************/
763
764 #if defined(ENABLE_REPLACEMENT)
765 void emit_replacement_stubs(jitdata *jd)
766 {
767         codegendata *cd;
768         codeinfo    *code;
769         rplpoint    *replacementpoint;
770         s4           disp;
771         s4           i;
772 #if !defined(NDEBUG)
773         u1          *savedmcodeptr;
774 #endif
775
776         /* get required compiler data */
777
778         cd   = jd->cd;
779         code = jd->code;
780
781         replacementpoint = jd->code->rplpoints;
782
783         for (i = 0; i < code->rplpointcount; ++i, ++replacementpoint) {
784                 /* do not generate stubs for non-trappable points */
785
786                 if (replacementpoint->flags & RPLPOINT_FLAG_NOTRAP)
787                         continue;
788
789
790                 /* check code segment size */
791
792                 MCODECHECK(100);
793
794 #if !defined(NDEBUG)
795                 savedmcodeptr = cd->mcodeptr;
796 #endif
797                 /* create stack frame - keep 16-byte aligned */
798
799                 M_AADD_IMM(REG_SP, -4 * 8, REG_SP);
800
801                 /* push address of `rplpoint` struct */
802
803                 disp = dseg_add_address(cd, replacementpoint);
804                 M_ALD(REG_ITMP3, REG_PV, disp);
805                 M_AST_INTERN(REG_ITMP3, REG_SP, 0 * 8);
806
807                 /* jump to replacement function */
808
809                 disp = dseg_add_functionptr(cd, asm_replacement_out);
810                 M_ALD(REG_ITMP3, REG_PV, disp);
811                 M_MTCTR(REG_ITMP3);
812                 M_RTS;
813
814                 assert((cd->mcodeptr - savedmcodeptr) == 4*REPLACEMENT_STUB_SIZE);
815
816 #if 0
817                 /* note start of stub code */
818
819                 replacementpoint->outcode = (u1 *) (cd->mcodeptr - cd->mcodebase);
820
821                 /* make machine code for patching */
822
823                 savedmcodeptr  = cd->mcodeptr;
824                 cd->mcodeptr = (u1 *) &(replacementpoint->mcode) + 1 /* big-endian */;
825
826                 disp = (ptrint)((s4*)replacementpoint->outcode - (s4*)replacementpoint->pc) - 1;
827                 M_BR(disp);
828
829                 cd->mcodeptr = savedmcodeptr;
830
831                 /* create stack frame - keep 16-byte aligned */
832
833                 M_AADD_IMM(REG_SP, -4 * 4, REG_SP);
834
835                 /* push address of `rplpoint` struct */
836
837                 disp = dseg_add_unique_address(cd, replacementpoint);
838                 M_ALD(REG_ITMP3, REG_PV, disp);
839                 M_AST_INTERN(REG_ITMP3, REG_SP, 0 * 4);
840
841                 /* jump to replacement function */
842
843                 disp = dseg_add_functionptr(cd, asm_replacement_out);
844                 M_ALD(REG_ITMP3, REG_PV, disp);
845                 M_MTCTR(REG_ITMP3);
846                 M_RTS;
847 #endif
848         }
849 }
850 #endif /* define(ENABLE_REPLACEMENT) */
851
852 /*
853 * These are local overrides for various environment variables in Emacs.
854 * Please do not remove this and leave it at the end of the file, where
855 * Emacs will automagically detect them.
856 * ---------------------------------------------------------------------
857 * Local variables:
858 * mode: c
859 * indent-tabs-mode: t
860 * c-basic-offset: 4
861 * tab-width: 4
862 * End:
863 * vim:noexpandtab:sw=4:ts=4:
864 */