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