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