6c0bee647298089781b74fecd0a64ec32e13e8f7
[cacao.git] / src / vm / jit / powerpc64 / emit.c
1 /* src/vm/jit/powerpc64/emit.c - PowerPC64 code emitter functions
2
3    Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    $Id: emitfuncs.c 4398 2006-01-31 23:43:08Z twisti $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33
34 #include "vm/types.h"
35
36 #include "mm/memory.h"
37
38 #include "md-abi.h"
39 #include "vm/jit/powerpc64/codegen.h"
40
41 #include "threads/lock-common.h"
42
43 #include "vm/builtin.h"
44 #include "vm/exceptions.h"
45 #include "vm/vm.h"
46
47 #include "vm/jit/abi.h"
48 #include "vm/jit/asmpart.h"
49 #include "vm/jit/emit-common.h"
50 #include "vm/jit/jit.h"
51
52 #include "vmcore/options.h"
53
54
55 /* emit_load *******************************************************************
56
57    Emits a possible load of an operand.
58
59 *******************************************************************************/
60
61 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
62 {
63         codegendata  *cd;
64         s4            disp;
65         s4            reg;
66
67         /* get required compiler data */
68
69         cd = jd->cd;
70
71         if (src->flags & INMEMORY) {
72                 COUNT_SPILLS;
73
74                 disp = src->vv.regoff;
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);
111                 }
112                 else {
113                         M_LST(d, REG_SP, dst->vv.regoff);
114                 }
115         }
116 }
117
118
119 /* emit_copy *******************************************************************
120
121    Generates a register/memory to register/memory copy.
122
123 *******************************************************************************/
124
125 void emit_copy(jitdata *jd, instruction *iptr)
126 {
127         codegendata *cd;
128         varinfo     *src;
129         varinfo     *dst;
130         s4           s1, d;
131
132         /* get required compiler data */
133
134         cd = jd->cd;
135
136         /* get source and destination variables */
137
138         src = VAROP(iptr->s1);
139         dst = VAROP(iptr->dst);
140
141         if ((src->vv.regoff != dst->vv.regoff) ||
142                 ((src->flags ^ dst->flags) & INMEMORY)) {
143
144                 if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
145                         /* emit nothing, as the value won't be used anyway */
146                         return;
147                 }
148
149                 /* If one of the variables resides in memory, we can eliminate
150                    the register move from/to the temporary register with the
151                    order of getting the destination register and the load. */
152
153                 if (IS_INMEMORY(src->flags)) {
154                         d  = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
155                         s1 = emit_load(jd, iptr, src, d);
156                 }
157                 else {
158                         s1 = emit_load(jd, iptr, src, REG_IFTMP);
159                         d  = codegen_reg_of_var(iptr->opc, dst, s1);
160                 }
161
162                 if (s1 != d) {
163                         if (IS_FLT_DBL_TYPE(src->type))
164                                 M_FMOV(s1, d);
165                         else
166                                 M_MOV(s1, d);
167                 }
168
169                 emit_store(jd, iptr, dst, d);
170         }
171 }
172
173
174 /* emit_iconst *****************************************************************
175
176    XXX
177
178 *******************************************************************************/
179
180 void emit_iconst(codegendata *cd, s4 d, s4 value)
181 {
182         s4 disp;
183
184         if ((value >= -32768) && (value <= 32767)) {
185                 M_LDA_INTERN(d, REG_ZERO, value);
186         } else {
187                 disp = dseg_add_s4(cd, value);
188                 M_ILD(d, REG_PV, disp);
189         }
190 }
191
192 void emit_lconst(codegendata *cd, s4 d, s8 value)
193 {
194         s4 disp;
195         if ((value >= -32768) && (value <= 32767)) {
196                 M_LDA_INTERN(d, REG_ZERO, value);
197         } else {
198                 disp = dseg_add_s8(cd, value);
199                 M_LLD(d, REG_PV, disp);
200         }
201 }
202
203
204 /* emit_verbosecall_enter ******************************************************
205
206    Generates the code for the call trace.
207
208 *******************************************************************************/
209
210 #if !defined(NDEBUG)
211 void emit_verbosecall_enter(jitdata *jd)
212 {
213         methodinfo   *m;
214         codegendata  *cd;
215         registerdata *rd;
216         s4 s1, p, t;
217         int stack_size;
218         methoddesc *md;
219
220         /* get required compiler data */
221
222         m  = jd->m;
223         cd = jd->cd;
224         rd = jd->rd;
225
226         md = m->parseddesc;
227         
228         /* Build up Stackframe for builtin_trace_args call (a multiple of 16) */
229         /* For Darwin:                                                        */
230         /* TODO                                                               */
231         /* For Linux:                                                         */
232         /* setup stack for TRACE_ARGS_NUM registers                           */
233         /* == LA_SIZE + PA_SIZE + 8 (methodinfo argument) + TRACE_ARGS_NUM*8 + 8 (itmp1)              */
234         
235         /* in nativestubs no Place to save the LR (Link Register) would be needed */
236         /* but since the stack frame has to be aligned the 4 Bytes would have to  */
237         /* be padded again */
238
239 #if defined(__DARWIN__)
240         stack_size = LA_SIZE + (TRACE_ARGS_NUM + 1) * 8;
241 #else
242         stack_size = LA_SIZE + PA_SIZE + 8 + TRACE_ARGS_NUM * 8 + 8;
243 #endif
244
245         /* mark trace code */
246         M_NOP;
247
248         M_MFLR(REG_ZERO);
249         M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
250         M_STDU(REG_SP, REG_SP, -stack_size);
251
252         for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++) {
253                 t = md->paramtypes[p].type;
254                 if (IS_INT_LNG_TYPE(t)) {
255                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
256                                 M_LST(md->params[p].regoff, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
257                         } else { /* Param on Stack */
258                                 s1 = md->params[p].regoff + cd->stackframesize * 8 + stack_size;
259                                 M_LLD(REG_ITMP2, REG_SP, s1);
260                                 M_LST(REG_ITMP2, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
261                         }
262                 } else { /* IS_FLT_DBL_TYPE(t) */
263                         if (!md->params[p].inmemory) { /* in Arg Reg */
264                                 s1 = md->params[p].regoff;
265                                 M_DST(s1, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
266                         } else { /* on Stack */
267                                 /* this should not happen */
268                                 assert(0);
269                         }
270                 }
271         }
272
273 #if defined(__DARWIN__)
274         #warning "emit_verbosecall_enter not implemented"
275 #else
276         /* LINUX */
277         /* Set integer and float argument registers for trace_args call */
278         /* offset to saved integer argument registers                   */
279         for (p = 0; (p < TRACE_ARGS_NUM) && (p < md->paramcount); p++) {
280                 t = md->paramtypes[p].type;
281                 if (IS_INT_LNG_TYPE(t)) {
282                         M_LLD(abi_registers_integer_argument[p], REG_SP,LA_SIZE + PA_SIZE + 8 + p * 8);
283                 } else { /* Float/Dbl */
284                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
285                                 /* use reserved Place on Stack (sp + 5 * 16) to copy  */
286                                 /* float/double arg reg to int reg                    */
287                                 s1 = md->params[p].regoff;
288                                 M_MOV(s1, abi_registers_integer_argument[p]);
289                         } else  {
290                                 assert(0);
291                         }
292                 }
293         }
294 #endif
295
296         /* put methodinfo pointer on Stackframe */
297         p = dseg_add_address(cd, m);
298         M_ALD(REG_ITMP1, REG_PV, p);
299 #if defined(__DARWIN__)
300         M_AST(REG_ITMP1, REG_SP, LA_SIZE + TRACE_ARGS_NUM * 8); 
301 #else
302         if (TRACE_ARGS_NUM == 8)        {
303                 /* need to pass via stack */
304                 M_AST(REG_ITMP1, REG_SP, LA_SIZE + PA_SIZE);
305         } else {
306                 /* pass via register, reg 3 is the first  */
307                 M_MOV(REG_ITMP1, 3 + TRACE_ARGS_NUM);
308         }
309 #endif
310         /* call via function descriptor */
311         /* XXX: what about TOC? */
312         p = dseg_add_functionptr(cd, builtin_verbosecall_enter);
313         M_ALD(REG_ITMP2, REG_PV, p);
314         M_ALD(REG_ITMP1, REG_ITMP2, 0);
315         M_MTCTR(REG_ITMP1);
316         M_JSR;
317
318 #if defined(__DARWIN__)
319         #warning "emit_verbosecall_enter not implemented"
320 #else
321         /* LINUX */
322         for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++) {
323                 t = md->paramtypes[p].type;
324                 if (IS_INT_LNG_TYPE(t)) {
325                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
326                                 /* restore integer argument registers */
327                                 M_LLD(abi_registers_integer_argument[p], REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
328                         } else {
329                                 assert(0);      /* TODO: implement this */
330                         }
331                 } else { /* FLT/DBL */
332                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
333                                 M_DLD(md->params[p].regoff, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
334                         } else {
335                                 assert(0); /* this shoudl never happen */
336                         }
337                         
338                 }
339         }
340 #endif
341         M_ALD(REG_ZERO, REG_SP, stack_size + LA_LR_OFFSET);
342         M_MTLR(REG_ZERO);
343         M_LDA(REG_SP, REG_SP, stack_size);
344
345         /* mark trace code */
346         M_NOP;
347 }
348 #endif
349
350
351 /* emit_verbosecall_exit ******************************************************
352
353    Generates the code for the call trace.
354
355    void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
356
357 *******************************************************************************/
358
359 #if !defined(NDEBUG)
360 void emit_verbosecall_exit(jitdata *jd)
361 {
362         methodinfo   *m;
363         codegendata  *cd;
364         s4            disp;
365
366         /* get required compiler data */
367
368         m  = jd->m;
369         cd = jd->cd;
370
371         /* mark trace code */
372
373         M_NOP;
374
375         M_MFLR(REG_ZERO);
376         M_LDA(REG_SP, REG_SP, -(LA_SIZE+PA_SIZE+10*8));
377         M_DST(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
378         M_LST(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+1*8);
379         M_AST(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+2*8);
380
381         M_MOV(REG_RESULT, REG_A0);
382
383         M_FLTMOVE(REG_FRESULT, REG_FA0);
384         M_FLTMOVE(REG_FRESULT, REG_FA1);
385
386         disp = dseg_add_address(cd, m);
387         M_ALD(REG_A3, REG_PV, disp);
388
389         disp = dseg_add_functionptr(cd, builtin_verbosecall_exit);
390         /* call via function descriptor, XXX: what about TOC ? */
391         M_ALD(REG_ITMP2, REG_PV, disp);
392         M_ALD(REG_ITMP2, REG_ITMP2, 0);
393         M_MTCTR(REG_ITMP2);
394         M_JSR;
395
396         M_DLD(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
397         M_LLD(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+1*8);
398         M_ALD(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+2*8);
399         M_LDA(REG_SP, REG_SP, LA_SIZE+PA_SIZE+10*8);
400         M_MTLR(REG_ZERO);
401
402         /* mark trace code */
403
404         M_NOP;
405 }
406 #endif
407
408
409 /* emit_branch *****************************************************************
410
411    Emits the code for conditional and unconditional branchs.
412
413 *******************************************************************************/
414
415 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
416 {
417         s4 checkdisp;
418         s4 branchdisp;
419
420         /* calculate the different displacements */
421
422         checkdisp  =  disp + 4;
423         branchdisp = (disp - 4) >> 2;
424
425         /* check which branch to generate */
426
427         if (condition == BRANCH_UNCONDITIONAL) {
428                 /* check displacement for overflow */
429
430                 if ((checkdisp < (s4) 0xfe000000) || (checkdisp > (s4) 0x01fffffc)) {
431                         /* if the long-branches flag isn't set yet, do it */
432
433                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
434                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
435                                                           CODEGENDATA_FLAG_LONGBRANCHES);
436                         }
437
438                         vm_abort("emit_branch: emit unconditional long-branch code");
439                 }
440                 else {
441                         M_BR(branchdisp);
442                 }
443         }
444         else {
445                 /* and displacement for overflow */
446
447                 if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
448                         /* if the long-branches flag isn't set yet, do it */
449
450                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
451                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
452                                                           CODEGENDATA_FLAG_LONGBRANCHES);
453                         }
454
455                         branchdisp --;          /* we jump from the second instruction */
456                         switch (condition) {
457                         case BRANCH_EQ:
458                                 M_BNE(1);
459                                 M_BR(branchdisp);
460                                 break;
461                         case BRANCH_NE:
462                                 M_BEQ(1);
463                                 M_BR(branchdisp);
464                                 break;
465                         case BRANCH_LT:
466                                 M_BGE(1);
467                                 M_BR(branchdisp);
468                                 break;
469                         case BRANCH_GE:
470                                 M_BLT(1);
471                                 M_BR(branchdisp);
472                                 break;
473                         case BRANCH_GT:
474                                 M_BLE(1);
475                                 M_BR(branchdisp);
476                                 break;
477                         case BRANCH_LE:
478                                 M_BGT(1);
479                                 M_BR(branchdisp);
480                                 break;
481                         case BRANCH_NAN:
482                                 vm_abort("emit_branch: long BRANCH_NAN");
483                                 break;
484                         default:
485                                 vm_abort("emit_branch: unknown condition %d", condition);
486                         }
487
488                 }
489                 else {
490                         switch (condition) {
491                         case BRANCH_EQ:
492                                 M_BEQ(branchdisp);
493                                 break;
494                         case BRANCH_NE:
495                                 M_BNE(branchdisp);
496                                 break;
497                         case BRANCH_LT:
498                                 M_BLT(branchdisp);
499                                 break;
500                         case BRANCH_GE:
501                                 M_BGE(branchdisp);
502                                 break;
503                         case BRANCH_GT:
504                                 M_BGT(branchdisp);
505                                 break;
506                         case BRANCH_LE:
507                                 M_BLE(branchdisp);
508                                 break;
509                         case BRANCH_NAN:
510                                 M_BNAN(branchdisp);
511                                 break;
512                         default:
513                                 vm_abort("emit_branch: unknown condition %d", condition);
514                         }
515                 }
516         }
517 }
518
519 /* emit_arrayindexoutofbounds_check ********************************************
520
521    Emit a ArrayIndexOutOfBoundsException check.
522
523 *******************************************************************************/
524
525 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
526 {
527         if (checkbounds) {
528 #define SOFTEX 0
529 #if SOFTEX
530                 M_ILD(REG_ITMP3, s1, OFFSET(java_array_t, size));
531                 M_CMPU(s2, REG_ITMP3);
532                 codegen_add_arrayindexoutofboundsexception_ref(cd, s2);
533                 BRANCH_NOPS;
534 #else
535                 M_ILD(REG_ITMP3, s1, OFFSET(java_array_t, size));
536                 M_CMPU(s2, REG_ITMP3);
537                 M_BLT(1);
538                 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
539                 M_LWZ(s2, REG_ZERO, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
540 #endif
541         }
542 }
543
544
545 /* emit_arithmetic_check *******************************************************
546
547    Emit an ArithmeticException check.
548
549 *******************************************************************************/
550
551 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
552 {
553         if (INSTRUCTION_MUST_CHECK(iptr))       {
554         #if SOFTEX
555                 M_TST(reg);
556                 codegen_add_arithmeticexception_ref(cd);
557                 BRANCH_NOPS;
558         #else
559                 M_TST(reg);
560                 M_BNE(1);
561                 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
562                 M_LWZ(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_ARITHMETIC);
563         #endif
564         }
565 }
566
567 #if 0
568 /* emit_arraystore_check *******************************************************
569
570    Emit an ArrayStoreException check.
571
572 *******************************************************************************/
573
574 void emit_arraystore_check(codegendata *cd, instruction *iptr, s4 reg)
575 {
576         if (INSTRUCTION_MUST_CHECK(iptr))       {
577                 M_TST(REG_RESULT);
578                 codegen_add_arraystoreexception_ref(cd);
579                 BRANCH_NOPS;
580         }
581 }
582 #endif
583
584 /* emit_classcast_check ********************************************************
585
586    Emit a ClassCastException check.
587
588 *******************************************************************************/
589
590 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
591 {
592         if (INSTRUCTION_MUST_CHECK(iptr))       {
593         #if SOFTEX
594                 codegen_add_classcastexception_ref(cd, condition, s1);
595                 BRANCH_NOPS;
596                 M_NOP;
597         #else
598                 switch(condition)       {
599                         case BRANCH_LE:
600                                 M_BGT(1);
601                                 break;
602                         case BRANCH_EQ:
603                                 M_BNE(1);
604                                 break;
605                         case BRANCH_GT:
606                                 M_BLE(1);
607                                 break;
608                         default:
609                                 vm_abort("emit_classcast_check: unknown condition %d", condition);
610                 }
611                 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
612                 M_LWZ(s1, REG_ZERO, EXCEPTION_HARDWARE_CLASSCAST);
613         #endif
614         }
615 }
616
617
618 /* emit_nullpointer_check ******************************************************
619
620    Emit a NullPointerException check.
621
622 *******************************************************************************/
623
624 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
625 {
626         if (INSTRUCTION_MUST_CHECK(iptr))       {
627                 M_TST(reg);
628                 M_BNE(1);
629                 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
630                 M_LWZ(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_NULLPOINTER);
631         }
632 }
633
634 /* emit_exception_check ********************************************************
635
636    Emit an Exception check.
637
638 *******************************************************************************/
639
640 void emit_exception_check(codegendata *cd, instruction *iptr)
641 {
642         if (INSTRUCTION_MUST_CHECK(iptr))       {
643         #if SOFTEX
644                 M_CMPI(REG_RESULT, 0);
645                 codegen_add_fillinstacktrace_ref(cd);
646                 BRANCH_NOPS;
647         #else
648                 M_TST(REG_RESULT);
649                 M_BNE(1);
650                 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
651                 M_LWZ(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_EXCEPTION);
652         #endif
653         }
654 }
655
656
657 /* emit_patcher_stubs **********************************************************
658
659    Generates the code for the patcher stubs.
660
661 *******************************************************************************/
662 void emit_patcher_stubs(jitdata *jd)
663 {
664         codegendata *cd;
665         patchref    *pref;
666         u4           mcode;
667         u1          *savedmcodeptr;
668         u1          *tmpmcodeptr;
669         s4           targetdisp;
670         s4           disp;
671
672         cd = jd->cd;
673
674         /* generate code patching stub call code */
675
676         targetdisp = 0;
677
678         for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
679                 /* check code segment size */
680
681                 MCODECHECK(32);
682
683                 /* Get machine code which is patched back in later. The
684                    call is 1 instruction word long. */
685
686                 tmpmcodeptr = (u1 *) (cd->mcodebase + pref->branchpos);
687
688                 mcode = *((u4 *) tmpmcodeptr);
689
690                 /* Patch in the call to call the following code (done at
691                    compile time). */
692
693                 savedmcodeptr = cd->mcodeptr;   /* save current mcodeptr          */
694                 cd->mcodeptr  = tmpmcodeptr;    /* set mcodeptr to patch position */
695
696                 disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 1);
697                 M_BR(disp);
698
699                 cd->mcodeptr = savedmcodeptr;   /* restore the current mcodeptr   */
700
701                 /* create stack frame - keep stack 16-byte aligned */
702                 M_AADD_IMM(REG_SP, -8 * 8, REG_SP);
703
704                 /* calculate return address and move it onto the stack */
705                 M_LDA(REG_ITMP3, REG_PV, pref->branchpos);
706                 M_AST_INTERN(REG_ITMP3, REG_SP, 5 * 8);
707
708                 /* move pointer to java_objectheader onto stack */
709
710 #if defined(ENABLE_THREADS)
711                 /* order reversed because of data segment layout */
712
713                 (void) dseg_add_unique_address(cd, NULL);                         /* flcword    */
714                 (void) dseg_add_unique_address(cd, lock_get_initial_lock_word()); /* monitorPtr */
715                 disp = dseg_add_unique_address(cd, NULL);                         /* vftbl      */
716
717                 M_LDA(REG_ITMP3, REG_PV, disp);
718                 M_AST_INTERN(REG_ITMP3, REG_SP, 4 * 8);
719 #else
720                 /* do nothing */
721 #endif
722
723                 /* move machine code onto stack */
724                 disp = dseg_add_s4(cd, mcode);
725                 M_ILD(REG_ITMP3, REG_PV, disp);
726                 M_IST_INTERN(REG_ITMP3, REG_SP, 3 * 8);
727
728                 /* move class/method/field reference onto stack */
729                 disp = dseg_add_address(cd, pref->ref);
730                 M_ALD(REG_ITMP3, REG_PV, disp);
731                 M_AST_INTERN(REG_ITMP3, REG_SP, 2 * 8);
732
733                 /* move data segment displacement onto stack */
734                 disp = dseg_add_s4(cd, pref->disp);
735                 M_ILD(REG_ITMP3, REG_PV, disp);
736                 M_IST_INTERN(REG_ITMP3, REG_SP, 1 * 8);
737
738                 /* move patcher function pointer onto stack */
739                 disp = dseg_add_functionptr(cd, pref->patcher);
740                 M_ALD(REG_ITMP3, REG_PV, disp);
741                 M_AST_INTERN(REG_ITMP3, REG_SP, 0 * 8);
742
743                 if (targetdisp == 0) {
744                         targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
745
746                         disp = dseg_add_functionptr(cd, asm_patcher_wrapper);
747                         M_ALD(REG_ITMP3, REG_PV, disp);
748                         M_MTCTR(REG_ITMP3);
749                         M_RTS;
750                 }
751                 else {
752                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
753                                 (((u4 *) cd->mcodeptr) + 1);
754                         M_BR(disp);
755                 }
756         }
757 }
758
759
760 /* emit_trap *******************************************************************
761
762    Emit a trap instruction and return the original machine code.
763
764 *******************************************************************************/
765
766 uint32_t emit_trap(codegendata *cd)
767 {
768         uint32_t mcode;
769
770         /* Get machine code which is patched back in later. The
771            trap is 1 instruction word long. */
772
773         mcode = *((uint32_t *) cd->mcodeptr);
774
775         M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_PATCHER);
776
777         return mcode;
778 }
779
780
781 /*
782  * These are local overrides for various environment variables in Emacs.
783  * Please do not remove this and leave it at the end of the file, where
784  * Emacs will automagically detect them.
785  * ---------------------------------------------------------------------
786  * Local variables:
787  * mode: c
788  * indent-tabs-mode: t
789  * c-basic-offset: 4
790  * tab-width: 4
791  * End:
792  * vim:noexpandtab:sw=4:ts=4:
793  */