* Removed all Id tags.
[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 */
26
27
28 #include "config.h"
29
30 #include <assert.h>
31
32 #include "vm/types.h"
33
34 #include "mm/memory.h"
35
36 #include "md-abi.h"
37 #include "vm/jit/powerpc64/codegen.h"
38
39 #include "threads/lock-common.h"
40
41 #include "vm/builtin.h"
42 #include "vm/exceptions.h"
43 #include "vm/vm.h"
44
45 #include "vm/jit/abi.h"
46 #include "vm/jit/asmpart.h"
47 #include "vm/jit/emit-common.h"
48 #include "vm/jit/jit.h"
49
50 #include "vmcore/options.h"
51
52
53 /* emit_load *******************************************************************
54
55    Emits a possible load of an operand.
56
57 *******************************************************************************/
58
59 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
60 {
61         codegendata  *cd;
62         s4            disp;
63         s4            reg;
64
65         /* get required compiler data */
66
67         cd = jd->cd;
68
69         if (src->flags & INMEMORY) {
70                 COUNT_SPILLS;
71
72                 disp = src->vv.regoff;
73
74                 if (IS_FLT_DBL_TYPE(src->type)) {
75                         M_DLD(tempreg, REG_SP, disp);
76                 }
77                 else {
78                         M_LLD(tempreg, REG_SP, disp);
79                 }
80
81                 reg = tempreg;
82         }
83         else
84                 reg = src->vv.regoff;
85
86         return reg;
87 }
88
89
90 /* emit_store ******************************************************************
91
92    Emits a possible store to a variable.
93
94 *******************************************************************************/
95
96 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
97 {
98         codegendata  *cd;
99
100         /* get required compiler data */
101
102         cd = jd->cd;
103
104         if (dst->flags & INMEMORY) {
105                 COUNT_SPILLS;
106
107                 if (IS_FLT_DBL_TYPE(dst->type)) {
108                         M_DST(d, REG_SP, dst->vv.regoff);
109                 }
110                 else {
111                         M_LST(d, REG_SP, dst->vv.regoff);
112                 }
113         }
114 }
115
116
117 /* emit_copy *******************************************************************
118
119    Generates a register/memory to register/memory copy.
120
121 *******************************************************************************/
122
123 void emit_copy(jitdata *jd, instruction *iptr)
124 {
125         codegendata *cd;
126         varinfo     *src;
127         varinfo     *dst;
128         s4           s1, d;
129
130         /* get required compiler data */
131
132         cd = jd->cd;
133
134         /* get source and destination variables */
135
136         src = VAROP(iptr->s1);
137         dst = VAROP(iptr->dst);
138
139         if ((src->vv.regoff != dst->vv.regoff) ||
140                 ((src->flags ^ dst->flags) & INMEMORY)) {
141
142                 if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
143                         /* emit nothing, as the value won't be used anyway */
144                         return;
145                 }
146
147                 /* If one of the variables resides in memory, we can eliminate
148                    the register move from/to the temporary register with the
149                    order of getting the destination register and the load. */
150
151                 if (IS_INMEMORY(src->flags)) {
152                         d  = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
153                         s1 = emit_load(jd, iptr, src, d);
154                 }
155                 else {
156                         s1 = emit_load(jd, iptr, src, REG_IFTMP);
157                         d  = codegen_reg_of_var(iptr->opc, dst, s1);
158                 }
159
160                 if (s1 != d) {
161                         if (IS_FLT_DBL_TYPE(src->type))
162                                 M_FMOV(s1, d);
163                         else
164                                 M_MOV(s1, d);
165                 }
166
167                 emit_store(jd, iptr, dst, d);
168         }
169 }
170
171
172 /* emit_iconst *****************************************************************
173
174    XXX
175
176 *******************************************************************************/
177
178 void emit_iconst(codegendata *cd, s4 d, s4 value)
179 {
180         s4 disp;
181
182         if ((value >= -32768) && (value <= 32767)) {
183                 M_LDA_INTERN(d, REG_ZERO, value);
184         } else {
185                 disp = dseg_add_s4(cd, value);
186                 M_ILD(d, REG_PV, disp);
187         }
188 }
189
190 void emit_lconst(codegendata *cd, s4 d, s8 value)
191 {
192         s4 disp;
193         if ((value >= -32768) && (value <= 32767)) {
194                 M_LDA_INTERN(d, REG_ZERO, value);
195         } else {
196                 disp = dseg_add_s8(cd, value);
197                 M_LLD(d, REG_PV, disp);
198         }
199 }
200
201
202 /* emit_verbosecall_enter ******************************************************
203
204    Generates the code for the call trace.
205
206 *******************************************************************************/
207
208 #if !defined(NDEBUG)
209 void emit_verbosecall_enter(jitdata *jd)
210 {
211         methodinfo   *m;
212         codegendata  *cd;
213         registerdata *rd;
214         s4 s1, p, t;
215         int stack_size;
216         methoddesc *md;
217
218         /* get required compiler data */
219
220         m  = jd->m;
221         cd = jd->cd;
222         rd = jd->rd;
223
224         md = m->parseddesc;
225         
226         /* Build up Stackframe for builtin_trace_args call (a multiple of 16) */
227         /* For Darwin:                                                        */
228         /* TODO                                                               */
229         /* For Linux:                                                         */
230         /* setup stack for TRACE_ARGS_NUM registers                           */
231         /* == LA_SIZE + PA_SIZE + 8 (methodinfo argument) + TRACE_ARGS_NUM*8 + 8 (itmp1)              */
232         
233         /* in nativestubs no Place to save the LR (Link Register) would be needed */
234         /* but since the stack frame has to be aligned the 4 Bytes would have to  */
235         /* be padded again */
236
237 #if defined(__DARWIN__)
238         stack_size = LA_SIZE + (TRACE_ARGS_NUM + 1) * 8;
239 #else
240         stack_size = LA_SIZE + PA_SIZE + 8 + TRACE_ARGS_NUM * 8 + 8;
241 #endif
242
243         /* mark trace code */
244         M_NOP;
245
246         M_MFLR(REG_ZERO);
247         M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
248         M_STDU(REG_SP, REG_SP, -stack_size);
249
250         for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++) {
251                 t = md->paramtypes[p].type;
252                 if (IS_INT_LNG_TYPE(t)) {
253                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
254                                 M_LST(md->params[p].regoff, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
255                         } else { /* Param on Stack */
256                                 s1 = md->params[p].regoff + cd->stackframesize * 8 + stack_size;
257                                 M_LLD(REG_ITMP2, REG_SP, s1);
258                                 M_LST(REG_ITMP2, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
259                         }
260                 } else { /* IS_FLT_DBL_TYPE(t) */
261                         if (!md->params[p].inmemory) { /* in Arg Reg */
262                                 s1 = md->params[p].regoff;
263                                 M_DST(s1, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
264                         } else { /* on Stack */
265                                 /* this should not happen */
266                                 assert(0);
267                         }
268                 }
269         }
270
271 #if defined(__DARWIN__)
272         #warning "emit_verbosecall_enter not implemented"
273 #else
274         /* LINUX */
275         /* Set integer and float argument registers for trace_args call */
276         /* offset to saved integer argument registers                   */
277         for (p = 0; (p < TRACE_ARGS_NUM) && (p < md->paramcount); p++) {
278                 t = md->paramtypes[p].type;
279                 if (IS_INT_LNG_TYPE(t)) {
280                         M_LLD(abi_registers_integer_argument[p], REG_SP,LA_SIZE + PA_SIZE + 8 + p * 8);
281                 } else { /* Float/Dbl */
282                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
283                                 /* use reserved Place on Stack (sp + 5 * 16) to copy  */
284                                 /* float/double arg reg to int reg                    */
285                                 s1 = md->params[p].regoff;
286                                 M_MOV(s1, abi_registers_integer_argument[p]);
287                         } else  {
288                                 assert(0);
289                         }
290                 }
291         }
292 #endif
293
294         /* put methodinfo pointer on Stackframe */
295         p = dseg_add_address(cd, m);
296         M_ALD(REG_ITMP1, REG_PV, p);
297 #if defined(__DARWIN__)
298         M_AST(REG_ITMP1, REG_SP, LA_SIZE + TRACE_ARGS_NUM * 8); 
299 #else
300         if (TRACE_ARGS_NUM == 8)        {
301                 /* need to pass via stack */
302                 M_AST(REG_ITMP1, REG_SP, LA_SIZE + PA_SIZE);
303         } else {
304                 /* pass via register, reg 3 is the first  */
305                 M_MOV(REG_ITMP1, 3 + TRACE_ARGS_NUM);
306         }
307 #endif
308         /* call via function descriptor */
309         /* XXX: what about TOC? */
310         p = dseg_add_functionptr(cd, builtin_verbosecall_enter);
311         M_ALD(REG_ITMP2, REG_PV, p);
312         M_ALD(REG_ITMP1, REG_ITMP2, 0);
313         M_MTCTR(REG_ITMP1);
314         M_JSR;
315
316 #if defined(__DARWIN__)
317         #warning "emit_verbosecall_enter not implemented"
318 #else
319         /* LINUX */
320         for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++) {
321                 t = md->paramtypes[p].type;
322                 if (IS_INT_LNG_TYPE(t)) {
323                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
324                                 /* restore integer argument registers */
325                                 M_LLD(abi_registers_integer_argument[p], REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
326                         } else {
327                                 assert(0);      /* TODO: implement this */
328                         }
329                 } else { /* FLT/DBL */
330                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
331                                 M_DLD(md->params[p].regoff, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
332                         } else {
333                                 assert(0); /* this shoudl never happen */
334                         }
335                         
336                 }
337         }
338 #endif
339         M_ALD(REG_ZERO, REG_SP, stack_size + LA_LR_OFFSET);
340         M_MTLR(REG_ZERO);
341         M_LDA(REG_SP, REG_SP, stack_size);
342
343         /* mark trace code */
344         M_NOP;
345 }
346 #endif
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 #if !defined(NDEBUG)
358 void emit_verbosecall_exit(jitdata *jd)
359 {
360         methodinfo   *m;
361         codegendata  *cd;
362         s4            disp;
363
364         /* get required compiler data */
365
366         m  = jd->m;
367         cd = jd->cd;
368
369         /* mark trace code */
370
371         M_NOP;
372
373         M_MFLR(REG_ZERO);
374         M_LDA(REG_SP, REG_SP, -(LA_SIZE+PA_SIZE+10*8));
375         M_DST(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
376         M_LST(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+1*8);
377         M_AST(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+2*8);
378
379         M_MOV(REG_RESULT, REG_A0);
380
381         M_FLTMOVE(REG_FRESULT, REG_FA0);
382         M_FLTMOVE(REG_FRESULT, REG_FA1);
383
384         disp = dseg_add_address(cd, m);
385         M_ALD(REG_A3, REG_PV, disp);
386
387         disp = dseg_add_functionptr(cd, builtin_verbosecall_exit);
388         /* call via function descriptor, XXX: what about TOC ? */
389         M_ALD(REG_ITMP2, REG_PV, disp);
390         M_ALD(REG_ITMP2, REG_ITMP2, 0);
391         M_MTCTR(REG_ITMP2);
392         M_JSR;
393
394         M_DLD(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
395         M_LLD(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+1*8);
396         M_ALD(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+2*8);
397         M_LDA(REG_SP, REG_SP, LA_SIZE+PA_SIZE+10*8);
398         M_MTLR(REG_ZERO);
399
400         /* mark trace code */
401
402         M_NOP;
403 }
404 #endif
405
406
407 /* emit_branch *****************************************************************
408
409    Emits the code for conditional and unconditional branchs.
410
411 *******************************************************************************/
412
413 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
414 {
415         s4 checkdisp;
416         s4 branchdisp;
417
418         /* calculate the different displacements */
419
420         checkdisp  =  disp + 4;
421         branchdisp = (disp - 4) >> 2;
422
423         /* check which branch to generate */
424
425         if (condition == BRANCH_UNCONDITIONAL) {
426                 /* check displacement for overflow */
427
428                 if ((checkdisp < (s4) 0xfe000000) || (checkdisp > (s4) 0x01fffffc)) {
429                         /* if the long-branches flag isn't set yet, do it */
430
431                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
432                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
433                                                           CODEGENDATA_FLAG_LONGBRANCHES);
434                         }
435
436                         vm_abort("emit_branch: emit unconditional long-branch code");
437                 }
438                 else {
439                         M_BR(branchdisp);
440                 }
441         }
442         else {
443                 /* and displacement for overflow */
444
445                 if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
446                         /* if the long-branches flag isn't set yet, do it */
447
448                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
449                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
450                                                           CODEGENDATA_FLAG_LONGBRANCHES);
451                         }
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_array_t, 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_array_t, 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(32);
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_trap *******************************************************************
759
760    Emit a trap instruction and return the original machine code.
761
762 *******************************************************************************/
763
764 uint32_t emit_trap(codegendata *cd)
765 {
766         uint32_t mcode;
767
768         /* Get machine code which is patched back in later. The
769            trap is 1 instruction word long. */
770
771         mcode = *((uint32_t *) cd->mcodeptr);
772
773         M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_PATCHER);
774
775         return mcode;
776 }
777
778
779 /*
780  * These are local overrides for various environment variables in Emacs.
781  * Please do not remove this and leave it at the end of the file, where
782  * Emacs will automagically detect them.
783  * ---------------------------------------------------------------------
784  * Local variables:
785  * mode: c
786  * indent-tabs-mode: t
787  * c-basic-offset: 4
788  * tab-width: 4
789  * End:
790  * vim:noexpandtab:sw=4:ts=4:
791  */